svghmi/svghmi.c
branchRuntimeLists
changeset 3399 95e0b926a8c3
parent 3397 75920c99ffc9
child 3400 c2b46d0965ca
equal deleted inserted replaced
3398:7ca3924be865 3399:95e0b926a8c3
     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*);
       
    67 static int traverse_hmi_tree(hmi_tree_iterator fp)
       
    68 {
       
    69     unsigned int i;
       
    70     for(i = 0; i < sizeof(hmi_tree_item)/sizeof(hmi_tree_item_t); i++){
       
    71         hmi_tree_item_t *dsc = &hmi_tree_item[i];
       
    72         int res = (*fp)(i, dsc);
       
    73         if(res != 0){
       
    74             return res;
       
    75         }
       
    76     }
       
    77     return 0;
       
    78 }
       
    79 
       
    80 #define __Unpack_desc_type hmi_tree_item_t
    95 #define __Unpack_desc_type hmi_tree_item_t
    81 
    96 
    82 %(var_access_code)s
    97 %(var_access_code)s
    83 
    98 
    84 static int write_iterator(uint32_t index, hmi_tree_item_t *dsc)
    99 static int write_iterator(hmi_tree_item_t *dsc)
    85 {
   100 {
    86     {
   101     {
    87         uint32_t session_index = 0;
   102         uint32_t session_index = 0;
    88         int value_changed = 0;
   103         int value_changed = 0;
    89         void *dest_p = NULL;
   104         void *dest_p = NULL;
   112                     if(!value_changed){
   127                     if(!value_changed){
   113                         if(!value_p){
   128                         if(!value_p){
   114                             UnpackVar(dsc, &value_p, NULL, &sz);
   129                             UnpackVar(dsc, &value_p, NULL, &sz);
   115                             if(__Is_a_string(dsc)){
   130                             if(__Is_a_string(dsc)){
   116                                 sz = ((STRING*)value_p)->len + 1;
   131                                 sz = ((STRING*)value_p)->len + 1;
   117                             } 
   132                             }
   118                             dest_p = &wbuf[dsc->buf_index];
   133                             dest_p = &wbuf[dsc->buf_index];
   119                         }
   134                         }
   120                         value_changed = memcmp(dest_p, value_p, sz) != 0;
   135                         value_changed = memcmp(dest_p, value_p, sz) != 0;
   121                         do_sample = value_changed;
   136                         do_sample = value_changed;
   122                     }else{
   137                     }else{
   149     }
   164     }
   150     // else ... : PLC can't wait, variable will be updated next turn
   165     // else ... : PLC can't wait, variable will be updated next turn
   151     return 0;
   166     return 0;
   152 }
   167 }
   153 
   168 
   154 static uint32_t send_session_index;
   169 static int send_iterator(uint32_t index, hmi_tree_item_t *dsc, uint32_t session_index)
   155 static int send_iterator(uint32_t index, hmi_tree_item_t *dsc)
   170 {
   156 {
   171     if(dsc->wstate[session_index] == buf_tosend)
   157     if(dsc->wstate[send_session_index] == buf_tosend)
       
   158     {
   172     {
   159         uint32_t sz = __get_type_enum_size(dsc->type);
   173         uint32_t sz = __get_type_enum_size(dsc->type);
   160         if(sbufidx + sizeof(uint32_t) + sz <=  sizeof(sbuf))
   174         if(sbufidx + sizeof(uint32_t) + sz <=  sizeof(sbuf))
   161         {
   175         {
   162             void *src_p = &wbuf[dsc->buf_index];
   176             void *src_p = &wbuf[dsc->buf_index];
   165                 sz = ((STRING*)src_p)->len + 1;
   179                 sz = ((STRING*)src_p)->len + 1;
   166             }
   180             }
   167             /* TODO : force into little endian */
   181             /* TODO : force into little endian */
   168             memcpy(dst_p, &index, sizeof(uint32_t));
   182             memcpy(dst_p, &index, sizeof(uint32_t));
   169             memcpy(dst_p + sizeof(uint32_t), src_p, sz);
   183             memcpy(dst_p + sizeof(uint32_t), src_p, sz);
   170             dsc->wstate[send_session_index] = buf_free;
   184             dsc->wstate[session_index] = buf_free;
   171             sbufidx += sizeof(uint32_t) /* index */ + sz;
   185             sbufidx += sizeof(uint32_t) /* index */ + sz;
   172         }
   186         }
   173         else
   187         else
   174         {
   188         {
   175             printf("BUG!!! %%d + %%ld + %%d >  %%ld \n", sbufidx, sizeof(uint32_t), sz,  sizeof(sbuf));
   189             printf("BUG!!! %%d + %%ld + %%d >  %%ld \n", sbufidx, sizeof(uint32_t), sz,  sizeof(sbuf));
   178     }
   192     }
   179 
   193 
   180     return 0;
   194     return 0;
   181 }
   195 }
   182 
   196 
   183 static int read_iterator(uint32_t index, hmi_tree_item_t *dsc)
   197 static int read_iterator(hmi_tree_item_t *dsc)
   184 {
   198 {
   185     if(dsc->rstate == buf_set)
   199     if(dsc->rstate == buf_set)
   186     {
   200     {
   187         void *src_p = &rbuf[dsc->buf_index];
   201         void *src_p = &rbuf[dsc->buf_index];
   188         void *value_p = NULL;
   202         void *value_p = NULL;
   194     return 0;
   208     return 0;
   195 }
   209 }
   196 
   210 
   197 void update_refresh_period(hmi_tree_item_t *dsc, uint32_t session_index, uint16_t refresh_period_ms)
   211 void update_refresh_period(hmi_tree_item_t *dsc, uint32_t session_index, uint16_t refresh_period_ms)
   198 {
   212 {
   199     if(refresh_period_ms) {
   213     uint32_t other_session_index = 0;
   200         if(!dsc->refresh_period_ms[session_index])
   214     int previously_subscribed = 0;
       
   215     int session_only_subscriber = 0;
       
   216     int session_subscriber = 0;
       
   217     int needs_subscription_for_session = (refresh_period_ms != 0);
       
   218 
       
   219     while(other_session_index < session_index) {
       
   220         previously_subscribed |= (dsc->refresh_period_ms[other_session_index++] != 0);
       
   221     }
       
   222     session_subscriber = (dsc->refresh_period_ms[other_session_index++] != 0);
       
   223     while(other_session_index < MAX_CONNECTIONS) {
       
   224         previously_subscribed |= (dsc->refresh_period_ms[other_session_index++] != 0);
       
   225     }
       
   226     session_only_subscriber = session_subscriber && !previously_subscribed;
       
   227     previously_subscribed |= session_subscriber;
       
   228 
       
   229     printf("update_refresh_period %%x,%%x index:%%d session_index:%%d refresh_period_ms:%%d\n",
       
   230            dsc,
       
   231            hmi_tree_items,
       
   232            dsc - hmi_tree_items,
       
   233            session_index,
       
   234            refresh_period_ms);
       
   235 
       
   236     if(needs_subscription_for_session) {
       
   237         if(!session_subscriber)
   201         {
   238         {
   202             dsc->wstate[session_index] = buf_new;
   239             dsc->wstate[session_index] = buf_new;
   203         }
   240         }
       
   241         /* if not already subscribed */
       
   242         if(!previously_subscribed){
       
   243             /* append subsciption to list */
       
   244             dsc->subscriptions_prev = subscriptions_tail;
       
   245             subscriptions_tail = dsc;
       
   246             dsc->subscriptions_next = NULL;
       
   247         }
   204     } else {
   248     } else {
   205         dsc->wstate[session_index] = buf_free;
   249         dsc->wstate[session_index] = buf_free;
       
   250         /* item is removed from list only when session was the only one remaining */
       
   251         if (session_only_subscriber) {
       
   252             if(dsc->subscriptions_next == NULL){ /* remove tail  */
       
   253                 /* re-link tail to previous */
       
   254                 subscriptions_tail = dsc->subscriptions_prev;
       
   255             } else { /* remove entry in between other entries */
       
   256                 /* re-link previous iand next node */
       
   257                 dsc->subscriptions_next->subscriptions_prev = dsc->subscriptions_prev;
       
   258                 dsc->subscriptions_prev->subscriptions_next = dsc->subscriptions_next;
       
   259             }
       
   260             /* unnecessary
       
   261             dsc->subscriptions_next = NULL;
       
   262             dsc->subscriptions_prev = NULL;
       
   263             */
       
   264         }
   206     }
   265     }
   207     dsc->refresh_period_ms[session_index] = refresh_period_ms;
   266     dsc->refresh_period_ms[session_index] = refresh_period_ms;
   208 }
       
   209 
       
   210 static uint32_t reset_session_index;
       
   211 static int reset_iterator(uint32_t index, hmi_tree_item_t *dsc)
       
   212 {
       
   213     update_refresh_period(dsc, reset_session_index, 0);
       
   214     return 0;
       
   215 }
   267 }
   216 
   268 
   217 static void *svghmi_handle;
   269 static void *svghmi_handle;
   218 
   270 
   219 void SVGHMI_SuspendFromPythonThread(void)
   271 void SVGHMI_SuspendFromPythonThread(void)
   236     svghmi_continue_collect = 1;
   288     svghmi_continue_collect = 1;
   237 
   289 
   238     /* create svghmi_pipe */
   290     /* create svghmi_pipe */
   239     svghmi_handle = create_RT_to_nRT_signal("SVGHMI_pipe");
   291     svghmi_handle = create_RT_to_nRT_signal("SVGHMI_pipe");
   240 
   292 
   241     if(!svghmi_handle) 
   293     if(!svghmi_handle)
   242         return 1;
   294         return 1;
   243 
   295 
   244     return 0;
   296     return 0;
   245 }
   297 }
   246 
   298 
   252 }
   304 }
   253 
   305 
   254 void __retrieve_svghmi()
   306 void __retrieve_svghmi()
   255 {
   307 {
   256     if(AtomicCompareExchange(&hmitree_rlock, 0, 1) == 0) {
   308     if(AtomicCompareExchange(&hmitree_rlock, 0, 1) == 0) {
   257         traverse_hmi_tree(read_iterator);
   309         hmi_tree_item_t *dsc = incoming_tail;
       
   310         /* iterate through read list (changes from HMI) */
       
   311         while(dsc){
       
   312             read_iterator(dsc);
       
   313             dsc = dsc->incoming_prev;
       
   314             /* unnecessary
       
   315             dsc->incoming_prev = NULL;
       
   316             */
       
   317         }
       
   318         /* flush read list */
       
   319         incoming_tail = NULL;
   258         AtomicCompareExchange(&hmitree_rlock, 1, 0);
   320         AtomicCompareExchange(&hmitree_rlock, 1, 0);
   259     }
   321     }
   260 }
   322 }
   261 
   323 
   262 void __publish_svghmi()
   324 void __publish_svghmi()
   263 {
   325 {
   264     global_write_dirty = 0;
   326     global_write_dirty = 0;
       
   327 
   265     if(AtomicCompareExchange(&hmitree_wlock, 0, 1) == 0) {
   328     if(AtomicCompareExchange(&hmitree_wlock, 0, 1) == 0) {
   266         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         }
   267         AtomicCompareExchange(&hmitree_wlock, 1, 0);
   334         AtomicCompareExchange(&hmitree_wlock, 1, 0);
   268     }
   335     }
       
   336 
   269     if(global_write_dirty) {
   337     if(global_write_dirty) {
   270         SVGHMI_WakeupFromRTThread();
   338         SVGHMI_WakeupFromRTThread();
   271     }
   339     }
   272 }
   340 }
   273 
   341 
   280 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){
   281 
   349 
   282     if(svghmi_continue_collect) {
   350     if(svghmi_continue_collect) {
   283         int res;
   351         int res;
   284         sbufidx = HMI_HASH_SIZE;
   352         sbufidx = HMI_HASH_SIZE;
   285         send_session_index = session_index;
       
   286 
   353 
   287         while(AtomicCompareExchange(&hmitree_wlock, 0, 1)){
   354         while(AtomicCompareExchange(&hmitree_wlock, 0, 1)){
   288             nRT_reschedule();
   355             nRT_reschedule();
   289         }
   356         }
   290 
   357 
   291         if((res = traverse_hmi_tree(send_iterator)) == 0)
   358         hmi_tree_item_t *dsc = subscriptions_tail;
       
   359         while(dsc){
       
   360             uint32_t index = dsc - hmi_tree_items;
       
   361             printf("Send index %%d\n", index);
       
   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)
   292         {
   369         {
   293             if(sbufidx > HMI_HASH_SIZE){
   370             if(sbufidx > HMI_HASH_SIZE){
   294                 memcpy(&sbuf[0], &hmi_hash[0], HMI_HASH_SIZE);
   371                 memcpy(&sbuf[0], &hmi_hash[0], HMI_HASH_SIZE);
   295                 *ptr = &sbuf[0];
   372                 *ptr = &sbuf[0];
   296                 *size = sbufidx;
   373                 *size = sbufidx;
   316     reset = 1,
   393     reset = 1,
   317     subscribe = 2
   394     subscribe = 2
   318 } cmd_from_JS;
   395 } cmd_from_JS;
   319 
   396 
   320 int svghmi_reset(uint32_t session_index){
   397 int svghmi_reset(uint32_t session_index){
   321     reset_session_index = session_index;
   398     hmi_tree_item_t *dsc = subscriptions_tail;
   322     traverse_hmi_tree(reset_iterator);
   399     while(dsc){
       
   400         update_refresh_period(dsc, session_index, 0);
       
   401         dsc = dsc->subscriptions_prev;
       
   402     }
   323     return 1;
   403     return 1;
   324 }
   404 }
   325 
   405 
   326 // Returns :
   406 // Returns :
   327 //   0 is OK, <0 is error, 1 is heartbeat
   407 //   0 is OK, <0 is error, 1 is heartbeat
   371                 if(index == heartbeat_index)
   451                 if(index == heartbeat_index)
   372                     was_hearbeat = 1;
   452                     was_hearbeat = 1;
   373 
   453 
   374                 if(index < HMI_ITEM_COUNT)
   454                 if(index < HMI_ITEM_COUNT)
   375                 {
   455                 {
   376                     hmi_tree_item_t *dsc = &hmi_tree_item[index];
   456                     hmi_tree_item_t *dsc = &hmi_tree_items[index];
   377                     void *value_p = NULL;
       
   378                     size_t sz = 0;
   457                     size_t sz = 0;
   379                     UnpackVar(dsc, &value_p, NULL, &sz);
       
   380                     void *dst_p = &rbuf[dsc->buf_index];
   458                     void *dst_p = &rbuf[dsc->buf_index];
   381 
   459 
   382                     if(__Is_a_string(dsc)){
   460                     if(__Is_a_string(dsc)){
   383                         sz = ((STRING*)valptr)->len + 1;
   461                         sz = ((STRING*)valptr)->len + 1;
       
   462                     } else {
       
   463                         UnpackVar(dsc, NULL, NULL, &sz);
   384                     }
   464                     }
   385 
   465 
   386                     if((valptr + sz) <= end)
   466                     if((valptr + sz) <= end)
   387                     {
   467                     {
   388                         // rescheduling spinlock until free
   468                         // rescheduling spinlock until free
   392                             }
   472                             }
   393                             got_rlock=1;
   473                             got_rlock=1;
   394                         }
   474                         }
   395 
   475 
   396                         memcpy(dst_p, valptr, sz);
   476                         memcpy(dst_p, valptr, sz);
   397                         dsc->rstate = buf_set;
   477 
       
   478                         /* check that rstate is not already buf_set */
       
   479                         if(dsc->rstate != buf_set){
       
   480                             dsc->rstate = buf_set;
       
   481                             /* append entry to read list (changes from HMI) */
       
   482                             dsc->incoming_prev = incoming_tail;
       
   483                             incoming_tail = dsc;
       
   484                         }
   398 
   485 
   399                         progress = sz + sizeof(uint32_t) /* index */;
   486                         progress = sz + sizeof(uint32_t) /* index */;
   400                     }
   487                     }
   401                     else
   488                     else
   402                     {
   489                     {
   413             break;
   500             break;
   414 
   501 
   415             case reset:
   502             case reset:
   416             {
   503             {
   417                 progress = 0;
   504                 progress = 0;
   418                 reset_session_index = session_index;
       
   419                 if(!got_wlock){
   505                 if(!got_wlock){
   420                     while(AtomicCompareExchange(&hmitree_wlock, 0, 1)){
   506                     while(AtomicCompareExchange(&hmitree_wlock, 0, 1)){
   421                         nRT_reschedule();
   507                         nRT_reschedule();
   422                     }
   508                     }
   423                     got_wlock = 1;
   509                     got_wlock = 1;
   424                 }
   510                 }
   425                 traverse_hmi_tree(reset_iterator);
   511                 {
       
   512                     hmi_tree_item_t *dsc = subscriptions_tail;
       
   513                     while(dsc){
       
   514                         update_refresh_period(dsc, session_index, 0);
       
   515                         dsc = dsc->subscriptions_prev;
       
   516                     }
       
   517                 }
   426             }
   518             }
   427             break;
   519             break;
   428 
   520 
   429             case subscribe:
   521             case subscribe:
   430             {
   522             {
   437                         while(AtomicCompareExchange(&hmitree_wlock, 0, 1)){
   529                         while(AtomicCompareExchange(&hmitree_wlock, 0, 1)){
   438                             nRT_reschedule();
   530                             nRT_reschedule();
   439                         }
   531                         }
   440                         got_wlock = 1;
   532                         got_wlock = 1;
   441                     }
   533                     }
   442                     hmi_tree_item_t *dsc = &hmi_tree_item[index];
   534                     hmi_tree_item_t *dsc = &hmi_tree_items[index];
   443                     update_refresh_period(dsc, session_index, refresh_period_ms);
   535                     update_refresh_period(dsc, session_index, refresh_period_ms);
   444                 }
   536                 }
   445                 else
   537                 else
   446                 {
   538                 {
   447                     ret = -EINVAL;
   539                     ret = -EINVAL;