svghmi/svghmi.c
branchwxPython4
changeset 3405 fdc12f7d27c8
parent 3400 c2b46d0965ca
child 3613 7af7a23e4adb
equal deleted inserted replaced
3391:0ae5a15efa18 3405:fdc12f7d27c8
     8 #define DEFAULT_REFRESH_PERIOD_MS 100
     8 #define DEFAULT_REFRESH_PERIOD_MS 100
     9 #define HMI_BUFFER_SIZE %(buffer_size)d
     9 #define HMI_BUFFER_SIZE %(buffer_size)d
    10 #define HMI_ITEM_COUNT %(item_count)d
    10 #define HMI_ITEM_COUNT %(item_count)d
    11 #define HMI_HASH_SIZE 8
    11 #define HMI_HASH_SIZE 8
    12 #define MAX_CONNECTIONS %(max_connections)d
    12 #define MAX_CONNECTIONS %(max_connections)d
       
    13 #define MAX_CON_INDEX MAX_CONNECTIONS - 1
    13 
    14 
    14 static uint8_t hmi_hash[HMI_HASH_SIZE] = {%(hmi_hash_ints)s};
    15 static uint8_t hmi_hash[HMI_HASH_SIZE] = {%(hmi_hash_ints)s};
    15 
    16 
    16 /* PLC reads from that buffer */
    17 /* PLC reads from that buffer */
    17 static char rbuf[HMI_BUFFER_SIZE];
    18 static char rbuf[HMI_BUFFER_SIZE];
    18 
    19 
    19 /* PLC writes to that buffer */
    20 /* PLC writes to that buffer */
    20 static char wbuf[HMI_BUFFER_SIZE];
    21 static char wbuf[HMI_BUFFER_SIZE];
    21 
    22 
    22 /* TODO change that in case of multiclient... */
       
    23 /* worst biggest send buffer. FIXME : use dynamic alloc ? */
    23 /* worst biggest send buffer. FIXME : use dynamic alloc ? */
    24 static char sbuf[HMI_HASH_SIZE +  HMI_BUFFER_SIZE + (HMI_ITEM_COUNT * sizeof(uint32_t))];
    24 static char sbuf[HMI_HASH_SIZE +  HMI_BUFFER_SIZE + (HMI_ITEM_COUNT * sizeof(uint32_t))];
    25 static unsigned int sbufidx;
    25 static unsigned int sbufidx;
    26 
    26 
    27 %(extern_variables_declarations)s
    27 %(extern_variables_declarations)s
    40 
    40 
    41 static int global_write_dirty = 0;
    41 static int global_write_dirty = 0;
    42 static long hmitree_rlock = 0;
    42 static long hmitree_rlock = 0;
    43 static long hmitree_wlock = 0;
    43 static long hmitree_wlock = 0;
    44 
    44 
    45 typedef struct {
    45 typedef struct hmi_tree_item_s hmi_tree_item_t;
       
    46 struct hmi_tree_item_s{
    46     void *ptr;
    47     void *ptr;
    47     __IEC_types_enum type;
    48     __IEC_types_enum type;
    48     uint32_t buf_index;
    49     uint32_t buf_index;
    49 
    50 
       
    51     /* retrieve/read/recv */
       
    52     buf_state_t rstate;
       
    53 
    50     /* publish/write/send */
    54     /* publish/write/send */
    51     buf_state_t wstate[MAX_CONNECTIONS];
    55     buf_state_t wstate[MAX_CONNECTIONS];
    52 
    56 
    53     /* zero means not subscribed */
    57     /* zero means not subscribed */
    54     uint16_t refresh_period_ms[MAX_CONNECTIONS];
    58     uint16_t refresh_period_ms[MAX_CONNECTIONS];
    55     uint16_t age_ms[MAX_CONNECTIONS];
    59     uint16_t age_ms[MAX_CONNECTIONS];
    56 
    60 
    57     /* retrieve/read/recv */
    61     /* dual linked list for subscriptions */
    58     buf_state_t rstate;
    62     hmi_tree_item_t *subscriptions_next;
    59 
    63     hmi_tree_item_t *subscriptions_prev;
    60 } hmi_tree_item_t;
    64 
    61 
    65     /* single linked list for changes from HMI */
    62 static hmi_tree_item_t hmi_tree_item[] = {
    66     hmi_tree_item_t *incoming_prev;
       
    67 
       
    68 };
       
    69 
       
    70 #define HMITREE_ITEM_INITIALIZER(cpath,type,buf_index) {        \
       
    71     &(cpath),                             /*ptr*/               \
       
    72     type,                                 /*type*/              \
       
    73     buf_index,                            /*buf_index*/         \
       
    74     buf_free,                             /*rstate*/            \
       
    75     {[0 ... MAX_CON_INDEX] = buf_free},   /*wstate*/            \
       
    76     {[0 ... MAX_CON_INDEX] = 0},          /*refresh_period_ms*/ \
       
    77     {[0 ... MAX_CON_INDEX] = 0},          /*age_ms*/            \
       
    78     NULL,                                 /*subscriptions_next*/\
       
    79     NULL,                                 /*subscriptions_prev*/\
       
    80     NULL}                                 /*incoming_next*/
       
    81 
       
    82 
       
    83 /* entry for dual linked list for HMI subscriptions */
       
    84 /* points to the end of the list */
       
    85 static hmi_tree_item_t  *subscriptions_tail = NULL;
       
    86 
       
    87 /* entry for single linked list for changes from HMI */
       
    88 /* points to the end of the list */
       
    89 static hmi_tree_item_t *incoming_tail = NULL;
       
    90 
       
    91 static hmi_tree_item_t hmi_tree_items[] = {
    63 %(variable_decl_array)s
    92 %(variable_decl_array)s
    64 };
    93 };
    65 
    94 
    66 typedef int(*hmi_tree_iterator)(uint32_t, hmi_tree_item_t*);
    95 #define __Unpack_desc_type hmi_tree_item_t
    67 static int traverse_hmi_tree(hmi_tree_iterator fp)
    96 
    68 {
    97 %(var_access_code)s
    69     unsigned int i;
    98 
    70     for(i = 0; i < sizeof(hmi_tree_item)/sizeof(hmi_tree_item_t); i++){
    99 static int write_iterator(hmi_tree_item_t *dsc)
    71         hmi_tree_item_t *dsc = &hmi_tree_item[i];
   100 {
    72         int res = (*fp)(i, dsc);
   101     uint32_t session_index = 0;
    73         if(res != 0){
   102     int value_changed = 0;
    74             return res;
   103     void *dest_p = NULL;
    75         }
   104     void *value_p = NULL;
    76     }
   105     size_t sz = 0;
       
   106     while(session_index < MAX_CONNECTIONS) {
       
   107         if(dsc->wstate[session_index] == buf_set){
       
   108             /* if being subscribed */
       
   109             if(dsc->refresh_period_ms[session_index]){
       
   110                 if(dsc->age_ms[session_index] + ticktime_ms < dsc->refresh_period_ms[session_index]){
       
   111                     dsc->age_ms[session_index] += ticktime_ms;
       
   112                 }else{
       
   113                     dsc->wstate[session_index] = buf_tosend;
       
   114                     global_write_dirty = 1;
       
   115                 }
       
   116             }
       
   117         }
       
   118 
       
   119         /* variable is sample only if just subscribed
       
   120            or already subscribed and having value change */
       
   121         int do_sample = 0;
       
   122         int just_subscribed = dsc->wstate[session_index] == buf_new;
       
   123         if(!just_subscribed){
       
   124             int already_subscribed = dsc->refresh_period_ms[session_index] > 0;
       
   125             if(already_subscribed){
       
   126                 if(!value_changed){
       
   127                     if(!value_p){
       
   128                         UnpackVar(dsc, &value_p, NULL, &sz);
       
   129                         if(__Is_a_string(dsc)){
       
   130                             sz = ((STRING*)value_p)->len + 1;
       
   131                         }
       
   132                         dest_p = &wbuf[dsc->buf_index];
       
   133                     }
       
   134                     value_changed = memcmp(dest_p, value_p, sz) != 0;
       
   135                     do_sample = value_changed;
       
   136                 }else{
       
   137                     do_sample = 1;
       
   138                 }
       
   139             }
       
   140         } else {
       
   141             do_sample = 1;
       
   142         }
       
   143 
       
   144 
       
   145         if(do_sample){
       
   146             if(dsc->wstate[session_index] != buf_set && dsc->wstate[session_index] != buf_tosend) {
       
   147                 if(dsc->wstate[session_index] == buf_new \
       
   148                    || ticktime_ms > dsc->refresh_period_ms[session_index]){
       
   149                     dsc->wstate[session_index] = buf_tosend;
       
   150                     global_write_dirty = 1;
       
   151                 } else {
       
   152                     dsc->wstate[session_index] = buf_set;
       
   153                 }
       
   154                 dsc->age_ms[session_index] = 0;
       
   155             }
       
   156         }
       
   157 
       
   158         session_index++;
       
   159     }
       
   160     /* copy value if changed (and subscribed) */
       
   161     if(value_changed)
       
   162         memcpy(dest_p, value_p, sz);
    77     return 0;
   163     return 0;
    78 }
   164 }
    79 
   165 
    80 #define __Unpack_desc_type hmi_tree_item_t
   166 static int send_iterator(uint32_t index, hmi_tree_item_t *dsc, uint32_t session_index)
    81 
   167 {
    82 %(var_access_code)s
   168     if(dsc->wstate[session_index] == buf_tosend)
    83 
       
    84 static int write_iterator(uint32_t index, hmi_tree_item_t *dsc)
       
    85 {
       
    86     {
       
    87         uint32_t session_index = 0;
       
    88         int value_changed = 0;
       
    89         void *dest_p = NULL;
       
    90         void *real_value_p = NULL;
       
    91         void *visible_value_p = NULL;
       
    92         USINT sz = 0;
       
    93         while(session_index < MAX_CONNECTIONS) {
       
    94             if(dsc->wstate[session_index] == buf_set){
       
    95                 /* if being subscribed */
       
    96                 if(dsc->refresh_period_ms[session_index]){
       
    97                     if(dsc->age_ms[session_index] + ticktime_ms < dsc->refresh_period_ms[session_index]){
       
    98                         dsc->age_ms[session_index] += ticktime_ms;
       
    99                     }else{
       
   100                         dsc->wstate[session_index] = buf_tosend;
       
   101                         global_write_dirty = 1;
       
   102                     }
       
   103                 }
       
   104             }
       
   105 
       
   106             /* variable is sample only if just subscribed
       
   107                or already subscribed and having value change */
       
   108             int do_sample = 0;
       
   109             int just_subscribed = dsc->wstate[session_index] == buf_new;
       
   110             if(!just_subscribed){
       
   111                 int already_subscribed = dsc->refresh_period_ms[session_index] > 0;
       
   112                 if(already_subscribed){
       
   113                     if(!value_changed){
       
   114                         if(!visible_value_p){
       
   115                             char flags = 0;
       
   116                             visible_value_p = UnpackVar(dsc, &real_value_p, &flags);
       
   117                             if(__Is_a_string(dsc)){
       
   118                                 sz = ((STRING*)visible_value_p)->len + 1;
       
   119                             } else {
       
   120                                 sz = __get_type_enum_size(dsc->type);
       
   121                             }
       
   122                             dest_p = &wbuf[dsc->buf_index];
       
   123                         }
       
   124                         value_changed = memcmp(dest_p, visible_value_p, sz) != 0;
       
   125                         do_sample = value_changed;
       
   126                     }else{
       
   127                         do_sample = 1;
       
   128                     }
       
   129                 }
       
   130             } else {
       
   131                 do_sample = 1;
       
   132             }
       
   133 
       
   134 
       
   135             if(do_sample){
       
   136                 if(dsc->wstate[session_index] != buf_set && dsc->wstate[session_index] != buf_tosend) {
       
   137                     if(dsc->wstate[session_index] == buf_new \
       
   138                        || ticktime_ms > dsc->refresh_period_ms[session_index]){
       
   139                         dsc->wstate[session_index] = buf_tosend;
       
   140                         global_write_dirty = 1;
       
   141                     } else {
       
   142                         dsc->wstate[session_index] = buf_set;
       
   143                     }
       
   144                     dsc->age_ms[session_index] = 0;
       
   145                 }
       
   146             }
       
   147 
       
   148             session_index++;
       
   149         }
       
   150         /* copy value if changed (and subscribed) */
       
   151         if(value_changed)
       
   152             memcpy(dest_p, visible_value_p, sz);
       
   153     }
       
   154     // else ... : PLC can't wait, variable will be updated next turn
       
   155     return 0;
       
   156 }
       
   157 
       
   158 static uint32_t send_session_index;
       
   159 static int send_iterator(uint32_t index, hmi_tree_item_t *dsc)
       
   160 {
       
   161     if(dsc->wstate[send_session_index] == buf_tosend)
       
   162     {
   169     {
   163         uint32_t sz = __get_type_enum_size(dsc->type);
   170         uint32_t sz = __get_type_enum_size(dsc->type);
   164         if(sbufidx + sizeof(uint32_t) + sz <=  sizeof(sbuf))
   171         if(sbufidx + sizeof(uint32_t) + sz <=  sizeof(sbuf))
   165         {
   172         {
   166             void *src_p = &wbuf[dsc->buf_index];
   173             void *src_p = &wbuf[dsc->buf_index];
   169                 sz = ((STRING*)src_p)->len + 1;
   176                 sz = ((STRING*)src_p)->len + 1;
   170             }
   177             }
   171             /* TODO : force into little endian */
   178             /* TODO : force into little endian */
   172             memcpy(dst_p, &index, sizeof(uint32_t));
   179             memcpy(dst_p, &index, sizeof(uint32_t));
   173             memcpy(dst_p + sizeof(uint32_t), src_p, sz);
   180             memcpy(dst_p + sizeof(uint32_t), src_p, sz);
   174             dsc->wstate[send_session_index] = buf_free;
   181             dsc->wstate[session_index] = buf_free;
   175             sbufidx += sizeof(uint32_t) /* index */ + sz;
   182             sbufidx += sizeof(uint32_t) /* index */ + sz;
   176         }
   183         }
   177         else
   184         else
   178         {
   185         {
   179             printf("BUG!!! %%d + %%ld + %%d >  %%ld \n", sbufidx, sizeof(uint32_t), sz,  sizeof(sbuf));
   186             printf("BUG!!! %%d + %%ld + %%d >  %%ld \n", sbufidx, sizeof(uint32_t), sz,  sizeof(sbuf));
   182     }
   189     }
   183 
   190 
   184     return 0;
   191     return 0;
   185 }
   192 }
   186 
   193 
   187 static int read_iterator(uint32_t index, hmi_tree_item_t *dsc)
   194 static int read_iterator(hmi_tree_item_t *dsc)
   188 {
   195 {
   189     if(dsc->rstate == buf_set)
   196     if(dsc->rstate == buf_set)
   190     {
   197     {
   191         void *src_p = &rbuf[dsc->buf_index];
   198         void *src_p = &rbuf[dsc->buf_index];
   192         void *real_value_p = NULL;
   199         void *value_p = NULL;
   193         char flags = 0;
   200         size_t sz = 0;
   194         void *visible_value_p = UnpackVar(dsc, &real_value_p, &flags);
   201         UnpackVar(dsc, &value_p, NULL, &sz);
   195         memcpy(real_value_p, src_p, __get_type_enum_size(dsc->type));
   202         memcpy(value_p, src_p, sz);
   196         dsc->rstate = buf_free;
   203         dsc->rstate = buf_free;
   197     }
   204     }
   198     return 0;
   205     return 0;
   199 }
   206 }
   200 
   207 
   201 void update_refresh_period(hmi_tree_item_t *dsc, uint32_t session_index, uint16_t refresh_period_ms)
   208 void update_refresh_period(hmi_tree_item_t *dsc, uint32_t session_index, uint16_t refresh_period_ms)
   202 {
   209 {
   203     if(refresh_period_ms) {
   210     uint32_t other_session_index = 0;
   204         if(!dsc->refresh_period_ms[session_index])
   211     int previously_subscribed = 0;
       
   212     int session_only_subscriber = 0;
       
   213     int session_already_subscriber = 0;
       
   214     int needs_subscription_for_session = (refresh_period_ms != 0);
       
   215 
       
   216     while(other_session_index < session_index) {
       
   217         previously_subscribed |= (dsc->refresh_period_ms[other_session_index++] != 0);
       
   218     }
       
   219     session_already_subscriber = (dsc->refresh_period_ms[other_session_index++] != 0);
       
   220     while(other_session_index < MAX_CONNECTIONS) {
       
   221         previously_subscribed |= (dsc->refresh_period_ms[other_session_index++] != 0);
       
   222     }
       
   223     session_only_subscriber = session_already_subscriber && !previously_subscribed;
       
   224     previously_subscribed |= session_already_subscriber;
       
   225 
       
   226     if(needs_subscription_for_session) {
       
   227         if(!session_already_subscriber)
   205         {
   228         {
   206             dsc->wstate[session_index] = buf_new;
   229             dsc->wstate[session_index] = buf_new;
   207         }
   230         }
       
   231         /* item is appended to list only when no session was previously subscribed */
       
   232         if(!previously_subscribed){
       
   233             /* append subsciption to list */
       
   234             if(subscriptions_tail != NULL){ 
       
   235                 /* if list wasn't empty, link with previous tail*/
       
   236                 subscriptions_tail->subscriptions_next = dsc;
       
   237             }
       
   238             dsc->subscriptions_prev = subscriptions_tail;
       
   239             subscriptions_tail = dsc;
       
   240             dsc->subscriptions_next = NULL;
       
   241         }
   208     } else {
   242     } else {
   209         dsc->wstate[session_index] = buf_free;
   243         dsc->wstate[session_index] = buf_free;
       
   244         /* item is removed from list only when session was the only one remaining */
       
   245         if (session_only_subscriber) {
       
   246             if(dsc->subscriptions_next == NULL){ /* remove tail  */
       
   247                 /* re-link tail to previous */
       
   248                 subscriptions_tail = dsc->subscriptions_prev;
       
   249                 if(subscriptions_tail != NULL){
       
   250                     subscriptions_tail->subscriptions_next = NULL;
       
   251                 }
       
   252             } else if(dsc->subscriptions_prev == NULL){ /* remove head  */
       
   253                 dsc->subscriptions_next->subscriptions_prev = NULL;
       
   254             } else { /* remove entry in between other entries */
       
   255                 /* re-link previous and next node */
       
   256                 dsc->subscriptions_next->subscriptions_prev = dsc->subscriptions_prev;
       
   257                 dsc->subscriptions_prev->subscriptions_next = dsc->subscriptions_next;
       
   258             }
       
   259             /* unnecessary
       
   260             dsc->subscriptions_next = NULL;
       
   261             dsc->subscriptions_prev = NULL;
       
   262             */
       
   263         }
   210     }
   264     }
   211     dsc->refresh_period_ms[session_index] = refresh_period_ms;
   265     dsc->refresh_period_ms[session_index] = refresh_period_ms;
   212 }
       
   213 
       
   214 static uint32_t reset_session_index;
       
   215 static int reset_iterator(uint32_t index, hmi_tree_item_t *dsc)
       
   216 {
       
   217     update_refresh_period(dsc, reset_session_index, 0);
       
   218     return 0;
       
   219 }
   266 }
   220 
   267 
   221 static void *svghmi_handle;
   268 static void *svghmi_handle;
   222 
   269 
   223 void SVGHMI_SuspendFromPythonThread(void)
   270 void SVGHMI_SuspendFromPythonThread(void)
   240     svghmi_continue_collect = 1;
   287     svghmi_continue_collect = 1;
   241 
   288 
   242     /* create svghmi_pipe */
   289     /* create svghmi_pipe */
   243     svghmi_handle = create_RT_to_nRT_signal("SVGHMI_pipe");
   290     svghmi_handle = create_RT_to_nRT_signal("SVGHMI_pipe");
   244 
   291 
   245     if(!svghmi_handle) 
   292     if(!svghmi_handle)
   246         return 1;
   293         return 1;
   247 
   294 
   248     return 0;
   295     return 0;
   249 }
   296 }
   250 
   297 
   256 }
   303 }
   257 
   304 
   258 void __retrieve_svghmi()
   305 void __retrieve_svghmi()
   259 {
   306 {
   260     if(AtomicCompareExchange(&hmitree_rlock, 0, 1) == 0) {
   307     if(AtomicCompareExchange(&hmitree_rlock, 0, 1) == 0) {
   261         traverse_hmi_tree(read_iterator);
   308         hmi_tree_item_t *dsc = incoming_tail;
       
   309         /* iterate through read list (changes from HMI) */
       
   310         while(dsc){
       
   311             hmi_tree_item_t *_dsc = dsc->incoming_prev;
       
   312             read_iterator(dsc);
       
   313             /* unnecessary
       
   314             dsc->incoming_prev = NULL;
       
   315             */
       
   316             dsc = _dsc;
       
   317         }
       
   318         /* flush read list */
       
   319         incoming_tail = NULL;
   262         AtomicCompareExchange(&hmitree_rlock, 1, 0);
   320         AtomicCompareExchange(&hmitree_rlock, 1, 0);
   263     }
   321     }
   264 }
   322 }
   265 
   323 
   266 void __publish_svghmi()
   324 void __publish_svghmi()
   267 {
   325 {
   268     global_write_dirty = 0;
   326     global_write_dirty = 0;
       
   327 
   269     if(AtomicCompareExchange(&hmitree_wlock, 0, 1) == 0) {
   328     if(AtomicCompareExchange(&hmitree_wlock, 0, 1) == 0) {
   270         traverse_hmi_tree(write_iterator);
   329         hmi_tree_item_t *dsc = subscriptions_tail;
       
   330         while(dsc){
       
   331             write_iterator(dsc);
       
   332             dsc = dsc->subscriptions_prev;
       
   333         }
   271         AtomicCompareExchange(&hmitree_wlock, 1, 0);
   334         AtomicCompareExchange(&hmitree_wlock, 1, 0);
   272     }
   335     }
       
   336 
   273     if(global_write_dirty) {
   337     if(global_write_dirty) {
   274         SVGHMI_WakeupFromRTThread();
   338         SVGHMI_WakeupFromRTThread();
   275     }
   339     }
   276 }
   340 }
   277 
   341 
   280 
   344 
   281     SVGHMI_SuspendFromPythonThread();
   345     SVGHMI_SuspendFromPythonThread();
   282 }
   346 }
   283 
   347 
   284 int svghmi_send_collect(uint32_t session_index, uint32_t *size, char **ptr){
   348 int svghmi_send_collect(uint32_t session_index, uint32_t *size, char **ptr){
       
   349 
   285 
   350 
   286     if(svghmi_continue_collect) {
   351     if(svghmi_continue_collect) {
   287         int res;
   352         int res;
   288         sbufidx = HMI_HASH_SIZE;
   353         sbufidx = HMI_HASH_SIZE;
   289         send_session_index = session_index;
       
   290 
   354 
   291         while(AtomicCompareExchange(&hmitree_wlock, 0, 1)){
   355         while(AtomicCompareExchange(&hmitree_wlock, 0, 1)){
   292             nRT_reschedule();
   356             nRT_reschedule();
   293         }
   357         }
   294 
   358 
   295         if((res = traverse_hmi_tree(send_iterator)) == 0)
   359         hmi_tree_item_t *dsc = subscriptions_tail;
       
   360         while(dsc){
       
   361             uint32_t index = dsc - hmi_tree_items;
       
   362             res = send_iterator(index, dsc, session_index);
       
   363             if(res != 0){
       
   364                 break;
       
   365             }
       
   366             dsc = dsc->subscriptions_prev;
       
   367         }
       
   368         if(res == 0)
   296         {
   369         {
   297             if(sbufidx > HMI_HASH_SIZE){
   370             if(sbufidx > HMI_HASH_SIZE){
   298                 memcpy(&sbuf[0], &hmi_hash[0], HMI_HASH_SIZE);
   371                 memcpy(&sbuf[0], &hmi_hash[0], HMI_HASH_SIZE);
   299                 *ptr = &sbuf[0];
   372                 *ptr = &sbuf[0];
   300                 *size = sbufidx;
   373                 *size = sbufidx;
   302                 return 0;
   375                 return 0;
   303             }
   376             }
   304             AtomicCompareExchange(&hmitree_wlock, 1, 0);
   377             AtomicCompareExchange(&hmitree_wlock, 1, 0);
   305             return ENODATA;
   378             return ENODATA;
   306         }
   379         }
   307         // printf("collected BAD result %%d\n", res);
       
   308         AtomicCompareExchange(&hmitree_wlock, 1, 0);
   380         AtomicCompareExchange(&hmitree_wlock, 1, 0);
   309         return res;
   381         return res;
   310     }
   382     }
   311     else
   383     else
   312     {
   384     {
   320     reset = 1,
   392     reset = 1,
   321     subscribe = 2
   393     subscribe = 2
   322 } cmd_from_JS;
   394 } cmd_from_JS;
   323 
   395 
   324 int svghmi_reset(uint32_t session_index){
   396 int svghmi_reset(uint32_t session_index){
   325     reset_session_index = session_index;
   397     hmi_tree_item_t *dsc = subscriptions_tail;
   326     traverse_hmi_tree(reset_iterator);
   398     while(AtomicCompareExchange(&hmitree_wlock, 0, 1)){
       
   399         nRT_reschedule();
       
   400     }
       
   401     while(dsc){
       
   402         hmi_tree_item_t *_dsc = dsc->subscriptions_prev;
       
   403         update_refresh_period(dsc, session_index, 0);
       
   404         dsc = _dsc;
       
   405     }
       
   406     AtomicCompareExchange(&hmitree_wlock, 1, 0);
   327     return 1;
   407     return 1;
   328 }
   408 }
   329 
   409 
   330 // Returns :
   410 // Returns :
   331 //   0 is OK, <0 is error, 1 is heartbeat
   411 //   0 is OK, <0 is error, 1 is heartbeat
   352     {
   432     {
   353         uint32_t progress;
   433         uint32_t progress;
   354 
   434 
   355         cmd_old = cmd;
   435         cmd_old = cmd;
   356         cmd = *(cursor++);
   436         cmd = *(cursor++);
       
   437 
   357 
   438 
   358         if(cmd_old != cmd){
   439         if(cmd_old != cmd){
   359             if(got_wlock){
   440             if(got_wlock){
   360                 AtomicCompareExchange(&hmitree_wlock, 1, 0);
   441                 AtomicCompareExchange(&hmitree_wlock, 1, 0);
   361                 got_wlock = 0;
   442                 got_wlock = 0;
   370             case setval:
   451             case setval:
   371             {
   452             {
   372                 uint32_t index = *(uint32_t*)(cursor);
   453                 uint32_t index = *(uint32_t*)(cursor);
   373                 uint8_t const *valptr = cursor + sizeof(uint32_t);
   454                 uint8_t const *valptr = cursor + sizeof(uint32_t);
   374 
   455 
       
   456 
   375                 if(index == heartbeat_index)
   457                 if(index == heartbeat_index)
   376                     was_hearbeat = 1;
   458                     was_hearbeat = 1;
   377 
   459 
   378                 if(index < HMI_ITEM_COUNT)
   460                 if(index < HMI_ITEM_COUNT)
   379                 {
   461                 {
   380                     hmi_tree_item_t *dsc = &hmi_tree_item[index];
   462                     hmi_tree_item_t *dsc = &hmi_tree_items[index];
   381                     void *real_value_p = NULL;
   463                     size_t sz = 0;
   382                     char flags = 0;
       
   383                     void *visible_value_p = UnpackVar(dsc, &real_value_p, &flags);
       
   384                     void *dst_p = &rbuf[dsc->buf_index];
   464                     void *dst_p = &rbuf[dsc->buf_index];
   385                     uint32_t sz = __get_type_enum_size(dsc->type);
       
   386 
   465 
   387                     if(__Is_a_string(dsc)){
   466                     if(__Is_a_string(dsc)){
   388                         sz = ((STRING*)valptr)->len + 1;
   467                         sz = ((STRING*)valptr)->len + 1;
       
   468                     } else {
       
   469                         UnpackVar(dsc, NULL, NULL, &sz);
   389                     }
   470                     }
   390 
   471 
   391                     if((valptr + sz) <= end)
   472                     if((valptr + sz) <= end)
   392                     {
   473                     {
   393                         // rescheduling spinlock until free
   474                         // rescheduling spinlock until free
   397                             }
   478                             }
   398                             got_rlock=1;
   479                             got_rlock=1;
   399                         }
   480                         }
   400 
   481 
   401                         memcpy(dst_p, valptr, sz);
   482                         memcpy(dst_p, valptr, sz);
   402                         dsc->rstate = buf_set;
   483 
       
   484                         /* check that rstate is not already buf_set */
       
   485                         if(dsc->rstate != buf_set){
       
   486                             dsc->rstate = buf_set;
       
   487                             /* append entry to read list (changes from HMI) */
       
   488                             dsc->incoming_prev = incoming_tail;
       
   489                             incoming_tail = dsc;
       
   490                         }
   403 
   491 
   404                         progress = sz + sizeof(uint32_t) /* index */;
   492                         progress = sz + sizeof(uint32_t) /* index */;
   405                     }
   493                     }
   406                     else
   494                     else
   407                     {
   495                     {
   418             break;
   506             break;
   419 
   507 
   420             case reset:
   508             case reset:
   421             {
   509             {
   422                 progress = 0;
   510                 progress = 0;
   423                 reset_session_index = session_index;
       
   424                 if(!got_wlock){
   511                 if(!got_wlock){
   425                     while(AtomicCompareExchange(&hmitree_wlock, 0, 1)){
   512                     while(AtomicCompareExchange(&hmitree_wlock, 0, 1)){
   426                         nRT_reschedule();
   513                         nRT_reschedule();
   427                     }
   514                     }
   428                     got_wlock = 1;
   515                     got_wlock = 1;
   429                 }
   516                 }
   430                 traverse_hmi_tree(reset_iterator);
   517                 {
       
   518                     hmi_tree_item_t *dsc = subscriptions_tail;
       
   519                     while(dsc){
       
   520                         hmi_tree_item_t *_dsc = dsc->subscriptions_prev;
       
   521                         update_refresh_period(dsc, session_index, 0);
       
   522                         dsc = _dsc;
       
   523                     }
       
   524                 }
   431             }
   525             }
   432             break;
   526             break;
   433 
   527 
   434             case subscribe:
   528             case subscribe:
   435             {
   529             {
   442                         while(AtomicCompareExchange(&hmitree_wlock, 0, 1)){
   536                         while(AtomicCompareExchange(&hmitree_wlock, 0, 1)){
   443                             nRT_reschedule();
   537                             nRT_reschedule();
   444                         }
   538                         }
   445                         got_wlock = 1;
   539                         got_wlock = 1;
   446                     }
   540                     }
   447                     hmi_tree_item_t *dsc = &hmi_tree_item[index];
   541                     hmi_tree_item_t *dsc = &hmi_tree_items[index];
   448                     update_refresh_period(dsc, session_index, refresh_period_ms);
   542                     update_refresh_period(dsc, session_index, refresh_period_ms);
   449                 }
   543                 }
   450                 else
   544                 else
   451                 {
   545                 {
   452                     ret = -EINVAL;
   546                     ret = -EINVAL;