mirror of
https://github.com/meshcore-dev/MeshCore.git
synced 2026-04-20 22:13:47 +00:00
Merge remote-tracking branch 'upstream/dev' into jbrazio/2025_3f11ad35
This commit is contained in:
commit
7fca20475a
110 changed files with 2339 additions and 950 deletions
|
|
@ -85,8 +85,7 @@ public:
|
|||
}
|
||||
|
||||
void powerOff() override {
|
||||
// TODO: re-enable this when there is a definite wake-up source pin:
|
||||
// enterDeepSleep(0);
|
||||
enterDeepSleep(0);
|
||||
}
|
||||
|
||||
uint16_t getBattMilliVolts() override {
|
||||
|
|
|
|||
|
|
@ -9,7 +9,6 @@
|
|||
|
||||
using namespace Adafruit_LittleFS_Namespace;
|
||||
#endif
|
||||
|
||||
#include <Identity.h>
|
||||
|
||||
class IdentityStore {
|
||||
|
|
@ -18,7 +17,8 @@ class IdentityStore {
|
|||
public:
|
||||
IdentityStore(FILESYSTEM& fs, const char* dir): _fs(&fs), _dir(dir) { }
|
||||
|
||||
void begin() { if (_dir && _dir[0] == '/') { _fs->mkdir(_dir); } }
|
||||
void begin() {
|
||||
if (_dir && _dir[0] == '/') { _fs->mkdir(_dir); } }
|
||||
bool load(const char *name, mesh::LocalIdentity& id);
|
||||
bool load(const char *name, mesh::LocalIdentity& id, char display_name[], int max_name_sz);
|
||||
bool save(const char *name, const mesh::LocalIdentity& id);
|
||||
|
|
|
|||
|
|
@ -27,8 +27,8 @@ void SerialBLEInterface::begin(const char* device_name, uint32_t pin_code) {
|
|||
|
||||
Bluefruit.configPrphBandwidth(BANDWIDTH_MAX);
|
||||
Bluefruit.configPrphConn(250, BLE_GAP_EVENT_LENGTH_MIN, 16, 16); // increase MTU
|
||||
Bluefruit.setTxPower(BLE_TX_POWER);
|
||||
Bluefruit.begin();
|
||||
Bluefruit.setTxPower(4); // Check bluefruit.h for supported values
|
||||
Bluefruit.setName(device_name);
|
||||
|
||||
Bluefruit.Security.setMITM(true);
|
||||
|
|
@ -80,7 +80,7 @@ void SerialBLEInterface::startAdv() {
|
|||
* https://developer.apple.com/library/content/qa/qa1931/_index.html
|
||||
*/
|
||||
Bluefruit.Advertising.restartOnDisconnect(false); // don't restart automatically as we handle it in onDisconnect
|
||||
Bluefruit.Advertising.setInterval(32, 244); // in unit of 0.625 ms
|
||||
Bluefruit.Advertising.setInterval(32, 1600);
|
||||
Bluefruit.Advertising.setFastTimeout(30); // number of seconds in fast mode
|
||||
Bluefruit.Advertising.start(0); // 0 = Don't stop advertising after n seconds
|
||||
|
||||
|
|
|
|||
|
|
@ -3,6 +3,10 @@
|
|||
#include "../BaseSerialInterface.h"
|
||||
#include <bluefruit.h>
|
||||
|
||||
#ifndef BLE_TX_POWER
|
||||
#define BLE_TX_POWER 4
|
||||
#endif
|
||||
|
||||
class SerialBLEInterface : public BaseSerialInterface {
|
||||
BLEUart bleuart;
|
||||
bool _isEnabled;
|
||||
|
|
|
|||
|
|
@ -1,125 +0,0 @@
|
|||
#include <Arduino.h>
|
||||
#include "T114Board.h"
|
||||
|
||||
#include <bluefruit.h>
|
||||
#include <Wire.h>
|
||||
|
||||
static BLEDfu bledfu;
|
||||
|
||||
static void connect_callback(uint16_t conn_handle)
|
||||
{
|
||||
(void)conn_handle;
|
||||
MESH_DEBUG_PRINTLN("BLE client connected");
|
||||
}
|
||||
|
||||
static void disconnect_callback(uint16_t conn_handle, uint8_t reason)
|
||||
{
|
||||
(void)conn_handle;
|
||||
(void)reason;
|
||||
|
||||
MESH_DEBUG_PRINTLN("BLE client disconnected");
|
||||
}
|
||||
|
||||
void T114Board::begin() {
|
||||
// for future use, sub-classes SHOULD call this from their begin()
|
||||
startup_reason = BD_STARTUP_NORMAL;
|
||||
|
||||
pinMode(PIN_VBAT_READ, INPUT);
|
||||
|
||||
// Enable SoftDevice low-power mode
|
||||
sd_power_mode_set(NRF_POWER_MODE_LOWPWR);
|
||||
|
||||
// Enable DC/DC converter for better efficiency (REG1 stage)
|
||||
NRF_POWER->DCDCEN = 1;
|
||||
|
||||
// Power down unused communication peripherals
|
||||
// UART1 - Not used on T114
|
||||
NRF_UARTE1->ENABLE = 0;
|
||||
|
||||
// SPIM2/SPIS2 - Not used (SPI is on SPIM0)
|
||||
NRF_SPIM2->ENABLE = 0;
|
||||
NRF_SPIS2->ENABLE = 0;
|
||||
|
||||
// TWI1 (I2C1) - Not used (I2C is on TWI0)
|
||||
NRF_TWIM1->ENABLE = 0;
|
||||
NRF_TWIS1->ENABLE = 0;
|
||||
|
||||
// PWM modules - Not used for standard T114 functions
|
||||
NRF_PWM1->ENABLE = 0;
|
||||
NRF_PWM2->ENABLE = 0;
|
||||
NRF_PWM3->ENABLE = 0;
|
||||
|
||||
// PDM (Digital Microphone Interface) - Not used
|
||||
NRF_PDM->ENABLE = 0;
|
||||
|
||||
// I2S - Not used
|
||||
NRF_I2S->ENABLE = 0;
|
||||
|
||||
// QSPI - Not used (no external flash)
|
||||
NRF_QSPI->ENABLE = 0;
|
||||
|
||||
// Disable unused analog peripherals
|
||||
// SAADC channels - only keep what's needed for battery monitoring
|
||||
NRF_SAADC->ENABLE = 0; // Re-enable only when needed for measurements
|
||||
|
||||
// COMP - Comparator not used
|
||||
NRF_COMP->ENABLE = 0;
|
||||
|
||||
#if defined(PIN_BOARD_SDA) && defined(PIN_BOARD_SCL)
|
||||
Wire.setPins(PIN_BOARD_SDA, PIN_BOARD_SCL);
|
||||
#endif
|
||||
|
||||
Wire.begin();
|
||||
|
||||
#ifdef P_LORA_TX_LED
|
||||
pinMode(P_LORA_TX_LED, OUTPUT);
|
||||
digitalWrite(P_LORA_TX_LED, HIGH);
|
||||
#endif
|
||||
|
||||
pinMode(SX126X_POWER_EN, OUTPUT);
|
||||
digitalWrite(SX126X_POWER_EN, HIGH);
|
||||
delay(10); // give sx1262 some time to power up
|
||||
}
|
||||
|
||||
bool T114Board::startOTAUpdate(const char* id, char reply[]) {
|
||||
// Config the peripheral connection with maximum bandwidth
|
||||
// more SRAM required by SoftDevice
|
||||
// Note: All config***() function must be called before begin()
|
||||
Bluefruit.configPrphBandwidth(BANDWIDTH_MAX);
|
||||
Bluefruit.configPrphConn(92, BLE_GAP_EVENT_LENGTH_MIN, 16, 16);
|
||||
|
||||
Bluefruit.begin(1, 0);
|
||||
// Set max power. Accepted values are: -40, -30, -20, -16, -12, -8, -4, 0, 4
|
||||
Bluefruit.setTxPower(4);
|
||||
// Set the BLE device name
|
||||
Bluefruit.setName("T114_OTA");
|
||||
|
||||
Bluefruit.Periph.setConnectCallback(connect_callback);
|
||||
Bluefruit.Periph.setDisconnectCallback(disconnect_callback);
|
||||
|
||||
// To be consistent OTA DFU should be added first if it exists
|
||||
bledfu.begin();
|
||||
|
||||
// Set up and start advertising
|
||||
// Advertising packet
|
||||
Bluefruit.Advertising.addFlags(BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE);
|
||||
Bluefruit.Advertising.addTxPower();
|
||||
Bluefruit.Advertising.addName();
|
||||
|
||||
/* Start Advertising
|
||||
- Enable auto advertising if disconnected
|
||||
- Interval: fast mode = 20 ms, slow mode = 152.5 ms
|
||||
- Timeout for fast mode is 30 seconds
|
||||
- Start(timeout) with timeout = 0 will advertise forever (until connected)
|
||||
|
||||
For recommended advertising interval
|
||||
https://developer.apple.com/library/content/qa/qa1931/_index.html
|
||||
*/
|
||||
Bluefruit.Advertising.restartOnDisconnect(true);
|
||||
Bluefruit.Advertising.setInterval(32, 244); // in unit of 0.625 ms
|
||||
Bluefruit.Advertising.setFastTimeout(30); // number of seconds in fast mode
|
||||
Bluefruit.Advertising.start(0); // 0 = Don't stop advertising after n seconds
|
||||
|
||||
strcpy(reply, "OK - started");
|
||||
return true;
|
||||
}
|
||||
|
|
@ -1,73 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <MeshCore.h>
|
||||
#include <Arduino.h>
|
||||
|
||||
// LoRa radio module pins for Heltec T114
|
||||
#define P_LORA_DIO_1 20
|
||||
#define P_LORA_NSS 24
|
||||
#define P_LORA_RESET 25
|
||||
#define P_LORA_BUSY 17
|
||||
#define P_LORA_SCLK 19
|
||||
#define P_LORA_MISO 23
|
||||
#define P_LORA_MOSI 22
|
||||
#define SX126X_POWER_EN 37
|
||||
|
||||
#define SX126X_DIO2_AS_RF_SWITCH true
|
||||
#define SX126X_DIO3_TCXO_VOLTAGE 1.8
|
||||
|
||||
// built-ins
|
||||
#define PIN_VBAT_READ 4
|
||||
#define PIN_BAT_CTL 6
|
||||
#define MV_LSB (3000.0F / 4096.0F) // 12-bit ADC with 3.0V input range
|
||||
|
||||
class T114Board : public mesh::MainBoard {
|
||||
protected:
|
||||
uint8_t startup_reason;
|
||||
|
||||
public:
|
||||
void begin();
|
||||
uint8_t getStartupReason() const override { return startup_reason; }
|
||||
|
||||
#if defined(P_LORA_TX_LED)
|
||||
void onBeforeTransmit() override {
|
||||
digitalWrite(P_LORA_TX_LED, LOW); // turn TX LED on
|
||||
}
|
||||
void onAfterTransmit() override {
|
||||
digitalWrite(P_LORA_TX_LED, HIGH); // turn TX LED off
|
||||
}
|
||||
#endif
|
||||
|
||||
uint16_t getBattMilliVolts() override {
|
||||
int adcvalue = 0;
|
||||
|
||||
NRF_SAADC->ENABLE = 1;
|
||||
|
||||
analogReadResolution(12);
|
||||
analogReference(AR_INTERNAL_3_0);
|
||||
pinMode(PIN_BAT_CTL, OUTPUT); // battery adc can be read only ctrl pin 6 set to high
|
||||
digitalWrite(PIN_BAT_CTL, 1);
|
||||
|
||||
delay(10);
|
||||
adcvalue = analogRead(PIN_VBAT_READ);
|
||||
digitalWrite(6, 0);
|
||||
|
||||
NRF_SAADC->ENABLE = 0;
|
||||
|
||||
return (uint16_t)((float)adcvalue * MV_LSB * 4.9);
|
||||
}
|
||||
|
||||
const char* getManufacturerName() const override {
|
||||
return "Heltec T114";
|
||||
}
|
||||
|
||||
void reboot() override {
|
||||
NVIC_SystemReset();
|
||||
}
|
||||
|
||||
void powerOff() override {
|
||||
sd_power_system_off();
|
||||
}
|
||||
|
||||
bool startOTAUpdate(const char* id, char reply[]) override;
|
||||
};
|
||||
|
|
@ -1,90 +0,0 @@
|
|||
#include <Arduino.h>
|
||||
#include "TechoBoard.h"
|
||||
|
||||
#ifdef LILYGO_TECHO
|
||||
|
||||
#include <bluefruit.h>
|
||||
#include <Wire.h>
|
||||
|
||||
static BLEDfu bledfu;
|
||||
|
||||
static void connect_callback(uint16_t conn_handle) {
|
||||
(void)conn_handle;
|
||||
MESH_DEBUG_PRINTLN("BLE client connected");
|
||||
}
|
||||
|
||||
static void disconnect_callback(uint16_t conn_handle, uint8_t reason) {
|
||||
(void)conn_handle;
|
||||
(void)reason;
|
||||
|
||||
MESH_DEBUG_PRINTLN("BLE client disconnected");
|
||||
}
|
||||
|
||||
void TechoBoard::begin() {
|
||||
// for future use, sub-classes SHOULD call this from their begin()
|
||||
startup_reason = BD_STARTUP_NORMAL;
|
||||
|
||||
Wire.begin();
|
||||
|
||||
pinMode(SX126X_POWER_EN, OUTPUT);
|
||||
digitalWrite(SX126X_POWER_EN, HIGH);
|
||||
delay(10); // give sx1262 some time to power up
|
||||
}
|
||||
|
||||
uint16_t TechoBoard::getBattMilliVolts() {
|
||||
int adcvalue = 0;
|
||||
|
||||
analogReference(AR_INTERNAL_3_0);
|
||||
analogReadResolution(12);
|
||||
delay(10);
|
||||
|
||||
// ADC range is 0..3000mV and resolution is 12-bit (0..4095)
|
||||
adcvalue = analogRead(PIN_VBAT_READ);
|
||||
// Convert the raw value to compensated mv, taking the resistor-
|
||||
// divider into account (providing the actual LIPO voltage)
|
||||
return (uint16_t)((float)adcvalue * REAL_VBAT_MV_PER_LSB);
|
||||
}
|
||||
|
||||
bool TechoBoard::startOTAUpdate(const char* id, char reply[]) {
|
||||
// Config the peripheral connection with maximum bandwidth
|
||||
// more SRAM required by SoftDevice
|
||||
// Note: All config***() function must be called before begin()
|
||||
Bluefruit.configPrphBandwidth(BANDWIDTH_MAX);
|
||||
Bluefruit.configPrphConn(92, BLE_GAP_EVENT_LENGTH_MIN, 16, 16);
|
||||
|
||||
Bluefruit.begin(1, 0);
|
||||
// Set max power. Accepted values are: -40, -30, -20, -16, -12, -8, -4, 0, 4
|
||||
Bluefruit.setTxPower(4);
|
||||
// Set the BLE device name
|
||||
Bluefruit.setName("TECHO_OTA");
|
||||
|
||||
Bluefruit.Periph.setConnectCallback(connect_callback);
|
||||
Bluefruit.Periph.setDisconnectCallback(disconnect_callback);
|
||||
|
||||
// To be consistent OTA DFU should be added first if it exists
|
||||
bledfu.begin();
|
||||
|
||||
// Set up and start advertising
|
||||
// Advertising packet
|
||||
Bluefruit.Advertising.addFlags(BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE);
|
||||
Bluefruit.Advertising.addTxPower();
|
||||
Bluefruit.Advertising.addName();
|
||||
|
||||
/* Start Advertising
|
||||
- Enable auto advertising if disconnected
|
||||
- Interval: fast mode = 20 ms, slow mode = 152.5 ms
|
||||
- Timeout for fast mode is 30 seconds
|
||||
- Start(timeout) with timeout = 0 will advertise forever (until connected)
|
||||
|
||||
For recommended advertising interval
|
||||
https://developer.apple.com/library/content/qa/qa1931/_index.html
|
||||
*/
|
||||
Bluefruit.Advertising.restartOnDisconnect(true);
|
||||
Bluefruit.Advertising.setInterval(32, 244); // in unit of 0.625 ms
|
||||
Bluefruit.Advertising.setFastTimeout(30); // number of seconds in fast mode
|
||||
Bluefruit.Advertising.start(0); // 0 = Don't stop advertising after n seconds
|
||||
|
||||
strcpy(reply, "OK - started");
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
|
@ -1,68 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <MeshCore.h>
|
||||
#include <Arduino.h>
|
||||
|
||||
// LoRa radio module pins for LilyGo T-Echo
|
||||
#define P_LORA_DIO_1 20
|
||||
#define P_LORA_NSS 24
|
||||
#define P_LORA_RESET 25
|
||||
#define P_LORA_BUSY 17
|
||||
#define P_LORA_SCLK 19
|
||||
#define P_LORA_MISO 23
|
||||
#define P_LORA_MOSI 22
|
||||
#define SX126X_POWER_EN 37
|
||||
|
||||
#define SX126X_DIO2_AS_RF_SWITCH true
|
||||
#define SX126X_DIO3_TCXO_VOLTAGE 1.8
|
||||
|
||||
// built-ins
|
||||
#define VBAT_MV_PER_LSB (0.73242188F) // 3.0V ADC range and 12-bit ADC resolution = 3000mV/4096
|
||||
|
||||
#define VBAT_DIVIDER (0.5F) // 150K + 150K voltage divider on VBAT
|
||||
#define VBAT_DIVIDER_COMP (2.0F) // Compensation factor for the VBAT divider
|
||||
|
||||
#define PIN_VBAT_READ (4)
|
||||
#define REAL_VBAT_MV_PER_LSB (VBAT_DIVIDER_COMP * VBAT_MV_PER_LSB)
|
||||
|
||||
class TechoBoard : public mesh::MainBoard {
|
||||
protected:
|
||||
uint8_t startup_reason;
|
||||
|
||||
public:
|
||||
|
||||
void begin();
|
||||
uint16_t getBattMilliVolts() override;
|
||||
bool startOTAUpdate(const char* id, char reply[]) override;
|
||||
|
||||
uint8_t getStartupReason() const override {
|
||||
return startup_reason;
|
||||
}
|
||||
|
||||
const char* getManufacturerName() const override {
|
||||
return "LilyGo T-Echo";
|
||||
}
|
||||
|
||||
void powerOff() override {
|
||||
#ifdef LED_RED
|
||||
digitalWrite(LED_RED, LOW);
|
||||
#endif
|
||||
#ifdef LED_GREEN
|
||||
digitalWrite(LED_GREEN, LOW);
|
||||
#endif
|
||||
#ifdef LED_BLUE
|
||||
digitalWrite(LED_BLUE, LOW);
|
||||
#endif
|
||||
#ifdef DISP_BACKLIGHT
|
||||
digitalWrite(DISP_BACKLIGHT, LOW);
|
||||
#endif
|
||||
#ifdef PIN_PWR_EN
|
||||
digitalWrite(PIN_PWR_EN, LOW);
|
||||
#endif
|
||||
sd_power_system_off();
|
||||
}
|
||||
|
||||
void reboot() override {
|
||||
NVIC_SystemReset();
|
||||
}
|
||||
};
|
||||
|
|
@ -1,95 +0,0 @@
|
|||
#include <Arduino.h>
|
||||
#include "ThinkNodeM1Board.h"
|
||||
|
||||
#ifdef THINKNODE_M1
|
||||
|
||||
#include <bluefruit.h>
|
||||
#include <Wire.h>
|
||||
|
||||
static BLEDfu bledfu;
|
||||
|
||||
static void connect_callback(uint16_t conn_handle) {
|
||||
(void)conn_handle;
|
||||
MESH_DEBUG_PRINTLN("BLE client connected");
|
||||
}
|
||||
|
||||
static void disconnect_callback(uint16_t conn_handle, uint8_t reason) {
|
||||
(void)conn_handle;
|
||||
(void)reason;
|
||||
|
||||
MESH_DEBUG_PRINTLN("BLE client disconnected");
|
||||
}
|
||||
|
||||
void ThinkNodeM1Board::begin() {
|
||||
// for future use, sub-classes SHOULD call this from their begin()
|
||||
startup_reason = BD_STARTUP_NORMAL;
|
||||
|
||||
Wire.begin();
|
||||
|
||||
#ifdef P_LORA_TX_LED
|
||||
pinMode(P_LORA_TX_LED, OUTPUT);
|
||||
digitalWrite(P_LORA_TX_LED, LOW);
|
||||
#endif
|
||||
|
||||
pinMode(SX126X_POWER_EN, OUTPUT);
|
||||
digitalWrite(SX126X_POWER_EN, HIGH);
|
||||
delay(10); // give sx1262 some time to power up
|
||||
}
|
||||
|
||||
uint16_t ThinkNodeM1Board::getBattMilliVolts() {
|
||||
int adcvalue = 0;
|
||||
|
||||
analogReference(AR_INTERNAL_3_0);
|
||||
analogReadResolution(12);
|
||||
delay(10);
|
||||
|
||||
// ADC range is 0..3000mV and resolution is 12-bit (0..4095)
|
||||
adcvalue = analogRead(PIN_VBAT_READ);
|
||||
// Convert the raw value to compensated mv, taking the resistor-
|
||||
// divider into account (providing the actual LIPO voltage)
|
||||
return (uint16_t)((float)adcvalue * REAL_VBAT_MV_PER_LSB);
|
||||
}
|
||||
|
||||
bool ThinkNodeM1Board::startOTAUpdate(const char* id, char reply[]) {
|
||||
// Config the peripheral connection with maximum bandwidth
|
||||
// more SRAM required by SoftDevice
|
||||
// Note: All config***() function must be called before begin()
|
||||
Bluefruit.configPrphBandwidth(BANDWIDTH_MAX);
|
||||
Bluefruit.configPrphConn(92, BLE_GAP_EVENT_LENGTH_MIN, 16, 16);
|
||||
|
||||
Bluefruit.begin(1, 0);
|
||||
// Set max power. Accepted values are: -40, -30, -20, -16, -12, -8, -4, 0, 4
|
||||
Bluefruit.setTxPower(4);
|
||||
// Set the BLE device name
|
||||
Bluefruit.setName("THINKNODE_M1_OTA");
|
||||
|
||||
Bluefruit.Periph.setConnectCallback(connect_callback);
|
||||
Bluefruit.Periph.setDisconnectCallback(disconnect_callback);
|
||||
|
||||
// To be consistent OTA DFU should be added first if it exists
|
||||
bledfu.begin();
|
||||
|
||||
// Set up and start advertising
|
||||
// Advertising packet
|
||||
Bluefruit.Advertising.addFlags(BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE);
|
||||
Bluefruit.Advertising.addTxPower();
|
||||
Bluefruit.Advertising.addName();
|
||||
|
||||
/* Start Advertising
|
||||
- Enable auto advertising if disconnected
|
||||
- Interval: fast mode = 20 ms, slow mode = 152.5 ms
|
||||
- Timeout for fast mode is 30 seconds
|
||||
- Start(timeout) with timeout = 0 will advertise forever (until connected)
|
||||
|
||||
For recommended advertising interval
|
||||
https://developer.apple.com/library/content/qa/qa1931/_index.html
|
||||
*/
|
||||
Bluefruit.Advertising.restartOnDisconnect(true);
|
||||
Bluefruit.Advertising.setInterval(32, 244); // in unit of 0.625 ms
|
||||
Bluefruit.Advertising.setFastTimeout(30); // number of seconds in fast mode
|
||||
Bluefruit.Advertising.start(0); // 0 = Don't stop advertising after n seconds
|
||||
|
||||
strcpy(reply, "OK - started");
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
|
@ -1,70 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <MeshCore.h>
|
||||
#include <Arduino.h>
|
||||
|
||||
// LoRa radio module pins for Elecrow ThinkNode M1
|
||||
#define P_LORA_DIO_1 20
|
||||
#define P_LORA_NSS 24
|
||||
#define P_LORA_RESET 25
|
||||
#define P_LORA_BUSY 17
|
||||
#define P_LORA_SCLK 19
|
||||
#define P_LORA_MISO 23
|
||||
#define P_LORA_MOSI 22
|
||||
#define SX126X_POWER_EN 37
|
||||
|
||||
#define SX126X_DIO2_AS_RF_SWITCH true
|
||||
#define SX126X_DIO3_TCXO_VOLTAGE 1.8
|
||||
|
||||
// built-ins
|
||||
#define VBAT_MV_PER_LSB (0.73242188F) // 3.0V ADC range and 12-bit ADC resolution = 3000mV/4096
|
||||
|
||||
#define VBAT_DIVIDER (0.5F) // 150K + 150K voltage divider on VBAT
|
||||
#define VBAT_DIVIDER_COMP (2.0F) // Compensation factor for the VBAT divider
|
||||
|
||||
#define PIN_VBAT_READ (4)
|
||||
#define REAL_VBAT_MV_PER_LSB (VBAT_DIVIDER_COMP * VBAT_MV_PER_LSB)
|
||||
|
||||
class ThinkNodeM1Board : public mesh::MainBoard {
|
||||
protected:
|
||||
uint8_t startup_reason;
|
||||
|
||||
public:
|
||||
|
||||
void begin();
|
||||
uint16_t getBattMilliVolts() override;
|
||||
bool startOTAUpdate(const char* id, char reply[]) override;
|
||||
|
||||
uint8_t getStartupReason() const override {
|
||||
return startup_reason;
|
||||
}
|
||||
|
||||
#if defined(P_LORA_TX_LED)
|
||||
void onBeforeTransmit() override {
|
||||
digitalWrite(P_LORA_TX_LED, HIGH); // turn TX LED on
|
||||
}
|
||||
void onAfterTransmit() override {
|
||||
digitalWrite(P_LORA_TX_LED, LOW); // turn TX LED off
|
||||
}
|
||||
#endif
|
||||
|
||||
const char* getManufacturerName() const override {
|
||||
return "Elecrow ThinkNode-M1";
|
||||
}
|
||||
|
||||
void reboot() override {
|
||||
NVIC_SystemReset();
|
||||
}
|
||||
|
||||
void powerOff() override {
|
||||
|
||||
// turn off all leds, sd_power_system_off will not do this for us
|
||||
#ifdef P_LORA_TX_LED
|
||||
digitalWrite(P_LORA_TX_LED, LOW);
|
||||
#endif
|
||||
|
||||
// power off board
|
||||
sd_power_system_off();
|
||||
|
||||
}
|
||||
};
|
||||
|
|
@ -1,42 +0,0 @@
|
|||
#include <Arduino.h>
|
||||
#include "PicoWBoard.h"
|
||||
|
||||
//#include <bluefruit.h>
|
||||
#include <Wire.h>
|
||||
|
||||
//static BLEDfu bledfu;
|
||||
|
||||
static void connect_callback(uint16_t conn_handle) {
|
||||
(void)conn_handle;
|
||||
MESH_DEBUG_PRINTLN("BLE client connected");
|
||||
}
|
||||
|
||||
static void disconnect_callback(uint16_t conn_handle, uint8_t reason) {
|
||||
(void)conn_handle;
|
||||
(void)reason;
|
||||
|
||||
MESH_DEBUG_PRINTLN("BLE client disconnected");
|
||||
}
|
||||
|
||||
void PicoWBoard::begin() {
|
||||
// for future use, sub-classes SHOULD call this from their begin()
|
||||
startup_reason = BD_STARTUP_NORMAL;
|
||||
pinMode(PIN_VBAT_READ, INPUT);
|
||||
#ifdef PIN_USER_BTN
|
||||
pinMode(PIN_USER_BTN, INPUT_PULLUP);
|
||||
#endif
|
||||
|
||||
#if defined(PIN_BOARD_SDA) && defined(PIN_BOARD_SCL)
|
||||
Wire.setPins(PIN_BOARD_SDA, PIN_BOARD_SCL);
|
||||
#endif
|
||||
|
||||
Wire.begin();
|
||||
|
||||
//pinMode(SX126X_POWER_EN, OUTPUT);
|
||||
//digitalWrite(SX126X_POWER_EN, HIGH);
|
||||
delay(10); // give sx1262 some time to power up
|
||||
}
|
||||
|
||||
bool PicoWBoard::startOTAUpdate(const char* id, char reply[]) {
|
||||
return false;
|
||||
}
|
||||
|
|
@ -1,64 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <MeshCore.h>
|
||||
#include <Arduino.h>
|
||||
|
||||
// LoRa radio module pins for PicoW
|
||||
#define P_LORA_DIO_1 20
|
||||
#define P_LORA_NSS 3
|
||||
#define P_LORA_RESET 15
|
||||
#define P_LORA_BUSY 2
|
||||
#define P_LORA_SCLK 10
|
||||
#define P_LORA_MISO 12
|
||||
#define P_LORA_MOSI 11
|
||||
//#define SX126X_POWER_EN ??? // Not Sure
|
||||
|
||||
#define SX126X_DIO2_AS_RF_SWITCH true
|
||||
#define SX126X_DIO3_TCXO_VOLTAGE 1.8
|
||||
|
||||
// built-ins
|
||||
#define PIN_VBAT_READ 26
|
||||
#define ADC_MULTIPLIER (3.1 * 3.3 * 1000) // MT Uses 3.1
|
||||
#define PIN_LED_BUILTIN LED_BUILTIN
|
||||
|
||||
class PicoWBoard : public mesh::MainBoard {
|
||||
protected:
|
||||
uint8_t startup_reason;
|
||||
|
||||
public:
|
||||
void begin();
|
||||
uint8_t getStartupReason() const override { return startup_reason; }
|
||||
|
||||
void onBeforeTransmit() override {
|
||||
digitalWrite(LED_BUILTIN, HIGH); // turn TX LED on
|
||||
}
|
||||
|
||||
void onAfterTransmit() override {
|
||||
digitalWrite(LED_BUILTIN, LOW); // turn TX LED off
|
||||
}
|
||||
|
||||
#define BATTERY_SAMPLES 8
|
||||
|
||||
uint16_t getBattMilliVolts() override {
|
||||
analogReadResolution(12);
|
||||
|
||||
uint32_t raw = 0;
|
||||
for (int i = 0; i < BATTERY_SAMPLES; i++) {
|
||||
raw += analogRead(PIN_VBAT_READ);
|
||||
}
|
||||
raw = raw / BATTERY_SAMPLES;
|
||||
|
||||
return (ADC_MULTIPLIER * raw) / 4096;
|
||||
}
|
||||
|
||||
const char* getManufacturerName() const override {
|
||||
return "Pico W";
|
||||
}
|
||||
|
||||
void reboot() override {
|
||||
//NVIC_SystemReset();
|
||||
rp2040.reboot();
|
||||
}
|
||||
|
||||
bool startOTAUpdate(const char* id, char reply[]) override;
|
||||
};
|
||||
|
|
@ -1,30 +0,0 @@
|
|||
#include "WaveshareBoard.h"
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <Wire.h>
|
||||
|
||||
void WaveshareBoard::begin() {
|
||||
// for future use, sub-classes SHOULD call this from their begin()
|
||||
startup_reason = BD_STARTUP_NORMAL;
|
||||
|
||||
#ifdef P_LORA_TX_LED
|
||||
pinMode(P_LORA_TX_LED, OUTPUT);
|
||||
#endif
|
||||
|
||||
#ifdef PIN_VBAT_READ
|
||||
pinMode(PIN_VBAT_READ, INPUT);
|
||||
#endif
|
||||
|
||||
#if defined(PIN_BOARD_SDA) && defined(PIN_BOARD_SCL)
|
||||
Wire.setSDA(PIN_BOARD_SDA);
|
||||
Wire.setSCL(PIN_BOARD_SCL);
|
||||
#endif
|
||||
|
||||
Wire.begin();
|
||||
|
||||
delay(10); // give sx1262 some time to power up
|
||||
}
|
||||
|
||||
bool WaveshareBoard::startOTAUpdate(const char *id, char reply[]) {
|
||||
return false;
|
||||
}
|
||||
|
|
@ -1,73 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <MeshCore.h>
|
||||
|
||||
// LoRa radio module pins for Waveshare RP2040-LoRa-HF/LF
|
||||
// https://files.waveshare.com/wiki/RP2040-LoRa/Rp2040-lora-sch.pdf
|
||||
|
||||
#define P_LORA_DIO_1 16
|
||||
#define P_LORA_NSS 13 // CS
|
||||
#define P_LORA_RESET 23
|
||||
#define P_LORA_BUSY 18
|
||||
#define P_LORA_SCLK 14
|
||||
#define P_LORA_MISO 24
|
||||
#define P_LORA_MOSI 15
|
||||
#define P_LORA_TX_LED 25
|
||||
|
||||
#define SX126X_DIO2_AS_RF_SWITCH true
|
||||
#define SX126X_DIO3_TCXO_VOLTAGE 0
|
||||
|
||||
/*
|
||||
* This board has no built-in way to read battery voltage.
|
||||
* Nevertheless it's very easy to make it work, you only require two 1% resistors.
|
||||
*
|
||||
* BAT+ -----+
|
||||
* |
|
||||
* VSYS --+ -/\/\/\/\- --+
|
||||
* 200k |
|
||||
* +-- GPIO28
|
||||
* |
|
||||
* GND --+ -/\/\/\/\- --+
|
||||
* | 100k
|
||||
* BAT- -----+
|
||||
*/
|
||||
#define PIN_VBAT_READ 28
|
||||
#define BATTERY_SAMPLES 8
|
||||
#define ADC_MULTIPLIER (3.0f * 3.3f * 1000)
|
||||
|
||||
class WaveshareBoard : public mesh::MainBoard {
|
||||
protected:
|
||||
uint8_t startup_reason;
|
||||
|
||||
public:
|
||||
void begin();
|
||||
uint8_t getStartupReason() const override { return startup_reason; }
|
||||
|
||||
#ifdef P_LORA_TX_LED
|
||||
void onBeforeTransmit() override { digitalWrite(P_LORA_TX_LED, HIGH); }
|
||||
void onAfterTransmit() override { digitalWrite(P_LORA_TX_LED, LOW); }
|
||||
#endif
|
||||
|
||||
uint16_t getBattMilliVolts() override {
|
||||
#if defined(PIN_VBAT_READ) && defined(ADC_MULTIPLIER)
|
||||
analogReadResolution(12);
|
||||
|
||||
uint32_t raw = 0;
|
||||
for (int i = 0; i < BATTERY_SAMPLES; i++) {
|
||||
raw += analogRead(PIN_VBAT_READ);
|
||||
}
|
||||
raw = raw / BATTERY_SAMPLES;
|
||||
|
||||
return (ADC_MULTIPLIER * raw) / 4096;
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
const char *getManufacturerName() const override { return "Waveshare RP2040-LoRa"; }
|
||||
|
||||
void reboot() override { rp2040.reboot(); }
|
||||
|
||||
bool startOTAUpdate(const char *id, char reply[]) override;
|
||||
};
|
||||
|
|
@ -1,30 +0,0 @@
|
|||
#include "XiaoRP2040Board.h"
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <Wire.h>
|
||||
|
||||
void XiaoRP2040Board::begin() {
|
||||
// for future use, sub-classes SHOULD call this from their begin()
|
||||
startup_reason = BD_STARTUP_NORMAL;
|
||||
|
||||
#ifdef P_LORA_TX_LED
|
||||
pinMode(P_LORA_TX_LED, OUTPUT);
|
||||
#endif
|
||||
|
||||
#ifdef PIN_VBAT_READ
|
||||
pinMode(PIN_VBAT_READ, INPUT);
|
||||
#endif
|
||||
|
||||
#if defined(PIN_BOARD_SDA) && defined(PIN_BOARD_SCL)
|
||||
Wire.setSDA(PIN_BOARD_SDA);
|
||||
Wire.setSCL(PIN_BOARD_SCL);
|
||||
#endif
|
||||
|
||||
Wire.begin();
|
||||
|
||||
delay(10); // give sx1262 some time to power up
|
||||
}
|
||||
|
||||
bool XiaoRP2040Board::startOTAUpdate(const char *id, char reply[]) {
|
||||
return false;
|
||||
}
|
||||
|
|
@ -1,75 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <MeshCore.h>
|
||||
|
||||
// LoRa radio module pins for the Xiao RP2040
|
||||
// https://wiki.seeedstudio.com/XIAO-RP2040/
|
||||
|
||||
#define P_LORA_DIO_1 27 // D1
|
||||
#define P_LORA_NSS 6 // D4
|
||||
#define P_LORA_RESET 28 // D2
|
||||
#define P_LORA_BUSY 29 // D3
|
||||
#define P_LORA_TX_LED 17
|
||||
|
||||
#define SX126X_RXEN 7 // D5
|
||||
#define SX126X_TXEN -1
|
||||
|
||||
#define SX126X_DIO2_AS_RF_SWITCH true
|
||||
#define SX126X_DIO3_TCXO_VOLTAGE 1.8
|
||||
|
||||
/*
|
||||
* This board has no built-in way to read battery voltage.
|
||||
* Nevertheless it's very easy to make it work, you only require two 1% resistors.
|
||||
* If your using the WIO SX1262 Addon for xaio, make sure you dont connect D0!
|
||||
*
|
||||
* BAT+ -----+
|
||||
* |
|
||||
* VSYS --+ -/\/\/\/\- --+
|
||||
* 200k |
|
||||
* +-- D0
|
||||
* |
|
||||
* GND --+ -/\/\/\/\- --+
|
||||
* | 100k
|
||||
* BAT- -----+
|
||||
*/
|
||||
#define PIN_VBAT_READ 26 // D0
|
||||
#define BATTERY_SAMPLES 8
|
||||
#define ADC_MULTIPLIER (3.0f * 3.3f * 1000)
|
||||
|
||||
class XiaoRP2040Board : public mesh::MainBoard {
|
||||
protected:
|
||||
uint8_t startup_reason;
|
||||
|
||||
public:
|
||||
void begin();
|
||||
uint8_t getStartupReason() const override { return startup_reason; }
|
||||
|
||||
#ifdef P_LORA_TX_LED
|
||||
void onBeforeTransmit() override { digitalWrite(P_LORA_TX_LED, HIGH); }
|
||||
void onAfterTransmit() override { digitalWrite(P_LORA_TX_LED, LOW); }
|
||||
#endif
|
||||
|
||||
|
||||
uint16_t getBattMilliVolts() override {
|
||||
#if defined(PIN_VBAT_READ) && defined(ADC_MULTIPLIER)
|
||||
analogReadResolution(12);
|
||||
|
||||
uint32_t raw = 0;
|
||||
for (int i = 0; i < BATTERY_SAMPLES; i++) {
|
||||
raw += analogRead(PIN_VBAT_READ);
|
||||
}
|
||||
raw = raw / BATTERY_SAMPLES;
|
||||
|
||||
return (ADC_MULTIPLIER * raw) / 4096;
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
const char *getManufacturerName() const override { return "Xiao RP2040"; }
|
||||
|
||||
void reboot() override { rp2040.reboot(); }
|
||||
|
||||
bool startOTAUpdate(const char *id, char reply[]) override;
|
||||
};
|
||||
|
|
@ -66,8 +66,8 @@ static Adafruit_INA260 INA260;
|
|||
#endif
|
||||
|
||||
#if ENV_INCLUDE_INA226
|
||||
#define TELEM_INA226_ADDRESS 0x44
|
||||
#define TELEM_INA226_SHUNT_VALUE 0.100
|
||||
#define TELEM_INA226_ADDRESS 0x44
|
||||
#define TELEM_INA226_SHUNT_VALUE 0.100
|
||||
#define TELEM_INA226_MAX_AMP 0.8
|
||||
#include <INA226.h>
|
||||
static INA226 INA226(TELEM_INA226_ADDRESS);
|
||||
|
|
@ -85,7 +85,11 @@ static Adafruit_MLX90614 MLX90614;
|
|||
static Adafruit_VL53L0X VL53L0X;
|
||||
#endif
|
||||
|
||||
#if ENV_INCLUDE_GPS && RAK_BOARD
|
||||
#if ENV_INCLUDE_GPS && defined(RAK_BOARD) && !defined(RAK_WISMESH_TAG)
|
||||
#define RAK_WISBLOCK_GPS
|
||||
#endif
|
||||
|
||||
#ifdef RAK_WISBLOCK_GPS
|
||||
static uint32_t gpsResetPin = 0;
|
||||
static bool i2cGPSFlag = false;
|
||||
static bool serialGPSFlag = false;
|
||||
|
|
@ -96,7 +100,7 @@ static SFE_UBLOX_GNSS ublox_GNSS;
|
|||
|
||||
bool EnvironmentSensorManager::begin() {
|
||||
#if ENV_INCLUDE_GPS
|
||||
#if RAK_BOARD
|
||||
#ifdef RAK_WISBLOCK_GPS
|
||||
rakGPSInit(); //probe base board/sockets for GPS
|
||||
#else
|
||||
initBasicGPS();
|
||||
|
|
@ -457,7 +461,7 @@ void EnvironmentSensorManager::initBasicGPS() {
|
|||
gps_active = false; //Set GPS visibility off until setting is changed
|
||||
}
|
||||
|
||||
#ifdef RAK_BOARD
|
||||
#ifdef RAK_WISBLOCK_GPS
|
||||
void EnvironmentSensorManager::rakGPSInit(){
|
||||
|
||||
Serial1.setPins(PIN_GPS_TX, PIN_GPS_RX);
|
||||
|
|
@ -531,7 +535,7 @@ bool EnvironmentSensorManager::gpsIsAwake(uint8_t ioPin){
|
|||
|
||||
void EnvironmentSensorManager::start_gps() {
|
||||
gps_active = true;
|
||||
#ifdef RAK_BOARD
|
||||
#ifdef RAK_WISBLOCK_GPS
|
||||
pinMode(gpsResetPin, OUTPUT);
|
||||
digitalWrite(gpsResetPin, HIGH);
|
||||
return;
|
||||
|
|
@ -547,7 +551,7 @@ void EnvironmentSensorManager::start_gps() {
|
|||
|
||||
void EnvironmentSensorManager::stop_gps() {
|
||||
gps_active = false;
|
||||
#ifdef RAK_BOARD
|
||||
#ifdef RAK_WISBLOCK_GPS
|
||||
pinMode(gpsResetPin, OUTPUT);
|
||||
digitalWrite(gpsResetPin, LOW);
|
||||
return;
|
||||
|
|
@ -568,13 +572,7 @@ void EnvironmentSensorManager::loop() {
|
|||
|
||||
if (millis() > next_gps_update) {
|
||||
if(gps_active){
|
||||
#ifndef RAK_BOARD
|
||||
if (_location->isValid()) {
|
||||
node_lat = ((double)_location->getLatitude())/1000000.;
|
||||
node_lon = ((double)_location->getLongitude())/1000000.;
|
||||
MESH_DEBUG_PRINTLN("lat %f lon %f", node_lat, node_lon);
|
||||
}
|
||||
#else
|
||||
#ifdef RAK_WISBLOCK_GPS
|
||||
if(i2cGPSFlag){
|
||||
node_lat = ((double)ublox_GNSS.getLatitude())/10000000.;
|
||||
node_lon = ((double)ublox_GNSS.getLongitude())/10000000.;
|
||||
|
|
@ -585,8 +583,12 @@ void EnvironmentSensorManager::loop() {
|
|||
node_lon = ((double)_location->getLongitude())/1000000.;
|
||||
MESH_DEBUG_PRINTLN("lat %f lon %f", node_lat, node_lon);
|
||||
}
|
||||
//else
|
||||
//MESH_DEBUG_PRINTLN("No valid GPS data");
|
||||
#else
|
||||
if (_location->isValid()) {
|
||||
node_lat = ((double)_location->getLatitude())/1000000.;
|
||||
node_lon = ((double)_location->getLongitude())/1000000.;
|
||||
MESH_DEBUG_PRINTLN("lat %f lon %f", node_lat, node_lon);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
next_gps_update = millis() + 1000;
|
||||
|
|
|
|||
|
|
@ -5,9 +5,6 @@
|
|||
#define DISPLAY_ROTATION 3
|
||||
#endif
|
||||
|
||||
#define SCALE_X 1.5625f // 200 / 128
|
||||
#define SCALE_Y 1.5625f // 200 / 128
|
||||
|
||||
bool GxEPDDisplay::begin() {
|
||||
display.epd2.selectSPI(SPI1, SPISettings(4000000, MSBFIRST, SPI_MODE0));
|
||||
SPI1.begin();
|
||||
|
|
@ -19,6 +16,7 @@ bool GxEPDDisplay::begin() {
|
|||
display.fillScreen(GxEPD_WHITE);
|
||||
display.display(true);
|
||||
#if DISP_BACKLIGHT
|
||||
digitalWrite(DISP_BACKLIGHT, LOW);
|
||||
pinMode(DISP_BACKLIGHT, OUTPUT);
|
||||
#endif
|
||||
_init = true;
|
||||
|
|
@ -27,14 +25,14 @@ bool GxEPDDisplay::begin() {
|
|||
|
||||
void GxEPDDisplay::turnOn() {
|
||||
if (!_init) begin();
|
||||
#if DISP_BACKLIGHT
|
||||
#if defined(DISP_BACKLIGHT) && !defined(BACKLIGHT_BTN)
|
||||
digitalWrite(DISP_BACKLIGHT, HIGH);
|
||||
#endif
|
||||
_isOn = true;
|
||||
}
|
||||
|
||||
void GxEPDDisplay::turnOff() {
|
||||
#if DISP_BACKLIGHT
|
||||
#if defined(DISP_BACKLIGHT) && !defined(BACKLIGHT_BTN)
|
||||
digitalWrite(DISP_BACKLIGHT, LOW);
|
||||
#endif
|
||||
_isOn = false;
|
||||
|
|
@ -43,14 +41,17 @@ void GxEPDDisplay::turnOff() {
|
|||
void GxEPDDisplay::clear() {
|
||||
display.fillScreen(GxEPD_WHITE);
|
||||
display.setTextColor(GxEPD_BLACK);
|
||||
display_crc.reset();
|
||||
}
|
||||
|
||||
void GxEPDDisplay::startFrame(Color bkg) {
|
||||
display.fillScreen(GxEPD_WHITE);
|
||||
display.setTextColor(_curr_color = GxEPD_BLACK);
|
||||
display_crc.reset();
|
||||
}
|
||||
|
||||
void GxEPDDisplay::setTextSize(int sz) {
|
||||
display_crc.update<int>(sz);
|
||||
switch(sz) {
|
||||
case 1: // Small
|
||||
display.setFont(&FreeSans9pt7b);
|
||||
|
|
@ -68,6 +69,7 @@ void GxEPDDisplay::setTextSize(int sz) {
|
|||
}
|
||||
|
||||
void GxEPDDisplay::setColor(Color c) {
|
||||
display_crc.update<Color> (c);
|
||||
// colours need to be inverted for epaper displays
|
||||
if (c == DARK) {
|
||||
display.setTextColor(_curr_color = GxEPD_WHITE);
|
||||
|
|
@ -77,25 +79,41 @@ void GxEPDDisplay::setColor(Color c) {
|
|||
}
|
||||
|
||||
void GxEPDDisplay::setCursor(int x, int y) {
|
||||
display.setCursor(x*SCALE_X, (y+10)*SCALE_Y);
|
||||
display_crc.update<int>(x);
|
||||
display_crc.update<int>(y);
|
||||
display.setCursor((x+offset_x)*scale_x, (y+offset_y)*scale_y);
|
||||
}
|
||||
|
||||
void GxEPDDisplay::print(const char* str) {
|
||||
display_crc.update<char>(str, strlen(str));
|
||||
display.print(str);
|
||||
}
|
||||
|
||||
void GxEPDDisplay::fillRect(int x, int y, int w, int h) {
|
||||
display.fillRect(x*SCALE_X, y*SCALE_Y, w*SCALE_X, h*SCALE_Y, _curr_color);
|
||||
display_crc.update<int>(x);
|
||||
display_crc.update<int>(y);
|
||||
display_crc.update<int>(w);
|
||||
display_crc.update<int>(h);
|
||||
display.fillRect(x*scale_x, y*scale_y, w*scale_x, h*scale_y, _curr_color);
|
||||
}
|
||||
|
||||
void GxEPDDisplay::drawRect(int x, int y, int w, int h) {
|
||||
display.drawRect(x*SCALE_X, y*SCALE_Y, w*SCALE_X, h*SCALE_Y, _curr_color);
|
||||
display_crc.update<int>(x);
|
||||
display_crc.update<int>(y);
|
||||
display_crc.update<int>(w);
|
||||
display_crc.update<int>(h);
|
||||
display.drawRect(x*scale_x, y*scale_y, w*scale_x, h*scale_y, _curr_color);
|
||||
}
|
||||
|
||||
void GxEPDDisplay::drawXbm(int x, int y, const uint8_t* bits, int w, int h) {
|
||||
display_crc.update<int>(x);
|
||||
display_crc.update<int>(y);
|
||||
display_crc.update<int>(w);
|
||||
display_crc.update<int>(h);
|
||||
display_crc.update<uint8_t>(bits, w * h / 8);
|
||||
// Calculate the base position in display coordinates
|
||||
uint16_t startX = x * SCALE_X;
|
||||
uint16_t startY = y * SCALE_Y;
|
||||
uint16_t startX = x * scale_x;
|
||||
uint16_t startY = y * scale_y;
|
||||
|
||||
// Width in bytes for bitmap processing
|
||||
uint16_t widthInBytes = (w + 7) / 8;
|
||||
|
|
@ -103,15 +121,15 @@ void GxEPDDisplay::drawXbm(int x, int y, const uint8_t* bits, int w, int h) {
|
|||
// Process the bitmap row by row
|
||||
for (uint16_t by = 0; by < h; by++) {
|
||||
// Calculate the target y-coordinates for this logical row
|
||||
int y1 = startY + (int)(by * SCALE_Y);
|
||||
int y2 = startY + (int)((by + 1) * SCALE_Y);
|
||||
int y1 = startY + (int)(by * scale_y);
|
||||
int y2 = startY + (int)((by + 1) * scale_y);
|
||||
int block_h = y2 - y1;
|
||||
|
||||
// Scan across the row bit by bit
|
||||
for (uint16_t bx = 0; bx < w; bx++) {
|
||||
// Calculate the target x-coordinates for this logical column
|
||||
int x1 = startX + (int)(bx * SCALE_X);
|
||||
int x2 = startX + (int)((bx + 1) * SCALE_X);
|
||||
int x1 = startX + (int)(bx * scale_x);
|
||||
int x2 = startX + (int)((bx + 1) * scale_x);
|
||||
int block_w = x2 - x1;
|
||||
|
||||
// Get the current bit
|
||||
|
|
@ -132,9 +150,13 @@ uint16_t GxEPDDisplay::getTextWidth(const char* str) {
|
|||
int16_t x1, y1;
|
||||
uint16_t w, h;
|
||||
display.getTextBounds(str, 0, 0, &x1, &y1, &w, &h);
|
||||
return ceil((w + 1) / SCALE_X);
|
||||
return ceil((w + 1) / scale_x);
|
||||
}
|
||||
|
||||
void GxEPDDisplay::endFrame() {
|
||||
display.display(true);
|
||||
uint32_t crc = display_crc.finalize();
|
||||
if (crc != last_display_crc_value) {
|
||||
display.display(true);
|
||||
last_display_crc_value = crc;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,10 +13,9 @@
|
|||
#include <Fonts/FreeSansBold12pt7b.h>
|
||||
#include <Fonts/FreeSans18pt7b.h>
|
||||
|
||||
#define GxEPD2_DISPLAY_CLASS GxEPD2_BW
|
||||
#define GxEPD2_DRIVER_CLASS GxEPD2_150_BN // DEPG0150BN 200x200, SSD1681, (FPC8101), TTGO T5 V2.4.1
|
||||
|
||||
#include <epd/GxEPD2_150_BN.h> // 1.54" b/w
|
||||
#include <epd/GxEPD2_213_B74.h> // 2.13" b/w
|
||||
#include <CRC32.h>
|
||||
|
||||
#include "DisplayDriver.h"
|
||||
|
||||
|
|
@ -25,15 +24,32 @@
|
|||
|
||||
class GxEPDDisplay : public DisplayDriver {
|
||||
|
||||
#if defined(HELTEC_MESH_POCKET)
|
||||
GxEPD2_BW<EINK_DISPLAY_MODEL, EINK_DISPLAY_MODEL::HEIGHT> display;
|
||||
const float scale_x = EINK_SCALE_X;
|
||||
const float scale_y = EINK_SCALE_Y;
|
||||
const float offset_x = EINK_X_OFFSET;
|
||||
const float offset_y = EINK_Y_OFFSET;
|
||||
#else
|
||||
GxEPD2_BW<GxEPD2_150_BN, 200> display;
|
||||
const float scale_x = 1.5625f;
|
||||
const float scale_y = 1.5625f;
|
||||
const float offset_x = 0;
|
||||
const float offset_y = 10;
|
||||
#endif
|
||||
bool _init = false;
|
||||
bool _isOn = false;
|
||||
uint16_t _curr_color;
|
||||
CRC32 display_crc;
|
||||
int last_display_crc_value = 0;
|
||||
|
||||
public:
|
||||
// there is a margin in y...
|
||||
GxEPDDisplay() : DisplayDriver(128, 128), display(GxEPD2_150_BN(DISP_CS, DISP_DC, DISP_RST, DISP_BUSY)) {
|
||||
}
|
||||
#if defined(HELTEC_MESH_POCKET)
|
||||
GxEPDDisplay() : DisplayDriver(128, 128), display(EINK_DISPLAY_MODEL(PIN_DISPLAY_CS, PIN_DISPLAY_DC, PIN_DISPLAY_RST, PIN_DISPLAY_BUSY)) {}
|
||||
#else
|
||||
GxEPDDisplay() : DisplayDriver(128, 128), display(GxEPD2_150_BN(DISP_CS, DISP_DC, DISP_RST, DISP_BUSY)) {}
|
||||
#endif
|
||||
|
||||
bool begin();
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
#include "MomentaryButton.h"
|
||||
|
||||
#define MULTI_CLICK_WINDOW_MS 280
|
||||
|
||||
MomentaryButton::MomentaryButton(int8_t pin, int long_press_millis, bool reverse, bool pulldownup) {
|
||||
_pin = pin;
|
||||
_reverse = reverse;
|
||||
|
|
@ -9,6 +11,10 @@ MomentaryButton::MomentaryButton(int8_t pin, int long_press_millis, bool reverse
|
|||
cancel = 0;
|
||||
_long_millis = long_press_millis;
|
||||
_threshold = 0;
|
||||
_click_count = 0;
|
||||
_last_click_time = 0;
|
||||
_multi_click_window = MULTI_CLICK_WINDOW_MS;
|
||||
_pending_click = false;
|
||||
}
|
||||
|
||||
MomentaryButton::MomentaryButton(int8_t pin, int long_press_millis, int analog_threshold) {
|
||||
|
|
@ -20,6 +26,10 @@ MomentaryButton::MomentaryButton(int8_t pin, int long_press_millis, int analog_t
|
|||
cancel = 0;
|
||||
_long_millis = long_press_millis;
|
||||
_threshold = analog_threshold;
|
||||
_click_count = 0;
|
||||
_last_click_time = 0;
|
||||
_multi_click_window = MULTI_CLICK_WINDOW_MS;
|
||||
_pending_click = false;
|
||||
}
|
||||
|
||||
void MomentaryButton::begin() {
|
||||
|
|
@ -35,6 +45,10 @@ bool MomentaryButton::isPressed() const {
|
|||
|
||||
void MomentaryButton::cancelClick() {
|
||||
cancel = 1;
|
||||
down_at = 0;
|
||||
_click_count = 0;
|
||||
_last_click_time = 0;
|
||||
_pending_click = false;
|
||||
}
|
||||
|
||||
bool MomentaryButton::isPressed(int level) const {
|
||||
|
|
@ -60,13 +74,20 @@ int MomentaryButton::check(bool repeat_click) {
|
|||
// button UP
|
||||
if (_long_millis > 0) {
|
||||
if (down_at > 0 && (unsigned long)(millis() - down_at) < _long_millis) { // only a CLICK if still within the long_press millis
|
||||
event = BUTTON_EVENT_CLICK;
|
||||
_click_count++;
|
||||
_last_click_time = millis();
|
||||
_pending_click = true;
|
||||
}
|
||||
} else {
|
||||
event = BUTTON_EVENT_CLICK; // any UP results in CLICK event when NOT using long_press feature
|
||||
_click_count++;
|
||||
_last_click_time = millis();
|
||||
_pending_click = true;
|
||||
}
|
||||
if (event == BUTTON_EVENT_CLICK && cancel) {
|
||||
event = BUTTON_EVENT_NONE;
|
||||
_click_count = 0;
|
||||
_last_click_time = 0;
|
||||
_pending_click = false;
|
||||
}
|
||||
down_at = 0;
|
||||
}
|
||||
|
|
@ -77,8 +98,16 @@ int MomentaryButton::check(bool repeat_click) {
|
|||
}
|
||||
|
||||
if (_long_millis > 0 && down_at > 0 && (unsigned long)(millis() - down_at) >= _long_millis) {
|
||||
event = BUTTON_EVENT_LONG_PRESS;
|
||||
down_at = 0;
|
||||
if (_pending_click) {
|
||||
// long press during multi-click detection - cancel pending clicks
|
||||
cancelClick();
|
||||
} else {
|
||||
event = BUTTON_EVENT_LONG_PRESS;
|
||||
down_at = 0;
|
||||
_click_count = 0;
|
||||
_last_click_time = 0;
|
||||
_pending_click = false;
|
||||
}
|
||||
}
|
||||
if (down_at > 0 && repeat_click) {
|
||||
unsigned long diff = (unsigned long)(millis() - down_at);
|
||||
|
|
@ -87,5 +116,30 @@ int MomentaryButton::check(bool repeat_click) {
|
|||
}
|
||||
}
|
||||
|
||||
if (_pending_click && (millis() - _last_click_time) >= _multi_click_window) {
|
||||
if (down_at > 0) {
|
||||
// still pressed - wait for button release before processing clicks
|
||||
return event;
|
||||
}
|
||||
switch (_click_count) {
|
||||
case 1:
|
||||
event = BUTTON_EVENT_CLICK;
|
||||
break;
|
||||
case 2:
|
||||
event = BUTTON_EVENT_DOUBLE_CLICK;
|
||||
break;
|
||||
case 3:
|
||||
event = BUTTON_EVENT_TRIPLE_CLICK;
|
||||
break;
|
||||
default:
|
||||
// For 4+ clicks, treat as triple click?
|
||||
event = BUTTON_EVENT_TRIPLE_CLICK;
|
||||
break;
|
||||
}
|
||||
_click_count = 0;
|
||||
_last_click_time = 0;
|
||||
_pending_click = false;
|
||||
}
|
||||
|
||||
return event;
|
||||
}
|
||||
|
|
@ -5,6 +5,8 @@
|
|||
#define BUTTON_EVENT_NONE 0
|
||||
#define BUTTON_EVENT_CLICK 1
|
||||
#define BUTTON_EVENT_LONG_PRESS 2
|
||||
#define BUTTON_EVENT_DOUBLE_CLICK 3
|
||||
#define BUTTON_EVENT_TRIPLE_CLICK 4
|
||||
|
||||
class MomentaryButton {
|
||||
int8_t _pin;
|
||||
|
|
@ -13,6 +15,10 @@ class MomentaryButton {
|
|||
int _long_millis;
|
||||
int _threshold; // analog mode
|
||||
unsigned long down_at;
|
||||
uint8_t _click_count;
|
||||
unsigned long _last_click_time;
|
||||
int _multi_click_window;
|
||||
bool _pending_click;
|
||||
|
||||
bool isPressed(int level) const;
|
||||
|
||||
|
|
|
|||
24
src/helpers/ui/NullDisplayDriver.h
Normal file
24
src/helpers/ui/NullDisplayDriver.h
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
#pragma once
|
||||
|
||||
#include <helpers/ui/DisplayDriver.h>
|
||||
|
||||
class NullDisplayDriver : public DisplayDriver {
|
||||
public:
|
||||
NullDisplayDriver() : DisplayDriver(128, 64) { }
|
||||
bool begin() { return false; } // not present
|
||||
|
||||
bool isOn() override { return false; }
|
||||
void turnOn() override { }
|
||||
void turnOff() override { }
|
||||
void clear() override { }
|
||||
void startFrame(Color bkg = DARK) override { }
|
||||
void setTextSize(int sz) override { }
|
||||
void setColor(Color c) override { }
|
||||
void setCursor(int x, int y) override { }
|
||||
void print(const char* str) override { }
|
||||
void fillRect(int x, int y, int w, int h) override { }
|
||||
void drawRect(int x, int y, int w, int h) override { }
|
||||
void drawXbm(int x, int y, const uint8_t* bits, int w, int h) override { }
|
||||
uint16_t getTextWidth(const char* str) override { return 0; }
|
||||
void endFrame() { }
|
||||
};
|
||||
|
|
@ -2,13 +2,17 @@
|
|||
|
||||
#include "DisplayDriver.h"
|
||||
|
||||
#define KEY_LEFT 0xB4
|
||||
#define KEY_UP 0xB5
|
||||
#define KEY_DOWN 0xB6
|
||||
#define KEY_RIGHT 0xB7
|
||||
#define KEY_SELECT 10
|
||||
#define KEY_ENTER 13
|
||||
#define KEY_BACK 27 // Esc
|
||||
#define KEY_LEFT 0xB4
|
||||
#define KEY_UP 0xB5
|
||||
#define KEY_DOWN 0xB6
|
||||
#define KEY_RIGHT 0xB7
|
||||
#define KEY_SELECT 10
|
||||
#define KEY_ENTER 13
|
||||
#define KEY_CANCEL 27 // Esc
|
||||
#define KEY_HOME 0xF0
|
||||
#define KEY_NEXT 0xF1
|
||||
#define KEY_PREV 0xF2
|
||||
#define KEY_CONTEXT_MENU 0xF3
|
||||
|
||||
class UIScreen {
|
||||
protected:
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue