From 91483e809609258bb92224a3d194fb9a1ab2833e Mon Sep 17 00:00:00 2001 From: lewisxhe Date: Wed, 18 Dec 2024 16:03:27 +0800 Subject: [PATCH] Added T-Beam factory example --- examples/Factory/Factory.ino | 1276 ++++++++++++++++++++++ examples/Factory/LoRaBoards.cpp | 1165 ++++++++++++++++++++ examples/Factory/LoRaBoards.h | 127 +++ examples/Factory/Roboto_Mono_Medium_12.h | 427 ++++++++ examples/Factory/utilities.h | 683 ++++++++++++ 5 files changed, 3678 insertions(+) create mode 100644 examples/Factory/Factory.ino create mode 100644 examples/Factory/LoRaBoards.cpp create mode 100644 examples/Factory/LoRaBoards.h create mode 100644 examples/Factory/Roboto_Mono_Medium_12.h create mode 100644 examples/Factory/utilities.h diff --git a/examples/Factory/Factory.ino b/examples/Factory/Factory.ino new file mode 100644 index 0000000..63981c2 --- /dev/null +++ b/examples/Factory/Factory.ino @@ -0,0 +1,1276 @@ +/** + * @file Factory.ino + * @author Lewis He (lewishe@outlook.com) + * @license MIT + * @copyright Copyright (c) 2024 Shenzhen Xin Yuan Electronic Technology Co., Ltd + * @date 2024-12-18 + * @note This example is for T-beam V1.2 and T-Beam SUPREME factory examples + * @note This example is for T-beam V1.2 and T-Beam SUPREME factory examples + * @note This example is for T-beam V1.2 and T-Beam SUPREME factory examples + * @note This example is for T-beam V1.2 and T-Beam SUPREME factory examples + */ + +#include +#include +#include +#include +#include +#include +#include +#include "OLEDDisplayUi.h" +#include +#include "utilities.h" +#include +#include +#include +#include +#include //MadgwickAHRS from https://github.com/arduino-libraries/MadgwickAHRS +#include "Roboto_Mono_Medium_12.h" +#include "LoRaBoards.h" + +#ifndef WIFI_SSID +#define WIFI_SSID "Your WiFi SSID" +#endif +#ifndef WIFI_PASSWORD +#define WIFI_PASSWORD "Your WiFi PASSWORD" +#endif + +#ifdef T_BEAM_S3_SUPREME +#include +#include +#include +#include +#include + +SensorQMC6310 qmc; +SensorQMI8658 qmi; +SensorPCF8563 rtc; +Adafruit_BME280 bme; +#endif + +using namespace ace_button; + +void radioTx(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y); +void radioRx(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y); +void wirelessInfo(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y); +void wifiTask(void *task); +void hwProbe(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y); + +#ifdef HAS_GPS +void gpsInfo(OLEDDisplay *display, OLEDDisplayUiState *disp_state, int16_t x, int16_t y); +#endif +#ifdef HAS_PMU +void pmuInfo(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y); +#endif + +#ifdef T_BEAM_S3_SUPREME +void dateTimeInfo(OLEDDisplay *display, OLEDDisplayUiState *disp_state, int16_t x, int16_t y); +void sensorInfo(OLEDDisplay *display, OLEDDisplayUiState *disp_state, int16_t x, int16_t y); +void imuInfo(OLEDDisplay *display, OLEDDisplayUiState *disp_state, int16_t x, int16_t y); +static void beginSensor(); +#else +#define beginSensor() +#endif + + +#if defined(USING_SX1276) +#define CONFIG_RADIO_FREQ 868.0 +#define CONFIG_RADIO_OUTPUT_POWER 17 +#define CONFIG_RADIO_BW 125.0 +#define CONFIG_RADIO_TYPE "SX1276" +SX1276 radio = new Module(RADIO_CS_PIN, RADIO_DIO0_PIN, RADIO_RST_PIN, RADIO_DIO1_PIN); + +#elif defined(USING_SX1278) +#define CONFIG_RADIO_FREQ 433.0 +#define CONFIG_RADIO_OUTPUT_POWER 17 +#define CONFIG_RADIO_BW 125.0 +SX1278 radio = new Module(RADIO_CS_PIN, RADIO_DIO0_PIN, RADIO_RST_PIN, RADIO_DIO1_PIN); + +#elif defined(USING_SX1262) +#define CONFIG_RADIO_FREQ 868.0 +#ifndef RADIO_MAX_OUTPUT_POWER +#define CONFIG_RADIO_OUTPUT_POWER 22 +#else +/* +* 2w LoRa max set power is +3 dBm ,After passing through PA, the power can reach 33dBm +* */ +#define CONFIG_RADIO_OUTPUT_POWER RADIO_MAX_OUTPUT_POWER +#endif +#define CONFIG_RADIO_BW 125.0 +#define CONFIG_RADIO_TYPE "SX1262" + +SX1262 radio = new Module(RADIO_CS_PIN, RADIO_DIO1_PIN, RADIO_RST_PIN, RADIO_BUSY_PIN); + +#elif defined(USING_SX1280) +#define CONFIG_RADIO_FREQ 2400.0 +#define CONFIG_RADIO_OUTPUT_POWER 13 +#define CONFIG_RADIO_BW 203.125 +#define CONFIG_RADIO_TYPE "SX1280" +SX1280 radio = new Module(RADIO_CS_PIN, RADIO_DIO1_PIN, RADIO_RST_PIN, RADIO_BUSY_PIN); + +#elif defined(USING_SX1280PA) +#define CONFIG_RADIO_FREQ 2400.0 +#define CONFIG_RADIO_OUTPUT_POWER 3 // PA Version power range : -18 ~ 3dBm +#define CONFIG_RADIO_BW 203.125 +#define CONFIG_RADIO_TYPE "SX1280PA" +SX1280 radio = new Module(RADIO_CS_PIN, RADIO_DIO1_PIN, RADIO_RST_PIN, RADIO_BUSY_PIN); + +#elif defined(USING_LR1121) + +// The maximum power of LR1121 2.4G band can only be set to 13 dBm +#define CONFIG_RADIO_FREQ 2450.0 +#define CONFIG_RADIO_OUTPUT_POWER 13 +#define CONFIG_RADIO_BW 125.0 + +// The maximum power of LR1121 Sub 1G band can only be set to 22 dBm +// #define CONFIG_RADIO_FREQ 868.0 +// #define CONFIG_RADIO_OUTPUT_POWER 22 +// #define CONFIG_RADIO_BW 125.0 +#define CONFIG_RADIO_TYPE "LR1121" + +LR1121 radio = new Module(RADIO_CS_PIN, RADIO_DIO9_PIN, RADIO_RST_PIN, RADIO_BUSY_PIN); +#endif + +enum TransmissionDirection { + TRANSMISSION, + RECEIVE, +}; + +// save transmission state between loops +int transmissionState = RADIOLIB_ERR_NONE; +bool transmittedFlag = false; +uint32_t transmissionCounter = 0; +TransmissionDirection transmissionDirection = TRANSMISSION; +bool wifi_is_config = false; +bool is_time_available = false; +DISPLAY_MODEL_SSD_LIB display(0x3c, I2C_SDA, I2C_SCL); +OLEDDisplayUi ui( &display ); + +FrameCallback frames[] = { + hwProbe, + radioTx, + radioRx, +#ifdef HAS_GPS + gpsInfo, +#endif +#ifdef HAS_PMU + pmuInfo, +#endif +#ifdef T_BEAM_S3_SUPREME + dateTimeInfo, + sensorInfo, + imuInfo, +#endif + wirelessInfo +}; + +const uint8_t max_frames = sizeof(frames) / sizeof(frames[0]); +int currentFrames = 0; +AceButton button; +WiFiMulti wifiMulti; + +#ifdef HAS_GPS +TinyGPSPlus gps; +#endif + +#ifdef BUTTON2_PIN +AceButton button2; +#endif + +String macStr; + +void setFlag(void) +{ + // we got a packet, set the flag + transmittedFlag = true; +} + +void sleepDevice() +{ + + Serial.println("Enter sleep..."); + +#ifndef HAS_PMU + digitalWrite(RADIO_RST_PIN, HIGH); + gpio_hold_en((gpio_num_t) RADIO_RST_PIN); + gpio_deep_sleep_hold_en(); +#endif + radio.sleep(); + + display.clear(); + display.drawString(60, 28, "Sleep"); + display.display(); + delay(2000); + display.displayOff(); + + +#ifdef RADIO_TCXO_ENABLE + digitalWrite(RADIO_TCXO_ENABLE, LOW); +#endif + +#ifdef BUTTON_PIN + while (digitalRead(BUTTON_PIN) == LOW) + delay(1); +#endif + + // PMU pre-sleep operation + disablePeripherals(); + + delay(200); + + SPI.end(); + + Wire.end(); + + // GPS pins +#ifdef HAS_GPS + SerialGPS.end(); + pinMode(GPS_RX_PIN, INPUT); + pinMode(GPS_TX_PIN, INPUT); +#endif + +#ifdef OLED_RST + pinMode(OLED_RST, INPUT); +#endif + // Wire pins + pinMode(I2C_SDA, INPUT); + pinMode(I2C_SCL, INPUT); + + + // Radio pins +#ifdef RADIO_DIO0_PIN + pinMode(RADIO_DIO0_PIN, INPUT); +#endif +#ifdef RADIO_DIO1_PIN + pinMode(RADIO_DIO1_PIN, INPUT); +#endif +#ifdef RADIO_DIO9_PIN + pinMode(RADIO_DIO9_PIN, INPUT); +#endif +#ifdef RADIO_BUSY_PIN + pinMode(RADIO_BUSY_PIN, INPUT); +#endif + pinMode(RADIO_CS_PIN, INPUT); + pinMode(RADIO_RST_PIN, INPUT); + pinMode(RADIO_SCLK_PIN, INPUT); + pinMode(RADIO_MISO_PIN, INPUT); + pinMode(RADIO_MOSI_PIN, INPUT); + + // SD Card pins +#ifdef SDCARD_MOSI + pinMode(SDCARD_MOSI, INPUT); + pinMode(SDCARD_MISO, INPUT); + pinMode(SDCARD_SCLK, INPUT); + pinMode(SDCARD_CS, INPUT); +#endif + +#ifdef HAS_PMU + pinMode(PMU_IRQ, INPUT); +#endif + +#ifdef BOARD_LED + pinMode(BOARD_LED, INPUT); +#endif + +#ifdef ADC_PIN + pinMode(ADC_PIN, INPUT); +#endif + + pinMode(BUTTON_PIN, INPUT); + +#ifdef IMU_INT + pinMode(IMU_INT, INPUT); +#endif + +#ifdef BUTTON2_PIN + pinMode(BUTTON2_PIN, INPUT); +#endif + +#if CONFIG_IDF_TARGET_ESP32 + esp_sleep_ext1_wakeup_mode_t wakeup_mode = ESP_EXT1_WAKEUP_ALL_LOW; +#else +#if ESP_ARDUINO_VERSION_VAL(2,0,17) >= ESP_ARDUINO_VERSION + esp_sleep_ext1_wakeup_mode_t wakeup_mode = ESP_EXT1_WAKEUP_ANY_LOW; +#else + esp_sleep_ext1_wakeup_mode_t wakeup_mode = ESP_EXT1_WAKEUP_ALL_LOW; +#endif +#endif + + /* + * + * The following power consumption test is only for T-Beam V1.2, not S3 and other models + * The following power consumption test is only for T-Beam V1.2, not S3 and other models + * The following power consumption test is only for T-Beam V1.2, not S3 and other models + * The following power consumption test is only for T-Beam V1.2, not S3 and other models + * The following power consumption test is only for T-Beam V1.2, not S3 and other models + * The following power consumption test is only for T-Beam V1.2, not S3 and other models + * The following power consumption test is only for T-Beam V1.2, not S3 and other models + * The following power consumption test is only for T-Beam V1.2, not S3 and other models + * + * * * */ + // GPIO WAKE UP EXT 1 NO OLED Display ~ 440 uA , + // GPIO WAKE UP EXT 1 + OLED Display ~ 450 uA , + // See sleep_current.jpg + // Serial.println("GPIO WAKE UP EXT 1"); + // esp_sleep_enable_ext1_wakeup(_BV(BUTTON_PIN), wakeup_mode); + + + // GPIO WAKE UP EXT 1 + TIMER WAKE UP NO OLED Display ~ 440 uA + // GPIO WAKE UP EXT 1 + TIMER WAKE UP + OLED Display ~ 450uA + // Serial.println("GPIO WAKE UP EXT 1 + TIMER WAKE UP"); + // esp_sleep_enable_ext1_wakeup(_BV(BUTTON_PIN), wakeup_mode); + // esp_sleep_enable_timer_wakeup(30 * 1000 * 1000); + + + // GPIO WAKE UP EXT0 + EXT 1 + TIMER WAKE UP NO OLED Display + Disable gnss power backup power ~ 420 uA + // GPIO WAKE UP EXT0 + EXT 1 + TIMER WAKE UP NO OLED Display ~ 540 uA + // GPIO WAKE UP EXT0 + EXT 1 + TIMER WAKE UP + OLED Display ~ 580 uA + // Serial.println("GPIO WAKE UP EXT0 + EXT 1 + TIMER WAKE UP"); + esp_sleep_enable_ext0_wakeup(GPIO_NUM_4, 0); + esp_sleep_enable_ext1_wakeup(_BV(BUTTON_PIN), wakeup_mode); + esp_sleep_enable_timer_wakeup(30 * 1000 * 1000); + + + Serial.flush(); + + Serial.end(); + + delay(1000); + + esp_deep_sleep_start(); + + Serial.println("Never print()"); +} + +void handleMenu() +{ + Serial.printf("currentFrames : %d\n", currentFrames); + switch (currentFrames) { + case 0: + break; + case 1: +#ifdef RADIO_LDO_EN + /* + * 2W LoRa LAN and PA Control ,Set high start power supply + * */ + digitalWrite(RADIO_LDO_EN, HIGH); +#endif +#ifdef RADIO_CTRL + /* + * 2W LoRa LAN Control ,set Low turn off LAN , TX Mode + * */ + digitalWrite(RADIO_CTRL, LOW); +#endif + + Serial.println("Start transmit"); + transmissionDirection = TRANSMISSION; + transmissionState = radio.transmit((uint8_t *)&transmissionCounter, 4); + if (transmissionState != RADIOLIB_ERR_NONE) { + Serial.println(F("[Radio] transmit packet failed!")); + } + break; + + case 2: +#ifdef RADIO_LDO_EN + /* + * 2W LoRa LAN and PA Control ,Set high start power supply + * */ + digitalWrite(RADIO_LDO_EN, HIGH); +#endif + + Serial.println("Start receive"); + transmissionDirection = RECEIVE; + transmissionState = radio.startReceive(); + if (transmissionState != RADIOLIB_ERR_NONE) { + Serial.println(F("[Radio] Received packet failed!")); + } + break; + default: + +#ifdef RADIO_LDO_EN + /* + * 2W LoRa LAN and PA Control ,Set low stop power supply + * */ + digitalWrite(RADIO_LDO_EN, LOW); +#endif + +#ifdef RADIO_CTRL + /* + * 2W LoRa LAN Control ,set HIGH turn on LAN ,RX Mode + * */ + digitalWrite(RADIO_CTRL, HIGH); +#endif + transmissionState = radio.startReceive(); + break; + } + ui.transitionToFrame(currentFrames); +} + + +void prevButtonHandleEvent(AceButton *button, uint8_t eventType, uint8_t buttonState) +{ + switch (eventType) { + case AceButton::kEventClicked: + Serial.printf("prevButtonHandleEvent currentFrames:%d frames_count:%d\n", currentFrames, max_frames); +#ifdef BUTTON2_PIN + currentFrames = ((currentFrames + 1) >= max_frames) ? currentFrames : currentFrames + 1; +#else + currentFrames++; + currentFrames %= max_frames; +#endif + handleMenu(); + break; + case AceButton::kEventLongPressed: + sleepDevice(); + break; + default: + break; + } +} + +void nextButtonHandleEvent(AceButton *button, uint8_t eventType, uint8_t buttonState) +{ + switch (eventType) { + case AceButton::kEventClicked: + Serial.printf("nextButtonHandleEvent currentFrames:%d frames_count:%d\n", currentFrames, max_frames); + currentFrames = ((currentFrames - 1) < 0) ? currentFrames : currentFrames - 1; + handleMenu(); + break; + case AceButton::kEventLongPressed: + Serial.println("Long pressed!"); +#ifdef FAN_CTRL + Serial.println("Long pressed! ,on/off FAN"); + digitalWrite(FAN_CTRL, 1 - digitalRead(FAN_CTRL)); +#endif + break; + } +} + +void timeavailable(struct timeval *t) +{ + Serial.println("[WiFi]: Got time adjustment from NTP!"); + is_time_available = true; + +#ifdef T_BEAM_S3_SUPREME + if (deviceOnline & PCF8563_ONLINE) { + rtc.hwClockWrite(); + } +#endif +} + +void setup() +{ + if (esp_sleep_get_wakeup_cause() != ESP_SLEEP_WAKEUP_ALL) { +#ifndef HAS_PMU + gpio_deep_sleep_hold_dis(); + gpio_hold_dis((gpio_num_t) RADIO_RST_PIN); +#endif + } + + setupBoards(true); + + setupBLE(); + + beginSensor(); + + if (String(WIFI_SSID) == "Your WiFi SSID" || String(WIFI_PASSWORD) == "Your WiFi PASSWORD" ) { + Serial.println("[Error] : WiFi ssid and password are not configured correctly"); + Serial.println("[Error] : WiFi ssid and password are not configured correctly"); + Serial.println("[Error] : WiFi ssid and password are not configured correctly"); + } else { + wifiMulti.addAP(WIFI_SSID, WIFI_PASSWORD); + wifi_is_config = true; + } + + // set notification call-back function + sntp_set_time_sync_notification_cb( timeavailable ); + + /** + * This will set configured ntp servers and constant TimeZone/daylightOffset + * should be OK if your time zone does not need to adjust daylightOffset twice a year, + * in such a case time adjustment won't be handled automagically. + */ + // configTime(gmtOffset_sec, daylightOffset_sec, ntpServer1, ntpServer2); + configTzTime("CST-8", "cn.ntp.org.cn", "pool.ntp.org", "time.nist.gov"); + + uint8_t mac[6]; + char buffer[18] = { 0 }; + esp_efuse_mac_get_default(mac); + sprintf(buffer, "%02X:%02X:%02X:%02X:%02X:%02X", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); + macStr = buffer; + delay(1000); + +#ifdef RADIO_TCXO_ENABLE + pinMode(RADIO_TCXO_ENABLE, OUTPUT); + digitalWrite(RADIO_TCXO_ENABLE, HIGH); +#endif + + static ButtonConfig prevButtonConfigure; + prevButtonConfigure.setEventHandler(prevButtonHandleEvent); + prevButtonConfigure.setFeature(ButtonConfig::kFeatureClick); + prevButtonConfigure.setFeature(ButtonConfig::kFeatureLongPress); + pinMode(BUTTON_PIN, INPUT_PULLUP); + button.init(BUTTON_PIN); + button.setButtonConfig(&prevButtonConfigure); + + +#ifdef BUTTON2_PIN + static ButtonConfig nextButtonConfigure; + nextButtonConfigure.setEventHandler(nextButtonHandleEvent); + nextButtonConfigure.setFeature(ButtonConfig::kFeatureClick); + nextButtonConfigure.setFeature(ButtonConfig::kFeatureLongPress); + pinMode(BUTTON2_PIN, INPUT_PULLUP); + button2.init(BUTTON2_PIN); + button2.setButtonConfig(&nextButtonConfigure); +#endif + + + // Initialising the UI will init the display too. + ui.setTargetFPS(60); + + // You can change this to + // TOP, LEFT, BOTTOM, RIGHT + // ui.setIndicatorPosition(BOTTOM); + ui.disableAllIndicators(); + + // Defines where the first frame is located in the bar. + ui.setIndicatorDirection(LEFT_RIGHT); + + // You can change the transition that is used + // SLIDE_LEFT, SLIDE_RIGHT, SLIDE_UP, SLIDE_DOWN + ui.setFrameAnimation(SLIDE_LEFT); + + // Add frames + ui.setFrames(frames, sizeof(frames) / sizeof(frames[0])); + + ui.disableAutoTransition(); + + // Initialising the UI will init the display too. + ui.init(); + + display.flipScreenVertically(); + + Serial.printf("[%s]:", CONFIG_RADIO_TYPE); + Serial.print(F(" Initializing ... ")); + int state = radio.begin(); + if ( state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + deviceOnline |= RADIO_ONLINE; + } else { + Serial.println(F("failed!")); + } + +#if defined(RADIO_RX_PIN) && defined(RADIO_TX_PIN) + //The SX1280 version needs to set RX, TX antenna switching pins + radio.setRfSwitchPins(RADIO_RX_PIN, RADIO_TX_PIN); +#endif + + if (state == RADIOLIB_ERR_NONE) { + /* + * Sets carrier frequency. + * SX1278/SX1276 : Allowed values range from 137.0 MHz to 525.0 MHz. + * SX1268/SX1262 : Allowed values are in range from 150.0 to 960.0 MHz. + * SX1280 : Allowed values are in range from 2400.0 to 2500.0 MHz. + * LR1121 : Allowed values are in range from 150.0 to 960.0 MHz, 1900 - 2200 MHz and 2400 - 2500 MHz. Will also perform calibrations. + * * * */ + + if (radio.setFrequency(CONFIG_RADIO_FREQ) == RADIOLIB_ERR_INVALID_FREQUENCY) { + Serial.println(F("Selected frequency is invalid for this module!")); + while (true); + } + + /* + * Sets LoRa link bandwidth. + * SX1278/SX1276 : Allowed values are 10.4, 15.6, 20.8, 31.25, 41.7, 62.5, 125, 250 and 500 kHz. Only available in %LoRa mode. + * SX1268/SX1262 : Allowed values are 7.8, 10.4, 15.6, 20.8, 31.25, 41.7, 62.5, 125.0, 250.0 and 500.0 kHz. + * SX1280 : Allowed values are 203.125, 406.25, 812.5 and 1625.0 kHz. + * LR1121 : Allowed values are 62.5, 125.0, 250.0 and 500.0 kHz. + * * * */ + if (radio.setBandwidth(CONFIG_RADIO_BW) == RADIOLIB_ERR_INVALID_BANDWIDTH) { + Serial.println(F("Selected bandwidth is invalid for this module!")); + while (true); + } + + + /* + * Sets LoRa link spreading factor. + * SX1278/SX1276 : Allowed values range from 6 to 12. Only available in LoRa mode. + * SX1262 : Allowed values range from 5 to 12. + * SX1280 : Allowed values range from 5 to 12. + * LR1121 : Allowed values range from 5 to 12. + * * * */ + if (radio.setSpreadingFactor(10) == RADIOLIB_ERR_INVALID_SPREADING_FACTOR) { + Serial.println(F("Selected spreading factor is invalid for this module!")); + while (true); + } + + /* + * Sets LoRa coding rate denominator. + * SX1278/SX1276/SX1268/SX1262 : Allowed values range from 5 to 8. Only available in LoRa mode. + * SX1280 : Allowed values range from 5 to 8. + * LR1121 : Allowed values range from 5 to 8. + * * * */ + if (radio.setCodingRate(6) == RADIOLIB_ERR_INVALID_CODING_RATE) { + Serial.println(F("Selected coding rate is invalid for this module!")); + while (true); + } + + /* + * Sets LoRa sync word. + * SX1278/SX1276/SX1268/SX1262/SX1280 : Sets LoRa sync word. Only available in LoRa mode. + * * */ + if (radio.setSyncWord(0xAB) != RADIOLIB_ERR_NONE) { + Serial.println(F("Unable to set sync word!")); + while (true); + } + + /* + * Sets transmission output power. + * SX1278/SX1276 : Allowed values range from -3 to 15 dBm (RFO pin) or +2 to +17 dBm (PA_BOOST pin). High power +20 dBm operation is also supported, on the PA_BOOST pin. Defaults to PA_BOOST. + * SX1262 : Allowed values are in range from -9 to 22 dBm. This method is virtual to allow override from the SX1261 class. + * SX1268 : Allowed values are in range from -9 to 22 dBm. + * SX1280 : Allowed values are in range from -18 to 13 dBm. PA Version range : -18 ~ 3dBm + * LR1121 : Allowed values are in range from -17 to 22 dBm (high-power PA) or -18 to 13 dBm (High-frequency PA) + * * * */ + if (radio.setOutputPower(CONFIG_RADIO_OUTPUT_POWER) == RADIOLIB_ERR_INVALID_OUTPUT_POWER) { + Serial.println(F("Selected output power is invalid for this module!")); + while (true); + } + +#if !defined(USING_SX1280) && !defined(USING_LR1121) && !defined(USING_SX1280PA) + /* + * Sets current limit for over current protection at transmitter amplifier. + * SX1278/SX1276 : Allowed values range from 45 to 120 mA in 5 mA steps and 120 to 240 mA in 10 mA steps. + * SX1262/SX1268 : Allowed values range from 45 to 120 mA in 2.5 mA steps and 120 to 240 mA in 10 mA steps. + * NOTE: set value to 0 to disable overcurrent protection + * * * */ + if (radio.setCurrentLimit(140) == RADIOLIB_ERR_INVALID_CURRENT_LIMIT) { + Serial.println(F("Selected current limit is invalid for this module!")); + while (true); + } +#endif + + /* + * Sets preamble length for LoRa or FSK modem. + * SX1278/SX1276 : Allowed values range from 6 to 65535 in %LoRa mode or 0 to 65535 in FSK mode. + * SX1262/SX1268 : Allowed values range from 1 to 65535. + * SX1280 : Allowed values range from 1 to 65535. + * LR1121 : Allowed values range from 1 to 65535. + * * */ + if (radio.setPreambleLength(15) == RADIOLIB_ERR_INVALID_PREAMBLE_LENGTH) { + Serial.println(F("Selected preamble length is invalid for this module!")); + while (true); + } + + // Enables or disables CRC check of received packets. + if (radio.setCRC(false) == RADIOLIB_ERR_INVALID_CRC_CONFIGURATION) { + Serial.println(F("Selected CRC is invalid for this module!")); + while (true); + } + + +#if defined(USING_LR1121) + // LR1121 + // set RF switch configuration for Wio WM1110 + // Wio WM1110 uses DIO5 and DIO6 for RF switching + static const uint32_t rfswitch_dio_pins[] = { + RADIOLIB_LR11X0_DIO5, RADIOLIB_LR11X0_DIO6, + RADIOLIB_NC, RADIOLIB_NC, RADIOLIB_NC + }; + + static const Module::RfSwitchMode_t rfswitch_table[] = { + // mode DIO5 DIO6 + { LR11x0::MODE_STBY, { LOW, LOW } }, + { LR11x0::MODE_RX, { HIGH, LOW } }, + { LR11x0::MODE_TX, { LOW, HIGH } }, + { LR11x0::MODE_TX_HP, { LOW, HIGH } }, + { LR11x0::MODE_TX_HF, { LOW, LOW } }, + { LR11x0::MODE_GNSS, { LOW, LOW } }, + { LR11x0::MODE_WIFI, { LOW, LOW } }, + END_OF_MODE_TABLE, + }; + radio.setRfSwitchTable(rfswitch_dio_pins, rfswitch_table); + + // LR1121 TCXO Voltage 2.85~3.15V + radio.setTCXO(3.0); + +#endif + +#if defined(USING_SX1262) + radio.setDio2AsRfSwitch(true); +#endif + + // set the function that will be called + // when new packet is received + radio.setPacketReceivedAction(setFlag); + + // start listening for LoRa packets + Serial.print(F("[Radio] Starting to listen ... ")); + state = radio.startReceive(); + if (state != RADIOLIB_ERR_NONE) { + Serial.println(F("[Radio] Received packet failed!")); + } + } + + + if (wifi_is_config) { + xTaskCreate(wifiTask, "wifi", 4 * 2048, NULL, 10, NULL); + } +} + +// PMU Power key callback +static uint8_t freq_index = 0; +const float factory_freq[] = {433.0, 470.0, 850.0, 868.0, 915.0, 923.0}; +float current_freq = CONFIG_RADIO_FREQ; + +void power_key_pressed() +{ + // Turn on/off display + // static bool isOn = true; + // isOn ? display.displayOff() : display.displayOn(); + // isOn ^= 1; + + // Set freq function + radio.standby(); + radio.setFrequency(factory_freq[freq_index]); + current_freq = factory_freq[freq_index]; + Serial.printf("setFrequency:%.2f\n", current_freq); + freq_index++; + freq_index %= sizeof(factory_freq) / sizeof(factory_freq[0]); + + switch (transmissionDirection) { + case TRANSMISSION: + transmissionState = radio.transmit((uint8_t *)&transmissionCounter, 4); + if (transmissionState != RADIOLIB_ERR_NONE) { + Serial.println(F("[Radio] transmit packet failed!")); + } + break; + default: + transmissionState = radio.startReceive(); + if (transmissionState != RADIOLIB_ERR_NONE) { + Serial.println(F("[Radio] Received packet failed!")); + } + break; + } +} + +void loop() +{ +#ifdef HAS_GPS + while (SerialGPS.available()) { + int r = SerialGPS.read(); + // Serial.write(r); + gps.encode(r); + } +#endif + +#ifdef HAS_PMU + loopPMU(power_key_pressed); +#endif + + button.check(); + +#ifdef BUTTON2_PIN + button2.check(); +#endif + + ui.update(); + delay(2); +} + +void radioTx(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y) +{ + static uint32_t interval = 0; + display->setTextAlignment(TEXT_ALIGN_LEFT); + + if (millis() > interval) { + if (transmittedFlag) { + // reset flag + transmittedFlag = false; + if (transmissionState == RADIOLIB_ERR_NONE) { + // packet was successfully sent + Serial.println(F("transmission finished!")); + + // NOTE: when using interrupt-driven transmit method, + // it is not possible to automatically measure + // transmission data rate using getDataRate() + + } else { + Serial.print(F("failed, code ")); + Serial.println(transmissionState); + + } + + // clean up after transmission is finished + // this will ensure transmitter is disabled, + // RF switch is powered down etc. + radio.finishTransmit(); + + // send another one + Serial.print(F("[Radio] Sending another packet ... ")); + + // you can transmit C-string or Arduino string up to + // 256 characters long + // transmissionState = radio.startTransmit("Hello World!"); + radio.transmit((uint8_t *)&transmissionCounter, 4); + transmissionCounter++; + + // you can also transmit byte array up to 256 bytes long + /* + byte byteArr[] = {0x01, 0x23, 0x45, 0x67, + 0x89, 0xAB, 0xCD, 0xEF}; + int state = radio.startTransmit(byteArr, 8); + */ +#ifdef BOARD_LED + digitalWrite(BOARD_LED, 1 - digitalRead(BOARD_LED)); +#endif + } + + Serial.println("Radio TX done !"); + interval = millis() + 1000; + + } + display->setFont(Roboto_Mono_Medium_12); + display->setTextAlignment(TEXT_ALIGN_CENTER); + display->drawString(64 + x, 0 + y, "RADIO TX"); + + if (transmissionState != RADIOLIB_ERR_NONE) { + display->setTextAlignment(TEXT_ALIGN_CENTER); + display->drawString(64 + x, 32 + y, "Radio Tx Failed!"); + } else { + display->setTextAlignment(TEXT_ALIGN_LEFT); + display->drawString(0 + x, 16 + y, "Freq:" + String(current_freq) + "MHz"); + display->drawString(0 + x, 32 + y, "TX :" + String(transmissionCounter)); + } + + static char buffer[2][32] = {0}; + +#ifdef NTC_PIN + sprintf(buffer[0], "%.2f*C", getTempForNTC()); + display->drawString(0 + x, 48 + y, "Temp "); + display->drawString(50 + x, 48 + y, buffer[0]); +#endif + +#ifdef ADC_PIN + static uint32_t batteryRunInterval = 0; + if (millis() > batteryRunInterval) { + analogReadResolution(12); + float voltage = (analogReadMilliVolts(ADC_PIN) * 2) / 1000.0; + sprintf(buffer[1], "%.2fV", voltage > 4.2 ? 4.2 : voltage); + display->drawString(50 + x, 48 + y, buffer[0]); + batteryRunInterval = millis() + 1000; + } +#endif +} + + +void radioRx(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y) +{ + static uint32_t recvCounter = 0; + static float radioRSSI = 0; + + display->setFont(ArialMT_Plain_10); + // The coordinates define the left starting point of the text + display->setTextAlignment(TEXT_ALIGN_LEFT); + + // check if the flag is set + if (transmittedFlag) { + Serial.println("Radio RX done !"); + +#ifdef BOARD_LED + digitalWrite(BOARD_LED, 1 - digitalRead(BOARD_LED)); +#endif + // reset flag + transmittedFlag = false; + // you can read received data as an Arduino String + transmissionState = radio.readData((uint8_t *)&recvCounter, 4); + // you can also read received data as byte array + /* + byte byteArr[8]; + int state = radio.readData(byteArr, 8); + */ + if (transmissionState == RADIOLIB_ERR_NONE) { + // packet was successfully received + Serial.println(F("[Radio] Received packet!")); + radioRSSI = radio.getRSSI(); + + } else if (transmissionState == RADIOLIB_ERR_CRC_MISMATCH) { + // packet was received, but is malformed + Serial.println(F("[Radio] CRC error!")); + + } else { + // some other error occurred + Serial.print(F("[Radio] Failed, code ")); + Serial.println(transmissionState); + } + // put module back to listen mode + radio.startReceive(); + } + display->setFont(Roboto_Mono_Medium_12); + display->setTextAlignment(TEXT_ALIGN_CENTER); + display->drawString(64 + x, 0 + y, "RADIO RX"); + + if (transmissionState != RADIOLIB_ERR_NONE) { + display->setTextAlignment(TEXT_ALIGN_CENTER); + display->drawString(64 + x, 32 + y, "Radio Rx Failed!"); + } else { + // The coordinates define the left starting point of the text + display->setTextAlignment(TEXT_ALIGN_LEFT); + display->drawString(0 + x, 16 + y, "Freq:" + String(current_freq) + "MHz"); + display->drawString(0 + x, 32 + y, "RX :" + String(recvCounter)); + display->drawString(0 + x, 48 + y, "RSSI:" + String(radioRSSI)); + } +} + +void hwProbe(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y) +{ + display->setFont(Roboto_Mono_Medium_12); + display->setTextAlignment(TEXT_ALIGN_LEFT); +#if defined(T_BEAM_S3_SUPREME) + display->drawString(x, 3 + y, "6DOF"); + display->drawString(x, 15 + y, "Power"); + display->drawString(x, 27 + y, "Radio"); + display->drawString(x, 39 + y, "GPS"); + display->drawString(x, 51 + y, "RTC"); + + display->setTextAlignment(TEXT_ALIGN_CENTER); + display->drawString(52 + x, 3 + y, (deviceOnline & QMI8658_ONLINE ) ? "+" : "-"); + display->drawString(52 + x, 15 + y, (deviceOnline & POWERMANAGE_ONLINE ) ? "+" : "-"); + display->drawString(52 + x, 27 + y, (deviceOnline & RADIO_ONLINE ) ? "+" : "-"); + display->drawString(52 + x, 39 + y, (deviceOnline & GPS_ONLINE ) ? "+" : "-"); + display->drawString(52 + x, 51 + y, (deviceOnline & PCF8563_ONLINE ) ? "+" : "-"); + + display->setTextAlignment(TEXT_ALIGN_LEFT); + display->drawString(62 + x, 3 + y, "MAG"); + display->drawString(62 + x, 15 + y, "BME"); + display->drawString(62 + x, 27 + y, "PSRAM"); + display->drawString(62 + x, 39 + y, "SDCARD"); + display->drawString(62 + x, 51 + y, "OSC"); + + display->setTextAlignment(TEXT_ALIGN_RIGHT); + display->drawString(display->width() + x, 3 + y, (deviceOnline & QMC6310_ONLINE ) ? "+" : "-"); + display->drawString(display->width() + x, 15 + y, (deviceOnline & BME280_ONLINE ) || (deviceOnline & BMP280_ONLINE ) ? "+" : "-"); + display->drawString(display->width() + x, 27 + y, (deviceOnline & PSRAM_ONLINE ) ? "+" : "-"); + display->drawString(display->width() + x, 39 + y, (deviceOnline & SDCARD_ONLINE ) ? "+" : "-"); + display->drawString(display->width() + x, 51 + y, (deviceOnline & OSC32768_ONLINE ) ? "+" : "-"); + +#else + display->drawString(x, 16 + y, "Power"); + display->drawString(x, 32 + y, "Radio"); + display->drawString(x, 48 + y, "GPS"); + + display->setTextAlignment(TEXT_ALIGN_CENTER); + display->drawString(52 + x, 16 + y, (deviceOnline & POWERMANAGE_ONLINE ) ? "+" : "-"); + display->drawString(52 + x, 32 + y, (deviceOnline & RADIO_ONLINE ) ? "+" : "-"); + display->drawString(52 + x, 48 + y, (deviceOnline & GPS_ONLINE ) ? "+" : "-"); + + display->setTextAlignment(TEXT_ALIGN_LEFT); + display->drawString(62 + x, 16 + y, "OLED"); + display->drawString(62 + x, 32 + y, "PSRAM"); +#if HAS_SDCARD + display->drawString(62 + x, 48 + y, "SDCARD"); +#endif + display->setTextAlignment(TEXT_ALIGN_RIGHT); + display->drawString(display->width() + x, 16 + y, (deviceOnline & DISPLAY_ONLINE ) ? "+" : "-"); + display->drawString(display->width() + x, 32 + y, (deviceOnline & PSRAM_ONLINE ) ? "+" : "-"); +#if HAS_SDCARD + display->drawString(display->width() + x, 48 + y, (deviceOnline & SDCARD_ONLINE ) ? "+" : "-"); +#endif +#endif +} + +void wirelessInfo(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y) +{ + display->setFont(Roboto_Mono_Medium_12); + display->setTextAlignment(TEXT_ALIGN_CENTER); + display->drawString(64 + x, 0 + y, "WIFI"); + + display->setTextAlignment(TEXT_ALIGN_LEFT); + display->drawString(0 + x, 16 + y, "SSID:"); + if (String(WIFI_SSID) == "Your WiFi SSID" ) { + display->drawString(38 + x, 16 + y, "NO SET"); + } else { + display->drawString(38 + x, 16 + y, WIFI_SSID); + } + + display->drawString(0 + x, 32 + y, "RSSI:"); + if (WiFi.isConnected()) { + display->drawString(38 + x, 32 + y, String(WiFi.RSSI())); + } else { + display->drawString(38 + x, 32 + y, "N.A"); + } + display->drawString(0 + x, 48 + y, "MAC:"); + display->drawString(30 + x, 48 + y, macStr); +} + +#ifdef HAS_GPS +void gpsInfo(OLEDDisplay *display, OLEDDisplayUiState *disp_state, int16_t x, int16_t y) +{ + const uint8_t buffer_size = 128; + static char buffer[buffer_size]; + display->setFont(Roboto_Mono_Medium_12); + display->setTextAlignment(TEXT_ALIGN_CENTER); + display->drawString(64 + x, 0 + y, "GPS"); + if (gps.location.isValid() && gps.date.isValid() && gps.time.isValid()) { + display->setTextAlignment(TEXT_ALIGN_LEFT); + snprintf(buffer, buffer_size, "lat:%.6f", gps.location.lat()); + display->drawString(0 + x, 16 + y, buffer); + snprintf(buffer, buffer_size, "lng:%.6f", gps.location.lng()); + display->drawString(0 + x, 32 + y, buffer); + snprintf(buffer, buffer_size, "%02d/%02d/%02d %02d:%02d:%02d", gps.date.year() - 2000, gps.date.month(), gps.date.day(), gps.time.hour(), gps.time.minute(), gps.time.second()); + display->drawString(0 + x, 48 + y, buffer); + } else { + display->drawString(64 + x, 16 + y, "RX:" + String(gps.charsProcessed())); + display->drawString(64 + x, 32 + y, "GPS No Lock"); + } +} +#endif + +#ifdef HAS_PMU +void pmuInfo(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y) +{ + float batteryVoltage = PMU->getBattVoltage(); + static char buffer[3][80]; + snprintf(buffer[0], sizeof(buffer[0]), "SYS VOL:%.2f V", PMU->getSystemVoltage() / 1000.0); + snprintf(buffer[1], sizeof(buffer[1]), "BAT VOL:%.2f V", batteryVoltage == -1 ? 0 : batteryVoltage / 1000.0); + if (PMU->isVbusIn()) { + snprintf(buffer[2], sizeof(buffer[2]), "USB VOL:%.2f V", PMU->getVbusVoltage() / 1000.0); + } else { + snprintf(buffer[2], sizeof(buffer[2]), "USB LOST"); + } + display->setFont(Roboto_Mono_Medium_12); + display->setTextAlignment(TEXT_ALIGN_CENTER); + display->drawString(64 + x, 0 + y, "PMU"); + display->drawString(64 + x, 16 + y, buffer[0]); + display->drawString(64 + x, 32 + y, buffer[1]); + display->drawString(64 + x, 48 + y, buffer[2]); +} +#endif + + + +#ifdef T_BEAM_S3_SUPREME +void dateTimeInfo(OLEDDisplay *display, OLEDDisplayUiState *disp_state, int16_t x, int16_t y) +{ + static char buffer[2][128] = {0}; + static uint32_t interval = 0; + + display->setFont(Roboto_Mono_Medium_12); + display->setTextAlignment(TEXT_ALIGN_CENTER); + + if (deviceOnline & PCF8563_ONLINE && millis() > interval) { + struct tm timeinfo; + rtc.getDateTime(&timeinfo); + snprintf(buffer[0], 128, "%04d/%02d/%02d", timeinfo.tm_year + 1900, timeinfo.tm_mon + 1, timeinfo.tm_mday); + snprintf(buffer[1], 128, "%02d:%02d:%02d", timeinfo.tm_hour, timeinfo.tm_min, timeinfo.tm_sec); + interval = millis() + 1000; + } + display->drawString(64 + x, 0 + y, "RTC"); + display->drawString(64 + x, 16 + y, buffer[0]); + display->drawString(64 + x, 32 + y, buffer[1]); +} + +void sensorInfo(OLEDDisplay *display, OLEDDisplayUiState *disp_state, int16_t x, int16_t y) +{ + static float temperature = 0; + static float humidity = 0; + static float pressure = 0; + static uint32_t interval = 0; + + display->setFont(Roboto_Mono_Medium_12); + display->setTextAlignment(TEXT_ALIGN_CENTER); + display->drawString(64 + x, 0 + y, "SENSOR"); + + if (deviceOnline & BME280_ONLINE) { + if (millis() > interval) { + temperature = bme.readTemperature(); + humidity = bme.readHumidity(); + pressure = bme.readPressure(); + interval = millis() + 1000; + } + } + display->setTextAlignment(TEXT_ALIGN_LEFT); + display->drawString(x + 0, y + 16, "TEMP:"); + display->drawString(x + 0, y + 32, "HUM:"); + display->drawString(x + 0, y + 48, "PRES:"); + + display->setTextAlignment(TEXT_ALIGN_RIGHT); + display->drawString(display->width() + x, y + 16, String(temperature) + "°C"); + display->drawString(display->width() + x, y + 32, String(humidity) + " %"); + display->drawString(display->width() + x, y + 48, String(pressure / 1000.0) + " kPa"); +} + + +static const int centreX = 32; +static const int centreY = 40; +static const int radius = 10; +Madgwick filter; + +int last_dx = centreX, last_dy = centreY, dx, dy; + +void arrow(OLEDDisplay *display, int offsetX, int offsetY, int x2, int y2, int x1, int y1, int alength, int awidth, OLEDDISPLAY_COLOR color) +{ + display->setColor(color); + float distance; + int dx, dy, x2o, y2o, x3, y3, x4, y4, k; + distance = sqrt(pow((x1 - x2), 2) + pow((y1 - y2), 2)); + dx = x2 + (x1 - x2) * alength / distance; + dy = y2 + (y1 - y2) * alength / distance; + k = awidth / alength; + x2o = x2 - dx; + y2o = dy - y2; + x3 = y2o * k + dx; + y3 = x2o * k + dy; + x4 = dx - y2o * k; + y4 = dy - x2o * k; + display->drawLine(x1 + offsetX, y1 + offsetY, offsetX + x2, offsetY + y2); + display->drawLine(x1 + offsetX, y1 + offsetY, offsetX + dx, offsetY + dy); + display->drawLine(x3 + offsetX, y3 + offsetY, offsetX + x4, offsetY + y4); + display->drawLine(x3 + offsetX, y3 + offsetY, offsetX + x2, offsetY + y2); + display->drawLine(x2 + offsetX, y2 + offsetY, offsetX + x4, offsetY + y4); +} + +int drawCompass(OLEDDisplay *display, int16_t x, int16_t y, float magX, float magY) +{ + int angle; + display->drawString(x + 29, y + 16, "N"); + display->drawString(x + 0, y + 32, "W"); + display->drawString(x + 58, y + 32, "E"); + display->drawString(x + 29, y + 50, "S"); + + float heading = atan2(magY, magX); // Result is in radians + // Now add the 'Declination Angle' for you location. Declination is the variation in magnetic field at your location. + // Find your declination here: http://www.magnetic-declination.com/ + // At my location it is : -2° 20' W, or -2.33 Degrees, which needs to be in radians so = -2.33 / 180 * PI = -0.041 West is + E is - + // Make declination = 0 if you can't find your Declination value, the error is negible for nearly all locations + float declination = -0.041; + heading = heading + declination; + if (heading < 0) heading += 2 * PI; // Correct for when signs are reversed. + if (heading > 2 * PI) heading -= 2 * PI; // Correct for when heading exceeds 360-degree, especially when declination is included + angle = int(heading * 180 / M_PI); // Convert radians to degrees for more a more usual result + // For the screen -X = up and +X = down and -Y = left and +Y = right, so does not follow coordinate conventions + dx = (0.7 * radius * cos((angle - 90) * 3.14 / 180)) + centreX + x; // calculate X position for the screen coordinates - can be confusing! + dy = (0.7 * radius * sin((angle - 90) * 3.14 / 180)) + centreY + y; // calculate Y position for the screen coordinates - can be confusing! + arrow(display, x, y, last_dx, last_dy, centreX + x, centreY + y, 2, 2, BLACK); // Erase last arrow + arrow(display, x, y, dx, dy, x + centreX, centreY + y, 2, 2, WHITE); // Draw arrow in new position + return angle; +} + +void getMagData(float *x, float *y) +{ + float z = 0; + if (qmc.isDataReady()) { + qmc.readData(); + qmc.getMag(*x, *y, z); + } +} + +void imuInfo(OLEDDisplay *display, OLEDDisplayUiState *disp_state, int16_t x, int16_t y) +{ + static float magX = 0, magY = 0; + static int angle = 0; + static float roll, pitch, heading; + + getMagData(&magX, &magY); + angle = drawCompass(display, x, y, magX, magY); + + display->setFont(Roboto_Mono_Medium_12); + display->setTextAlignment(TEXT_ALIGN_CENTER); + display->drawString(64 + x, 0 + y, "IMU"); + + display->setTextAlignment(TEXT_ALIGN_LEFT); + display->setColor(BLACK); + display->fillRect(x + 80, y + 16, 25, 50); + display->setColor(WHITE); + display->setFont(Roboto_Mono_Medium_12); + display->drawString(x + 75, y + 16, String(angle) + "°"); + + // Read raw data from IMU + if (digitalRead(IMU_INT) == HIGH) { + IMUdata acc, gyr; + qmi.getAccelerometer(acc.x, acc.y, acc.z); + qmi.getGyroscope(gyr.x, gyr.y, gyr.z); + // Update the filter, which computes orientation + filter.updateIMU(gyr.x, gyr.y, gyr.z, acc.x, acc.y, acc.z); + roll = filter.getRoll(); + pitch = filter.getPitch(); + heading = filter.getYaw(); + // Serial.printf("roll:%.2f pitch:%.2f heading:%.2f\n", roll, pitch, heading); + } + + display->drawString(x + 75, y + 32, String(heading) + "°"); +} + +static void beginSensor() +{ + // PMU and RTC share I2C bus + if (!rtc.begin(PMU_WIRE_PORT, PCF8563_SLAVE_ADDRESS, I2C_SDA, I2C_SCL)) { + Serial.println("Failed to find PCF8563 - check your wiring!"); + } + if (!qmc.begin(Wire, QMC6310_SLAVE_ADDRESS, I2C_SDA, I2C_SCL)) { + Serial.println("Failed to find QMC6310 - check your wiring!"); + } else { + qmc.configMagnetometer( + SensorQMC6310::MODE_CONTINUOUS, + SensorQMC6310::RANGE_8G, + SensorQMC6310::DATARATE_200HZ, + SensorQMC6310::OSR_1, + SensorQMC6310::DSR_1); + } + if (!bme.begin()) { + Serial.println("Failed to find BME280 - check your wiring!"); + } + + pinMode(SPI_CS, OUTPUT); //sdcard pin set high + digitalWrite(SPI_CS, HIGH); + + + pinMode(IMU_INT, INPUT_PULLUP); //IMU set interrupt pin + // SDCard shares SPI bus with QMI8658 + // SPI has been initialized in initBoard. + // Only need to pass SPIhandler to the QMI class. + if (!qmi.begin(IMU_CS, -1, -1, -1, SDCardSPI)) { + Serial.println("Failed to find QMI8658 - check your wiring!"); + } else { + /* Get chip id*/ + Serial.print("Device ID:"); + Serial.println(qmi.getChipID(), HEX); + deviceOnline |= QMI8658_ONLINE; + + qmi.configAccelerometer( + SensorQMI8658::ACC_RANGE_4G, + SensorQMI8658::ACC_ODR_1000Hz, + SensorQMI8658::LPF_MODE_0, + true); + qmi.configGyroscope( + SensorQMI8658::GYR_RANGE_256DPS, + SensorQMI8658::GYR_ODR_896_8Hz, + SensorQMI8658::LPF_MODE_3, + true); + + + // In 6DOF mode (accelerometer and gyroscope are both enabled), + // the output data rate is derived from the nature frequency of gyroscope + qmi.enableGyroscope(); + qmi.enableAccelerometer(); + + // Enable data ready to interrupt pin2 + qmi.enableINT(SensorQMI8658::IntPin2); + qmi.enableDataReadyINT(); + } + + // start filter + filter.begin(25); +} +#endif + +void wifiTask(void *task) +{ + while (1) { + wifiMulti.run(); + if (is_time_available) { + vTaskDelete(NULL); + } + delay(1000); + } +} diff --git a/examples/Factory/LoRaBoards.cpp b/examples/Factory/LoRaBoards.cpp new file mode 100644 index 0000000..88db437 --- /dev/null +++ b/examples/Factory/LoRaBoards.cpp @@ -0,0 +1,1165 @@ +/** + * @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" + +#include "soc/rtc.h" +#ifdef ENABLE_BLE +#include +#include +#include +#endif + +#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; +String gps_model = "None"; +#endif + + +uint32_t deviceOnline = 0x00; + + +#ifdef HAS_PMU +XPowersLibInterface *PMU = NULL; +bool pmuInterrupt; + +static void setPmuFlag() +{ + pmuInterrupt = true; +} +#endif + +static void enable_slow_clock(); + + +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; + } + + deviceOnline |= POWERMANAGE_ONLINE; + + 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); + PMU->disablePowerOutput(XPOWERS_CPULDO); + + // 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; + + PMU->setChargingLedMode(XPOWERS_CHG_LED_OFF); + // Disable the PMU measurement section + PMU->disableSystemVoltageMeasure(); + PMU->disableVbusVoltageMeasure(); + PMU->disableBattVoltageMeasure(); + PMU->disableTemperatureMeasure(); + PMU->disableBattDetection(); + +#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); +#else + + if (PMU->getChipModel() == XPOWERS_AXP2101) { + + // Disable all PMU interrupts + PMU->disableIRQ(XPOWERS_AXP2101_ALL_IRQ); + // Clear the PMU interrupt status before sleeping, otherwise the sleep current will increase + PMU->clearIrqStatus(); + // GNSS RTC Power , Turning off GPS backup voltage and current can further reduce ~ 100 uA + PMU->disablePowerOutput(XPOWERS_VBACKUP); + // LoRa VDD + PMU->disablePowerOutput(XPOWERS_ALDO2); + // GNSS VDD + PMU->disablePowerOutput(XPOWERS_ALDO3); + + } else if (PMU->getChipModel() == XPOWERS_AXP192) { + + // Disable all PMU interrupts + PMU->disableIRQ(XPOWERS_AXP192_ALL_IRQ); + // Clear the PMU interrupt status before sleeping, otherwise the sleep current will increase + PMU->clearIrqStatus(); + // LoRa VDD + PMU->disablePowerOutput(XPOWERS_LDO2); + // GNSS VDD + PMU->disablePowerOutput(XPOWERS_LDO3); + + + } +#endif +#endif +} + +void loopPMU(void (*pressed_cb)(void)) +{ +#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 (pressed_cb) { + pressed_cb(); + } + } + if (PMU->isPekeyLongPressIrq()) { + Serial.println("isPekeyLongPress"); + } + if (PMU->isBatChargeDoneIrq()) { + Serial.println("isBatChargeDone"); + } + if (PMU->isBatChargeStartIrq()) { + Serial.println("isBatChargeStart"); + } + // 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"); + deviceOnline |= SDCARD_ONLINE; + return true; + } else { + Serial.println("Warning: Failed to init Sd Card"); + } +#endif + return false; +} + +void beginWiFi() +{ +#ifdef ARDUINO_ARCH_ESP32 + if (!WiFi.softAP(BOARD_VARIANT_NAME)) { + log_e("Soft AP creation failed."); + } + IPAddress myIP = WiFi.softAPIP(); + Serial.print("AP IP address: "); + Serial.println(myIP); +#endif +} + + +void printWakeupReason() +{ +#ifdef ARDUINO_ARCH_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 (psramFound()) { + uint32_t psram = ESP.getPsramSize(); + devInfo.psramSize = psram / 1024.0 / 1024.0; + Serial.printf("PSRAM is enable! PSRAM: %.2fMB\n", devInfo.psramSize); + deviceOnline |= PSRAM_ONLINE; + } else { + Serial.println("PSRAM is disable!"); + devInfo.psramSize = 0; + } + + + 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__); + + uint8_t mac[6]; + char macStr[18] = { 0 }; + esp_efuse_mac_get_default(mac); + sprintf(macStr, "%02X:%02X:%02X:%02X:%02X:%02X", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); + Serial.print("EFUSE MAC: "); + Serial.print(macStr); + 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); + Serial.println("Scan Wire..."); + scanDevices(&Wire); +#endif + +#ifdef I2C1_SDA + Wire1.begin(I2C1_SDA, I2C1_SCL); + Serial.println("Scan Wire1..."); + scanDevices(&Wire1); +#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 + /* + * 2W LoRa LDO enable + * */ + pinMode(RADIO_LDO_EN, OUTPUT); + digitalWrite(RADIO_LDO_EN, LOW); +#endif + +#ifdef RADIO_CTRL + /* + * 2W LoRa RX TX Control + * */ + pinMode(RADIO_CTRL, OUTPUT); + digitalWrite(RADIO_CTRL, LOW); +#endif + + beginPower(); + + beginSDCard(); + + if (!disable_u8g2) { + beginDisplay(); + } + + // beginWiFi(); + +#ifdef FAN_CTRL + pinMode(FAN_CTRL, OUTPUT); +#endif + +#ifdef HAS_GPS + find_gps = beginGPS(); + uint32_t baudrate[] = {9600, 19200, 38400, 57600, 115200, 230400, 460800, 921600, 4800}; + if (!find_gps) { + // Restore factory settings + for ( int i = 0; i < sizeof(baudrate) / sizeof(baudrate[0]); ++i) { + Serial.printf("Update baudrate : %u\n", baudrate[i]); + SerialGPS.updateBaudRate(baudrate[i]); + if (recoveryGPS()) { + Serial.println("UBlox GNSS init succeeded, using UBlox GNSS Module\n"); + gps_model = "UBlox"; + find_gps = true; + break; + } + } + } else { + gps_model = "L76K"; + } + + if (find_gps) { + deviceOnline |= GPS_ONLINE; + } + +#ifdef T_BEAM_S3_SUPREME + enable_slow_clock(); +#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 + Serial.print("GPS : "); + Serial.println(( find_gps ) ? "+" : "-"); +#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 +} + + +#ifdef BOARD_LED +static uint8_t ledState = LOW; +static const uint32_t debounceDelay = 50; +static uint32_t lastDebounceTime = 0; +#endif + + +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!"); + deviceOnline |= BME280_ONLINE; + break; + case 0x34: + Serial.println("\tFind AXP192/AXP2101 PMU!"); + deviceOnline |= POWERMANAGE_ONLINE; + break; + case 0x3C: + Serial.println("\tFind SSD1306/SH1106 dispaly!"); + deviceOnline |= DISPLAY_ONLINE; + break; + case 0x51: + Serial.println("\tFind PCF8563 RTC!"); + deviceOnline |= PCF8563_ONLINE; + break; + case 0x1C: + Serial.println("\tFind QMC6310 MAG Sensor!"); + deviceOnline |= QMC6310_ONLINE; + 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 ."); + SerialGPS.flush(); + 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; +} + + + +static int getAck(uint8_t *buffer, uint16_t size, uint8_t requestedClass, uint8_t requestedID) +{ + uint16_t ubxFrameCounter = 0; + bool ubxFrame = 0; + uint32_t startTime = millis(); + uint16_t needRead; + + while (millis() - startTime < 800) { + while (SerialGPS.available()) { + int c = SerialGPS.read(); + switch (ubxFrameCounter) { + case 0: + if (c == 0xB5) { + ubxFrameCounter++; + } + break; + case 1: + if (c == 0x62) { + ubxFrameCounter++; + } else { + ubxFrameCounter = 0; + } + break; + case 2: + if (c == requestedClass) { + ubxFrameCounter++; + } else { + ubxFrameCounter = 0; + } + break; + case 3: + if (c == requestedID) { + ubxFrameCounter++; + } else { + ubxFrameCounter = 0; + } + break; + case 4: + needRead = c; + ubxFrameCounter++; + break; + case 5: + needRead |= (c << 8); + ubxFrameCounter++; + break; + case 6: + if (needRead >= size) { + ubxFrameCounter = 0; + break; + } + if (SerialGPS.readBytes(buffer, needRead) != needRead) { + ubxFrameCounter = 0; + } else { + return needRead; + } + break; + + default: + break; + } + } + } + return 0; +} + +bool recoveryGPS() +{ + uint8_t buffer[256]; + uint8_t cfg_clear1[] = {0xB5, 0x62, 0x06, 0x09, 0x0D, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x1C, 0xA2}; + uint8_t cfg_clear2[] = {0xB5, 0x62, 0x06, 0x09, 0x0D, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x1B, 0xA1}; + uint8_t cfg_clear3[] = {0xB5, 0x62, 0x06, 0x09, 0x0D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x03, 0x1D, 0xB3}; + SerialGPS.write(cfg_clear1, sizeof(cfg_clear1)); + + if (getAck(buffer, 256, 0x05, 0x01)) { + Serial.println("Get ack successes!"); + } + SerialGPS.write(cfg_clear2, sizeof(cfg_clear2)); + if (getAck(buffer, 256, 0x05, 0x01)) { + Serial.println("Get ack successes!"); + } + SerialGPS.write(cfg_clear3, sizeof(cfg_clear3)); + if (getAck(buffer, 256, 0x05, 0x01)) { + Serial.println("Get ack successes!"); + } + // UBX-CFG-RATE, Size 8, 'Navigation/measurement rate settings' + uint8_t cfg_rate[] = {0xB5, 0x62, 0x06, 0x08, 0x00, 0x00, 0x0E, 0x30}; + SerialGPS.write(cfg_rate, sizeof(cfg_rate)); + if (getAck(buffer, 256, 0x06, 0x08)) { + Serial.println("Get ack successes!"); + } else { + return false; + } + return true; +} + +#endif + + +#if defined(ARDUINO_ARCH_ESP32) + +//NCP18XH103F03RB: https://item.szlcsc.com/14214.html +#define NTC_PIN 14 // NTC connection pins +#define SERIES_RESISTOR 10000 // Series resistance value (10kΩ) +#define B_COEFFICIENT 3950 // B value, set according to the NTC specification +#define ROOM_TEMP 298.15 // 25°C absolute temperature (K) +#define ROOM_TEMP_RESISTANCE 10000 // Resistance of NTC at 25°C (10kΩ) + +float getTempForNTC() +{ + static float temperature = 0.0f; +#ifdef NTC_PIN + static uint32_t check_temperature = 0; + if (millis() > check_temperature) { + float voltage = analogReadMilliVolts(NTC_PIN) / 1000.0; + float resistance = SERIES_RESISTOR * ((3.3 / voltage) - 1); // Calculate the resistance of NTC + + // Calculate temperature using the Steinhart-Hart equation + temperature = (1.0 / (log(resistance / ROOM_TEMP_RESISTANCE) / B_COEFFICIENT + 1.0 / ROOM_TEMP)) - 273.15; + + Serial.print("Temperature: "); + Serial.print(temperature); + Serial.println(" °C"); + + check_temperature = millis() + 1000; + } +#endif + return temperature; +} + + +#define SERVICE_UUID "4fafc201-1fb5-459e-8fcc-c5c9c331914b" +#define CHARACTERISTIC_UUID "beb5483e-36e1-4688-b7f5-ea07361b26a8" + +void setupBLE() +{ +#ifdef ENABLE_BLE + + uint8_t mac[6]; + char macStr[18] = { 0 }; + esp_efuse_mac_get_default(mac); + sprintf(macStr, "%02X:%02X", mac[0], mac[1]); + + String dev = BOARD_VARIANT_NAME; + dev.concat('-'); + dev.concat(macStr); + + Serial.print("Starting BLE:"); + Serial.println(dev); + + BLEDevice::init(dev.c_str()); + BLEServer *pServer = BLEDevice::createServer(); + BLEService *pService = pServer->createService(SERVICE_UUID); + BLECharacteristic *pCharacteristic = pService->createCharacteristic( + CHARACTERISTIC_UUID, + BLECharacteristic::PROPERTY_READ | + BLECharacteristic::PROPERTY_WRITE); + + pCharacteristic->setValue("Hello World"); + pService->start(); + // BLEAdvertising *pAdvertising = pServer->getAdvertising(); // this still is working for backward compatibility + BLEAdvertising *pAdvertising = BLEDevice::getAdvertising(); + pAdvertising->addServiceUUID(SERVICE_UUID); + pAdvertising->setScanResponse(true); + pAdvertising->setMinPreferred(0x06); // functions that help with iPhone connections issue + pAdvertising->setMinPreferred(0x12); + BLEDevice::startAdvertising(); + Serial.println("Characteristic defined! Now you can read it in your phone!"); +#endif +} + +#define CALIBRATE_ONE(cali_clk) calibrate_one(cali_clk, #cali_clk) + +static uint32_t calibrate_one(rtc_cal_sel_t cal_clk, const char *name) +{ + const uint32_t cal_count = 1000; + const float factor = (1 << 19) * 1000.0f; + uint32_t cali_val; + for (int i = 0; i < 5; ++i) { + cali_val = rtc_clk_cal(cal_clk, cal_count); + } + return cali_val; +} + +static void enable_slow_clock() +{ + rtc_clk_32k_enable(true); + CALIBRATE_ONE(RTC_CAL_RTC_MUX); + uint32_t cal_32k = CALIBRATE_ONE(RTC_CAL_32K_XTAL); + if (cal_32k == 0) { + Serial.printf("32K XTAL OSC has not started up"); + } else { + rtc_clk_slow_freq_set(RTC_SLOW_FREQ_32K_XTAL); + Serial.println("Switching RTC Source to 32.768Khz succeeded, using 32K XTAL"); + CALIBRATE_ONE(RTC_CAL_RTC_MUX); + CALIBRATE_ONE(RTC_CAL_32K_XTAL); + } + CALIBRATE_ONE(RTC_CAL_RTC_MUX); + CALIBRATE_ONE(RTC_CAL_32K_XTAL); + if (rtc_clk_slow_freq_get() != RTC_SLOW_FREQ_32K_XTAL) { + Serial.println("Warning: Failed to set rtc clk to 32.768Khz !!! "); return; + } + deviceOnline |= OSC32768_ONLINE; +} + + +#endif /*ARDUINO_ARCH_ESP32*/ + diff --git a/examples/Factory/LoRaBoards.h b/examples/Factory/LoRaBoards.h new file mode 100644 index 0000000..a718d65 --- /dev/null +++ b/examples/Factory/LoRaBoards.h @@ -0,0 +1,127 @@ +/** + * @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 +#endif + +#if defined(ARDUINO_ARCH_ESP32) +#include +#include +#endif + +#include +#include +#include +#include +#include + +#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 + +enum { + POWERMANAGE_ONLINE = _BV(0), + DISPLAY_ONLINE = _BV(1), + RADIO_ONLINE = _BV(2), + GPS_ONLINE = _BV(3), + PSRAM_ONLINE = _BV(4), + SDCARD_ONLINE = _BV(5), + AXDL345_ONLINE = _BV(6), + BME280_ONLINE = _BV(7), + BMP280_ONLINE = _BV(8), + BME680_ONLINE = _BV(9), + QMC6310_ONLINE = _BV(10), + QMI8658_ONLINE = _BV(11), + PCF8563_ONLINE = _BV(12), + OSC32768_ONLINE = _BV(13), +}; + + +#define ENABLE_BLE //Enable ble function + +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(); + +bool recoveryGPS(); + +void loopPMU(void (*pressed_cb)(void)); + +#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 + +float getTempForNTC(); + +void setupBLE(); + +extern uint32_t deviceOnline; diff --git a/examples/Factory/Roboto_Mono_Medium_12.h b/examples/Factory/Roboto_Mono_Medium_12.h new file mode 100644 index 0000000..d6301ad --- /dev/null +++ b/examples/Factory/Roboto_Mono_Medium_12.h @@ -0,0 +1,427 @@ +#include +#include +// Created by https://oleddisplay.squix.ch/ Consider a donation +// In case of problems make sure that you are using the font file with the correct version! +const uint8_t Roboto_Mono_Medium_12[] PROGMEM = { + 0x07, // Width: 7 + 0x0F, // Height: 15 + 0x20, // First Char: 32 + 0xE0, // Numbers of Chars: 224 + + // Jump Table: + 0xFF, 0xFF, 0x00, 0x07, // 32:65535 + 0x00, 0x00, 0x08, 0x07, // 33:0 + 0x00, 0x08, 0x09, 0x07, // 34:8 + 0x00, 0x11, 0x0D, 0x07, // 35:17 + 0x00, 0x1E, 0x0E, 0x07, // 36:30 + 0x00, 0x2C, 0x0E, 0x07, // 37:44 + 0x00, 0x3A, 0x0E, 0x07, // 38:58 + 0x00, 0x48, 0x07, 0x07, // 39:72 + 0x00, 0x4F, 0x0A, 0x07, // 40:79 + 0x00, 0x59, 0x0A, 0x07, // 41:89 + 0x00, 0x63, 0x0D, 0x07, // 42:99 + 0x00, 0x70, 0x0B, 0x07, // 43:112 + 0x00, 0x7B, 0x08, 0x07, // 44:123 + 0x00, 0x83, 0x0B, 0x07, // 45:131 + 0x00, 0x8E, 0x0A, 0x07, // 46:142 + 0x00, 0x98, 0x0B, 0x07, // 47:152 + 0x00, 0xA3, 0x0C, 0x07, // 48:163 + 0x00, 0xAF, 0x0A, 0x07, // 49:175 + 0x00, 0xB9, 0x0C, 0x07, // 50:185 + 0x00, 0xC5, 0x0C, 0x07, // 51:197 + 0x00, 0xD1, 0x0E, 0x07, // 52:209 + 0x00, 0xDF, 0x0C, 0x07, // 53:223 + 0x00, 0xEB, 0x0C, 0x07, // 54:235 + 0x00, 0xF7, 0x0B, 0x07, // 55:247 + 0x01, 0x02, 0x0C, 0x07, // 56:258 + 0x01, 0x0E, 0x0C, 0x07, // 57:270 + 0x01, 0x1A, 0x0A, 0x07, // 58:282 + 0x01, 0x24, 0x0A, 0x07, // 59:292 + 0x01, 0x2E, 0x0C, 0x07, // 60:302 + 0x01, 0x3A, 0x0C, 0x07, // 61:314 + 0x01, 0x46, 0x0C, 0x07, // 62:326 + 0x01, 0x52, 0x0B, 0x07, // 63:338 + 0x01, 0x5D, 0x0E, 0x07, // 64:349 + 0x01, 0x6B, 0x0E, 0x07, // 65:363 + 0x01, 0x79, 0x0E, 0x07, // 66:377 + 0x01, 0x87, 0x0E, 0x07, // 67:391 + 0x01, 0x95, 0x0E, 0x07, // 68:405 + 0x01, 0xA3, 0x0C, 0x07, // 69:419 + 0x01, 0xAF, 0x0D, 0x07, // 70:431 + 0x01, 0xBC, 0x0E, 0x07, // 71:444 + 0x01, 0xCA, 0x0C, 0x07, // 72:458 + 0x01, 0xD6, 0x0C, 0x07, // 73:470 + 0x01, 0xE2, 0x0C, 0x07, // 74:482 + 0x01, 0xEE, 0x0E, 0x07, // 75:494 + 0x01, 0xFC, 0x0C, 0x07, // 76:508 + 0x02, 0x08, 0x0E, 0x07, // 77:520 + 0x02, 0x16, 0x0C, 0x07, // 78:534 + 0x02, 0x22, 0x0E, 0x07, // 79:546 + 0x02, 0x30, 0x0D, 0x07, // 80:560 + 0x02, 0x3D, 0x0E, 0x07, // 81:573 + 0x02, 0x4B, 0x0E, 0x07, // 82:587 + 0x02, 0x59, 0x0E, 0x07, // 83:601 + 0x02, 0x67, 0x0D, 0x07, // 84:615 + 0x02, 0x74, 0x0C, 0x07, // 85:628 + 0x02, 0x80, 0x0D, 0x07, // 86:640 + 0x02, 0x8D, 0x0D, 0x07, // 87:653 + 0x02, 0x9A, 0x0E, 0x07, // 88:666 + 0x02, 0xA8, 0x0D, 0x07, // 89:680 + 0x02, 0xB5, 0x0E, 0x07, // 90:693 + 0x02, 0xC3, 0x0A, 0x07, // 91:707 + 0x02, 0xCD, 0x0C, 0x07, // 92:717 + 0x02, 0xD9, 0x0A, 0x07, // 93:729 + 0x02, 0xE3, 0x0B, 0x07, // 94:739 + 0x02, 0xEE, 0x0C, 0x07, // 95:750 + 0x02, 0xFA, 0x09, 0x07, // 96:762 + 0x03, 0x03, 0x0C, 0x07, // 97:771 + 0x03, 0x0F, 0x0C, 0x07, // 98:783 + 0x03, 0x1B, 0x0C, 0x07, // 99:795 + 0x03, 0x27, 0x0C, 0x07, // 100:807 + 0x03, 0x33, 0x0E, 0x07, // 101:819 + 0x03, 0x41, 0x0D, 0x07, // 102:833 + 0x03, 0x4E, 0x0C, 0x07, // 103:846 + 0x03, 0x5A, 0x0C, 0x07, // 104:858 + 0x03, 0x66, 0x0C, 0x07, // 105:870 + 0x03, 0x72, 0x0A, 0x07, // 106:882 + 0x03, 0x7C, 0x0E, 0x07, // 107:892 + 0x03, 0x8A, 0x0E, 0x07, // 108:906 + 0x03, 0x98, 0x0E, 0x07, // 109:920 + 0x03, 0xA6, 0x0C, 0x07, // 110:934 + 0x03, 0xB2, 0x0E, 0x07, // 111:946 + 0x03, 0xC0, 0x0C, 0x07, // 112:960 + 0x03, 0xCC, 0x0C, 0x07, // 113:972 + 0x03, 0xD8, 0x0B, 0x07, // 114:984 + 0x03, 0xE3, 0x0C, 0x07, // 115:995 + 0x03, 0xEF, 0x0C, 0x07, // 116:1007 + 0x03, 0xFB, 0x0C, 0x07, // 117:1019 + 0x04, 0x07, 0x0D, 0x07, // 118:1031 + 0x04, 0x14, 0x0D, 0x07, // 119:1044 + 0x04, 0x21, 0x0E, 0x07, // 120:1057 + 0x04, 0x2F, 0x0D, 0x07, // 121:1071 + 0x04, 0x3C, 0x0E, 0x07, // 122:1084 + 0x04, 0x4A, 0x0C, 0x07, // 123:1098 + 0x04, 0x56, 0x08, 0x07, // 124:1110 + 0x04, 0x5E, 0x0B, 0x07, // 125:1118 + 0x04, 0x69, 0x0D, 0x07, // 126:1129 + 0xFF, 0xFF, 0x00, 0x07, // 127:65535 + 0xFF, 0xFF, 0x00, 0x07, // 128:65535 + 0xFF, 0xFF, 0x00, 0x07, // 129:65535 + 0xFF, 0xFF, 0x00, 0x07, // 130:65535 + 0xFF, 0xFF, 0x00, 0x07, // 131:65535 + 0xFF, 0xFF, 0x00, 0x07, // 132:65535 + 0xFF, 0xFF, 0x00, 0x07, // 133:65535 + 0xFF, 0xFF, 0x00, 0x07, // 134:65535 + 0xFF, 0xFF, 0x00, 0x07, // 135:65535 + 0xFF, 0xFF, 0x00, 0x07, // 136:65535 + 0xFF, 0xFF, 0x00, 0x07, // 137:65535 + 0xFF, 0xFF, 0x00, 0x07, // 138:65535 + 0xFF, 0xFF, 0x00, 0x07, // 139:65535 + 0xFF, 0xFF, 0x00, 0x07, // 140:65535 + 0xFF, 0xFF, 0x00, 0x07, // 141:65535 + 0xFF, 0xFF, 0x00, 0x07, // 142:65535 + 0xFF, 0xFF, 0x00, 0x07, // 143:65535 + 0xFF, 0xFF, 0x00, 0x07, // 144:65535 + 0xFF, 0xFF, 0x00, 0x07, // 145:65535 + 0xFF, 0xFF, 0x00, 0x07, // 146:65535 + 0xFF, 0xFF, 0x00, 0x07, // 147:65535 + 0xFF, 0xFF, 0x00, 0x07, // 148:65535 + 0xFF, 0xFF, 0x00, 0x07, // 149:65535 + 0xFF, 0xFF, 0x00, 0x07, // 150:65535 + 0xFF, 0xFF, 0x00, 0x07, // 151:65535 + 0xFF, 0xFF, 0x00, 0x07, // 152:65535 + 0xFF, 0xFF, 0x00, 0x07, // 153:65535 + 0xFF, 0xFF, 0x00, 0x07, // 154:65535 + 0xFF, 0xFF, 0x00, 0x07, // 155:65535 + 0xFF, 0xFF, 0x00, 0x07, // 156:65535 + 0xFF, 0xFF, 0x00, 0x07, // 157:65535 + 0xFF, 0xFF, 0x00, 0x07, // 158:65535 + 0xFF, 0xFF, 0x00, 0x07, // 159:65535 + 0xFF, 0xFF, 0x00, 0x07, // 160:65535 + 0x04, 0x76, 0x09, 0x07, // 161:1142 + 0x04, 0x7F, 0x0C, 0x07, // 162:1151 + 0x04, 0x8B, 0x0E, 0x07, // 163:1163 + 0x04, 0x99, 0x0E, 0x07, // 164:1177 + 0x04, 0xA7, 0x0D, 0x07, // 165:1191 + 0x04, 0xB4, 0x08, 0x07, // 166:1204 + 0x04, 0xBC, 0x0E, 0x07, // 167:1212 + 0x04, 0xCA, 0x0B, 0x07, // 168:1226 + 0x04, 0xD5, 0x0E, 0x07, // 169:1237 + 0x04, 0xE3, 0x0B, 0x07, // 170:1251 + 0x04, 0xEE, 0x0C, 0x07, // 171:1262 + 0x04, 0xFA, 0x0C, 0x07, // 172:1274 + 0x05, 0x06, 0x0B, 0x07, // 173:1286 + 0x05, 0x11, 0x0E, 0x07, // 174:1297 + 0x05, 0x1F, 0x0B, 0x07, // 175:1311 + 0x05, 0x2A, 0x09, 0x07, // 176:1322 + 0x05, 0x33, 0x0C, 0x07, // 177:1331 + 0x05, 0x3F, 0x09, 0x07, // 178:1343 + 0x05, 0x48, 0x09, 0x07, // 179:1352 + 0x05, 0x51, 0x09, 0x07, // 180:1361 + 0x05, 0x5A, 0x0C, 0x07, // 181:1370 + 0x05, 0x66, 0x0C, 0x07, // 182:1382 + 0x05, 0x72, 0x09, 0x07, // 183:1394 + 0x05, 0x7B, 0x0A, 0x07, // 184:1403 + 0x05, 0x85, 0x09, 0x07, // 185:1413 + 0x05, 0x8E, 0x0B, 0x07, // 186:1422 + 0x05, 0x99, 0x0C, 0x07, // 187:1433 + 0x05, 0xA5, 0x0E, 0x07, // 188:1445 + 0x05, 0xB3, 0x0E, 0x07, // 189:1459 + 0x05, 0xC1, 0x0E, 0x07, // 190:1473 + 0x05, 0xCF, 0x0C, 0x07, // 191:1487 + 0x05, 0xDB, 0x0E, 0x07, // 192:1499 + 0x05, 0xE9, 0x0E, 0x07, // 193:1513 + 0x05, 0xF7, 0x0E, 0x07, // 194:1527 + 0x06, 0x05, 0x0E, 0x07, // 195:1541 + 0x06, 0x13, 0x0E, 0x07, // 196:1555 + 0x06, 0x21, 0x0E, 0x07, // 197:1569 + 0x06, 0x2F, 0x0E, 0x07, // 198:1583 + 0x06, 0x3D, 0x0E, 0x07, // 199:1597 + 0x06, 0x4B, 0x0C, 0x07, // 200:1611 + 0x06, 0x57, 0x0C, 0x07, // 201:1623 + 0x06, 0x63, 0x0C, 0x07, // 202:1635 + 0x06, 0x6F, 0x0C, 0x07, // 203:1647 + 0x06, 0x7B, 0x0C, 0x07, // 204:1659 + 0x06, 0x87, 0x0C, 0x07, // 205:1671 + 0x06, 0x93, 0x0C, 0x07, // 206:1683 + 0x06, 0x9F, 0x0C, 0x07, // 207:1695 + 0x06, 0xAB, 0x0E, 0x07, // 208:1707 + 0x06, 0xB9, 0x0C, 0x07, // 209:1721 + 0x06, 0xC5, 0x0E, 0x07, // 210:1733 + 0x06, 0xD3, 0x0E, 0x07, // 211:1747 + 0x06, 0xE1, 0x0E, 0x07, // 212:1761 + 0x06, 0xEF, 0x0E, 0x07, // 213:1775 + 0x06, 0xFD, 0x0E, 0x07, // 214:1789 + 0x07, 0x0B, 0x0C, 0x07, // 215:1803 + 0x07, 0x17, 0x0E, 0x07, // 216:1815 + 0x07, 0x25, 0x0C, 0x07, // 217:1829 + 0x07, 0x31, 0x0C, 0x07, // 218:1841 + 0x07, 0x3D, 0x0C, 0x07, // 219:1853 + 0x07, 0x49, 0x0C, 0x07, // 220:1865 + 0x07, 0x55, 0x0D, 0x07, // 221:1877 + 0x07, 0x62, 0x0E, 0x07, // 222:1890 + 0x07, 0x70, 0x0E, 0x07, // 223:1904 + 0x07, 0x7E, 0x0C, 0x07, // 224:1918 + 0x07, 0x8A, 0x0C, 0x07, // 225:1930 + 0x07, 0x96, 0x0C, 0x07, // 226:1942 + 0x07, 0xA2, 0x0C, 0x07, // 227:1954 + 0x07, 0xAE, 0x0C, 0x07, // 228:1966 + 0x07, 0xBA, 0x0C, 0x07, // 229:1978 + 0x07, 0xC6, 0x0E, 0x07, // 230:1990 + 0x07, 0xD4, 0x0C, 0x07, // 231:2004 + 0x07, 0xE0, 0x0E, 0x07, // 232:2016 + 0x07, 0xEE, 0x0E, 0x07, // 233:2030 + 0x07, 0xFC, 0x0E, 0x07, // 234:2044 + 0x08, 0x0A, 0x0E, 0x07, // 235:2058 + 0x08, 0x18, 0x0E, 0x07, // 236:2072 + 0x08, 0x26, 0x0E, 0x07, // 237:2086 + 0x08, 0x34, 0x0E, 0x07, // 238:2100 + 0x08, 0x42, 0x0E, 0x07, // 239:2114 + 0x08, 0x50, 0x0C, 0x07, // 240:2128 + 0x08, 0x5C, 0x0C, 0x07, // 241:2140 + 0x08, 0x68, 0x0E, 0x07, // 242:2152 + 0x08, 0x76, 0x0E, 0x07, // 243:2166 + 0x08, 0x84, 0x0E, 0x07, // 244:2180 + 0x08, 0x92, 0x0E, 0x07, // 245:2194 + 0x08, 0xA0, 0x0E, 0x07, // 246:2208 + 0x08, 0xAE, 0x0D, 0x07, // 247:2222 + 0x08, 0xBB, 0x0E, 0x07, // 248:2235 + 0x08, 0xC9, 0x0C, 0x07, // 249:2249 + 0x08, 0xD5, 0x0C, 0x07, // 250:2261 + 0x08, 0xE1, 0x0C, 0x07, // 251:2273 + 0x08, 0xED, 0x0C, 0x07, // 252:2285 + 0x08, 0xF9, 0x0D, 0x07, // 253:2297 + 0x09, 0x06, 0x0C, 0x07, // 254:2310 + 0x09, 0x12, 0x0D, 0x07, // 255:2322 + + // Font Data: + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0x09, // 33 + 0x00, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x1C, // 34 + 0x00, 0x01, 0x20, 0x0D, 0xF0, 0x03, 0x28, 0x01, 0xE0, 0x0F, 0x38, 0x01, 0x20, // 35 + 0x00, 0x00, 0x30, 0x06, 0x78, 0x0C, 0xCE, 0x18, 0x88, 0x08, 0xB8, 0x0F, 0x20, 0x02, // 36 + 0x30, 0x00, 0x48, 0x00, 0x78, 0x06, 0x80, 0x01, 0x70, 0x0F, 0x10, 0x09, 0x00, 0x0F, // 37 + 0x00, 0x00, 0x30, 0x0F, 0xF8, 0x09, 0xC8, 0x09, 0x78, 0x0E, 0x00, 0x0E, 0x00, 0x0B, // 38 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1C, // 39 + 0x00, 0x00, 0x00, 0x00, 0xC0, 0x07, 0x70, 0x18, 0x0C, 0x60, // 40 + 0x00, 0x00, 0x00, 0x00, 0x0C, 0x60, 0x30, 0x38, 0xE0, 0x0F, // 41 + 0x00, 0x00, 0x40, 0x00, 0x40, 0x03, 0xF0, 0x01, 0x80, 0x01, 0x40, 0x02, 0x40, // 42 + 0x00, 0x00, 0x80, 0x00, 0x80, 0x00, 0xF0, 0x07, 0x80, 0x00, 0x80, // 43 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x38, // 44 + 0x00, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, // 45 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x0C, // 46 + 0x00, 0x00, 0x00, 0x10, 0x00, 0x1C, 0x80, 0x03, 0x70, 0x00, 0x18, // 47 + 0x00, 0x00, 0xF0, 0x07, 0x18, 0x0D, 0x88, 0x08, 0x58, 0x0C, 0xF0, 0x07, // 48 + 0x00, 0x00, 0x30, 0x00, 0x10, 0x00, 0xF8, 0x0F, 0xF8, 0x0F, // 49 + 0x20, 0x00, 0x30, 0x0C, 0x08, 0x0E, 0x08, 0x0B, 0xD8, 0x08, 0x70, 0x08, // 50 + 0x00, 0x00, 0x10, 0x04, 0x88, 0x08, 0x88, 0x08, 0xD8, 0x0D, 0x70, 0x07, // 51 + 0x00, 0x02, 0x80, 0x03, 0xC0, 0x02, 0x30, 0x02, 0xF8, 0x0F, 0xF8, 0x0F, 0x00, 0x02, // 52 + 0x00, 0x00, 0xF0, 0x06, 0xF8, 0x0C, 0x48, 0x08, 0xC8, 0x0C, 0x88, 0x07, // 53 + 0x00, 0x00, 0xE0, 0x07, 0xF0, 0x0C, 0x58, 0x08, 0xC8, 0x0C, 0x80, 0x07, // 54 + 0x00, 0x00, 0x08, 0x00, 0x08, 0x0C, 0x08, 0x07, 0xE8, 0x00, 0x38, // 55 + 0x00, 0x00, 0x70, 0x07, 0xD8, 0x0D, 0x88, 0x08, 0x98, 0x08, 0x70, 0x07, // 56 + 0x00, 0x00, 0xF0, 0x01, 0x98, 0x09, 0x08, 0x09, 0x18, 0x05, 0xF0, 0x03, // 57 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x0C, 0x60, 0x0C, // 58 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x60, 0x60, 0x38, // 59 + 0x00, 0x00, 0x80, 0x01, 0x80, 0x01, 0x80, 0x02, 0x40, 0x02, 0x40, 0x06, // 60 + 0x00, 0x00, 0x40, 0x02, 0x40, 0x02, 0x40, 0x02, 0x40, 0x02, 0x40, 0x02, // 61 + 0x00, 0x00, 0x40, 0x06, 0x40, 0x02, 0x80, 0x02, 0x80, 0x03, 0x80, 0x01, // 62 + 0x00, 0x00, 0x10, 0x00, 0x18, 0x00, 0x08, 0x0B, 0x88, 0x01, 0x70, // 63 + 0xC0, 0x03, 0x30, 0x04, 0xD8, 0x0B, 0x28, 0x0A, 0xE8, 0x0B, 0x10, 0x02, 0xE0, 0x01, // 64 + 0x00, 0x08, 0x00, 0x0F, 0xE0, 0x03, 0x38, 0x02, 0xF0, 0x02, 0x80, 0x0F, 0x00, 0x0C, // 65 + 0x00, 0x00, 0xF8, 0x0F, 0x88, 0x08, 0x88, 0x08, 0x88, 0x08, 0x78, 0x0F, 0x20, 0x07, // 66 + 0x00, 0x00, 0xF0, 0x07, 0x18, 0x0C, 0x08, 0x08, 0x08, 0x08, 0x30, 0x06, 0x20, 0x02, // 67 + 0x00, 0x00, 0xF8, 0x0F, 0x08, 0x08, 0x08, 0x08, 0x18, 0x0C, 0xF0, 0x07, 0xC0, 0x01, // 68 + 0x00, 0x00, 0xF8, 0x0F, 0x88, 0x08, 0x88, 0x08, 0x88, 0x08, 0x88, 0x08, // 69 + 0x00, 0x00, 0xF8, 0x0F, 0x88, 0x00, 0x88, 0x00, 0x88, 0x00, 0x88, 0x00, 0x08, // 70 + 0x00, 0x00, 0xF0, 0x07, 0x18, 0x0C, 0x08, 0x08, 0x88, 0x08, 0xB0, 0x0F, 0xA0, 0x07, // 71 + 0x00, 0x00, 0xF8, 0x0F, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0xF8, 0x0F, // 72 + 0x00, 0x00, 0x08, 0x08, 0x08, 0x08, 0xF8, 0x0F, 0x08, 0x08, 0x08, 0x08, // 73 + 0x00, 0x00, 0x00, 0x06, 0x00, 0x0C, 0x00, 0x08, 0x00, 0x0C, 0xF8, 0x07, // 74 + 0x00, 0x00, 0xF8, 0x0F, 0x80, 0x01, 0xC0, 0x01, 0x30, 0x03, 0x18, 0x0E, 0x08, 0x08, // 75 + 0x00, 0x00, 0xF8, 0x0F, 0x00, 0x08, 0x00, 0x08, 0x00, 0x08, 0x00, 0x08, // 76 + 0x00, 0x00, 0xF8, 0x0F, 0x78, 0x00, 0x80, 0x01, 0xF0, 0x00, 0xF8, 0x0F, 0xF8, 0x0F, // 77 + 0x00, 0x00, 0xF8, 0x0F, 0x70, 0x00, 0xC0, 0x01, 0x00, 0x07, 0xF8, 0x0F, // 78 + 0x00, 0x00, 0xF0, 0x07, 0x18, 0x0C, 0x08, 0x08, 0x18, 0x0C, 0xF0, 0x07, 0xC0, 0x01, // 79 + 0x00, 0x00, 0xF8, 0x0F, 0x88, 0x00, 0x88, 0x00, 0x88, 0x00, 0xF8, 0x00, 0x70, // 80 + 0x00, 0x00, 0xF0, 0x07, 0x18, 0x0C, 0x08, 0x08, 0x18, 0x0C, 0xF0, 0x1F, 0xE0, 0x13, // 81 + 0x00, 0x00, 0xF8, 0x0F, 0x88, 0x00, 0x88, 0x00, 0x88, 0x03, 0xF8, 0x0E, 0x20, 0x08, // 82 + 0x00, 0x00, 0x70, 0x06, 0xD8, 0x0C, 0x88, 0x08, 0x88, 0x08, 0x38, 0x0F, 0x20, 0x06, // 83 + 0x08, 0x00, 0x08, 0x00, 0x08, 0x00, 0xF8, 0x0F, 0x08, 0x00, 0x08, 0x00, 0x08, // 84 + 0x00, 0x00, 0xF8, 0x07, 0x00, 0x0C, 0x00, 0x08, 0x00, 0x0C, 0xF8, 0x07, // 85 + 0x08, 0x00, 0x78, 0x00, 0xE0, 0x07, 0x00, 0x0E, 0xC0, 0x07, 0xF8, 0x00, 0x08, // 86 + 0x18, 0x00, 0xF8, 0x0F, 0x80, 0x0F, 0x78, 0x00, 0xE0, 0x0F, 0xE0, 0x0F, 0x78, // 87 + 0x08, 0x08, 0x18, 0x0C, 0x70, 0x07, 0xC0, 0x01, 0xE0, 0x03, 0x38, 0x0E, 0x08, 0x08, // 88 + 0x08, 0x00, 0x38, 0x00, 0xE0, 0x00, 0x80, 0x0F, 0xE0, 0x00, 0x38, 0x00, 0x08, // 89 + 0x00, 0x00, 0x08, 0x0C, 0x08, 0x0B, 0xC8, 0x09, 0x68, 0x08, 0x18, 0x08, 0x00, 0x08, // 90 + 0x00, 0x00, 0x00, 0x00, 0xFC, 0x3F, 0xFC, 0x3F, 0x04, 0x20, // 91 + 0x00, 0x00, 0x08, 0x00, 0x38, 0x00, 0xE0, 0x01, 0x00, 0x0F, 0x00, 0x18, // 92 + 0x00, 0x00, 0x00, 0x00, 0x04, 0x20, 0xFC, 0x3F, 0xFC, 0x3F, // 93 + 0x00, 0x00, 0x80, 0x00, 0xE0, 0x00, 0x18, 0x00, 0x70, 0x00, 0x80, // 94 + 0x00, 0x00, 0x00, 0x10, 0x00, 0x10, 0x00, 0x10, 0x00, 0x10, 0x00, 0x10, // 95 + 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x08, 0x00, 0x08, // 96 + 0x00, 0x00, 0x40, 0x0E, 0x60, 0x09, 0x20, 0x09, 0x60, 0x05, 0xC0, 0x0F, // 97 + 0x00, 0x00, 0xFC, 0x0F, 0x40, 0x04, 0x20, 0x08, 0x60, 0x0C, 0xC0, 0x07, // 98 + 0x00, 0x00, 0xC0, 0x07, 0x60, 0x0C, 0x20, 0x08, 0x20, 0x08, 0xC0, 0x04, // 99 + 0x00, 0x00, 0xC0, 0x07, 0x60, 0x0C, 0x20, 0x08, 0x60, 0x0C, 0xFC, 0x0F, // 100 + 0x00, 0x00, 0xC0, 0x07, 0x60, 0x0D, 0x20, 0x09, 0x20, 0x09, 0xC0, 0x0D, 0x00, 0x01, // 101 + 0x00, 0x00, 0x20, 0x00, 0xE0, 0x0F, 0xFC, 0x0F, 0x24, 0x00, 0x24, 0x00, 0x04, // 102 + 0x00, 0x00, 0xC0, 0x27, 0x60, 0x4C, 0x20, 0x48, 0x60, 0x68, 0xE0, 0x3F, // 103 + 0x00, 0x00, 0xFC, 0x0F, 0x40, 0x00, 0x20, 0x00, 0x20, 0x00, 0xE0, 0x0F, // 104 + 0x00, 0x00, 0x20, 0x08, 0x20, 0x08, 0xE8, 0x0F, 0xE8, 0x0F, 0x00, 0x08, // 105 + 0x00, 0x00, 0x00, 0x40, 0x20, 0x40, 0x28, 0x60, 0xE8, 0x3F, // 106 + 0x00, 0x00, 0xFC, 0x0F, 0x00, 0x03, 0xC0, 0x03, 0x60, 0x06, 0x20, 0x0C, 0x00, 0x08, // 107 + 0x00, 0x00, 0x04, 0x08, 0x04, 0x08, 0xFC, 0x0F, 0xFC, 0x0F, 0x00, 0x08, 0x00, 0x08, // 108 + 0xE0, 0x0F, 0xE0, 0x0F, 0x20, 0x00, 0xE0, 0x0F, 0x20, 0x00, 0xE0, 0x0F, 0xC0, 0x0F, // 109 + 0x00, 0x00, 0xE0, 0x0F, 0x40, 0x00, 0x20, 0x00, 0x20, 0x00, 0xE0, 0x0F, // 110 + 0x00, 0x00, 0xC0, 0x07, 0x60, 0x0C, 0x20, 0x08, 0x60, 0x0C, 0xC0, 0x07, 0x00, 0x01, // 111 + 0x00, 0x00, 0xE0, 0x7F, 0x40, 0x04, 0x20, 0x08, 0x60, 0x0C, 0xC0, 0x07, // 112 + 0x00, 0x00, 0xC0, 0x07, 0x60, 0x0C, 0x20, 0x08, 0x60, 0x0C, 0xE0, 0x7F, // 113 + 0x00, 0x00, 0x00, 0x00, 0xE0, 0x0F, 0x40, 0x00, 0x20, 0x00, 0x20, // 114 + 0x00, 0x00, 0xC0, 0x04, 0xE0, 0x0D, 0x20, 0x09, 0x20, 0x09, 0x40, 0x0E, // 115 + 0x00, 0x00, 0x20, 0x00, 0xF8, 0x07, 0xF8, 0x0F, 0x20, 0x08, 0x20, 0x08, // 116 + 0x00, 0x00, 0xE0, 0x07, 0x00, 0x0C, 0x00, 0x08, 0x00, 0x0C, 0xE0, 0x0F, // 117 + 0x20, 0x00, 0xE0, 0x00, 0x80, 0x07, 0x00, 0x0C, 0x80, 0x07, 0xE0, 0x00, 0x20, // 118 + 0x60, 0x00, 0xE0, 0x0F, 0x00, 0x0F, 0xE0, 0x00, 0x80, 0x0F, 0x80, 0x0F, 0xE0, // 119 + 0x00, 0x00, 0x20, 0x08, 0xE0, 0x06, 0x80, 0x03, 0xC0, 0x07, 0x60, 0x0C, 0x20, 0x08, // 120 + 0x20, 0x00, 0xE0, 0x40, 0x80, 0x63, 0x00, 0x3C, 0x00, 0x07, 0xE0, 0x01, 0x20, // 121 + 0x00, 0x00, 0x20, 0x0C, 0x20, 0x0E, 0xA0, 0x0B, 0xE0, 0x08, 0x60, 0x08, 0x00, 0x08, // 122 + 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0xF0, 0x0F, 0x7C, 0x3E, 0x04, 0x20, // 123 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0x7F, // 124 + 0x00, 0x00, 0x00, 0x00, 0x04, 0x20, 0x7C, 0x3F, 0xC0, 0x01, 0x80, // 125 + 0x00, 0x01, 0x80, 0x00, 0x80, 0x00, 0x80, 0x01, 0x00, 0x01, 0x00, 0x01, 0x80, // 126 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x7E, 0x20, // 161 + 0x00, 0x00, 0x80, 0x07, 0xC0, 0x0C, 0x70, 0x38, 0x40, 0x08, 0xC0, 0x0C, // 162 + 0x00, 0x00, 0x80, 0x0C, 0xF8, 0x0F, 0x88, 0x08, 0x88, 0x08, 0x18, 0x08, 0x10, 0x08, // 163 + 0x00, 0x00, 0xE0, 0x0F, 0x60, 0x0C, 0x20, 0x08, 0x20, 0x08, 0xE0, 0x0F, 0x20, 0x09, // 164 + 0x08, 0x00, 0x98, 0x02, 0xE0, 0x02, 0x80, 0x0F, 0xE0, 0x02, 0xB8, 0x02, 0x08, // 165 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0x3E, // 166 + 0x00, 0x10, 0xF0, 0x37, 0xD8, 0x44, 0x88, 0x44, 0x88, 0x4C, 0xB8, 0x7F, 0x20, 0x13, // 167 + 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x08, // 168 + 0x00, 0x00, 0xC0, 0x07, 0xA0, 0x0B, 0x60, 0x0C, 0xE0, 0x0E, 0x40, 0x04, 0x80, 0x03, // 169 + 0x00, 0x00, 0x00, 0x00, 0xF8, 0x00, 0xA8, 0x00, 0xF8, 0x00, 0x80, // 170 + 0x00, 0x00, 0x00, 0x01, 0x80, 0x03, 0x40, 0x05, 0x80, 0x03, 0x40, 0x04, // 171 + 0x00, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x03, // 172 + 0x00, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, // 173 + 0x00, 0x00, 0xC0, 0x07, 0xE0, 0x0B, 0x60, 0x09, 0xE0, 0x0B, 0x40, 0x04, 0x80, 0x03, // 174 + 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x08, 0x00, 0x08, 0x00, 0x08, // 175 + 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x28, 0x00, 0x38, // 176 + 0x00, 0x00, 0x40, 0x08, 0x40, 0x08, 0xF0, 0x0B, 0x40, 0x08, 0x40, 0x08, // 177 + 0x00, 0x00, 0x00, 0x00, 0x98, 0x00, 0xC8, 0x00, 0xB8, // 178 + 0x00, 0x00, 0x00, 0x00, 0x98, 0x00, 0xA8, 0x00, 0xF8, // 179 + 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x08, 0x00, 0x08, // 180 + 0x00, 0x00, 0xE0, 0x7F, 0x00, 0x0C, 0x00, 0x08, 0x00, 0x08, 0xE0, 0x0F, // 181 + 0x00, 0x00, 0x60, 0x00, 0xF8, 0x01, 0xF8, 0x01, 0xF8, 0x01, 0xF8, 0x0F, // 182 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x80, // 183 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x00, 0x20, // 184 + 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0xF8, 0x00, 0xF8, // 185 + 0x00, 0x00, 0x00, 0x00, 0xF8, 0x00, 0x88, 0x00, 0xD8, 0x00, 0x70, // 186 + 0x00, 0x00, 0x40, 0x04, 0xC0, 0x06, 0x40, 0x05, 0xC0, 0x06, 0x00, 0x01, // 187 + 0x10, 0x00, 0xF0, 0x00, 0x00, 0x06, 0x80, 0x01, 0x60, 0x06, 0x80, 0x0F, 0x00, 0x04, // 188 + 0x10, 0x00, 0xF0, 0x00, 0x00, 0x06, 0x80, 0x01, 0x60, 0x0D, 0x80, 0x0D, 0x00, 0x0B, // 189 + 0x00, 0x00, 0x90, 0x00, 0xA8, 0x06, 0xD0, 0x01, 0x60, 0x06, 0x80, 0x0F, 0x00, 0x04, // 190 + 0x00, 0x00, 0x00, 0x38, 0x00, 0x7E, 0x20, 0x43, 0x20, 0x60, 0x00, 0x30, // 191 + 0x00, 0x08, 0x02, 0x0F, 0xE2, 0x03, 0x3A, 0x02, 0xF0, 0x02, 0x80, 0x0F, 0x00, 0x0C, // 192 + 0x00, 0x08, 0x00, 0x0F, 0xE0, 0x03, 0x3C, 0x02, 0xF2, 0x02, 0x82, 0x0F, 0x00, 0x0C, // 193 + 0x00, 0x08, 0x00, 0x0F, 0xE2, 0x03, 0x39, 0x02, 0xF1, 0x02, 0x82, 0x0F, 0x00, 0x0C, // 194 + 0x00, 0x08, 0x00, 0x0F, 0xE3, 0x03, 0x39, 0x02, 0xF2, 0x02, 0x83, 0x0F, 0x00, 0x0C, // 195 + 0x00, 0x08, 0x00, 0x0F, 0xE2, 0x03, 0x38, 0x02, 0xF2, 0x02, 0x82, 0x0F, 0x00, 0x0C, // 196 + 0x00, 0x08, 0x00, 0x0F, 0xE2, 0x03, 0x3D, 0x02, 0xF7, 0x02, 0x80, 0x0F, 0x00, 0x0C, // 197 + 0x00, 0x08, 0x00, 0x0F, 0xE0, 0x03, 0x38, 0x02, 0xF8, 0x0F, 0x88, 0x08, 0x88, 0x08, // 198 + 0x00, 0x00, 0xF0, 0x07, 0x18, 0x0C, 0x08, 0x58, 0x08, 0x28, 0x30, 0x06, 0x20, 0x02, // 199 + 0x00, 0x00, 0xFA, 0x0F, 0x8A, 0x08, 0x8A, 0x08, 0x88, 0x08, 0x88, 0x08, // 200 + 0x00, 0x00, 0xF8, 0x0F, 0x88, 0x08, 0x8C, 0x08, 0x8A, 0x08, 0x8A, 0x08, // 201 + 0x00, 0x00, 0xF8, 0x0F, 0x8A, 0x08, 0x89, 0x08, 0x89, 0x08, 0x8A, 0x08, // 202 + 0x00, 0x00, 0xF8, 0x0F, 0x8A, 0x08, 0x88, 0x08, 0x8A, 0x08, 0x8A, 0x08, // 203 + 0x00, 0x00, 0x0A, 0x08, 0x0A, 0x08, 0xFA, 0x0F, 0x08, 0x08, 0x08, 0x08, // 204 + 0x00, 0x00, 0x08, 0x08, 0x08, 0x08, 0xFC, 0x0F, 0x0A, 0x08, 0x0A, 0x08, // 205 + 0x00, 0x00, 0x08, 0x08, 0x0A, 0x08, 0xF9, 0x0F, 0x09, 0x08, 0x0A, 0x08, // 206 + 0x00, 0x00, 0x08, 0x08, 0x0A, 0x08, 0xF8, 0x0F, 0x0A, 0x08, 0x0A, 0x08, // 207 + 0x80, 0x00, 0xF8, 0x0F, 0x88, 0x08, 0x88, 0x08, 0x18, 0x0C, 0xF0, 0x07, 0xE0, 0x03, // 208 + 0x00, 0x00, 0xF8, 0x0F, 0x73, 0x00, 0xC1, 0x01, 0x02, 0x07, 0xFB, 0x0F, // 209 + 0x00, 0x00, 0xF2, 0x07, 0x1A, 0x0C, 0x0A, 0x08, 0x18, 0x0C, 0xF0, 0x07, 0xC0, 0x01, // 210 + 0x00, 0x00, 0xF0, 0x07, 0x18, 0x0C, 0x0C, 0x08, 0x1A, 0x0C, 0xF2, 0x07, 0xC0, 0x01, // 211 + 0x00, 0x00, 0xF0, 0x07, 0x1A, 0x0C, 0x09, 0x08, 0x19, 0x0C, 0xF2, 0x07, 0xC0, 0x01, // 212 + 0x00, 0x00, 0xF0, 0x07, 0x1B, 0x0C, 0x09, 0x08, 0x1A, 0x0C, 0xF3, 0x07, 0xC0, 0x01, // 213 + 0x00, 0x00, 0xF0, 0x07, 0x1A, 0x0C, 0x08, 0x08, 0x1A, 0x0C, 0xF2, 0x07, 0xC0, 0x01, // 214 + 0x00, 0x00, 0x60, 0x06, 0xC0, 0x03, 0x80, 0x01, 0xC0, 0x03, 0x60, 0x06, // 215 + 0x00, 0x08, 0xF0, 0x0F, 0x18, 0x0E, 0x88, 0x09, 0x78, 0x0C, 0xF8, 0x07, 0xC4, 0x01, // 216 + 0x00, 0x00, 0xFA, 0x07, 0x02, 0x0C, 0x02, 0x08, 0x00, 0x0C, 0xF8, 0x07, // 217 + 0x00, 0x00, 0xF8, 0x07, 0x00, 0x0C, 0x04, 0x08, 0x02, 0x0C, 0xFA, 0x07, // 218 + 0x00, 0x00, 0xF8, 0x07, 0x02, 0x0C, 0x01, 0x08, 0x01, 0x0C, 0xFA, 0x07, // 219 + 0x00, 0x00, 0xF8, 0x07, 0x02, 0x0C, 0x00, 0x08, 0x02, 0x0C, 0xFA, 0x07, // 220 + 0x08, 0x00, 0x38, 0x00, 0xE0, 0x00, 0x84, 0x0F, 0xE2, 0x00, 0x3A, 0x00, 0x08, // 221 + 0x00, 0x00, 0xF8, 0x0F, 0x20, 0x02, 0x20, 0x02, 0x20, 0x02, 0xE0, 0x03, 0xC0, 0x01, // 222 + 0x00, 0x00, 0xF8, 0x0F, 0x0C, 0x00, 0x04, 0x0C, 0xFC, 0x08, 0x18, 0x0F, 0x00, 0x06, // 223 + 0x00, 0x00, 0x48, 0x0E, 0x68, 0x09, 0x28, 0x09, 0x60, 0x05, 0xC0, 0x0F, // 224 + 0x00, 0x00, 0x40, 0x0E, 0x60, 0x09, 0x30, 0x09, 0x68, 0x05, 0xC8, 0x0F, // 225 + 0x00, 0x00, 0x40, 0x0E, 0x68, 0x09, 0x24, 0x09, 0x64, 0x05, 0xC8, 0x0F, // 226 + 0x00, 0x00, 0x40, 0x0E, 0x6C, 0x09, 0x24, 0x09, 0x68, 0x05, 0xCC, 0x0F, // 227 + 0x00, 0x00, 0x40, 0x0E, 0x68, 0x09, 0x20, 0x09, 0x68, 0x05, 0xC8, 0x0F, // 228 + 0x00, 0x00, 0x40, 0x0E, 0x68, 0x09, 0x34, 0x09, 0x7C, 0x05, 0xC0, 0x0F, // 229 + 0x40, 0x06, 0x60, 0x0F, 0x20, 0x09, 0xE0, 0x07, 0x20, 0x0D, 0x20, 0x09, 0xC0, 0x0D, // 230 + 0x00, 0x00, 0xC0, 0x07, 0x60, 0x0C, 0x20, 0x58, 0x20, 0x28, 0xC0, 0x04, // 231 + 0x00, 0x00, 0xC8, 0x07, 0x68, 0x0D, 0x28, 0x09, 0x20, 0x09, 0xC0, 0x0D, 0x00, 0x01, // 232 + 0x00, 0x00, 0xC0, 0x07, 0x60, 0x0D, 0x30, 0x09, 0x28, 0x09, 0xC8, 0x0D, 0x00, 0x01, // 233 + 0x00, 0x00, 0xC0, 0x07, 0x68, 0x0D, 0x24, 0x09, 0x24, 0x09, 0xC8, 0x0D, 0x00, 0x01, // 234 + 0x00, 0x00, 0xC0, 0x07, 0x68, 0x0D, 0x20, 0x09, 0x28, 0x09, 0xC8, 0x0D, 0x00, 0x01, // 235 + 0x00, 0x00, 0x28, 0x08, 0x28, 0x08, 0xE8, 0x0F, 0xE0, 0x0F, 0x00, 0x08, 0x00, 0x08, // 236 + 0x00, 0x00, 0x20, 0x08, 0x20, 0x08, 0xF0, 0x0F, 0xE8, 0x0F, 0x08, 0x08, 0x00, 0x08, // 237 + 0x00, 0x00, 0x20, 0x08, 0x28, 0x08, 0xE4, 0x0F, 0xE4, 0x0F, 0x08, 0x08, 0x00, 0x08, // 238 + 0x00, 0x00, 0x20, 0x08, 0x28, 0x08, 0xE0, 0x0F, 0xE8, 0x0F, 0x08, 0x08, 0x00, 0x08, // 239 + 0x00, 0x03, 0xC0, 0x07, 0x68, 0x08, 0x58, 0x08, 0x78, 0x0C, 0xE8, 0x07, // 240 + 0x00, 0x00, 0xE0, 0x0F, 0x4C, 0x00, 0x24, 0x00, 0x28, 0x00, 0xEC, 0x0F, // 241 + 0x00, 0x00, 0xC8, 0x07, 0x68, 0x0C, 0x28, 0x08, 0x60, 0x0C, 0xC0, 0x07, 0x00, 0x01, // 242 + 0x00, 0x00, 0xC0, 0x07, 0x60, 0x0C, 0x30, 0x08, 0x68, 0x0C, 0xC8, 0x07, 0x00, 0x01, // 243 + 0x00, 0x00, 0xC0, 0x07, 0x68, 0x0C, 0x24, 0x08, 0x64, 0x0C, 0xC8, 0x07, 0x00, 0x01, // 244 + 0x00, 0x00, 0xC0, 0x07, 0x6C, 0x0C, 0x24, 0x08, 0x68, 0x0C, 0xCC, 0x07, 0x00, 0x01, // 245 + 0x00, 0x00, 0xC0, 0x07, 0x68, 0x0C, 0x20, 0x08, 0x68, 0x0C, 0xC8, 0x07, 0x00, 0x01, // 246 + 0x00, 0x00, 0x80, 0x00, 0x80, 0x00, 0xA0, 0x04, 0x80, 0x00, 0x80, 0x00, 0x80, // 247 + 0x00, 0x00, 0xC0, 0x0F, 0x60, 0x0C, 0x20, 0x0B, 0xE0, 0x0C, 0xD0, 0x07, 0x00, 0x01, // 248 + 0x00, 0x00, 0xE8, 0x07, 0x08, 0x0C, 0x08, 0x08, 0x00, 0x0C, 0xE0, 0x0F, // 249 + 0x00, 0x00, 0xE0, 0x07, 0x00, 0x0C, 0x10, 0x08, 0x08, 0x0C, 0xE8, 0x0F, // 250 + 0x00, 0x00, 0xE0, 0x07, 0x08, 0x0C, 0x04, 0x08, 0x04, 0x0C, 0xE8, 0x0F, // 251 + 0x00, 0x00, 0xE0, 0x07, 0x08, 0x0C, 0x00, 0x08, 0x08, 0x0C, 0xE8, 0x0F, // 252 + 0x20, 0x00, 0xE0, 0x40, 0x80, 0x63, 0x10, 0x3C, 0x08, 0x07, 0xE8, 0x01, 0x20, // 253 + 0x00, 0x00, 0xFC, 0x7F, 0x40, 0x04, 0x20, 0x08, 0x60, 0x0C, 0xC0, 0x07, // 254 + 0x20, 0x00, 0xE0, 0x40, 0x88, 0x63, 0x00, 0x3C, 0x08, 0x07, 0xE8, 0x01, 0x20 // 255 +}; diff --git a/examples/Factory/utilities.h b/examples/Factory/utilities.h new file mode 100644 index 0000000..a14bdbf --- /dev/null +++ b/examples/Factory/utilities.h @@ -0,0 +1,683 @@ +/** + * @file utilities.h + * @author Lewis He (lewishe@outlook.com) + * @license MIT + * @copyright Copyright (c) 2024 ShenZhen XinYuan Electronic Technology Co., Ltd + * @date 2024-05-12 + * @last-update 2024-08-07 + */ +#pragma once + + +// Support board list , Macro definition below, select the board definition to be used + +// #define T3_V1_3_SX1276 +// #define T3_V1_3_SX1278 + +// #define T3_V1_6_SX1276 +// #define T3_V1_6_SX1278 + +// #define T3_V1_6_SX1276_TCXO +// #define T3_V3_0_SX1276_TCXO + +// #define T_BEAM_SX1262 +// #define T_BEAM_SX1276 +// #define T_BEAM_SX1278 +// #define T_BEAM_LR1121 + +// #define T_BEAM_S3_SUPREME_SX1262 +// #define T_BEAM_S3_SUPREME_LR1121 + +// #define T3_S3_V1_2_SX1262 +// #define T3_S3_V1_2_SX1276 +// #define T3_S3_V1_2_SX1278 +// #define T3_S3_V1_2_SX1280 +// #define T3_S3_V1_2_SX1280_PA +// #define T3_S3_V1_2_LR1121 + +// #define T_MOTION + +// #define T3_C6 + +// #define T_BEAM_S3_BPF + + +#define UNUSED_PIN (0) + +#if defined(T_BEAM_SX1262) || defined(T_BEAM_SX1276) || defined(T_BEAM_SX1278) || defined(T_BEAM_LR1121) + + +#if defined(T_BEAM_SX1262) +#ifndef USING_SX1262 +#define USING_SX1262 +#endif +#elif defined(T_BEAM_SX1276) +#ifndef USING_SX1276 +#define USING_SX1276 +#endif +#elif defined(T_BEAM_SX1278) +#ifndef USING_SX1278 +#define USING_SX1278 +#endif +#elif defined(T_BEAM_LR1121) +#ifndef USING_LR1121 +#define USING_LR1121 +#endif +#endif // T_BEAM_SX1262 + + +#define GPS_RX_PIN 34 +#define GPS_TX_PIN 12 +#define BUTTON_PIN 38 +#define BUTTON_PIN_MASK GPIO_SEL_38 +#define I2C_SDA 21 +#define I2C_SCL 22 +#define PMU_IRQ 35 + +#define RADIO_SCLK_PIN 5 +#define RADIO_MISO_PIN 19 +#define RADIO_MOSI_PIN 27 +#define RADIO_CS_PIN 18 +#define RADIO_DIO0_PIN 26 +#define RADIO_RST_PIN 23 +#define RADIO_DIO1_PIN 33 +// SX1276/78 +#define RADIO_DIO2_PIN 32 +// SX1262 +#define RADIO_BUSY_PIN 32 + +// LR1121 Only +#define RADIO_DIO9_PIN 33 + + +#define BOARD_LED 4 +#define LED_ON LOW +#define LED_OFF HIGH + +#define BUTTON_PIN 38 + +#define GPS_BAUD_RATE 9600 +#define HAS_GPS +#define HAS_DISPLAY //Optional, bring your own board, no OLED !! +#define HAS_PMU + +#define BOARD_VARIANT_NAME "T-Beam" +#define DISPLAY_MODEL_SSD_LIB SSD1306Wire + +#elif defined(T3_V1_3_SX1276) || defined(T3_V1_3_SX1278) + + +#if defined(T3_V1_3_SX1276) + +#ifndef USING_SX1276 +#define USING_SX1276 +#endif + +#elif defined(T3_V1_3_SX1278) + +#ifndef USING_SX1278 +#define USING_SX1278 +#endif + +#endif // T3_V1_3_SX1276 + + + +#define I2C_SDA 21 +#define I2C_SCL 22 +#define OLED_RST UNUSED_PIN + +#define RADIO_SCLK_PIN 5 +#define RADIO_MISO_PIN 19 +#define RADIO_MOSI_PIN 27 +#define RADIO_CS_PIN 18 +#define RADIO_DIO0_PIN 26 +#define RADIO_RST_PIN 14 +#define RADIO_DIO1_PIN 33 + +// SX1276/78 +#define RADIO_DIO2_PIN 32 +// SX1262 +#define RADIO_BUSY_PIN 32 + + +#define ADC_PIN 35 +#define HAS_DISPLAY +#define BOARD_VARIANT_NAME "T3 V1.3" + +#elif defined(T3_V1_6_SX1276) || defined(T3_V1_6_SX1278) + + +#if defined(T3_V1_6_SX1276) +#ifndef USING_SX1276 +#define USING_SX1276 +#endif +#elif defined(T3_V1_6_SX1278) +#ifndef USING_SX1278 +#define USING_SX1278 +#endif +#endif // T3_V1_6_SX1276 + +#define I2C_SDA 21 +#define I2C_SCL 22 +#define OLED_RST UNUSED_PIN + +#define RADIO_SCLK_PIN 5 +#define RADIO_MISO_PIN 19 +#define RADIO_MOSI_PIN 27 +#define RADIO_CS_PIN 18 +#define RADIO_DIO0_PIN 26 +#define RADIO_RST_PIN 23 +#define RADIO_DIO1_PIN 33 +// SX1276/78 +#define RADIO_DIO2_PIN 32 +// SX1262 +#define RADIO_BUSY_PIN 32 + +#define SDCARD_MOSI 15 +#define SDCARD_MISO 2 +#define SDCARD_SCLK 14 +#define SDCARD_CS 13 + +#define BOARD_LED 25 +#define LED_ON HIGH + +#define ADC_PIN 35 + +#define HAS_SDCARD +#define HAS_DISPLAY + +#define BOARD_VARIANT_NAME "T3 V1.6" + + +#elif defined(T3_V1_6_SX1276_TCXO) + +#ifndef USING_SX1276 +#define USING_SX1276 +#endif + +#define I2C_SDA 21 +#define I2C_SCL 22 +#define OLED_RST UNUSED_PIN + +#define RADIO_SCLK_PIN 5 +#define RADIO_MISO_PIN 19 +#define RADIO_MOSI_PIN 27 +#define RADIO_CS_PIN 18 +#define RADIO_DIO0_PIN 26 +#define RADIO_RST_PIN 23 +#define RADIO_DIO1_PIN -1//33 +/* +* In the T3 V1.6.1 TCXO version, Radio DIO1 is connected to Radio’s +* internal temperature-compensated crystal oscillator enable +* */ +// TCXO pin must be set to HIGH before enabling Radio +#define RADIO_TCXO_ENABLE 33 +#define RADIO_BUSY_PIN 32 + +#define SDCARD_MOSI 15 +#define SDCARD_MISO 2 +#define SDCARD_SCLK 14 +#define SDCARD_CS 13 + +#define BOARD_LED 25 +#define LED_ON HIGH + +#define ADC_PIN 35 + +#define HAS_SDCARD +#define HAS_DISPLAY + +#define BOARD_VARIANT_NAME "T3 V1.6 TCXO" + + + +#elif defined(T3_V3_0) + + +#define I2C_SDA 21 +#define I2C_SCL 22 +#define OLED_RST 4 + +#define RADIO_SCLK_PIN 5 +#define RADIO_MISO_PIN 19 +#define RADIO_MOSI_PIN 27 +#define RADIO_CS_PIN 18 +#define RADIO_RST_PIN 23 + +// TCXO pin must be set to HIGH before enabling Radio +#define RADIO_TCXO_ENABLE 12 //only sx1276 tcxo version +#define RADIO_BUSY_PIN 32 + + +#if defined(USING_SX1262) + +#define RADIO_DIO1_PIN 26 +#define RADIO_BUSY_PIN 32 + +#elif defined(USING_SX1276) || defined(USING_SX1278) +//!SX1276/78 module only + +#define RADIO_DIO0_PIN 26 +#define RADIO_DIO1_PIN 32 + +#elif defined(USING_LR1121) + +#define RADIO_DIO9_PIN 26 //LR1121 DIO9 +#define RADIO_BUSY_PIN 32 //LR1121 BUSY + +#endif + +#define SDCARD_MOSI 15 +#define SDCARD_MISO 2 +#define SDCARD_SCLK 14 +#define SDCARD_CS 13 + +#define BOARD_LED 25 +#define LED_ON HIGH + +#define ADC_PIN 35 + +#define HAS_SDCARD +#define HAS_DISPLAY + +#define BOARD_VARIANT_NAME "T3 V3.0" + +#define BUTTON_PIN 0 +#define ADC_PIN 35 + + +#elif defined(T3_S3_V1_2_SX1262) || defined(ARDUINO_LILYGO_T3S3_SX1262) || \ + defined(T3_S3_V1_2_SX1276) || defined(ARDUINO_LILYGO_T3S3_SX1276) || \ + defined(T3_S3_V1_2_SX1278) || defined(ARDUINO_LILYGO_T3S3_SX1278) || \ + defined(T3_S3_V1_2_SX1280) || defined(ARDUINO_LILYGO_T3S3_SX1280) || \ + defined(T3_S3_V1_2_SX1280_PA) || defined(ARDUINO_LILYGO_T3S3_SX1280PA) || \ + defined(T3_S3_V1_2_LR1121) || defined(ARDUINO_LILYGO_T3S3_LR1121) + + +#if defined(T3_S3_V1_2_SX1262) || defined(ARDUINO_LILYGO_T3S3_SX1262) +#ifndef USING_SX1262 +#define USING_SX1262 +#endif +#elif defined(T3_S3_V1_2_SX1276) || defined(ARDUINO_LILYGO_T3S3_SX1276) +#ifndef USING_SX1276 +#define USING_SX1276 +#endif +#elif defined(T3_S3_V1_2_SX1278) || defined(ARDUINO_LILYGO_T3S3_SX1278) +#ifndef USING_SX1278 +#define USING_SX1278 +#endif +#elif defined(T3_S3_V1_2_SX1280) || defined(ARDUINO_LILYGO_T3S3_SX1280) +#ifndef USING_SX1280 +#define USING_SX1280 +#endif +#elif defined(T3_S3_V1_2_SX1280_PA) || defined(ARDUINO_LILYGO_T3S3_SX1280PA) +#ifndef USING_SX1280PA +#define USING_SX1280PA +#endif +#elif defined(T3_S3_V1_2_LR1121) || defined(ARDUINO_LILYGO_T3S3_LR1121) +#ifndef USING_LR1121 +#define USING_LR1121 +#endif + +#endif // T3_S3_V1_2_SX1262 + + +#define I2C_SDA 18 +#define I2C_SCL 17 +#define OLED_RST UNUSED_PIN + +#define RADIO_SCLK_PIN 5 +#define RADIO_MISO_PIN 3 +#define RADIO_MOSI_PIN 6 +#define RADIO_CS_PIN 7 + +#define SDCARD_MOSI 11 +#define SDCARD_MISO 2 +#define SDCARD_SCLK 14 +#define SDCARD_CS 13 + +#define BOARD_LED 37 +#define LED_ON HIGH + +#define BUTTON_PIN 0 +#define ADC_PIN 1 + +#define RADIO_RST_PIN 8 + +#if defined(USING_SX1262) + +#define RADIO_DIO1_PIN 33 +#define RADIO_BUSY_PIN 34 + +#elif defined(USING_SX1276) || defined(USING_SX1278) +//!SX1276/78 module only +#define RADIO_BUSY_PIN 33 //DIO1 + +#define RADIO_DIO0_PIN 9 +#define RADIO_DIO1_PIN 33 +#define RADIO_DIO2_PIN 34 +#define RADIO_DIO3_PIN 21 +#define RADIO_DIO4_PIN 10 +#define RADIO_DIO5_PIN 36 + +#elif defined(USING_SX1280) + +#define RADIO_DIO1_PIN 9 //SX1280 DIO1 = IO9 +#define RADIO_BUSY_PIN 36 //SX1280 BUSY = IO36 + +#elif defined(USING_SX1280PA) + +#define RADIO_DIO1_PIN 9 //SX1280 DIO1 = IO9 +#define RADIO_BUSY_PIN 36 //SX1280 BUSY = IO36 +#define RADIO_RX_PIN 21 +#define RADIO_TX_PIN 10 + + +#elif defined(USING_LR1121) + +#define RADIO_DIO9_PIN 36 //LR1121 DIO9 = IO36 +#define RADIO_BUSY_PIN 34 //LR1121 BUSY = IO34 + +#endif + +#define BUTTON_PIN 0 + +#define HAS_SDCARD +#define HAS_DISPLAY + +#define BOARD_VARIANT_NAME "T3-S3-V1.X" + + +#elif defined(T_BEAM_S3_SUPREME_SX1262) || defined(T_BEAM_S3_SUPREME_LR1121) + +#ifndef T_BEAM_S3_SUPREME +#define T_BEAM_S3_SUPREME +#endif + +#if defined(T_BEAM_S3_SUPREME_SX1262) +#ifndef USING_SX1262 +#define USING_SX1262 +#endif +#elif defined(T_BEAM_S3_SUPREME_LR1121) +#ifndef USING_LR1121 +#define USING_LR1121 +#endif +#endif + +#define I2C_SDA (17) +#define I2C_SCL (18) + +#define I2C1_SDA (42) +#define I2C1_SCL (41) +#define PMU_IRQ (40) + +#define GPS_RX_PIN (9) +#define GPS_TX_PIN (8) +#define GPS_WAKEUP_PIN (7) +#define GPS_PPS_PIN (6) + +#define BUTTON_PIN (0) +#define BUTTON_PIN_MASK (GPIO_SEL_0) +#define BUTTON_COUNT (1) +#define BUTTON_ARRAY {BUTTON_PIN} + +#define RADIO_SCLK_PIN (12) +#define RADIO_MISO_PIN (13) +#define RADIO_MOSI_PIN (11) +#define RADIO_CS_PIN (10) +#define RADIO_DIO0_PIN (-1) +#define RADIO_RST_PIN (5) +#define RADIO_DIO1_PIN (1) +#define RADIO_BUSY_PIN (4) + +// LR1121 Version +#define RADIO_DIO9_PIN (1) + +#define SPI_MOSI (35) +#define SPI_SCK (36) +#define SPI_MISO (37) +#define SPI_CS (47) +#define IMU_CS (34) +#define IMU_INT (33) + +#define SDCARD_MOSI SPI_MOSI +#define SDCARD_MISO SPI_MISO +#define SDCARD_SCLK SPI_SCK +#define SDCARD_CS SPI_CS + +#define RTC_INT (14) + +#define GPS_BAUD_RATE (9600) + +#define HAS_SDCARD +#define HAS_GPS +#define HAS_DISPLAY +#define HAS_PMU + +#define __HAS_SPI1__ +#define HAS_SENSOR + +#define PMU_WIRE_PORT Wire1 +#define DISPLAY_MODEL U8G2_SH1106_128X64_NONAME_F_HW_I2C +#define DISPLAY_MODEL_SSD_LIB SH1106Wire +#define BOARD_VARIANT_NAME "T-Beam S3" + +#elif defined(T_MOTION_S76G) + +#ifndef USING_SX1276 +#define USING_SX1276 +#endif + + +#define RADIO_SCLK_PIN PB13 +#define RADIO_MISO_PIN PB14 +#define RADIO_MOSI_PIN PB15 +#define RADIO_CS_PIN PB12 +#define RADIO_RST_PIN PB10 + +#define RADIO_DIO0_PIN PB11 +#define RADIO_DIO1_PIN PC13 +#define RADIO_DIO2_PIN PB9 +#define RADIO_DIO3_PIN PB4 +#define RADIO_DIO4_PIN PB3 +#define RADIO_DIO5_PIN PA15 + +#undef RADIO_BUSY_PIN +#undef RADIO_DIO1_PIN +#define RADIO_BUSY_PIN PC13 //DIO1 +#define RADIO_DIO1_PIN PB11 //DIO0 + +#define RADIO_SWITCH_PIN PA1 //1:Rx, 0:Tx + +#define GPS_EN_PIN PC6 +#define GPS_RST_PIN PB2 +#define GPS_RX_PIN PC11 +#define GPS_TX_PIN PC10 +#define GPS_ENABLE_PIN PC6 +#define GPS_BAUD_RATE 115200 +#define GPS_PPS_PIN PB5 + +#define UART_RX_PIN PA10 +#define UART_TX_PIN PA9 + +#define I2C_SCL PB6 +#define I2C_SDA PB7 + +#define BOARD_VARIANT_NAME "T-Motion S76G" + +#define HAS_GPS + +#elif defined(T3_C6) + + +#ifndef USING_SX1262 +#define USING_SX1262 +#endif + + +#define RADIO_SCLK_PIN 6 +#define RADIO_MISO_PIN 1 +#define RADIO_MOSI_PIN 0 +#define RADIO_CS_PIN 18 +#define RADIO_DIO1_PIN 23 +#define RADIO_BUSY_PIN 22 +#define RADIO_RST_PIN 21 + +#define I2C_SDA 8 +#define I2C_SCL 9 + +#define BOARD_LED 7 +#define LED_ON HIGH +#define RADIO_RX_PIN 15 +#define RADIO_TX_PIN 14 + + +#define BOARD_VARIANT_NAME "T3-C6" + +#define USING_DIO2_AS_RF_SWITCH + + +#elif defined(T_BEAM_S3_BPF) + + +#ifndef USING_SX1278 +#define USING_SX1278 +#endif + +#define I2C_SDA 8 +#define I2C_SCL 9 + +#define PMU_IRQ 4 + +#define GPS_RX_PIN 5 +#define GPS_TX_PIN 6 +#define GPS_PPS_PIN 7 + +#define BUTTON_PIN 0 +#define BUTTON_PIN_MASK GPIO_SEL_0 /*BUTTON 1 = GPIO0*/ +#define BUTTON_COUNT (2) +#define BUTTON_ARRAY {BUTTON_PIN, 3 /*BUTTON 2 = GPIO3*/} + +#define RADIO_SCLK_PIN (41) +#define RADIO_MISO_PIN (42) +#define RADIO_MOSI_PIN (2) +#define RADIO_CS_PIN (1) +#define RADIO_RST_PIN (18) + +#define RADIO_DIO0_PIN (14) +#define RADIO_DIO1_PIN (21) +#define RADIO_DIO2_PIN (15) + +#define RADIO_TCXO_ENABLE (17) +#define RADIO_LDO_EN (16) +#define RADIO_BUSY_PIN (RADIO_DIO1_PIN) + +#define SPI_MOSI (11) +#define SPI_SCK (12) +#define SPI_MISO (13) +#define SPI_CS (10) + +#define SDCARD_MOSI SPI_MOSI +#define SDCARD_MISO SPI_MISO +#define SDCARD_SCLK SPI_SCK +#define SDCARD_CS SPI_CS + + +#define GPS_BAUD_RATE 9600 + +#define HAS_SDCARD +#define HAS_GPS +#define HAS_DISPLAY +#define HAS_PMU + +#define __HAS_SPI1__ +#define HAS_SENSOR + +#define PMU_WIRE_PORT Wire +#define DISPLAY_MODEL U8G2_SH1106_128X64_NONAME_F_HW_I2C +#define DISPLAY_MODEL_SSD_LIB SSD1306Wire +#define BOARD_VARIANT_NAME "T-Beam BPF" + + +#elif defined(T_BEAM_2W) + +#ifndef USING_SX1262 +#define USING_SX1262 +#endif + +#define I2C_SDA (8) +#define I2C_SCL (9) +#define GPS_RX_PIN (5) +#define GPS_TX_PIN (6) +#define GPS_PPS_PIN (7) + +#define BUTTON_PIN (0) /*BUTTON 1 = GPIO0*/ +#define BUTTON2_PIN (3) /*BUTTON 2 = GPIO3*/ + +#define BUTTON_PIN_MASK GPIO_SEL_0 +#define BUTTON_CONUT (2) +#define BUTTON_ARRAY {BUTTON_PIN,BUTTON2_PIN/*BUTTON 2 = GPIO3*/} + + +#define RADIO_SCLK_PIN (16) +#define RADIO_MISO_PIN (17) +#define RADIO_MOSI_PIN (18) +#define RADIO_CS_PIN (15) +#define RADIO_RST_PIN (3) +#define RADIO_LDO_EN (40) +#define RADIO_CTRL (21) + +#define RADIO_DIO1_PIN (1) +// #define RADIO_DIO3_PIN (2) + +#define RADIO_BUSY_PIN (38) + +#define SPI_MOSI (11) +#define SPI_SCK (13) +#define SPI_MISO (12) +#define SPI_CS (10) + +#define SDCARD_MOSI SPI_MOSI +#define SDCARD_MISO SPI_MISO +#define SDCARD_SCLK SPI_SCK +#define SDCARD_CS SPI_CS + + +#define NTC_PIN (14) +#define FAN_CTRL (41) +#define ADC_PIN (4) + +#define GPS_BAUD_RATE 9600 + +#define HAS_SDCARD +#define HAS_GPS +#define HAS_DISPLAY + +#define __HAS_SPI1__ + +#define DISPLAY_MODEL U8G2_SH1106_128X64_NONAME_F_HW_I2C +#define DISPLAY_MODEL_SSD_LIB SH1106Wire +#define BOARD_VARIANT_NAME "LoRa 2W" + +/* +* 2w LoRa max set power is +3 dBm ,After passing through PA, the power can reach 33dBm +* -3dBm = +27dBm +* 0 dBm = +30dBm +* 3 dBm = +33dBm +* */ +#define RADIO_MAX_OUTPUT_POWER 3 + + +#else +#error "When using it for the first time, please define the board model in " +#endif + + + + + + + + +