ModBusTCP with some fixes

ModBus-TCP.cpp

Committer:
gulchi
Date:
2017-06-30
Revision:
3:ebea8e061ae6
Parent:
2:fcd20e2cd110

File content as of revision 3:ebea8e061ae6:

/* Copyright (C) 2013 Hiroshi Suga, MIT License
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
 * and associated documentation files (the "Software"), to deal in the Software without restriction,
 * including without limitation the rights to use, copy, modify, merge, publish, distribute,
 * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or
 * substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
 * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include "ModBus-TCP.h"

Modbus * Modbus::_inst;

Modbus::Modbus () {
    _inst = this;
    memset(_state, 0, sizeof(_state));
    _handler_count = 0;
}

int Modbus::start (EthernetInterface *ns, int port) {
    int i;

    m_ns = ns;
    
    for (i = 0; i < MODBUS_MAX_CLIENTS; i ++) {
       // _state[i].buf = new CircBuffer<char>(MODBUS_BUF_SIZE);
        _state[i].thread = new Thread(osPriorityNormal, MODBUS_STACK_SIZE);
        _state[i].client = new TCPSocket();
        _state[i].thread->start(callback(child, (void*)i));
    }
    
#ifdef MODBUS_ENABLE_CLOSER
    _state[MODBUS_MAX_CLIENTS].thread = new Thread(closer, (void*)MODBUS_MAX_CLIENTS, osPriorityNormal, 128);
    _state[MODBUS_MAX_CLIENTS].client = new TCPSocket(m_ns);
#endif

    _server.open(m_ns);
    _server.bind(port);
    _server.set_blocking(true);
    _server.listen(MODBUS_MAX_CLIENTS);
    _daemon = new Thread(osPriorityNormal, MODBUS_STACK_SIZE);
    _daemon->start(Modbus::daemon);
    return 0;
}

void Modbus::daemon () {
    Modbus *modbus = Modbus::getInstance();
    int i, t = 0;

    
    for (;;) {
        //DBG("Wait for new connection... child %i",t);
        if (t >= 0) {
            if (modbus->_server.accept(modbus->_state[t].client) == 0) {
                INFO("accept %d\r\n", t);
                modbus->_state[t].thread->signal_set(0x1);
            }
        } else {
#ifdef HTTPD_ENABLE_CLOSER
            if (modbus->_server.accept(modbus->_state[MODBUS_MAX_CLIENTS].client) == 0) {
                INFO("accept x\r\n");
                modbus->_state[MODBUS_MAX_CLIENTS].thread->signal_set(0x1);
            }
#endif
        }

        t = -1;
        for (i = 0; i < MODBUS_MAX_CLIENTS; i ++) {
            //DBG("Child %i in State : %u", i, modbus->_state[i].thread->get_state());
            if ( modbus->_state[i].thread->get_state() == Thread::WaitingThreadFlag) {
                if (t < 0) t = i; // next empty thread
            }
        }
    }
}

void Modbus::child (void const *arg) {
    Modbus *modbus = Modbus::getInstance();
    int id = (int)arg;
    int i, n;
    char buf[MODBUS_BUF_SIZE];

    for (;;) {
        //DBG("child %i waiting for connection",id);
        Thread::signal_wait(0x1);
        
       

        INFO("Connection from client on child %i", id);
//      INFO("Connection from %s\r\n", httpd->_state[id].client->get_ip_address());

        modbus->_state[id].client->set_blocking(true);
        modbus->_state[id].client->set_timeout(15000);
        time_t t1 = time(NULL);
        for (;;) {
            //if (! httpd->_state[id].client->is_connected()) break;
            modbus->_state[id].client->set_blocking(true);
            modbus->_state[id].client->set_timeout(15000);
            n = modbus->_state[id].client->recv(buf, sizeof(buf));
            
            if (n < 0 ) {
                printf("Modbus::child breaking n = %d\r\n", n);
                break;
            }
            
            if( n > 0 ) { // We received something
                
                t1 = time(NULL);
            
                //DBG("Recv %d bytes Content: %x", n, buf)
            
                modbus->recvData(id, buf, n);
            }
            
            if(abs((int)(time(NULL) - t1))> 15) {
                DBG("Timeout in child %i",id);
                break;    
            }
            
        }

        modbus->_state[id].client->close(); // Needs to bere moved 
        INFO("Closed client connection");
        //INFO("Close %s\r\n", httpd->_state[id].client->get_ip_address());
    }
}

void Modbus::closer (void const *arg) {
    Modbus *modbus = Modbus::getInstance();
    int id = (int)arg;

    for (;;) {
        Thread::signal_wait(1);

        modbus->_state[id].client->close();
        INFO("Closed client connection\r\n");
        //INFO("Close %s\r\n", httpd->_state[id].client->get_ip_address());
    }
}