ModBusTCP with some fixes
ModBus-TCP.cpp@5:1bf121618c2f, 2020-12-03 (annotated)
- Committer:
- kcherneha_aitheon
- Date:
- Thu Dec 03 14:01:33 2020 +0000
- Revision:
- 5:1bf121618c2f
- Parent:
- 3:ebea8e061ae6
fixed error jump to case label [-fpermissive]
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
okini3939 | 0:d18dff347122 | 1 | /* Copyright (C) 2013 Hiroshi Suga, MIT License |
okini3939 | 0:d18dff347122 | 2 | * |
okini3939 | 0:d18dff347122 | 3 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software |
okini3939 | 0:d18dff347122 | 4 | * and associated documentation files (the "Software"), to deal in the Software without restriction, |
okini3939 | 0:d18dff347122 | 5 | * including without limitation the rights to use, copy, modify, merge, publish, distribute, |
okini3939 | 0:d18dff347122 | 6 | * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is |
okini3939 | 0:d18dff347122 | 7 | * furnished to do so, subject to the following conditions: |
okini3939 | 0:d18dff347122 | 8 | * |
okini3939 | 0:d18dff347122 | 9 | * The above copyright notice and this permission notice shall be included in all copies or |
okini3939 | 0:d18dff347122 | 10 | * substantial portions of the Software. |
okini3939 | 0:d18dff347122 | 11 | * |
okini3939 | 0:d18dff347122 | 12 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING |
okini3939 | 0:d18dff347122 | 13 | * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
okini3939 | 0:d18dff347122 | 14 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, |
okini3939 | 0:d18dff347122 | 15 | * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
okini3939 | 0:d18dff347122 | 16 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
okini3939 | 0:d18dff347122 | 17 | */ |
okini3939 | 0:d18dff347122 | 18 | |
gulchi | 2:fcd20e2cd110 | 19 | #include "ModBus-TCP.h" |
okini3939 | 0:d18dff347122 | 20 | |
gulchi | 2:fcd20e2cd110 | 21 | Modbus * Modbus::_inst; |
okini3939 | 0:d18dff347122 | 22 | |
gulchi | 2:fcd20e2cd110 | 23 | Modbus::Modbus () { |
okini3939 | 0:d18dff347122 | 24 | _inst = this; |
okini3939 | 0:d18dff347122 | 25 | memset(_state, 0, sizeof(_state)); |
okini3939 | 0:d18dff347122 | 26 | _handler_count = 0; |
okini3939 | 0:d18dff347122 | 27 | } |
okini3939 | 0:d18dff347122 | 28 | |
gulchi | 3:ebea8e061ae6 | 29 | int Modbus::start (EthernetInterface *ns, int port) { |
okini3939 | 0:d18dff347122 | 30 | int i; |
okini3939 | 0:d18dff347122 | 31 | |
dgriffin65 | 1:b724fdb741e7 | 32 | m_ns = ns; |
dgriffin65 | 1:b724fdb741e7 | 33 | |
gulchi | 2:fcd20e2cd110 | 34 | for (i = 0; i < MODBUS_MAX_CLIENTS; i ++) { |
gulchi | 3:ebea8e061ae6 | 35 | // _state[i].buf = new CircBuffer<char>(MODBUS_BUF_SIZE); |
gulchi | 2:fcd20e2cd110 | 36 | _state[i].thread = new Thread(osPriorityNormal, MODBUS_STACK_SIZE); |
dgriffin65 | 1:b724fdb741e7 | 37 | _state[i].client = new TCPSocket(); |
dgriffin65 | 1:b724fdb741e7 | 38 | _state[i].thread->start(callback(child, (void*)i)); |
okini3939 | 0:d18dff347122 | 39 | } |
dgriffin65 | 1:b724fdb741e7 | 40 | |
gulchi | 2:fcd20e2cd110 | 41 | #ifdef MODBUS_ENABLE_CLOSER |
gulchi | 2:fcd20e2cd110 | 42 | _state[MODBUS_MAX_CLIENTS].thread = new Thread(closer, (void*)MODBUS_MAX_CLIENTS, osPriorityNormal, 128); |
gulchi | 2:fcd20e2cd110 | 43 | _state[MODBUS_MAX_CLIENTS].client = new TCPSocket(m_ns); |
okini3939 | 0:d18dff347122 | 44 | #endif |
okini3939 | 0:d18dff347122 | 45 | |
dgriffin65 | 1:b724fdb741e7 | 46 | _server.open(m_ns); |
okini3939 | 0:d18dff347122 | 47 | _server.bind(port); |
dgriffin65 | 1:b724fdb741e7 | 48 | _server.set_blocking(true); |
gulchi | 3:ebea8e061ae6 | 49 | _server.listen(MODBUS_MAX_CLIENTS); |
gulchi | 2:fcd20e2cd110 | 50 | _daemon = new Thread(osPriorityNormal, MODBUS_STACK_SIZE); |
gulchi | 2:fcd20e2cd110 | 51 | _daemon->start(Modbus::daemon); |
okini3939 | 0:d18dff347122 | 52 | return 0; |
okini3939 | 0:d18dff347122 | 53 | } |
okini3939 | 0:d18dff347122 | 54 | |
gulchi | 2:fcd20e2cd110 | 55 | void Modbus::daemon () { |
gulchi | 2:fcd20e2cd110 | 56 | Modbus *modbus = Modbus::getInstance(); |
okini3939 | 0:d18dff347122 | 57 | int i, t = 0; |
okini3939 | 0:d18dff347122 | 58 | |
gulchi | 3:ebea8e061ae6 | 59 | |
okini3939 | 0:d18dff347122 | 60 | for (;;) { |
gulchi | 3:ebea8e061ae6 | 61 | //DBG("Wait for new connection... child %i",t); |
okini3939 | 0:d18dff347122 | 62 | if (t >= 0) { |
gulchi | 2:fcd20e2cd110 | 63 | if (modbus->_server.accept(modbus->_state[t].client) == 0) { |
okini3939 | 0:d18dff347122 | 64 | INFO("accept %d\r\n", t); |
gulchi | 3:ebea8e061ae6 | 65 | modbus->_state[t].thread->signal_set(0x1); |
okini3939 | 0:d18dff347122 | 66 | } |
okini3939 | 0:d18dff347122 | 67 | } else { |
okini3939 | 0:d18dff347122 | 68 | #ifdef HTTPD_ENABLE_CLOSER |
gulchi | 2:fcd20e2cd110 | 69 | if (modbus->_server.accept(modbus->_state[MODBUS_MAX_CLIENTS].client) == 0) { |
okini3939 | 0:d18dff347122 | 70 | INFO("accept x\r\n"); |
gulchi | 3:ebea8e061ae6 | 71 | modbus->_state[MODBUS_MAX_CLIENTS].thread->signal_set(0x1); |
okini3939 | 0:d18dff347122 | 72 | } |
okini3939 | 0:d18dff347122 | 73 | #endif |
okini3939 | 0:d18dff347122 | 74 | } |
okini3939 | 0:d18dff347122 | 75 | |
okini3939 | 0:d18dff347122 | 76 | t = -1; |
gulchi | 2:fcd20e2cd110 | 77 | for (i = 0; i < MODBUS_MAX_CLIENTS; i ++) { |
gulchi | 3:ebea8e061ae6 | 78 | //DBG("Child %i in State : %u", i, modbus->_state[i].thread->get_state()); |
gulchi | 3:ebea8e061ae6 | 79 | if ( modbus->_state[i].thread->get_state() == Thread::WaitingThreadFlag) { |
okini3939 | 0:d18dff347122 | 80 | if (t < 0) t = i; // next empty thread |
okini3939 | 0:d18dff347122 | 81 | } |
okini3939 | 0:d18dff347122 | 82 | } |
okini3939 | 0:d18dff347122 | 83 | } |
okini3939 | 0:d18dff347122 | 84 | } |
okini3939 | 0:d18dff347122 | 85 | |
gulchi | 2:fcd20e2cd110 | 86 | void Modbus::child (void const *arg) { |
gulchi | 3:ebea8e061ae6 | 87 | Modbus *modbus = Modbus::getInstance(); |
okini3939 | 0:d18dff347122 | 88 | int id = (int)arg; |
okini3939 | 0:d18dff347122 | 89 | int i, n; |
gulchi | 3:ebea8e061ae6 | 90 | char buf[MODBUS_BUF_SIZE]; |
okini3939 | 0:d18dff347122 | 91 | |
okini3939 | 0:d18dff347122 | 92 | for (;;) { |
gulchi | 3:ebea8e061ae6 | 93 | //DBG("child %i waiting for connection",id); |
gulchi | 3:ebea8e061ae6 | 94 | Thread::signal_wait(0x1); |
gulchi | 3:ebea8e061ae6 | 95 | |
gulchi | 3:ebea8e061ae6 | 96 | |
gulchi | 3:ebea8e061ae6 | 97 | |
gulchi | 3:ebea8e061ae6 | 98 | INFO("Connection from client on child %i", id); |
dgriffin65 | 1:b724fdb741e7 | 99 | // INFO("Connection from %s\r\n", httpd->_state[id].client->get_ip_address()); |
dgriffin65 | 1:b724fdb741e7 | 100 | |
gulchi | 3:ebea8e061ae6 | 101 | modbus->_state[id].client->set_blocking(true); |
gulchi | 3:ebea8e061ae6 | 102 | modbus->_state[id].client->set_timeout(15000); |
gulchi | 3:ebea8e061ae6 | 103 | time_t t1 = time(NULL); |
okini3939 | 0:d18dff347122 | 104 | for (;;) { |
dgriffin65 | 1:b724fdb741e7 | 105 | //if (! httpd->_state[id].client->is_connected()) break; |
gulchi | 3:ebea8e061ae6 | 106 | modbus->_state[id].client->set_blocking(true); |
gulchi | 3:ebea8e061ae6 | 107 | modbus->_state[id].client->set_timeout(15000); |
gulchi | 2:fcd20e2cd110 | 108 | n = modbus->_state[id].client->recv(buf, sizeof(buf)); |
dgriffin65 | 1:b724fdb741e7 | 109 | |
dgriffin65 | 1:b724fdb741e7 | 110 | if (n < 0 ) { |
gulchi | 3:ebea8e061ae6 | 111 | printf("Modbus::child breaking n = %d\r\n", n); |
dgriffin65 | 1:b724fdb741e7 | 112 | break; |
dgriffin65 | 1:b724fdb741e7 | 113 | } |
gulchi | 3:ebea8e061ae6 | 114 | |
gulchi | 3:ebea8e061ae6 | 115 | if( n > 0 ) { // We received something |
gulchi | 3:ebea8e061ae6 | 116 | |
gulchi | 3:ebea8e061ae6 | 117 | t1 = time(NULL); |
gulchi | 3:ebea8e061ae6 | 118 | |
gulchi | 3:ebea8e061ae6 | 119 | //DBG("Recv %d bytes Content: %x", n, buf) |
gulchi | 3:ebea8e061ae6 | 120 | |
gulchi | 3:ebea8e061ae6 | 121 | modbus->recvData(id, buf, n); |
okini3939 | 0:d18dff347122 | 122 | } |
gulchi | 3:ebea8e061ae6 | 123 | |
gulchi | 3:ebea8e061ae6 | 124 | if(abs((int)(time(NULL) - t1))> 15) { |
gulchi | 3:ebea8e061ae6 | 125 | DBG("Timeout in child %i",id); |
gulchi | 3:ebea8e061ae6 | 126 | break; |
gulchi | 3:ebea8e061ae6 | 127 | } |
gulchi | 3:ebea8e061ae6 | 128 | |
okini3939 | 0:d18dff347122 | 129 | } |
okini3939 | 0:d18dff347122 | 130 | |
gulchi | 2:fcd20e2cd110 | 131 | modbus->_state[id].client->close(); // Needs to bere moved |
gulchi | 3:ebea8e061ae6 | 132 | INFO("Closed client connection"); |
dgriffin65 | 1:b724fdb741e7 | 133 | //INFO("Close %s\r\n", httpd->_state[id].client->get_ip_address()); |
okini3939 | 0:d18dff347122 | 134 | } |
okini3939 | 0:d18dff347122 | 135 | } |
okini3939 | 0:d18dff347122 | 136 | |
gulchi | 2:fcd20e2cd110 | 137 | void Modbus::closer (void const *arg) { |
gulchi | 2:fcd20e2cd110 | 138 | Modbus *modbus = Modbus::getInstance(); |
okini3939 | 0:d18dff347122 | 139 | int id = (int)arg; |
okini3939 | 0:d18dff347122 | 140 | |
okini3939 | 0:d18dff347122 | 141 | for (;;) { |
okini3939 | 0:d18dff347122 | 142 | Thread::signal_wait(1); |
okini3939 | 0:d18dff347122 | 143 | |
gulchi | 2:fcd20e2cd110 | 144 | modbus->_state[id].client->close(); |
dgriffin65 | 1:b724fdb741e7 | 145 | INFO("Closed client connection\r\n"); |
dgriffin65 | 1:b724fdb741e7 | 146 | //INFO("Close %s\r\n", httpd->_state[id].client->get_ip_address()); |
okini3939 | 0:d18dff347122 | 147 | } |
okini3939 | 0:d18dff347122 | 148 | } |
okini3939 | 0:d18dff347122 | 149 |