An example program for SerialFileTransfer, receives files from a java application and stores them on the LocalFileSystem

Dependencies:   MODSERIAL SerialFileTransfer SimpleSerialProtocol mbed

SerialFileReceiver allow the mbed to receive a file using binary packets over the serial connection,

you can test the library with this java application /media/uploads/p3p/mbedserialfiletransfer.zip

the arguments to the command are, Comport Baudrate file to see the console output use java, not javaw

Example command: java -jar SerialTransfer.jar com3 115200 test.bin

Files at this revision

API Documentation at this revision

Comitter:
p3p
Date:
Wed Aug 27 17:51:48 2014 +0000
Child:
1:7bba1d7d9680
Commit message:
Initial Commit, Using the SimpleSerialProtocol library to send files to the mbed

Changed in this revision

MODSERIAL.lib Show annotated file Show diff for this revision Revisions of this file
SerialFileTransfer.cpp Show annotated file Show diff for this revision Revisions of this file
SerialFileTransfer.h Show annotated file Show diff for this revision Revisions of this file
SimpleSerialProtocol.lib 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
mbed.bld Show annotated file Show diff for this revision Revisions of this file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MODSERIAL.lib	Wed Aug 27 17:51:48 2014 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/AjK/code/MODSERIAL/#ae0408ebdd68
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/SerialFileTransfer.cpp	Wed Aug 27 17:51:48 2014 +0000
@@ -0,0 +1,106 @@
+#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->sendPacket(&message);
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/SerialFileTransfer.h	Wed Aug 27 17:51:48 2014 +0000
@@ -0,0 +1,97 @@
+#ifndef _SFT_PROTOCOL_H
+#define _SFT_PROTOCOL_H
+
+#include <mbed.h>
+#include <SimpleSerialProtocol/Protocol.h>
+
+//class will receive a packet and echo it back out
+class SFTProtocol {
+public:
+    SFTProtocol() { //LED1 to 4 for a status led, NC to disable        
+        transfer_in_progress = false;
+        chunks_total = 0;
+        chunks_last = 0;
+        packet_retry_attempts = 0;
+        fp = 0;
+    }
+    virtual ~SFTProtocol() {};
+    
+    //the callbacks and packet sending methods
+    virtual void update(SimpleSerialProtocol::Protocol* comms);
+    void onFileStart(SimpleSerialProtocol::Protocol* comms, SimpleSerialProtocol::Packet* packet);
+    void ack(SimpleSerialProtocol::Protocol* comms, uint8_t ack_type);
+    void onFileStream(SimpleSerialProtocol::Protocol* comms, SimpleSerialProtocol::Packet* packet);
+    
+    //variables to control the transfer and save the file
+    bool transfer_in_progress;
+    int chunks_total;
+    int chunks_last;
+    Timer last_chunk_timer;
+    int packet_retry_attempts;
+    FILE *fp;
+    
+    
+    //This packed is used to start a file transfer it is sent by the client
+    //once received a file is created and an ack packet sent to start the file stream
+    class FileStartPacket : public SimpleSerialProtocol::Packet {
+    public:
+        FileStartPacket() {}
+        virtual ~FileStartPacket() {}
+        
+#pragma pack(push, 1) //must pack the structure to byte boundary for raw recast to work reliably
+        struct Interface {
+            Interface() {
+                type = 1; // initialise the type
+            }
+            uint8_t type;
+            uint8_t name[9];
+            uint8_t ext[4];
+            uint32_t chunks;
+        } interface;
+#pragma pack(pop)
+        
+    };
+    
+    //A very simple Ack packet used to inform the client that we need more data, and other commands based on the ack_type value
+    class AckFileStartPacket : public SimpleSerialProtocol::Packet {
+    public:
+        AckFileStartPacket() {}
+        virtual ~AckFileStartPacket() {}
+        
+#pragma pack(push, 1) //must pack the structure to byte boundary for raw recast to work reliably
+        struct Interface {
+            Interface() {
+                type = 2; // initialise the type
+            }
+            uint8_t type;
+            uint8_t ack_type;
+        } interface;
+#pragma pack(pop)
+        
+    };
+    
+    //This is the packet used to send the file data 128 bytes at a time
+    //its posible to send upto 256 bytes but this was causing my xbees to drop a lot of data
+    class FileStreamPacket : public SimpleSerialProtocol::Packet {
+    public:
+        FileStreamPacket() { }
+        virtual ~FileStreamPacket() {}
+        
+#pragma pack(push, 1) //must pack the structure to byte boundary for raw recast to work reliably
+        struct Interface {
+            Interface() {
+                type = 3; // initialise the type
+            }
+            uint8_t type;
+            uint16_t chunk;
+            uint8_t length;
+            uint8_t data[128];
+            
+        } interface;
+#pragma pack(pop)
+        
+    };
+ 
+};
+
+#endif
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/SimpleSerialProtocol.lib	Wed Aug 27 17:51:48 2014 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/p3p/code/SimpleSerialProtocol/#98ad30934a71
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main.cpp	Wed Aug 27 17:51:48 2014 +0000
@@ -0,0 +1,29 @@
+#include "mbed.h"
+#include "SerialFileTransfer.h"
+
+//Create an instance of the SimpleSerialProtocol on a Serial port, optionaly choose a status led
+SimpleSerialProtocol::Protocol comms(USBTX, USBRX, LED1);
+
+Serial debug(p13,p14);
+
+SFTProtocol fileAcceptor;
+
+int main() {
+    //initialise the comm port at 155200 baud
+    comms.initialise(115200);
+    //listen for packets of type 1 and relay the data to the onFileStart callback in SFTProtocol
+    comms.receiveCallback(1, &fileAcceptor, &SFTProtocol::onFileStart);
+    //listen for packets of type 3 and relay
+    comms.receiveCallback(3, &fileAcceptor, &SFTProtocol::onFileStream);
+    
+    debug.baud(115200);
+    debug.printf("Debug Terminal:\r\n");
+    
+    while(true){
+        //the protocol needs constant updates to process packets and forward the data
+        comms.update();
+        
+        //the SFTProtocol is updated so it can timeout, and request packet resends, 
+        fileAcceptor.update(&comms);
+    }
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed.bld	Wed Aug 27 17:51:48 2014 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/mbed_official/code/mbed/builds/9327015d4013
\ No newline at end of file