//21.08.2024 1937-modbusTCP
//

#include "dlfcn.h"
#include <stdio.h>
#include "modbus.h"
#include <iostream>
#include <fstream>
#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;


ifstream fmTK;	//Файл настройки
int nCfg;       //Строка в файле настройки

string GetKeyVal2(string sKey);


int main(int argc,char* argv[])
{
    cout << "krym52.ru\n\n";
    cout << "Example modbus TCP master to read 2 REAL value.\n";
    cout << "Testing application for MV210-101 of OBEH with channels 1 and 3\n";
    cout << "Library libmodbus.so is used\n";
    cout << "Call with the only param. config file\n\n";
    sleep(2);

    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");

    modbus_t *ctx;
    uint16_t tab_reg[100];
    memset(tab_reg,0,sizeof(tab_reg));

    string sIP;     //IP modbus slave
    int port=502;   //порт modbus slave
    int iSlave;     //адрес modbus slave
    int adr0=0;     //начальный индекс регистров в modbus slave
    int nReg;       //число читаемых регистров
    int ofs1;       //индекс 1-го регстра WORD 1-го измерительного канала (REAL)
    int ofs2;       //индекс 1-го регстра WORD 2-го измерительного канала (REAL)

    fmTK.open(string(argv[1]),ios::in);
    string sVal;
    sVal=GetKeyVal2("IP");
    sIP=sVal;
    sVal=GetKeyVal2("port");
    port=stoi(sVal);
    sVal=GetKeyVal2("slave");
    iSlave=stoi(sVal);
    sVal=GetKeyVal2("adr0");
    adr0=stoi(sVal);
    sVal=GetKeyVal2("nReg");
    nReg=stoi(sVal);
    sVal=GetKeyVal2("ofs1");
    ofs1=stoi(sVal);
    sVal=GetKeyVal2("ofs2");
    ofs2=stoi(sVal);

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

    errno=0;

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

    for(int j=0;j<5;j++){
        iRes=(*pmodbus_read_registers)(ctx,adr0,nReg,tab_reg);
        cout << "read_registers: iRes=" << iRes << " errno=" << errno << " " << (*pmodbus_strerror)(errno) << endl;
        float z1=*(float*)&(tab_reg[ofs1]);
        float z2=*(float*)&(tab_reg[ofs2]);
        cout << z1 << " " << z2 << endl;

        for(int i=0;i<nReg;i++)
            printf("%.4X ",tab_reg[i]);

        cout << endl;

        usleep(200000);

    }	//for(int j

    (*pmodbus_close)(ctx);
    (*pmodbus_free)(ctx);

    dlclose(handle);

    return 0;
}


string GetKeyVal(string sKey);

//поиск по sKey
string GetKeyVal2(string sKey){
    string s;
    fmTK.seekg(0,ios::beg);
    nCfg=0;
    while(true){
        s=GetKeyVal(sKey);
        if(s=="eof")
            return "";
        if(s!="")
            return s;
    }
    return "";
}   //GetKeyVal2

string GetKeyVal(string sKey){
    string s;
    if(fmTK.eof())
        return "eof";
    getline(fmTK,s);
    if(s.length()>0){
        if(s.back()==13)    //if prepared in windows
            s.pop_back();
    }
    int i=s.find("//");
    if(i!=string::npos){
        if(i==0)
            return "";
        s=s.substr(0,i-1);
        while((s.length()>0)&&((s.back()==' ')||(s.back()=='\t')))
            s.pop_back();
    }
    nCfg++;
    i=s.find("=");
    if(i == string::npos)
        return "";
    if(s.substr(0,i) != sKey)
        return "";
    else{
        s=s.substr(i+1,s.length()-i);
        i=s.find("\"");
        if(i!=string::npos)
            s.replace(i,1,"");
        i=s.find("\"");
        if(i!=string::npos)
           s=s.substr(0,i);
        return s;
    }
}   //GetKeyVal

