/******************************************************************
                   CAN slave HW module example
 ******************************************************************
 module simulates getting/setting of industrial process values
 reads stdin and writes it to object 6000:01 (8 bit digital input)
 changes in object 6200:01 writes to stdout  (8 bit digital outpud)
 (see nascan.eds)
 ******************************************************************/
// necessary for getline()
#define _GNU_SOURCE 
 
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>

#include "vca_hwmod.h"

#include "ul_evcbase.h"
#include "sui_event.h"
#include "sui_dinfo.h"
#include "sui_dievc.h"

#define HW_DI_CNT 2

static sui_dinfo_t *diList[HW_DI_CNT];
static unsigned int valList[HW_DI_CNT];

evc_rx_hub_t hub1;

static int init_fnished = 0;

static void hub1_hevent(evc_rx_hub_t *hub, sui_event_t *event)
{
  long val = 0;
  sui_dinfo_t *calling_dinfo = (sui_dinfo_t*)(event->u_u.message.ptr);
  printf("Digital output (object 6200:01) changed\n");
  sui_rd_long(calling_dinfo, 0, &val);
  printf("\tnew value: 0x%04x\n", (unsigned)val);
}

int vcaHwModule_initModule(void)
{
    int i;
    printf("HW module init\n");
    // create and init dinfos
    for(i=0; i<HW_DI_CNT; i++) {
        diList[i] = sui_create_dinfo_uint(valList + i, 1, sizeof(valList[i]));
        if(!diList[i]) fprintf(stderr, "*** ERROR *** creating dinfo\n");
        //printf("vcaHwModule_initModule(): created dinfo[%i]: %p\n", i, diList[i]);
    }
    // init rx hub
    evc_rx_hub_init(&hub1, (evc_rx_fnc_t*)&hub1_hevent, /*hub context*/NULL);
    sui_dinfo_connect_to_hub(diList[1], &hub1, NULL); // NULL - use default propagation function
    init_fnished = 1;
    return 0;
}

void vcaHwModule_cleanupModule(void)
{
    // decrementing refcnt frees dinfo, if it is not referenced by someone else
    int i;
    printf("HW module cleanup\n");
    for(i=0; i<HW_DI_CNT; i++) {
        if(diList[i]) sui_dinfo_dec_refcnt(diList[i]);
        diList[i] = NULL;
    }
}

int vcaHwModule_getDinfoCnt() 
{
    // to avoid strange errors caused by using not initialized module    
    if(!init_fnished) return 0;
    return HW_DI_CNT;
}

sui_dinfo_t *vcaHwModule_getDinfoRef(int dinfo_ix)
{
    if(dinfo_ix < HW_DI_CNT) {
        sui_dinfo_t *di = diList[dinfo_ix];
        // do not foreget increment returned dinfo reference
        sui_dinfo_inc_refcnt(di);
        //printf("\nvcaHwModule_getDinfoRef(%i): %p\n", dinfo_ix, di);
        return di;
    }
    return NULL;
}

uint32_t vcaHwModule_getDinfoObjectIndex(int dinfo_ix)
{
    switch(dinfo_ix) {
        case 0: return 0x600001; // digital input
        case 1: return 0x620001; // digital output
    }
    return 0;
}

static void* workingThread(void *param)
{
    vcaHwModule_initModule();
    {
        int linelen = 0;
        char *line = NULL;
        while(1) {
            long n;
            int ret;
            printf("Enter int to send to CAN or 'q':\n");
            ret = getline(&line, &linelen, stdin);
            if(ret < 0) {
                perror("getline ERROR:");
                break;
            }
            if(line[0] == 'q') break;
            //printf("\tconverting '%s' to int\n", line);
            n = strtol(line, NULL, 0);
            //printf("\tconverted value: %li\n", n);
            printf("\twriting 0x%04x to object 6000:01", (int)n);
            if(sui_wr_long(diList[0], 0, &n) == SUDI_DATA_OK) {
                printf(" ... OK\n");
                //printf("workingThread(): firing value object change\n");
                //sui_dinfo_changed(diList[0]);
            }
            else {
                printf(" ... ERROR\n");
            }
        }
        printf("Bye\n");
    }
    vcaHwModule_cleanupModule();
    pthread_exit(0);
}

vcaHwModule_workingThread_fn_t* vcaHwModule_getWorkingThreadFunction()
{
    return workingThread;
}


