Super lightweight, not at all robust, TFTP server for FRDM-K64F eval board.

Dependencies:   EthernetInterface mbed-rtos mbed

Fork of FRDM_K64F-Ethernet by Rangel Alvarado

Super lightweight, not at all robust, TFTP server for FRDM-K64F eval board. This tool supports read-only access to two files. 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.

main.cpp

Committer:
audim
Date:
2018-10-11
Revision:
1:2944c0d494ff
Parent:
0:bbc9cfdee3bc
Child:
2:28ddb9b073ec

File content as of revision 1:2944c0d494ff:

/*
** 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"
#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;
    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();
    
    // main loop    
    while (true) {

        // 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");
        }
        // 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();
    }
}