Init fork from Stuart Robinson's repo
This commit is contained in:
@ -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
|
||||
Reference in New Issue
Block a user