Audi McAvoy / Mbed 2 deprecated FRDM_K64F-TFTP

Dependencies:   EthernetInterface mbed-rtos mbed

Fork of FRDM_K64F-Ethernet by Rangel Alvarado

Revision:
1:2944c0d494ff
Parent:
0:bbc9cfdee3bc
Child:
2:28ddb9b073ec
--- a/main.cpp	Mon Sep 22 02:34:12 2014 +0000
+++ b/main.cpp	Thu Oct 11 15:25:58 2018 +0000
@@ -1,38 +1,143 @@
+/*
+** Super lightweight, not at all robust, TFTP server for FRDM-K64F eval board.
+** This tool supports read-only access to one file. It does not support NACK responses
+** or timeouts. The tool is intended for use by our test department to check out Ethernet
+** functionality on our main processor board.
+**
+** 11 October 2018
+** - am
+*/
+
 #include "mbed.h"
 #include "EthernetInterface.h"
- 
-#define MBED_DEV_IP       "192.168.0.52"
-#define MBED_DEV_MASK     "255.255.255.0"
-#define MBED_DEV_GW       "0.0.0.0"
-#define ECHO_SERVER_PORT   5000
+#include "string.h"
+
+#include "env.h"
+
+#define IP_ADDR     "192.168.1.10"
+#define NET_MASK    "255.255.255.0"
+#define GATEWAY     "192.168.1.1"
+#define TFTP_PORT   69
+
+#define LED_ON  0
+#define LED_OFF 1
+
+// status LEDs
+DigitalOut led_error(LED1);     // red
+DigitalOut led_waiting(LED2);   // green
+DigitalOut led_connected(LED3); // blue
+
+// TFTP opcodes
+enum opcode { RRQ=1, WRQ, DATA, ACK, ERROR };
+
+// TFTP packet structure
+typedef union {
+
+    uint16_t opcode;
+
+    struct {
+        uint16_t opcode; // RRQ or WRQ
+        char filename_and_mode[512];
+    } request;
 
- 
+    struct {
+        uint16_t opcode; // DATA
+        uint16_t block_number;
+        char data[512];
+    } data;
+
+    struct {
+        uint16_t opcode; // ACK
+        uint16_t block_number;
+    } ack;
+
+    struct {
+        uint16_t opcode; // ERROR
+        uint16_t error_code;
+        char error_string[512];
+    } error;
+
+} tftp_packet_t;
+
+int tftp_send_error(UDPSocket socket, Endpoint end_point, int error_code, char *error_string) {
+    
+    tftp_packet_t packet;
+    char *packet_ptr = (char *)&packet;
+
+    packet.opcode = htons(ERROR);
+    packet.error.error_code = htons(error_code);
+    strcpy(packet.error.error_string, error_string);
+
+    return socket.sendTo(end_point, packet_ptr, 4 + strlen(error_string)); // 4 = sizeof(opcode + error_code)
+}
+
 int main (void) {
+
     EthernetInterface eth;
-    eth.init(MBED_DEV_IP, MBED_DEV_MASK, MBED_DEV_GW); //Assign a device ip, mask and gateway
+    UDPSocket tftp_server;
+    Endpoint client;
+
+    // create data packet storage    
+    tftp_packet_t packet;
+    char *packet_ptr = (char *)&packet;
+
+    // assign ip address, net mask and gateway to Ethernet interface
+    eth.init(IP_ADDR, NET_MASK, GATEWAY);
     eth.connect();
-    printf("IP Address is %s\n", eth.getIPAddress());
     
-    TCPSocketServer server;
-    server.bind(ECHO_SERVER_PORT);
-    server.listen();
-    
+    // main loop    
     while (true) {
-        printf("\nWait for new connection...\n");
-        TCPSocketConnection client;
-        server.accept(client);
-        client.set_blocking(false, 1500); // Timeout after (1.5)s
-        
-        printf("Connection from: %s\n", client.get_address());
-        char buffer[256];
-        while (true) {
-            int n = client.receive(buffer, sizeof(buffer));
-            if (n <= 0) break;
-            
-            client.send_all(buffer, n);
-            if (n <= 0) break;
+
+        // clear status LEDs
+        led_error = LED_OFF;
+        led_waiting = LED_OFF;
+        led_connected = LED_OFF;
+        wait(1); // one second
+
+        // wait for request
+        led_waiting = LED_ON;
+        tftp_server.bind(TFTP_PORT);
+        tftp_server.receiveFrom(client, packet_ptr, sizeof(packet));
+
+        // if it's a read request
+        if (ntohs(packet.opcode) == RRQ) {
+            // and it's for the environment file
+            if (!strncmp(packet.request.filename_and_mode, "/production/u-boot-env_txt", 26)) {
+                led_waiting = LED_OFF;
+                // send file
+                int i_block = 1;
+                int i_string = 0;
+                int i_char = 0;
+                int i_buff = 512;
+                while (i_buff == 512) {
+                    led_connected = LED_ON;
+                    i_buff = 0;
+                    packet.opcode = htons(DATA);
+                    packet.data.block_number = htons(i_block++);
+                    do {
+                        packet.data.data[i_buff++] = env_string[i_string][i_char++];
+                        // check for end of string
+                        if (env_string[i_string][i_char] == '\0') {
+                            i_char = 0;
+                            i_string++;
+                        }
+                    } while ((i_buff < 512) && (env_string[i_string][0] != '\0'));
+                    tftp_server.sendTo(client, packet_ptr, 4 + i_buff); // 4 = sizeof(opcode + block_number)
+                    led_connected = LED_OFF;
+                    led_error = LED_ON;
+                    tftp_server.receiveFrom(client, packet_ptr, sizeof(packet)); // wait for ACK
+                    led_error = LED_OFF;
+                };
+            }
+            // error, we only support the u-boot-env.txt file
+            else tftp_send_error(tftp_server, client, 0, "this test board only supports reading the u-boot-env.txt file");
         }
-        
-        client.close();
+        // error, we only support read requests
+        else tftp_send_error(tftp_server, client, 0, "this test board only supports reading the u-boot-env.txt file");
+
+        led_connected = LED_ON;
+        led_waiting = LED_ON;
+        wait(1); // one second
+        tftp_server.close();
     }
-}
\ No newline at end of file
+}