//13.08.2024 modbus master 2 modbu_t: 1 - ПЛК; 2 -МВ210
//ПЛК110-30 собирает через modbus master по RS-485 значения температуры (float) с 1-го канала МВ110-224 и
// передает их по сети TCP через modbus slave на ПК (ctx и 192.168.13.12).
//Программа CoDeSys в ПЛК110-30 получает значение float канала 1 в регистры 0 и 1 modbus master
// (индекы регистров в МВ110-224 4 и 5) и копирует их в регистры 1 и 0 modbus slave для передачи по сети
// TCP на компьютер.
//МВ210-101 непосредственно передает данные каналов 1 и 3 по сети TCP (ctx2 и 192.168.13.11).
//


#include "dlfcn.h"
#include <stdio.h>
#include "modbus.h"
#include <iostream>
#include <cstring>
#include <unistd.h>

using namespace std;


typedef modbus_t* modbus_tp;

typedef const char* (*p_modbus_strerror)(int);
typedef modbus_tp (*p_modbus_new_tcp)(const char*,int);
typedef void (*p_modbus_free)(modbus_t*);
typedef int (*p_modbus_connect)(modbus_t*);
typedef void (*p_modbus_close)(modbus_t*);
typedef int (*p_modbus_flush)(modbus_t*);
typedef int (*p_modbus_set_slave)(modbus_t*, int);
typedef int (*p_modbus_read_registers)(modbus_t*, int, int, uint16_t*);

p_modbus_strerror pmodbus_strerror;
p_modbus_new_tcp pmodbus_new_tcp;
p_modbus_free pmodbus_free;
p_modbus_connect pmodbus_connect;
p_modbus_close pmodbus_close;
p_modbus_flush pmodbus_flush;
p_modbus_set_slave pmodbus_set_slave;
p_modbus_read_registers pmodbus_read_registers;

int runFlag;

//Ctrl-C обработчик
#ifndef _WIN32
static void f_abort_handler(int sig)
{
    runFlag=0;
}
#endif



int main(void)
{
    cout << "krym52.ru" << endl << endl;
    cout << "Example: modbus master of 2 contexts ctx and ctx2\n to get data from 3 channels of 2 devices\n\n";

    usleep(4000000);

//Обработчик Ctrl-C
#ifndef _WIN32
    struct sigaction sa;
    memset(&sa, 0, sizeof(sa));
    /* В ОС Linux устанавливаем свой обработчик на сигнал закрытия,
       чтобы завершить сбор корректно */
    sa.sa_handler = f_abort_handler;
    sigaction(SIGTERM, &sa, NULL);
    sigaction(SIGINT, &sa, NULL);
    sigaction(SIGABRT, &sa, NULL);
#endif

    void* handle=dlopen("libmodbus.so.5",RTLD_NOW);   //.5.1.0
    pmodbus_new_tcp=(p_modbus_new_tcp)dlsym(handle,"modbus_new_tcp");
    pmodbus_free=(p_modbus_free)dlsym(handle,"modbus_free");
    pmodbus_connect=(p_modbus_connect)dlsym(handle,"modbus_connect");
    pmodbus_close=(p_modbus_close)dlsym(handle,"modbus_close");
    pmodbus_flush=(p_modbus_flush)dlsym(handle,"modbus_flush");
    pmodbus_set_slave=(p_modbus_set_slave)dlsym(handle,"modbus_set_slave");
    pmodbus_strerror=(p_modbus_strerror)dlsym(handle,"modbus_strerror");
    pmodbus_read_registers=(p_modbus_read_registers)dlsym(handle,"modbus_read_registers");
//    const int REMOTE_ID = 1;
    modbus_t *ctx;
    modbus_t *ctx2;
    uint16_t tab_reg[100];
    memset(tab_reg,0,sizeof(tab_reg));

    ctx = (*pmodbus_new_tcp)("192.168.13.12", 502);
    if (ctx == NULL) {
        fprintf(stderr, "1 Unable to create the libmodbus context\n");
        dlclose(handle);
        return -1;
    }

    int iRes;
    iRes=(*pmodbus_connect)(ctx);
    cout << "1 connect: iRes=" << iRes << " errno=" << errno << endl;
    if (iRes == -1) {
        fprintf(stderr, "Connection failed: %s\n", (*pmodbus_strerror)(errno));
        (*pmodbus_free)(ctx);
        dlclose(handle);
        return -2;
    }

    (*pmodbus_set_slave)(ctx, 1);

    ctx2 = (*pmodbus_new_tcp)("192.168.13.11", 502);
    if (ctx2 == NULL) {
        fprintf(stderr, "2 Unable to create the libmodbus context\n");
        (*pmodbus_close)(ctx);
        (*pmodbus_free)(ctx);
        dlclose(handle);
        return -3;
    }

    iRes=(*pmodbus_connect)(ctx2);
    cout << "2 connect: iRes=" << iRes << " errno=" << errno << endl;
    if (iRes == -1) {
        fprintf(stderr, "Connection failed: %s\n", (*pmodbus_strerror)(errno));
        (*pmodbus_close)(ctx);
        (*pmodbus_free)(ctx);
        (*pmodbus_free)(ctx2);
        dlclose(handle);
        return -1;
    }

    (*pmodbus_set_slave)(ctx2, 2);

    int iCycle=0;
    runFlag=1;
    while (runFlag) {
        iCycle++;
        cout << iCycle << "******\n";

        iRes=(*pmodbus_read_registers)(ctx,0,2,tab_reg);
        cout << "1 read_registers: iRes=" << iRes << " errno=" << errno << " " << (*pmodbus_strerror)(errno) << endl;
        float z1=*(float*)&(tab_reg[0]);
        for(int i=0;i<2;i++)
            printf("%.4X ",tab_reg[i]);
        cout << endl;
        iRes=(*pmodbus_read_registers)(ctx2,4000,8,tab_reg);
        cout << "2 read_registers: iRes=" << iRes << " errno=" << errno << " " << (*pmodbus_strerror)(errno) << endl;
        float z2=*(float*)&(tab_reg[0]);
        float z3=*(float*)&(tab_reg[6]);
        for(int i=0;i<8;i++)
            printf("%.4X ",tab_reg[i]);
        cout << endl;
        cout << z1 << " " << z2 << " " << z3 << endl;
        usleep(2000000);
    }


//    (*pmodbus_flush)(ctx);
    (*pmodbus_close)(ctx2);
    (*pmodbus_free)(ctx2);
    (*pmodbus_close)(ctx);
    (*pmodbus_free)(ctx);

    dlclose(handle);

    return 0;

}

