Init fork from Stuart Robinson's repo

This commit is contained in:
2024-10-03 14:30:13 +03:00
commit 9395706524
201 changed files with 45709 additions and 0 deletions

View File

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

View File

@ -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);
}
}

View File

@ -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