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@605: #define __Unpack_case_t(TYPENAME) \ edouard@450: case TYPENAME##_ENUM :\ edouard@483: *flags = ((__IEC_##TYPENAME##_t *)varp)->flags;\ Edouard@605: forced_value_p = *real_value_p = &((__IEC_##TYPENAME##_t *)varp)->value;\ Edouard@605: break; Edouard@605: Edouard@605: #define __Unpack_case_p(TYPENAME)\ Edouard@605: case TYPENAME##_O_ENUM :\ Edouard@605: *flags = __IEC_OUTPUT_FLAG;\ edouard@450: case TYPENAME##_P_ENUM :\ Edouard@605: *flags |= ((__IEC_##TYPENAME##_p *)varp)->flags;\ Edouard@605: *real_value_p = ((__IEC_##TYPENAME##_p *)varp)->value;\ Edouard@605: forced_value_p = &((__IEC_##TYPENAME##_p *)varp)->fvalue;\ Edouard@605: break; Edouard@605: Edouard@605: void* UnpackVar(void* varp, __IEC_types_enum vartype, void **real_value_p, char *flags) Edouard@605: { Edouard@605: void *forced_value_p = NULL; Edouard@605: *flags = 0; edouard@450: /* find data to copy*/ edouard@450: switch(vartype){ laurent@611: __ANY(__Unpack_case_t) laurent@611: __ANY(__Unpack_case_p) edouard@452: default: edouard@452: break; edouard@450: } Edouard@605: if (*flags & __IEC_FORCE_FLAG) Edouard@605: return forced_value_p; Edouard@605: return *real_value_p; 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@605: void *real_value_p = NULL; edouard@483: char flags = 0; Edouard@605: UnpackVar(varp, vartype, &real_value_p, &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@605: Remind(retain_offset, size, real_value_p); edouard@483: /* increment cursor according size*/ edouard@483: retain_offset = next_retain_offset; edouard@483: } edouard@483: } edouard@483: edouard@580: extern 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: edouard@483: void Retain(unsigned int offset, unsigned int count, void * p); Edouard@605: Edouard@605: inline void BufferIterator(void* varp, __IEC_types_enum vartype, int do_debug) Edouard@605: { Edouard@605: void *real_value_p = NULL; Edouard@605: void *visible_value_p = NULL; edouard@483: char flags = 0; Edouard@605: Edouard@605: visible_value_p = UnpackVar(varp, vartype, &real_value_p, &flags); Edouard@605: Edouard@605: 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@605: /* copy visible variable to buffer */; Edouard@605: if(do_debug){ Edouard@605: /* compute next cursor positon. Edouard@605: No need to check overflow, as BUFFER_SIZE Edouard@605: is computed large enough */ Edouard@605: char* next_cursor = buffer_cursor + size; Edouard@605: /* copy data to the buffer */ Edouard@605: memcpy(buffer_cursor, visible_value_p, size); Edouard@605: /* increment cursor according size*/ Edouard@605: buffer_cursor = next_cursor; Edouard@605: } Edouard@605: /* re-force real value of outputs (M and Q)*/ Edouard@605: if(flags & (__IEC_FORCE_FLAG | __IEC_OUTPUT_FLAG)){ Edouard@605: memcpy(real_value_p, visible_value_p, size); Edouard@605: } edouard@450: } edouard@483: if(flags & __IEC_RETAIN_FLAG){ Edouard@605: /* compute next cursor positon*/ Edouard@605: unsigned int next_retain_offset = retain_offset + size; Edouard@605: /* if buffer not full */ Edouard@605: Retain(retain_offset, size, real_value_p); Edouard@605: /* increment cursor according size*/ Edouard@605: retain_offset = next_retain_offset; edouard@483: } edouard@483: } edouard@483: } edouard@483: Edouard@605: void DebugIterator(void* varp, __IEC_types_enum vartype){ Edouard@605: BufferIterator(varp, vartype, 1); Edouard@605: } Edouard@605: Edouard@605: void RetainIterator(void* varp, __IEC_types_enum vartype){ Edouard@605: BufferIterator(varp, vartype, 0); 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@580: extern void ValidateRetainBuffer(void); edouard@580: extern void InValidateRetainBuffer(void); edouard@450: greg@423: void __publish_debug(void) etisserant@209: { edouard@483: retain_offset = 0; edouard@580: InValidateRetainBuffer(); 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@605: __for_each_variable_do(DebugIterator); etisserant@239: etisserant@239: /* Leave debug section, etisserant@239: * Trigger asynchronous transmission etisserant@239: * (returns immediately) */ etisserant@239: InitiateDebugTransfer(); /* size */ edouard@581: }else{ edouard@581: /* when not debugging, do only retain */ edouard@581: __for_each_variable_do(RetainIterator); 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: } edouard@580: ValidateRetainBuffer(); 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;\ edouard@582: if(force){\ laurent@511: ((__IEC_##TYPENAME##_p *)varp)->fvalue = *((TYPENAME *)force);\ laurent@511: *(((__IEC_##TYPENAME##_p *)varp)->value) = *((TYPENAME *)force);\ edouard@582: }\ 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)){ laurent@611: __ANY(__RegisterDebugVariable_case_t) laurent@611: __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@582: case TYPENAME##_O_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){ laurent@611: __ANY(__ResetDebugVariablesIterator_case_t) laurent@611: __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: