/* * Copyright (c) 2020 PHYTEC Messtechnik GmbH * Copyright (c) 2021 Nordic Semiconductor ASA * * SPDX-License-Identifier: Apache-2.0 */ #include #include #include #include #include LOG_MODULE_REGISTER(tcp_gateway, LOG_LEVEL_INF); #define MODBUS_TCP_PORT 502 static struct modbus_adu tmp_adu; static int backend; const static struct modbus_iface_param backend_param = { .mode = MODBUS_MODE_RTU, .rx_timeout = 50000, .serial = { .baud = 19200, .parity = UART_CFG_PARITY_NONE, }, }; #define MODBUS_NODE DT_COMPAT_GET_ANY_STATUS_OKAY(zephyr_modbus_serial) static int init_backend_iface(void) { const char bend_name[] = {DEVICE_DT_NAME(MODBUS_NODE)}; backend = modbus_iface_get_by_name(bend_name); if (backend < 0) { LOG_ERR("Failed to get iface index for %s", bend_name); return -ENODEV; } return modbus_init_client(backend, backend_param); } static int modbus_tcp_reply(int client, struct modbus_adu *adu) { uint8_t header[MODBUS_MBAP_AND_FC_LENGTH]; modbus_raw_put_header(adu, header); if (send(client, header, sizeof(header), 0) < 0) { return -errno; } if (send(client, adu->data, adu->length, 0) < 0) { return -errno; } return 0; } static int modbus_tcp_connection(int client) { uint8_t header[MODBUS_MBAP_AND_FC_LENGTH]; int rc; int data_len; rc = recv(client, header, sizeof(header), MSG_WAITALL); if (rc <= 0) { return rc == 0 ? -ENOTCONN : -errno; } LOG_HEXDUMP_DBG(header, sizeof(header), "h:>"); modbus_raw_get_header(&tmp_adu, header); data_len = tmp_adu.length; rc = recv(client, tmp_adu.data, data_len, MSG_WAITALL); if (rc <= 0) { return rc == 0 ? -ENOTCONN : -errno; } LOG_HEXDUMP_DBG(tmp_adu.data, tmp_adu.length, "d:>"); rc = modbus_raw_backend_txn(backend, &tmp_adu); if (rc == -ENOTSUP || rc == -ENODEV) { LOG_WRN("Backend interface error: %d", rc); } return modbus_tcp_reply(client, &tmp_adu); } int main(void) { int serv; struct sockaddr_in bind_addr; static int counter; if (init_backend_iface()) { LOG_ERR("Modbus initialization failed"); return 0; } serv = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (serv < 0) { LOG_ERR("error: socket: %d", errno); return 0; } bind_addr.sin_family = AF_INET; bind_addr.sin_addr.s_addr = htonl(INADDR_ANY); bind_addr.sin_port = htons(MODBUS_TCP_PORT); if (bind(serv, (struct sockaddr *)&bind_addr, sizeof(bind_addr)) < 0) { LOG_ERR("error: bind: %d", errno); return 0; } if (listen(serv, 5) < 0) { LOG_ERR("error: listen: %d", errno); return 0; } LOG_INF("Started MODBUS TCP gateway example on port %d", MODBUS_TCP_PORT); while (1) { struct sockaddr_in client_addr; socklen_t client_addr_len = sizeof(client_addr); char addr_str[INET_ADDRSTRLEN]; int client; int rc; client = accept(serv, (struct sockaddr *)&client_addr, &client_addr_len); if (client < 0) { LOG_ERR("error: accept: %d", errno); continue; } inet_ntop(client_addr.sin_family, &client_addr.sin_addr, addr_str, sizeof(addr_str)); LOG_INF("Connection #%d from %s", counter++, addr_str); do { rc = modbus_tcp_connection(client); } while (!rc); close(client); LOG_INF("Connection from %s closed, errno %d", addr_str, rc); } return 0; }