Edouard@2765: #include Edouard@2764: #include "iec_types_all.h" Edouard@2764: #include "POUS.h" Edouard@2764: #include "config.h" Edouard@2764: #include "beremiz.h" Edouard@2750: Edouard@2768: #define DEFAULT_REFRESH_PERIOD_MS 100 Edouard@2765: #define HMI_BUFFER_SIZE %(buffer_size)d Edouard@2765: Edouard@2765: /* PLC reads from that buffer */ Edouard@2765: static char rbuf[HMI_BUFFER_SIZE]; Edouard@2765: Edouard@2765: /* PLC writes to that buffer */ Edouard@2765: static char wbuf[HMI_BUFFER_SIZE]; Edouard@2765: Edouard@2768: %(extern_variables_declarations)s Edouard@2765: Edouard@2771: #define ticktime_ns %(PLC_ticktime)d Edouard@2771: uint16_t ticktime_ms = (ticktime_ns>1000000)? Edouard@2768: ticktime_ns/1000000: Edouard@2768: 1; Edouard@2768: Edouard@2768: typedef enum { Edouard@2768: buf_free = 0, Edouard@2768: buf_set, Edouard@2768: buf_tosend Edouard@2768: } buf_state_t; Edouard@2768: Edouard@2768: int global_write_dirty = 0; Edouard@2764: Edouard@2771: typedef struct { Edouard@2764: void *ptr; Edouard@2764: __IEC_types_enum type; Edouard@2765: uint32_t buf_index; Edouard@2768: Edouard@2768: /* publish/write/send */ Edouard@2771: long wlock; Edouard@2768: /* zero means not subscribed */ Edouard@2768: uint16_t refresh_period_ms; Edouard@2768: uint16_t age_ms; Edouard@2768: Edouard@2768: buf_state_t wstate; Edouard@2768: Edouard@2768: /* retrieve/read/recv */ Edouard@2771: long rlock; Edouard@2768: buf_state_t rstate; Edouard@2768: Edouard@2764: } hmi_tree_item_t; Edouard@2764: Edouard@2764: static hmi_tree_item_t hmi_tree_item[] = { Edouard@2764: %(variable_decl_array)s Edouard@2764: }; Edouard@2764: Edouard@2765: typedef void(*hmi_tree_iterator)(hmi_tree_item_t*); Edouard@2765: void traverse_hmi_tree(hmi_tree_iterator fp) Edouard@2765: { Edouard@2765: unsigned int i; Edouard@2765: for(i = 0; i < sizeof(hmi_tree_item)/sizeof(hmi_tree_item_t); i++){ Edouard@2765: hmi_tree_item_t *dsc = &hmi_tree_item[i]; Edouard@2765: if(dsc->type != UNKNOWN_ENUM) Edouard@2765: (*fp)(dsc); Edouard@2765: } Edouard@2765: } Edouard@2765: Edouard@2767: #define __Unpack_desc_type hmi_tree_item_t Edouard@2766: Edouard@2767: %(var_access_code)s Edouard@2765: Edouard@2766: void write_iterator(hmi_tree_item_t *dsc) Edouard@2766: { Edouard@2766: void *dest_p = &wbuf[dsc->buf_index]; Edouard@2766: void *real_value_p = NULL; Edouard@2766: char flags = 0; Edouard@2766: Edouard@2766: void *visible_value_p = UnpackVar(dsc, &real_value_p, &flags); Edouard@2766: Edouard@2768: /* Try take lock */ Edouard@2768: long was_locked = AtomicCompareExchange(&dsc->wlock, 0, 1); Edouard@2768: Edouard@2768: if(was_locked) { Edouard@2768: /* was locked. give up*/ Edouard@2768: return; Edouard@2768: } Edouard@2768: Edouard@2771: if(dsc->wstate == buf_set){ Edouard@2768: /* if being subscribed */ Edouard@2768: if(dsc->refresh_period_ms){ Edouard@2768: if(dsc->age_ms + ticktime_ms < dsc->refresh_period_ms){ Edouard@2768: dsc->age_ms += ticktime_ms; Edouard@2768: }else{ Edouard@2768: dsc->wstate = buf_tosend; Edouard@2768: } Edouard@2768: } Edouard@2768: } Edouard@2768: Edouard@2768: /* if new value differs from previous one */ Edouard@2768: if(memcmp(dest_p, visible_value_p, __get_type_enum_size(dsc->type)) != 0){ Edouard@2768: /* copy and flag as set */ Edouard@2768: memcpy(dest_p, visible_value_p, __get_type_enum_size(dsc->type)); Edouard@2768: if(dsc->wstate == buf_free) { Edouard@2768: dsc->wstate = buf_set; Edouard@2768: dsc->age_ms = 0; Edouard@2768: } Edouard@2768: global_write_dirty = 1; Edouard@2768: } Edouard@2768: Edouard@2768: /* unlock - use AtomicComparExchange to have memory barrier */ Edouard@2768: AtomicCompareExchange(&dsc->wlock, 1, 0); Edouard@2768: } Edouard@2768: Edouard@2768: struct timespec sending_now; Edouard@2768: struct timespec next_sending; Edouard@2768: void send_iterator(hmi_tree_item_t *dsc) Edouard@2768: { Edouard@2768: while(AtomicCompareExchange(&dsc->wlock, 0, 1)) sched_yield(); Edouard@2768: Edouard@2768: // check for variable being modified Edouard@2771: if(dsc->wstate == buf_tosend){ Edouard@2768: // send Edouard@2768: Edouard@2771: // TODO call the python callback Edouard@2768: Edouard@2768: dsc->wstate = buf_free; Edouard@2768: } Edouard@2768: Edouard@2768: AtomicCompareExchange(&dsc->wlock, 1, 0); Edouard@2766: } Edouard@2766: Edouard@2766: void read_iterator(hmi_tree_item_t *dsc) Edouard@2766: { Edouard@2766: void *src_p = &rbuf[dsc->buf_index]; Edouard@2766: void *real_value_p = NULL; Edouard@2766: char flags = 0; Edouard@2766: Edouard@2766: void *visible_value_p = UnpackVar(dsc, &real_value_p, &flags); Edouard@2766: Edouard@2768: Edouard@2766: memcpy(visible_value_p, src_p, __get_type_enum_size(dsc->type)); Edouard@2765: } Edouard@2765: Edouard@2764: int __init_svghmi() Edouard@2764: { Edouard@2765: bzero(rbuf,sizeof(rbuf)); Edouard@2765: bzero(wbuf,sizeof(wbuf)); Edouard@2768: Edouard@2771: // TODO - sending pthread condition variable Edouard@2765: Edouard@2764: return 0; Edouard@2750: } Edouard@2764: Edouard@2764: void __cleanup_svghmi() Edouard@2764: { Edouard@2764: } Edouard@2764: Edouard@2764: void __retrieve_svghmi() Edouard@2764: { Edouard@2768: traverse_hmi_tree(read_iterator); Edouard@2764: } Edouard@2764: Edouard@2764: void __publish_svghmi() Edouard@2764: { Edouard@2768: global_write_dirty = 0; Edouard@2768: traverse_hmi_tree(write_iterator); Edouard@2768: if(global_write_dirty) { Edouard@2771: // TODO : set condition variable to wakeup sending collector Edouard@2765: } Edouard@2768: Edouard@2764: } Edouard@2764: Edouard@2771: void* collect_updates_to_send(void* args){ Edouard@2771: Edouard@2771: // TODO : get callback from args Edouard@2771: Edouard@2768: Edouard@2768: // TODO : wait for Edouard@2771: // - condition variable Edouard@2771: Edouard@2771: // TODO add arg to traverse_hmi_tree to pass callback Edouard@2768: Edouard@2768: traverse_hmi_tree(send_iterator); Edouard@2771: Edouard@2768: }