--- a/svghmi/svghmi.c Thu Dec 16 08:32:58 2021 +0100
+++ b/svghmi/svghmi.c Thu Dec 23 11:36:37 2021 +0100
@@ -10,6 +10,7 @@
#define HMI_ITEM_COUNT %(item_count)d
#define MAX_CONNECTIONS %(max_connections)d
+#define MAX_CON_INDEX MAX_CONNECTIONS - 1 static uint8_t hmi_hash[HMI_HASH_SIZE] = {%(hmi_hash_ints)s};
@@ -19,7 +20,6 @@
/* PLC writes to that buffer */
static char wbuf[HMI_BUFFER_SIZE];
-/* TODO change that in case of multiclient... */
/* worst biggest send buffer. FIXME : use dynamic alloc ? */
static char sbuf[HMI_HASH_SIZE + HMI_BUFFER_SIZE + (HMI_ITEM_COUNT * sizeof(uint32_t))];
static unsigned int sbufidx;
@@ -42,11 +42,15 @@
static long hmitree_rlock = 0;
static long hmitree_wlock = 0;
+typedef struct hmi_tree_item_s hmi_tree_item_t; + /* retrieve/read/recv */ buf_state_t wstate[MAX_CONNECTIONS];
@@ -54,34 +58,45 @@
uint16_t refresh_period_ms[MAX_CONNECTIONS];
uint16_t age_ms[MAX_CONNECTIONS];
- /* retrieve/read/recv */
+ /* dual linked list for subscriptions */ + hmi_tree_item_t *subscriptions_next; + hmi_tree_item_t *subscriptions_prev;
+ /* single linked list for changes from HMI */ + hmi_tree_item_t *incoming_prev; -static hmi_tree_item_t hmi_tree_item[] = {
-typedef int(*hmi_tree_iterator)(uint32_t, hmi_tree_item_t*);
-static int traverse_hmi_tree(hmi_tree_iterator fp)
- for(i = 0; i < sizeof(hmi_tree_item)/sizeof(hmi_tree_item_t); i++){
- hmi_tree_item_t *dsc = &hmi_tree_item[i];
- int res = (*fp)(i, dsc);
+#define HMITREE_ITEM_INITIALIZER(cpath,type,buf_index) { \ + buf_index, /*buf_index*/ \ + {[0 ... MAX_CON_INDEX] = buf_free}, /*wstate*/ \ + {[0 ... MAX_CON_INDEX] = 0}, /*refresh_period_ms*/ \ + {[0 ... MAX_CON_INDEX] = 0}, /*age_ms*/ \ + NULL, /*subscriptions_next*/\ + NULL, /*subscriptions_prev*/\ + NULL} /*incoming_next*/ +/* entry for dual linked list for HMI subscriptions */ +/* points to the end of the list */ +static hmi_tree_item_t *subscriptions_tail = NULL; +/* entry for single linked list for changes from HMI */ +/* points to the end of the list */ +static hmi_tree_item_t *incoming_tail = NULL; +static hmi_tree_item_t hmi_tree_items[] = { #define __Unpack_desc_type hmi_tree_item_t
-static int write_iterator(uint32_t index, hmi_tree_item_t *dsc)
+static int write_iterator(hmi_tree_item_t *dsc) uint32_t session_index = 0;
@@ -114,7 +129,7 @@
UnpackVar(dsc, &value_p, NULL, &sz);
sz = ((STRING*)value_p)->len + 1;
dest_p = &wbuf[dsc->buf_index];
value_changed = memcmp(dest_p, value_p, sz) != 0;
@@ -151,10 +166,9 @@
-static uint32_t send_session_index;
-static int send_iterator(uint32_t index, hmi_tree_item_t *dsc)
+static int send_iterator(uint32_t index, hmi_tree_item_t *dsc, uint32_t session_index) - if(dsc->wstate[send_session_index] == buf_tosend)
+ if(dsc->wstate[session_index] == buf_tosend) uint32_t sz = __get_type_enum_size(dsc->type);
if(sbufidx + sizeof(uint32_t) + sz <= sizeof(sbuf))
@@ -167,7 +181,7 @@
/* TODO : force into little endian */
memcpy(dst_p, &index, sizeof(uint32_t));
memcpy(dst_p + sizeof(uint32_t), src_p, sz);
- dsc->wstate[send_session_index] = buf_free;
+ dsc->wstate[session_index] = buf_free; sbufidx += sizeof(uint32_t) /* index */ + sz;
@@ -180,7 +194,7 @@
-static int read_iterator(uint32_t index, hmi_tree_item_t *dsc)
+static int read_iterator(hmi_tree_item_t *dsc) if(dsc->rstate == buf_set)
@@ -196,24 +210,62 @@
void update_refresh_period(hmi_tree_item_t *dsc, uint32_t session_index, uint16_t refresh_period_ms)
- if(refresh_period_ms) {
- if(!dsc->refresh_period_ms[session_index])
+ uint32_t other_session_index = 0; + int previously_subscribed = 0; + int session_only_subscriber = 0; + int session_subscriber = 0; + int needs_subscription_for_session = (refresh_period_ms != 0); + while(other_session_index < session_index) { + previously_subscribed |= (dsc->refresh_period_ms[other_session_index++] != 0); + session_subscriber = (dsc->refresh_period_ms[other_session_index++] != 0); + while(other_session_index < MAX_CONNECTIONS) { + previously_subscribed |= (dsc->refresh_period_ms[other_session_index++] != 0); + session_only_subscriber = session_subscriber && !previously_subscribed; + previously_subscribed |= session_subscriber; + printf("update_refresh_period %%x,%%x index:%%d session_index:%%d refresh_period_ms:%%d\n", + if(needs_subscription_for_session) { + if(!session_subscriber) dsc->wstate[session_index] = buf_new;
+ /* if not already subscribed */ + if(!previously_subscribed){ + /* append subsciption to list */ + dsc->subscriptions_prev = subscriptions_tail; + subscriptions_tail = dsc; + dsc->subscriptions_next = NULL; dsc->wstate[session_index] = buf_free;
+ /* item is removed from list only when session was the only one remaining */ + if (session_only_subscriber) { + if(dsc->subscriptions_next == NULL){ /* remove tail */ + /* re-link tail to previous */ + subscriptions_tail = dsc->subscriptions_prev; + } else { /* remove entry in between other entries */ + /* re-link previous iand next node */ + dsc->subscriptions_next->subscriptions_prev = dsc->subscriptions_prev; + dsc->subscriptions_prev->subscriptions_next = dsc->subscriptions_next; + dsc->subscriptions_next = NULL; + dsc->subscriptions_prev = NULL; dsc->refresh_period_ms[session_index] = refresh_period_ms;
-static uint32_t reset_session_index;
-static int reset_iterator(uint32_t index, hmi_tree_item_t *dsc)
- update_refresh_period(dsc, reset_session_index, 0);
static void *svghmi_handle;
void SVGHMI_SuspendFromPythonThread(void)
@@ -238,7 +290,7 @@
svghmi_handle = create_RT_to_nRT_signal("SVGHMI_pipe");
@@ -254,7 +306,17 @@
if(AtomicCompareExchange(&hmitree_rlock, 0, 1) == 0) {
- traverse_hmi_tree(read_iterator);
+ hmi_tree_item_t *dsc = incoming_tail; + /* iterate through read list (changes from HMI) */ + dsc = dsc->incoming_prev; + dsc->incoming_prev = NULL; AtomicCompareExchange(&hmitree_rlock, 1, 0);
@@ -262,10 +324,16 @@
if(AtomicCompareExchange(&hmitree_wlock, 0, 1) == 0) {
- traverse_hmi_tree(write_iterator);
+ hmi_tree_item_t *dsc = subscriptions_tail; + dsc = dsc->subscriptions_prev; AtomicCompareExchange(&hmitree_wlock, 1, 0);
SVGHMI_WakeupFromRTThread();
@@ -282,13 +350,22 @@
if(svghmi_continue_collect) {
- send_session_index = session_index;
while(AtomicCompareExchange(&hmitree_wlock, 0, 1)){
- if((res = traverse_hmi_tree(send_iterator)) == 0)
+ hmi_tree_item_t *dsc = subscriptions_tail; + uint32_t index = dsc - hmi_tree_items; + printf("Send index %%d\n", index); + res = send_iterator(index, dsc, session_index); + dsc = dsc->subscriptions_prev; if(sbufidx > HMI_HASH_SIZE){
memcpy(&sbuf[0], &hmi_hash[0], HMI_HASH_SIZE);
@@ -318,8 +395,11 @@
int svghmi_reset(uint32_t session_index){
- reset_session_index = session_index;
- traverse_hmi_tree(reset_iterator);
+ hmi_tree_item_t *dsc = subscriptions_tail; + update_refresh_period(dsc, session_index, 0); + dsc = dsc->subscriptions_prev; @@ -373,14 +453,14 @@
if(index < HMI_ITEM_COUNT)
- hmi_tree_item_t *dsc = &hmi_tree_item[index];
+ hmi_tree_item_t *dsc = &hmi_tree_items[index]; - UnpackVar(dsc, &value_p, NULL, &sz);
void *dst_p = &rbuf[dsc->buf_index];
sz = ((STRING*)valptr)->len + 1;
+ UnpackVar(dsc, NULL, NULL, &sz); @@ -394,7 +474,14 @@
memcpy(dst_p, valptr, sz);
+ /* check that rstate is not already buf_set */ + if(dsc->rstate != buf_set){ + /* append entry to read list (changes from HMI) */ + dsc->incoming_prev = incoming_tail; progress = sz + sizeof(uint32_t) /* index */;
@@ -415,14 +502,19 @@
- reset_session_index = session_index;
while(AtomicCompareExchange(&hmitree_wlock, 0, 1)){
- traverse_hmi_tree(reset_iterator);
+ hmi_tree_item_t *dsc = subscriptions_tail; + update_refresh_period(dsc, session_index, 0); + dsc = dsc->subscriptions_prev; @@ -439,7 +531,7 @@
- hmi_tree_item_t *dsc = &hmi_tree_item[index];
+ hmi_tree_item_t *dsc = &hmi_tree_items[index]; update_refresh_period(dsc, session_index, refresh_period_ms);