Adds file transfer capability to SimpleSerialProtocol

Dependents:   SerialFileReceiver

SerialFileTransfer.cpp

Committer:
p3p
Date:
2014-09-18
Revision:
1:f8aaff9c57e3
Parent:
0:31dff1f79b4f

File content as of revision 1:f8aaff9c57e3:

#include "SerialFileTransfer.h"

extern Serial debug;

LocalFileSystem local("local");

void SFTProtocol::update(SimpleSerialProtocol::Protocol* comms){
    if(last_chunk_timer.read_ms() > 100 && transfer_in_progress){
        last_chunk_timer.reset();
        packet_retry_attempts++;
        if(packet_retry_attempts > 50){
            ack(comms, 3);
            //debug.printf("Transfer Timeout\r\n");
            packet_retry_attempts = 0;
            transfer_in_progress = false;
            chunks_last = 0;
            chunks_total = 0;
            fclose(fp);
            fp = 0;
            last_chunk_timer.stop();
            last_chunk_timer.reset();
        } else {
            //debug.printf("Request Packet Resend %d, %d\r\n", comms->droppedBytes(), comms->_corrupt_packets);
            ack(comms, 2);
        }
    }
}

void SFTProtocol::onFileStart(SimpleSerialProtocol::Protocol* comms, SimpleSerialProtocol::Packet* packet){
    if(!packet)return;
    if (packet->_valid) {
        FileStartPacket::Interface* interface = packet->interpretData<FileStartPacket::Interface>();
        if (interface) {
            //debug.printf("%s.%s has %d chunks\r\n", interface->name, interface->ext, interface->chunks);
            
            char buffer[25];
            sprintf(buffer, "/local/%s.%s", interface->name, interface->ext);
            fp = fopen(buffer, "w");
            if(fp){
                transfer_in_progress = true;
                chunks_total = interface->chunks;
                ack(comms, 0);
                last_chunk_timer.start();
            }
        }
    }
    return;
}

void SFTProtocol::onFileStream(SimpleSerialProtocol::Protocol* comms, SimpleSerialProtocol::Packet* packet){
    if(!packet)return;
    if(transfer_in_progress){
        if (packet->_valid) {
            FileStreamPacket::Interface* interface = packet->interpretData<FileStreamPacket::Interface>();
            if (interface) {
                //debug.printf("%d,%d\r\n", interface->chunk, interface->length);
                //if(rand()%5 < 1){ //1in5 packet loss emulation
                    if((interface->chunk <= chunks_last + 1) && fp ){
                        
                        if(interface->chunk == chunks_last + 1){
                            chunks_last = interface->chunk;
                            fwrite(interface->data, 1, interface->length, fp);
                        } else {
                            //debug.printf("Allready have chunk %d\r\n", interface->chunk);
                        }
                        
                        if(chunks_last == chunks_total){
                            //debug.printf("Transfer Complete: Acked\r\n");
                            ack(comms, 1);
                            fclose(fp);
                            fp = 0;
                            transfer_in_progress = false;
                            chunks_last = 0;
                            chunks_total = 0;
                            last_chunk_timer.stop();
                            last_chunk_timer.reset();
                        }else{
                            ack(comms, 0);
                            packet_retry_attempts = 0;
                            last_chunk_timer.reset();
                        }
                        
                    } else {
                        //debug.printf("Transfer Failed: chunk dropped or out of order\r\n");
                        transfer_in_progress = false;
                        chunks_last = 0;
                        chunks_total = 0;
                        fclose(fp);
                        fp = 0;
                        ack(comms, 3);
                        last_chunk_timer.stop();
                        last_chunk_timer.reset();
                    }
                }
            //}
        }
    }
    return;
}

void SFTProtocol::ack(SimpleSerialProtocol::Protocol* comms, uint8_t ack_type) {
    AckFileStartPacket message;
    message.interface.ack_type = ack_type;
    message.buildData<AckFileStartPacket::Interface>(&message.interface);
    comms->send(&message);
}