//26.08.2024 1936-modbusSlave-1 пример modbus slave с передачей значений REAL в holding registers
//22.08.2024 1936-modbusSlave-1 пример modbus slave для одного modbus master
// Просто выдает поступающие от modbus master команды
// Чуток упростил пример с сайта
// https://cpp.hotexamples.com/examples/-/-/modbus_tcp_listen/cpp-modbus_tcp_listen-function-examples.html
//
 

#include "dlfcn.h"
#include <iostream>
#include <cstring>
#include <string>
#include "modbus.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*);
typedef int (*p_modbus_receive)(modbus_t*, uint8_t*);
typedef int (*p_modbus_reply)(modbus_t*,const uint8_t*,int,modbus_mapping_t*);
typedef modbus_mapping_t* (*p_modbus_mapping_new)(int, int, int, int);
typedef int (*p_modbus_tcp_listen)(modbus_t*, int);
typedef int (*p_modbus_set_debug)(modbus_t*, int);
typedef int (*p_modbus_tcp_accept)(modbus_t*, int*);
typedef void (*p_modbus_mapping_free)(modbus_mapping_t*);
typedef void (*p_modbus_set_error_recovery)(modbus_t*, int);

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;
p_modbus_receive pmodbus_receive;
p_modbus_reply pmodbus_reply;
p_modbus_mapping_new pmodbus_mapping_new;
p_modbus_tcp_listen pmodbus_tcp_listen;
p_modbus_set_debug pmodbus_set_debug;
p_modbus_tcp_accept pmodbus_tcp_accept;
p_modbus_mapping_free pmodbus_mapping_free;
p_modbus_set_error_recovery pmodbus_set_error_recovery;



int main(int argc, char *argv[])
{
	cout << "krym52.ru\n\n";
	cout << "Пример modbus slave. Чуток упростил пример из\n";
	cout << "https://cpp.hotexamples.com/examples/-/-/modbus_tcp_listen/cpp-modbus_tcp_listen-function-examples.html\n";

	void* handle=dlopen("libmodbus.so.5.1.0",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");
	pmodbus_receive=(p_modbus_receive)dlsym(handle,"modbus_receive");
	pmodbus_reply=(p_modbus_reply)dlsym(handle,"modbus_reply");
	pmodbus_mapping_new=(p_modbus_mapping_new)dlsym(handle,"modbus_mapping_new");
	pmodbus_set_debug=(p_modbus_set_debug)dlsym(handle,"modbus_set_debug");
	pmodbus_tcp_listen=(p_modbus_tcp_listen)dlsym(handle,"modbus_tcp_listen");
	pmodbus_tcp_accept=(p_modbus_tcp_accept)dlsym(handle,"modbus_tcp_accept");
	pmodbus_mapping_free=(p_modbus_mapping_free)dlsym(handle,"modbus_mapping_free");
	pmodbus_set_error_recovery=(p_modbus_set_error_recovery)dlsym(handle,"modbus_set_error_recovery");

	modbus_t *m;
	modbus_mapping_t *mb_mapping;
	
	uint8_t *q;
	int header_length;
	int socket=-1;
	int rc;

	m = (*pmodbus_new_tcp)("127.0.0.1", 1502);	//127.0.0.1	192.168.1.148
	mb_mapping = (*pmodbus_mapping_new)(500, 500, 500, 500);
	if (mb_mapping == NULL) {
		printf("Failed to allocate the mapping: %i\n",errno);
		(*pmodbus_free)(m);
	return -1;
	}
	
	cout << mb_mapping->start_registers << " hold.reg.\n";

	q = (uint8_t*)malloc(MODBUS_TCP_MAX_ADU_LENGTH);

//	header_length = modbus_get_header_length(m);

	(*pmodbus_set_debug)(m, TRUE);
	(*pmodbus_set_error_recovery)(m, TRUE);
cout << "listen\n";
	socket = (*pmodbus_tcp_listen)(m, 1);
cout << "accept\n";
	(*pmodbus_tcp_accept)(m, &socket);

	int n=3;
	while (n) {
		cout << "receive\n";
		rc = (*pmodbus_receive)(m, q);
		if (rc < 0) {
			printf("modbus_receive() returned %d\n", rc);
			n--;
		} else {
			for(int i=0;i<rc;i++)
				printf("%.2x ", q[i]);
			cout << endl;
			cout << "reply\n";
			*(float*)(mb_mapping->tab_registers)=2.718281828;
			*(float*)(mb_mapping->tab_registers+2)=3.14159;
			(*pmodbus_reply)(m,q,rc,mb_mapping);
		}
	}
	
	(*pmodbus_mapping_free)(mb_mapping);
	(*pmodbus_close)(m);
	(*pmodbus_free)(m);

	dlclose(handle);
	
}
