
-
Dependencies: EthernetInterface TCPSocket_HelloWorld mbed-rtos mbed
Fork of TCPSocket_HelloWorld by
main.cpp@16:22169975b5d8, 2016-02-09 (annotated)
- Committer:
- offroad
- Date:
- Tue Feb 09 11:56:52 2016 +0000
- Revision:
- 16:22169975b5d8
- Parent:
- 15:10c1be621ad6
initial public release
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
donatien | 0:bb128f0e952f | 1 | #include "mbed.h" |
donatien | 0:bb128f0e952f | 2 | #include "EthernetInterface.h" |
offroad | 15:10c1be621ad6 | 3 | LocalFileSystem local("local"); |
offroad | 15:10c1be621ad6 | 4 | |
offroad | 15:10c1be621ad6 | 5 | #define NPORTS 30 |
offroad | 15:10c1be621ad6 | 6 | static char FSM_buf[16]; |
offroad | 15:10c1be621ad6 | 7 | #define FSM_STATE_IDLE 0 |
offroad | 15:10c1be621ad6 | 8 | #define FSM_STATE_READNUM 1 |
offroad | 15:10c1be621ad6 | 9 | static int FSM_state1 = FSM_STATE_IDLE; |
offroad | 15:10c1be621ad6 | 10 | static int FSM_state2 = 0; |
offroad | 15:10c1be621ad6 | 11 | static char FSM_cmd = 'x'; |
offroad | 15:10c1be621ad6 | 12 | |
offroad | 16:22169975b5d8 | 13 | static void FSM_reset(){ |
offroad | 16:22169975b5d8 | 14 | FSM_state1 = FSM_STATE_IDLE; |
offroad | 16:22169975b5d8 | 15 | FSM_state2 = 0; |
offroad | 16:22169975b5d8 | 16 | FSM_cmd = 'x'; |
offroad | 16:22169975b5d8 | 17 | } |
offroad | 16:22169975b5d8 | 18 | |
offroad | 16:22169975b5d8 | 19 | static void FSM_handleChar(DigitalOut* gpo, char inputChar, char** bufOut){ |
offroad | 15:10c1be621ad6 | 20 | |
offroad | 15:10c1be621ad6 | 21 | // === handle incoming char === |
offroad | 15:10c1be621ad6 | 22 | switch (FSM_state1){ |
offroad | 15:10c1be621ad6 | 23 | case FSM_STATE_IDLE: |
offroad | 15:10c1be621ad6 | 24 | // === handle new command char === |
offroad | 15:10c1be621ad6 | 25 | switch(inputChar){ |
offroad | 15:10c1be621ad6 | 26 | case '+': |
offroad | 15:10c1be621ad6 | 27 | case '-': |
offroad | 15:10c1be621ad6 | 28 | case '?': |
offroad | 15:10c1be621ad6 | 29 | FSM_cmd = inputChar; |
offroad | 15:10c1be621ad6 | 30 | FSM_state1 = FSM_STATE_READNUM; |
offroad | 15:10c1be621ad6 | 31 | goto doneCont; |
offroad | 15:10c1be621ad6 | 32 | default: |
offroad | 15:10c1be621ad6 | 33 | goto reset; |
offroad | 15:10c1be621ad6 | 34 | } // switch inputChar |
offroad | 15:10c1be621ad6 | 35 | goto lockup; |
offroad | 15:10c1be621ad6 | 36 | case FSM_STATE_READNUM: |
offroad | 15:10c1be621ad6 | 37 | if (FSM_state2 > 8) |
offroad | 15:10c1be621ad6 | 38 | goto reset; // too many digits |
offroad | 15:10c1be621ad6 | 39 | |
offroad | 15:10c1be621ad6 | 40 | if ((inputChar == 32 || inputChar == 9 || inputChar == 13 || inputChar == 10) && (FSM_state2 > 0)){ |
offroad | 15:10c1be621ad6 | 41 | // === got command terminated by whitespace, and at least one digit |
offroad | 15:10c1be621ad6 | 42 | FSM_buf[FSM_state2] = 0; |
offroad | 15:10c1be621ad6 | 43 | int ixGpio = atoi(FSM_buf); |
offroad | 15:10c1be621ad6 | 44 | if (ixGpio < 0 || ixGpio >= NPORTS) |
offroad | 15:10c1be621ad6 | 45 | goto reset; // invalid port number |
offroad | 15:10c1be621ad6 | 46 | switch(FSM_cmd){ |
offroad | 15:10c1be621ad6 | 47 | case '+': |
offroad | 15:10c1be621ad6 | 48 | // === set GPO === |
offroad | 15:10c1be621ad6 | 49 | *(gpo+ixGpio) = 1; |
offroad | 15:10c1be621ad6 | 50 | goto reset; // success |
offroad | 15:10c1be621ad6 | 51 | case '-': |
offroad | 15:10c1be621ad6 | 52 | // === clear GPO === |
offroad | 15:10c1be621ad6 | 53 | *(gpo+ixGpio) = 0; |
offroad | 15:10c1be621ad6 | 54 | goto reset; // success |
offroad | 15:10c1be621ad6 | 55 | case '?': |
offroad | 15:10c1be621ad6 | 56 | // === query GPO state (verify) === |
offroad | 16:22169975b5d8 | 57 | *((*bufOut)++) = *(gpo+ixGpio) ? '1' : '0'; |
offroad | 16:22169975b5d8 | 58 | *((*bufOut)++) = 13; |
offroad | 16:22169975b5d8 | 59 | *((*bufOut)++) = 10; |
offroad | 15:10c1be621ad6 | 60 | goto reset; // success |
offroad | 15:10c1be621ad6 | 61 | default: |
offroad | 15:10c1be621ad6 | 62 | goto reset; // invalid command byte |
offroad | 15:10c1be621ad6 | 63 | } |
offroad | 15:10c1be621ad6 | 64 | } |
offroad | 15:10c1be621ad6 | 65 | |
offroad | 15:10c1be621ad6 | 66 | if (inputChar >= '0' && inputChar <= '9'){ |
offroad | 15:10c1be621ad6 | 67 | // === append digit === |
offroad | 15:10c1be621ad6 | 68 | FSM_buf[FSM_state2++] = inputChar; |
offroad | 15:10c1be621ad6 | 69 | goto doneCont; |
offroad | 15:10c1be621ad6 | 70 | } |
offroad | 15:10c1be621ad6 | 71 | |
offroad | 15:10c1be621ad6 | 72 | // invalid character (not digit) |
offroad | 15:10c1be621ad6 | 73 | goto reset; |
offroad | 15:10c1be621ad6 | 74 | default: |
offroad | 15:10c1be621ad6 | 75 | // === invalid FSM state === |
offroad | 15:10c1be621ad6 | 76 | goto lockup; |
offroad | 15:10c1be621ad6 | 77 | } // switch FSM_state1 |
offroad | 15:10c1be621ad6 | 78 | |
offroad | 16:22169975b5d8 | 79 | // === internal error. Should never be reached. === |
offroad | 15:10c1be621ad6 | 80 | lockup: |
offroad | 15:10c1be621ad6 | 81 | goto lockup; |
offroad | 15:10c1be621ad6 | 82 | |
offroad | 15:10c1be621ad6 | 83 | // === reset state machine (on completion and any invalid input === |
offroad | 15:10c1be621ad6 | 84 | reset: |
offroad | 16:22169975b5d8 | 85 | FSM_reset(); |
offroad | 15:10c1be621ad6 | 86 | |
offroad | 15:10c1be621ad6 | 87 | doneCont: |
offroad | 15:10c1be621ad6 | 88 | return; |
offroad | 15:10c1be621ad6 | 89 | } |
donatien | 0:bb128f0e952f | 90 | |
emilmont | 7:65188f4a8c25 | 91 | int main() { |
offroad | 16:22169975b5d8 | 92 | printf("\r\nLANGPIO server v2.1 20151107 mn\r\n"); |
offroad | 15:10c1be621ad6 | 93 | fflush(stdout); |
offroad | 15:10c1be621ad6 | 94 | static DigitalOut myGpo[NPORTS] = { |
offroad | 15:10c1be621ad6 | 95 | DigitalOut(LED1), |
offroad | 15:10c1be621ad6 | 96 | DigitalOut(LED2), |
offroad | 15:10c1be621ad6 | 97 | DigitalOut(LED3), |
offroad | 15:10c1be621ad6 | 98 | DigitalOut(LED4), |
offroad | 15:10c1be621ad6 | 99 | DigitalOut(p5), |
offroad | 15:10c1be621ad6 | 100 | DigitalOut(p6), |
offroad | 15:10c1be621ad6 | 101 | DigitalOut(p7), |
offroad | 15:10c1be621ad6 | 102 | DigitalOut(p8), |
offroad | 15:10c1be621ad6 | 103 | DigitalOut(p9), |
offroad | 15:10c1be621ad6 | 104 | DigitalOut(p10), |
offroad | 15:10c1be621ad6 | 105 | DigitalOut(p11), |
offroad | 15:10c1be621ad6 | 106 | DigitalOut(p12), |
offroad | 15:10c1be621ad6 | 107 | DigitalOut(p13), |
offroad | 15:10c1be621ad6 | 108 | DigitalOut(p14), |
offroad | 15:10c1be621ad6 | 109 | DigitalOut(p15), |
offroad | 15:10c1be621ad6 | 110 | DigitalOut(p16), |
offroad | 15:10c1be621ad6 | 111 | DigitalOut(p17), |
offroad | 15:10c1be621ad6 | 112 | DigitalOut(p18), |
offroad | 15:10c1be621ad6 | 113 | DigitalOut(p19), |
offroad | 15:10c1be621ad6 | 114 | DigitalOut(p20), |
offroad | 15:10c1be621ad6 | 115 | DigitalOut(p21), |
offroad | 15:10c1be621ad6 | 116 | DigitalOut(p22), |
offroad | 15:10c1be621ad6 | 117 | DigitalOut(p23), |
offroad | 15:10c1be621ad6 | 118 | DigitalOut(p24), |
offroad | 15:10c1be621ad6 | 119 | DigitalOut(p25), |
offroad | 15:10c1be621ad6 | 120 | DigitalOut(p26), |
offroad | 15:10c1be621ad6 | 121 | DigitalOut(p27), |
offroad | 15:10c1be621ad6 | 122 | DigitalOut(p28), |
offroad | 15:10c1be621ad6 | 123 | DigitalOut(p29), |
offroad | 15:10c1be621ad6 | 124 | DigitalOut(p30)}; |
offroad | 15:10c1be621ad6 | 125 | |
offroad | 15:10c1be621ad6 | 126 | char buffer[256]; |
offroad | 15:10c1be621ad6 | 127 | char ipAddress[256]; |
offroad | 15:10c1be621ad6 | 128 | char subnetMask[256]; |
offroad | 15:10c1be621ad6 | 129 | sprintf(ipAddress, "%s", "192.168.1.10"); |
offroad | 15:10c1be621ad6 | 130 | sprintf(subnetMask, "%s", "255.255.255.0"); |
offroad | 15:10c1be621ad6 | 131 | int port = 7; |
offroad | 15:10c1be621ad6 | 132 | |
offroad | 15:10c1be621ad6 | 133 | FILE* f = fopen("/local/config.txt", "r"); |
offroad | 15:10c1be621ad6 | 134 | if (f != NULL){ |
offroad | 15:10c1be621ad6 | 135 | int n = fscanf(f, "%s", ipAddress); if (n <= 0) goto endOfFile; |
offroad | 15:10c1be621ad6 | 136 | n = fscanf(f, "%s", subnetMask); if (n <= 0) goto endOfFile; |
offroad | 15:10c1be621ad6 | 137 | n = fscanf(f, "%s", buffer); if (n <= 0) goto endOfFile; |
offroad | 15:10c1be621ad6 | 138 | port = atoi(buffer); |
offroad | 15:10c1be621ad6 | 139 | endOfFile: |
offroad | 15:10c1be621ad6 | 140 | fclose(f); |
offroad | 15:10c1be621ad6 | 141 | } |
offroad | 15:10c1be621ad6 | 142 | |
donatien | 0:bb128f0e952f | 143 | EthernetInterface eth; |
offroad | 15:10c1be621ad6 | 144 | eth.init(ipAddress, subnetMask, ""); |
donatien | 0:bb128f0e952f | 145 | eth.connect(); |
offroad | 15:10c1be621ad6 | 146 | printf("IP address: %s (configured: %s) port %i\r\n", eth.getIPAddress(), ipAddress, port); |
donatien | 0:bb128f0e952f | 147 | |
offroad | 15:10c1be621ad6 | 148 | TCPSocketServer server; |
offroad | 15:10c1be621ad6 | 149 | server.bind(port); |
offroad | 15:10c1be621ad6 | 150 | server.listen(); |
offroad | 15:10c1be621ad6 | 151 | |
emilmont | 7:65188f4a8c25 | 152 | while (true) { |
offroad | 15:10c1be621ad6 | 153 | printf("\nWait for new connection...\n"); |
offroad | 15:10c1be621ad6 | 154 | TCPSocketConnection client; |
offroad | 15:10c1be621ad6 | 155 | server.accept(client); |
offroad | 15:10c1be621ad6 | 156 | client.set_blocking(true, 0); |
offroad | 15:10c1be621ad6 | 157 | |
offroad | 15:10c1be621ad6 | 158 | printf("Connection from: %s\n", client.get_address()); |
offroad | 15:10c1be621ad6 | 159 | client.send_all(">\r\n", 3); |
offroad | 16:22169975b5d8 | 160 | FSM_reset(); |
offroad | 16:22169975b5d8 | 161 | |
offroad | 15:10c1be621ad6 | 162 | // === main loop === |
offroad | 15:10c1be621ad6 | 163 | while (true) { |
offroad | 15:10c1be621ad6 | 164 | |
offroad | 15:10c1be621ad6 | 165 | // === read data from socket === |
offroad | 15:10c1be621ad6 | 166 | int n = client.receive(buffer, sizeof(buffer)); |
offroad | 15:10c1be621ad6 | 167 | |
offroad | 15:10c1be621ad6 | 168 | // === detect connection break === |
offroad | 15:10c1be621ad6 | 169 | if (n < 0) |
offroad | 16:22169975b5d8 | 170 | goto conn_exit; |
offroad | 15:10c1be621ad6 | 171 | |
offroad | 16:22169975b5d8 | 172 | // maximum length of a single reply. Anything longer will be split. |
offroad | 16:22169975b5d8 | 173 | #define MAX_PACKETLEN (1024) |
offroad | 16:22169975b5d8 | 174 | // maximum length of a single message to guarantee there is enough output buffer |
offroad | 16:22169975b5d8 | 175 | #define MAX_MSGLEN (16) |
offroad | 16:22169975b5d8 | 176 | char bufOut[MAX_PACKETLEN]; |
offroad | 16:22169975b5d8 | 177 | char* pWriteStart = &bufOut[0]; |
offroad | 16:22169975b5d8 | 178 | char* pWrite = pWriteStart; |
offroad | 16:22169975b5d8 | 179 | |
offroad | 16:22169975b5d8 | 180 | // === iterate over input characters === |
offroad | 15:10c1be621ad6 | 181 | int ix; |
offroad | 16:22169975b5d8 | 182 | for (ix = 0; ix < n; ++ix){ |
offroad | 16:22169975b5d8 | 183 | FSM_handleChar(&myGpo[0], buffer[ix], &pWrite); |
offroad | 15:10c1be621ad6 | 184 | |
offroad | 16:22169975b5d8 | 185 | // === send reply, if there is any === |
offroad | 16:22169975b5d8 | 186 | // - when processing last char of incoming packet |
offroad | 16:22169975b5d8 | 187 | // - when output buffer is too full |
offroad | 16:22169975b5d8 | 188 | int nInBuf = pWrite - pWriteStart; |
offroad | 16:22169975b5d8 | 189 | if (nInBuf > 0) |
offroad | 16:22169975b5d8 | 190 | if ((ix == n-1) || (nInBuf > MAX_PACKETLEN - MAX_MSGLEN)){ |
offroad | 16:22169975b5d8 | 191 | client.send_all(bufOut, nInBuf); |
offroad | 16:22169975b5d8 | 192 | pWrite = pWriteStart; |
offroad | 16:22169975b5d8 | 193 | } |
offroad | 16:22169975b5d8 | 194 | } // for input character |
offroad | 15:10c1be621ad6 | 195 | } // while connection |
offroad | 16:22169975b5d8 | 196 | |
offroad | 16:22169975b5d8 | 197 | conn_exit: |
offroad | 15:10c1be621ad6 | 198 | client.close(); |
offroad | 15:10c1be621ad6 | 199 | } // eternal main loop |
offroad | 15:10c1be621ad6 | 200 | } // void main |