|
|
@@ -0,0 +1,390 @@
|
|
|
+#include <stdio.h>
|
|
|
+#include <unistd.h>
|
|
|
+#include <modbus.h>
|
|
|
+#include <string.h>
|
|
|
+#include <errno.h>
|
|
|
+#include <stdlib.h>
|
|
|
+#include <math.h>
|
|
|
+#include <sys/select.h>
|
|
|
+#include <sys/socket.h>
|
|
|
+#include <arpa/inet.h>
|
|
|
+#include <netinet/in.h>
|
|
|
+
|
|
|
+#define NB_REGS 120
|
|
|
+#define NB_CONNECTION 5
|
|
|
+#define IEM3155_ADDRESS 1 // Modbus RTU slave address for iEM3155
|
|
|
+#define METER_OR_GATEWAY_IP_ADDRESS "10.0.1.100"
|
|
|
+#define METER_OR_GATEWAY_PORT "502"
|
|
|
+#define TRANSLATOR_IP_ADDRESS "10.0.1.2"
|
|
|
+
|
|
|
+#define MODBUS_SET_INT32_TO_INT16_FRONIUS(tab_int16, index, value) \
|
|
|
+ do { \
|
|
|
+ ((int16_t *) (tab_int16))[(index) + 1] = (int16_t) ((value) >> 16); \
|
|
|
+ ((int16_t *) (tab_int16))[(index)] = (int16_t) (value); \
|
|
|
+ } while (0)
|
|
|
+
|
|
|
+int stringModbusCopy(char * destination,char * source, int n){ // Custom method to write string in the right format for Modbus
|
|
|
+ // Copy even characters
|
|
|
+ for(int i = 0; i < n; i+=2){
|
|
|
+ destination[i + 1] = source[i];
|
|
|
+ }
|
|
|
+ // Copy odd characters
|
|
|
+ for(int i = 1; i < n; i+=2){
|
|
|
+ destination[i - 1] = source[i];
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+static int server_socket = -1;
|
|
|
+static modbus_mapping_t *mb_mapping_sunspec;
|
|
|
+static modbus_t *ctx2; // Context for requests from GEN24
|
|
|
+
|
|
|
+static void close_sigint(int dummy)
|
|
|
+{
|
|
|
+ if (server_socket != -1) {
|
|
|
+ close(server_socket);
|
|
|
+ }
|
|
|
+ modbus_free(ctx2);
|
|
|
+ modbus_mapping_free(mb_mapping_sunspec);
|
|
|
+
|
|
|
+ exit(dummy);
|
|
|
+}
|
|
|
+
|
|
|
+int main()
|
|
|
+{
|
|
|
+ printf("Begin\n");
|
|
|
+ int ret;
|
|
|
+ int rc;
|
|
|
+ int header_length;
|
|
|
+ uint8_t *query;
|
|
|
+ uint8_t nb_retry = 0;
|
|
|
+ modbus_t *ctx; // Context for requests to iEM3155
|
|
|
+ uint16_t dest [NB_REGS];
|
|
|
+ uint16_t reg_address;
|
|
|
+ uint16_t nb_registers;
|
|
|
+ uint16_t tempTab [2];
|
|
|
+ float current_ph1, current_ph2, current_ph3, current_total, apower_ph1, apower_ph2, apower_ph3, apower_total, apower_max, apPower_total, rpower_total, pf;
|
|
|
+ int64_t activeEnergyImport, activeEnergyExport;
|
|
|
+ fd_set refset;
|
|
|
+ fd_set rdset;
|
|
|
+ /* Maximum file descriptor number */
|
|
|
+ int fdmax;
|
|
|
+ int master_socket;
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ //Reader preparation
|
|
|
+ ctx = modbus_new_tcp_pi(METER_OR_GATEWAY_IP_ADDRESS, METER_OR_GATEWAY_PORT);
|
|
|
+ if (ctx == NULL) {
|
|
|
+ perror("Unable to create the libmodbus context\n");
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+
|
|
|
+ modbus_set_response_timeout(ctx, 1, 0);
|
|
|
+
|
|
|
+ ret = modbus_set_slave(ctx, IEM3155_ADDRESS);
|
|
|
+ if(ret < 0){
|
|
|
+ perror("modbus_set_slave error\n");
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+ ret = modbus_connect(ctx);
|
|
|
+ if(ret < 0){
|
|
|
+ perror("modbus_connect error\n");
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+
|
|
|
+ // Receiver preparation
|
|
|
+ ctx2 = modbus_new_tcp_pi(TRANSLATOR_IP_ADDRESS, "502"); // You have to use port TCP/502 here, because the GEN24 doesn't appreciate otherwise
|
|
|
+ if (ctx2 == NULL) {
|
|
|
+ perror("Unable to create the libmodbus context\n");
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+ query = malloc(MODBUS_TCP_MAX_ADU_LENGTH);
|
|
|
+
|
|
|
+ ret = modbus_set_slave(ctx2, 1);
|
|
|
+ if(ret < 0){
|
|
|
+ perror("modbus_set_slave error\n");
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+
|
|
|
+ server_socket = modbus_tcp_pi_listen(ctx2, NB_CONNECTION);
|
|
|
+ if (server_socket == -1) {
|
|
|
+ perror("Unable to listen\n");
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+ signal(SIGINT, close_sigint);
|
|
|
+
|
|
|
+ /* Clear the reference set of socket */
|
|
|
+ FD_ZERO(&refset);
|
|
|
+ /* Add the server socket */
|
|
|
+ FD_SET(server_socket, &refset);
|
|
|
+
|
|
|
+ /* Keep track of the max file descriptor */
|
|
|
+ fdmax = server_socket;
|
|
|
+
|
|
|
+ //mb_mapping = modbus_mapping_new_start_address(0,0,0,0,0,50002,0,0); //
|
|
|
+ mb_mapping_sunspec = modbus_mapping_new_start_address(0,0,0,0,40000,178,0,0);
|
|
|
+
|
|
|
+ // Static Sunspec Values
|
|
|
+ mb_mapping_sunspec->tab_registers[0] = 0x5375; // Sunspec ID
|
|
|
+ mb_mapping_sunspec->tab_registers[1] = 0x6e53; // Sunspec ID
|
|
|
+ mb_mapping_sunspec->tab_registers[2] = 1; // Sunspec ID
|
|
|
+ mb_mapping_sunspec->tab_registers[3] = 65; // Length of Sunspec model meter common
|
|
|
+ stringModbusCopy((char *) &mb_mapping_sunspec->tab_registers[4], "Schneider Electric", 18); // Manufacturer name
|
|
|
+ stringModbusCopy((char *) &mb_mapping_sunspec->tab_registers[20], "iEM3155", 7); // Meter product name
|
|
|
+ stringModbusCopy((char *) &mb_mapping_sunspec->tab_registers[36], "Utility", 7); // Meter name (test)
|
|
|
+ stringModbusCopy((char *) &mb_mapping_sunspec->tab_registers[44], "1.3.007", 7); // SW version
|
|
|
+ stringModbusCopy((char *) &mb_mapping_sunspec->tab_registers[52], "0123456789", 10); // Serial number
|
|
|
+ mb_mapping_sunspec->tab_registers[68] = 1; // Modbus address
|
|
|
+ mb_mapping_sunspec->tab_registers[69] = 203; // Meter type (203 = Three phases + Neutral)
|
|
|
+ mb_mapping_sunspec->tab_registers[70] = 105; // Length of Sunspec model ac_meter
|
|
|
+
|
|
|
+ // Static power factor
|
|
|
+ mb_mapping_sunspec->tab_registers[75] = -3; // Current scale factor (dynamic)
|
|
|
+ mb_mapping_sunspec->tab_registers[84] = -1; // Voltage scale factor
|
|
|
+ mb_mapping_sunspec->tab_registers[86] = -2; // Frequency scale factor
|
|
|
+ mb_mapping_sunspec->tab_registers[91] = 0; // Active power scale factor (dynamic)
|
|
|
+ mb_mapping_sunspec->tab_registers[96] = 0; // Apparent power scale factor (dynamic)
|
|
|
+ mb_mapping_sunspec->tab_registers[101] = 0; // Reactive power scale factor (dynamic)
|
|
|
+ mb_mapping_sunspec->tab_registers[106] = -1; // Power factor scale factor
|
|
|
+ mb_mapping_sunspec->tab_registers[123] = 0; // Active energy scale factor
|
|
|
+
|
|
|
+ mb_mapping_sunspec->tab_registers[70] = 105; // Length of Sunspec model ac_meter
|
|
|
+
|
|
|
+ mb_mapping_sunspec->tab_registers[176] = 0xFFFF; // End of model ac_meter
|
|
|
+ mb_mapping_sunspec->tab_registers[177] = 0; // End of model ac_meter
|
|
|
+
|
|
|
+ // Not implemented registers
|
|
|
+ mb_mapping_sunspec->tab_registers[93] = 0xFFFF; // Apparent power phase 1
|
|
|
+ mb_mapping_sunspec->tab_registers[94] = 0xFFFF; // Apparent power phase 2
|
|
|
+ mb_mapping_sunspec->tab_registers[95] = 0xFFFF; // Apparent power phase 3
|
|
|
+ mb_mapping_sunspec->tab_registers[98] = 0xFFFF; // Reactive power phase 1
|
|
|
+ mb_mapping_sunspec->tab_registers[99] = 0xFFFF; // Reactive power phase 2
|
|
|
+ mb_mapping_sunspec->tab_registers[100] = 0xFFFF; // Reactive power phase 3
|
|
|
+ mb_mapping_sunspec->tab_registers[103] = 0xFFFF; // Power factor phase 1
|
|
|
+ mb_mapping_sunspec->tab_registers[104] = 0xFFFF; // Power factor phase 2
|
|
|
+ mb_mapping_sunspec->tab_registers[105] = 0xFFFF; // Power factor phase 3
|
|
|
+ mb_mapping_sunspec->tab_registers[140] = 0x8000; // Apparent energy scale factor (not implemented)
|
|
|
+ mb_mapping_sunspec->tab_registers[173] = 0x8000; // Reactive energy scale factor (not implemented)
|
|
|
+
|
|
|
+ header_length = modbus_get_header_length(ctx2);
|
|
|
+
|
|
|
+ for (;;) {
|
|
|
+ rdset = refset;
|
|
|
+ if (select(fdmax + 1, &rdset, NULL, NULL, NULL) == -1) {
|
|
|
+ perror("Server select() failure.");
|
|
|
+ close_sigint(1);
|
|
|
+ }
|
|
|
+
|
|
|
+ /* Run through the existing connections looking for data to be
|
|
|
+ * read */
|
|
|
+ for (master_socket = 0; master_socket <= fdmax; master_socket++) {
|
|
|
+ if (!FD_ISSET(master_socket, &rdset)) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ if (master_socket == server_socket) {
|
|
|
+ /* A client is asking a new connection */
|
|
|
+ socklen_t addrlen;
|
|
|
+ struct sockaddr_in clientaddr;
|
|
|
+ int newfd;
|
|
|
+
|
|
|
+ /* Handle new connections */
|
|
|
+ addrlen = sizeof(clientaddr);
|
|
|
+ memset(&clientaddr, 0, sizeof(clientaddr));
|
|
|
+ newfd = accept(server_socket, (struct sockaddr *) &clientaddr, &addrlen);
|
|
|
+ if (newfd == -1) {
|
|
|
+ perror("Server accept() error");
|
|
|
+ } else {
|
|
|
+ FD_SET(newfd, &refset);
|
|
|
+
|
|
|
+ if (newfd > fdmax) {
|
|
|
+ /* Keep track of the maximum */
|
|
|
+ fdmax = newfd;
|
|
|
+ }
|
|
|
+ printf("New connection from %s:%d on socket %d\n",
|
|
|
+ inet_ntoa(clientaddr.sin_addr),
|
|
|
+ clientaddr.sin_port,
|
|
|
+ newfd);
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ modbus_set_socket(ctx2, master_socket);
|
|
|
+ rc = modbus_receive(ctx2, query);
|
|
|
+ if (rc > 0) {
|
|
|
+ if (query[header_length] == 0x03) {
|
|
|
+ //Read holding registers
|
|
|
+ reg_address = (uint16_t) MODBUS_GET_INT16_FROM_INT8(query, header_length + 1);
|
|
|
+ nb_registers = (uint16_t) MODBUS_GET_INT16_FROM_INT8(query, header_length + 3);
|
|
|
+ //printf("Request received. Address : %d, nb registers : %d\n", reg_address, nb_registers);
|
|
|
+ if((reg_address >= 40071 && reg_address < 40107) || ((reg_address + nb_registers) >= 40071 && (reg_address + nb_registers) < 40108) || (reg_address < 40071 && (reg_address + nb_registers) >= 40108)) { // Request dynamic registers (realtime data (V, I, PF, W...)), so we have to update registers
|
|
|
+ //if(reg_address >= 40071 && (reg_address + nb_registers) < 40179) { // Request dynamic registers, so we have to update registers
|
|
|
+ //printf("Realtime data update\n");
|
|
|
+ ret = modbus_read_registers(ctx, 2999, 112, dest); // Request realtime data (V, I, PF, W...)
|
|
|
+ if(ret < 0){
|
|
|
+ if(nb_retry < 10){
|
|
|
+ printf("Error number : %d\n", errno);
|
|
|
+ perror("modbus_read_regs error (Realtime registers)\n");
|
|
|
+ nb_retry++;
|
|
|
+ } else {
|
|
|
+ printf("Error number : %d\n", errno);
|
|
|
+ perror("modbus_read_regs error (Realtime registers)\n");
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ nb_retry = 0;
|
|
|
+ }
|
|
|
+ // Current
|
|
|
+ current_ph1 = modbus_get_float_abcd(&dest[0]);
|
|
|
+ current_ph2 = modbus_get_float_abcd(&dest[2]);
|
|
|
+ current_ph3 = modbus_get_float_abcd(&dest[4]);
|
|
|
+ current_total = current_ph1 + current_ph2 + current_ph3;
|
|
|
+ //printf("Phase 1 current : %f\n", current_ph1);
|
|
|
+ if(current_ph1 > 32.5 || current_ph1 < -32.5 || current_ph2 > 32.5 || current_ph2 < -32.5 || current_ph3 > 32.5 || current_ph3 < -32.5 || current_total > 32.5 || current_total < -32.5){
|
|
|
+ mb_mapping_sunspec->tab_registers[75] = -2; // Current scale factor (dynamic)
|
|
|
+ mb_mapping_sunspec->tab_registers[71] = (int16_t) (100 * current_total);
|
|
|
+ mb_mapping_sunspec->tab_registers[72] = (int16_t) (100 * current_ph1);
|
|
|
+ mb_mapping_sunspec->tab_registers[73] = (int16_t) (100 * current_ph2);
|
|
|
+ mb_mapping_sunspec->tab_registers[74] = (int16_t) (100 * current_ph3);
|
|
|
+ } else {
|
|
|
+ mb_mapping_sunspec->tab_registers[75] = -3; // Current scale factor (dynamic)
|
|
|
+ mb_mapping_sunspec->tab_registers[71] = (int16_t) (1000 * current_total);
|
|
|
+ mb_mapping_sunspec->tab_registers[72] = (int16_t) (1000 * current_ph1);
|
|
|
+ mb_mapping_sunspec->tab_registers[73] = (int16_t) (1000 * current_ph2);
|
|
|
+ mb_mapping_sunspec->tab_registers[74] = (int16_t) (1000 * current_ph3);
|
|
|
+ }
|
|
|
+ // L-N Voltage
|
|
|
+ mb_mapping_sunspec->tab_registers[76] = (int16_t) (10 * modbus_get_float_abcd(&dest[36])); // L-N Voltage (avg)
|
|
|
+ //printf("L-N Voltage : %d\n", (int16_t) (10 * modbus_get_float_abcd(&dest[36])));
|
|
|
+ mb_mapping_sunspec->tab_registers[77] = (int16_t) (10 * modbus_get_float_abcd(&dest[28])); // L-N Voltage ph1
|
|
|
+ mb_mapping_sunspec->tab_registers[78] = (int16_t) (10 * modbus_get_float_abcd(&dest[30])); // L-N Voltage ph2
|
|
|
+ mb_mapping_sunspec->tab_registers[79] = (int16_t) (10 * modbus_get_float_abcd(&dest[32])); // L-N Voltage ph3
|
|
|
+
|
|
|
+ // L-L Voltage
|
|
|
+ mb_mapping_sunspec->tab_registers[80] = (int16_t) (10 * modbus_get_float_abcd(&dest[26])); // L-L Voltage (avg)
|
|
|
+ //printf("L-L Voltage : %d\n", (int16_t) (10 * modbus_get_float_abcd(&dest[26])));
|
|
|
+ mb_mapping_sunspec->tab_registers[81] = (int16_t) (10 * modbus_get_float_abcd(&dest[20])); // L1-L2 Voltage
|
|
|
+ mb_mapping_sunspec->tab_registers[82] = (int16_t) (10 * modbus_get_float_abcd(&dest[22])); // L2-L3 Voltage
|
|
|
+ mb_mapping_sunspec->tab_registers[83] = (int16_t) (10 * modbus_get_float_abcd(&dest[24])); // L3-L1 Voltage
|
|
|
+
|
|
|
+ // Frequency
|
|
|
+ mb_mapping_sunspec->tab_registers[85] = (int16_t) (100 * modbus_get_float_abcd(&dest[110]));
|
|
|
+ //printf("Frequency : %d\n", (int16_t) (100 * modbus_get_float_abcd(&dest[110])));
|
|
|
+
|
|
|
+ // Active power
|
|
|
+ apower_ph1 = modbus_get_float_abcd(&dest[54]);
|
|
|
+ apower_ph2 = modbus_get_float_abcd(&dest[56]);
|
|
|
+ apower_ph3 = modbus_get_float_abcd(&dest[58]);
|
|
|
+ apower_total = modbus_get_float_abcd(&dest[60]);
|
|
|
+ apower_max = fmaxf(fabsf(apower_ph1),fmaxf(fabsf(apower_ph2),fmaxf(fabsf(apower_ph3),fabsf(apower_total))));
|
|
|
+ //printf("Active Power : %f\n", apower_total);
|
|
|
+
|
|
|
+ if(apower_max > 32.5){
|
|
|
+ mb_mapping_sunspec->tab_registers[91] = 1; // Active power scale factor (dynamic)
|
|
|
+ mb_mapping_sunspec->tab_registers[87] = (int16_t) (100 * apower_total);
|
|
|
+ mb_mapping_sunspec->tab_registers[88] = (int16_t) (100 * apower_ph1);
|
|
|
+ mb_mapping_sunspec->tab_registers[89] = (int16_t) (100 * apower_ph2);
|
|
|
+ mb_mapping_sunspec->tab_registers[90] = (int16_t) (100 * apower_ph3);
|
|
|
+ } else {
|
|
|
+ mb_mapping_sunspec->tab_registers[91] = 0; // Active power scale factor (dynamic)
|
|
|
+ mb_mapping_sunspec->tab_registers[87] = (int16_t) (1000 * apower_total);
|
|
|
+ mb_mapping_sunspec->tab_registers[88] = (int16_t) (1000 * apower_ph1);
|
|
|
+ mb_mapping_sunspec->tab_registers[89] = (int16_t) (1000 * apower_ph2);
|
|
|
+ mb_mapping_sunspec->tab_registers[90] = (int16_t) (1000 * apower_ph3);
|
|
|
+ }
|
|
|
+
|
|
|
+ // Apparent power (sum)
|
|
|
+ apPower_total = modbus_get_float_abcd(&dest[76]);
|
|
|
+ //printf("Apparent Power : %f\n", modbus_get_float_abcd(&dest[76]));
|
|
|
+ if(fabsf(apPower_total) > 32.6){
|
|
|
+ mb_mapping_sunspec->tab_registers[96] = 1; // Apparent power scale factor (dynamic)
|
|
|
+ mb_mapping_sunspec->tab_registers[92] = (int16_t) (100 * apPower_total);
|
|
|
+ } else {
|
|
|
+ mb_mapping_sunspec->tab_registers[96] = 0; // Apparent power scale factor (dynamic)
|
|
|
+ mb_mapping_sunspec->tab_registers[92] = (int16_t) (1000 * apPower_total);
|
|
|
+ }
|
|
|
+ // Reactive power (sum)
|
|
|
+ rpower_total = modbus_get_float_abcd(&dest[68]);
|
|
|
+ //printf("Reactive Power : %f\n", modbus_get_float_abcd(&dest[68]));
|
|
|
+ if(fabsf(rpower_total) > 32.6){
|
|
|
+ mb_mapping_sunspec->tab_registers[101] = 1; // Reactive power scale factor (dynamic)
|
|
|
+ mb_mapping_sunspec->tab_registers[97] = (int16_t) (100 * rpower_total);
|
|
|
+ } else {
|
|
|
+ mb_mapping_sunspec->tab_registers[101] = 0; // Reactive power scale factor (dynamic)
|
|
|
+ mb_mapping_sunspec->tab_registers[97] = (int16_t) (1000 * rpower_total);
|
|
|
+ }
|
|
|
+ // Power factor (sum)
|
|
|
+ pf = modbus_get_float_abcd(&dest[84]);
|
|
|
+ if(pf<-1){ // Calculation according to iEM3155 manual and Sunspec specification. It might be erronous.
|
|
|
+ pf = - 2 - pf;
|
|
|
+ } else if(pf < 0){
|
|
|
+ pf = -pf;
|
|
|
+ } else if(pf < 1){
|
|
|
+ pf = -pf;
|
|
|
+ } else {
|
|
|
+ pf = 2 - pf;
|
|
|
+ }
|
|
|
+ mb_mapping_sunspec->tab_registers[102] = (int16_t) (1000 * pf);
|
|
|
+ //printf("Power factor : %d\n", (int16_t) (1000 * pf));
|
|
|
+ //printf("Power factor raw : %f\n",pf);
|
|
|
+ }
|
|
|
+ if((reg_address >= 40107 && reg_address < 40142) || ((reg_address + nb_registers) > 40107 && (reg_address + nb_registers) < 40142) || (reg_address < 40107 && (reg_address + nb_registers) >= 40142)) { // Request dynamic registers (energy registers (Wh)), so we have to update registers
|
|
|
+ //printf("Energy data update\n");
|
|
|
+ ret = modbus_read_registers(ctx, 3203, 8, dest); // Request energy registers (Wh)
|
|
|
+ if(ret < 0){
|
|
|
+ if(nb_retry < 10){
|
|
|
+ printf("Error number : %d\n", errno);
|
|
|
+ perror("modbus_read_regs error (Energy registers)\n");
|
|
|
+ nb_retry++;
|
|
|
+ } else {
|
|
|
+ printf("Error number : %d\n", errno);
|
|
|
+ perror("modbus_read_regs error (Energy registers)\n");
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ nb_retry = 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ // Active energy exported
|
|
|
+ activeEnergyExport = MODBUS_GET_INT64_FROM_INT16(dest, 4);
|
|
|
+ //printf("Active Energy Export : %d\n", activeEnergyExport);
|
|
|
+ // Active energy imported
|
|
|
+ activeEnergyImport = MODBUS_GET_INT64_FROM_INT16(dest, 0);
|
|
|
+ //printf("Active Energy Import : %d\n", activeEnergyImport);
|
|
|
+ if(fmax((double) (activeEnergyExport),(double) (activeEnergyImport)) > 4294967295) {
|
|
|
+ mb_mapping_sunspec->tab_registers[123] = 1; // Active energy scale factor
|
|
|
+ MODBUS_SET_INT32_TO_INT16(mb_mapping_sunspec->tab_registers, 107, (uint32_t) (activeEnergyExport / 10));
|
|
|
+ MODBUS_SET_INT32_TO_INT16(mb_mapping_sunspec->tab_registers, 115, (uint32_t) (activeEnergyImport / 10));
|
|
|
+ } else {
|
|
|
+ mb_mapping_sunspec->tab_registers[123] = 0; // Active energy scale factor
|
|
|
+ MODBUS_SET_INT32_TO_INT16(mb_mapping_sunspec->tab_registers, 107, (uint32_t) (activeEnergyExport));
|
|
|
+ MODBUS_SET_INT32_TO_INT16(mb_mapping_sunspec->tab_registers, 115, (uint32_t) (activeEnergyImport));
|
|
|
+ }
|
|
|
+ }
|
|
|
+ rc = modbus_reply(ctx2, query, rc, mb_mapping_sunspec);
|
|
|
+ if (rc == -1) {
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } else if (rc == -1) {
|
|
|
+ /* This example server in ended on connection closing or
|
|
|
+ * any errors. */
|
|
|
+ printf("Connection closed on socket %d\n", master_socket);
|
|
|
+ close(master_socket);
|
|
|
+
|
|
|
+ /* Remove from reference set */
|
|
|
+ FD_CLR(master_socket, &refset);
|
|
|
+
|
|
|
+ if (master_socket == fdmax) {
|
|
|
+ fdmax--;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ //modbus_close(ctx);
|
|
|
+ //modbus_free(ctx);
|
|
|
+ free(query);
|
|
|
+ modbus_close(ctx2);
|
|
|
+ modbus_free(ctx2);
|
|
|
+
|
|
|
+}
|