Init fork from Stuart Robinson's repo
This commit is contained in:
@ -0,0 +1,72 @@
|
||||
// --------------------------------------
|
||||
// i2c_scanner
|
||||
// from: https://playground.arduino.cc/Main/I2cScanner/
|
||||
|
||||
// This sketch tests the standard 7-bit addresses
|
||||
// Devices with higher bit address might not be seen properly.
|
||||
|
||||
|
||||
#include <Wire.h>
|
||||
uint16_t counter;
|
||||
|
||||
#define SDA 21
|
||||
#define SCL 22
|
||||
|
||||
void setup()
|
||||
{
|
||||
Wire.begin(SDA, SCL); //format is Wire.begin(SDA,SCL);
|
||||
|
||||
Serial.begin(9600);
|
||||
Serial.println(F("I2C Scanner starting"));
|
||||
Serial.println();
|
||||
}
|
||||
|
||||
|
||||
void loop()
|
||||
{
|
||||
uint8_t error, address;
|
||||
int16_t nDevices;
|
||||
|
||||
counter++;
|
||||
Serial.print(counter);
|
||||
Serial.println(F(" Scanning..."));
|
||||
|
||||
nDevices = 0;
|
||||
for (address = 1; address < 127; address++ )
|
||||
{
|
||||
// The i2c_scanner uses the return value of
|
||||
// the Write.endTransmisstion to see if
|
||||
// a device did acknowledge to the address.
|
||||
Wire.beginTransmission(address);
|
||||
error = Wire.endTransmission();
|
||||
|
||||
if (error == 0)
|
||||
{
|
||||
Serial.print(F("I2C device found at address 0x"));
|
||||
if (address < 16)
|
||||
Serial.print(F("0"));
|
||||
Serial.println(address, HEX);
|
||||
nDevices++;
|
||||
}
|
||||
else if (error == 4)
|
||||
{
|
||||
Serial.print(F("Unknown error at address 0x"));
|
||||
if (address < 16)
|
||||
Serial.print(F("0"));
|
||||
Serial.println(address, HEX);
|
||||
}
|
||||
}
|
||||
|
||||
if (nDevices == 0)
|
||||
{
|
||||
Serial.println(F("No I2C devices found"));
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.println();
|
||||
Serial.println(F("Done"));
|
||||
Serial.println();
|
||||
}
|
||||
|
||||
delay(5000); // wait 5 seconds for next scan
|
||||
}
|
||||
@ -0,0 +1,262 @@
|
||||
/*******************************************************************************************************
|
||||
Programs for Arduino - Copyright of the author Stuart Robinson - 04/06/20
|
||||
|
||||
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 test program has been written to check that a connected SD card adapter, Micro
|
||||
or standard, is functional.
|
||||
|
||||
When the program runs it will attempts to create a file that is next in sequence to Log0000.txt, thus
|
||||
if this is the first time the program has run on the SD card it will create file Log0001.txt. If the
|
||||
file Log0001.txt exists it will create Log0002.txt etc. This ensures that everytime the program starts
|
||||
it creates a new file for testing.
|
||||
|
||||
Next the program checks if the Logxxxx.txt file exists and if so attempts to delete it.
|
||||
|
||||
Then the program starts a loop. First the same file is again opened for append, it will be created if it
|
||||
does not exist and then the line '1 Hello World' is writtent to the file. The file is closed and the
|
||||
contents of the file are dumped to the serial monitor. The loop restarts, and this time the line
|
||||
'2 Hello World' is appended to the file.
|
||||
|
||||
As the program progresses the file will grow in size and after 4 iterrations of the open,write,close
|
||||
and dump loop the file dump on serial monitor will look like this
|
||||
|
||||
1 Hello World
|
||||
2 Hello World
|
||||
3 Hello World
|
||||
4 Hello World
|
||||
|
||||
This file dump will grow if you let the program run. If an error with the SD card is detected at any
|
||||
time the LED will rapid flash continuously and the message 'X Card failed, or not present' is printed
|
||||
to serial monitor. The number X will allow you to check the program listing for where the error occured.
|
||||
|
||||
1 Card failed = SD card did not initialise
|
||||
2 Card failed = Could nt setup logFile for new name
|
||||
3 Card failed = Could not open file for append
|
||||
4 Card failed = Failure to dump file to serial monitor
|
||||
|
||||
Note: At the time of writing, 04/06/20, the function that the dumpFile() routine uses to check if an SD
|
||||
card is still present, SD.exists(filename), does not work on the SD.h file included in the current Expressif
|
||||
core for Arduino. If the SD card is removed, the SD.exists(filename) function returns true so the following
|
||||
dump of the file locks up the ESP32.
|
||||
|
||||
Serial monitor baud rate is set at 9600
|
||||
*******************************************************************************************************/
|
||||
|
||||
#include <SD.h>
|
||||
#include <SPI.h>
|
||||
|
||||
//pin definitions. You also need to connect the card SCK to pin 18, MISO to pin 19 and MOSI to pin 23
|
||||
#define LED1 2 //pin number for LED
|
||||
#define SDCS 13 //pin number for device select on SD card module
|
||||
|
||||
File logFile;
|
||||
|
||||
char filename[] = "/LOG0000.TXT"; //filename used as base for creating logfile, 0000 replaced with numbers
|
||||
|
||||
uint16_t linecount;
|
||||
|
||||
|
||||
void loop()
|
||||
{
|
||||
Serial.println();
|
||||
Serial.println("Initializing SD card");
|
||||
|
||||
if (!SD.begin(SDCS))
|
||||
{
|
||||
cardFail(1);
|
||||
}
|
||||
|
||||
Serial.println("Card initialized");
|
||||
|
||||
logFile = SD.open("/");
|
||||
Serial.println("Card directory");
|
||||
Serial.println();
|
||||
printDirectory(logFile, 0);
|
||||
Serial.println();
|
||||
Serial.println();
|
||||
|
||||
if (!setupSDLOG(filename)) //setup logfile name for writing
|
||||
{
|
||||
cardFail(2);
|
||||
}
|
||||
|
||||
Serial.print(F("logFile name is "));
|
||||
Serial.println(filename);
|
||||
|
||||
if (SD.exists(filename))
|
||||
{
|
||||
Serial.print(filename);
|
||||
Serial.println(" exists - delete");
|
||||
SD.remove(filename);
|
||||
}
|
||||
|
||||
if (!SD.exists(filename))
|
||||
{
|
||||
Serial.print(filename);
|
||||
Serial.println(" does not exist");
|
||||
}
|
||||
|
||||
while (1)
|
||||
{
|
||||
logFile = SD.open(filename, FILE_APPEND);
|
||||
|
||||
if (!logFile)
|
||||
{
|
||||
cardFail(3);
|
||||
}
|
||||
|
||||
linecount++;
|
||||
logFile.print(linecount);
|
||||
logFile.println(" Hello World");
|
||||
logFile.close();
|
||||
|
||||
Serial.println();
|
||||
Serial.print("Dump file ");
|
||||
Serial.println(filename);
|
||||
Serial.println();
|
||||
|
||||
digitalWrite(LED1, HIGH);
|
||||
|
||||
if (dumpFile(filename))
|
||||
{
|
||||
Serial.println();
|
||||
Serial.println("Finished File Dump");
|
||||
}
|
||||
else
|
||||
{
|
||||
cardFail(4);
|
||||
}
|
||||
|
||||
digitalWrite(LED1, LOW);
|
||||
delay(2000);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void printDirectory(File dir, int numTabs)
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
|
||||
File entry = dir.openNextFile();
|
||||
if (! entry)
|
||||
{
|
||||
//no more files
|
||||
break;
|
||||
}
|
||||
for (uint8_t i = 0; i < numTabs; i++) {
|
||||
Serial.print('\t');
|
||||
}
|
||||
Serial.print(entry.name());
|
||||
if (entry.isDirectory())
|
||||
{
|
||||
Serial.println("/");
|
||||
printDirectory(entry, numTabs + 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
//files have sizes, directories do not
|
||||
Serial.print("\t\t");
|
||||
Serial.println(entry.size(), DEC);
|
||||
}
|
||||
entry.close();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool dumpFile(char *buf)
|
||||
{
|
||||
//Note, this function will return true if the SD card is remove. See note at program start.
|
||||
if (SD.exists(buf))
|
||||
{
|
||||
Serial.print(buf);
|
||||
Serial.println(" found");
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.print(filename);
|
||||
Serial.println(" not found");
|
||||
return false;
|
||||
}
|
||||
|
||||
logFile = SD.open(buf);
|
||||
|
||||
if (logFile) //if the file is available, read from it
|
||||
{
|
||||
while (logFile.available())
|
||||
{
|
||||
Serial.write(logFile.read());
|
||||
}
|
||||
logFile.close();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
uint8_t setupSDLOG(char *buf)
|
||||
{
|
||||
//creats a new filename
|
||||
|
||||
uint16_t index;
|
||||
|
||||
for (index = 1; index <= 9999; index++) {
|
||||
buf[4] = index / 1000 + '0';
|
||||
buf[5] = ((index % 1000) / 100) + '0';
|
||||
buf[6] = ((index % 100) / 10) + '0';
|
||||
buf[7] = index % 10 + '0' ;
|
||||
if (! SD.exists(filename)) {
|
||||
// only open a new file if it doesn't exist
|
||||
logFile = SD.open(buf, FILE_WRITE);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!logFile)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return index; //return number of logfile created
|
||||
}
|
||||
|
||||
|
||||
void cardFail(uint8_t num)
|
||||
{
|
||||
while (1)
|
||||
{
|
||||
Serial.print(num); //so we can tell where card failed
|
||||
Serial.println(" Card failed, or not present");
|
||||
led_Flash(100, 25);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void led_Flash(unsigned int flashes, unsigned int delaymS)
|
||||
{
|
||||
unsigned int index;
|
||||
|
||||
for (index = 1; index <= flashes; index++)
|
||||
{
|
||||
digitalWrite(LED1, HIGH);
|
||||
delay(delaymS);
|
||||
digitalWrite(LED1, LOW);
|
||||
delay(delaymS);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void setup()
|
||||
{
|
||||
pinMode(LED1, OUTPUT); //for PCB LED
|
||||
led_Flash(4, 125);
|
||||
|
||||
Serial.begin(9600);
|
||||
Serial.println(F("43_SD_Card_Test_ESP32 Starting"));
|
||||
}
|
||||
@ -0,0 +1,99 @@
|
||||
/*******************************************************************************************************
|
||||
Programs for Arduino - Copyright of the author Stuart Robinson - 20/01/20
|
||||
|
||||
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 test program has been written to check that a connected SD card adapter, Micro
|
||||
or standard, is funtional with the FS functions. To use the program first copy the file (in this programs
|
||||
directory) called testfile.txt to the root directory of the SD card.
|
||||
|
||||
When the program runs it will attempt to open 'testfile.txt' and spool the contents to the Arduino IDE
|
||||
serial monitor. The testfile is part of the source code for the Apollo 11 Lunar Lander navigation and
|
||||
guidance computer. There are LED flashes at power up or reset, then at start of every loop of the test.
|
||||
The LED is on whilst the testfile is being read. If the LED flashes very rapidly then there is a problem
|
||||
accessing the SD card.
|
||||
|
||||
The program also has the option of using a logic pin to control the power to the lora and SD card
|
||||
devices, which can save power in sleep mode. If the hardware is fitted to your board these devices are
|
||||
powered on by setting the VCCPOWER pin low. If your board does not have this feature set VCCPOWER to -1.
|
||||
|
||||
Serial monitor baud rate is set at 9600
|
||||
*******************************************************************************************************/
|
||||
|
||||
#include "FS.h"
|
||||
#include "SD.h"
|
||||
#include "SPI.h"
|
||||
|
||||
|
||||
#define SWITCH1 0 //pin number to attach switch
|
||||
#define LED1 2 //pin number for LED
|
||||
#define SDCS 13 //ESP32 pin number for device select on SD card module
|
||||
|
||||
|
||||
void loop()
|
||||
{
|
||||
Serial.println(F("LED Flash"));
|
||||
Serial.println();
|
||||
led_Flash(2, 50);
|
||||
readFile(SD, "/testfile.txt");
|
||||
delay(1000);
|
||||
}
|
||||
|
||||
|
||||
void readFile(fs::FS &fs, const char * path) {
|
||||
Serial.printf("Reading file: %s\n", path);
|
||||
|
||||
File file = fs.open(path);
|
||||
if (!file) {
|
||||
Serial.println();
|
||||
Serial.println("Failed to open file for reading");
|
||||
Serial.println();
|
||||
return;
|
||||
}
|
||||
|
||||
Serial.print("Read from file: ");
|
||||
digitalWrite(LED1, HIGH);
|
||||
while (file.available()) {
|
||||
Serial.write(file.read());
|
||||
}
|
||||
file.close();
|
||||
digitalWrite(LED1, LOW);
|
||||
}
|
||||
|
||||
|
||||
void led_Flash(unsigned int flashes, unsigned int delaymS)
|
||||
{
|
||||
unsigned int index;
|
||||
|
||||
for (index = 1; index <= flashes; index++)
|
||||
{
|
||||
digitalWrite(LED1, HIGH);
|
||||
delay(delaymS);
|
||||
digitalWrite(LED1, LOW);
|
||||
delay(delaymS);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void setup()
|
||||
{
|
||||
pinMode(LED1, OUTPUT); //for PCB LED
|
||||
led_Flash(4, 125);
|
||||
|
||||
Serial.begin(9600);
|
||||
|
||||
Serial.println(F("44_SD_Card_Test_With_FS_ESP32 Starting"));
|
||||
Serial.print("Initializing SD card...");
|
||||
|
||||
if (!SD.begin(SDCS)) {
|
||||
Serial.println("Card failed, or not present.");
|
||||
led_Flash(100, 25);
|
||||
return; //loop if no card found
|
||||
}
|
||||
|
||||
Serial.println("Card initialized.");
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,104 @@
|
||||
/*******************************************************************************************************
|
||||
Programs for Arduino - Copyright of the author Stuart Robinson - 20/01/20
|
||||
|
||||
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 test program has been written to check that hardware for reading the battery
|
||||
voltage has been assembled correctly such that it is funtional. The value defined as 'ADMultiplier'
|
||||
in settings.h is used to adjust the value read from the 91K\11K resistor divider and convert into mV.
|
||||
|
||||
There is also an option of using a logic pin to turn the resistor divider used to read battery voltage
|
||||
on and off. This reduces current used in sleep mode. To use the feature set the define for pin BATVREADON
|
||||
in 'Settings.h' to the pin used. If not using the feature set the pin number to -1.
|
||||
|
||||
Serial monitor baud rate is set at 9600
|
||||
*******************************************************************************************************/
|
||||
|
||||
|
||||
#define ADMultiplier 10.872 //adjustment to convert AD value read into mV of battery voltage
|
||||
#define BATVREADON 25 //used to turn on the resistor divider to measure voltage //this pin turns on the MOSFET that switches in the resistor divider
|
||||
#define LED1 2 //pin for PCB LED
|
||||
#define SupplyAD 36 //Resitor divider for battery connected here
|
||||
|
||||
|
||||
void loop()
|
||||
{
|
||||
Serial.println(F("LED Flash"));
|
||||
led_Flash(4, 125);
|
||||
printSupplyVoltage();
|
||||
Serial.println();
|
||||
delay(1500);
|
||||
}
|
||||
|
||||
|
||||
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 printSupplyVoltage()
|
||||
{
|
||||
//get and display supply volts on terminal or monitor
|
||||
Serial.print(F("Supply Volts "));
|
||||
Serial.print(readSupplyVoltage());
|
||||
Serial.println(F("mV"));
|
||||
}
|
||||
|
||||
|
||||
uint16_t readSupplyVoltage()
|
||||
{
|
||||
//ESP32 uses the 3.3V VCC as reference
|
||||
|
||||
uint16_t temp;
|
||||
uint16_t volts = 0;
|
||||
byte index;
|
||||
|
||||
if (BATVREADON >= 0)
|
||||
{
|
||||
digitalWrite(BATVREADON, HIGH); //turn on MOSFET connecting resitor divider in circuit
|
||||
}
|
||||
|
||||
temp = analogRead(SupplyAD);
|
||||
|
||||
for (index = 0; index <= 4; index++) //sample AD 5 times
|
||||
{
|
||||
temp = analogRead(SupplyAD);
|
||||
volts = volts + temp;
|
||||
}
|
||||
volts = ((volts / 5) * ADMultiplier);
|
||||
|
||||
if (BATVREADON >= 0)
|
||||
{
|
||||
digitalWrite(BATVREADON, LOW); //turn off MOSFET connecting resitor divider in circuit
|
||||
}
|
||||
|
||||
return volts;
|
||||
}
|
||||
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(9600); //setup Serial console ouput
|
||||
Serial.println("45_Battery_Voltage_Read_Test_ESP32 Starting");
|
||||
|
||||
pinMode(LED1, OUTPUT); //for PCB LED
|
||||
|
||||
if (BATVREADON >= 0)
|
||||
{
|
||||
pinMode(BATVREADON, OUTPUT); //controls MOSFET connecting resitor divider in circuit
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,90 @@
|
||||
/*******************************************************************************************************
|
||||
Programs for Arduino - Copyright of the author Stuart Robinson - 20/02/20
|
||||
|
||||
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 flashes a LED connected to the pin defined by LED1, and puts the ESP32
|
||||
to deep_sleep for a period determined by the TIME_TO_SLEEP variable (in seconds).
|
||||
|
||||
The program also has the option of using a logic pin to control the power to the lora and SD card
|
||||
devices, which can save power in sleep mode. If the hardware is fitted to your board these devices are
|
||||
powered on by setting the VCCPOWER pin low. If your board does not have this feature set VCCPOWER to -1.
|
||||
|
||||
Current in deep_sleep for a bare bones ESP32 with regulator and no other devices was 27uA.
|
||||
|
||||
Serial monitor baud rate is set at 9600.
|
||||
*******************************************************************************************************/
|
||||
|
||||
#define LED1 2 //pin number for LED
|
||||
#define VCCPOWER 14 //pin may control power to external devices, -1 if not used
|
||||
|
||||
#define uS_TO_S_FACTOR 1000000 //Conversion factor for micro seconds to seconds
|
||||
#define TIME_TO_SLEEP 15 //Time ESP32 will go to sleep (in seconds)
|
||||
|
||||
RTC_DATA_ATTR int32_t bootCount = 0;
|
||||
RTC_DATA_ATTR uint32_t sleepcount = 0;
|
||||
|
||||
|
||||
void loop()
|
||||
{
|
||||
Serial.print(F("Bootcount "));
|
||||
Serial.println(bootCount);
|
||||
Serial.print(F("Sleepcount "));
|
||||
Serial.println(sleepcount);
|
||||
Serial.println(F("LED Flash"));
|
||||
led_Flash(4, 125);
|
||||
Serial.println(F("LED On"));
|
||||
digitalWrite(LED1, HIGH);
|
||||
delay(2500);
|
||||
Serial.println(F("LED Off"));
|
||||
digitalWrite(LED1, LOW);
|
||||
|
||||
esp_sleep_enable_timer_wakeup(TIME_TO_SLEEP * uS_TO_S_FACTOR);
|
||||
Serial.println(F("Start Sleep"));
|
||||
Serial.flush();
|
||||
sleepcount++;
|
||||
esp_deep_sleep_start();
|
||||
Serial.println();
|
||||
Serial.println();
|
||||
Serial.println(F("Awake !"));
|
||||
}
|
||||
|
||||
|
||||
void led_Flash(unsigned int flashes, unsigned int delaymS)
|
||||
{
|
||||
//flash LED to show tracker is alive
|
||||
unsigned int index;
|
||||
|
||||
for (index = 1; index <= flashes; index++)
|
||||
{
|
||||
digitalWrite(LED1, LOW);
|
||||
delay(delaymS);
|
||||
digitalWrite(LED1, HIGH);
|
||||
delay(delaymS);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(9600); //setup Serial console ouput
|
||||
Serial.println(F("47_DeepSleep_Timed_Wakeup_ESP32 - Starting"));
|
||||
|
||||
if (bootCount == 0) //Run this only the first time
|
||||
{
|
||||
bootCount = bootCount + 1;
|
||||
}
|
||||
|
||||
pinMode(LED1, OUTPUT); //for PCB LED
|
||||
|
||||
if (VCCPOWER >= 0)
|
||||
{
|
||||
pinMode(VCCPOWER, OUTPUT);
|
||||
digitalWrite(VCCPOWER, HIGH); //VCCOUT off
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -0,0 +1,91 @@
|
||||
/*******************************************************************************************************
|
||||
Programs for Arduino - Copyright of the author Stuart Robinson - 03/02/20
|
||||
|
||||
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 flashes a LED connected to the pin defined by LED1, and puts the ESP32 to
|
||||
light_sleep for a period determined by TIME_TO_SLEEP (in seconds).
|
||||
|
||||
The program also has the option of using a logic pin to control the power to the lora.SD card and DS18B20
|
||||
devices, which can save power in sleep mode. If the hardware is fitted to your board these devices are
|
||||
powered on by setting the VCCPOWER pin low. If your board does not have this feature set VCCPOWER to -1.
|
||||
|
||||
Current in light_sleep mode was 1500uA
|
||||
****************************************************************************************************************
|
||||
*/
|
||||
|
||||
|
||||
#define VCCPOWER 14 //when low supplies VCC power to external devices. Set to -1 if not used
|
||||
#define LED1 2 //On board LED, high for on
|
||||
|
||||
|
||||
#define uS_TO_S_FACTOR 1000000 //Conversion factor for micro seconds to seconds
|
||||
#define TIME_TO_SLEEP 15 //Time ESP32 will go to sleep (in seconds)
|
||||
|
||||
RTC_DATA_ATTR int16_t bootCount = 0;
|
||||
RTC_DATA_ATTR uint16_t sleepcount = 0;
|
||||
|
||||
|
||||
void loop()
|
||||
{
|
||||
Serial.print(F("Bootcount "));
|
||||
Serial.println(bootCount);
|
||||
Serial.print(F("Sleepcount "));
|
||||
Serial.println(sleepcount);
|
||||
Serial.println(F("LED Flash"));
|
||||
led_Flash(4, 125);
|
||||
Serial.println(F("LED On"));
|
||||
digitalWrite(LED1, HIGH);
|
||||
delay(2500);
|
||||
Serial.println(F("LED Off"));
|
||||
digitalWrite(LED1, LOW);
|
||||
|
||||
esp_sleep_enable_timer_wakeup(TIME_TO_SLEEP * uS_TO_S_FACTOR);
|
||||
Serial.println(F("Start Sleep"));
|
||||
Serial.flush();
|
||||
sleepcount++;
|
||||
esp_light_sleep_start();
|
||||
Serial.println();
|
||||
Serial.println();
|
||||
Serial.println(F("Awake !"));
|
||||
}
|
||||
|
||||
|
||||
void led_Flash(unsigned int flashes, unsigned int delaymS)
|
||||
{
|
||||
//flash LED to show tracker is alive
|
||||
unsigned int index;
|
||||
|
||||
for (index = 1; index <= flashes; index++)
|
||||
{
|
||||
digitalWrite(LED1, LOW);
|
||||
delay(delaymS);
|
||||
digitalWrite(LED1, HIGH);
|
||||
delay(delaymS);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(9600); //setup Serial console ouput
|
||||
Serial.println(F("50_LightSleep_Timed_Wakeup_ESP32 - Starting"));
|
||||
|
||||
if (bootCount == 0) //Run this only the first time
|
||||
{
|
||||
bootCount = bootCount + 1;
|
||||
}
|
||||
|
||||
pinMode(LED1, OUTPUT); //for PCB LED
|
||||
|
||||
if (VCCPOWER >= 0)
|
||||
{
|
||||
pinMode(VCCPOWER, OUTPUT); //For controlling power to external devices
|
||||
digitalWrite(VCCPOWER, HIGH); //VCCOUT off, lora device and SD card off
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,86 @@
|
||||
/*******************************************************************************************************
|
||||
Programs for Arduino - Copyright of the author Stuart Robinson - 20/02/20
|
||||
|
||||
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 flashes a LED connected to the pin defined by LED1, and puts the ESP32
|
||||
to deep_sleep. Pressing BOOT switch should wake up the ESP32 from sleep.
|
||||
|
||||
Only the specific RTC IO pins can be used as a source for external wakeup.
|
||||
These are pins: 0,2,4,12-15,25-27,32-39.
|
||||
|
||||
Current in deep_sleep for a bare bones ESP32 with regulator and no other devices was 27uA.
|
||||
|
||||
Serial monitor baud rate is set at 9600.
|
||||
*******************************************************************************************************/
|
||||
|
||||
#define LED1 2 //pin number for LED
|
||||
#define SWITCH1 0 //pin number wakeup switch
|
||||
|
||||
|
||||
RTC_DATA_ATTR int16_t bootCount = 0;
|
||||
RTC_DATA_ATTR uint16_t sleepcount = 0;
|
||||
|
||||
|
||||
void loop()
|
||||
{
|
||||
Serial.print(F("Bootcount "));
|
||||
Serial.println(bootCount);
|
||||
Serial.print(F("Sleepcount "));
|
||||
Serial.println(sleepcount);
|
||||
Serial.println(F("LED Flash"));
|
||||
led_Flash(4, 125);
|
||||
Serial.println(F("LED On"));
|
||||
digitalWrite(LED1, HIGH);
|
||||
delay(2500);
|
||||
Serial.println(F("LED Off"));
|
||||
digitalWrite(LED1, LOW);
|
||||
|
||||
//esp_sleep_enable_timer_wakeup(TIME_TO_SLEEP * uS_TO_S_FACTOR);
|
||||
|
||||
esp_sleep_enable_ext0_wakeup(GPIO_NUM_0, 0); //wakeup on pin GPIO0 going low
|
||||
|
||||
Serial.println(F("Start Sleep"));
|
||||
Serial.flush();
|
||||
sleepcount++;
|
||||
esp_deep_sleep_start();
|
||||
Serial.println();
|
||||
Serial.println();
|
||||
Serial.println(F("Awake ?")); //should not really see this, deep sleep wakeup causes reset ....
|
||||
}
|
||||
|
||||
|
||||
void led_Flash(unsigned int flashes, unsigned int delaymS)
|
||||
{
|
||||
//flash LED to show tracker is alive
|
||||
unsigned int index;
|
||||
|
||||
for (index = 1; index <= flashes; index++)
|
||||
{
|
||||
digitalWrite(LED1, LOW);
|
||||
delay(delaymS);
|
||||
digitalWrite(LED1, HIGH);
|
||||
delay(delaymS);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(9600); //setup Serial console ouput
|
||||
Serial.println();
|
||||
Serial.println();
|
||||
Serial.println(F("51_DeepSleep_Timed_Wakeup_ESP32 - Starting"));
|
||||
|
||||
if (bootCount == 0) //Run this only the first time
|
||||
{
|
||||
bootCount = bootCount + 1;
|
||||
}
|
||||
|
||||
pinMode(LED1, OUTPUT); //for PCB LED
|
||||
pinMode(SWITCH1, INPUT_PULLUP); //for wakeup switch
|
||||
|
||||
}
|
||||
@ -0,0 +1,131 @@
|
||||
/*******************************************************************************************************
|
||||
lora Programs for Arduino - Copyright of the author Stuart Robinson - 20/01/20
|
||||
|
||||
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 - When the ESP32 turns on the WiFi function, there is a short high current pulse that
|
||||
can cause the ESP32 brownout detect to operate.
|
||||
|
||||
This test program at startup flashes an LED, leaves it on and then starts the WiFi. If the Wifi initiates
|
||||
a brownout, you will see the LED flash again. The LED stays on when scanning, the program reports the
|
||||
networks found to the serial console and displays them on an attached SSD1306 OLED.
|
||||
|
||||
Thus if you see the LED continually doing short bursts of flashing the turn on\off the WiFi is causing
|
||||
the ESP32 to reset. There will also be a message on the serial monitor that the brownout detector operated.
|
||||
|
||||
Serial monitor baud rate is set at 9600
|
||||
*******************************************************************************************************/
|
||||
|
||||
#include "WiFi.h"
|
||||
#define LED1 2 //Arduino pin number for LED, when high LED should be on.
|
||||
|
||||
#include <U8x8lib.h> //get library here > https://github.com/olikraus/u8g2
|
||||
//U8X8_SSD1306_128X64_NONAME_HW_I2C disp(U8X8_PIN_NONE); //use this line for standard 0.96" SSD1306
|
||||
U8X8_SH1106_128X64_NONAME_HW_I2C disp(U8X8_PIN_NONE); //use this line for 1.3" OLED often sold as 1.3" SSD1306
|
||||
|
||||
|
||||
void loop()
|
||||
{
|
||||
Serial.println("Set WiFi to Station mode"); //Set WiFi to station mode
|
||||
Serial.flush();
|
||||
WiFi.mode(WIFI_STA);
|
||||
WiFi.disconnect();
|
||||
delay(1000);
|
||||
|
||||
Serial.println("Setup done");
|
||||
Serial.flush();
|
||||
|
||||
digitalWrite(LED1, HIGH);
|
||||
Serial.println("WiFi scan start");
|
||||
Serial.flush();
|
||||
int n = WiFi.scanNetworks(); //WiFi.scanNetworks will return the number of networks found
|
||||
digitalWrite(LED1, LOW);
|
||||
delay(500);
|
||||
disp.clear();
|
||||
disp.setCursor(0, 0);
|
||||
|
||||
if (n == 0) {
|
||||
Serial.println("No WiFi");
|
||||
disp.println("No WiFi");
|
||||
} else {
|
||||
Serial.print(n);
|
||||
disp.print(n);
|
||||
Serial.println(" WiFi found");
|
||||
disp.println(" WiFi found");
|
||||
led_Flash(n, 500);
|
||||
|
||||
if (n > 16) //only want to display first 16 networks
|
||||
{
|
||||
n = 16;
|
||||
}
|
||||
|
||||
for (int i = 0; i < n; ++i) {
|
||||
//Print SSID and RSSI for each network found
|
||||
Serial.print(i + 1);
|
||||
Serial.print(": ");
|
||||
Serial.print(WiFi.SSID(i));
|
||||
|
||||
if (i > 7)
|
||||
{ disp.clearLine(i - 8);
|
||||
disp.setCursor(0, i - 8);
|
||||
}
|
||||
else
|
||||
{
|
||||
disp.clearLine(i);
|
||||
disp.setCursor(0, i);
|
||||
}
|
||||
|
||||
disp.print(WiFi.SSID(i));
|
||||
Serial.print(" (");
|
||||
Serial.print(WiFi.RSSI(i));
|
||||
Serial.print(")");
|
||||
Serial.println((WiFi.encryptionType(i) == WIFI_AUTH_OPEN) ? " " : "*");
|
||||
if (i == 7) //check if 8 lines have already been sent to display
|
||||
{
|
||||
delay(2000); //leave last 8 on display for a while
|
||||
disp.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
Serial.println();
|
||||
disp.println();
|
||||
|
||||
|
||||
// Wait a bit before scanning again
|
||||
delay(5000);
|
||||
}
|
||||
|
||||
|
||||
void led_Flash(unsigned int flashes, unsigned int delaymS)
|
||||
{
|
||||
//flash LED
|
||||
unsigned int index;
|
||||
|
||||
for (index = 1; index <= flashes; index++)
|
||||
{
|
||||
digitalWrite(LED1, HIGH);
|
||||
delay(delaymS);
|
||||
digitalWrite(LED1, LOW);
|
||||
delay(delaymS);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void setup()
|
||||
{
|
||||
pinMode(LED1, OUTPUT);
|
||||
led_Flash(5, 50);
|
||||
digitalWrite(LED1, LOW);
|
||||
delay(1000);
|
||||
Serial.begin(9600);
|
||||
|
||||
disp.begin();
|
||||
disp.setFont(u8x8_font_chroma48medium8_r);
|
||||
disp.clear();
|
||||
disp.setCursor(0, 0);
|
||||
disp.print(F("Scanner Ready"));
|
||||
}
|
||||
636
examples/ReadMe.md
Normal file
636
examples/ReadMe.md
Normal file
@ -0,0 +1,636 @@
|
||||
## SX12XX Library Example Programs
|
||||
|
||||
|
||||
For the majority of the program examples you will need to define the pins used plus the frequency and the LoRa settings used in the Settings.h file. The default provided settings may not be optimised for long distance. See the 'What is LoRa' document for information on how LoRa settings affect range.
|
||||
|
||||
Some of the examples use sleep mode on the processor and LoRa device to save power. Typical sleep currents may be mentioned in the description of the program. In most all cases a 'bare bones' Atmel based Arduino has been used to measure the sleep currents and you may not get even close to the quoted figures using standard Arduinos such as Pro Minis or similar. Optimising particular Arduino boards for low power sleep is outside of the scope of this library and examples.
|
||||
|
||||
|
||||
|
||||
|
||||
#### 1\_LED\_Blink             (Basics folder)
|
||||
|
||||
This program blinks an LED connected the pin number defined by LED1.The pin 13 LED, fitted to some Arduinos is blinked as well. The blinks should be close to one per second. Messages are sent to the Serial Monitor also.
|
||||
|
||||
#### 2\_Register\_Test             (Basics folder)
|
||||
This program is stand alone, it is not necessary to install the SX12XX-LoRa library to use it.
|
||||
|
||||
The program checks that a lora device can be accessed by doing a test register write and read. If there is no device found a message is printed on the serial monitor. The contents of the registers from 0x00 to 0x7F are printed, there is a copy of a typical printout below. Note that the read back changed frequency may be different to the programmed frequency, there is a rounding error due to the use of floats to calculate the frequency.
|
||||
|
||||
SX1276-79 Selected
|
||||
LoRa Device found
|
||||
Device version 0x12
|
||||
Frequency at reset 434000000
|
||||
Registers at reset
|
||||
Reg 0 1 2 3 4 5 6 7 8 9 A B C D E F
|
||||
0x00 00 09 1A 0B 00 52 6C 80 00 4F 09 2B 20 08 02 0A
|
||||
0x10 FF 70 15 0B 28 0C 12 47 32 3E 00 00 00 00 00 40
|
||||
0x20 00 00 00 00 05 00 03 93 55 55 55 55 55 55 55 55
|
||||
0x30 90 40 40 00 00 0F 00 00 00 F5 20 82 04 02 80 40
|
||||
0x40 00 00 12 24 2D 00 03 00 04 23 00 09 05 84 32 2B
|
||||
0x50 14 00 00 10 00 00 00 0F E0 00 0C 04 06 00 5C 78
|
||||
0x60 00 19 0C 4B CC 0D FD 20 04 47 AF 3F F2 3F D9 0B
|
||||
0x70 D0 01 10 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||
|
||||
|
||||
Changed Frequency 434099968
|
||||
Reg 0 1 2 3 4 5 6 7 8 9 A B C D E F
|
||||
0x00 00 09 1A 0B 00 52 6C 86 66 4F 09 2B 20 08 02 0A
|
||||
0x10 FF 70 15 0B 28 0C 12 47 32 3E 00 00 00 00 00 40
|
||||
0x20 00 00 00 00 05 00 03 93 55 55 55 55 55 55 55 55
|
||||
0x30 90 40 40 00 00 0F 00 00 00 F5 20 82 04 02 80 40
|
||||
0x40 00 00 12 24 2D 00 03 00 04 23 00 09 05 84 32 2B
|
||||
0x50 14 00 00 10 00 00 00 0F E0 00 0C 04 06 00 5C 78
|
||||
0x60 00 19 0C 4B CC 0D FD 20 04 47 AF 3F F2 3F D9 0B
|
||||
0x70 D0 01 10 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||
|
||||
|
||||
#### 3\_LoRa\_Transmitter             (Basics folder)
|
||||
This is a minimum setup LoRa test transmitter. A packet containing the ASCII text "Hello World 1234567890" is sent using the frequency and LoRa settings specified in the LT.setupLoRa() command. The pins to access the lora device need to be defined at the top of the program also.
|
||||
|
||||
The details of the packet sent and any errors are shown on the Arduino IDE Serial Monitor, together with the transmit power used and the packet length. The matching receiver program, '4\_LoRa\_Receiver' can be used
|
||||
to check the packets are being sent correctly, the frequency and LoRa settings (in the LT.setupLoRa() commands) must be the same for the transmitter and receiver programs. Sample Serial Monitor output;
|
||||
|
||||
10dBm Packet> Hello World 1234567890 BytesSent,23 PacketsSent,6
|
||||
|
||||
For an example of a more detailed configuration for a transmitter, see program 103\_LoRa\_Transmitter.
|
||||
|
||||
Serial monitor baud rate is set at 9600
|
||||
|
||||
#### 4\_LoRa\_Receiver             (Basics folder)
|
||||
|
||||
This is a minimum setup LoRa test receiver. The program listens for incoming packets using the frequency and LoRa settings in the LT.setupLoRa() command. The pins to access the lora device need to be defined at the top of the program also.
|
||||
|
||||
There is a printout on the Arduino IDE serial monitor of the valid packets received, the packet is assumed to be in ASCII printable text, if it's not ASCII text characters from 0x20 to 0x7F, expect weird things to happen on the Serial Monitor. Sample serial monitor output;
|
||||
|
||||
8s Hello World 1234567890,RSSI,-44dBm,SNR,9dB,Length,23,Packets,7,Errors,0,IRQreg,50
|
||||
|
||||
If there is a packet error it might look like this, which is showing a CRC error;
|
||||
|
||||
137s PacketError,RSSI,-89dBm,SNR,-8dB,Length,23,Packets,37,Errors,2,IRQreg,70,IRQ\_HEADER\_VALID,IRQ\_CRC\_ERROR,IRQ\_RX\_DONE
|
||||
|
||||
If there are no packets received in a 10 second period then you should see a message like this;
|
||||
|
||||
112s RXTimeout
|
||||
|
||||
For an example of a more detailed configuration for a receiver, see program 104\_LoRa\_Receiver.
|
||||
|
||||
Serial monitor baud rate is set at 9600.
|
||||
<br>
|
||||
|
||||
#### 5\_LoRa\_TX\_Sleep\_Timed\_Wakeup\_Atmel             (Sleep folder)
|
||||
|
||||
This program tests the sleep mode and register retention of the lora device in sleep mode, it assumes an Atmel ATMega328P processor is in use. The LoRa settings to use are specified in the 'Settings.h' file.
|
||||
|
||||
A packet is sent, containing the text 'Before Device Sleep' and the LoRa device and Atmel processor are put to sleep. The processor watchdog timer should wakeup the processor in 15 seconds (approx) and register values should be retained. The device then attempts to transmit another packet 'After Device Sleep' without re-loading all the LoRa settings. The receiver should see 'After Device Sleep' for the first packet and 'After Device Sleep' for the second.
|
||||
|
||||
Tested on a 'bare bones' ATmega328P board, the current in sleep mode was 6.5uA.
|
||||
|
||||
|
||||
#### 6\_LoRa\_RX\_and\_Sleep\_Atmel             (Sleep folder)
|
||||
|
||||
|
||||
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.
|
||||
|
||||
When the program starts the LoRa device is set-up to receive packets with pin DIO0 set to go high when a packet arrives. The receiver remains powered (it cannot receive otherwise) and the processor (Atmel ATMega328P or 1284P) is put to sleep. When pin DIO0 does go high, indicating a packet is received, the processor wakes up and prints the packet. It then goes back to sleep.
|
||||
|
||||
There is a printout of the valid packets received, these are assumed to be in ASCII printable text. The LED will flash for each packet received and the buzzer will sound,if fitted.
|
||||
|
||||
Tested on a 'bare bones' ATmega328P board, the current in sleep mode was 12.26mA.
|
||||
|
||||
#### 7\_LoRa\_TX\_Sleep\_Switch\_Wakeup\_Atmel             (Sleep folder)
|
||||
|
||||
|
||||
This program tests the sleep mode and register retention of the lora device in sleep mode, it assumes an Atmel ATMega328P processor is in use. The LoRa settings to use are specified in the 'Settings.h' file.
|
||||
|
||||
A packet is sent, containing the text 'Before Device Sleep' and the lora device and Atmel processor are put to sleep. The processor should remain asleep until the pin defined by SWITCH1 in the Settings.h file is connected to ground and the LoRa device register values should be retained. The LoRa device then attempts to transmit another packet 'After Device Sleep' without re-loading all the LoRa settings. The receiver should see 'After Device Sleep' for the first packet and 'After Device Sleep' for the second.
|
||||
|
||||
Tested on a bare bones ATmega328P board, the current in sleep mode was 2.4uA.
|
||||
|
||||
#### 8\_LoRa\_LowMemory\_TX             (LowMemory folder)
|
||||
|
||||
The program transmits a packet without using a processor buffer, the LoRa device internal buffer is filled direct with variables. The program is a simulation of the type of packet that might be sent from a GPS tracker. Note that in this example a buffer of text is part of the transmitted packet, this does need a processor buffer which is used to fill the LoRa device internal buffer, if you don't need to transmit text then the uint8_t trackerID[] = "tracker1"; definition can be omitted.
|
||||
|
||||
The matching receiving program '9\_LoRa\_LowMemory\_RX' can be used to receive and display the packet, though the program '15\_LoRa\_RX\_Structure' should receive it as well, since the packet contents are the same.
|
||||
|
||||
The contents of the packet received, and printed to serial monitor, should be;
|
||||
|
||||
"tracker1" (buffer) - trackerID
|
||||
1+ (uint32\_t) - packet count
|
||||
51.23456 (float) - latitude
|
||||
-3.12345 (float) - longitude
|
||||
199 (uint16\_t) - altitude
|
||||
8 (uint8\_t) - number of satellites
|
||||
3999 (uint16\_t) - battery voltage
|
||||
-9 (int8_t) - temperature
|
||||
|
||||
#### 9\_LoRa\_LowMemory\_RX             (LowMemory folder)
|
||||
|
||||
The program receives a packet without using a processor buffer, the LoRa device internal buffer is read direct and copied to variables. The program is a simulation of the type of packet that might be received from a GPS tracker. Note that in this example a buffer of text is part of the received packet, this does need a processor buffer which is filled with data from the LoRa device internal buffer, if you don't need to send and receive text then the uint8_t receivebuffer[32]; definition can be omitted.
|
||||
|
||||
The contents of the packet received, and printed to serial monitor, should be;
|
||||
|
||||
"tracker1" (buffer) - trackerID
|
||||
1+ (uint32\_t) - packet count
|
||||
51.23456 (float) - latitude
|
||||
-3.12345 (float) - longitude
|
||||
199 (uint16\_t) - altitude
|
||||
8 (uint8\_t) - number of satellites
|
||||
3999 (uint16\_t) - battery voltage
|
||||
-9 (int8_t) - temperature
|
||||
|
||||
|
||||
#### 10\_LoRa\_Link\_Test\_Transmitter             (Diagnostics and Test folder)
|
||||
|
||||
This is a program that can save you a great deal of time if your testing the effectiveness of a LoRa links or attached antennas. Simulations of antenna performance are no substitute for real world tests and this simple program allows both long distance link performance to be evaluated and antenna performance to be compared.
|
||||
|
||||
The program sends short test packets that reduce in power by 1dBm at a time. The start power is defined by start\_power and the end power is defined by end\_power (see Settings.h file). Once the end\_power point is reached, the program pauses a short while and starts the transmit sequence again at start\_power. The packet sent contains the power used to send the packet. By listening for the packets with the basic LoRa receive program (4\_LoRa\_Receiver) you can see the reception results, which should look something like this;
|
||||
|
||||
11s 1*T+05,CRC,80B8,RSSI,-03dBm,SNR,9dB,Length,6, Packets,9,Errors,0,IRQreg,50
|
||||
12s 1*T+04,CRC,9099,RSSI,-74dBm,SNR,9dB,Length,6, Packets,10,Errors,0,IRQreg,50
|
||||
14s 1*T+03,CRC,E07E,RSSI,-75dBm,SNR,9dB,Length,6, Packets,11,Errors,0,IRQreg,50
|
||||
|
||||
Above shows 3 packets received, the first at +05dBm (+05 in printout), the second at 4dBm (+04 in printout) and the third at 3dBm (+03) in printout.
|
||||
|
||||
If it is arranged so that reception of packets fails halfway through the sequence by attenuating either the transmitter (with an SMA attenuator for instance) or the receiver (by placing it in a tin perhaps) then if you swap transmitter antennas you can see the dBm difference in reception, which will be the dBm difference (gain) of the antenna.
|
||||
|
||||
To start the sequence a packet is sent with the number 999, when received it looks like this;
|
||||
|
||||
T*1999
|
||||
|
||||
This received packet could be used for the RX program to be able to print totals etc.
|
||||
|
||||
LoRa settings to use for the link test are specified in the 'Settings.h' file.
|
||||
|
||||
|
||||
#### 11\_LoRa\_Packet\_Logger\_Receiver             (Diagnostics and Test folder)
|
||||
|
||||
|
||||
This is a useful packet logger program. It 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 and the buzzer will sound, if fitted. The measured frequency difference between the frequency used by the transmitter and the frequency used by the receiver is shown. If this frequency difference gets to 25% of the set LoRa bandwidth, packet reception will fail. The displayed error can be reduced by using the 'offset' setting in the 'Settings.h' file.
|
||||
|
||||
#### 12\_ATmel\_Sleep\_with\_Switch\_Wakeup             (Hardware_Checks folder)
|
||||
|
||||
This program tests the deep sleep mode and wakeup with a switch of an Atmel 328P or 1284P processor. The program starts, flashes the LED and then puts the processor into permanent sleep. It can be woken up with a switch press. Used as a base test routine for checking the sleep current of a board.
|
||||
|
||||
Tested on an 'bare bones' ATmega328P board, the current in sleep mode was 1.7uA with a 3.3V MCP1700 regulator being used.
|
||||
|
||||
|
||||
#### 13\_Frequency\_and\_Power\_Check\_TX             (Diagnostics and Test folder)
|
||||
|
||||
This is a program that transmits a long LoRa packets lasting about 5 seconds that can be used to measure the frequency and power of the transmission using external equipment. The bandwidth of the transmission is only 10khz, so a frequency counter should give reasonable average result.
|
||||
|
||||
The LoRa settings to use, including transmit power, are specified in the 'Settings.h' file.
|
||||
|
||||
|
||||
#### 14\_LoRa\_Structure\_TX             (Basics folder)
|
||||
|
||||
This program demonstrates the transmitting of a structure as a LoRa packet. The contents of the structure are the same as in the '8\_LoRa\_LowMemory\_TX' program. The packet sent is typical of what might be sent from a GPS tracker. The structure type is defined as trackerPacket and an instance called location1 is created. The structure which includes a character array (text) is filled with values and transmitted.
|
||||
|
||||
The matching receiving program '15\_LoRa\_RX\_Structure' can be used to receive and display the packet, though the program '9\_LoRa\_LowMemory\_RX' should receive it as well, since the contents are the same.
|
||||
|
||||
Note that the structure definition and variable order (including the buffer size) used in the transmitter need to match those used in the receiver.
|
||||
|
||||
The contents of the packet transmitted should be;
|
||||
|
||||
"tracker1" (buffer) - trackerID
|
||||
1+ (uint32\_t) - packet count
|
||||
51.23456 (float) - latitude
|
||||
-3.12345 (float) - longitude
|
||||
199 (uint16\_t) - altitude
|
||||
8 (uint8\_t) - number of satellites
|
||||
3999 (uint16\_t) - battery voltage
|
||||
-9 (int8_t) - temperature
|
||||
|
||||
#### 15\_LoRa\_Structure\_RX             (Basics folder)
|
||||
|
||||
|
||||
This program demonstrates the receiving of a structure as a LoRa packet. The packet sent is typical of what might be sent from a GPS tracker.
|
||||
|
||||
The structure type is defined as trackerPacket and an instance called location1 is created. The structure includes a character array (text).
|
||||
|
||||
The matching receiving program is '15\_LoRa\_RX\_Structure' can be used to receive and display the packet, though the program '9\_LoRa\_LowMemory\_RX' should receive it as well, since the packet contents are the same.
|
||||
|
||||
Not that the structure definition and variable order (including the buffer size) used in the transmitter need to match those used in the receiver. Good luck.
|
||||
|
||||
The contents of the packet received, and printed to serial monitor, should be;
|
||||
|
||||
"tracker1" (buffer) - trackerID
|
||||
1+ (uint32\_t) - packet count
|
||||
51.23456 (float) - latitude
|
||||
-3.12345 (float) - longitude
|
||||
199 (uint16\_t) - altitude
|
||||
8 (uint8\_t) - number of satellites
|
||||
3999 (uint16\_t) - battery voltage
|
||||
-9 (int8_t) - temperature
|
||||
|
||||
|
||||
#### 16\_LoRa\_RX\_Frequency\_Error\_Check             (Diagnostics and Test folder)
|
||||
|
||||
This program can be used to check the frequency error between a pair of LoRa devices, a transmitter and receiver. This receiver measures the frequecy error between the receivers centre frequency and the centre frequency of the transmitted packet. The frequency difference is shown
|
||||
for each packet and an average over 10 received packets reported. Any transmitter program can be used to give this program something to listen to, including example program '3\_LoRa\_Transmitter'.
|
||||
|
||||
|
||||
#### 17\_Sensor\_Transmitter             (Sensor folder)
|
||||
|
||||
The program transmits a LoRa packet without using a processor buffer, the LoRa devices internal buffer is filled directly with variables.
|
||||
|
||||
The sensor used is a BME280. The pressure, humidity, and temperature are read and transmitted. There is also a 16bit value of battery mV (simulated) and and a 8 bit status value at the packet end.
|
||||
|
||||
Although the LoRa packet transmitted and received has its own internal CRC error checking, you could still receive packets of the same length from another source. If this valid packet were to be used to recover the sensor values, you could be reading rubbish. To reduce the risk of this, when the packet is transmitted the CRC value of the actual sensor data is calculated and sent out with the packet. This CRC value is read by the receiver and used to check that the received CRC matches the supposed
|
||||
sensor data in the packet. As an additional check there is some addressing information at the beginning of the packet which is also checked for validity. Thus we can be relatively confident when reading the
|
||||
received packet that its genuine and from this transmitter. The packet is built and sent in the sendSensorPacket() function, there is a 'highlighted section' where the actual sensor data is added to the packet.
|
||||
|
||||
Between readings the LoRa device, BME280 sensor, and Atmel micro controller are put to sleep in units of 8 seconds using the Atmel processor internal watchdog.
|
||||
|
||||
The pin definitions, LoRa frequency and LoRa modem settings are in the Settings.h file. The Atmel watchdog timer is a viable option for a very low current sensor node. A bare bones ATmega328P with regulator and LoRa device has a sleep current of 6.6uA, add the LoRa devices and BME280 sensor module and the average sleep current only rises to 6.8uA.
|
||||
|
||||
One of these transmitter programs is running on a long term test with a 175mAh battery, to see how long the battery actually lasts.
|
||||
|
||||
|
||||
#### 18\_Sensor\_Receiver             (Sensor folder)
|
||||
|
||||
The program receives a LoRa packet without using a processor buffer, the LoRa devices internal buffer is read direct for the received sensor data.
|
||||
|
||||
The sensor used in the matching '17\_Sensor\_Transmitter' program is a BME280 and the pressure, humidity, and temperature are being and received. There is also a 16bit value of battery mV and and a 8 bit status value at the end of the packet.
|
||||
|
||||
When the program starts, the LoRa device is set-up to set the DIO0 pin high when a packet is received, the Atmel processor is then put to sleep and will wake up when a packet is received. When a packet is received, its printed and assuming the packet is validated, the sensor results are printed to the serial monitor and screen. Between readings the sensor transmitter is put to sleep in units of 8 seconds using the Atmel
|
||||
processor internal watchdog.
|
||||
|
||||
For the sensor data to be accepted as valid the flowing need to match;
|
||||
|
||||
The 16bit CRC on the received sensor data must match the CRC value transmitted with the packet.
|
||||
The packet must start with a byte that matches the packet type sent, 'Sensor1'
|
||||
The RXdestination byte in the packet must match this node ID of this receiver node, defined by 'This_Node'
|
||||
|
||||
In total that's 16 + 8 + 8 = 32bits of checking, so a 1:4294967296 chance (approx) that an invalid packet is acted on and erroneous values displayed.
|
||||
|
||||
The pin definitions, LoRa frequency and LoRa modem settings are in the Settings.h file.
|
||||
|
||||
With a standard Arduino Pro Mini and SSD1306 display the current consumption was 20.25mA with the display and 16.6mA without the display.
|
||||
|
||||
|
||||
#### 20\_LoRa\_Link\_Test\_Receiver             (Diagnostics and Test folder)
|
||||
|
||||
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.
|
||||
|
||||
The program is a matching receiver program for the '10\_LoRa\_Link\_Test\_TX'. The packets received are displayed on the serial monitor and analysed to extract the packet data which indicates the power used to send the packet. A count is kept of the numbers of each power setting received. When the transmitter sends the test mode packet at the beginning of the sequence (displayed as 999) the running totals of the powers received are printed. Thus you can quickly see at what transmit power levels the reception fails.
|
||||
|
||||
|
||||
#### 21\_On\_Off\_Transmitter             (Remote Control folder)
|
||||
|
||||
This program is a remote control transmitter. When one of four switches are made (shorted to ground) a packet is transmitted with single byte indicating the state of Switch0 as bit 0, Switch1 as bit 1 and Switch2 as bit 2. To prevent false triggering at the receiver the packet contains a
|
||||
32 bit number called the TXIdentity which in this example is set to 1234554321. The receiver will only act on, change the state of the outputs, if the identity set in the receiver matches that of the transmitter. The chance of a false trigger is fairly remote.
|
||||
|
||||
Between switch presses the LoRa device and Atmel micro controller are put to sleep. A switch press wakes up the processor from sleep, the switches are read and a packet sent. On a 'bare bones' Arduino set-up the transmitter has a sleep current of approx 2.2uA, so it's ideal for a battery powered remote control with a potential range of many kilometres.
|
||||
|
||||
|
||||
The pin definitions, LoRa frequency and LoRa modem settings are in the Settings.h file.
|
||||
|
||||
|
||||
#### 22\_On\_Off\_Receiver             (Remote Control folder)
|
||||
|
||||
This program is a remote control receiver. When a packet is received an 8 bit byte (SwitchByte) is read and the four outputs (defined in Settings.h) are toggled according to the bits set in this byte. If the Switch1 byte has bit 0 cleared, then OUTPUT0 is toggled. If the Switch1 byte has bit 1 cleared, then OUTPUT1 is toggled. If the Switch1 byte has bit 2 cleared, then OUTPUT2 is toggled.
|
||||
|
||||
To prevent false triggering at the receiver the packet also contains a 32 bit number called the TXIdentity which in this example is set to 1234554321. The receiver will only act on, change the state of the outputs, if the identity set in the receiver matches that of the transmitter. The chance of a false trigger is fairly remote.
|
||||
|
||||
The pin definitions, LoRa frequency and LoRa modem settings are in the Settings.h file.
|
||||
|
||||
|
||||
#### 23\_GPS\_Tracker\_Transmitter             (Tracker folder)
|
||||
|
||||
This program is an example of a basic GPS tracker. The program reads the GPS, waits for an updated fix and transmits location and altitude, number of satellites in view, the HDOP value, the fix time of the GPS and the battery voltage. This transmitter can be also be used to investigate GPS performance. At start-up there should be a couple of seconds of recognisable text from the GPS printed to the serial monitor. If you see garbage or funny characters its likely the GPS baud rate is wrong. If the transmitter is turned on from cold, the receiver will pick up the cold fix time, which is an indication of GPS performance. The GPS will be powered on for around 4 seconds before the timing of the fix starts. Outside with a good view of the sky most GPSs should produce a fix in around 45 seconds. The number of satellites and HDOP are good indications to how well a GPS is working.
|
||||
|
||||
The program writes direct to the LoRa devices internal buffer, no memory buffer is used.
|
||||
|
||||
The LoRa settings are configured in the Settings.h file.
|
||||
|
||||
The program has the option of using a pin to control the power to the GPS, if the GPS module being used has this feature. To use the option change the define in the Settings.h file; '#define GPSPOWER -1' from -1 to the pin number being used. Also set the GPSONSTATE and GPSOFFSTATE to the appropriate logic levels.
|
||||
|
||||
|
||||
#### 24\_GPS\_Tracker\_Receiver             (Tracker folder)
|
||||
|
||||
This program is an basic receiver for the '23\_Simple\_GPS\_Tracker\_Transmitter' program.
|
||||
|
||||
The program reads the received packet from the tracker transmitter and displays the results on the serial monitor. The LoRa and frequency settings provided in the Settings.h file must match those used by the transmitter.
|
||||
|
||||
The program receives direct from the LoRa devices internal buffer.
|
||||
|
||||
|
||||
#### 25\_GPS\_Tracker\_Receiver\_with\_Display\_and\_GPS             (Tracker folder)
|
||||
|
||||
This program is an example of a basic portable GPS tracker receiver. The program receives the location packets from the remote tracker and displays them on an OLED display. The program also reads a local GPS and when that has a fix, will display the distance and direction to the remote tracker.
|
||||
|
||||
The program writes direct to the LoRa devices internal buffer, no memory buffer is used.
|
||||
|
||||
The LoRa settings are configured in the Settings.h file.
|
||||
|
||||
The received information is printed to screen in this order top to bottom;
|
||||
|
||||
Latitude, Longitude, Altitude, HDOP, GPS Fixtime, Tracker battery mV, Number of received packets, Distance and direction to tracker, if local GPS fix. In addition if there is a recent tracker transmitter GPS fix a 'T' is shown on line 0 right of screen and if there is a recent local (receiver) GPS fix a 'R' is displayed line 1 right of screen.
|
||||
|
||||
The received information is printed to the Serial Monitor as CSV data in this order;
|
||||
|
||||
Packet Address information, Latitude, Longitude, Altitude, Satellites in use, HDOP, TX status byte, GPS Fixtime, Tracker battery mV, Number of received packets, Distance and direction to tracker, if local GPS fix.
|
||||
|
||||
The program has the option of using a pin to control the power to the GPS, if the GPS module being used has this feature. To use the option change the define in Settings.h; '#define GPSPOWER -1' from -1 to the pin number being used. Also set the GPSONSTATE and GPSOFFSTATE to the appropriate logic levels.
|
||||
|
||||
The program by default uses software serial to read the GPS, you can use hardware serial by commenting out this line in the Settings.h file;
|
||||
|
||||
#define USE\_SOFTSERIAL\_GPS
|
||||
|
||||
And then defining the hardware serial port you are using, which defaults to Serial1.
|
||||
|
||||
#### 26\_GPS\_Echo             (Hardware_Checks folder)
|
||||
|
||||
This is a simple program to test a GPS. It reads characters from the GPS using software serial and sends them (echoes) to the IDE serial monitor. If your ever having problems with a GPS (or just think you are) use this program first.
|
||||
|
||||
If you get no data displayed on the serial monitor, the most likely cause is that you have the receive data pin into the Arduino (RX) pin connected incorrectly.
|
||||
|
||||
If the data displayed on the serial terminal appears to be random text with odd symbols its very likely you have the GPS serial baud rate set incorrectly.
|
||||
|
||||
Note that not all pins on all Arduinos will work with software serial, see here;
|
||||
|
||||
https://www.arduino.cc/en/Reference/softwareSerial
|
||||
|
||||
Serial monitor baud rate is set at 115200.
|
||||
|
||||
|
||||
#### 28\_GPS\_Checker             (Hardware_Checks folder)
|
||||
|
||||
This program is a portable GPS checker and display. At start-up the program starts checking the data coming from the GPS for a valid fix. It checks for 5 seconds and if there is no fix, prints a message on the serial monitor. During this time the data coming from the GPS is copied to the serial monitor also.
|
||||
|
||||
When the program detects that the GPS has a fix, it prints the Latitude, Longitude, Altitude, Number of satellites in use and the HDOP value to the serial monitor.
|
||||
|
||||
Serial monitor baud rate is set at 115200, GPS baud rate to 9600, both are configured in setup().
|
||||
|
||||
|
||||
#### 29\_GPS\_Checker\_With\_Display             (Hardware_Checks folder)
|
||||
|
||||
This program is a GPS checker with a display output. It uses an SSD1306 or SH1106 128x64 I2C OLED display. At start-up the program starts checking the data coming from the GPS for a valid fix. It reads the GPS for 5 seconds and if there is no fix, prints a message on the serial monitor and updates the seconds without a fix on the display. During this time the data coming from the GPS is copied to the serial monitor also.
|
||||
|
||||
When the program detects that the GPS has a fix, it prints the Latitude, Longitude, Altitude, Number of satellites in use, the HDOP value, time and date to the serial monitor. If the I2C OLED display is attached that is updated as well. Display is assumed to be on I2C address 0x3C.
|
||||
|
||||
|
||||
#### 30\_I2C\_Scanner             (Hardware_Checks folder)
|
||||
|
||||
The program scans the I2C bus and displays the addresses of any devices found. Useful first check when using I2C devices.
|
||||
|
||||
|
||||
#### 31\_SSD1306\_OLED\_Checker             (Diagnostics and Test folder)
|
||||
|
||||
This program is a simple test program for the SSD1306 and SH1106 OLEDs. The program prints a short message on each line, pauses, clears the screen, and starts again.
|
||||
|
||||
OLED address is defined as 0x3C.
|
||||
|
||||
#### 33\_LoRa\_RSSI\_Checker\_With\_Display             (Diagnostics and Test folder)
|
||||
|
||||
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, the packet is assumed to be in ASCII printable text, if its not ASCII text characters from 0x20 to 0x7F, expect weird things to happen on the Serial Monitor. The LED will flash for each packet received and the buzzer will sound, if fitted.
|
||||
|
||||
Sample serial monitor output;
|
||||
|
||||
1109s {packet contents} CRC,3882,RSSI,-69dBm,SNR,10dB,Length,19,Packets,1026,Errors,0,IRQreg,50
|
||||
|
||||
If there is a packet error it might look like this, which is showing a CRC error,
|
||||
|
||||
1189s PacketError,RSSI,-111dBm,SNR,-12dB,Length,0,Packets,1126,Errors,1,IRQreg,70,IRQ\_HEADER\_VALID,IRQ\_CRC\_ERROR,IRQ\_RX\_DONE
|
||||
|
||||
A summary of the packet reception is sent to the OLED display as well, useful for portable applications.
|
||||
|
||||
|
||||
#### 34\_ATmel\_Sleep\_with\_Watchdog\_Wakeup             (Hardware_Checks folder)
|
||||
|
||||
This program tests the sleep mode of an Atmel ATMega328P processor.
|
||||
|
||||
At power up the flashes an LED 4 times, then turns on the LED for 5 seconds. Then the processor is put to sleep for 8 seconds. On wakeup the LED flashes twice, then is on for 5 seconds and the board goes to sleep again. And the sequence repeats.
|
||||
|
||||
Sleep current for a 'bare bones' ATmega328 with a MCP1700 regulator @ 3.3V and using an external event such as a switch to wakeup from sleep should be around 2uA. Using the watchdog timer to wakeup raises the deep sleep current to circa 6.2uA.
|
||||
|
||||
#### 35\_Remote\_Control\_Servo\_Transmitter             (Remote Control folder)
|
||||
|
||||
This is a remote control transmitter that uses a LoRa link to transmit the positions from a simple joystick to a remote receiver. The receiver uses the sent joystick positions to adjust the positions of servos. The positions of the joysticks potentiometers on the transmitter are read with the analogueRead() function.
|
||||
|
||||
If the joystick has a switch, often made by pressing on the joystick, then this can be used to remote control an output on the receiver. The switch is read by an interrupt, the interrupt routine sets a flag byte which is read in loop().
|
||||
|
||||
The program is intended as a proof of concept demonstration of how to remote control servos, the program is not designed as a practical remote control device for RC model cars for instance.
|
||||
|
||||
It would be straight forward to make the transmitter program send packets continuously, but in most places in the world that would break a normal limitation of 10% duty cycle for unlicensed use. Therefore the program was designed to only transmit at a 10% duty cycle. Thus the fastest (lowest air time) packets are used, spreading factor 6 at a bandwidth of 500khz. This results in an air time for the 5 byte control packet of around 4mS, so there are around 25 sent per second.
|
||||
|
||||
To have the transmitter program print out the values read from the joystick, comment in the line;
|
||||
|
||||
//#define DEBUG
|
||||
|
||||
Which is just above the loop() function. With the DEBUG enabled the transmission rate, the rate at which the control packets are transmitted will be slowed down.
|
||||
|
||||
To reduce the risk of the receiver picking up LoRa packets from other sources, the packet sent contains a 'TXidentity' number, valid values are 0 - 255. The receiver must be set-up with the matching identity number or the received packets will be ignored.
|
||||
|
||||
The pin definitions, LoRa frequency and LoRa modem settings are in the Settings.h file. These settings are not necessarily optimised for long range.
|
||||
|
||||
|
||||
#### 36\_Remote\_Control\_Servo\_Receiver             (Remote Control folder)
|
||||
|
||||
This is a remote control receiver that uses a LoRa link to control the positions of servos sent from a remote transmitter.
|
||||
|
||||
If the transmitter joystick has a switch, often made by pressing on the joystick, then this can be used to remote control an output on the receiver.
|
||||
|
||||
The program is intended as a proof of concept demonstration of how to remote control servos, the program is not designed as a practical remote control device for RC model cars for instance.
|
||||
|
||||
It would be straight forward to make the transmitter program send packets continuously, but in most places in the world that would break a normal limitation of 10% duty cycle for unlicensed use. Therefore the program was designed to only transmit at a 10% duty cycle. Thus the fastest (lowest air time) packets are used, spreading factor 6 at a bandwidth of 500khz. This results in an air time for the 5 byte control packet of around 4mS, so there are around 25 sent per second.
|
||||
To have the receiver program print out the joystick values (0-255) read from the received packet, comment in the line;
|
||||
|
||||
//#define DEBUG
|
||||
|
||||
Which is just above the loop() function. With the DEBUG enabled then there is a possibility that some transmitted packets will be missed. With the DEBUG line enabled to servos should also sweep to and fro 3 times at program start-up.
|
||||
|
||||
To reduce the risk of the receiver picking up LoRa packets from other sources, the packet sent contains a 'TXidentity' number, valid values are 0 - 255. The receiver must be set-up with the matching RXIdentity number in Settings.h or the received packets will be ignored.
|
||||
|
||||
The pin definitions, LoRa frequency and LoRa modem settings are in the Settings.h file. These settings are not necessarily optimised for long range.
|
||||
|
||||
|
||||
#### 37\_Servo\_Sweep\_Tester             (Hardware_Checks folder)
|
||||
|
||||
This program sweeps two servos from one end of their travel to the other. Useful to check servos are connected correctly and working.
|
||||
|
||||
|
||||
#### 38\_lora\_Relay             (Tracker folder)
|
||||
|
||||
This program will receive a lora packet and relay (re-transmit) it. The receiving and transmitting can use different frequencies and lora settings. The receiving and transmitting settings are in the 'Settings.h' file. For an example of it's use see this report;
|
||||
|
||||
How to Search 500 Square Kilometres in 10 minutes.pdf in the libraries 'Test_Reports' folder.
|
||||
|
||||
|
||||
|
||||
#### 40\_LoRa\_Transmitter\_ImplicitPacket             (Implicit folder)
|
||||
|
||||
This is an example of the use of implicit or fixed length LoRa packets.
|
||||
Implicit packets have no header so both transmitter and receiver need to be programmed with the packet length in use. The use of spreading factor 6 requires implicit packets and together with a bandwidth of 500khz, leads to the shortest possible and lowest air time packets.
|
||||
|
||||
This example sends a buffer that is 23 characters long and that length must be defined in Settings.h as the constant 'PacketLength'.
|
||||
|
||||
A packet containing ASCII text is sent according to the frequency and LoRa settings specified in the 'Settings.h' file. The pins to access the lora device need to be defined in the 'Settings.h' file also.
|
||||
|
||||
The details of the packet sent and any errors are shown on the Serial Monitor, together with the transmit power used, the packet length and the CRC of the packet. The matching receive program, '41\_LoRa\_Receiver\_ImplicitPackets' can be used to check the packets are being sent correctly, the frequency and LoRa settings (in Settings.h) must be the same for the Transmit and Receive program.
|
||||
|
||||
Sample Serial Monitor output;
|
||||
|
||||
10dBm Packet> {packet contents*} BytesSent,23 CRC,DAAB TransmitTime,8mS PacketsSent,1
|
||||
|
||||
|
||||
#### 41\_LoRa\_Receiver\_ImplicitPacket             (Implicit folder)
|
||||
|
||||
This is an example of the use of implicit or fixed length LoRa packets. Implicit packets have no header so both transmitter and receiver need to be programmed with the packet length in use. The use of spreading factor 6 requires implicit packets and together with a bandwidth of 500khz, leads to the shortest possible and lowest air time packets. The program listens for incoming packets using the LoRa settings in the 'Settings.h'.
|
||||
|
||||
This example receives a buffer that is 19 characters long and that length must be defined in Settings.h as the constant 'PacketLength'.
|
||||
|
||||
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, the packet is assumed to be in ASCII printable text, if its not ASCII text characters from 0x20 to 0x7F, expect weird things to happen on the Serial Monitor. The LED will flash for each packet received and the buzzer will sound, if fitted.
|
||||
|
||||
Sample serial monitor output;
|
||||
|
||||
1109s {packet contents} CRC,3882,RSSI,-69dBm,SNR,10dB,Length,19,Packets,1026,Errors,0,IRQreg,50
|
||||
|
||||
If there is a packet error it might look like this, which is showing a CRC error,
|
||||
|
||||
1189s PacketError,RSSI,-111dBm,SNR,-12dB,Length,0,Packets,1126,Errors,1,IRQreg,70,IRQ\_HEADER\_VALID,IRQ\_CRC\_ERROR,IRQ\_RX\_DONE
|
||||
|
||||
|
||||
#### 42\_WiFi\_Scanner\_Display\_ESP32             (Hardware Checks\ESP32 folder)
|
||||
|
||||
When the ESP32 turns on the WiFi function, there is a short high current pulse that can cause the ESP32 brownout detect to operate.
|
||||
|
||||
This test program at startup flashes an LED, leaves it on and then starts the WiFi. If the Wifi initiates a brownout, you will see the LED flash again. The LED stays on when scanning, the program reports the networks found to the serial console and displays them on an attached SSD1306 OLED.
|
||||
|
||||
Thus if you see the LED continually doing short bursts of flashing the turn on off the WiFi is causing the ESP32 to reset. There will also be a message on the serial monitor that the brownout detector operated.
|
||||
|
||||
|
||||
#### 43\_SD\_Card\_Test\_ESP32             (Hardware Checks\ESP32 folder)
|
||||
|
||||
This test program has been written to check that a connected SD card adapter, Micro or standard, is functional. To use the program first copy the file (in this programs directory) called testfile.txt to the root directory of the SD card.
|
||||
|
||||
When the program runs it will attempt to open 'testfile.txt' and spool the contents to the Arduino IDE serial monitor. The testfile is part of the source code for the Apollo 11 Lunar Lander navigation and guidance computer. There are LED flashes at power up or reset, then at start of every loop of the test. The LED is on whilst the testfile is being read. If the LED flashes very rapidly then there is a problem accessing the SD card.
|
||||
|
||||
The program also has the option of using a logic pin to control the power to the lora and SD card devices, which can save power in sleep mode. If the hardware is fitted to your board these devices are powered on by setting the VCCPOWER pin low. If your board does not have this feature set VCCPOWER to -1.
|
||||
|
||||
#### 44\_SD\_Card\_Test\_With\_FS\_ESP322             (Hardware Checks\ESP32 folder)
|
||||
|
||||
This test program has been written to check that a connected SD card adapter, Micro or standard, is functional with the FS functions. To use the program first copy the file (in this programs directory) called testfile.txt to the root directory of the SD card.
|
||||
|
||||
When the program runs it will attempt to open 'testfile.txt' and spool the contents to the Arduino IDE serial monitor. The testfile is part of the source code for the Apollo 11 Lunar Lander navigation and guidance computer. There are LED flashes at power up or reset, then at start of every loop of the test. The LED is on whilst the testfile is being read. If the LED flashes very rapidly then there is a problem accessing the SD card.
|
||||
|
||||
The program also has the option of using a logic pin to control the power to the lora and SD card devices, which can save power in sleep mode. If the hardware is fitted to your board these devices are powered on by setting the VCCPOWER pin low. If your board does not have this feature set VCCPOWER to -1.
|
||||
|
||||
|
||||
#### 45\_Battery\_Voltage\_Read\_Test             (Hardware_Checks folder)
|
||||
|
||||
|
||||
This test program has been written to check that hardware for reading the battery voltage has been assembled correctly such that it is funtional. The value defined as 'ADMultiplier' in settings.h is used to adjust the value read from the 91K\11K resistor divider and convert into mV.
|
||||
|
||||
There is also an option of using a logic pin to turn the resistor divider used to read battery voltage on and off. This reduces current used in sleep mode. To use the feature set the define for pin BATVREADON in 'Settings.h' to the pin used. If not using the feature set the pin number to -1.
|
||||
|
||||
#### 47\_DeepSleep\_Timed\_Wakeup\_ESP32             (Hardware_Checks\ESP32 folder)
|
||||
|
||||
This program flashes a LED connected to the pin defined by LED1, and puts the ESP32 to deep_sleep for a period determined by the TIME_TO_SLEEP variable (in seconds).
|
||||
|
||||
The program also has the option of using a logic pin to control the power to the lora and SD card devices, which can save power in sleep mode. If the hardware is fitted to your board these devices are powered on by setting the VCCPOWER pin low. If your board does not have this feature set VCCPOWER to -1.
|
||||
|
||||
Current in deep_sleep for a bare bones ESP32 with regulator and no other devices was 27uA.
|
||||
|
||||
|
||||
#### 48\_DS18B20\_Test             (Hardware_Checks folder)
|
||||
|
||||
|
||||
The program reads a single DS18B20 temperature sensor and prints the result to the serial monitor.
|
||||
|
||||
The program also has the option of using a logic pin to control the power to the lora and SD card devices, which can save power in sleep mode. If the hardware is fitted to your board then these devices are assumed to be powered on by setting the VCCPOWER pin low. If your board does not have this feature set VCCPOWER to -1.
|
||||
|
||||
|
||||
|
||||
#### 50\_LightSleep\_Timed\_Wakeup\_ESP32             (ESP32 folder)
|
||||
|
||||
The program flashes a LED connected to the pin defined by LED1, and puts the ESP32 to light_sleep for a period determined by TIME_TO_SLEEP (in seconds).
|
||||
|
||||
The program also has the option of using a logic pin to control the power to the lora device, SD card and DS18B20 devices, which can save power in sleep mode. If the hardware is fitted to your board these devices are powered on by setting the VCCPOWER pin low. If your board does not have this feature set VCCPOWER to -1.
|
||||
|
||||
#### 51\_DeepSleep\_Switch\_Wakeup\_ESP32             (ESP32 folder)
|
||||
|
||||
The program flashes a LED connected to the pin defined by LED1, and puts the ESP32 to deep_sleep. Pressing BOOT switch should wake up the ESP32 from sleep.
|
||||
|
||||
Only the specific RTC IO pins can be used as a source for external wakeup.
|
||||
These are pins: 0,2,4,12-15,25-27,32-39.
|
||||
|
||||
Current in deep sleep for a bare bones ESP32 with regulator and no other devices was 27uA.
|
||||
|
||||
#### 52\_FLRC\_Transmitter             (SX128X\Examples\Basics folder)
|
||||
|
||||
This is a test transmitter for the Fast Long Range Communication (FLRC) mode introduced in the SX128X devices. A packet containing ASCII text is sent according to the frequency and FLRC settings specified in the 'Settings.h' file. The pins to access the SX128X device need to be defined
|
||||
in the 'Settings.h' file also.
|
||||
|
||||
The details of the packet sent and any errors are shown on the Serial Monitor, together with the transmit power used, the packet length and the CRC of the packet. The matching receive program, '53_FLRC_Receiver' can be used to check the packets are being sent correctly, the frequency and FLRC settings (in Settings.h) must be the same for the Transmit and Receive program. Sample Serial Monitor output;
|
||||
|
||||
10dBm Packet> {packet contents*} BytesSent,23 CRC,DAAB TransmitTime,54mS PacketsSent,1
|
||||
|
||||
|
||||
#### 53\_FLRC\_Receiver             (SX128X_Examples\Basics folder)
|
||||
|
||||
This is a test receiver for the Fast Long Range Communication (FLRC) mode introduced in the SX128X devices. The program listens for incoming packets using the FLRC settings in the 'Settings.h' file. The pins to access the SX128X device need to be defined in the 'Settings.h' file also.
|
||||
|
||||
There is a printout of the valid packets received, the packet is assumed to be in ASCII printable text, if its not ASCII text characters from 0x20 to 0x7F, expect weird things to happen on the Serial Monitor. The LED will flash for each packet received and the buzzer will sound, if fitted.
|
||||
|
||||
Sample serial monitor output;
|
||||
|
||||
3s Hello World 1234567890*,CRC,DAAB,RSSI,-73dB,Length,23,Packets,1,Errors,0,IRQreg,6
|
||||
|
||||
If there is a packet error it might look like this, which is showing a CRC error,
|
||||
|
||||
6s PacketError,RSSI,-103dB,Length,119,Packets,3,Errors,1,IRQreg,46,IRQ\_RX\_DONE,IRQ\_SYNCWORD\_VALID,IRQ\_CRC\_ERROR
|
||||
|
||||
|
||||
#### 58\_FM\_Tone             (Basics folder)
|
||||
|
||||
Transmits a FM tone using the LoRa device that can be picked up on an FM UHF handheld receiver. The tones are not true FM but the UHF receiver does not know that.
|
||||
|
||||
|
||||
#### 59\_Play\_Star\_Wars\_Tune             (Silly folder)
|
||||
|
||||
A silly program really, but does demonstrate that you can shift a carrier generated by the LoRa device in FSK mode fast enough to play audio tones that can be picked up on an FM UHF handheld receiver. The tones are not true FM but the receiver does not know that.
|
||||
|
||||
|
||||
#### 60\_LoRa\_Packet\_Logger\_Receiver\_SD             (Diagnostics and Test folder)
|
||||
|
||||
|
||||
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 and save to SD card 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 and the buzzer will sound, if fitted. The measured frequency difference between the frequency used by the transmitter and the frequency used by the receiver is shown. If this frequency difference gets to 25% of the set LoRa bandwidth, packet reception will fail. The displayed error can be reduced by using the 'offset' setting in the 'Settings.h' file.
|
||||
|
||||
There will be a limit to how fast the logger can receive packets, mainly caused by the delay in writing to SD card, so at high packet rates, packets will be lost.
|
||||
|
||||
|
||||
|
||||
#### 103\_LoRa\_Transmitter\_Detailed\_Setup             (Basics folder)
|
||||
|
||||
This is a program that demonstrates the detailed setup of a LoRa test transmitter. A packet containing ASCII text is sent according to the frequency and LoRa settings specified in the Settings.h' file. The pins to access the lora device need to be defined in the 'Settings.h' file also.
|
||||
|
||||
The details of the packet sent and any errors are shown on the Arduino IDE Serial Monitor, together with the transmit power used, the packet length and the CRC of the packet. The matching receive program, '104\_LoRa\_Receiver' can be used to check the packets are being sent correctly, the frequency and LoRa settings (in Settings.h) must be the same for the transmitter and receiver programs. Sample Serial Monitor output;
|
||||
|
||||
10dBm Packet> Hello World 1234567890* BytesSent,23 CRC,DAAB TransmitTime,64mS PacketsSent,2
|
||||
|
||||
Serial monitor baud rate is set at 9600
|
||||
|
||||
#### 104\_LoRa\_Receiver\_Detailed\_Setup             (Basics folder)
|
||||
|
||||
This is a program that demonstrates the detailed setup of a LoRa test receiver. 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 on the Arduino IDE Serial Monitor of the valid packets received, the packet is assumed to be in ASCII printable text, if it's not ASCII text characters from 0x20 to 0x7F, expect weird things to happen on the Serial Monitor. The LED will flash for each packet received and the buzzer will sound, if fitted. Sample serial monitor output;
|
||||
|
||||
7s Hello World 1234567890*,CRC,DAAB,RSSI,-52dBm,SNR,9dB,Length,23,Packets,5,Errors,0,IRQreg,50
|
||||
|
||||
If there is a packet error it might look like this, which is showing a CRC error,
|
||||
|
||||
968s PacketError,RSSI,-87dBm,SNR,-11dB,Length,23,Packets,613,Errors,2,IRQreg,70,IRQ\_HEADER\_VALID,IRQ\_CRC\_ERROR,IRQ\_RX\_DONE
|
||||
|
||||
Serial monitor baud rate is set at 9600.
|
||||
|
||||
@ -0,0 +1,175 @@
|
||||
/*******************************************************************************************************
|
||||
Programs for Arduino - Copyright of the author Stuart Robinson - 19/03/20
|
||||
|
||||
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 demonstrates the detailed setup of a LoRa test transmitter.
|
||||
A packet containing ASCII text is sent according to the frequency and LoRa settings specified in the
|
||||
'Settings.h' file. The pins to access the lora device need to be defined in the 'Settings.h' file also.
|
||||
|
||||
The details of the packet sent and any errors are shown on the Arduino IDE Serial Monitor, together with
|
||||
the transmit power used, the packet length and the CRC of the packet. The matching receive program,
|
||||
'104_LoRa_Receiver' can be used to check the packets are being sent correctly, the frequency and LoRa
|
||||
settings (in Settings.h) must be the same for the transmitter and receiver programs. Sample Serial
|
||||
Monitor output;
|
||||
|
||||
10dBm Packet> Hello World 1234567890* BytesSent,23 CRC,DAAB TransmitTime,64mS PacketsSent,2
|
||||
|
||||
Serial monitor baud rate is set at 9600
|
||||
*******************************************************************************************************/
|
||||
|
||||
#include <SPI.h> //the lora device is SPI based so load the SPI library
|
||||
#include <SX128XLT.h> //include the appropriate library
|
||||
#include "Settings.h" //include the setiings file, frequencies, LoRa settings etc
|
||||
|
||||
SX128XLT LT; //create a library class instance called LT
|
||||
|
||||
uint8_t TXPacketL;
|
||||
uint32_t TXPacketCount, startmS, endmS;
|
||||
|
||||
uint8_t buff[] = "Hello World 1234567890";
|
||||
|
||||
void loop()
|
||||
{
|
||||
Serial.print(TXpower); //print the transmit power defined
|
||||
Serial.print(F("dBm "));
|
||||
Serial.print(F("Packet> "));
|
||||
Serial.flush();
|
||||
|
||||
TXPacketL = sizeof(buff); //set TXPacketL to length of array
|
||||
buff[TXPacketL - 1] = '*'; //replace null character at buffer end so its visible on receiver
|
||||
|
||||
LT.printASCIIPacket(buff, TXPacketL); //print the buffer (the sent packet) as ASCII
|
||||
|
||||
digitalWrite(LED1, HIGH);
|
||||
startmS = millis(); //start transmit timer
|
||||
if (LT.transmit(buff, TXPacketL, 10000, TXpower, WAIT_TX)) //will return packet length sent if OK, otherwise 0 if transmit error
|
||||
{
|
||||
endmS = millis(); //packet sent, note end time
|
||||
TXPacketCount++;
|
||||
packet_is_OK();
|
||||
}
|
||||
else
|
||||
{
|
||||
packet_is_Error(); //transmit packet returned 0, there was an error
|
||||
}
|
||||
|
||||
digitalWrite(LED1, LOW);
|
||||
Serial.println();
|
||||
delay(packet_delay); //have a delay between packets
|
||||
}
|
||||
|
||||
|
||||
void packet_is_OK()
|
||||
{
|
||||
//if here packet has been sent OK
|
||||
uint16_t localCRC;
|
||||
|
||||
Serial.print(F(" BytesSent,"));
|
||||
Serial.print(TXPacketL); //print transmitted packet length
|
||||
localCRC = LT.CRCCCITT(buff, TXPacketL, 0xFFFF);
|
||||
Serial.print(F(" CRC,"));
|
||||
Serial.print(localCRC, HEX); //print CRC of transmitted packet
|
||||
Serial.print(F(" TransmitTime,"));
|
||||
Serial.print(endmS - startmS); //print transmit time of packet
|
||||
Serial.print(F("mS"));
|
||||
Serial.print(F(" PacketsSent,"));
|
||||
Serial.print(TXPacketCount); //print total of packets sent OK
|
||||
}
|
||||
|
||||
|
||||
void packet_is_Error()
|
||||
{
|
||||
//if here there was an error transmitting packet
|
||||
uint16_t IRQStatus;
|
||||
IRQStatus = LT.readIrqStatus(); //read the the interrupt register
|
||||
Serial.print(F(" SendError,"));
|
||||
Serial.print(F("Length,"));
|
||||
Serial.print(TXPacketL); //print transmitted packet length
|
||||
Serial.print(F(",IRQreg,"));
|
||||
Serial.print(IRQStatus, HEX); //print IRQ status
|
||||
LT.printIrqStatus(); //prints the text of which IRQs set
|
||||
}
|
||||
|
||||
|
||||
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(9600);
|
||||
Serial.println();
|
||||
Serial.println(F("103_LoRa_Transmitter_Detailed_Setup 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));
|
||||
|
||||
//setup hardware pins used by device, then check if device is found
|
||||
if (LT.begin(NSS, NRESET, RFBUSY, DIO1, DIO2, DIO3, RX_EN, TX_EN, LORA_DEVICE))
|
||||
{
|
||||
Serial.println(F("LoRa Device found"));
|
||||
led_Flash(2, 125); //two further quick LED flashes to indicate device found
|
||||
delay(1000);
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.println(F("No device responding"));
|
||||
while (1)
|
||||
{
|
||||
led_Flash(50, 50); //long fast speed LED flash indicates device error
|
||||
}
|
||||
}
|
||||
|
||||
//The function call list below shows the complete setup for the LoRa device using the information defined in the
|
||||
//Settings.h file.
|
||||
//The 'Setup LoRa device' list below can be replaced with a single function call;
|
||||
//LT.setupLoRa(Frequency, Offset, SpreadingFactor, Bandwidth, CodeRate);
|
||||
|
||||
//***************************************************************************************************
|
||||
//Setup LoRa device
|
||||
//***************************************************************************************************
|
||||
LT.setMode(MODE_STDBY_RC);
|
||||
LT.setRegulatorMode(USE_LDO);
|
||||
LT.setPacketType(PACKET_TYPE_LORA);
|
||||
LT.setRfFrequency(Frequency, Offset);
|
||||
LT.setBufferBaseAddress(0, 0);
|
||||
LT.setModulationParams(SpreadingFactor, Bandwidth, CodeRate);
|
||||
LT.setPacketParams(12, LORA_PACKET_VARIABLE_LENGTH, 255, LORA_CRC_ON, LORA_IQ_NORMAL, 0, 0);
|
||||
LT.setDioIrqParams(IRQ_RADIO_ALL, (IRQ_TX_DONE + IRQ_RX_TX_TIMEOUT), 0, 0);
|
||||
LT.setHighSensitivity();
|
||||
//***************************************************************************************************
|
||||
|
||||
|
||||
Serial.println();
|
||||
LT.printModemSettings(); //reads and prints the configured LoRa settings, useful check
|
||||
Serial.println();
|
||||
LT.printOperatingSettings(); //reads and prints the configured operating settings, useful check
|
||||
Serial.println();
|
||||
Serial.println();
|
||||
LT.printRegisters(0x900, 0x9FF); //print contents of device registers, normally 0x900 to 0x9FF
|
||||
Serial.println();
|
||||
Serial.println();
|
||||
|
||||
Serial.print(F("Transmitter ready"));
|
||||
Serial.println();
|
||||
}
|
||||
@ -0,0 +1,42 @@
|
||||
/*******************************************************************************************************
|
||||
Programs for Arduino - Copyright of the author Stuart Robinson - 02/03/20
|
||||
|
||||
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. Some pins such as DIO2,
|
||||
//DIO3, BUZZER are not used by this sketch so they do not need to be connected and
|
||||
//should be set to -1.
|
||||
|
||||
#define NSS 10
|
||||
#define RFBUSY 7
|
||||
#define NRESET 9
|
||||
#define LED1 8
|
||||
#define DIO1 3
|
||||
#define DIO2 -1 //not used
|
||||
#define DIO3 -1 //not used
|
||||
#define RX_EN -1 //pin for RX enable, used on some SX1280 devices, set to -1 if not used
|
||||
#define TX_EN -1 //pin for TX enable, used on some SX1280 devices, set to -1 if not used
|
||||
|
||||
#define BUZZER -1 //connect a buzzer here if wanted
|
||||
|
||||
#define LORA_DEVICE DEVICE_SX1280 //we need to define the device we are using
|
||||
|
||||
|
||||
//******* Setup LoRa Parameters Here ! ***************
|
||||
|
||||
//LoRa Modem Parameters
|
||||
#define Frequency 2445000000 //frequency of transmissions
|
||||
#define Offset 0 //offset frequency for calibration purposes
|
||||
#define Bandwidth LORA_BW_0400 //LoRa bandwidth
|
||||
#define SpreadingFactor LORA_SF7 //LoRa spreading factor
|
||||
#define CodeRate LORA_CR_4_5 //LoRa coding rate
|
||||
|
||||
const int8_t TXpower = 10; //LoRa transmit power in dBm
|
||||
|
||||
const uint16_t packet_delay = 1000; //mS delay between packets
|
||||
|
||||
@ -0,0 +1,240 @@
|
||||
/*******************************************************************************************************
|
||||
Programs for Arduino - Copyright of the author Stuart Robinson - 19/03/20
|
||||
|
||||
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 demonstrates the detailed setup of a LoRa test receiver.
|
||||
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 on the Arduino IDE Serial Monitor of the valid packets received, the packet is
|
||||
assumed to be in ASCII printable text, if it's not ASCII text characters from 0x20 to 0x7F, expect
|
||||
weird things to happen on the Serial Monitor. The LED will flash for each packet received and the
|
||||
buzzer will sound, if fitted.
|
||||
|
||||
Sample serial monitor output;
|
||||
|
||||
7s Hello World 1234567890*,CRC,DAAB,RSSI,-52dBm,SNR,9dB,Length,23,Packets,5,Errors,0,IRQreg,50
|
||||
|
||||
If there is a packet error it might look like this, which is showing a CRC error,
|
||||
|
||||
968s PacketError,RSSI,-87dBm,SNR,-11dB,Length,23,Packets,613,Errors,2,IRQreg,70,IRQ_HEADER_VALID,IRQ_CRC_ERROR,IRQ_RX_DONE
|
||||
|
||||
Serial monitor baud rate is set at 9600.
|
||||
*******************************************************************************************************/
|
||||
|
||||
#include <SPI.h> //the lora device is SPI based so load the SPI library
|
||||
#include <SX128XLT.h> //include the appropriate library
|
||||
#include "Settings.h" //include the setiings file, frequencies, LoRa settings etc
|
||||
|
||||
SX128XLT LT; //create a library class instance called LT
|
||||
|
||||
uint32_t RXpacketCount;
|
||||
uint32_t errors;
|
||||
|
||||
uint8_t RXBUFFER[RXBUFFER_SIZE]; //create the buffer that received packets are copied into
|
||||
|
||||
uint8_t RXPacketL; //stores length of packet received
|
||||
int16_t PacketRSSI; //stores RSSI of received packet
|
||||
int8_t PacketSNR; //stores signal to noise ratio (SNR) of received packet
|
||||
|
||||
|
||||
void loop()
|
||||
{
|
||||
RXPacketL = LT.receive(RXBUFFER, RXBUFFER_SIZE, 60000, WAIT_RX); //wait for a packet to arrive with 60seconds (60000mS) timeout
|
||||
|
||||
digitalWrite(LED1, HIGH); //something has happened
|
||||
|
||||
if (BUZZER > 0) //turn buzzer on
|
||||
{
|
||||
digitalWrite(BUZZER, HIGH);
|
||||
}
|
||||
|
||||
PacketRSSI = LT.readPacketRSSI(); //read the recived RSSI value
|
||||
PacketSNR = LT.readPacketSNR(); //read the received SNR value
|
||||
|
||||
if (RXPacketL == 0) //if the LT.receive() function detects an error, RXpacketL is 0
|
||||
{
|
||||
packet_is_Error();
|
||||
}
|
||||
else
|
||||
{
|
||||
packet_is_OK();
|
||||
}
|
||||
|
||||
if (BUZZER > 0)
|
||||
{
|
||||
digitalWrite(BUZZER, LOW); //buzzer off
|
||||
}
|
||||
|
||||
digitalWrite(LED1, LOW); //LED off
|
||||
|
||||
Serial.println();
|
||||
}
|
||||
|
||||
|
||||
void packet_is_OK()
|
||||
{
|
||||
uint16_t IRQStatus, localCRC;
|
||||
|
||||
IRQStatus = LT.readIrqStatus(); //read the LoRa device IRQ status register
|
||||
|
||||
RXpacketCount++;
|
||||
|
||||
printElapsedTime(); //print elapsed time to Serial Monitor
|
||||
Serial.print(F(" "));
|
||||
LT.printASCIIPacket(RXBUFFER, RXPacketL); //print the packet as ASCII characters
|
||||
|
||||
localCRC = LT.CRCCCITT(RXBUFFER, RXPacketL, 0xFFFF); //calculate the CRC, this is the external CRC calculation of the RXBUFFER
|
||||
Serial.print(F(",CRC,")); //contents, not the LoRa device internal CRC
|
||||
Serial.print(localCRC, HEX);
|
||||
Serial.print(F(",RSSI,"));
|
||||
Serial.print(PacketRSSI);
|
||||
Serial.print(F("dBm,SNR,"));
|
||||
Serial.print(PacketSNR);
|
||||
Serial.print(F("dB,Length,"));
|
||||
Serial.print(RXPacketL);
|
||||
Serial.print(F(",Packets,"));
|
||||
Serial.print(RXpacketCount);
|
||||
Serial.print(F(",Errors,"));
|
||||
Serial.print(errors);
|
||||
Serial.print(F(",IRQreg,"));
|
||||
Serial.print(IRQStatus, HEX);
|
||||
}
|
||||
|
||||
|
||||
void packet_is_Error()
|
||||
{
|
||||
uint16_t IRQStatus;
|
||||
IRQStatus = LT.readIrqStatus(); //read the LoRa device IRQ status register
|
||||
|
||||
printElapsedTime(); //print elapsed time to Serial Monitor
|
||||
|
||||
if (IRQStatus & IRQ_RX_TIMEOUT) //check for an RX timeout
|
||||
{
|
||||
Serial.print(F(" RXTimeout"));
|
||||
}
|
||||
else
|
||||
{
|
||||
errors++;
|
||||
Serial.print(F(" PacketError"));
|
||||
Serial.print(F(",RSSI,"));
|
||||
Serial.print(PacketRSSI);
|
||||
Serial.print(F("dBm,SNR,"));
|
||||
Serial.print(PacketSNR);
|
||||
Serial.print(F("dB,Length,"));
|
||||
Serial.print(LT.readRXPacketL()); //get the device packet length
|
||||
Serial.print(F(",Packets,"));
|
||||
Serial.print(RXpacketCount);
|
||||
Serial.print(F(",Errors,"));
|
||||
Serial.print(errors);
|
||||
Serial.print(F(",IRQreg,"));
|
||||
Serial.print(IRQStatus, HEX);
|
||||
LT.printIrqStatus(); //print the names of the IRQ registers set
|
||||
}
|
||||
|
||||
delay(250); //gives a longer buzzer and LED flash for error
|
||||
|
||||
}
|
||||
|
||||
|
||||
void printElapsedTime()
|
||||
{
|
||||
float seconds;
|
||||
seconds = millis() / 1000;
|
||||
Serial.print(seconds, 0);
|
||||
Serial.print(F("s"));
|
||||
}
|
||||
|
||||
|
||||
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(9600);
|
||||
Serial.println();
|
||||
Serial.println(F("104_LoRa_Receiver_Detailed_Setup Starting"));
|
||||
Serial.println();
|
||||
|
||||
if (BUZZER > 0)
|
||||
{
|
||||
pinMode(BUZZER, OUTPUT);
|
||||
digitalWrite(BUZZER, HIGH);
|
||||
delay(50);
|
||||
digitalWrite(BUZZER, LOW);
|
||||
}
|
||||
|
||||
SPI.begin();
|
||||
|
||||
//SPI beginTranscation is normally part of library routines, but if it is disabled in the library
|
||||
//a single instance is needed here, so uncomment the program line below
|
||||
//SPI.beginTransaction(SPISettings(8000000, MSBFIRST, SPI_MODE0));
|
||||
|
||||
//setup hardware pins used by device, then check if device is found
|
||||
if (LT.begin(NSS, NRESET, RFBUSY, DIO1, DIO2, DIO3, RX_EN, TX_EN, LORA_DEVICE))
|
||||
{
|
||||
Serial.println(F("LoRa Device found"));
|
||||
led_Flash(2, 125);
|
||||
delay(1000);
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.println(F("No device responding"));
|
||||
while (1)
|
||||
{
|
||||
led_Flash(50, 50); //long fast speed LED flash indicates device error
|
||||
}
|
||||
}
|
||||
|
||||
//The function call list below shows the complete setup for the LoRa device using the information defined in the
|
||||
//Settings.h file.
|
||||
//The 'Setup LoRa device' list below can be replaced with a single function call;
|
||||
//LT.setupLoRa(Frequency, Offset, SpreadingFactor, Bandwidth, CodeRate);
|
||||
|
||||
//***************************************************************************************************
|
||||
//Setup LoRa device
|
||||
//***************************************************************************************************
|
||||
LT.setMode(MODE_STDBY_RC);
|
||||
LT.setRegulatorMode(USE_LDO);
|
||||
LT.setPacketType(PACKET_TYPE_LORA);
|
||||
LT.setRfFrequency(Frequency, Offset);
|
||||
LT.setBufferBaseAddress(0, 0);
|
||||
LT.setModulationParams(SpreadingFactor, Bandwidth, CodeRate);
|
||||
LT.setPacketParams(12, LORA_PACKET_VARIABLE_LENGTH, 255, LORA_CRC_ON, LORA_IQ_NORMAL, 0, 0);
|
||||
LT.setDioIrqParams(IRQ_RADIO_ALL, (IRQ_TX_DONE + IRQ_RX_TX_TIMEOUT), 0, 0);
|
||||
LT.setHighSensitivity();
|
||||
//***************************************************************************************************
|
||||
|
||||
|
||||
Serial.println();
|
||||
LT.printModemSettings(); //reads and prints the configured LoRa settings, useful check
|
||||
Serial.println();
|
||||
LT.printOperatingSettings(); //reads and prints the configured operting settings, useful check
|
||||
Serial.println();
|
||||
Serial.println();
|
||||
LT.printRegisters(0x900, 0x9FF); //print contents of device registers, normally 0x900 to 0x9FF
|
||||
Serial.println();
|
||||
Serial.println();
|
||||
|
||||
Serial.print(F("Receiver ready - RXBUFFER_SIZE "));
|
||||
Serial.println(RXBUFFER_SIZE);
|
||||
Serial.println();
|
||||
}
|
||||
@ -0,0 +1,44 @@
|
||||
/*******************************************************************************************************
|
||||
Programs for Arduino - Copyright of the author Stuart Robinson - 19/03/20
|
||||
|
||||
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. Some pins such as DIO2,
|
||||
//DIO3, BUZZER are not used by this sketch so they do not need to be connected and
|
||||
//should be set to -1.
|
||||
|
||||
#define NSS 10 //select pin on LoRa device
|
||||
#define NRESET 9 //reset pin on LoRa device
|
||||
#define RFBUSY 7 //busy pin on LoRa device
|
||||
#define DIO1 3 //DIO1 pin on LoRa device, used for RX and TX done
|
||||
#define DIO2 -1 //DIO2 pin on LoRa device, normally not used so set to -1
|
||||
#define DIO3 -1 //DIO3 pin on LoRa device, normally not used so set to -1
|
||||
#define RX_EN -1 //pin for RX enable, used on some SX128X devices, set to -1 if not used
|
||||
#define TX_EN -1 //pin for TX enable, used on some SX128X devices, set to -1 if not used
|
||||
#define LED1 8 //on board LED, high for on
|
||||
#define BUZZER -1 //pin for buzzer, set to -1 if not used
|
||||
|
||||
#define LORA_DEVICE DEVICE_SX1280 //we need to define the device we are using
|
||||
|
||||
|
||||
|
||||
//******* Setup LoRa Parameters Here ! ***************
|
||||
|
||||
//LoRa Modem Parameters
|
||||
#define Frequency 2445000000 //frequency of transmissions
|
||||
#define Offset 0 //offset frequency for calibration purposes
|
||||
#define Bandwidth LORA_BW_0400 //LoRa bandwidth
|
||||
#define SpreadingFactor LORA_SF7 //LoRa spreading factor
|
||||
#define CodeRate LORA_CR_4_5 //LoRa coding rate
|
||||
|
||||
const uint16_t packet_delay = 1000; //mS delay between packets
|
||||
|
||||
#define RXBUFFER_SIZE 32 //RX buffer size
|
||||
|
||||
|
||||
|
||||
@ -0,0 +1,144 @@
|
||||
/*******************************************************************************************************
|
||||
Programs for Arduino - Copyright of the author Stuart Robinson - 08/02/20
|
||||
|
||||
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 program demonstrates the transmitting of a structure as a LoRa packet. The
|
||||
contents of the structure are the same as in the '8_LoRa_LowMemory_TX' program. The packet sent is
|
||||
typical of what might be sent from a GPS tracker.
|
||||
|
||||
The structure type is defined as trackerPacket and an instance called location1 is created. The struture
|
||||
which includes a character array (text) is filled with values and transmitted.
|
||||
|
||||
The matching receiving program '15_LoRa_RX_Structure' can be used to receive and display the packet,
|
||||
though the program '9_LoRa_LowMemory_RX' should receive it as well, since the contents are the same.
|
||||
|
||||
Note that the structure definition and variable order (including the buffer size) used in the transmitter
|
||||
need to match those used in the receiver.
|
||||
|
||||
The contents of the packet transmitted should be;
|
||||
|
||||
"tracker1" (buffer) - trackerID
|
||||
1+ (uint32_t) - packet count
|
||||
51.23456 (float) - latitude
|
||||
-3.12345 (float) - longitude
|
||||
199 (uint16_t) - altitude
|
||||
8 (uint8_t) - number of satellites
|
||||
3999 (uint16_t) - battery voltage
|
||||
-9 (int8_t) - temperature
|
||||
|
||||
Good luck.
|
||||
|
||||
Serial monitor baud rate is set at 9600.
|
||||
|
||||
*******************************************************************************************************/
|
||||
|
||||
#include <SPI.h>
|
||||
#include <SX128XLT.h>
|
||||
#include "Settings.h"
|
||||
|
||||
SX128XLT LT;
|
||||
|
||||
uint32_t TXpacketCount = 1;
|
||||
uint32_t startmS, endmS;
|
||||
|
||||
struct trackerPacket
|
||||
{
|
||||
uint8_t trackerID[13];
|
||||
uint32_t txcount;
|
||||
float latitude;
|
||||
float longitude;
|
||||
uint16_t altitude;
|
||||
uint8_t satellites;
|
||||
uint16_t voltage;
|
||||
int8_t temperature;
|
||||
} __attribute__((packed, aligned(1))); //remove structure padding so there is compatibility between 8bit and 32bit Arduinos
|
||||
|
||||
struct trackerPacket location1; //define an instance called location1 of the structure trackerPacket
|
||||
|
||||
|
||||
void loop()
|
||||
{
|
||||
|
||||
//fill the defined structure with values
|
||||
uint8_t buff[] = "tracker1"; //create the contents to be of location1.trackerID
|
||||
memcpy (&location1.trackerID, &buff, sizeof(buff)); //copy the contents of buff[] into the structure
|
||||
location1.txcount = TXpacketCount;
|
||||
location1.latitude = 51.23456;
|
||||
location1.longitude = -3.12345;
|
||||
location1.altitude = 199;
|
||||
location1.satellites = 8;
|
||||
location1.voltage = 3999;
|
||||
location1.temperature = -9;
|
||||
|
||||
digitalWrite(LED1, HIGH);
|
||||
startmS = millis();
|
||||
|
||||
if (LT.transmit((uint8_t *) &location1, sizeof(location1), 0, TXpower, WAIT_TX)) //will return packet length sent if OK, otherwise 0
|
||||
{
|
||||
endmS = millis();
|
||||
digitalWrite(LED1, LOW);
|
||||
TXpacketCount++;
|
||||
Serial.print(TXpacketCount);
|
||||
Serial.print(F(" "));
|
||||
Serial.print(sizeof(location1));
|
||||
Serial.print(F(" Bytes Sent"));
|
||||
Serial.print(F(" "));
|
||||
Serial.print(endmS - startmS);
|
||||
Serial.print(F("mS"));
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.print(F("Send Error - IRQreg,"));
|
||||
Serial.print(LT.readIrqStatus(), HEX);
|
||||
}
|
||||
|
||||
digitalWrite(LED1, LOW);
|
||||
Serial.println();
|
||||
delay(packet_delay);
|
||||
}
|
||||
|
||||
|
||||
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(9600);
|
||||
|
||||
SPI.begin();
|
||||
|
||||
if (LT.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
|
||||
}
|
||||
}
|
||||
|
||||
LT.setupLoRa(Frequency, Offset, SpreadingFactor, Bandwidth, CodeRate);
|
||||
|
||||
Serial.println(F("Transmitter ready"));
|
||||
Serial.println();
|
||||
}
|
||||
@ -0,0 +1,30 @@
|
||||
/*******************************************************************************************************
|
||||
Programs for Arduino - Copyright of the author Stuart Robinson - 08/02/20
|
||||
|
||||
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
|
||||
#define RFBUSY 7
|
||||
#define NRESET 9
|
||||
#define LED1 8
|
||||
#define DIO1 3
|
||||
|
||||
#define LORA_DEVICE DEVICE_SX1280 //we need to define the device we are using
|
||||
|
||||
//LoRa Modem Parameters
|
||||
#define Frequency 2445000000 //frequency of transmissions
|
||||
#define Offset 0 //offset frequency for calibration purposes
|
||||
#define Bandwidth LORA_BW_0400 //LoRa bandwidth
|
||||
#define SpreadingFactor LORA_SF7 //LoRa spreading factor
|
||||
#define CodeRate LORA_CR_4_5 //LoRa coding rate
|
||||
|
||||
#define TXpower 10 //power for transmissions in dBm
|
||||
|
||||
#define packet_delay 1000 //mS delay between packets
|
||||
@ -0,0 +1,193 @@
|
||||
/*******************************************************************************************************
|
||||
Programs for Arduino - Copyright of the author Stuart Robinson - 08/02/20
|
||||
|
||||
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 program demonstrates the receiving of a structure as a LoRa packet. The packet
|
||||
sent is typical of what might be sent from a GPS tracker.
|
||||
|
||||
The structure type is defined as trackerPacket and an instance called location1 is created. The structure
|
||||
includes a character array (text).
|
||||
|
||||
The matching receiving program is '15_LoRa_RX_Structure' can be used to receive and display the packet,
|
||||
though the program '9_LoRa_LowMemory_RX' should receive it as well, since the packet contents are the same.
|
||||
|
||||
Not that the structure definition and variable order (including the buffer size) used in the transmitter
|
||||
need to match those used in the receiver. Good luck.
|
||||
|
||||
The contents of the packet received, and printed to serial monitor, should be;
|
||||
|
||||
"tracker1" (buffer) - trackerID
|
||||
1+ (uint32_t) - packet count
|
||||
51.23456 (float) - latitude
|
||||
-3.12345 (float) - longitude
|
||||
199 (uint16_t) - altitude
|
||||
8 (uint8_t) - number of satellites
|
||||
3999 (uint16_t) - battery voltage
|
||||
-9 (int8_t) - temperature
|
||||
|
||||
Serial monitor baud rate is set at 9600.
|
||||
|
||||
*******************************************************************************************************/
|
||||
|
||||
#include <SPI.h>
|
||||
#include <SX128XLT.h>
|
||||
#include "Settings.h"
|
||||
|
||||
SX128XLT LT;
|
||||
|
||||
uint8_t RXPacketL; //stores length of packet received
|
||||
uint32_t RXpacketCount; //count of received packets
|
||||
int16_t PacketRSSI; //RSSI of received packet
|
||||
int8_t PacketSNR; //signal to noise ratio of received packet
|
||||
uint32_t errors; //count of packet errors
|
||||
|
||||
|
||||
struct trackerPacket
|
||||
{
|
||||
uint8_t trackerID[13];
|
||||
uint32_t txcount;
|
||||
float latitude;
|
||||
float longitude;
|
||||
uint16_t altitude;
|
||||
uint8_t satellites;
|
||||
uint16_t voltage;
|
||||
int8_t temperature;
|
||||
} __attribute__((packed, aligned(1))); //remove structure padding so there is compatibility between 8bit and 32bit Arduinos
|
||||
|
||||
struct trackerPacket location1; //define an instance called location1 of the structure trackerPacket
|
||||
|
||||
|
||||
void loop()
|
||||
{
|
||||
RXPacketL = LT.receive( (uint8_t *) &location1, sizeof(location1), 0, WAIT_RX); //wait for a packet to arrive with no timeout
|
||||
|
||||
digitalWrite(LED1, HIGH); //something has happened, what I wonder ?
|
||||
|
||||
PacketRSSI = LT.readPacketRSSI();
|
||||
PacketSNR = LT.readPacketSNR();
|
||||
|
||||
if (RXPacketL == 0)
|
||||
{
|
||||
packet_is_Error();
|
||||
}
|
||||
else
|
||||
{
|
||||
packet_is_OK();
|
||||
}
|
||||
|
||||
digitalWrite(LED1, LOW);
|
||||
Serial.println();
|
||||
}
|
||||
|
||||
|
||||
void printlocation1()
|
||||
{
|
||||
uint8_t buff[13]; //define a buffer to receive a copy from the structure
|
||||
memcpy (&buff, &location1.trackerID, sizeof(buff)); //copy the contents of buffer in struture to buff[]
|
||||
|
||||
//now print the contents of the structure
|
||||
Serial.print((char*) buff); //cast to a char type for printing
|
||||
Serial.print(F(","));
|
||||
Serial.print(location1.txcount);
|
||||
Serial.print(F(","));
|
||||
Serial.print(location1.latitude, 5);
|
||||
Serial.print(F(","));
|
||||
Serial.print(location1.longitude, 5);
|
||||
Serial.print(F(","));
|
||||
Serial.print(location1.altitude);
|
||||
Serial.print(F("m,"));
|
||||
Serial.print(location1.satellites);
|
||||
Serial.print(F("sats,"));
|
||||
Serial.print(location1.voltage);
|
||||
Serial.print(F("mV,"));
|
||||
Serial.print(location1.temperature);
|
||||
Serial.print(F("c "));
|
||||
}
|
||||
|
||||
|
||||
void packet_is_OK()
|
||||
{
|
||||
RXpacketCount++;
|
||||
Serial.print(RXpacketCount);
|
||||
Serial.print(F(" "));
|
||||
printlocation1();
|
||||
printpacketDetails();
|
||||
}
|
||||
|
||||
|
||||
void packet_is_Error()
|
||||
{
|
||||
uint16_t IRQStatus;
|
||||
IRQStatus = LT.readIrqStatus();
|
||||
|
||||
if (IRQStatus & IRQ_RX_TIMEOUT)
|
||||
{
|
||||
Serial.print(F("RXTimeout"));
|
||||
}
|
||||
else
|
||||
{
|
||||
errors++;
|
||||
Serial.print(F("PacketError"));
|
||||
printpacketDetails();
|
||||
Serial.print(F("IRQreg,"));
|
||||
Serial.print(IRQStatus, HEX);
|
||||
}
|
||||
}
|
||||
|
||||
void printpacketDetails()
|
||||
{
|
||||
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 setup(void)
|
||||
{
|
||||
pinMode(LED1, OUTPUT); //setup pin as output for indicator LED
|
||||
led_Flash(2, 125); //two quick LED flashes to indicate program start
|
||||
|
||||
Serial.begin(9600);
|
||||
|
||||
SPI.begin();
|
||||
|
||||
if (LT.begin(NSS, NRESET, RFBUSY, DIO1, LORA_DEVICE))
|
||||
{
|
||||
led_Flash(2, 125);
|
||||
delay(1000);
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.println(F("Device error"));
|
||||
while (1)
|
||||
{
|
||||
led_Flash(50, 50);
|
||||
}
|
||||
}
|
||||
|
||||
LT.setupLoRa(Frequency, Offset, SpreadingFactor, Bandwidth, CodeRate);
|
||||
|
||||
Serial.print(F("Receiver ready"));
|
||||
Serial.println();
|
||||
Serial.println();
|
||||
}
|
||||
@ -0,0 +1,30 @@
|
||||
/*******************************************************************************************************
|
||||
Programs for Arduino - Copyright of the author Stuart Robinson - 06/02/20
|
||||
|
||||
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
|
||||
#define RFBUSY 7
|
||||
#define NRESET 9
|
||||
#define LED1 8
|
||||
#define DIO1 3
|
||||
|
||||
#define LORA_DEVICE DEVICE_SX1280 //we need to define the device we are using
|
||||
|
||||
//LoRa Modem Parameters
|
||||
#define Frequency 2445000000 //frequency of transmissions
|
||||
#define Offset 0 //offset frequency for calibration purposes
|
||||
#define Bandwidth LORA_BW_0400 //LoRa bandwidth
|
||||
#define SpreadingFactor LORA_SF7 //LoRa spreading factor
|
||||
#define CodeRate LORA_CR_4_5 //LoRa coding rate
|
||||
|
||||
#define TXpower 10 //power for transmissions in dBm
|
||||
|
||||
#define packet_delay 1000 //mS delay between packets
|
||||
61
examples/SX128x_examples/Basics/1_LED_Blink/1_LED_Blink.ino
Normal file
61
examples/SX128x_examples/Basics/1_LED_Blink/1_LED_Blink.ino
Normal file
@ -0,0 +1,61 @@
|
||||
/*******************************************************************************************************
|
||||
Programs for Arduino - Copyright of the author Stuart Robinson - 06/02/20
|
||||
|
||||
This programs is supplied as is, it is up to the user of the program to decide if the programs are
|
||||
suitable for the intended purpose and free from errors.
|
||||
*******************************************************************************************************/
|
||||
|
||||
/*******************************************************************************************************
|
||||
Program Operation - This program blinks an LED connected the pin number defined below. The pin 13 LED,
|
||||
fitted to some Arduinos is blinked as well. The blinks should be close to one per second. messages are
|
||||
sent to the Serial Monitor also.
|
||||
|
||||
Serial monitor baud rate is set at 9600.
|
||||
*******************************************************************************************************/
|
||||
|
||||
#define LED1 8 //pin number for LED, set logic level high for on
|
||||
|
||||
uint16_t seconds; //used to display time elapsed on Serial Monitor
|
||||
|
||||
void loop()
|
||||
{
|
||||
Serial.print(seconds);
|
||||
Serial.println(F(" Seconds")); //this message should print on console at close to once per second
|
||||
seconds++;
|
||||
digitalWrite(LED1, HIGH);
|
||||
digitalWrite(13, HIGH);
|
||||
delay(100);
|
||||
digitalWrite(LED1, LOW);
|
||||
digitalWrite(13, LOW);
|
||||
delay(890); //should give approx 1 second flash
|
||||
}
|
||||
|
||||
|
||||
void led_Flash(uint16_t flashes, uint16_t delaymS)
|
||||
{
|
||||
//general purpose routine for flashing LED as indicator
|
||||
uint16_t index;
|
||||
|
||||
for (index = 1; index <= flashes; index++)
|
||||
{
|
||||
digitalWrite(LED1, HIGH); //LED on
|
||||
digitalWrite(13, HIGH); //Arduino board LED on
|
||||
delay(delaymS);
|
||||
digitalWrite(LED1, LOW); //LED off
|
||||
digitalWrite(13, LOW); //Arduino board LED off
|
||||
delay(delaymS);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void setup()
|
||||
{
|
||||
pinMode(LED1, OUTPUT); //setup pin as output for indicator LED
|
||||
pinMode(13, OUTPUT); //setup pin as output for some Arduino boards that include an LED on pin 13
|
||||
led_Flash(2, 125); //two quick LED flashes to indicate program start
|
||||
|
||||
Serial.begin(9600);
|
||||
Serial.println();
|
||||
|
||||
Serial.println(F("1_LED_Blink Starting"));
|
||||
}
|
||||
@ -0,0 +1,358 @@
|
||||
/*******************************************************************************************************
|
||||
Programs for Arduino - Copyright of the author Stuart Robinson - 11/02/20
|
||||
|
||||
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 program is stand alone, it is not necessary to install the SX12XX-LoRa library
|
||||
to use it. This test program is for the SX128X LoRa devices.
|
||||
|
||||
The program checks that a SX128X LoRa device can be accessed by doing a test register write and read.
|
||||
If there is no device found a message is printed on the serial monitor. The contents of the registers
|
||||
from 0x00 to 0x7F are printed, there is a copy of a typical printout below. Note that the read back
|
||||
changed frequency may be slightly different to the programmed frequency, there is a rounding error due
|
||||
to the use of floats to calculate the frequency.
|
||||
|
||||
The Arduino pin numbers that the NSS and NRESET pins on the LoRa device are connected to must be
|
||||
specified in the hardware definitions section below. The LoRa device type in use, SX1280 or SX1281
|
||||
must be specified also.
|
||||
|
||||
Typical printout;
|
||||
|
||||
2_Register_Test Starting
|
||||
Reset device
|
||||
LoRa Device found
|
||||
Reset device
|
||||
Registers at reset
|
||||
Reg 0 1 2 3 4 5 6 7 8 9 A B C D E F
|
||||
0x900 80 0C 7B 02 20 FA C0 00 00 80 00 00 00 00 00 FF
|
||||
0x910 FF FF 00 00 00 19 00 00 00 19 87 65 43 21 7F FF
|
||||
0x920 FF FF FF 0C 70 37 0A 50 D0 80 00 C0 5F D2 8F 0A
|
||||
0x930 00 C0 00 00 00 24 00 21 28 B0 30 09 1A 59 70 08
|
||||
0x940 58 0B 32 0A 14 24 6A 96 00 18 00 00 00 00 00 00
|
||||
0x950 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||
0x960 00 00 00 00 00 00 00 00 00 00 FF FF FF FF FF FF
|
||||
0x970 FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF 04
|
||||
0x980 00 0B 18 70 00 00 00 4C 00 F0 64 00 00 00 00 00
|
||||
0x990 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||
0x9A0 00 08 EC B8 9D 8A E6 66 06 00 00 00 00 00 00 00
|
||||
0x9B0 00 08 EC B8 9D 8A E6 66 06 00 00 00 00 00 00 00
|
||||
0x9C0 00 16 00 3F E8 01 FF FF FF FF 5E 4D 25 10 55 55
|
||||
0x9D0 55 55 55 55 55 55 55 55 55 55 55 55 55 00 00 00
|
||||
0x9E0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||
0x9F0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||
|
||||
Frequency at reset 2495996672hz
|
||||
Change Frequency to 2445000000hz
|
||||
Frequency now 2444999936hz
|
||||
|
||||
Reg 0 1 2 3 4 5 6 7 8 9 A B C D E F
|
||||
0x900 80 0C 7B 02 20 FA BC 13 C1 80 00 00 00 00 00 61
|
||||
|
||||
Serial monitor baud rate is set at 9600.
|
||||
*******************************************************************************************************/
|
||||
|
||||
const uint16_t REG_RFFrequency23_16 = 0x906;
|
||||
const uint16_t REG_RFFrequency15_8 = 0x907;
|
||||
const uint16_t REG_RFFrequency7_0 = 0x908;
|
||||
const uint8_t RADIO_WRITE_REGISTER = 0x18;
|
||||
const uint8_t RADIO_READ_REGISTER = 0x19;
|
||||
const uint8_t RADIO_SET_RFFREQUENCY = 0x86; //commnad to change frequency
|
||||
const uint8_t RADIO_SET_PACKETTYPE = 0x8A; //commnad to set packet mode
|
||||
const float FREQ_STEP = 198.364;
|
||||
const uint8_t PACKET_TYPE_LORA = 0x01;
|
||||
|
||||
//********* Setup hardware definitions here ! *****************
|
||||
|
||||
//These are the pin definitions for one of the Tracker boards, be sure to change them to match your
|
||||
//own setup. You will also need to connect up the pins for the SPI bus, which on an Arduino Pro Mini are
|
||||
//SCK pin 13, MISO pin 12, and MOSI pin 11.
|
||||
|
||||
#define NSS 10 //SX128X device select
|
||||
#define NRESET 9 //SX128X reset pin
|
||||
#define RFBUSY 7 //SX128X busy pin
|
||||
#define LED1 8 //for on board LED, put high for on
|
||||
|
||||
//**************************************************************/
|
||||
|
||||
#include <SPI.h>
|
||||
|
||||
uint8_t saveddevice;
|
||||
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(9600);
|
||||
Serial.println(F("2_Register_Test Starting"));
|
||||
|
||||
SPI.begin();
|
||||
SPI.beginTransaction(SPISettings(8000000, MSBFIRST, SPI_MODE0));
|
||||
|
||||
//The begin function setups the hardware pins used by device and then checks if device is found
|
||||
//the DIO1 pin is not used in this example
|
||||
|
||||
if (begin(NSS, NRESET, RFBUSY, 0))
|
||||
{
|
||||
Serial.println(F("Device found"));
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.println(F("No device responding"));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void loop()
|
||||
{
|
||||
uint32_t frequency;
|
||||
resetDevice(); //reset the device
|
||||
Serial.println(F("Registers at reset")); //show the all registers following a reset
|
||||
printRegisters(0x0900, 0x09FF);
|
||||
Serial.println();
|
||||
Serial.println();
|
||||
|
||||
frequency = getFreqInt(); //read the set frequency following a reset
|
||||
Serial.print(F(" Frequency at reset "));
|
||||
Serial.print(frequency);
|
||||
Serial.println(F("hz"));
|
||||
|
||||
Serial.print(F("Change Frequency to 2445000000hz"));
|
||||
setPacketType(PACKET_TYPE_LORA); //this is needed to ensure frequency change is reflected in register print
|
||||
setRfFrequency(2445000000, 0); //change the frequency to 2445000000hertz
|
||||
|
||||
frequency = getFreqInt(); //read back the changed frequency
|
||||
Serial.println();
|
||||
Serial.print(F(" Frequency now "));
|
||||
Serial.print(frequency); //print the changed frequency, did the write work (allow for rounding errors) ?
|
||||
Serial.println(F("hz"));
|
||||
Serial.println();
|
||||
printRegisters(0x0900, 0x090F); //show the registers after frequency change
|
||||
Serial.println();
|
||||
Serial.println();
|
||||
delay(5000);
|
||||
}
|
||||
|
||||
|
||||
void readRegisters(uint16_t address, uint8_t *buffer, uint16_t size)
|
||||
{
|
||||
uint16_t index;
|
||||
uint8_t addr_l, addr_h;
|
||||
|
||||
addr_h = address >> 8;
|
||||
addr_l = address & 0x00FF;
|
||||
checkBusy();
|
||||
|
||||
digitalWrite(NSS, LOW);
|
||||
SPI.transfer(RADIO_READ_REGISTER);
|
||||
SPI.transfer(addr_h); //MSB
|
||||
SPI.transfer(addr_l); //LSB
|
||||
SPI.transfer(0xFF);
|
||||
for (index = 0; index < size; index++)
|
||||
{
|
||||
*(buffer + index) = SPI.transfer(0xFF);
|
||||
}
|
||||
|
||||
digitalWrite(NSS, HIGH);
|
||||
checkBusy();
|
||||
}
|
||||
|
||||
|
||||
uint8_t readRegister(uint16_t address)
|
||||
{
|
||||
uint8_t data;
|
||||
|
||||
readRegisters(address, &data, 1);
|
||||
return data;
|
||||
}
|
||||
|
||||
|
||||
void writeRegisters(uint16_t address, uint8_t *buffer, uint16_t size)
|
||||
{
|
||||
uint8_t addr_l, addr_h;
|
||||
uint8_t i;
|
||||
|
||||
addr_l = address & 0xff;
|
||||
addr_h = address >> 8;
|
||||
checkBusy();
|
||||
|
||||
digitalWrite(NSS, LOW);
|
||||
SPI.transfer(RADIO_WRITE_REGISTER);
|
||||
SPI.transfer(addr_h); //MSB
|
||||
SPI.transfer(addr_l); //LSB
|
||||
|
||||
for (i = 0; i < size; i++)
|
||||
{
|
||||
SPI.transfer(buffer[i]);
|
||||
}
|
||||
|
||||
digitalWrite(NSS, HIGH);
|
||||
|
||||
checkBusy();
|
||||
}
|
||||
|
||||
|
||||
void writeRegister(uint16_t address, uint8_t value)
|
||||
{
|
||||
writeRegisters(address, &value, 1 );
|
||||
}
|
||||
|
||||
|
||||
uint32_t getFreqInt()
|
||||
{
|
||||
//get the current set device frequency, return as long integer
|
||||
uint8_t Msb, Mid, Lsb;
|
||||
uint32_t uinttemp;
|
||||
float floattemp;
|
||||
Msb = readRegister(REG_RFFrequency23_16);
|
||||
Mid = readRegister(REG_RFFrequency15_8);
|
||||
Lsb = readRegister(REG_RFFrequency7_0);
|
||||
floattemp = ((Msb * 0x10000ul) + (Mid * 0x100ul) + Lsb);
|
||||
floattemp = ((floattemp * FREQ_STEP) / 1000000ul);
|
||||
uinttemp = (uint32_t)(floattemp * 1000000);
|
||||
return uinttemp;
|
||||
}
|
||||
|
||||
|
||||
void printRegisters(uint16_t Start, uint16_t End)
|
||||
{
|
||||
//prints the contents of SX128x registers to serial monitor
|
||||
|
||||
uint16_t Loopv1, Loopv2, RegData;
|
||||
|
||||
Serial.print(F("Reg 0 1 2 3 4 5 6 7 8 9 A B C D E F"));
|
||||
Serial.println();
|
||||
|
||||
for (Loopv1 = Start; Loopv1 <= End;) //32 lines
|
||||
{
|
||||
Serial.print(F("0x"));
|
||||
Serial.print((Loopv1), HEX); //print the register number
|
||||
Serial.print(F(" "));
|
||||
for (Loopv2 = 0; Loopv2 <= 15; Loopv2++)
|
||||
{
|
||||
RegData = readRegister(Loopv1);
|
||||
if (RegData < 0x10)
|
||||
{
|
||||
Serial.print(F("0"));
|
||||
}
|
||||
Serial.print(RegData, HEX); //print the register number
|
||||
Serial.print(F(" "));
|
||||
Loopv1++;
|
||||
}
|
||||
Serial.println();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void setRfFrequency(uint32_t frequency, int32_t offset)
|
||||
{
|
||||
frequency = frequency + offset;
|
||||
uint8_t buffer[3];
|
||||
uint32_t freqtemp = 0;
|
||||
freqtemp = ( uint32_t )( (float) frequency / (float) FREQ_STEP);
|
||||
buffer[0] = ( uint8_t )( ( freqtemp >> 16 ) & 0xFF );
|
||||
buffer[1] = ( uint8_t )( ( freqtemp >> 8 ) & 0xFF );
|
||||
buffer[2] = ( uint8_t )( freqtemp & 0xFF );
|
||||
writeCommand(RADIO_SET_RFFREQUENCY, buffer, 3);
|
||||
writeCommand(RADIO_SET_RFFREQUENCY, buffer, 3);
|
||||
}
|
||||
|
||||
|
||||
void checkBusy()
|
||||
{
|
||||
uint8_t busy_timeout_cnt;
|
||||
busy_timeout_cnt = 0;
|
||||
|
||||
while (digitalRead(RFBUSY))
|
||||
{
|
||||
delay(1);
|
||||
busy_timeout_cnt++;
|
||||
|
||||
if (busy_timeout_cnt > 10) //wait 10mS for busy to complete
|
||||
{
|
||||
busy_timeout_cnt = 0;
|
||||
Serial.println(F("ERROR - Busy Timeout!"));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void resetDevice()
|
||||
{
|
||||
Serial.println(F("Reset device"));
|
||||
delay(10);
|
||||
digitalWrite(NRESET, LOW);
|
||||
delay(2);
|
||||
digitalWrite(NRESET, HIGH);
|
||||
delay(25);
|
||||
checkBusy();
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool begin(int8_t pinNSS, int8_t pinNRESET, int8_t pinRFBUSY, uint8_t device)
|
||||
{
|
||||
saveddevice = device;
|
||||
|
||||
pinMode(pinNSS, OUTPUT);
|
||||
digitalWrite(pinNSS, HIGH);
|
||||
pinMode(pinNRESET, OUTPUT);
|
||||
digitalWrite(pinNRESET, HIGH);
|
||||
pinMode(pinRFBUSY, INPUT);
|
||||
|
||||
resetDevice();
|
||||
|
||||
if (checkDevice())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool checkDevice()
|
||||
{
|
||||
//check there is a device out there, writes a register and reads back
|
||||
|
||||
uint8_t Regdata1, Regdata2;
|
||||
Regdata1 = readRegister(0x0908); //low byte of frequency setting
|
||||
writeRegister(0x0908, (Regdata1 + 1));
|
||||
Regdata2 = readRegister(0x0908); //read changed value back
|
||||
writeRegister(0x0908, Regdata1); //restore register to original value
|
||||
|
||||
if (Regdata2 == (Regdata1 + 1))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void writeCommand(uint8_t Opcode, uint8_t *buffer, uint16_t size)
|
||||
{
|
||||
uint8_t index;
|
||||
checkBusy();
|
||||
|
||||
digitalWrite(NSS, LOW);
|
||||
SPI.transfer(Opcode);
|
||||
|
||||
for (index = 0; index < size; index++)
|
||||
{
|
||||
SPI.transfer(buffer[index]);
|
||||
//Serial.println(buffer[index], HEX);
|
||||
}
|
||||
digitalWrite(NSS, HIGH);
|
||||
|
||||
checkBusy();
|
||||
}
|
||||
|
||||
void setPacketType(uint8_t packettype)
|
||||
{
|
||||
writeCommand(RADIO_SET_PACKETTYPE, &packettype, 1);
|
||||
}
|
||||
@ -0,0 +1,174 @@
|
||||
/*******************************************************************************************************
|
||||
Programs for Arduino - Copyright of the author Stuart Robinson - 06/02/20
|
||||
|
||||
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 simple LoRa test transmitter. A packet containing ASCII text is sent
|
||||
according to the frequency and LoRa settings specified in the 'Settings.h' file. The pins to access
|
||||
the lora device need to be defined in the 'Settings.h' file also.
|
||||
|
||||
The details of the packet sent and any errors are shown on the Serial Monitor, together with the transmit
|
||||
power used, the packet length and the CRC of the packet. The matching receive program, '4_LoRa_Receive'
|
||||
can be used to check the packets are being sent correctly, the frequency and LoRa settings (in Settings.h)
|
||||
must be the same for the Transmit and Receive program. Sample Serial Monitor output;
|
||||
|
||||
10dBm Packet> {packet contents*} BytesSent,23 CRC,DAAB TransmitTime,54mS PacketsSent,1
|
||||
|
||||
Serial monitor baud rate is set at 9600
|
||||
*******************************************************************************************************/
|
||||
|
||||
#include <SPI.h> //the SX128X device is SPI based so load the SPI library
|
||||
#include <SX128XLT.h> //include the appropriate library
|
||||
#include "Settings.h" //include the setiings file, frequencies, LoRa settings etc
|
||||
|
||||
SX128XLT LT; //create a library class instance called LT
|
||||
|
||||
uint8_t TXPacketL;
|
||||
uint32_t TXPacketCount, startmS, endmS;
|
||||
|
||||
uint8_t buff[] = "Hello World 1234567890";
|
||||
|
||||
void loop()
|
||||
{
|
||||
Serial.print(TXpower); //print the transmit power defined
|
||||
Serial.print(F("dBm "));
|
||||
Serial.print(F("Packet> "));
|
||||
Serial.flush();
|
||||
|
||||
TXPacketL = sizeof(buff); //set TXPacketL to length of array
|
||||
buff[TXPacketL - 1] = '*'; //replace null character at buffer end so its visible on reciver
|
||||
|
||||
LT.printASCIIPacket(buff, TXPacketL); //print the buffer (the sent packet) as ASCII
|
||||
|
||||
digitalWrite(LED1, HIGH);
|
||||
startmS = millis(); //start transmit timer
|
||||
if (LT.transmit(buff, TXPacketL, 10000, TXpower, WAIT_TX)) //will return packet length sent if OK, otherwise 0 if transmit, timeout 10 seconds
|
||||
{
|
||||
endmS = millis(); //packet sent, note end time
|
||||
TXPacketCount++;
|
||||
packet_is_OK();
|
||||
}
|
||||
else
|
||||
{
|
||||
packet_is_Error(); //transmit packet returned 0, there was an error
|
||||
}
|
||||
|
||||
digitalWrite(LED1, LOW);
|
||||
Serial.println();
|
||||
delay(packet_delay); //have a delay between packets
|
||||
}
|
||||
|
||||
|
||||
void packet_is_OK()
|
||||
{
|
||||
//if here packet has been sent OK
|
||||
uint16_t localCRC;
|
||||
|
||||
Serial.print(F(" BytesSent,"));
|
||||
Serial.print(TXPacketL); //print transmitted packet length
|
||||
localCRC = LT.CRCCCITT(buff, TXPacketL, 0xFFFF);
|
||||
Serial.print(F(" CRC,"));
|
||||
Serial.print(localCRC, HEX); //print CRC of sent packet
|
||||
Serial.print(F(" TransmitTime,"));
|
||||
Serial.print(endmS - startmS); //print transmit time of packet
|
||||
Serial.print(F("mS"));
|
||||
Serial.print(F(" PacketsSent,"));
|
||||
Serial.print(TXPacketCount); //print total of packets sent OK
|
||||
}
|
||||
|
||||
|
||||
void packet_is_Error()
|
||||
{
|
||||
//if here there was an error transmitting packet
|
||||
uint16_t IRQStatus;
|
||||
IRQStatus = LT.readIrqStatus(); //read the the interrupt register
|
||||
Serial.print(F(" SendError,"));
|
||||
Serial.print(F("Length,"));
|
||||
Serial.print(TXPacketL); //print transmitted packet length
|
||||
Serial.print(F(",IRQreg,"));
|
||||
Serial.print(IRQStatus, HEX); //print IRQ status
|
||||
LT.printIrqStatus(); //prints the text of which IRQs set
|
||||
}
|
||||
|
||||
|
||||
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(9600);
|
||||
Serial.println();
|
||||
Serial.println(F("3_LoRa_Transmitter 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));
|
||||
|
||||
//setup hardware pins used by device, then check if device is found
|
||||
|
||||
if (LT.begin(NSS, NRESET, RFBUSY, DIO1, RX_EN, TX_EN, LORA_DEVICE))
|
||||
{
|
||||
Serial.println(F("LoRa Device found"));
|
||||
led_Flash(2, 125); //two further quick LED flashes to indicate device found
|
||||
delay(1000);
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.println(F("No device responding"));
|
||||
while (1)
|
||||
{
|
||||
led_Flash(50, 50); //long fast speed LED flash indicates device error
|
||||
}
|
||||
}
|
||||
|
||||
//The function call list below shows the complete setup for the LoRa device using the information defined in the
|
||||
//Settings.h file.
|
||||
//The 'Setup LoRa device' list below can be replaced with a single function call;
|
||||
//LT.setupLoRa(Frequency, Offset, SpreadingFactor, Bandwidth, CodeRate);
|
||||
|
||||
//***************************************************************************************************
|
||||
//Setup LoRa device
|
||||
//***************************************************************************************************
|
||||
LT.setMode(MODE_STDBY_RC);
|
||||
LT.setRegulatorMode(USE_LDO);
|
||||
LT.setPacketType(PACKET_TYPE_LORA);
|
||||
LT.setRfFrequency(Frequency, Offset);
|
||||
LT.setBufferBaseAddress(0, 0);
|
||||
LT.setModulationParams(SpreadingFactor, Bandwidth, CodeRate);
|
||||
LT.setPacketParams(12, LORA_PACKET_VARIABLE_LENGTH, 255, LORA_CRC_ON, LORA_IQ_NORMAL, 0, 0);
|
||||
LT.setDioIrqParams(IRQ_RADIO_ALL, (IRQ_TX_DONE + IRQ_RX_TX_TIMEOUT), 0, 0);
|
||||
LT.setHighSensitivity();
|
||||
//***************************************************************************************************
|
||||
|
||||
Serial.println();
|
||||
LT.printModemSettings(); //reads and prints the configured LoRa settings, useful check
|
||||
Serial.println();
|
||||
LT.printOperatingSettings(); //reads and prints the configured operating settings, useful check
|
||||
Serial.println();
|
||||
Serial.println();
|
||||
LT.printRegisters(0x900, 0x9FF); //print contents of device registers
|
||||
Serial.println();
|
||||
Serial.println();
|
||||
|
||||
Serial.print(F("Transmitter ready"));
|
||||
Serial.println();
|
||||
}
|
||||
@ -0,0 +1,34 @@
|
||||
/*******************************************************************************************************
|
||||
Programs for Arduino - Copyright of the author Stuart Robinson - 06/02/20
|
||||
|
||||
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
|
||||
#define RFBUSY 7
|
||||
#define NRESET 9
|
||||
#define LED1 8
|
||||
#define DIO1 3
|
||||
#define RX_EN -1 //pin for RX enable, used on some SX1280 devices, set to -1 if not used
|
||||
#define TX_EN -1 //pin for TX enable, used on some SX1280 devices, set to -1 if not used
|
||||
#define BUZZER -1 //pin for BUZZER, set to -1 if not used
|
||||
|
||||
|
||||
#define LORA_DEVICE DEVICE_SX1280 //we need to define the device we are using
|
||||
|
||||
//LoRa Modem Parameters
|
||||
const uint32_t Frequency = 2445000000; //frequency of transmissions
|
||||
const int32_t Offset = 0; //offset frequency for calibration purposes
|
||||
const uint8_t Bandwidth = LORA_BW_0400; //LoRa bandwidth
|
||||
const uint8_t SpreadingFactor = LORA_SF7; //LoRa spreading factor
|
||||
const uint8_t CodeRate = LORA_CR_4_5; //LoRa coding rate
|
||||
|
||||
const int8_t TXpower = 10; //Power for transmissions in dBm
|
||||
|
||||
const uint16_t packet_delay = 1000; //mS delay between packets
|
||||
@ -0,0 +1,123 @@
|
||||
/*******************************************************************************************************
|
||||
Programs for Arduino - Copyright of the author Stuart Robinson - 21/09/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.
|
||||
*******************************************************************************************************/
|
||||
|
||||
|
||||
/*******************************************************************************************************
|
||||
Program Operation - This is a minimum setup LoRa test transmitter. A packet containing the ASCII text
|
||||
"Hello World 1234567890" is sent using the frequency and LoRa settings specified in the LT.setupLoRa()
|
||||
command. The pins to access the lora device need to be defined at the top of the program also.
|
||||
|
||||
This program does not need the DIO1 pin on the LoRa device connected.
|
||||
|
||||
The details of the packet sent and any errors are shown on the Arduino IDE Serial Monitor, together with
|
||||
the transmit power used and the packet length. The matching receiver program, '4_LoRa_Receiver' can be used
|
||||
to check the packets are being sent correctly, the frequency and LoRa settings (in the LT.setupLoRa()
|
||||
commands) must be the same for the transmitter and receiver programs. Sample Serial Monitor output;
|
||||
|
||||
10dBm Packet> Hello World 1234567890* BytesSent,23 PacketsSent,6
|
||||
|
||||
This is a version of example 3_LoRa_Transmitter.ino that does not require the use of the DIO1 pin to
|
||||
check for transmit done. In addition no NRESET pin is needed either, so its a program for use with a
|
||||
minimum pin count Arduino. Leave the DIO1 and NRESET pins on the LoRa device not connected.
|
||||
|
||||
For an example of a more detailed configuration for a transmitter, see program 103_LoRa_Transmitter.
|
||||
|
||||
Serial monitor baud rate is set at 9600
|
||||
*******************************************************************************************************/
|
||||
|
||||
#include <SPI.h> //the lora device is SPI based so load the SPI library
|
||||
#include <SX128XLT.h> //include the appropriate library
|
||||
|
||||
SX128XLT LT; //create a library class instance called LT
|
||||
|
||||
#define NSS 10 //select pin on LoRa device
|
||||
#define NRESET 9 //reset pin on LoRa device
|
||||
#define RFBUSY 7 //busy pin on LoRa device
|
||||
#define LORA_DEVICE DEVICE_SX1280 //we need to define the device we are using
|
||||
#define TXpower 10 //LoRa transmit power in dBm
|
||||
|
||||
uint8_t TXPacketL;
|
||||
uint32_t TXPacketCount;
|
||||
|
||||
uint8_t buff[] = "Hello World 1234567890"; //the message to send
|
||||
|
||||
|
||||
void loop()
|
||||
{
|
||||
Serial.print(TXpower); //print the transmit power defined
|
||||
Serial.print(F("dBm "));
|
||||
Serial.print(F("Packet> "));
|
||||
Serial.flush();
|
||||
|
||||
TXPacketL = sizeof(buff); //set TXPacketL to length of array
|
||||
buff[TXPacketL - 1] = '*'; //replace null character at buffer end so its visible on receiver
|
||||
|
||||
LT.printASCIIPacket(buff, TXPacketL); //print the buffer (the sent packet) as ASCII
|
||||
|
||||
if (LT.transmitIRQ(buff, TXPacketL, 10000, TXpower, WAIT_TX)) //will return packet length sent if OK, otherwise 0 if transmit error
|
||||
{
|
||||
TXPacketCount++;
|
||||
packet_is_OK();
|
||||
}
|
||||
else
|
||||
{
|
||||
packet_is_Error(); //transmit packet returned 0, there was an error
|
||||
}
|
||||
|
||||
Serial.println();
|
||||
delay(1000); //have a delay between packets
|
||||
}
|
||||
|
||||
|
||||
void packet_is_OK()
|
||||
{
|
||||
//if here packet has been sent OK
|
||||
Serial.print(F(" BytesSent,"));
|
||||
Serial.print(TXPacketL); //print transmitted packet length
|
||||
Serial.print(F(" PacketsSent,"));
|
||||
Serial.print(TXPacketCount); //print total of packets sent OK
|
||||
}
|
||||
|
||||
|
||||
void packet_is_Error()
|
||||
{
|
||||
//if here there was an error transmitting packet
|
||||
uint16_t IRQStatus;
|
||||
IRQStatus = LT.readIrqStatus(); //read the the interrupt register
|
||||
Serial.print(F(" SendError,"));
|
||||
Serial.print(F("Length,"));
|
||||
Serial.print(TXPacketL); //print transmitted packet length
|
||||
Serial.print(F(",IRQreg,"));
|
||||
Serial.print(IRQStatus, HEX); //print IRQ status
|
||||
LT.printIrqStatus(); //prints the text of which IRQs set
|
||||
}
|
||||
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(9600);
|
||||
Serial.println();
|
||||
Serial.println(F("3_LoRa_TransmitterIRQ Starting"));
|
||||
|
||||
SPI.begin();
|
||||
|
||||
if (LT.begin(NSS, NRESET, RFBUSY, LORA_DEVICE))
|
||||
{
|
||||
Serial.println(F("LoRa Device found"));
|
||||
delay(1000);
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.println(F("No LoRa device responding"));
|
||||
while (1);
|
||||
}
|
||||
|
||||
LT.setupLoRa(2445000000, 0, LORA_SF7, LORA_BW_0400, LORA_CR_4_5); //configure frequency and LoRa settings
|
||||
|
||||
Serial.print(F("Transmitter ready"));
|
||||
Serial.println();
|
||||
}
|
||||
@ -0,0 +1,237 @@
|
||||
/*******************************************************************************************************
|
||||
Programs for Arduino - Copyright of the author Stuart Robinson - 08/02/20
|
||||
|
||||
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, the packet is assumed to be in ASCII printable text,
|
||||
if its not ASCII text characters from 0x20 to 0x7F, expect weird things to happen on the Serial Monitor.
|
||||
The LED will flash for each packet received and the buzzer will sound, if fitted.
|
||||
|
||||
Sample serial monitor output;
|
||||
|
||||
1109s Hello World 1234567890*,CRC,DAAB,RSSI,-61dBm,SNR,9dB,Length,23,Packets,1026,Errors,0,IRQreg,50
|
||||
|
||||
If there is a packet error it might look like this, which is showing a CRC error,
|
||||
|
||||
1189s PacketError,RSSI,-111dBm,SNR,-12dB,Length,0,Packets,1126,Errors,1,IRQreg,70,IRQ_HEADER_VALID,IRQ_CRC_ERROR,IRQ_RX_DONE
|
||||
|
||||
Serial monitor baud rate is set at 9600.
|
||||
*******************************************************************************************************/
|
||||
|
||||
#include <SPI.h> //the lora device is SPI based so load the SPI library
|
||||
#include <SX128XLT.h> //include the appropriate library
|
||||
#include "Settings.h" //include the setiings file, frequencies, LoRa settings etc
|
||||
|
||||
SX128XLT LT; //create a library class instance called LT
|
||||
|
||||
uint32_t RXpacketCount;
|
||||
uint32_t errors;
|
||||
|
||||
uint8_t RXBUFFER[RXBUFFER_SIZE]; //create the buffer that received packets are copied into
|
||||
|
||||
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 = LT.receive(RXBUFFER, RXBUFFER_SIZE, 60000, WAIT_RX); //wait for a packet to arrive with 60seconds (60000mS) timeout
|
||||
|
||||
digitalWrite(LED1, HIGH); //something has happened
|
||||
|
||||
if (BUZZER > 0) //turn buzzer on
|
||||
{
|
||||
digitalWrite(BUZZER, HIGH);
|
||||
}
|
||||
|
||||
PacketRSSI = LT.readPacketRSSI(); //read the recived RSSI value
|
||||
PacketSNR = LT.readPacketSNR(); //read the received SNR value
|
||||
|
||||
if (RXPacketL == 0) //if the LT.receive() function detects an error, RXpacketL == 0
|
||||
{
|
||||
packet_is_Error();
|
||||
}
|
||||
else
|
||||
{
|
||||
packet_is_OK();
|
||||
}
|
||||
|
||||
if (BUZZER > 0)
|
||||
{
|
||||
digitalWrite(BUZZER, LOW); //buzzer off
|
||||
}
|
||||
|
||||
digitalWrite(LED1, LOW); //LED off
|
||||
|
||||
Serial.println();
|
||||
}
|
||||
|
||||
|
||||
void packet_is_OK()
|
||||
{
|
||||
uint16_t IRQStatus, localCRC;
|
||||
|
||||
IRQStatus = LT.readIrqStatus(); //read the LoRa device IRQ status register
|
||||
|
||||
RXpacketCount++;
|
||||
|
||||
printElapsedTime(); //print elapsed time to Serial Monitor
|
||||
Serial.print(F(" "));
|
||||
LT.printASCIIPacket(RXBUFFER, RXPacketL); //print the packet as ASCII characters
|
||||
|
||||
localCRC = LT.CRCCCITT(RXBUFFER, RXPacketL, 0xFFFF); //calculate the CRC, this is the external CRC calculation of the RXBUFFER
|
||||
Serial.print(F(",CRC,")); //contents, not the LoRa device internal CRC
|
||||
Serial.print(localCRC, HEX);
|
||||
Serial.print(F(",RSSI,"));
|
||||
Serial.print(PacketRSSI);
|
||||
Serial.print(F("dBm,SNR,"));
|
||||
Serial.print(PacketSNR);
|
||||
Serial.print(F("dB,Length,"));
|
||||
Serial.print(RXPacketL);
|
||||
Serial.print(F(",Packets,"));
|
||||
Serial.print(RXpacketCount);
|
||||
Serial.print(F(",Errors,"));
|
||||
Serial.print(errors);
|
||||
Serial.print(F(",IRQreg,"));
|
||||
Serial.print(IRQStatus, HEX);
|
||||
}
|
||||
|
||||
|
||||
void packet_is_Error()
|
||||
{
|
||||
uint16_t IRQStatus;
|
||||
IRQStatus = LT.readIrqStatus(); //read the LoRa device IRQ status register
|
||||
|
||||
printElapsedTime(); //print elapsed time to Serial Monitor
|
||||
|
||||
if (IRQStatus & IRQ_RX_TIMEOUT) //check for an RX timeout
|
||||
{
|
||||
Serial.print(F(" RXTimeout"));
|
||||
}
|
||||
else
|
||||
{
|
||||
errors++;
|
||||
Serial.print(F(" PacketError"));
|
||||
Serial.print(F(",RSSI,"));
|
||||
Serial.print(PacketRSSI);
|
||||
Serial.print(F("dBm,SNR,"));
|
||||
Serial.print(PacketSNR);
|
||||
Serial.print(F("dB,Length,"));
|
||||
Serial.print(LT.readRXPacketL()); //get the real packet length
|
||||
Serial.print(F(",Packets,"));
|
||||
Serial.print(RXpacketCount);
|
||||
Serial.print(F(",Errors,"));
|
||||
Serial.print(errors);
|
||||
Serial.print(F(",IRQreg,"));
|
||||
Serial.print(IRQStatus, HEX);
|
||||
LT.printIrqStatus(); //print the names of the IRQ registers set
|
||||
}
|
||||
|
||||
delay(250); //gives a longer buzzer and LED flash for error
|
||||
|
||||
}
|
||||
|
||||
|
||||
void printElapsedTime()
|
||||
{
|
||||
float seconds;
|
||||
seconds = millis() / 1000;
|
||||
Serial.print(seconds, 0);
|
||||
Serial.print(F("s"));
|
||||
}
|
||||
|
||||
|
||||
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(9600);
|
||||
Serial.println();
|
||||
Serial.println(F("4_LoRa_Receiver Starting"));
|
||||
|
||||
if (BUZZER > 0)
|
||||
{
|
||||
pinMode(BUZZER, OUTPUT);
|
||||
digitalWrite(BUZZER, HIGH);
|
||||
delay(50);
|
||||
digitalWrite(BUZZER, LOW);
|
||||
}
|
||||
|
||||
SPI.begin();
|
||||
|
||||
//SPI beginTranscation is normally part of library routines, but if it is disabled in the library
|
||||
//a single instance is needed here, so uncomment the program line below
|
||||
//SPI.beginTransaction(SPISettings(8000000, MSBFIRST, SPI_MODE0));
|
||||
|
||||
//setup hardware pins used by device, then check if device is found
|
||||
if (LT.begin(NSS, NRESET, RFBUSY, DIO1, RX_EN, TX_EN, LORA_DEVICE))
|
||||
{
|
||||
Serial.println(F("LoRa Device found"));
|
||||
led_Flash(2, 125);
|
||||
delay(1000);
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.println(F("No device responding"));
|
||||
while (1)
|
||||
{
|
||||
led_Flash(50, 50); //long fast speed LED flash indicates device error
|
||||
}
|
||||
}
|
||||
|
||||
//The function call list below shows the complete setup for the LoRa device using the information defined in the
|
||||
//Settings.h file.
|
||||
//The 'Setup LoRa device' list below can be replaced with a single function call;
|
||||
//LT.setupLoRa(Frequency, Offset, SpreadingFactor, Bandwidth, CodeRate);
|
||||
|
||||
//***************************************************************************************************
|
||||
//Setup LoRa device
|
||||
//***************************************************************************************************
|
||||
LT.setMode(MODE_STDBY_RC);
|
||||
LT.setRegulatorMode(USE_LDO);
|
||||
LT.setPacketType(PACKET_TYPE_LORA);
|
||||
LT.setRfFrequency(Frequency, Offset);
|
||||
LT.setBufferBaseAddress(0, 0);
|
||||
LT.setModulationParams(SpreadingFactor, Bandwidth, CodeRate);
|
||||
LT.setPacketParams(12, LORA_PACKET_VARIABLE_LENGTH, 255, LORA_CRC_ON, LORA_IQ_NORMAL, 0, 0);
|
||||
LT.setDioIrqParams(IRQ_RADIO_ALL, (IRQ_TX_DONE + IRQ_RX_TX_TIMEOUT), 0, 0);
|
||||
LT.setHighSensitivity();
|
||||
//***************************************************************************************************
|
||||
|
||||
|
||||
Serial.println();
|
||||
LT.printModemSettings(); //reads and prints the configured LoRa settings, useful check
|
||||
Serial.println();
|
||||
LT.printOperatingSettings(); //reads and prints the configured operting settings, useful check
|
||||
Serial.println();
|
||||
Serial.println();
|
||||
LT.printRegisters(0x900, 0x9FF); //print contents of device registers
|
||||
Serial.println();
|
||||
Serial.println();
|
||||
|
||||
Serial.print(F("Receiver ready - RXBUFFER_SIZE "));
|
||||
Serial.println(RXBUFFER_SIZE);
|
||||
Serial.println();
|
||||
}
|
||||
35
examples/SX128x_examples/Basics/4_LoRa_Receiver/Settings.h
Normal file
35
examples/SX128x_examples/Basics/4_LoRa_Receiver/Settings.h
Normal file
@ -0,0 +1,35 @@
|
||||
/*******************************************************************************************************
|
||||
Programs for Arduino - Copyright of the author Stuart Robinson - 06/02/20
|
||||
|
||||
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
|
||||
#define RFBUSY 7
|
||||
#define NRESET 9
|
||||
#define LED1 8
|
||||
#define DIO1 3
|
||||
#define RX_EN -1 //pin for RX enable, used on some SX1280 devices, set to -1 if not used
|
||||
#define TX_EN -1 //pin for TX enable, used on some SX1280 devices, set to -1 if not used
|
||||
#define BUZZER -1 //pin for BUZZER, set to -1 if not used
|
||||
|
||||
#define LORA_DEVICE DEVICE_SX1280 //we need to define the device we are using
|
||||
|
||||
//LoRa Modem Parameters
|
||||
const uint32_t Frequency = 2445000000; //frequency of transmissions
|
||||
const int32_t Offset = 0; //offset frequency for calibration purposes
|
||||
const uint8_t Bandwidth = LORA_BW_0400; //LoRa bandwidth
|
||||
const uint8_t SpreadingFactor = LORA_SF7; //LoRa spreading factor
|
||||
const uint8_t CodeRate = LORA_CR_4_5; //LoRa coding rate
|
||||
|
||||
const int8_t TXpower = 10; //Power for transmissions in dBm
|
||||
|
||||
const uint16_t packet_delay = 1000; //mS delay between packets
|
||||
|
||||
#define RXBUFFER_SIZE 255 //RX buffer size
|
||||
@ -0,0 +1,168 @@
|
||||
/*******************************************************************************************************
|
||||
Programs for Arduino - Copyright of the author Stuart Robinson - 05/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.
|
||||
*******************************************************************************************************/
|
||||
|
||||
/*******************************************************************************************************
|
||||
Program Operation - This is a minimum setup LoRa test receiver. The program listens for incoming packets
|
||||
using the frequency and LoRa settings in the LT.setupLoRa() command. The pins to access the lora device
|
||||
need to be defined at the top of the program also.
|
||||
|
||||
This program does not need the DIO1 pin on the LoRa device connected.
|
||||
|
||||
There is a printout on the Arduino IDE serial monitor of the valid packets received, the packet is assumed
|
||||
to be in ASCII printable text, if it's not ASCII text characters from 0x20 to 0x7F, expect weird things to
|
||||
happen on the Serial Monitor. Sample serial monitor output;
|
||||
|
||||
8s Hello World 1234567890*,RSSI,-44dBm,SNR,9dB,Length,23,Packets,7,Errors,0,IRQreg,50
|
||||
|
||||
If there is a packet error it might look like this, which is showing a CRC error;
|
||||
|
||||
137s PacketError,RSSI,-89dBm,SNR,-8dB,Length,23,Packets,37,Errors,2,IRQreg,70,IRQ_HEADER_VALID,IRQ_CRC_ERROR,IRQ_RX_DONE
|
||||
|
||||
If there are no packets received in a 10 second period then you should see a message like this;
|
||||
|
||||
112s RXTimeout
|
||||
|
||||
For an example of a more detailed configuration for a receiver, see program 104_LoRa_Receiver.
|
||||
|
||||
Serial monitor baud rate is set at 9600.
|
||||
*******************************************************************************************************/
|
||||
|
||||
#include <SPI.h> //the lora device is SPI based so load the SPI library
|
||||
#include <SX128XLT.h> //include the appropriate library
|
||||
|
||||
SX128XLT LT; //create a library class instance called LT
|
||||
|
||||
#define NSS 10 //select pin on LoRa device
|
||||
#define NRESET 9 //reset pin on LoRa device
|
||||
#define RFBUSY 7 //busy pin on LoRa device
|
||||
#define LORA_DEVICE DEVICE_SX1280 //we need to define the device we are using
|
||||
|
||||
#define RXBUFFER_SIZE 255 //RX buffer size
|
||||
|
||||
uint32_t RXpacketCount;
|
||||
uint32_t errors;
|
||||
|
||||
uint8_t RXBUFFER[RXBUFFER_SIZE]; //create the buffer that received packets are copied into
|
||||
|
||||
uint8_t RXPacketL; //stores length of packet received
|
||||
int16_t PacketRSSI; //stores RSSI of received packet
|
||||
int8_t PacketSNR; //stores signal to noise ratio (SNR) of received packet
|
||||
|
||||
|
||||
void loop()
|
||||
{
|
||||
RXPacketL = LT.receiveIRQ(RXBUFFER, RXBUFFER_SIZE, 60000, WAIT_RX); //wait for a packet to arrive with 60seconds (60000mS) timeout
|
||||
|
||||
PacketRSSI = LT.readPacketRSSI(); //read the received packets RSSI value
|
||||
PacketSNR = LT.readPacketSNR(); //read the received packets SNR value
|
||||
|
||||
if (RXPacketL == 0) //if the LT.receive() function detects an error RXpacketL is 0
|
||||
{
|
||||
packet_is_Error();
|
||||
}
|
||||
else
|
||||
{
|
||||
packet_is_OK();
|
||||
}
|
||||
|
||||
Serial.println();
|
||||
}
|
||||
|
||||
|
||||
void packet_is_OK()
|
||||
{
|
||||
uint16_t IRQStatus;
|
||||
|
||||
RXpacketCount++;
|
||||
IRQStatus = LT.readIrqStatus(); //read the LoRa device IRQ status register
|
||||
printElapsedTime(); //print elapsed time to Serial Monitor
|
||||
|
||||
Serial.print(F(" "));
|
||||
LT.printASCIIPacket(RXBUFFER, RXPacketL); //print the packet as ASCII characters
|
||||
|
||||
Serial.print(F(",RSSI,"));
|
||||
Serial.print(PacketRSSI);
|
||||
Serial.print(F("dBm,SNR,"));
|
||||
Serial.print(PacketSNR);
|
||||
Serial.print(F("dB,Length,"));
|
||||
Serial.print(RXPacketL);
|
||||
Serial.print(F(",Packets,"));
|
||||
Serial.print(RXpacketCount);
|
||||
Serial.print(F(",Errors,"));
|
||||
Serial.print(errors);
|
||||
Serial.print(F(",IRQreg,"));
|
||||
Serial.print(IRQStatus, HEX);
|
||||
}
|
||||
|
||||
|
||||
void packet_is_Error()
|
||||
{
|
||||
uint16_t IRQStatus;
|
||||
IRQStatus = LT.readIrqStatus(); //read the LoRa device IRQ status register
|
||||
|
||||
printElapsedTime(); //print elapsed time to Serial Monitor
|
||||
|
||||
if (IRQStatus & IRQ_RX_TIMEOUT) //check for an RX timeout
|
||||
{
|
||||
Serial.print(F(" RXTimeout"));
|
||||
}
|
||||
else
|
||||
{
|
||||
errors++;
|
||||
Serial.print(F(" PacketError"));
|
||||
Serial.print(F(",RSSI,"));
|
||||
Serial.print(PacketRSSI);
|
||||
Serial.print(F("dBm,SNR,"));
|
||||
Serial.print(PacketSNR);
|
||||
Serial.print(F("dB,Length,"));
|
||||
Serial.print(LT.readRXPacketL()); //get the real packet length
|
||||
Serial.print(F(",Packets,"));
|
||||
Serial.print(RXpacketCount);
|
||||
Serial.print(F(",Errors,"));
|
||||
Serial.print(errors);
|
||||
Serial.print(F(",IRQreg,"));
|
||||
Serial.print(IRQStatus, HEX);
|
||||
LT.printIrqStatus(); //print the names of the IRQ registers set
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void printElapsedTime()
|
||||
{
|
||||
float seconds;
|
||||
seconds = millis() / 1000;
|
||||
Serial.print(seconds, 0);
|
||||
Serial.print(F("s"));
|
||||
}
|
||||
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(9600);
|
||||
Serial.println();
|
||||
Serial.println(F("4_LoRa_ReceiverIRQ Starting"));
|
||||
Serial.println();
|
||||
|
||||
SPI.begin();
|
||||
|
||||
if (LT.begin(NSS, NRESET, RFBUSY, LORA_DEVICE))
|
||||
{
|
||||
Serial.println(F("LoRa Device found"));
|
||||
delay(1000);
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.println(F("No LoRa device responding"));
|
||||
while (1);
|
||||
}
|
||||
|
||||
LT.setupLoRa(2445000000, 0, LORA_SF7, LORA_BW_0400, LORA_CR_4_5); //configure frequency and LoRa settings
|
||||
|
||||
Serial.print(F("Receiver ready - RXBUFFER_SIZE "));
|
||||
Serial.println(RXBUFFER_SIZE);
|
||||
Serial.println();
|
||||
}
|
||||
@ -0,0 +1,175 @@
|
||||
/*******************************************************************************************************
|
||||
Programs for Arduino - Copyright of the author Stuart Robinson - 29/09/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.
|
||||
*******************************************************************************************************/
|
||||
|
||||
|
||||
/*******************************************************************************************************
|
||||
Program Operation - This is a test transmitter for the Fast Long Range Communication (FLRC) mode
|
||||
introduced in the SX128X devices. A packet containing ASCII text is sent according to the frequency and
|
||||
FLRC settings specified in the 'Settings.h' file. The pins to access the SX128X device need to be defined
|
||||
in the 'Settings.h' file also.
|
||||
|
||||
The details of the packet sent and any errors are shown on the Serial Monitor, together with the transmit
|
||||
power used, the packet length and the CRC of the packet. The matching receive program, '53_FLRC_Receiver'
|
||||
can be used to check the packets are being sent correctly, the frequency and FLRC settings (in Settings.h)
|
||||
must be the same for the Transmit and Receive program. Sample Serial Monitor output;
|
||||
|
||||
10dBm Packet> {packet contents*} BytesSent,23 CRC,DAAB TransmitTime,54mS PacketsSent,1
|
||||
|
||||
Serial monitor baud rate is set at 9600
|
||||
*******************************************************************************************************/
|
||||
|
||||
#include <SPI.h> //the SX128X device is SPI based so load the SPI library
|
||||
#include <SX128XLT.h> //include the appropriate library
|
||||
#include "Settings.h" //include the setiings file, frequencies, LoRa settings etc
|
||||
|
||||
SX128XLT LT; //create a library class instance called LT
|
||||
|
||||
uint8_t TXPacketL;
|
||||
uint32_t TXPacketCount, startmS, endmS;
|
||||
|
||||
uint8_t buff[] = "Hello World 1234567890";
|
||||
|
||||
void loop()
|
||||
{
|
||||
Serial.print(TXpower); //print the transmit power defined
|
||||
Serial.print(F("dBm "));
|
||||
Serial.print(F("Packet> "));
|
||||
Serial.flush();
|
||||
|
||||
TXPacketL = sizeof(buff); //set TXPacketL to length of array
|
||||
buff[TXPacketL - 1] = '*'; //replace null character at buffer end so its visible on reciver
|
||||
|
||||
LT.printASCIIPacket(buff, TXPacketL); //print the buffer (the sent packet) as ASCII
|
||||
|
||||
digitalWrite(LED1, HIGH);
|
||||
startmS = millis(); //start transmit timer
|
||||
|
||||
TXPacketL = LT.transmit(buff, TXPacketL, 10000, TXpower, WAIT_TX); //will return 0 if transmit fails, timeout 10 seconds
|
||||
|
||||
if (TXPacketL > 0)
|
||||
{
|
||||
endmS = millis(); //packet sent, note end time
|
||||
TXPacketCount++;
|
||||
packet_is_OK();
|
||||
}
|
||||
else
|
||||
{
|
||||
packet_is_Error(); //transmit packet returned 0, so there was an error
|
||||
}
|
||||
|
||||
digitalWrite(LED1, LOW);
|
||||
Serial.println();
|
||||
delay(packet_delay); //have a delay between packets
|
||||
}
|
||||
|
||||
|
||||
void packet_is_OK()
|
||||
{
|
||||
//if here packet has been sent OK
|
||||
uint16_t localCRC;
|
||||
|
||||
Serial.print(F(" BytesSent,"));
|
||||
Serial.print(TXPacketL); //print transmitted packet length
|
||||
localCRC = LT.CRCCCITT(buff, TXPacketL, 0xFFFF);
|
||||
Serial.print(F(" CRC,"));
|
||||
Serial.print(localCRC, HEX); //print CRC of sent packet
|
||||
Serial.print(F(" TransmitTime,"));
|
||||
Serial.print(endmS - startmS); //print transmit time of packet
|
||||
Serial.print(F("mS"));
|
||||
Serial.print(F(" PacketsSent,"));
|
||||
Serial.print(TXPacketCount); //print total of packets sent OK
|
||||
}
|
||||
|
||||
|
||||
void packet_is_Error()
|
||||
{
|
||||
//if here there was an error transmitting packet
|
||||
uint16_t IRQStatus;
|
||||
IRQStatus = LT.readIrqStatus(); //read the the interrupt register
|
||||
Serial.print(F(" SendError,"));
|
||||
Serial.print(F("Length,"));
|
||||
Serial.print(TXPacketL); //print transmitted packet length
|
||||
Serial.print(F(",IRQreg,"));
|
||||
Serial.print(IRQStatus, HEX); //print IRQ status
|
||||
LT.printIrqStatus(); //prints the text of which IRQs set
|
||||
}
|
||||
|
||||
|
||||
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(9600);
|
||||
Serial.println();
|
||||
Serial.println(F("52_FLRC_Transmitter 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));
|
||||
|
||||
//setup hardware pins used by device, then check if device is found
|
||||
if (LT.begin(NSS, NRESET, RFBUSY, DIO1, LORA_DEVICE))
|
||||
{
|
||||
Serial.println(F("FLRC Device found"));
|
||||
led_Flash(2, 125); //two further quick LED flashes to indicate device found
|
||||
delay(1000);
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.println(F("No FLRC device responding"));
|
||||
while (1)
|
||||
{
|
||||
led_Flash(50, 50); //long fast speed LED flash indicates device error
|
||||
}
|
||||
}
|
||||
|
||||
LT.setupFLRC(Frequency, Offset, BandwidthBitRate, CodingRate, BT, Syncword);
|
||||
|
||||
//The full details of the setupFLRC function call above are listed below
|
||||
//***************************************************************************************************
|
||||
//Setup FLRC
|
||||
//***************************************************************************************************
|
||||
//LT.setMode(MODE_STDBY_RC);
|
||||
//LT.setRegulatorMode(USE_LDO);
|
||||
//LT.setPacketType(PACKET_TYPE_FLRC);
|
||||
//LT.setRfFrequency(Frequency, Offset);
|
||||
//LT.setBufferBaseAddress(0, 0);
|
||||
//LT.setModulationParams(BandwidthBitRate, CodingRate, BT);
|
||||
//LT.setPacketParams(PREAMBLE_LENGTH_32_BITS, FLRC_SYNC_WORD_LEN_P32S, RADIO_RX_MATCH_SYNCWORD_1, RADIO_PACKET_VARIABLE_LENGTH, 127, RADIO_CRC_3_BYTES, RADIO_WHITENING_OFF);
|
||||
//LT.setDioIrqParams(IRQ_RADIO_ALL, (IRQ_TX_DONE + IRQ_RX_TX_TIMEOUT), 0, 0); //set for IRQ on TX done and timeout on DIO1
|
||||
//LT.setSyncWord1(Syncword);
|
||||
//***************************************************************************************************
|
||||
|
||||
Serial.println();
|
||||
LT.printModemSettings(); //reads and prints the configured modem settings, useful check
|
||||
Serial.println();
|
||||
LT.printOperatingSettings(); //reads and prints the configured operating settings, useful check
|
||||
Serial.println();
|
||||
Serial.println();
|
||||
LT.printRegisters(0x900, 0x9FF); //print contents of device registers
|
||||
Serial.println();
|
||||
Serial.println();
|
||||
|
||||
Serial.print(F("Transmitter ready"));
|
||||
Serial.println();
|
||||
}
|
||||
@ -0,0 +1,31 @@
|
||||
/*******************************************************************************************************
|
||||
Programs for Arduino - Copyright of the author Stuart Robinson - 29/09/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
|
||||
#define RFBUSY 7
|
||||
#define NRESET 9
|
||||
#define LED1 8
|
||||
#define DIO1 3
|
||||
|
||||
#define LORA_DEVICE DEVICE_SX1280 //we need to define the device we are using
|
||||
|
||||
//FLRC Modem Parameters
|
||||
const uint32_t Frequency = 2445000000; //frequency of transmissions
|
||||
const int32_t Offset = 0; //offset frequency for calibration purposes
|
||||
|
||||
const uint8_t BandwidthBitRate = FLRC_BR_1_300_BW_1_2; //FLRC bandwidth and bit rate, 1.3Mbs
|
||||
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 int8_t TXpower = 0; //power for transmissions in dBm
|
||||
const uint16_t packet_delay = 1000; //mS delay between packets
|
||||
@ -0,0 +1,213 @@
|
||||
/*******************************************************************************************************
|
||||
Programs for Arduino - Copyright of the author Stuart Robinson - 29/09/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.
|
||||
*******************************************************************************************************/
|
||||
|
||||
|
||||
/*******************************************************************************************************
|
||||
Program Operation - This is a test receiver for the Fast Long Range Communication (FLRC) mode introduced
|
||||
in the SX128X devices. The program listens for incoming packets using the FLRC settings in the 'Settings.h'
|
||||
file. The pins to access the SX128X device need to be defined in the 'Settings.h' file also.
|
||||
|
||||
There is a printout of the valid packets received, the packet is assumed to be in ASCII printable text,
|
||||
if its not ASCII text characters from 0x20 to 0x7F, expect weird things to happen on the Serial Monitor.
|
||||
The LED will flash for each packet received.
|
||||
|
||||
Sample serial monitor output;
|
||||
|
||||
3s Hello World 1234567890*,CRC,DAAB,RSSI,-73dB,Length,23,Packets,1,Errors,0,IRQreg,6
|
||||
|
||||
If there is a packet error it might look like this, which is showing a CRC error,
|
||||
|
||||
6s PacketError,RSSI,-103dB,Length,119,Packets,3,Errors,1,IRQreg,46,IRQ_RX_DONE,IRQ_SYNCWORD_VALID,IRQ_CRC_ERROR
|
||||
|
||||
Serial monitor baud rate is set at 9600.
|
||||
*******************************************************************************************************/
|
||||
|
||||
#include <SPI.h> //the lora device is SPI based so load the SPI library
|
||||
#include <SX128XLT.h> //include the appropriate library
|
||||
#include "Settings.h" //include the setiings file, frequencies, LoRa settings etc
|
||||
|
||||
SX128XLT LT; //create a library class instance called LT
|
||||
|
||||
uint32_t RXpacketCount;
|
||||
uint32_t errors;
|
||||
|
||||
uint8_t RXBUFFER[RXBUFFER_SIZE]; //create the buffer that received packets are copied into
|
||||
|
||||
uint8_t RXPacketL; //stores length of packet received
|
||||
int16_t PacketRSSI; //stores RSSI of received packet
|
||||
|
||||
|
||||
void loop()
|
||||
{
|
||||
RXPacketL = LT.receive(RXBUFFER, RXBUFFER_SIZE, 60000, WAIT_RX); //wait for a packet to arrive with 60seconds (60000mS) timeout
|
||||
|
||||
digitalWrite(LED1, HIGH); //something has happened
|
||||
|
||||
PacketRSSI = LT.readPacketRSSI(); //read the recived RSSI value
|
||||
|
||||
if (RXPacketL == 0) //if the LT.receive() function detects an error, RXpacketL == 0
|
||||
{
|
||||
packet_is_Error();
|
||||
}
|
||||
else
|
||||
{
|
||||
packet_is_OK();
|
||||
}
|
||||
|
||||
digitalWrite(LED1, LOW); //LED off
|
||||
|
||||
Serial.println();
|
||||
}
|
||||
|
||||
|
||||
void packet_is_OK()
|
||||
{
|
||||
uint16_t IRQStatus, localCRC;
|
||||
|
||||
IRQStatus = LT.readIrqStatus(); //read the LoRa device IRQ status register
|
||||
|
||||
RXpacketCount++;
|
||||
|
||||
printElapsedTime(); //print elapsed time to Serial Monitor
|
||||
Serial.print(F(" "));
|
||||
LT.printASCIIPacket(RXBUFFER, RXPacketL); //print the packet as ASCII characters
|
||||
|
||||
localCRC = LT.CRCCCITT(RXBUFFER, RXPacketL, 0xFFFF); //calculate the CRC, this is the external CRC calculation of the RXBUFFER
|
||||
Serial.print(F(",CRC,")); //contents, not the LoRa device internal CRC
|
||||
Serial.print(localCRC, HEX);
|
||||
Serial.print(F(",RSSI,"));
|
||||
Serial.print(PacketRSSI);
|
||||
Serial.print(F("dB,Length,"));
|
||||
Serial.print(RXPacketL);
|
||||
Serial.print(F(",Packets,"));
|
||||
Serial.print(RXpacketCount);
|
||||
Serial.print(F(",Errors,"));
|
||||
Serial.print(errors);
|
||||
Serial.print(F(",IRQreg,"));
|
||||
Serial.print(IRQStatus, HEX);
|
||||
}
|
||||
|
||||
|
||||
void packet_is_Error()
|
||||
{
|
||||
uint16_t IRQStatus;
|
||||
IRQStatus = LT.readIrqStatus(); //read the LoRa device IRQ status register
|
||||
|
||||
printElapsedTime(); //print elapsed time to Serial Monitor
|
||||
|
||||
if (IRQStatus & IRQ_RX_TIMEOUT) //check for an RX timeout
|
||||
{
|
||||
Serial.print(F(" RXTimeout"));
|
||||
}
|
||||
else
|
||||
{
|
||||
errors++;
|
||||
Serial.print(F(" PacketError"));
|
||||
Serial.print(F(",RSSI,"));
|
||||
Serial.print(PacketRSSI);
|
||||
Serial.print(F("dB,Length,"));
|
||||
Serial.print(LT.readRXPacketL()); //get the real packet length
|
||||
Serial.print(F(",Packets,"));
|
||||
Serial.print(RXpacketCount);
|
||||
Serial.print(F(",Errors,"));
|
||||
Serial.print(errors);
|
||||
Serial.print(F(",IRQreg,"));
|
||||
Serial.print(IRQStatus, HEX);
|
||||
LT.printIrqStatus(); //print the names of the IRQ registers set
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
void printElapsedTime()
|
||||
{
|
||||
float seconds;
|
||||
seconds = millis() / 1000;
|
||||
Serial.print(seconds, 0);
|
||||
Serial.print(F("s"));
|
||||
}
|
||||
|
||||
|
||||
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(9600);
|
||||
Serial.println();
|
||||
Serial.println(F("53_FLRC_Receiver Starting"));
|
||||
Serial.println();
|
||||
|
||||
SPI.begin();
|
||||
|
||||
//SPI beginTranscation is normally part of library routines, but if it is disabled in the library
|
||||
//a single instance is needed here, so uncomment the program line below
|
||||
//SPI.beginTransaction(SPISettings(8000000, MSBFIRST, SPI_MODE0));
|
||||
|
||||
//setup hardware pins used by device, then check if device is found
|
||||
if (LT.begin(NSS, NRESET, RFBUSY, DIO1, LORA_DEVICE))
|
||||
{
|
||||
Serial.println(F("FLRC Device found"));
|
||||
led_Flash(2, 125);
|
||||
delay(1000);
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.println(F("No FLRC device responding"));
|
||||
while (1)
|
||||
{
|
||||
led_Flash(50, 50); //long fast speed LED flash indicates device error
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
LT.setupFLRC(Frequency, Offset, BandwidthBitRate, CodingRate, BT, Syncword);
|
||||
|
||||
//The full details of the setupFLRC function call above are listed below
|
||||
//***************************************************************************************************
|
||||
//Setup FLRC
|
||||
//***************************************************************************************************
|
||||
//LT.setMode(MODE_STDBY_RC);
|
||||
//LT.setRegulatorMode(USE_LDO);
|
||||
//LT.setPacketType(PACKET_TYPE_FLRC);
|
||||
//LT.setRfFrequency(Frequency, Offset);
|
||||
//LT.setBufferBaseAddress(0, 0);
|
||||
//LT.setModulationParams(BandwidthBitRate, CodingRate, BT);
|
||||
//LT.setPacketParams(PREAMBLE_LENGTH_32_BITS, FLRC_SYNC_WORD_LEN_P32S, RADIO_RX_MATCH_SYNCWORD_1, RADIO_PACKET_VARIABLE_LENGTH, 127, RADIO_CRC_3_BYTES, RADIO_WHITENING_OFF);
|
||||
//LT.setDioIrqParams(IRQ_RADIO_ALL, (IRQ_TX_DONE + IRQ_RX_TX_TIMEOUT), 0, 0); //set for IRQ on TX done and timeout on DIO1
|
||||
//LT.setSyncWord1(Syncword);
|
||||
//***************************************************************************************************
|
||||
LT.setFLRCPayloadLengthReg(127); //FLRC will filter packets on receive according to length, so set to longest packet
|
||||
Serial.println();
|
||||
LT.printModemSettings(); //reads and prints the configured modem settings, useful check
|
||||
Serial.println();
|
||||
LT.printOperatingSettings(); //reads and prints the configured operting settings, useful check
|
||||
Serial.println();
|
||||
Serial.println();
|
||||
LT.printRegisters(0x900, 0x9FF); //print contents of device registers
|
||||
Serial.println();
|
||||
Serial.println();
|
||||
|
||||
Serial.print(F("Receiver ready - RXBUFFER_SIZE "));
|
||||
Serial.println(RXBUFFER_SIZE);
|
||||
Serial.println();
|
||||
}
|
||||
33
examples/SX128x_examples/Basics/53_FLRC_Receiver/Settings.h
Normal file
33
examples/SX128x_examples/Basics/53_FLRC_Receiver/Settings.h
Normal file
@ -0,0 +1,33 @@
|
||||
/*******************************************************************************************************
|
||||
Programs for Arduino - Copyright of the author Stuart Robinson - 29/09/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
|
||||
#define RFBUSY 7
|
||||
#define NRESET 9
|
||||
#define LED1 8
|
||||
#define DIO1 3
|
||||
|
||||
#define LORA_DEVICE DEVICE_SX1280 //we need to define the device we are using
|
||||
|
||||
//FLRC Modem Parameters
|
||||
const uint32_t Frequency = 2445000000; //frequency of transmissions
|
||||
const int32_t Offset = 0; //offset frequency for calibration purposes
|
||||
|
||||
const uint8_t BandwidthBitRate = FLRC_BR_1_300_BW_1_2; //FLRC bandwidth and bit rate, 1.3Mbs
|
||||
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 int8_t TXpower = 0; //power for transmissions in dBm
|
||||
|
||||
const uint16_t packet_delay = 1000; //mS delay between packets
|
||||
|
||||
#define RXBUFFER_SIZE 127 //Max RX buffer size
|
||||
@ -0,0 +1,158 @@
|
||||
/*******************************************************************************************************
|
||||
Based on the OV2640 Arducam programs.
|
||||
|
||||
ArduCAM demo (C)2017 Lee
|
||||
Web: http://www.ArduCAM.com
|
||||
*******************************************************************************************************/
|
||||
|
||||
/*******************************************************************************************************
|
||||
Programs for Arduino - Copyright of the author Stuart Robinson - 19/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 demonstration program that uses LoRa to transfer an image taken with an
|
||||
OV2640 Arducam camera. The LoRa transfer is carried out using the data transfer functions of the
|
||||
SX12XX-LoRa library. Program tested on Arduino DUE.
|
||||
|
||||
The Arducam software takes an image and saves it to a SD card. The filename is then passed across to
|
||||
the LoRa library which transfers the file already on SD across to the remote receiver, which is running
|
||||
program 239_StuartCAM_LoRa_Receiver or program 234_SDfile_Transfer_Receiver.
|
||||
|
||||
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 <ArduCAM.h> //get library here > https://github.com/ArduCAM/Arduino
|
||||
#include <Wire.h>
|
||||
#include <SPI.h>
|
||||
#include <SD.h>
|
||||
#include "memorysaver.h" //part of Arducam library
|
||||
|
||||
#include <SX128XLT.h>
|
||||
#include <ProgramLT_Definitions.h>
|
||||
#include "Settings.h" //LoRa settings etc.
|
||||
|
||||
SX128XLT LoRa; //create an SX128XLT library instance called LoRa
|
||||
|
||||
#define ENABLEMONITOR //enable monitor prints
|
||||
#define PRINTSEGMENTNUM //enable this define to print segment numbers
|
||||
//#define DEBUG //enable this define to print debug info for segment transfers
|
||||
//#define DEBUGSD //enable this defien to print SD file debug info
|
||||
#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 //DTSDlibrary.h needs to use SD.h
|
||||
|
||||
#include "DTSDlibrary.h" //part of SX12XX library
|
||||
#include "SDtransfer.h" //part of SX12XX library
|
||||
|
||||
char FileName[13]; //filename passed to both Arducam and LoRa routines
|
||||
|
||||
ArduCAM myCAM( OV2640, OV2640CS );
|
||||
#include "OV2640.h" //include local Arducam code for OV2640 camera
|
||||
|
||||
|
||||
void loop()
|
||||
{
|
||||
myCAMSaveToSDFile(FileName, sizeof(FileName)); //when finished FileName[] contains name of file saved on SD
|
||||
Serial.print(FileName);
|
||||
Serial.println(F(" Saved to SD card"));
|
||||
SDsendFile(FileName, sizeof(FileName)); //transfer image via LoRa
|
||||
Serial.println();
|
||||
Serial.println();
|
||||
delay(60000); //wait 60 seconds
|
||||
}
|
||||
|
||||
|
||||
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
|
||||
|
||||
digitalWrite(OV2640CS, HIGH);
|
||||
pinMode(OV2640CS, OUTPUT); //set the camera CS as an output
|
||||
digitalWrite(SDCS, HIGH);
|
||||
pinMode(SDCS, OUTPUT); //set the SDCS as an output
|
||||
|
||||
Serial.begin(115200);
|
||||
Serial.println(__FILE__);
|
||||
|
||||
Wire.begin();
|
||||
SPI.begin();
|
||||
|
||||
//Initialize SD Card
|
||||
while (!SD.begin(SDCS))
|
||||
{
|
||||
Serial.println(F("SD Card Error - program halted"));
|
||||
while (1);
|
||||
}
|
||||
Serial.println(F("SD Card detected"));
|
||||
|
||||
//Initialize camera
|
||||
setupOV2640(OV2640resolution); //resolution choice, see Settings.h file
|
||||
|
||||
//Initialise LoRa device
|
||||
if (LoRa.begin(NSS, NRESET, RFBUSY, DIO1, LORA_DEVICE))
|
||||
{
|
||||
Serial.println(F("LoRa device found"));
|
||||
led_Flash(2, 125);
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.println(F("LoRa device error"));
|
||||
while (1)
|
||||
{
|
||||
led_Flash(50, 50); //long fast speed flash indicates device error
|
||||
}
|
||||
}
|
||||
|
||||
Serial.println();
|
||||
|
||||
#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();
|
||||
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"));
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,458 @@
|
||||
|
||||
GNU LESSER GENERAL PUBLIC LICENSE
|
||||
Version 2.1, February 1999
|
||||
|
||||
Copyright (C) 1991, 1999 Free Software Foundation, Inc.
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
[This is the first released version of the Lesser GPL. It also counts
|
||||
as the successor of the GNU Library Public License, version 2, hence
|
||||
the version number 2.1.]
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
Licenses are intended to guarantee your freedom to share and change
|
||||
free software--to make sure the software is free for all its users.
|
||||
|
||||
This license, the Lesser General Public License, applies to some
|
||||
specially designated software packages--typically libraries--of the
|
||||
Free Software Foundation and other authors who decide to use it. You
|
||||
can use it too, but we suggest you first think carefully about whether
|
||||
this license or the ordinary General Public License is the better
|
||||
strategy to use in any particular case, based on the explanations below.
|
||||
|
||||
When we speak of free software, we are referring to freedom of use,
|
||||
not price. Our General Public Licenses are designed to make sure that
|
||||
you have the freedom to distribute copies of free software (and charge
|
||||
for this service if you wish); that you receive source code or can get
|
||||
it if you want it; that you can change the software and use pieces of
|
||||
it in new free programs; and that you are informed that you can do
|
||||
these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
distributors to deny you these rights or to ask you to surrender these
|
||||
rights. These restrictions translate to certain responsibilities for
|
||||
you if you distribute copies of the library or if you modify it.
|
||||
|
||||
For example, if you distribute copies of the library, whether gratis
|
||||
or for a fee, you must give the recipients all the rights that we gave
|
||||
you. You must make sure that they, too, receive or can get the source
|
||||
code. If you link other code with the library, you must provide
|
||||
complete object files to the recipients, so that they can relink them
|
||||
with the library after making changes to the library and recompiling
|
||||
it. And you must show them these terms so they know their rights.
|
||||
|
||||
We protect your rights with a two-step method: (1) we copyright the
|
||||
library, and (2) we offer you this license, which gives you legal
|
||||
permission to copy, distribute and/or modify the library.
|
||||
|
||||
To protect each distributor, we want to make it very clear that
|
||||
there is no warranty for the free library. Also, if the library is
|
||||
modified by someone else and passed on, the recipients should know
|
||||
that what they have is not the original version, so that the original
|
||||
author's reputation will not be affected by problems that might be
|
||||
introduced by others.
|
||||
|
||||
Finally, software patents pose a constant threat to the existence of
|
||||
any free program. We wish to make sure that a company cannot
|
||||
effectively restrict the users of a free program by obtaining a
|
||||
restrictive license from a patent holder. Therefore, we insist that
|
||||
any patent license obtained for a version of the library must be
|
||||
consistent with the full freedom of use specified in this license.
|
||||
|
||||
Most GNU software, including some libraries, is covered by the
|
||||
ordinary GNU General Public License. This license, the GNU Lesser
|
||||
General Public License, applies to certain designated libraries, and
|
||||
is quite different from the ordinary General Public License. We use
|
||||
this license for certain libraries in order to permit linking those
|
||||
libraries into non-free programs.
|
||||
|
||||
When a program is linked with a library, whether statically or using
|
||||
a shared library, the combination of the two is legally speaking a
|
||||
combined work, a derivative of the original library. The ordinary
|
||||
General Public License therefore permits such linking only if the
|
||||
entire combination fits its criteria of freedom. The Lesser General
|
||||
Public License permits more lax criteria for linking other code with
|
||||
the library.
|
||||
|
||||
We call this license the "Lesser" General Public License because it
|
||||
does Less to protect the user's freedom than the ordinary General
|
||||
Public License. It also provides other free software developers Less
|
||||
of an advantage over competing non-free programs. These disadvantages
|
||||
are the reason we use the ordinary General Public License for many
|
||||
libraries. However, the Lesser license provides advantages in certain
|
||||
special circumstances.
|
||||
|
||||
For example, on rare occasions, there may be a special need to
|
||||
encourage the widest possible use of a certain library, so that it becomes
|
||||
a de-facto standard. To achieve this, non-free programs must be
|
||||
allowed to use the library. A more frequent case is that a free
|
||||
library does the same job as widely used non-free libraries. In this
|
||||
case, there is little to gain by limiting the free library to free
|
||||
software only, so we use the Lesser General Public License.
|
||||
|
||||
In other cases, permission to use a particular library in non-free
|
||||
programs enables a greater number of people to use a large body of
|
||||
free software. For example, permission to use the GNU C Library in
|
||||
non-free programs enables many more people to use the whole GNU
|
||||
operating system, as well as its variant, the GNU/Linux operating
|
||||
system.
|
||||
|
||||
Although the Lesser General Public License is Less protective of the
|
||||
users' freedom, it does ensure that the user of a program that is
|
||||
linked with the Library has the freedom and the wherewithal to run
|
||||
that program using a modified version of the Library.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow. Pay close attention to the difference between a
|
||||
"work based on the library" and a "work that uses the library". The
|
||||
former contains code derived from the library, whereas the latter must
|
||||
be combined with the library in order to run.
|
||||
|
||||
GNU LESSER GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License Agreement applies to any software library or other
|
||||
program which contains a notice placed by the copyright holder or
|
||||
other authorized party saying it may be distributed under the terms of
|
||||
this Lesser General Public License (also called "this License").
|
||||
Each licensee is addressed as "you".
|
||||
|
||||
A "library" means a collection of software functions and/or data
|
||||
prepared so as to be conveniently linked with application programs
|
||||
(which use some of those functions and data) to form executables.
|
||||
|
||||
The "Library", below, refers to any such software library or work
|
||||
which has been distributed under these terms. A "work based on the
|
||||
Library" means either the Library or any derivative work under
|
||||
copyright law: that is to say, a work containing the Library or a
|
||||
portion of it, either verbatim or with modifications and/or translated
|
||||
straightforwardly into another language. (Hereinafter, translation is
|
||||
included without limitation in the term "modification".)
|
||||
|
||||
"Source code" for a work means the preferred form of the work for
|
||||
making modifications to it. For a library, complete source code means
|
||||
all the source code for all modules it contains, plus any associated
|
||||
interface definition files, plus the scripts used to control compilation
|
||||
and installation of the library.
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running a program using the Library is not restricted, and output from
|
||||
such a program is covered only if its contents constitute a work based
|
||||
on the Library (independent of the use of the Library in a tool for
|
||||
writing it). Whether that is true depends on what the Library does
|
||||
and what the program that uses the Library does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Library's
|
||||
complete source code as you receive it, in any medium, provided that
|
||||
you conspicuously and appropriately publish on each copy an
|
||||
appropriate copyright notice and disclaimer of warranty; keep intact
|
||||
all the notices that refer to this License and to the absence of any
|
||||
warranty; and distribute a copy of this License along with the
|
||||
Library.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy,
|
||||
and you may at your option offer warranty protection in exchange for a
|
||||
fee.
|
||||
|
||||
2. You may modify your copy or copies of the Library or any portion
|
||||
of it, thus forming a work based on the Library, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
a) The modified work must itself be a software library.
|
||||
|
||||
b) You must cause the files modified to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
c) You must cause the whole of the work to be licensed at no
|
||||
charge to all third parties under the terms of this License.
|
||||
|
||||
d) If a facility in the modified Library refers to a function or a
|
||||
table of data to be supplied by an application program that uses
|
||||
the facility, other than as an argument passed when the facility
|
||||
is invoked, then you must make a good faith effort to ensure that,
|
||||
in the event an application does not supply such function or
|
||||
table, the facility still operates, and performs whatever part of
|
||||
its purpose remains meaningful.
|
||||
|
||||
(For example, a function in a library to compute square roots has
|
||||
a purpose that is entirely well-defined independent of the
|
||||
application. Therefore, Subsection 2d requires that any
|
||||
application-supplied function or table used by this function must
|
||||
be optional: if the application does not supply it, the square
|
||||
root function must still compute square roots.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Library,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Library, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote
|
||||
it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Library.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Library
|
||||
with the Library (or with a work based on the Library) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may opt to apply the terms of the ordinary GNU General Public
|
||||
License instead of this License to a given copy of the Library. To do
|
||||
this, you must alter all the notices that refer to this License, so
|
||||
that they refer to the ordinary GNU General Public License, version 2,
|
||||
instead of to this License. (If a newer version than version 2 of the
|
||||
ordinary GNU General Public License has appeared, then you can specify
|
||||
that version instead if you wish.) Do not make any other change in
|
||||
these notices.
|
||||
|
||||
Once this change is made in a given copy, it is irreversible for
|
||||
that copy, so the ordinary GNU General Public License applies to all
|
||||
subsequent copies and derivative works made from that copy.
|
||||
|
||||
This option is useful when you wish to copy part of the code of
|
||||
the Library into a program that is not a library.
|
||||
|
||||
4. You may copy and distribute the Library (or a portion or
|
||||
derivative of it, under Section 2) in object code or executable form
|
||||
under the terms of Sections 1 and 2 above provided that you accompany
|
||||
it with the complete corresponding machine-readable source code, which
|
||||
must be distributed under the terms of Sections 1 and 2 above on a
|
||||
medium customarily used for software interchange.
|
||||
|
||||
If distribution of object code is made by offering access to copy
|
||||
from a designated place, then offering equivalent access to copy the
|
||||
source code from the same place satisfies the requirement to
|
||||
distribute the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
5. A program that contains no derivative of any portion of the
|
||||
Library, but is designed to work with the Library by being compiled or
|
||||
linked with it, is called a "work that uses the Library". Such a
|
||||
work, in isolation, is not a derivative work of the Library, and
|
||||
therefore falls outside the scope of this License.
|
||||
|
||||
However, linking a "work that uses the Library" with the Library
|
||||
creates an executable that is a derivative of the Library (because it
|
||||
contains portions of the Library), rather than a "work that uses the
|
||||
library". The executable is therefore covered by this License.
|
||||
Section 6 states terms for distribution of such executables.
|
||||
|
||||
When a "work that uses the Library" uses material from a header file
|
||||
that is part of the Library, the object code for the work may be a
|
||||
derivative work of the Library even though the source code is not.
|
||||
Whether this is true is especially significant if the work can be
|
||||
linked without the Library, or if the work is itself a library. The
|
||||
threshold for this to be true is not precisely defined by law.
|
||||
|
||||
If such an object file uses only numerical parameters, data
|
||||
structure layouts and accessors, and small macros and small inline
|
||||
functions (ten lines or less in length), then the use of the object
|
||||
file is unrestricted, regardless of whether it is legally a derivative
|
||||
work. (Executables containing this object code plus portions of the
|
||||
Library will still fall under Section 6.)
|
||||
|
||||
Otherwise, if the work is a derivative of the Library, you may
|
||||
distribute the object code for the work under the terms of Section 6.
|
||||
Any executables containing that work also fall under Section 6,
|
||||
whether or not they are linked directly with the Library itself.
|
||||
|
||||
6. As an exception to the Sections above, you may also combine or
|
||||
link a "work that uses the Library" with the Library to produce a
|
||||
work containing portions of the Library, and distribute that work
|
||||
under terms of your choice, provided that the terms permit
|
||||
modification of the work for the customer's own use and reverse
|
||||
engineering for debugging such modifications.
|
||||
|
||||
You must give prominent notice with each copy of the work that the
|
||||
Library is used in it and that the Library and its use are covered by
|
||||
this License. You must supply a copy of this License. If the work
|
||||
during execution displays copyright notices, you must include the
|
||||
copyright notice for the Library among them, as well as a reference
|
||||
directing the user to the copy of this License. Also, you must do one
|
||||
of these things:
|
||||
|
||||
a) Accompany the work with the complete corresponding
|
||||
machine-readable source code for the Library including whatever
|
||||
changes were used in the work (which must be distributed under
|
||||
Sections 1 and 2 above); and, if the work is an executable linked
|
||||
with the Library, with the complete machine-readable "work that
|
||||
uses the Library", as object code and/or source code, so that the
|
||||
user can modify the Library and then relink to produce a modified
|
||||
executable containing the modified Library. (It is understood
|
||||
that the user who changes the contents of definitions files in the
|
||||
Library will not necessarily be able to recompile the application
|
||||
to use the modified definitions.)
|
||||
|
||||
b) Use a suitable shared library mechanism for linking with the
|
||||
Library. A suitable mechanism is one that (1) uses at run time a
|
||||
copy of the library already present on the user's computer system,
|
||||
rather than copying library functions into the executable, and (2)
|
||||
will operate properly with a modified version of the library, if
|
||||
the user installs one, as long as the modified version is
|
||||
interface-compatible with the version that the work was made with.
|
||||
|
||||
c) Accompany the work with a written offer, valid for at
|
||||
least three years, to give the same user the materials
|
||||
specified in Subsection 6a, above, for a charge no more
|
||||
than the cost of performing this distribution.
|
||||
|
||||
d) If distribution of the work is made by offering access to copy
|
||||
from a designated place, offer equivalent access to copy the above
|
||||
specified materials from the same place.
|
||||
|
||||
e) Verify that the user has already received a copy of these
|
||||
materials or that you have already sent this user a copy.
|
||||
|
||||
For an executable, the required form of the "work that uses the
|
||||
Library" must include any data and utility programs needed for
|
||||
reproducing the executable from it. However, as a special exception,
|
||||
the materials to be distributed need not include anything that is
|
||||
normally distributed (in either source or binary form) with the major
|
||||
components (compiler, kernel, and so on) of the operating system on
|
||||
which the executable runs, unless that component itself accompanies
|
||||
the executable.
|
||||
|
||||
It may happen that this requirement contradicts the license
|
||||
restrictions of other proprietary libraries that do not normally
|
||||
accompany the operating system. Such a contradiction means you cannot
|
||||
use both them and the Library together in an executable that you
|
||||
distribute.
|
||||
|
||||
7. You may place library facilities that are a work based on the
|
||||
Library side-by-side in a single library together with other library
|
||||
facilities not covered by this License, and distribute such a combined
|
||||
library, provided that the separate distribution of the work based on
|
||||
the Library and of the other library facilities is otherwise
|
||||
permitted, and provided that you do these two things:
|
||||
|
||||
a) Accompany the combined library with a copy of the same work
|
||||
based on the Library, uncombined with any other library
|
||||
facilities. This must be distributed under the terms of the
|
||||
Sections above.
|
||||
|
||||
b) Give prominent notice with the combined library of the fact
|
||||
that part of it is a work based on the Library, and explaining
|
||||
where to find the accompanying uncombined form of the same work.
|
||||
|
||||
8. You may not copy, modify, sublicense, link with, or distribute
|
||||
the Library except as expressly provided under this License. Any
|
||||
attempt otherwise to copy, modify, sublicense, link with, or
|
||||
distribute the Library is void, and will automatically terminate your
|
||||
rights under this License. However, parties who have received copies,
|
||||
or rights, from you under this License will not have their licenses
|
||||
terminated so long as such parties remain in full compliance.
|
||||
|
||||
9. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Library or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Library (or any work based on the
|
||||
Library), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Library or works based on it.
|
||||
|
||||
10. Each time you redistribute the Library (or any work based on the
|
||||
Library), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute, link with or modify the Library
|
||||
subject to these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties with
|
||||
this License.
|
||||
|
||||
11. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Library at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Library by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Library.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under any
|
||||
particular circumstance, the balance of the section is intended to apply,
|
||||
and the section as a whole is intended to apply in other circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
12. If the distribution and/or use of the Library is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Library under this License may add
|
||||
an explicit geographical distribution limitation excluding those countries,
|
||||
so that distribution is permitted only in or among countries not thus
|
||||
excluded. In such case, this License incorporates the limitation as if
|
||||
written in the body of this License.
|
||||
|
||||
13. The Free Software Foundation may publish revised and/or new
|
||||
versions of the Lesser General Public License from time to time.
|
||||
Such new versions will be similar in spirit to the present version,
|
||||
but may differ in detail to address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the Library
|
||||
specifies a version number of this License which applies to it and
|
||||
"any later version", you have the option of following the terms and
|
||||
conditions either of that version or of any later version published by
|
||||
the Free Software Foundation. If the Library does not specify a
|
||||
license version number, you may choose any version ever published by
|
||||
the Free Software Foundation.
|
||||
|
||||
14. If you wish to incorporate parts of the Library into other free
|
||||
programs whose distribution conditions are incompatible with these,
|
||||
write to the author to ask for permission. For software which is
|
||||
copyrighted by the Free Software Foundation, write to the Free
|
||||
Software Foundation; we sometimes make exceptions for this. Our
|
||||
decision will be guided by the two goals of preserving the free status
|
||||
of all derivatives of our free software and of promoting the sharing
|
||||
and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
|
||||
WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
|
||||
EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
|
||||
OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
|
||||
KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
|
||||
LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
|
||||
THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||
|
||||
16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
|
||||
WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
|
||||
AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
|
||||
FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
|
||||
CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
|
||||
LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
|
||||
RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
|
||||
FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
|
||||
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
|
||||
DAMAGES.
|
||||
|
||||
@ -0,0 +1,253 @@
|
||||
/*******************************************************************************************************
|
||||
Based on the OV2640 Arducam programs by;
|
||||
|
||||
ArduCAM demo (C)2017 Lee
|
||||
Web: http://www.ArduCAM.com
|
||||
*******************************************************************************************************/
|
||||
#define OV2640_CHIPID_HIGH 0x0A
|
||||
#define OV2640_CHIPID_LOW 0x0B
|
||||
|
||||
void setupOV2640(uint8_t resolution);
|
||||
void myCAMSaveToSDFile2();
|
||||
void myCAMSaveToSDFile(char *ACfilename, uint8_t ACfilenamesize);
|
||||
|
||||
void setupOV2640(uint8_t resolution)
|
||||
{
|
||||
uint8_t vid, pid;
|
||||
uint8_t temp;
|
||||
//Reset the CPLD
|
||||
myCAM.write_reg(0x07, 0x80);
|
||||
delay(100);
|
||||
myCAM.write_reg(0x07, 0x00);
|
||||
delay(100);
|
||||
|
||||
while (1) {
|
||||
//Check if the ArduCAM SPI bus is OK
|
||||
myCAM.write_reg(ARDUCHIP_TEST1, 0x55);
|
||||
temp = myCAM.read_reg(ARDUCHIP_TEST1);
|
||||
|
||||
if (temp != 0x55) {
|
||||
Serial.println(F("OV2640 SPI interface Error!"));
|
||||
delay(1000); continue;
|
||||
} else {
|
||||
Serial.println(F("OV2640 SPI interface OK")); break;
|
||||
}
|
||||
}
|
||||
|
||||
while (1) {
|
||||
//Check if the camera module type is OV2640
|
||||
myCAM.wrSensorReg8_8(0xff, 0x01);
|
||||
myCAM.rdSensorReg8_8(OV2640_CHIPID_HIGH, &vid);
|
||||
myCAM.rdSensorReg8_8(OV2640_CHIPID_LOW, &pid);
|
||||
if ((vid != 0x26 ) && (( pid != 0x41 ) || ( pid != 0x42 ))) {
|
||||
Serial.println(F("Can't find OV2640 module!"));
|
||||
delay(1000); continue;
|
||||
}
|
||||
else {
|
||||
Serial.println(F("OV2640 setup on I2C")); break;
|
||||
}
|
||||
}
|
||||
|
||||
myCAM.set_format(JPEG);
|
||||
myCAM.InitCAM();
|
||||
|
||||
myCAM.OV2640_set_JPEG_size(resolution);
|
||||
}
|
||||
|
||||
|
||||
void myCAMSaveToSDFile2()
|
||||
{
|
||||
char str[8];
|
||||
byte buf[256];
|
||||
static int i = 0;
|
||||
static int k = 0;
|
||||
uint8_t temp = 0, temp_last = 0;
|
||||
uint32_t length = 0;
|
||||
bool is_header = false;
|
||||
File outFile;
|
||||
|
||||
myCAM.flush_fifo(); //Flush the FIFO
|
||||
|
||||
myCAM.clear_fifo_flag(); //Clear the capture done flag
|
||||
|
||||
myCAM.start_capture(); //Start capture
|
||||
Serial.println(F("start Capture"));
|
||||
|
||||
while (!myCAM.get_bit(ARDUCHIP_TRIG , CAP_DONE_MASK));
|
||||
Serial.println(F("Capture Done"));
|
||||
|
||||
length = myCAM.read_fifo_length();
|
||||
|
||||
Serial.print(F("The fifo length is :"));
|
||||
Serial.println(length, DEC);
|
||||
|
||||
if (length >= MAX_FIFO_SIZE) //384K
|
||||
{
|
||||
Serial.println(F("Over size."));
|
||||
return ;
|
||||
}
|
||||
if (length == 0 ) //0 kb
|
||||
{
|
||||
Serial.println(F("Size is 0."));
|
||||
return ;
|
||||
}
|
||||
|
||||
k = k + 1; //Construct a file name
|
||||
itoa(k, str, 10);
|
||||
strcat(str, ".jpg");
|
||||
|
||||
outFile = SD.open(str, O_WRITE | O_CREAT | O_TRUNC); //Open the new file
|
||||
|
||||
if (!outFile) {
|
||||
Serial.println(F("File open failed"));
|
||||
return;
|
||||
}
|
||||
myCAM.CS_LOW();
|
||||
myCAM.set_fifo_burst();
|
||||
|
||||
while ( length-- )
|
||||
{
|
||||
temp_last = temp;
|
||||
temp = SPI.transfer(0x00);
|
||||
//Read JPEG data from FIFO
|
||||
if ( (temp == 0xD9) && (temp_last == 0xFF) ) //If find the end ,break while,
|
||||
{
|
||||
buf[i++] = temp; //save the last 0XD9
|
||||
//Write the remain bytes in the buffer
|
||||
myCAM.CS_HIGH();
|
||||
outFile.write(buf, i);
|
||||
//Close the file
|
||||
outFile.close();
|
||||
Serial.print(str);
|
||||
Serial.println(F(" Image save OK"));
|
||||
is_header = false;
|
||||
i = 0;
|
||||
}
|
||||
if (is_header == true)
|
||||
{
|
||||
//Write image data to buffer if not full
|
||||
if (i < 256)
|
||||
buf[i++] = temp;
|
||||
else
|
||||
{
|
||||
//Write 256 bytes image data to file
|
||||
myCAM.CS_HIGH();
|
||||
outFile.write(buf, 256);
|
||||
i = 0;
|
||||
buf[i++] = temp;
|
||||
myCAM.CS_LOW();
|
||||
myCAM.set_fifo_burst();
|
||||
}
|
||||
}
|
||||
else if ((temp == 0xD8) & (temp_last == 0xFF))
|
||||
{
|
||||
is_header = true;
|
||||
buf[i++] = temp_last;
|
||||
buf[i++] = temp;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void myCAMSaveToSDFile(char *ACfilename, uint8_t ACfilenamesize)
|
||||
{
|
||||
byte buf[256];
|
||||
char ACfilename2[ACfilenamesize+1];
|
||||
static uint16_t i = 0;
|
||||
static uint16_t k = 0;
|
||||
uint8_t temp = 0, temp_last = 0;
|
||||
uint32_t length = 0;
|
||||
bool is_header = false;
|
||||
File dataFile;
|
||||
memset(ACfilename, 0, ACfilenamesize); //fill ACfilename array with nulls.
|
||||
myCAM.flush_fifo(); //Flush the FIFO
|
||||
myCAM.clear_fifo_flag(); //Clear the capture done flag
|
||||
myCAM.start_capture(); //Start capture
|
||||
|
||||
Serial.println(F("Start capture "));
|
||||
|
||||
while (!myCAM.get_bit(ARDUCHIP_TRIG , CAP_DONE_MASK));
|
||||
Serial.println(F("Done"));
|
||||
length = myCAM.read_fifo_length();
|
||||
Serial.print(F("FIFO length "));
|
||||
Serial.println(length, DEC);
|
||||
|
||||
if (length >= MAX_FIFO_SIZE) //384K
|
||||
{
|
||||
Serial.println(F("FIFO over size"));
|
||||
return ;
|
||||
}
|
||||
if (length == 0 ) //0 kb
|
||||
{
|
||||
Serial.println(F("FIFO size is 0"));
|
||||
return ;
|
||||
}
|
||||
|
||||
//Construct a file name
|
||||
k = k + 1;
|
||||
itoa(k, ACfilename2, 10);
|
||||
strcat(ACfilename2, ".jpg");
|
||||
|
||||
ACfilename[0] = '/';
|
||||
memcpy(ACfilename+1, ACfilename2, ACfilenamesize);
|
||||
|
||||
//Serial.print(F("Adjusted filename "));
|
||||
//Serial.println(ACfilename);
|
||||
|
||||
dataFile = SD.open(ACfilename, O_WRITE | O_CREAT | O_TRUNC); //Open the new file
|
||||
|
||||
if (!dataFile)
|
||||
{
|
||||
Serial.print(ACfilename);
|
||||
Serial.println(F(" File open failed"));
|
||||
return;
|
||||
}
|
||||
|
||||
myCAM.CS_LOW();
|
||||
myCAM.set_fifo_burst();
|
||||
|
||||
while ( length-- )
|
||||
{
|
||||
temp_last = temp;
|
||||
temp = SPI.transfer(0x00);
|
||||
|
||||
//Read JPEG data from FIFO
|
||||
if ( (temp == 0xD9) && (temp_last == 0xFF) )
|
||||
{
|
||||
buf[i++] = temp; //save the last 0XD9
|
||||
|
||||
myCAM.CS_HIGH();
|
||||
dataFile.write(buf, i); //Write the remain bytes in the buffer
|
||||
|
||||
dataFile.close(); //Close the file
|
||||
Serial.print(ACfilename);
|
||||
Serial.println();
|
||||
is_header = false;
|
||||
i = 0;
|
||||
|
||||
}
|
||||
|
||||
if (is_header == true)
|
||||
{
|
||||
//Write image data to buffer if not full
|
||||
if (i < 256)
|
||||
buf[i++] = temp;
|
||||
else
|
||||
{
|
||||
//Write 256 bytes image data to file
|
||||
myCAM.CS_HIGH();
|
||||
dataFile.write(buf, 256);
|
||||
i = 0;
|
||||
buf[i++] = temp;
|
||||
myCAM.CS_LOW();
|
||||
myCAM.set_fifo_burst();
|
||||
}
|
||||
}
|
||||
else if ((temp == 0xD8) & (temp_last == 0xFF))
|
||||
{
|
||||
is_header = true;
|
||||
buf[i++] = temp_last;
|
||||
buf[i++] = temp;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,72 @@
|
||||
/*******************************************************************************************************
|
||||
Programs for Arduino - Copyright of the author Stuart Robinson - 19/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 on LoRa device
|
||||
#define NRESET 9 //reset on LoRa device
|
||||
#define RFBUSY 7 //RFBUSY pin on LoRa device
|
||||
#define DIO1 3 //DIO1 on LoRa device, used for RX and TX done
|
||||
#define LED1 8 //On board LED, high for on
|
||||
#define SDCS 30 //select pin for SD card
|
||||
#define OV2640CS 22 //select for SPI on camera
|
||||
|
||||
#define LORA_DEVICE DEVICE_SX1280 //this is the device we are using
|
||||
|
||||
#define Monitorport Serial //Port where serial prints go
|
||||
|
||||
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 = 750; //mS to wait for receiving an ACK before re-trying transmit file open
|
||||
const uint32_t ACKclosetimeoutmS = 750; //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 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 DTSendAttempts = 10; //number of attempts sending a packet before a restart
|
||||
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 uint8_t Maxfilenamesize = 32; //size of DTfilename buffer
|
||||
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 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
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
Setup the resolution OV2640 required, the choices are;
|
||||
|
||||
OV2640_160x120,OV2640_176x144,OV2640_320x240,OV2640_352x288,OV2640_640x480,
|
||||
OV2640_800x600, OV2640_1024x768,OV2640_1280x1024,OV2640_1600x1200
|
||||
*******************************************************************************/
|
||||
|
||||
const uint8_t OV2640resolution = OV2640_640x480;
|
||||
@ -0,0 +1,142 @@
|
||||
/*******************************************************************************************************
|
||||
Programs for Arduino - Copyright of the author Stuart Robinson - 19/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 to receive images sent via LoRa using program
|
||||
238_StuartCAM_LoRa_Remote_Camera which uses an OV2640 Arducam camera to take pictures.
|
||||
|
||||
The received images\files are saved onto an SD card. Arduino DUEs were used for this test.
|
||||
|
||||
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.
|
||||
|
||||
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,60 @@
|
||||
/*******************************************************************************************************
|
||||
Programs for Arduino - Copyright of the author Stuart Robinson - 19/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 on LoRa device
|
||||
#define NRESET 9 //reset on LoRa device
|
||||
#define RFBUSY 7 //RFBUSY pin on LoRa device
|
||||
#define DIO1 3 //DIO1 on LoRa device, used for RX and TX done
|
||||
#define LED1 8 //On board LED, high for on
|
||||
#define SDCS 30 //select pin for SD card
|
||||
|
||||
#define LORA_DEVICE DEVICE_SX1280 //this is the device we are using
|
||||
|
||||
#define Monitorport Serial //Port where serial prints go
|
||||
|
||||
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 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
|
||||
|
||||
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,447 @@
|
||||
/*******************************************************************************************************
|
||||
Programs for Arduino - Copyright of the author Stuart Robinson - 19/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.
|
||||
*******************************************************************************************************/
|
||||
|
||||
/*********
|
||||
Rui Santos
|
||||
Complete project details at https://RandomNerdTutorials.com/esp32-cam-take-photo-save-microsd-card
|
||||
Github repository at https://github.com/RuiSantosdotme/ESP32-CAM-Arduino-IDE
|
||||
|
||||
IMPORTANT!!!
|
||||
- Select Board "AI Thinker ESP32-CAM"
|
||||
- GPIO 0 must be connected to GND to upload a sketch
|
||||
- After connecting GPIO 0 to GND, press the ESP32-CAM on-board RESET button to put your board in flashing mode
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files.
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
*********/
|
||||
|
||||
|
||||
/*******************************************************************************************************
|
||||
Program Operation - This is a program using the ESP32CAM to take pictures and transmit those pictures via
|
||||
LoRa radio to another remote Arduino.
|
||||
|
||||
This program is for an ESP32CAM board that has an SPI LoRa module set up on the following pins; NSS 12,
|
||||
NRESET 14, SCK 4, MISO 13, MOSI 2, RFBUSY 15, 3.3V VCC and GND. All other pins on the SX128X are not
|
||||
connected.
|
||||
|
||||
Note that the white LED on pin 4 or the transistor controlling it need to be removed so that the LoRa
|
||||
device can properly use pin 4.
|
||||
|
||||
The program wakes up, takes a picture and starts the transfer of the picture (from its memory array in
|
||||
PSRAM) with LoRa, more details of the file transfer process will be found here;
|
||||
|
||||
https://stuartsprojects.github.io/2021/09/20/Large-Data-Transfers-with-LoRa-Part3.html
|
||||
|
||||
Note that if the camera fails then the program will attempt to send, and wait for the acknowledge, for a
|
||||
DTinfo packet reporting the fail.
|
||||
|
||||
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 <Arduino.h>
|
||||
#include "FS.h" //SD Card ESP32
|
||||
#include "SD_MMC.h" //SD Card ESP32
|
||||
#include "soc/soc.h" //disable brownout problems
|
||||
#include "soc/rtc_cntl_reg.h" //disable brownout problems
|
||||
#include "driver/rtc_io.h"
|
||||
|
||||
#include <SPI.h>
|
||||
#include <SX128XLT.h> //get library here > https://github.com/StuartsProjects/SX12XX-LoRa
|
||||
#include <ProgramLT_Definitions.h>
|
||||
#include "Settings.h" //LoRa and program settings
|
||||
SX128XLT LoRa; //create a library class instance called LoRa, needed for ARtransferIRQ.h
|
||||
|
||||
#define ENABLEMONITOR //enable define to see progress messages in ARtransferIRQ.h
|
||||
#define PRINTSEGMENTNUM //enable to print segment numbers as transfer progresses
|
||||
#define ENABLEARRAYCRC //enable this define to use and show CRCs
|
||||
//#define DISABLEPAYLOADCRC //enable this define if you want to not use packet payload CRC checking
|
||||
//#define DEBUG //enable this define to show data transfer debug info
|
||||
|
||||
RTC_DATA_ATTR int16_t bootCount = 0; //variables to save in RTC ram
|
||||
RTC_DATA_ATTR uint16_t sleepcount = 0;
|
||||
RTC_DATA_ATTR uint16_t pictureNumber = 0; //number of picture taken, set to 0 on reset
|
||||
|
||||
#include "esp_camera.h"
|
||||
camera_config_t config; //stores the camera configuration parameters
|
||||
#include <ARtransferIRQ.h> //library of array transfer functions
|
||||
|
||||
bool SDOK;
|
||||
|
||||
|
||||
void loop()
|
||||
{
|
||||
SDOK = false;
|
||||
ARDTflags = 0;
|
||||
|
||||
if (initMicroSDCard()) //need to setup SD card before camera
|
||||
{
|
||||
Serial.println(F("SD Card OK"));
|
||||
SDOK = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.println(F("****************************"));
|
||||
Serial.println(F("ERROR - SD Card Mount Failed"));
|
||||
Serial.println(F("****************************"));
|
||||
bitSet(ARDTflags, ARNoFileSave);
|
||||
}
|
||||
|
||||
if (!configInitCamera())
|
||||
{
|
||||
bitSet(ARDTflags, ARNoCamera); //set flag bit for no camera working
|
||||
Serial.println(F("Camera config failed"));
|
||||
Serial.println(F("Sending DTInfo packet"));
|
||||
setupLoRaDevice();
|
||||
ARsendDTInfo();
|
||||
startSleep();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (takePhotoSend(PicturesToTake, PictureDelaymS))
|
||||
{
|
||||
//picture taken OK
|
||||
startSleep();
|
||||
}
|
||||
else
|
||||
{
|
||||
//picture take failed
|
||||
Serial.println("********************************");
|
||||
Serial.println("ERROR - Take picture send failed");
|
||||
Serial.println("********************************");
|
||||
Serial.println();
|
||||
Serial.println("Sending DTInfo packet");
|
||||
Serial.flush();
|
||||
bitSet(ARDTflags, ARNoCamera); //set flag bit for no camera working
|
||||
setupLoRaDevice();
|
||||
ARsendDTInfo();
|
||||
startSleep();
|
||||
}
|
||||
}
|
||||
startSleep();
|
||||
}
|
||||
|
||||
void startSleep()
|
||||
{
|
||||
LoRa.setSleep(CONFIGURATION_RETENTION);
|
||||
rtc_gpio_hold_en(GPIO_NUM_4);
|
||||
rtc_gpio_hold_en(GPIO_NUM_12); //hold LoRa device off in sleep
|
||||
esp_sleep_enable_timer_wakeup(SleepTimesecs * uS_TO_S_FACTOR);
|
||||
Serial.print(F("Start Sleep "));
|
||||
Serial.print(SleepTimesecs);
|
||||
Serial.println(F("s"));
|
||||
Serial.flush();
|
||||
sleepcount++;
|
||||
esp_deep_sleep_start();
|
||||
Serial.println("This should never be printed !!!");
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool initMicroSDCard()
|
||||
{
|
||||
if (!SD_MMC.begin("/sdcard", true)) //use this line for 1 bit mode, pin 2 only, 4,12,13 not used
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
uint8_t cardType = SD_MMC.cardType();
|
||||
|
||||
if (cardType == CARD_NONE)
|
||||
{
|
||||
Serial.println(F("Unknown SD card type"));
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void redFlash(uint16_t flashes, uint16_t ondelaymS, uint16_t offdelaymS)
|
||||
{
|
||||
uint16_t index;
|
||||
|
||||
pinMode(REDLED, OUTPUT); //setup pin as output
|
||||
|
||||
for (index = 1; index <= flashes; index++)
|
||||
{
|
||||
digitalWrite(REDLED, LOW);
|
||||
delay(ondelaymS);
|
||||
digitalWrite(REDLED, HIGH);
|
||||
delay(offdelaymS);
|
||||
}
|
||||
pinMode(REDLED, INPUT); //setup pin as input
|
||||
}
|
||||
|
||||
bool setupLoRaDevice()
|
||||
{
|
||||
SPI.begin(SCK, MISO, MOSI, NSS);
|
||||
|
||||
if (LoRa.begin(NSS, NRESET, RFBUSY, LORA_DEVICE))
|
||||
{
|
||||
Serial.println(F("LoRa device found"));
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.println(F("LoRa Device error"));
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef USELORA
|
||||
LoRa.setupLoRa(Frequency, Offset, SpreadingFactor, Bandwidth, CodeRate);
|
||||
Monitorport.println(F("Using LoRa packets"));
|
||||
#endif
|
||||
|
||||
#ifdef USEFLRC
|
||||
LoRa.setupFLRC(Frequency, Offset, BandwidthBitRate, CodingRate, BT, Syncword);
|
||||
Monitorport.println(F("Using FLRC packets"));
|
||||
#endif
|
||||
|
||||
Serial.println();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void setup()
|
||||
{
|
||||
redFlash(4, 125, 125);
|
||||
|
||||
//WRITE_PERI_REG(RTC_CNTL_BROWN_OUT_REG, 0); //disable brownout detector
|
||||
rtc_gpio_hold_dis(GPIO_NUM_4);
|
||||
rtc_gpio_hold_dis(GPIO_NUM_12); //LoRa NSS back to normal control after sleep
|
||||
|
||||
pinMode(2, INPUT_PULLUP);
|
||||
digitalWrite(NSS, HIGH);
|
||||
pinMode(NSS, OUTPUT);
|
||||
|
||||
Serial.begin(115200);
|
||||
Serial.println();
|
||||
Serial.println(F(__FILE__));
|
||||
|
||||
if (bootCount == 0) //run this only the first time after programming or power up
|
||||
{
|
||||
bootCount = bootCount + 1;
|
||||
}
|
||||
|
||||
Serial.println(F("Awake !"));
|
||||
Serial.print(F("Bootcount "));
|
||||
Serial.println(bootCount);
|
||||
Serial.print(F("Sleepcount "));
|
||||
Serial.println(sleepcount);
|
||||
|
||||
#ifdef DISABLEPAYLOADCRC
|
||||
LoRa.setReliableConfig(NoReliableCRC);
|
||||
#endif
|
||||
|
||||
if (LoRa.getReliableConfig(NoReliableCRC))
|
||||
{
|
||||
Serial.println(F("Payload CRC disabled"));
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.println(F("Payload CRC enabled"));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//***********************************************************************************************
|
||||
// Start camera Code
|
||||
//***********************************************************************************************
|
||||
|
||||
bool configInitCamera()
|
||||
{
|
||||
Serial.println(F("Initialising the camera module "));
|
||||
|
||||
config.ledc_channel = LEDC_CHANNEL_0;
|
||||
config.ledc_timer = LEDC_TIMER_0;
|
||||
config.pin_d0 = Y2_GPIO_NUM;
|
||||
config.pin_d1 = Y3_GPIO_NUM;
|
||||
config.pin_d2 = Y4_GPIO_NUM;
|
||||
config.pin_d3 = Y5_GPIO_NUM;
|
||||
config.pin_d4 = Y6_GPIO_NUM;
|
||||
config.pin_d5 = Y7_GPIO_NUM;
|
||||
config.pin_d6 = Y8_GPIO_NUM;
|
||||
config.pin_d7 = Y9_GPIO_NUM;
|
||||
config.pin_xclk = XCLK_GPIO_NUM;
|
||||
config.pin_pclk = PCLK_GPIO_NUM;
|
||||
config.pin_vsync = VSYNC_GPIO_NUM;
|
||||
config.pin_href = HREF_GPIO_NUM;
|
||||
config.pin_sscb_sda = SIOD_GPIO_NUM;
|
||||
config.pin_sscb_scl = SIOC_GPIO_NUM;
|
||||
config.pin_pwdn = PWDN_GPIO_NUM;
|
||||
config.pin_reset = RESET_GPIO_NUM;
|
||||
config.xclk_freq_hz = 20000000;
|
||||
config.pixel_format = PIXFORMAT_JPEG; //YUV422,GRAYSCALE,RGB565,JPEG
|
||||
|
||||
//Select lower framesize if the camera doesn't support PSRAM
|
||||
if (psramFound())
|
||||
{
|
||||
Serial.println(F("PSRAM found"));
|
||||
config.frame_size = FRAMESIZE_SVGA; //FRAMESIZE_ + QVGA|CIF|VGA|SVGA|XGA|SXGA|UXGA, XUGA == 100K+, SVGA = 25K+
|
||||
config.jpeg_quality = 10; //10-63 lower number means higher quality
|
||||
config.fb_count = 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.println(F("No PSRAM"));
|
||||
config.frame_size = FRAMESIZE_XGA;
|
||||
config.jpeg_quality = 12;
|
||||
config.fb_count = 1;
|
||||
}
|
||||
|
||||
esp_err_t err = esp_camera_init(&config); //Initialize the Camera
|
||||
if (err != ESP_OK)
|
||||
{
|
||||
Serial.printf("Camera init failed with error 0x%x", err);
|
||||
Serial.println();
|
||||
return false;
|
||||
}
|
||||
|
||||
sensor_t * s = esp_camera_sensor_get();
|
||||
s->set_brightness(s, 0); // -2 to 2
|
||||
s->set_contrast(s, 0); // -2 to 2
|
||||
s->set_saturation(s, 0); // -2 to 2
|
||||
s->set_special_effect(s, 0); // 0 to 6 (0 - No Effect, 1 - Negative, 2 - Grayscale, 3 - Red Tint, 4 - Green Tint, 5 - Blue Tint, 6 - Sepia)
|
||||
s->set_whitebal(s, 1); // 0 = disable , 1 = enable
|
||||
s->set_awb_gain(s, 1); // 0 = disable , 1 = enable
|
||||
s->set_wb_mode(s, 1); // 0 to 4 - if awb_gain enabled (0 - Auto, 1 - Sunny, 2 - Cloudy, 3 - Office, 4 - Home)
|
||||
s->set_exposure_ctrl(s, 1); // 0 = disable , 1 = enable
|
||||
s->set_aec2(s, 1); // 0 = disable , 1 = enable
|
||||
s->set_ae_level(s, 0); // -2 to 2
|
||||
s->set_aec_value(s, 450); // 0 to 1200
|
||||
s->set_gain_ctrl(s, 1); // 0 = disable , 1 = enable
|
||||
s->set_agc_gain(s, 0); // 0 to 30
|
||||
s->set_gainceiling(s, (gainceiling_t)0); // 0 to 6
|
||||
s->set_bpc(s, 1); // 0 = disable , 1 = enable
|
||||
s->set_wpc(s, 0); // 0 = disable , 1 = enable
|
||||
s->set_raw_gma(s, 1); // 0 = disable , 1 = enable
|
||||
s->set_lenc(s, 0); // 0 = disable , 1 = enable
|
||||
s->set_hmirror(s, 0); // 0 = disable , 1 = enable
|
||||
s->set_vflip(s, 0); // 0 = disable , 1 = enable
|
||||
s->set_dcw(s, 1); // 0 = disable , 1 = enable
|
||||
s->set_colorbar(s, 0); // 0 = disable , 1 = enable
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
uint16_t takePhotoSend(uint8_t num, uint32_t gapmS)
|
||||
{
|
||||
uint8_t index = 1;
|
||||
char filenamearray[32];
|
||||
bool sentOK = false;
|
||||
String path;
|
||||
camera_fb_t * fb = esp_camera_fb_get();
|
||||
|
||||
for (index = 1; index <= num; index++) //take a number of pictures, send last
|
||||
{
|
||||
pictureNumber++;
|
||||
path = "/pic" + String(pictureNumber) + ".jpg";
|
||||
Serial.print("Next picture file name ");
|
||||
Serial.println(path.c_str());
|
||||
|
||||
if (!fb)
|
||||
{
|
||||
Serial.println(F("*****************************"));
|
||||
Serial.println(F("ERROR - Camera capture failed"));
|
||||
Serial.println(F("*****************************"));
|
||||
delay(1000);
|
||||
pictureNumber--; //restore picture number
|
||||
bitSet(ARDTflags, ARNoFileSave);
|
||||
}
|
||||
|
||||
Serial.println(F("Camera capture success"));
|
||||
|
||||
#ifdef DEBUG
|
||||
Serial.print(F("First 8 bytes "));
|
||||
printarrayHEX(fb->buf, 0, 8);
|
||||
Serial.println();
|
||||
Serial.print(F("Last 8 bytes "));
|
||||
printarrayHEX(fb->buf, (fb->len - 8), 8);
|
||||
Serial.println();
|
||||
#endif
|
||||
|
||||
if (SDOK)
|
||||
{
|
||||
Serial.println(F("Save picture to SD card"));
|
||||
fs::FS &fs = SD_MMC; //save picture to microSD card
|
||||
File file = fs.open(path.c_str(), FILE_WRITE);
|
||||
if (!file)
|
||||
{
|
||||
Serial.println(F("*********************************************"));
|
||||
Serial.println(F("ERROR Failed to open SD file in writing mode"));
|
||||
Serial.println(F("*********************************************"));
|
||||
bitSet(ARDTflags, ARNoFileSave);
|
||||
}
|
||||
else
|
||||
{
|
||||
file.write(fb->buf, fb->len); // payload (image), payload length
|
||||
Serial.printf("Saved file to path: %s\r\n", path.c_str());
|
||||
}
|
||||
file.close();
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.println(F("***************"));
|
||||
Serial.println(F("No SD available"));
|
||||
Serial.println(F("***************"));
|
||||
}
|
||||
}
|
||||
|
||||
SD_MMC.end();
|
||||
if (setupLoRaDevice())
|
||||
{
|
||||
Serial.print(F("Send with LoRa "));
|
||||
Serial.println(path.c_str());
|
||||
uint8_t tempsize = path.length();
|
||||
path.toCharArray(filenamearray, tempsize + 1); //copy file name to the local filenamearray
|
||||
filenamearray[tempsize + 1] = 0; //ensure there is a null at end of filename in filenamearray
|
||||
sentOK = ARsendArray(fb->buf, fb->len, filenamearray, tempsize + 1); //pass array pointer and length across to LoRa send function
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.println(F("LoRa device not available"));
|
||||
}
|
||||
|
||||
esp_camera_fb_return(fb); //return the frame buffer back to the driver for reuse
|
||||
|
||||
delay(gapmS);
|
||||
|
||||
if (sentOK)
|
||||
{
|
||||
Serial.print(filenamearray);
|
||||
Serial.println(F(" Sent OK"));
|
||||
return pictureNumber;
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.print(filenamearray);
|
||||
Serial.println(F(" Send picture failed"));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void printarrayHEX(uint8_t *buff, uint32_t startaddr, uint32_t len)
|
||||
{
|
||||
uint32_t index;
|
||||
uint8_t buffdata;
|
||||
|
||||
for (index = startaddr; index < (startaddr + len); index++)
|
||||
{
|
||||
buffdata = buff[index];
|
||||
if (buffdata < 16)
|
||||
{
|
||||
Serial.print(F("0"));
|
||||
}
|
||||
Serial.print(buffdata, HEX);
|
||||
Serial.print(F(" "));
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,92 @@
|
||||
/*******************************************************************************************************
|
||||
Programs for Arduino - Copyright of the author Stuart Robinson - 19/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.
|
||||
*******************************************************************************************************/
|
||||
|
||||
//updated pinouts for 'ESP32CAM_Long_Range_Wireless_Adapter PCB dated 271121
|
||||
//Note transistor driving the White LED on pin 4, or the LED needs to be removed
|
||||
|
||||
#define NSS 12 //select on LoRa device
|
||||
#define NRESET 14 //reset pin on LoRa device
|
||||
#define RFBUSY 15 //busy pin on LoRa device
|
||||
#define SCK 4 //SCK on SPI3
|
||||
#define MISO 13 //MISO on SPI3
|
||||
#define MOSI 2 //MOSI on SPI3
|
||||
#define REDLED 33 //pin number for ESP32CAM on board red LED, set logic level low for on
|
||||
|
||||
#define LORA_DEVICE DEVICE_SX1280 //this is the device we are using
|
||||
|
||||
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 ACKdelaystartendmS = 25; //ms delay before ack sent at array start wrie and end write
|
||||
const uint32_t ACKsegtimeoutmS = 75; //mS to wait for receiving an ACK before re-trying transmit segment
|
||||
const uint32_t ACKopentimeoutmS = 500; //mS to wait for receiving an ACK before re-trying transmit file open
|
||||
const uint32_t ACKclosetimeoutmS = 500; //mS to wait for receiving an ACK before re-trying transmit file close
|
||||
const uint32_t DuplicatedelaymS = 25; //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 DTSegmentSize = 245; //number of bytes in each segment or payload
|
||||
const uint8_t ARDTfilenamesize = 32; //size of filename buffer
|
||||
|
||||
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 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 uint16_t NetworkID = 0x3210; //a unique identifier to go out with packet
|
||||
|
||||
const uint16_t SleepTimesecs = 15; //sleep time in seconds after each TX loop
|
||||
const uint32_t uS_TO_S_FACTOR = 1000000; //Conversion factor for micro seconds to seconds
|
||||
const uint8_t PicturesToTake = 1; //number of pictures to take at each wakeup, only last is sent via LoRa
|
||||
const uint32_t PictureDelaymS = 1000; //delay in mS between pictures
|
||||
|
||||
|
||||
#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
|
||||
|
||||
|
||||
// Pin definition for CAMERA_MODEL_AI_THINKER
|
||||
// Change pin definition if you're using another ESP32 with camera module
|
||||
#define PWDN_GPIO_NUM 32
|
||||
#define RESET_GPIO_NUM -1
|
||||
#define XCLK_GPIO_NUM 0
|
||||
#define SIOD_GPIO_NUM 26
|
||||
#define SIOC_GPIO_NUM 27
|
||||
#define Y9_GPIO_NUM 35
|
||||
#define Y8_GPIO_NUM 34
|
||||
#define Y7_GPIO_NUM 39
|
||||
#define Y6_GPIO_NUM 36
|
||||
#define Y5_GPIO_NUM 21
|
||||
#define Y4_GPIO_NUM 19
|
||||
#define Y3_GPIO_NUM 18
|
||||
#define Y2_GPIO_NUM 5
|
||||
#define VSYNC_GPIO_NUM 25
|
||||
#define HREF_GPIO_NUM 23
|
||||
#define PCLK_GPIO_NUM 22
|
||||
@ -0,0 +1,222 @@
|
||||
/*******************************************************************************************************
|
||||
Programs for Arduino - Copyright of the author Stuart Robinson - 20/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 receiver program for an ESP32CAM board that has an SPI LoRa module set up
|
||||
on the following pins; NSS 12, NRESET 14, SCK 4, MISO 13, MOSI 2, RFBUSY 15, 3.3V VCC and GND. All other
|
||||
pins on the SX128X are not connected. The received pictures are saved to the ESP32CAMs SD card.
|
||||
|
||||
Note that the white LED on pin 4 or the transistor controlling it need to be removed so that the LoRa
|
||||
device can properly use pin 4.
|
||||
|
||||
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 "FS.h" //SD Card ESP32
|
||||
#include "SD_MMC.h" //SD Card ESP32
|
||||
#include "soc/soc.h" //disable brownout problems
|
||||
#include "soc/rtc_cntl_reg.h" //disable brownout problems
|
||||
#include "driver/rtc_io.h"
|
||||
#include <SX128XLT.h> //SX12XX-LoRa library
|
||||
#include <ProgramLT_Definitions.h> //part of SX12XX-LoRa library
|
||||
#include "Settings.h" //LoRa settings etc.
|
||||
|
||||
#define ENABLEMONITOR //enable this define to monitor data transfer information, needed for ARtransferIRQ.h
|
||||
#define ENABLEARRAYCRC //enable this define to check and print CRC of sent array
|
||||
#define PRINTSEGMENTNUM //enable this define to print segment numbers during data transfer
|
||||
//#define DISABLEPAYLOADCRC //enable this define if you want to disable payload CRC checking
|
||||
//#define DEBUG //enable more detail of transfer progress
|
||||
|
||||
|
||||
SX128XLT LoRa; //create an SX128XLT library instance called LoRa
|
||||
#include <ARtransferIRQ.h>
|
||||
|
||||
uint8_t *PSRAMptr; //create a global pointer to the array to send, so all functions have access
|
||||
bool SDOK;
|
||||
bool savedtoSDOK;
|
||||
|
||||
|
||||
void loop()
|
||||
{
|
||||
uint32_t arraylength;
|
||||
SDOK = false;
|
||||
Serial.println(F("LoRa file transfer receiver ready"));
|
||||
setupLoRaDevice();
|
||||
|
||||
//if there is a successful array transfer the returned length > 0
|
||||
|
||||
arraylength = ARreceiveArray(PSRAMptr, sizeof(ARDTarraysize), ReceiveTimeoutmS);
|
||||
|
||||
SPI.end();
|
||||
|
||||
digitalWrite(NSS, HIGH);
|
||||
digitalWrite(NRESET, HIGH);
|
||||
|
||||
if (arraylength)
|
||||
{
|
||||
Serial.print(F("Returned picture length "));
|
||||
Serial.println(arraylength);
|
||||
if (initMicroSDCard())
|
||||
{
|
||||
SDOK = true;
|
||||
Serial.println("SD Card OK");
|
||||
Serial.print(ARDTfilenamebuff);
|
||||
Serial.println(F(" Save picture to SD card"));
|
||||
|
||||
fs::FS &fs = SD_MMC; //save picture to microSD card
|
||||
File file = fs.open(ARDTfilenamebuff, FILE_WRITE);
|
||||
if (!file)
|
||||
{
|
||||
Serial.println("*********************************************");
|
||||
Serial.println("ERROR Failed to open SD file in writing mode");
|
||||
Serial.println("*********************************************");
|
||||
savedtoSDOK = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
file.write(PSRAMptr, arraylength); // pointer to array and length
|
||||
Serial.print(ARDTfilenamebuff);
|
||||
Serial.println(" Saved to SD");
|
||||
savedtoSDOK = true;
|
||||
}
|
||||
file.close();
|
||||
SD_MMC.end();
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.println("No SD available");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.println(F("Error receiving picture"));
|
||||
if (ARDTArrayTimeout)
|
||||
{
|
||||
Serial.println(F("Timeout receiving picture"));
|
||||
}
|
||||
}
|
||||
Serial.println();
|
||||
}
|
||||
|
||||
|
||||
bool setupLoRaDevice()
|
||||
{
|
||||
SPI.begin(SCK, MISO, MOSI, NSS);
|
||||
|
||||
if (LoRa.begin(NSS, NRESET, RFBUSY, LORA_DEVICE))
|
||||
{
|
||||
Serial.println(F("LoRa device found"));
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.println(F("LoRa Device error"));
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef USELORA
|
||||
LoRa.setupLoRa(Frequency, Offset, SpreadingFactor, Bandwidth, CodeRate);
|
||||
Monitorport.println(F("Using LoRa packets"));
|
||||
#endif
|
||||
|
||||
#ifdef USEFLRC
|
||||
LoRa.setupFLRC(Frequency, Offset, BandwidthBitRate, CodingRate, BT, Syncword);
|
||||
Monitorport.println(F("Using FLRC packets"));
|
||||
#endif
|
||||
|
||||
#ifdef DISABLEPAYLOADCRC
|
||||
LoRa.setReliableConfig(NoReliableCRC);
|
||||
#endif
|
||||
|
||||
if (LoRa.getReliableConfig(NoReliableCRC))
|
||||
{
|
||||
Serial.println(F("Payload CRC disabled"));
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.println(F("Payload CRC enabled"));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool initMicroSDCard()
|
||||
{
|
||||
if (!SD_MMC.begin("/sdcard", true)) //use this line for 1 bit mode, pin 2 only, 4,12,13 not used
|
||||
{
|
||||
Serial.println("*****************************");
|
||||
Serial.println("ERROR - SD Card Mount Failed");
|
||||
Serial.println("*****************************");
|
||||
return false;
|
||||
}
|
||||
|
||||
uint8_t cardType = SD_MMC.cardType();
|
||||
|
||||
if (cardType == CARD_NONE)
|
||||
{
|
||||
Serial.println("No SD Card found");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void led_Flash(uint16_t flashes, uint16_t delaymS)
|
||||
{
|
||||
uint16_t index;
|
||||
for (index = 1; index <= flashes; index++)
|
||||
{
|
||||
digitalWrite(REDLED, HIGH);
|
||||
delay(delaymS);
|
||||
digitalWrite(REDLED, LOW);
|
||||
delay(delaymS);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void setup()
|
||||
{
|
||||
uint32_t available_PSRAM_size;
|
||||
uint32_t new_available_PSRAM_size;
|
||||
|
||||
//WRITE_PERI_REG(RTC_CNTL_BROWN_OUT_REG, 0); //disable brownout detector
|
||||
pinMode(REDLED, OUTPUT); //setup pin as output for indicator LED
|
||||
led_Flash(2, 125); //two quick LED flashes to indicate program start
|
||||
ARsetDTLED(REDLED); //setup LED pin for data transfer indicator
|
||||
|
||||
digitalWrite(NSS, HIGH);
|
||||
pinMode(NSS, OUTPUT); //disable LoRa device for now
|
||||
|
||||
Serial.begin(115200); //format is Serial.begin(baud-rate, protocol, RX pin, TX pin);
|
||||
Serial.println();
|
||||
Serial.println(__FILE__);
|
||||
|
||||
if (psramInit())
|
||||
{
|
||||
Serial.println("PSRAM is correctly initialised");
|
||||
available_PSRAM_size = ESP.getFreePsram();
|
||||
Serial.println((String)"PSRAM Size available: " + available_PSRAM_size);
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.println("PSRAM not available");
|
||||
while (1);
|
||||
}
|
||||
|
||||
Serial.println("Allocate array in PSRAM");
|
||||
uint8_t *byte_array = (uint8_t *) ps_malloc(ARDTarraysize * sizeof(uint8_t));
|
||||
PSRAMptr = byte_array; //save the pointe to byte_array to global pointer
|
||||
|
||||
new_available_PSRAM_size = ESP.getFreePsram();
|
||||
Serial.println((String)"PSRAM Size available: " + new_available_PSRAM_size);
|
||||
Serial.print("PSRAM array bytes allocated: ");
|
||||
Serial.println(available_PSRAM_size - new_available_PSRAM_size);
|
||||
Serial.println();
|
||||
}
|
||||
@ -0,0 +1,63 @@
|
||||
/*******************************************************************************************************
|
||||
Programs for Arduino - Copyright of the author Stuart Robinson - 20/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 12 //select on LoRa device
|
||||
#define NRESET 14 //reset pin on LoRa device
|
||||
#define RFBUSY 15 //busy pin on LoRa device
|
||||
#define SCK 4 //SCK on SPI3
|
||||
#define MISO 13 //MISO on SPI3
|
||||
#define MOSI 2 //MOSI on SPI3
|
||||
#define REDLED 33 //pin number for ESP32CAM on board red LED, set logic level low for on
|
||||
|
||||
#define LORA_DEVICE DEVICE_SX1280 //this is the device we are using
|
||||
|
||||
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 = 3000000; //mS to wait for receiving a packet
|
||||
const uint32_t ACKdelaymS = 0; //ms delay after general packet actioned and ack sent
|
||||
const uint32_t ACKdelaystartendmS = 25; //ms delay before ack sent at array start wrie and end write
|
||||
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 = 25; //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 uint32_t ReceiveTimeoutmS = 60000; //mS waiting for array transfer before timeout
|
||||
const uint8_t HeaderSizeMax = 12; //max size of header in bytes, minimum size is 6 bytes
|
||||
const uint8_t DataSizeMax = 245; //max size of data array in bytes
|
||||
const uint8_t ARDTfilenamesize = 32; //size of DTfilename buffer used by array transfer functions
|
||||
const uint32_t ARDTarraysize = 0x20000; //maximum file\array size to receive
|
||||
const uint16_t NetworkID = 0x3210; //a unique identifier to go out with packet
|
||||
|
||||
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
|
||||
|
||||
#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,253 @@
|
||||
/*******************************************************************************************************
|
||||
Programs for Arduino - Copyright of the author Stuart Robinson - 20/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 receiver program for an ESP32CAM board that has an SPI LoRa module set up
|
||||
on the following pins; NSS 12, NRESET 14, SCK 4, MISO 13, MOSI 2, RFBUSY 15, 3.3V VCC and GND. All other
|
||||
pins on the SX128X are not connected. The received pictures are saved to the ESP32CAMs SD card and also
|
||||
transferred to a connected PC using the YModem protocol over the normal program upload port. Progress
|
||||
or debug messages can be seen by connection an additional serial adapter to pin 33 on the ESP32CAM.
|
||||
|
||||
For details of the PC upload process see here;
|
||||
|
||||
https://stuartsprojects.github.io/2022/02/05/Long-Range-Wireless-Adapter-for-ESP32CAM.html
|
||||
|
||||
Note that the white LED on pin 4 or the transistor controlling it need to be removed so that the LoRa
|
||||
device can properly use pin 4.
|
||||
|
||||
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 "FS.h" //SD Card ESP32
|
||||
#include "SD_MMC.h" //SD Card ESP32
|
||||
#include "soc/soc.h" //disable brownout problems
|
||||
#include "soc/rtc_cntl_reg.h" //disable brownout problems
|
||||
#include "driver/rtc_io.h"
|
||||
#include <SX128XLT.h> //SX12XX-LoRa library
|
||||
#include <ProgramLT_Definitions.h> //part of SX12XX-LoRa library
|
||||
#include "Settings.h" //LoRa settings etc.
|
||||
|
||||
#define ENABLEMONITOR //enable this define to monitor data transfer information, needed for ARtransferIRQ.h
|
||||
#define ENABLEARRAYCRC //enable this define to check and print CRC of sent array
|
||||
#define PRINTSEGMENTNUM //enable this define to print segment numbers during data transfer
|
||||
//#define DISABLEPAYLOADCRC //enable this define if you want to disable payload CRC checking
|
||||
//#define DEBUG //enable more detail of transfer progress
|
||||
|
||||
|
||||
SX128XLT LoRa; //create an SX128XLT library instance called LoRa
|
||||
#include <ARtransferIRQ.h>
|
||||
|
||||
uint8_t *PSRAMptr; //create a global pointer to the array to send, so all functions have access
|
||||
bool SDOK;
|
||||
bool savedtoSDOK;
|
||||
|
||||
#include "YModemArray.h"
|
||||
|
||||
|
||||
void loop()
|
||||
{
|
||||
uint32_t arraylength, bytestransfered;
|
||||
SDOK = false;
|
||||
Monitorport.println(F("LoRa file transfer receiver ready"));
|
||||
|
||||
setupLoRaDevice();
|
||||
|
||||
//if there is a successful array transfer the returned length > 0
|
||||
//arraylength = LocalARreceiveArray(PSRAMptr, sizeof(ARDTarraysize), ReceiveTimeoutmS);
|
||||
|
||||
arraylength = ARreceiveArray(PSRAMptr, sizeof(ARDTarraysize), ReceiveTimeoutmS);
|
||||
|
||||
SPI.end();
|
||||
|
||||
digitalWrite(NSS, HIGH);
|
||||
digitalWrite(NRESET, HIGH);
|
||||
|
||||
if (arraylength)
|
||||
{
|
||||
Monitorport.print(F("Returned picture length "));
|
||||
Monitorport.println(arraylength);
|
||||
if (initMicroSDCard())
|
||||
{
|
||||
SDOK = true;
|
||||
Monitorport.println("SD Card OK");
|
||||
Monitorport.print(ARDTfilenamebuff);
|
||||
Monitorport.println(F(" Save picture to SD card"));
|
||||
|
||||
fs::FS &fs = SD_MMC; //save picture to microSD card
|
||||
File file = fs.open(ARDTfilenamebuff, FILE_WRITE);
|
||||
if (!file)
|
||||
{
|
||||
Monitorport.println("*********************************************");
|
||||
Monitorport.println("ERROR Failed to open SD file in writing mode");
|
||||
Monitorport.println("*********************************************");
|
||||
savedtoSDOK = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
file.write(PSRAMptr, arraylength); // pointer to array and length
|
||||
Monitorport.print(ARDTfilenamebuff);
|
||||
Monitorport.println(" Saved to SD");
|
||||
savedtoSDOK = true;
|
||||
}
|
||||
file.close();
|
||||
SD_MMC.end();
|
||||
}
|
||||
else
|
||||
{
|
||||
Monitorport.println("No SD available");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Monitorport.println(F("Error receiving picture"));
|
||||
if (ARDTArrayTimeout)
|
||||
{
|
||||
Monitorport.println(F("Timeout receiving picture"));
|
||||
}
|
||||
}
|
||||
Monitorport.println();
|
||||
|
||||
if (arraylength)
|
||||
{
|
||||
Monitorport.println(F("File received - start YModem transfer to PC"));
|
||||
|
||||
//bytestransfered = yModemSend(ARDTfilenamebuff, 1, 1);
|
||||
bytestransfered = yModemSend(ARDTfilenamebuff, PSRAMptr, arraylength, 1, 1);
|
||||
|
||||
if (bytestransfered > 0)
|
||||
{
|
||||
Monitorport.print(F("YModem transfer completed "));
|
||||
Monitorport.print(bytestransfered);
|
||||
Monitorport.println(F(" bytes sent"));
|
||||
}
|
||||
else
|
||||
{
|
||||
Monitorport.println(F("YModem transfer FAILED"));
|
||||
}
|
||||
Monitorport.println();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool setupLoRaDevice()
|
||||
{
|
||||
SPI.begin(SCK, MISO, MOSI, NSS);
|
||||
|
||||
if (LoRa.begin(NSS, NRESET, RFBUSY, LORA_DEVICE))
|
||||
{
|
||||
Monitorport.println(F("LoRa device found"));
|
||||
}
|
||||
else
|
||||
{
|
||||
Monitorport.println(F("LoRa Device error"));
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef USELORA
|
||||
LoRa.setupLoRa(Frequency, Offset, SpreadingFactor, Bandwidth, CodeRate);
|
||||
Monitorport.println(F("Using LoRa packets"));
|
||||
#endif
|
||||
|
||||
#ifdef USEFLRC
|
||||
LoRa.setupFLRC(Frequency, Offset, BandwidthBitRate, CodingRate, BT, Syncword);
|
||||
Monitorport.println(F("Using FLRC packets"));
|
||||
#endif
|
||||
|
||||
#ifdef DISABLEPAYLOADCRC
|
||||
LoRa.setReliableConfig(NoReliableCRC);
|
||||
#endif
|
||||
|
||||
if (LoRa.getReliableConfig(NoReliableCRC))
|
||||
{
|
||||
Monitorport.println(F("Payload CRC disabled"));
|
||||
}
|
||||
else
|
||||
{
|
||||
Monitorport.println(F("Payload CRC enabled"));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool initMicroSDCard()
|
||||
{
|
||||
if (!SD_MMC.begin("/sdcard", true)) //use this line for 1 bit mode, pin 2 only, 4,12,13 not used
|
||||
{
|
||||
Monitorport.println("*****************************");
|
||||
Monitorport.println("ERROR - SD Card Mount Failed");
|
||||
Monitorport.println("*****************************");
|
||||
return false;
|
||||
}
|
||||
|
||||
uint8_t cardType = SD_MMC.cardType();
|
||||
|
||||
if (cardType == CARD_NONE)
|
||||
{
|
||||
Monitorport.println("No SD Card found");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void led_Flash(uint16_t flashes, uint16_t delaymS)
|
||||
{
|
||||
uint16_t index;
|
||||
for (index = 1; index <= flashes; index++)
|
||||
{
|
||||
digitalWrite(REDLED, HIGH);
|
||||
delay(delaymS);
|
||||
digitalWrite(REDLED, LOW);
|
||||
delay(delaymS);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void setup()
|
||||
{
|
||||
uint32_t available_PSRAM_size;
|
||||
uint32_t new_available_PSRAM_size;
|
||||
|
||||
//WRITE_PERI_REG(RTC_CNTL_BROWN_OUT_REG, 0); //disable brownout detector
|
||||
pinMode(REDLED, OUTPUT); //setup pin as output for indicator LED
|
||||
led_Flash(2, 125); //two quick LED flashes to indicate program start
|
||||
ARsetDTLED(REDLED); //setup LED pin for data transfer indicator
|
||||
|
||||
digitalWrite(NSS, HIGH);
|
||||
pinMode(NSS, OUTPUT); //disable LoRa device for now
|
||||
|
||||
YModemSerial.begin(115200);
|
||||
Monitorport.begin(115200, SERIAL_8N1, RXD2, TXD2); //monitor port, format is Monitorport.begin(baud-rate, protocol, RX pin, TX pin);
|
||||
Monitorport.println();
|
||||
Monitorport.println(__FILE__);
|
||||
|
||||
if (psramInit())
|
||||
{
|
||||
Monitorport.println("PSRAM is correctly initialised");
|
||||
available_PSRAM_size = ESP.getFreePsram();
|
||||
Monitorport.println((String)"PSRAM Size available: " + available_PSRAM_size);
|
||||
}
|
||||
else
|
||||
{
|
||||
Monitorport.println("PSRAM not available");
|
||||
while (1);
|
||||
}
|
||||
|
||||
Monitorport.println("Allocate array in PSRAM");
|
||||
uint8_t *byte_array = (uint8_t *) ps_malloc(ARDTarraysize * sizeof(uint8_t));
|
||||
PSRAMptr = byte_array; //save the pointe to byte_array to global pointer
|
||||
|
||||
new_available_PSRAM_size = ESP.getFreePsram();
|
||||
Monitorport.println((String)"PSRAM Size available: " + new_available_PSRAM_size);
|
||||
Monitorport.print("PSRAM array bytes allocated: ");
|
||||
Monitorport.println(available_PSRAM_size - new_available_PSRAM_size);
|
||||
Monitorport.println();
|
||||
}
|
||||
@ -0,0 +1,69 @@
|
||||
/*******************************************************************************************************
|
||||
Programs for Arduino - Copyright of the author Stuart Robinson - 20/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 12 //select on LoRa device
|
||||
#define NRESET 14 //reset pin on LoRa device
|
||||
#define RFBUSY 15 //busy pin on LoRa device
|
||||
#define SCK 4 //SCK on SPI3
|
||||
#define MISO 13 //MISO on SPI3
|
||||
#define MOSI 2 //MOSI on SPI3
|
||||
#define REDLED 33 //pin number for ESP32CAM on board red LED, set logic level low for on
|
||||
|
||||
#define RXD2 40 //RX pin for monitor port, not used
|
||||
#define TXD2 33 //TX pin for monitor port
|
||||
|
||||
#define LORA_DEVICE DEVICE_SX1280 //this is the device we are using
|
||||
|
||||
#define YModemSerial Serial
|
||||
#define Monitorport Serial2
|
||||
|
||||
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 = 3000000; //mS to wait for receiving a packet
|
||||
const uint32_t ACKdelaymS = 0; //ms delay after general packet actioned and ack sent
|
||||
const uint32_t ACKdelaystartendmS = 25; //ms delay before ack sent at array start wrie and end write
|
||||
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 = 25; //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 uint32_t ReceiveTimeoutmS = 60000; //mS waiting for array transfer before timeout
|
||||
const uint8_t HeaderSizeMax = 12; //max size of header in bytes, minimum size is 6 bytes
|
||||
const uint8_t DataSizeMax = 245; //max size of data array in bytes
|
||||
const uint8_t ARDTfilenamesize = 32; //size of DTfilename buffer used by array transfer functions
|
||||
const uint32_t ARDTarraysize = 0x20000; //maximum file\array size to receive
|
||||
const uint16_t NetworkID = 0x3210; //a unique identifier to go out with packet
|
||||
|
||||
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
|
||||
|
||||
#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,280 @@
|
||||
// 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
|
||||
|
||||
//Revised code 02/01/22, changed for ESP32;
|
||||
//sprintf(spfBuff, "%ld", numBytesStillToSend); to sprintf(spfBuff, "%lu", numBytesStillToSend);
|
||||
//uint32_t numBytesStillToSend = 0; to long unsigned int numBytesStillToSend = 0;
|
||||
//numBytesThisPacket = min( numBytesStillToSend, sizeof(yPacket.payload)); to numBytesThisPacket = min( (uint32_t) numBytesStillToSend, sizeof(yPacket.payload));
|
||||
|
||||
//Revised code 05/01/22, changed;
|
||||
//Organised YModem transfer to operate from previously filled memor array rather then and SD file
|
||||
|
||||
//Revised code 28/01/22 to stop transfer hanging if PC receiving YModem stops responding
|
||||
|
||||
#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 uint32_t yModemSend(const char *filename, uint8_t *arraydata, uint32_t arraysize, int waitForReceiver, int batchMode )
|
||||
{
|
||||
//*filename is pointer to filename
|
||||
//*arraydata is pointer to the transferred array
|
||||
//arraysize is the lengrth of data to transfer
|
||||
|
||||
//uint32_t numBytesStillToSend = 0;
|
||||
long unsigned int 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 index;
|
||||
uint32_t arraybytescopied = 0;
|
||||
uint32_t startmS;
|
||||
|
||||
uint8_t ackerrors = 0;
|
||||
|
||||
if (arraysize > ARDTarraysize)
|
||||
{
|
||||
Monitorport.println("Array too big");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// get the size of the file and convert to an ASCII representation for header packet
|
||||
numBytesStillToSend = arraysize;
|
||||
sprintf(spfBuff, "%lu", numBytesStillToSend);
|
||||
|
||||
// wait here for the receiving device to respond
|
||||
if (waitForReceiver)
|
||||
{
|
||||
Monitorport.println("Waiting for receiver ping ...");
|
||||
while ( YModemSerial.available() ) YModemSerial.read();
|
||||
|
||||
startmS = millis();
|
||||
|
||||
do
|
||||
{
|
||||
if (YModemSerial.available()) answer = YModemSerial.read();
|
||||
}
|
||||
while ((answer != 'C') && ((uint32_t) (millis() - startmS) < transfertimeoutmS));
|
||||
}
|
||||
|
||||
if (answer != 'C')
|
||||
{
|
||||
Monitorport.println("Timeout starting YModem transfer");
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
Monitorport.println("done");
|
||||
}
|
||||
|
||||
Monitorport.print("Ymodem Sending ");
|
||||
Monitorport.println(filename);
|
||||
Monitorport.print(spfBuff);
|
||||
Monitorport.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 ); //spfBuff is file size ?
|
||||
|
||||
// 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( (uint32_t) numBytesStillToSend, sizeof(yPacket.payload));
|
||||
|
||||
//now fill yPacket.payload with numBytesThisPacket from arraydata
|
||||
for (index = 0; index < numBytesThisPacket; index++)
|
||||
{
|
||||
yPacket.payload[index] = arraydata[arraybytescopied];
|
||||
arraybytescopied++;
|
||||
}
|
||||
|
||||
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
|
||||
YModemSerial.write( (uint8_t*) &yPacket, sizeof(yPacket));
|
||||
|
||||
// wait for the receiver to send back a response to the packet
|
||||
startmS = millis();
|
||||
while ((!YModemSerial.available()) && ((uint32_t) (millis() - startmS) < transfertimeoutmS));
|
||||
if (!YModemSerial.available())
|
||||
{
|
||||
Monitorport.println("Timeout waiting YModem response");
|
||||
return 0;
|
||||
}
|
||||
|
||||
answer = YModemSerial.read();
|
||||
|
||||
switch (answer)
|
||||
{
|
||||
case X_NAK:
|
||||
//something went wrong - send the same packet again?
|
||||
Monitorport.print("N");
|
||||
ackerrors++;
|
||||
break;
|
||||
|
||||
case X_ACK:
|
||||
//got ACK to move to the next block of data
|
||||
Monitorport.print(".");
|
||||
doNextBlock = 1;
|
||||
break;
|
||||
|
||||
default:
|
||||
//unknown response
|
||||
Monitorport.print("?");
|
||||
ackerrors++;
|
||||
break;
|
||||
}
|
||||
|
||||
if (ackerrors >= ackerrorlimit)
|
||||
{
|
||||
Monitorport.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 ((!YModemSerial.available()) && ((uint32_t) (millis() - startmS) < transfertimeoutmS));
|
||||
if (!YModemSerial.available())
|
||||
{
|
||||
Monitorport.println("Timeout waiting YModem response");
|
||||
return 0;
|
||||
}
|
||||
|
||||
answer = YModemSerial.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
|
||||
YModemSerial.write(X_EOT);
|
||||
|
||||
// need to send EOT again for YMODEM
|
||||
startmS = millis();
|
||||
while ((!YModemSerial.available()) && ((uint32_t) (millis() - startmS) < transfertimeoutmS));
|
||||
if (!YModemSerial.available())
|
||||
{
|
||||
Monitorport.println("Timeout waiting YModem response");
|
||||
return 0;
|
||||
}
|
||||
|
||||
answer = YModemSerial.read();
|
||||
YModemSerial.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)));
|
||||
YModemSerial.write( (uint8_t*)&yPacket, sizeof(yPacket));
|
||||
}
|
||||
|
||||
Monitorport.println("done");
|
||||
return arraybytescopied;
|
||||
}
|
||||
@ -0,0 +1,200 @@
|
||||
/*******************************************************************************************************
|
||||
Programs for Arduino - Copyright of the author Stuart Robinson - 19/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 for receiving files transmitted by LoRa and saving them to SD card
|
||||
and then optionally transfering them to a PC using a second serial port and the Ymodem protocol. Arduino
|
||||
DUEs were used for testing the program, these have multiple hardware Serial ports.
|
||||
|
||||
Progress messages on the transfer are sent to the IDE Serial monitor and printed on a connected ILI9341
|
||||
TFT display.
|
||||
|
||||
For details of the PC upload process see here;
|
||||
|
||||
https://stuartsprojects.github.io/2022/01/01/StuartCAM-ESP32CAM-Getting-the-Pictures-Onto-a-PC.html
|
||||
|
||||
|
||||
Serial monitor baud rate is set at 115200.
|
||||
*******************************************************************************************************/
|
||||
|
||||
#include <SPI.h>
|
||||
#include <SX128XLT.h>
|
||||
#include <ProgramLT_Definitions.h>
|
||||
|
||||
#define USELORA //enable this define to use LoRa packets
|
||||
//#define USEFLRC //enable this define to use FLRC packets
|
||||
#include "Settings.h" //LoRa settings etc.
|
||||
SX128XLT LoRa; //create an SX128XLT library instance called LoRa, required by SDtransfer
|
||||
|
||||
//#define SDLIB //define SDLIB for SD.h or SDFATLIB for SDfat.h
|
||||
#define SDFATLIB
|
||||
#include "DTSDlibrary.h"
|
||||
|
||||
#include "Adafruit_GFX.h" //get library here > https://github.com/adafruit/Adafruit-GFX-Library
|
||||
#include "Adafruit_ILI9341.h" //get library here > https://github.com/adafruit/Adafruit_ILI9341
|
||||
Adafruit_ILI9341 disp = Adafruit_ILI9341(DISPCS, DISPDC, DISPRESET); //for dispaly defaults, textsize and rotation, see Settings.h
|
||||
|
||||
#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
|
||||
#define ENABLEPCTRANSFER //enable this define for YModem transfer to PC
|
||||
|
||||
#include "SDtransferDisplay.h" //library of data transfer with display functions
|
||||
#include "YModem.h" //YModem for the the save SD File
|
||||
|
||||
uint32_t bytestransfered; //bytes transfered via YModem
|
||||
|
||||
|
||||
void loop()
|
||||
{
|
||||
SDreceiveaPacketDT();
|
||||
|
||||
#ifdef ENABLEPCTRANSFER
|
||||
if (SDDTFileSaved)
|
||||
{
|
||||
Monitorport.println(F("File saved to SD - start YModem transfer to PC"));
|
||||
setCursor(0, 4);
|
||||
disp.print(F("Run YModem"));
|
||||
digitalWrite(LED1, HIGH);
|
||||
setCursor(0, 6);
|
||||
disp.print(F(" ")); //clear segment number
|
||||
|
||||
bytestransfered = yModemSend(SDDTfilenamebuff, 1, 1);
|
||||
|
||||
if (bytestransfered > 0)
|
||||
{
|
||||
Monitorport.print(F("YModem transfer completed "));
|
||||
Monitorport.print(bytestransfered);
|
||||
Monitorport.println(F(" bytes sent"));
|
||||
}
|
||||
else
|
||||
{
|
||||
Monitorport.println(F("YModem transfer FAILED"));
|
||||
}
|
||||
Monitorport.println();
|
||||
|
||||
setCursor(0, 4);
|
||||
disp.print(F(" "));
|
||||
digitalWrite(LED1, LOW);
|
||||
SDDTFileSaved = false;
|
||||
//Monitorport.println(F("YModem transfer finished"));
|
||||
//Monitorport.println();
|
||||
Monitorport.println(F("Wait for file"));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
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
|
||||
|
||||
YModemSerial.begin(115200);
|
||||
|
||||
#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
|
||||
}
|
||||
|
||||
disp.begin();
|
||||
disp.fillScreen(ILI9341_BLACK);
|
||||
disp.setTextColor(ILI9341_WHITE, ILI9341_BLACK);
|
||||
disp.setRotation(rotation);
|
||||
disp.setTextSize(textscale);
|
||||
setCursor(0, 0);
|
||||
disp.print(F("Waiting File"));
|
||||
|
||||
SDDTSegmentNext = 0;
|
||||
SDDTFileOpened = false;
|
||||
SDDTFileSaved = false; //file has not been saved to SD yet
|
||||
|
||||
#ifdef ENABLEMONITOR
|
||||
Monitorport.println(F("SDfile transfer receiver ready"));
|
||||
Monitorport.println();
|
||||
#endif
|
||||
}
|
||||
@ -0,0 +1,461 @@
|
||||
/*******************************************************************************************************
|
||||
Programs for Arduino - Copyright of the author Stuart Robinson - 19/03/22
|
||||
|
||||
This code 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.
|
||||
*******************************************************************************************************/
|
||||
|
||||
#ifdef SDFATLIB
|
||||
#include <SdFat.h>
|
||||
SdFat SD;
|
||||
File dataFile; //name the file instance needed for SD library routines
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef SDLIB
|
||||
#include <SD.h>
|
||||
File dataFile; //name the file instance needed for SD library routines
|
||||
#endif
|
||||
|
||||
#ifndef Monitorport
|
||||
#define Monitorport Serial //output to Serial if no other port defined
|
||||
#endif
|
||||
|
||||
bool DTSD_dumpFileASCII(char *buff);
|
||||
bool DTSD_dumpFileHEX(char *buff);
|
||||
bool DTSD_dumpSegmentHEX(uint8_t segmentsize);
|
||||
bool DTSD_initSD(uint8_t CSpin);
|
||||
uint32_t DTSD_getFileSize(char *buff);
|
||||
void DTSD_printDirectory();
|
||||
uint32_t DTSD_openFileRead(char *buff);
|
||||
uint16_t DTSD_getNumberSegments(uint32_t filesize, uint8_t segmentsize);
|
||||
uint8_t DTSD_getLastSegmentSize(uint32_t filesize, uint8_t segmentsize);
|
||||
bool DTSD_openNewFileWrite(char *buff);
|
||||
bool DTSD_openFileWrite(char *buff, uint32_t position);
|
||||
uint8_t DTSD_readFileSegment(uint8_t *buff, uint8_t segmentsize);
|
||||
uint8_t DTSD_writeSegmentFile(uint8_t *buff, uint8_t segmentsize);
|
||||
void DTSD_seekFileLocation(uint32_t position);
|
||||
uint16_t DTSD_createFile(char *buff);
|
||||
uint16_t DTSD_fileCRCCCITT();
|
||||
void DTSD_fileFlush();
|
||||
void DTSD_closeFile();
|
||||
void printDirectorySD(File dir, int numTabs);
|
||||
|
||||
|
||||
bool DTSD_dumpFileASCII(char *buff)
|
||||
{
|
||||
|
||||
File dataFile = SD.open(buff); //open the test file note that only one file can be open at a time,
|
||||
|
||||
if (dataFile) //if the file is available, read from it
|
||||
{
|
||||
while (dataFile.available())
|
||||
{
|
||||
Monitorport.write(dataFile.read());
|
||||
}
|
||||
dataFile.close();
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool DTSD_dumpFileHEX(char *buff)
|
||||
{
|
||||
//Note, this function will return true if the SD card is removed.
|
||||
uint16_t Loopv1, Loopv2;
|
||||
uint8_t fileData;
|
||||
uint32_t filesize;
|
||||
|
||||
if (!SD.exists(buff))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
dataFile = SD.open(buff);
|
||||
filesize = dataFile.size();
|
||||
filesize--; //file data locations are from 0 to (filesize -1);
|
||||
Monitorport.print(F("Lcn 0 1 2 3 4 5 6 7 8 9 A B C D E F"));
|
||||
Monitorport.println();
|
||||
|
||||
if (dataFile) //if the file is available, read from it
|
||||
{
|
||||
while (dataFile.available())
|
||||
{
|
||||
for (Loopv1 = 0; Loopv1 <= filesize;)
|
||||
{
|
||||
Monitorport.print(F("0x"));
|
||||
if (Loopv1 < 0x10)
|
||||
{
|
||||
Monitorport.print(F("0"));
|
||||
}
|
||||
Monitorport.print((Loopv1), HEX);
|
||||
Monitorport.print(F(" "));
|
||||
for (Loopv2 = 0; Loopv2 <= 15; Loopv2++)
|
||||
{
|
||||
fileData = dataFile.read();
|
||||
if (fileData < 0x10)
|
||||
{
|
||||
Monitorport.print(F("0"));
|
||||
}
|
||||
Monitorport.print(fileData, HEX);
|
||||
Monitorport.print(F(" "));
|
||||
Loopv1++;
|
||||
}
|
||||
Monitorport.println();
|
||||
}
|
||||
}
|
||||
dataFile.close();
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
Monitorport.println(F("File not available"));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool DTSD_initSD(uint8_t CSpin)
|
||||
{
|
||||
if (SD.begin(CSpin))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
#ifdef SDFATLIB
|
||||
void DTSD_printDirectory()
|
||||
{
|
||||
dataFile = SD.open("/");
|
||||
Monitorport.println(F("Card directory"));
|
||||
SD.ls("/", LS_R);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef SDLIB
|
||||
void DTSD_printDirectory()
|
||||
{
|
||||
dataFile = SD.open("/");
|
||||
|
||||
printDirectorySD(dataFile, 0);
|
||||
|
||||
Monitorport.println();
|
||||
}
|
||||
|
||||
|
||||
void printDirectorySD(File dir, int numTabs)
|
||||
{
|
||||
|
||||
while (true)
|
||||
{
|
||||
File entry = dir.openNextFile();
|
||||
|
||||
if (! entry)
|
||||
{
|
||||
//no more files
|
||||
break;
|
||||
}
|
||||
|
||||
for (uint8_t i = 0; i < numTabs; i++)
|
||||
{
|
||||
Monitorport.print('\t');
|
||||
}
|
||||
|
||||
Monitorport.print(entry.name());
|
||||
|
||||
if (entry.isDirectory())
|
||||
{
|
||||
Monitorport.println("/");
|
||||
printDirectorySD(entry, numTabs + 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
// files have sizes, directories do not
|
||||
Monitorport.print("\t\t");
|
||||
Monitorport.println(entry.size(), DEC);
|
||||
}
|
||||
entry.close();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
bool DTSD_dumpSegmentHEX(uint8_t segmentsize)
|
||||
{
|
||||
uint16_t Loopv1, Loopv2;
|
||||
uint8_t fileData;
|
||||
|
||||
Monitorport.print(F("Print segment of "));
|
||||
Monitorport.print(segmentsize);
|
||||
Monitorport.println(F(" bytes"));
|
||||
Monitorport.print(F("Lcn 0 1 2 3 4 5 6 7 8 9 A B C D E F"));
|
||||
Monitorport.println();
|
||||
|
||||
if (dataFile) //if the file is available, read from it
|
||||
{
|
||||
for (Loopv1 = 0; Loopv1 < segmentsize;)
|
||||
{
|
||||
Monitorport.print(F("0x"));
|
||||
if (Loopv1 < 0x10)
|
||||
{
|
||||
Monitorport.print(F("0"));
|
||||
}
|
||||
Monitorport.print((Loopv1), HEX);
|
||||
Monitorport.print(F(" "));
|
||||
for (Loopv2 = 0; Loopv2 <= 15; Loopv2++)
|
||||
{
|
||||
//stop printing if all of segment has been printed
|
||||
if (Loopv1 < segmentsize)
|
||||
{
|
||||
fileData = dataFile.read();
|
||||
if (fileData < 0x10)
|
||||
{
|
||||
Monitorport.print(F("0"));
|
||||
}
|
||||
Monitorport.print(fileData, HEX);
|
||||
Monitorport.print(F(" "));
|
||||
Loopv1++;
|
||||
}
|
||||
}
|
||||
Monitorport.println();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
uint32_t DTSD_openFileRead2(char *buff)
|
||||
{
|
||||
uint32_t filesize;
|
||||
|
||||
dataFile = SD.open(buff);
|
||||
filesize = dataFile.size();
|
||||
dataFile.seek(0);
|
||||
return filesize;
|
||||
}
|
||||
|
||||
|
||||
uint32_t DTSD_openFileRead(char *buff)
|
||||
{
|
||||
uint32_t filesize;
|
||||
|
||||
if (SD.exists(buff))
|
||||
{
|
||||
//Monitorport.println(F("File exists"));
|
||||
dataFile = SD.open(buff);
|
||||
filesize = dataFile.size();
|
||||
dataFile.seek(0);
|
||||
return filesize;
|
||||
}
|
||||
else
|
||||
{
|
||||
//Monitorport.println(F("File does not exist"));
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
bool DTSD_openNewFileWrite(char *buff)
|
||||
{
|
||||
if (SD.exists(buff))
|
||||
{
|
||||
//Monitorport.print(buff);
|
||||
//Monitorport.println(F(" File exists - deleting"));
|
||||
SD.remove(buff);
|
||||
}
|
||||
|
||||
if (dataFile = SD.open(buff, FILE_WRITE))
|
||||
{
|
||||
//Monitorport.print(buff);
|
||||
//Monitorport.println(F(" SD File opened"));
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
//Monitorport.print(buff);
|
||||
//Monitorport.println(F(" ERROR opening file"));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool DTSD_openFileWrite(char *buff, uint32_t position)
|
||||
{
|
||||
dataFile = SD.open(buff, FILE_WRITE); //seems to operate as append
|
||||
dataFile.seek(position); //seek to first position in file
|
||||
|
||||
if (dataFile)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
uint8_t DTSD_readFileSegment(uint8_t *buff, uint8_t segmentsize)
|
||||
{
|
||||
uint8_t index = 0;
|
||||
uint8_t fileData;
|
||||
|
||||
while (index < segmentsize)
|
||||
{
|
||||
fileData = (uint8_t) dataFile.read();
|
||||
buff[index] = fileData;
|
||||
index++;
|
||||
};
|
||||
|
||||
if (index == segmentsize)
|
||||
{
|
||||
return segmentsize; //if all written return segment size
|
||||
}
|
||||
else
|
||||
{
|
||||
return index - 1; //if not all written return number bytes read
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
uint8_t DTSD_writeSegmentFile(uint8_t *buff, uint8_t segmentsize)
|
||||
{
|
||||
uint8_t index, byteswritten = 0;
|
||||
|
||||
for (index = 0; index < segmentsize; index++)
|
||||
{
|
||||
dataFile.write(buff[index]);
|
||||
byteswritten++;
|
||||
}
|
||||
return byteswritten;
|
||||
}
|
||||
|
||||
|
||||
void DTSD_seekFileLocation(uint32_t position)
|
||||
{
|
||||
dataFile.seek(position); //seek to position in file
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
uint16_t DTSD_createFile(char *buff)
|
||||
{
|
||||
//creats a new filename use this definition as the base;
|
||||
//char filename[] = "/SD0000.txt"; //filename used as base for creating logfile, 0000 replaced with numbers
|
||||
//the 0000 in the filename is replaced with the next number avaialable
|
||||
|
||||
uint16_t index;
|
||||
|
||||
for (index = 1; index <= 9999; index++) {
|
||||
buff[3] = index / 1000 + '0';
|
||||
buff[4] = ((index % 1000) / 100) + '0';
|
||||
buff[5] = ((index % 100) / 10) + '0';
|
||||
buff[6] = index % 10 + '0' ;
|
||||
if (! SD.exists(buff))
|
||||
{
|
||||
// only open a new file if it doesn't exist
|
||||
dataFile = SD.open(buff, FILE_WRITE);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!dataFile)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return index; //return number of logfile created
|
||||
}
|
||||
|
||||
|
||||
uint16_t DTSD_fileCRCCCITT(uint32_t fsize)
|
||||
{
|
||||
uint32_t index;
|
||||
uint16_t CRCcalc;
|
||||
uint8_t j, filedata;
|
||||
|
||||
CRCcalc = 0xFFFF; //start value for CRC16
|
||||
|
||||
for (index = 0; index < fsize; index++)
|
||||
{
|
||||
filedata = dataFile.read();
|
||||
CRCcalc ^= (((uint16_t) filedata ) << 8);
|
||||
for (j = 0; j < 8; j++)
|
||||
{
|
||||
if (CRCcalc & 0x8000)
|
||||
CRCcalc = (CRCcalc << 1) ^ 0x1021;
|
||||
else
|
||||
CRCcalc <<= 1;
|
||||
}
|
||||
}
|
||||
|
||||
return CRCcalc;
|
||||
}
|
||||
|
||||
|
||||
void DTSD_fileFlush()
|
||||
{
|
||||
dataFile.flush();
|
||||
}
|
||||
|
||||
|
||||
void DTSD_closeFile()
|
||||
{
|
||||
dataFile.close(); //close local file
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,71 @@
|
||||
/*******************************************************************************************************
|
||||
Programs for Arduino - Copyright of the author Stuart Robinson - 19/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 on LoRa device
|
||||
#define NRESET 9 //reset on LoRa device
|
||||
#define RFBUSY 7 //RFBUSY pin on LoRa device
|
||||
#define DIO1 3 //DIO1 on LoRa device, used for RX and TX done
|
||||
#define LED1 8 //On board LED, high for on
|
||||
#define SDCS 30 //select pin for SD card
|
||||
|
||||
#define LORA_DEVICE DEVICE_SX1280 //this is the device we are using
|
||||
|
||||
#define DISPCS 23 //CS for ILI9341
|
||||
#define DISPDC 24 //DC for ILI9341
|
||||
#define DISPRESET 25 //RESET for ILI9341
|
||||
#define TOUCHCS 29 //ILI9341 may have touch ICs, so we need to disable it, set to -1 if not fitted
|
||||
|
||||
#define YModemSerial Serial2 //define Serial port to use for Ymodem transfer here
|
||||
#define Monitorport Serial //define Hardware Serial monitor port to use for monitoring
|
||||
|
||||
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 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
|
||||
|
||||
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
|
||||
|
||||
|
||||
//******* ILI9341 Display settings here ***************
|
||||
|
||||
const uint8_t textscale = 3;
|
||||
const byte rotation = 1;
|
||||
@ -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;
|
||||
}
|
||||
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**
|
||||
@ -0,0 +1,258 @@
|
||||
/*******************************************************************************************************
|
||||
Programs for Arduino - Copyright of the author Stuart Robinson - 19/03/20
|
||||
|
||||
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 can be used to test the effectiveness of a LoRa link or its
|
||||
attached antennas. Simulations of antenna performance are no substitute for real world tests and this
|
||||
simple program allows both long distance link performance to be evaluated and antenna performance to be
|
||||
compared.
|
||||
|
||||
The program sends short test packets that reduce in power by 1dBm at a time. The start power is defined
|
||||
by start_power and the end power is defined by end_power (see Settings.h file). Once the end_power point
|
||||
is reached, the program pauses a short while and starts the transmit sequence again at start_power.
|
||||
The packet sent contains the power used to send the packet. By listening for the packets with the basic
|
||||
LoRa receive program (4_LoRa_Receiver) you can see the reception results, which should look something
|
||||
like this;
|
||||
|
||||
11s 1*T+05,CRC,80B8,RSSI,-73dBm,SNR,9dB,Length,6,Packets,9,Errors,0,IRQreg,50
|
||||
12s 1*T+04,CRC,9099,RSSI,-74dBm,SNR,9dB,Length,6,Packets,10,Errors,0,IRQreg,50
|
||||
14s 1*T+03,CRC,E07E,RSSI,-75dBm,SNR,9dB,Length,6,Packets,11,Errors,0,IRQreg,50
|
||||
|
||||
Above shows 3 packets received, the first at +05dBm (+05 in printout), the second at 4dBm (+04 in
|
||||
printout) and the third at 3dBm (+03) in printout.
|
||||
|
||||
If it is arranged so that reception of packets fails halfway through the sequence by attenuating either the
|
||||
transmitter (with an SMA attenuator for instance) or the receiver (by placing it in a tin perhaps) then
|
||||
if you swap transmitter antennas you can see the dBm difference in reception, which will be the dBm difference
|
||||
(gain) of the antenna.
|
||||
|
||||
To start the sequence a packet is sent with the number 999, when received it looks like this;
|
||||
|
||||
T*1999
|
||||
|
||||
This received packet could be used for the RX program to be able to print totals etc.
|
||||
|
||||
LoRa settings to use for the link test are specified in the 'Settings.h' file.
|
||||
|
||||
Serial monitor baud rate is set at 9600.
|
||||
*******************************************************************************************************/
|
||||
|
||||
#include <SPI.h>
|
||||
#include <SX128XLT.h>
|
||||
#include <ProgramLT_Definitions.h>
|
||||
#include "Settings.h"
|
||||
|
||||
SX128XLT LT;
|
||||
|
||||
int8_t TestPower;
|
||||
uint8_t TXPacketL;
|
||||
|
||||
|
||||
void loop()
|
||||
{
|
||||
Serial.println(F("Start Test Sequence"));
|
||||
Serial.print(TXpower);
|
||||
Serial.print(F("dBm "));
|
||||
Serial.print(F("Start Packet> "));
|
||||
|
||||
SendTest1ModePacket();
|
||||
|
||||
Serial.println();
|
||||
|
||||
for (TestPower = start_power; TestPower >= end_power; TestPower--)
|
||||
{
|
||||
Serial.print(TestPower);
|
||||
Serial.print(F("dBm "));
|
||||
Serial.print(F("Test Packet> "));
|
||||
Serial.flush();
|
||||
SendTestPacket(TestPower);
|
||||
Serial.println();
|
||||
delay(packet_delay);
|
||||
}
|
||||
|
||||
Serial.println(F("Finished Test Sequence"));
|
||||
Serial.println();
|
||||
}
|
||||
|
||||
|
||||
void SendTestPacket(int8_t lpower)
|
||||
{
|
||||
//build and send the test packet in addressed form, 3 bytes will be added to begining of packet
|
||||
int8_t temppower;
|
||||
uint8_t buff[3]; //the packet is built in this buffer
|
||||
TXPacketL = sizeof(buff);
|
||||
|
||||
if (lpower < 0)
|
||||
{
|
||||
buff[0] = '-';
|
||||
}
|
||||
else
|
||||
{
|
||||
buff[0] = '+';
|
||||
}
|
||||
|
||||
if (TestPower == 0)
|
||||
{
|
||||
buff[0] = ' ';
|
||||
}
|
||||
|
||||
temppower = TestPower;
|
||||
|
||||
if (temppower < 0)
|
||||
{
|
||||
temppower = -temppower;
|
||||
}
|
||||
|
||||
if (temppower > 19)
|
||||
{
|
||||
buff[1] = '2';
|
||||
buff[2] = ((temppower - 20) + 0x30);
|
||||
}
|
||||
else if (temppower > 9)
|
||||
{
|
||||
buff[1] = '1';
|
||||
buff[2] = ((temppower - 10) + 0x30);
|
||||
}
|
||||
else
|
||||
{
|
||||
buff[1] = '0';
|
||||
buff[2] = (temppower + 0x30);
|
||||
}
|
||||
|
||||
LT.printASCIIPacket(buff, sizeof(buff));
|
||||
|
||||
digitalWrite(LED1, HIGH);
|
||||
TXPacketL = LT.transmitAddressed(buff, sizeof(buff), TestPacket, Broadcast, ThisNode, 5000, lpower, WAIT_TX);
|
||||
digitalWrite(LED1, LOW);
|
||||
|
||||
if (TXPacketL == 0)
|
||||
{
|
||||
packet_is_Error();
|
||||
}
|
||||
else
|
||||
{
|
||||
packet_is_OK();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void SendTest1ModePacket()
|
||||
{
|
||||
//used to allow an RX to recognise the start off the sequence and possibly print totals
|
||||
|
||||
uint8_t buff[3]; //the packet is built in this buffer
|
||||
|
||||
buff[0] = '9';
|
||||
buff[1] = '9';
|
||||
buff[2] = '9';
|
||||
TXPacketL = sizeof(buff);
|
||||
|
||||
LT.printASCIIPacket(buff, sizeof(buff));
|
||||
|
||||
digitalWrite(LED1, HIGH);
|
||||
TXPacketL = LT.transmitAddressed(buff, sizeof(buff), TestMode1, Broadcast, ThisNode, 5000, start_power, WAIT_TX);
|
||||
delay(mode_delaymS); //longer delay, so that the start test sequence is obvious
|
||||
digitalWrite(LED1, LOW);
|
||||
|
||||
if (TXPacketL == 0)
|
||||
{
|
||||
packet_is_Error();
|
||||
}
|
||||
else
|
||||
{
|
||||
packet_is_OK();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void packet_is_OK()
|
||||
{
|
||||
uint16_t IRQStatus;
|
||||
IRQStatus = LT.readIrqStatus(); //get the IRQ status
|
||||
Serial.print(F(" "));
|
||||
Serial.print(TXPacketL);
|
||||
Serial.print(F(" Bytes SentOK"));
|
||||
Serial.print(F(",IRQreg,"));
|
||||
Serial.print(IRQStatus, HEX);
|
||||
LT.printIrqStatus();
|
||||
}
|
||||
|
||||
|
||||
void packet_is_Error()
|
||||
{
|
||||
uint16_t IRQStatus;
|
||||
IRQStatus = LT.readIrqStatus(); //get the IRQ status
|
||||
Serial.print(F(" SendError,"));
|
||||
Serial.print(F("Length,"));
|
||||
Serial.print(TXPacketL);
|
||||
Serial.print(F(",IRQreg,"));
|
||||
Serial.print(IRQStatus, HEX);
|
||||
LT.printIrqStatus();
|
||||
delay(packet_delay); //change LED flash so packet error visible
|
||||
delay(packet_delay);
|
||||
digitalWrite(LED1, HIGH);
|
||||
delay(packet_delay);
|
||||
delay(packet_delay);
|
||||
digitalWrite(LED1, LOW);
|
||||
}
|
||||
|
||||
|
||||
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(9600);
|
||||
Serial.println();
|
||||
Serial.println(F("10_LoRa_Link_Test_Transmitter Starting"));
|
||||
|
||||
SPI.begin();
|
||||
|
||||
if (LT.begin(NSS, NRESET, RFBUSY, DIO1, LORA_DEVICE))
|
||||
{
|
||||
Serial.println(F("Device found"));
|
||||
led_Flash(2, 125);
|
||||
delay(1000);
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.println(F("No device responding"));
|
||||
while (1)
|
||||
{
|
||||
led_Flash(50, 50); //long fast speed flash indicates device error
|
||||
}
|
||||
}
|
||||
|
||||
LT.setupLoRa(Frequency, Offset, SpreadingFactor, Bandwidth, CodeRate);
|
||||
|
||||
Serial.println();
|
||||
LT.printModemSettings(); //reads and prints the configured LoRa settings, useful check
|
||||
Serial.println();
|
||||
LT.printOperatingSettings(); //reads and prints the configured operting settings, useful check
|
||||
Serial.println();
|
||||
Serial.println();
|
||||
LT.printRegisters(0x900, 0x9FF); //print contents of device registers
|
||||
Serial.println();
|
||||
Serial.println();
|
||||
|
||||
Serial.print(F("Transmitter ready"));
|
||||
Serial.println();
|
||||
|
||||
}
|
||||
@ -0,0 +1,39 @@
|
||||
/*******************************************************************************************************
|
||||
Programs for Arduino - Copyright of the author Stuart Robinson - 19/03/20
|
||||
|
||||
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 LED1 8 //on board LED, high for on
|
||||
#define RFBUSY 7 //SX128X busy pin
|
||||
#define DIO1 3 //DIO1 pin on LoRa device, used for RX and TX done
|
||||
|
||||
#define LORA_DEVICE DEVICE_SX1280 //this is the device we are using
|
||||
|
||||
|
||||
//******* Setup LoRa Test Parameters Here ! ***************
|
||||
|
||||
//LoRa Modem Parameters
|
||||
#define Frequency 2445000000 //frequency of transmissions
|
||||
#define Offset 0 //offset frequency for calibration purposes
|
||||
#define Bandwidth LORA_BW_0400 //LoRa bandwidth
|
||||
#define SpreadingFactor LORA_SF7 //LoRa spreading factor
|
||||
#define CodeRate LORA_CR_4_5 //LoRa coding rate
|
||||
|
||||
const int8_t TXpower = 10; //Transmit power used when sending packet starting test sequence
|
||||
const int8_t start_power = 10; //link test starts at this transmit power, maximum +12dBm
|
||||
const int8_t end_power = -18; //and ends at this power, minimum -18dBm
|
||||
const uint8_t ThisNode = 'T'; //this identifies the node in transmissions
|
||||
|
||||
|
||||
#define packet_delay 250 //mS delay between packets
|
||||
#define mode_delaymS 2000 //mS delay after sending start test sequence
|
||||
@ -0,0 +1,213 @@
|
||||
/*******************************************************************************************************
|
||||
Programs for Arduino - Copyright of the author Stuart Robinson - 01/03/20
|
||||
|
||||
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 and the buzzer will sound,
|
||||
if fitted. The measured frequency difference between the frequency used by the transmitter and the
|
||||
frequency used by the receiver is shown. If this frequency difference gets to 25% of the set LoRa
|
||||
bandwidth, packet reception will fail. The displayed error can be reduced by using the 'offset'
|
||||
setting in the 'Settings.h' file.
|
||||
|
||||
Serial monitor baud rate is set at 9600.
|
||||
*******************************************************************************************************/
|
||||
|
||||
#include <SPI.h>
|
||||
#include <SX128XLT.h>
|
||||
#include "Settings.h"
|
||||
#include <TimeLib.h> //get the library here; https://github.com/PaulStoffregen/Time
|
||||
time_t recordtime; //used to record the current time, preventing displayed rollover on printing
|
||||
|
||||
SX128XLT LT;
|
||||
|
||||
uint32_t RXpacketCount;
|
||||
uint32_t errors;
|
||||
|
||||
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 = LT.receiveSXBuffer(0, 60000, WAIT_RX); //returns 0 if packet error of some sort, timeout set at 60secs\60000mS
|
||||
|
||||
digitalWrite(LED1, HIGH); //something has happened
|
||||
recordtime = now(); //stop the time to be displayed rolling over
|
||||
printtime();
|
||||
|
||||
PacketRSSI = LT.readPacketRSSI();
|
||||
PacketSNR = LT.readPacketSNR();
|
||||
|
||||
if (RXPacketL == 0)
|
||||
{
|
||||
packet_is_Error();
|
||||
}
|
||||
else
|
||||
{
|
||||
packet_is_OK();
|
||||
}
|
||||
|
||||
digitalWrite(LED1, LOW);
|
||||
|
||||
if (BUZZER > 0)
|
||||
{
|
||||
delay(50); //lets have a slightly longer beep
|
||||
digitalWrite(BUZZER, LOW);
|
||||
}
|
||||
|
||||
Serial.println();
|
||||
}
|
||||
|
||||
|
||||
void packet_is_OK()
|
||||
{
|
||||
uint16_t IRQStatus;
|
||||
IRQStatus = LT.readIrqStatus();
|
||||
|
||||
RXpacketCount++;
|
||||
|
||||
if (BUZZER > 0)
|
||||
{
|
||||
digitalWrite(BUZZER, HIGH);
|
||||
}
|
||||
|
||||
Serial.print(F(" FreqErrror,"));
|
||||
Serial.print(LT.getFrequencyErrorHz());
|
||||
Serial.print(F("hz "));
|
||||
|
||||
LT.printSXBufferHEX(0, (RXPacketL - 1));
|
||||
|
||||
Serial.print(F(" RSSI,"));
|
||||
Serial.print(PacketRSSI);
|
||||
Serial.print(F("dBm,SNR,"));
|
||||
Serial.print(PacketSNR);
|
||||
Serial.print(F("dB,Length,"));
|
||||
Serial.print(RXPacketL);
|
||||
Serial.print(F(",Packets,"));
|
||||
Serial.print(RXpacketCount);
|
||||
Serial.print(F(",Errors,"));
|
||||
Serial.print(errors);
|
||||
Serial.print(F(",IRQreg,"));
|
||||
Serial.print(IRQStatus, HEX);
|
||||
}
|
||||
|
||||
|
||||
void packet_is_Error()
|
||||
{
|
||||
uint16_t IRQStatus;
|
||||
IRQStatus = LT.readIrqStatus(); //get the IRQ status
|
||||
|
||||
if (IRQStatus & IRQ_RX_TIMEOUT)
|
||||
{
|
||||
Serial.print(F(" RXTimeout"));
|
||||
}
|
||||
else
|
||||
{
|
||||
errors++;
|
||||
Serial.print(F(" PacketError"));
|
||||
Serial.print(F(",RSSI,"));
|
||||
Serial.print(PacketRSSI);
|
||||
Serial.print(F("dBm,SNR,"));
|
||||
Serial.print(PacketSNR);
|
||||
Serial.print(F("dB,Length,"));
|
||||
Serial.print(LT.readRXPacketL()); //get the real packet length
|
||||
Serial.print(F(",Packets,"));
|
||||
Serial.print(RXpacketCount);
|
||||
Serial.print(F(",Errors,"));
|
||||
Serial.print(errors);
|
||||
Serial.print(F(",IRQreg,"));
|
||||
Serial.print(IRQStatus, HEX);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
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 printDigits(int8_t digits)
|
||||
{
|
||||
//utility function for digital clock display: prints preceding colon and leading 0
|
||||
Serial.print(F(":"));
|
||||
if (digits < 10)
|
||||
Serial.print('0');
|
||||
Serial.print(digits);
|
||||
}
|
||||
|
||||
|
||||
void printtime()
|
||||
{
|
||||
Serial.print(hour(recordtime));
|
||||
printDigits(minute(recordtime));
|
||||
printDigits(second(recordtime));
|
||||
}
|
||||
|
||||
|
||||
void setup()
|
||||
{
|
||||
pinMode(LED1, OUTPUT);
|
||||
led_Flash(2, 125);
|
||||
|
||||
Serial.begin(9600);
|
||||
Serial.println(F("11_LoRa_Packet_Logger_Receiver Starting"));
|
||||
Serial.println();
|
||||
|
||||
if (BUZZER > 0)
|
||||
{
|
||||
pinMode(BUZZER, OUTPUT);
|
||||
digitalWrite(BUZZER, HIGH);
|
||||
delay(50);
|
||||
digitalWrite(BUZZER, LOW);
|
||||
}
|
||||
|
||||
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 (LT.begin(NSS, NRESET, RFBUSY, LORA_DEVICE))
|
||||
{
|
||||
Serial.println(F("LoRa Device found"));
|
||||
led_Flash(2, 125);
|
||||
delay(1000);
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.println(F("No device responding"));
|
||||
while (1)
|
||||
{
|
||||
led_Flash(50, 50);
|
||||
}
|
||||
}
|
||||
|
||||
LT.setupLoRa(Frequency, Offset, SpreadingFactor, Bandwidth, CodeRate);
|
||||
|
||||
Serial.println();
|
||||
LT.printModemSettings();
|
||||
Serial.println();
|
||||
LT.printOperatingSettings();
|
||||
Serial.println();
|
||||
Serial.println();
|
||||
printtime();
|
||||
Serial.print(F(" Receiver ready"));
|
||||
Serial.println();
|
||||
}
|
||||
@ -0,0 +1,33 @@
|
||||
/*******************************************************************************************************
|
||||
Programs for Arduino - Copyright of the author Stuart Robinson - 01/03/20
|
||||
|
||||
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
|
||||
#define RFBUSY 7
|
||||
#define NRESET 9
|
||||
#define LED1 8
|
||||
#define DIO1 3
|
||||
#define BUZZER -1 //pin for buzzer, set to -1 if not used
|
||||
|
||||
#define LORA_DEVICE DEVICE_SX1280 //this is the device we are using
|
||||
|
||||
//******* Setup LoRa Test Parameters Here ! ***************
|
||||
|
||||
//LoRa Modem Parameters
|
||||
const uint32_t Frequency = 2445000000; //frequency of transmissions
|
||||
const int32_t Offset = 0; //offset frequency for calibration purposes
|
||||
const uint8_t Bandwidth = LORA_BW_0400; //LoRa bandwidth
|
||||
const uint8_t SpreadingFactor = LORA_SF7; //LoRa spreading factor
|
||||
const uint8_t CodeRate = LORA_CR_4_5; //LoRa coding rate
|
||||
|
||||
const int8_t TXpower = 10; //Power for transmissions in dBm
|
||||
|
||||
#define packet_delay 1000 //mS delay between packets
|
||||
@ -0,0 +1,171 @@
|
||||
/*******************************************************************************************************
|
||||
Programs for Arduino - Copyright of the author Stuart Robinson - 29/02/20
|
||||
|
||||
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 program can be used to check the frequency error between a pair of LoRa
|
||||
devices, a transmitter and receiver. This receiver measures the frequecy error between the receivers
|
||||
centre frequency and the centre frequency of the transmitted packet. The frequency difference is shown
|
||||
for each packet and an average over 10 received packets reported. Any transmitter program can be used
|
||||
to give this program something to listen to, including example program '3_LoRa_Transmit'.
|
||||
|
||||
Serial monitor baud rate is set at 9600.
|
||||
*******************************************************************************************************/
|
||||
|
||||
#include <SPI.h>
|
||||
#include <SX128XLT.h>
|
||||
#include "Settings.h"
|
||||
|
||||
SX128XLT LT;
|
||||
|
||||
uint32_t RXpacketCount;
|
||||
uint32_t errors;
|
||||
|
||||
uint8_t RXBUFFER[RXBUFFER_SIZE]; //a buffer is needed to receive packets
|
||||
|
||||
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
|
||||
int32_t totalHzError = 0; //used to keep a running total of hZ error for averaging
|
||||
|
||||
|
||||
void loop()
|
||||
{
|
||||
|
||||
RXPacketL = LT.receive(RXBUFFER, RXBUFFER_SIZE, 0, WAIT_RX); //wait for a packet to arrive
|
||||
|
||||
digitalWrite(LED1, HIGH); //something has happened
|
||||
|
||||
PacketRSSI = LT.readPacketRSSI();
|
||||
PacketSNR = LT.readPacketSNR();
|
||||
|
||||
if (RXPacketL == 0)
|
||||
{
|
||||
packet_is_Error();
|
||||
}
|
||||
else
|
||||
{
|
||||
packet_is_OK();
|
||||
}
|
||||
|
||||
digitalWrite(LED1, LOW);
|
||||
|
||||
Serial.println();
|
||||
}
|
||||
|
||||
|
||||
void packet_is_OK()
|
||||
{
|
||||
uint16_t IRQStatus;
|
||||
IRQStatus = LT.readIrqStatus();
|
||||
|
||||
RXpacketCount++;
|
||||
Serial.print(F("PacketOK > "));
|
||||
Serial.print(F(" RSSI,"));
|
||||
Serial.print(PacketRSSI);
|
||||
Serial.print(F("dBm,SNR,"));
|
||||
Serial.print(PacketSNR);
|
||||
Serial.print(F("dB,Length,"));
|
||||
Serial.print(RXPacketL);
|
||||
Serial.print(F(",Packets,"));
|
||||
Serial.print(RXpacketCount);
|
||||
Serial.print(F(",Errors,"));
|
||||
Serial.print(errors);
|
||||
Serial.print(F(",IRQreg,"));
|
||||
Serial.print(IRQStatus, HEX);
|
||||
Serial.println();
|
||||
printFrequencyError();
|
||||
}
|
||||
|
||||
|
||||
void printFrequencyError()
|
||||
{
|
||||
int32_t hertzerror, regdata;
|
||||
regdata = LT.getFrequencyErrorRegValue();
|
||||
hertzerror = LT.getFrequencyErrorHz();
|
||||
Serial.print(F("ErrorRegValue,"));
|
||||
Serial.print(regdata, HEX);
|
||||
Serial.print(F(" PacketHertzError,"));
|
||||
Serial.print(hertzerror);
|
||||
Serial.println(F("hz"));
|
||||
|
||||
totalHzError = totalHzError + hertzerror;
|
||||
|
||||
if (RXpacketCount == 10)
|
||||
{
|
||||
Serial.print(F("******** AverageHertzerror "));
|
||||
Serial.print((totalHzError / 10));
|
||||
Serial.println(F("hz"));
|
||||
RXpacketCount = 0;
|
||||
totalHzError = 0;
|
||||
delay(5000);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void packet_is_Error()
|
||||
{
|
||||
uint16_t IRQStatus;
|
||||
|
||||
IRQStatus = LT.readIrqStatus(); //get the IRQ status
|
||||
errors++;
|
||||
Serial.print(F("PacketError,RSSI,"));
|
||||
Serial.print(PacketRSSI);
|
||||
Serial.print(F("dBm,SNR,"));
|
||||
Serial.print(PacketSNR);
|
||||
Serial.print(F("dB,Length,"));
|
||||
Serial.print(LT.readRXPacketL()); //get the real packet length
|
||||
Serial.print(F(",IRQreg,"));
|
||||
Serial.print(IRQStatus, HEX);
|
||||
LT.printIrqStatus();
|
||||
digitalWrite(LED1, LOW);
|
||||
}
|
||||
|
||||
|
||||
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(9600);
|
||||
Serial.println(F("16_LoRa_RX_Frequency_Error_Check Starting"));
|
||||
Serial.println();
|
||||
|
||||
SPI.begin();
|
||||
|
||||
if (LT.begin(NSS, NRESET, RFBUSY, DIO1, LORA_DEVICE))
|
||||
{
|
||||
Serial.println(F("LoRa Device found"));
|
||||
led_Flash(2, 125);
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.println(F("No device responding"));
|
||||
while (1)
|
||||
{
|
||||
led_Flash(50, 50); //long fast speed flash indicates device error
|
||||
}
|
||||
}
|
||||
|
||||
LT.setupLoRa(Frequency, Offset, SpreadingFactor, Bandwidth, CodeRate);
|
||||
|
||||
Serial.println(F("Receiver ready"));
|
||||
Serial.println();
|
||||
}
|
||||
@ -0,0 +1,35 @@
|
||||
/*******************************************************************************************************
|
||||
Programs for Arduino - Copyright of the author Stuart Robinson - 29/02/20
|
||||
|
||||
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
|
||||
#define RFBUSY 7
|
||||
#define NRESET 9
|
||||
#define LED1 8
|
||||
#define DIO1 3
|
||||
|
||||
#define LORA_DEVICE DEVICE_SX1280 //we need to define the device we are using
|
||||
|
||||
//******* Setup LoRa Test Parameters Here ! ***************
|
||||
|
||||
//LoRa Modem Parameters
|
||||
const uint32_t Frequency = 2445000000; //frequency of transmissions
|
||||
const int32_t Offset = 0; //offset frequency for calibration purposes
|
||||
const uint8_t Bandwidth = LORA_BW_0400; //LoRa bandwidth
|
||||
const uint8_t SpreadingFactor = LORA_SF7; //LoRa spreading factor
|
||||
const uint8_t CodeRate = LORA_CR_4_5; //LoRa coding rate
|
||||
|
||||
const int8_t TXpower = 10; //Power for transmissions in dBm
|
||||
|
||||
#define packet_delay 1000 //mS delay between packets
|
||||
|
||||
#define RXBUFFER_SIZE 32 //RX buffer size
|
||||
@ -0,0 +1,308 @@
|
||||
/*******************************************************************************************************
|
||||
Programs for Arduino - Copyright of the author Stuart Robinson - 19/03/20
|
||||
|
||||
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.
|
||||
|
||||
The program is a matching receiver program for the '10_LoRa_Link_Test_Transmitter'. The packets received
|
||||
are displayed on the serial monitor and analysed to extract the packet data which indicates the power
|
||||
used to send the packet. A count is kept of the numbers of each power setting received. When the transmitter
|
||||
sends the test mode packet at the beginning of the sequence (displayed as 999) the running totals of the
|
||||
powers received are printed. Thus you can quickly see at what transmit power levels the reception fails.
|
||||
|
||||
Serial monitor baud rate is set at 9600.
|
||||
*******************************************************************************************************/
|
||||
|
||||
#include <SPI.h> //the lora device is SPI based so load the SPI library
|
||||
#include <SX128XLT.h> //include the appropriate library
|
||||
#include "Settings.h" //include the setiings file, frequencies, LoRa settings etc
|
||||
#include <ProgramLT_Definitions.h>
|
||||
|
||||
SX128XLT LT; //create a library class instance called LT
|
||||
|
||||
uint32_t RXpacketCount;
|
||||
uint32_t errors;
|
||||
|
||||
uint8_t RXBUFFER[RXBUFFER_SIZE]; //create the buffer that received packets are copied into
|
||||
|
||||
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
|
||||
|
||||
uint32_t Test1Count[32]; //buffer where counts of received packets are stored, -18dbm to +12dBm
|
||||
uint32_t Mode1_Cycles = 0; //count the number of cyles received
|
||||
bool updateCounts = false; //update counts set to tru when first TestMode1 received, at sequence start
|
||||
|
||||
|
||||
void loop()
|
||||
{
|
||||
RXPacketL = LT.receiveAddressed(RXBUFFER, RXBUFFER_SIZE, 15000, WAIT_RX); //wait for a packet to arrive with 15seconds (15000mS) timeout
|
||||
|
||||
digitalWrite(LED1, HIGH); //something has happened
|
||||
|
||||
PacketRSSI = LT.readPacketRSSI(); //read the recived RSSI value
|
||||
PacketSNR = LT.readPacketSNR(); //read the received SNR value
|
||||
|
||||
if (RXPacketL == 0) //if the LT.receive() function detects an error, RXpacketL == 0
|
||||
{
|
||||
packet_is_Error();
|
||||
}
|
||||
else
|
||||
{
|
||||
packet_is_OK();
|
||||
}
|
||||
|
||||
if (BUZZER > 0)
|
||||
{
|
||||
delay(25); //gives a slightly longer beep
|
||||
digitalWrite(BUZZER, LOW); //buzzer off
|
||||
}
|
||||
|
||||
digitalWrite(LED1, LOW); //LED off
|
||||
|
||||
Serial.println();
|
||||
}
|
||||
|
||||
|
||||
void packet_is_OK()
|
||||
{
|
||||
uint16_t IRQStatus;
|
||||
|
||||
if (BUZZER > 0) //turn buzzer on for a valid packet
|
||||
{
|
||||
digitalWrite(BUZZER, HIGH);
|
||||
}
|
||||
|
||||
IRQStatus = LT.readIrqStatus(); //read the LoRa device IRQ status register
|
||||
|
||||
RXpacketCount++;
|
||||
|
||||
printElapsedTime(); //print elapsed time to Serial Monitor
|
||||
Serial.print(F(" "));
|
||||
LT.printASCIIPacket(RXBUFFER, RXPacketL - 3); //print the packet as ASCII characters
|
||||
|
||||
Serial.print(F(",RSSI,"));
|
||||
Serial.print(PacketRSSI);
|
||||
Serial.print(F("dBm,SNR,"));
|
||||
Serial.print(PacketSNR);
|
||||
Serial.print(F("dB,Length,"));
|
||||
Serial.print(RXPacketL);
|
||||
Serial.print(F(",Packets,"));
|
||||
Serial.print(RXpacketCount);
|
||||
Serial.print(F(",Errors,"));
|
||||
Serial.print(errors);
|
||||
Serial.print(F(",IRQreg,"));
|
||||
Serial.print(IRQStatus, HEX);
|
||||
|
||||
processPacket();
|
||||
}
|
||||
|
||||
|
||||
void processPacket()
|
||||
{
|
||||
int8_t lTXpower;
|
||||
uint8_t packettype;
|
||||
uint32_t temp;
|
||||
|
||||
packettype = LT.readRXPacketType(); //need to know the packet type so we can decide what to do
|
||||
|
||||
if (packettype == TestPacket)
|
||||
{
|
||||
if (RXBUFFER[0] == ' ')
|
||||
{
|
||||
lTXpower = 0;
|
||||
}
|
||||
|
||||
if (RXBUFFER[0] == '+')
|
||||
{
|
||||
lTXpower = ((RXBUFFER[1] - 48) * 10) + (RXBUFFER[2] - 48); //convert packet text to power
|
||||
}
|
||||
|
||||
if (RXBUFFER[0] == '-')
|
||||
{
|
||||
lTXpower = (((RXBUFFER[1] - 48) * 10) + (RXBUFFER[2] - 48)) * -1; //convert packet text to power
|
||||
}
|
||||
|
||||
Serial.print(F(" ("));
|
||||
|
||||
if (RXBUFFER[0] != '-')
|
||||
{
|
||||
Serial.write(RXBUFFER[0]);
|
||||
}
|
||||
|
||||
Serial.print(lTXpower);
|
||||
Serial.print(F("dBm)"));
|
||||
|
||||
if (updateCounts)
|
||||
{
|
||||
temp = (Test1Count[lTXpower + 18]);
|
||||
Test1Count[lTXpower + 18] = temp + 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (packettype == TestMode1)
|
||||
{
|
||||
//this is a command to switch to TestMode1 also updates totals and logs
|
||||
updateCounts = true;
|
||||
Serial.println();
|
||||
Serial.println(F("End test sequence"));
|
||||
|
||||
if (Mode1_Cycles > 0)
|
||||
{
|
||||
print_Test1Count();
|
||||
}
|
||||
|
||||
Serial.println();
|
||||
Mode1_Cycles++;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
void print_Test1Count()
|
||||
{
|
||||
//prints running totals of the powers of received packets
|
||||
int8_t index;
|
||||
uint32_t j;
|
||||
|
||||
Serial.print(F("Test Packets "));
|
||||
Serial.println(RXpacketCount);
|
||||
Serial.print(F("Test Cycles "));
|
||||
Serial.println(Mode1_Cycles);
|
||||
|
||||
Serial.println();
|
||||
for (index = 30; index >= 0; index--)
|
||||
{
|
||||
Serial.print(index - 18);
|
||||
Serial.print(F("dBm,"));
|
||||
j = Test1Count[index];
|
||||
Serial.print(j);
|
||||
Serial.print(F(" "));
|
||||
}
|
||||
Serial.println();
|
||||
|
||||
Serial.print(F("CSV"));
|
||||
for (index = 30; index >= 0; index--)
|
||||
{
|
||||
Serial.print(F(","));
|
||||
j = Test1Count[index];
|
||||
Serial.print(j);
|
||||
}
|
||||
Serial.println();
|
||||
}
|
||||
|
||||
|
||||
void packet_is_Error()
|
||||
{
|
||||
uint16_t IRQStatus;
|
||||
IRQStatus = LT.readIrqStatus(); //read the LoRa device IRQ status register
|
||||
|
||||
printElapsedTime(); //print elapsed time to Serial Monitor
|
||||
|
||||
if (IRQStatus & IRQ_RX_TIMEOUT) //check for an RX timeout
|
||||
{
|
||||
Serial.print(F(" RXTimeout"));
|
||||
}
|
||||
else
|
||||
{
|
||||
errors++;
|
||||
Serial.print(F(" PacketError"));
|
||||
Serial.print(F(",RSSI,"));
|
||||
Serial.print(PacketRSSI);
|
||||
Serial.print(F("dBm,SNR,"));
|
||||
Serial.print(PacketSNR);
|
||||
Serial.print(F("dB,Length,"));
|
||||
Serial.print(LT.readRXPacketL()); //get the real packet length
|
||||
Serial.print(F(",Packets,"));
|
||||
Serial.print(RXpacketCount);
|
||||
Serial.print(F(",Errors,"));
|
||||
Serial.print(errors);
|
||||
Serial.print(F(",IRQreg,"));
|
||||
Serial.print(IRQStatus, HEX);
|
||||
LT.printIrqStatus(); //print the names of the IRQ registers set
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void printElapsedTime()
|
||||
{
|
||||
float seconds;
|
||||
seconds = millis() / 1000;
|
||||
Serial.print(seconds, 0);
|
||||
Serial.print(F("s"));
|
||||
}
|
||||
|
||||
|
||||
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(9600);
|
||||
Serial.println(F("20_LoRa_Link_Test_Receiver Starting"));
|
||||
Serial.println();
|
||||
|
||||
if (BUZZER > 0)
|
||||
{
|
||||
pinMode(BUZZER, OUTPUT);
|
||||
digitalWrite(BUZZER, HIGH);
|
||||
delay(50);
|
||||
digitalWrite(BUZZER, LOW);
|
||||
}
|
||||
|
||||
//setup SPI, its external to library on purpose, so settings can be mixed and matched with other SPI devices
|
||||
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));
|
||||
|
||||
//setup hardware pins used by device, then check if device is found
|
||||
if (LT.begin(NSS, NRESET, RFBUSY, DIO1, LORA_DEVICE))
|
||||
{
|
||||
Serial.println(F("LoRa Device found"));
|
||||
led_Flash(2, 125);
|
||||
delay(1000);
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.println(F("No device responding"));
|
||||
while (1)
|
||||
{
|
||||
led_Flash(50, 50); //long fast speed LED flash indicates device error
|
||||
}
|
||||
}
|
||||
|
||||
//this function call sets up the device for LoRa using the settings from settings.h
|
||||
LT.setupLoRa(Frequency, Offset, SpreadingFactor, Bandwidth, CodeRate);
|
||||
|
||||
Serial.println();
|
||||
LT.printModemSettings(); //reads and prints the configured LoRa settings, useful check
|
||||
Serial.println();
|
||||
LT.printOperatingSettings(); //reads and prints the configured operting settings, useful check
|
||||
Serial.println();
|
||||
Serial.println();
|
||||
|
||||
Serial.print(F("Receiver ready - RXBUFFER_SIZE "));
|
||||
Serial.println(RXBUFFER_SIZE);
|
||||
Serial.println();
|
||||
}
|
||||
@ -0,0 +1,36 @@
|
||||
/*******************************************************************************************************
|
||||
Programs for Arduino - Copyright of the author Stuart Robinson - 19/03/20
|
||||
|
||||
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 LED1 8 //on board LED, high for on
|
||||
#define RFBUSY 7 //SX128X busy pin
|
||||
#define DIO1 3 //DIO1 pin on LoRa device, used for RX and TX done
|
||||
#define BUZZER -1 //pin for buzzer, set to -1 if not used
|
||||
|
||||
#define LORA_DEVICE DEVICE_SX1280 //this is the device we are using
|
||||
|
||||
|
||||
//******* Setup LoRa Parameters Here ! ***************
|
||||
|
||||
//LoRa Modem Parameters
|
||||
#define Frequency 2445000000 //frequency of transmissions
|
||||
#define Offset 0 //offset frequency for calibration purposes
|
||||
#define Bandwidth LORA_BW_0400 //LoRa bandwidth
|
||||
#define SpreadingFactor LORA_SF7 //LoRa spreading factor
|
||||
#define CodeRate LORA_CR_4_5 //LoRa coding rate
|
||||
|
||||
const int8_t TXpower = 10; //LoRa transmit power in dBm
|
||||
|
||||
const uint16_t packet_delay = 1000; //mS delay between packets
|
||||
|
||||
#define RXBUFFER_SIZE 32 //RX buffer size
|
||||
@ -0,0 +1,274 @@
|
||||
/*******************************************************************************************************
|
||||
Programs for Arduino - Copyright of the author Stuart Robinson - 01/03/20
|
||||
|
||||
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, the packet is assumed to be in ASCII printable text,
|
||||
if its not ASCII text characters from 0x20 to 0x7F, expect weird things to happen on the Serial Monitor.
|
||||
The LED will flash for each packet received and the buzzer will sound, if fitted.
|
||||
|
||||
Sample serial monitor output;
|
||||
|
||||
1109s {packet contents} CRC,3882,RSSI,-69dBm,SNR,10dB,Length,19,Packets,1026,Errors,0,IRQreg,50
|
||||
|
||||
If there is a packet error it might look like this, which is showing a CRC error,
|
||||
|
||||
1189s PacketError,RSSI,-111dBm,SNR,-12dB,Length,0,Packets,1126,Errors,1,IRQreg,70,IRQ_HEADER_VALID,IRQ_CRC_ERROR,IRQ_RX_DONE
|
||||
|
||||
A summary of the packet reception is sent to the OLED display as well, useful for portable applications.
|
||||
|
||||
Serial monitor baud rate is set at 9600.
|
||||
*******************************************************************************************************/
|
||||
|
||||
#include <SPI.h> //the lora device is SPI based so load the SPI library
|
||||
#include <SX128XLT.h> //include the appropriate library
|
||||
#include "Settings.h" //include the setiings file, frequencies, LoRa settings etc
|
||||
|
||||
SX128XLT LT; //create a library class instance called LT
|
||||
|
||||
#include <U8x8lib.h> //get library here > https://github.com/olikraus/u8g2
|
||||
U8X8_SSD1306_128X64_NONAME_HW_I2C disp(U8X8_PIN_NONE); //use this line for standard 0.96" SSD1306
|
||||
//U8X8_SH1106_128X64_NONAME_HW_I2C disp(U8X8_PIN_NONE); //use this line for 1.3" OLED often sold as 1.3" SSD1306
|
||||
|
||||
|
||||
uint32_t RXpacketCount;
|
||||
uint32_t RXpacketErrors;
|
||||
uint16_t IRQStatus;
|
||||
|
||||
uint8_t RXBUFFER[RXBUFFER_SIZE]; //create the buffer that received packets are copied into
|
||||
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 = LT.receive(RXBUFFER, RXBUFFER_SIZE, 0, WAIT_RX); //wait for a packet to arrive with no timeout
|
||||
|
||||
digitalWrite(LED1, HIGH); //something has happened
|
||||
|
||||
if (BUZZER > 0)
|
||||
{
|
||||
digitalWrite(BUZZER, HIGH); //buzzer on
|
||||
}
|
||||
|
||||
PacketRSSI = LT.readPacketRSSI(); //read the recived RSSI value
|
||||
PacketSNR = LT.readPacketSNR(); //read the received SNR value
|
||||
IRQStatus = LT.readIrqStatus(); //read the LoRa device IRQ status register
|
||||
|
||||
if (RXPacketL == 0) //if the LT.receive() function detects an error, RXpacketL == 0
|
||||
{
|
||||
packet_is_Error();
|
||||
}
|
||||
else
|
||||
{
|
||||
packet_is_OK();
|
||||
}
|
||||
|
||||
if (BUZZER > 0)
|
||||
{
|
||||
digitalWrite(BUZZER, LOW); //buzzer off
|
||||
}
|
||||
|
||||
digitalWrite(LED1, LOW); //LED off
|
||||
|
||||
Serial.println();
|
||||
}
|
||||
|
||||
|
||||
void packet_is_OK()
|
||||
{
|
||||
uint16_t localCRC;
|
||||
|
||||
RXpacketCount++;
|
||||
|
||||
printElapsedTime(); //print elapsed time to Serial Monitor
|
||||
Serial.print(F(" "));
|
||||
LT.printASCIIPacket(RXBUFFER, RXPacketL); //print the packet as ASCII characters
|
||||
|
||||
localCRC = LT.CRCCCITT(RXBUFFER, RXPacketL, 0xFFFF); //calculate the CRC, this is the external CRC calculation of the RXBUFFER
|
||||
Serial.print(F(",CRC,")); //contents, not the LoRa device internal CRC
|
||||
Serial.print(localCRC, HEX);
|
||||
Serial.print(F(",RSSI,"));
|
||||
Serial.print(PacketRSSI);
|
||||
Serial.print(F("dBm,SNR,"));
|
||||
Serial.print(PacketSNR);
|
||||
Serial.print(F("dB,Length,"));
|
||||
Serial.print(RXPacketL);
|
||||
Serial.print(F(",Packets,"));
|
||||
Serial.print(RXpacketCount);
|
||||
Serial.print(F(",Errors,"));
|
||||
Serial.print(RXpacketErrors);
|
||||
Serial.print(F(",IRQreg,"));
|
||||
Serial.print(IRQStatus, HEX);
|
||||
|
||||
disp.clearLine(0);
|
||||
disp.setCursor(0, 0);
|
||||
disp.print(F("OK"));
|
||||
dispscreen1();
|
||||
}
|
||||
|
||||
|
||||
void packet_is_Error()
|
||||
{
|
||||
printElapsedTime(); //print elapsed time to Serial Monitor
|
||||
|
||||
RXpacketErrors++;
|
||||
Serial.print(F(" PacketError"));
|
||||
Serial.print(F(",RSSI,"));
|
||||
Serial.print(PacketRSSI);
|
||||
Serial.print(F("dBm,SNR,"));
|
||||
Serial.print(PacketSNR);
|
||||
Serial.print(F("dB,Length,"));
|
||||
Serial.print(LT.readRXPacketL()); //get the real packet length
|
||||
Serial.print(F(",Packets,"));
|
||||
Serial.print(RXpacketCount);
|
||||
Serial.print(F(",Errors,"));
|
||||
Serial.print(RXpacketErrors);
|
||||
Serial.print(F(",IRQreg,"));
|
||||
Serial.print(IRQStatus, HEX);
|
||||
LT.printIrqStatus(); //print the names of the IRQ registers set
|
||||
disp.clearLine(0);
|
||||
disp.setCursor(0, 0);
|
||||
disp.print(F("Packet Error"));
|
||||
dispscreen1();
|
||||
|
||||
delay(500); //gives longer buzzer and LED falsh for error
|
||||
|
||||
}
|
||||
|
||||
|
||||
void printElapsedTime()
|
||||
{
|
||||
float seconds;
|
||||
seconds = millis() / 1000;
|
||||
Serial.print(seconds, 0);
|
||||
Serial.print(F("s"));
|
||||
}
|
||||
|
||||
|
||||
void dispscreen1()
|
||||
{
|
||||
disp.clearLine(1);
|
||||
disp.setCursor(0, 1);
|
||||
disp.print(F("RSSI "));
|
||||
disp.print(PacketRSSI);
|
||||
disp.print(F("dBm"));
|
||||
disp.clearLine(2);
|
||||
disp.setCursor(0, 2);
|
||||
disp.print(F("SNR "));
|
||||
|
||||
if (PacketSNR > 0)
|
||||
{
|
||||
disp.print(F("+"));
|
||||
}
|
||||
|
||||
disp.print(PacketSNR);
|
||||
disp.print(F("dB"));
|
||||
disp.clearLine(3);
|
||||
disp.setCursor(0, 3);
|
||||
disp.print(F("Length "));
|
||||
disp.print(LT.readRXPacketL());
|
||||
disp.clearLine(4);
|
||||
disp.setCursor(0, 4);
|
||||
disp.print(F("Packets "));
|
||||
disp.print(RXpacketCount);
|
||||
disp.clearLine(5);
|
||||
disp.setCursor(0, 5);
|
||||
disp.print(F("Errors "));
|
||||
disp.print(RXpacketErrors);
|
||||
disp.clearLine(6);
|
||||
disp.setCursor(0, 6);
|
||||
disp.print(F("IRQreg "));
|
||||
disp.print(IRQStatus, HEX);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
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(9600);
|
||||
Serial.println(F("33_LoRa_RSSI_Checker_With_Display Starting"));
|
||||
Serial.println();
|
||||
|
||||
if (BUZZER > 0)
|
||||
{
|
||||
pinMode(BUZZER, OUTPUT);
|
||||
digitalWrite(BUZZER, HIGH);
|
||||
delay(50);
|
||||
digitalWrite(BUZZER, LOW);
|
||||
}
|
||||
|
||||
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));
|
||||
|
||||
disp.begin();
|
||||
disp.setFont(u8x8_font_chroma48medium8_r);
|
||||
|
||||
disp.clear();
|
||||
disp.setCursor(0, 0);
|
||||
disp.print(F("Check LoRa"));
|
||||
disp.setCursor(0, 1);
|
||||
|
||||
//setup hardware pins used by device, then check if device is found
|
||||
if (LT.begin(NSS, NRESET, RFBUSY, DIO1, LORA_DEVICE))
|
||||
{
|
||||
disp.print(F("LoRa OK"));
|
||||
Serial.println(F("LoRa Device found"));
|
||||
led_Flash(2, 125);
|
||||
delay(1000);
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.println(F("No device responding"));
|
||||
while (1)
|
||||
{
|
||||
disp.print(F("Device error"));
|
||||
led_Flash(50, 50); //long fast speed LED flash indicates device error
|
||||
}
|
||||
}
|
||||
|
||||
//this function call sets up the device for LoRa using the settings from settings.h
|
||||
LT.setupLoRa(Frequency, Offset, SpreadingFactor, Bandwidth, CodeRate);
|
||||
|
||||
Serial.println();
|
||||
LT.printModemSettings(); //reads and prints the configured LoRa settings, useful check
|
||||
Serial.println();
|
||||
LT.printOperatingSettings(); //reads and prints the configured operting settings, useful check
|
||||
Serial.println();
|
||||
Serial.println();
|
||||
LT.printRegisters(0x900, 0x9FF); //print contents of device registers
|
||||
Serial.println();
|
||||
Serial.println();
|
||||
|
||||
Serial.print(F("Receiver ready - RXBUFFER_SIZE "));
|
||||
Serial.println(RXBUFFER_SIZE);
|
||||
Serial.println();
|
||||
}
|
||||
@ -0,0 +1,33 @@
|
||||
/*******************************************************************************************************
|
||||
Programs for Arduino - Copyright of the author Stuart Robinson - 01/03/20
|
||||
|
||||
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
|
||||
#define RFBUSY 7
|
||||
#define NRESET 9
|
||||
#define LED1 8
|
||||
#define DIO1 3
|
||||
#define BUZZER -1 //pin for BUZZER, set to -1 if not used
|
||||
|
||||
#define LORA_DEVICE DEVICE_SX1280 //we need to define the device we are using
|
||||
|
||||
//LoRa Modem Parameters
|
||||
const uint32_t Frequency = 2445000000; //frequency of transmissions
|
||||
const int32_t Offset = 0; //offset frequency for calibration purposes
|
||||
const uint8_t Bandwidth = LORA_BW_0400; //LoRa bandwidth
|
||||
const uint8_t SpreadingFactor = LORA_SF7; //LoRa spreading factor
|
||||
const uint8_t CodeRate = LORA_CR_4_5; //LoRa coding rate
|
||||
|
||||
const int8_t TXpower = 10; //Power for transmissions in dBm
|
||||
|
||||
const uint16_t packet_delay = 1000; //mS delay between packets
|
||||
|
||||
#define RXBUFFER_SIZE 32 //RX buffer size
|
||||
@ -0,0 +1,278 @@
|
||||
/*******************************************************************************************************
|
||||
Programs for Arduino - Copyright of the author Stuart Robinson - 15/05/20
|
||||
|
||||
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 can be used to test the throughput of a LoRa transmitter in
|
||||
FLRC mode.
|
||||
|
||||
Whilst the various LoRa calculators tell you the on air data rate, in practice the achievable data
|
||||
rate will be less than that due to the overhead of the software routines to load and send a packet
|
||||
and internal delays in the LoRa device itself.
|
||||
|
||||
A buffer is filled with characters and that buffer is then transmitted. The total time for a number of
|
||||
transmissions is recorded and the bit rate calculated. The packet size (1 - 127 bytes) and the number of
|
||||
packets to send in the test are specified in the 'Settings.h' file, see the 'Setup packet parameters Here !'
|
||||
section. The setting file also has the lora settings to use. A lower spreading factors and higher
|
||||
bandwidths will result in higher bitrates.
|
||||
|
||||
There is the option of turning on an a requirement for an acknowledgement from a remote receiver, before
|
||||
the transmitter sends the next packet, set this; 'const bool waitforACK = true;' definition in the
|
||||
settings file. The matching receiver program '43_FLRC_Data_Throughput_Acknowledge_Receiver' does then need
|
||||
to be configured with same FLRC settings as this transmitter. When this option is set, the program will
|
||||
keep running until the number of transmissions and acknowledgements has completed without any timeouts
|
||||
in order to produce a valid average.
|
||||
|
||||
Serial monitor baud rate is set at 9600
|
||||
*******************************************************************************************************/
|
||||
|
||||
#include <SPI.h> //the lora device is SPI based so load the SPI library
|
||||
#include <SX128XLT.h> //include the appropriate library
|
||||
#include <ProgramLT_Definitions.h>
|
||||
#include "Settings.h" //include the setiings file, frequencies, LoRa settings etc
|
||||
|
||||
SX128XLT LT; //create a library class instance called LT
|
||||
|
||||
uint32_t startmS, endmS, sendtimemS, bitspersecond, bitsPerpacket;
|
||||
uint32_t TXPacketCount;
|
||||
float averagePacketTime;
|
||||
uint8_t packetNumber;
|
||||
uint8_t RXPacketL; //length of received packet
|
||||
uint8_t PacketType; //for packet addressing, identifies packet type received
|
||||
uint32_t packetCheck;
|
||||
bool loopFail = false;
|
||||
|
||||
|
||||
void loop()
|
||||
{
|
||||
uint16_t index, index2;
|
||||
uint8_t TXBUFFER[TXPacketL + 1]; //create buffer for transmitted packet
|
||||
loopFail = false;
|
||||
|
||||
Serial.println(F("Start transmit test"));
|
||||
|
||||
startmS = millis(); //start transmit timer
|
||||
|
||||
for (index = 0; index < numberPackets; index++)
|
||||
{
|
||||
//fill the buffer
|
||||
for (index2 = 0; index2 < TXPacketL; index2++)
|
||||
{
|
||||
TXBUFFER[index2] = index2;
|
||||
}
|
||||
|
||||
TXBUFFER[0] = TestPacket; //set first byte to identify this test packet
|
||||
TXBUFFER[1] = index; //put the index as packet number in second byte of packet
|
||||
Serial.print(index); //print number of packet sent
|
||||
|
||||
if (waitforACK)
|
||||
{
|
||||
packetCheck = ( (uint32_t) TXBUFFER[4] << 24) + ( (uint32_t) TXBUFFER[3] << 16) + ( (uint32_t) TXBUFFER[2] << 8) + (uint32_t) TXBUFFER[1];
|
||||
Serial.print(F(",Checkvalue,"));
|
||||
Serial.print(packetCheck, HEX);
|
||||
Serial.print(F(","));
|
||||
}
|
||||
|
||||
digitalWrite(LED1, HIGH);
|
||||
|
||||
if (LT.transmit(TXBUFFER, TXPacketL, 10000, TXpower, WAIT_TX)) //will return 0 if transmit error
|
||||
{
|
||||
digitalWrite(LED1, LOW);
|
||||
|
||||
if (waitforACK)
|
||||
{
|
||||
if (!waitAck(packetCheck))
|
||||
{
|
||||
Serial.print(F("NoACKreceived,"));
|
||||
loopFail = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
packet_is_Error(); //transmit packet returned 0, there was an error
|
||||
loopFail = true;
|
||||
}
|
||||
|
||||
Serial.println();
|
||||
|
||||
}
|
||||
|
||||
if (!loopFail)
|
||||
{
|
||||
endmS = millis(); //all packets sent, note end time
|
||||
digitalWrite(LED1, LOW);
|
||||
Serial.println();
|
||||
LT.printModemSettings();
|
||||
sendtimemS = endmS - startmS;
|
||||
Serial.println();
|
||||
Serial.print(F("Total transmit time "));
|
||||
Serial.print(numberPackets);
|
||||
Serial.print(F(" packets = "));
|
||||
Serial.print(sendtimemS);
|
||||
Serial.println(F("mS"));
|
||||
|
||||
averagePacketTime = (float) ((endmS - startmS) / numberPackets);
|
||||
|
||||
if (waitforACK)
|
||||
{
|
||||
Serial.print(F("Average "));
|
||||
Serial.print(TXPacketL);
|
||||
Serial.print(F(" byte packet transmit and acknowledge time = "));
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.print(F("Average "));
|
||||
Serial.print(TXPacketL);
|
||||
Serial.print(F(" byte packet transmit time = "));
|
||||
}
|
||||
|
||||
Serial.print(averagePacketTime, 2);
|
||||
Serial.println(F("mS"));
|
||||
Serial.print(F("Packets per second "));
|
||||
Serial.println((float) (1000 / averagePacketTime));
|
||||
bitsPerpacket = (uint32_t) (TXPacketL * 8);
|
||||
Serial.print(F("Bits per packet sent = "));
|
||||
Serial.println(bitsPerpacket);
|
||||
|
||||
Serial.print(F("Data rate = "));
|
||||
Serial.print((bitsPerpacket / (averagePacketTime / 1000)), 0);
|
||||
Serial.print(F("bps"));
|
||||
Serial.println();
|
||||
Serial.println();
|
||||
delay(10000); //have a delay between loops so we can see result
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.println(F("Transmit test failed, trying again"));
|
||||
Serial.println();
|
||||
delay(1000);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
bool waitAck(uint32_t TXnum)
|
||||
{
|
||||
uint32_t RXnum;
|
||||
uint16_t IRQStatus;
|
||||
|
||||
RXPacketL = LT.receiveSXBuffer(0, 1000, WAIT_RX); //returns 0 if packet error of some sort
|
||||
|
||||
IRQStatus = LT.readIrqStatus(); //read the LoRa device IRQ status register
|
||||
|
||||
if (IRQStatus & IRQ_RX_TIMEOUT) //check for an RX timeout
|
||||
{
|
||||
Serial.print(F("RXTimeout,"));
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.print(F("ACKRX,"));
|
||||
}
|
||||
|
||||
LT.startReadSXBuffer(0);
|
||||
PacketType = LT.readUint8();
|
||||
RXnum = LT.readUint32();
|
||||
RXPacketL = LT.endReadSXBuffer();
|
||||
|
||||
if ( (PacketType != ACK) || (RXnum != TXnum))
|
||||
{
|
||||
Serial.print(F("NotValidACK,"));
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.print(RXnum, HEX);
|
||||
Serial.print(F(",OK"));
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
void packet_is_Error()
|
||||
{
|
||||
//if here there was an error transmitting packet
|
||||
uint16_t IRQStatus;
|
||||
IRQStatus = LT.readIrqStatus(); //read the the interrupt register
|
||||
Serial.print(F(" SendError,"));
|
||||
Serial.print(F("Length,"));
|
||||
Serial.print(TXPacketL); //print transmitted packet length
|
||||
Serial.print(F(",IRQreg,"));
|
||||
Serial.print(IRQStatus, HEX); //print IRQ status
|
||||
LT.printIrqStatus(); //prints the text of which IRQs set
|
||||
}
|
||||
|
||||
|
||||
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(9600);
|
||||
Serial.println();
|
||||
Serial.println(F("42_FLRC_Data_Throughput_Test_Transmitter Starting"));
|
||||
|
||||
SPI.begin();
|
||||
|
||||
//setup hardware pins used by device, then check if device is found
|
||||
if (LT.begin(NSS, NRESET, RFBUSY, DIO1, LORA_DEVICE))
|
||||
{
|
||||
Serial.println(F("LoRa Device found"));
|
||||
led_Flash(2, 125); //two further quick LED flashes to indicate device found
|
||||
delay(1000);
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.println(F("No device responding"));
|
||||
while (1)
|
||||
{
|
||||
led_Flash(50, 50); //long fast speed LED flash indicates device error
|
||||
}
|
||||
}
|
||||
|
||||
//***************************************************************************************************
|
||||
//Setup FLRC
|
||||
//***************************************************************************************************
|
||||
LT.setMode(MODE_STDBY_RC);
|
||||
LT.setRegulatorMode(USE_LDO);
|
||||
LT.setPacketType(PACKET_TYPE_FLRC);
|
||||
LT.setRfFrequency(Frequency, Offset);
|
||||
LT.setBufferBaseAddress(0, 0);
|
||||
LT.setModulationParams(BandwidthBitRate, CodingRate, BT);
|
||||
LT.setPacketParams(PREAMBLE_LENGTH_32_BITS, FLRC_SYNC_WORD_LEN_P32S, RADIO_RX_MATCH_SYNCWORD_1, RADIO_PACKET_VARIABLE_LENGTH, 127, RADIO_CRC_3_BYTES, RADIO_WHITENING_OFF);
|
||||
LT.setDioIrqParams(IRQ_RADIO_ALL, (IRQ_TX_DONE + IRQ_RX_TX_TIMEOUT), 0, 0); //set for IRQ on TX done and timeout on DIO1
|
||||
LT.setSyncWord1(Sample_Syncword);
|
||||
//***************************************************************************************************
|
||||
|
||||
Serial.println();
|
||||
LT.printModemSettings(); //reads and prints the configured LoRa settings, useful check
|
||||
Serial.println();
|
||||
LT.printOperatingSettings(); //reads and prints the configured operating settings, useful check
|
||||
Serial.println();
|
||||
Serial.println();
|
||||
|
||||
Serial.print(F("Transmitter ready"));
|
||||
Serial.println();
|
||||
}
|
||||
@ -0,0 +1,38 @@
|
||||
/*******************************************************************************************************
|
||||
Programs for Arduino - Copyright of the author Stuart Robinson - 26/03/20
|
||||
|
||||
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 LED1 8 //on board LED, high for on
|
||||
#define DIO1 3 //DIO1 pin on LoRa device, used for RX and TX done
|
||||
|
||||
#define LORA_DEVICE DEVICE_SX1280 //we need to define the device we are using
|
||||
|
||||
|
||||
//******* Setup LoRa Parameters Here ! ***************
|
||||
|
||||
//LoRa Modem FLRC mode Parameters
|
||||
#define Frequency 2445000000 //frequency of transmissions
|
||||
#define Offset 0 //offset frequency for calibration purposes
|
||||
|
||||
const uint8_t BandwidthBitRate = FLRC_BR_1_300_BW_1_2; //FLRC bandwidth and bit rate, 1.3Mbs
|
||||
const uint8_t CodingRate = FLRC_CR_1_2; //FLRC coding rate
|
||||
const uint8_t BT = RADIO_MOD_SHAPING_BT_1_0; //FLRC BT
|
||||
const uint32_t Sample_Syncword = 0x01234567; //FLRC uses syncword
|
||||
const int8_t TXpower = 10; //LoRa transmit power in dBm
|
||||
|
||||
|
||||
//******* Setup packet parameters Here ! ***************
|
||||
const uint8_t numberPackets = 50; //number of packets to send in transmit loop
|
||||
const uint8_t TXPacketL = 16; //length of packet to send, 1 to 127 bytes
|
||||
const bool waitforACK = false; //set to true to have transmit wait for ack before continuing
|
||||
@ -0,0 +1,274 @@
|
||||
/*******************************************************************************************************
|
||||
Programs for Arduino - Copyright of the author Stuart Robinson - 04/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.
|
||||
*******************************************************************************************************/
|
||||
|
||||
|
||||
/*******************************************************************************************************
|
||||
Program Operation - This is a program that can be used to test the throughput of a LoRa transmitter.
|
||||
Whilst the various LoRa calculators tell you the on air data rate, in practice the achievable data
|
||||
rate will be less than that due to the overhead of the software routines to load and send a packet
|
||||
and internal delays in the LoRa device itself.
|
||||
|
||||
A buffer is filled with characters and that buffer is then transmitted. The total time for a number of
|
||||
transmissions is recorded and the bit rate calculated. The packet size (1 - 255 bytes) and the number of
|
||||
packets to send in the test are specified in the 'Settings.h' file, see the 'Setup packet parameters Here !'
|
||||
section. The setting file also has the lora settings to use. A lower spreading factors and higher
|
||||
bandwidths will result in higher bitrates.
|
||||
|
||||
There is the option of turning on an a requirement for an acknowledgement from a remote receiver, before
|
||||
the transmitter sends the next packet, set this; 'const bool waitforACK = true;' definition in the
|
||||
settings file. The matching receiver program '43_LoRa_Data_Throughput_Acknowledge_Receiver' does then need
|
||||
to be configured with same lora settings as this transmitter. When this option is set, the program will
|
||||
keep running until the number of transmissions and acknowledgements has completed without any timeouts
|
||||
in order to produce a valid average.
|
||||
|
||||
The results of the test are printed out thus;
|
||||
|
||||
SX1280,PacketMode_LORA,2444999936hz,SF5,BW1625000,CR4:5
|
||||
Total transmit time 50 packets = 199mS
|
||||
Average 16 byte packet transmit time = 3.00mS
|
||||
Packets per second 333.33
|
||||
Bits per packet sent = 128
|
||||
Data rate = 42667bps
|
||||
|
||||
|
||||
|
||||
Serial monitor baud rate is set at 9600
|
||||
*******************************************************************************************************/
|
||||
|
||||
#include <SPI.h> //the lora device is SPI based so load the SPI library
|
||||
#include <SX128XLT.h> //include the appropriate library
|
||||
#include <ProgramLT_Definitions.h>
|
||||
#include "Settings.h" //include the setiings file, frequencies, LoRa settings etc
|
||||
|
||||
SX128XLT LT; //create a library class instance called LT
|
||||
|
||||
uint32_t startmS, endmS, sendtimemS, bitspersecond, bitsPerpacket;
|
||||
uint32_t TXPacketCount;
|
||||
float averagePacketTime;
|
||||
uint8_t packetNumber;
|
||||
uint8_t RXPacketL; //length of received packet
|
||||
uint8_t PacketType; //for packet addressing, identifies packet type received
|
||||
uint32_t packetCheck;
|
||||
bool loopFail = false;
|
||||
|
||||
|
||||
void loop()
|
||||
{
|
||||
uint16_t index, index2;
|
||||
uint8_t TXBUFFER[TXPacketL + 1]; //create buffer for transmitted packet
|
||||
loopFail = false;
|
||||
|
||||
Serial.println(F("Start transmit test"));
|
||||
|
||||
startmS = millis(); //start transmit timer
|
||||
|
||||
for (index = 0; index < numberPackets; index++)
|
||||
{
|
||||
//fill the buffer
|
||||
for (index2 = 0; index2 < TXPacketL; index2++)
|
||||
{
|
||||
TXBUFFER[index2] = index2;
|
||||
}
|
||||
|
||||
TXBUFFER[0] = TestPacket; //set first byte to identify this test packet
|
||||
TXBUFFER[1] = index; //put the index as packet number in second byte of packet
|
||||
Serial.print(index); //print number of packet sent
|
||||
|
||||
if (waitforACK)
|
||||
{
|
||||
packetCheck = ( (uint32_t) TXBUFFER[4] << 24) + ( (uint32_t) TXBUFFER[3] << 16) + ( (uint32_t) TXBUFFER[2] << 8) + (uint32_t) TXBUFFER[1];
|
||||
Serial.print(F(",Checkvalue,"));
|
||||
Serial.print(packetCheck, HEX);
|
||||
Serial.print(F(","));
|
||||
}
|
||||
|
||||
digitalWrite(LED1, HIGH);
|
||||
|
||||
if (LT.transmit(TXBUFFER, TXPacketL, 10000, TXpower, WAIT_TX)) //will return 0 if transmit error
|
||||
{
|
||||
digitalWrite(LED1, LOW);
|
||||
|
||||
if (waitforACK)
|
||||
{
|
||||
if (!waitAck(packetCheck))
|
||||
{
|
||||
Serial.print(F("NoACKreceived,"));
|
||||
loopFail = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
packet_is_Error(); //transmit packet returned 0, there was an error
|
||||
loopFail = true;
|
||||
}
|
||||
|
||||
Serial.println();
|
||||
|
||||
}
|
||||
|
||||
if (!loopFail)
|
||||
{
|
||||
endmS = millis(); //all packets sent, note end time
|
||||
digitalWrite(LED1, LOW);
|
||||
Serial.println();
|
||||
LT.printModemSettings();
|
||||
sendtimemS = endmS - startmS;
|
||||
Serial.println();
|
||||
Serial.print(F("Total transmit time "));
|
||||
Serial.print(numberPackets);
|
||||
Serial.print(F(" packets = "));
|
||||
Serial.print(sendtimemS);
|
||||
Serial.println(F("mS"));
|
||||
|
||||
averagePacketTime = (float) ((endmS - startmS) / numberPackets);
|
||||
|
||||
if (waitforACK)
|
||||
{
|
||||
Serial.print(F("Average "));
|
||||
Serial.print(TXPacketL);
|
||||
Serial.print(F(" byte packet transmit and acknowledge time = "));
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.print(F("Average "));
|
||||
Serial.print(TXPacketL);
|
||||
Serial.print(F(" byte packet transmit time = "));
|
||||
}
|
||||
|
||||
Serial.print(averagePacketTime, 2);
|
||||
Serial.println(F("mS"));
|
||||
Serial.print(F("Packets per second "));
|
||||
Serial.println((float) (1000 / averagePacketTime));
|
||||
bitsPerpacket = (uint32_t) (TXPacketL * 8);
|
||||
Serial.print(F("Bits per packet sent = "));
|
||||
Serial.println(bitsPerpacket);
|
||||
|
||||
Serial.print(F("Data rate = "));
|
||||
Serial.print((bitsPerpacket / (averagePacketTime / 1000)), 0);
|
||||
Serial.print(F("bps"));
|
||||
Serial.println();
|
||||
Serial.println();
|
||||
delay(10000); //have a delay between loops so we can see result
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.println(F("Transmit test failed, trying again"));
|
||||
Serial.println();
|
||||
delay(1000);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
bool waitAck(uint32_t TXnum)
|
||||
{
|
||||
uint32_t RXnum;
|
||||
uint16_t IRQStatus;
|
||||
|
||||
RXPacketL = LT.receiveSXBuffer(0, 1000, WAIT_RX); //returns 0 if packet error of some sort
|
||||
|
||||
IRQStatus = LT.readIrqStatus(); //read the LoRa device IRQ status register
|
||||
|
||||
if (IRQStatus & IRQ_RX_TIMEOUT) //check for an RX timeout
|
||||
{
|
||||
Serial.print(F("RXTimeout,"));
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.print(F("ACKRX,"));
|
||||
}
|
||||
|
||||
LT.startReadSXBuffer(0);
|
||||
PacketType = LT.readUint8();
|
||||
RXnum = LT.readUint32();
|
||||
RXPacketL = LT.endReadSXBuffer();
|
||||
|
||||
if ( (PacketType != ACK) || (RXnum != TXnum))
|
||||
{
|
||||
Serial.print(F("NotValidACK,"));
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.print(RXnum, HEX);
|
||||
Serial.print(F(",OK"));
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
void packet_is_Error()
|
||||
{
|
||||
//if here there was an error transmitting packet
|
||||
uint16_t IRQStatus;
|
||||
IRQStatus = LT.readIrqStatus(); //read the the interrupt register
|
||||
Serial.print(F(" SendError,"));
|
||||
Serial.print(F("Length,"));
|
||||
Serial.print(TXPacketL); //print transmitted packet length
|
||||
Serial.print(F(",IRQreg,"));
|
||||
Serial.print(IRQStatus, HEX); //print IRQ status
|
||||
LT.printIrqStatus(); //prints the text of which IRQs set
|
||||
}
|
||||
|
||||
|
||||
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(9600);
|
||||
Serial.println(F("42_LoRa_Data_Throughput_Test_Transmitter Starting"));
|
||||
|
||||
SPI.begin();
|
||||
|
||||
//setup hardware pins used by device, then check if device is found
|
||||
if (LT.begin(NSS, NRESET, RFBUSY, DIO1, LORA_DEVICE))
|
||||
{
|
||||
Serial.println(F("LoRa Device found"));
|
||||
led_Flash(2, 125); //two further quick LED flashes to indicate device found
|
||||
delay(1000);
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.println(F("No device responding"));
|
||||
while (1)
|
||||
{
|
||||
led_Flash(50, 50); //long fast speed LED flash indicates device error
|
||||
}
|
||||
}
|
||||
|
||||
LT.setupLoRa(Frequency, Offset, SpreadingFactor, Bandwidth, CodeRate);
|
||||
|
||||
Serial.println();
|
||||
LT.printModemSettings(); //reads and prints the configured LoRa settings, useful check
|
||||
Serial.println();
|
||||
LT.printOperatingSettings(); //reads and prints the configured operating settings, useful check
|
||||
Serial.println();
|
||||
Serial.println();
|
||||
|
||||
Serial.print(F("Transmitter ready"));
|
||||
Serial.println();
|
||||
}
|
||||
@ -0,0 +1,38 @@
|
||||
/*******************************************************************************************************
|
||||
Programs for Arduino - Copyright of the author Stuart Robinson - 26/03/20
|
||||
|
||||
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 LED1 8 //on board LED, high for on
|
||||
#define DIO1 3 //DIO1 pin on LoRa device, used for RX and TX done
|
||||
|
||||
#define LORA_DEVICE DEVICE_SX1280 //we need to define the device we are using
|
||||
|
||||
|
||||
//******* Setup LoRa Parameters Here ! ***************
|
||||
|
||||
//LoRa Modem Parameters
|
||||
#define Frequency 2445000000 //frequency of transmissions
|
||||
#define Offset 0 //offset frequency for calibration purposes
|
||||
|
||||
#define Bandwidth LORA_BW_1600 //LoRa bandwidth
|
||||
#define SpreadingFactor LORA_SF5 //LoRa spreading factor
|
||||
#define CodeRate LORA_CR_4_5 //LoRa coding rate
|
||||
|
||||
const int8_t TXpower = 10; //LoRa transmit power in dBm
|
||||
|
||||
|
||||
//******* Setup packet parameters Here ! ***************
|
||||
const uint8_t numberPackets = 50; //number of packets to send in transmit loop
|
||||
const uint8_t TXPacketL = 16; //length of packet to send
|
||||
const bool waitforACK = true; //set to true to have transmit wait for ack before continuing
|
||||
@ -0,0 +1,177 @@
|
||||
/*******************************************************************************************************
|
||||
Programs for Arduino - Copyright of the author Stuart Robinson - 04/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.
|
||||
*******************************************************************************************************/
|
||||
|
||||
/*******************************************************************************************************
|
||||
Program Operation - This is a receiver program that can be used to test the throughput of a LoRa
|
||||
transmitter. The matching program '42_FLRC_Data_Throughput_Test_Transmitter' is setup to send packets
|
||||
that require an acknowledgement before sending the next packet. This will slow down the effective
|
||||
throughput. Make sure the lora settings in the 'Settings.h' file match those used in the transmitter.
|
||||
|
||||
Serial monitor baud rate is set at 9600.
|
||||
*******************************************************************************************************/
|
||||
|
||||
#include <SPI.h> //the lora device is SPI based so load the SPI library
|
||||
#include <SX128XLT.h> //include the appropriate library
|
||||
#include <ProgramLT_Definitions.h>
|
||||
#include "Settings.h" //include the setiings file, frequencies, LoRa settings etc
|
||||
|
||||
SX128XLT LT; //create a library class instance called LT
|
||||
|
||||
uint32_t RXpacketCount;
|
||||
uint32_t errors;
|
||||
|
||||
uint8_t RXBUFFER[255]; //create the buffer that received packets are copied into
|
||||
|
||||
uint8_t RXPacketL; //stores length of packet received
|
||||
uint8_t TXPacketL; //stores length of packet sent
|
||||
int16_t PacketRSSI; //stores RSSI of received packet
|
||||
int8_t PacketSNR; //stores signal to noise ratio (SNR) of received packet
|
||||
|
||||
uint8_t PacketType; //for packet addressing, identifies packet type
|
||||
uint32_t packetCheck;
|
||||
|
||||
void loop()
|
||||
{
|
||||
RXPacketL = LT.receive(RXBUFFER, 255, 60000, WAIT_RX); //wait for a packet to arrive with 60seconds (60000mS) timeout
|
||||
|
||||
digitalWrite(LED1, HIGH); //something has happened
|
||||
|
||||
if (RXPacketL == 0) //if the LT.receive() function detects an error, RXpacketL is 0
|
||||
{
|
||||
packet_is_Error();
|
||||
}
|
||||
else
|
||||
{
|
||||
packet_is_OK();
|
||||
}
|
||||
|
||||
digitalWrite(LED1, LOW); //LED off
|
||||
|
||||
Serial.println();
|
||||
}
|
||||
|
||||
|
||||
void packet_is_OK()
|
||||
{
|
||||
RXpacketCount++;
|
||||
Serial.print(RXBUFFER[1]);
|
||||
Serial.print(F(" RX"));
|
||||
packetCheck = ( (uint32_t) RXBUFFER[4] << 24) + ( (uint32_t) RXBUFFER[3] << 16) + ( (uint32_t) RXBUFFER[2] << 8 ) + (uint32_t) RXBUFFER[1];
|
||||
Serial.print(F(",SendACK"));
|
||||
sendAck(packetCheck);
|
||||
}
|
||||
|
||||
|
||||
void sendAck(uint32_t num)
|
||||
{
|
||||
//acknowledge the packet received
|
||||
uint8_t len;
|
||||
|
||||
LT.startWriteSXBuffer(0); //initialise buffer write at address 0
|
||||
LT.writeUint8(ACK); //identify type of packet
|
||||
LT.writeUint32(num); //send the packet check, bytes 1 to 5 of packet
|
||||
len = LT.endWriteSXBuffer(); //close buffer write
|
||||
|
||||
digitalWrite(LED1, HIGH);
|
||||
TXPacketL = LT.transmitSXBuffer(0, len, 10000, TXpower, WAIT_TX);
|
||||
digitalWrite(LED1, LOW);
|
||||
}
|
||||
|
||||
|
||||
void packet_is_Error()
|
||||
{
|
||||
uint16_t IRQStatus;
|
||||
IRQStatus = LT.readIrqStatus(); //read the LoRa device IRQ status register
|
||||
|
||||
if (IRQStatus & IRQ_RX_TIMEOUT) //check for an RX timeout
|
||||
{
|
||||
Serial.print(F(",RXTimeout"));
|
||||
}
|
||||
else
|
||||
{
|
||||
errors++;
|
||||
PacketRSSI = LT.readPacketRSSI(); //read the recived RSSI value
|
||||
Serial.print(F("Error"));
|
||||
Serial.print(F(",RSSI,"));
|
||||
Serial.print(PacketRSSI);
|
||||
Serial.print(F("dBm,Len,"));
|
||||
Serial.print(LT.readRXPacketL()); //get the device packet length
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void printElapsedTime()
|
||||
{
|
||||
float seconds;
|
||||
seconds = millis() / 1000;
|
||||
Serial.print(seconds, 0);
|
||||
Serial.print(F("s"));
|
||||
}
|
||||
|
||||
|
||||
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(9600);
|
||||
Serial.println(F("43_LoRa_Data_Throughput_Acknowledge_Receiver Starting"));
|
||||
Serial.println();
|
||||
|
||||
SPI.begin();
|
||||
|
||||
if (LT.begin(NSS, NRESET, RFBUSY, DIO1, LORA_DEVICE))
|
||||
{
|
||||
Serial.println(F("LoRa Device found"));
|
||||
led_Flash(2, 125);
|
||||
delay(1000);
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.println(F("No device responding"));
|
||||
while (1)
|
||||
{
|
||||
led_Flash(50, 50); //long fast speed LED flash indicates device error
|
||||
}
|
||||
}
|
||||
|
||||
//***************************************************************************************************
|
||||
//Setup FLRC
|
||||
//***************************************************************************************************
|
||||
LT.setMode(MODE_STDBY_RC);
|
||||
LT.setRegulatorMode(USE_LDO);
|
||||
LT.setPacketType(PACKET_TYPE_FLRC);
|
||||
LT.setRfFrequency(Frequency, Offset);
|
||||
LT.setBufferBaseAddress(0, 0);
|
||||
LT.setModulationParams(BandwidthBitRate, CodingRate, BT);
|
||||
LT.setPacketParams(PREAMBLE_LENGTH_32_BITS, FLRC_SYNC_WORD_LEN_P32S, RADIO_RX_MATCH_SYNCWORD_1, RADIO_PACKET_VARIABLE_LENGTH, 127, RADIO_CRC_3_BYTES, RADIO_WHITENING_OFF);
|
||||
LT.setDioIrqParams(IRQ_RADIO_ALL, (IRQ_TX_DONE + IRQ_RX_TX_TIMEOUT), 0, 0); //set for IRQ on TX done and timeout on DIO1
|
||||
LT.setSyncWord1(Sample_Syncword);
|
||||
//***************************************************************************************************
|
||||
|
||||
Serial.println();
|
||||
LT.printModemSettings(); //reads and prints the configured LoRa settings, useful check
|
||||
Serial.println();
|
||||
Serial.println();
|
||||
|
||||
Serial.print(F("Receiver ready"));
|
||||
Serial.println();
|
||||
}
|
||||
@ -0,0 +1,33 @@
|
||||
/*******************************************************************************************************
|
||||
Programs for Arduino - Copyright of the author Stuart Robinson - 25/03/20
|
||||
|
||||
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 //busy pin on LoRa device
|
||||
#define DIO1 3 //DIO1 pin on LoRa device, used for RX and TX done
|
||||
|
||||
#define LED1 8 //on board LED, high for on
|
||||
|
||||
#define LORA_DEVICE DEVICE_SX1280 //we need to define the device we are using
|
||||
|
||||
|
||||
//******* Setup LoRa Parameters Here ! ***************
|
||||
|
||||
//LoRa Modem FLRC mode Parameters
|
||||
#define Frequency 2445000000 //frequency of transmissions
|
||||
#define Offset 0 //offset frequency for calibration purposes
|
||||
|
||||
const uint8_t BandwidthBitRate = FLRC_BR_1_300_BW_1_2; //FLRC bandwidth and bit rate, 1.3Mbs
|
||||
const uint8_t CodingRate = FLRC_CR_1_2; //FLRC coding rate
|
||||
const uint8_t BT = RADIO_MOD_SHAPING_BT_1_0; //FLRC BT
|
||||
const uint32_t Sample_Syncword = 0x01234567; //FLRC uses syncword
|
||||
const int8_t TXpower = 10; //LoRa transmit power in dBm
|
||||
@ -0,0 +1,165 @@
|
||||
/*******************************************************************************************************
|
||||
Programs for Arduino - Copyright of the author Stuart Robinson - 04/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.
|
||||
*******************************************************************************************************/
|
||||
|
||||
/*******************************************************************************************************
|
||||
Program Operation - This is a receiver program that can be used to test the throughput of a LoRa
|
||||
transmitter. The matching program '42_LoRa_Data_Throughput_Test_Transmitter' is setup to send packets
|
||||
that require an acknowledgement before sending the next packet. This will slow down the effective
|
||||
throughput. Make sure the lora settings in the 'Settings.h' file match those used in the transmitter.
|
||||
|
||||
Serial monitor baud rate is set at 9600.
|
||||
*******************************************************************************************************/
|
||||
|
||||
#include <SPI.h> //the lora device is SPI based so load the SPI library
|
||||
#include <SX128XLT.h> //include the appropriate library
|
||||
#include <ProgramLT_Definitions.h>
|
||||
#include "Settings.h" //include the setiings file, frequencies, LoRa settings etc
|
||||
|
||||
SX128XLT LT; //create a library class instance called LT
|
||||
|
||||
uint32_t RXpacketCount;
|
||||
uint32_t errors;
|
||||
|
||||
uint8_t RXBUFFER[255]; //create the buffer that received packets are copied into
|
||||
|
||||
uint8_t RXPacketL; //stores length of packet received
|
||||
uint8_t TXPacketL; //stores length of packet sent
|
||||
int16_t PacketRSSI; //stores RSSI of received packet
|
||||
int8_t PacketSNR; //stores signal to noise ratio (SNR) of received packet
|
||||
|
||||
uint8_t PacketType; //for packet addressing, identifies packet type
|
||||
uint32_t packetCheck;
|
||||
|
||||
void loop()
|
||||
{
|
||||
RXPacketL = LT.receive(RXBUFFER, 255, 60000, WAIT_RX); //wait for a packet to arrive with 60seconds (60000mS) timeout
|
||||
|
||||
digitalWrite(LED1, HIGH); //something has happened
|
||||
|
||||
if (RXPacketL == 0) //if the LT.receive() function detects an error, RXpacketL is 0
|
||||
{
|
||||
packet_is_Error();
|
||||
}
|
||||
else
|
||||
{
|
||||
packet_is_OK();
|
||||
}
|
||||
|
||||
digitalWrite(LED1, LOW); //LED off
|
||||
|
||||
Serial.println();
|
||||
}
|
||||
|
||||
|
||||
void packet_is_OK()
|
||||
{
|
||||
RXpacketCount++;
|
||||
Serial.print(RXBUFFER[1]);
|
||||
Serial.print(F(" RX"));
|
||||
packetCheck = ( (uint32_t) RXBUFFER[4] << 24) + ( (uint32_t) RXBUFFER[3] << 16) + ( (uint32_t) RXBUFFER[2] << 8 ) + (uint32_t) RXBUFFER[1];
|
||||
Serial.print(F(",SendACK"));
|
||||
sendAck(packetCheck);
|
||||
}
|
||||
|
||||
|
||||
void sendAck(uint32_t num)
|
||||
{
|
||||
//acknowledge the packet received
|
||||
uint8_t len;
|
||||
|
||||
LT.startWriteSXBuffer(0); //initialise buffer write at address 0
|
||||
LT.writeUint8(ACK); //identify type of packet
|
||||
LT.writeUint32(num); //send the packet check, bytes 1 to 5 of packet
|
||||
len = LT.endWriteSXBuffer(); //close buffer write
|
||||
|
||||
digitalWrite(LED1, HIGH);
|
||||
TXPacketL = LT.transmitSXBuffer(0, len, 10000, TXpower, WAIT_TX);
|
||||
digitalWrite(LED1, LOW);
|
||||
}
|
||||
|
||||
|
||||
void packet_is_Error()
|
||||
{
|
||||
uint16_t IRQStatus;
|
||||
IRQStatus = LT.readIrqStatus(); //read the LoRa device IRQ status register
|
||||
|
||||
if (IRQStatus & IRQ_RX_TIMEOUT) //check for an RX timeout
|
||||
{
|
||||
Serial.print(F(",RXTimeout"));
|
||||
}
|
||||
else
|
||||
{
|
||||
errors++;
|
||||
PacketRSSI = LT.readPacketRSSI(); //read the recived RSSI value
|
||||
Serial.print(F("Error"));
|
||||
Serial.print(F(",RSSI,"));
|
||||
Serial.print(PacketRSSI);
|
||||
Serial.print(F("dBm,Len,"));
|
||||
Serial.print(LT.readRXPacketL()); //get the device packet length
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void printElapsedTime()
|
||||
{
|
||||
float seconds;
|
||||
seconds = millis() / 1000;
|
||||
Serial.print(seconds, 0);
|
||||
Serial.print(F("s"));
|
||||
}
|
||||
|
||||
|
||||
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(9600);
|
||||
Serial.println(F("43_LoRa_Data_Throughput_Acknowledge_Receiver Starting"));
|
||||
Serial.println();
|
||||
|
||||
SPI.begin();
|
||||
|
||||
if (LT.begin(NSS, NRESET, RFBUSY, DIO1, LORA_DEVICE))
|
||||
{
|
||||
Serial.println(F("LoRa Device found"));
|
||||
led_Flash(2, 125);
|
||||
delay(1000);
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.println(F("No device responding"));
|
||||
while (1)
|
||||
{
|
||||
led_Flash(50, 50); //long fast speed LED flash indicates device error
|
||||
}
|
||||
}
|
||||
|
||||
LT.setupLoRa(Frequency, Offset, SpreadingFactor, Bandwidth, CodeRate);
|
||||
|
||||
Serial.println();
|
||||
LT.printModemSettings(); //reads and prints the configured LoRa settings, useful check
|
||||
Serial.println();
|
||||
Serial.println();
|
||||
|
||||
Serial.print(F("Receiver ready"));
|
||||
Serial.println();
|
||||
}
|
||||
@ -0,0 +1,33 @@
|
||||
/*******************************************************************************************************
|
||||
Programs for Arduino - Copyright of the author Stuart Robinson - 25/03/20
|
||||
|
||||
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 //busy pin on LoRa device
|
||||
#define DIO1 3 //DIO1 pin on LoRa device, used for RX and TX done
|
||||
|
||||
#define LED1 8 //on board LED, high for on
|
||||
|
||||
#define LORA_DEVICE DEVICE_SX1280 //we need to define the device we are using
|
||||
|
||||
|
||||
//******* Setup LoRa Parameters Here ! ***************
|
||||
|
||||
//LoRa Modem Parameters
|
||||
#define Frequency 2445000000 //frequency of transmissions
|
||||
#define Offset 0 //offset frequency for calibration purposes
|
||||
|
||||
#define Bandwidth LORA_BW_1600 //LoRa bandwidth
|
||||
#define SpreadingFactor LORA_SF5 //LoRa spreading factor
|
||||
#define CodeRate LORA_CR_4_5 //LoRa coding rate
|
||||
|
||||
const int8_t TXpower = 10; //LoRa transmit power in dBm
|
||||
@ -0,0 +1,183 @@
|
||||
/*******************************************************************************************************
|
||||
Programs for Arduino - Copyright of the author Stuart Robinson - 04/04/20
|
||||
|
||||
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 demonstrates the detailed setup of a LoRa test transmitter.
|
||||
A packet containing ASCII text is sent according to the frequency and LoRa settings specified in the
|
||||
'Settings.h' file. The pins to access the lora device need to be defined in the 'Settings.h' file also.
|
||||
|
||||
The details of the packet sent and any errors are shown on the Arduino IDE Serial Monitor, together with
|
||||
the transmit power used, the packet length and the CRC of the packet. The matching receive program,
|
||||
'104_LoRa_Receiver' can be used to check the packets are being sent correctly, the frequency and LoRa
|
||||
settings (in Settings.h) must be the same for the transmitter and receiver programs. Sample Serial
|
||||
Monitor output;
|
||||
|
||||
10dBm Packet> Hello World 1234567890* BytesSent,23 CRC,DAAB TransmitTime,64mS PacketsSent,2
|
||||
|
||||
Serial monitor baud rate is set at 9600
|
||||
*******************************************************************************************************/
|
||||
|
||||
#define Program_Version "V1.1"
|
||||
|
||||
#include <SPI.h> //the lora device is SPI based so load the SPI library
|
||||
#include <SX128XLT.h> //include the appropriate library
|
||||
#include "Settings.h" //include the setiings file, frequencies, LoRa settings etc
|
||||
|
||||
SX128XLT LT; //create a library class instance called LT
|
||||
|
||||
uint8_t TXPacketL;
|
||||
uint32_t TXPacketCount, startmS, endmS;
|
||||
|
||||
uint8_t buff[] = "Hello World 1234567890";
|
||||
|
||||
void loop()
|
||||
{
|
||||
Serial.print(TXpower); //print the transmit power defined
|
||||
Serial.print(F("dBm "));
|
||||
Serial.print(F("Packet> "));
|
||||
Serial.flush();
|
||||
|
||||
TXPacketL = sizeof(buff); //set TXPacketL to length of array
|
||||
buff[TXPacketL - 1] = '*'; //replace null character at buffer end so its visible on reciver
|
||||
|
||||
LT.printASCIIPacket(buff, TXPacketL); //print the buffer (the sent packet) as ASCII
|
||||
|
||||
digitalWrite(LED1, HIGH);
|
||||
startmS = millis(); //start transmit timer
|
||||
if (LT.transmit(buff, TXPacketL, 10000, TXpower, WAIT_TX)) //will return packet length sent if OK, otherwise 0 if transmit error
|
||||
{
|
||||
endmS = millis(); //packet sent, note end time
|
||||
TXPacketCount++;
|
||||
packet_is_OK();
|
||||
}
|
||||
else
|
||||
{
|
||||
packet_is_Error(); //transmit packet returned 0, there was an error
|
||||
}
|
||||
|
||||
digitalWrite(LED1, LOW);
|
||||
Serial.println();
|
||||
delay(packet_delay); //have a delay between packets
|
||||
}
|
||||
|
||||
|
||||
void packet_is_OK()
|
||||
{
|
||||
//if here packet has been sent OK
|
||||
uint16_t localCRC;
|
||||
|
||||
Serial.print(F(" BytesSent,"));
|
||||
Serial.print(TXPacketL); //print transmitted packet length
|
||||
localCRC = LT.CRCCCITT(buff, TXPacketL, 0xFFFF);
|
||||
Serial.print(F(" CRC,"));
|
||||
Serial.print(localCRC, HEX); //print CRC of transmitted packet
|
||||
Serial.print(F(" TransmitTime,"));
|
||||
Serial.print(endmS - startmS); //print transmit time of packet
|
||||
Serial.print(F("mS"));
|
||||
Serial.print(F(" PacketsSent,"));
|
||||
Serial.print(TXPacketCount); //print total of packets sent OK
|
||||
}
|
||||
|
||||
|
||||
void packet_is_Error()
|
||||
{
|
||||
//if here there was an error transmitting packet
|
||||
uint16_t IRQStatus;
|
||||
IRQStatus = LT.readIrqStatus(); //read the the interrupt register
|
||||
Serial.print(F(" SendError,"));
|
||||
Serial.print(F("Length,"));
|
||||
Serial.print(TXPacketL); //print transmitted packet length
|
||||
Serial.print(F(",IRQreg,"));
|
||||
Serial.print(IRQStatus, HEX); //print IRQ status
|
||||
LT.printIrqStatus(); //prints the text of which IRQs set
|
||||
}
|
||||
|
||||
|
||||
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(9600);
|
||||
Serial.println();
|
||||
Serial.print(F(__TIME__));
|
||||
Serial.print(F(" "));
|
||||
Serial.println(F(__DATE__));
|
||||
Serial.println(F(Program_Version));
|
||||
Serial.println();
|
||||
Serial.println(F("103_LoRa_Transmitter_Detailed_Setup Starting"));
|
||||
|
||||
//SPI.begin(); //default setup can be used be used
|
||||
SPI.begin(SCK, MISO, MOSI, NSS); //alternative format for SPI3, VSPI; SPI.begin(SCK,MISO,MOSI,SS)
|
||||
|
||||
//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));
|
||||
|
||||
//setup hardware pins used by device, then check if device is found
|
||||
if (LT.begin(NSS, NRESET, RFBUSY, DIO1, DIO2, DIO3, RX_EN, TX_EN, LORA_DEVICE))
|
||||
{
|
||||
Serial.println(F("LoRa Device found"));
|
||||
led_Flash(2, 125); //two further quick LED flashes to indicate device found
|
||||
delay(1000);
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.println(F("No device responding"));
|
||||
while (1)
|
||||
{
|
||||
led_Flash(50, 50); //long fast speed LED flash indicates device error
|
||||
}
|
||||
}
|
||||
|
||||
//The function call list below shows the complete setup for the LoRa device using the information defined in the
|
||||
//Settings.h file.
|
||||
//The 'Setup LoRa device' list below can be replaced with a single function call;
|
||||
//LT.setupLoRa(Frequency, Offset, SpreadingFactor, Bandwidth, CodeRate);
|
||||
|
||||
|
||||
//***************************************************************************************************
|
||||
//Setup LoRa device
|
||||
//***************************************************************************************************
|
||||
LT.setMode(MODE_STDBY_RC);
|
||||
LT.setRegulatorMode(USE_LDO);
|
||||
LT.setPacketType(PACKET_TYPE_LORA);
|
||||
LT.setRfFrequency(Frequency, Offset);
|
||||
LT.setBufferBaseAddress(0, 0);
|
||||
LT.setModulationParams(SpreadingFactor, Bandwidth, CodeRate);
|
||||
LT.setPacketParams(12, LORA_PACKET_VARIABLE_LENGTH, 255, LORA_CRC_ON, LORA_IQ_NORMAL, 0, 0);
|
||||
LT.setDioIrqParams(IRQ_RADIO_ALL, (IRQ_TX_DONE + IRQ_RX_TX_TIMEOUT), 0, 0);
|
||||
//***************************************************************************************************
|
||||
|
||||
|
||||
Serial.println();
|
||||
LT.printModemSettings(); //reads and prints the configured LoRa settings, useful check
|
||||
Serial.println();
|
||||
LT.printOperatingSettings(); //reads and prints the configured operating settings, useful check
|
||||
Serial.println();
|
||||
Serial.println();
|
||||
LT.printRegisters(0x900, 0x9FF); //print contents of device registers, normally 0x900 to 0x9FF
|
||||
Serial.println();
|
||||
Serial.println();
|
||||
|
||||
Serial.print(F("Transmitter ready"));
|
||||
Serial.println();
|
||||
}
|
||||
@ -0,0 +1,45 @@
|
||||
/*******************************************************************************************************
|
||||
Programs for Arduino - Copyright of the author Stuart Robinson - 02/03/20
|
||||
|
||||
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, a ESP32 shield base with BBF board shield on
|
||||
//top. Be sure to change the definitions to match your own setup. Some pins such as DIO2, DIO3, BUZZER
|
||||
//may not be in used by this sketch so they do not need to be connected and should be included and be
|
||||
//set to -1.
|
||||
|
||||
#define NSS 5 //select pin on LoRa device
|
||||
#define SCK 18 //SCK on SPI3
|
||||
#define MISO 19 //MISO on SPI3
|
||||
#define MOSI 23 //MOSI on SPI3
|
||||
|
||||
#define NRESET 27 //reset pin on LoRa device
|
||||
#define RFBUSY 25 //busy line
|
||||
|
||||
#define LED1 2 //on board LED, high for on
|
||||
#define DIO1 35 //DIO1 pin on LoRa device, used for RX and TX done
|
||||
#define DIO2 -1 //DIO2 pin on LoRa device, normally not used so set to -1
|
||||
#define DIO3 -1 //DIO3 pin on LoRa device, normally not used so set to -1
|
||||
#define RX_EN -1 //pin for RX enable, used on some SX128X devices, set to -1 if not used
|
||||
#define TX_EN -1 //pin for TX enable, used on some SX128X devices, set to -1 if not used
|
||||
#define BUZZER -1 //pin for buzzer, set to -1 if not used
|
||||
#define VCCPOWER 14 //pin controls power to external devices
|
||||
#define LORA_DEVICE DEVICE_SX1280 //we need to define the device we are using
|
||||
|
||||
|
||||
//******* Setup LoRa Parameters Here ! ***************
|
||||
|
||||
//LoRa Modem Parameters
|
||||
const uint32_t Frequency = 2445000000; //frequency of transmissions
|
||||
const int32_t Offset = 0; //offset frequency for calibration purposes
|
||||
const uint8_t Bandwidth = LORA_BW_0400; //LoRa bandwidth
|
||||
const uint8_t SpreadingFactor = LORA_SF7; //LoRa spreading factor
|
||||
const uint8_t CodeRate = LORA_CR_4_5; //LoRa coding rate
|
||||
|
||||
const int8_t TXpower = 10; //LoRa transmit power in dBm
|
||||
|
||||
const uint16_t packet_delay = 1000; //mS delay between packets
|
||||
@ -0,0 +1,223 @@
|
||||
/*******************************************************************************************************
|
||||
Programs for Arduino - Copyright of the author Stuart Robinson - 04/04/20
|
||||
|
||||
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 demonstrates the detailed setup of a LoRa test receiver.
|
||||
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 on the Arduino IDE Serial Monitor of the valid packets received, the packet is
|
||||
assumed to be in ASCII printable text, if it's not ASCII text characters from 0x20 to 0x7F, expect
|
||||
weird things to happen on the Serial Monitor. The LED will flash for each packet received and the
|
||||
buzzer will sound, if fitted.
|
||||
|
||||
Sample serial monitor output;
|
||||
|
||||
7s Hello World 1234567890*,CRC,DAAB,RSSI,-52dBm,SNR,9dB,Length,23,Packets,5,Errors,0,IRQreg,50
|
||||
|
||||
If there is a packet error it might look like this, which is showing a CRC error,
|
||||
|
||||
968s PacketError,RSSI,-87dBm,SNR,-11dB,Length,23,Packets,613,Errors,2,IRQreg,70,IRQ_HEADER_VALID,IRQ_CRC_ERROR,IRQ_RX_DONE
|
||||
|
||||
Serial monitor baud rate is set at 9600.
|
||||
*******************************************************************************************************/
|
||||
|
||||
#include <SPI.h> //the lora device is SPI based so load the SPI library
|
||||
#include <SX128XLT.h> //include the appropriate library
|
||||
#include "Settings.h" //include the setiings file, frequencies, LoRa settings etc
|
||||
|
||||
SX128XLT LT; //create a library class instance called LT
|
||||
|
||||
uint32_t RXpacketCount;
|
||||
uint32_t errors;
|
||||
|
||||
uint8_t RXBUFFER[RXBUFFER_SIZE]; //create the buffer that received packets are copied into
|
||||
|
||||
uint8_t RXPacketL; //stores length of packet received
|
||||
int16_t PacketRSSI; //stores RSSI of received packet
|
||||
int8_t PacketSNR; //stores signal to noise ratio (SNR) of received packet
|
||||
|
||||
|
||||
void loop()
|
||||
{
|
||||
RXPacketL = LT.receive(RXBUFFER, RXBUFFER_SIZE, 60000, WAIT_RX); //wait for a packet to arrive with 60seconds (60000mS) timeout
|
||||
|
||||
digitalWrite(LED1, HIGH); //something has happened
|
||||
|
||||
PacketRSSI = LT.readPacketRSSI(); //read the recived RSSI value
|
||||
PacketSNR = LT.readPacketSNR(); //read the received SNR value
|
||||
|
||||
if (RXPacketL == 0) //if the LT.receive() function detects an error, RXpacketL is 0
|
||||
{
|
||||
packet_is_Error();
|
||||
}
|
||||
else
|
||||
{
|
||||
packet_is_OK();
|
||||
}
|
||||
|
||||
digitalWrite(LED1, LOW); //LED off
|
||||
|
||||
Serial.println();
|
||||
}
|
||||
|
||||
|
||||
void packet_is_OK()
|
||||
{
|
||||
uint16_t IRQStatus, localCRC;
|
||||
|
||||
IRQStatus = LT.readIrqStatus(); //read the LoRa device IRQ status register
|
||||
|
||||
RXpacketCount++;
|
||||
|
||||
printElapsedTime(); //print elapsed time to Serial Monitor
|
||||
Serial.print(F(" "));
|
||||
LT.printASCIIPacket(RXBUFFER, RXPacketL); //print the packet as ASCII characters
|
||||
|
||||
localCRC = LT.CRCCCITT(RXBUFFER, RXPacketL, 0xFFFF); //calculate the CRC, this is the external CRC calculation of the RXBUFFER
|
||||
Serial.print(F(",CRC,")); //contents, not the LoRa device internal CRC
|
||||
Serial.print(localCRC, HEX);
|
||||
Serial.print(F(",RSSI,"));
|
||||
Serial.print(PacketRSSI);
|
||||
Serial.print(F("dBm,SNR,"));
|
||||
Serial.print(PacketSNR);
|
||||
Serial.print(F("dB,Length,"));
|
||||
Serial.print(RXPacketL);
|
||||
Serial.print(F(",Packets,"));
|
||||
Serial.print(RXpacketCount);
|
||||
Serial.print(F(",Errors,"));
|
||||
Serial.print(errors);
|
||||
Serial.print(F(",IRQreg,"));
|
||||
Serial.print(IRQStatus, HEX);
|
||||
}
|
||||
|
||||
|
||||
void packet_is_Error()
|
||||
{
|
||||
uint16_t IRQStatus;
|
||||
IRQStatus = LT.readIrqStatus(); //read the LoRa device IRQ status register
|
||||
|
||||
printElapsedTime(); //print elapsed time to Serial Monitor
|
||||
|
||||
if (IRQStatus & IRQ_RX_TIMEOUT) //check for an RX timeout
|
||||
{
|
||||
Serial.print(F(" RXTimeout"));
|
||||
}
|
||||
else
|
||||
{
|
||||
errors++;
|
||||
Serial.print(F(" PacketError"));
|
||||
Serial.print(F(",RSSI,"));
|
||||
Serial.print(PacketRSSI);
|
||||
Serial.print(F("dBm,SNR,"));
|
||||
Serial.print(PacketSNR);
|
||||
Serial.print(F("dB,Length,"));
|
||||
Serial.print(LT.readRXPacketL()); //get the device packet length
|
||||
Serial.print(F(",Packets,"));
|
||||
Serial.print(RXpacketCount);
|
||||
Serial.print(F(",Errors,"));
|
||||
Serial.print(errors);
|
||||
Serial.print(F(",IRQreg,"));
|
||||
Serial.print(IRQStatus, HEX);
|
||||
LT.printIrqStatus(); //print the names of the IRQ registers set
|
||||
}
|
||||
|
||||
delay(250); //gives a longer buzzer and LED flash for error
|
||||
|
||||
}
|
||||
|
||||
|
||||
void printElapsedTime()
|
||||
{
|
||||
float seconds;
|
||||
seconds = millis() / 1000;
|
||||
Serial.print(seconds, 0);
|
||||
Serial.print(F("s"));
|
||||
}
|
||||
|
||||
|
||||
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(9600);
|
||||
Serial.println();
|
||||
Serial.println(F("104_LoRa_Receiver_Detailed_Setup_ESP32 Starting"));
|
||||
Serial.println();
|
||||
|
||||
//SPI.begin(); //default setup can be used be used
|
||||
SPI.begin(SCK, MISO, MOSI, NSS); //alternative format for SPI3, VSPI; SPI.begin(SCK,MISO,MOSI,SS)
|
||||
|
||||
|
||||
//SPI beginTranscation is normally part of library routines, but if it is disabled in the library
|
||||
//a single instance is needed here, so uncomment the program line below
|
||||
//SPI.beginTransaction(SPISettings(8000000, MSBFIRST, SPI_MODE0));
|
||||
|
||||
//setup hardware pins used by device, then check if device is found
|
||||
if (LT.begin(NSS, NRESET, RFBUSY, DIO1, LORA_DEVICE))
|
||||
{
|
||||
Serial.println(F("LoRa Device found"));
|
||||
led_Flash(2, 125);
|
||||
delay(1000);
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.println(F("No device responding"));
|
||||
while (1)
|
||||
{
|
||||
led_Flash(50, 50); //long fast speed LED flash indicates device error
|
||||
}
|
||||
}
|
||||
|
||||
//The function call list below shows the complete setup for the LoRa device using the information defined in the
|
||||
//Settings.h file.
|
||||
//The 'Setup LoRa device' list below can be replaced with a single function call;
|
||||
//LT.setupLoRa(Frequency, Offset, SpreadingFactor, Bandwidth, CodeRate);
|
||||
|
||||
//***************************************************************************************************
|
||||
//Setup LoRa device
|
||||
//***************************************************************************************************
|
||||
LT.setMode(MODE_STDBY_RC);
|
||||
LT.setRegulatorMode(USE_LDO);
|
||||
LT.setPacketType(PACKET_TYPE_LORA);
|
||||
LT.setRfFrequency(Frequency, Offset);
|
||||
LT.setBufferBaseAddress(0, 0);
|
||||
LT.setModulationParams(SpreadingFactor, Bandwidth, CodeRate);
|
||||
LT.setPacketParams(12, LORA_PACKET_VARIABLE_LENGTH, 255, LORA_CRC_ON, LORA_IQ_NORMAL, 0, 0);
|
||||
LT.setDioIrqParams(IRQ_RADIO_ALL, (IRQ_TX_DONE + IRQ_RX_TX_TIMEOUT), 0, 0);
|
||||
//***************************************************************************************************
|
||||
|
||||
|
||||
Serial.println();
|
||||
LT.printModemSettings(); //reads and prints the configured LoRa settings, useful check
|
||||
Serial.println();
|
||||
LT.printOperatingSettings(); //reads and prints the configured operting settings, useful check
|
||||
Serial.println();
|
||||
Serial.println();
|
||||
LT.printRegisters(0x900, 0x9FF); //print contents of device registers, normally 0x900 to 0x9FF
|
||||
Serial.println();
|
||||
Serial.println();
|
||||
|
||||
Serial.print(F("Receiver ready - RXBUFFER_SIZE "));
|
||||
Serial.println(RXBUFFER_SIZE);
|
||||
Serial.println();
|
||||
}
|
||||
@ -0,0 +1,40 @@
|
||||
/*******************************************************************************************************
|
||||
Programs for Arduino - Copyright of the author Stuart Robinson - 04/04/20
|
||||
|
||||
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, a ESP32 shield base with BBF board shield on
|
||||
//top. Be sure to change the definitions to match your own setup.
|
||||
|
||||
#define NSS 5 //select pin on LoRa device
|
||||
#define SCK 18 //SCK on SPI3
|
||||
#define MISO 19 //MISO on SPI3
|
||||
#define MOSI 23 //MOSI on SPI3
|
||||
|
||||
#define NRESET 27 //reset pin on LoRa device
|
||||
#define RFBUSY 25 //busy line
|
||||
|
||||
#define LED1 2 //on board LED, high for on
|
||||
#define DIO1 35 //DIO1 pin on LoRa device, used for RX and TX done
|
||||
|
||||
#define LORA_DEVICE DEVICE_SX1280 //we need to define the device we are using
|
||||
|
||||
|
||||
//******* Setup LoRa Parameters Here ! ***************
|
||||
|
||||
//LoRa Modem Parameters
|
||||
const uint32_t Frequency = 2445000000; //frequency of transmissions
|
||||
const int32_t Offset = 0; //offset frequency for calibration purposes
|
||||
const uint8_t Bandwidth = LORA_BW_0400; //LoRa bandwidth
|
||||
const uint8_t SpreadingFactor = LORA_SF7; //LoRa spreading factor
|
||||
const uint8_t CodeRate = LORA_CR_4_5; //LoRa coding rate
|
||||
|
||||
const int8_t TXpower = 10; //LoRa transmit power in dBm
|
||||
|
||||
const uint16_t packet_delay = 1000; //mS delay between packets
|
||||
|
||||
#define RXBUFFER_SIZE 32 //RX buffer size
|
||||
BIN
examples/SX128x_examples/ESP32/ESP32_Bare_Bones_Schematic.jpg
Normal file
BIN
examples/SX128x_examples/ESP32/ESP32_Bare_Bones_Schematic.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 38 KiB |
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user