An access controller for man doors at our facility. It receives Wiegand signals from a keypad/card reader and activates a relay to open the door. Access codes are stored in EEPROM. The active code list is updated from TFTP on a local server.

Dependencies:   24LCxx_I2C CardReader USBHOST

TFTPClient.cpp

Committer:
acesrobertm
Date:
2017-09-25
Revision:
0:a56239ae90c2

File content as of revision 0:a56239ae90c2:


#include "TFTPClient.h"

bool TFTPClient::readFile(char* data, const char* host, const char* filename, const uint16_t port, const uint32_t timeout)
{
    printf("TFTP read file\n");
    m_data = data;
    
    if (m_tftp_addr)
    {
        delete m_tftp_addr;
        m_tftp_addr = NULL;
    }
    m_tftp_addr = new SocketAddress(host, port);
    
    printf("IP: %d\n", m_eth);
    
    m_sock.open(m_eth);
    printf("TFTP before blocking\n");
    m_sock.set_blocking(false);
    printf("TFTP before bind\n");
    m_sock.bind(0);
    
    printf("TFTP port bound\n");
    
    char chunk[TFTP_MAX_PACKET_SIZE];
    uint16_t tftp_opcode = htons(RRQ);
    char tftp_mode[] = "octet";
    
    // Construct read request packet
    memcpy(chunk, &tftp_opcode, 2);
    memcpy(chunk + 2, filename, strlen(filename) + 1);
    memcpy(chunk + 2 + (strlen(filename) + 1), tftp_mode, strlen(tftp_mode) + 1);
    int packet_size = 2 + strlen(filename) + 1 + strlen(tftp_mode) + 1;
    
    // Debug output request data.
    printf("TFTP RRQ packet: ");
    fwrite(chunk, 1, packet_size, stdout);
    printf("\n");
    
    // Send read request
    m_bytes_received = 0;
    m_block_number = 1;
    m_bytes_sent = m_sock.sendto(*m_tftp_addr, chunk, packet_size);
    
    if (m_bytes_sent == packet_size)
    {
        m_download_in_progress = true;
    }
    else
    {
        printf("TFTP read request failed. %d\n", m_bytes_sent);
    }
    
    m_next_data_byte_index = 0;
    
    return m_download_in_progress;
}

int TFTPClient::update()
{
    int return_value = -1;
    char chunk[TFTP_MAX_PACKET_SIZE];
    
    if (m_download_in_progress)
    {
        // Get data packet from the TFTP server
        m_bytes_received = m_sock.recvfrom(m_tftp_addr, chunk, TFTP_MAX_PACKET_SIZE);
        if (m_bytes_received <= 0)
        {
            return_value = m_bytes_received; // UDP packet recevie failed.
        }
        else
        {
            // Convert the opcode and block back into host endian format.
            uint16_t temp_opcode, temp_block;
            memcpy(&temp_opcode, chunk, 2);
            memcpy(&temp_block, chunk + 2, 2);
            temp_opcode = ntohs(temp_opcode);
            temp_block = ntohs(temp_block);
            
            if (temp_opcode == ERR)
            {
                printf("  TFTP Error: %u, %s\n", temp_block, chunk + 4);
                return_value = -2; // Error response from server.
            }
            else if (temp_opcode == DATA)
            {
                if (temp_block == m_block_number)
                {
                    int chunk_size = m_bytes_received - 4;
                    // Debug output for incoming chunks of data.
                    //printf("  TFTP Chunk Received: %u\n", chunk_size);
                    //fwrite(chunk, 1, m_bytes_received, stdout);
                    
                    // Strip the TFTP info from the beginning of the data buffer.
                    memcpy(m_data + m_next_data_byte_index, chunk + 4, chunk_size);
                    m_next_data_byte_index += chunk_size;
                    // Terminate the data string.
                    m_data[m_next_data_byte_index] = 0;
                    
                    // Send an ACK for the current data block
                    uint16_t tftp_opcode = htons(ACK);
                    temp_block = htons(temp_block);
                    memcpy(chunk, &tftp_opcode, 2);
                    memcpy(chunk + 2, &temp_block, 2);
                    int m_bytes_sent = m_sock.sendto(*m_tftp_addr, chunk, 4); // Send
                    
                    m_block_number++;
                }
                else
                {
                    return_value = -3; // Incorrect data block number.
                    m_download_in_progress = false;
                }
            }
            else
            {
                return_value = -4; // Wrong opcode
                m_download_in_progress = false;
            }
            
            if (m_bytes_received != TFTP_MAX_PACKET_SIZE)
            {
                m_download_in_progress = false;
                
                if (m_bytes_received > 0)
                {
                    // Finished download.
                    return_value = 1;
                }
            }
        }
    }
    
    if (!m_download_in_progress)
    {
        m_sock.close();
    }
    
    return return_value;
}