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: Edouard@3395: typedef unsigned int dbgvardsc_index_t; Edouard@3395: typedef unsigned short trace_buf_offset_t; Edouard@3395: Edouard@3395: #define BUFFER_EMPTY 0 Edouard@3395: #define BUFFER_FULL 1 Edouard@3395: andrej@2501: #ifndef TARGET_ONLINE_DEBUG_DISABLE Edouard@3395: Edouard@3394: #define TRACE_BUFFER_SIZE 4096 Edouard@3394: #define TRACE_LIST_SIZE 1024 etisserant@209: etisserant@209: /* Atomically accessed variable for buffer state */ Edouard@3395: static long trace_buffer_state = BUFFER_EMPTY; Edouard@3394: Edouard@3394: typedef struct trace_item_s { Edouard@3394: dbgvardsc_index_t dbgvardsc_index; Edouard@3394: } trace_item_t; Edouard@3394: Edouard@3394: trace_item_t trace_list[TRACE_LIST_SIZE]; Edouard@3394: char trace_buffer[TRACE_BUFFER_SIZE]; etisserant@209: Edouard@3395: /* Trace's cursor*/ Edouard@3394: static trace_item_t *trace_list_collect_cursor = trace_list; Edouard@3394: static trace_item_t *trace_list_addvar_cursor = trace_list; Edouard@3394: static const trace_item_t *trace_list_end = Edouard@3394: &trace_list[TRACE_LIST_SIZE-1]; Edouard@3394: static char *trace_buffer_cursor = trace_buffer; Edouard@3394: static const char *trace_buffer_end = trace_buffer + TRACE_BUFFER_SIZE; Edouard@3395: Edouard@3395: Edouard@3395: Edouard@3395: #define FORCE_BUFFER_SIZE 1024 Edouard@3395: #define FORCE_LIST_SIZE 256 Edouard@3395: Edouard@3395: typedef struct force_item_s { Edouard@3395: dbgvardsc_index_t dbgvardsc_index; Edouard@3395: void *value_pointer_backup; Edouard@3395: } force_item_t; Edouard@3395: Edouard@3395: force_item_t force_list[FORCE_LIST_SIZE]; Edouard@3395: char force_buffer[FORCE_BUFFER_SIZE]; Edouard@3395: Edouard@3395: /* Force's cursor*/ Edouard@3395: static force_item_t *force_list_apply_cursor = force_list; Edouard@3395: static force_item_t *force_list_addvar_cursor = force_list; Edouard@3395: static const force_item_t *force_list_end = Edouard@3395: &force_list[FORCE_LIST_SIZE-1]; Edouard@3395: static char *force_buffer_cursor = force_buffer; Edouard@3395: static const char *force_buffer_end = force_buffer + FORCE_BUFFER_SIZE; Edouard@3395: Edouard@3395: andrej@2501: #endif andrej@2501: 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@3396: static const dbgvardsc_t dbgvardsc[] = { Edouard@1432: %(variable_decl_array)s Edouard@1432: }; Edouard@1432: Edouard@3396: static const dbgvardsc_index_t retain_list[] = { Edouard@3396: %(retain_vardsc_index_array)s Edouard@3396: }; Edouard@3396: static unsigned int retain_list_collect_cursor = 0; Edouard@3396: static const unsigned int retain_list_size = sizeof(retain_list)/sizeof(dbgvardsc_index_t); Edouard@3396: 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@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@3394: trace_buffer_cursor = trace_buffer; Edouard@3394: trace_list_addvar_cursor = trace_list; Edouard@3394: trace_list_collect_cursor = trace_list; Edouard@3395: trace_buffer_state = BUFFER_EMPTY; Edouard@3395: Edouard@3395: force_buffer_cursor = force_buffer; Edouard@3395: force_list_addvar_cursor = force_list; Edouard@3395: force_list_apply_cursor = force_list; andrej@2501: #endif andrej@2501: Edouard@1457: InitRetain(); edouard@483: /* Iterate over all variables to fill debug buffer */ Edouard@1459: if(CheckRetainBuffer()){ Edouard@3396: static unsigned int retain_offset = 0; Edouard@3396: retain_list_collect_cursor = 0; Edouard@3396: Edouard@3396: /* iterate over retain list */ Edouard@3396: while(retain_list_collect_cursor < retain_list_size){ Edouard@3396: void *value_p = NULL; Edouard@3396: size_t size; Edouard@3396: char* next_cursor; Edouard@3396: Edouard@3396: dbgvardsc_t *dsc = &dbgvardsc[ Edouard@3396: retain_list[retain_list_collect_cursor]]; Edouard@3396: Edouard@3396: UnpackVar(dsc, &value_p, NULL, &size); Edouard@3396: Edouard@3396: printf("Reminding %%d %%ld \n", retain_list_collect_cursor, size); Edouard@3396: Edouard@3396: /* if buffer not full */ Edouard@3396: Remind(retain_offset, size, value_p); Edouard@3396: /* increment cursor according size*/ Edouard@3396: retain_offset += size; Edouard@3396: Edouard@3396: retain_list_collect_cursor++; Edouard@3396: } Edouard@1459: }else{ edouard@2710: char mstr[] = "RETAIN memory invalid - defaults used"; Edouard@1459: LogMessage(LOG_WARNING, mstr, sizeof(mstr)); Edouard@1459: } 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@3394: trace_buffer_cursor = trace_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: void Retain(unsigned int offset, unsigned int count, void * p); Edouard@605: andrej@2172: /* Return size of all retain variables */ andrej@2172: unsigned int GetRetainSize(void) andrej@2172: { Edouard@3396: unsigned int retain_size = 0; Edouard@3396: retain_list_collect_cursor = 0; Edouard@3396: Edouard@3396: /* iterate over retain list */ Edouard@3396: while(retain_list_collect_cursor < retain_list_size){ Edouard@3396: void *value_p = NULL; Edouard@3396: size_t size; Edouard@3396: char* next_cursor; Edouard@3396: Edouard@3396: dbgvardsc_t *dsc = &dbgvardsc[ Edouard@3396: retain_list[retain_list_collect_cursor]]; Edouard@3396: Edouard@3396: UnpackVar(dsc, &value_p, NULL, &size); Edouard@3396: Edouard@3396: retain_size += size; Edouard@3396: retain_list_collect_cursor++; Edouard@3396: } Edouard@3396: Edouard@3396: printf("Retain size %%d \n", retain_size); Edouard@3396: 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: Edouard@3395: #define __ReForceOutput_case_p(TYPENAME) \ Edouard@3395: case TYPENAME##_P_ENUM : \ Edouard@3395: case TYPENAME##_O_ENUM : \ Edouard@3395: { \ Edouard@3395: char *next_cursor = force_buffer_cursor + sizeof(TYPENAME); \ Edouard@3395: if(next_cursor <= force_buffer_end ){ \ Edouard@3395: /* outputs real value must be systematically forced */ \ Edouard@3395: if(vartype == TYPENAME##_O_ENUM) \ Edouard@3395: /* overwrite value pointed by backup */ \ Edouard@3395: *((TYPENAME *)force_list_apply_cursor->value_pointer_backup) = \ Edouard@3395: *((TYPENAME *)force_buffer_cursor); \ Edouard@3395: /* inc force_buffer cursor */ \ Edouard@3395: force_buffer_cursor = next_cursor; \ Edouard@3395: }else{ \ Edouard@3395: stop = 1; \ Edouard@3395: } \ Edouard@3395: } \ Edouard@3395: break; greg@423: void __publish_debug(void) etisserant@209: { 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( Edouard@3394: &trace_buffer_state, Edouard@3395: BUFFER_EMPTY, Edouard@3395: BUFFER_FULL); etisserant@239: etisserant@239: /* If buffer was free */ Edouard@3395: if(latest_state == BUFFER_EMPTY) etisserant@209: { Edouard@3395: int stop = 0; Edouard@3395: /* Reset force list cursor */ Edouard@3395: force_list_apply_cursor = force_list; Edouard@3395: Edouard@3395: /* iterate over force list */ Edouard@3395: while(!stop && force_list_apply_cursor < force_list_addvar_cursor){ Edouard@3395: dbgvardsc_t *dsc = &dbgvardsc[ Edouard@3395: force_list_apply_cursor->dbgvardsc_index]; Edouard@3395: void *varp = dsc->ptr; Edouard@3395: __IEC_types_enum vartype = dsc->type; Edouard@3395: switch(vartype){ Edouard@3395: __ANY(__ReForceOutput_case_p) Edouard@3395: default: Edouard@3395: break; Edouard@3395: } Edouard@3395: force_list_apply_cursor++; \ Edouard@3395: } Edouard@3395: etisserant@239: /* Reset buffer cursor */ Edouard@3394: trace_buffer_cursor = trace_buffer; Edouard@3394: /* Reset trace list cursor */ Edouard@3394: trace_list_collect_cursor = trace_list; Edouard@3395: Edouard@3395: /* iterate over trace list */ Edouard@3394: while(trace_list_collect_cursor < trace_list_addvar_cursor){ Edouard@3395: void *value_p = NULL; Edouard@3395: size_t size; Edouard@3394: char* next_cursor; Edouard@3394: Edouard@3394: dbgvardsc_t *dsc = &dbgvardsc[ Edouard@3394: trace_list_collect_cursor->dbgvardsc_index]; Edouard@3394: Edouard@3395: UnpackVar(dsc, &value_p, NULL, &size); Edouard@3394: Edouard@3394: /* copy visible variable to buffer */; Edouard@3394: if(__Is_a_string(dsc)){ Edouard@3394: /* optimization for strings */ Edouard@3394: /* assume NULL terminated strings */ Edouard@3395: size = ((STRING*)value_p)->len + 1; Edouard@3394: } Edouard@3394: Edouard@3394: /* compute next cursor positon.*/ Edouard@3394: next_cursor = trace_buffer_cursor + size; Edouard@3394: /* check for buffer overflow */ Edouard@3394: if(next_cursor < trace_buffer_end) Edouard@3394: /* copy data to the buffer */ Edouard@3395: memcpy(trace_buffer_cursor, value_p, size); Edouard@3394: else Edouard@3394: /* stop looping in case of overflow */ Edouard@3394: break; Edouard@3394: /* increment cursor according size*/ Edouard@3394: trace_buffer_cursor = next_cursor; Edouard@3394: trace_list_collect_cursor++; Edouard@3394: } 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@3394: } Edouard@3394: #endif Edouard@3396: static unsigned int retain_offset = 0; Edouard@3394: /* when not debugging, do only retain */ Edouard@3396: retain_list_collect_cursor = 0; Edouard@3396: Edouard@3396: /* iterate over retain list */ Edouard@3396: while(retain_list_collect_cursor < retain_list_size){ Edouard@3396: void *value_p = NULL; Edouard@3396: size_t size; Edouard@3396: char* next_cursor; Edouard@3396: Edouard@3396: dbgvardsc_t *dsc = &dbgvardsc[ Edouard@3396: retain_list[retain_list_collect_cursor]]; Edouard@3396: Edouard@3396: UnpackVar(dsc, &value_p, NULL, &size); Edouard@3396: Edouard@3396: printf("Retaining %%d %%ld \n", retain_list_collect_cursor, size); Edouard@3396: Edouard@3396: /* if buffer not full */ Edouard@3396: Retain(retain_offset, size, value_p); Edouard@3396: /* increment cursor according size*/ Edouard@3396: retain_offset += size; Edouard@3396: Edouard@3396: retain_list_collect_cursor++; Edouard@3396: } edouard@580: ValidateRetainBuffer(); etisserant@209: } etisserant@209: andrej@2501: #ifndef TARGET_ONLINE_DEBUG_DISABLE Edouard@3395: Edouard@3395: #define TRACE_LIST_OVERFLOW 1 Edouard@3395: #define FORCE_LIST_OVERFLOW 2 Edouard@3395: #define FORCE_BUFFER_OVERFLOW 3 Edouard@3395: Edouard@3395: #define __ForceVariable_case_t(TYPENAME) \ Edouard@3395: case TYPENAME##_ENUM : \ Edouard@3395: /* add to force_list*/ \ Edouard@3395: force_list_addvar_cursor->dbgvardsc_index = idx; \ Edouard@3395: ((__IEC_##TYPENAME##_t *)varp)->flags |= __IEC_FORCE_FLAG; \ Edouard@3395: ((__IEC_##TYPENAME##_t *)varp)->value = *((TYPENAME *)force); \ Edouard@3395: break; Edouard@3395: #define __ForceVariable_case_p(TYPENAME) \ Edouard@3395: case TYPENAME##_P_ENUM : \ Edouard@3395: case TYPENAME##_O_ENUM : \ Edouard@3395: { \ Edouard@3395: char *next_cursor = force_buffer_cursor + sizeof(TYPENAME); \ Edouard@3395: if(next_cursor <= force_buffer_end ){ \ Edouard@3395: /* add to force_list*/ \ Edouard@3395: force_list_addvar_cursor->dbgvardsc_index = idx; \ Edouard@3395: /* save pointer to backup */ \ Edouard@3395: force_list_addvar_cursor->value_pointer_backup = \ Edouard@3395: ((__IEC_##TYPENAME##_p *)varp)->value; \ Edouard@3395: /* store forced value in force_buffer */ \ Edouard@3395: *((TYPENAME *)force_buffer_cursor) = *((TYPENAME *)force); \ Edouard@3395: /* replace pointer with pointer to force_buffer */ \ Edouard@3395: ((__IEC_##TYPENAME##_p *)varp)->value = \ Edouard@3395: (TYPENAME *)force_buffer_cursor; \ Edouard@3395: /* mark variable as forced */ \ Edouard@3395: ((__IEC_##TYPENAME##_p *)varp)->flags |= __IEC_FORCE_FLAG; \ Edouard@3395: /* inc force_buffer cursor */ \ Edouard@3395: force_buffer_cursor = next_cursor; \ Edouard@3395: /* outputs real value must be systematically forced */ \ Edouard@3395: if(vartype == TYPENAME##_O_ENUM) \ Edouard@3395: *(((__IEC_##TYPENAME##_p *)varp)->value) = *((TYPENAME *)force);\ Edouard@3395: } else { \ Edouard@3395: error_code = FORCE_BUFFER_OVERFLOW; \ Edouard@3395: goto error_cleanup; \ Edouard@3395: } \ Edouard@3395: } \ Edouard@3395: break; Edouard@3395: Edouard@3395: Edouard@3395: void ResetDebugVariables(void); Edouard@3395: Edouard@3395: int RegisterDebugVariable(dbgvardsc_index_t idx, void* force) Edouard@3395: { Edouard@3395: int error_code = 0; Edouard@3394: if(idx < sizeof(dbgvardsc)/sizeof(dbgvardsc_t)){ Edouard@3395: /* add to trace_list, inc trace_list_addvar_cursor*/ Edouard@3394: if(trace_list_addvar_cursor <= trace_list_end){ Edouard@3394: trace_list_addvar_cursor->dbgvardsc_index = idx; Edouard@3394: trace_list_addvar_cursor++; Edouard@3395: } else { Edouard@3395: error_code = TRACE_LIST_OVERFLOW; Edouard@3395: goto error_cleanup; Edouard@3394: } Edouard@3394: if(force){ Edouard@3395: if(force_list_addvar_cursor <= force_list_end){ Edouard@3395: dbgvardsc_t *dsc = &dbgvardsc[idx]; Edouard@3395: void *varp = dsc->ptr; Edouard@3395: __IEC_types_enum vartype = dsc->type; Edouard@3395: Edouard@3395: switch(vartype){ Edouard@3395: __ANY(__ForceVariable_case_t) Edouard@3395: __ANY(__ForceVariable_case_p) Edouard@3395: default: Edouard@3395: break; Edouard@3395: } Edouard@3395: /* inc force_list cursor */ Edouard@3395: force_list_addvar_cursor++; Edouard@3395: } else { Edouard@3395: error_code = FORCE_LIST_OVERFLOW; Edouard@3395: goto error_cleanup; Edouard@3394: } Edouard@1432: } edouard@450: } Edouard@3395: return 0; Edouard@3395: Edouard@3395: error_cleanup: Edouard@3395: ResetDebugVariables(); Edouard@3395: trace_buffer_state = BUFFER_EMPTY; Edouard@3395: return error_code; Edouard@3395: Edouard@3395: } Edouard@3395: Edouard@3395: #define ResetForcedVariable_case_t(TYPENAME) \ Edouard@3395: case TYPENAME##_ENUM : \ Edouard@3395: ((__IEC_##TYPENAME##_t *)varp)->flags &= ~__IEC_FORCE_FLAG; \ Edouard@3395: /* for local variable we don't restore original value */ \ Edouard@3395: /* that can be added if needed, but it was like that since ever */ \ Edouard@3395: break; Edouard@3395: Edouard@3395: #define ResetForcedVariable_case_p(TYPENAME) \ Edouard@3395: case TYPENAME##_P_ENUM : \ Edouard@3395: case TYPENAME##_O_ENUM : \ Edouard@3395: ((__IEC_##TYPENAME##_p *)varp)->flags &= ~__IEC_FORCE_FLAG; \ Edouard@3395: /* restore backup to pointer */ \ Edouard@3395: ((__IEC_##TYPENAME##_p *)varp)->value = \ Edouard@3395: force_list_apply_cursor->value_pointer_backup; \ Edouard@3395: break; etisserant@209: etisserant@209: void ResetDebugVariables(void) etisserant@209: { Edouard@3395: /* Reset trace list */ Edouard@3394: trace_list_addvar_cursor = trace_list; Edouard@3395: Edouard@3395: force_list_apply_cursor = force_list; Edouard@3395: /* Restore forced variables */ Edouard@3395: while(force_list_apply_cursor < force_list_addvar_cursor){ Edouard@3395: dbgvardsc_t *dsc = &dbgvardsc[ Edouard@3395: force_list_apply_cursor->dbgvardsc_index]; Edouard@3395: void *varp = dsc->ptr; Edouard@3395: switch(dsc->type){ Edouard@3395: __ANY(ResetForcedVariable_case_t) Edouard@3395: __ANY(ResetForcedVariable_case_p) Edouard@3395: default: Edouard@3395: break; Edouard@3395: } Edouard@3395: /* inc force_list cursor */ Edouard@3395: force_list_apply_cursor++; Edouard@3395: } /* else TODO: warn user about failure to force */ Edouard@3395: Edouard@3395: /* Reset force list */ Edouard@3395: force_list_addvar_cursor = force_list; Edouard@3395: /* Reset force buffer */ Edouard@3395: force_buffer_cursor = force_buffer; etisserant@209: } etisserant@209: greg@423: void FreeDebugData(void) etisserant@209: { etisserant@209: /* atomically mark buffer as free */ Edouard@1403: AtomicCompareExchange( Edouard@3394: &trace_buffer_state, Edouard@3395: BUFFER_FULL, Edouard@3395: BUFFER_EMPTY); 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@3394: *size = trace_buffer_cursor - trace_buffer; Edouard@3394: *buffer = trace_buffer; edouard@502: } edouard@504: return wait_error; edouard@504: } andrej@2501: #endif andrej@2501: #endif andrej@2501: