SVGHMI: Intermediate state while working on svghmi.c svghmi
authorEdouard Tisserant
Tue, 03 Sep 2019 12:17:33 +0200
branchsvghmi
changeset 2768 31785529a657
parent 2767 302347f48193
child 2769 b20c94352074
SVGHMI: Intermediate state while working on svghmi.c
svghmi/svghmi.c
svghmi/svghmi.py
--- a/svghmi/svghmi.c	Mon Aug 26 08:54:02 2019 +0200
+++ b/svghmi/svghmi.c	Tue Sep 03 12:17:33 2019 +0200
@@ -4,6 +4,7 @@
 #include "config.h"
 #include "beremiz.h"
 
+#define DEFAULT_REFRESH_PERIOD_MS 100
 #define HMI_BUFFER_SIZE %(buffer_size)d
 
 /* PLC reads from that buffer */
@@ -12,16 +13,38 @@
 /* PLC writes to that buffer */
 static char wbuf[HMI_BUFFER_SIZE];
 
-static pthread_mutex_t wbuf_mutex = PTHREAD_MUTEX_INITIALIZER;
-static pthread_mutex_t rbuf_mutex = PTHREAD_MUTEX_INITIALIZER;
+%(extern_variables_declarations)s
 
-%(extern_variables_declarations)s
+#define ticktime_ns %(PLC_ticktime)d;
+uint16_t ticktime_ms (ticktime_ns>1000000)?
+                     ticktime_ns/1000000:
+                     1;
+
+typedef enum {
+    buf_free = 0,
+    buf_set,
+    buf_tosend
+} buf_state_t;
+
+int global_write_dirty = 0;
 
 typedef const struct {
     void *ptr;
     __IEC_types_enum type;
     uint32_t buf_index;
-    uint32_t flags;
+
+    /* publish/write/send */
+    int wlock;
+    /* zero means not subscribed */
+    uint16_t refresh_period_ms;
+    uint16_t age_ms;
+
+    buf_state_t wstate;
+
+    /* retrieve/read/recv */
+    int rlock;
+    buf_state_t rstate;
+
 } hmi_tree_item_t;
 
 static hmi_tree_item_t hmi_tree_item[] = {
@@ -51,7 +74,56 @@
 
     void *visible_value_p = UnpackVar(dsc, &real_value_p, &flags);
 
-    memcpy(dest_p, visible_value_p, __get_type_enum_size(dsc->type));
+    /* Try take lock */
+    long was_locked = AtomicCompareExchange(&dsc->wlock, 0, 1);
+
+    if(was_locked) {
+        /* was locked. give up*/
+        return;
+    }
+
+    if(dsc->wstate == buf_set)
+        /* if being subscribed */
+        if(dsc->refresh_period_ms){
+            if(dsc->age_ms + ticktime_ms < dsc->refresh_period_ms){
+                dsc->age_ms += ticktime_ms;
+            }else{
+                dsc->wstate = buf_tosend;
+            }
+        }
+    }
+    
+    /* if new value differs from previous one */
+    if(memcmp(dest_p, visible_value_p, __get_type_enum_size(dsc->type)) != 0){
+        /* copy and flag as set */
+        memcpy(dest_p, visible_value_p, __get_type_enum_size(dsc->type));
+        if(dsc->wstate == buf_free) {
+            dsc->wstate = buf_set;
+            dsc->age_ms = 0;
+        }
+        global_write_dirty = 1;
+    }
+
+    /* unlock - use AtomicComparExchange to have memory barrier */
+    AtomicCompareExchange(&dsc->wlock, 1, 0);
+}
+
+struct timespec sending_now;
+struct timespec next_sending;
+void send_iterator(hmi_tree_item_t *dsc)
+{
+    while(AtomicCompareExchange(&dsc->wlock, 0, 1)) sched_yield();
+
+    // check for variable being modified
+    if(dsc->wstat == buf_tosend){
+        // send 
+
+        // TODO write to some socket
+
+        dsc->wstate = buf_free; 
+    }
+
+    AtomicCompareExchange(&dsc->wlock, 1, 0);
 }
 
 void read_iterator(hmi_tree_item_t *dsc)
@@ -62,6 +134,7 @@
 
     void *visible_value_p = UnpackVar(dsc, &real_value_p, &flags);
 
+
     memcpy(visible_value_p, src_p, __get_type_enum_size(dsc->type));
 }
 
@@ -69,6 +142,11 @@
 {
     bzero(rbuf,sizeof(rbuf));
     bzero(wbuf,sizeof(wbuf));
+    
+    // create - connection endpoint
+    //        - sending thread
+    //        - sending semaphore
+    //        - recv thread
 
     return 0;
 }
@@ -79,16 +157,24 @@
 
 void __retrieve_svghmi()
 {
-    if(!pthread_mutex_lock(&rbuf_mutex)){
-        traverse_hmi_tree(read_iterator);
-        pthread_mutex_unlock(&rbuf_mutex);
-    }
+    traverse_hmi_tree(read_iterator);
 }
 
 void __publish_svghmi()
 {
-    if(!pthread_mutex_lock(&wbuf_mutex)){
-        pthread_mutex_unlock(&wbuf_mutex);
+    global_write_dirty = 0;
+    traverse_hmi_tree(write_iterator);
+    if(global_write_dirty) {
+        // TODO : set emaphore to wakeup sending thread
     }
+
 }
 
+void sending_thread_proc(void* args){
+
+    // TODO : wait for 
+    //        - semaphore
+    //        - next autonomous send thread wakeup. (impl as wait timeout ?) 
+
+    traverse_hmi_tree(send_iterator);
+}
--- a/svghmi/svghmi.py	Mon Aug 26 08:54:02 2019 +0200
+++ b/svghmi/svghmi.py	Tue Sep 03 12:17:33 2019 +0200
@@ -181,7 +181,7 @@
                         "OUT": "_O_ENUM",
                         "VAR": "_ENUM"
                     }[node.vartype] + ", " +
-                    str(buf_index) + ", 0}"]
+                    str(buf_index) + ", 0, }"]
                 buf_index += sz
                 if len(node.path) == 1:
                     extern_variables_declarations += [
@@ -208,7 +208,8 @@
             "variable_decl_array": ",\n".join(variable_decl_array),
             "extern_variables_declarations": "\n".join(extern_variables_declarations),
             "buffer_size": buf_index,
-            "var_access_code": targets.GetCode("var_access.c")
+            "var_access_code": targets.GetCode("var_access.c"),
+            "PLC_ticktime": self.GetCTRoot().GetTicktime()
             }
 
         gen_svghmi_c_path = os.path.join(buildpath, "svghmi.c")