Init fork from Stuart Robinson's repo
This commit is contained in:
BIN
examples/SX128x_examples/DataTransfer/$50SATL.JPG
Normal file
BIN
examples/SX128x_examples/DataTransfer/$50SATL.JPG
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 62 KiB |
BIN
examples/SX128x_examples/DataTransfer/$50SATS.JPG
Normal file
BIN
examples/SX128x_examples/DataTransfer/$50SATS.JPG
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 6.7 KiB |
BIN
examples/SX128x_examples/DataTransfer/$50SATT.JPG
Normal file
BIN
examples/SX128x_examples/DataTransfer/$50SATT.JPG
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.0 KiB |
@ -0,0 +1,166 @@
|
||||
/*******************************************************************************************************
|
||||
Programs for Arduino - Copyright of the author Stuart Robinson - 22/03/22
|
||||
|
||||
This program is supplied as is, it is up to the user of the program to decide if the program is
|
||||
suitable for the intended purpose and free from errors.
|
||||
*******************************************************************************************************/
|
||||
|
||||
/*******************************************************************************************************
|
||||
Program Operation - The program listens for incoming packets using the LoRa settings in the 'Settings.h'
|
||||
file. The pins to access the lora device need to be defined in the 'Settings.h' file also.
|
||||
|
||||
There is a printout of the valid packets received in HEX format. Thus the program can be used to receive
|
||||
and record non-ASCII packets. The LED will flash for each packet received. To keep up with fast transfers
|
||||
only the first bytes defined by constant BytesToPrint in the Settings.h file are printed.
|
||||
|
||||
Serial monitor baud rate is set at 115200.
|
||||
*******************************************************************************************************/
|
||||
|
||||
#include <SPI.h>
|
||||
#include <SX128XLT.h>
|
||||
#include "Settings.h"
|
||||
|
||||
SX128XLT LoRa;
|
||||
|
||||
uint8_t RXPacketL; //stores length of packet received
|
||||
int16_t PacketRSSI; //stores RSSI of received packet
|
||||
int8_t PacketSNR; //stores signal to noise ratio of received packet
|
||||
|
||||
|
||||
void loop()
|
||||
{
|
||||
RXPacketL = LoRa.receiveSXBuffer(0, 60000, WAIT_RX); //returns 0 if packet error of some sort, timeout set at 60secs\60000mS
|
||||
|
||||
digitalWrite(LED1, HIGH); //something has happened
|
||||
|
||||
printSeconds();
|
||||
|
||||
PacketRSSI = LoRa.readPacketRSSI();
|
||||
PacketSNR = LoRa.readPacketSNR();
|
||||
|
||||
if (RXPacketL == 0)
|
||||
{
|
||||
packet_is_Error();
|
||||
}
|
||||
else
|
||||
{
|
||||
packet_is_OK();
|
||||
}
|
||||
|
||||
digitalWrite(LED1, LOW);
|
||||
|
||||
Serial.println();
|
||||
}
|
||||
|
||||
|
||||
void packet_is_OK()
|
||||
{
|
||||
printReceptionDetails();
|
||||
Serial.print(RXPacketL);
|
||||
Serial.print(F(" bytes > "));
|
||||
|
||||
if (RXPacketL > BytesToPrint)
|
||||
{
|
||||
LoRa.printSXBufferHEX(0, (BytesToPrint - 1));
|
||||
}
|
||||
else
|
||||
{
|
||||
LoRa.printSXBufferHEX(0, (RXPacketL - 1));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void packet_is_Error()
|
||||
{
|
||||
uint16_t IRQStatus;
|
||||
IRQStatus = LoRa.readIrqStatus(); //get the IRQ status
|
||||
|
||||
if (IRQStatus & IRQ_RX_TIMEOUT)
|
||||
{
|
||||
Serial.print(F(" RXTimeout"));
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.print(F(" PacketError"));
|
||||
printReceptionDetails();
|
||||
Serial.print(F(" Length,"));
|
||||
Serial.print(LoRa.readRXPacketL()); //get the real packet length
|
||||
Serial.print(F(",IRQreg,"));
|
||||
Serial.print(IRQStatus, HEX);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void printReceptionDetails()
|
||||
{
|
||||
Serial.print(F(" RSSI,"));
|
||||
Serial.print(PacketRSSI);
|
||||
Serial.print(F("dBm,SNR,"));
|
||||
Serial.print(PacketSNR);
|
||||
Serial.print(F("dB "));
|
||||
}
|
||||
|
||||
|
||||
void led_Flash(uint16_t flashes, uint16_t delaymS)
|
||||
{
|
||||
uint16_t index;
|
||||
|
||||
for (index = 1; index <= flashes; index++)
|
||||
{
|
||||
digitalWrite(LED1, HIGH);
|
||||
delay(delaymS);
|
||||
digitalWrite(LED1, LOW);
|
||||
delay(delaymS);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void printSeconds()
|
||||
{
|
||||
float secs;
|
||||
|
||||
secs = ( (float) millis() / 1000);
|
||||
Serial.print(secs, 3);
|
||||
}
|
||||
|
||||
|
||||
void setup()
|
||||
{
|
||||
pinMode(LED1, OUTPUT);
|
||||
led_Flash(2, 125);
|
||||
|
||||
Serial.begin(115200);
|
||||
|
||||
Serial.println(F("221_LoRa_Packet_Monitor Starting"));
|
||||
|
||||
SPI.begin();
|
||||
|
||||
//SPI beginTranscation is normally part of library routines, but if it is disabled in library
|
||||
//a single instance is needed here, so uncomment the program line below
|
||||
//SPI.beginTransaction(SPISettings(8000000, MSBFIRST, SPI_MODE0));
|
||||
|
||||
if (LoRa.begin(NSS, NRESET, RFBUSY, DIO1, LORA_DEVICE))
|
||||
{
|
||||
Serial.println(F("LoRa Device found"));
|
||||
led_Flash(2, 125);
|
||||
delay(1000);
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.println(F("No LoRa device responding"));
|
||||
while (1)
|
||||
{
|
||||
led_Flash(50, 50);
|
||||
}
|
||||
}
|
||||
|
||||
LoRa.setupLoRa(Frequency, Offset, SpreadingFactor, Bandwidth, CodeRate);
|
||||
|
||||
Serial.println();
|
||||
LoRa.printModemSettings();
|
||||
Serial.println();
|
||||
LoRa.printOperatingSettings();
|
||||
Serial.println();
|
||||
Serial.print(F("Packet monitor ready"));
|
||||
Serial.println();
|
||||
}
|
||||
@ -0,0 +1,31 @@
|
||||
/*******************************************************************************************************
|
||||
Programs for Arduino - Copyright of the author Stuart Robinson - 06/11/21
|
||||
|
||||
This program is supplied as is, it is up to the user of the program to decide if the program is
|
||||
suitable for the intended purpose and free from errors.
|
||||
*******************************************************************************************************/
|
||||
|
||||
//******* Setup hardware pin definitions here ! ***************
|
||||
|
||||
//These are the pin definitions for one of my own boards, the Easy Pro Mini,
|
||||
//be sure to change the definitions to match your own setup.
|
||||
|
||||
#define NSS 10 //select pin on LoRa device
|
||||
#define NRESET 9 //reset pin on LoRa device
|
||||
#define RFBUSY 7 //RFBUSY pin on LoRa device
|
||||
#define DIO1 3 //DIO1 pin on LoRa device, used for sensing RX and TX done
|
||||
#define LED1 8 //LED used to indicate transmission
|
||||
|
||||
#define LORA_DEVICE DEVICE_SX1280 //this is the device we are using
|
||||
|
||||
//******* Setup LoRa Test Parameters Here ! ***************
|
||||
|
||||
const uint32_t Frequency = 2445000000; //frequency of transmissions
|
||||
const uint32_t Offset = 0; //offset frequency for calibration purposes
|
||||
|
||||
//******* Setup LoRa modem parameters here ! ***************
|
||||
const uint8_t Bandwidth = LORA_BW_1600; //LoRa bandwidth
|
||||
const uint8_t SpreadingFactor = LORA_SF5; //LoRa spreading factor
|
||||
const uint8_t CodeRate = LORA_CR_4_5; //LoRa coding rate
|
||||
|
||||
const uint8_t BytesToPrint = 16; //number of bytes of packet to print
|
||||
@ -0,0 +1,162 @@
|
||||
/*******************************************************************************************************
|
||||
Programs for Arduino - Copyright of the author Stuart Robinson - 12/03/22
|
||||
|
||||
This program is supplied as is, it is up to the user of the program to decide if the program is
|
||||
suitable for the intended purpose and free from errors.
|
||||
*******************************************************************************************************/
|
||||
|
||||
/*******************************************************************************************************
|
||||
Program Operation - The program listens for incoming packets using the FLRC settings in the 'Settings.h'
|
||||
file. The pins to access the lora device need to be defined in the 'Settings.h' file also.
|
||||
|
||||
There is a printout of the valid packets received in HEX format. Thus the program can be used to receive
|
||||
and record non-ASCII packets. The LED will flash for each packet received. To keep up with fast transfers
|
||||
only the first bytes defined by constant BytesToPrint in the Settings.h file are printed.
|
||||
|
||||
Serial monitor baud rate is set at 115200.
|
||||
*******************************************************************************************************/
|
||||
|
||||
#include <SPI.h>
|
||||
#include <SX128XLT.h>
|
||||
#include "Settings.h"
|
||||
|
||||
SX128XLT LoRa;
|
||||
|
||||
uint8_t RXPacketL; //stores length of packet received
|
||||
int16_t PacketRSSI; //stores RSSI of received packet
|
||||
|
||||
|
||||
void loop()
|
||||
{
|
||||
RXPacketL = LoRa.receiveSXBuffer(0, 60000, WAIT_RX); //returns 0 if packet error of some sort, timeout set at 60secs\60000mS
|
||||
|
||||
digitalWrite(LED1, HIGH); //something has happened
|
||||
|
||||
printSeconds();
|
||||
|
||||
PacketRSSI = LoRa.readPacketRSSI();
|
||||
|
||||
if (RXPacketL == 0)
|
||||
{
|
||||
packet_is_Error();
|
||||
}
|
||||
else
|
||||
{
|
||||
packet_is_OK();
|
||||
}
|
||||
|
||||
digitalWrite(LED1, LOW);
|
||||
|
||||
Serial.println();
|
||||
}
|
||||
|
||||
|
||||
void packet_is_OK()
|
||||
{
|
||||
printReceptionDetails();
|
||||
Serial.print(RXPacketL);
|
||||
Serial.print(F(" bytes > "));
|
||||
|
||||
if (RXPacketL > BytesToPrint)
|
||||
{
|
||||
LoRa.printSXBufferHEX(0, (BytesToPrint - 1));
|
||||
}
|
||||
else
|
||||
{
|
||||
LoRa.printSXBufferHEX(0, (RXPacketL - 1));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void packet_is_Error()
|
||||
{
|
||||
uint16_t IRQStatus;
|
||||
IRQStatus = LoRa.readIrqStatus(); //get the IRQ status
|
||||
|
||||
if (IRQStatus & IRQ_RX_TIMEOUT)
|
||||
{
|
||||
Serial.print(F(" RXTimeout"));
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.print(F(" PacketError"));
|
||||
printReceptionDetails();
|
||||
Serial.print(F(" Length,"));
|
||||
Serial.print(LoRa.readRXPacketL()); //get the real packet length
|
||||
Serial.print(F(",IRQreg,"));
|
||||
Serial.print(IRQStatus, HEX);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void printReceptionDetails()
|
||||
{
|
||||
Serial.print(F(" RSSI,"));
|
||||
Serial.print(PacketRSSI);
|
||||
Serial.print(F("dBm "));
|
||||
}
|
||||
|
||||
|
||||
void led_Flash(uint16_t flashes, uint16_t delaymS)
|
||||
{
|
||||
uint16_t index;
|
||||
|
||||
for (index = 1; index <= flashes; index++)
|
||||
{
|
||||
digitalWrite(LED1, HIGH);
|
||||
delay(delaymS);
|
||||
digitalWrite(LED1, LOW);
|
||||
delay(delaymS);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void printSeconds()
|
||||
{
|
||||
float secs;
|
||||
|
||||
secs = ( (float) millis() / 1000);
|
||||
Serial.print(secs, 3);
|
||||
}
|
||||
|
||||
|
||||
void setup()
|
||||
{
|
||||
pinMode(LED1, OUTPUT);
|
||||
led_Flash(2, 125);
|
||||
|
||||
Serial.begin(115200);
|
||||
|
||||
Serial.println(F("221_LoRa_Packet_Monitor Starting"));
|
||||
|
||||
SPI.begin();
|
||||
|
||||
//SPI beginTranscation is normally part of library routines, but if it is disabled in library
|
||||
//a single instance is needed here, so uncomment the program line below
|
||||
//SPI.beginTransaction(SPISettings(8000000, MSBFIRST, SPI_MODE0));
|
||||
|
||||
if (LoRa.begin(NSS, NRESET, RFBUSY, DIO1, LORA_DEVICE))
|
||||
{
|
||||
Serial.println(F("LoRa Device found"));
|
||||
led_Flash(2, 125);
|
||||
delay(1000);
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.println(F("No LoRa device responding"));
|
||||
while (1)
|
||||
{
|
||||
led_Flash(50, 50);
|
||||
}
|
||||
}
|
||||
|
||||
LoRa.setupFLRC(Frequency, Offset, BandwidthBitRate, CodingRate, BT, Syncword);
|
||||
|
||||
Serial.println();
|
||||
LoRa.printModemSettings();
|
||||
Serial.println();
|
||||
LoRa.printOperatingSettings();
|
||||
Serial.println();
|
||||
Serial.print(F("Packet monitor ready"));
|
||||
Serial.println();
|
||||
}
|
||||
@ -0,0 +1,34 @@
|
||||
/*******************************************************************************************************
|
||||
Programs for Arduino - Copyright of the author Stuart Robinson - 06/11/21
|
||||
|
||||
This program is supplied as is, it is up to the user of the program to decide if the program is
|
||||
suitable for the intended purpose and free from errors.
|
||||
*******************************************************************************************************/
|
||||
|
||||
//******* Setup hardware pin definitions here ! ***************
|
||||
|
||||
//These are the pin definitions for one of my own boards, the Easy Pro Mini,
|
||||
//be sure to change the definitions to match your own setup.
|
||||
|
||||
#define NSS 10 //select pin on LoRa device
|
||||
#define NRESET 9 //reset pin on LoRa device
|
||||
#define RFBUSY 7 //RFBUSY pin on LoRa device
|
||||
#define DIO1 3 //DIO1 pin on LoRa device, used for sensing RX and TX done
|
||||
#define LED1 8 //LED used to indicate transmission
|
||||
|
||||
#define LORA_DEVICE DEVICE_SX1280 //this is the device we are using
|
||||
|
||||
//******* Setup LoRa Test Parameters Here ! ***************
|
||||
|
||||
const uint32_t Frequency = 2445000000; //frequency of transmissions
|
||||
const uint32_t Offset = 0; //offset frequency for calibration purposes
|
||||
|
||||
|
||||
//******* Setup FLRC modem parameters here ! ***************
|
||||
const uint8_t BandwidthBitRate = FLRC_BR_1_300_BW_1_2; //FLRC bandwidth and bit rate, 1.3Mbs
|
||||
//const uint8_t BandwidthBitRate = FLRC_BR_0_260_BW_0_3; //FLRC 260kbps
|
||||
const uint8_t CodingRate = FLRC_CR_1_0; //FLRC coding rate
|
||||
const uint8_t BT = RADIO_MOD_SHAPING_BT_1_0; //FLRC BT
|
||||
const uint32_t Syncword = 0x01234567; //FLRC uses syncword, needs to match transmitter
|
||||
|
||||
const uint8_t BytesToPrint = 32; //number of bytes of packet to print
|
||||
@ -0,0 +1,103 @@
|
||||
/*******************************************************************************************************
|
||||
Programs for Arduino - Copyright of the author Stuart Robinson - 14/03/22
|
||||
|
||||
This program is supplied as is, it is up to the user of the program to decide if the program is
|
||||
suitable for the intended purpose and free from errors.
|
||||
*******************************************************************************************************/
|
||||
|
||||
/*******************************************************************************************************
|
||||
Program Operation - This is a program that transfers a file from an Arduinos SD card to a folder on a
|
||||
PC that is connected to the Arduino via a Serial port. The transfer process uses the YModem protocol
|
||||
and the PC receives the file using the Tera Term Serial terminal program.
|
||||
|
||||
This program was run on an Arduino DUE, with Serial2 used as the transfer port to the PC.
|
||||
|
||||
Instructions for using the program are to be found here;
|
||||
|
||||
https://stuartsprojects.github.io/2021/12/28/Arduino-to-PC-File-Transfers.html
|
||||
|
||||
Serial monitor baud rate is set at 115200.
|
||||
*******************************************************************************************************/
|
||||
|
||||
#include <SPI.h>
|
||||
#include <SD.h>
|
||||
#include "YModem.h"
|
||||
|
||||
File root;
|
||||
|
||||
const uint16_t SDCS = 30;
|
||||
const uint16_t LED1 = 8; //LED indicator etc. on during transfers
|
||||
char FileName[] = "$50SATL.JPG"; //file length 63091 bytes, file CRC 0x59CE
|
||||
uint16_t transferNumber = 0;;
|
||||
uint32_t filelength;
|
||||
uint32_t bytestransfered;
|
||||
|
||||
|
||||
void loop()
|
||||
{
|
||||
transferNumber++;
|
||||
digitalWrite(LED1, HIGH);
|
||||
Serial.print(F("Start transfer "));
|
||||
Serial.print(transferNumber);
|
||||
Serial.print(F(" "));
|
||||
Serial.println(FileName);
|
||||
Serial.flush();
|
||||
digitalWrite(LED1, HIGH);
|
||||
|
||||
bytestransfered = yModemSend(FileName, 1, 1); //transfer filename with waitForReceiver and batchMode options set
|
||||
|
||||
if (bytestransfered > 0)
|
||||
{
|
||||
Serial.print(F("YModem transfer completed "));
|
||||
Serial.print(bytestransfered);
|
||||
Serial.println(F(" bytes sent"));
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.println(F("YModem transfer FAILED"));
|
||||
}
|
||||
Serial.println();
|
||||
|
||||
digitalWrite(LED1, LOW);
|
||||
Serial.println();
|
||||
delay(10000);
|
||||
}
|
||||
|
||||
|
||||
void led_Flash(uint16_t flashes, uint16_t delaymS)
|
||||
{
|
||||
uint16_t index;
|
||||
for (index = 1; index <= flashes; index++)
|
||||
{
|
||||
digitalWrite(LED1, HIGH);
|
||||
delay(delaymS);
|
||||
digitalWrite(LED1, LOW);
|
||||
delay(delaymS);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void setup()
|
||||
{
|
||||
pinMode(LED1, OUTPUT); //setup pin as output for indicator LED
|
||||
led_Flash(2, 125); //two quick LED flashes to indicate program start
|
||||
|
||||
Serial.begin(115200);
|
||||
Serial2.begin(115200); //Serial port used for file transfers
|
||||
Serial.println();
|
||||
Serial.println(F(__FILE__));
|
||||
Serial.flush();
|
||||
Serial.println("Using Serial2 for YModem comms @ 115200 baud.");
|
||||
Serial.println("Initializing SD card...");
|
||||
|
||||
if (SD.begin(SDCS))
|
||||
{
|
||||
Serial.println(F("SD Card initialized."));
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.println(F("SD Card failed, or not present."));
|
||||
while (1) led_Flash(100, 25);
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,264 @@
|
||||
//29/12/21 Working for repeat transfer - source of this version not clear
|
||||
// Code below taken from https://gist.github.com/zonque/0ae2dc8cedbcdbd9b933
|
||||
// file xymodem-mini.c
|
||||
|
||||
// MarkD modifcations
|
||||
// - uses 128 byte packets for low RAM devices
|
||||
// - supports batch upload of several files at once
|
||||
|
||||
//StuartsProjects - hard coded for Serial2
|
||||
//080222 - added timeouts
|
||||
|
||||
#define X_SOH 0x01
|
||||
#define X_STX 0x02
|
||||
#define X_ACK 0x06
|
||||
#define X_NAK 0x15
|
||||
#define X_EOT 0x04
|
||||
|
||||
const uint32_t transfertimeoutmS = 5000;
|
||||
const uint8_t ackerrorlimit = 16;
|
||||
|
||||
struct yModemPacket {
|
||||
uint8_t start;
|
||||
uint8_t block;
|
||||
uint8_t block_neg;
|
||||
uint8_t payload[128];
|
||||
uint16_t crc;
|
||||
} __attribute__((packed));
|
||||
|
||||
#define CRC_POLY 0x1021
|
||||
|
||||
static uint16_t crc_update(uint16_t crc_in, int incr)
|
||||
{
|
||||
uint16_t _xor = crc_in >> 15;
|
||||
uint16_t _out = crc_in << 1;
|
||||
|
||||
if (incr)
|
||||
_out++;
|
||||
|
||||
if (_xor)
|
||||
_out ^= CRC_POLY;
|
||||
|
||||
return _out;
|
||||
}
|
||||
|
||||
static uint16_t crc16(const uint8_t *data, uint16_t size)
|
||||
{
|
||||
uint16_t crc, i;
|
||||
|
||||
for (crc = 0; size > 0; size--, data++)
|
||||
for (i = 0x80; i; i >>= 1)
|
||||
crc = crc_update(crc, *data & i);
|
||||
|
||||
for (i = 0; i < 16; i++)
|
||||
crc = crc_update(crc, 0);
|
||||
|
||||
return crc;
|
||||
}
|
||||
|
||||
|
||||
static uint16_t swap16(uint16_t in)
|
||||
{
|
||||
return (in >> 8) | ((in & 0xff) << 8);
|
||||
}
|
||||
|
||||
// Main YModem code.
|
||||
// filename is pointer to null terminated string
|
||||
// set waitForReceiver to 1 so that the upload begins when TeraTerm is ready
|
||||
// set batchMode to 0 when sending 1 file
|
||||
// set batchMode to 1 for each file sent apart from the last one.
|
||||
|
||||
static int yModemSend(const char *filename, int waitForReceiver, int batchMode )
|
||||
{
|
||||
uint32_t numBytesStillToSend = 0;
|
||||
uint16_t numBytesThisPacket = 0;
|
||||
uint8_t skip_payload;
|
||||
uint8_t doNextBlock;
|
||||
uint8_t answer = 0;
|
||||
char spfBuff[16];
|
||||
struct yModemPacket yPacket;
|
||||
uint32_t filebytescopied = 0;
|
||||
uint32_t startmS;
|
||||
uint8_t ackerrors = 0;
|
||||
|
||||
File srcFile = SD.open(filename, O_RDONLY);
|
||||
|
||||
if (srcFile < 0)
|
||||
{
|
||||
Serial.println("Open error");
|
||||
return 0;
|
||||
}
|
||||
|
||||
numBytesStillToSend = srcFile.size();
|
||||
|
||||
if (numBytesStillToSend == 0)
|
||||
{
|
||||
Serial.println("SD file error");
|
||||
return 0;
|
||||
}
|
||||
|
||||
//convert the size of the file to an ASCII representation for header packet
|
||||
sprintf(spfBuff, "%ld", numBytesStillToSend);
|
||||
|
||||
// wait here for the receiving device to respond
|
||||
if ( waitForReceiver )
|
||||
{
|
||||
Serial.print("Waiting for receiver ping ... ");
|
||||
while ( Serial2.available() ) Serial2.read();
|
||||
startmS = millis();
|
||||
|
||||
do
|
||||
{
|
||||
if ( Serial2.available() ) answer = Serial2.read();
|
||||
}
|
||||
while ((answer != 'C') && ((uint32_t) (millis() - startmS) < transfertimeoutmS));
|
||||
|
||||
if (answer != 'C')
|
||||
{
|
||||
Serial.println("Timeout starting YModem transfer");
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.println("done");
|
||||
}
|
||||
}
|
||||
|
||||
Serial.print("YModem Sending ");
|
||||
Serial.print(filename);
|
||||
Serial.print(" ");
|
||||
Serial.print(spfBuff);
|
||||
Serial.println(" bytes");
|
||||
|
||||
yPacket.start = X_SOH;
|
||||
yPacket.block = 0;
|
||||
|
||||
// copy the filename into the payload - fill remainder of payload with 0x00
|
||||
strncpy((char *) yPacket.payload, filename, sizeof(yPacket.payload));
|
||||
|
||||
// insert the file size in bytes as ASCII after the NULL of the filename string
|
||||
strcpy( (char *)(yPacket.payload) + strlen(filename) + 1 , spfBuff );
|
||||
|
||||
// first pass - don't read any file data as it will overwrite the file details packet
|
||||
skip_payload = 1;
|
||||
|
||||
while (numBytesStillToSend > 0)
|
||||
{
|
||||
doNextBlock = 0;
|
||||
|
||||
// if this isn't the 1st pass, then read a block of up to 128 bytes from the file
|
||||
if (skip_payload == 0)
|
||||
{
|
||||
numBytesThisPacket = min(numBytesStillToSend, sizeof(yPacket.payload));
|
||||
srcFile.read(yPacket.payload, numBytesThisPacket);
|
||||
|
||||
filebytescopied = filebytescopied + numBytesThisPacket;
|
||||
|
||||
if (numBytesThisPacket < sizeof(yPacket.payload)) {
|
||||
// pad out the rest of the payload block with 0x1A
|
||||
memset(yPacket.payload + numBytesThisPacket, 0x1A, sizeof(yPacket.payload) - numBytesThisPacket);
|
||||
}
|
||||
}
|
||||
|
||||
yPacket.block_neg = 0xff - yPacket.block;
|
||||
|
||||
// calculate and insert the CRC16 checksum into the packet
|
||||
yPacket.crc = swap16(crc16(yPacket.payload, sizeof(yPacket.payload)));
|
||||
|
||||
// send the whole packet to the receiver - will block here
|
||||
startmS = millis();
|
||||
Serial2.write( (uint8_t*)&yPacket, sizeof(yPacket));
|
||||
|
||||
// wait for the receiver to send back a response to the packet
|
||||
while ((!Serial2.available()) && ((uint32_t) (millis() - startmS) < transfertimeoutmS));
|
||||
|
||||
if ( ((uint32_t) (millis() - startmS) >= transfertimeoutmS))
|
||||
{
|
||||
Serial.println("Timeout waiting YModem response");
|
||||
return 0;
|
||||
}
|
||||
|
||||
answer = Serial2.read();
|
||||
switch (answer) {
|
||||
case X_NAK:
|
||||
// something went wrong - send the same packet again?
|
||||
Serial.print("N");
|
||||
ackerrors++;
|
||||
break;
|
||||
case X_ACK:
|
||||
// got ACK to move to the next block of data
|
||||
Serial.print(".");
|
||||
doNextBlock = 1;
|
||||
break;
|
||||
default:
|
||||
// unknown response
|
||||
Serial.print("?");
|
||||
ackerrors++;
|
||||
break;
|
||||
}
|
||||
|
||||
if (ackerrors >= ackerrorlimit)
|
||||
{
|
||||
Serial.println("Ack error limit reached");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// need to handle the 'C' response after the initial file details packet has been sent
|
||||
if (skip_payload == 1) {
|
||||
|
||||
startmS = millis();
|
||||
while ((!Serial2.available()) && ((uint32_t) (millis() - startmS) < transfertimeoutmS));
|
||||
|
||||
if ( ((uint32_t) (millis() - startmS) >= transfertimeoutmS))
|
||||
{
|
||||
Serial.println("Timeout waiting YModem response");
|
||||
return 0;
|
||||
}
|
||||
|
||||
answer = Serial2.read();
|
||||
if (answer == 'C') {
|
||||
// good - start sending the data in the next transmission
|
||||
skip_payload = 0;
|
||||
} else {
|
||||
// error? send the file details packet again?
|
||||
doNextBlock = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// move on to the next block of data
|
||||
if (doNextBlock == 1) {
|
||||
yPacket.block++;
|
||||
numBytesStillToSend = numBytesStillToSend - numBytesThisPacket;
|
||||
}
|
||||
}
|
||||
|
||||
// all done - send the end of transmission code
|
||||
Serial2.write( X_EOT );
|
||||
|
||||
// need to send EOT again for YMODEM
|
||||
startmS = millis();
|
||||
while ((!Serial2.available()) && ((uint32_t) (millis() - startmS) < transfertimeoutmS));
|
||||
|
||||
if ( ((uint32_t) (millis() - startmS) >= transfertimeoutmS))
|
||||
{
|
||||
Serial.println("Timeout waiting YModem response");
|
||||
return 0;
|
||||
}
|
||||
|
||||
answer = Serial2.read();
|
||||
Serial2.write( X_EOT );
|
||||
|
||||
if (batchMode == 0) {
|
||||
// and then a packet full of NULL seems to terminate the process
|
||||
// and make TeraTerm close the receive dialog box
|
||||
yPacket.block = 0;
|
||||
yPacket.block_neg = 0xff - yPacket.block;
|
||||
memset(yPacket.payload, 0x00, sizeof(yPacket.payload) );
|
||||
yPacket.crc = swap16(crc16(yPacket.payload, sizeof(yPacket.payload)));
|
||||
Serial2.write( (uint8_t*)&yPacket, sizeof(yPacket));
|
||||
}
|
||||
Serial.println("done");
|
||||
|
||||
srcFile.close();
|
||||
return filebytescopied;
|
||||
}
|
||||
@ -0,0 +1,202 @@
|
||||
/*******************************************************************************************************
|
||||
Programs for Arduino - Copyright of the author Stuart Robinson - 12/03/22
|
||||
|
||||
This program is supplied as is, it is up to the user of the program to decide if the program is
|
||||
suitable for the intended purpose and free from errors.
|
||||
*******************************************************************************************************/
|
||||
|
||||
/*******************************************************************************************************
|
||||
Program Operation - This is a program that simulates the transfer of a file using data transfer (DT)
|
||||
packet functions from the SX128X library. No SD cards are needed for the simulation. The file length
|
||||
used to simulate the transfer is defined by DTFileSize in the DTSettings.h file. Use with matching
|
||||
receiver program 232_Data_Transfer_Test_Receiver.ino.
|
||||
|
||||
DT packets can be used for transfering large amounts of data in a sequence of packets or segments,
|
||||
in a reliable and resiliant way. The file open requests to the remote receiver, each segement sent and
|
||||
the remote file close will all keep transmitting until a valid acknowledge comes from the receiver.
|
||||
|
||||
On transmission the NetworkID and CRC of the payload are appended to the end of the packet by the library
|
||||
routines. The use of a NetworkID and CRC ensures that the receiver can validate the packet to a high degree
|
||||
of certainty.
|
||||
|
||||
The transmitter sends the sequence of segments in order. If the sequence fails for some reason, the receiver
|
||||
will return a NACK packet to the transmitter requesting the segment sequence it was expecting.
|
||||
|
||||
Details of the packet identifiers, header and data lengths and formats used are in the file;
|
||||
'Data transfer packet definitions.md' in the \SX128X_examples\DataTransfer\ folder.
|
||||
|
||||
The transfers can be carried out using LoRa packets, max segment size (defined by DTSegmentSize) is 245 bytes
|
||||
for LoRa, or FLRC packets where 117 is maximum segment size.
|
||||
|
||||
Serial monitor baud rate is set at 115200.
|
||||
*******************************************************************************************************/
|
||||
|
||||
#define USELORA //enable this define to use LoRa packets
|
||||
//#define USEFLRC //enable this define to use FLRC packets
|
||||
|
||||
#include <SPI.h>
|
||||
|
||||
#include <SX128XLT.h>
|
||||
#include <ProgramLT_Definitions.h>
|
||||
#include "DTSettings.h" //LoRa settings etc.
|
||||
#include <arrayRW.h>
|
||||
|
||||
SX128XLT LoRa; //create an SX128XLT library instance called LoRa
|
||||
|
||||
#define PRINTSEGMENTNUM //enable this define to print segment numbers
|
||||
|
||||
//#define DEBUG
|
||||
//#define DISABLEPAYLOADCRC //enable this define if you want to disable payload CRC checking
|
||||
|
||||
#include "DTLibrarySIM.h"
|
||||
|
||||
char DTFileName[] = "/Simulate.JPG"; //file name to simulate sending
|
||||
|
||||
|
||||
void loop()
|
||||
{
|
||||
Serial.println(("Transfer started"));
|
||||
|
||||
do
|
||||
{
|
||||
DTStartmS = millis();
|
||||
|
||||
//opens the local file to send and sets up transfer parameters
|
||||
if (startFileTransfer(DTFileName, sizeof(DTFileName), DTSendAttempts))
|
||||
{
|
||||
Serial.print(DTFileName);
|
||||
Serial.println(F(" opened OK on remote"));
|
||||
printLocalFileDetails();
|
||||
Serial.println();
|
||||
NoAckCount = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.print(DTFileName);
|
||||
Serial.println(F(" Error opening remote file - restart transfer"));
|
||||
DTFileTransferComplete = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
delay(packetdelaymS);
|
||||
|
||||
if (!sendSegments())
|
||||
{
|
||||
Serial.println();
|
||||
Serial.println(F("**********************************************************"));
|
||||
Serial.println(F("Error - Segment write with no file open - Restart received"));
|
||||
Serial.println(F("**********************************************************"));
|
||||
Serial.println();
|
||||
continue;
|
||||
}
|
||||
|
||||
if (endFileTransfer(DTFileName, sizeof(DTFileName))) //send command to close remote file
|
||||
{
|
||||
DTSendmS = millis() - DTStartmS; //record time taken for transfer
|
||||
Serial.print(DTFileName);
|
||||
Serial.println(F(" closed OK on remote"));
|
||||
beginarrayRW(DTheader, 4);
|
||||
DTDestinationFileLength = arrayReadUint32();
|
||||
Serial.print(F("Acknowledged remote destination file length "));
|
||||
Serial.println(DTDestinationFileLength);
|
||||
DTFileTransferComplete = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
DTFileTransferComplete = false;
|
||||
Serial.println(F("ERROR send close remote destination file failed - program halted"));
|
||||
}
|
||||
}
|
||||
while (!DTFileTransferComplete);
|
||||
|
||||
|
||||
Serial.print(F("NoAckCount "));
|
||||
Serial.println( NoAckCount);
|
||||
Serial.println();
|
||||
|
||||
DTsendSecs = (float) DTSendmS / 1000;
|
||||
Serial.print(F("Transmit time "));
|
||||
Serial.print(DTsendSecs, 3);
|
||||
Serial.println(F("secs"));
|
||||
Serial.print(F("Transmit rate "));
|
||||
Serial.print( (DTFileSize * 8) / (DTsendSecs), 0 );
|
||||
Serial.println(F("bps"));
|
||||
Serial.println(("Transfer finished"));
|
||||
|
||||
Serial.println(("Program halted"));
|
||||
while (1);
|
||||
}
|
||||
|
||||
|
||||
void led_Flash(uint16_t flashes, uint16_t delaymS)
|
||||
{
|
||||
uint16_t index;
|
||||
for (index = 1; index <= flashes; index++)
|
||||
{
|
||||
digitalWrite(LED1, HIGH);
|
||||
delay(delaymS);
|
||||
digitalWrite(LED1, LOW);
|
||||
delay(delaymS);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void setup()
|
||||
{
|
||||
pinMode(LED1, OUTPUT); //setup pin as output for indicator LED
|
||||
led_Flash(2, 125); //two quick LED flashes to indicate program start
|
||||
setDTLED(LED1); //setup LED pin for data transfer indicator
|
||||
|
||||
Serial.begin(115200);
|
||||
Serial.println();
|
||||
Serial.println(F(__FILE__));
|
||||
Serial.flush();
|
||||
|
||||
SPI.begin();
|
||||
|
||||
if (LoRa.begin(NSS, NRESET, RFBUSY, DIO1, LORA_DEVICE))
|
||||
{
|
||||
led_Flash(2, 125);
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.println(F("LoRa device error"));
|
||||
while (1)
|
||||
{
|
||||
led_Flash(50, 50); //long fast speed flash indicates device error
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef USELORA
|
||||
LoRa.setupLoRa(Frequency, Offset, SpreadingFactor, Bandwidth, CodeRate);
|
||||
Serial.println(F("Using LoRa packets"));
|
||||
#endif
|
||||
|
||||
#ifdef USEFLRC
|
||||
LoRa.setupFLRC(Frequency, Offset, BandwidthBitRate, CodingRate, BT, Syncword);
|
||||
Serial.println(F("Using FLRC packets"));
|
||||
#endif
|
||||
|
||||
LoRa.printOperatingSettings();
|
||||
Serial.println();
|
||||
LoRa.printModemSettings();
|
||||
Serial.println();
|
||||
|
||||
#ifdef DISABLEPAYLOADCRC
|
||||
LoRa.setReliableConfig(NoReliableCRC);
|
||||
#endif
|
||||
|
||||
if (LoRa.getReliableConfig(NoReliableCRC))
|
||||
{
|
||||
Serial.println(F("Payload CRC disabled"));
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.println(F("Payload CRC enabled"));
|
||||
}
|
||||
|
||||
DTFileTransferComplete = false;
|
||||
|
||||
Serial.println(F("File transfer ready"));
|
||||
Serial.println();
|
||||
}
|
||||
@ -0,0 +1,973 @@
|
||||
/*******************************************************************************************************
|
||||
Programs for Arduino - Copyright of the author Stuart Robinson - - 12/03/22
|
||||
|
||||
This program is supplied as is, it is up to the user of the program to decide if the program is
|
||||
suitable for the intended purpose and free from errors.
|
||||
*******************************************************************************************************/
|
||||
|
||||
uint8_t RXPacketL; //length of received packet
|
||||
uint8_t RXPacketType; //type of received packet, segment write, ACK, NACK etc
|
||||
uint16_t RXErrors; //count of packets received with error
|
||||
uint8_t RXFlags; //DTflags byte in header, could be used to control actions in TX and RX
|
||||
uint8_t RXHeaderL; //length of header
|
||||
uint8_t RXDataarrayL; //length of data array\segment
|
||||
int16_t PacketRSSI; //stores RSSI of received packet
|
||||
int8_t PacketSNR; //stores signal to noise ratio of received packet
|
||||
|
||||
uint16_t TXNetworkID; //this is used to store the 'network' number, receiver must have the same networkID
|
||||
uint16_t TXArrayCRC; //should contain CRC of data array sent
|
||||
uint8_t TXPacketL; //length of transmitted packet
|
||||
|
||||
uint16_t AckCount; //keep a count of acks that are received within timeout period
|
||||
uint16_t NoAckCount; //keep a count of acks not received within timeout period
|
||||
uint16_t LocalPayloadCRC; //for calculating the local data array CRC
|
||||
|
||||
uint16_t DTDestinationFileCRC; //CRC of file received
|
||||
uint16_t DTSourceFileCRC; //CRC of returned of the remote saved file
|
||||
|
||||
uint32_t DTDestinationFileLength; //length of file written on this destination
|
||||
uint32_t DTSourceFileLength; //length of file at source
|
||||
|
||||
uint32_t DTStartmS; //used for timeing transfers
|
||||
bool DTFileOpened; //bool to record when file has been opened
|
||||
|
||||
uint16_t DTSegment = 0; //current segment number
|
||||
uint16_t DTSegmentNext; //next segment expected
|
||||
uint16_t DTReceivedSegments; //count of segments received
|
||||
uint16_t DTSegmentLast; //last segment processed
|
||||
uint8_t DTLastSegmentSize; //size of the last segment
|
||||
uint16_t DTNumberSegments; //number of segments for a file transfer
|
||||
uint16_t DTSentSegments; //count of segments sent
|
||||
|
||||
bool DTFileTransferComplete; //bool to flag file transfer complete
|
||||
uint32_t DTSendmS; //used for timing transfers
|
||||
float DTsendSecs; //seconds to transfer a file
|
||||
|
||||
char DTfilenamebuff[DTfilenamesize];
|
||||
|
||||
int DTLED = -1; //pin number for indicator LED, if -1 then not used
|
||||
|
||||
bool sendFile(char *DTFileName, uint8_t namelength);
|
||||
bool sendFileSegment(uint16_t segnum, uint8_t segmentsize);
|
||||
bool startFileTransfer(char *buff, uint8_t filenamesize, uint8_t attempts);
|
||||
bool endFileTransfer(char *buff, uint8_t filenamesize);
|
||||
void build_DTFileOpenHeader(uint8_t *header, uint8_t headersize, uint8_t datalength, uint32_t filelength, uint16_t filecrc, uint8_t segsize);
|
||||
void build_DTSegmentHeader(uint8_t *header, uint8_t headersize, uint8_t datalen, uint16_t segnum);
|
||||
void build_DTFileCloseHeader(uint8_t *header, uint8_t headersize, uint8_t datalength, uint32_t filelength, uint16_t filecrc, uint8_t segsize);
|
||||
void printLocalFileDetails();
|
||||
bool sendSegments();
|
||||
void printheader(uint8_t *hdr, uint8_t hdrsize);
|
||||
void printSeconds();
|
||||
void printAckBrief();
|
||||
void printAckDetails();
|
||||
void printdata(uint8_t *dataarray, uint8_t arraysize);
|
||||
void printACKdetail();
|
||||
void printPacketHex();
|
||||
void printPacketRSSI();
|
||||
void printPacketDetails();
|
||||
void readHeaderDT();
|
||||
void printSourceFileDetails();
|
||||
void printDestinationFileDetails();
|
||||
bool processFileClose();
|
||||
bool processFileOpen(uint8_t *buff, uint8_t filenamesize);
|
||||
bool processSegmentWrite();
|
||||
bool processPacket(uint8_t packettype);
|
||||
bool receiveaPacketDT();
|
||||
uint16_t getNumberSegments(uint32_t filesize, uint8_t segmentsize);
|
||||
uint8_t getLastSegmentSize(uint32_t filesize, uint8_t segmentsize);
|
||||
void setDTLED(int8_t pinnumber);
|
||||
|
||||
uint8_t DTheader[16]; //header array
|
||||
uint8_t DTdata[245]; //data/segment array
|
||||
|
||||
bool sendFile(char *DTFileName, uint8_t namelength)
|
||||
{
|
||||
//**************************************************************************************************************
|
||||
// Start filesend process
|
||||
// This routine allows the file transfer to be run with a function call of sendFile(FileName, sizeof(FileName));
|
||||
//**************************************************************************************************************
|
||||
|
||||
do
|
||||
{
|
||||
|
||||
DTStartmS = millis();
|
||||
|
||||
//opens the local file to send and sets up transfer parameters
|
||||
if (startFileTransfer(DTFileName, namelength, DTSendAttempts))
|
||||
{
|
||||
Serial.print(DTFileName);
|
||||
Serial.println(F(" opened OK on remote"));
|
||||
printLocalFileDetails();
|
||||
Serial.println();
|
||||
NoAckCount = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.print(DTFileName);
|
||||
Serial.println(F(" Error opening remote file - restart transfer"));
|
||||
DTFileTransferComplete = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
delay(packetdelaymS);
|
||||
|
||||
if (!sendSegments())
|
||||
{
|
||||
Serial.println();
|
||||
Serial.println(F("**********************************************************"));
|
||||
Serial.println(F("Error - Segment write with no file open - Restart received"));
|
||||
Serial.println(F("**********************************************************"));
|
||||
Serial.println();
|
||||
continue;
|
||||
}
|
||||
|
||||
if (endFileTransfer(DTFileName, namelength)) //send command to close remote file
|
||||
{
|
||||
DTSendmS = millis() - DTStartmS; //record time taken for transfer
|
||||
Serial.print(DTFileName);
|
||||
Serial.println(F(" closed OK on remote"));
|
||||
beginarrayRW(DTheader, 4);
|
||||
DTDestinationFileLength = arrayReadUint32();
|
||||
Serial.print(F("Acknowledged remote destination file length "));
|
||||
Serial.println(DTDestinationFileLength);
|
||||
if (DTDestinationFileLength != DTSourceFileLength)
|
||||
{
|
||||
Serial.println(F("ERROR - file lengths do not match"));
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.println(F("File lengths match"));
|
||||
}
|
||||
DTFileTransferComplete = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
DTFileTransferComplete = false;
|
||||
Serial.println(F("ERROR send close remote destination file failed - program halted"));
|
||||
}
|
||||
}
|
||||
while (!DTFileTransferComplete);
|
||||
|
||||
Serial.print(F("NoAckCount "));
|
||||
Serial.println( NoAckCount);
|
||||
Serial.println();
|
||||
DTsendSecs = (float) DTSendmS / 1000;
|
||||
Serial.print(F("Transmit time "));
|
||||
Serial.print(DTsendSecs, 3);
|
||||
Serial.println(F("secs"));
|
||||
Serial.print(F("Transmit rate "));
|
||||
Serial.print( (DTDestinationFileLength * 8) / (DTsendSecs), 0 );
|
||||
Serial.println(F("bps"));
|
||||
Serial.println(("Transfer finished"));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool sendFileSegment(uint16_t segnum, uint8_t segmentsize)
|
||||
{
|
||||
//****************************************************************
|
||||
//Send file segment as payload in a packet
|
||||
//****************************************************************
|
||||
|
||||
uint8_t ValidACK;
|
||||
|
||||
build_DTSegmentHeader(DTheader, DTSegmentWriteHeaderL, segmentsize, segnum);
|
||||
|
||||
#ifdef PRINTSEGMENTNUM
|
||||
//Serial.print(F("Segment,"));
|
||||
Serial.println(segnum);
|
||||
#endif
|
||||
|
||||
#ifdef DEBUG
|
||||
printheader(DTheader, DTSegmentWriteHeaderL);
|
||||
Serial.print(F(" "));
|
||||
printdata(DTdata, segmentsize); //print segment size of data array only
|
||||
#endif
|
||||
|
||||
do
|
||||
{
|
||||
digitalWrite(DTLED, HIGH);
|
||||
TXPacketL = LoRa.transmitDT(DTheader, DTSegmentWriteHeaderL, (uint8_t *) DTdata, segmentsize, NetworkID, TXtimeoutmS, TXpower, WAIT_TX);
|
||||
digitalWrite(DTLED, LOW);
|
||||
|
||||
if (TXPacketL == 0) //if there has been an error TXPacketL returns as 0
|
||||
{
|
||||
Serial.println(F("Transmit error"));
|
||||
}
|
||||
|
||||
ValidACK = LoRa.waitACKDT(DTheader, DTSegmentWriteHeaderL, ACKsegtimeoutmS);
|
||||
RXPacketType = DTheader[0];
|
||||
|
||||
if (ValidACK > 0)
|
||||
{
|
||||
if (RXPacketType == DTSegmentWriteNACK)
|
||||
{
|
||||
DTSegment = DTheader[4] + (DTheader[5] << 8); //load what the segment number should be
|
||||
RXHeaderL = DTheader[2];
|
||||
Serial.println();
|
||||
Serial.println(F("************************************"));
|
||||
Serial.print(F("Received restart request at segment "));
|
||||
Serial.println(DTSegment);
|
||||
printheader(DTheader, RXHeaderL);
|
||||
Serial.println();
|
||||
Serial.print(F("Seek to file location "));
|
||||
Serial.println(DTSegment * DTSegmentSize);
|
||||
Serial.println(F("************************************"));
|
||||
Serial.println();
|
||||
Serial.flush();
|
||||
}
|
||||
|
||||
//ack is valid, segment was acknowledged if here
|
||||
|
||||
if (RXPacketType == DTStartNACK)
|
||||
{
|
||||
Serial.println(F("Received DTStartNACK "));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (RXPacketType == DTSegmentWriteACK)
|
||||
{
|
||||
AckCount++;
|
||||
#ifdef DEBUG
|
||||
printAckBrief();
|
||||
//printAckDetails()
|
||||
#endif
|
||||
DTSegment++; //increase value for next segment
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
NoAckCount++;
|
||||
Serial.print(F("Error no ACK received "));
|
||||
Serial.println(NoAckCount);
|
||||
if (NoAckCount > NoAckCountLimit)
|
||||
{
|
||||
Serial.println(F("ERROR NoACK limit reached"));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} while (ValidACK == 0);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool startFileTransfer(char *buff, uint8_t filenamesize, uint8_t attempts)
|
||||
{
|
||||
//*********************************************************************
|
||||
//Start file transfer, simulate open local file first then remote file.
|
||||
//*********************************************************************
|
||||
|
||||
uint8_t ValidACK;
|
||||
|
||||
Serial.print(F("Start file transfer "));
|
||||
Serial.println(buff);
|
||||
|
||||
DTSourceFileLength = DTFileSize; //get the file length
|
||||
|
||||
if (DTSourceFileLength == 0)
|
||||
{
|
||||
Serial.print(F("Error opening local file "));
|
||||
Serial.println(buff);
|
||||
return false;
|
||||
}
|
||||
|
||||
DTNumberSegments = getNumberSegments(DTSourceFileLength, DTSegmentSize);
|
||||
DTLastSegmentSize = getLastSegmentSize(DTSourceFileLength, DTSegmentSize);
|
||||
|
||||
build_DTFileOpenHeader(DTheader, DTFileOpenHeaderL, filenamesize, DTSourceFileLength, DTSourceFileCRC, DTSegmentSize);
|
||||
LocalPayloadCRC = LoRa.CRCCCITT((uint8_t *) buff, filenamesize, 0xFFFF);
|
||||
|
||||
do
|
||||
{
|
||||
Serial.println(F("Send open remote file request"));
|
||||
digitalWrite(DTLED, HIGH);
|
||||
TXPacketL = LoRa.transmitDT(DTheader, DTFileOpenHeaderL, (uint8_t *) buff, filenamesize, NetworkID, TXtimeoutmS, TXpower, WAIT_TX);
|
||||
digitalWrite(DTLED, LOW);
|
||||
|
||||
#ifdef DEBUG
|
||||
Serial.print(F("Send attempt "));
|
||||
Serial.println(DTSendAttempts - attempts + 1);
|
||||
#endif
|
||||
|
||||
attempts--;
|
||||
TXNetworkID = LoRa.getTXNetworkID(TXPacketL); //get the networkID appended to packet
|
||||
TXArrayCRC = LoRa.getTXPayloadCRC(TXPacketL); //get the payload CRC appended to packet
|
||||
|
||||
#ifdef DEBUG
|
||||
Serial.print(F("TXNetworkID,0x"));
|
||||
Serial.print(TXNetworkID, HEX); //get the NetworkID of the packet just sent, its placed at the packet end
|
||||
Serial.print(F(",TXarrayCRC,0x"));
|
||||
Serial.println(TXArrayCRC, HEX); //get the CRC of the data array just sent, its placed at the packet end
|
||||
Serial.println();
|
||||
#endif
|
||||
|
||||
if (TXPacketL == 0) //if there has been a send and ack error, TXPacketL returns as 0
|
||||
{
|
||||
Serial.println(F("Transmit error"));
|
||||
}
|
||||
|
||||
Serial.print(F("Wait ACK "));
|
||||
ValidACK = LoRa.waitACKDT(DTheader, DTFileOpenHeaderL, ACKopentimeoutmS);
|
||||
RXPacketType = DTheader[0];
|
||||
|
||||
if ((ValidACK > 0) && (RXPacketType == DTFileOpenACK))
|
||||
{
|
||||
#ifdef DEBUG
|
||||
printPacketHex();
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
NoAckCount++;
|
||||
Serial.println(F("No ACK received"));
|
||||
Serial.println(NoAckCount);
|
||||
if (NoAckCount > NoAckCountLimit)
|
||||
{
|
||||
Serial.println(F("ERROR NoACK limit reached"));
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
printACKdetail();
|
||||
Serial.print(F("ACKPacket "));
|
||||
printPacketHex();
|
||||
#endif
|
||||
Serial.println();
|
||||
}
|
||||
Serial.println();
|
||||
}
|
||||
while ((ValidACK == 0) && (attempts != 0));
|
||||
|
||||
if (attempts == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool endFileTransfer(char *buff, uint8_t filenamesize)
|
||||
{
|
||||
//****************************************************************
|
||||
//End file transfer, close local file first then remote file.
|
||||
//****************************************************************
|
||||
|
||||
uint8_t ValidACK;
|
||||
|
||||
build_DTFileCloseHeader(DTheader, DTFileCloseHeaderL, filenamesize, DTSourceFileLength, DTSourceFileCRC, DTSegmentSize);
|
||||
|
||||
do
|
||||
{
|
||||
printSeconds();
|
||||
Serial.println(F("Send close remote file"));
|
||||
|
||||
digitalWrite(DTLED, HIGH);
|
||||
TXPacketL = LoRa.transmitDT(DTheader, DTFileCloseHeaderL, (uint8_t *) buff, filenamesize, NetworkID, TXtimeoutmS, TXpower, WAIT_TX);
|
||||
digitalWrite(DTLED, LOW);
|
||||
|
||||
TXNetworkID = LoRa.getTXNetworkID(TXPacketL);
|
||||
TXArrayCRC = LoRa.getTXPayloadCRC(TXPacketL);
|
||||
|
||||
#ifdef DEBUG
|
||||
Serial.print(F("TXNetworkID,0x"));
|
||||
Serial.print(TXNetworkID, HEX); //get the NetworkID of the packet just sent, its placed at the packet end
|
||||
Serial.print(F(",TXarrayCRC,0x"));
|
||||
Serial.println(TXArrayCRC, HEX); //get the CRC of the data array just sent, its placed at the packet end
|
||||
Serial.println();
|
||||
#endif
|
||||
|
||||
if (TXPacketL == 0) //if there has been a send and ack error, RXPacketL returns as 0
|
||||
{
|
||||
Serial.println(F("Transmit error"));
|
||||
}
|
||||
|
||||
ValidACK = LoRa.waitACKDT(DTheader, DTFileCloseHeaderL, ACKclosetimeoutmS);
|
||||
RXPacketType = DTheader[0];
|
||||
|
||||
if ((ValidACK > 0) && (RXPacketType == DTFileCloseACK))
|
||||
{
|
||||
#ifdef DEBUG
|
||||
printPacketHex();
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
NoAckCount++;
|
||||
Serial.print(F("Error no ACK received "));
|
||||
Serial.println(NoAckCount);
|
||||
if (NoAckCount > NoAckCountLimit)
|
||||
{
|
||||
Serial.println(F("ERROR NoACK limit reached"));
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
Serial.println();
|
||||
Serial.print(F("ACKPacket "));
|
||||
printPacketHex();
|
||||
Serial.println();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
while (ValidACK == 0);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void build_DTFileOpenHeader(uint8_t *header, uint8_t headersize, uint8_t datalength, uint32_t filelength, uint16_t filecrc, uint8_t segsize)
|
||||
{
|
||||
//this builds the header buffer for the filename to send
|
||||
|
||||
beginarrayRW(header, 0); //start writing to array at location 0
|
||||
arrayWriteUint8(DTFileOpen); //byte 0, write the packet type
|
||||
arrayWriteUint8(0); //byte 1, initial DTflags byte, not used here
|
||||
arrayWriteUint8(headersize); //byte 2, write length of header
|
||||
arrayWriteUint8(datalength); //byte 3, write length of dataarray
|
||||
arrayWriteUint32(filelength); //byte 4,5,6,7, write the file length
|
||||
arrayWriteUint16(filecrc); //byte 8, 9, write file CRC
|
||||
arrayWriteUint8(segsize); //byte 10, segment size
|
||||
arrayWriteUint8(0); //byte 11, unused byte
|
||||
endarrayRW();
|
||||
}
|
||||
|
||||
|
||||
void build_DTSegmentHeader(uint8_t *header, uint8_t headersize, uint8_t datalen, uint16_t segnum)
|
||||
{
|
||||
//this builds the header buffer for a segment transmit
|
||||
|
||||
beginarrayRW(header, 0); //start writing to array at location 0
|
||||
arrayWriteUint8(DTSegmentWrite); //write the packet type
|
||||
arrayWriteUint8(0); //initial DTflags byte, not used here
|
||||
arrayWriteUint8(headersize); //write length of header
|
||||
arrayWriteUint8(datalen); //write length of data array
|
||||
arrayWriteUint16(segnum); //write the DTsegment number
|
||||
endarrayRW();
|
||||
}
|
||||
|
||||
|
||||
void build_DTFileCloseHeader(uint8_t *header, uint8_t headersize, uint8_t datalength, uint32_t filelength, uint16_t filecrc, uint8_t segsize)
|
||||
{
|
||||
//this builds the header buffer for the filename passed
|
||||
|
||||
beginarrayRW(header, 0); //start writing to array at location 0
|
||||
arrayWriteUint8(DTFileClose); //byte 0, write the packet type
|
||||
arrayWriteUint8(0); //byte 1, initial DTflags byte, not used here
|
||||
arrayWriteUint8(headersize); //byte 2, write length of header
|
||||
arrayWriteUint8(datalength); //byte 3, write length of dataarray
|
||||
arrayWriteUint32(filelength); //byte 4,5,6,7, write the file length
|
||||
arrayWriteUint16(filecrc); //byte 8, 9, write file CRC
|
||||
arrayWriteUint8(segsize); //byte 10, segment size
|
||||
arrayWriteUint8(0); //byte 11, unused byte
|
||||
endarrayRW();
|
||||
}
|
||||
|
||||
|
||||
void printLocalFileDetails()
|
||||
{
|
||||
Serial.print(F("Source file length is "));
|
||||
Serial.print(DTSourceFileLength);
|
||||
Serial.println(F(" bytes"));
|
||||
Serial.print(F("Segment Size "));
|
||||
Serial.println(DTSegmentSize);
|
||||
Serial.print(F("Number segments "));
|
||||
Serial.println(DTNumberSegments);
|
||||
Serial.print(F("Last segment size "));
|
||||
Serial.println(DTLastSegmentSize);
|
||||
}
|
||||
|
||||
|
||||
bool sendSegments()
|
||||
{
|
||||
//start the file transfer at segment 0
|
||||
DTSegment = 0;
|
||||
DTSentSegments = 0;
|
||||
|
||||
while (DTSegment < (DTNumberSegments - 1))
|
||||
{
|
||||
#ifdef DEBUG
|
||||
printSeconds();
|
||||
#endif
|
||||
|
||||
if (sendFileSegment(DTSegment, DTSegmentSize))
|
||||
{
|
||||
DTSentSegments++;
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.println(F("ERROR in sendFileSegment"));
|
||||
Serial.println();
|
||||
return false;
|
||||
}
|
||||
|
||||
delay(packetdelaymS);
|
||||
};
|
||||
|
||||
printSeconds();
|
||||
Serial.println(F("Last segment"));
|
||||
|
||||
if (!sendFileSegment(DTSegment, DTLastSegmentSize))
|
||||
{
|
||||
Serial.println(F("ERROR in sendFileSegment"));
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void printheader(uint8_t *hdr, uint8_t hdrsize)
|
||||
{
|
||||
Serial.print(F("HeaderBytes,"));
|
||||
Serial.print(hdrsize);
|
||||
Serial.print(F(" "));
|
||||
printarrayHEX(hdr, hdrsize);
|
||||
}
|
||||
|
||||
|
||||
void printSeconds()
|
||||
{
|
||||
float secs;
|
||||
secs = ( (float) millis() / 1000);
|
||||
Serial.print(secs, 2);
|
||||
Serial.print(F(" "));
|
||||
}
|
||||
|
||||
|
||||
void printdata(uint8_t *dataarray, uint8_t arraysize)
|
||||
{
|
||||
Serial.print(F("DataBytes,"));
|
||||
Serial.print(arraysize);
|
||||
Serial.print(F(" "));
|
||||
printarrayHEX((uint8_t *) dataarray, 16); //There is a lot of data to print so only print first 16 bytes
|
||||
}
|
||||
|
||||
|
||||
void printAckDetails()
|
||||
{
|
||||
PacketRSSI = LoRa.readPacketRSSI();
|
||||
PacketSNR = LoRa.readPacketSNR();
|
||||
Serial.print(F("AckCount,"));
|
||||
Serial.print(AckCount);
|
||||
Serial.print(F(",NoAckCount,"));
|
||||
Serial.print(NoAckCount);
|
||||
Serial.print(F(",AckRSSI,"));
|
||||
Serial.print(PacketRSSI);
|
||||
Serial.print(F("dBm,AckSNR,"));
|
||||
Serial.print(PacketSNR);
|
||||
Serial.print(F("dB"));
|
||||
Serial.println();
|
||||
}
|
||||
|
||||
|
||||
void printAckBrief()
|
||||
{
|
||||
PacketRSSI = LoRa.readPacketRSSI();
|
||||
Serial.print(F(",AckRSSI,"));
|
||||
Serial.print(PacketRSSI);
|
||||
Serial.println(F("dBm"));
|
||||
}
|
||||
|
||||
|
||||
void printACKdetail()
|
||||
{
|
||||
Serial.print(F("ACKDetail"));
|
||||
Serial.print(F(",RXNetworkID,0x"));
|
||||
Serial.print(LoRa.getRXNetworkID(RXPacketL), HEX);
|
||||
Serial.print(F(",RXPayloadCRC,0x"));
|
||||
Serial.print(LoRa.getRXPayloadCRC(RXPacketL), HEX);
|
||||
Serial.print(F(",RXPacketL,"));
|
||||
Serial.print(RXPacketL);
|
||||
Serial.print(F(" "));
|
||||
LoRa.printReliableStatus();
|
||||
Serial.println();
|
||||
}
|
||||
|
||||
|
||||
void printPacketHex()
|
||||
{
|
||||
RXPacketL = LoRa.readRXPacketL();
|
||||
Serial.print(RXPacketL);
|
||||
Serial.print(F(" bytes > "));
|
||||
if (RXPacketL > 0)
|
||||
{
|
||||
LoRa.printSXBufferHEX(0, RXPacketL - 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void printPacketDetails()
|
||||
{
|
||||
PacketRSSI = LoRa.readPacketRSSI();
|
||||
PacketSNR = LoRa.readPacketSNR();
|
||||
Serial.print(F(" RSSI,"));
|
||||
Serial.print(PacketRSSI);
|
||||
Serial.print(F("dBm"));
|
||||
|
||||
#ifdef DEBUG
|
||||
Serial.print(F(",SNR,"));
|
||||
Serial.print(PacketSNR);
|
||||
Serial.print(F("dBm,RXOKCount,"));
|
||||
Serial.print(DTReceivedSegments);
|
||||
Serial.print(F(",RXErrs,"));
|
||||
Serial.print(RXErrors);
|
||||
Serial.print(F(" RX"));
|
||||
printheader(DTheader, RXHeaderL);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void printPacketRSSI()
|
||||
{
|
||||
PacketRSSI = LoRa.readPacketRSSI();
|
||||
Serial.print(F(" RSSI,"));
|
||||
Serial.print(PacketRSSI);
|
||||
Serial.print(F("dBm"));
|
||||
}
|
||||
|
||||
void readHeaderDT()
|
||||
{
|
||||
//the first 6 bytes of the header contain the important stuff, so load it up
|
||||
//so we can decide what to do next.
|
||||
beginarrayRW(DTheader, 0); //start buffer read at location 0
|
||||
RXPacketType = arrayReadUint8(); //load the packet type
|
||||
RXFlags = arrayReadUint8(); //initial DTflags byte, not used here
|
||||
RXHeaderL = arrayReadUint8(); //load the header length
|
||||
RXDataarrayL = arrayReadUint8(); //load the datalength
|
||||
DTSegment = arrayReadUint16(); //load the segment number
|
||||
}
|
||||
|
||||
|
||||
void printSourceFileDetails()
|
||||
{
|
||||
Serial.print(DTfilenamebuff);
|
||||
Serial.print(F(" Source file length is "));
|
||||
Serial.print(DTSourceFileLength);
|
||||
Serial.println(F(" bytes"));
|
||||
Serial.print(DTfilenamebuff);
|
||||
}
|
||||
|
||||
|
||||
void printDestinationFileDetails()
|
||||
{
|
||||
Serial.print(F("Destination file length is "));
|
||||
Serial.print(DTDestinationFileLength);
|
||||
Serial.println(F(" bytes"));
|
||||
if (DTDestinationFileLength != DTSourceFileLength)
|
||||
{
|
||||
Serial.println(F("ERROR - file lengths do not match"));
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.println(F("File lengths match"));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool processFileClose()
|
||||
{
|
||||
//***********************************************************************************************
|
||||
// Code for closing local SD file and sending request to remote
|
||||
//***********************************************************************************************
|
||||
|
||||
Serial.print(F("File close for "));
|
||||
Serial.println((char*) DTfilenamebuff);
|
||||
|
||||
if (DTFileOpened) //check if file has been opened, close it if it is
|
||||
{
|
||||
if (1) //simulate file exists
|
||||
{
|
||||
|
||||
Serial.print(F("Transfer time "));
|
||||
Serial.print(millis() - DTStartmS);
|
||||
Serial.print(F("mS"));
|
||||
Serial.println();
|
||||
Serial.println(F("File closed"));
|
||||
Serial.println();
|
||||
|
||||
DTFileOpened = false;
|
||||
DTDestinationFileLength = DTFileSize;
|
||||
beginarrayRW(DTheader, 4); //start writing to array at location 12
|
||||
arrayWriteUint32(DTDestinationFileLength); //write file length of file just written just written to ACK header
|
||||
arrayWriteUint16(DTDestinationFileCRC); //write CRC of file just written to ACK header
|
||||
|
||||
printDestinationFileDetails();
|
||||
}
|
||||
}
|
||||
|
||||
delay(ACKdelaymS);
|
||||
#ifdef DEBUG
|
||||
Serial.println(F("Sending ACK"));
|
||||
#endif
|
||||
DTheader[0] = DTFileCloseACK;
|
||||
|
||||
digitalWrite(DTLED, HIGH);
|
||||
LoRa.sendACKDT(DTheader, DTFileCloseHeaderL, TXpower);
|
||||
digitalWrite(DTLED, LOW);
|
||||
|
||||
Serial.println();
|
||||
Serial.println();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool processFileOpen(uint8_t *buff, uint8_t filenamesize)
|
||||
{
|
||||
//*************************************************************************
|
||||
// Code for simulating opening local SD file and sending request to remote
|
||||
//*************************************************************************
|
||||
|
||||
beginarrayRW(DTheader, 4); //start buffer read at location 4
|
||||
DTSourceFileLength = arrayReadUint32(); //load the file length of the remote file being sent
|
||||
DTSourceFileCRC = arrayReadUint16(); //load the CRC of the source file being sent
|
||||
|
||||
memset(DTfilenamebuff, 0, DTfilenamesize); //clear DTfilenamebuff to all 0s
|
||||
memcpy(DTfilenamebuff, buff, filenamesize); //copy received DTdata into DTfilenamebuff
|
||||
|
||||
Serial.print(F("File Open request for "));
|
||||
Serial.print((char*) DTfilenamebuff);
|
||||
Serial.println();
|
||||
printSourceFileDetails();
|
||||
|
||||
if (1) //simulate open file for write at beginning, delete if it exists
|
||||
{
|
||||
Serial.print((char*) DTfilenamebuff);
|
||||
Serial.println(F(" File Opened OK"));
|
||||
Serial.println(F("Waiting transfer"));
|
||||
DTSegmentNext = 0; //since file is opened the next sequence should be the first
|
||||
DTFileOpened = true;
|
||||
DTStartmS = millis();
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.print((char*) DTfilenamebuff);
|
||||
Serial.println(F(" File Open fail"));
|
||||
DTFileOpened = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
DTStartmS = millis();
|
||||
delay(ACKdelaymS);
|
||||
#ifdef DEBUG
|
||||
Serial.println(F("Sending ACK"));
|
||||
#endif
|
||||
DTheader[0] = DTFileOpenACK; //set the ACK packet type
|
||||
digitalWrite(DTLED, HIGH);
|
||||
LoRa.sendACKDT(DTheader, DTFileOpenHeaderL, TXpower);
|
||||
digitalWrite(DTLED, LOW);
|
||||
DTSegmentNext = 0; //after file open, segment 0 is next
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool processSegmentWrite()
|
||||
{
|
||||
//***********************************************************************************************
|
||||
// Code for dealing with segment writes - checks that the sequence of segment writes is correct
|
||||
//***********************************************************************************************
|
||||
|
||||
if (!DTFileOpened)
|
||||
{
|
||||
//something is wrong, have received a request to write a segment but there is no file opened
|
||||
//need to reject the segment write with a restart NACK
|
||||
Serial.println();
|
||||
Serial.println(F("***************************************************"));
|
||||
Serial.println(F("Error - Segment write with no file open - send NACK"));
|
||||
Serial.println(F("***************************************************"));
|
||||
Serial.println();
|
||||
DTheader[0] = DTStartNACK;
|
||||
delay(ACKdelaymS);
|
||||
digitalWrite(DTLED, HIGH);
|
||||
LoRa.sendACKDT(DTheader, DTStartHeaderL, TXpower);
|
||||
digitalWrite(DTLED, LOW);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (DTSegment == DTSegmentNext)
|
||||
{
|
||||
|
||||
#ifdef PRINTSEGMENTNUM
|
||||
//Serial.print(F("Segment,"));
|
||||
Serial.println(DTSegment);
|
||||
#endif
|
||||
|
||||
#ifdef DEBUG
|
||||
Serial.print(F(",Bytes,"));
|
||||
Serial.print(RXDataarrayL);
|
||||
//printPacketDetails();
|
||||
printPacketRSSI();
|
||||
Serial.println(F(" SendACK"));
|
||||
#endif
|
||||
|
||||
DTheader[0] = DTSegmentWriteACK;
|
||||
delay(ACKdelaymS);
|
||||
digitalWrite(DTLED, HIGH);
|
||||
LoRa.sendACKDT(DTheader, DTSegmentWriteHeaderL, TXpower);
|
||||
digitalWrite(DTLED, LOW);
|
||||
DTReceivedSegments++;
|
||||
DTSegmentLast = DTSegment; //so we can tell if sequece has been received twice
|
||||
DTSegmentNext = DTSegment + 1;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (DTSegment == DTSegmentLast)
|
||||
{
|
||||
Serial.print(F("ERROR segment "));
|
||||
Serial.print(DTSegment);
|
||||
Serial.print(F(" already received "));
|
||||
//printPacketDetails();
|
||||
printPacketRSSI();
|
||||
DTheader[0] = DTSegmentWriteACK;
|
||||
Serial.print(F(" Send ACK"));
|
||||
delay(ACKdelaymS);
|
||||
delay(DuplicatedelaymS);
|
||||
digitalWrite(DTLED, HIGH);
|
||||
LoRa.sendACKDT(DTheader, DTSegmentWriteHeaderL, TXpower);
|
||||
digitalWrite(DTLED, LOW);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (DTSegment != DTSegmentNext )
|
||||
{
|
||||
Serial.print(F(" ERROR Received Segment "));
|
||||
Serial.print(DTSegment);
|
||||
Serial.print(F(" expected "));
|
||||
Serial.print(DTSegmentNext);
|
||||
Serial.print(F(" "));
|
||||
//printPacketDetails();
|
||||
printPacketRSSI();
|
||||
DTheader[0] = DTSegmentWriteNACK;
|
||||
DTheader[4] = lowByte(DTSegmentNext);
|
||||
DTheader[5] = highByte(DTSegmentNext);
|
||||
|
||||
Serial.print(F(" Send NACK for segment "));
|
||||
Serial.print(DTSegmentNext);
|
||||
delay(ACKdelaymS);
|
||||
delay(DuplicatedelaymS);
|
||||
digitalWrite(DTLED, HIGH);
|
||||
|
||||
Serial.println();
|
||||
Serial.println();
|
||||
Serial.println(F("*****************************************"));
|
||||
Serial.print(F("Transmit restart request for segment "));
|
||||
Serial.println(DTSegmentNext);
|
||||
printheader(DTheader, RXHeaderL);
|
||||
Serial.println();
|
||||
Serial.println(F("*****************************************"));
|
||||
Serial.println();
|
||||
Serial.flush();
|
||||
|
||||
LoRa.sendACKDT(DTheader, DTSegmentWriteHeaderL, TXpower);
|
||||
digitalWrite(DTLED, LOW);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool processPacket(uint8_t packettype)
|
||||
{
|
||||
//***********************************************************************************************
|
||||
// Decide what to do with an incoming packet
|
||||
//***********************************************************************************************
|
||||
|
||||
if (packettype == DTSegmentWrite)
|
||||
{
|
||||
processSegmentWrite();
|
||||
return true;
|
||||
}
|
||||
|
||||
if (packettype == DTFileOpen)
|
||||
{
|
||||
processFileOpen(DTdata, RXDataarrayL);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (packettype == DTFileClose)
|
||||
{
|
||||
processFileClose();
|
||||
return true;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool receiveaPacketDT()
|
||||
{
|
||||
//******************************
|
||||
//Receive Data transfer packets
|
||||
//******************************
|
||||
|
||||
RXPacketType = 0;
|
||||
|
||||
RXPacketL = LoRa.receiveDT(DTheader, HeaderSizeMax, (uint8_t *) DTdata, DataSizeMax, NetworkID, RXtimeoutmS, WAIT_RX);
|
||||
digitalWrite(DTLED, HIGH);
|
||||
|
||||
#ifdef DEBUG
|
||||
printSeconds();
|
||||
#endif
|
||||
|
||||
if (RXPacketL > 0)
|
||||
{
|
||||
//if the LT.receiveDT() returns a value > 0 for RXPacketL then packet was received OK
|
||||
//then only action payload if destinationNode = thisNode
|
||||
readHeaderDT(); //get the basic header details into global variables RXPacketType etc
|
||||
processPacket(RXPacketType); //process and act on the packet
|
||||
digitalWrite(DTLED, LOW);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
//if the LoRa.receiveDT() function detects an error RXOK is 0
|
||||
Serial.print(F("PacketError"));
|
||||
RXErrors++;
|
||||
printPacketDetails();
|
||||
#ifdef DEBUG
|
||||
LoRa.printReliableStatus();
|
||||
LoRa.printIrqStatus();
|
||||
#endif
|
||||
Serial.println();
|
||||
digitalWrite(DTLED, LOW);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
uint16_t getNumberSegments(uint32_t filesize, uint8_t segmentsize)
|
||||
{
|
||||
uint16_t segments;
|
||||
segments = filesize / segmentsize;
|
||||
if ((filesize % segmentsize) > 0)
|
||||
{
|
||||
segments++;
|
||||
}
|
||||
return segments;
|
||||
}
|
||||
|
||||
|
||||
uint8_t getLastSegmentSize(uint32_t filesize, uint8_t segmentsize)
|
||||
{
|
||||
uint8_t lastsize;
|
||||
lastsize = filesize % segmentsize;
|
||||
if (lastsize == 0)
|
||||
{
|
||||
lastsize = segmentsize;
|
||||
}
|
||||
return lastsize;
|
||||
}
|
||||
|
||||
|
||||
void setDTLED(int8_t pinnumber)
|
||||
{
|
||||
if (pinnumber >= 0)
|
||||
{
|
||||
DTLED = pinnumber;
|
||||
pinMode(pinnumber, OUTPUT);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,60 @@
|
||||
/*******************************************************************************************************
|
||||
Programs for Arduino - Copyright of the author Stuart Robinson - 12/03/22
|
||||
|
||||
This program is supplied as is, it is up to the user of the program to decide if the program is
|
||||
suitable for the intended purpose and free from errors.
|
||||
*******************************************************************************************************/
|
||||
|
||||
#define NSS 10 //select pin on LoRa device
|
||||
#define NRESET 9 //reset pin on LoRa device
|
||||
#define RFBUSY 7 //RFBUSY pin on LoRa device
|
||||
#define DIO1 3 //DIO1 pin on LoRa device, used for sensing RX and TX done
|
||||
#define LED1 8 //LED used to indicate transmission
|
||||
|
||||
#define LORA_DEVICE DEVICE_SX1280 //this is the device we are using
|
||||
|
||||
|
||||
//******* Setup LoRa Test Parameters Here ! ***************
|
||||
|
||||
const uint32_t Frequency = 2445000000; //frequency of transmissions
|
||||
const uint32_t Offset = 0; //offset frequency for calibration purposes
|
||||
const int8_t TXpower = 10; //LoRa transmit power
|
||||
|
||||
//******* Setup LoRa modem parameters here ! ***************
|
||||
const uint8_t Bandwidth = LORA_BW_1600; //LoRa bandwidth
|
||||
const uint8_t SpreadingFactor = LORA_SF5; //LoRa spreading factor
|
||||
const uint8_t CodeRate = LORA_CR_4_5; //LoRa coding rate
|
||||
|
||||
//******* Setup FLRC modem parameters here ! ***************
|
||||
const uint8_t BandwidthBitRate = FLRC_BR_1_300_BW_1_2; //FLRC bandwidth and bit rate, 1.3Mbs
|
||||
//const uint8_t BandwidthBitRate = FLRC_BR_0_260_BW_0_3; //FLRC 260kbps
|
||||
const uint8_t CodingRate = FLRC_CR_1_0; //FLRC coding rate
|
||||
const uint8_t BT = RADIO_MOD_SHAPING_BT_1_0; //FLRC BT
|
||||
const uint32_t Syncword = 0x01234567; //FLRC uses syncword
|
||||
|
||||
const uint32_t TXtimeoutmS = 5000; //mS to wait for TX to complete
|
||||
const uint32_t RXtimeoutmS = 60000; //mS to wait for receiving a packet
|
||||
const uint32_t ACKdelaymS = 0; //ms delay after packet actioned and ack sent
|
||||
const uint32_t ACKsegtimeoutmS = 75; //mS to wait for receiving an ACK before re-trying transmit segment
|
||||
const uint32_t ACKopentimeoutmS = 250; //mS to wait for receiving an ACK before re-trying transmit file open
|
||||
const uint32_t ACKclosetimeoutmS = 250; //mS to wait for receiving an ACK before re-trying transmit file close
|
||||
const uint32_t NoAckCountLimit = 250; //if no NoAckCount exceeds this value - restart transfer
|
||||
const uint32_t DuplicatedelaymS = 10; //ms delay if there has been an duplicate segment or command receipt
|
||||
const uint32_t packetdelaymS = 0; //mS delay between transmitted packets
|
||||
|
||||
const uint8_t HeaderSizeMax = 12; //max size of header in bytes, minimum size is 7 bytes
|
||||
const uint8_t DataSizeMax = 245; //max size of data array in bytes
|
||||
const uint8_t DTfilenamesize = 32; //size of DTfilename buffer
|
||||
|
||||
const uint16_t NetworkID = 0x3210; //a unique identifier to go out with packet
|
||||
const uint8_t DTSendAttempts = 10; //number of attempts sending a packet before a restart
|
||||
|
||||
const uint32_t DTFileSize = 65535; //size of file to simulate
|
||||
|
||||
#ifdef USELORA
|
||||
const uint8_t DTSegmentSize = 245; //number of bytes in each segment, 245 is maximum value for LoRa
|
||||
#endif
|
||||
|
||||
#ifdef USEFLRC
|
||||
const uint8_t DTSegmentSize = 117; //number of bytes in each segment, 117 is maximum value for FLRC
|
||||
#endif
|
||||
@ -0,0 +1,134 @@
|
||||
/*******************************************************************************************************
|
||||
Programs for Arduino - Copyright of the author Stuart Robinson - 12/03/22
|
||||
|
||||
This program is supplied as is, it is up to the user of the program to decide if the program is
|
||||
suitable for the intended purpose and free from errors.
|
||||
*******************************************************************************************************/
|
||||
|
||||
/*******************************************************************************************************
|
||||
Program Operation - This is a program that simulates the transfer of a file using data transfer (DT)
|
||||
packet functions from the SX128X library. No SD cards are needed for the simulation. Use with matching
|
||||
receiver program 231_Data_Transfer_Test_Transmitter.ino.
|
||||
|
||||
DT packets can be used for transfering large amounts of data in a sequence of packets or segments,
|
||||
in a reliable and resiliant way. The remote file open request, the segements sent and the remote file close
|
||||
will be transmitted until a valid acknowledge comes from the receiver.
|
||||
|
||||
Each DT packet contains a variable length header array and a variable length data array as the payload.
|
||||
On transmission the NetworkID and CRC of the payload are appended to the end of the packet by the library
|
||||
routines. The use of a NetworkID and CRC ensures that the receiver can validate the packet to a high degree
|
||||
of certainty. The receiver will not accept packets that dont have the appropriate NetworkID or payload CRC
|
||||
at the end of the packet.
|
||||
|
||||
The transmitter sends a sequence of segments in order and the receiver keeps track of the sequence. If
|
||||
the sequence fails for some reason, the receiver will return a NACK packet to the transmitter requesting
|
||||
the segment sequence it was expecting.
|
||||
|
||||
The transfers can be carried out using LoRa packets, max segment size (defined by DTSegmentSize) is 245 bytes
|
||||
for LoRa, or FLRC packets where 117 is maximum segment size.
|
||||
|
||||
Details of the packet identifiers, header and data lengths and formats used are in the file
|
||||
Data_transfer_packet_definitions.md in the \SX128X_examples\DataTransfer\ folder.
|
||||
|
||||
Serial monitor baud rate is set at 115200.
|
||||
*******************************************************************************************************/
|
||||
|
||||
#define USELORA //enable this define to use LoRa packets
|
||||
//#define USEFLRC //enable this define to use FLRC packets
|
||||
|
||||
#include <SPI.h>
|
||||
|
||||
#include <SX128XLT.h>
|
||||
#include <ProgramLT_Definitions.h>
|
||||
#include "DTSettings.h" //LoRa settings etc.
|
||||
#include <arrayRW.h>
|
||||
|
||||
SX128XLT LoRa; //create an SX128XLT library instance called LoRa
|
||||
|
||||
#define PRINTSEGMENTNUM //enable this define to print segment numbers
|
||||
|
||||
//#define DEBUG
|
||||
//#define DISABLEPAYLOADCRC //enable this define if you want to disable payload CRC checking
|
||||
|
||||
#include "DTLibrarySIM.h"
|
||||
|
||||
|
||||
void loop()
|
||||
{
|
||||
receiveaPacketDT();
|
||||
}
|
||||
|
||||
|
||||
void led_Flash(uint16_t flashes, uint16_t delaymS)
|
||||
{
|
||||
uint16_t index;
|
||||
for (index = 1; index <= flashes; index++)
|
||||
{
|
||||
digitalWrite(LED1, HIGH);
|
||||
delay(delaymS);
|
||||
digitalWrite(LED1, LOW);
|
||||
delay(delaymS);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void setup()
|
||||
{
|
||||
pinMode(LED1, OUTPUT); //setup pin as output for indicator LED
|
||||
led_Flash(2, 125); //two quick LED flashes to indicate program start
|
||||
setDTLED(LED1); //setup LED pin for data transfer indicator
|
||||
|
||||
Serial.begin(115200);
|
||||
Serial.println();
|
||||
Serial.println(F(__FILE__));
|
||||
|
||||
SPI.begin();
|
||||
|
||||
if (LoRa.begin(NSS, NRESET, RFBUSY, DIO1, LORA_DEVICE))
|
||||
{
|
||||
led_Flash(2, 125);
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.println(F("LoRa device error"));
|
||||
while (1)
|
||||
{
|
||||
led_Flash(50, 50); //long fast speed flash indicates device error
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef USELORA
|
||||
LoRa.setupLoRa(Frequency, Offset, SpreadingFactor, Bandwidth, CodeRate);
|
||||
Serial.println(F("Using LoRa packets"));
|
||||
#endif
|
||||
|
||||
#ifdef USEFLRC
|
||||
LoRa.setupFLRC(Frequency, Offset, BandwidthBitRate, CodingRate, BT, Syncword);
|
||||
Serial.println(F("Using FLRC packets"));
|
||||
#endif
|
||||
|
||||
|
||||
LoRa.printOperatingSettings();
|
||||
Serial.println();
|
||||
LoRa.printModemSettings();
|
||||
Serial.println();
|
||||
|
||||
#ifdef DISABLEPAYLOADCRC
|
||||
LoRa.setReliableConfig(NoReliableCRC);
|
||||
#endif
|
||||
|
||||
if (LoRa.getReliableConfig(NoReliableCRC))
|
||||
{
|
||||
Serial.println(F("Payload CRC disabled"));
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.println(F("Payload CRC enabled"));
|
||||
}
|
||||
|
||||
DTSegmentNext = 0;
|
||||
DTFileOpened = false;
|
||||
|
||||
Serial.println(F("File transfer receiver ready"));
|
||||
Serial.println();
|
||||
}
|
||||
@ -0,0 +1,972 @@
|
||||
/*******************************************************************************************************
|
||||
Programs for Arduino - Copyright of the author Stuart Robinson - - 12/03/22
|
||||
|
||||
This program is supplied as is, it is up to the user of the program to decide if the program is
|
||||
suitable for the intended purpose and free from errors.
|
||||
*******************************************************************************************************/
|
||||
|
||||
uint8_t RXPacketL; //length of received packet
|
||||
uint8_t RXPacketType; //type of received packet, segment write, ACK, NACK etc
|
||||
uint16_t RXErrors; //count of packets received with error
|
||||
uint8_t RXFlags; //DTflags byte in header, could be used to control actions in TX and RX
|
||||
uint8_t RXHeaderL; //length of header
|
||||
uint8_t RXDataarrayL; //length of data array\segment
|
||||
int16_t PacketRSSI; //stores RSSI of received packet
|
||||
int8_t PacketSNR; //stores signal to noise ratio of received packet
|
||||
|
||||
uint16_t TXNetworkID; //this is used to store the 'network' number, receiver must have the same networkID
|
||||
uint16_t TXArrayCRC; //should contain CRC of data array sent
|
||||
uint8_t TXPacketL; //length of transmitted packet
|
||||
|
||||
uint16_t AckCount; //keep a count of acks that are received within timeout period
|
||||
uint16_t NoAckCount; //keep a count of acks not received within timeout period
|
||||
uint16_t LocalPayloadCRC; //for calculating the local data array CRC
|
||||
|
||||
uint16_t DTDestinationFileCRC; //CRC of file received
|
||||
uint16_t DTSourceFileCRC; //CRC of returned of the remote saved file
|
||||
|
||||
uint32_t DTDestinationFileLength; //length of file written on this destination
|
||||
uint32_t DTSourceFileLength; //length of file at source
|
||||
|
||||
uint32_t DTStartmS; //used for timeing transfers
|
||||
bool DTFileOpened; //bool to record when file has been opened
|
||||
|
||||
uint16_t DTSegment = 0; //current segment number
|
||||
uint16_t DTSegmentNext; //next segment expected
|
||||
uint16_t DTReceivedSegments; //count of segments received
|
||||
uint16_t DTSegmentLast; //last segment processed
|
||||
uint8_t DTLastSegmentSize; //size of the last segment
|
||||
uint16_t DTNumberSegments; //number of segments for a file transfer
|
||||
uint16_t DTSentSegments; //count of segments sent
|
||||
|
||||
bool DTFileTransferComplete; //bool to flag file transfer complete
|
||||
uint32_t DTSendmS; //used for timing transfers
|
||||
float DTsendSecs; //seconds to transfer a file
|
||||
|
||||
char DTfilenamebuff[DTfilenamesize];
|
||||
|
||||
int DTLED = -1; //pin number for indicator LED, if -1 then not used
|
||||
|
||||
bool sendFile(char *DTFileName, uint8_t namelength);
|
||||
bool sendFileSegment(uint16_t segnum, uint8_t segmentsize);
|
||||
bool startFileTransfer(char *buff, uint8_t filenamesize, uint8_t attempts);
|
||||
bool endFileTransfer(char *buff, uint8_t filenamesize);
|
||||
void build_DTFileOpenHeader(uint8_t *header, uint8_t headersize, uint8_t datalength, uint32_t filelength, uint16_t filecrc, uint8_t segsize);
|
||||
void build_DTSegmentHeader(uint8_t *header, uint8_t headersize, uint8_t datalen, uint16_t segnum);
|
||||
void build_DTFileCloseHeader(uint8_t *header, uint8_t headersize, uint8_t datalength, uint32_t filelength, uint16_t filecrc, uint8_t segsize);
|
||||
void printLocalFileDetails();
|
||||
bool sendSegments();
|
||||
void printheader(uint8_t *hdr, uint8_t hdrsize);
|
||||
void printSeconds();
|
||||
void printAckBrief();
|
||||
void printAckDetails();
|
||||
void printdata(uint8_t *dataarray, uint8_t arraysize);
|
||||
void printACKdetail();
|
||||
void printPacketHex();
|
||||
void printPacketRSSI();
|
||||
void printPacketDetails();
|
||||
void readHeaderDT();
|
||||
void printSourceFileDetails();
|
||||
void printDestinationFileDetails();
|
||||
bool processFileClose();
|
||||
bool processFileOpen(uint8_t *buff, uint8_t filenamesize);
|
||||
bool processSegmentWrite();
|
||||
bool processPacket(uint8_t packettype);
|
||||
bool receiveaPacketDT();
|
||||
uint16_t getNumberSegments(uint32_t filesize, uint8_t segmentsize);
|
||||
uint8_t getLastSegmentSize(uint32_t filesize, uint8_t segmentsize);
|
||||
void setDTLED(int8_t pinnumber);
|
||||
|
||||
uint8_t DTheader[16]; //header array
|
||||
uint8_t DTdata[245]; //data/segment array
|
||||
|
||||
bool sendFile(char *DTFileName, uint8_t namelength)
|
||||
{
|
||||
//**************************************************************************************************************
|
||||
// Start filesend process
|
||||
// This routine allows the file transfer to be run with a function call of sendFile(FileName, sizeof(FileName));
|
||||
//**************************************************************************************************************
|
||||
|
||||
do
|
||||
{
|
||||
|
||||
DTStartmS = millis();
|
||||
|
||||
//opens the local file to send and sets up transfer parameters
|
||||
if (startFileTransfer(DTFileName, namelength, DTSendAttempts))
|
||||
{
|
||||
Serial.print(DTFileName);
|
||||
Serial.println(F(" opened OK on remote"));
|
||||
printLocalFileDetails();
|
||||
Serial.println();
|
||||
NoAckCount = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.print(DTFileName);
|
||||
Serial.println(F(" Error opening remote file - restart transfer"));
|
||||
DTFileTransferComplete = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
delay(packetdelaymS);
|
||||
|
||||
if (!sendSegments())
|
||||
{
|
||||
Serial.println();
|
||||
Serial.println(F("**********************************************************"));
|
||||
Serial.println(F("Error - Segment write with no file open - Restart received"));
|
||||
Serial.println(F("**********************************************************"));
|
||||
Serial.println();
|
||||
continue;
|
||||
}
|
||||
|
||||
if (endFileTransfer(DTFileName, namelength)) //send command to close remote file
|
||||
{
|
||||
DTSendmS = millis() - DTStartmS; //record time taken for transfer
|
||||
Serial.print(DTFileName);
|
||||
Serial.println(F(" closed OK on remote"));
|
||||
beginarrayRW(DTheader, 4);
|
||||
DTDestinationFileLength = arrayReadUint32();
|
||||
Serial.print(F("Acknowledged remote destination file length "));
|
||||
Serial.println(DTDestinationFileLength);
|
||||
if (DTDestinationFileLength != DTSourceFileLength)
|
||||
{
|
||||
Serial.println(F("ERROR - file lengths do not match"));
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.println(F("File lengths match"));
|
||||
}
|
||||
DTFileTransferComplete = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
DTFileTransferComplete = false;
|
||||
Serial.println(F("ERROR send close remote destination file failed - program halted"));
|
||||
}
|
||||
}
|
||||
while (!DTFileTransferComplete);
|
||||
|
||||
Serial.print(F("NoAckCount "));
|
||||
Serial.println( NoAckCount);
|
||||
Serial.println();
|
||||
DTsendSecs = (float) DTSendmS / 1000;
|
||||
Serial.print(F("Transmit time "));
|
||||
Serial.print(DTsendSecs, 3);
|
||||
Serial.println(F("secs"));
|
||||
Serial.print(F("Transmit rate "));
|
||||
Serial.print( (DTDestinationFileLength * 8) / (DTsendSecs), 0 );
|
||||
Serial.println(F("bps"));
|
||||
Serial.println(("Transfer finished"));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool sendFileSegment(uint16_t segnum, uint8_t segmentsize)
|
||||
{
|
||||
//****************************************************************
|
||||
//Send file segment as payload in a packet
|
||||
//****************************************************************
|
||||
|
||||
uint8_t ValidACK;
|
||||
|
||||
build_DTSegmentHeader(DTheader, DTSegmentWriteHeaderL, segmentsize, segnum);
|
||||
|
||||
#ifdef PRINTSEGMENTNUM
|
||||
//Serial.print(F("Segment,"));
|
||||
Serial.println(segnum);
|
||||
#endif
|
||||
|
||||
#ifdef DEBUG
|
||||
printheader(DTheader, DTSegmentWriteHeaderL);
|
||||
Serial.print(F(" "));
|
||||
printdata(DTdata, segmentsize); //print segment size of data array only
|
||||
#endif
|
||||
|
||||
do
|
||||
{
|
||||
digitalWrite(DTLED, HIGH);
|
||||
TXPacketL = LoRa.transmitDT(DTheader, DTSegmentWriteHeaderL, (uint8_t *) DTdata, segmentsize, NetworkID, TXtimeoutmS, TXpower, WAIT_TX);
|
||||
digitalWrite(DTLED, LOW);
|
||||
|
||||
if (TXPacketL == 0) //if there has been an error TXPacketL returns as 0
|
||||
{
|
||||
Serial.println(F("Transmit error"));
|
||||
}
|
||||
|
||||
ValidACK = LoRa.waitACKDT(DTheader, DTSegmentWriteHeaderL, ACKsegtimeoutmS);
|
||||
RXPacketType = DTheader[0];
|
||||
|
||||
if (ValidACK > 0)
|
||||
{
|
||||
if (RXPacketType == DTSegmentWriteNACK)
|
||||
{
|
||||
DTSegment = DTheader[4] + (DTheader[5] << 8); //load what the segment number should be
|
||||
RXHeaderL = DTheader[2];
|
||||
Serial.println();
|
||||
Serial.println(F("************************************"));
|
||||
Serial.print(F("Received restart request at segment "));
|
||||
Serial.println(DTSegment);
|
||||
printheader(DTheader, RXHeaderL);
|
||||
Serial.println();
|
||||
Serial.print(F("Seek to file location "));
|
||||
Serial.println(DTSegment * DTSegmentSize);
|
||||
Serial.println(F("************************************"));
|
||||
Serial.println();
|
||||
Serial.flush();
|
||||
}
|
||||
|
||||
//ack is valid, segment was acknowledged if here
|
||||
|
||||
if (RXPacketType == DTStartNACK)
|
||||
{
|
||||
Serial.println(F("Received DTStartNACK "));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (RXPacketType == DTSegmentWriteACK)
|
||||
{
|
||||
AckCount++;
|
||||
#ifdef DEBUG
|
||||
printAckBrief();
|
||||
//printAckDetails()
|
||||
#endif
|
||||
DTSegment++; //increase value for next segment
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
NoAckCount++;
|
||||
Serial.print(F("Error no ACK received "));
|
||||
Serial.println(NoAckCount);
|
||||
if (NoAckCount > NoAckCountLimit)
|
||||
{
|
||||
Serial.println(F("ERROR NoACK limit reached"));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} while (ValidACK == 0);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool startFileTransfer(char *buff, uint8_t filenamesize, uint8_t attempts)
|
||||
{
|
||||
//*********************************************************************
|
||||
//Start file transfer, simulate open local file first then remote file.
|
||||
//*********************************************************************
|
||||
|
||||
uint8_t ValidACK;
|
||||
|
||||
Serial.print(F("Start file transfer "));
|
||||
Serial.println(buff);
|
||||
|
||||
DTSourceFileLength = DTFileSize; //get the file length
|
||||
|
||||
if (DTSourceFileLength == 0)
|
||||
{
|
||||
Serial.print(F("Error opening local file "));
|
||||
Serial.println(buff);
|
||||
return false;
|
||||
}
|
||||
|
||||
DTNumberSegments = getNumberSegments(DTSourceFileLength, DTSegmentSize);
|
||||
DTLastSegmentSize = getLastSegmentSize(DTSourceFileLength, DTSegmentSize);
|
||||
|
||||
build_DTFileOpenHeader(DTheader, DTFileOpenHeaderL, filenamesize, DTSourceFileLength, DTSourceFileCRC, DTSegmentSize);
|
||||
LocalPayloadCRC = LoRa.CRCCCITT((uint8_t *) buff, filenamesize, 0xFFFF);
|
||||
|
||||
do
|
||||
{
|
||||
Serial.println(F("Send open remote file request"));
|
||||
digitalWrite(DTLED, HIGH);
|
||||
TXPacketL = LoRa.transmitDT(DTheader, DTFileOpenHeaderL, (uint8_t *) buff, filenamesize, NetworkID, TXtimeoutmS, TXpower, WAIT_TX);
|
||||
digitalWrite(DTLED, LOW);
|
||||
|
||||
#ifdef DEBUG
|
||||
Serial.print(F("Send attempt "));
|
||||
Serial.println(DTSendAttempts - attempts + 1);
|
||||
#endif
|
||||
|
||||
attempts--;
|
||||
TXNetworkID = LoRa.getTXNetworkID(TXPacketL); //get the networkID appended to packet
|
||||
TXArrayCRC = LoRa.getTXPayloadCRC(TXPacketL); //get the payload CRC appended to packet
|
||||
|
||||
#ifdef DEBUG
|
||||
Serial.print(F("TXNetworkID,0x"));
|
||||
Serial.print(TXNetworkID, HEX); //get the NetworkID of the packet just sent, its placed at the packet end
|
||||
Serial.print(F(",TXarrayCRC,0x"));
|
||||
Serial.println(TXArrayCRC, HEX); //get the CRC of the data array just sent, its placed at the packet end
|
||||
Serial.println();
|
||||
#endif
|
||||
|
||||
if (TXPacketL == 0) //if there has been a send and ack error, TXPacketL returns as 0
|
||||
{
|
||||
Serial.println(F("Transmit error"));
|
||||
}
|
||||
|
||||
Serial.print(F("Wait ACK "));
|
||||
ValidACK = LoRa.waitACKDT(DTheader, DTFileOpenHeaderL, ACKopentimeoutmS);
|
||||
RXPacketType = DTheader[0];
|
||||
|
||||
if ((ValidACK > 0) && (RXPacketType == DTFileOpenACK))
|
||||
{
|
||||
#ifdef DEBUG
|
||||
printPacketHex();
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
NoAckCount++;
|
||||
Serial.println(F("No ACK received"));
|
||||
Serial.println(NoAckCount);
|
||||
if (NoAckCount > NoAckCountLimit)
|
||||
{
|
||||
Serial.println(F("ERROR NoACK limit reached"));
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
printACKdetail();
|
||||
Serial.print(F("ACKPacket "));
|
||||
printPacketHex();
|
||||
#endif
|
||||
Serial.println();
|
||||
}
|
||||
Serial.println();
|
||||
}
|
||||
while ((ValidACK == 0) && (attempts != 0));
|
||||
|
||||
if (attempts == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool endFileTransfer(char *buff, uint8_t filenamesize)
|
||||
{
|
||||
//****************************************************************
|
||||
//End file transfer, close local file first then remote file.
|
||||
//****************************************************************
|
||||
|
||||
uint8_t ValidACK;
|
||||
|
||||
build_DTFileCloseHeader(DTheader, DTFileCloseHeaderL, filenamesize, DTSourceFileLength, DTSourceFileCRC, DTSegmentSize);
|
||||
|
||||
do
|
||||
{
|
||||
printSeconds();
|
||||
Serial.println(F("Send close remote file"));
|
||||
|
||||
digitalWrite(DTLED, HIGH);
|
||||
TXPacketL = LoRa.transmitDT(DTheader, DTFileCloseHeaderL, (uint8_t *) buff, filenamesize, NetworkID, TXtimeoutmS, TXpower, WAIT_TX);
|
||||
digitalWrite(DTLED, LOW);
|
||||
|
||||
TXNetworkID = LoRa.getTXNetworkID(TXPacketL);
|
||||
TXArrayCRC = LoRa.getTXPayloadCRC(TXPacketL);
|
||||
|
||||
#ifdef DEBUG
|
||||
Serial.print(F("TXNetworkID,0x"));
|
||||
Serial.print(TXNetworkID, HEX); //get the NetworkID of the packet just sent, its placed at the packet end
|
||||
Serial.print(F(",TXarrayCRC,0x"));
|
||||
Serial.println(TXArrayCRC, HEX); //get the CRC of the data array just sent, its placed at the packet end
|
||||
Serial.println();
|
||||
#endif
|
||||
|
||||
if (TXPacketL == 0) //if there has been a send and ack error, RXPacketL returns as 0
|
||||
{
|
||||
Serial.println(F("Transmit error"));
|
||||
}
|
||||
|
||||
ValidACK = LoRa.waitACKDT(DTheader, DTFileCloseHeaderL, ACKclosetimeoutmS);
|
||||
RXPacketType = DTheader[0];
|
||||
|
||||
if ((ValidACK > 0) && (RXPacketType == DTFileCloseACK))
|
||||
{
|
||||
#ifdef DEBUG
|
||||
printPacketHex();
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
NoAckCount++;
|
||||
Serial.print(F("Error no ACK received "));
|
||||
Serial.println(NoAckCount);
|
||||
if (NoAckCount > NoAckCountLimit)
|
||||
{
|
||||
Serial.println(F("ERROR NoACK limit reached"));
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
Serial.println();
|
||||
Serial.print(F("ACKPacket "));
|
||||
printPacketHex();
|
||||
Serial.println();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
while (ValidACK == 0);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void build_DTFileOpenHeader(uint8_t *header, uint8_t headersize, uint8_t datalength, uint32_t filelength, uint16_t filecrc, uint8_t segsize)
|
||||
{
|
||||
//this builds the header buffer for the filename to send
|
||||
|
||||
beginarrayRW(header, 0); //start writing to array at location 0
|
||||
arrayWriteUint8(DTFileOpen); //byte 0, write the packet type
|
||||
arrayWriteUint8(0); //byte 1, initial DTflags byte, not used here
|
||||
arrayWriteUint8(headersize); //byte 2, write length of header
|
||||
arrayWriteUint8(datalength); //byte 3, write length of dataarray
|
||||
arrayWriteUint32(filelength); //byte 4,5,6,7, write the file length
|
||||
arrayWriteUint16(filecrc); //byte 8, 9, write file CRC
|
||||
arrayWriteUint8(segsize); //byte 10, segment size
|
||||
arrayWriteUint8(0); //byte 11, unused byte
|
||||
endarrayRW();
|
||||
}
|
||||
|
||||
|
||||
void build_DTSegmentHeader(uint8_t *header, uint8_t headersize, uint8_t datalen, uint16_t segnum)
|
||||
{
|
||||
//this builds the header buffer for a segment transmit
|
||||
|
||||
beginarrayRW(header, 0); //start writing to array at location 0
|
||||
arrayWriteUint8(DTSegmentWrite); //write the packet type
|
||||
arrayWriteUint8(0); //initial DTflags byte, not used here
|
||||
arrayWriteUint8(headersize); //write length of header
|
||||
arrayWriteUint8(datalen); //write length of data array
|
||||
arrayWriteUint16(segnum); //write the DTsegment number
|
||||
endarrayRW();
|
||||
}
|
||||
|
||||
|
||||
void build_DTFileCloseHeader(uint8_t *header, uint8_t headersize, uint8_t datalength, uint32_t filelength, uint16_t filecrc, uint8_t segsize)
|
||||
{
|
||||
//this builds the header buffer for the filename passed
|
||||
|
||||
beginarrayRW(header, 0); //start writing to array at location 0
|
||||
arrayWriteUint8(DTFileClose); //byte 0, write the packet type
|
||||
arrayWriteUint8(0); //byte 1, initial DTflags byte, not used here
|
||||
arrayWriteUint8(headersize); //byte 2, write length of header
|
||||
arrayWriteUint8(datalength); //byte 3, write length of dataarray
|
||||
arrayWriteUint32(filelength); //byte 4,5,6,7, write the file length
|
||||
arrayWriteUint16(filecrc); //byte 8, 9, write file CRC
|
||||
arrayWriteUint8(segsize); //byte 10, segment size
|
||||
arrayWriteUint8(0); //byte 11, unused byte
|
||||
endarrayRW();
|
||||
}
|
||||
|
||||
|
||||
void printLocalFileDetails()
|
||||
{
|
||||
Serial.print(F("Source file length is "));
|
||||
Serial.print(DTSourceFileLength);
|
||||
Serial.println(F(" bytes"));
|
||||
Serial.print(F("Segment Size "));
|
||||
Serial.println(DTSegmentSize);
|
||||
Serial.print(F("Number segments "));
|
||||
Serial.println(DTNumberSegments);
|
||||
Serial.print(F("Last segment size "));
|
||||
Serial.println(DTLastSegmentSize);
|
||||
}
|
||||
|
||||
|
||||
bool sendSegments()
|
||||
{
|
||||
//start the file transfer at segment 0
|
||||
DTSegment = 0;
|
||||
DTSentSegments = 0;
|
||||
|
||||
while (DTSegment < (DTNumberSegments - 1))
|
||||
{
|
||||
#ifdef DEBUG
|
||||
printSeconds();
|
||||
#endif
|
||||
|
||||
if (sendFileSegment(DTSegment, DTSegmentSize))
|
||||
{
|
||||
DTSentSegments++;
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.println(F("ERROR in sendFileSegment"));
|
||||
Serial.println();
|
||||
return false;
|
||||
}
|
||||
|
||||
delay(packetdelaymS);
|
||||
};
|
||||
|
||||
printSeconds();
|
||||
Serial.println(F("Last segment"));
|
||||
|
||||
if (!sendFileSegment(DTSegment, DTLastSegmentSize))
|
||||
{
|
||||
Serial.println(F("ERROR in sendFileSegment"));
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void printheader(uint8_t *hdr, uint8_t hdrsize)
|
||||
{
|
||||
Serial.print(F("HeaderBytes,"));
|
||||
Serial.print(hdrsize);
|
||||
Serial.print(F(" "));
|
||||
printarrayHEX(hdr, hdrsize);
|
||||
}
|
||||
|
||||
|
||||
void printSeconds()
|
||||
{
|
||||
float secs;
|
||||
secs = ( (float) millis() / 1000);
|
||||
Serial.print(secs, 2);
|
||||
Serial.print(F(" "));
|
||||
}
|
||||
|
||||
|
||||
void printdata(uint8_t *dataarray, uint8_t arraysize)
|
||||
{
|
||||
Serial.print(F("DataBytes,"));
|
||||
Serial.print(arraysize);
|
||||
Serial.print(F(" "));
|
||||
printarrayHEX((uint8_t *) dataarray, 16); //There is a lot of data to print so only print first 16 bytes
|
||||
}
|
||||
|
||||
|
||||
void printAckDetails()
|
||||
{
|
||||
PacketRSSI = LoRa.readPacketRSSI();
|
||||
PacketSNR = LoRa.readPacketSNR();
|
||||
Serial.print(F("AckCount,"));
|
||||
Serial.print(AckCount);
|
||||
Serial.print(F(",NoAckCount,"));
|
||||
Serial.print(NoAckCount);
|
||||
Serial.print(F(",AckRSSI,"));
|
||||
Serial.print(PacketRSSI);
|
||||
Serial.print(F("dBm,AckSNR,"));
|
||||
Serial.print(PacketSNR);
|
||||
Serial.print(F("dB"));
|
||||
Serial.println();
|
||||
}
|
||||
|
||||
|
||||
void printAckBrief()
|
||||
{
|
||||
PacketRSSI = LoRa.readPacketRSSI();
|
||||
Serial.print(F(",AckRSSI,"));
|
||||
Serial.print(PacketRSSI);
|
||||
Serial.println(F("dBm"));
|
||||
}
|
||||
|
||||
|
||||
void printACKdetail()
|
||||
{
|
||||
Serial.print(F("ACKDetail"));
|
||||
Serial.print(F(",RXNetworkID,0x"));
|
||||
Serial.print(LoRa.getRXNetworkID(RXPacketL), HEX);
|
||||
Serial.print(F(",RXPayloadCRC,0x"));
|
||||
Serial.print(LoRa.getRXPayloadCRC(RXPacketL), HEX);
|
||||
Serial.print(F(",RXPacketL,"));
|
||||
Serial.print(RXPacketL);
|
||||
Serial.print(F(" "));
|
||||
LoRa.printReliableStatus();
|
||||
Serial.println();
|
||||
}
|
||||
|
||||
|
||||
void printPacketHex()
|
||||
{
|
||||
RXPacketL = LoRa.readRXPacketL();
|
||||
Serial.print(RXPacketL);
|
||||
Serial.print(F(" bytes > "));
|
||||
if (RXPacketL > 0)
|
||||
{
|
||||
LoRa.printSXBufferHEX(0, RXPacketL - 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void printPacketDetails()
|
||||
{
|
||||
PacketRSSI = LoRa.readPacketRSSI();
|
||||
PacketSNR = LoRa.readPacketSNR();
|
||||
Serial.print(F(" RSSI,"));
|
||||
Serial.print(PacketRSSI);
|
||||
Serial.print(F("dBm"));
|
||||
|
||||
#ifdef DEBUG
|
||||
Serial.print(F(",SNR,"));
|
||||
Serial.print(PacketSNR);
|
||||
Serial.print(F("dBm,RXOKCount,"));
|
||||
Serial.print(DTReceivedSegments);
|
||||
Serial.print(F(",RXErrs,"));
|
||||
Serial.print(RXErrors);
|
||||
Serial.print(F(" RX"));
|
||||
printheader(DTheader, RXHeaderL);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void printPacketRSSI()
|
||||
{
|
||||
PacketRSSI = LoRa.readPacketRSSI();
|
||||
Serial.print(F(" RSSI,"));
|
||||
Serial.print(PacketRSSI);
|
||||
Serial.print(F("dBm"));
|
||||
}
|
||||
|
||||
void readHeaderDT()
|
||||
{
|
||||
//the first 6 bytes of the header contain the important stuff, so load it up
|
||||
//so we can decide what to do next.
|
||||
beginarrayRW(DTheader, 0); //start buffer read at location 0
|
||||
RXPacketType = arrayReadUint8(); //load the packet type
|
||||
RXFlags = arrayReadUint8(); //initial DTflags byte, not used here
|
||||
RXHeaderL = arrayReadUint8(); //load the header length
|
||||
RXDataarrayL = arrayReadUint8(); //load the datalength
|
||||
DTSegment = arrayReadUint16(); //load the segment number
|
||||
}
|
||||
|
||||
|
||||
void printSourceFileDetails()
|
||||
{
|
||||
Serial.print(DTfilenamebuff);
|
||||
Serial.print(F(" Source file length is "));
|
||||
Serial.print(DTSourceFileLength);
|
||||
Serial.println(F(" bytes"));
|
||||
Serial.print(DTfilenamebuff);
|
||||
}
|
||||
|
||||
|
||||
void printDestinationFileDetails()
|
||||
{
|
||||
Serial.print(F("Destination file length is "));
|
||||
Serial.print(DTDestinationFileLength);
|
||||
Serial.println(F(" bytes"));
|
||||
if (DTDestinationFileLength != DTSourceFileLength)
|
||||
{
|
||||
Serial.println(F("ERROR - file lengths do not match"));
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.println(F("File lengths match"));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool processFileClose()
|
||||
{
|
||||
//***********************************************************************************************
|
||||
// Code for closing local SD file and sending request to remote
|
||||
//***********************************************************************************************
|
||||
|
||||
Serial.print(F("File close for "));
|
||||
Serial.println((char*) DTfilenamebuff);
|
||||
|
||||
if (DTFileOpened) //check if file has been opened, close it if it is
|
||||
{
|
||||
if (1) //simulate file exists
|
||||
{
|
||||
|
||||
Serial.print(F("Transfer time "));
|
||||
Serial.print(millis() - DTStartmS);
|
||||
Serial.print(F("mS"));
|
||||
Serial.println();
|
||||
Serial.println(F("File closed"));
|
||||
Serial.println();
|
||||
|
||||
DTFileOpened = false;
|
||||
DTDestinationFileLength = DTFileSize;
|
||||
beginarrayRW(DTheader, 4); //start writing to array at location 12
|
||||
arrayWriteUint32(DTDestinationFileLength); //write file length of file just written just written to ACK header
|
||||
arrayWriteUint16(DTDestinationFileCRC); //write CRC of file just written to ACK header
|
||||
|
||||
printDestinationFileDetails();
|
||||
}
|
||||
}
|
||||
|
||||
delay(ACKdelaymS);
|
||||
#ifdef DEBUG
|
||||
Serial.println(F("Sending ACK"));
|
||||
#endif
|
||||
DTheader[0] = DTFileCloseACK;
|
||||
|
||||
digitalWrite(DTLED, HIGH);
|
||||
LoRa.sendACKDT(DTheader, DTFileCloseHeaderL, TXpower);
|
||||
digitalWrite(DTLED, LOW);
|
||||
|
||||
Serial.println();
|
||||
Serial.println();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool processFileOpen(uint8_t *buff, uint8_t filenamesize)
|
||||
{
|
||||
//*************************************************************************
|
||||
// Code for simulating opening local SD file and sending request to remote
|
||||
//*************************************************************************
|
||||
|
||||
beginarrayRW(DTheader, 4); //start buffer read at location 4
|
||||
DTSourceFileLength = arrayReadUint32(); //load the file length of the remote file being sent
|
||||
DTSourceFileCRC = arrayReadUint16(); //load the CRC of the source file being sent
|
||||
|
||||
memset(DTfilenamebuff, 0, DTfilenamesize); //clear DTfilenamebuff to all 0s
|
||||
memcpy(DTfilenamebuff, buff, filenamesize); //copy received DTdata into DTfilenamebuff
|
||||
|
||||
Serial.print(F("File Open request for "));
|
||||
Serial.print((char*) DTfilenamebuff);
|
||||
Serial.println();
|
||||
printSourceFileDetails();
|
||||
|
||||
if (1) //simulate open file for write at beginning, delete if it exists
|
||||
{
|
||||
Serial.print((char*) DTfilenamebuff);
|
||||
Serial.println(F(" File Opened OK"));
|
||||
Serial.println(F("Waiting transfer"));
|
||||
DTSegmentNext = 0; //since file is opened the next sequence should be the first
|
||||
DTFileOpened = true;
|
||||
DTStartmS = millis();
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.print((char*) DTfilenamebuff);
|
||||
Serial.println(F(" File Open fail"));
|
||||
DTFileOpened = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
DTStartmS = millis();
|
||||
delay(ACKdelaymS);
|
||||
#ifdef DEBUG
|
||||
Serial.println(F("Sending ACK"));
|
||||
#endif
|
||||
DTheader[0] = DTFileOpenACK; //set the ACK packet type
|
||||
digitalWrite(DTLED, HIGH);
|
||||
LoRa.sendACKDT(DTheader, DTFileOpenHeaderL, TXpower);
|
||||
digitalWrite(DTLED, LOW);
|
||||
DTSegmentNext = 0; //after file open, segment 0 is next
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool processSegmentWrite()
|
||||
{
|
||||
//***********************************************************************************************
|
||||
// Code for dealing with segment writes - checks that the sequence of segment writes is correct
|
||||
//***********************************************************************************************
|
||||
|
||||
if (!DTFileOpened)
|
||||
{
|
||||
//something is wrong, have received a request to write a segment but there is no file opened
|
||||
//need to reject the segment write with a restart NACK
|
||||
Serial.println();
|
||||
Serial.println(F("***************************************************"));
|
||||
Serial.println(F("Error - Segment write with no file open - send NACK"));
|
||||
Serial.println(F("***************************************************"));
|
||||
Serial.println();
|
||||
DTheader[0] = DTStartNACK;
|
||||
delay(ACKdelaymS);
|
||||
digitalWrite(DTLED, HIGH);
|
||||
LoRa.sendACKDT(DTheader, DTStartHeaderL, TXpower);
|
||||
digitalWrite(DTLED, LOW);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (DTSegment == DTSegmentNext)
|
||||
{
|
||||
#ifdef PRINTSEGMENTNUM
|
||||
//Serial.print(F("Segment,"));
|
||||
Serial.println(DTSegment);
|
||||
#endif
|
||||
|
||||
#ifdef DEBUG
|
||||
Serial.print(F(",Bytes,"));
|
||||
Serial.print(RXDataarrayL);
|
||||
//printPacketDetails();
|
||||
printPacketRSSI();
|
||||
Serial.println(F(" SendACK"));
|
||||
#endif
|
||||
|
||||
DTheader[0] = DTSegmentWriteACK;
|
||||
delay(ACKdelaymS);
|
||||
digitalWrite(DTLED, HIGH);
|
||||
LoRa.sendACKDT(DTheader, DTSegmentWriteHeaderL, TXpower);
|
||||
digitalWrite(DTLED, LOW);
|
||||
DTReceivedSegments++;
|
||||
DTSegmentLast = DTSegment; //so we can tell if sequece has been received twice
|
||||
DTSegmentNext = DTSegment + 1;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (DTSegment == DTSegmentLast)
|
||||
{
|
||||
Serial.print(F("ERROR segment "));
|
||||
Serial.print(DTSegment);
|
||||
Serial.print(F(" already received "));
|
||||
//printPacketDetails();
|
||||
printPacketRSSI();
|
||||
DTheader[0] = DTSegmentWriteACK;
|
||||
Serial.print(F(" Send ACK"));
|
||||
delay(ACKdelaymS);
|
||||
delay(DuplicatedelaymS);
|
||||
digitalWrite(DTLED, HIGH);
|
||||
LoRa.sendACKDT(DTheader, DTSegmentWriteHeaderL, TXpower);
|
||||
digitalWrite(DTLED, LOW);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (DTSegment != DTSegmentNext )
|
||||
{
|
||||
Serial.print(F(" ERROR Received Segment "));
|
||||
Serial.print(DTSegment);
|
||||
Serial.print(F(" expected "));
|
||||
Serial.print(DTSegmentNext);
|
||||
Serial.print(F(" "));
|
||||
//printPacketDetails();
|
||||
printPacketRSSI();
|
||||
DTheader[0] = DTSegmentWriteNACK;
|
||||
DTheader[4] = lowByte(DTSegmentNext);
|
||||
DTheader[5] = highByte(DTSegmentNext);
|
||||
|
||||
Serial.print(F(" Send NACK for segment "));
|
||||
Serial.print(DTSegmentNext);
|
||||
delay(ACKdelaymS);
|
||||
delay(DuplicatedelaymS);
|
||||
digitalWrite(DTLED, HIGH);
|
||||
|
||||
Serial.println();
|
||||
Serial.println();
|
||||
Serial.println(F("*****************************************"));
|
||||
Serial.print(F("Transmit restart request for segment "));
|
||||
Serial.println(DTSegmentNext);
|
||||
printheader(DTheader, RXHeaderL);
|
||||
Serial.println();
|
||||
Serial.println(F("*****************************************"));
|
||||
Serial.println();
|
||||
Serial.flush();
|
||||
|
||||
LoRa.sendACKDT(DTheader, DTSegmentWriteHeaderL, TXpower);
|
||||
digitalWrite(DTLED, LOW);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool processPacket(uint8_t packettype)
|
||||
{
|
||||
//***********************************************************************************************
|
||||
// Decide what to do with an incoming packet
|
||||
//***********************************************************************************************
|
||||
|
||||
if (packettype == DTSegmentWrite)
|
||||
{
|
||||
processSegmentWrite();
|
||||
return true;
|
||||
}
|
||||
|
||||
if (packettype == DTFileOpen)
|
||||
{
|
||||
processFileOpen(DTdata, RXDataarrayL);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (packettype == DTFileClose)
|
||||
{
|
||||
processFileClose();
|
||||
return true;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool receiveaPacketDT()
|
||||
{
|
||||
//******************************
|
||||
//Receive Data transfer packets
|
||||
//******************************
|
||||
|
||||
RXPacketType = 0;
|
||||
|
||||
RXPacketL = LoRa.receiveDT(DTheader, HeaderSizeMax, (uint8_t *) DTdata, DataSizeMax, NetworkID, RXtimeoutmS, WAIT_RX);
|
||||
digitalWrite(DTLED, HIGH);
|
||||
|
||||
#ifdef DEBUG
|
||||
printSeconds();
|
||||
#endif
|
||||
|
||||
if (RXPacketL > 0)
|
||||
{
|
||||
//if the LT.receiveDT() returns a value > 0 for RXPacketL then packet was received OK
|
||||
//then only action payload if destinationNode = thisNode
|
||||
readHeaderDT(); //get the basic header details into global variables RXPacketType etc
|
||||
processPacket(RXPacketType); //process and act on the packet
|
||||
digitalWrite(DTLED, LOW);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
//if the LoRa.receiveDT() function detects an error RXOK is 0
|
||||
Serial.print(F("PacketError"));
|
||||
RXErrors++;
|
||||
printPacketDetails();
|
||||
#ifdef DEBUG
|
||||
LoRa.printReliableStatus();
|
||||
LoRa.printIrqStatus();
|
||||
#endif
|
||||
Serial.println();
|
||||
digitalWrite(DTLED, LOW);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
uint16_t getNumberSegments(uint32_t filesize, uint8_t segmentsize)
|
||||
{
|
||||
uint16_t segments;
|
||||
segments = filesize / segmentsize;
|
||||
if ((filesize % segmentsize) > 0)
|
||||
{
|
||||
segments++;
|
||||
}
|
||||
return segments;
|
||||
}
|
||||
|
||||
|
||||
uint8_t getLastSegmentSize(uint32_t filesize, uint8_t segmentsize)
|
||||
{
|
||||
uint8_t lastsize;
|
||||
lastsize = filesize % segmentsize;
|
||||
if (lastsize == 0)
|
||||
{
|
||||
lastsize = segmentsize;
|
||||
}
|
||||
return lastsize;
|
||||
}
|
||||
|
||||
|
||||
void setDTLED(int8_t pinnumber)
|
||||
{
|
||||
if (pinnumber >= 0)
|
||||
{
|
||||
DTLED = pinnumber;
|
||||
pinMode(pinnumber, OUTPUT);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,60 @@
|
||||
/*******************************************************************************************************
|
||||
Programs for Arduino - Copyright of the author Stuart Robinson - 12/03/22
|
||||
|
||||
This program is supplied as is, it is up to the user of the program to decide if the program is
|
||||
suitable for the intended purpose and free from errors.
|
||||
*******************************************************************************************************/
|
||||
#define NSS 10 //select pin on LoRa device
|
||||
#define NRESET 9 //reset pin on LoRa device
|
||||
#define RFBUSY 7 //RFBUSY pin on LoRa device
|
||||
#define DIO1 3 //DIO1 pin on LoRa device, used for sensing RX and TX done
|
||||
#define LED1 8 //LED used to indicate transmission
|
||||
|
||||
#define LORA_DEVICE DEVICE_SX1280 //this is the device we are using
|
||||
|
||||
|
||||
//******* Setup LoRa Test Parameters Here ! ***************
|
||||
|
||||
const uint32_t Frequency = 2445000000; //frequency of transmissions
|
||||
const uint32_t Offset = 0; //offset frequency for calibration purposes
|
||||
const int8_t TXpower = 10; //LoRa transmit power
|
||||
|
||||
//******* Setup LoRa modem parameters here ! ***************
|
||||
const uint8_t Bandwidth = LORA_BW_1600; //LoRa bandwidth
|
||||
const uint8_t SpreadingFactor = LORA_SF5; //LoRa spreading factor
|
||||
const uint8_t CodeRate = LORA_CR_4_5; //LoRa coding rate
|
||||
|
||||
//******* Setup FLRC modem parameters here ! ***************
|
||||
const uint8_t BandwidthBitRate = FLRC_BR_1_300_BW_1_2; //FLRC bandwidth and bit rate, 1.3Mbs
|
||||
//const uint8_t BandwidthBitRate = FLRC_BR_0_260_BW_0_3; //FLRC 260kbps
|
||||
const uint8_t CodingRate = FLRC_CR_1_0; //FLRC coding rate
|
||||
const uint8_t BT = RADIO_MOD_SHAPING_BT_1_0; //FLRC BT
|
||||
const uint32_t Syncword = 0x01234567; //FLRC uses syncword
|
||||
|
||||
|
||||
const uint32_t TXtimeoutmS = 5000; //mS to wait for TX to complete
|
||||
const uint32_t RXtimeoutmS = 60000; //mS to wait for receiving a packet
|
||||
const uint32_t ACKdelaymS = 0; //ms delay after packet actioned and ack sent
|
||||
const uint32_t ACKsegtimeoutmS = 75; //mS to wait for receiving an ACK before re-trying transmit segment
|
||||
const uint32_t ACKopentimeoutmS = 250; //mS to wait for receiving an ACK before re-trying transmit file open
|
||||
const uint32_t ACKclosetimeoutmS = 250; //mS to wait for receiving an ACK before re-trying transmit file close
|
||||
const uint32_t NoAckCountLimit = 250; //if no NoAckCount exceeds this value - restart transfer
|
||||
const uint32_t DuplicatedelaymS = 10; //ms delay if there has been an duplicate segment or command receipt
|
||||
const uint32_t packetdelaymS = 0; //mS delay between transmitted packets
|
||||
|
||||
const uint8_t HeaderSizeMax = 12; //max size of header in bytes, minimum size is 7 bytes
|
||||
const uint8_t DataSizeMax = 245; //max size of data array in bytes
|
||||
const uint8_t DTfilenamesize = 32; //size of DTfilename buffer
|
||||
|
||||
const uint16_t NetworkID = 0x3210; //a unique identifier to go out with packet
|
||||
const uint8_t DTSendAttempts = 10; //number of attempts sending a packet before a restart
|
||||
|
||||
const uint32_t DTFileSize = 65535; //size of file to simulate
|
||||
|
||||
#ifdef USELORA
|
||||
const uint8_t DTSegmentSize = 245; //number of bytes in each segment, 245 is maximum value for LoRa
|
||||
#endif
|
||||
|
||||
#ifdef USEFLRC
|
||||
const uint8_t DTSegmentSize = 117; //number of bytes in each segment, 117 is maximum value for FLRC
|
||||
#endif
|
||||
@ -0,0 +1,189 @@
|
||||
/*******************************************************************************************************
|
||||
Programs for Arduino - Copyright of the author Stuart Robinson - 12/03/22
|
||||
|
||||
This program is supplied as is, it is up to the user of the program to decide if the program is
|
||||
suitable for the intended purpose and free from errors.
|
||||
*******************************************************************************************************/
|
||||
|
||||
/*******************************************************************************************************
|
||||
Program Operation - This is a program that transfers a file using data transfer (DT) packet functions
|
||||
from the SX128X library to send a file from the SD card on one Arduino to the SD card on another Arduino.
|
||||
Arduino DUEs were used for the test and this example transfers an JPG image.
|
||||
|
||||
DT packets can be used for transfering large amounts of data in a sequence of packets or segments,
|
||||
in a reliable and resiliant way. The file open requests to the remote receiver, each segement sent and
|
||||
the remote file close will all keep transmitting until a valid acknowledge comes from the receiver.
|
||||
Use this transmitter with the matching receiver program, 234_SDfile_Transfer_Receiver.ino.
|
||||
|
||||
On transmission the NetworkID and CRC of the payload are appended to the end of the packet by the library
|
||||
routines. The use of a NetworkID and CRC ensures that the receiver can validate the packet to a high degree
|
||||
of certainty.
|
||||
|
||||
The transmitter sends the sequence of segments in order. If the sequence fails for some reason, the receiver
|
||||
will return a NACK packet to the transmitter requesting the segment sequence it was expecting.
|
||||
|
||||
Details of the packet identifiers, header and data lengths and formats used are in the file;
|
||||
'Data transfer packet definitions.md' in the \SX128X_examples\DataTransfer\ folder.
|
||||
|
||||
The transfer can be carried out using LoRa or FLRC packets, max segment size (defined by DTSegmentSize) is
|
||||
245 bytes for LoRa and 117 bytes for FLRC.
|
||||
|
||||
Serial monitor baud rate is set at 115200.
|
||||
*******************************************************************************************************/
|
||||
#define USELORA //enable this define to use LoRa packets
|
||||
//#define USEFLRC //enable this define to use FLRC packets
|
||||
|
||||
#include <SPI.h>
|
||||
|
||||
#include <SX128XLT.h>
|
||||
#include <ProgramLT_Definitions.h>
|
||||
#include "DTSettings.h" //LoRa settings etc.
|
||||
|
||||
SX128XLT LoRa; //create an SX128XLT library instance called LoRa, required by SDtransfer.h
|
||||
|
||||
#define ENABLEMONITOR //enable monitor prints
|
||||
#define PRINTSEGMENTNUM //enable this define to print segment numbers
|
||||
#define ENABLEFILECRC //enable this define to uses and show file CRCs
|
||||
//#define DISABLEPAYLOADCRC //enable this define if you want to disable payload CRC checking
|
||||
//#define DEBUG //see additional debug info
|
||||
|
||||
//#define SDLIB //define SDLIB for SD.h or SDFATLIB for SDfat.h
|
||||
#define SDFATLIB
|
||||
|
||||
#include <DTSDlibrary.h> //library of SD functions
|
||||
#include <SDtransfer.h> //library of data transfer functions
|
||||
|
||||
//choice of files to send
|
||||
//char FileName[] = "/$50SATL.JPG"; //file length 63091 bytes, file CRC 0x59CE
|
||||
char FileName[] = "/$50SATS.JPG"; //file length 6880 bytes, file CRC 0x0281
|
||||
//char FileName[] = "/$50SATT.JPG"; //file length 1068 bytes, file CRC 0x6A02
|
||||
|
||||
|
||||
void loop()
|
||||
{
|
||||
uint32_t filelength;
|
||||
|
||||
#ifdef ENABLEMONITOR
|
||||
Monitorport.println(F("Transfer started"));
|
||||
#endif
|
||||
|
||||
filelength = SDsendFile(FileName, sizeof(FileName));
|
||||
|
||||
if (filelength)
|
||||
{
|
||||
#ifdef ENABLEMONITOR
|
||||
Monitorport.println(F("Transfer finished"));
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef ENABLEMONITOR
|
||||
Monitorport.println(F("Transfer failed"));
|
||||
Monitorport.println();
|
||||
#endif
|
||||
}
|
||||
|
||||
delay(15000);
|
||||
|
||||
}
|
||||
|
||||
|
||||
void led_Flash(uint16_t flashes, uint16_t delaymS)
|
||||
{
|
||||
uint16_t index;
|
||||
for (index = 1; index <= flashes; index++)
|
||||
{
|
||||
digitalWrite(LED1, HIGH);
|
||||
delay(delaymS);
|
||||
digitalWrite(LED1, LOW);
|
||||
delay(delaymS);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void setup()
|
||||
{
|
||||
pinMode(LED1, OUTPUT); //setup pin as output for indicator LED
|
||||
led_Flash(2, 125); //two quick LED flashes to indicate program start
|
||||
SDsetLED(LED1); //setup LED pin for data transfer indicator
|
||||
|
||||
#ifdef ENABLEMONITOR
|
||||
Monitorport.begin(115200);
|
||||
Monitorport.println();
|
||||
Monitorport.println(F(__FILE__));
|
||||
Monitorport.flush();
|
||||
#endif
|
||||
|
||||
SPI.begin();
|
||||
|
||||
if (LoRa.begin(NSS, NRESET, RFBUSY, DIO1, LORA_DEVICE))
|
||||
{
|
||||
led_Flash(2, 125);
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef ENABLEMONITOR
|
||||
Monitorport.println(F("LoRa device error"));
|
||||
#endif
|
||||
while (1)
|
||||
{
|
||||
led_Flash(50, 50); //long fast speed flash indicates device error
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef USELORA
|
||||
LoRa.setupLoRa(Frequency, Offset, SpreadingFactor, Bandwidth, CodeRate);
|
||||
Serial.println(F("Using LoRa packets"));
|
||||
#endif
|
||||
|
||||
#ifdef USEFLRC
|
||||
LoRa.setupFLRC(Frequency, Offset, BandwidthBitRate, CodingRate, BT, Syncword);
|
||||
Serial.println(F("Using FLRC packets"));
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef ENABLEMONITOR
|
||||
Monitorport.println();
|
||||
Monitorport.print(F("Initializing SD card..."));
|
||||
#endif
|
||||
|
||||
if (DTSD_initSD(SDCS))
|
||||
{
|
||||
#ifdef ENABLEMONITOR
|
||||
Monitorport.println(F("SD Card initialized."));
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
Monitorport.println(F("SD Card failed, or not present."));
|
||||
while (1) led_Flash(100, 25);
|
||||
}
|
||||
|
||||
#ifdef ENABLEMONITOR
|
||||
Monitorport.println();
|
||||
#endif
|
||||
|
||||
#ifdef DISABLEPAYLOADCRC
|
||||
LoRa.setReliableConfig(NoReliableCRC);
|
||||
#endif
|
||||
|
||||
if (LoRa.getReliableConfig(NoReliableCRC))
|
||||
{
|
||||
#ifdef ENABLEMONITOR
|
||||
Monitorport.println(F("Payload CRC disabled"));
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef ENABLEMONITOR
|
||||
Monitorport.println(F("Payload CRC enabled"));
|
||||
#endif
|
||||
}
|
||||
|
||||
SDDTFileTransferComplete = false;
|
||||
|
||||
#ifdef ENABLEMONITOR
|
||||
Monitorport.println(F("SDfile transfer ready"));
|
||||
Monitorport.println();
|
||||
#endif
|
||||
}
|
||||
@ -0,0 +1,64 @@
|
||||
/*******************************************************************************************************
|
||||
Programs for Arduino - Copyright of the author Stuart Robinson - 12/03/22
|
||||
|
||||
This program is supplied as is, it is up to the user of the program to decide if the program is
|
||||
suitable for the intended purpose and free from errors.
|
||||
*******************************************************************************************************/
|
||||
|
||||
#define NSS 10 //select pin on LoRa device
|
||||
#define NRESET 9 //reset pin on LoRa device
|
||||
#define RFBUSY 7 //RFBUSY pin on LoRa device
|
||||
#define DIO1 3 //DIO1 pin on LoRa device, used for sensing RX and TX done
|
||||
#define LED1 8 //LED used to indicate transmission
|
||||
#define SDCS 30
|
||||
#define Monitorport Serial //Port where serial prints go
|
||||
|
||||
#define LORA_DEVICE DEVICE_SX1280 //this is the device we are using
|
||||
|
||||
|
||||
//******* Setup LoRa Test Parameters Here ! ***************
|
||||
|
||||
const uint32_t Frequency = 2445000000; //frequency of transmissions
|
||||
const uint32_t Offset = 0; //offset frequency for calibration purposes
|
||||
const int8_t TXpower = 10; //LoRa transmit power
|
||||
|
||||
//******* Setup LoRa modem parameters here ! ***************
|
||||
const uint8_t Bandwidth = LORA_BW_1600; //LoRa bandwidth
|
||||
const uint8_t SpreadingFactor = LORA_SF5; //LoRa spreading factor
|
||||
const uint8_t CodeRate = LORA_CR_4_5; //LoRa coding rate
|
||||
|
||||
//******* Setup FLRC modem parameters here ! ***************
|
||||
const uint8_t BandwidthBitRate = FLRC_BR_1_300_BW_1_2; //FLRC bandwidth and bit rate, 1.3Mbs
|
||||
//const uint8_t BandwidthBitRate = FLRC_BR_0_260_BW_0_3; //FLRC 260kbps
|
||||
const uint8_t CodingRate = FLRC_CR_1_0; //FLRC coding rate
|
||||
const uint8_t BT = RADIO_MOD_SHAPING_BT_1_0; //FLRC BT
|
||||
const uint32_t Syncword = 0x01234567; //FLRC uses syncword
|
||||
|
||||
|
||||
const uint32_t TXtimeoutmS = 5000; //mS to wait for TX to complete
|
||||
const uint32_t RXtimeoutmS = 60000; //mS to wait for receiving a packet
|
||||
const uint32_t ACKdelaymS = 0; //ms delay after packet actioned and ack sent
|
||||
const uint32_t ACKsegtimeoutmS = 75; //mS to wait for receiving an ACK before re-trying transmit segment
|
||||
const uint32_t ACKopentimeoutmS = 250; //mS to wait for receiving an ACK before re-trying transmit file open
|
||||
const uint32_t ACKclosetimeoutmS = 250; //mS to wait for receiving an ACK before re-trying transmit file close
|
||||
const uint32_t DuplicatedelaymS = 10; //ms delay if there has been an duplicate segment or command receipt
|
||||
const uint32_t FunctionDelaymS = 0; //delay between functions such as open file, send segments etc
|
||||
const uint32_t PacketDelaymS = 1000; //mS delay between transmitted packets such as DTInfo etc
|
||||
|
||||
const uint8_t StartAttempts = 2; //number of attempts to start transfer before a fail
|
||||
const uint8_t SendAttempts = 5; //number of attempts carrying out a process before a restart
|
||||
const uint32_t NoAckCountLimit = 250; //if no NoAckCount exceeds this value - restart transfer
|
||||
|
||||
const uint8_t HeaderSizeMax = 12; //max size of header in bytes, minimum size is 7 bytes
|
||||
const uint8_t DataSizeMax = 245; //max size of data array in bytes
|
||||
const uint8_t Maxfilenamesize = 32; //size of DTfilename buffer
|
||||
|
||||
const uint16_t NetworkID = 0x3210; //a unique identifier to go out with packet
|
||||
|
||||
#ifdef USELORA
|
||||
const uint8_t SegmentSize = 245; //number of bytes in each segment, 245 is maximum value for LoRa
|
||||
#endif
|
||||
|
||||
#ifdef USEFLRC
|
||||
const uint8_t SegmentSize = 117; //number of bytes in each segment, 117 is maximum value for FLRC
|
||||
#endif
|
||||
@ -0,0 +1,164 @@
|
||||
/*******************************************************************************************************
|
||||
Programs for Arduino - Copyright of the author Stuart Robinson - 10/03/22
|
||||
|
||||
This program is supplied as is, it is up to the user of the program to decide if the program is
|
||||
suitable for the intended purpose and free from errors.
|
||||
*******************************************************************************************************/
|
||||
|
||||
/*******************************************************************************************************
|
||||
Program Operation - This is a test program for the use of a data transfer (DT) packet to send a file
|
||||
from the SD card on one Arduino to the SD card on another Arduino, Arduino DUEs were used for the test.
|
||||
|
||||
DT packets can be used for transfering large amounts of data in a sequence of packets or segments,
|
||||
in a reliable and resiliant way. The remote file open request, the segements sent and the remote file close
|
||||
will be transmitted until a valid acknowledge comes from the receiver. Use with the matching transmitter
|
||||
program, 233_LoRa_SDfile_Transfer_Transmitter.ino.
|
||||
|
||||
Each DT packet contains a variable length header array and a variable length data array as the payload.
|
||||
On transmission the NetworkID and CRC of the payload are appended to the end of the packet by the library
|
||||
routines. The use of a NetworkID and CRC ensures that the receiver can validate the packet to a high degree
|
||||
of certainty. The receiver will not accept packets that dont have the appropriate NetworkID or payload CRC
|
||||
at the end of the packet.
|
||||
|
||||
The transmitter sends a sequence of segments in order and the receiver keeps track of the sequence. If
|
||||
the sequence fails for some reason, the receiver will return a NACK packet to the transmitter requesting
|
||||
the segment sequence it was expecting.
|
||||
|
||||
The transfer can be carried out using LoRa or FLRC packets, max segment size (defined by DTSegmentSize) is
|
||||
245 bytes for LoRa and 117 bytes for FLRC.
|
||||
|
||||
Details of the packet identifiers, header and data lengths and formats used are in the file
|
||||
Data_transfer_packet_definitions.md in the \SX128X_examples\DataTransfer\ folder.
|
||||
|
||||
Serial monitor baud rate is set at 115200.
|
||||
*******************************************************************************************************/
|
||||
#define USELORA //enable this define to use LoRa packets
|
||||
//#define USEFLRC //enable this define to use FLRC packets
|
||||
|
||||
#include <SPI.h>
|
||||
|
||||
#include <SX128XLT.h>
|
||||
#include <ProgramLT_Definitions.h>
|
||||
#include "DTSettings.h" //LoRa settings etc.
|
||||
|
||||
SX128XLT LoRa; //create an SX128XLT library instance called LoRa, required by SDtransfer.h
|
||||
|
||||
//#define SDLIB //define SDLIB for SD.h or SDFATLIB for SDfat.h
|
||||
#define SDFATLIB
|
||||
|
||||
#define ENABLEMONITOR //enable monitor prints
|
||||
#define PRINTSEGMENTNUM
|
||||
#define ENABLEFILECRC //enable this define to uses and show file CRCs
|
||||
//#define DISABLEPAYLOADCRC //enable this define if you want to disable payload CRC checking
|
||||
//#define DEBUG //see additional debug info
|
||||
|
||||
#include <DTSDlibrary.h> //library of SD functions
|
||||
#include <SDtransfer.h> //library of data transfer functions
|
||||
|
||||
|
||||
|
||||
void loop()
|
||||
{
|
||||
SDreceiveaPacketDT();
|
||||
}
|
||||
|
||||
|
||||
void led_Flash(uint16_t flashes, uint16_t delaymS)
|
||||
{
|
||||
uint16_t index;
|
||||
for (index = 1; index <= flashes; index++)
|
||||
{
|
||||
digitalWrite(LED1, HIGH);
|
||||
delay(delaymS);
|
||||
digitalWrite(LED1, LOW);
|
||||
delay(delaymS);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void setup()
|
||||
{
|
||||
pinMode(LED1, OUTPUT); //setup pin as output for indicator LED
|
||||
led_Flash(2, 125); //two quick LED flashes to indicate program start
|
||||
SDsetLED(LED1); //setup LED pin for data transfer indicator
|
||||
|
||||
#ifdef ENABLEMONITOR
|
||||
Monitorport.begin(115200);
|
||||
Monitorport.println();
|
||||
Monitorport.println(F(__FILE__));
|
||||
#endif
|
||||
|
||||
SPI.begin();
|
||||
|
||||
if (LoRa.begin(NSS, NRESET, RFBUSY, DIO1, LORA_DEVICE))
|
||||
{
|
||||
led_Flash(2, 125);
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef ENABLEMONITOR
|
||||
Monitorport.println(F("LoRa device error"));
|
||||
#endif
|
||||
while (1)
|
||||
{
|
||||
led_Flash(50, 50); //long fast speed flash indicates device error
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef USELORA
|
||||
LoRa.setupLoRa(Frequency, Offset, SpreadingFactor, Bandwidth, CodeRate);
|
||||
Serial.println(F("Using LoRa packets"));
|
||||
#endif
|
||||
|
||||
#ifdef USEFLRC
|
||||
LoRa.setupFLRC(Frequency, Offset, BandwidthBitRate, CodingRate, BT, Syncword);
|
||||
Serial.println(F("Using FLRC packets"));
|
||||
#endif
|
||||
|
||||
#ifdef ENABLEMONITOR
|
||||
Monitorport.println();
|
||||
Monitorport.print(F("Initializing SD card..."));
|
||||
#endif
|
||||
|
||||
if (DTSD_initSD(SDCS))
|
||||
{
|
||||
Monitorport.println(F("SD Card initialized."));
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef ENABLEMONITOR
|
||||
Monitorport.println(F("SD Card failed, or not present."));
|
||||
#endif
|
||||
while (1) led_Flash(100, 50);
|
||||
}
|
||||
|
||||
#ifdef ENABLEMONITOR
|
||||
Monitorport.println();
|
||||
#endif
|
||||
|
||||
#ifdef DISABLEPAYLOADCRC
|
||||
LoRa.setReliableConfig(NoReliableCRC);
|
||||
#endif
|
||||
|
||||
if (LoRa.getReliableConfig(NoReliableCRC))
|
||||
{
|
||||
Monitorport.println(F("Payload CRC disabled"));
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef ENABLEMONITOR
|
||||
Monitorport.println(F("Payload CRC enabled"));
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
SDDTSegmentNext = 0;
|
||||
SDDTFileOpened = false;
|
||||
|
||||
#ifdef ENABLEMONITOR
|
||||
Monitorport.println(F("SDfile transfer receiver ready"));
|
||||
Monitorport.println();
|
||||
#endif
|
||||
|
||||
|
||||
}
|
||||
@ -0,0 +1,64 @@
|
||||
/*******************************************************************************************************
|
||||
Programs for Arduino - Copyright of the author Stuart Robinson - 12/03/22
|
||||
|
||||
This program is supplied as is, it is up to the user of the program to decide if the program is
|
||||
suitable for the intended purpose and free from errors.
|
||||
*******************************************************************************************************/
|
||||
|
||||
#define NSS 10 //select pin on LoRa device
|
||||
#define NRESET 9 //reset pin on LoRa device
|
||||
#define RFBUSY 7 //RFBUSY pin on LoRa device
|
||||
#define DIO1 3 //DIO1 pin on LoRa device, used for sensing RX and TX done
|
||||
#define LED1 8 //LED used to indicate transmission
|
||||
#define SDCS 30
|
||||
#define Monitorport Serial //Port where serial prints go
|
||||
|
||||
#define LORA_DEVICE DEVICE_SX1280 //this is the device we are using
|
||||
|
||||
|
||||
//******* Setup LoRa Test Parameters Here ! ***************
|
||||
|
||||
const uint32_t Frequency = 2445000000; //frequency of transmissions
|
||||
const uint32_t Offset = 0; //offset frequency for calibration purposes
|
||||
const int8_t TXpower = 10; //LoRa transmit power
|
||||
|
||||
//******* Setup LoRa modem parameters here ! ***************
|
||||
const uint8_t Bandwidth = LORA_BW_1600; //LoRa bandwidth
|
||||
const uint8_t SpreadingFactor = LORA_SF5; //LoRa spreading factor
|
||||
const uint8_t CodeRate = LORA_CR_4_5; //LoRa coding rate
|
||||
|
||||
//******* Setup FLRC modem parameters here ! ***************
|
||||
const uint8_t BandwidthBitRate = FLRC_BR_1_300_BW_1_2; //FLRC bandwidth and bit rate, 1.3Mbs
|
||||
//const uint8_t BandwidthBitRate = FLRC_BR_0_260_BW_0_3; //FLRC 260kbps
|
||||
const uint8_t CodingRate = FLRC_CR_1_0; //FLRC coding rate
|
||||
const uint8_t BT = RADIO_MOD_SHAPING_BT_1_0; //FLRC BT
|
||||
const uint32_t Syncword = 0x01234567; //FLRC uses syncword
|
||||
|
||||
|
||||
const uint32_t TXtimeoutmS = 5000; //mS to wait for TX to complete
|
||||
const uint32_t RXtimeoutmS = 60000; //mS to wait for receiving a packet
|
||||
const uint32_t ACKdelaymS = 0; //ms delay after packet actioned and ack sent
|
||||
const uint32_t ACKsegtimeoutmS = 75; //mS to wait for receiving an ACK before re-trying transmit segment
|
||||
const uint32_t ACKopentimeoutmS = 250; //mS to wait for receiving an ACK before re-trying transmit file open
|
||||
const uint32_t ACKclosetimeoutmS = 250; //mS to wait for receiving an ACK before re-trying transmit file close
|
||||
const uint32_t DuplicatedelaymS = 10; //ms delay if there has been an duplicate segment or command receipt
|
||||
const uint32_t NoAckCountLimit = 250; //if no NoAckCount exceeds this value - restart transfer
|
||||
const uint32_t FunctionDelaymS = 0; //delay between functions such as open file, send segments etc
|
||||
const uint32_t PacketDelaymS = 1000; //mS delay between transmitted packets such as DTInfo etc
|
||||
|
||||
const uint8_t HeaderSizeMax = 12; //max size of header in bytes, minimum size is 7 bytes
|
||||
const uint8_t DataSizeMax = 245; //max size of data array in bytes
|
||||
const uint8_t Maxfilenamesize = 32; //size of DTfilename buffer
|
||||
|
||||
const uint16_t NetworkID = 0x3210; //a unique identifier to go out with packet
|
||||
const uint8_t SendAttempts = 10; //number of attempts sending a packet or attempting a process before a restart of transfer
|
||||
const uint8_t StartAttempts = 10; //number of attempts sending the file
|
||||
|
||||
|
||||
#ifdef USELORA
|
||||
const uint8_t SegmentSize = 245; //number of bytes in each segment, 245 is maximum value for LoRa
|
||||
#endif
|
||||
|
||||
#ifdef USEFLRC
|
||||
const uint8_t SegmentSize = 117; //number of bytes in each segment, 117 is maximum value for FLRC
|
||||
#endif
|
||||
@ -0,0 +1,846 @@
|
||||
/*******************************************************************************************************
|
||||
Programs for Arduino - Copyright of the author Stuart Robinson - 12/03/22
|
||||
|
||||
This program is supplied as is, it is up to the user of the program to decide if the program is
|
||||
suitable for the intended purpose and free from errors.
|
||||
*******************************************************************************************************/
|
||||
|
||||
/*******************************************************************************************************
|
||||
Program Operation - This is a simulation test program for the use of a data transfer (DT) packet to send
|
||||
the contents of a memory array (DTsendarray) on one Arduino to the SD card as a file on another Arduino,
|
||||
Arduino DUEs were used for the test. For this example the memory array is first loaded from an SD file.
|
||||
|
||||
DT packets can be used for transfering large amounts of data in a sequence of packets or segments,
|
||||
in a reliable and resiliant way. The remote file open request, the segements sent and the remote file close
|
||||
will be transmitted until a valid acknowledge comes from the receiver. Use with the matching receiver
|
||||
program, 234_SDfile_Transfer_Receiver.ino or 236_SDfile_Transfer_ReceiverIRQ.ino.
|
||||
|
||||
Each DT packet contains a variable length header array and a variable length data array as the payload.
|
||||
On transmission the NetworkID and CRC of the payload are appended to the end of the packet by the library
|
||||
routines. The use of a NetworkID and CRC ensures that the receiver can validate the packet to a high degree
|
||||
of certainty. The receiver will not accept packets that dont have the appropriate NetworkID or payload CRC
|
||||
at the end of the packet.
|
||||
|
||||
The transfer can be carried out using LoRa or FLRC packets, max segment size (defined by DTSegmentSize) is
|
||||
245 bytes for LoRa and 117 bytes for FLRC.
|
||||
|
||||
Details of the packet identifiers, header and data lengths and formats used are in the file
|
||||
Data_transfer_packet_definitions.md in the \SX128X_examples\DataTransfer\ folder.
|
||||
|
||||
Serial monitor baud rate is set at 115200.
|
||||
*******************************************************************************************************/
|
||||
#define USELORA //enable this define to use LoRa packets
|
||||
//#define USEFLRC //enable this define to use FLRC packets
|
||||
|
||||
#include <SPI.h>
|
||||
#include <SX128XLT.h>
|
||||
#include <ProgramLT_Definitions.h>
|
||||
#include "Settings.h" //LoRa settings etc.
|
||||
#include <arrayRW.h>
|
||||
#include "Variables.h"
|
||||
|
||||
SX128XLT LoRa; //create an SX128XLT library instance called LoRa
|
||||
|
||||
#include <SdFat.h>
|
||||
SdFat SD;
|
||||
File dataFile; //name the file instance needed for SD library routines
|
||||
|
||||
uint8_t DTheader[16]; //header array
|
||||
uint8_t DTdata[245]; //data/segment array
|
||||
uint8_t DTsendarray[0x10000]; //create a global array to hold data to transfer
|
||||
uint8_t *ptrDTsendarray; //create a global pointer to the array to send, so all functions have access
|
||||
|
||||
//choice of files to send
|
||||
char DTfilenamebuff[] = "/$50SATS.JPG"; //file length 6880 bytes, file CRC 0x0281
|
||||
//char DTfilenamebuff[] = "/$50SATT.JPG"; //file length 1068 bytes, file CRC 0x6A02
|
||||
|
||||
|
||||
//#define DEBUG //enable define to see more detail for data transfer operation
|
||||
//#define DEBUGSDLIB //enable define to see more detail for SD operation
|
||||
//#define DISABLEPAYLOADCRC //enable this define if you want to disable payload CRC checking
|
||||
|
||||
|
||||
void loop()
|
||||
{
|
||||
|
||||
DTLocalArrayLength = moveFileArray(DTfilenamebuff, DTsendarray, sizeof(DTsendarray)); //move the file to a global array to be sent
|
||||
|
||||
if (DTLocalArrayLength == 0)
|
||||
{
|
||||
Serial.println("ERROR moving local file to array - program halted");
|
||||
while (1);
|
||||
}
|
||||
|
||||
doArrayTransfer(DTsendarray);
|
||||
Serial.println("Array transfer complete - program halted");
|
||||
while (1);
|
||||
}
|
||||
|
||||
|
||||
void printSeconds()
|
||||
{
|
||||
float secs;
|
||||
secs = ( (float) millis() / 1000);
|
||||
Serial.print(secs, 3);
|
||||
Serial.print(F(" "));
|
||||
}
|
||||
|
||||
|
||||
void led_Flash(uint16_t flashes, uint16_t delaymS)
|
||||
{
|
||||
uint16_t index;
|
||||
for (index = 1; index <= flashes; index++)
|
||||
{
|
||||
digitalWrite(LED1, HIGH);
|
||||
delay(delaymS);
|
||||
digitalWrite(LED1, LOW);
|
||||
delay(delaymS);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//**********************************
|
||||
// Start Code for transfer of array
|
||||
//**********************************
|
||||
|
||||
bool doArrayTransfer(uint8_t *ptrarray)
|
||||
{
|
||||
ptrDTsendarray = ptrarray; //set the global ptr for the the array to send
|
||||
DTLocalArrayCRC = LoRa.CRCCCITT(ptrDTsendarray, DTLocalArrayLength, 0xFFFF);
|
||||
|
||||
DTStartmS = millis();
|
||||
do
|
||||
{
|
||||
if (startArrayTransfer(DTfilenamebuff, sizeof(DTfilenamebuff))) //sends the DTsendarray to a remote filename
|
||||
{
|
||||
Serial.print(DTfilenamebuff);
|
||||
Serial.println(" opened OK on remote");
|
||||
DTNumberSegments = getNumberSegments(DTLocalArrayLength, DTSegmentSize);
|
||||
DTLastSegmentSize = getLastSegmentSize(DTLocalArrayLength, DTSegmentSize);
|
||||
printLocalFileDetails();
|
||||
Serial.println();
|
||||
NoAckCount = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.print(DTfilenamebuff);
|
||||
Serial.println("Error opening remote file - restart transfer");
|
||||
DTFileTransferComplete = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
delay(packetdelaymS);
|
||||
|
||||
if (!sendSegments())
|
||||
{
|
||||
Serial.println();
|
||||
Serial.println(F("**********************************************************"));
|
||||
Serial.println(F("Error - Segment write with no file open - Restart received"));
|
||||
Serial.println(F("**********************************************************"));
|
||||
Serial.println();
|
||||
continue;
|
||||
}
|
||||
|
||||
if (endArrayTransfer(DTfilenamebuff, sizeof(DTfilenamebuff))) //send command to close remote file
|
||||
{
|
||||
//the header returned from file close contains a 16bit CRC of the file saved on the remotes SD
|
||||
Serial.print(DTfilenamebuff);
|
||||
Serial.println(" closed OK on remote");
|
||||
beginarrayRW(DTheader, 4);
|
||||
DTRemoteFileLength = arrayReadUint32();
|
||||
DTRemoteFileCRC = arrayReadUint16();
|
||||
Serial.print(F("Acknowledged remote file length "));
|
||||
Serial.println(DTRemoteFileLength);
|
||||
Serial.print(F("Acknowledged remote file CRC 0x"));
|
||||
Serial.println(DTRemoteFileCRC, HEX);
|
||||
}
|
||||
else
|
||||
{
|
||||
DTFileTransferComplete = false;
|
||||
Serial.println(F("ERROR send close remote file failed - program halted"));
|
||||
}
|
||||
|
||||
Serial.print(F("NoAckCount "));
|
||||
Serial.println( NoAckCount);
|
||||
Serial.print(F("Total file transmit time "));
|
||||
Serial.print(millis() - DTStartmS);
|
||||
Serial.println(F("mS"));
|
||||
DTFileTransferComplete = true;
|
||||
}
|
||||
while (!DTFileTransferComplete);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
uint16_t getNumberSegments(uint32_t arraysize, uint8_t segmentsize)
|
||||
{
|
||||
uint16_t segments;
|
||||
segments = arraysize / segmentsize;
|
||||
if ((arraysize % segmentsize) > 0)
|
||||
{
|
||||
segments++;
|
||||
}
|
||||
return segments;
|
||||
}
|
||||
|
||||
|
||||
uint8_t getLastSegmentSize(uint32_t arraysize, uint8_t segmentsize)
|
||||
{
|
||||
uint8_t lastsize;
|
||||
lastsize = arraysize % segmentsize;
|
||||
if (lastsize == 0)
|
||||
{
|
||||
lastsize = segmentsize;
|
||||
}
|
||||
return lastsize;
|
||||
}
|
||||
|
||||
|
||||
bool startArrayTransfer(char *buff, uint8_t filenamesize)
|
||||
{
|
||||
uint8_t ValidACK;
|
||||
|
||||
Serial.print(F("Start Array transfer "));
|
||||
Serial.print(DTLocalArrayLength);
|
||||
Serial.println(F(" bytes"));
|
||||
|
||||
build_DTFileOpenHeader(DTheader, DTFileOpenHeaderL, filenamesize, DTLocalArrayLength, DTLocalArrayCRC, DTSegmentSize);
|
||||
LocalPayloadCRC = LoRa.CRCCCITT((uint8_t *) buff, filenamesize, 0xFFFF);
|
||||
|
||||
do
|
||||
{
|
||||
Serial.println(F("Transmit open remote file request"));
|
||||
digitalWrite(LED1, HIGH);
|
||||
TXPacketL = LoRa.transmitDT(DTheader, DTFileOpenHeaderL, (uint8_t *) buff, filenamesize, NetworkID, TXtimeoutmS, TXpower, WAIT_TX);
|
||||
digitalWrite(LED1, LOW);
|
||||
TXNetworkID = LoRa.getTXNetworkID(TXPacketL); //get the networkID appended to packet
|
||||
TXArrayCRC = LoRa.getTXPayloadCRC(TXPacketL); //get the payload CRC appended to packet
|
||||
|
||||
#ifdef DEBUG
|
||||
Serial.print(F("TXNetworkID,0x"));
|
||||
Serial.print(TXNetworkID, HEX); //get the NetworkID of the packet just sent, its placed at the packet end
|
||||
Serial.print(F(",TXarrayCRC,0x"));
|
||||
Serial.println(TXArrayCRC, HEX); //get the CRC of the data array just sent, its placed at the packet end
|
||||
Serial.println();
|
||||
#endif
|
||||
|
||||
if (TXPacketL == 0) //if there has been a send and ack error, TXPacketL returns as 0
|
||||
{
|
||||
Serial.println(F("Transmit error"));
|
||||
}
|
||||
|
||||
Serial.print(F("Wait ACK "));
|
||||
ValidACK = LoRa.waitACKDT(DTheader, DTFileOpenHeaderL, ACKtimeoutDTmS);
|
||||
RXPacketType = DTheader[0];
|
||||
|
||||
if ((ValidACK > 0) && (RXPacketType == DTFileOpenACK))
|
||||
{
|
||||
Serial.println(F(" - Valid ACK received"));
|
||||
#ifdef DEBUG
|
||||
printPacketHex();
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
NoAckCount++;
|
||||
Serial.println(F("No Valid ACK received"));
|
||||
#ifdef DEBUG
|
||||
printACKdetail();
|
||||
Serial.print(F("ACKPacket "));
|
||||
printPacketHex();
|
||||
#endif
|
||||
Serial.println();
|
||||
}
|
||||
Serial.println();
|
||||
}
|
||||
while (ValidACK == 0);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void build_DTFileOpenHeader(uint8_t *header, uint8_t headersize, uint8_t datalength, uint32_t filelength, uint16_t filecrc, uint8_t segsize)
|
||||
{
|
||||
//this builds the header buffer for the filename passed
|
||||
|
||||
beginarrayRW(header, 0); //start writing to array at location 0
|
||||
arrayWriteUint8(DTFileOpen); //byte 0, write the packet type
|
||||
arrayWriteUint8(0); //byte 1, initial DTflags byte, not used here
|
||||
arrayWriteUint8(headersize); //byte 2, write length of header
|
||||
arrayWriteUint8(datalength); //byte 3, write length of dataarray
|
||||
arrayWriteUint32(filelength); //byte 4,5,6,7, write the file length
|
||||
arrayWriteUint16(filecrc); //byte 8, 9, write dataarray (filename) CRC
|
||||
arrayWriteUint8(segsize); //byte 10, segment size
|
||||
arrayWriteUint8(0); //byte 11, unused byte
|
||||
endarrayRW();
|
||||
}
|
||||
|
||||
|
||||
bool sendSegments()
|
||||
{
|
||||
//start the array transfer at segment 0
|
||||
DTSegment = 0;
|
||||
DTSentSegments = 0;
|
||||
|
||||
DTarraylocation = 0; //ensure at first position in array
|
||||
|
||||
while (DTSegment < (DTNumberSegments - 1))
|
||||
{
|
||||
printSeconds();
|
||||
|
||||
if (sendArraySegment(DTSegment, DTSegmentSize))
|
||||
{
|
||||
Serial.println();
|
||||
//DTSegment++;
|
||||
DTSentSegments++;
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.println(F("ERROR in sendArraySegment"));
|
||||
Serial.println();
|
||||
return false;
|
||||
}
|
||||
|
||||
delay(packetdelaymS);
|
||||
};
|
||||
|
||||
Serial.println("Last segment");
|
||||
|
||||
if (!sendArraySegment(DTSegment, DTLastSegmentSize))
|
||||
{
|
||||
Serial.println(F("ERROR in sendArraySegment"));
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool sendArraySegment(uint16_t segnum, uint8_t segmentsize)
|
||||
{
|
||||
uint8_t ValidACK;
|
||||
uint8_t index;
|
||||
uint8_t tempdata;
|
||||
|
||||
for (index = 0; index < segmentsize; index++)
|
||||
{
|
||||
tempdata = ptrDTsendarray[DTarraylocation];
|
||||
DTdata[index] = tempdata;
|
||||
DTarraylocation++;
|
||||
}
|
||||
|
||||
build_DTSegmentHeader(DTheader, DTSegmentWriteHeaderL, segmentsize, segnum);
|
||||
|
||||
Serial.print(F("Send Segment,"));
|
||||
Serial.print(segnum);
|
||||
Serial.print(F(" "));
|
||||
printheader(DTheader, DTSegmentWriteHeaderL);
|
||||
Serial.println();
|
||||
|
||||
do
|
||||
{
|
||||
digitalWrite(LED1, HIGH);
|
||||
TXPacketL = LoRa.transmitDT(DTheader, DTSegmentWriteHeaderL, (uint8_t *) DTdata, segmentsize, NetworkID, TXtimeoutmS, TXpower, WAIT_TX);
|
||||
digitalWrite(LED1, LOW);
|
||||
|
||||
if (TXPacketL == 0) //if there has been a send TXPacketL returns as 0
|
||||
{
|
||||
Serial.println(F("Transmit error"));
|
||||
}
|
||||
|
||||
ValidACK = LoRa.waitACKDT(DTheader, DTSegmentWriteHeaderL, ACKtimeoutDTmS);
|
||||
RXPacketType = DTheader[0];
|
||||
|
||||
if (ValidACK > 0)
|
||||
{
|
||||
if (RXPacketType == DTSegmentWriteNACK)
|
||||
{
|
||||
DTSegment = DTheader[4] + (DTheader[5] << 8); //load what the segment should be
|
||||
RXHeaderL = DTheader[2];
|
||||
Serial.println();
|
||||
Serial.println(F("************************************"));
|
||||
Serial.print(F("Received restart request at segment "));
|
||||
Serial.println(DTSegment);
|
||||
printheader(DTheader, RXHeaderL);
|
||||
Serial.println();
|
||||
Serial.print(F("Seek to file location "));
|
||||
Serial.println(DTSegment * DTSegmentSize);
|
||||
Serial.println(F("************************************"));
|
||||
Serial.println();
|
||||
Serial.flush();
|
||||
DTarraylocation = (DTSegment * DTSegmentSize);
|
||||
}
|
||||
|
||||
//ack is valid, segment was acknowledged if here
|
||||
|
||||
if (RXPacketType == DTStartNACK)
|
||||
{
|
||||
Serial.println(F("Received DTStartNACK "));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (RXPacketType == DTSegmentWriteACK)
|
||||
{
|
||||
readACKHeader();
|
||||
AckCount++;
|
||||
printPacketDetails();
|
||||
DTSegment++; //increase value for next segment
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
NoAckCount++;
|
||||
Serial.print(F("Error No Ack "));
|
||||
Serial.print(F("NoAckCount,"));
|
||||
Serial.print(NoAckCount);
|
||||
LoRa.printReliableStatus();
|
||||
Serial.println();
|
||||
}
|
||||
} while (ValidACK == 0);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void build_DTSegmentHeader(uint8_t *header, uint8_t headersize, uint8_t datalen, uint16_t segnum)
|
||||
{
|
||||
//this builds the header buffer for the a segment transmit
|
||||
beginarrayRW(header, 0); //start writing to array at location 0
|
||||
arrayWriteUint8(DTSegmentWrite); //write the packet type
|
||||
arrayWriteUint8(0); //initial DTflags byte, not used here
|
||||
arrayWriteUint8(headersize); //write length of header
|
||||
arrayWriteUint8(datalen); //write length of data array
|
||||
arrayWriteUint16(segnum); //write the DTsegment number
|
||||
endarrayRW();
|
||||
}
|
||||
|
||||
|
||||
void printPacketDetails()
|
||||
{
|
||||
PacketRSSI = LoRa.readPacketRSSI();
|
||||
PacketSNR = LoRa.readPacketSNR();
|
||||
Serial.print(F("AckCount,"));
|
||||
Serial.print(AckCount);
|
||||
Serial.print(F(",NoAckCount,"));
|
||||
Serial.print(NoAckCount);
|
||||
Serial.print(F(",AckRSSI,"));
|
||||
Serial.print(PacketRSSI);
|
||||
Serial.print(F("dBm,AckSNR,"));
|
||||
Serial.print(PacketSNR);
|
||||
Serial.print(F("dB"));
|
||||
Serial.println();
|
||||
}
|
||||
|
||||
|
||||
void printLocalFileDetails()
|
||||
{
|
||||
Serial.print(DTfilenamebuff);
|
||||
Serial.print(F(" LocalFilelength is "));
|
||||
Serial.print(DTLocalFileLength);
|
||||
Serial.println(F(" bytes"));
|
||||
Serial.print(DTfilenamebuff);
|
||||
Serial.print(F(" Array to send CRC is 0x"));
|
||||
Serial.println(DTLocalArrayCRC, HEX);
|
||||
Serial.print(F("DTSegmentSize "));
|
||||
Serial.println(DTSegmentSize);
|
||||
Serial.print(F("Number Segments "));
|
||||
Serial.println(DTNumberSegments);
|
||||
Serial.print(F("DTLastSegmentSize "));
|
||||
Serial.println(DTLastSegmentSize);
|
||||
}
|
||||
|
||||
|
||||
void printPacketHex()
|
||||
{
|
||||
RXPacketL = LoRa.readRXPacketL();
|
||||
Serial.print(RXPacketL);
|
||||
Serial.print(F(" bytes > "));
|
||||
if (RXPacketL > 0)
|
||||
{
|
||||
LoRa.printSXBufferHEX(0, RXPacketL - 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void printACKdetail()
|
||||
{
|
||||
Serial.print(F("ACKDetail"));
|
||||
Serial.print(F(",RXNetworkID,0x"));
|
||||
Serial.print(LoRa.getRXNetworkID(RXPacketL), HEX);
|
||||
Serial.print(F(",RXPayloadCRC,0x"));
|
||||
Serial.print(LoRa.getRXPayloadCRC(RXPacketL), HEX);
|
||||
Serial.print(F(",RXPacketL,"));
|
||||
Serial.print(RXPacketL);
|
||||
Serial.print(F(" "));
|
||||
LoRa.printReliableStatus();
|
||||
Serial.println();
|
||||
}
|
||||
|
||||
|
||||
void printdata(uint8_t *dataarray, uint8_t arraysize)
|
||||
{
|
||||
Serial.print(F("DataBytes,"));
|
||||
Serial.print(arraysize);
|
||||
Serial.print(F(" "));
|
||||
printarrayHEX((uint8_t *) dataarray, arraysize);
|
||||
}
|
||||
|
||||
|
||||
void printheader(uint8_t *hdr, uint8_t hdrsize)
|
||||
{
|
||||
Serial.print(F("HeaderBytes,"));
|
||||
Serial.print(hdrsize);
|
||||
Serial.print(F(" "));
|
||||
printarrayHEX(hdr, hdrsize);
|
||||
}
|
||||
|
||||
|
||||
void readACKHeader()
|
||||
{
|
||||
//the first 6 bytes of the segment write header contain the important stuff, so load it up
|
||||
//so we can decide what to do next.
|
||||
beginarrayRW(DTheader, 0); //start buffer read at location 0
|
||||
RXPacketType = arrayReadUint8(); //load the packet type
|
||||
RXFlags = arrayReadUint8(); //initial DTflags byte, not used here
|
||||
RXHeaderL = arrayReadUint8(); //load the header length
|
||||
RXDataarrayL = arrayReadUint8(); //load the datalength
|
||||
DTSegment = arrayReadUint16(); //load the segment number
|
||||
}
|
||||
|
||||
|
||||
bool endArrayTransfer(char *buff, uint8_t filenamesize)
|
||||
{
|
||||
uint8_t ValidACK;
|
||||
|
||||
Serial.print(F("End file transfer "));
|
||||
Serial.println(buff);
|
||||
DTSD_closeFile();
|
||||
build_DTFileCloseHeader(DTheader, DTFileCloseHeaderL, filenamesize, DTLocalArrayLength, DTLocalArrayCRC, DTSegmentSize);
|
||||
|
||||
do
|
||||
{
|
||||
Serial.println(F("Transmit close remote file request"));
|
||||
digitalWrite(LED1, HIGH);
|
||||
TXPacketL = LoRa.transmitDT(DTheader, DTFileCloseHeaderL, (uint8_t *) buff, filenamesize, NetworkID, TXtimeoutmS, TXpower, WAIT_TX);
|
||||
digitalWrite(LED1, LOW);
|
||||
TXNetworkID = LoRa.getTXNetworkID(TXPacketL);
|
||||
TXArrayCRC = LoRa.getTXPayloadCRC(TXPacketL);
|
||||
|
||||
#ifdef DEBUG
|
||||
Serial.print(F("TXNetworkID,0x"));
|
||||
Serial.print(TXNetworkID, HEX); //get the NetworkID of the packet just sent, its placed at the packet end
|
||||
Serial.print(F(",TXarrayCRC,0x"));
|
||||
Serial.println(TXArrayCRC, HEX); //get the CRC of the data array just sent, its placed at the packet end
|
||||
Serial.println();
|
||||
#endif
|
||||
|
||||
if (TXPacketL == 0) //if there has been a send and ack error, RXPacketL returns as 0
|
||||
{
|
||||
Serial.println(F("Transmit error"));
|
||||
}
|
||||
|
||||
Serial.print(F("Wait ACK "));
|
||||
ValidACK = LoRa.waitACKDT(DTheader, DTFileCloseHeaderL, ACKtimeoutDTmS);
|
||||
RXPacketType = DTheader[0];
|
||||
|
||||
if ((ValidACK > 0) && (RXPacketType == DTFileCloseACK))
|
||||
{
|
||||
Serial.println(F(" - Valid ACK received"));
|
||||
#ifdef DEBUG
|
||||
printPacketHex();
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
NoAckCount++;
|
||||
Serial.println(F("No Valid ACK received"));
|
||||
printACKdetail();
|
||||
#ifdef DEBUG
|
||||
Serial.print(F("ACKPacket "));
|
||||
printPacketHex();
|
||||
#endif
|
||||
Serial.println();
|
||||
}
|
||||
Serial.println();
|
||||
}
|
||||
while (ValidACK == 0);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void build_DTFileCloseHeader(uint8_t *header, uint8_t headersize, uint8_t datalength, uint32_t filelength, uint16_t filecrc, uint8_t segsize)
|
||||
{
|
||||
//this builds the header buffer for the filename passed
|
||||
|
||||
beginarrayRW(header, 0); //start writing to array at location 0
|
||||
arrayWriteUint8(DTFileClose); //byte 0, write the packet type
|
||||
arrayWriteUint8(0); //byte 1, initial DTflags byte, not used here
|
||||
arrayWriteUint8(headersize); //byte 2, write length of header
|
||||
arrayWriteUint8(datalength); //byte 3, write length of dataarray
|
||||
arrayWriteUint32(filelength); //byte 4,5,6,7, write the file length
|
||||
arrayWriteUint16(filecrc); //byte 8, 9, write dataarray (filename) CRC
|
||||
arrayWriteUint8(segsize); //byte 10, segment size
|
||||
arrayWriteUint8(0); //byte 11, unused byte
|
||||
endarrayRW();
|
||||
}
|
||||
|
||||
|
||||
//*********************************
|
||||
// Start Code for dealing with SD
|
||||
//*********************************
|
||||
|
||||
uint32_t moveFileArray(char *filenamebuff, uint8_t *buff, uint32_t buffsize)
|
||||
{
|
||||
uint32_t index;
|
||||
|
||||
ptrDTsendarray = buff; //assign passed array ptr to global ptr
|
||||
DTLocalFileLength = DTSD_getFileSize(filenamebuff); //get the file length
|
||||
|
||||
if (DTLocalFileLength == 0)
|
||||
{
|
||||
Serial.print(F("Error - opening local file "));
|
||||
Serial.println(filenamebuff);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (DTLocalFileLength > buffsize)
|
||||
{
|
||||
Serial.println(filenamebuff);
|
||||
Serial.print(F("Error - file length of "));
|
||||
Serial.print(DTLocalFileLength);
|
||||
Serial.print(F(" bytes exceeds array length of "));
|
||||
Serial.print(buffsize);
|
||||
Serial.println(F(" bytes"));
|
||||
return 0;
|
||||
}
|
||||
|
||||
DTSD_openFileRead(filenamebuff);
|
||||
Serial.print(F("Opened local file "));
|
||||
Serial.print(filenamebuff);
|
||||
Serial.print(F(" "));
|
||||
Serial.print(DTLocalFileLength);
|
||||
Serial.println(F(" bytes"));
|
||||
DTLocalFileCRC = DTSD_fileCRCCCITT(DTLocalFileLength); //get file CRC from position 0 to end
|
||||
Serial.print(F("DTLocalFileCRC 0x"));
|
||||
Serial.println(DTLocalFileCRC, HEX);
|
||||
|
||||
//now tranfer SD file to global array
|
||||
dataFile.seek(0); //ensure at first position in file
|
||||
for (index = 0; index < DTLocalFileLength; index++)
|
||||
{
|
||||
buff[index] = dataFile.read();
|
||||
}
|
||||
|
||||
Serial.println(F("DTsendarray loaded from SD"));
|
||||
Serial.print(F("Last written location "));
|
||||
Serial.println(index);
|
||||
Serial.print(F("First 16 bytes of array to send "));
|
||||
LoRa.printHEXPacket(buff, 16);
|
||||
Serial.println();
|
||||
DTarraylocation = 0;
|
||||
return DTLocalFileLength;
|
||||
}
|
||||
|
||||
|
||||
bool DTSD_initSD(uint8_t CSpin)
|
||||
{
|
||||
if (SD.begin(CSpin))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void DTSD_printDirectory()
|
||||
{
|
||||
dataFile = SD.open("/");
|
||||
Serial.println("Card directory");
|
||||
SD.ls("/", LS_R);
|
||||
}
|
||||
|
||||
|
||||
uint32_t DTSD_openFileRead(char *buff)
|
||||
{
|
||||
uint32_t filesize;
|
||||
dataFile = SD.open(buff);
|
||||
filesize = dataFile.size();
|
||||
dataFile.seek(0);
|
||||
return filesize;
|
||||
}
|
||||
|
||||
|
||||
void DTSD_closeFile()
|
||||
{
|
||||
dataFile.close(); //close local file
|
||||
}
|
||||
|
||||
|
||||
uint16_t DTSD_fileCRCCCITT(uint32_t fsize)
|
||||
{
|
||||
//does a CRC calculation on the file open via dataFile
|
||||
uint32_t index;
|
||||
uint16_t CRCcalc;
|
||||
uint8_t j, filedata;
|
||||
|
||||
CRCcalc = 0xFFFF; //start value for CRC16
|
||||
dataFile.seek(0); //be sure at start of file position
|
||||
|
||||
for (index = 0; index < fsize; index++)
|
||||
{
|
||||
filedata = dataFile.read();
|
||||
#ifdef DEBUGSDLIB
|
||||
Serial.print(F(" 0x"));
|
||||
Serial.print(filedata, HEX);
|
||||
#endif
|
||||
CRCcalc ^= (((uint16_t) filedata ) << 8);
|
||||
for (j = 0; j < 8; j++)
|
||||
{
|
||||
if (CRCcalc & 0x8000)
|
||||
CRCcalc = (CRCcalc << 1) ^ 0x1021;
|
||||
else
|
||||
CRCcalc <<= 1;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef DEBUGSDLIB
|
||||
Serial.print(F(" {DEBUGSDLIB} "));
|
||||
Serial.print(index);
|
||||
Serial.print(F(" Bytes checked - CRC "));
|
||||
Serial.println(CRCcalc, HEX);
|
||||
#endif
|
||||
|
||||
return CRCcalc;
|
||||
}
|
||||
|
||||
|
||||
uint16_t DTSD_getNumberSegments(uint32_t filesize, uint8_t segmentsize)
|
||||
{
|
||||
uint16_t segments;
|
||||
segments = filesize / segmentsize;
|
||||
if ((filesize % segmentsize) > 0)
|
||||
{
|
||||
segments++;
|
||||
}
|
||||
return segments;
|
||||
}
|
||||
|
||||
|
||||
uint8_t DTSD_getLastSegmentSize(uint32_t filesize, uint8_t segmentsize)
|
||||
{
|
||||
uint8_t lastsize;
|
||||
lastsize = filesize % segmentsize;
|
||||
if (lastsize == 0)
|
||||
{
|
||||
lastsize = segmentsize;
|
||||
}
|
||||
return lastsize;
|
||||
}
|
||||
|
||||
|
||||
void DTSD_seekFileLocation(uint32_t position)
|
||||
{
|
||||
dataFile.seek(position); //seek to position in file
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
uint32_t DTSD_getFileSize(char *buff)
|
||||
{
|
||||
uint32_t filesize;
|
||||
|
||||
if (!SD.exists(buff))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
dataFile = SD.open(buff);
|
||||
filesize = dataFile.size();
|
||||
dataFile.close();
|
||||
return filesize;
|
||||
}
|
||||
|
||||
//*******************************
|
||||
// End Code for dealing with SD
|
||||
//*******************************
|
||||
|
||||
|
||||
void setup()
|
||||
{
|
||||
pinMode(LED1, OUTPUT); //setup pin as output for indicator LED
|
||||
led_Flash(2, 125); //two quick LED flashes to indicate program start
|
||||
|
||||
Serial.begin(115200);
|
||||
|
||||
while (!Serial); // wait for serial port to connect. Needed for native USB
|
||||
|
||||
Serial.println();
|
||||
Serial.println(F("235_Array_Transfer_Transmitter starting"));
|
||||
Serial.flush();
|
||||
|
||||
SPI.begin();
|
||||
|
||||
if (LoRa.begin(NSS, NRESET, RFBUSY, DIO1, LORA_DEVICE))
|
||||
{
|
||||
led_Flash(2, 125);
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.println(F("Device error"));
|
||||
while (1)
|
||||
{
|
||||
led_Flash(50, 50); //long fast speed flash indicates device error
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef USELORA
|
||||
LoRa.setupLoRa(Frequency, Offset, SpreadingFactor, Bandwidth, CodeRate);
|
||||
Serial.println(F("Using LoRa packets"));
|
||||
#endif
|
||||
|
||||
#ifdef USEFLRC
|
||||
LoRa.setupFLRC(Frequency, Offset, BandwidthBitRate, CodingRate, BT, Syncword);
|
||||
Serial.println(F("Using FLRC packets"));
|
||||
#endif
|
||||
|
||||
Serial.print(F("Initializing SD card..."));
|
||||
|
||||
if (DTSD_initSD(SDCS))
|
||||
{
|
||||
Serial.println(F("Card initialized."));
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.println(F("Card failed, or not present."));
|
||||
while (1) led_Flash(100, 25);
|
||||
}
|
||||
|
||||
Serial.println();
|
||||
DTSD_printDirectory();
|
||||
Serial.println();
|
||||
Serial.println();
|
||||
Serial.println(F("Array transfer ready"));
|
||||
Serial.println();
|
||||
|
||||
#ifdef DISABLEPAYLOADCRC
|
||||
LoRa.setReliableConfig(NoReliableCRC);
|
||||
#endif
|
||||
|
||||
if (LoRa.getReliableConfig(NoReliableCRC))
|
||||
{
|
||||
Serial.println(F("Payload CRC disabled"));
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.println(F("Payload CRC enabled"));
|
||||
}
|
||||
|
||||
DTFileTransferComplete = false;
|
||||
|
||||
}
|
||||
@ -0,0 +1,50 @@
|
||||
/*******************************************************************************************************
|
||||
Programs for Arduino - Copyright of the author Stuart Robinson - 12/03/22
|
||||
|
||||
This program is supplied as is, it is up to the user of the program to decide if the program is
|
||||
suitable for the intended purpose and free from errors.
|
||||
*******************************************************************************************************/
|
||||
|
||||
#define NSS 10 //select pin on LoRa device
|
||||
#define NRESET 9 //reset pin on LoRa device
|
||||
#define RFBUSY 7 //RFBUSY pin on LoRa device
|
||||
#define DIO1 3 //DIO1 pin on LoRa device, used for sensing RX and TX done
|
||||
#define LED1 8 //LED used to indicate transmission
|
||||
#define SDCS 30
|
||||
|
||||
#define LORA_DEVICE DEVICE_SX1280 //this is the device we are using
|
||||
|
||||
|
||||
//******* Setup LoRa Test Parameters Here ! ***************
|
||||
|
||||
const uint32_t Frequency = 2445000000; //frequency of transmissions
|
||||
const uint32_t Offset = 0; //offset frequency for calibration purposes
|
||||
const int8_t TXpower = 10; //LoRa transmit power
|
||||
|
||||
//******* Setup LoRa modem parameters here ! ***************
|
||||
const uint8_t Bandwidth = LORA_BW_1600; //LoRa bandwidth
|
||||
const uint8_t SpreadingFactor = LORA_SF5; //LoRa spreading factor
|
||||
const uint8_t CodeRate = LORA_CR_4_5; //LoRa coding rate
|
||||
|
||||
//******* Setup FLRC modem parameters here ! ***************
|
||||
const uint8_t BandwidthBitRate = FLRC_BR_1_300_BW_1_2; //FLRC bandwidth and bit rate, 1.3Mbs
|
||||
//const uint8_t BandwidthBitRate = FLRC_BR_0_260_BW_0_3; //FLRC 260kbps
|
||||
const uint8_t CodingRate = FLRC_CR_1_0; //FLRC coding rate
|
||||
const uint8_t BT = RADIO_MOD_SHAPING_BT_1_0; //FLRC BT
|
||||
const uint32_t Syncword = 0x01234567; //FLRC uses syncword
|
||||
|
||||
|
||||
const uint32_t TXtimeoutmS = 5000; //mS to wait for TX to complete
|
||||
const uint32_t RXtimeoutmS = 60000; //mS to wait for receiving a packet
|
||||
const uint32_t ACKdelaymS = 0; //ms delay after packet actioned and ack sent
|
||||
const uint32_t ACKtimeoutDTmS = 100; //mS to wait for receiving an ACK and re-trying TX
|
||||
const uint32_t packetdelaymS = 0; //mS delay between transmitted packets
|
||||
const uint16_t NetworkID = 0x3210; //a unique identifier to go out with packet
|
||||
|
||||
#ifdef USELORA
|
||||
const uint8_t DTSegmentSize = 245; //number of bytes in each segment, 245 is maximum value for LoRa
|
||||
#endif
|
||||
|
||||
#ifdef USEFLRC
|
||||
const uint8_t DTSegmentSize = 117; //number of bytes in each segment, 117 is maximum value for FLRC
|
||||
#endif
|
||||
@ -0,0 +1,35 @@
|
||||
uint8_t RXPacketType; //type of received packet, segment write, ACK, NACK etc
|
||||
uint8_t RXPacketL; //length of received packet
|
||||
uint16_t RXErrors; //count of packets received with error
|
||||
uint8_t RXFlags; //DTflags byte in header, could be used to control actions in TX and RX
|
||||
uint8_t RXHeaderL; //length of header
|
||||
uint8_t RXDataarrayL; //length of data array\segment
|
||||
int16_t PacketRSSI; //stores RSSI of received packet
|
||||
int8_t PacketSNR; //stores signal to noise ratio of received packet
|
||||
|
||||
uint16_t TXNetworkID; //this is used to identify a transaction, receiver must have the same DTnetworkID
|
||||
uint16_t TXArrayCRC; //should contain CRC of data array sent
|
||||
uint8_t TXPacketL; //length of transmitted packet
|
||||
|
||||
uint16_t LocalPayloadCRC; //for calculating the local data array CRC
|
||||
uint16_t DTLocalFileCRC; //CRC of file being transferred
|
||||
uint16_t DTLocalArrayCRC; //CRC of array being transferred
|
||||
uint32_t DTLocalFileLength; //length of file to transfer
|
||||
uint32_t DTLocalArrayLength; //length of array to send
|
||||
uint16_t DTSegment; //current segment number
|
||||
uint16_t DTNumberSegments; //number of segments for a file transfer
|
||||
uint8_t DTLastSegmentSize; //size of the last segment
|
||||
uint16_t DTSegmentNext; //next segment to send\receive
|
||||
uint16_t DTReceivedSegments; //count of segments received
|
||||
uint16_t DTSegmentLast; //last segment to send\receive
|
||||
uint16_t DTSentSegments; //count of segments sent
|
||||
uint32_t DTarraylocation; //a global variable giving the location in the array last written to
|
||||
uint16_t DTRemoteFileCRC; //CRC of returned of the remote saved file
|
||||
uint32_t DTRemoteFileLength; //filelength returned of the remote saved file
|
||||
uint32_t DTStartmS; //used for timeing transfers
|
||||
|
||||
uint16_t AckCount; //keep a track of acks that are received within timeout period
|
||||
uint16_t NoAckCount; //keep a track of acks not received within timeout period
|
||||
|
||||
bool DTFileIsOpen; //bool to record if file open or closed
|
||||
bool DTFileTransferComplete; //bool to flag file transfer complete
|
||||
@ -0,0 +1,191 @@
|
||||
/*******************************************************************************************************
|
||||
Programs for Arduino - Copyright of the author Stuart Robinson - 12/02/22
|
||||
|
||||
This program is supplied as is, it is up to the user of the program to decide if the program is
|
||||
suitable for the intended purpose and free from errors.
|
||||
*******************************************************************************************************/
|
||||
|
||||
/*******************************************************************************************************
|
||||
Program Operation - This is a program that transfers a file using data transfer (DT) packet functions
|
||||
from the SX128X library to send a file from the SD card on one Arduino to the SD card on another Arduino.
|
||||
Arduino DUEs were used for the test and this example transfers an JPG image.
|
||||
|
||||
This program uses routines that do not need to use the DIO1 pin on the LoRa device which is usually used
|
||||
to indicate RXDONE or TXDONE.
|
||||
|
||||
DT packets can be used for transfering large amounts of data in a sequence of packets or segments,
|
||||
in a reliable and resiliant way. The file open requests to the remote receiver, each segement sent and
|
||||
the remote file close will all keep transmitting until a valid acknowledge comes from the receiver.
|
||||
Use this transmitter with the matching receiver program, 234_SDfile_Transfer_Receiver.ino.
|
||||
|
||||
On transmission the NetworkID and CRC of the payload are appended to the end of the packet by the library
|
||||
routines. The use of a NetworkID and CRC ensures that the receiver can validate the packet to a high degree
|
||||
of certainty.
|
||||
|
||||
The transmitter sends the sequence of segments in order. If the sequence fails for some reason, the receiver
|
||||
will return a NACK packet to the transmitter requesting the segment sequence it was expecting.
|
||||
|
||||
Details of the packet identifiers, header and data lengths and formats used are in the file;
|
||||
'Data transfer packet definitions.md' in the \SX128X_examples\DataTransfer\ folder.
|
||||
|
||||
The transfer can be carried out using LoRa or FLRC packets, max segment size (defined by DTSegmentSize) is
|
||||
245 bytes for LoRa and 117 bytes for FLRC.
|
||||
|
||||
Serial monitor baud rate is set at 115200.
|
||||
*******************************************************************************************************/
|
||||
|
||||
#define USELORA //enable this define to use LoRa packets
|
||||
//#define USEFLRC //enable this define to use FLRC packets
|
||||
|
||||
#include <SPI.h>
|
||||
|
||||
#include <SX128XLT.h>
|
||||
#include <ProgramLT_Definitions.h>
|
||||
#include "DTSettings.h" //LoRa settings etc.
|
||||
|
||||
SX128XLT LoRa; //create an SX128XLT library instance called LoRa, required by SDtransfer.h
|
||||
|
||||
#define ENABLEMONITOR //enable monitor prints
|
||||
#define PRINTSEGMENTNUM //enable this define to print segment numbers
|
||||
#define ENABLEFILECRC //enable this define to uses and show file CRCs
|
||||
//#define DISABLEPAYLOADCRC //enable this define if you want to disable payload CRC checking
|
||||
|
||||
//#define SDLIB //define SDLIB for SD.h or SDFATLIB for SDfat.h
|
||||
#define SDFATLIB
|
||||
|
||||
#include <DTSDlibrary.h> //library of SD functions
|
||||
#include <SDtransferIRQ.h> //library of data transfer functions
|
||||
|
||||
//choice of files to send
|
||||
//char FileName[] = "/$50SATL.JPG"; //file length 63091 bytes, file CRC 0x59CE
|
||||
char FileName[] = "/$50SATS.JPG"; //file length 6880 bytes, file CRC 0x0281
|
||||
//char FileName[] = "/$50SATT.JPG"; //file length 1068 bytes, file CRC 0x6A02
|
||||
|
||||
|
||||
void loop()
|
||||
{
|
||||
uint32_t filelength;
|
||||
|
||||
#ifdef ENABLEMONITOR
|
||||
Monitorport.println(F("Transfer started"));
|
||||
#endif
|
||||
|
||||
filelength = SDsendFile(FileName, sizeof(FileName));
|
||||
|
||||
if (filelength)
|
||||
{
|
||||
#ifdef ENABLEMONITOR
|
||||
Monitorport.println(F("Transfer finished"));
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef ENABLEMONITOR
|
||||
Monitorport.println(F("Transfer failed"));
|
||||
Monitorport.println();
|
||||
#endif
|
||||
}
|
||||
|
||||
delay(15000);
|
||||
|
||||
}
|
||||
|
||||
|
||||
void led_Flash(uint16_t flashes, uint16_t delaymS)
|
||||
{
|
||||
uint16_t index;
|
||||
for (index = 1; index <= flashes; index++)
|
||||
{
|
||||
digitalWrite(LED1, HIGH);
|
||||
delay(delaymS);
|
||||
digitalWrite(LED1, LOW);
|
||||
delay(delaymS);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void setup()
|
||||
{
|
||||
pinMode(LED1, OUTPUT); //setup pin as output for indicator LED
|
||||
led_Flash(2, 125); //two quick LED flashes to indicate program start
|
||||
SDsetLED(LED1); //setup LED pin for data transfer indicator
|
||||
|
||||
#ifdef ENABLEMONITOR
|
||||
Monitorport.begin(115200);
|
||||
Monitorport.println();
|
||||
Monitorport.println(F(__FILE__));
|
||||
Monitorport.flush();
|
||||
#endif
|
||||
|
||||
SPI.begin();
|
||||
|
||||
if (LoRa.begin(NSS, NRESET, RFBUSY, LORA_DEVICE))
|
||||
{
|
||||
led_Flash(2, 125);
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef ENABLEMONITOR
|
||||
Monitorport.println(F("LoRa device error"));
|
||||
#endif
|
||||
while (1)
|
||||
{
|
||||
led_Flash(50, 50); //long fast speed flash indicates device error
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef USELORA
|
||||
LoRa.setupLoRa(Frequency, Offset, SpreadingFactor, Bandwidth, CodeRate);
|
||||
Serial.println(F("Using LoRa packets"));
|
||||
#endif
|
||||
|
||||
#ifdef USEFLRC
|
||||
LoRa.setupFLRC(Frequency, Offset, BandwidthBitRate, CodingRate, BT, Syncword);
|
||||
Serial.println(F("Using FLRC packets"));
|
||||
#endif
|
||||
|
||||
#ifdef ENABLEMONITOR
|
||||
Monitorport.println();
|
||||
Monitorport.print(F("Initializing SD card..."));
|
||||
#endif
|
||||
|
||||
if (DTSD_initSD(SDCS))
|
||||
{
|
||||
#ifdef ENABLEMONITOR
|
||||
Monitorport.println(F("SD Card initialized."));
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
Monitorport.println(F("SD Card failed, or not present."));
|
||||
while (1) led_Flash(100, 25);
|
||||
}
|
||||
|
||||
#ifdef ENABLEMONITOR
|
||||
Monitorport.println();
|
||||
#endif
|
||||
|
||||
#ifdef DISABLEPAYLOADCRC
|
||||
LoRa.setReliableConfig(NoReliableCRC);
|
||||
#endif
|
||||
|
||||
if (LoRa.getReliableConfig(NoReliableCRC))
|
||||
{
|
||||
#ifdef ENABLEMONITOR
|
||||
Monitorport.println(F("Payload CRC disabled"));
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef ENABLEMONITOR
|
||||
Monitorport.println(F("Payload CRC enabled"));
|
||||
#endif
|
||||
}
|
||||
|
||||
SDDTFileTransferComplete = false;
|
||||
|
||||
#ifdef ENABLEMONITOR
|
||||
Monitorport.println(F("SDfile transfer ready"));
|
||||
Monitorport.println();
|
||||
#endif
|
||||
}
|
||||
@ -0,0 +1,60 @@
|
||||
/*******************************************************************************************************
|
||||
Programs for Arduino - Copyright of the author Stuart Robinson - 12/02/22
|
||||
|
||||
This program is supplied as is, it is up to the user of the program to decide if the program is
|
||||
suitable for the intended purpose and free from errors.
|
||||
*******************************************************************************************************/
|
||||
|
||||
#define NSS 10 //select pin on LoRa device
|
||||
#define NRESET 9 //reset pin on LoRa device
|
||||
#define RFBUSY 7 //RFBUSY pin on LoRa device
|
||||
#define LED1 8 //LED used to indicate transmission
|
||||
#define SDCS 30
|
||||
#define Monitorport Serial //Port where serial prints go
|
||||
|
||||
#define LORA_DEVICE DEVICE_SX1280 //this is the device we are using
|
||||
|
||||
//******* Setup LoRa Test Parameters Here ! ***************
|
||||
|
||||
const uint32_t Frequency = 2445000000; //frequency of transmissions
|
||||
const uint32_t Offset = 0; //offset frequency for calibration purposes
|
||||
const int8_t TXpower = 10; //LoRa transmit power
|
||||
|
||||
//******* Setup LoRa modem parameters here ! ***************
|
||||
const uint8_t Bandwidth = LORA_BW_1600; //LoRa bandwidth
|
||||
const uint8_t SpreadingFactor = LORA_SF5; //LoRa spreading factor
|
||||
const uint8_t CodeRate = LORA_CR_4_5; //LoRa coding rate
|
||||
|
||||
//******* Setup FLRC modem parameters here ! ***************
|
||||
const uint8_t BandwidthBitRate = FLRC_BR_1_300_BW_1_2; //FLRC bandwidth and bit rate, 1.3Mbs
|
||||
//const uint8_t BandwidthBitRate = FLRC_BR_0_260_BW_0_3; //FLRC 260kbps
|
||||
const uint8_t CodingRate = FLRC_CR_1_0; //FLRC coding rate
|
||||
const uint8_t BT = RADIO_MOD_SHAPING_BT_1_0; //FLRC BT
|
||||
const uint32_t Syncword = 0x01234567; //FLRC uses syncword
|
||||
|
||||
const uint32_t TXtimeoutmS = 5000; //mS to wait for TX to complete
|
||||
const uint32_t RXtimeoutmS = 60000; //mS to wait for receiving a packet
|
||||
const uint32_t ACKdelaymS = 0; //ms delay after packet actioned and ack sent
|
||||
const uint32_t ACKsegtimeoutmS = 75; //mS to wait for receiving an ACK before re-trying transmit segment
|
||||
const uint32_t ACKopentimeoutmS = 250; //mS to wait for receiving an ACK before re-trying transmit file open
|
||||
const uint32_t ACKclosetimeoutmS = 250; //mS to wait for receiving an ACK before re-trying transmit file close
|
||||
const uint32_t DuplicatedelaymS = 10; //ms delay if there has been an duplicate segment or command receipt
|
||||
const uint32_t FunctionDelaymS = 0; //delay between functions such as open file, send segments etc
|
||||
const uint32_t PacketDelaymS = 1000; //mS delay between transmitted packets such as DTInfo etc
|
||||
const uint8_t StartAttempts = 2; //number of attempts to start transfer before a fail
|
||||
const uint8_t SendAttempts = 5; //number of attempts carrying out a process before a restart
|
||||
const uint32_t NoAckCountLimit = 250; //if no NoAckCount exceeds this value - restart transfer
|
||||
|
||||
const uint8_t HeaderSizeMax = 12; //max size of header in bytes, minimum size is 7 bytes
|
||||
const uint8_t DataSizeMax = 245; //max size of data array in bytes
|
||||
const uint8_t Maxfilenamesize = 32; //size of DTfilename buffer
|
||||
|
||||
const uint16_t NetworkID = 0x3210; //a unique identifier to go out with packet
|
||||
|
||||
#ifdef USELORA
|
||||
const uint8_t SegmentSize = 245; //number of bytes in each segment, 245 is maximum value for LoRa
|
||||
#endif
|
||||
|
||||
#ifdef USEFLRC
|
||||
const uint8_t SegmentSize = 117; //number of bytes in each segment, 117 is maximum value for FLRC
|
||||
#endif
|
||||
@ -0,0 +1,165 @@
|
||||
/*******************************************************************************************************
|
||||
Programs for Arduino - Copyright of the author Stuart Robinson - 12/02/22
|
||||
|
||||
This program is supplied as is, it is up to the user of the program to decide if the program is
|
||||
suitable for the intended purpose and free from errors.
|
||||
*******************************************************************************************************/
|
||||
|
||||
/*******************************************************************************************************
|
||||
Program Operation - This is a test program for the use of a data transfer (DT) packet to send a file
|
||||
from the SD card on one Arduino to the SD card on another Arduino, Arduino DUEs were used for the test.
|
||||
|
||||
This program uses routines that do not need to use the DIO1 pin on the LoRa device which is usually used
|
||||
to indicate RXDONE or TXDONE.
|
||||
|
||||
DT packets can be used for transfering large amounts of data in a sequence of packets or segments,
|
||||
in a reliable and resiliant way. The remote file open request, the segements sent and the remote file close
|
||||
will be transmitted until a valid acknowledge comes from the receiver. Use with the matching transmitter
|
||||
program, 233_LoRa_SDfile_Transfer_Transmitter.ino.
|
||||
|
||||
Each DT packet contains a variable length header array and a variable length data array as the payload.
|
||||
On transmission the NetworkID and CRC of the payload are appended to the end of the packet by the library
|
||||
routines. The use of a NetworkID and CRC ensures that the receiver can validate the packet to a high degree
|
||||
of certainty. The receiver will not accept packets that dont have the appropriate NetworkID or payload CRC
|
||||
at the end of the packet.
|
||||
|
||||
The transmitter sends a sequence of segments in order and the receiver keeps track of the sequence. If
|
||||
the sequence fails for some reason, the receiver will return a NACK packet to the transmitter requesting
|
||||
the segment sequence it was expecting.
|
||||
|
||||
The transfer can be carried out using LoRa or FLRC packets, max segment size (defined by DTSegmentSize) is
|
||||
245 bytes for LoRa and 117 bytes for FLRC.
|
||||
|
||||
Details of the packet identifiers, header and data lengths and formats used are in the file
|
||||
Data_transfer_packet_definitions.md in the \SX128X_examples\DataTransfer\ folder.
|
||||
|
||||
Serial monitor baud rate is set at 115200.
|
||||
*******************************************************************************************************/
|
||||
#define USELORA //enable this define to use LoRa packets
|
||||
//#define USEFLRC //enable this define to use FLRC packets
|
||||
|
||||
#include <SPI.h>
|
||||
|
||||
#include <SX128XLT.h>
|
||||
#include <ProgramLT_Definitions.h>
|
||||
#include "DTSettings.h" //LoRa settings etc.
|
||||
|
||||
SX128XLT LoRa; //create an SX128XLT library instance called LoRa, required by SDtransfer.h
|
||||
|
||||
//#define SDLIB //define SDLIB for SD.h or SDFATLIB for SDfat.h
|
||||
#define SDFATLIB
|
||||
|
||||
#define ENABLEMONITOR //enable monitor prints
|
||||
#define PRINTSEGMENTNUM
|
||||
#define ENABLEFILECRC //enable this define to uses and show file CRCs
|
||||
//#define DISABLEPAYLOADCRC //enable this define if you want to disable payload CRC checking
|
||||
|
||||
#include <DTSDlibrary.h> //library of SD functions
|
||||
#include <SDtransferIRQ.h> //library of data transfer functions
|
||||
|
||||
|
||||
void loop()
|
||||
{
|
||||
SDreceiveaPacketDT();
|
||||
}
|
||||
|
||||
|
||||
void led_Flash(uint16_t flashes, uint16_t delaymS)
|
||||
{
|
||||
uint16_t index;
|
||||
for (index = 1; index <= flashes; index++)
|
||||
{
|
||||
digitalWrite(LED1, HIGH);
|
||||
delay(delaymS);
|
||||
digitalWrite(LED1, LOW);
|
||||
delay(delaymS);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void setup()
|
||||
{
|
||||
pinMode(LED1, OUTPUT); //setup pin as output for indicator LED
|
||||
led_Flash(2, 125); //two quick LED flashes to indicate program start
|
||||
SDsetLED(LED1); //setup LED pin for data transfer indicator
|
||||
|
||||
#ifdef ENABLEMONITOR
|
||||
Monitorport.begin(115200);
|
||||
Monitorport.println();
|
||||
Monitorport.println(F(__FILE__));
|
||||
#endif
|
||||
|
||||
SPI.begin();
|
||||
|
||||
if (LoRa.begin(NSS, NRESET, RFBUSY, LORA_DEVICE))
|
||||
{
|
||||
led_Flash(2, 125);
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef ENABLEMONITOR
|
||||
Monitorport.println(F("LoRa device error"));
|
||||
#endif
|
||||
while (1)
|
||||
{
|
||||
led_Flash(50, 50); //long fast speed flash indicates device error
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef USELORA
|
||||
LoRa.setupLoRa(Frequency, Offset, SpreadingFactor, Bandwidth, CodeRate);
|
||||
Serial.println(F("Using LoRa packets"));
|
||||
#endif
|
||||
|
||||
#ifdef USEFLRC
|
||||
LoRa.setupFLRC(Frequency, Offset, BandwidthBitRate, CodingRate, BT, Syncword);
|
||||
Serial.println(F("Using FLRC packets"));
|
||||
#endif
|
||||
|
||||
#ifdef ENABLEMONITOR
|
||||
Monitorport.println();
|
||||
Monitorport.print(F("Initializing SD card..."));
|
||||
#endif
|
||||
|
||||
if (DTSD_initSD(SDCS))
|
||||
{
|
||||
Monitorport.println(F("SD Card initialized."));
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef ENABLEMONITOR
|
||||
Monitorport.println(F("SD Card failed, or not present."));
|
||||
#endif
|
||||
while (1) led_Flash(100, 50);
|
||||
}
|
||||
|
||||
#ifdef ENABLEMONITOR
|
||||
Monitorport.println();
|
||||
#endif
|
||||
|
||||
#ifdef DISABLEPAYLOADCRC
|
||||
LoRa.setReliableConfig(NoReliableCRC);
|
||||
#endif
|
||||
|
||||
if (LoRa.getReliableConfig(NoReliableCRC))
|
||||
{
|
||||
Monitorport.println(F("Payload CRC disabled"));
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef ENABLEMONITOR
|
||||
Monitorport.println(F("Payload CRC enabled"));
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
SDDTSegmentNext = 0;
|
||||
SDDTFileOpened = false;
|
||||
|
||||
#ifdef ENABLEMONITOR
|
||||
Monitorport.println(F("SDfile transfer receiver ready"));
|
||||
Monitorport.println();
|
||||
#endif
|
||||
|
||||
|
||||
}
|
||||
@ -0,0 +1,61 @@
|
||||
/*******************************************************************************************************
|
||||
Programs for Arduino - Copyright of the author Stuart Robinson - 12/02/22
|
||||
|
||||
This program is supplied as is, it is up to the user of the program to decide if the program is
|
||||
suitable for the intended purpose and free from errors.
|
||||
*******************************************************************************************************/
|
||||
|
||||
#define NSS 10 //select pin on LoRa device
|
||||
#define NRESET 9 //reset pin on LoRa device
|
||||
#define RFBUSY 7 //RFBUSY pin on LoRa device
|
||||
#define LED1 8 //LED used to indicate transmission
|
||||
#define SDCS 30
|
||||
#define Monitorport Serial //Port where serial prints go
|
||||
|
||||
#define LORA_DEVICE DEVICE_SX1280 //this is the device we are using
|
||||
|
||||
|
||||
//******* Setup LoRa Test Parameters Here ! ***************
|
||||
|
||||
const uint32_t Frequency = 2445000000; //frequency of transmissions
|
||||
const uint32_t Offset = 0; //offset frequency for calibration purposes
|
||||
const int8_t TXpower = 10; //LoRa transmit power
|
||||
|
||||
//******* Setup LoRa modem parameters here ! ***************
|
||||
const uint8_t Bandwidth = LORA_BW_1600; //LoRa bandwidth
|
||||
const uint8_t SpreadingFactor = LORA_SF5; //LoRa spreading factor
|
||||
const uint8_t CodeRate = LORA_CR_4_5; //LoRa coding rate
|
||||
|
||||
//******* Setup FLRC modem parameters here ! ***************
|
||||
const uint8_t BandwidthBitRate = FLRC_BR_1_300_BW_1_2; //FLRC bandwidth and bit rate, 1.3Mbs
|
||||
//const uint8_t BandwidthBitRate = FLRC_BR_0_260_BW_0_3; //FLRC 260kbps
|
||||
const uint8_t CodingRate = FLRC_CR_1_0; //FLRC coding rate
|
||||
const uint8_t BT = RADIO_MOD_SHAPING_BT_1_0; //FLRC BT
|
||||
const uint32_t Syncword = 0x01234567; //FLRC uses syncword
|
||||
|
||||
const uint32_t TXtimeoutmS = 5000; //mS to wait for TX to complete
|
||||
const uint32_t RXtimeoutmS = 60000; //mS to wait for receiving a packet
|
||||
const uint32_t ACKdelaymS = 10; //ms delay after packet actioned and ack sent
|
||||
const uint32_t ACKsegtimeoutmS = 75; //mS to wait for receiving an ACK before re-trying transmit segment
|
||||
const uint32_t ACKopentimeoutmS = 250; //mS to wait for receiving an ACK before re-trying transmit file open
|
||||
const uint32_t ACKclosetimeoutmS = 250; //mS to wait for receiving an ACK before re-trying transmit file close
|
||||
const uint32_t DuplicatedelaymS = 10; //ms delay if there has been an duplicate segment or command receipt
|
||||
const uint32_t NoAckCountLimit = 250; //if no NoAckCount exceeds this value - restart transfer
|
||||
const uint32_t FunctionDelaymS = 0; //delay between functions such as open file, send segments etc
|
||||
const uint32_t PacketDelaymS = 1000; //mS delay between transmitted packets such as DTInfo etc
|
||||
|
||||
const uint8_t HeaderSizeMax = 12; //max size of header in bytes, minimum size is 7 bytes
|
||||
const uint8_t DataSizeMax = 245; //max size of data array in bytes
|
||||
const uint8_t Maxfilenamesize = 32; //size of DTfilename buffer
|
||||
|
||||
const uint16_t NetworkID = 0x3210; //a unique identifier to go out with packet
|
||||
const uint8_t SendAttempts = 10; //number of attempts sending a packet or attempting a process before a restart of transfer
|
||||
const uint8_t StartAttempts = 10; //number of attempts sending the file
|
||||
|
||||
#ifdef USELORA
|
||||
const uint8_t SegmentSize = 245; //number of bytes in each segment, 245 is maximum value for LoRa
|
||||
#endif
|
||||
|
||||
#ifdef USEFLRC
|
||||
const uint8_t SegmentSize = 117; //number of bytes in each segment, 117 is maximum value for FLRC
|
||||
#endif
|
||||
@ -0,0 +1,340 @@
|
||||
## Data Transfer packet Definitions
|
||||
|
||||
0xA0 Request to TX, DTSegmentWrite, Header Length 6, Data length Max, 245
|
||||
0xA1 ACK to RX, DTSegmentWriteACK, Header Length 6, Data length Max, 245
|
||||
0xA2 NACK to RX, DTSegmentWriteNACK, Header Length 6, Data length Max, 245
|
||||
|
||||
0xA4 Request to TX, DTFileOpen, Header Length 12, Data length Max, 239
|
||||
0xA5 ACK to RX, DTFileOpenACK, Header Length 12, Data length Max, 239
|
||||
0xA6 NACK to RX, DTFileOpenNACK, Header Length 12, Data length Max, 239
|
||||
|
||||
0xA8 Request to TX, DTFileClose, Header Length 12, Data length Max, 239
|
||||
0xA9 ACK to RX, DTFileCloseACK, Header Length 12, Data length Max, 239
|
||||
0xAA NACK to RX, DTFileCloseNACK, Header Length 12, Data length Max, 239
|
||||
|
||||
0xAC Request to TX, DTFileSeek, Header Length 9, Data length Max, 242
|
||||
0xAD ACK to RX, DTFileSeekACK, Header Length 9, Data length Max, 242
|
||||
0xAE NACK to RX, DTFileSeekNACK, Header Length 9, Data length Max, 242
|
||||
|
||||
0xB0 Request to TX, DTStart, Header Length 6, Data length Max, 245
|
||||
0xB1 ACK to RX, DTStartACK, Header Length 6, Data length Max, 245
|
||||
0xB2 NACK to RX, DTStartNACK, Header Length 6, Data length Max, 245
|
||||
|
||||
0xB4 Request to TX, DTWake, Header Length 6, Data length Max, 245
|
||||
0xB5 ACK to RX, DTWakeACK, Header Length 6, Data length Max, 245
|
||||
0xB6 NACK to RX, DTWakeNACK, Header Length 6, Data length Max, 245
|
||||
|
||||
|
||||
0xA0
|
||||
DTSegmentWrite, Header Length 6, Data length Max, 245
|
||||
Header
|
||||
Byte Purpose
|
||||
0 0xA0
|
||||
1 Flags
|
||||
2 Header length
|
||||
3 Data length
|
||||
4 SegmentNum0
|
||||
5 SegmentNum1
|
||||
Data
|
||||
Byte Purpose
|
||||
6 DataArray Start
|
||||
7 More data etc
|
||||
|
||||
|
||||
0xA1
|
||||
DTSegmentWriteACK, Header Length 6
|
||||
Header
|
||||
Byte Purpose
|
||||
0 0xA1
|
||||
1 Flags
|
||||
2 Header length
|
||||
3 Data length
|
||||
4 SegmentNum0
|
||||
5 SegmentNum1
|
||||
|
||||
0xA2
|
||||
DTSegmentWriteACK, Header Length 6
|
||||
Header
|
||||
Byte Purpose
|
||||
0 0xA2
|
||||
1 Flags
|
||||
2 Header length
|
||||
3 Data length
|
||||
4 Required SegmentNum0
|
||||
5 Required SegmentNum1
|
||||
|
||||
|
||||
0xA4
|
||||
DTFileOpen, Header Length 12, Data length Max, 239
|
||||
Header
|
||||
Byte Purpose
|
||||
0 0xA4
|
||||
1 Flags
|
||||
2 Header length
|
||||
3 Data length
|
||||
4 Filelength0
|
||||
5 Filelength1
|
||||
6 Filelength2
|
||||
7 Filelength3
|
||||
8 FileCRC0
|
||||
9 FileCRC1
|
||||
10 SegmentSize
|
||||
11 Unused
|
||||
Data
|
||||
Byte Purpose
|
||||
12 FilenameArray Start
|
||||
13 More FilenameArray etc
|
||||
|
||||
|
||||
0xA5
|
||||
DTFileOpenACK, Header Length 12
|
||||
Header
|
||||
Byte Purpose
|
||||
0 0xA5
|
||||
1 Flags
|
||||
2 Header length
|
||||
3 Data length
|
||||
4 Filelength0
|
||||
5 Filelength1
|
||||
6 Filelength2
|
||||
7 Filelength3
|
||||
8 FileCRC0
|
||||
9 FileCRC1
|
||||
10 SegmentSize
|
||||
11 Unused
|
||||
|
||||
0xA6
|
||||
DTFileOpenNACK, Header Length 12
|
||||
Header
|
||||
Byte Purpose
|
||||
0 0xA6
|
||||
1 Flags
|
||||
2 Header length
|
||||
3 Data length
|
||||
4 Filelength0
|
||||
5 Filelength1
|
||||
6 Filelength2
|
||||
7 Filelength3
|
||||
8 FileCRC0
|
||||
9 FileCRC1
|
||||
10 SegmentSize
|
||||
11 Unused
|
||||
|
||||
|
||||
0xA8
|
||||
DTFileClose, Header Length 12, Data length Max, 239
|
||||
Header
|
||||
Byte Purpose
|
||||
0 0xA8
|
||||
1 Flags
|
||||
2 Header length
|
||||
3 Data length
|
||||
4 Filelength0
|
||||
5 Filelength1
|
||||
6 Filelength2
|
||||
7 Filelength3
|
||||
8 FileCRC0
|
||||
9 FileCRC1
|
||||
10 SegmentSize
|
||||
11 Unused
|
||||
Data
|
||||
Byte Purpose
|
||||
12 FilenameArray Start
|
||||
13 More FilenameArray etc
|
||||
|
||||
|
||||
0xA9
|
||||
DTFileCloseACK, Header Length 12
|
||||
Header
|
||||
Byte Purpose
|
||||
0 0xA9
|
||||
1 Flags
|
||||
2 Header length
|
||||
3 Data length
|
||||
4 Filelength0
|
||||
5 Filelength1
|
||||
6 Filelength2
|
||||
7 Filelength3
|
||||
8 FileCRC0
|
||||
9 FileCRC1
|
||||
10 SegmentSize
|
||||
11 Unused
|
||||
|
||||
0xAA
|
||||
DTFileCloseNACK, Header Length 12
|
||||
Header
|
||||
Byte Purpose
|
||||
0 0xAA
|
||||
1 Flags
|
||||
2 Header length
|
||||
3 Data length
|
||||
4 Filelength0
|
||||
5 Filelength1
|
||||
6 Filelength2
|
||||
7 Filelength3
|
||||
8 FileCRC0
|
||||
9 FileCRC1
|
||||
10 SegmentSize
|
||||
11 Unused
|
||||
|
||||
0xAC
|
||||
DTDataSeek, Header Length 9, Data length Max, 242
|
||||
Header
|
||||
Byte Purpose
|
||||
0 0xAC
|
||||
1 Flags
|
||||
2 Header length
|
||||
3 Data length
|
||||
4 DataSeek0
|
||||
5 DataSeek1
|
||||
6 DataSeek2
|
||||
7 DataSeek3
|
||||
8Unused
|
||||
Data
|
||||
Byte Purpose
|
||||
9 FilenameArray Start
|
||||
13 More FilenameArray etc
|
||||
|
||||
|
||||
0xAD
|
||||
DTDataSeekACK, Header Length 9, Data length Max, 242
|
||||
Header
|
||||
Byte Purpose
|
||||
0 0xAD
|
||||
1 Flags
|
||||
2 Header length
|
||||
3 Data length
|
||||
4 DataSeek0
|
||||
5 DataSeek1
|
||||
6 DataSeek2
|
||||
7 DataSeek3
|
||||
8Unused
|
||||
|
||||
|
||||
0xAE
|
||||
DTDataSeekNACK, Header Length 9, Data length Max, 242
|
||||
Header
|
||||
Byte Purpose
|
||||
0 0xAE
|
||||
1 Flags
|
||||
2 Header length
|
||||
3 Data length
|
||||
4 DataSeek0
|
||||
5 DataSeek1
|
||||
6 DataSeek2
|
||||
7 DataSeek3
|
||||
8Unused
|
||||
|
||||
|
||||
0xB0
|
||||
DTStart, Header Length 6, Data length Max, 245
|
||||
Header
|
||||
Byte Purpose
|
||||
0 0xB0
|
||||
1 Flags
|
||||
2 Header length
|
||||
3 Data length
|
||||
4 Unused
|
||||
5 Unused
|
||||
|
||||
Data
|
||||
Byte Purpose
|
||||
6 SegmentSize
|
||||
7 LastSegmentSize
|
||||
8 TXtimeoutmS0
|
||||
9 TXtimeoutmS1
|
||||
10 TXtimeoutmS2
|
||||
11 TXtimeoutmS3
|
||||
12 RXtimeoutmS0
|
||||
13 RXtimeoutmS1
|
||||
14 RXtimeoutmS2
|
||||
15 RXtimeoutmS3
|
||||
16 ACKtimeoutDTmS0
|
||||
17 ACKtimeoutDTmS1
|
||||
18 ACKtimeoutDTmS2
|
||||
19 ACKtimeoutDTmS3
|
||||
20 ACKdelaymS0
|
||||
21 ACKdelaymS1
|
||||
22 ACKdelaymS2
|
||||
23 ACKdelaymS3
|
||||
24 packetdelaymS0
|
||||
25 packetdelaymS1
|
||||
26 packetdelaymS2
|
||||
27 packetdelaymS3
|
||||
28 Frequency0
|
||||
29 Frequency1
|
||||
30 Frequency2
|
||||
31 Frequency3
|
||||
32 Offset0
|
||||
33 Offset1
|
||||
34 Offset2
|
||||
35 Offset3
|
||||
36 Spreading Factor
|
||||
37 Bandwidth
|
||||
38 Coding Rate
|
||||
39 Optimisation
|
||||
40 TXPower
|
||||
41 Implicit/Explicit
|
||||
42 TXattempts0
|
||||
43 TXattempts1
|
||||
44 HeaderSizeMax
|
||||
45 DataSizeMax
|
||||
|
||||
|
||||
0xB1
|
||||
DTStartACK, Header Length 6, Data length Max, 245
|
||||
Header
|
||||
Byte Purpose
|
||||
0 0xB1
|
||||
1 Flags
|
||||
2 Header length
|
||||
3 Data length
|
||||
4 Unused
|
||||
5 Unused
|
||||
|
||||
|
||||
0xB2
|
||||
DTStartNACK, Header Length 6, Data length Max, 245
|
||||
Header
|
||||
Byte Purpose
|
||||
0 0xB2
|
||||
1 Flags
|
||||
2 Header length
|
||||
3 Data length
|
||||
4 Unused
|
||||
5 Unused
|
||||
|
||||
0xB4
|
||||
DTWake, Header Length 6, Data length Max, 245
|
||||
Header
|
||||
Byte Purpose
|
||||
0 0xB4
|
||||
1 Flags
|
||||
2 Header length
|
||||
3 Data length
|
||||
4 Unused
|
||||
5 Unused
|
||||
|
||||
|
||||
0xB5
|
||||
DTWakeACK, Header Length 6, Data length Max, 245
|
||||
Header
|
||||
Byte Purpose
|
||||
0 0xB5
|
||||
1 Flags
|
||||
2 Header length
|
||||
3 Data length
|
||||
4 Unused
|
||||
5 Unused
|
||||
|
||||
|
||||
0xB6
|
||||
DTWakeNACK, Header Length 6, Data length Max, 245
|
||||
Header
|
||||
Byte Purpose
|
||||
0 0xB6
|
||||
1 Flags
|
||||
2 Header length
|
||||
3 Data length
|
||||
4 Unused
|
||||
5 Unused
|
||||
@ -0,0 +1,340 @@
|
||||
Data Transfer packet Definitions
|
||||
|
||||
0xA0 Request to TX, DTSegmentWrite, Header Length 6, Data length Max, 245
|
||||
0xA1 ACK to RX, DTSegmentWriteACK, Header Length 6, Data length Max, 245
|
||||
0xA2 NACK to RX, DTSegmentWriteNACK, Header Length 6, Data length Max, 245
|
||||
|
||||
0xA4 Request to TX, DTFileOpen, Header Length 12, Data length Max, 239
|
||||
0xA5 ACK to RX, DTFileOpenACK, Header Length 12, Data length Max, 239
|
||||
0xA6 NACK to RX, DTFileOpenNACK, Header Length 12, Data length Max, 239
|
||||
|
||||
0xA8 Request to TX, DTFileClose, Header Length 12, Data length Max, 239
|
||||
0xA9 ACK to RX, DTFileCloseACK, Header Length 12, Data length Max, 239
|
||||
0xAA NACK to RX, DTFileCloseNACK, Header Length 12, Data length Max, 239
|
||||
|
||||
0xAC Request to TX, DTFileSeek, Header Length 9, Data length Max, 242
|
||||
0xAD ACK to RX, DTFileSeekACK, Header Length 9, Data length Max, 242
|
||||
0xAE NACK to RX, DTFileSeekNACK, Header Length 9, Data length Max, 242
|
||||
|
||||
0xB0 Request to TX, DTStart, Header Length 6, Data length Max, 245
|
||||
0xB1 ACK to RX, DTStartACK, Header Length 6, Data length Max, 245
|
||||
0xB2 NACK to RX, DTStartNACK, Header Length 6, Data length Max, 245
|
||||
|
||||
0xB4 Request to TX, DTWake, Header Length 6, Data length Max, 245
|
||||
0xB5 ACK to RX, DTWakeACK, Header Length 6, Data length Max, 245
|
||||
0xB6 NACK to RX, DTWakeNACK, Header Length 6, Data length Max, 245
|
||||
|
||||
|
||||
0xA0
|
||||
DTSegmentWrite, Header Length 6, Data length Max, 245
|
||||
Header
|
||||
Byte Purpose
|
||||
0 0xA0
|
||||
1 Flags
|
||||
2 Header length
|
||||
3 Data length
|
||||
4 SegmentNum0
|
||||
5 SegmentNum1
|
||||
Data
|
||||
Byte Purpose
|
||||
6 DataArray Start
|
||||
7 More data etc
|
||||
|
||||
|
||||
0xA1
|
||||
DTSegmentWriteACK, Header Length 6
|
||||
Header
|
||||
Byte Purpose
|
||||
0 0xA1
|
||||
1 Flags
|
||||
2 Header length
|
||||
3 Data length
|
||||
4 SegmentNum0
|
||||
5 SegmentNum1
|
||||
|
||||
0xA2
|
||||
DTSegmentWriteACK, Header Length 6
|
||||
Header
|
||||
Byte Purpose
|
||||
0 0xA2
|
||||
1 Flags
|
||||
2 Header length
|
||||
3 Data length
|
||||
4 Required SegmentNum0
|
||||
5 Required SegmentNum1
|
||||
|
||||
|
||||
0xA4
|
||||
DTFileOpen, Header Length 12, Data length Max, 239
|
||||
Header
|
||||
Byte Purpose
|
||||
0 0xA4
|
||||
1 Flags
|
||||
2 Header length
|
||||
3 Data length
|
||||
4 Filelength0
|
||||
5 Filelength1
|
||||
6 Filelength2
|
||||
7 Filelength3
|
||||
8 FileCRC0
|
||||
9 FileCRC1
|
||||
10 SegmentSize
|
||||
11 Unused
|
||||
Data
|
||||
Byte Purpose
|
||||
12 FilenameArray Start
|
||||
13 More FilenameArray etc
|
||||
|
||||
|
||||
0xA5
|
||||
DTFileOpenACK, Header Length 12
|
||||
Header
|
||||
Byte Purpose
|
||||
0 0xA5
|
||||
1 Flags
|
||||
2 Header length
|
||||
3 Data length
|
||||
4 Filelength0
|
||||
5 Filelength1
|
||||
6 Filelength2
|
||||
7 Filelength3
|
||||
8 FileCRC0
|
||||
9 FileCRC1
|
||||
10 SegmentSize
|
||||
11 Unused
|
||||
|
||||
0xA6
|
||||
DTFileOpenNACK, Header Length 12
|
||||
Header
|
||||
Byte Purpose
|
||||
0 0xA6
|
||||
1 Flags
|
||||
2 Header length
|
||||
3 Data length
|
||||
4 Filelength0
|
||||
5 Filelength1
|
||||
6 Filelength2
|
||||
7 Filelength3
|
||||
8 FileCRC0
|
||||
9 FileCRC1
|
||||
10 SegmentSize
|
||||
11 Unused
|
||||
|
||||
|
||||
0xA8
|
||||
DTFileClose, Header Length 12, Data length Max, 239
|
||||
Header
|
||||
Byte Purpose
|
||||
0 0xA8
|
||||
1 Flags
|
||||
2 Header length
|
||||
3 Data length
|
||||
4 Filelength0
|
||||
5 Filelength1
|
||||
6 Filelength2
|
||||
7 Filelength3
|
||||
8 FileCRC0
|
||||
9 FileCRC1
|
||||
10 SegmentSize
|
||||
11 Unused
|
||||
Data
|
||||
Byte Purpose
|
||||
12 FilenameArray Start
|
||||
13 More FilenameArray etc
|
||||
|
||||
|
||||
0xA9
|
||||
DTFileCloseACK, Header Length 12
|
||||
Header
|
||||
Byte Purpose
|
||||
0 0xA9
|
||||
1 Flags
|
||||
2 Header length
|
||||
3 Data length
|
||||
4 Filelength0
|
||||
5 Filelength1
|
||||
6 Filelength2
|
||||
7 Filelength3
|
||||
8 FileCRC0
|
||||
9 FileCRC1
|
||||
10 SegmentSize
|
||||
11 Unused
|
||||
|
||||
0xAA
|
||||
DTFileCloseNACK, Header Length 12
|
||||
Header
|
||||
Byte Purpose
|
||||
0 0xAA
|
||||
1 Flags
|
||||
2 Header length
|
||||
3 Data length
|
||||
4 Filelength0
|
||||
5 Filelength1
|
||||
6 Filelength2
|
||||
7 Filelength3
|
||||
8 FileCRC0
|
||||
9 FileCRC1
|
||||
10 SegmentSize
|
||||
11 Unused
|
||||
|
||||
0xAC
|
||||
DTDataSeek, Header Length 9, Data length Max, 242
|
||||
Header
|
||||
Byte Purpose
|
||||
0 0xAC
|
||||
1 Flags
|
||||
2 Header length
|
||||
3 Data length
|
||||
4 DataSeek0
|
||||
5 DataSeek1
|
||||
6 DataSeek2
|
||||
7 DataSeek3
|
||||
8Unused
|
||||
Data
|
||||
Byte Purpose
|
||||
9 FilenameArray Start
|
||||
13 More FilenameArray etc
|
||||
|
||||
|
||||
0xAD
|
||||
DTDataSeekACK, Header Length 9, Data length Max, 242
|
||||
Header
|
||||
Byte Purpose
|
||||
0 0xAD
|
||||
1 Flags
|
||||
2 Header length
|
||||
3 Data length
|
||||
4 DataSeek0
|
||||
5 DataSeek1
|
||||
6 DataSeek2
|
||||
7 DataSeek3
|
||||
8Unused
|
||||
|
||||
|
||||
0xAE
|
||||
DTDataSeekNACK, Header Length 9, Data length Max, 242
|
||||
Header
|
||||
Byte Purpose
|
||||
0 0xAE
|
||||
1 Flags
|
||||
2 Header length
|
||||
3 Data length
|
||||
4 DataSeek0
|
||||
5 DataSeek1
|
||||
6 DataSeek2
|
||||
7 DataSeek3
|
||||
8Unused
|
||||
|
||||
|
||||
0xB0
|
||||
DTStart, Header Length 6, Data length Max, 245
|
||||
Header
|
||||
Byte Purpose
|
||||
0 0xB0
|
||||
1 Flags
|
||||
2 Header length
|
||||
3 Data length
|
||||
4 Unused
|
||||
5 Unused
|
||||
|
||||
Data
|
||||
Byte Purpose
|
||||
6 SegmentSize
|
||||
7 LastSegmentSize
|
||||
8 TXtimeoutmS0
|
||||
9 TXtimeoutmS1
|
||||
10 TXtimeoutmS2
|
||||
11 TXtimeoutmS3
|
||||
12 RXtimeoutmS0
|
||||
13 RXtimeoutmS1
|
||||
14 RXtimeoutmS2
|
||||
15 RXtimeoutmS3
|
||||
16 ACKtimeoutDTmS0
|
||||
17 ACKtimeoutDTmS1
|
||||
18 ACKtimeoutDTmS2
|
||||
19 ACKtimeoutDTmS3
|
||||
20 ACKdelaymS0
|
||||
21 ACKdelaymS1
|
||||
22 ACKdelaymS2
|
||||
23 ACKdelaymS3
|
||||
24 packetdelaymS0
|
||||
25 packetdelaymS1
|
||||
26 packetdelaymS2
|
||||
27 packetdelaymS3
|
||||
28 Frequency0
|
||||
29 Frequency1
|
||||
30 Frequency2
|
||||
31 Frequency3
|
||||
32 Offset0
|
||||
33 Offset1
|
||||
34 Offset2
|
||||
35 Offset3
|
||||
36 Spreading Factor
|
||||
37 Bandwidth
|
||||
38 Coding Rate
|
||||
39 Optimisation
|
||||
40 TXPower
|
||||
41 Implicit/Explicit
|
||||
42 TXattempts0
|
||||
43 TXattempts1
|
||||
44 HeaderSizeMax
|
||||
45 DataSizeMax
|
||||
|
||||
|
||||
0xB1
|
||||
DTStartACK, Header Length 6, Data length Max, 245
|
||||
Header
|
||||
Byte Purpose
|
||||
0 0xB1
|
||||
1 Flags
|
||||
2 Header length
|
||||
3 Data length
|
||||
4 Unused
|
||||
5 Unused
|
||||
|
||||
|
||||
0xB2
|
||||
DTStartNACK, Header Length 6, Data length Max, 245
|
||||
Header
|
||||
Byte Purpose
|
||||
0 0xB2
|
||||
1 Flags
|
||||
2 Header length
|
||||
3 Data length
|
||||
4 Unused
|
||||
5 Unused
|
||||
|
||||
0xB4
|
||||
DTWake, Header Length 6, Data length Max, 245
|
||||
Header
|
||||
Byte Purpose
|
||||
0 0xB4
|
||||
1 Flags
|
||||
2 Header length
|
||||
3 Data length
|
||||
4 Unused
|
||||
5 Unused
|
||||
|
||||
|
||||
0xB5
|
||||
DTWakeACK, Header Length 6, Data length Max, 245
|
||||
Header
|
||||
Byte Purpose
|
||||
0 0xB5
|
||||
1 Flags
|
||||
2 Header length
|
||||
3 Data length
|
||||
4 Unused
|
||||
5 Unused
|
||||
|
||||
|
||||
0xB6
|
||||
DTWakeNACK, Header Length 6, Data length Max, 245
|
||||
Header
|
||||
Byte Purpose
|
||||
0 0xB6
|
||||
1 Flags
|
||||
2 Header length
|
||||
3 Data length
|
||||
4 Unused
|
||||
5 Unused
|
||||
79
examples/SX128x_examples/DataTransfer/ReadMe.md
Normal file
79
examples/SX128x_examples/DataTransfer/ReadMe.md
Normal file
@ -0,0 +1,79 @@
|
||||
Several of the functions needed to make the data transfers work were already incorporated in the reliable packets functions, so I just had to add the library functions to transmit and receive the packets that consisted of a configurable header array and a data array.
|
||||
|
||||
The additional functions needed were;
|
||||
|
||||
uint8_t transmitDT(uint8_t *header, uint8_t headersize, uint8_t *dataarray, uint8_t size, uint16_t networkID, uint32_t txtimeout, int8_t txpower, uint8_t wait);
|
||||
uint8_t receiveDT(uint8_t *header, uint8_t headersize, uint8_t *dataarray, uint8_t size, uint16_t networkID, uint32_t rxtimeout, uint8_t wait );
|
||||
uint8_t sendACKDT(uint8_t *header, uint8_t headersize, int8_t txpower);
|
||||
uint8_t waitACKDT(uint8_t *header, uint8_t headersize, uint32_t acktimeout);
|
||||
|
||||
The various sketch functions required such as sending an openfile command to the receiver, sending the the segments of the file and a close file command, would use the above core library functions with various different header formats. The detail of passing the file names across (for the receiver to save to SD with), calculating segment sizes and dealing with the segment sequencing would be dealt with at the Arduino sketch level where it would be easier to see exactly what is going on during a transfer. Perhaps at a later date it might be possible to move more of the required sketch code into a library function.
|
||||
|
||||
|
||||
## Example Programs
|
||||
|
||||
A simple test program was needed so that you could check a particular set of LoRa modem parameters to see how reliable they were at a chosen distance for sending the large packets. This is the purpose of the first two example sketches, '**231\_Data\_Transfer\_Test\_Transmitter.ino**' and '**232\_Data\_Transfer\_Test\_Receiver.ino**'
|
||||
|
||||
The transmitter sends a test segment of size defined by DTSegmentSize in the Settings.h file where the LoRa modem settings can also be defined.
|
||||
|
||||
The test program does implement a check on the segment sequence. If the receiver has just had segment 10, then it next expects segment 11. If something goes wrong and say segment 12 appears next then the receiver recognises this and sends a NACK packet back to the transmitter to restart the sequence from number 11. You can test this recovery at any time by resetting the transmitter.
|
||||
|
||||
The program **221\_LoRa\_DTPacket\_Monitor.ino** or **222\_FLRC\_DTPacket\_Monitor.ino** can be used to monitor the progress of the test transmitter, be sure to use the same LoRa modem settings as the test transmitter and receiver.
|
||||
|
||||
## File Transfer
|
||||
|
||||
The purpose of the Data Transfer functions in the SX12XX Library is for applications such as moving files from one Arduino to another over a LoRa link. There are no guarantees in radio frequency reception of data packets, it's inevitable that some will be missed. Thus the data transfer functions need to deal with this as well as coping with packets from possible foreign sources or missed segments in the file. A single bit error in a graphic image for instance can render the image unreadable.
|
||||
|
||||
The examples **233\_SDfile\_Transfer\_Transmitter.ino** and **234\_SDfile\_Transfer\_Receiver.ino** transfer a choice of files; $50SATL.JPG 63091 bytes, $50SATS.JPG 6880 bytes and $50SATT.JPG 1068 bytes) from the SD card on the transmitter Arduino to the SD card on another receiver Arduino. Arduino DUEs were used for testing these examples. The JPG image files above are located in the examples\SX128x_examples\DataTransfer folder and will need to be copied to the SD card on the transmitter.
|
||||
|
||||
<br>
|
||||
<p align="center">
|
||||
<img width="250" src="/$50SATL.jpg">
|
||||
</p>
|
||||
<br>
|
||||
|
||||
The transmitter starts the transfer by requesting that the file name chosen is opened on the remote receiver, the transmitter will keep sending this open file request till it succeeds. Then the actual segment\data transfer is started and each segment will be transmitted until it is accepted. If there is a segment sequence error at the receiver then the transmitter is notified and the transmission of segments restarts at the correct location. The last segment sent can be a different size to those in the main body of the file transfer. The transmitter then sends a file close request and the receiver then returns the file length and CRC of the file now on it's SD card data back to the transmitter. This is a further integrity check that the data has been transferred correctly.
|
||||
|
||||
The transfer could be organised in such a way that the segment transmissions were blind, with no acknowledge, but that would then require the receiver to keep track of missed segments and later request re-transmission. There are some LoRa set-ups that use SSDV to transfer images from cameras, the image is processed and spilt into blocks and a part image can be displayed even if there are some blocks missing. However, the data transfer method described here has no processing that is dependant on an image or file type, it just treats the image or file as a string of bytes.
|
||||
|
||||
## Transfer a memory array
|
||||
|
||||
Example **235\_Array\_Transfer\_Transmitter.ino** is a version of **233\_SDfile\_Transfer\_Transmitter.ino** that demonstrates sending a memory array (DTsendarray) from a transmitter to a receiver that then saves the received array onto a file on an SD card. The DTsendarray is first populated with data from a file /$50SATS.JPG or /$50SATT.JPG by the transmitter. In this example the array is then sent as a sequence of segments, similar to the way a file would be read from SD and sent.
|
||||
|
||||
|
||||
##Fine tuning for performance
|
||||
|
||||
The speed of the data transfers is mainly dependant on the LoRa settings used, higher\faster data rates come from using a lower spreading factor
|
||||
and a higher bandwidth, although of course the higher the data rate the shorter the distance covered.
|
||||
|
||||
There are two program parameters in the example sketches that you may need to adjust. When the receiver has picked up a packet from the transmitter there is a programmable delay before the acknowledge is sent. This is the ACKdelaymS parameter. If the transmitter is particularly slow in changing from transmitting a packet and being ready to pick up the start of the acknowledge then it might miss it. Due to the delays in the receiver of writing a segment to SD an ACKdelaymS of 0 will likely work, but increase it if the transmitter is missing a lot of the acknowledge packets.
|
||||
|
||||
A second parameter to adjust is the ACKtimeoutDTmS, and this is the period the transmitter waits for a valid acknowledge before sending the packet again. This time-out needs to be long enough to receive an acknowledge, but not too long or every missed acknowledge could slow down the transfer as it waits for the time-out period before re-transmitting.
|
||||
|
||||
|
||||
## Achieved data rates
|
||||
|
||||
With the segment length set at maximum for LoRa, 245 bytes, and LoRa settings of spreading factor 5, bandwidth 1600khz and coding rate 4:5 the 63019 byte $50SATL.JPG file took 4.54 seconds to transfer to the SD card on the receiver Arduino. That is an achieved data rate of;
|
||||
|
||||
(63091 * 8) / 4.54 = **111,173bps**.
|
||||
|
||||
The equivalent data sheet on air rate for the LoRa settings used is **203kbps**.
|
||||
|
||||
In FLRC mode, at its fastest rate, the same 63019 image file took 2.48 seconds to transfer an achieved data rate of **203,601bps**, the on air rate for this fastest FLRC mode is **1,300,000bps**
|
||||
|
||||
The Data Transfer examples will be found in the \examples\SX128x_examples\DataTransfer folder of the [**SX12XX-LoRa Library**](https://github.com/StuartsProjects/SX12XX-LoRa).
|
||||
|
||||
## Conclusions
|
||||
|
||||
Well, the data transfers work and the LoRa and FLRC are considerably faster than UHF LoRa devices.
|
||||
|
||||
## Duty Cycle
|
||||
|
||||
Whilst the described routines work well enough for SX127x in the UHF 433Mhz band in a lot of places in the World your limited to 10% duty cycle, so sending images continuously is not legal. However the library functions described here are for the 2.4Ghz SX128X library, and at 2.4Ghz there are few duty cycle restrictions.
|
||||
|
||||
<br>
|
||||
|
||||
|
||||
**Stuart Robinson**
|
||||
|
||||
**November 2021**
|
||||
Reference in New Issue
Block a user