Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependencies: NTPClient W5500Interface Watchdog device_configuration eeprom_flash mbed-rpc-nucleo mbed-rtos mbed
Fork of F103-Serial-to-Ethernet by
Revision 40:c966abbe2d62, committed 2016-06-16
- Comitter:
- olympux
- Date:
- Thu Jun 16 08:38:31 2016 +0000
- Parent:
- 39:083cf93121a9
- Child:
- 41:a50a534a2fbb
- Commit message:
- Working with a few issues:; - Added RPC AnalogIn, wdt reset when creating new object on PC_0; - Added creating RPC string but not tested yet
Changed in this revision
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/Formatter.cpp Thu Jun 16 08:38:31 2016 +0000
@@ -0,0 +1,187 @@
+#include "Formatter.h"
+#include "mbed.h"
+#include "RPCObjectManager.h"
+#include "EthernetInterface.h"
+
+const char *SIMPLE_HTML_CODE = "\
+<!DOCTYPE html>\
+<html>\
+<head>\
+<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\">\
+<title>TCP Server</title>\
+</head>\
+ <body>";
+
+
+const char* INTERACTIVE_HTML_CODE_1 = "\
+<!DOCTYPE html> \
+<html>\
+<head>\
+<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\">\
+<title>TCP Server</title>\
+<script type=\"text/javascript\">\
+var ip = \"%s\";\
+function submitCreateForm()\
+{\
+var list = document.getElementById(\"type\");\
+var type = list.options[list.selectedIndex].value;\
+var name = document.getElementById(\"name\").value;\
+if(name === \"\") \
+return;\
+var arg = document.getElementById(\"arg\").value;\
+var url;\
+if(arg === \"\") url = \"http://\" + ip + type + \"new?name=\" + name;\
+else url = \"http://\" + ip + type + \"new?arg=\" + arg + \"&name=\" + name;\
+location.href= url;\
+}\
+function submitCallFuncForm()\
+{\
+var command = document.getElementById(\"command\").value;\
+if(command === \"\") \
+return; \
+var tmp = command.split(\' \');\
+var url = tmp[0];\
+if(tmp.length > 1)\
+url += \"?\";\
+for(var i = 1; i < tmp.length; ++i)\
+{\
+url += \"arg\" + i + \"=\" + tmp[i];\
+if(i+1 < tmp.length)\
+url += \"&\";\
+}\
+location.href = url;\
+}\
+</script>\
+</head> \
+<body>";
+
+const char* INTERACTIVE_HTML_CODE_2 = "<h3>Create Object :</h3>\
+<form>\
+Type: <select id=\"type\">\
+<option value=\"/DigitalOut/\">DigitalOut</option>\
+<option value=\"/DigitalIn/\">DigitalIn</option>\
+<option value=\"/DigitalInOut/\">DigitalInOut</option>\
+<option value=\"/AnalogIn/\">AnalogIn</option>\
+<option value=\"/PwmOut/\">PwmOut</option>\
+<option value=\"/Timer/\">Timer</option>\
+</select><br>\
+name: <input type=\"text\" id=\"name\"><br>\
+arg(optional): <input type=\"text\" id=\"arg\">\
+<p><input type=\"button\" value=\"Create\" onclick=\"javascript:submitCreateForm();\"></p>\
+</form> \
+ \
+<h3>Call a function :</h3>\
+<p>Enter an RPC command.</p>\
+<form>\
+Command: <input type= \"text\" id=\"command\" maxlength=127><br>\
+<p><input type=\"button\" value=\"Send\" onclick=\"javascript:submitCallFuncForm();\"></p><br>\
+</form>\
+</body> \
+</html>";
+
+static char chunk[1024];
+
+Formatter::Formatter(int nb):
+currentChunk(0),
+nbChunk(nb)
+{
+}
+
+char* Formatter::get_page(char *reply)
+{
+ chunk[0] = '\0';
+
+ if(currentChunk < nbChunk)
+ {
+ get_chunk(currentChunk, reply);
+ currentChunk++;
+ }
+ else
+ currentChunk = 0;
+
+ return chunk;
+}
+
+void Formatter::get_chunk(const int c, char *reply)
+{
+ strcat(chunk, reply);
+}
+
+SimpleHTMLFormatter::SimpleHTMLFormatter():
+Formatter()
+{
+}
+
+void SimpleHTMLFormatter::get_chunk(const int c, char* reply)
+{
+ strcat(chunk, SIMPLE_HTML_CODE);
+
+ if(reply != NULL && strlen(reply) != 0)
+ {
+ strcat(chunk, "RPC reply : ");
+ strcat(chunk, reply);
+ }
+
+ if(!RPCObjectManager::instance().is_empty())
+ {
+ strcat(chunk, "<ul>");
+ for(std::list<char*>::iterator itor = RPCObjectManager::instance().begin();
+ itor != RPCObjectManager::instance().end();
+ ++itor)
+ {
+ strcat(chunk, "<li>");
+ strcat(chunk, *itor);
+ strcat(chunk, "</li>");
+ }
+ strcat(chunk, "</ul>");
+ }
+
+ strcat(chunk, "</body></html>");
+}
+
+InteractiveHTMLFormatter::InteractiveHTMLFormatter():
+Formatter(3)
+{
+}
+
+void InteractiveHTMLFormatter::get_chunk(const int c, char *reply)
+{
+ if(c == 0)
+ //sprintf(chunk, INTERACTIVE_HTML_CODE_1, EthernetInterface::getIPAddress());
+ sprintf(chunk, INTERACTIVE_HTML_CODE_1, eth.getIPAddress());
+
+ else if(c == 1)
+ {
+ if(reply != NULL && strlen(reply) != 0)
+ {
+ strcat(chunk, "RPC reply : ");
+ strcat(chunk, reply);
+ }
+ if(!RPCObjectManager::instance().is_empty())
+ {
+ strcat(chunk, "<p>Objects created :</p>");
+
+ strcat(chunk, "<ul>");
+ for(std::list<char*>::iterator itor = RPCObjectManager::instance().begin();
+ itor != RPCObjectManager::instance().end();
+ ++itor)
+ {
+ strcat(chunk, "<li>");
+ strcat(chunk, *itor);
+ strcat(chunk, " (<a href=\"http://");
+ //strcat(chunk, EthernetInterface::getIPAddress());
+ strcat(chunk, eth.getIPAddress());
+ strcat(chunk, "/");
+ strcat(chunk, *itor);
+ strcat(chunk, "/delete\">delete</a>)");
+ strcat(chunk, "</li>");
+ }
+ strcat(chunk, "</ul>");
+ }
+ strcat(chunk, " ");
+ }
+ else if(c == 2)
+ strcat(chunk, INTERACTIVE_HTML_CODE_2);
+}
+
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/Formatter.h Thu Jun 16 08:38:31 2016 +0000
@@ -0,0 +1,51 @@
+#ifndef FORMATTER
+#define FORMATTER
+
+#include "EthernetInterface.h"
+
+extern EthernetInterface eth;
+
+class Formatter
+{
+ public :
+
+ Formatter(int nbChunk = 1);
+
+ char* get_page(char *reply);
+
+ protected :
+
+ virtual void get_chunk(const int c, char *reply);
+
+ private :
+
+ int currentChunk;
+ int nbChunk;
+};
+
+class SimpleHTMLFormatter : public Formatter
+{
+ public :
+
+ SimpleHTMLFormatter();
+
+ protected :
+
+ virtual void get_chunk(const int c, char *reply);
+
+};
+
+class InteractiveHTMLFormatter : public Formatter
+{
+ public :
+
+ InteractiveHTMLFormatter();
+
+ protected :
+
+ virtual void get_chunk(const int c, char *reply);
+};
+
+
+#endif
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/HTTPServer.cpp Thu Jun 16 08:38:31 2016 +0000
@@ -0,0 +1,120 @@
+#include "HTTPServer.h"
+
+#define INVALID_FORMATTER "No valid formatter specified"
+
+bool cmp(char* a, char* b)
+{
+ return strcmp(a,b) < 0;
+}
+
+HTTPServer::HTTPServer(Formatter *f):
+socket(),
+handlers(&cmp),
+formatter(f),
+reply(),
+command()
+{
+}
+
+HTTPServer::~HTTPServer()
+{
+ for(std::map<char*, RequestHandler*>::iterator itor = handlers.begin();
+ itor != handlers.end();
+ ++itor)
+ delete itor->second;
+
+ if(formatter)
+ delete formatter;
+}
+
+bool HTTPServer::init(int port)
+{
+ socket.set_blocking(true);
+ if(socket.bind(port))
+ {
+ printf("Could not bind on port %d.\n", port);
+ return false;
+ }
+
+ if(socket.listen())
+ {
+ printf("Could not listen %d\n", port);
+ return false;
+ }
+
+ return true;
+}
+
+void HTTPServer::run()
+{
+ TCPSocketConnection c;
+ while(true)
+ {
+ while(socket.accept(c));
+ c.set_blocking(false, 1000);
+ while(c.is_connected())
+ {
+ char buffer[512];
+ int n = c.receive_all(buffer, sizeof(buffer)-1);
+ if(n == 0)
+ {
+ c.close();
+ break;
+ }
+ else if(n != -1)
+ {
+ printf("Received data\n");
+ buffer[n] = '\0';
+ handle_request(buffer);
+ if(formatter != NULL)
+ {
+ printf("Sending data...");
+ char *page = formatter->get_page(reply);
+ do
+ {
+ c.send(page, strlen(page)+1);
+ page = formatter->get_page(reply);
+ }while(strlen(page)>0);
+ printf("done\n");
+ }
+ else
+ c.send(INVALID_FORMATTER, strlen(INVALID_FORMATTER)+1);
+ }
+ else
+ printf("Error while receiving data\n");
+ }
+ }
+}
+
+void HTTPServer::handle_request(char *buffer)
+{
+ char *request_type = strtok(buffer, " ");
+ char *request = strtok(NULL, " ");
+
+ reply[0] = '\0';
+ if(!strcmp(request, "/"))
+ return;
+
+ if(!command.decode(request))
+ {
+ strcat(reply, "Malformed request");
+ return;
+ }
+
+ std::map<char*, RequestHandler*>::iterator itor = handlers.find(request_type);
+ if(itor == handlers.end())
+ {
+ strcat(reply, "No request handler found for this type of request.");
+ return;
+ }
+ if(itor->second != NULL)
+ itor->second->handle(command, reply);
+ else
+ strcat(reply, "Invalid request handler");
+}
+
+void HTTPServer::add_request_handler(char *name, RequestHandler* handler)
+{
+ handlers[name] = handler;
+}
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/HTTPServer.h Thu Jun 16 08:38:31 2016 +0000
@@ -0,0 +1,39 @@
+#ifndef HTTP_SERVER
+#define HTTP_SERVER
+
+#include <map>
+
+#include "mbed.h"
+#include "mbed_rpc.h"
+#include "RequestHandler.h"
+#include "Formatter.h"
+#include "EthernetInterface.h"
+#include "RPCCommand.h"
+
+
+class HTTPServer
+{
+ public :
+
+ HTTPServer(Formatter *f = new Formatter());
+ virtual ~HTTPServer();
+
+ bool init(int port);
+
+ void run();
+
+ void add_request_handler(char *name, RequestHandler* handler);
+
+ private :
+
+ void handle_request(char *buffer);
+
+ TCPSocketServer socket;
+ std::map<char*, RequestHandler*, bool(*)(char*, char*)> handlers;
+ Formatter *formatter;
+ char reply[RPC_MAX_STRING];
+ RPCCommand command;
+};
+
+#endif
+
--- a/README.md Tue Jun 14 21:25:04 2016 +0000 +++ b/README.md Thu Jun 16 08:38:31 2016 +0000 @@ -1,102 +1,12 @@ -# Features - -Forked of F103_NNIO_RPC rev36:3055e4 -Firmware for NNIO modules based on STM32F103RBT6 and W5500. - -- TCP/UDP server for controlling and monitoring using NNIO v2.0 and RPC protocols. -- UDP server for discovering and configuring. - -# Usage - -## Set RTC for timed Digital Ouputs - -Use TCP client or UDP to send configuration to the module: - -Set the current_time variable - -``` -/Time/write abcdef -``` - -where abcdef is time from 00:00am in seconds. - -Run RPC SetTime() function to execute set_current_time() to set current time to the current_time variable +Forked of RPC over HTTP server -``` -/SetTime/run x -``` - -## Set On/Off time for Digital Outputs - -``` -/do0OnTime/write abcdef -/do0OffTime/write abcdef -``` - -where abcdef is time in seconds, start from 00:00am. Check it by sending to read - -``` -/do0OnTime/read x -/do0OffTime/read x -``` - - -# Releases - -## v2.0.0 (04/06/2016) - -New features +------------------ +Modified but not commit yet: -- RPCVariable -- RPCFunction - -Improvements - -- Removed private mbed-rpc -- Updated to latest mbed-rtos, NTPClient, Watchdog, W5500Interface and mbed. - -Bug fixes - -- Had to compile from source as eeprom library failed when using the compiled mbed library - -## v1.1.1 (07/02/2015) - -Improvements - -- Updated RPC names - -## v1.1 (24/01/2015) - -New features - -- Process RPC-style command in tcp client, similar to TCP/UDP server. - -Improvements - -- Control command is able to be processed by both TCP and UDP. -- Use only one network output buffer for both RPC-style and NNIO protocols. -- Automatically reset after setting network configuration or setting TCP server for auto update mode. -- RPC object name is 16 chars max. - - -## v1.0 (06/01/2014) - -New features - -- RPC command replies as following object_name:reply_value - -Improvements - -- Modified: clean code in my_eeprom_funcs and main.cpp - -## v0.1 (29/12/2014) - -Initial - -- Imported F103_NNIO rev27:22f289beceb8 -- process_control_command() with return value. 0 if NNIO protocol or RPC protocol without reply; length of RPC outbut buffer; or -1 if RPC failed. -- TCP server now checks to return data to client. -- use device description instead of device config code in Discovery command. -- working with ConfigurationTool v2.0 and AlarmMonitoring v1.1. - - +1. Updated Formatter.c to use eth.getIPAddress() +2. Added AnalogIn + - to HTML code in Formatter.c + - to RPCType.c + +Tested working but creating RPC object AnalogIn at PC_0 caused watchdog resets +------------------- \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/RPCCommand.cpp Thu Jun 16 08:38:31 2016 +0000
@@ -0,0 +1,130 @@
+#include "RPCCommand.h"
+#include "mbed.h"
+#include "RPCType.h"
+
+
+RPCCommand::RPCCommand():
+cmd(),
+obj_name(NULL),
+func_name(NULL)
+{
+
+}
+
+bool RPCCommand::decode(char *buffer)
+{
+ if(buffer == NULL)
+ return false;
+ if(buffer[0] != '/')
+ return false;
+
+ ++buffer;
+ char *tmp = strchr(buffer ,'/');
+
+ if(tmp == NULL)
+ return false;
+ if(tmp == buffer)
+ return false;
+
+ tmp[0] = '\0';
+ obj_name = buffer;
+
+ buffer = tmp+1;
+
+ if(buffer[0] == '\0' || buffer[0] == '?')
+ return false;
+
+ func_name = buffer;
+
+ tmp = strchr(buffer, '?');
+ if(tmp != NULL)
+ {
+ if(tmp[1] == '\0')
+ return false;
+ tmp[0] = '\0';
+ }
+
+ cmd[0] = '\0';
+ strcat(cmd, "/");
+ strcat(cmd, obj_name);
+ strcat(cmd, "/");
+ strcat(cmd, func_name);
+
+ if(tmp == NULL)
+ return true;
+
+ buffer = tmp+1;
+ do
+ {
+ tmp = strchr(buffer, '&');
+
+ if(tmp != NULL)
+ {
+ if(tmp[1] == '\0' || buffer == tmp)
+ return false;
+ tmp[0] = '\0';
+ }
+
+ char *sep = strchr(buffer, '=');
+ if(sep == NULL)
+ return false;
+ if(sep == buffer)
+ return false;
+ if(sep[1] == '\0' || sep[1] == '&')
+ return false;
+
+ strcat(cmd, " ");
+ strcat(cmd, sep+1);
+
+ if(tmp != NULL)
+ buffer = tmp+1;
+ else
+ buffer = NULL;
+ }while(buffer);
+
+ return true;
+}
+
+
+
+char* RPCCommand::get_cmd() const
+{
+ return (char*)cmd;
+}
+
+RPC_COMMAND_TYPE RPCCommand::get_type() const
+{
+ if(!strcmp(func_name, "new") && RPCType::instance().is_supported_type(obj_name))
+ return CREATE;
+
+ RPC* r = RPC::lookup(obj_name);
+ if(r == NULL)
+ return INVALID;
+
+ if(!strcmp(func_name, "delete"))
+ return DELETE;
+
+ const struct rpc_method *methods = r->get_rpc_methods();
+ int i = 0;
+ while(methods[i].name != NULL)
+ {
+ if(!strcmp(func_name, methods[i].name))
+ {
+ return FUNCTION_CALL;
+ }
+ ++i;
+ }
+
+ return INVALID;
+}
+
+char* RPCCommand::get_obj_name() const
+{
+ return obj_name;
+}
+
+char* RPCCommand::get_func_name() const
+{
+ return func_name;
+}
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/RPCCommand.h Thu Jun 16 08:38:31 2016 +0000
@@ -0,0 +1,36 @@
+#ifndef RPCCOMMAND
+#define RPCCOMMAND
+
+#include <list>
+#include "mbed_rpc.h"
+
+enum RPC_COMMAND_TYPE { INVALID, CREATE, DELETE, FUNCTION_CALL };
+
+struct rpc_arg
+{
+ char *name;
+ char *val;
+};
+
+class RPCCommand
+{
+ public :
+
+ RPCCommand();
+
+ bool decode(char *buffer);
+
+ char* get_cmd() const;
+ RPC_COMMAND_TYPE get_type() const;
+ char* get_obj_name() const;
+ char* get_func_name() const;
+
+ private :
+
+ char cmd[RPC_MAX_STRING];
+ char* obj_name;
+ char* func_name;
+};
+
+#endif
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/RPCObjectManager.cpp Thu Jun 16 08:38:31 2016 +0000
@@ -0,0 +1,68 @@
+#include "RPCObjectManager.h"
+#include "mbed.h"
+
+RPCObjectManager& RPCObjectManager::instance()
+{
+ static RPCObjectManager om;
+ return om;
+}
+
+RPCObjectManager::RPCObjectManager():
+objects()
+{
+}
+
+RPCObjectManager::~RPCObjectManager()
+{
+ for(std::list<char*>::iterator itor = objects.begin();
+ itor != objects.end();
+ ++itor)
+ delete *itor;
+}
+
+void RPCObjectManager::store_object(char *obj_name)
+{
+ char *obj = new char[strlen(obj_name)+1];
+ strcpy(obj, obj_name);
+ obj[strlen(obj_name)] = '\0';
+ objects.push_back(obj);
+}
+
+void RPCObjectManager::remove_object(char *obj_name)
+{
+ for(std::list<char*>::iterator itor = objects.begin();
+ itor != objects.end();
+ ++itor)
+ if(!strcmp(obj_name, *itor))
+ {
+ delete *itor;
+ objects.erase(itor);
+ break;
+ }
+}
+
+bool RPCObjectManager::lookup_object(char *obj_name)
+{
+ for(std::list<char*>::iterator itor = objects.begin();
+ itor != objects.end();
+ ++itor)
+ if(!strcmp(obj_name, *itor))
+ return true;
+ return false;
+}
+
+bool RPCObjectManager::is_empty()
+{
+ return objects.empty();
+}
+
+std::list<char*>::iterator RPCObjectManager::begin()
+{
+ return objects.begin();
+}
+
+std::list<char*>::iterator RPCObjectManager::end()
+{
+ return objects.end();
+}
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/RPCObjectManager.h Thu Jun 16 08:38:31 2016 +0000
@@ -0,0 +1,29 @@
+#ifndef RPCOBJECTMANAGER
+#define RPCOBJECTMANAGER
+
+#include <list>
+
+class RPCObjectManager
+{
+ public :
+
+ static RPCObjectManager& instance();
+
+ void store_object(char *obj_name);
+ void remove_object(char *obj_name);
+ bool lookup_object(char *obj_name);
+
+ std::list<char*>::iterator begin();
+ std::list<char*>::iterator end();
+
+ bool is_empty();
+
+ private :
+
+ RPCObjectManager();
+ ~RPCObjectManager();
+
+ std::list<char*> objects;
+};
+#endif
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/RPCType.cpp Thu Jun 16 08:38:31 2016 +0000
@@ -0,0 +1,59 @@
+#include "mbed.h"
+#include "mbed_rpc.h"
+#include "RPCType.h"
+
+
+RPCType::RPCType():
+supported_types()
+{
+}
+
+RPCType& RPCType::instance()
+{
+ static RPCType t;
+ return t;
+}
+
+void RPCType::register_types()
+{
+ RPCType &t = instance();
+
+ RPC::add_rpc_class<RpcDigitalOut>();
+ t.supported_types.push_back("DigitalOut");
+ RPC::add_rpc_class<RpcDigitalIn>();
+ t.supported_types.push_back("DigitalIn");
+ RPC::add_rpc_class<RpcDigitalInOut>();
+ t.supported_types.push_back("DigitalInOut");
+
+ #if DEVICE_ANALOGIN
+ RPC::add_rpc_class<RpcAnalogIn>();
+ t.supported_types.push_back("AnalogIn");
+ #endif
+ #if DEVICE_PWMOUT
+ RPC::add_rpc_class<RpcPwmOut>();
+ t.supported_types.push_back("PwmOut");
+ #endif
+ #if DEVICE_SPI
+ t.supported_types.push_back("SPI");
+ RPC::add_rpc_class<RpcSPI>();
+ #endif
+ #if DEVICE_SERIAL
+ t.supported_types.push_back("Serial");
+ RPC::add_rpc_class<RpcSerial>();
+ #endif
+ RPC::add_rpc_class<RpcTimer>();
+ t.supported_types.push_back("Timer");
+}
+
+bool RPCType::is_supported_type(char *type)
+{
+ for(std::list<char*>::iterator itor = instance().supported_types.begin();
+ itor != instance().supported_types.end();
+ ++itor)
+ if(!strcmp(*itor,type))
+ return true;
+
+ return false;
+}
+
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/RPCType.h Thu Jun 16 08:38:31 2016 +0000
@@ -0,0 +1,23 @@
+#ifndef RPCTYPE_H
+#define RPCTYPE_H
+
+#include <list>
+
+class RPCType
+{
+ public :
+
+ static RPCType& instance();
+
+ void register_types();
+
+ bool is_supported_type(char *type);
+
+ private :
+
+ RPCType();
+ std::list<char*> supported_types;
+};
+
+#endif
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/RequestHandler.cpp Thu Jun 16 08:38:31 2016 +0000
@@ -0,0 +1,109 @@
+#include "RequestHandler.h"
+#include "mbed_rpc.h"
+#include "RPCObjectManager.h"
+#include "RPCCommand.h"
+
+const char* INVALID_CMD = "Invalid RPC command";
+const char* DELETE_ERROR = "You must send a DELETE request to remove an object ";
+const char* CREATE_ERROR = "You must send a PUT request to create an object";
+const char* FUNC_CALL_ERROR = "You must send a GET request to call a function";
+
+void GetRequestHandler::handle(const RPCCommand& cmd, char *reply)
+{
+ switch(cmd.get_type())
+ {
+ case DELETE:
+ printf("Error: %s\n", DELETE_ERROR);
+ strcat(reply, DELETE_ERROR);
+ break;
+ case FUNCTION_CALL:
+ RPC::call(cmd.get_cmd(), reply);
+ break;
+ case CREATE:
+ printf("Error: %s\n", CREATE_ERROR);
+ strcat(reply, CREATE_ERROR);
+ break;
+ default:
+ printf("Error: %s\n", INVALID_CMD);
+ strcat(reply, INVALID_CMD);
+ break;
+ }
+}
+
+void PutRequestHandler::handle(const RPCCommand& cmd, char *reply)
+{
+ switch(cmd.get_type())
+ {
+ case DELETE:
+ printf("Error: %s\n", DELETE_ERROR);
+ strcat(reply, DELETE_ERROR);
+ break;
+ case FUNCTION_CALL:
+ printf("Error: %s\n", FUNC_CALL_ERROR);
+ strcat(reply, FUNC_CALL_ERROR);
+ break;
+ case CREATE:
+ RPC::call(cmd.get_cmd(), reply);
+ if(strlen(reply) > 0)
+ {
+ RPCObjectManager::instance().store_object(reply);
+ strcat(reply, " has been created");
+ }
+ else
+ {
+ printf("Error while creating object\n");
+ strcat(reply, "Error while creating object.");
+ }
+ break;
+ default:
+ printf("Error: %s\n", INVALID_CMD);
+ strcat(reply, INVALID_CMD);
+ break;
+ }
+}
+
+void DeleteRequestHandler::handle(const RPCCommand& cmd, char *reply)
+{
+ switch(cmd.get_type())
+ {
+ case CREATE:
+ printf("Error: %s\n", CREATE_ERROR);
+ strcat(reply, CREATE_ERROR);
+ break;
+ case FUNCTION_CALL:
+ printf("Error: %s\n", FUNC_CALL_ERROR);
+ strcat(reply, FUNC_CALL_ERROR);
+ break;
+ case DELETE:
+ RPC::call(cmd.get_cmd(), reply);
+ RPCObjectManager::instance().remove_object(cmd.get_obj_name());
+ strcat(reply, "Deleted object ");
+ strcat(reply, cmd.get_obj_name());
+ break;
+ default:
+ printf("Error: %s\n", INVALID_CMD);
+ strcat(reply, INVALID_CMD);
+ break;
+ }
+}
+
+void ComplexRequestHandler::handle(const RPCCommand& cmd, char *reply)
+{
+ switch(cmd.get_type())
+ {
+ case CREATE :
+ putHandler.handle(cmd, reply);
+ break;
+ case DELETE :
+ deleteHandler.handle(cmd, reply);
+ break;
+ case FUNCTION_CALL :
+ getHandler.handle(cmd, reply);
+ break;
+ default :
+ printf("Error: %s\n", INVALID_CMD);
+ strcat(reply, INVALID_CMD);
+ break;
+ }
+}
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/RequestHandler.h Thu Jun 16 08:38:31 2016 +0000
@@ -0,0 +1,51 @@
+#ifndef REQUEST_HANDLER
+#define REQUEST_HANDLER
+
+#include "RPCCommand.h"
+
+class RequestHandler
+{
+ public :
+
+ virtual void handle(const RPCCommand& cmd, char* reply) = 0;
+};
+
+class GetRequestHandler : public RequestHandler
+{
+ public :
+
+ virtual void handle(const RPCCommand& cmd, char* reply);
+};
+
+class PutRequestHandler : public RequestHandler
+{
+ public :
+
+ virtual void handle(const RPCCommand& cmd, char* reply);
+
+};
+
+
+class DeleteRequestHandler : public RequestHandler
+{
+ public :
+
+ virtual void handle(const RPCCommand& cmd, char* reply);
+
+};
+
+class ComplexRequestHandler : public RequestHandler
+{
+ public :
+
+ virtual void handle(const RPCCommand& cmd, char* reply);
+
+ private :
+
+ GetRequestHandler getHandler;
+ PutRequestHandler putHandler;
+ DeleteRequestHandler deleteHandler;
+};
+
+#endif
+
--- a/main.cpp Tue Jun 14 21:25:04 2016 +0000
+++ b/main.cpp Thu Jun 16 08:38:31 2016 +0000
@@ -13,6 +13,14 @@
#include "my_eeprom_funcs.h"
#include "Watchdog.h"
+#include "RPCCommand.h"
+#include "HTTPServer.h"
+#include "Formatter.h"
+#include "RequestHandler.h"
+#include "RPCType.h"
+
+#define SERVER_PORT 80
+
/** Debug option
*
@@ -37,6 +45,7 @@
// Ethernet
SPI spi(PA_7, PA_6, PA_5); // mosi, miso, sclk
EthernetInterface eth(&spi, PA_4, PC_9); // spi, cs, reset
+int ethernet_init(void);
/*
* EEPROM section
@@ -63,33 +72,6 @@
/*
-* Network configuration
-*/
-#define TCP_SERVER
-#define TCP_CLIENT
-#define UDP_SERVER
-//#define UDP_CLIENT
-#define NTP
-
-#define TCP_SERVER_WAIT_CLIENT_TIMEOUT 200 // timeout for local tcp server wait for a remote client
-#define TCP_SERVER_RECEIVE_TIMEOUT 2000 // timeout for local tcp server wait to receive from remote client
-#define TCP_CLIENT_RECEIVE_TIMEOUT 200 // timeout for local tcp client try to connect remote server
-#define UDP_SERVER_RECEIVE_TIMEOUT 100 // timeout for checking config command
-
-
-// TCP server function
-TCPSocketServer tcp_server;
-TCPSocketConnection tcp_client;
-// TCP client function
-TCPSocketConnection tcp_sock;
-// UDP server
-UDPSocket udp_server;
-Endpoint ep_udp_client;
-// NTP
-NTPClient ntp;
-
-
-/*
* Variables for network configuration, TCP server
*/
uint8_t u8mac[6], u8ip_addr[4];// keep mac and ip address in 8-bits
@@ -109,191 +91,21 @@
uint16_t u16tcp_server_port; // directly loaded from eeprom
uint16_t u16enable_tcp_client, u16enable_tcp_server;// flags for enabling TCP client or TCP server
-#define NET_BUF_LEN 256
-char tcp_receiving_buffer[NET_BUF_LEN];
-char udp_receiving_buffer[NET_BUF_LEN];
-char network_output_buffer[NET_BUF_LEN]; // output buffer for TCP/UDP control command
-
-/*
- * RPC Protocol
- * Use the RPC enabled wrapped class - see RpcClasses.h for more info
- */
-// DigitalIn
-RpcDigitalIn di0(PB_14, "di0");
-RpcDigitalIn di1(PB_12, "di1");
-RpcDigitalIn di2(PB_10, "di2");
-RpcDigitalIn di3(PB_1, "di3");
-RpcDigitalIn di4(PB_15, "di4");
-RpcDigitalIn di5(PB_13, "di5");
-RpcDigitalIn di6(PB_11, "di6");
-RpcDigitalIn di7(PB_2, "di7");
-DigitalIn din0(PB_14);
-DigitalIn din1(PB_12);
-DigitalIn din2(PB_10);
-DigitalIn din3(PB_1);
-DigitalIn din4(PB_15);
-DigitalIn din5(PB_13);
-DigitalIn din6(PB_11);
-DigitalIn din7(PB_2);
-// DigitalOut
-RpcDigitalOut do0(PB_3, "do0");
-RpcDigitalOut do1(PB_5, "do1");
-RpcDigitalOut do2(PB_7, "do2");
-RpcDigitalOut do3(PB_9, "do3");
-RpcDigitalOut do4(PD_2, "do4");
-RpcDigitalOut do5(PB_4, "do5");
-RpcDigitalOut do6(PB_6, "do6");
-RpcDigitalOut do7(PB_8, "do7");
-DigitalOut dout0(PB_3);
-DigitalOut dout1(PB_5);
-DigitalOut dout2(PB_7);
-DigitalOut dout3(PB_9);
-DigitalOut dout4(PD_2);
-DigitalOut dout5(PB_4);
-DigitalOut dout6(PB_6);
-DigitalOut dout7(PB_8);
-// AnalogIn
-RpcAnalogIn adc10(PC_0, "ai0"); // adc10
-RpcAnalogIn adc11(PC_1, "ai1"); // adc11
-AnalogIn ain0(PC_0);
-AnalogIn ain1(PC_1);
-// AnalogOut, PWM
-RpcPwmOut pwm11(PA_8, "pwm0"); // pwm11
-RpcPwmOut pwm21(PA_15, "pwm1"); // pwm21
// Serial
-RpcSerial usart2(USBTX, USBRX, "uart"); // usart2
Serial uart(USBTX,USBRX);
-// Timer
-RpcTimer timer1("tmr1");
// Watchdog
Watchdog wdt;
-
-// Some variable types that can be modified through RPC.
-//int wheelsOn;
-//char lcdBannerMessage;
-//float speed;
-int current_time;
-int do0OnTime, do0OffTime;
-int do1OnTime, do1OffTime;
-
-//RPCVariable<int> rpcLights(&wheelsOn, "wheels");
-//RPCVariable<char> rpcBanner(&lcdBannerMessage, "banner");
-//RPCVariable<float> rpcSpeed(&speed, "speed");
-RPCVariable<int> rpcCurrentTime(¤t_time, "Time");
-RPCVariable<int> rpcdo0OnTime(&do0OnTime, "do0OnTime");
-RPCVariable<int> rpcdo0OffTime(&do0OffTime, "do0OffTime");
-RPCVariable<int> rpcdo1OnTime(&do0OnTime, "do1OnTime");
-RPCVariable<int> rpcdo1OffTime(&do0OffTime, "do1OffTime");
-
-// RPC function definitions
-// Create a function of the required format
-void set_current_time(Arguments* args, Reply* rep);
-void set_current_time(Arguments* args, Reply* rep){
- time_t ct = (time_t)current_time; // convert
- struct tm *st = localtime(&ct);
-
- set_time(ct); // set time
-
- DBG("Set current time to: %s", ctime(&ct));
- DBG("Time only: %d:%d:%d", st->tm_hour, st->tm_min, st->tm_sec);
-}
-// Attach it to an RPC object
-RPCFunction rpcSetCurrentTime(&set_current_time, "SetTime");
-
-/*
- * NNIO Protocol
- */
-// Commands
-#define DEVICE_DESCRIPTION "NNIO"
-#define DEVICE_CONFIG_CODE "NNCF"
-#define DEVICE_CONTROL_CODE "NNIO"
-
-#define RECEIVING_PROTOCOL_LENGTH 58
-#define SENDING_PROTOCOL_LENGTH 39
-#define QUERY_NETWORK_CONFIG_CMD_LENGTH 6
-#define SET_NETWORK_CONFIG_CMD_LENGTH 19
-#define UPDATE_TCP_SERVER_INFO_COMMAND_LENGTH 12
-
-#define QUERY_DISCOVERY_CMD "NNCFDS"
-#define QUERY_IP_CMD "NNCFIP"
-#define QUERY_SUBNET_CMD "NNCFSN"
-#define QUERY_GATEWAY_CMD "NNCFGW"
-#define QUERY_MAC_CMD "NNCFMC"
-#define QUERY_UDP_PORT_CMD "NNCFUP"
-#define QUERY_TCP_PORT_CMD "NNCFTP"
-#define QUERY_UPDATE_TIME_CMD "NNCFTM"
-#define RECEIVING_PROTOCOL_ENABLE_OUTPUT 'O'
-#define QUERY_STATUS_COMMAND 'Q'
-#define DIGITAL_HIGH 'H'
-#define DIGITAL_LOW 'L'
-
-
-// Positions
-#define RECEIVING_PROTOCOL_ID_POS 0
-#define RECEIVING_PROTOCOL_OP_POS 4
-#define RECEIVING_PROTOCOL_EN_DO_POS RECEIVING_PROTOCOL_OP_POS + 0
-#define RECEIVING_PROTOCOL_EN_A0O_POS RECEIVING_PROTOCOL_OP_POS + 1
-#define RECEIVING_PROTOCOL_EN_A1O_POS RECEIVING_PROTOCOL_OP_POS + 2
-#define RECEIVING_PROTOCOL_EN_UART_POS RECEIVING_PROTOCOL_OP_POS + 3
-#define RECEIVING_PROTOCOL_COMMAND_POS RECEIVING_PROTOCOL_OP_POS + 4
-
-#define RECEIVING_PROTOCOL_IP_POS 9
-#define RECEIVING_PROTOCOL_DO_POS 13
-#define RECEIVING_PROTOCOL_A0O_POS 21
-#define RECEIVING_PROTOCOL_A01_POS 23
-#define RECEIVING_PROTOCOL_UART_POS 25
-
-
-#define SENDING_PROTOCOL_ID_POS 0
-#define SENDING_PROTOCOL_MAC_POS 4
-#define SENDING_PROTOCOL_IP_POS 10
-#define SENDING_PROTOCOL_DI_POS 14
-#define SENDING_PROTOCOL_DO_POS 22
-#define SENDING_PROTOCOL_AI0_POS 30
-#define SENDING_PROTOCOL_AI1_POS 32
-#define SENDING_PROTOCOL_AO0_POS 34
-#define SENDING_PROTOCOL_AO1_POS 36
-#define SENDING_PROTOCOL_CR_POS 38
-
-
-/*
-* RTOS
-*/
-struct message_t {
- int len;
- char *msg;
-};
-Queue<message_t, 16> uart_queue;
-Queue<bool, 1> auto_update_queue;
-
-
-
-// Prototypes
-int ethernet_init(void);
-int process_control_command(char* received_buffer, int len);
-void process_config_command(char* received_buffer, int len);
-void update_digital_outputs(char* buf);
-void update_sending_frame(char* buf);
+float speed;
+RPCVariable<float> rpcSpeed(&speed, "speed");
+char stripaddr[20];
+RPCVariable<char*> rpcIPAddress(stripaddr, "ipaddr");
/*
* Threads
*/
-// Timer thread for auto update in TCP client function
-void auto_update_timer_thread(void const* args)
-{
- bool update_flag = true;
-
- Thread::wait(500);
- while(true) {
- auto_update_queue.put(&update_flag);
- Thread::wait(1000*transmit_time_period); // Thread::wait() in ms
- }
-}
-
-
// WDT reset
void wdt_reset_thread(void const* args)
{
@@ -301,104 +113,21 @@
wdt.Service();
}
-// Timer thread to check on/off time
-void digital_outputs_timer_thread(void const* args)
+
+HTTPServer create_simple_server()
+{
+ HTTPServer srv;
+ srv.add_request_handler("DELETE", new DeleteRequestHandler());
+ srv.add_request_handler("GET", new GetRequestHandler());
+ srv.add_request_handler("PUT", new PutRequestHandler());
+ return srv;
+}
+
+HTTPServer create_interactive_server()
{
- Thread::wait(700);
-
- while(true) {
- // read current time
- time_t seconds = time(NULL);
- struct tm *st = localtime(&seconds);
- int current_time_in_seconds = 3600*(st->tm_hour) + 60*(st->tm_min) + st->tm_sec;
- DBG("Current time: %d:%d:%d", st->tm_hour, st->tm_min, st->tm_sec);
-
- // check do0
- if (do0OnTime < do0OffTime) {
- if ((current_time_in_seconds >= do0OnTime) && (current_time_in_seconds < do0OffTime)){
- if (dout0 == 0) {
- dout0 = 1;
- DBG("do0 ON");
- }
- else {
- DBG("do0 ON'ed");
- }
- }
- else {
- if (dout0 == 1) {
- dout0 = 0;
- DBG("do0 OFF'ed");
- }
- else {
- DBG("do0 OFF");
- }
- }
- }
- else {
- if ((current_time_in_seconds >= do0OffTime) && ((current_time_in_seconds < do0OnTime))) {
- if (dout0 == 1) {
- dout0 = 0;
- DBG("do0 OFF");
- }
- else {
- DBG("do0 OFF'ed");
- }
- }
- else {
- if (dout0 == 0) {
- dout0 = 1;
- DBG("do0 ON");
- }
- else {
- DBG("do0 ON'ed");
- }
- }
- }
-
- // check do1
- if (do1OnTime < do1OffTime) {
- if ((current_time_in_seconds >= do1OnTime) && (current_time_in_seconds < do1OffTime)){
- if (dout1 == 0) {
- dout1 = 1;
- DBG("do1 ON");
- }
- else {
- DBG("do1 ON'ed");
- }
- }
- else {
- if (dout1 == 1) {
- dout1 = 0;
- DBG("do1 OFF");
- }
- else {
- DBG("do1 OFF'ed");
- }
- }
- }
- else {
- if ((current_time_in_seconds >= do1OffTime) && ((current_time_in_seconds < do1OnTime))) {
- if (dout1 == 1) {
- dout1 = 0;
- DBG("do1 OFF");
- }
- else {
- DBG("do1 OFF'ed");
- }
- }
- else {
- if (dout1 == 0) {
- dout1 = 1;
- DBG("do1 ON");
- }
- else {
- DBG("do1 ON'ed");
- }
- }
- }
- // wait 1s
- Thread::wait(10000); // Thread::wait() in ms
- }
+ HTTPServer srv(new InteractiveHTMLFormatter());
+ srv.add_request_handler("GET", new ComplexRequestHandler());
+ return srv;
}
// Main code
@@ -428,9 +157,10 @@
/*
* UI threads
*/
- Thread t2(auto_update_timer_thread);
Thread t3(wdt_reset_thread);
- Thread t4(digital_outputs_timer_thread);
+
+ // rpc
+ RPCType::instance().register_types();
/*
* Ethernet
@@ -442,400 +172,23 @@
}
Thread::wait(2000); // TCP/UDP stack delay
-
- /*
- * UDP server
- * TCP server/client
- */
-#ifdef UDP_SERVER
- ret = udp_server.bind(udp_server_local_port);
- DBG("UDP server started (sock.bind = %d)...", ret);
- udp_server.set_blocking(false, UDP_SERVER_RECEIVE_TIMEOUT);
-#endif
-
-#ifdef TCP_SERVER
- tcp_server.bind(tcp_server_local_port);
- tcp_server.listen();
- DBG("TCP server started...");
- tcp_server.set_blocking(false, TCP_SERVER_WAIT_CLIENT_TIMEOUT);
-#endif
-
-#ifdef TCP_CLIENT
-
-#endif
-
- /*
- * Network loop processor
- */
- while (true) {
-#ifdef TCP_CLIENT // auto update device status to a remote TCP server
- if (auto_transmit_flag == DEFAULT_ENABLE_FLAG_VALUE) {
- // connect to TCP server if required
- if (!tcp_sock.is_connected()) {
- ret = tcp_sock.connect(str_server_ip_addr, u16tcp_server_port); // timeout is default in connect() in W5500.h
- if (ret > -1) {
- DBG("Successfully connected to %s on port %d", str_server_ip_addr, u16tcp_server_port);
- } else {
- ERR("Unable to connect to %s on port %d", str_server_ip_addr, u16tcp_server_port);
- }
- }
-
- // transmit data if connected
- if (tcp_sock.is_connected()) {
- osEvent evt = auto_update_queue.get(1); // timeout after 1ms
- if (evt.status == osEventMessage) {
- DBG("Updating...");
- update_sending_frame(network_output_buffer);
- tcp_sock.send_all(network_output_buffer, SENDING_PROTOCOL_LENGTH);
- }
-
- // check to receive or timeout
- tcp_sock.set_blocking(false, TCP_CLIENT_RECEIVE_TIMEOUT);
- n = tcp_sock.receive(tcp_receiving_buffer, sizeof(tcp_receiving_buffer));
- if (n > 0) {
- // got some data, test it
- DBG("TCP client received %d bytes: %s", n, tcp_receiving_buffer);
- n = process_control_command(tcp_receiving_buffer, n);
- // send reply back to client, NNIO protocol always returns 0
- // RPC-style protocol
- if (n > 0) {
- network_output_buffer[n] = '\0';
- tcp_sock.send_all(network_output_buffer, strlen(network_output_buffer));
- } // RPC-style protocol
- else if (n == 0) {
- // then, check query status command and sending protocol if required
- if (tcp_receiving_buffer[RECEIVING_PROTOCOL_COMMAND_POS] == QUERY_STATUS_COMMAND) {
- DBG("Requested to send device status through TCP");
- // sending protocol
- update_sending_frame(network_output_buffer);
- tcp_sock.send_all(network_output_buffer, SENDING_PROTOCOL_LENGTH);
- DBG("Sent");
- }
- } // NNIO protocol
- }
- }
- } // if tcp client enabled && auto transmit
-#endif
-
-
-#ifdef TCP_SERVER // control and monitor from a remote TCP client, both NNIO and RPC-style
- // no tcp client connected{
- if (1) {
- // wait for client within timeout
- ret = tcp_server.accept(tcp_client);
-
- // tcp client connected
- if (ret > -1) {
- DBG("Connection from: %s", tcp_client.get_address());
-
- // loop waiting and receiving data within timeout
- tcp_client.set_blocking(false, TCP_SERVER_RECEIVE_TIMEOUT); // Timeout after x seconds
- while (tcp_client.is_connected()) {
- n = tcp_client.receive(tcp_receiving_buffer, sizeof(tcp_receiving_buffer));
- if (n <= 0) break;
-
- // got some data, process it
- tcp_receiving_buffer[n] = '\0'; // for debugging purpose
- DBG("TCP server received: %s", tcp_receiving_buffer);
- n = process_control_command(tcp_receiving_buffer, n);
- // send reply back to client, NNIO protocol always returns 0
- // RPC-style protocol
- if (n > 0) {
- network_output_buffer[n] = '\0';
- tcp_client.send_all(network_output_buffer, strlen(network_output_buffer));
- } // RPC-style protocol
- else if (n == 0) {
- // then, check query status command and sending protocol if required
- if (tcp_receiving_buffer[RECEIVING_PROTOCOL_COMMAND_POS] == QUERY_STATUS_COMMAND) {
- DBG("Requested to send device status through TCP");
- // sending protocol
- update_sending_frame(network_output_buffer);
- tcp_client.send_all(network_output_buffer, SENDING_PROTOCOL_LENGTH);
- DBG("Sent");
- }
- } // NNIO protocol
- } // end loop if no data received within timeout
- } // if client connected
- tcp_client.close();
- } // if tcp server enabled && no client connected
-#endif
-
-#ifdef UDP_SERVER // configuration and control, both NNIO and RPC-style
- bool discovery_mode_flag, config_mode_flag;
-
- n = udp_server.receiveFrom(ep_udp_client, udp_receiving_buffer, sizeof(udp_receiving_buffer));
-
- // check to see if it is a query command
- // if yes, is it a discovery command or an ip query to enter config mode
- discovery_mode_flag = false;
- config_mode_flag = false;
- if ((n == QUERY_NETWORK_CONFIG_CMD_LENGTH) && (strstr(udp_receiving_buffer, QUERY_DISCOVERY_CMD) != NULL)) {
- discovery_mode_flag = true;
- DBG("Received discovery command");
- char str[50];
- sprintf(str, "%s%s%s", DEVICE_DESCRIPTION, eth.getMACAddress(), eth.getIPAddress());
- udp_server.sendTo(ep_udp_client, str, strlen(str));
- } // NNCFDS
- else if ((n == QUERY_NETWORK_CONFIG_CMD_LENGTH) && (strstr(udp_receiving_buffer, QUERY_IP_CMD) != NULL)) {
- config_mode_flag = true;
- DBG("Entered configuration mode...");
- DBG("!!! RESET when finished");
- } // NNCFIP
+
+ // Test parsing ip address string
+ char* ipaddr = "192.168.0.121";
+ int b[4];
+ sscanf(ipaddr, "%d.%d.%d.%d", &b[0], &b[1], &b[2], &b[3]);
+ DBG("%d.%d.%d.%d",b[0],b[1],b[2],b[3]);
- // if received NNCFIP, enter config mode
- if (config_mode_flag) {
- while (n > 0) {
- // got some data, test it
- DBG("UDP received (%s) from (%s:%d)", udp_receiving_buffer, ep_udp_client.get_address(), ep_udp_client.get_port());
- process_config_command(udp_receiving_buffer, n);
- // wait to receive new config command
- udp_server.set_blocking(true);
- n = udp_server.receiveFrom(ep_udp_client, udp_receiving_buffer, sizeof(udp_receiving_buffer));
- } // while (n > 0), config loop
- } // if (config_mode_flag)
- // process control packages sent using UDP
- else if ((n > 0) && (!discovery_mode_flag)) {
- n = process_control_command(udp_receiving_buffer, n);
- // send rpc reply back to client, NNIO protocol always returns 0
- // RPC-style protocol
- if (n > 0) {
- network_output_buffer[n] = '\0';
- udp_server.sendTo(ep_udp_client, network_output_buffer, strlen(network_output_buffer));
- } // RPC-style protocol
- else if (n == 0) {
- // then, check query status command and sending protocol if required
- if (udp_receiving_buffer[RECEIVING_PROTOCOL_COMMAND_POS] == QUERY_STATUS_COMMAND) {
- DBG("Requested to send device status through UDP");
- // sending protocol
- update_sending_frame(network_output_buffer);
- udp_server.sendTo(ep_udp_client, network_output_buffer, SENDING_PROTOCOL_LENGTH);
- DBG("Sent");
- }
- } // NNIO protocol
- }
-#endif
- } // network processor
-}
-
-
-/*
- * Process NNCF commands
- */
-void process_config_command(char* received_buffer, int len)
-{
- DBG("Processing configuration command");
-
- // a configuration command always starts with NN
- if ((received_buffer[0] == 'N') && (received_buffer[1] == 'N') &&
- (received_buffer[2] == 'C') && (received_buffer[3] == 'F')) {
- switch (len) {
- // length = 6, a QUERY command (discovery command, TCP port, or UDP port)
- // Format: NNCFDS, NNCFTP, NNCFUP, NNCFTM
- case QUERY_NETWORK_CONFIG_CMD_LENGTH: {
- if (strstr(received_buffer, QUERY_IP_CMD) != NULL) {
- udp_server.sendTo(ep_udp_client, eth.getIPAddress(), strlen(eth.getIPAddress()));
- } // NNCFIP
- else if (strstr(received_buffer, QUERY_SUBNET_CMD) != NULL) {
- udp_server.sendTo(ep_udp_client, eth.getNetworkMask(), strlen(eth.getNetworkMask()));
- } // NNCFSN
- else if (strstr(received_buffer, QUERY_GATEWAY_CMD) != NULL) {
- udp_server.sendTo(ep_udp_client, eth.getGateway(), strlen(eth.getGateway()));
- } // NNCFGW
- else if (strstr(received_buffer, QUERY_MAC_CMD) != NULL) {
- udp_server.sendTo(ep_udp_client, eth.getMACAddress(), strlen(eth.getMACAddress()));
- } // NNCFMC
- // ask for TCP server port
- else if (strstr(received_buffer, QUERY_TCP_PORT_CMD) != NULL) {
- char port[5];
- sprintf(port, "%5d", tcp_server_local_port);
- udp_server.sendTo(ep_udp_client, port, strlen(port));
- } // NNCFTP
- // ask for UDP server port
- else if (strstr(received_buffer, QUERY_UDP_PORT_CMD) != NULL) {
- char port[5];
- sprintf(port, "%5d", udp_server_local_port);
- udp_server.sendTo(ep_udp_client, port, strlen(port));
- } // NNCFUP
- else if (strstr(received_buffer, QUERY_UPDATE_TIME_CMD) != NULL) {
-#ifdef NTP
- char str_time[50];
-
- DBG("Trying to update time...");
- if (ntp.setTime("0.pool.ntp.org") == 0) {
- DBG("Set time successfully");
- time_t ctTime;
- ctTime = time(NULL);
+ // create rpc http server
+ HTTPServer srv = create_interactive_server();
- DBG("Time is set to (UTC): %s", ctime(&ctTime));
- sprintf(str_time, "%s", ctime(&ctTime));
- udp_server.sendTo(ep_udp_client, str_time, strlen(str_time));
- } else {
- WARN("Error");
- sprintf(str_time, "ERR");
- udp_server.sendTo(ep_udp_client, str_time, strlen(str_time));
- }
-#else
- WARN("NTP disabled");
- sprintf(str_time, "DIS");
- udp_server.sendTo(ep_udp_client, str_time, strlen(str_time));
-#endif
- } // NNCFTM
- break;
- }
- // length = 19, SET NETWORK CONFIGURATION
- // Format: 4E 4E 43 46 C0 A8 00 78 FF FF FF 00 C0 A8 00 01 00 00 01
- // (NNCF; IP: 192.168.0.120; Subnet: 255.255.255.0; GW: 192.168.0.1; MAC: 0 0 1)
- case SET_NETWORK_CONFIG_CMD_LENGTH: {
- // check device id
- char* id = strstr(received_buffer, DEVICE_CONFIG_CODE);
- if (id == NULL)
- break;
- else if ((id - received_buffer) > 0)
- break;
-
- DBG("Received user configuration");
- write_eeprom_network(&received_buffer[strlen(DEVICE_CONFIG_CODE)]); // parameters from 5th char, 15-bytes
- NVIC_SystemReset();
- break;
- }
- // length = 12, SET TCP SERVER CONFIGURATION
- // auto update & its time period, TCP server configuration (IP & port)
- // Format: 4E 4E 43 46 'Y' 01 C0 A8 00 09 E0 2E (LSB MSB)
- // NNCF Auto 1s 192.168.0.9 12000
- case UPDATE_TCP_SERVER_INFO_COMMAND_LENGTH: {
- char* id = strstr(received_buffer, DEVICE_CONFIG_CODE);
- if (id == NULL)
- break;
- else if ((id - received_buffer) > 0)
- break;
-
- DBG("Received TCP server configuration");
- write_eeprom_tcpserver(&received_buffer[strlen(DEVICE_CONFIG_CODE)]); // parameters from 5th char
- NVIC_SystemReset();
- break;
- }
- default:
- break;
- } // switch (n), check configuration command length
- } // if starts with NNCF, a config command
- else { // if not a configuration command
- }
-}
-
-/*
- * Procedure to process receiving protocol, which includes command to control outputs.
- * Support both NNIO and RPC-style commands.
- * RPC always starts with '/'.
- * Return:
- * 0 if NNIO protocol;
- * length of rpc output buffer if rpc;
- * -1 if rpc failed
- */
-int process_control_command(char* received_buffer, int len)
-{
- char* received_frame;
- bool rpc_style;
- int pos;
- char inbuf[NET_BUF_LEN];
-
- DBG("Processing control command");
-
- /*
- * This section is for RPC-style command
- */
- // check if it is a RPC-style command
- rpc_style = false;
- strncpy(inbuf, received_buffer, len);
- inbuf[len] = '\r'; // use inbuf for RPC protocol
- inbuf[len+1] = '\n';
- inbuf[len+2] = '\0'; // add CR-LF
- if ((len > 0) && (inbuf[0] == '/')) {
- char obj_name[16];
- bool ok;
-
- rpc_style = true;
- // find RPC object name
- for (int i = 1; i < strlen(inbuf); i++) {
- if (inbuf[i] != '/') {
- obj_name[i-1] = inbuf[i];
- } else {
- obj_name[i-1] = '\0';
- break;
- }
- }
- DBG("Rpc command = %s", inbuf);
- /*
- * execute RPC command, return reply length and reply in rpc_outbuf
- */
- ok = RPC::call(inbuf, network_output_buffer);
- if (ok) {
- // re-arrange output buffer as following: object_name:output_value
- strcpy(inbuf, network_output_buffer); // use inbuf as temp
- strcpy(network_output_buffer, obj_name); // rpc object name
- strcat(network_output_buffer, ":");
- strcat(network_output_buffer, inbuf); // concat rpc reply
- strcat(network_output_buffer, "\r\n"); // CR-LF
- int j = strlen(network_output_buffer);
- DBG("Reply of rpc command on \"%s\" (%d bytes): %s", obj_name, j, network_output_buffer);
- return j; // return length of rpc_outbuf
- } else {
- ERR("Failed: %s", inbuf);
- return -1;
- }
+ if(!srv.init(SERVER_PORT))
+ {
+ eth.disconnect();
+ return -1;
}
- /*
- * This section below is for NNIO protocol
- */
- while ((!rpc_style) && (len >= RECEIVING_PROTOCOL_LENGTH)) {
- // find device ID
- DBG("Checking device ID...");
- char* id = strstr(received_buffer, DEVICE_CONTROL_CODE);
- if (id == NULL) {
- DBG("No device ID found");
- break;
- }
- pos = id - received_buffer;
- DBG("Found a frame at %d", pos);
-
- // extract this frame
- received_frame = &received_buffer[pos];
- // calculate the rest
- received_buffer = &received_buffer[pos + RECEIVING_PROTOCOL_LENGTH];
- len -= RECEIVING_PROTOCOL_LENGTH;
-
- // process this received frame
- // firstly, update outputs if required
- // digital outputs
- if (received_frame[RECEIVING_PROTOCOL_EN_DO_POS] == RECEIVING_PROTOCOL_ENABLE_OUTPUT) {
- DBG("Update digital outputs");
- char str_dout[9];
- memcpy(str_dout, &received_frame[RECEIVING_PROTOCOL_DO_POS], 8);
- str_dout[8] = '\0';
- update_digital_outputs(str_dout);
- }
- // analog output 0
- if (received_frame[RECEIVING_PROTOCOL_EN_A0O_POS] == RECEIVING_PROTOCOL_ENABLE_OUTPUT) {
- DBG("Update analog output 0");
- //TODO Update analog output
- }
- // analog output 1
- if (received_buffer[RECEIVING_PROTOCOL_EN_A1O_POS] == RECEIVING_PROTOCOL_ENABLE_OUTPUT) {
- DBG("Update analog output 1");
- //TODO Update analog output
- }
- // UART
- if (received_frame[RECEIVING_PROTOCOL_EN_UART_POS] == RECEIVING_PROTOCOL_ENABLE_OUTPUT) {
- DBG("UART data: ");
- char str_uart[33];
- memcpy(str_uart, &received_frame[RECEIVING_PROTOCOL_UART_POS], 32);
- str_uart[32] = '\0';
- uart.printf("%s\r\n", str_uart);
- }
- }
-
- DBG("Successfully processed.");
- return 0;
+ srv.run();
}
@@ -885,59 +238,3 @@
return 0;
}
-
-/*
-* Update digital outputs according to receiving protocol
-*/
-void update_digital_outputs(char* buf)
-{
- DBG("Digital outputs: %s", buf);
-
- dout0 = (buf[0] == DIGITAL_HIGH)? 1 : 0;
- dout1 = (buf[1] == DIGITAL_HIGH)? 1 : 0;
- dout2 = (buf[2] == DIGITAL_HIGH)? 1 : 0;
- dout3 = (buf[3] == DIGITAL_HIGH)? 1 : 0;
- dout4 = (buf[4] == DIGITAL_HIGH)? 1 : 0;
- dout5 = (buf[5] == DIGITAL_HIGH)? 1 : 0;
- dout6 = (buf[6] == DIGITAL_HIGH)? 1 : 0;
- dout7 = (buf[7] == DIGITAL_HIGH)? 1 : 0;
-}
-
-/*
-* Prepare a frame for sending protocol, which includes status of I/Os
-*/
-void update_sending_frame(char* buf)
-{
- memcpy(&buf[SENDING_PROTOCOL_ID_POS], DEVICE_CONTROL_CODE, 4); // device id
- memcpy(&buf[SENDING_PROTOCOL_MAC_POS], &u8mac, 6);
- memcpy(&buf[SENDING_PROTOCOL_IP_POS], &u8ip_addr, 4);
-
- buf[SENDING_PROTOCOL_DI_POS+0] = (din0 == 1) ? DIGITAL_HIGH : DIGITAL_LOW;
- buf[SENDING_PROTOCOL_DI_POS+1] = (din1 == 1) ? DIGITAL_HIGH : DIGITAL_LOW;
- buf[SENDING_PROTOCOL_DI_POS+2] = (din2 == 1) ? DIGITAL_HIGH : DIGITAL_LOW;
- buf[SENDING_PROTOCOL_DI_POS+3] = (din3 == 1) ? DIGITAL_HIGH : DIGITAL_LOW;
- buf[SENDING_PROTOCOL_DI_POS+4] = (din4 == 1) ? DIGITAL_HIGH : DIGITAL_LOW;
- buf[SENDING_PROTOCOL_DI_POS+5] = (din5 == 1) ? DIGITAL_HIGH : DIGITAL_LOW;
- buf[SENDING_PROTOCOL_DI_POS+6] = (din6 == 1) ? DIGITAL_HIGH : DIGITAL_LOW;
- buf[SENDING_PROTOCOL_DI_POS+7] = (din7 == 1) ? DIGITAL_HIGH : DIGITAL_LOW;
-
- buf[SENDING_PROTOCOL_DO_POS+0] = (dout0 == 1) ? DIGITAL_HIGH : DIGITAL_LOW;
- buf[SENDING_PROTOCOL_DO_POS+1] = (dout1 == 1) ? DIGITAL_HIGH : DIGITAL_LOW;
- buf[SENDING_PROTOCOL_DO_POS+2] = (dout2 == 1) ? DIGITAL_HIGH : DIGITAL_LOW;
- buf[SENDING_PROTOCOL_DO_POS+3] = (dout3 == 1) ? DIGITAL_HIGH : DIGITAL_LOW;
- buf[SENDING_PROTOCOL_DO_POS+4] = (dout4 == 1) ? DIGITAL_HIGH : DIGITAL_LOW;
- buf[SENDING_PROTOCOL_DO_POS+5] = (dout5 == 1) ? DIGITAL_HIGH : DIGITAL_LOW;
- buf[SENDING_PROTOCOL_DO_POS+6] = (dout6 == 1) ? DIGITAL_HIGH : DIGITAL_LOW;
- buf[SENDING_PROTOCOL_DO_POS+7] = (dout7 == 1) ? DIGITAL_HIGH : DIGITAL_LOW;
-
- uint16_t val = ain0.read_u16(); // 16-bits normalised
- memcpy(&buf[SENDING_PROTOCOL_AI0_POS], &val, 2); // LSB MSB
- val = ain1.read_u16(); // 16-bits normalised
- memcpy(&buf[SENDING_PROTOCOL_AI1_POS], &val, 2); // LSB MSB
- val = 0x1234;
- memcpy(&buf[SENDING_PROTOCOL_AO0_POS], &val, 2); // LSB MSB
- val = 0x5678;
- memcpy(&buf[SENDING_PROTOCOL_AO1_POS], &val, 2); // LSB MSB
- buf[SENDING_PROTOCOL_CR_POS] = 0x0D;
- buf[SENDING_PROTOCOL_CR_POS+1] = '\0';
-}
\ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mbed-rpc-nucleo.lib Thu Jun 16 08:38:31 2016 +0000 @@ -0,0 +1,1 @@ +http://developer.mbed.org/users/olympux/code/mbed-rpc-nucleo/#e65ed29fd4d1
--- a/mbed-rpc.lib Tue Jun 14 21:25:04 2016 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1 +0,0 @@ -https://developer.mbed.org/users/olympux/code/mbed-rpc-nucleo/#e6a835c40639
--- a/protocol_rpc.txt Tue Jun 14 21:25:04 2016 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,65 +0,0 @@ -NNIO module can be controlled through TCP/UDP using RPC commands. - - -1. Connections - + UDP port: 11000 - + TCP port: 10000 (NNIO module is TCP server) - -2. Digital inputs - + Digital inputs: di0 - di7 - + Commands: /di0/read x - -3. Digital outputs - + Digital outputs: do0 - do7 - + Commands: - /do0/read x - /do0/write 1 - -3. Analog inputs - + Analog inputs: ai0 - ai1 - + Commands: - /ai0/read x: returns a value between 0 to 1 - /ai0/read_u16 x: returns a value between 0 to 0xFFFF - -4. PWM outputs: - + PWM outputs: pwm0 - pwm1 - + Commands: - /pwm/period 0.5: Set the PWM period, specified in seconds (float), keeping the duty cycle the same. - /pwm/period_ms 500: Set the PWM period, specified in milli-seconds (int), keeping the duty cycle the same. - /pwm/pulsewidth 1: Set the PWM pulsewidth, specified in seconds (float), keeping the period the same. - /pwm/pulsewidth_ms 1000: Set the PWM pulsewidth, specified in milli-seconds (int), keeping the period the same. - /pwm/read x: Return the current output duty-cycle setting, measured as a percentage (float). - /pwm/write 0.6: Set the ouput duty-cycle, specified as a percentage (float). - -5. Timers: - + Timer: timer1 - + Commands: - /tmr1/start x - /tmr1/stop x - /tmr1/reset x - /tmr1/read x: returns float, between 0 to 1. - /tmr1/read_ms - /tmr1/read_us - -6. UARTs: - + Uart: uart - + Commands: - /uart/baud 9600 - /uart/putc 60: send ASCII code, '<' - /uart/getc x: return ASCII code - /uart/puts helloworld: print helloworld to serial port - -7. RPCVariable - + Declare normal variables and associate them with RPCVariable, e.g. int wheels, float speed, char banner - + Commands: - /speed/write 34.5 - /speed/read x - /wheels/write 64 - /wheels/read x - /banner/write c - /banner/read x - -8. RPCFunction - + Declare a function and associate it with RPCFunction - + Commands: - /func_name/run x \ No newline at end of file
--- a/protocol_v2.0.txt Tue Jun 14 21:25:04 2016 +0000
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,93 +0,0 @@
-CONFIGURATION SECTION (UDP)
-A configuration command always starts with "NNCF"
-1. DISCOVERY Command
- + UDP broadcast: 192.168.0.255 to port 11000
- + Send: NNCFDS
- + Receive: NNCF (4-bytes) MAC-address (6-bytes) IP-address
-1a. Query Command: IP, subnet, gateway, mac
- + Send: NNCFIP (enter configuration mode), NNCFSN, NNCFGW, NNCFMC
-
-2. TCP SERVER PORT Command
- + Send: NNCFTP
- + Receive: 10000
-
-3. UDP SERVER PORT Command
- + Send: NNCFUP
- + Receive: 11000
-
-4. Set time using NTP Command
- + Send NNCFTM
- + Receive:
- DIS: if NTP is disabled
- ERR: if cannot update time
- Successful: Fri Sep 26 20:28:01 2014 {0A}
-
-5. Set new network configuration
- + Send: 19 bytes in total, NNCF + 15-byte
- NNCF 4-byte IP address 4-byte subnet 4-byte gateway 3-byte MAC
- 4E 4E 43 46 C0 A8 00 78 FF FF FF 00 C0 A8 00 01 00 00 01
-
-6. Set TCP server info (only when the device is as a TCP client)
- + Send: 12 bytes in total, NNIO + 8 bytes
- NNCF 1-byte auto flag 1-byte time period (s) 4-byte IP 2-byte port (LSB MSB)
- 4E 4E 43 46 'Y' or others 05 (5s) C0 A8 00 09 E0 2E (0x2EE0 = 12000)
-
-NOTE:
-1. Both TCP client and server are working. Can be enabled/disabled using u16enable_tcp_client/server flags in eeprom (not in use now).
-2. UDP server is always working.
-
-
-INTERFACING SECTION (TCP)
-4. Receiving Protocol: 58-bytes in total
-Ex in hex
-ID: 4E 4E 49 4F
-OP: 4F 4F 4F 4F 51
-IP: C0 A8 00 78
-DO: 48 48 48 48 48 48 48 48
-AO: 80 00 80 00 (no DAC)
-UART: 32-byte
-CR: 0D
-
- + Field ID (4-bytes) = NNIO
- + Field OP (5-bytes): output control enable flag
- Byte 1: Digital output
- Byte 2: Analog output 0
- Byte 3: Analog output 1
- Byte 4: UART output
- Byte 5: Command (Q: query status)
- 'O': enable controlling output
- Others: disable controlling output
- If Command is 'Q', device will update its outputs if needed and send its status including new outputs
- + Field IP (4-bytes): device IP address
- + Field DO[n] (8-bytes): digital output values
- 'H': output set to high
- 'L': output set to low
- + Field AO_0 (2-bytes): 16-bit analog output value, channel 0
- no DAC
- + Field AO_1 (2-bytes): 16-bit analog output value, channel 1
- no DAC
- + UART output (32-bytes): max 32 bytes, stop string by NULL
- + End char: CR
-
-5. Sending Protocol: 39-bytes in total
- + Field ID (4-bytes) = NNIO
- + Field MAC (6-bytes)
- + Field IP (4-bytes)
- + Field DI[n]: 8-bit digital input values
- 'H' if input is HIGH
- 'L' if input is LOW
- + Field DO[n]: 8-bit digital output values
- 'H' if output is HIGH
- 'L' if output is LOW
- + Field AI_0 (2-bytes): analog 16-bit input value, normalised, channel 0
- 1st byte = LSB, 2nd byte = MSB
- + Field AI_1 (2-bytes): analog 16-bit input value, normalised, channel 1
- 1st byte = LSB, 2nd byte = MSB
- + Field AO_0 (2-bytes): 16-bit analog output value, channel 0
- no DAC, fixed
- + Field AO_1 (2-bytes): 16-bit analog output value, channel 1
- no DAC, fixed
- + End char: CR
-
-6 Commands:
- + QUERY STATUS ('Q')
\ No newline at end of file
