Update LoRaWAN examples

This commit is contained in:
lewisxhe 2024-11-05 10:39:42 +08:00
commit 95553f48e7
6 changed files with 1442 additions and 74 deletions

View file

@ -0,0 +1,850 @@
/**
* @file boards.cpp
* @author Lewis He (lewishe@outlook.com)
* @license MIT
* @copyright Copyright (c) 2024 ShenZhen XinYuan Electronic Technology Co., Ltd
* @date 2024-04-24
* @last-update 2024-08-07
*
*/
#include "LoRaBoards.h"
#if defined(HAS_SDCARD)
SPIClass SDCardSPI(HSPI);
#endif
#if defined(ARDUINO_ARCH_STM32)
HardwareSerial SerialGPS(GPS_RX_PIN, GPS_TX_PIN);
#endif
#if defined(ARDUINO_ARCH_ESP32)
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5,0,0)
#include "hal/gpio_hal.h"
#endif
#include "driver/gpio.h"
#endif //ARDUINO_ARCH_ESP32
DISPLAY_MODEL *u8g2 = NULL;
static DevInfo_t devInfo;
#ifdef HAS_GPS
static bool find_gps = false;
#endif
#ifdef HAS_PMU
XPowersLibInterface *PMU = NULL;
bool pmuInterrupt;
static void setPmuFlag()
{
pmuInterrupt = true;
}
#endif
bool beginPower()
{
#ifdef HAS_PMU
if (!PMU) {
PMU = new XPowersAXP2101(PMU_WIRE_PORT);
if (!PMU->init()) {
Serial.println("Warning: Failed to find AXP2101 power management");
delete PMU;
PMU = NULL;
} else {
Serial.println("AXP2101 PMU init succeeded, using AXP2101 PMU");
}
}
if (!PMU) {
PMU = new XPowersAXP192(PMU_WIRE_PORT);
if (!PMU->init()) {
Serial.println("Warning: Failed to find AXP192 power management");
delete PMU;
PMU = NULL;
} else {
Serial.println("AXP192 PMU init succeeded, using AXP192 PMU");
}
}
if (!PMU) {
return false;
}
PMU->setChargingLedMode(XPOWERS_CHG_LED_CTRL_CHG);
pinMode(PMU_IRQ, INPUT_PULLUP);
attachInterrupt(PMU_IRQ, setPmuFlag, FALLING);
if (PMU->getChipModel() == XPOWERS_AXP192) {
PMU->setProtectedChannel(XPOWERS_DCDC3);
// lora
PMU->setPowerChannelVoltage(XPOWERS_LDO2, 3300);
// gps
PMU->setPowerChannelVoltage(XPOWERS_LDO3, 3300);
// oled
PMU->setPowerChannelVoltage(XPOWERS_DCDC1, 3300);
PMU->enablePowerOutput(XPOWERS_LDO2);
PMU->enablePowerOutput(XPOWERS_LDO3);
//protected oled power source
PMU->setProtectedChannel(XPOWERS_DCDC1);
//protected esp32 power source
PMU->setProtectedChannel(XPOWERS_DCDC3);
// enable oled power
PMU->enablePowerOutput(XPOWERS_DCDC1);
//disable not use channel
PMU->disablePowerOutput(XPOWERS_DCDC2);
PMU->disableIRQ(XPOWERS_AXP192_ALL_IRQ);
PMU->enableIRQ(XPOWERS_AXP192_VBUS_REMOVE_IRQ |
XPOWERS_AXP192_VBUS_INSERT_IRQ |
XPOWERS_AXP192_BAT_CHG_DONE_IRQ |
XPOWERS_AXP192_BAT_CHG_START_IRQ |
XPOWERS_AXP192_BAT_REMOVE_IRQ |
XPOWERS_AXP192_BAT_INSERT_IRQ |
XPOWERS_AXP192_PKEY_SHORT_IRQ
);
} else if (PMU->getChipModel() == XPOWERS_AXP2101) {
#if defined(CONFIG_IDF_TARGET_ESP32)
//Unuse power channel
PMU->disablePowerOutput(XPOWERS_DCDC2);
PMU->disablePowerOutput(XPOWERS_DCDC3);
PMU->disablePowerOutput(XPOWERS_DCDC4);
PMU->disablePowerOutput(XPOWERS_DCDC5);
PMU->disablePowerOutput(XPOWERS_ALDO1);
PMU->disablePowerOutput(XPOWERS_ALDO4);
PMU->disablePowerOutput(XPOWERS_BLDO1);
PMU->disablePowerOutput(XPOWERS_BLDO2);
PMU->disablePowerOutput(XPOWERS_DLDO1);
PMU->disablePowerOutput(XPOWERS_DLDO2);
// GNSS RTC PowerVDD 3300mV
PMU->setPowerChannelVoltage(XPOWERS_VBACKUP, 3300);
PMU->enablePowerOutput(XPOWERS_VBACKUP);
//ESP32 VDD 3300mV
// ! No need to set, automatically open , Don't close it
// PMU->setPowerChannelVoltage(XPOWERS_DCDC1, 3300);
// PMU->setProtectedChannel(XPOWERS_DCDC1);
PMU->setProtectedChannel(XPOWERS_DCDC1);
// LoRa VDD 3300mV
PMU->setPowerChannelVoltage(XPOWERS_ALDO2, 3300);
PMU->enablePowerOutput(XPOWERS_ALDO2);
//GNSS VDD 3300mV
PMU->setPowerChannelVoltage(XPOWERS_ALDO3, 3300);
PMU->enablePowerOutput(XPOWERS_ALDO3);
#endif /*CONFIG_IDF_TARGET_ESP32*/
#if defined(T_BEAM_S3_SUPREME)
//t-beam m.2 inface
//gps
PMU->setPowerChannelVoltage(XPOWERS_ALDO4, 3300);
PMU->enablePowerOutput(XPOWERS_ALDO4);
// lora
PMU->setPowerChannelVoltage(XPOWERS_ALDO3, 3300);
PMU->enablePowerOutput(XPOWERS_ALDO3);
// In order to avoid bus occupation, during initialization, the SD card and QMC sensor are powered off and restarted
if (ESP_SLEEP_WAKEUP_UNDEFINED == esp_sleep_get_wakeup_cause()) {
Serial.println("Power off and restart ALDO BLDO..");
PMU->disablePowerOutput(XPOWERS_ALDO1);
PMU->disablePowerOutput(XPOWERS_ALDO2);
PMU->disablePowerOutput(XPOWERS_BLDO1);
delay(250);
}
// Sensor
PMU->setPowerChannelVoltage(XPOWERS_ALDO1, 3300);
PMU->enablePowerOutput(XPOWERS_ALDO1);
PMU->setPowerChannelVoltage(XPOWERS_ALDO2, 3300);
PMU->enablePowerOutput(XPOWERS_ALDO2);
//Sdcard
PMU->setPowerChannelVoltage(XPOWERS_BLDO1, 3300);
PMU->enablePowerOutput(XPOWERS_BLDO1);
PMU->setPowerChannelVoltage(XPOWERS_BLDO2, 3300);
PMU->enablePowerOutput(XPOWERS_BLDO2);
//face m.2
PMU->setPowerChannelVoltage(XPOWERS_DCDC3, 3300);
PMU->enablePowerOutput(XPOWERS_DCDC3);
PMU->setPowerChannelVoltage(XPOWERS_DCDC4, XPOWERS_AXP2101_DCDC4_VOL2_MAX);
PMU->enablePowerOutput(XPOWERS_DCDC4);
PMU->setPowerChannelVoltage(XPOWERS_DCDC5, 3300);
PMU->enablePowerOutput(XPOWERS_DCDC5);
//not use channel
PMU->disablePowerOutput(XPOWERS_DCDC2);
// PMU->disablePowerOutput(XPOWERS_DCDC4);
// PMU->disablePowerOutput(XPOWERS_DCDC5);
PMU->disablePowerOutput(XPOWERS_DLDO1);
PMU->disablePowerOutput(XPOWERS_DLDO2);
PMU->disablePowerOutput(XPOWERS_VBACKUP);
#elif defined(T_BEAM_S3_BPF)
//gps
PMU->setPowerChannelVoltage(XPOWERS_ALDO4, 3300);
PMU->enablePowerOutput(XPOWERS_ALDO4);
//Sdcard
PMU->setPowerChannelVoltage(XPOWERS_ALDO2, 3300);
PMU->enablePowerOutput(XPOWERS_ALDO2);
// Extern Power source
PMU->setPowerChannelVoltage(XPOWERS_DCDC3, 3300);
PMU->enablePowerOutput(XPOWERS_DCDC3);
PMU->setPowerChannelVoltage(XPOWERS_DCDC5, 3300);
PMU->enablePowerOutput(XPOWERS_DCDC5);
PMU->setPowerChannelVoltage(XPOWERS_ALDO1, 3300);
PMU->enablePowerOutput(XPOWERS_ALDO1);
//not use channel
PMU->disablePowerOutput(XPOWERS_BLDO1);
PMU->disablePowerOutput(XPOWERS_BLDO2);
PMU->disablePowerOutput(XPOWERS_DCDC4);
PMU->disablePowerOutput(XPOWERS_DCDC2);
PMU->disablePowerOutput(XPOWERS_DCDC4);
PMU->disablePowerOutput(XPOWERS_DCDC5);
PMU->disablePowerOutput(XPOWERS_DLDO1);
PMU->disablePowerOutput(XPOWERS_DLDO2);
PMU->disablePowerOutput(XPOWERS_VBACKUP);
#endif
// Set constant current charge current limit
PMU->setChargerConstantCurr(XPOWERS_AXP2101_CHG_CUR_500MA);
// Set charge cut-off voltage
PMU->setChargeTargetVoltage(XPOWERS_AXP2101_CHG_VOL_4V2);
// Disable all interrupts
PMU->disableIRQ(XPOWERS_AXP2101_ALL_IRQ);
// Clear all interrupt flags
PMU->clearIrqStatus();
// Enable the required interrupt function
PMU->enableIRQ(
XPOWERS_AXP2101_BAT_INSERT_IRQ | XPOWERS_AXP2101_BAT_REMOVE_IRQ | //BATTERY
XPOWERS_AXP2101_VBUS_INSERT_IRQ | XPOWERS_AXP2101_VBUS_REMOVE_IRQ | //VBUS
XPOWERS_AXP2101_PKEY_SHORT_IRQ | XPOWERS_AXP2101_PKEY_LONG_IRQ | //POWER KEY
XPOWERS_AXP2101_BAT_CHG_DONE_IRQ | XPOWERS_AXP2101_BAT_CHG_START_IRQ //CHARGE
// XPOWERS_AXP2101_PKEY_NEGATIVE_IRQ | XPOWERS_AXP2101_PKEY_POSITIVE_IRQ | //POWER KEY
);
}
PMU->enableSystemVoltageMeasure();
PMU->enableVbusVoltageMeasure();
PMU->enableBattVoltageMeasure();
Serial.printf("=========================================\n");
if (PMU->isChannelAvailable(XPOWERS_DCDC1)) {
Serial.printf("DC1 : %s Voltage: %04u mV \n", PMU->isPowerChannelEnable(XPOWERS_DCDC1) ? "+" : "-", PMU->getPowerChannelVoltage(XPOWERS_DCDC1));
}
if (PMU->isChannelAvailable(XPOWERS_DCDC2)) {
Serial.printf("DC2 : %s Voltage: %04u mV \n", PMU->isPowerChannelEnable(XPOWERS_DCDC2) ? "+" : "-", PMU->getPowerChannelVoltage(XPOWERS_DCDC2));
}
if (PMU->isChannelAvailable(XPOWERS_DCDC3)) {
Serial.printf("DC3 : %s Voltage: %04u mV \n", PMU->isPowerChannelEnable(XPOWERS_DCDC3) ? "+" : "-", PMU->getPowerChannelVoltage(XPOWERS_DCDC3));
}
if (PMU->isChannelAvailable(XPOWERS_DCDC4)) {
Serial.printf("DC4 : %s Voltage: %04u mV \n", PMU->isPowerChannelEnable(XPOWERS_DCDC4) ? "+" : "-", PMU->getPowerChannelVoltage(XPOWERS_DCDC4));
}
if (PMU->isChannelAvailable(XPOWERS_DCDC5)) {
Serial.printf("DC5 : %s Voltage: %04u mV \n", PMU->isPowerChannelEnable(XPOWERS_DCDC5) ? "+" : "-", PMU->getPowerChannelVoltage(XPOWERS_DCDC5));
}
if (PMU->isChannelAvailable(XPOWERS_LDO2)) {
Serial.printf("LDO2 : %s Voltage: %04u mV \n", PMU->isPowerChannelEnable(XPOWERS_LDO2) ? "+" : "-", PMU->getPowerChannelVoltage(XPOWERS_LDO2));
}
if (PMU->isChannelAvailable(XPOWERS_LDO3)) {
Serial.printf("LDO3 : %s Voltage: %04u mV \n", PMU->isPowerChannelEnable(XPOWERS_LDO3) ? "+" : "-", PMU->getPowerChannelVoltage(XPOWERS_LDO3));
}
if (PMU->isChannelAvailable(XPOWERS_ALDO1)) {
Serial.printf("ALDO1: %s Voltage: %04u mV \n", PMU->isPowerChannelEnable(XPOWERS_ALDO1) ? "+" : "-", PMU->getPowerChannelVoltage(XPOWERS_ALDO1));
}
if (PMU->isChannelAvailable(XPOWERS_ALDO2)) {
Serial.printf("ALDO2: %s Voltage: %04u mV \n", PMU->isPowerChannelEnable(XPOWERS_ALDO2) ? "+" : "-", PMU->getPowerChannelVoltage(XPOWERS_ALDO2));
}
if (PMU->isChannelAvailable(XPOWERS_ALDO3)) {
Serial.printf("ALDO3: %s Voltage: %04u mV \n", PMU->isPowerChannelEnable(XPOWERS_ALDO3) ? "+" : "-", PMU->getPowerChannelVoltage(XPOWERS_ALDO3));
}
if (PMU->isChannelAvailable(XPOWERS_ALDO4)) {
Serial.printf("ALDO4: %s Voltage: %04u mV \n", PMU->isPowerChannelEnable(XPOWERS_ALDO4) ? "+" : "-", PMU->getPowerChannelVoltage(XPOWERS_ALDO4));
}
if (PMU->isChannelAvailable(XPOWERS_BLDO1)) {
Serial.printf("BLDO1: %s Voltage: %04u mV \n", PMU->isPowerChannelEnable(XPOWERS_BLDO1) ? "+" : "-", PMU->getPowerChannelVoltage(XPOWERS_BLDO1));
}
if (PMU->isChannelAvailable(XPOWERS_BLDO2)) {
Serial.printf("BLDO2: %s Voltage: %04u mV \n", PMU->isPowerChannelEnable(XPOWERS_BLDO2) ? "+" : "-", PMU->getPowerChannelVoltage(XPOWERS_BLDO2));
}
Serial.printf("=========================================\n");
// Set the time of pressing the button to turn off
PMU->setPowerKeyPressOffTime(XPOWERS_POWEROFF_4S);
uint8_t opt = PMU->getPowerKeyPressOffTime();
Serial.print("PowerKeyPressOffTime:");
switch (opt) {
case XPOWERS_POWEROFF_4S: Serial.println("4 Second");
break;
case XPOWERS_POWEROFF_6S: Serial.println("6 Second");
break;
case XPOWERS_POWEROFF_8S: Serial.println("8 Second");
break;
case XPOWERS_POWEROFF_10S: Serial.println("10 Second");
break;
default:
break;
}
#endif
return true;
}
void disablePeripherals()
{
#ifdef HAS_PMU
if (!PMU)return;
#if defined(T_BEAM_S3_BPF)
PMU->disablePowerOutput(XPOWERS_ALDO4); //gps
PMU->disablePowerOutput(XPOWERS_ALDO2); //Sdcard
PMU->disablePowerOutput(XPOWERS_DCDC3); // Extern Power source
PMU->disablePowerOutput(XPOWERS_DCDC5);
PMU->disablePowerOutput(XPOWERS_ALDO1);
#endif
#endif
}
void loopPMU()
{
#ifdef HAS_PMU
if (!PMU) {
return;
}
if (!pmuInterrupt) {
return;
}
pmuInterrupt = false;
// Get PMU Interrupt Status Register
uint32_t status = PMU->getIrqStatus();
Serial.print("STATUS => HEX:");
Serial.print(status, HEX);
Serial.print(" BIN:");
Serial.println(status, BIN);
if (PMU->isVbusInsertIrq()) {
Serial.println("isVbusInsert");
}
if (PMU->isVbusRemoveIrq()) {
Serial.println("isVbusRemove");
}
if (PMU->isBatInsertIrq()) {
Serial.println("isBatInsert");
}
if (PMU->isBatRemoveIrq()) {
Serial.println("isBatRemove");
}
if (PMU->isPekeyShortPressIrq()) {
Serial.println("isPekeyShortPress");
}
if (PMU->isPekeyLongPressIrq()) {
Serial.println("isPekeyLongPress");
}
if (PMU->isBatChagerDoneIrq()) {
Serial.println("isBatChagerDone");
}
if (PMU->isBatChagerStartIrq()) {
Serial.println("isBatChagerStart");
}
// Clear PMU Interrupt Status Register
PMU->clearIrqStatus();
#endif
}
bool beginDisplay()
{
Wire.beginTransmission(DISPLAY_ADDR);
if (Wire.endTransmission() == 0) {
Serial.printf("Find Display model at 0x%X address\n", DISPLAY_ADDR);
u8g2 = new DISPLAY_MODEL(U8G2_R0, U8X8_PIN_NONE);
u8g2->begin();
u8g2->clearBuffer();
u8g2->setFont(u8g2_font_inb19_mr);
u8g2->drawStr(0, 30, "LilyGo");
u8g2->drawHLine(2, 35, 47);
u8g2->drawHLine(3, 36, 47);
u8g2->drawVLine(45, 32, 12);
u8g2->drawVLine(46, 33, 12);
u8g2->setFont(u8g2_font_inb19_mf);
u8g2->drawStr(58, 60, "LoRa");
u8g2->sendBuffer();
u8g2->setFont(u8g2_font_fur11_tf);
delay(3000);
return true;
}
Serial.printf("Warning: Failed to find Display at 0x%0X address\n", DISPLAY_ADDR);
return false;
}
bool beginSDCard()
{
#ifdef SDCARD_CS
if (SD.begin(SDCARD_CS, SDCardSPI)) {
uint32_t cardSize = SD.cardSize() / (1024 * 1024);
Serial.print("Sd Card init succeeded, The current available capacity is ");
Serial.print(cardSize / 1024.0);
Serial.println(" GB");
return true;
} else {
Serial.println("Warning: Failed to init Sd Card");
}
#endif
return false;
}
void beginWiFi()
{
if (!WiFi.softAP(BOARD_VARIANT_NAME)) {
log_e("Soft AP creation failed.");
}
IPAddress myIP = WiFi.softAPIP();
Serial.print("AP IP address: ");
Serial.println(myIP);
}
void printWakeupReason()
{
#ifdef ESP32
Serial.print("Reset reason:");
esp_sleep_wakeup_cause_t wakeup_reason;
wakeup_reason = esp_sleep_get_wakeup_cause();
switch (wakeup_reason) {
case ESP_SLEEP_WAKEUP_UNDEFINED:
Serial.println(" In case of deep sleep, reset was not caused by exit from deep sleep");
break;
case ESP_SLEEP_WAKEUP_ALL :
break;
case ESP_SLEEP_WAKEUP_EXT0 :
Serial.println("Wakeup caused by external signal using RTC_IO");
break;
case ESP_SLEEP_WAKEUP_EXT1 :
Serial.println("Wakeup caused by external signal using RTC_CNTL");
break;
case ESP_SLEEP_WAKEUP_TIMER :
Serial.println("Wakeup caused by timer");
break;
case ESP_SLEEP_WAKEUP_TOUCHPAD :
Serial.println("Wakeup caused by touchpad");
break;
case ESP_SLEEP_WAKEUP_ULP :
Serial.println("Wakeup caused by ULP program");
break;
default :
Serial.printf("Wakeup was not caused by deep sleep: %d\n", wakeup_reason);
break;
}
#endif
}
void getChipInfo()
{
#if defined(ARDUINO_ARCH_ESP32)
Serial.println("-----------------------------------");
printWakeupReason();
#if defined(CONFIG_IDF_TARGET_ESP32) || defined(CONFIG_IDF_TARGET_ESP32S3)
if (psramFound()) {
uint32_t psram = ESP.getPsramSize();
devInfo.psramSize = psram / 1024.0 / 1024.0;
Serial.printf("PSRAM is enable! PSRAM: %.2fMB\n", devInfo.psramSize);
} else {
Serial.println("PSRAM is disable!");
devInfo.psramSize = 0;
}
#endif
Serial.print("Flash:");
devInfo.flashSize = ESP.getFlashChipSize() / 1024.0 / 1024.0;
devInfo.flashSpeed = ESP.getFlashChipSpeed() / 1000 / 1000;
devInfo.chipModel = ESP.getChipModel();
devInfo.chipModelRev = ESP.getChipRevision();
devInfo.chipFreq = ESP.getCpuFreqMHz();
Serial.print(devInfo.flashSize);
Serial.println(" MB");
Serial.print("Flash speed:");
Serial.print(devInfo.flashSpeed);
Serial.println(" M");
Serial.print("Model:");
Serial.println(devInfo.chipModel);
Serial.print("Chip Revision:");
Serial.println(devInfo.chipModelRev);
Serial.print("Freq:");
Serial.print(devInfo.chipFreq);
Serial.println(" MHZ");
Serial.print("SDK Ver:");
Serial.println(ESP.getSdkVersion());
Serial.print("DATE:");
Serial.println(__DATE__);
Serial.print("TIME:");
Serial.println(__TIME__);
Serial.print("EFUSE MAC: ");
Serial.print( ESP.getEfuseMac(), HEX);
Serial.println();
Serial.println("-----------------------------------");
#elif defined(ARDUINO_ARCH_STM32)
uint32_t uid[3];
uid[0] = HAL_GetUIDw0();
uid[1] = HAL_GetUIDw1();
uid[2] = HAL_GetUIDw2();
Serial.print("STM UID: 0X");
Serial.print( uid[0], HEX);
Serial.print( uid[1], HEX);
Serial.print( uid[2], HEX);
Serial.println();
#endif
}
void setupBoards(bool disable_u8g2 )
{
Serial.begin(115200);
// while (!Serial);
Serial.println("setupBoards");
getChipInfo();
#if defined(ARDUINO_ARCH_ESP32)
SPI.begin(RADIO_SCLK_PIN, RADIO_MISO_PIN, RADIO_MOSI_PIN);
#elif defined(ARDUINO_ARCH_STM32)
SPI.setMISO(RADIO_MISO_PIN);
SPI.setMOSI(RADIO_MOSI_PIN);
SPI.setSCLK(RADIO_SCLK_PIN);
SPI.begin();
#endif
#ifdef HAS_SDCARD
SDCardSPI.begin(SDCARD_SCLK, SDCARD_MISO, SDCARD_MOSI);
#endif
#ifdef I2C_SDA
Wire.begin(I2C_SDA, I2C_SCL);
scanDevices(&Wire);
#endif
#ifdef I2C1_SDA
Wire1.begin(I2C1_SDA, I2C1_SCL);
#endif
#ifdef HAS_GPS
#if defined(ARDUINO_ARCH_ESP32)
SerialGPS.begin(GPS_BAUD_RATE, SERIAL_8N1, GPS_RX_PIN, GPS_TX_PIN);
#elif defined(ARDUINO_ARCH_STM32)
SerialGPS.setRx(GPS_RX_PIN);
SerialGPS.setTx(GPS_TX_PIN);
SerialGPS.begin(GPS_BAUD_RATE);
#endif // ARDUINO_ARCH_
#endif // HAS_GPS
#if OLED_RST
pinMode(OLED_RST, OUTPUT);
digitalWrite(OLED_RST, HIGH); delay(20);
digitalWrite(OLED_RST, LOW); delay(20);
digitalWrite(OLED_RST, HIGH); delay(20);
#endif
#ifdef BOARD_LED
/*
* T-Beam LED defaults to low level as turn on,
* so it needs to be forced to pull up
* * * * */
#if LED_ON == LOW
#if defined(ARDUINO_ARCH_ESP32)
gpio_hold_dis((gpio_num_t)BOARD_LED);
#endif //ARDUINO_ARCH_ESP32
#endif
pinMode(BOARD_LED, OUTPUT);
digitalWrite(BOARD_LED, LED_ON);
#endif
#ifdef GPS_EN_PIN
pinMode(GPS_EN_PIN, OUTPUT);
digitalWrite(GPS_EN_PIN, HIGH);
#endif
#ifdef GPS_RST_PIN
pinMode(GPS_RST_PIN, OUTPUT);
digitalWrite(GPS_RST_PIN, HIGH);
#endif
#if defined(ARDUINO_ARCH_STM32)
SerialGPS.println("@GSR"); delay(300);
SerialGPS.println("@GSR"); delay(300);
SerialGPS.println("@GSR"); delay(300);
SerialGPS.println("@GSR"); delay(300);
SerialGPS.println("@GSR"); delay(300);
#endif
#ifdef RADIO_LDO_EN
pinMode(RADIO_LDO_EN, OUTPUT);
digitalWrite(RADIO_LDO_EN, HIGH);
#endif
beginPower();
beginSDCard();
if (!disable_u8g2) {
beginDisplay();
}
// beginWiFi();
#ifdef HAS_GPS
#ifdef T_BEAM_S3_BPF
find_gps = beginGPS();
#endif
#endif
Serial.println("init done . ");
}
void printResult(bool radio_online)
{
Serial.print("Radio : ");
Serial.println((radio_online) ? "+" : "-");
#if defined(CONFIG_IDF_TARGET_ESP32) || defined(CONFIG_IDF_TARGET_ESP32S3)
Serial.print("PSRAM : ");
Serial.println((psramFound()) ? "+" : "-");
Serial.print("Display : ");
Serial.println(( u8g2) ? "+" : "-");
#ifdef HAS_SDCARD
Serial.print("Sd Card : ");
Serial.println((SD.cardSize() != 0) ? "+" : "-");
#endif
#ifdef HAS_PMU
Serial.print("Power : ");
Serial.println(( PMU ) ? "+" : "-");
#endif
#ifdef HAS_GPS
#ifdef T_BEAM_S3_BPF
Serial.print("GPS : ");
Serial.println(( find_gps ) ? "+" : "-");
#endif
#endif
if (u8g2) {
u8g2->clearBuffer();
u8g2->setFont(u8g2_font_NokiaLargeBold_tf );
uint16_t str_w = u8g2->getStrWidth(BOARD_VARIANT_NAME);
u8g2->drawStr((u8g2->getWidth() - str_w) / 2, 16, BOARD_VARIANT_NAME);
u8g2->drawHLine(5, 21, u8g2->getWidth() - 5);
u8g2->drawStr( 0, 38, "Disp:"); u8g2->drawStr( 45, 38, ( u8g2) ? "+" : "-");
#ifdef HAS_SDCARD
u8g2->drawStr( 0, 54, "SD :"); u8g2->drawStr( 45, 54, (SD.cardSize() != 0) ? "+" : "-");
#endif
u8g2->drawStr( 62, 38, "Radio:"); u8g2->drawStr( 120, 38, ( radio_online ) ? "+" : "-");
#ifdef HAS_PMU
u8g2->drawStr( 62, 54, "Power:"); u8g2->drawStr( 120, 54, ( PMU ) ? "+" : "-");
#endif
u8g2->sendBuffer();
delay(2000);
}
#endif
}
static uint8_t ledState = LOW;
static const uint32_t debounceDelay = 50;
static uint32_t lastDebounceTime = 0;
void flashLed()
{
#ifdef BOARD_LED
if ((millis() - lastDebounceTime) > debounceDelay) {
ledState = !ledState;
if (ledState) {
digitalWrite(BOARD_LED, LED_ON);
} else {
digitalWrite(BOARD_LED, !LED_ON);
}
lastDebounceTime = millis();
}
#endif
}
void scanDevices(TwoWire *w)
{
uint8_t err, addr;
int nDevices = 0;
uint32_t start = 0;
Serial.println("I2C Devices scanning");
for (addr = 1; addr < 127; addr++) {
start = millis();
w->beginTransmission(addr); delay(2);
err = w->endTransmission();
if (err == 0) {
nDevices++;
switch (addr) {
case 0x77:
case 0x76:
Serial.println("\tFind BMX280 Sensor!");
break;
case 0x34:
Serial.println("\tFind AXP192/AXP2101 PMU!");
break;
case 0x3C:
Serial.println("\tFind SSD1306/SH1106 dispaly!");
break;
case 0x51:
Serial.println("\tFind PCF8563 RTC!");
break;
case 0x1C:
Serial.println("\tFind QMC6310 MAG Sensor!");
break;
default:
Serial.print("\tI2C device found at address 0x");
if (addr < 16) {
Serial.print("0");
}
Serial.print(addr, HEX);
Serial.println(" !");
break;
}
} else if (err == 4) {
Serial.print("Unknow error at address 0x");
if (addr < 16) {
Serial.print("0");
}
Serial.println(addr, HEX);
}
}
if (nDevices == 0)
Serial.println("No I2C devices found\n");
Serial.println("Scan devices done.");
Serial.println("\n");
}
#ifdef HAS_GPS
bool beginGPS()
{
SerialGPS.begin(GPS_BAUD_RATE, SERIAL_8N1, GPS_RX_PIN, GPS_TX_PIN);
bool result = false;
uint32_t startTimeout ;
for (int i = 0; i < 3; ++i) {
SerialGPS.write("$PCAS03,0,0,0,0,0,0,0,0,0,0,,,0,0*02\r\n");
delay(5);
// Get version information
startTimeout = millis() + 3000;
Serial.print("Try to init L76K . Wait stop .");
while (SerialGPS.available()) {
Serial.print(".");
SerialGPS.readString();
if (millis() > startTimeout) {
Serial.println("Wait L76K stop NMEA timeout!");
return false;
}
};
Serial.println();
SerialGPS.flush();
delay(200);
SerialGPS.write("$PCAS06,0*1B\r\n");
startTimeout = millis() + 500;
String ver = "";
while (!SerialGPS.available()) {
if (millis() > startTimeout) {
Serial.println("Get L76K timeout!");
return false;
}
}
SerialGPS.setTimeout(10);
ver = SerialGPS.readStringUntil('\n');
if (ver.startsWith("$GPTXT,01,01,02")) {
Serial.println("L76K GNSS init succeeded, using L76K GNSS Module\n");
result = true;
break;
}
delay(500);
}
// Initialize the L76K Chip, use GPS + GLONASS
SerialGPS.write("$PCAS04,5*1C\r\n");
delay(250);
// only ask for RMC and GGA
SerialGPS.write("$PCAS03,1,0,0,0,1,0,0,0,0,0,,,0,0*02\r\n");
delay(250);
// Switch to Vehicle Mode, since SoftRF enables Aviation < 2g
SerialGPS.write("$PCAS11,3*1E\r\n");
return result;
}
#endif

View file

@ -0,0 +1,102 @@
/**
* @file boards.h
* @author Lewis He (lewishe@outlook.com)
* @license MIT
* @copyright Copyright (c) 2024 ShenZhen XinYuan Electronic Technology Co., Ltd
* @date 2024-04-25
* @last-update 2024-08-07
*/
#pragma once
#include "utilities.h"
#ifdef HAS_SDCARD
#include <SD.h>
#endif
#if defined(ARDUINO_ARCH_ESP32)
#include <FS.h>
#include <WiFi.h>
#endif
#include <Arduino.h>
#include <SPI.h>
#include <Wire.h>
#include <U8g2lib.h>
#include <XPowersLib.h>
#ifndef DISPLAY_MODEL
#define DISPLAY_MODEL U8G2_SSD1306_128X64_NONAME_F_HW_I2C
#endif
#ifndef OLED_WIRE_PORT
#define OLED_WIRE_PORT Wire
#endif
#ifndef PMU_WIRE_PORT
#define PMU_WIRE_PORT Wire
#endif
#ifndef DISPLAY_ADDR
#define DISPLAY_ADDR 0x3C
#endif
#ifndef LORA_FREQ_CONFIG
#define LORA_FREQ_CONFIG 915.0
#endif
typedef struct {
String chipModel;
float psramSize;
uint8_t chipModelRev;
uint8_t chipFreq;
uint8_t flashSize;
uint8_t flashSpeed;
} DevInfo_t;
void setupBoards(bool disable_u8g2 = false);
bool beginSDCard();
bool beginDisplay();
void disablePeripherals();
bool beginPower();
void printResult(bool radio_online);
void flashLed();
void scanDevices(TwoWire *w);
bool beginGPS();
void loopPMU();
#ifdef HAS_PMU
extern XPowersLibInterface *PMU;
extern bool pmuInterrupt;
#endif
extern DISPLAY_MODEL *u8g2;
#define U8G2_HOR_ALIGN_CENTER(t) ((u8g2->getDisplayWidth() - (u8g2->getUTF8Width(t))) / 2)
#define U8G2_HOR_ALIGN_RIGHT(t) ( u8g2->getDisplayWidth() - u8g2->getUTF8Width(t))
#if defined(ARDUINO_ARCH_ESP32)
#if defined(HAS_SDCARD)
extern SPIClass SDCardSPI;
#endif
#define SerialGPS Serial1
#elif defined(ARDUINO_ARCH_STM32)
extern HardwareSerial SerialGPS;
#endif

View file

@ -0,0 +1,96 @@
/*
RadioLib LoRaWAN ABP Example
ABP = Activation by Personalisation, an alternative
to OTAA (Over the Air Activation). OTAA is preferable.
This example will send uplink packets to a LoRaWAN network.
Before you start, you will have to register your device at
https://www.thethingsnetwork.org/
After your device is registered, you can run this example.
The device will join the network and start uploading data.
LoRaWAN v1.0.4/v1.1 requires the use of persistent storage.
As this example does not use persistent storage, running this
examples REQUIRES you to check "Resets frame counters"
on your LoRaWAN dashboard. Refer to the notes or the
network's documentation on how to do this.
To comply with LoRaWAN's persistent storage, refer to
https://github.com/radiolib-org/radiolib-persistence
For default module settings, see the wiki page
https://github.com/jgromes/RadioLib/wiki/Default-configuration
For full API reference, see the GitHub Pages
https://jgromes.github.io/RadioLib/
For LoRaWAN details, see the wiki page
https://github.com/jgromes/RadioLib/wiki/LoRaWAN
*/
#include "configABP.h"
void setup()
{
Serial.begin(115200);
while (!Serial);
setupBoards();
#ifdef RADIO_TCXO_ENABLE
pinMode(RADIO_TCXO_ENABLE, OUTPUT);
digitalWrite(RADIO_TCXO_ENABLE, HIGH);
#endif
delay(5000); // Give time to switch to the serial monitor
Serial.println(F("\nSetup ... "));
Serial.println(F("Initialise the radio"));
int state = radio.begin();
debug(state != RADIOLIB_ERR_NONE, F("Initialise radio failed"), state, true);
Serial.println(F("Initialise LoRaWAN Network credentials"));
node.beginABP(devAddr, fNwkSIntKey, sNwkSIntKey, nwkSEncKey, appSKey);
node.activateABP();
debug(state != RADIOLIB_ERR_NONE, F("Activate ABP failed"), state, true);
Serial.println(F("Ready!\n"));
}
void loop()
{
Serial.println(F("Sending uplink"));
// This is the place to gather the sensor inputs
// Instead of reading any real sensor, we just generate some random numbers as example
uint8_t value1 = radio.random(100);
uint16_t value2 = radio.random(2000);
// Build payload byte array
uint8_t uplinkPayload[3];
uplinkPayload[0] = value1;
uplinkPayload[1] = highByte(value2); // See notes for high/lowByte functions
uplinkPayload[2] = lowByte(value2);
// Perform an uplink
int state = node.sendReceive(uplinkPayload, sizeof(uplinkPayload));
debug(state < RADIOLIB_ERR_NONE, F("Error in sendReceive"), state, false);
// Check if a downlink was received
// (state 0 = no downlink, state 1/2 = downlink in window Rx1/Rx2)
if (state > 0) {
Serial.println(F("Received a downlink"));
} else {
Serial.println(F("No downlink received"));
}
Serial.print(F("Next uplink in "));
Serial.print(uplinkIntervalSeconds);
Serial.println(F(" seconds\n"));
// Wait until next uplink - observing legal & TTN FUP constraints
delay(uplinkIntervalSeconds * 1000UL); // delay needs milli-seconds
}

View file

@ -0,0 +1,155 @@
#ifndef _RADIOLIB_EX_LORAWAN_CONFIG_H
#define _RADIOLIB_EX_LORAWAN_CONFIG_H
#include <RadioLib.h>
#include "LoRaBoards.h"
#if defined(USING_SX1276)
SX1276 radio = new Module(RADIO_CS_PIN, RADIO_DIO0_PIN, RADIO_RST_PIN, RADIO_DIO1_PIN);
#elif defined(USING_SX1262)
SX1262 radio = new Module(RADIO_CS_PIN, RADIO_DIO1_PIN, RADIO_RST_PIN, RADIO_BUSY_PIN);
#elif defined(USING_SX1278)
SX1278 radio = new Module(RADIO_CS_PIN, RADIO_DIO0_PIN, RADIO_RST_PIN, RADIO_DIO1_PIN);
#elif defined(USING_LR1121)
LR1121 radio = new Module(RADIO_CS_PIN, RADIO_DIO9_PIN, RADIO_RST_PIN, RADIO_BUSY_PIN);
#endif
// how often to send an uplink - consider legal & FUP constraints - see notes
const uint32_t uplinkIntervalSeconds = 1UL * 60UL; // minutes x seconds
// device address - either a development address or one assigned
// to the LoRaWAN Service Provider - TTN will generate one for you
#ifndef RADIOLIB_LORAWAN_DEV_ADDR // Replace with your DevAddr
#define RADIOLIB_LORAWAN_DEV_ADDR 0x260DA9E1
#endif
#ifndef RADIOLIB_LORAWAN_FNWKSINT_KEY // Replace with your FNwkSInt Key
#define RADIOLIB_LORAWAN_FNWKSINT_KEY 0xD2, 0xB1, 0x21, 0xCC, 0xDE, 0xBE, 0xE5, 0x29, 0xEC, 0x00, 0xD2, 0xE4, 0xBB, 0x25, 0x9D, 0xFF
#endif
#ifndef RADIOLIB_LORAWAN_SNWKSINT_KEY // Replace with your SNwkSInt Key
#define RADIOLIB_LORAWAN_SNWKSINT_KEY 0x17, 0x4A, 0xAD, 0x42, 0x32, 0x5B, 0x54, 0xAC, 0xA5, 0xB9, 0xE6, 0x45, 0x60, 0x3E, 0x6E, 0x64
#endif
#ifndef RADIOLIB_LORAWAN_NWKSENC_KEY // Replace with your NwkSEnc Key
#define RADIOLIB_LORAWAN_NWKSENC_KEY 0xA6, 0xFB, 0xE9, 0xDC, 0xB7, 0x16, 0x34, 0x6C, 0xC1, 0x6F, 0xB8, 0x3C, 0x94, 0x0C, 0xA1, 0x63
#endif
#ifndef RADIOLIB_LORAWAN_APPS_KEY // Replace with your AppS Key
#define RADIOLIB_LORAWAN_APPS_KEY 0xCB, 0xE2, 0x15, 0x39, 0xFB, 0xD4, 0x9A, 0x6E, 0xF5, 0x82, 0xE1, 0x97, 0xEC, 0x2B, 0x0E, 0x3C
#endif
// for the curious, the #ifndef blocks allow for automated testing &/or you can
// put your EUI & keys in to your platformio.ini - see wiki for more tips
// regional choices: EU868, US915, AU915, AS923, AS923_2, AS923_3, AS923_4, IN865, KR920, CN500
const LoRaWANBand_t Region = CN500;
const uint8_t subBand = 0; // For US915, change this to 2, otherwise leave on 0
// ============================================================================
// Below is to support the sketch - only make changes if the notes say so ...
// copy over the keys in to the something that will not compile if incorrectly formatted
uint32_t devAddr = RADIOLIB_LORAWAN_DEV_ADDR;
uint8_t fNwkSIntKey[] = { RADIOLIB_LORAWAN_FNWKSINT_KEY };
uint8_t sNwkSIntKey[] = { RADIOLIB_LORAWAN_SNWKSINT_KEY };
uint8_t nwkSEncKey[] = { RADIOLIB_LORAWAN_NWKSENC_KEY };
uint8_t appSKey[] = { RADIOLIB_LORAWAN_APPS_KEY };
// create the LoRaWAN node
LoRaWANNode node(&radio, &Region, subBand);
// result code to text - these are error codes that can be raised when using LoRaWAN
// however, RadioLib has many more - see https://jgromes.github.io/RadioLib/group__status__codes.html for a complete list
String stateDecode(const int16_t result) {
switch (result) {
case RADIOLIB_ERR_NONE:
return "ERR_NONE";
case RADIOLIB_ERR_CHIP_NOT_FOUND:
return "ERR_CHIP_NOT_FOUND";
case RADIOLIB_ERR_PACKET_TOO_LONG:
return "ERR_PACKET_TOO_LONG";
case RADIOLIB_ERR_RX_TIMEOUT:
return "ERR_RX_TIMEOUT";
case RADIOLIB_ERR_CRC_MISMATCH:
return "ERR_CRC_MISMATCH";
case RADIOLIB_ERR_INVALID_BANDWIDTH:
return "ERR_INVALID_BANDWIDTH";
case RADIOLIB_ERR_INVALID_SPREADING_FACTOR:
return "ERR_INVALID_SPREADING_FACTOR";
case RADIOLIB_ERR_INVALID_CODING_RATE:
return "ERR_INVALID_CODING_RATE";
case RADIOLIB_ERR_INVALID_FREQUENCY:
return "ERR_INVALID_FREQUENCY";
case RADIOLIB_ERR_INVALID_OUTPUT_POWER:
return "ERR_INVALID_OUTPUT_POWER";
case RADIOLIB_ERR_NETWORK_NOT_JOINED:
return "RADIOLIB_ERR_NETWORK_NOT_JOINED";
case RADIOLIB_ERR_DOWNLINK_MALFORMED:
return "RADIOLIB_ERR_DOWNLINK_MALFORMED";
case RADIOLIB_ERR_INVALID_REVISION:
return "RADIOLIB_ERR_INVALID_REVISION";
case RADIOLIB_ERR_INVALID_PORT:
return "RADIOLIB_ERR_INVALID_PORT";
case RADIOLIB_ERR_NO_RX_WINDOW:
return "RADIOLIB_ERR_NO_RX_WINDOW";
case RADIOLIB_ERR_INVALID_CID:
return "RADIOLIB_ERR_INVALID_CID";
case RADIOLIB_ERR_UPLINK_UNAVAILABLE:
return "RADIOLIB_ERR_UPLINK_UNAVAILABLE";
case RADIOLIB_ERR_COMMAND_QUEUE_FULL:
return "RADIOLIB_ERR_COMMAND_QUEUE_FULL";
case RADIOLIB_ERR_COMMAND_QUEUE_ITEM_NOT_FOUND:
return "RADIOLIB_ERR_COMMAND_QUEUE_ITEM_NOT_FOUND";
case RADIOLIB_ERR_JOIN_NONCE_INVALID:
return "RADIOLIB_ERR_JOIN_NONCE_INVALID";
case RADIOLIB_ERR_N_FCNT_DOWN_INVALID:
return "RADIOLIB_ERR_N_FCNT_DOWN_INVALID";
case RADIOLIB_ERR_A_FCNT_DOWN_INVALID:
return "RADIOLIB_ERR_A_FCNT_DOWN_INVALID";
case RADIOLIB_ERR_DWELL_TIME_EXCEEDED:
return "RADIOLIB_ERR_DWELL_TIME_EXCEEDED";
case RADIOLIB_ERR_CHECKSUM_MISMATCH:
return "RADIOLIB_ERR_CHECKSUM_MISMATCH";
case RADIOLIB_ERR_NO_JOIN_ACCEPT:
return "RADIOLIB_ERR_NO_JOIN_ACCEPT";
case RADIOLIB_LORAWAN_SESSION_RESTORED:
return "RADIOLIB_LORAWAN_SESSION_RESTORED";
case RADIOLIB_LORAWAN_NEW_SESSION:
return "RADIOLIB_LORAWAN_NEW_SESSION";
case RADIOLIB_ERR_NONCES_DISCARDED:
return "RADIOLIB_ERR_NONCES_DISCARDED";
case RADIOLIB_ERR_SESSION_DISCARDED:
return "RADIOLIB_ERR_SESSION_DISCARDED";
}
return "See https://jgromes.github.io/RadioLib/group__status__codes.html";
}
// helper function to display any issues
void debug(bool failed, const __FlashStringHelper *message, int state, bool halt)
{
if (failed) {
Serial.print(message);
Serial.print(" - ");
Serial.print(stateDecode(state));
Serial.print(" (");
Serial.print(state);
Serial.println(")");
while (halt) {
delay(1);
}
}
}
// helper function to display a byte array
void arrayDump(uint8_t *buffer, uint16_t len)
{
for (uint16_t c = 0; c < len; c++) {
char b = buffer[c];
if (b < 0x10) {
Serial.print('0');
}
Serial.print(b, HEX);
}
Serial.println();
}
#endif

View file

@ -648,7 +648,7 @@ void setupBoards(bool disable_u8g2 )
beginDisplay();
}
beginWiFi();
// beginWiFi();
#ifdef HAS_GPS
#ifdef T_BEAM_S3_BPF

View file

@ -25,16 +25,6 @@
#include <RadioLib.h>
#include "LoRaBoards.h"
// !!!!! APP EUI
#define RADIOLIB_LORAWAN_JOIN_EUI 0xAABB112233445566
// !!!!! DEV EUI
#define RADIOLIB_LORAWAN_DEV_EUI 0x70B3D57ED0066FDA
// !!!!! APP EUI
#define RADIOLIB_LORAWAN_APP_KEY 0xAA, 0xBB, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66
// !!! APP KEY
#define RADIOLIB_LORAWAN_NWK_KEY 0xF2, 0x84, 0x31, 0x0F, 0x82, 0x65, 0x99, 0x4F, 0x70, 0xCB, 0x88, 0x74, 0xFA, 0xD6, 0x71, 0xA2
#if defined(USING_SX1276)
SX1276 radio = new Module(RADIO_CS_PIN, RADIO_DIO0_PIN, RADIO_RST_PIN, RADIO_DIO1_PIN);
#elif defined(USING_SX1262)
@ -45,6 +35,21 @@ SX1278 radio = new Module(RADIO_CS_PIN, RADIO_DIO0_PIN, RADIO_RST_PIN, RADIO_DIO
LR1121 radio = new Module(RADIO_CS_PIN, RADIO_DIO9_PIN, RADIO_RST_PIN, RADIO_BUSY_PIN);
#endif
// joinEUI - previous versions of LoRaWAN called this AppEUI
// for development purposes you can use all zeros - see wiki for details
#define RADIOLIB_LORAWAN_JOIN_EUI 0x0000000000000000
// the Device EUI & two keys can be generated on the TTN console
#ifndef RADIOLIB_LORAWAN_DEV_EUI // Replace with your Device EUI
#define RADIOLIB_LORAWAN_DEV_EUI 0x---------------
#endif
#ifndef RADIOLIB_LORAWAN_APP_KEY // Replace with your App Key
#define RADIOLIB_LORAWAN_APP_KEY 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--
#endif
#ifndef RADIOLIB_LORAWAN_NWK_KEY // Put your Nwk Key here
#define RADIOLIB_LORAWAN_NWK_KEY 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--
#endif
// how often to send an uplink - consider legal & FUP constraints - see notes
const uint32_t uplinkIntervalSeconds = 5UL * 60UL; // minutes x seconds
@ -69,15 +74,87 @@ uint8_t nwkKey[] = { RADIOLIB_LORAWAN_NWK_KEY };
// create the LoRaWAN node
LoRaWANNode node(&radio, &Region, subBand);
// helper function to display any issues
void debug(bool isFail, const __FlashStringHelper *message, int state, bool Freeze)
// result code to text - these are error codes that can be raised when using LoRaWAN
// however, RadioLib has many more - see https://jgromes.github.io/RadioLib/group__status__codes.html for a complete list
String stateDecode(const int16_t result)
{
if (isFail) {
switch (result) {
case RADIOLIB_ERR_NONE:
return "ERR_NONE";
case RADIOLIB_ERR_CHIP_NOT_FOUND:
return "ERR_CHIP_NOT_FOUND";
case RADIOLIB_ERR_PACKET_TOO_LONG:
return "ERR_PACKET_TOO_LONG";
case RADIOLIB_ERR_RX_TIMEOUT:
return "ERR_RX_TIMEOUT";
case RADIOLIB_ERR_CRC_MISMATCH:
return "ERR_CRC_MISMATCH";
case RADIOLIB_ERR_INVALID_BANDWIDTH:
return "ERR_INVALID_BANDWIDTH";
case RADIOLIB_ERR_INVALID_SPREADING_FACTOR:
return "ERR_INVALID_SPREADING_FACTOR";
case RADIOLIB_ERR_INVALID_CODING_RATE:
return "ERR_INVALID_CODING_RATE";
case RADIOLIB_ERR_INVALID_FREQUENCY:
return "ERR_INVALID_FREQUENCY";
case RADIOLIB_ERR_INVALID_OUTPUT_POWER:
return "ERR_INVALID_OUTPUT_POWER";
case RADIOLIB_ERR_NETWORK_NOT_JOINED:
return "RADIOLIB_ERR_NETWORK_NOT_JOINED";
case RADIOLIB_ERR_DOWNLINK_MALFORMED:
return "RADIOLIB_ERR_DOWNLINK_MALFORMED";
case RADIOLIB_ERR_INVALID_REVISION:
return "RADIOLIB_ERR_INVALID_REVISION";
case RADIOLIB_ERR_INVALID_PORT:
return "RADIOLIB_ERR_INVALID_PORT";
case RADIOLIB_ERR_NO_RX_WINDOW:
return "RADIOLIB_ERR_NO_RX_WINDOW";
case RADIOLIB_ERR_INVALID_CID:
return "RADIOLIB_ERR_INVALID_CID";
case RADIOLIB_ERR_UPLINK_UNAVAILABLE:
return "RADIOLIB_ERR_UPLINK_UNAVAILABLE";
case RADIOLIB_ERR_COMMAND_QUEUE_FULL:
return "RADIOLIB_ERR_COMMAND_QUEUE_FULL";
case RADIOLIB_ERR_COMMAND_QUEUE_ITEM_NOT_FOUND:
return "RADIOLIB_ERR_COMMAND_QUEUE_ITEM_NOT_FOUND";
case RADIOLIB_ERR_JOIN_NONCE_INVALID:
return "RADIOLIB_ERR_JOIN_NONCE_INVALID";
case RADIOLIB_ERR_N_FCNT_DOWN_INVALID:
return "RADIOLIB_ERR_N_FCNT_DOWN_INVALID";
case RADIOLIB_ERR_A_FCNT_DOWN_INVALID:
return "RADIOLIB_ERR_A_FCNT_DOWN_INVALID";
case RADIOLIB_ERR_DWELL_TIME_EXCEEDED:
return "RADIOLIB_ERR_DWELL_TIME_EXCEEDED";
case RADIOLIB_ERR_CHECKSUM_MISMATCH:
return "RADIOLIB_ERR_CHECKSUM_MISMATCH";
case RADIOLIB_ERR_NO_JOIN_ACCEPT:
return "RADIOLIB_ERR_NO_JOIN_ACCEPT";
case RADIOLIB_LORAWAN_SESSION_RESTORED:
return "RADIOLIB_LORAWAN_SESSION_RESTORED";
case RADIOLIB_LORAWAN_NEW_SESSION:
return "RADIOLIB_LORAWAN_NEW_SESSION";
case RADIOLIB_ERR_NONCES_DISCARDED:
return "RADIOLIB_ERR_NONCES_DISCARDED";
case RADIOLIB_ERR_SESSION_DISCARDED:
return "RADIOLIB_ERR_SESSION_DISCARDED";
}
return "See https://jgromes.github.io/RadioLib/group__status__codes.html";
}
// helper function to display any issues
void debug(bool failed, const __FlashStringHelper *message, int state, bool halt)
{
if (failed) {
Serial.print(message);
Serial.print("(");
Serial.print(" - ");
Serial.print(stateDecode(state));
Serial.print(" (");
Serial.print(state);
Serial.println(")");
while (Freeze);
while (halt) {
delay(1);
}
}
}
@ -94,8 +171,6 @@ void arrayDump(uint8_t *buffer, uint16_t len)
Serial.println();
}
static uint32_t txCounter = 0;
void setup()
{
@ -116,10 +191,10 @@ void setup()
Serial.println(F("Initialise the radio"));
int state = radio.begin();
int16_t state = 0; // return value for calls to RadioLib
Serial.println(F("Initialise the radio"));
state = radio.begin();
debug(state != RADIOLIB_ERR_NONE, F("Initialise radio failed"), state, true);
printResult(state == RADIOLIB_ERR_NONE);
delay(2000);
#ifdef USING_DIO2_AS_RF_SWITCH
#ifdef USING_SX1262
@ -174,38 +249,60 @@ void setup()
radio.setTCXO(3.0);
#endif
int retry = 0;
while (1) {
if (u8g2) {
u8g2->clearBuffer();
u8g2->setFont(u8g2_font_NokiaLargeBold_tf );
uint16_t str_w = u8g2->getStrWidth(BOARD_VARIANT_NAME);
u8g2->drawStr((u8g2->getWidth() - str_w) / 2, 16, BOARD_VARIANT_NAME);
u8g2->drawHLine(5, 21, u8g2->getWidth() - 5);
// Override the default join rate
uint8_t joinDR = 4;
u8g2->setCursor(0, 38);
u8g2->print("Join LoRaWAN :");
u8g2->println(String(retry++));
u8g2->sendBuffer();
}
Serial.println(F("Join ('login') to the LoRaWAN Network"));
node.beginOTAA(joinEUI, devEUI, nwkKey, appKey);
state = node.activateOTAA();
debug(state < RADIOLIB_ERR_NONE, F("Join failed"), state, false);
if (state == RADIOLIB_ERR_NONE || state == RADIOLIB_LORAWAN_NEW_SESSION) {
break;
}
delay(10000);
Serial.print("Retry ");
// Setup the OTAA session information
node.beginOTAA(joinEUI, devEUI, nwkKey, appKey);
Serial.println(F("Join ('login') the LoRaWAN Network"));
state = node.activateOTAA(joinDR);
debug(state != RADIOLIB_LORAWAN_NEW_SESSION, F("Join failed"), state, true);
// Print the DevAddr
Serial.print("[LoRaWAN] DevAddr: ");
Serial.println((unsigned long)node.getDevAddr(), HEX);
// Enable the ADR algorithm (on by default which is preferable)
node.setADR(true);
// Set a datarate to start off with
node.setDatarate(5);
// Manages uplink intervals to the TTN Fair Use Policy
node.setDutyCycle(true, 1250);
// Enable the dwell time limits - 400ms is the limit for the US
node.setDwellTime(true, 400);
Serial.println(F("Ready!\n"));
if (u8g2) {
u8g2->clearBuffer();
u8g2->setFont(u8g2_font_NokiaLargeBold_tf );
uint16_t str_w = u8g2->getStrWidth(BOARD_VARIANT_NAME);
u8g2->drawStr((u8g2->getWidth() - str_w) / 2, 16, BOARD_VARIANT_NAME);
u8g2->drawHLine(5, 21, u8g2->getWidth() - 5);
u8g2->setCursor(0, 38);
u8g2->print("Join LoRaWAN Ready!");
u8g2->sendBuffer();
}
Serial.println(F("Joined!\n"));
}
void loop()
{
Serial.println(F("Sending uplink"));
int16_t state = RADIOLIB_ERR_NONE;
// set battery fill level - the LoRaWAN network server
// may periodically request this information
// 0 = external power source
// 1 = lowest (empty battery)
// 254 = highest (full battery)
// 255 = unable to measure
uint8_t battLevel = 146;
node.setDeviceStatus(battLevel);
// This is the place to gather the sensor inputs
// Instead of reading any real sensor, we just generate some random numbers as example
@ -218,37 +315,105 @@ void loop()
uplinkPayload[1] = highByte(value2); // See notes for high/lowByte functions
uplinkPayload[2] = lowByte(value2);
// Perform an uplink
int state = node.sendReceive(uplinkPayload, sizeof(uplinkPayload));
debug((state != RADIOLIB_LORAWAN_NO_DOWNLINK) && (state != RADIOLIB_ERR_NONE), F("Error in sendReceive"), state, false);
uint8_t downlinkPayload[10]; // Make sure this fits your plans!
size_t downlinkSize; // To hold the actual payload size received
if (u8g2) {
u8g2->clearBuffer();
u8g2->setFont(u8g2_font_NokiaLargeBold_tf );
uint16_t str_w = u8g2->getStrWidth(BOARD_VARIANT_NAME);
u8g2->drawStr((u8g2->getWidth() - str_w) / 2, 16, BOARD_VARIANT_NAME);
u8g2->drawHLine(5, 21, u8g2->getWidth() - 5);
u8g2->setCursor(0, 38);
u8g2->print(node.isActivated() ? "Joined." : "NoJoin");
u8g2->print("\tTx:"); u8g2->println(++txCounter);
#ifdef ARDUINO_ARCH_ESP32
u8g2->setCursor(0, 54);
u8g2->println("MAC:"); u8g2->println(ESP.getEfuseMac(), HEX);
#endif
u8g2->sendBuffer();
// you can also retrieve additional information about an uplink or
// downlink by passing a reference to LoRaWANEvent_t structure
LoRaWANEvent_t uplinkDetails;
LoRaWANEvent_t downlinkDetails;
uint8_t fPort = 10;
// Retrieve the last uplink frame counter
uint32_t fCntUp = node.getFCntUp();
// Send a confirmed uplink on the second uplink
// and also request the LinkCheck and DeviceTime MAC commands
Serial.println(F("Sending uplink"));
if (fCntUp == 1) {
Serial.println(F("and requesting LinkCheck and DeviceTime"));
node.sendMacCommandReq(RADIOLIB_LORAWAN_MAC_LINK_CHECK);
node.sendMacCommandReq(RADIOLIB_LORAWAN_MAC_DEVICE_TIME);
state = node.sendReceive(uplinkPayload, sizeof(uplinkPayload), fPort, downlinkPayload, &downlinkSize, true, &uplinkDetails, &downlinkDetails);
} else {
state = node.sendReceive(uplinkPayload, sizeof(uplinkPayload), fPort, downlinkPayload, &downlinkSize, false, &uplinkDetails, &downlinkDetails);
}
debug(state < RADIOLIB_ERR_NONE, F("Error in sendReceive"), state, false);
// Check if a downlink was received
// (state 0 = no downlink, state 1/2 = downlink in window Rx1/Rx2)
if (state > 0) {
Serial.println(F("Received a downlink"));
// Did we get a downlink with data for us
if (downlinkSize > 0) {
Serial.println(F("Downlink data: "));
arrayDump(downlinkPayload, downlinkSize);
} else {
Serial.println(F("<MAC commands only>"));
}
// print RSSI (Received Signal Strength Indicator)
Serial.print(F("[LoRaWAN] RSSI:\t\t"));
Serial.print(radio.getRSSI());
Serial.println(F(" dBm"));
// print SNR (Signal-to-Noise Ratio)
Serial.print(F("[LoRaWAN] SNR:\t\t"));
Serial.print(radio.getSNR());
Serial.println(F(" dB"));
// print extra information about the event
Serial.println(F("[LoRaWAN] Event information:"));
Serial.print(F("[LoRaWAN] Confirmed:\t"));
Serial.println(downlinkDetails.confirmed);
Serial.print(F("[LoRaWAN] Confirming:\t"));
Serial.println(downlinkDetails.confirming);
Serial.print(F("[LoRaWAN] Datarate:\t"));
Serial.println(downlinkDetails.datarate);
Serial.print(F("[LoRaWAN] Frequency:\t"));
Serial.print(downlinkDetails.freq, 3);
Serial.println(F(" MHz"));
Serial.print(F("[LoRaWAN] Frame count:\t"));
Serial.println(downlinkDetails.fCnt);
Serial.print(F("[LoRaWAN] Port:\t\t"));
Serial.println(downlinkDetails.fPort);
Serial.print(F("[LoRaWAN] Time-on-air: \t"));
Serial.print(node.getLastToA());
Serial.println(F(" ms"));
Serial.print(F("[LoRaWAN] Rx window: \t"));
Serial.println(state);
uint8_t margin = 0;
uint8_t gwCnt = 0;
if (node.getMacLinkCheckAns(&margin, &gwCnt) == RADIOLIB_ERR_NONE) {
Serial.print(F("[LoRaWAN] LinkCheck margin:\t"));
Serial.println(margin);
Serial.print(F("[LoRaWAN] LinkCheck count:\t"));
Serial.println(gwCnt);
}
uint32_t networkTime = 0;
uint8_t fracSecond = 0;
if (node.getMacDeviceTimeAns(&networkTime, &fracSecond, true) == RADIOLIB_ERR_NONE) {
Serial.print(F("[LoRaWAN] DeviceTime Unix:\t"));
Serial.println(networkTime);
Serial.print(F("[LoRaWAN] DeviceTime second:\t1/"));
Serial.println(fracSecond);
}
} else {
Serial.println(F("[LoRaWAN] No downlink received"));
}
// wait before sending another packet
uint32_t minimumDelay = uplinkIntervalSeconds * 1000UL;
uint32_t interval = node.timeUntilUplink(); // calculate minimum duty cycle delay (per FUP & law!)
uint32_t delayMs = max(interval, minimumDelay); // cannot send faster than duty cycle allows
Serial.print(F("Uplink complete, next in "));
Serial.print(uplinkIntervalSeconds);
Serial.println(F(" seconds"));
Serial.print(F("[LoRaWAN] Next uplink in "));
Serial.print(delayMs / 1000);
Serial.println(F(" seconds\n"));
#ifdef BOARD_LED
digitalWrite(BOARD_LED, LED_ON);
delay(200);
digitalWrite(BOARD_LED, !LED_ON);
#endif
// Wait until next uplink - observing legal & TTN FUP constraints
delay(uplinkIntervalSeconds * 1000UL); // delay needs milli-seconds
delay(delayMs);
}