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: #define MAX_SUBSCRIBTION %(subscription_table_count)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; etisserant@209: 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: greg@423: void __init_debug(void) etisserant@209: { etisserant@280: buffer_state = BUFFER_FREE; greg@244: } etisserant@209: greg@423: void __cleanup_debug(void) etisserant@209: { etisserant@209: } etisserant@209: greg@423: void __retrieve_debug(void) etisserant@209: { etisserant@209: } etisserant@209: etisserant@239: extern int TryEnterDebugSection(void); etisserant@239: extern void LeaveDebugSection(void); laurent@386: extern long AtomicCompareExchange(long*, long, long); laurent@386: extern void InitiateDebugTransfer(void); etisserant@239: laurent@397: extern unsigned long __tick; edouard@450: edouard@450: #define __BufferDebugDataIterator_case_t(TYPENAME) \ edouard@450: case TYPENAME##_ENUM :\ edouard@450: flags = ((__IEC_##TYPENAME##_t *)varp)->flags;\ edouard@450: ptrvalue = &((__IEC_##TYPENAME##_t *)varp)->value; edouard@450: edouard@450: #define __BufferDebugDataIterator_case_p(TYPENAME)\ edouard@450: case TYPENAME##_P_ENUM :\ edouard@450: flags = ((__IEC_##TYPENAME##_p *)varp)->flags;\ edouard@450: ptrvalue = ((__IEC_##TYPENAME##_p *)varp)->value; edouard@450: edouard@450: void BufferDebugDataIterator(void* varp, __IEC_types_enum vartype) edouard@450: { edouard@450: void *ptrvalue = NULL; edouard@450: char flags = 0; 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@450: if(flags && __IEC_DEBUG_FLAG){ edouard@450: USINT size = __get_type_enum_size(vartype); edouard@450: /* compute next cursor positon*/ edouard@450: char* next_cursor = buffer_cursor + size; edouard@450: /* if buffer not full */ edouard@450: if(next_cursor <= debug_buffer + BUFFER_SIZE) edouard@450: { edouard@450: /* copy data to the buffer */ edouard@450: memcpy(buffer_cursor, ptrvalue, size); edouard@450: /* increment cursor according size*/ edouard@450: buffer_cursor = next_cursor; edouard@450: }else{ edouard@450: /*TODO : signal overflow*/ edouard@450: } edouard@450: } edouard@450: } edouard@450: edouard@450: greg@423: void __publish_debug(void) etisserant@209: { 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(); etisserant@209: } etisserant@209: } etisserant@209: edouard@450: #define __RegisterDebugVariable_case_t(TYPENAME) \ edouard@450: case TYPENAME##_ENUM :\ edouard@450: ((__IEC_##TYPENAME##_t *)varp)->flags |= __IEC_DEBUG_FLAG; edouard@450: #define __RegisterDebugVariable_case_p(TYPENAME)\ edouard@450: case TYPENAME##_P_ENUM :\ edouard@450: ((__IEC_##TYPENAME##_p *)varp)->flags |= __IEC_DEBUG_FLAG; etisserant@209: void RegisterDebugVariable(int idx) etisserant@209: { edouard@452: void *varp = NULL; edouard@450: 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@450: ((__IEC_##TYPENAME##_t *)varp)->flags &= ~__IEC_DEBUG_FLAG; edouard@450: edouard@450: #define __ResetDebugVariablesIterator_case_p(TYPENAME)\ edouard@450: case TYPENAME##_P_ENUM :\ edouard@450: ((__IEC_##TYPENAME##_p *)varp)->flags &= ~__IEC_DEBUG_FLAG;\ 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@450: int res = WaitDebugData(tick); edouard@450: *size = buffer_cursor - debug_buffer; edouard@450: *buffer = NULL; edouard@450: return res; etisserant@209: } etisserant@209: