TCP/IP based digital io controller for operating DigitalsOuts and reading DigitalIns.

Dependencies:   EthernetInterface NetworkAPI mbed-rtos mbed

Fork of NetRelais by Roy van Dam

Revision:
10:22d49341340c
Child:
11:e5375ae5c8c3
diff -r a4c85bea2d77 -r 22d49341340c controller.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/controller.cpp	Thu Jul 19 11:13:50 2012 +0000
@@ -0,0 +1,310 @@
+/**
+ * Copyright (c) 2012, Roy van Dam <roy@vandam-innovations.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "controller.hpp"
+
+Controller::~Controller()
+{
+    this->stop();
+}
+
+int
+Controller::start(int port, int max_pending)
+{
+    if (this->_network.server.open() < 0) {
+        printf("Could not open server socket.\n\r");
+        return -1;
+    }
+    
+    if (this->_network.server.bind(port) < 0) {
+        printf("Could not bind server socket to port '%d'.\n\r", port);
+        return -1;
+    }
+    
+    if (this->_network.server.listen(max_pending) < 0) {
+        printf("Could not put server socket into listening mode.\n\r");
+        return -1;
+    }
+    
+    return 0;
+}
+
+int
+Controller::stop()
+{
+    this->_network.server.close();
+    this->_network.client.close();
+}
+
+int
+Controller::dispatch()
+{
+    int result = 0;
+    network::Buffer buffer(256);
+
+    while (this->_network.server.getStatus() == network::Socket::Listening) {
+        if (this->_network.server.accept(this->_network.client) < 0) {
+            printf("Warning: failed to accept connection.\n\r");
+            continue;
+        }
+                        
+        printf("Client connected '%s:%d'.\n\r",
+            this->_network.client.getRemoteEndpoint().getAddress().toString().c_str(),
+            this->_network.client.getRemoteEndpoint().getPort());
+        
+        while (this->_network.client.getStatus() == network::Socket::Connected) {
+            buffer.flush();
+            
+            switch (this->_network.client.read(buffer)) {
+                case -1:
+                    printf("Warning: failed to read data from client.\n\r");
+                    break;
+                
+                case 0:
+                    printf("Connection closed.\n\r");
+                    break;
+                
+                default:
+                    printf("Received %d bytes.\n\r%s\r", buffer.length(), (char *)buffer.pointer());
+                    
+                    // Parse command
+                    result = this->_parseCommand(buffer);
+    
+                    // Format reply code
+                    buffer.flush();
+                    buffer.setLength(std::snprintf(
+                        (char *)buffer.pointer(), buffer.size(),
+                        "e;%i;", result));
+                   
+                    if (buffer.length() < 4) {
+                        printf("Warning: failed to format error reply.\n\r");
+                        continue;
+                    }
+                    
+                    if (this->_network.client.write(buffer) < 0) {
+                        printf("Warning: failed to reply.\n\r");
+                    }
+                    continue;
+            }
+            
+            this->_network.client.shutdown();
+            this->_network.client.close();
+        }
+    } 
+}
+
+int
+Controller::_parseCommand(network::Buffer &buffer)
+{
+    int index = 0;
+    network::Buffer response(32);
+    char *cursor = (char *)buffer.pointer();
+    
+    enum Controller::ParseState state = Controller::S_Init;
+    enum Controller::Command command = Controller::C_None;
+    
+    while (cursor != NULL) {
+        switch (state) {
+            case Controller::S_Init: {
+                if (((*cursor) == 'r') && ((*(cursor + 1)) == ';')) {
+                    command = Controller::C_Read;
+                    state = Controller::S_Index;
+                    cursor += 2;
+                    continue;
+                }
+                
+                if (((*cursor) == 'w') && ((*(cursor + 1)) == ';')) {
+                    command = Controller::C_Write;
+                    state = Controller::S_Index;
+                    cursor += 2;
+                    continue;
+                }
+                
+                return Controller::E_InvalidCommand;
+            }
+            
+            case Controller::S_Index: {
+                if (std::sscanf(cursor, "%d;", &index) != 1) {
+                    return Controller::E_InvalidFormat;
+                }
+                
+                char *offset = std::strchr(cursor, ';');
+                if (offset == NULL) {
+                    return Controller::E_InvalidFormat;
+                }
+                
+                cursor = offset + 1;
+                state = Controller::S_Execute;
+                continue;
+            }
+            
+            case Controller::S_Execute: {
+                switch (command) {
+                    case Controller::C_Read: {
+                        DigitalIn *input = this->getInput(index);
+                        if (input == NULL) {
+                            return Controller::E_UnknownIndex;
+                        }
+                        
+                        response.setLength(std::snprintf(
+                            (char *)response.pointer(), response.size(),
+                            "r;%d;%d;", index, input->read()));
+                       
+                        if (response.length() < 6) {
+                            printf("Warning: failed to format reply.\n\r");
+                            return Controller::E_Internal;
+                        }
+                        
+                        if (this->_network.client.write(response) < 0) {
+                            printf("Warning: failed to reply on read request.\n\r");
+                            return Controller::E_Internal;
+                        }
+                        
+                        if ((*cursor) == 0 || (*(cursor + 1)) == 0) {
+                            return 0;
+                        }
+                        
+                        command = Controller::C_None;
+                        state = Controller::S_Init;
+                        continue;
+                    }
+                    
+                    case Controller::C_Write: {
+                        DigitalOut *output = this->getOutput(index);
+                        if (output == NULL) {
+                            return Controller::E_UnknownIndex;
+                        }
+                    
+                        int value = 0;
+                        if (std::sscanf(cursor, "%d;", &value) != 1) {
+                            return Controller::E_InvalidFormat;
+                        }
+                        
+                        char *offset = std::strchr(cursor, ';');
+                        if (offset == NULL) {
+                            return Controller::E_InvalidFormat;
+                        }                         
+                        cursor = offset + 1;
+                        
+                        if (value != 0 && value != 1) {
+                            return Controller::E_InvalidValue;
+                        }
+                        
+                        output->write(value);
+                        
+                        if ((*cursor) == 0 || (*(cursor + 1)) == 0) {
+                            return 0;
+                        }
+                        
+                        command = Controller::C_None;
+                        state = Controller::S_Init;
+                        continue;
+                    }
+                }
+            }
+        }
+    }
+    
+    return 0;
+}
+
+
+int
+Controller::addOutput(DigitalOut *output)
+{
+    if (this->_outputExists(output)) {
+        return false;
+    }
+    
+    this->_io.output.push_back(output);
+    return true;
+}
+
+int
+Controller::addInput(DigitalIn *input)
+{
+    if (this->_inputExists(input)) {
+        return false;
+    }
+    
+    this->_io.input.push_back(input);
+    return true;
+}
+
+DigitalOut *
+Controller::getOutput(size_t index)
+{
+    Controller::DigitalOutputList::iterator output;
+    output = this->_io.output.begin();
+    output = output + (int)index;
+    
+    if (output >= this->_io.output.end()) {
+        return NULL;
+    }
+    
+    return (*output);
+}
+
+DigitalIn *
+Controller::getInput(size_t index)
+{
+    DigitalInputList::iterator input;
+    input = this->_io.input.begin();
+    input = input + (int)index;
+    
+    if (input >= this->_io.input.end()) {
+        return NULL;
+    }
+    
+    return (*input);
+}
+
+bool
+Controller::_outputExists(DigitalOut *output)
+{
+    DigitalOutputList::iterator entry;
+    entry = this->_io.output.begin();
+    for (;entry != this->_io.output.end(); entry++) {
+        if (output == (*entry)) {
+            return true;
+        }
+    }
+    
+    return false;
+}
+
+bool
+Controller::_inputExists(DigitalIn *input)
+{
+    Controller::DigitalInputList::iterator entry;
+    entry = this->_io.input.begin();
+    for (;entry != this->_io.input.end(); entry++) {
+        if (input == (*entry)) {
+            return true;
+        }
+    }
+    
+    return false;
+}
\ No newline at end of file