diff -r 78add3f69e39 -r 9a82918e063c svghmi/svghmi.c --- a/svghmi/svghmi.c Tue Oct 26 11:41:03 2021 +0200 +++ b/svghmi/svghmi.c Fri Oct 29 09:45:39 2021 +0200 @@ -39,6 +39,8 @@ } buf_state_t; static int global_write_dirty = 0; +static long hmitree_rlock = 0; +static long hmitree_wlock = 0; typedef struct { void *ptr; @@ -46,7 +48,6 @@ uint32_t buf_index; /* publish/write/send */ - long wlock; buf_state_t wstate[MAX_CONNECTIONS]; /* zero means not subscribed */ @@ -54,7 +55,6 @@ uint16_t age_ms[MAX_CONNECTIONS]; /* retrieve/read/recv */ - long rlock; buf_state_t rstate; } hmi_tree_item_t; @@ -83,17 +83,13 @@ static int write_iterator(uint32_t index, hmi_tree_item_t *dsc) { - uint32_t session_index = 0; - int value_changed = 0; - if(AtomicCompareExchange(&dsc->wlock, 0, 1) == 0) { - void *dest_p = &wbuf[dsc->buf_index]; + { + uint32_t session_index = 0; + int value_changed = 0; + void *dest_p = NULL; void *real_value_p = NULL; - char flags = 0; - void *visible_value_p = UnpackVar(dsc, &real_value_p, &flags); - USINT sz = __get_type_enum_size(dsc->type); - if(__Is_a_string(dsc)){ - sz = ((STRING*)visible_value_p)->len + 1; - } + void *visible_value_p = NULL; + USINT sz = 0; while(session_index < MAX_CONNECTIONS) { if(dsc->wstate[session_index] == buf_set){ /* if being subscribed */ @@ -107,13 +103,39 @@ } } - if(dsc->wstate[session_index] == buf_new /* just subscribed - or already subscribed having value change */ - || (dsc->refresh_period_ms[session_index] > 0 - && (value_changed || (value_changed=memcmp(dest_p, visible_value_p, sz))) != 0)){ - /* if not already marked/signaled, do it */ + /* variable is sample only if just subscribed + or already subscribed and having value change */ + int do_sample = 0; + int just_subscribed = dsc->wstate[session_index] == buf_new; + if(!just_subscribed){ + int already_subscribed = dsc->refresh_period_ms[session_index] > 0; + if(already_subscribed){ + if(!value_changed){ + if(!visible_value_p){ + char flags = 0; + visible_value_p = UnpackVar(dsc, &real_value_p, &flags); + if(__Is_a_string(dsc)){ + sz = ((STRING*)visible_value_p)->len + 1; + } else { + sz = __get_type_enum_size(dsc->type); + } + dest_p = &wbuf[dsc->buf_index]; + } + value_changed = memcmp(dest_p, visible_value_p, sz) != 0; + do_sample = value_changed; + }else{ + do_sample = 1; + } + } + } else { + do_sample = 1; + } + + + if(do_sample){ if(dsc->wstate[session_index] != buf_set && dsc->wstate[session_index] != buf_tosend) { - if(dsc->wstate[session_index] == buf_new || ticktime_ms > dsc->refresh_period_ms[session_index]){ + if(dsc->wstate[session_index] == buf_new \ + || ticktime_ms > dsc->refresh_period_ms[session_index]){ dsc->wstate[session_index] = buf_tosend; global_write_dirty = 1; } else { @@ -128,7 +150,6 @@ /* copy value if changed (and subscribed) */ if(value_changed) memcpy(dest_p, visible_value_p, sz); - AtomicCompareExchange(&dsc->wlock, 1, 0); } // else ... : PLC can't wait, variable will be updated next turn return 0; @@ -137,9 +158,6 @@ static uint32_t send_session_index; static int send_iterator(uint32_t index, hmi_tree_item_t *dsc) { - while(AtomicCompareExchange(&dsc->wlock, 0, 1)) - nRT_reschedule(); - if(dsc->wstate[send_session_index] == buf_tosend) { uint32_t sz = __get_type_enum_size(dsc->type); @@ -159,39 +177,29 @@ else { printf("BUG!!! %%d + %%ld + %%d > %%ld \n", sbufidx, sizeof(uint32_t), sz, sizeof(sbuf)); - AtomicCompareExchange(&dsc->wlock, 1, 0); return EOVERFLOW; } } - AtomicCompareExchange(&dsc->wlock, 1, 0); return 0; } static int read_iterator(uint32_t index, hmi_tree_item_t *dsc) { - if(AtomicCompareExchange(&dsc->rlock, 0, 1) == 0) - { - if(dsc->rstate == buf_set) - { - void *src_p = &rbuf[dsc->buf_index]; - void *real_value_p = NULL; - char flags = 0; - void *visible_value_p = UnpackVar(dsc, &real_value_p, &flags); - memcpy(real_value_p, src_p, __get_type_enum_size(dsc->type)); - dsc->rstate = buf_free; - } - AtomicCompareExchange(&dsc->rlock, 1, 0); - } - // else ... : PLC can't wait, variable will be updated next turn + if(dsc->rstate == buf_set) + { + void *src_p = &rbuf[dsc->buf_index]; + void *real_value_p = NULL; + char flags = 0; + void *visible_value_p = UnpackVar(dsc, &real_value_p, &flags); + memcpy(real_value_p, src_p, __get_type_enum_size(dsc->type)); + dsc->rstate = buf_free; + } return 0; } void update_refresh_period(hmi_tree_item_t *dsc, uint32_t session_index, uint16_t refresh_period_ms) { - while(AtomicCompareExchange(&dsc->wlock, 0, 1)) - nRT_reschedule(); - if(refresh_period_ms) { if(!dsc->refresh_period_ms[session_index]) { @@ -201,7 +209,6 @@ dsc->wstate[session_index] = buf_free; } dsc->refresh_period_ms[session_index] = refresh_period_ms; - AtomicCompareExchange(&dsc->wlock, 1, 0); } static uint32_t reset_session_index; @@ -250,13 +257,19 @@ void __retrieve_svghmi() { - traverse_hmi_tree(read_iterator); + if(AtomicCompareExchange(&hmitree_rlock, 0, 1) == 0) { + traverse_hmi_tree(read_iterator); + AtomicCompareExchange(&hmitree_rlock, 1, 0); + } } void __publish_svghmi() { global_write_dirty = 0; - traverse_hmi_tree(write_iterator); + if(AtomicCompareExchange(&hmitree_wlock, 0, 1) == 0) { + traverse_hmi_tree(write_iterator); + AtomicCompareExchange(&hmitree_wlock, 1, 0); + } if(global_write_dirty) { SVGHMI_WakeupFromRTThread(); } @@ -274,17 +287,25 @@ int res; sbufidx = HMI_HASH_SIZE; send_session_index = session_index; + + while(AtomicCompareExchange(&hmitree_wlock, 0, 1)){ + nRT_reschedule(); + } + if((res = traverse_hmi_tree(send_iterator)) == 0) { if(sbufidx > HMI_HASH_SIZE){ memcpy(&sbuf[0], &hmi_hash[0], HMI_HASH_SIZE); *ptr = &sbuf[0]; *size = sbufidx; + AtomicCompareExchange(&hmitree_wlock, 1, 0); return 0; } + AtomicCompareExchange(&hmitree_wlock, 1, 0); return ENODATA; } // printf("collected BAD result %%d\n", res); + AtomicCompareExchange(&hmitree_wlock, 1, 0); return res; } else @@ -294,6 +315,7 @@ } typedef enum { + unset = -1, setval = 0, reset = 1, subscribe = 2 @@ -320,10 +342,29 @@ return -EINVAL; } + int ret; + int got_wlock = 0; + int got_rlock = 0; + cmd_from_JS cmd_old = unset; + cmd_from_JS cmd = unset; + while(cursor < end) { uint32_t progress; - cmd_from_JS cmd = *(cursor++); + + cmd_old = cmd; + cmd = *(cursor++); + + if(cmd_old != cmd){ + if(got_wlock){ + AtomicCompareExchange(&hmitree_wlock, 1, 0); + got_wlock = 0; + } + if(got_rlock){ + AtomicCompareExchange(&hmitree_rlock, 1, 0); + got_rlock = 0; + } + } switch(cmd) { case setval: @@ -350,23 +391,28 @@ if((valptr + sz) <= end) { // rescheduling spinlock until free - while(AtomicCompareExchange(&dsc->rlock, 0, 1)) - nRT_reschedule(); + if(!got_rlock){ + while(AtomicCompareExchange(&hmitree_rlock, 0, 1)){ + nRT_reschedule(); + } + got_rlock=1; + } memcpy(dst_p, valptr, sz); dsc->rstate = buf_set; - AtomicCompareExchange(&dsc->rlock, 1, 0); progress = sz + sizeof(uint32_t) /* index */; } else { - return -EINVAL; + ret = -EINVAL; + goto exit_free; } } else { - return -EINVAL; + ret = -EINVAL; + goto exit_free; } } break; @@ -375,6 +421,12 @@ { progress = 0; reset_session_index = session_index; + if(!got_wlock){ + while(AtomicCompareExchange(&hmitree_wlock, 0, 1)){ + nRT_reschedule(); + } + got_wlock = 1; + } traverse_hmi_tree(reset_iterator); } break; @@ -386,12 +438,19 @@ if(index < HMI_ITEM_COUNT) { + if(!got_wlock){ + while(AtomicCompareExchange(&hmitree_wlock, 0, 1)){ + nRT_reschedule(); + } + got_wlock = 1; + } hmi_tree_item_t *dsc = &hmi_tree_item[index]; update_refresh_period(dsc, session_index, refresh_period_ms); } else { - return -EINVAL; + ret = -EINVAL; + goto exit_free; } progress = sizeof(uint32_t) /* index */ + @@ -404,6 +463,17 @@ } cursor += progress; } - return was_hearbeat; -} - + ret = was_hearbeat; + +exit_free: + if(got_wlock){ + AtomicCompareExchange(&hmitree_wlock, 1, 0); + got_wlock = 0; + } + if(got_rlock){ + AtomicCompareExchange(&hmitree_rlock, 1, 0); + got_rlock = 0; + } + return ret; +} +