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 31:2e4b6de6c2f3, committed 2015-01-24
- Comitter:
- olympux
- Date:
- Sat Jan 24 20:49:24 2015 +0000
- Parent:
- 30:15e23257e786
- Child:
- 32:db2e8ea06ee1
- Commit message:
- Process both RPC and NNIO control commands with UDP and TCP
Changed in this revision
| main.cpp | Show annotated file Show diff for this revision Revisions of this file |
| readme.txt | Show annotated file Show diff for this revision Revisions of this file |
--- a/main.cpp Sun Jan 11 13:53:53 2015 +0000
+++ b/main.cpp Sat Jan 24 20:49:24 2015 +0000
@@ -14,20 +14,20 @@
#include "Watchdog.h"
-//Debug is disabled by default
+/** Debug option
+ *
+ */
#if 1
//Enable debug
#include <cstdio>
-#define DBG(x, ...) std::printf("[main : DBG]"x"\r\n", ##__VA_ARGS__);
-#define WARN(x, ...) std::printf("[main : WARN]"x"\r\n", ##__VA_ARGS__);
-#define ERR(x, ...) std::printf("[main : ERR]"x"\r\n", ##__VA_ARGS__);
-
+#define DBG(x, ...) std::printf("[main : DBG]"x"\r\n", ##__VA_ARGS__);
+#define WARN(x, ...) std::printf("[main : WARN]"x"\r\n", ##__VA_ARGS__);
+#define ERR(x, ...) std::printf("[main : ERR]"x"\r\n", ##__VA_ARGS__);
#else
//Disable debug
-#define DBG(x, ...)
+#define DBG(x, ...)
#define WARN(x, ...)
-#define ERR(x, ...)
-
+#define ERR(x, ...)
#endif
@@ -49,18 +49,18 @@
0x5212, // UDP server port, not used
0x8888, // 1st run? 0xA5A5 = configured
0x6212, 0x6313, 0x6414, // MAC
-
+
// this section is for the TCP server that this device connects to in TCP client mode
0x7212, 0x7313, // 0xA5A5 = auto transmit status, time period
0x8212, 0x8313,0x8414, 0x8515, // TCP server IP address
0x9212, // TCP server port
-
+
// this section is for selecting protocol, not used
0xA212, // 0xA5A5 = enable TCP server
0xA313, // 0xA5A5 = eanble TCP client
0xA414 // 0xA5A5 = enable UDP server
- };
-
+ };
+
/*
* Network configuration
@@ -110,11 +110,9 @@
uint16_t u16enable_tcp_client, u16enable_tcp_server;// flags for enabling TCP client or TCP server
#define NET_BUF_LEN 256
-#define RPC_BUF_LEN 256
char tcp_receiving_buffer[NET_BUF_LEN];
-char tcp_sending_buffer[NET_BUF_LEN]; // socket buffer
char udp_receiving_buffer[NET_BUF_LEN];
-char rpc_outbuf[RPC_BUF_LEN]; // rpc output buffer
+char network_output_buffer[NET_BUF_LEN]; // output buffer for TCP/UDP control command
/*
@@ -251,10 +249,11 @@
/*
* Threads
*/
-// Timer thread for auto update
-void auto_update_timer_thread(void const* args) {
+// 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);
@@ -264,7 +263,8 @@
// WDT reset
-void wdt_reset_thread(void const* args) {
+void wdt_reset_thread(void const* args)
+{
while (true)
wdt.Service();
}
@@ -273,31 +273,32 @@
int main()
{
int n, ret;
-
+
Thread::wait(500); // turn on delay
-
+
/*
* Configure
*/
uart.baud(115200);
DBG("\r\nStarting...");
-
+
+ // check watchdog
if (wdt.WatchdogCausedReset())
DBG("Watchdog caused reset.");
wdt.Configure(4);
-
+
/*
* FLASH
*/
load_eeprom_network();
load_eeprom_tcpserver();
-
+
/*
* UI threads
*/
Thread t2(auto_update_timer_thread);
Thread t3(wdt_reset_thread);
-
+
/*
* Ethernet
*/
@@ -306,13 +307,13 @@
ERR("Ethernet initialisation failed. App halted.");
while (true) {};
}
-
+
Thread::wait(2000); // TCP/UDP stack delay
-/*
-* UDP server
-* TCP server/client
-*/
+ /*
+ * UDP server
+ * TCP server/client
+ */
#ifdef UDP_SERVER
ret = udp_server.bind(udp_server_local_port);
DBG("UDP server started (sock.bind = %d)...", ret);
@@ -329,7 +330,7 @@
#ifdef TCP_CLIENT
#endif
-
+
/*
* Network loop processor
*/
@@ -341,21 +342,20 @@
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 {
+ } 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(tcp_sending_buffer);
- tcp_sock.send_all(tcp_sending_buffer, SENDING_PROTOCOL_LENGTH);
+ 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));
@@ -374,26 +374,37 @@
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 (true) {
+ 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 rpc reply back to client, NNIO protocol always returns 0
+ // send reply back to client, NNIO protocol always returns 0
+ // RPC-style protocol
if (n > 0) {
- rpc_outbuf[n] = '\0';
- tcp_client.send_all(rpc_outbuf, strlen(rpc_outbuf));
- }
+ 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();
@@ -402,9 +413,9 @@
#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;
@@ -421,11 +432,10 @@
DBG("Entered configuration mode...");
DBG("!!! RESET when finished");
} // NNCFIP
-
+
// if received NNCFIP, enter config mode
if (config_mode_flag) {
- while (n > 0)
- {
+ 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);
@@ -438,9 +448,20 @@
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) {
- rpc_outbuf[n] = '\0';
- udp_server.sendTo(ep_udp_client, rpc_outbuf, strlen(rpc_outbuf));
+ 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");
+ }
}
}
#endif
@@ -454,13 +475,13 @@
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')) {
+ (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
+ // 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()));
@@ -564,10 +585,10 @@
char* received_frame;
bool rpc_style;
int pos;
- char inbuf[RPC_BUF_LEN];
-
+ char inbuf[NET_BUF_LEN];
+
DBG("Processing control command");
-
+
/*
* This section is for RPC-style command
*/
@@ -580,14 +601,13 @@
if ((len > 0) && (inbuf[0] == '/')) {
char obj_name[32];
bool result;
-
+
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 {
+ } else {
obj_name[i-1] = '\0';
break;
}
@@ -596,24 +616,23 @@
/*
* execute RPC command, return reply length and reply in rpc_outbuf
*/
- result = RPC::call(inbuf, rpc_outbuf);
+ result = RPC::call(inbuf, network_output_buffer);
if (result) {
// re-arrange output buffer as following: object_name:output_value
- strcpy(inbuf, rpc_outbuf); // use inbuf as temp
- strcpy(rpc_outbuf, obj_name); // rpc object name
- strcat(rpc_outbuf, ":");
- strcat(rpc_outbuf, inbuf); // concat rpc reply
- strcat(rpc_outbuf, "\r\n"); // CR-LF
- int j = strlen(rpc_outbuf);
- DBG("Reply of rpc command on \"%s\" (%d bytes): %s", obj_name, j, rpc_outbuf);
+ 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 {
+ } else {
ERR("Failed: %s", inbuf);
return -1;
}
}
-
+
/*
* This section below is for NNIO protocol
*/
@@ -627,13 +646,13 @@
}
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
@@ -662,17 +681,8 @@
str_uart[32] = '\0';
uart.printf("%s\r\n", str_uart);
}
-
- // then, check query status command and sending protocol if required
- if (received_frame[RECEIVING_PROTOCOL_COMMAND_POS] == QUERY_STATUS_COMMAND) {
- DBG("Requested to send device status through TCP");
- // sending protocol
- update_sending_frame(tcp_sending_buffer);
- tcp_client.send_all(tcp_sending_buffer, SENDING_PROTOCOL_LENGTH);
- DBG("Sent");
- }
}
-
+
DBG("Successfully processed.");
return 0;
}
@@ -681,11 +691,12 @@
/*
* W5500 Ethernet init
*/
-int ethernet_init(void) {
+int ethernet_init(void)
+{
int dhcp_ret, ret;
-
+
DBG("Initialising ethernet...");
-
+
// if not configured, try dhcp
dhcp_ret = -1;
if (configured_ip != DEFAULT_ENABLE_FLAG_VALUE) {
@@ -694,7 +705,7 @@
if (dhcp_ret == 0)
dhcp_ret = eth.connect();
}
-
+
if (dhcp_ret != 0) {
DBG("No DHCP, load static IP configuration");
ret = eth.init(u8mac, str_ip_addr, str_ip_subnet, str_ip_gateway); // static
@@ -719,7 +730,7 @@
ERR("Error eth.connect() - ret = %d", ret);
return -1;
}
-
+
return 0;
}
@@ -727,9 +738,10 @@
/*
* Update digital outputs according to receiving protocol
*/
-void update_digital_outputs(char* buf) {
+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;
@@ -743,11 +755,12 @@
/*
* Prepare a frame for sending protocol, which includes status of I/Os
*/
-void update_sending_frame(char* buf) {
+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;
@@ -756,7 +769,7 @@
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;
@@ -765,7 +778,7 @@
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
--- a/readme.txt Sun Jan 11 13:53:53 2015 +0000
+++ b/readme.txt Sat Jan 24 20:49:24 2015 +0000
@@ -12,4 +12,8 @@
v1.0 (06/01/2014)
+ Added: RPC command replies as following object_name:reply_value
- + Modified: clean code in my_eeprom_funcs and main.cpp
\ No newline at end of file
+ + Modified: clean code in my_eeprom_funcs and main.cpp
+
+v1.1 (24/01/2015)
+ + Modified: control command is able to be processed by both TCP and UDP.
+ Only one network output buffer is used for RPC-style and NNIO protocols.
\ No newline at end of file
