#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <signal.h>

#include "dido-modbus.h"
#include "dy_common.h"

struct dido_modbus * dido_modbus_create(struct dido_modbus * pdm)
{
    int ret;
    const char * mbver;

    pdm = (struct dido_modbus *) calloc(0x1, sizeof(*pdm));
    pdm->dm_num_di = 16;
    pdm->dm_num_do = 4;
    pdm->dm_num_dio = 4;
    pdm->dm_dios = (struct dido_single *)calloc(24,sizeof(struct dido_single));

    if (pdm == NULL) {
err0:
        fputs("Error, system out of memory!\n", stderr);
        fflush(stderr);
        return pdm;
    }
        pdm->dm_dios = (struct dido_single *)calloc(24,sizeof(struct dido_single));

    pdm->dm_sock = -1;
    ret = pthread_mutex_init(&pdm->dm_lock, NULL);
    if (ret != 0) {
        free(pdm); pdm = NULL;
        fprintf(stderr, "Error, failed to initialize mutex: %d\n", ret);
        fflush(stderr);
        return pdm;
    }

    mbver = getenv("DIDO_MODBUS_VERBOSE");
    if (mbver && mbver[0] == '1')
        pdm->dm_verbose = 1;

    return pdm;
}

int dido_modbus_opentcp(struct dido_modbus * dido, const char * hostaddr, int portno)
{
    dido->dm_ctx = modbus_new_tcp(hostaddr, portno);
    dido->dm_map = modbus_mapping_new(WOOLINK_DIDO_MAX, 0, WOOLINK_DIDO_MAX, 0);

    if (dido->dm_ctx == NULL || dido->dm_map == NULL) {
        fprintf(stderr, "Error, failed to initialize modbus context or data-mapping: %p, %p\n",
            dido->dm_ctx, dido->dm_map);
        fflush(stderr);
        return -1;
    }

    dido->dm_sock = modbus_tcp_listen(dido->dm_ctx, NB_CONNECTION);
    if (dido->dm_sock == -1) {
        fputs("Error, failed to get listening socket!\n", stderr);
        fflush(stderr);
        return -1;
    }

    return 0;
}

void dido_modbus_free(struct dido_modbus * dido)
{
    int ret;
    if (dido->dm_thread != (pthread_t) 0ul) {
        void * retval = NULL;
        pthread_kill(dido->dm_thread, SIGINT);
        pthread_join(dido->dm_thread, &retval);
        dido->dm_thread = (pthread_t) 0ul;
    }

    ret = pthread_mutex_destroy(&dido->dm_lock);
    if (ret != 0) {
        fprintf(stderr, "Error, failed to destroy mutex lock: %d\n", ret);
        fflush(stderr);
    }

    if (dido->dm_sock != -1) {
        close(dido->dm_sock);
        dido->dm_sock = -1;
    }

    if (dido->dm_ctx != NULL) {
        modbus_free(dido->dm_ctx);
        dido->dm_ctx = NULL;
    }

    if (dido->dm_map != NULL) {
        modbus_mapping_free(dido->dm_map);
        dido->dm_map = NULL;
    }

    free(dido);
}

int dido_getval(struct dido_single * dios, int gnum)
{
    int idx, rval;
    uint32_t rc, di_value;

    rval = 0;
    for (idx = 0; idx < gnum; ++idx) {
        rc = VM1220_DI_GetValues(idx, 1, &di_value);
        if (rc != VM1220_IO_ERR_OK)
        {
            printf("VM1220_DI_GetValues() = %d\n", rc);
            rval--;
            break;
        }
        dios[idx].dio_val = di_value;
    }

    return rval;
}

int do_setval(uint8_t n, uint32_t val)
{
    uint32_t rc;

    if (val & 0x01)
    {
        val &= ~0x01;
    }
    else
    {
        val |= 0x1;
    }

    rc = VM1220_DO_SetValues(n, 1, val);
    if (rc != VM1220_IO_ERR_OK)
    {
        printf("VM1220_DO_SetValues() = %d\n", rc);
        return -1;
    }
	//printf("D0_%d= %d\n",n ,val);
	return 0;
}

int dio_setval(uint8_t n, uint32_t val)
{
    uint32_t rc;
    uint32_t dio_mode = 1;

    rc = VM1220_DIO_SetModes(n, 1, dio_mode);
    if (rc != VM1220_IO_ERR_OK)
    {
        printf("VM1220_DIO_SetModes() = %d\n", rc);
        return -1;
    }

    dio_mode = 2;
    rc = VM1220_DIO_GetModes(n, 1, &dio_mode);
    if (rc != VM1220_IO_ERR_OK)
    {
        printf("VM1220_DIO_GetModes() = %d\n", rc);
        return -1;
    }

    if (dio_mode == 1)
    {
        if (val & 0x01)
        {
            val &= ~0x01;
        }
        else
        {
            val |= 0x1;
        }
    
        rc = VM1220_DIO_SetValues(n, 1, val);
        if (rc != VM1220_IO_ERR_OK)
        {
            printf("VM1220_DIO_SetValues() = %d\n", rc);
            return -1;
        }
    }else
    {
        return -1;
    }
    //printf("DIO_%d = %d\n", n, val);
    return 0;
}
