Webserver only w/o any other functions, single thread. Running on STM32F013+W5500
Dependencies: NTPClient W5500Interface Watchdog device_configuration eeprom_flash mbed-rpc-nucleo mbed-rtos mbed
Fork of F103-Serial-to-Ethernet by
Revision 27:22f289beceb8, committed 2014-12-29
- Comitter:
- olympux
- Date:
- Mon Dec 29 21:40:55 2014 +0000
- Parent:
- 26:09e0dd020900
- Child:
- 28:00c0c20d03c1
- Commit message:
- Added and tested Rpc with TCP/UDP
Changed in this revision
--- a/main.cpp Wed Dec 24 13:23:33 2014 +0000 +++ b/main.cpp Mon Dec 29 21:40:55 2014 +0000 @@ -3,10 +3,13 @@ * Alarm and Monitoring application */ #include "mbed.h" +#include "rtos.h" +#include "mbed_rpc.h" +#include "Arguments.h" + #include "eeprom.h" #include "EthernetInterface.h" #include "NTPClient.h" -#include "rtos.h" #include "my_eeprom_funcs.h" #include "Watchdog.h" @@ -40,10 +43,16 @@ EthernetInterface eth(&spi, PA_4, PC_9); // spi, cs, reset #endif -// Serial -Serial uart(USBTX,USBRX); - -// Digital inputs +//Use the RPC enabled wrapped class - see RpcClasses.h for more info +// DigitalIn +RpcDigitalIn di0(PB_14, "din0"); +RpcDigitalIn di1(PB_12, "din1"); +RpcDigitalIn di2(PB_10, "din2"); +RpcDigitalIn di3(PB_1, "din3"); +RpcDigitalIn di4(PB_15, "din4"); +RpcDigitalIn di5(PB_13, "din5"); +RpcDigitalIn di6(PB_11, "din6"); +RpcDigitalIn di7(PB_2, "din7"); DigitalIn din0(PB_14); DigitalIn din1(PB_12); DigitalIn din2(PB_10); @@ -52,7 +61,15 @@ DigitalIn din5(PB_13); DigitalIn din6(PB_11); DigitalIn din7(PB_2); -// Digital outputs +// DigitalOut +RpcDigitalOut do0(PB_3, "dout0"); +RpcDigitalOut do1(PB_5, "dout1"); +RpcDigitalOut do2(PB_7, "dout2"); +RpcDigitalOut do3(PB_9, "dout3"); +RpcDigitalOut do4(PD_2, "dout4"); +RpcDigitalOut do5(PB_4, "dout5"); +RpcDigitalOut do6(PB_6, "dout6"); +RpcDigitalOut do7(PB_8, "dout7"); DigitalOut dout0(PB_3); DigitalOut dout1(PB_5); DigitalOut dout2(PB_7); @@ -61,18 +78,23 @@ DigitalOut dout5(PB_4); DigitalOut dout6(PB_6); DigitalOut dout7(PB_8); -// Analog inputs +// AnalogIn +RpcAnalogIn adc10(PC_0, "ain0"); // adc10 +RpcAnalogIn adc11(PC_1, "ain1"); // adc11 AnalogIn ain0(PC_0); AnalogIn ain1(PC_1); -// Analog outputs -//AnalogOut ano0(PA_8); -//AnalogOut ano1(PA_15); - +// 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("timer1"); // Watchdog Watchdog wdt; - /* * EEPROM section */ @@ -153,7 +175,8 @@ * Protocol */ // Commands -#define DEVICE_ID "NNIO" +#define DEVICE_CONFIG_CODE "NNCF" +#define DEVICE_CONTROL_CODE "NNIO" #define RECEIVING_PROTOCOL_LENGTH 58 #define SENDING_PROTOCOL_LENGTH 39 @@ -161,14 +184,14 @@ #define SET_NETWORK_CONFIG_CMD_LENGTH 19 #define UPDATE_TCP_SERVER_INFO_COMMAND_LENGTH 12 -#define QUERY_DISCOVERY_CMD "NNIODS" -#define QUERY_IP_CMD "NNIOIP" -#define QUERY_SUBNET_CMD "NNIOSN" -#define QUERY_GATEWAY_CMD "NNIOGW" -#define QUERY_MAC_CMD "NNIOMC" -#define QUERY_UDP_PORT_CMD "NNIOUP" -#define QUERY_TCP_PORT_CMD "NNIOTP" -#define QUERY_UPDATE_TIME_CMD "NNIOTM" +#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' @@ -366,6 +389,7 @@ if (n <= 0) break; // got some data, test it + tcp_receiving_buffer[n] = '\0'; // for debugging purpose DBG("TCP server received: %s", tcp_receiving_buffer); process_control_command(tcp_receiving_buffer, n); } // end loop if no data received within timeout @@ -375,38 +399,40 @@ #endif #ifdef UDP_SERVER - bool config_mode_flag; + 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_ID, eth.getMACAddress(), eth.getIPAddress()); + sprintf(str, "%s%s%s", DEVICE_CONFIG_CODE, eth.getMACAddress(), eth.getIPAddress()); udp_server.sendTo(ep_udp_client, str, strlen(str)); - } // NNIODS + } // NNCFDS else if ((n == QUERY_NETWORK_CONFIG_CMD_LENGTH) && (strstr(udp_receiving_buffer, QUERY_IP_CMD) != NULL)) { config_mode_flag = true; - DBG("Enabled configuration mode..."); + DBG("Entered configuration mode..."); DBG("!!! RESET when finished"); - } // NNIOIP + } // NNCFIP - // if received NNIOIP, enter config mode + // if received NNCFIP, enter config mode if (config_mode_flag) { while (n > 0) { // got some data, test it - DBG("UDP received (%s) from (%s) and port (%d)", udp_receiving_buffer, ep_udp_client.get_address(), ep_udp_client.get_port()); + 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) - else if (n > 0) { // process control packages sent using UDP + else if ((n > 0) && (!discovery_mode_flag)) { // process control packages sent using UDP process_control_command(udp_receiving_buffer, n); } #endif @@ -416,37 +442,40 @@ void process_config_command(char* received_buffer, int len) { + DBG("Processing configuration command"); + // process received data // a configuration command always starts with NN - if ((received_buffer[0] == 'N') && (received_buffer[1] == 'N')) { + 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: NNIODS, NNIOTP, NNIOUP, NNIOTM + // 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())); - } // NNIOIP + } // NNCFIP else if (strstr(received_buffer, QUERY_SUBNET_CMD) != NULL) { udp_server.sendTo(ep_udp_client, eth.getNetworkMask(), strlen(eth.getNetworkMask())); - } // NNIOSN + } // NNCFSN else if (strstr(received_buffer, QUERY_GATEWAY_CMD) != NULL) { udp_server.sendTo(ep_udp_client, eth.getGateway(), strlen(eth.getGateway())); - } // NNIOGW + } // NNCFGW else if (strstr(received_buffer, QUERY_MAC_CMD) != NULL) { udp_server.sendTo(ep_udp_client, eth.getMACAddress(), strlen(eth.getMACAddress())); - } // NNIOMC + } // 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)); - } // NNIOTP + } // 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)); - } // NNIOUP + } // NNCFUP else if (strstr(received_buffer, QUERY_UPDATE_TIME_CMD) != NULL) { #ifdef NTP char str_time[50]; @@ -470,43 +499,43 @@ sprintf(str_time, "DIS"); udp_server.sendTo(ep_udp_client, str_time, strlen(str_time)); #endif - } // NNIOTM + } // NNCFTM break; // length = 19, SET NETWORK CONFIGURATION - // Format: 4E 4E 49 4F C0 A8 00 78 FF FF FF 00 C0 A8 00 01 00 00 01 - // (NNIO; IP: 192.168.0.120; Subnet: 255.255.255.0; GW: 192.168.0.1; MAC: 0 0 1) + // 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_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_ID)]); // parameters from 5th char, 15-bytes + write_eeprom_network(&received_buffer[strlen(DEVICE_CONFIG_CODE)]); // parameters from 5th char, 15-bytes break; } // length = 12, SET TCP SERVER CONFIGURATION // auto update & its time period, TCP server configuration (IP & port) - // Format: 4E 4E 49 4F 'Y' 01 C0 A8 00 09 E0 2E (LSB MSB) - // NNIO Auto 1s 192.168.0.9 12000 + // 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_ID); + 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_ID)]); // parameters from 5th char + write_eeprom_tcpserver(&received_buffer[strlen(DEVICE_CONFIG_CODE)]); // parameters from 5th char break; } default: break; } // switch (n), check configuration command length - } // if starts with NN, a config command + } // if starts with NNCF, a config command else { // if not a command, check to see if it is a 6-byte data package // process 6-byte data package } @@ -519,11 +548,32 @@ { char* received_frame; int pos; + char inbuf[256], outbuf[256]; + DBG("Processing control command"); + + // check RPC protocol + strncpy(inbuf, received_buffer, len); + inbuf[len] = '\r'; // use inbuf for RPC protocol + inbuf[len+1] = '\n'; + inbuf[len+2] = '\0'; // add CR-LF + DBG("inbuf = %s", inbuf); + if ((len > 0) && (inbuf[0] == '/')) { + bool result; + result = RPC::call(inbuf, outbuf); + if (result) { + DBG("I: %s O: %s\n", inbuf, outbuf); + } + else { + ERR("Failed: %s", inbuf); + } + } + + // NNIO protocol while (len >= RECEIVING_PROTOCOL_LENGTH) { // find device ID DBG("Checking device ID..."); - char* id = strstr(received_buffer, DEVICE_ID); + char* id = strstr(received_buffer, DEVICE_CONTROL_CODE); if (id == NULL) { DBG("No device ID found"); break; @@ -575,8 +625,7 @@ DBG("Sent"); } } - - DBG("Successful"); + DBG("Successfully processed."); } @@ -586,12 +635,12 @@ int ethernet_init(void) { int dhcp_ret, ret; - DBG("Start initialising ethernet"); + DBG("Initialising ethernet..."); // if not configured, try dhcp dhcp_ret = -1; if (configured_ip != DEFAULT_ENABLE_FLAG_VALUE) { - DBG("Connecting DHCP server..."); + DBG("Connecting to DHCP server..."); dhcp_ret = eth.init(u8mac); if (dhcp_ret == 0) dhcp_ret = eth.connect(); @@ -646,7 +695,7 @@ * 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_ID, 4); // device id + 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);
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mbed-rpc.lib Mon Dec 29 21:40:55 2014 +0000 @@ -0,0 +1,1 @@ +http://developer.mbed.org/users/olympux/code/mbed-rpc/#5e3dc699ab25
--- a/my_eeprom_funcs.lib Wed Dec 24 13:23:33 2014 +0000 +++ b/my_eeprom_funcs.lib Mon Dec 29 21:40:55 2014 +0000 @@ -1,1 +1,1 @@ -http://mbed.org/users/olympux/code/my_eeprom_funcs/#4fc4b1b5509b +http://mbed.org/users/olympux/code/my_eeprom_funcs/#b5fbb35bbc02
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/protocol_rpc.txt Mon Dec 29 21:40:55 2014 +0000 @@ -0,0 +1,50 @@ +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: din0 - din7 + + Commands: /din0/read x + +3. Digital outputs + + Digital outputs: dout0 - dout7 + + Commands: + /dout0/read x + /dout0/write 1 + +3. Analog inputs + + Analog inputs: ain0 - ain1 + + Commands: + /ain0/read x: returns a value between 0 to 1 + /ain0/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: + /timer1/start x + /timer1/stop x + /timer1/reset x + /timer1/read x: returns float, between 0 to 1. + /timer1/read_ms + /timer1/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 \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/protocol_v2.0.txt Mon Dec 29 21:40:55 2014 +0000 @@ -0,0 +1,93 @@ +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
--- a/readme.txt Wed Dec 24 13:23:33 2014 +0000 +++ b/readme.txt Mon Dec 29 21:40:55 2014 +0000 @@ -1,16 +1,3 @@ -#NNIO Command and Configuration Processors - -This version is forked from F103_NNIO git rev25:48dd18cc147c, which is used for running demos. -It intends to separate command processor and method to receive commands. - -v2.0 24/12/2014 - + Use official mbed-rtos. - - - - - - Features 0. Wait for 2s after resetting for ethernet to work. 1. When auto update enabled and no TCP server is running, module will try to connect to server which results in a timeout every 15s. @@ -34,5 +21,12 @@ + Added: Discovery command now returns NNIO MAC IP + Added: receive and process receiving protocol using UDP -v1.2.1 01/12/2014 - + Modified: enter config mode with query ip command, not discovery command \ No newline at end of file +v1.2.1 01/12/2014 (demo version: git rev25) + + Modified: enter config mode with query ip command, not discovery command + +v2.0 24/12/2014 + + Use official mbed-rtos + + Updated: configuration comands now use prefix NNCF, control commands use prefix NNIO. + + Run with demo software v2.0 + + Added RPC through TCP/UDP: tested after fixed (Rpc)DigitalIn/Out names. + RPC control commands can be sent to TCP/UDP server on NNIO module. However, no reply yet, only debug with uart. \ No newline at end of file