#include "iec_types_all.h"
#define DEFAULT_REFRESH_PERIOD_MS 100
#define HMI_BUFFER_SIZE %(buffer_size)d
/* PLC reads from that buffer */
static char rbuf[HMI_BUFFER_SIZE];
/* PLC writes to that buffer */
static char wbuf[HMI_BUFFER_SIZE];
%(extern_variables_declarations)s
#define ticktime_ns %(PLC_ticktime)d
uint16_t ticktime_ms = (ticktime_ns>1000000)?
int global_write_dirty = 0;
/* zero means not subscribed */
uint16_t refresh_period_ms;
static hmi_tree_item_t hmi_tree_item[] = {
typedef void(*hmi_tree_iterator)(hmi_tree_item_t*);
void 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];
if(dsc->type != UNKNOWN_ENUM)
#define __Unpack_desc_type hmi_tree_item_t
void write_iterator(hmi_tree_item_t *dsc)
void *dest_p = &wbuf[dsc->buf_index];
void *real_value_p = NULL;
void *visible_value_p = UnpackVar(dsc, &real_value_p, &flags);
long was_locked = AtomicCompareExchange(&dsc->wlock, 0, 1);
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) {
/* 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->wstate == buf_tosend){
// TODO call the python callback
AtomicCompareExchange(&dsc->wlock, 1, 0);
void read_iterator(hmi_tree_item_t *dsc)
void *src_p = &rbuf[dsc->buf_index];
void *real_value_p = NULL;
void *visible_value_p = UnpackVar(dsc, &real_value_p, &flags);
memcpy(visible_value_p, src_p, __get_type_enum_size(dsc->type));
bzero(rbuf,sizeof(rbuf));
bzero(wbuf,sizeof(wbuf));
// TODO - sending pthread condition variable
traverse_hmi_tree(read_iterator);
traverse_hmi_tree(write_iterator);
// TODO : set condition variable to wakeup sending collector
void* collect_updates_to_send(void* args){
// TODO : get callback from args
// TODO add arg to traverse_hmi_tree to pass callback
traverse_hmi_tree(send_iterator);