Edouard@2765: #include <pthread.h>
Edouard@2776: #include <errno.h>
Edouard@2764: #include "iec_types_all.h"
Edouard@2764: #include "POUS.h"
Edouard@2764: #include "config.h"
Edouard@2764: #include "beremiz.h"
Edouard@2750: 
Edouard@2768: #define DEFAULT_REFRESH_PERIOD_MS 100
Edouard@2765: #define HMI_BUFFER_SIZE %(buffer_size)d
Edouard@2776: #define HMI_ITEM_COUNT %(item_count)d
Edouard@2788: #define HMI_HASH_SIZE 8
Edouard@3270: #define MAX_CONNECTIONS %(max_connections)d
Edouard@3399: #define MAX_CON_INDEX MAX_CONNECTIONS - 1
Edouard@3270: 
Edouard@2788: static uint8_t hmi_hash[HMI_HASH_SIZE] = {%(hmi_hash_ints)s};
Edouard@2765: 
Edouard@2765: /* PLC reads from that buffer */
Edouard@2765: static char rbuf[HMI_BUFFER_SIZE];
Edouard@2765: 
Edouard@2765: /* PLC writes to that buffer */
Edouard@2765: static char wbuf[HMI_BUFFER_SIZE];
Edouard@2765: 
Edouard@2788: /* worst biggest send buffer. FIXME : use dynamic alloc ? */
Edouard@2788: static char sbuf[HMI_HASH_SIZE +  HMI_BUFFER_SIZE + (HMI_ITEM_COUNT * sizeof(uint32_t))];
Edouard@2788: static unsigned int sbufidx;
Edouard@2788: 
Edouard@2768: %(extern_variables_declarations)s
Edouard@2765: 
Edouard@2771: #define ticktime_ns %(PLC_ticktime)d
Edouard@2788: static uint16_t ticktime_ms = (ticktime_ns>1000000)?
Edouard@2768:                      ticktime_ns/1000000:
Edouard@2768:                      1;
Edouard@2768: 
Edouard@2768: typedef enum {
Edouard@2768:     buf_free = 0,
Edouard@2805:     buf_new,
Edouard@2768:     buf_set,
Edouard@2768:     buf_tosend
Edouard@2768: } buf_state_t;
Edouard@2768: 
Edouard@2788: static int global_write_dirty = 0;
Edouard@3374: static long hmitree_rlock = 0;
Edouard@3374: static long hmitree_wlock = 0;
Edouard@2764: 
Edouard@3399: typedef struct hmi_tree_item_s hmi_tree_item_t;
Edouard@3399: struct hmi_tree_item_s{
Edouard@2764:     void *ptr;
Edouard@2764:     __IEC_types_enum type;
Edouard@2765:     uint32_t buf_index;
Edouard@2768: 
Edouard@3399:     /* retrieve/read/recv */
Edouard@3399:     buf_state_t rstate;
Edouard@3399: 
Edouard@2768:     /* publish/write/send */
Edouard@3270:     buf_state_t wstate[MAX_CONNECTIONS];
Edouard@2788: 
Edouard@2768:     /* zero means not subscribed */
Edouard@3270:     uint16_t refresh_period_ms[MAX_CONNECTIONS];
Edouard@3270:     uint16_t age_ms[MAX_CONNECTIONS];
Edouard@2768: 
Edouard@3399:     /* dual linked list for subscriptions */
Edouard@3399:     hmi_tree_item_t *subscriptions_next;
Edouard@3399:     hmi_tree_item_t *subscriptions_prev;
Edouard@3399: 
Edouard@3399:     /* single linked list for changes from HMI */
Edouard@3399:     hmi_tree_item_t *incoming_prev;
Edouard@3399: 
Edouard@3399: };
Edouard@3399: 
Edouard@3399: #define HMITREE_ITEM_INITIALIZER(cpath,type,buf_index) {        \
Edouard@3399:     &(cpath),                             /*ptr*/               \
Edouard@3399:     type,                                 /*type*/              \
Edouard@3399:     buf_index,                            /*buf_index*/         \
Edouard@3399:     buf_free,                             /*rstate*/            \
Edouard@3399:     {[0 ... MAX_CON_INDEX] = buf_free},   /*wstate*/            \
Edouard@3399:     {[0 ... MAX_CON_INDEX] = 0},          /*refresh_period_ms*/ \
Edouard@3399:     {[0 ... MAX_CON_INDEX] = 0},          /*age_ms*/            \
Edouard@3399:     NULL,                                 /*subscriptions_next*/\
Edouard@3399:     NULL,                                 /*subscriptions_prev*/\
Edouard@3399:     NULL}                                 /*incoming_next*/
Edouard@3399: 
Edouard@3399: 
Edouard@3399: /* entry for dual linked list for HMI subscriptions */
Edouard@3399: /* points to the end of the list */
Edouard@3399: static hmi_tree_item_t  *subscriptions_tail = NULL;
Edouard@3399: 
Edouard@3399: /* entry for single linked list for changes from HMI */
Edouard@3399: /* points to the end of the list */
Edouard@3399: static hmi_tree_item_t *incoming_tail = NULL;
Edouard@3399: 
Edouard@3399: static hmi_tree_item_t hmi_tree_items[] = {
Edouard@2764: %(variable_decl_array)s
Edouard@2764: };
Edouard@2764: 
Edouard@2767: #define __Unpack_desc_type hmi_tree_item_t
Edouard@2766: 
Edouard@2767: %(var_access_code)s
Edouard@2765: 
Edouard@3399: static int write_iterator(hmi_tree_item_t *dsc)
Edouard@2788: {
edouard@3400:     uint32_t session_index = 0;
edouard@3400:     int value_changed = 0;
edouard@3400:     void *dest_p = NULL;
edouard@3400:     void *value_p = NULL;
edouard@3400:     size_t sz = 0;
edouard@3400:     while(session_index < MAX_CONNECTIONS) {
edouard@3400:         if(dsc->wstate[session_index] == buf_set){
edouard@3400:             /* if being subscribed */
edouard@3400:             if(dsc->refresh_period_ms[session_index]){
edouard@3400:                 if(dsc->age_ms[session_index] + ticktime_ms < dsc->refresh_period_ms[session_index]){
edouard@3400:                     dsc->age_ms[session_index] += ticktime_ms;
edouard@3400:                 }else{
edouard@3400:                     dsc->wstate[session_index] = buf_tosend;
edouard@3400:                     global_write_dirty = 1;
edouard@3400:                 }
edouard@3400:             }
edouard@3400:         }
edouard@3400: 
edouard@3400:         /* variable is sample only if just subscribed
edouard@3400:            or already subscribed and having value change */
edouard@3400:         int do_sample = 0;
edouard@3400:         int just_subscribed = dsc->wstate[session_index] == buf_new;
edouard@3400:         if(!just_subscribed){
edouard@3400:             int already_subscribed = dsc->refresh_period_ms[session_index] > 0;
edouard@3400:             if(already_subscribed){
edouard@3400:                 if(!value_changed){
edouard@3400:                     if(!value_p){
edouard@3400:                         UnpackVar(dsc, &value_p, NULL, &sz);
edouard@3400:                         if(__Is_a_string(dsc)){
edouard@3400:                             sz = ((STRING*)value_p)->len + 1;
Edouard@3374:                         }
edouard@3400:                         dest_p = &wbuf[dsc->buf_index];
edouard@3400:                     }
edouard@3400:                     value_changed = memcmp(dest_p, value_p, sz) != 0;
edouard@3400:                     do_sample = value_changed;
edouard@3400:                 }else{
edouard@3400:                     do_sample = 1;
edouard@3400:                 }
edouard@3400:             }
edouard@3400:         } else {
edouard@3400:             do_sample = 1;
edouard@3400:         }
edouard@3400: 
edouard@3400: 
edouard@3400:         if(do_sample){
edouard@3400:             if(dsc->wstate[session_index] != buf_set && dsc->wstate[session_index] != buf_tosend) {
edouard@3400:                 if(dsc->wstate[session_index] == buf_new \
edouard@3400:                    || ticktime_ms > dsc->refresh_period_ms[session_index]){
edouard@3400:                     dsc->wstate[session_index] = buf_tosend;
edouard@3400:                     global_write_dirty = 1;
edouard@3400:                 } else {
edouard@3400:                     dsc->wstate[session_index] = buf_set;
edouard@3400:                 }
edouard@3400:                 dsc->age_ms[session_index] = 0;
edouard@3400:             }
edouard@3400:         }
edouard@3400: 
edouard@3400:         session_index++;
edouard@3400:     }
edouard@3400:     /* copy value if changed (and subscribed) */
edouard@3400:     if(value_changed)
edouard@3400:         memcpy(dest_p, value_p, sz);
Edouard@2788:     return 0;
Edouard@2788: }
Edouard@2788: 
Edouard@3399: static int send_iterator(uint32_t index, hmi_tree_item_t *dsc, uint32_t session_index)
Edouard@3399: {
Edouard@3399:     if(dsc->wstate[session_index] == buf_tosend)
Edouard@2788:     {
Edouard@2788:         uint32_t sz = __get_type_enum_size(dsc->type);
Edouard@2799:         if(sbufidx + sizeof(uint32_t) + sz <=  sizeof(sbuf))
Edouard@2788:         {
Edouard@2788:             void *src_p = &wbuf[dsc->buf_index];
Edouard@2788:             void *dst_p = &sbuf[sbufidx];
edouard@2826:             if(__Is_a_string(dsc)){
edouard@2826:                 sz = ((STRING*)src_p)->len + 1;
edouard@2826:             }
Edouard@2799:             /* TODO : force into little endian */
Edouard@2788:             memcpy(dst_p, &index, sizeof(uint32_t));
Edouard@2788:             memcpy(dst_p + sizeof(uint32_t), src_p, sz);
Edouard@3399:             dsc->wstate[session_index] = buf_free;
Edouard@2788:             sbufidx += sizeof(uint32_t) /* index */ + sz;
Edouard@2788:         }
Edouard@2788:         else
Edouard@2788:         {
Edouard@2799:             printf("BUG!!! %%d + %%ld + %%d >  %%ld \n", sbufidx, sizeof(uint32_t), sz,  sizeof(sbuf));
Edouard@2862:             return EOVERFLOW;
Edouard@2788:         }
Edouard@2788:     }
Edouard@2788: 
Edouard@2862:     return 0;
Edouard@2788: }
Edouard@2788: 
Edouard@3399: static int read_iterator(hmi_tree_item_t *dsc)
Edouard@2788: {
Edouard@3374:     if(dsc->rstate == buf_set)
Edouard@3374:     {
Edouard@3374:         void *src_p = &rbuf[dsc->buf_index];
Edouard@3397:         void *value_p = NULL;
Edouard@3397:         size_t sz = 0;
Edouard@3397:         UnpackVar(dsc, &value_p, NULL, &sz);
Edouard@3397:         memcpy(value_p, src_p, sz);
Edouard@3374:         dsc->rstate = buf_free;
Edouard@3374:     }
Edouard@2788:     return 0;
Edouard@2788: }
Edouard@2788: 
Edouard@3270: void update_refresh_period(hmi_tree_item_t *dsc, uint32_t session_index, uint16_t refresh_period_ms)
Edouard@2768: {
Edouard@3399:     uint32_t other_session_index = 0;
Edouard@3399:     int previously_subscribed = 0;
Edouard@3399:     int session_only_subscriber = 0;
edouard@3400:     int session_already_subscriber = 0;
Edouard@3399:     int needs_subscription_for_session = (refresh_period_ms != 0);
Edouard@3399: 
Edouard@3399:     while(other_session_index < session_index) {
Edouard@3399:         previously_subscribed |= (dsc->refresh_period_ms[other_session_index++] != 0);
Edouard@3399:     }
edouard@3400:     session_already_subscriber = (dsc->refresh_period_ms[other_session_index++] != 0);
Edouard@3399:     while(other_session_index < MAX_CONNECTIONS) {
Edouard@3399:         previously_subscribed |= (dsc->refresh_period_ms[other_session_index++] != 0);
Edouard@3399:     }
edouard@3400:     session_only_subscriber = session_already_subscriber && !previously_subscribed;
edouard@3400:     previously_subscribed |= session_already_subscriber;
Edouard@3399: 
Edouard@3399:     if(needs_subscription_for_session) {
edouard@3400:         if(!session_already_subscriber)
Edouard@3270:         {
Edouard@3270:             dsc->wstate[session_index] = buf_new;
Edouard@2863:         }
edouard@3400:         /* item is appended to list only when no session was previously subscribed */
Edouard@3399:         if(!previously_subscribed){
Edouard@3399:             /* append subsciption to list */
edouard@3400:             if(subscriptions_tail != NULL){ 
edouard@3400:                 /* if list wasn't empty, link with previous tail*/
edouard@3400:                 subscriptions_tail->subscriptions_next = dsc;
edouard@3400:             }
Edouard@3399:             dsc->subscriptions_prev = subscriptions_tail;
Edouard@3399:             subscriptions_tail = dsc;
Edouard@3399:             dsc->subscriptions_next = NULL;
Edouard@3399:         }
Edouard@2805:     } else {
Edouard@3270:         dsc->wstate[session_index] = buf_free;
Edouard@3399:         /* item is removed from list only when session was the only one remaining */
Edouard@3399:         if (session_only_subscriber) {
Edouard@3399:             if(dsc->subscriptions_next == NULL){ /* remove tail  */
Edouard@3399:                 /* re-link tail to previous */
Edouard@3399:                 subscriptions_tail = dsc->subscriptions_prev;
edouard@3400:                 if(subscriptions_tail != NULL){
edouard@3400:                     subscriptions_tail->subscriptions_next = NULL;
edouard@3400:                 }
edouard@3400:             } else if(dsc->subscriptions_prev == NULL){ /* remove head  */
edouard@3400:                 dsc->subscriptions_next->subscriptions_prev = NULL;
Edouard@3399:             } else { /* remove entry in between other entries */
edouard@3400:                 /* re-link previous and next node */
Edouard@3399:                 dsc->subscriptions_next->subscriptions_prev = dsc->subscriptions_prev;
Edouard@3399:                 dsc->subscriptions_prev->subscriptions_next = dsc->subscriptions_next;
Edouard@3399:             }
Edouard@3399:             /* unnecessary
Edouard@3399:             dsc->subscriptions_next = NULL;
Edouard@3399:             dsc->subscriptions_prev = NULL;
Edouard@3399:             */
Edouard@3399:         }
Edouard@3270:     }
Edouard@3270:     dsc->refresh_period_ms[session_index] = refresh_period_ms;
Edouard@2766: }
Edouard@2766: 
edouard@3294: static void *svghmi_handle;
edouard@3294: 
edouard@3294: void SVGHMI_SuspendFromPythonThread(void)
edouard@3294: {
edouard@3294:     wait_RT_to_nRT_signal(svghmi_handle);
edouard@3294: }
edouard@3294: 
edouard@3294: void SVGHMI_WakeupFromRTThread(void)
edouard@3294: {
edouard@3294:     unblock_RT_to_nRT_signal(svghmi_handle);
edouard@3294: }
Edouard@2775: 
Edouard@3281: int svghmi_continue_collect;
Edouard@2776: 
Edouard@2764: int __init_svghmi()
Edouard@2764: {
edouard@3295:     memset(rbuf,0,sizeof(rbuf));
edouard@3295:     memset(wbuf,0,sizeof(wbuf));
Edouard@2819: 
Edouard@3281:     svghmi_continue_collect = 1;
Edouard@2765: 
edouard@3294:     /* create svghmi_pipe */
edouard@3294:     svghmi_handle = create_RT_to_nRT_signal("SVGHMI_pipe");
edouard@3294: 
Edouard@3399:     if(!svghmi_handle)
edouard@3294:         return 1;
edouard@3294: 
Edouard@2764:     return 0;
Edouard@2750: }
Edouard@2764: 
Edouard@2764: void __cleanup_svghmi()
Edouard@2764: {
Edouard@3281:     svghmi_continue_collect = 0;
Edouard@2820:     SVGHMI_WakeupFromRTThread();
edouard@3294:     delete_RT_to_nRT_signal(svghmi_handle);
Edouard@2764: }
Edouard@2764: 
Edouard@2764: void __retrieve_svghmi()
Edouard@2764: {
Edouard@3374:     if(AtomicCompareExchange(&hmitree_rlock, 0, 1) == 0) {
Edouard@3399:         hmi_tree_item_t *dsc = incoming_tail;
Edouard@3399:         /* iterate through read list (changes from HMI) */
Edouard@3399:         while(dsc){
edouard@3400:             hmi_tree_item_t *_dsc = dsc->incoming_prev;
Edouard@3399:             read_iterator(dsc);
Edouard@3399:             /* unnecessary
Edouard@3399:             dsc->incoming_prev = NULL;
Edouard@3399:             */
edouard@3400:             dsc = _dsc;
Edouard@3399:         }
Edouard@3399:         /* flush read list */
Edouard@3399:         incoming_tail = NULL;
Edouard@3374:         AtomicCompareExchange(&hmitree_rlock, 1, 0);
Edouard@3374:     }
Edouard@2764: }
Edouard@2764: 
Edouard@2764: void __publish_svghmi()
Edouard@2764: {
Edouard@2768:     global_write_dirty = 0;
Edouard@3399: 
Edouard@3374:     if(AtomicCompareExchange(&hmitree_wlock, 0, 1) == 0) {
Edouard@3399:         hmi_tree_item_t *dsc = subscriptions_tail;
Edouard@3399:         while(dsc){
Edouard@3399:             write_iterator(dsc);
Edouard@3399:             dsc = dsc->subscriptions_prev;
Edouard@3399:         }
Edouard@3374:         AtomicCompareExchange(&hmitree_wlock, 1, 0);
Edouard@3374:     }
Edouard@3399: 
Edouard@2768:     if(global_write_dirty) {
Edouard@2820:         SVGHMI_WakeupFromRTThread();
Edouard@2775:     }
Edouard@2775: }
Edouard@2775: 
Edouard@2775: /* PYTHON CALLS */
Edouard@3271: int svghmi_wait(void){
Edouard@3271: 
Edouard@3271:     SVGHMI_SuspendFromPythonThread();
Edouard@3271: }
Edouard@3271: 
Edouard@3270: int svghmi_send_collect(uint32_t session_index, uint32_t *size, char **ptr){
Edouard@2775: 
edouard@3400: 
Edouard@3281:     if(svghmi_continue_collect) {
Edouard@2788:         int res;
Edouard@2788:         sbufidx = HMI_HASH_SIZE;
Edouard@3374: 
Edouard@3374:         while(AtomicCompareExchange(&hmitree_wlock, 0, 1)){
Edouard@3374:             nRT_reschedule();
Edouard@3374:         }
Edouard@3374: 
Edouard@3399:         hmi_tree_item_t *dsc = subscriptions_tail;
Edouard@3399:         while(dsc){
Edouard@3399:             uint32_t index = dsc - hmi_tree_items;
Edouard@3399:             res = send_iterator(index, dsc, session_index);
Edouard@3399:             if(res != 0){
Edouard@3399:                 break;
Edouard@3399:             }
Edouard@3399:             dsc = dsc->subscriptions_prev;
Edouard@3399:         }
Edouard@3399:         if(res == 0)
Edouard@2788:         {
Edouard@2799:             if(sbufidx > HMI_HASH_SIZE){
Edouard@2799:                 memcpy(&sbuf[0], &hmi_hash[0], HMI_HASH_SIZE);
Edouard@2799:                 *ptr = &sbuf[0];
Edouard@2799:                 *size = sbufidx;
Edouard@3374:                 AtomicCompareExchange(&hmitree_wlock, 1, 0);
Edouard@2799:                 return 0;
Edouard@2799:             }
Edouard@3374:             AtomicCompareExchange(&hmitree_wlock, 1, 0);
Edouard@2799:             return ENODATA;
Edouard@2799:         }
Edouard@3374:         AtomicCompareExchange(&hmitree_wlock, 1, 0);
Edouard@2788:         return res;
Edouard@2775:     }
Edouard@2775:     else
Edouard@2775:     {
Edouard@2775:         return EINTR;
Edouard@2775:     }
Edouard@2775: }
Edouard@2775: 
Edouard@2788: typedef enum {
Edouard@3374:     unset = -1,
Edouard@2788:     setval = 0,
Edouard@2788:     reset = 1,
Edouard@2798:     subscribe = 2
Edouard@2788: } cmd_from_JS;
Edouard@2788: 
Edouard@3271: int svghmi_reset(uint32_t session_index){
Edouard@3399:     hmi_tree_item_t *dsc = subscriptions_tail;
edouard@3400:     while(AtomicCompareExchange(&hmitree_wlock, 0, 1)){
edouard@3400:         nRT_reschedule();
edouard@3400:     }
Edouard@3399:     while(dsc){
edouard@3400:         hmi_tree_item_t *_dsc = dsc->subscriptions_prev;
Edouard@3399:         update_refresh_period(dsc, session_index, 0);
edouard@3400:         dsc = _dsc;
edouard@3400:     }
edouard@3400:     AtomicCompareExchange(&hmitree_wlock, 1, 0);
Edouard@3271:     return 1;
Edouard@3271: }
Edouard@3271: 
Edouard@2822: // Returns :
Edouard@2822: //   0 is OK, <0 is error, 1 is heartbeat
Edouard@3270: int svghmi_recv_dispatch(uint32_t session_index, uint32_t size, const uint8_t *ptr){
Edouard@2788:     const uint8_t* cursor = ptr + HMI_HASH_SIZE;
Edouard@2788:     const uint8_t* end = ptr + size;
Edouard@2788: 
Edouard@2822:     int was_hearbeat = 0;
Edouard@2788: 
Edouard@2788:     /* match hmitree fingerprint */
Edouard@2789:     if(size <= HMI_HASH_SIZE || memcmp(ptr, hmi_hash, HMI_HASH_SIZE) != 0)
Edouard@2788:     {
Edouard@2788:         printf("svghmi_recv_dispatch MISMATCH !!\n");
Edouard@2822:         return -EINVAL;
Edouard@2788:     }
Edouard@2788: 
Edouard@3374:     int ret;
Edouard@3374:     int got_wlock = 0;
Edouard@3374:     int got_rlock = 0;
Edouard@3374:     cmd_from_JS cmd_old = unset;
Edouard@3374:     cmd_from_JS cmd = unset;
Edouard@3374: 
Edouard@2788:     while(cursor < end)
Edouard@2788:     {
Edouard@2788:         uint32_t progress;
Edouard@3374: 
Edouard@3374:         cmd_old = cmd;
Edouard@3374:         cmd = *(cursor++);
Edouard@3374: 
edouard@3400: 
Edouard@3374:         if(cmd_old != cmd){
Edouard@3374:             if(got_wlock){
Edouard@3374:                 AtomicCompareExchange(&hmitree_wlock, 1, 0);
Edouard@3374:                 got_wlock = 0;
Edouard@3374:             }
Edouard@3374:             if(got_rlock){
Edouard@3374:                 AtomicCompareExchange(&hmitree_rlock, 1, 0);
Edouard@3374:                 got_rlock = 0;
Edouard@3374:             }
Edouard@3374:         }
Edouard@2788:         switch(cmd)
Edouard@2788:         {
Edouard@2788:             case setval:
Edouard@2788:             {
Edouard@2788:                 uint32_t index = *(uint32_t*)(cursor);
Edouard@2789:                 uint8_t const *valptr = cursor + sizeof(uint32_t);
Edouard@2862: 
edouard@3400: 
Edouard@2822:                 if(index == heartbeat_index)
Edouard@2822:                     was_hearbeat = 1;
Edouard@2788: 
Edouard@2788:                 if(index < HMI_ITEM_COUNT)
Edouard@2788:                 {
Edouard@3399:                     hmi_tree_item_t *dsc = &hmi_tree_items[index];
Edouard@3397:                     size_t sz = 0;
Edouard@2788:                     void *dst_p = &rbuf[dsc->buf_index];
Edouard@2829: 
Edouard@2829:                     if(__Is_a_string(dsc)){
Edouard@2829:                         sz = ((STRING*)valptr)->len + 1;
Edouard@3399:                     } else {
Edouard@3399:                         UnpackVar(dsc, NULL, NULL, &sz);
Edouard@2829:                     }
Edouard@2788: 
Edouard@2802:                     if((valptr + sz) <= end)
Edouard@2788:                     {
Edouard@2788:                         // rescheduling spinlock until free
Edouard@3374:                         if(!got_rlock){
Edouard@3374:                             while(AtomicCompareExchange(&hmitree_rlock, 0, 1)){
Edouard@3374:                                 nRT_reschedule();
Edouard@3374:                             }
Edouard@3374:                             got_rlock=1;
Edouard@3374:                         }
Edouard@2788: 
Edouard@2788:                         memcpy(dst_p, valptr, sz);
Edouard@3399: 
Edouard@3399:                         /* check that rstate is not already buf_set */
Edouard@3399:                         if(dsc->rstate != buf_set){
Edouard@3399:                             dsc->rstate = buf_set;
Edouard@3399:                             /* append entry to read list (changes from HMI) */
Edouard@3399:                             dsc->incoming_prev = incoming_tail;
Edouard@3399:                             incoming_tail = dsc;
Edouard@3399:                         }
Edouard@2788: 
Edouard@2788:                         progress = sz + sizeof(uint32_t) /* index */;
Edouard@2788:                     }
Edouard@2862:                     else
Edouard@2799:                     {
Edouard@3374:                         ret = -EINVAL;
Edouard@3374:                         goto exit_free;
Edouard@2799:                     }
Edouard@2799:                 }
Edouard@2862:                 else
Edouard@2799:                 {
Edouard@3374:                     ret = -EINVAL;
Edouard@3374:                     goto exit_free;
Edouard@2799:                 }
Edouard@2788:             }
Edouard@2788:             break;
Edouard@2788: 
Edouard@2788:             case reset:
Edouard@2788:             {
Edouard@2788:                 progress = 0;
Edouard@3374:                 if(!got_wlock){
Edouard@3374:                     while(AtomicCompareExchange(&hmitree_wlock, 0, 1)){
Edouard@3374:                         nRT_reschedule();
Edouard@3374:                     }
Edouard@3374:                     got_wlock = 1;
Edouard@3374:                 }
Edouard@3399:                 {
Edouard@3399:                     hmi_tree_item_t *dsc = subscriptions_tail;
Edouard@3399:                     while(dsc){
edouard@3400:                         hmi_tree_item_t *_dsc = dsc->subscriptions_prev;
Edouard@3399:                         update_refresh_period(dsc, session_index, 0);
edouard@3400:                         dsc = _dsc;
Edouard@3399:                     }
Edouard@3399:                 }
Edouard@2788:             }
Edouard@2788:             break;
Edouard@2788: 
Edouard@2788:             case subscribe:
Edouard@2788:             {
Edouard@2788:                 uint32_t index = *(uint32_t*)(cursor);
Edouard@2788:                 uint16_t refresh_period_ms = *(uint32_t*)(cursor + sizeof(uint32_t));
Edouard@2788: 
Edouard@2788:                 if(index < HMI_ITEM_COUNT)
Edouard@2788:                 {
Edouard@3374:                     if(!got_wlock){
Edouard@3374:                         while(AtomicCompareExchange(&hmitree_wlock, 0, 1)){
Edouard@3374:                             nRT_reschedule();
Edouard@3374:                         }
Edouard@3374:                         got_wlock = 1;
Edouard@3374:                     }
Edouard@3399:                     hmi_tree_item_t *dsc = &hmi_tree_items[index];
Edouard@3270:                     update_refresh_period(dsc, session_index, refresh_period_ms);
Edouard@2799:                 }
Edouard@2862:                 else
Edouard@2799:                 {
Edouard@3374:                     ret = -EINVAL;
Edouard@3374:                     goto exit_free;
Edouard@2799:                 }
Edouard@2788: 
Edouard@2862:                 progress = sizeof(uint32_t) /* index */ +
Edouard@2788:                            sizeof(uint16_t) /* refresh period */;
Edouard@2788:             }
Edouard@2788:             break;
Edouard@2799:             default:
Edouard@2799:                 printf("svghmi_recv_dispatch unknown %%d\n",cmd);
Edouard@2788: 
Edouard@2788:         }
Edouard@2788:         cursor += progress;
Edouard@2788:     }
Edouard@3374:     ret = was_hearbeat;
Edouard@3374: 
Edouard@3374: exit_free:
Edouard@3374:     if(got_wlock){
Edouard@3374:         AtomicCompareExchange(&hmitree_wlock, 1, 0);
Edouard@3374:         got_wlock = 0;
Edouard@3374:     }
Edouard@3374:     if(got_rlock){
Edouard@3374:         AtomicCompareExchange(&hmitree_rlock, 1, 0);
Edouard@3374:         got_rlock = 0;
Edouard@3374:     }
Edouard@3374:     return ret;
Edouard@3374: }
Edouard@3374: