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: * */ andrej@2501: #ifdef TARGET_DEBUG_AND_RETAIN_DISABLE andrej@1800: andrej@1800: void __init_debug (void){} andrej@1800: void __cleanup_debug (void){} andrej@1800: void __retrieve_debug(void){} andrej@1800: void __publish_debug (void){} andrej@1800: andrej@1800: #else andrej@1800: etisserant@209: #include "iec_types_all.h" etisserant@209: #include "POUS.h" etisserant@209: /*for memcpy*/ etisserant@209: #include greg@335: #include etisserant@209: andrej@2501: #ifndef TARGET_ONLINE_DEBUG_DISABLE 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; andrej@2501: #endif andrej@2501: 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@1432: typedef const struct { Edouard@1432: void *ptr; Edouard@1432: __IEC_types_enum type; Edouard@1432: } dbgvardsc_t; Edouard@1432: Edouard@1432: static dbgvardsc_t dbgvardsc[] = { Edouard@1432: %(variable_decl_array)s Edouard@1432: }; Edouard@1432: Edouard@1432: typedef void(*__for_each_variable_do_fp)(dbgvardsc_t*); edouard@452: void __for_each_variable_do(__for_each_variable_do_fp fp) edouard@450: { andrej@2190: unsigned int i; Edouard@1432: for(i = 0; i < sizeof(dbgvardsc)/sizeof(dbgvardsc_t); i++){ Edouard@1432: dbgvardsc_t *dsc = &dbgvardsc[i]; Edouard@1432: if(dsc->type != UNKNOWN_ENUM) Edouard@1432: (*fp)(dsc); edouard@452: } edouard@450: } etisserant@209: Edouard@2632: #define __Unpack_desc_type dbgvardsc_t Edouard@2632: Edouard@2632: %(var_access_code)s edouard@483: edouard@483: void Remind(unsigned int offset, unsigned int count, void * p); edouard@483: Edouard@1432: void RemindIterator(dbgvardsc_t *dsc) edouard@483: { Edouard@605: void *real_value_p = NULL; edouard@483: char flags = 0; Edouard@1432: UnpackVar(dsc, &real_value_p, &flags); edouard@483: laurent@507: if(flags & __IEC_RETAIN_FLAG){ Edouard@1432: USINT size = __get_type_enum_size(dsc->type); 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@1457: extern void InitRetain(void); edouard@521: edouard@483: void __init_debug(void) edouard@483: { edouard@483: /* init local static vars */ edouard@2710: #ifndef TARGET_ONLINE_DEBUG_DISABLE edouard@483: buffer_cursor = debug_buffer; andrej@2501: buffer_state = BUFFER_FREE; andrej@2501: #endif andrej@2501: edouard@483: retain_offset = 0; Edouard@1457: InitRetain(); edouard@483: /* Iterate over all variables to fill debug buffer */ Edouard@1459: if(CheckRetainBuffer()){ edouard@2710: __for_each_variable_do(RemindIterator); Edouard@1459: }else{ edouard@2710: char mstr[] = "RETAIN memory invalid - defaults used"; Edouard@1459: LogMessage(LOG_WARNING, mstr, sizeof(mstr)); Edouard@1459: } edouard@483: retain_offset = 0; edouard@483: } edouard@483: edouard@483: extern void InitiateDebugTransfer(void); Edouard@1457: extern void CleanupRetain(void); edouard@483: edouard@483: extern unsigned long __tick; edouard@483: edouard@483: void __cleanup_debug(void) edouard@483: { edouard@2710: #ifndef TARGET_ONLINE_DEBUG_DISABLE edouard@483: buffer_cursor = debug_buffer; edouard@483: InitiateDebugTransfer(); andrej@2501: #endif andrej@2501: Edouard@1457: CleanupRetain(); 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: andrej@1479: static inline void BufferIterator(dbgvardsc_t *dsc, 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@1432: visible_value_p = UnpackVar(dsc, &real_value_p, &flags); Edouard@605: Edouard@605: if(flags & ( __IEC_DEBUG_FLAG | __IEC_RETAIN_FLAG)){ Edouard@1432: USINT size = __get_type_enum_size(dsc->type); andrej@2501: edouard@2710: #ifndef TARGET_ONLINE_DEBUG_DISABLE 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@2710: if(__Is_a_string(dsc)){ Edouard@1074: /* optimization for strings */ Edouard@1074: size = ((STRING*)visible_value_p)->len + 1; Edouard@1074: } 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)*/ laurent@649: if((flags & __IEC_FORCE_FLAG) && (flags & __IEC_OUTPUT_FLAG)){ Edouard@605: memcpy(real_value_p, visible_value_p, size); Edouard@605: } edouard@450: } edouard@2710: #endif andrej@2501: 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@1432: void DebugIterator(dbgvardsc_t *dsc){ Edouard@1432: BufferIterator(dsc, 1); Edouard@1432: } Edouard@1432: Edouard@1432: void RetainIterator(dbgvardsc_t *dsc){ Edouard@1432: BufferIterator(dsc, 0); edouard@483: } edouard@483: andrej@2172: andrej@2172: unsigned int retain_size = 0; andrej@2172: andrej@2172: /* GetRetainSizeIterator */ andrej@2172: void GetRetainSizeIterator(dbgvardsc_t *dsc) andrej@2172: { andrej@2172: void *real_value_p = NULL; andrej@2172: char flags = 0; andrej@2172: UnpackVar(dsc, &real_value_p, &flags); andrej@2172: andrej@2172: if(flags & __IEC_RETAIN_FLAG){ andrej@2172: USINT size = __get_type_enum_size(dsc->type); andrej@2172: /* Calc retain buffer size */ andrej@2172: retain_size += size; andrej@2172: } andrej@2172: } andrej@2172: andrej@2172: /* Return size of all retain variables */ andrej@2172: unsigned int GetRetainSize(void) andrej@2172: { andrej@2172: __for_each_variable_do(GetRetainSizeIterator); andrej@2172: return retain_size; andrej@2172: } andrej@2172: andrej@2172: Laurent@969: extern void PLC_GetTime(IEC_TIME*); edouard@483: extern int TryEnterDebugSection(void); edouard@483: extern long AtomicCompareExchange(long*, long, long); Edouard@954: extern long long AtomicCompareExchange64(long long* , long 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(); andrej@2501: andrej@2501: #ifndef TARGET_ONLINE_DEBUG_DISABLE 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(); andrej@2501: }else andrej@2501: #endif andrej@2501: { edouard@483: /* when not debugging, do only retain */ edouard@483: __for_each_variable_do(RetainIterator); etisserant@209: } edouard@580: ValidateRetainBuffer(); etisserant@209: } etisserant@209: andrej@2501: #ifndef TARGET_ONLINE_DEBUG_DISABLE 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; andrej@2190: void RegisterDebugVariable(unsigned int idx, void* force) etisserant@209: { Edouard@1432: if(idx < sizeof(dbgvardsc)/sizeof(dbgvardsc_t)){ Edouard@1432: unsigned char flags = force ? Edouard@1432: __IEC_DEBUG_FLAG | __IEC_FORCE_FLAG : Edouard@1432: __IEC_DEBUG_FLAG; Edouard@1432: dbgvardsc_t *dsc = &dbgvardsc[idx]; Edouard@1432: void *varp = dsc->ptr; Edouard@1432: switch(dsc->type){ Edouard@1432: __ANY(__RegisterDebugVariable_case_t) Edouard@1432: __ANY(__RegisterDebugVariable_case_p) Edouard@1432: default: Edouard@1432: break; Edouard@1432: } 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@1432: void ResetDebugVariablesIterator(dbgvardsc_t *dsc) edouard@450: { edouard@450: /* force debug flag to 0*/ Edouard@1432: void *varp = dsc->ptr; Edouard@1432: switch(dsc->type){ 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 */ Edouard@1403: 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: } andrej@2501: #endif andrej@2501: #endif andrej@2501: