Audi McAvoy / Mbed 2 deprecated FRDM_K64F-TFTP

Dependencies:   EthernetInterface mbed-rtos mbed

Fork of FRDM_K64F-Ethernet by Rangel Alvarado

Files at this revision

API Documentation at this revision

Comitter:
audim
Date:
Thu Oct 11 15:25:58 2018 +0000
Parent:
0:bbc9cfdee3bc
Child:
2:28ddb9b073ec
Commit message:
first working concept; only supports ETH0 due to "eTSEC1" setting in environment variables

Changed in this revision

env.h Show annotated file Show diff for this revision Revisions of this file
main.cpp Show annotated file Show diff for this revision Revisions of this file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/env.h	Thu Oct 11 15:25:58 2018 +0000
@@ -0,0 +1,77 @@
+/* If you make any chnages to this file, then you must take the following steps.
+**  1) compile and upload this program to FRDM-K64F
+**  2) reset FRDM-K64F and wait for green light
+**  3) connect FRDM-K64F and IPCU 2 to the same Ethernet switch
+**  4) gain access to the IPCU 2 u-boot prompt
+**  5) type 'run upenv' and press Enter
+**  6) wait for green light
+**  7) type 'run chkenv' and press Enter
+       notice that there is an error, for example "byte at 0x0100033b (0x62) != byte at 0x0200033b (0x63)"
+**  8) type 'md.b 2000x00 100' and press Enter
+       replace the x with the base address in the error message
+       in the example above the error was at 33b, so enter 'md.b 2000300 100' and press Enter
+**  9) find the 'filesize' entry in the memory dump, and edit the filesize value below to match
+** 10) repeat steps 1 through 7 above, this time there should be no error message
+*/
+char *env_string[] = {
+"addargs=setenv bootargs $bootargs ip=$ipaddr:$serverip:$gatewayip:$netmask:$hostname:$netdev:off console=$consoledev,$baudrate sdhci-of.max_clock=$sdclk\n",
+"baudrate=115200\n",
+"bootcmd=echo && echo This is a test environment. Must 'run upenv' against && echo production server to restore production environment.\n",
+"bootdelay=0\n",
+"bootdrive=sda1\n",
+"bootfile=uImage\n",
+"chkenv=mw.b 1000000 0 1000 && tftpboot 1000000 $tftpdir/$ubootenv && mw.b 2000000 0 1000 && env export -t 2000000 && cmp.b 1000000 2000000 $filesize\n",
+"consoledev=ttyS0\n",
+"doboot=bootm $loadaddr - $fdtaddr;\n",
+"dtboffset=180000\n",
+"dtbsize=3500\n",
+"envimport=if mmc part 0 && fatload mmc 0:1 $loadaddr $ubootenv; then env -d import $loadaddr $filesize && saveenv; else echo \"Missing file: $ubootenv\"; fi'\n",
+"ethact=eTSEC1\n",
+"ethprime=eTSEC1\n",
+"fdtaddr=ff0000\n",
+"fdtfile=p1022ipcu_dtb\n",
+"fileaddr=1000000\n",
+"filesize=c5c\n",
+"flashfsfile=flashfs_jffs2\n",
+"flashfsoffset=A00000\n",
+"flashfssize=600000\n",
+"flashhdboot=run sethdargs addargs;nand read $fdtaddr $dtboffset $dtbsize;nand read $loadaddr $kernoffset $kernsize; run doboot;\n",
+"gatewayip=192.168.1.1\n",
+"hostname=ipcu\n",
+"hwconfig=esdhc;\n",
+"ipaddr=192.168.1.100\n",
+"kernoffset=200000\n",
+"kernsize=800000\n",
+"loadaddr=1000000\n",
+"minimalboot=run setminimalargs addargs; nand read $fdtaddr $dtboffset $dtbsize; nand read $loadaddr $kernoffset $kernsize; run doboot;\n",
+"minimalfsfile=rootfs_jffs2\n",
+"minimalfsoffset=1000000\n",
+"minimalfssize=F000000\n",
+"monitor=1\n",
+"netdev=eth0\n",
+"netmask=255.255.255.0\n",
+"nfsargs=setenv bootargs root=/dev/nfs rw nfsroot=$serverip:$rootpath\n",
+"nfsboot=run nfsargs addargs nfsget doboot;\n",
+"nfsget=nfs $loadaddr $rootpath/boot/$bootfile; nfs $fdtaddr $rootpath/boot/$fdtfile;\n",
+"ramboot=setenv bootargs root=/dev/ram rw console=$consoledev,$baudrate;tftp $ramdiskaddr $tftpdir/$ramdiskfile;tftp $loadaddr $tftpdir/$bootfile;tftp $fdtaddr $tftpdir/$fdtfile;bootm $loadaddr $tftpdir/$ramdiskaddr $fdtaddr\n",
+"ramdiskaddr=2000000\n",
+"ramdiskfile=uramdisk\n",
+"rootpath=/opt/nfsroot\n",
+"sdclk=22000000\n",
+"serverip=192.168.1.10\n",
+"sethdargs=setenv bootargs root=/dev/$bootdrive rw\n",
+"setminimalargs=setenv bootargs tftpserver=$serverip tftpdir=$tftpdir root=/dev/mtdblock4 rw rootfstype=jffs2\n",
+"tftpdir=/production\n",
+"tftpkernel=setenv bootargs root=/dev/sda1 rw console=ttyS0,115200; tftpboot $loadaddr $tftpdir/$bootfile;tftpboot $fdtaddr $tftpdir/$fdtfile;run doboot\n",
+"uboot=u-boot-nand_bin\n",
+"ubootenv=u-boot-env_txt\n",
+"updtb=tftpboot $loadaddr $tftpdir/$fdtfile; nand erase $dtboffset $filesize; nand write $loadaddr $dtboffset $filesize;\n",
+"upenv=if tftpboot $loadaddr $tftpdir/$ubootenv; then env import -d $loadaddr $filesize && saveenv; else echo \"Missing file: $ubootenv\"; fi\n",
+"upflashfs=tftpboot $loadaddr $tftpdir/$flashfsfile; nand erase $flashfsoffset $flashfssize; nand write $loadaddr $flashfsoffset $filesize;\n",
+"upkernel=tftpboot $loadaddr $tftpdir/$bootfile; nand erase $kernoffset $filesize; nand write $loadaddr $kernoffset $filesize;\n",
+"upminimal=tftpboot $loadaddr $tftpdir/$minimalfsfile; nand erase $minimalfsoffset $minimalfssize; nand write $loadaddr $minimalfsoffset $filesize;\n",
+"upuboot=if tftpboot $loadaddr $tftpdir/$uboot; then nand erase 0 $filesize; nand write $loadaddr 0 $filesize; fi\n",
+"usb_phy_type=ulpi\n",
+"vtos=tftpboot 0x01000000 $tftpdir/vtos.ipcu.bin; go 0x01003000\n",
+"\0" // end of table
+};
--- 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
+}