etisserant@209: /* etisserant@209: * DEBUGGER code etisserant@209: * etisserant@209: * On "publish", when buffer is free, debugger stores arbitrary variables etisserant@209: * content into, and mark this buffer as filled etisserant@209: * etisserant@209: * etisserant@209: * Buffer content is read asynchronously, (from non real time part), etisserant@209: * and then buffer marked free again. etisserant@209: * etisserant@209: * etisserant@209: * */ etisserant@209: #include "iec_types_all.h" etisserant@209: #include "POUS.h" etisserant@209: /*for memcpy*/ etisserant@209: #include greg@335: #include etisserant@209: greg@335: #define BUFFER_SIZE %(buffer_size)d etisserant@209: etisserant@209: /* Atomically accessed variable for buffer state */ etisserant@209: #define BUFFER_FREE 0 etisserant@209: #define BUFFER_BUSY 1 etisserant@209: static long buffer_state = BUFFER_FREE; etisserant@209: etisserant@209: /* The buffer itself */ etisserant@209: char debug_buffer[BUFFER_SIZE]; etisserant@209: etisserant@209: /* Buffer's cursor*/ etisserant@209: static char* buffer_cursor = debug_buffer; edouard@483: static unsigned int retain_offset = 0; etisserant@209: /*** etisserant@209: * Declare programs etisserant@209: **/ etisserant@209: %(programs_declarations)s etisserant@209: etisserant@209: /*** etisserant@209: * Declare global variables from resources and conf etisserant@209: **/ etisserant@209: %(extern_variables_declarations)s etisserant@209: edouard@450: typedef void(*__for_each_variable_do_fp)(void*, __IEC_types_enum); edouard@452: void __for_each_variable_do(__for_each_variable_do_fp fp) edouard@450: { edouard@450: %(for_each_variable_do_code)s edouard@450: } etisserant@209: edouard@450: __IEC_types_enum __find_variable(unsigned int varindex, void ** varp) edouard@450: { edouard@450: switch(varindex){ edouard@450: %(find_variable_case_code)s edouard@452: default: edouard@452: *varp = NULL; edouard@452: return UNKNOWN_ENUM; edouard@452: } edouard@450: } etisserant@209: edouard@450: #define __BufferDebugDataIterator_case_t(TYPENAME) \ edouard@450: case TYPENAME##_ENUM :\ edouard@483: *flags = ((__IEC_##TYPENAME##_t *)varp)->flags;\ edouard@483: *ptrvalue = &((__IEC_##TYPENAME##_t *)varp)->value;\ edouard@458: break; edouard@450: edouard@450: #define __BufferDebugDataIterator_case_p(TYPENAME)\ edouard@450: case TYPENAME##_P_ENUM :\ laurent@511: case TYPENAME##_O_ENUM :\ edouard@483: *flags = ((__IEC_##TYPENAME##_p *)varp)->flags;\ laurent@507: if (*flags & __IEC_FORCE_FLAG)\ laurent@491: *ptrvalue = &((__IEC_##TYPENAME##_p *)varp)->fvalue;\ laurent@491: else\ laurent@491: *ptrvalue = ((__IEC_##TYPENAME##_p *)varp)->value;\ edouard@483: break; edouard@483: edouard@483: void UnpackVar(void* varp, __IEC_types_enum vartype, void **ptrvalue, char *flags) edouard@483: { edouard@450: /* find data to copy*/ edouard@450: switch(vartype){ edouard@450: ANY(__BufferDebugDataIterator_case_t) edouard@450: ANY(__BufferDebugDataIterator_case_p) edouard@452: default: edouard@452: break; edouard@450: } edouard@483: } edouard@483: edouard@483: void Remind(unsigned int offset, unsigned int count, void * p); edouard@483: edouard@483: void RemindIterator(void* varp, __IEC_types_enum vartype) edouard@483: { edouard@483: void *ptrvalue = NULL; edouard@483: char flags = 0; edouard@483: UnpackVar(varp, vartype, &ptrvalue, &flags); edouard@483: laurent@507: if(flags & __IEC_RETAIN_FLAG){ edouard@450: USINT size = __get_type_enum_size(vartype); edouard@450: /* compute next cursor positon*/ edouard@483: unsigned int next_retain_offset = retain_offset + size; edouard@450: /* if buffer not full */ edouard@483: Remind(retain_offset, size, ptrvalue); edouard@483: /* increment cursor according size*/ edouard@483: retain_offset = next_retain_offset; edouard@483: } edouard@483: } edouard@483: edouard@521: int CheckRetainBuffer(void); edouard@521: edouard@483: void __init_debug(void) edouard@483: { edouard@483: /* init local static vars */ edouard@483: buffer_cursor = debug_buffer; edouard@483: retain_offset = 0; edouard@483: buffer_state = BUFFER_FREE; edouard@483: /* Iterate over all variables to fill debug buffer */ edouard@521: if(CheckRetainBuffer()) edouard@521: __for_each_variable_do(RemindIterator); edouard@483: retain_offset = 0; edouard@483: } edouard@483: edouard@483: extern void InitiateDebugTransfer(void); edouard@483: edouard@483: extern unsigned long __tick; edouard@483: edouard@483: void __cleanup_debug(void) edouard@483: { edouard@483: buffer_cursor = debug_buffer; edouard@483: InitiateDebugTransfer(); edouard@483: } edouard@483: edouard@483: void __retrieve_debug(void) edouard@483: { edouard@483: } edouard@483: edouard@483: void DoDebug(void *ptrvalue, char flags, USINT size) edouard@483: { edouard@483: /* compute next cursor positon*/ edouard@483: char* next_cursor = buffer_cursor + size; edouard@483: /* if buffer not full */ edouard@483: if(next_cursor <= debug_buffer + BUFFER_SIZE) edouard@483: { edouard@483: /* copy data to the buffer */ edouard@483: memcpy(buffer_cursor, ptrvalue, size); edouard@483: /* increment cursor according size*/ edouard@483: buffer_cursor = next_cursor; edouard@483: }else{ edouard@483: /*TODO : signal overflow*/ edouard@483: } edouard@483: } edouard@483: edouard@483: void Retain(unsigned int offset, unsigned int count, void * p); edouard@483: void DoRetain(void *ptrvalue, char flags, USINT size){ edouard@483: /* compute next cursor positon*/ edouard@483: unsigned int next_retain_offset = retain_offset + size; edouard@483: /* if buffer not full */ edouard@483: Retain(retain_offset, size, ptrvalue); edouard@483: /* increment cursor according size*/ edouard@483: retain_offset = next_retain_offset; edouard@483: } edouard@483: edouard@483: void BufferDebugDataIterator(void* varp, __IEC_types_enum vartype) edouard@483: { edouard@483: void *ptrvalue = NULL; edouard@483: char flags = 0; edouard@483: UnpackVar(varp, vartype, &ptrvalue, &flags); edouard@483: /* For optimization purpose we do retain and debug in the same pass */ edouard@483: if(flags & (__IEC_DEBUG_FLAG | __IEC_RETAIN_FLAG)){ edouard@483: USINT size = __get_type_enum_size(vartype); edouard@483: if(flags & __IEC_DEBUG_FLAG){ edouard@483: DoDebug(ptrvalue, flags, size); edouard@450: } edouard@483: if(flags & __IEC_RETAIN_FLAG){ edouard@483: DoRetain(ptrvalue, flags, size); edouard@483: } edouard@483: } edouard@483: } edouard@483: edouard@483: void RetainIterator(void* varp, __IEC_types_enum vartype) edouard@483: { edouard@483: void *ptrvalue = NULL; edouard@483: char flags = 0; edouard@483: UnpackVar(varp, vartype, &ptrvalue, &flags); edouard@483: edouard@483: if(flags & __IEC_RETAIN_FLAG){ edouard@483: USINT size = __get_type_enum_size(vartype); edouard@483: DoRetain(ptrvalue, flags, size); edouard@483: } edouard@483: } edouard@483: edouard@483: extern int TryEnterDebugSection(void); edouard@483: extern long AtomicCompareExchange(long*, long, long); edouard@483: extern void LeaveDebugSection(void); edouard@450: greg@423: void __publish_debug(void) etisserant@209: { edouard@483: retain_offset = 0; etisserant@239: /* Check there is no running debugger re-configuration */ etisserant@239: if(TryEnterDebugSection()){ etisserant@239: /* Lock buffer */ etisserant@239: long latest_state = AtomicCompareExchange( etisserant@239: &buffer_state, etisserant@239: BUFFER_FREE, etisserant@239: BUFFER_BUSY); etisserant@239: etisserant@239: /* If buffer was free */ etisserant@239: if(latest_state == BUFFER_FREE) etisserant@209: { etisserant@239: /* Reset buffer cursor */ etisserant@239: buffer_cursor = debug_buffer; edouard@450: /* Iterate over all variables to fill debug buffer */ edouard@450: __for_each_variable_do(BufferDebugDataIterator); etisserant@239: etisserant@239: /* Leave debug section, etisserant@239: * Trigger asynchronous transmission etisserant@239: * (returns immediately) */ etisserant@239: InitiateDebugTransfer(); /* size */ etisserant@209: } etisserant@239: LeaveDebugSection(); edouard@483: }else{ edouard@483: /* when not debugging, do only retain */ edouard@483: __for_each_variable_do(RetainIterator); etisserant@209: } etisserant@209: } etisserant@209: edouard@450: #define __RegisterDebugVariable_case_t(TYPENAME) \ edouard@450: case TYPENAME##_ENUM :\ edouard@477: ((__IEC_##TYPENAME##_t *)varp)->flags |= flags;\ edouard@477: if(force)\ edouard@477: ((__IEC_##TYPENAME##_t *)varp)->value = *((TYPENAME *)force);\ edouard@458: break; edouard@450: #define __RegisterDebugVariable_case_p(TYPENAME)\ edouard@450: case TYPENAME##_P_ENUM :\ edouard@477: ((__IEC_##TYPENAME##_p *)varp)->flags |= flags;\ edouard@477: if(force)\ edouard@477: ((__IEC_##TYPENAME##_p *)varp)->fvalue = *((TYPENAME *)force);\ laurent@511: break;\ laurent@511: case TYPENAME##_O_ENUM :\ laurent@511: ((__IEC_##TYPENAME##_p *)varp)->flags |= flags;\ laurent@511: if(force)\ laurent@511: ((__IEC_##TYPENAME##_p *)varp)->fvalue = *((TYPENAME *)force);\ laurent@511: *(((__IEC_##TYPENAME##_p *)varp)->value) = *((TYPENAME *)force);\ edouard@477: break; edouard@477: void RegisterDebugVariable(int idx, void* force) etisserant@209: { edouard@452: void *varp = NULL; edouard@477: unsigned char flags = force ? __IEC_DEBUG_FLAG | __IEC_FORCE_FLAG : __IEC_DEBUG_FLAG; edouard@458: switch(__find_variable(idx, &varp)){ edouard@450: ANY(__RegisterDebugVariable_case_t) edouard@450: ANY(__RegisterDebugVariable_case_p) edouard@452: default: edouard@452: break; edouard@450: } edouard@450: } edouard@450: edouard@450: #define __ResetDebugVariablesIterator_case_t(TYPENAME) \ edouard@450: case TYPENAME##_ENUM :\ edouard@477: ((__IEC_##TYPENAME##_t *)varp)->flags &= ~(__IEC_DEBUG_FLAG|__IEC_FORCE_FLAG);\ edouard@458: break; edouard@450: edouard@450: #define __ResetDebugVariablesIterator_case_p(TYPENAME)\ edouard@450: case TYPENAME##_P_ENUM :\ edouard@477: ((__IEC_##TYPENAME##_p *)varp)->flags &= ~(__IEC_DEBUG_FLAG|__IEC_FORCE_FLAG);\ edouard@458: break; edouard@450: edouard@450: void ResetDebugVariablesIterator(void* varp, __IEC_types_enum vartype) edouard@450: { edouard@450: /* force debug flag to 0*/ edouard@450: switch(vartype){ edouard@450: ANY(__ResetDebugVariablesIterator_case_t) edouard@450: ANY(__ResetDebugVariablesIterator_case_p) edouard@452: default: edouard@452: break; etisserant@209: } etisserant@209: } etisserant@209: etisserant@209: void ResetDebugVariables(void) etisserant@209: { edouard@450: __for_each_variable_do(ResetDebugVariablesIterator); etisserant@209: } etisserant@209: greg@423: void FreeDebugData(void) etisserant@209: { etisserant@209: /* atomically mark buffer as free */ greg@423: long latest_state; greg@423: latest_state = AtomicCompareExchange( etisserant@209: &buffer_state, etisserant@209: BUFFER_BUSY, etisserant@209: BUFFER_FREE); etisserant@209: } edouard@452: int WaitDebugData(unsigned long *tick); edouard@450: /* Wait until debug data ready and return pointer to it */ edouard@450: int GetDebugData(unsigned long *tick, unsigned long *size, void **buffer){ edouard@504: int wait_error = WaitDebugData(tick); edouard@504: if(!wait_error){ edouard@502: *size = buffer_cursor - debug_buffer; edouard@502: *buffer = debug_buffer; edouard@502: } edouard@504: return wait_error; edouard@504: } edouard@504: