--- 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 @@
+#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 +#define ticktime_ns %(PLC_ticktime)d; +uint16_t ticktime_ms (ticktime_ns>1000000)? -%(extern_variables_declarations)s
+int global_write_dirty = 0;
+ /* publish/write/send */ + /* zero means not subscribed */ + uint16_t refresh_period_ms; + /* retrieve/read/recv */ 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));
+ long was_locked = AtomicCompareExchange(&dsc->wlock, 0, 1); + /* was locked. give up*/ + 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; + 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) { + 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){ + // 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 @@ -79,16 +157,24 @@
- if(!pthread_mutex_lock(&rbuf_mutex)){
- traverse_hmi_tree(read_iterator);
- pthread_mutex_unlock(&rbuf_mutex);
+ traverse_hmi_tree(read_iterator); - 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){ + // - 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 @@
- str(buf_index) + ", 0}"]
+ str(buf_index) + ", 0, }"] 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")