Merge branch '2264-feature-check-for-low-heap-before-adding-to-nodedb-was-reboot-loop-heap-too-low' of github.com:meshtastic/firmware into 2264-feature-check-for-low-heap-before-adding-to-nodedb-was-reboot-loop-heap-too-low

This commit is contained in:
Thomas Göttgens 2023-03-10 21:39:33 +01:00
commit e0a6a37bef
46 changed files with 921 additions and 399 deletions

59
.github/workflows/build_esp32_s3.yml vendored Normal file
View File

@ -0,0 +1,59 @@
name: Build ESP32-S3
on:
workflow_call:
inputs:
board:
required: true
type: string
jobs:
build-esp32-s3:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Build base
id: base
uses: ./.github/actions/setup-base
- name: Pull web ui
uses: dsaltares/fetch-gh-release-asset@master
with:
repo: "meshtastic/web"
file: "build.tar"
target: "build.tar"
token: ${{ secrets.GITHUB_TOKEN }}
- name: Unpack web ui
run: |
tar -xf build.tar -C data/static
rm build.tar
- name: Remove debug flags for release
if: ${{ github.event_name == 'workflow_dispatch' }}
run: |
sed -i '/DDEBUG_HEAP/d' ./arch/esp32/esp32.ini
sed -i '/DDEBUG_HEAP/d' ./arch/esp32/esp32s2.ini
sed -i '/DDEBUG_HEAP/d' ./arch/esp32/esp32s3.ini
- name: Build ESP32
run: bin/build-esp32.sh ${{ inputs.board }}
- name: Pull OTA Firmware
uses: dsaltares/fetch-gh-release-asset@master
with:
repo: "meshtastic/firmware-ota"
file: "firmware-s3.bin"
target: "release/bleota-s3.bin"
token: ${{ secrets.GITHUB_TOKEN }}
- name: Get release version string
shell: bash
run: echo "version=$(./bin/buildinfo.py long)" >> $GITHUB_OUTPUT
id: version
- name: Store binaries as an artifact
uses: actions/upload-artifact@v3
with:
name: firmware-${{ inputs.board }}-${{ steps.version.outputs.version }}.zip
path: |
release/*.bin
release/*.elf

View File

@ -62,8 +62,6 @@ jobs:
- board: heltec-v1 - board: heltec-v1
- board: heltec-v2.0 - board: heltec-v2.0
- board: heltec-v2.1 - board: heltec-v2.1
- board: heltec-v3
- board: heltec-wsl-v3
- board: tbeam0.7 - board: tbeam0.7
- board: meshtastic-diy-v1 - board: meshtastic-diy-v1
- board: meshtastic-dr-dev - board: meshtastic-dr-dev
@ -71,13 +69,24 @@ jobs:
- board: station-g1 - board: station-g1
- board: m5stack-core - board: m5stack-core
- board: m5stack-coreink - board: m5stack-coreink
- board: tbeam-s3-core
- board: tlora-t3s3-v1
- board: nano-g1-explorer - board: nano-g1-explorer
uses: ./.github/workflows/build_esp32.yml uses: ./.github/workflows/build_esp32.yml
with: with:
board: ${{ matrix.board }} board: ${{ matrix.board }}
build-esp32-s3:
strategy:
fail-fast: false
matrix:
include:
- board: heltec-v3
- board: heltec-wsl-v3
- board: tbeam-s3-core
- board: tlora-t3s3-v1
uses: ./.github/workflows/build_esp32_s3.yml
with:
board: ${{ matrix.board }}
build-nrf52: build-nrf52:
strategy: strategy:
fail-fast: false fail-fast: false
@ -176,7 +185,7 @@ jobs:
gather-artifacts: gather-artifacts:
runs-on: ubuntu-latest runs-on: ubuntu-latest
needs: [build-esp32, build-nrf52, build-native] #, build-rpi2040] needs: [build-esp32, build-esp32-s3, build-nrf52, build-native] #, build-rpi2040]
steps: steps:
- name: Checkout code - name: Checkout code
uses: actions/checkout@v3 uses: actions/checkout@v3
@ -193,7 +202,7 @@ jobs:
id: version id: version
- name: Move files up - name: Move files up
run: mv -b -t ./ ./*tbeam-2*/littlefs*.bin ./*tbeam-2*/bleota.bin ./**/firmware*.bin ./*t-echo*/Meshtastic_nRF52_factory_erase.uf2 ./**/firmware-*.uf2 ./**/firmware-*-ota.zip ./**/*.elf ./*native*/*device-*.sh ./*native*/*device-*.bat run: mv -b -t ./ ./*tbeam-2*/littlefs*.bin ./*tbeam-2*/bleota.bin ./*tbeam-s3*/bleota-s3.bin ./**/firmware*.bin ./*t-echo*/Meshtastic_nRF52_factory_erase.uf2 ./**/firmware-*.uf2 ./**/firmware-*-ota.zip ./**/*.elf ./*native*/*device-*.sh ./*native*/*device-*.bat
- name: Repackage in single firmware zip - name: Repackage in single firmware zip
uses: actions/upload-artifact@v3 uses: actions/upload-artifact@v3

View File

@ -1,7 +1,7 @@
; Common settings for ESP targes, mixin with extends = esp32_base ; Common settings for ESP targes, mixin with extends = esp32_base
[esp32_base] [esp32_base]
extends = arduino_base extends = arduino_base
platform = platformio/espressif32@^6.0.0 platform = platformio/espressif32@^6.1.0
build_src_filter = build_src_filter =
${arduino_base.build_src_filter} -<platform/nrf52/> -<platform/stm32wl> -<platform/rp2040> -<mesh/eth/> ${arduino_base.build_src_filter} -<platform/nrf52/> -<platform/stm32wl> -<platform/rp2040> -<mesh/eth/>
upload_speed = 921600 upload_speed = 921600

View File

@ -1,6 +1,6 @@
[esp32s2_base] [esp32s2_base]
extends = arduino_base extends = arduino_base
platform = platformio/espressif32@^6.0.0 platform = platformio/espressif32@^6.1.0
build_src_filter = build_src_filter =
${arduino_base.build_src_filter} -<platform/nrf52/> -<platform/stm32wl> -<platform/rp2040> -<mesh/eth/> -<nimble/> ${arduino_base.build_src_filter} -<platform/nrf52/> -<platform/stm32wl> -<platform/rp2040> -<mesh/eth/> -<nimble/>
upload_speed = 961200 upload_speed = 961200

View File

@ -1,6 +1,6 @@
[esp32s3_base] [esp32s3_base]
extends = arduino_base extends = arduino_base
platform = platformio/espressif32@^6.0.0 platform = platformio/espressif32@^6.1.0
build_src_filter = build_src_filter =
${arduino_base.build_src_filter} -<platform/nrf52/> -<platform/stm32wl> -<platform/rp2040> -<mesh/eth/> ${arduino_base.build_src_filter} -<platform/nrf52/> -<platform/stm32wl> -<platform/rp2040> -<mesh/eth/>
upload_speed = 961200 upload_speed = 961200

View File

@ -1,6 +1,6 @@
[nrf52_base] [nrf52_base]
; Instead of the standard nordicnrf52 platform, we use our fork which has our added variant files ; Instead of the standard nordicnrf52 platform, we use our fork which has our added variant files
platform = platformio/nordicnrf52@^9.4.0 platform = platformio/nordicnrf52@^9.5.0
extends = arduino_base extends = arduino_base
build_type = debug ; I'm debugging with ICE a lot now build_type = debug ; I'm debugging with ICE a lot now

View File

@ -34,7 +34,7 @@ SRCBIN=.pio/build/$1/firmware.bin
cp $SRCBIN $OUTDIR/$basename-update.bin cp $SRCBIN $OUTDIR/$basename-update.bin
echo "Building Filesystem for ESP32 targets" echo "Building Filesystem for ESP32 targets"
pio run --environment tbeam -t buildfs pio run --environment $1 -t buildfs
cp .pio/build/tbeam/littlefs.bin $OUTDIR/littlefs-$VERSION.bin cp .pio/build/$1/littlefs.bin $OUTDIR/littlefs-$VERSION.bin
cp bin/device-install.* $OUTDIR cp bin/device-install.* $OUTDIR
cp bin/device-update.* $OUTDIR cp bin/device-update.* $OUTDIR

View File

@ -30,7 +30,13 @@ IF EXIST %FILENAME% IF x%FILENAME:update=%==x%FILENAME% (
echo Trying to flash update %FILENAME%, but first erasing and writing system information" echo Trying to flash update %FILENAME%, but first erasing and writing system information"
%PYTHON% -m esptool --baud 115200 erase_flash %PYTHON% -m esptool --baud 115200 erase_flash
%PYTHON% -m esptool --baud 115200 write_flash 0x00 %FILENAME% %PYTHON% -m esptool --baud 115200 write_flash 0x00 %FILENAME%
%PYTHON% -m esptool --baud 115200 write_flash 0x260000 bleota.bin
@REM Account for S3 board's different OTA partition
IF x%FILENAME:s3=%==x%FILENAME% IF x%FILENAME:v3=%==x%FILENAME% (
%PYTHON% -m esptool --baud 115200 write_flash 0x260000 bleota.bin
) else (
%PYTHON% -m esptool --baud 115200 write_flash 0x260000 bleota-s3.bin
)
for %%f in (littlefs-*.bin) do ( for %%f in (littlefs-*.bin) do (
%PYTHON% -m esptool --baud 115200 write_flash 0x300000 %%f %PYTHON% -m esptool --baud 115200 write_flash 0x300000 %%f
) )

View File

@ -49,7 +49,12 @@ if [ -f "${FILENAME}" ] && [ ! -z "${FILENAME##*"update"*}" ]; then
echo "Trying to flash ${FILENAME}, but first erasing and writing system information" echo "Trying to flash ${FILENAME}, but first erasing and writing system information"
"$PYTHON" -m esptool erase_flash "$PYTHON" -m esptool erase_flash
"$PYTHON" -m esptool write_flash 0x00 ${FILENAME} "$PYTHON" -m esptool write_flash 0x00 ${FILENAME}
"$PYTHON" -m esptool write_flash 0x260000 bleota.bin # Account for S3 board's different OTA partition
if [ ! -z "${FILENAME##*"s3"*}" ] && [ ! -z "${FILENAME##*"-v3"*}" ]; then
"$PYTHON" -m esptool write_flash 0x260000 bleota.bin
else
"$PYTHON" -m esptool write_flash 0x260000 bleota-s3.bin
fi
"$PYTHON" -m esptool write_flash 0x300000 littlefs-*.bin "$PYTHON" -m esptool write_flash 0x300000 littlefs-*.bin
else else

View File

@ -9,7 +9,8 @@
"-DARDUINO_USB_CDC_ON_BOOT=1", "-DARDUINO_USB_CDC_ON_BOOT=1",
"-DARDUINO_USB_MODE=0", "-DARDUINO_USB_MODE=0",
"-DARDUINO_RUNNING_CORE=1", "-DARDUINO_RUNNING_CORE=1",
"-DARDUINO_EVENT_RUNNING_CORE=1" "-DARDUINO_EVENT_RUNNING_CORE=1",
"-DBOARD_HAS_PSRAM"
], ],
"f_cpu": "240000000L", "f_cpu": "240000000L",
"f_flash": "80000000L", "f_flash": "80000000L",

View File

@ -59,15 +59,14 @@ build_flags = -Wno-missing-field-initializers
monitor_speed = 115200 monitor_speed = 115200
lib_deps = lib_deps =
https://github.com/meshtastic/esp8266-oled-ssd1306.git#da1ede4dfcd91074283b029080759fd744120909 ; ESP8266_SSD1306 https://github.com/meshtastic/esp8266-oled-ssd1306.git#b38094e03dfa964fbc0e799bc374e91a605c1223 ; ESP8266_SSD1306
mathertel/OneButton@^2.0.3 ; OneButton library for non-blocking button debounce mathertel/OneButton@^2.0.3 ; OneButton library for non-blocking button debounce
https://github.com/meshtastic/arduino-fsm.git#7db3702bf0cfe97b783d6c72595e3f38e0b19159 https://github.com/meshtastic/arduino-fsm.git#7db3702bf0cfe97b783d6c72595e3f38e0b19159
https://github.com/meshtastic/TinyGPSPlus.git#127ad674ef85f0201cb68a065879653ed94792c4 https://github.com/meshtastic/TinyGPSPlus.git#127ad674ef85f0201cb68a065879653ed94792c4
https://github.com/meshtastic/ArduinoThread.git#72921ac222eed6f526ba1682023cee290d9aa1b3 https://github.com/meshtastic/ArduinoThread.git#72921ac222eed6f526ba1682023cee290d9aa1b3
nanopb/Nanopb@^0.4.6 nanopb/Nanopb@^0.4.7
erriez/ErriezCRC32@^1.0.1 erriez/ErriezCRC32@^1.0.1
; jgromes/RadioLib@^5.5.1 jgromes/RadioLib@^5.7.0
https://github.com/jgromes/RadioLib.git#1afa947030c5637f71f6563bc22aa75032e53a57
; Used for the code analysis in PIO Home / Inspect ; Used for the code analysis in PIO Home / Inspect
check_tool = cppcheck check_tool = cppcheck
@ -101,7 +100,7 @@ lib_deps =
[environmental_base] [environmental_base]
lib_deps = lib_deps =
adafruit/Adafruit BusIO@^1.11.4 adafruit/Adafruit BusIO@^1.11.4
adafruit/Adafruit Unified Sensor@^1.1.4 adafruit/Adafruit Unified Sensor@^1.1.9
adafruit/Adafruit BMP280 Library@^2.6.6 adafruit/Adafruit BMP280 Library@^2.6.6
adafruit/Adafruit BME280 Library@^2.2.2 adafruit/Adafruit BME280 Library@^2.2.2
adafruit/Adafruit BME680 Library@^2.0.1 adafruit/Adafruit BME680 Library@^2.0.1

@ -1 +1 @@
Subproject commit b3d05ec995844ae888e1d43d6e5c770b7d654309 Subproject commit 19d49ec5280b6904f8c4cd1182ba4250d4122dbe

70
src/detect/ScanI2C.cpp Normal file
View File

@ -0,0 +1,70 @@
#include "ScanI2C.h"
const ScanI2C::DeviceAddress ScanI2C::ADDRESS_NONE = ScanI2C::DeviceAddress();
const ScanI2C::FoundDevice ScanI2C::DEVICE_NONE = ScanI2C::FoundDevice(ScanI2C::DeviceType::NONE, ADDRESS_NONE);
ScanI2C::ScanI2C() = default;
void ScanI2C::scanPort(ScanI2C::I2CPort port) {}
void ScanI2C::setSuppressScreen()
{
shouldSuppressScreen = true;
}
ScanI2C::FoundDevice ScanI2C::firstScreen() const
{
// Allow to override the scanner results for screen
if (shouldSuppressScreen)
return DEVICE_NONE;
ScanI2C::DeviceType types[] = {SCREEN_SSD1306, SCREEN_SH1106, SCREEN_ST7567, SCREEN_UNKNOWN};
return firstOfOrNONE(4, types);
}
ScanI2C::FoundDevice ScanI2C::firstRTC() const
{
ScanI2C::DeviceType types[] = {RTC_RV3028, RTC_PCF8563};
return firstOfOrNONE(2, types);
}
ScanI2C::FoundDevice ScanI2C::firstKeyboard() const
{
ScanI2C::DeviceType types[] = {CARDKB, RAK14004};
return firstOfOrNONE(2, types);
}
ScanI2C::FoundDevice ScanI2C::find(ScanI2C::DeviceType) const
{
return DEVICE_NONE;
}
bool ScanI2C::exists(ScanI2C::DeviceType) const
{
return false;
}
ScanI2C::FoundDevice ScanI2C::firstOfOrNONE(size_t count, ScanI2C::DeviceType *types) const
{
return DEVICE_NONE;
}
size_t ScanI2C::countDevices() const
{
return 0;
}
ScanI2C::DeviceAddress::DeviceAddress(ScanI2C::I2CPort port, uint8_t address) : port(port), address(address) {}
ScanI2C::DeviceAddress::DeviceAddress() : DeviceAddress(I2CPort::NO_I2C, 0) {}
bool ScanI2C::DeviceAddress::operator<(const ScanI2C::DeviceAddress &other) const
{
return
// If this one has no port and other has a port
(port == NO_I2C && other.port != NO_I2C)
// if both have a port and this one's address is lower
|| (port != NO_I2C && other.port != NO_I2C && (address < other.address));
}
ScanI2C::FoundDevice::FoundDevice(ScanI2C::DeviceType type, ScanI2C::DeviceAddress address) : type(type), address(address) {}

93
src/detect/ScanI2C.h Normal file
View File

@ -0,0 +1,93 @@
#pragma once
#include <stddef.h>
#include <stdint.h>
class ScanI2C
{
public:
typedef enum DeviceType {
NONE,
SCREEN_SSD1306,
SCREEN_SH1106,
SCREEN_UNKNOWN, // has the same address as the two above but does not respond to the same commands
SCREEN_ST7567,
ATECC608B,
RTC_RV3028,
RTC_PCF8563,
CARDKB,
RAK14004,
PMU_AXP192_AXP2101,
BME_680,
BME_280,
BMP_280,
INA260,
INA219,
MCP9808,
SHT31,
SHTC3,
LPS22HB,
QMC6310,
QMI8658,
QMC5883L,
PMSA0031,
} DeviceType;
// typedef uint8_t DeviceAddress;
typedef enum I2CPort {
NO_I2C,
WIRE,
WIRE1,
} I2CPort;
typedef struct DeviceAddress {
I2CPort port;
uint8_t address;
explicit DeviceAddress(I2CPort port, uint8_t address);
DeviceAddress();
bool operator<(const DeviceAddress &other) const;
} DeviceAddress;
static const DeviceAddress ADDRESS_NONE;
typedef uint8_t RegisterAddress;
typedef struct FoundDevice {
DeviceType type;
DeviceAddress address;
explicit FoundDevice(DeviceType = DeviceType::NONE, DeviceAddress = ADDRESS_NONE);
} FoundDevice;
static const FoundDevice DEVICE_NONE;
public:
ScanI2C();
virtual void scanPort(ScanI2C::I2CPort);
/*
* A bit of a hack, this tells the scanner not to tell later systems there is a screen to avoid enabling it.
*/
void setSuppressScreen();
FoundDevice firstScreen() const;
FoundDevice firstRTC() const;
FoundDevice firstKeyboard() const;
virtual FoundDevice find(DeviceType) const;
virtual bool exists(DeviceType) const;
virtual size_t countDevices() const;
protected:
virtual FoundDevice firstOfOrNONE(size_t, DeviceType[]) const;
private:
bool shouldSuppressScreen = false;
};

View File

@ -0,0 +1,297 @@
#include "ScanI2CTwoWire.h"
#include "concurrency/LockGuard.h"
#include "configuration.h"
#if !defined(ARCH_PORTDUINO) && !defined(ARCH_STM32WL)
#include "main.h" // atecc
#endif
// AXP192 and AXP2101 have the same device address, we just need to identify it in Power.cpp
#ifndef XPOWERS_AXP192_AXP2101_ADDRESS
#define XPOWERS_AXP192_AXP2101_ADDRESS 0x34
#endif
ScanI2C::FoundDevice ScanI2CTwoWire::find(ScanI2C::DeviceType type) const
{
concurrency::LockGuard guard((concurrency::Lock *)&lock);
return exists(type) ? ScanI2C::FoundDevice(type, deviceAddresses.at(type)) : DEVICE_NONE;
}
bool ScanI2CTwoWire::exists(ScanI2C::DeviceType type) const
{
return deviceAddresses.find(type) != deviceAddresses.end();
}
ScanI2C::FoundDevice ScanI2CTwoWire::firstOfOrNONE(size_t count, DeviceType types[]) const
{
concurrency::LockGuard guard((concurrency::Lock *)&lock);
for (size_t k = 0; k < count; k++) {
ScanI2C::DeviceType current = types[k];
if (exists(current)) {
return ScanI2C::FoundDevice(current, deviceAddresses.at(current));
}
}
return DEVICE_NONE;
}
ScanI2C::DeviceType ScanI2CTwoWire::probeOLED(ScanI2C::DeviceAddress addr) const
{
TwoWire *i2cBus = fetchI2CBus(addr);
uint8_t r = 0;
uint8_t r_prev = 0;
uint8_t c = 0;
ScanI2C::DeviceType o_probe = ScanI2C::DeviceType::SCREEN_UNKNOWN;
do {
r_prev = r;
i2cBus->beginTransmission(addr.address);
i2cBus->write((uint8_t)0x00);
i2cBus->endTransmission();
i2cBus->requestFrom((int)addr.address, 1);
if (i2cBus->available()) {
r = i2cBus->read();
}
r &= 0x0f;
if (r == 0x08 || r == 0x00) {
LOG_INFO("sh1106 display found\n");
o_probe = SCREEN_SH1106; // SH1106
} else if (r == 0x03 || r == 0x04 || r == 0x06 || r == 0x07) {
LOG_INFO("ssd1306 display found\n");
o_probe = SCREEN_SSD1306; // SSD1306
}
c++;
} while ((r != r_prev) && (c < 4));
LOG_DEBUG("0x%x subtype probed in %i tries \n", r, c);
return o_probe;
}
void ScanI2CTwoWire::printATECCInfo() const
{
#if !defined(ARCH_PORTDUINO) && !defined(ARCH_STM32WL)
atecc.readConfigZone(false);
LOG_DEBUG("ATECC608B Serial Number: ");
for (int i = 0; i < 9; i++) {
LOG_DEBUG("%02x", atecc.serialNumber[i]);
}
LOG_DEBUG(", Rev Number: ");
for (int i = 0; i < 4; i++) {
LOG_DEBUG("%02x", atecc.revisionNumber[i]);
}
LOG_DEBUG("\n");
LOG_DEBUG("ATECC608B Config %s", atecc.configLockStatus ? "Locked" : "Unlocked");
LOG_DEBUG(", Data %s", atecc.dataOTPLockStatus ? "Locked" : "Unlocked");
LOG_DEBUG(", Slot 0 %s\n", atecc.slot0LockStatus ? "Locked" : "Unlocked");
if (atecc.configLockStatus && atecc.dataOTPLockStatus && atecc.slot0LockStatus) {
if (atecc.generatePublicKey() == false) {
LOG_DEBUG("ATECC608B Error generating public key\n");
} else {
LOG_DEBUG("ATECC608B Public Key: ");
for (int i = 0; i < 64; i++) {
LOG_DEBUG("%02x", atecc.publicKey64Bytes[i]);
}
LOG_DEBUG("\n");
}
}
#endif
}
uint16_t ScanI2CTwoWire::getRegisterValue(const ScanI2CTwoWire::RegisterLocation &registerLocation,
ScanI2CTwoWire::ResponseWidth responseWidth) const
{
uint16_t value = 0x00;
TwoWire *i2cBus = fetchI2CBus(registerLocation.i2cAddress);
i2cBus->beginTransmission(registerLocation.i2cAddress.address);
i2cBus->write(registerLocation.registerAddress);
i2cBus->endTransmission();
delay(20);
i2cBus->requestFrom(registerLocation.i2cAddress.address, responseWidth);
LOG_DEBUG("Wire.available() = %d\n", i2cBus->available());
if (i2cBus->available() == 2) {
// Read MSB, then LSB
value = (uint16_t)i2cBus->read() << 8;
value |= i2cBus->read();
} else if (i2cBus->available()) {
value = i2cBus->read();
}
return value;
}
#define SCAN_SIMPLE_CASE(ADDR, T, ...) \
case ADDR: \
LOG_INFO(__VA_ARGS__); \
type = T; \
break;
void ScanI2CTwoWire::scanPort(I2CPort port)
{
concurrency::LockGuard guard((concurrency::Lock *)&lock);
LOG_DEBUG("Scanning for i2c devices on port %d\n", port);
uint8_t err;
DeviceAddress addr(port, 0x00);
uint16_t registerValue = 0x00;
ScanI2C::DeviceType type;
TwoWire *i2cBus;
#ifdef RV3028_RTC
Melopero_RV3028 rtc;
#endif
#ifdef I2C_SDA1
if (port == I2CPort::WIRE1) {
i2cBus = &Wire1;
} else {
#endif
i2cBus = &Wire;
#ifdef I2C_SDA1
}
#endif
for (addr.address = 1; addr.address < 127; addr.address++) {
i2cBus->beginTransmission(addr.address);
err = i2cBus->endTransmission();
type = NONE;
if (err == 0) {
LOG_DEBUG("I2C device found at address 0x%x\n", addr.address);
switch (addr.address) {
case SSD1306_ADDRESS:
type = probeOLED(addr);
break;
#if !defined(ARCH_PORTDUINO) && !defined(ARCH_STM32WL)
case ATECC608B_ADDR:
type = ATECC608B;
if (atecc.begin(addr.address) == true) {
LOG_INFO("ATECC608B initialized\n");
} else {
LOG_WARN("ATECC608B initialization failed\n");
}
printATECCInfo();
break;
#endif
#ifdef RV3028_RTC
case RV3028_RTC:
// foundDevices[addr] = RTC_RV3028;
type = RTC_RV3028;
LOG_INFO("RV3028 RTC found\n");
rtc.initI2C(*i2cBus);
rtc.writeToRegister(0x35, 0x07); // no Clkout
rtc.writeToRegister(0x37, 0xB4);
break;
#endif
#ifdef PCF8563_RTC
SCAN_SIMPLE_CASE(PCF8563_RTC, RTC_PCF8563, "PCF8563 RTC found\n")
#endif
case CARDKB_ADDR:
// Do we have the RAK14006 instead?
registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0x04), 1);
if (registerValue == 0x02) {
// KEYPAD_VERSION
LOG_INFO("RAK14004 found\n");
type = RAK14004;
} else {
LOG_INFO("m5 cardKB found\n");
type = CARDKB;
}
break;
SCAN_SIMPLE_CASE(ST7567_ADDRESS, SCREEN_ST7567, "st7567 display found\n")
#ifdef HAS_PMU
SCAN_SIMPLE_CASE(XPOWERS_AXP192_AXP2101_ADDRESS, PMU_AXP192_AXP2101, "axp192/axp2101 PMU found\n")
#endif
case BME_ADDR:
case BME_ADDR_ALTERNATE:
registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0xD0), 1); // GET_ID
switch (registerValue) {
case 0x61:
LOG_INFO("BME-680 sensor found at address 0x%x\n", (uint8_t)addr.address);
type = BME_680;
break;
case 0x60:
LOG_INFO("BME-280 sensor found at address 0x%x\n", (uint8_t)addr.address);
type = BME_280;
break;
default:
LOG_INFO("BMP-280 sensor found at address 0x%x\n", (uint8_t)addr.address);
type = BMP_280;
}
break;
case INA_ADDR:
case INA_ADDR_ALTERNATE:
registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0xFE), 2);
LOG_DEBUG("Register MFG_UID: 0x%x\n", registerValue);
if (registerValue == 0x5449) {
LOG_INFO("INA260 sensor found at address 0x%x\n", (uint8_t)addr.address);
type = INA260;
} else { // Assume INA219 if INA260 ID is not found
LOG_INFO("INA219 sensor found at address 0x%x\n", (uint8_t)addr.address);
type = INA219;
}
break;
SCAN_SIMPLE_CASE(MCP9808_ADDR, MCP9808, "MCP9808 sensor found\n")
SCAN_SIMPLE_CASE(SHT31_ADDR, SHT31, "SHT31 sensor found\n")
SCAN_SIMPLE_CASE(SHTC3_ADDR, SHTC3, "SHTC3 sensor found\n")
case LPS22HB_ADDR_ALT:
SCAN_SIMPLE_CASE(LPS22HB_ADDR, LPS22HB, "LPS22HB sensor found\n")
SCAN_SIMPLE_CASE(QMC6310_ADDR, QMC6310, "QMC6310 Highrate 3-Axis magnetic sensor found\n")
SCAN_SIMPLE_CASE(QMI8658_ADDR, QMI8658, "QMI8658 Highrate 6-Axis inertial measurement sensor found\n")
SCAN_SIMPLE_CASE(QMC5883L_ADDR, QMC5883L, "QMC5883L Highrate 3-Axis magnetic sensor found\n")
SCAN_SIMPLE_CASE(PMSA0031_ADDR, PMSA0031, "PMSA0031 air quality sensor found\n")
default:
LOG_INFO("Device found at address 0x%x was not able to be enumerated\n", addr.address);
}
} else if (err == 4) {
LOG_ERROR("Unknown error at address 0x%x\n", addr);
}
// Check if a type was found for the enumerated device - save, if so
if (type != NONE) {
deviceAddresses[type] = addr;
foundDevices[addr] = type;
}
}
}
TwoWire *ScanI2CTwoWire::fetchI2CBus(ScanI2C::DeviceAddress address) const
{
if (address.port == ScanI2C::I2CPort::WIRE1) {
return &Wire;
} else {
#ifdef I2C_SDA1
return &Wire1;
#else
return &Wire;
#endif
}
}
size_t ScanI2CTwoWire::countDevices() const
{
return foundDevices.size();
}

View File

@ -0,0 +1,56 @@
#pragma once
#include <map>
#include <memory>
#include <stddef.h>
#include <stdint.h>
#include <Wire.h>
#include "ScanI2C.h"
#include "../concurrency/Lock.h"
class ScanI2CTwoWire : public ScanI2C
{
public:
void scanPort(ScanI2C::I2CPort) override;
ScanI2C::FoundDevice find(ScanI2C::DeviceType) const override;
bool exists(ScanI2C::DeviceType) const override;
size_t countDevices() const override;
protected:
FoundDevice firstOfOrNONE(size_t, DeviceType[]) const override;
private:
typedef struct RegisterLocation {
DeviceAddress i2cAddress;
RegisterAddress registerAddress;
RegisterLocation(DeviceAddress deviceAddress, RegisterAddress registerAddress)
: i2cAddress(deviceAddress), registerAddress(registerAddress)
{
}
} RegisterLocation;
typedef uint8_t ResponseWidth;
std::map<ScanI2C::DeviceAddress, ScanI2C::DeviceType> foundDevices;
// note: prone to overwriting if multiple devices of a type are added at different addresses (rare?)
std::map<ScanI2C::DeviceType, ScanI2C::DeviceAddress> deviceAddresses;
concurrency::Lock lock;
void printATECCInfo() const;
uint16_t getRegisterValue(const RegisterLocation &, ResponseWidth) const;
DeviceType probeOLED(ScanI2C::DeviceAddress) const;
TwoWire *fetchI2CBus(ScanI2C::DeviceAddress) const;
};

View File

@ -1,237 +0,0 @@
#include "../configuration.h"
#include "../main.h"
#include "mesh/generated/meshtastic/telemetry.pb.h"
#include <Wire.h>
// AXP192 and AXP2101 have the same device address, we just need to identify it in Power.cpp
#ifndef XPOWERS_AXP192_AXP2101_ADDRESS
#define XPOWERS_AXP192_AXP2101_ADDRESS 0x34
#endif
#if HAS_WIRE
void printATECCInfo()
{
#if !defined(ARCH_PORTDUINO) && !defined(ARCH_STM32WL)
atecc.readConfigZone(false);
LOG_DEBUG("ATECC608B Serial Number: ");
for (int i = 0; i < 9; i++) {
LOG_DEBUG("%02x", atecc.serialNumber[i]);
}
LOG_DEBUG(", Rev Number: ");
for (int i = 0; i < 4; i++) {
LOG_DEBUG("%02x", atecc.revisionNumber[i]);
}
LOG_DEBUG("\n");
LOG_DEBUG("ATECC608B Config %s", atecc.configLockStatus ? "Locked" : "Unlocked");
LOG_DEBUG(", Data %s", atecc.dataOTPLockStatus ? "Locked" : "Unlocked");
LOG_DEBUG(", Slot 0 %s\n", atecc.slot0LockStatus ? "Locked" : "Unlocked");
if (atecc.configLockStatus && atecc.dataOTPLockStatus && atecc.slot0LockStatus) {
if (atecc.generatePublicKey() == false) {
LOG_DEBUG("ATECC608B Error generating public key\n");
} else {
LOG_DEBUG("ATECC608B Public Key: ");
for (int i = 0; i < 64; i++) {
LOG_DEBUG("%02x", atecc.publicKey64Bytes[i]);
}
LOG_DEBUG("\n");
}
}
#endif
}
uint16_t getRegisterValue(uint8_t address, uint8_t reg, uint8_t length)
{
uint16_t value = 0x00;
Wire.beginTransmission(address);
Wire.write(reg);
Wire.endTransmission();
delay(20);
Wire.requestFrom(address, length);
LOG_DEBUG("Wire.available() = %d\n", Wire.available());
if (Wire.available() == 2) {
// Read MSB, then LSB
value = (uint16_t)Wire.read() << 8;
value |= Wire.read();
} else if (Wire.available()) {
value = Wire.read();
}
return value;
}
uint8_t oled_probe(byte addr)
{
uint8_t r = 0;
uint8_t r_prev = 0;
uint8_t c = 0;
uint8_t o_probe = 0;
do {
r_prev = r;
Wire.beginTransmission(addr);
Wire.write(0x00);
Wire.endTransmission();
Wire.requestFrom((int)addr, 1);
if (Wire.available()) {
r = Wire.read();
}
r &= 0x0f;
if (r == 0x08 || r == 0x00) {
o_probe = 2; // SH1106
} else if (r == 0x03 || r == 0x04 || r == 0x06 || r == 0x07) {
o_probe = 1; // SSD1306
}
c++;
} while ((r != r_prev) && (c < 4));
LOG_DEBUG("0x%x subtype probed in %i tries \n", r, c);
return o_probe;
}
void scanI2Cdevice()
{
byte err, addr;
uint16_t registerValue = 0x00;
int nDevices = 0;
for (addr = 1; addr < 127; addr++) {
Wire.beginTransmission(addr);
err = Wire.endTransmission();
if (err == 0) {
LOG_DEBUG("I2C device found at address 0x%x\n", addr);
nDevices++;
if (addr == SSD1306_ADDRESS) {
screen_found = addr;
screen_model = oled_probe(addr);
if (screen_model == 1) {
LOG_INFO("ssd1306 display found\n");
} else if (screen_model == 2) {
LOG_INFO("sh1106 display found\n");
} else {
LOG_INFO("unknown display found\n");
}
}
#if !defined(ARCH_PORTDUINO) && !defined(ARCH_STM32WL)
if (addr == ATECC608B_ADDR) {
keystore_found = addr;
if (atecc.begin(keystore_found) == true) {
LOG_INFO("ATECC608B initialized\n");
} else {
LOG_WARN("ATECC608B initialization failed\n");
}
printATECCInfo();
}
#endif
#ifdef RV3028_RTC
if (addr == RV3028_RTC) {
rtc_found = addr;
LOG_INFO("RV3028 RTC found\n");
Melopero_RV3028 rtc;
rtc.initI2C();
rtc.writeToRegister(0x35, 0x07); // no Clkout
rtc.writeToRegister(0x37, 0xB4);
}
#endif
#ifdef PCF8563_RTC
if (addr == PCF8563_RTC) {
rtc_found = addr;
LOG_INFO("PCF8563 RTC found\n");
}
#endif
if (addr == CARDKB_ADDR) {
cardkb_found = addr;
// Do we have the RAK14006 instead?
registerValue = getRegisterValue(addr, 0x04, 1);
if (registerValue == 0x02) { // KEYPAD_VERSION
LOG_INFO("RAK14004 found\n");
kb_model = 0x02;
} else {
LOG_INFO("m5 cardKB found\n");
kb_model = 0x00;
}
}
if (addr == ST7567_ADDRESS) {
screen_found = addr;
LOG_INFO("st7567 display found\n");
}
#ifdef HAS_PMU
if (addr == XPOWERS_AXP192_AXP2101_ADDRESS) {
pmu_found = true;
LOG_INFO("axp192/axp2101 PMU found\n");
}
#endif
if (addr == BME_ADDR || addr == BME_ADDR_ALTERNATE) {
registerValue = getRegisterValue(addr, 0xD0, 1); // GET_ID
if (registerValue == 0x61) {
LOG_INFO("BME-680 sensor found at address 0x%x\n", (uint8_t)addr);
nodeTelemetrySensorsMap[meshtastic_TelemetrySensorType_BME680] = addr;
} else if (registerValue == 0x60) {
LOG_INFO("BME-280 sensor found at address 0x%x\n", (uint8_t)addr);
nodeTelemetrySensorsMap[meshtastic_TelemetrySensorType_BME280] = addr;
} else {
LOG_INFO("BMP-280 sensor found at address 0x%x\n", (uint8_t)addr);
nodeTelemetrySensorsMap[meshtastic_TelemetrySensorType_BMP280] = addr;
}
}
if (addr == INA_ADDR || addr == INA_ADDR_ALTERNATE) {
registerValue = getRegisterValue(addr, 0xFE, 2);
LOG_DEBUG("Register MFG_UID: 0x%x\n", registerValue);
if (registerValue == 0x5449) {
LOG_INFO("INA260 sensor found at address 0x%x\n", (uint8_t)addr);
nodeTelemetrySensorsMap[meshtastic_TelemetrySensorType_INA260] = addr;
} else { // Assume INA219 if INA260 ID is not found
LOG_INFO("INA219 sensor found at address 0x%x\n", (uint8_t)addr);
nodeTelemetrySensorsMap[meshtastic_TelemetrySensorType_INA219] = addr;
}
}
if (addr == MCP9808_ADDR) {
nodeTelemetrySensorsMap[meshtastic_TelemetrySensorType_MCP9808] = addr;
LOG_INFO("MCP9808 sensor found\n");
}
if (addr == SHT31_ADDR) {
LOG_INFO("SHT31 sensor found\n");
nodeTelemetrySensorsMap[meshtastic_TelemetrySensorType_SHT31] = addr;
}
if (addr == SHTC3_ADDR) {
LOG_INFO("SHTC3 sensor found\n");
nodeTelemetrySensorsMap[meshtastic_TelemetrySensorType_SHTC3] = addr;
}
if (addr == LPS22HB_ADDR || addr == LPS22HB_ADDR_ALT) {
LOG_INFO("LPS22HB sensor found\n");
nodeTelemetrySensorsMap[meshtastic_TelemetrySensorType_LPS22] = addr;
}
// High rate sensors, will be processed internally
if (addr == QMC6310_ADDR) {
LOG_INFO("QMC6310 Highrate 3-Axis magnetic sensor found\n");
nodeTelemetrySensorsMap[meshtastic_TelemetrySensorType_QMC6310] = addr;
}
if (addr == QMI8658_ADDR) {
LOG_INFO("QMI8658 Highrate 6-Axis inertial measurement sensor found\n");
nodeTelemetrySensorsMap[meshtastic_TelemetrySensorType_QMI8658] = addr;
}
if (addr == QMC5883L_ADDR) {
LOG_INFO("QMC5883L Highrate 3-Axis magnetic sensor found\n");
nodeTelemetrySensorsMap[meshtastic_TelemetrySensorType_QMC5883L] = addr;
}
if (addr == PMSA0031_ADDR) {
LOG_INFO("PMSA0031 air quality sensor found\n");
nodeTelemetrySensorsMap[meshtastic_TelemetrySensorType_PMSA003I] = addr;
}
} else if (err == 4) {
LOG_ERROR("Unknow error at address 0x%x\n", addr);
}
}
if (nDevices == 0)
LOG_INFO("No I2C devices found\n");
else
LOG_INFO("%i I2C devices found\n", nDevices);
}
#else
void scanI2Cdevice() {}
#endif

View File

@ -1,5 +1,6 @@
#include "RTC.h" #include "RTC.h"
#include "configuration.h" #include "configuration.h"
#include "detect/ScanI2C.h"
#include "main.h" #include "main.h"
#include <sys/time.h> #include <sys/time.h>
#include <time.h> #include <time.h>
@ -20,10 +21,14 @@ void readFromRTC()
{ {
struct timeval tv; /* btw settimeofday() is helpfull here too*/ struct timeval tv; /* btw settimeofday() is helpfull here too*/
#ifdef RV3028_RTC #ifdef RV3028_RTC
if (rtc_found == RV3028_RTC) { if (rtc_found.address == RV3028_RTC) {
uint32_t now = millis(); uint32_t now = millis();
Melopero_RV3028 rtc; Melopero_RV3028 rtc;
#ifdef I2C_SDA1
rtc.initI2C(rtc_found.port == ScanI2C::I2CPort::WIRE1 ? Wire1 : Wire);
#else
rtc.initI2C(); rtc.initI2C();
#endif
tm t; tm t;
t.tm_year = rtc.getYear() - 1900; t.tm_year = rtc.getYear() - 1900;
t.tm_mon = rtc.getMonth() - 1; t.tm_mon = rtc.getMonth() - 1;
@ -41,14 +46,16 @@ void readFromRTC()
} }
} }
#elif defined(PCF8563_RTC) #elif defined(PCF8563_RTC)
if (rtc_found == PCF8563_RTC) { if (rtc_found.address == PCF8563_RTC) {
uint32_t now = millis(); uint32_t now = millis();
PCF8563_Class rtc; PCF8563_Class rtc;
#ifdef RTC_USE_WIRE1
rtc.begin(Wire1); #ifdef I2C_SDA1
rtc.begin(rtc_found.port == ScanI2C::I2CPort::WIRE1 ? Wire1 : Wire);
#else #else
rtc.begin(); rtc.begin();
#endif #endif
auto tc = rtc.getDateTime(); auto tc = rtc.getDateTime();
tm t; tm t;
t.tm_year = tc.year - 1900; t.tm_year = tc.year - 1900;
@ -103,19 +110,24 @@ bool perhapsSetRTC(RTCQuality q, const struct timeval *tv)
// If this platform has a setable RTC, set it // If this platform has a setable RTC, set it
#ifdef RV3028_RTC #ifdef RV3028_RTC
if (rtc_found == RV3028_RTC) { if (rtc_found.address == RV3028_RTC) {
Melopero_RV3028 rtc; Melopero_RV3028 rtc;
#ifdef I2C_SDA1
rtc.initI2C(rtc_found.port == ScanI2C::I2CPort::WIRE1 ? Wire1 : Wire);
#else
rtc.initI2C(); rtc.initI2C();
#endif
tm *t = localtime(&tv->tv_sec); tm *t = localtime(&tv->tv_sec);
rtc.setTime(t->tm_year + 1900, t->tm_mon + 1, t->tm_wday, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec); rtc.setTime(t->tm_year + 1900, t->tm_mon + 1, t->tm_wday, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec);
LOG_DEBUG("RV3028_RTC setTime %02d-%02d-%02d %02d:%02d:%02d %ld\n", t->tm_year + 1900, t->tm_mon + 1, t->tm_mday, LOG_DEBUG("RV3028_RTC setTime %02d-%02d-%02d %02d:%02d:%02d %ld\n", t->tm_year + 1900, t->tm_mon + 1, t->tm_mday,
t->tm_hour, t->tm_min, t->tm_sec, tv->tv_sec); t->tm_hour, t->tm_min, t->tm_sec, tv->tv_sec);
} }
#elif defined(PCF8563_RTC) #elif defined(PCF8563_RTC)
if (rtc_found == PCF8563_RTC) { if (rtc_found.address == PCF8563_RTC) {
PCF8563_Class rtc; PCF8563_Class rtc;
#ifdef RTC_USE_WIRE1
rtc.begin(Wire1); #ifdef I2C_SDA1
rtc.begin(rtc_found.port == ScanI2C::I2CPort::WIRE1 ? Wire1 : Wire);
#else #else
rtc.begin(); rtc.begin();
#endif #endif

View File

@ -41,7 +41,7 @@
GxEPD2_BW<TECHO_DISPLAY_MODEL, TECHO_DISPLAY_MODEL::HEIGHT> *adafruitDisplay; GxEPD2_BW<TECHO_DISPLAY_MODEL, TECHO_DISPLAY_MODEL::HEIGHT> *adafruitDisplay;
EInkDisplay::EInkDisplay(uint8_t address, int sda, int scl, uint8_t screen_model) EInkDisplay::EInkDisplay(uint8_t address, int sda, int scl, OLEDDISPLAY_GEOMETRY geometry, HW_I2C i2cBus)
{ {
#if defined(TTGO_T_ECHO) #if defined(TTGO_T_ECHO)
setGeometry(GEOMETRY_RAWMODE, TECHO_DISPLAY_MODEL::WIDTH, TECHO_DISPLAY_MODEL::HEIGHT); setGeometry(GEOMETRY_RAWMODE, TECHO_DISPLAY_MODEL::WIDTH, TECHO_DISPLAY_MODEL::HEIGHT);

View File

@ -22,7 +22,7 @@ class EInkDisplay : public OLEDDisplay
/* constructor /* constructor
FIXME - the parameters are not used, just a temporary hack to keep working like the old displays FIXME - the parameters are not used, just a temporary hack to keep working like the old displays
*/ */
EInkDisplay(uint8_t address, int sda, int scl, uint8_t screen_model); EInkDisplay(uint8_t, int, int, OLEDDISPLAY_GEOMETRY, HW_I2C);
// Write the buffer to the display memory (for eink we only do this occasionally) // Write the buffer to the display memory (for eink we only do this occasionally)
virtual void display(void) override; virtual void display(void) override;

View File

@ -19,6 +19,7 @@ You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "Screen.h"
#include "configuration.h" #include "configuration.h"
#if HAS_SCREEN #if HAS_SCREEN
#include <OLEDDisplay.h> #include <OLEDDisplay.h>
@ -26,7 +27,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "GPS.h" #include "GPS.h"
#include "MeshService.h" #include "MeshService.h"
#include "NodeDB.h" #include "NodeDB.h"
#include "Screen.h"
#include "gps/GeoCoord.h" #include "gps/GeoCoord.h"
#include "gps/RTC.h" #include "gps/RTC.h"
#include "graphics/images.h" #include "graphics/images.h"
@ -886,13 +886,11 @@ static void drawNodeInfo(OLEDDisplay *display, OLEDDisplayUiState *state, int16_
// } // }
// } // }
// #else // #else
Screen::Screen(uint8_t address, int sda, int scl) Screen::Screen(ScanI2C::DeviceAddress address, meshtastic_Config_DisplayConfig_OledType screenType, OLEDDISPLAY_GEOMETRY geometry)
: OSThread("Screen"), cmdQueue(32), : concurrency::OSThread("Screen"), address_found(address), model(screenType), geometry(geometry), cmdQueue(32),
dispdev(address, sda, scl, dispdev(address.address, -1, -1, geometry, (address.port == ScanI2C::I2CPort::WIRE1) ? HW_I2C::I2C_TWO : HW_I2C::I2C_ONE),
screen_model == meshtastic_Config_DisplayConfig_OledType_OLED_SH1107 ? GEOMETRY_128_128 : GEOMETRY_128_64),
ui(&dispdev) ui(&dispdev)
{ {
address_found = address;
cmdQueue.setReader(this); cmdQueue.setReader(this);
} }
// #endif // #endif
@ -940,9 +938,11 @@ void Screen::setup()
useDisplay = true; useDisplay = true;
#ifdef AutoOLEDWire_h #ifdef AutoOLEDWire_h
if (screen_model == meshtastic_Config_DisplayConfig_OledType_OLED_SH1107) dispdev.setDetected(model);
screen_model = meshtastic_Config_DisplayConfig_OledType_OLED_SH1106; #endif
dispdev.setDetected(screen_model);
#ifdef USE_SH1107_128_64
dispdev.setSubtype(7);
#endif #endif
// Initialising the UI will init the display too. // Initialising the UI will init the display too.
@ -1177,7 +1177,7 @@ void Screen::drawDebugInfoWiFiTrampoline(OLEDDisplay *display, OLEDDisplayUiStat
* it is expected that this will be used during the boot phase */ * it is expected that this will be used during the boot phase */
void Screen::setSSLFrames() void Screen::setSSLFrames()
{ {
if (address_found) { if (address_found.address) {
// LOG_DEBUG("showing SSL frames\n"); // LOG_DEBUG("showing SSL frames\n");
static FrameCallback sslFrames[] = {drawSSLScreen}; static FrameCallback sslFrames[] = {drawSSLScreen};
ui.setFrames(sslFrames, 1); ui.setFrames(sslFrames, 1);
@ -1189,7 +1189,7 @@ void Screen::setSSLFrames()
* it is expected that this will be used during the boot phase */ * it is expected that this will be used during the boot phase */
void Screen::setWelcomeFrames() void Screen::setWelcomeFrames()
{ {
if (address_found) { if (address_found.address) {
// LOG_DEBUG("showing Welcome frames\n"); // LOG_DEBUG("showing Welcome frames\n");
ui.disableAllIndicators(); ui.disableAllIndicators();
@ -1821,5 +1821,6 @@ int Screen::handleUIFrameEvent(const UIFrameEvent *event)
} }
} // namespace graphics } // namespace graphics
#else
graphics::Screen::Screen(ScanI2C::DeviceAddress, meshtastic_Config_DisplayConfig_OledType, OLEDDISPLAY_GEOMETRY) {}
#endif // HAS_SCREEN #endif // HAS_SCREEN

View File

@ -2,6 +2,10 @@
#include "configuration.h" #include "configuration.h"
#include "detect/ScanI2C.h"
#include "mesh/generated/meshtastic/config.pb.h"
#include <OLEDDisplay.h>
#if !HAS_SCREEN #if !HAS_SCREEN
#include "power.h" #include "power.h"
namespace graphics namespace graphics
@ -10,7 +14,7 @@ namespace graphics
class Screen class Screen
{ {
public: public:
explicit Screen(char) {} explicit Screen(ScanI2C::DeviceAddress, meshtastic_Config_DisplayConfig_OledType, OLEDDISPLAY_GEOMETRY);
void onPress() {} void onPress() {}
void setup() {} void setup() {}
void setOn(bool) {} void setOn(bool) {}
@ -24,7 +28,6 @@ class Screen
void startFirmwareUpdateScreen() {} void startFirmwareUpdateScreen() {}
}; };
} // namespace graphics } // namespace graphics
#else #else
#include <cstring> #include <cstring>
@ -34,7 +37,7 @@ class Screen
#ifdef USE_ST7567 #ifdef USE_ST7567
#include <ST7567Wire.h> #include <ST7567Wire.h>
#elif defined(USE_SH1106) || defined(USE_SH1107) #elif defined(USE_SH1106) || defined(USE_SH1107) || defined(USE_SH1107_128_64)
#include <SH1106Wire.h> #include <SH1106Wire.h>
#elif defined(USE_SSD1306) #elif defined(USE_SSD1306)
#include <SSD1306Wire.h> #include <SSD1306Wire.h>
@ -116,12 +119,14 @@ class Screen : public concurrency::OSThread
CallbackObserver<Screen, const UIFrameEvent *>(this, &Screen::handleUIFrameEvent); CallbackObserver<Screen, const UIFrameEvent *>(this, &Screen::handleUIFrameEvent);
public: public:
explicit Screen(uint8_t address, int sda = -1, int scl = -1); explicit Screen(ScanI2C::DeviceAddress, meshtastic_Config_DisplayConfig_OledType, OLEDDISPLAY_GEOMETRY);
Screen(const Screen &) = delete; Screen(const Screen &) = delete;
Screen &operator=(const Screen &) = delete; Screen &operator=(const Screen &) = delete;
uint8_t address_found; ScanI2C::DeviceAddress address_found;
meshtastic_Config_DisplayConfig_OledType model;
OLEDDISPLAY_GEOMETRY geometry;
/// Initializes the UI, turns on the display, starts showing boot screen. /// Initializes the UI, turns on the display, starts showing boot screen.
// //
@ -370,7 +375,7 @@ class Screen : public concurrency::OSThread
/// Display device /// Display device
#if defined(USE_SH1106) || defined(USE_SH1107) #if defined(USE_SH1106) || defined(USE_SH1107) || defined(USE_SH1107_128_64)
SH1106Wire dispdev; SH1106Wire dispdev;
#elif defined(USE_SSD1306) #elif defined(USE_SSD1306)
SSD1306Wire dispdev; SSD1306Wire dispdev;

View File

@ -8,7 +8,7 @@
static TFT_eSPI tft = TFT_eSPI(); // Invoke library, pins defined in User_Setup.h static TFT_eSPI tft = TFT_eSPI(); // Invoke library, pins defined in User_Setup.h
TFTDisplay::TFTDisplay(uint8_t address, int sda, int scl, uint8_t screen_model) TFTDisplay::TFTDisplay(uint8_t address, int sda, int scl, OLEDDISPLAY_GEOMETRY geometry, HW_I2C i2cBus)
{ {
#ifdef SCREEN_ROTATE #ifdef SCREEN_ROTATE
setGeometry(GEOMETRY_RAWMODE, TFT_HEIGHT, TFT_WIDTH); setGeometry(GEOMETRY_RAWMODE, TFT_HEIGHT, TFT_WIDTH);

View File

@ -18,7 +18,7 @@ class TFTDisplay : public OLEDDisplay
/* constructor /* constructor
FIXME - the parameters are not used, just a temporary hack to keep working like the old displays FIXME - the parameters are not used, just a temporary hack to keep working like the old displays
*/ */
TFTDisplay(uint8_t address, int sda, int scl, uint8_t screen_model); TFTDisplay(uint8_t, int, int, OLEDDISPLAY_GEOMETRY, HW_I2C);
// Write the buffer to the display memory // Write the buffer to the display memory
virtual void display(void) override; virtual void display(void) override;

View File

@ -7,7 +7,7 @@ CardKbI2cImpl::CardKbI2cImpl() : KbI2cBase("cardKB") {}
void CardKbI2cImpl::init() void CardKbI2cImpl::init()
{ {
if (cardkb_found != CARDKB_ADDR) { if (cardkb_found.address != CARDKB_ADDR) {
disable(); disable();
return; return;
} }

View File

@ -1,8 +1,9 @@
#include "kbI2cBase.h" #include "kbI2cBase.h"
#include "configuration.h"
#include <Wire.h>
extern uint8_t cardkb_found; #include "configuration.h"
#include "detect/ScanI2C.h"
extern ScanI2C::DeviceAddress cardkb_found;
extern uint8_t kb_model; extern uint8_t kb_model;
KbI2cBase::KbI2cBase(const char *name) : concurrency::OSThread(name) KbI2cBase::KbI2cBase(const char *name) : concurrency::OSThread(name)
@ -10,43 +11,64 @@ KbI2cBase::KbI2cBase(const char *name) : concurrency::OSThread(name)
this->_originName = name; this->_originName = name;
} }
uint8_t read_from_14004(uint8_t reg, uint8_t *data, uint8_t length) uint8_t read_from_14004(TwoWire *i2cBus, uint8_t reg, uint8_t *data, uint8_t length)
{ {
uint8_t readflag = 0; uint8_t readflag = 0;
Wire.beginTransmission(CARDKB_ADDR); i2cBus->beginTransmission(CARDKB_ADDR);
Wire.write(reg); i2cBus->write(reg);
Wire.endTransmission(); // stop transmitting i2cBus->endTransmission(); // stop transmitting
delay(20); delay(20);
Wire.requestFrom(CARDKB_ADDR, (int)length); i2cBus->requestFrom(CARDKB_ADDR, (int)length);
int i = 0; int i = 0;
while (Wire.available()) // slave may send less than requested while (i2cBus->available()) // slave may send less than requested
{ {
data[i++] = Wire.read(); // receive a byte as a proper uint8_t data[i++] = i2cBus->read(); // receive a byte as a proper uint8_t
readflag = 1; readflag = 1;
} }
return readflag; return readflag;
} }
void write_to_14004(uint8_t reg, uint8_t data) // Unused for now - flagging it off
#if 0
void write_to_14004(const TwoWire * i2cBus, uint8_t reg, uint8_t data)
{ {
Wire.beginTransmission(CARDKB_ADDR); i2cBus->beginTransmission(CARDKB_ADDR);
Wire.write(reg); i2cBus->write(reg);
Wire.write(data); i2cBus->write(data);
Wire.endTransmission(); // stop transmitting i2cBus->endTransmission(); // stop transmitting
} }
#endif
int32_t KbI2cBase::runOnce() int32_t KbI2cBase::runOnce()
{ {
if (cardkb_found != CARDKB_ADDR) { if (cardkb_found.address != CARDKB_ADDR) {
// Input device is not detected. // Input device is not detected.
return INT32_MAX; return INT32_MAX;
} }
if (!i2cBus) {
switch (cardkb_found.port) {
case ScanI2C::WIRE1:
#ifdef I2C_SDA1
LOG_DEBUG("Using I2C Bus 1 (the second one)\n");
i2cBus = &Wire1;
break;
#endif
case ScanI2C::WIRE:
LOG_DEBUG("Using I2C Bus 0 (the first one)\n");
i2cBus = &Wire;
break;
case ScanI2C::NO_I2C:
default:
i2cBus = 0;
}
}
if (kb_model == 0x02) { if (kb_model == 0x02) {
// RAK14004 // RAK14004
uint8_t rDataBuf[8] = {0}; uint8_t rDataBuf[8] = {0};
uint8_t PrintDataBuf = 0; uint8_t PrintDataBuf = 0;
if (read_from_14004(0x01, rDataBuf, 0x04) == 1) { if (read_from_14004(i2cBus, 0x01, rDataBuf, 0x04) == 1) {
for (uint8_t aCount = 0; aCount < 0x04; aCount++) { for (uint8_t aCount = 0; aCount < 0x04; aCount++) {
for (uint8_t bCount = 0; bCount < 0x04; bCount++) { for (uint8_t bCount = 0; bCount < 0x04; bCount++) {
if (((rDataBuf[aCount] >> bCount) & 0x01) == 0x01) { if (((rDataBuf[aCount] >> bCount) & 0x01) == 0x01) {
@ -65,10 +87,10 @@ int32_t KbI2cBase::runOnce()
} }
} else { } else {
// m5 cardkb // m5 cardkb
Wire.requestFrom(CARDKB_ADDR, 1); i2cBus->requestFrom(CARDKB_ADDR, 1);
while (Wire.available()) { while (i2cBus->available()) {
char c = Wire.read(); char c = i2cBus->read();
InputEvent e; InputEvent e;
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_NONE; e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_NONE;
e.source = this->_originName; e.source = this->_originName;

View File

@ -2,6 +2,7 @@
#include "InputBroker.h" #include "InputBroker.h"
#include "SinglePortModule.h" // TODO: what header file to include? #include "SinglePortModule.h" // TODO: what header file to include?
#include "Wire.h"
class KbI2cBase : public Observable<const InputEvent *>, public concurrency::OSThread class KbI2cBase : public Observable<const InputEvent *>, public concurrency::OSThread
{ {
@ -13,4 +14,6 @@ class KbI2cBase : public Observable<const InputEvent *>, public concurrency::OST
private: private:
const char *_originName; const char *_originName;
TwoWire *i2cBus = 0;
}; };

View File

@ -15,16 +15,19 @@
#include "SPILock.h" #include "SPILock.h"
#include "concurrency/OSThread.h" #include "concurrency/OSThread.h"
#include "concurrency/Periodic.h" #include "concurrency/Periodic.h"
#include "detect/ScanI2C.h"
#include "detect/ScanI2CTwoWire.h"
#include "detect/axpDebug.h" #include "detect/axpDebug.h"
#include "detect/einkScan.h" #include "detect/einkScan.h"
#include "detect/i2cScan.h"
#include "graphics/Screen.h" #include "graphics/Screen.h"
#include "main.h" #include "main.h"
#include "mesh/generated/meshtastic/config.pb.h"
#include "modules/Modules.h" #include "modules/Modules.h"
#include "shutdown.h" #include "shutdown.h"
#include "sleep.h" #include "sleep.h"
#include "target_specific.h" #include "target_specific.h"
#include <Wire.h> #include <Wire.h>
#include <memory>
// #include <driver/rtc_io.h> // #include <driver/rtc_io.h>
#include "mesh/eth/ethClient.h" #include "mesh/eth/ethClient.h"
@ -79,20 +82,19 @@ meshtastic::GPSStatus *gpsStatus = new meshtastic::GPSStatus();
// Global Node status // Global Node status
meshtastic::NodeStatus *nodeStatus = new meshtastic::NodeStatus(); meshtastic::NodeStatus *nodeStatus = new meshtastic::NodeStatus();
// Scan for I2C Devices
/// The I2C address of our display (if found) /// The I2C address of our display (if found)
uint8_t screen_found; ScanI2C::DeviceAddress screen_found = ScanI2C::ADDRESS_NONE;
uint8_t screen_model;
// The I2C address of the cardkb or RAK14004 (if found) // The I2C address of the cardkb or RAK14004 (if found)
uint8_t cardkb_found; ScanI2C::DeviceAddress cardkb_found = ScanI2C::ADDRESS_NONE;
// 0x02 for RAK14004 and 0x00 for cardkb // 0x02 for RAK14004 and 0x00 for cardkb
uint8_t kb_model; uint8_t kb_model;
// The I2C address of the RTC Module (if found) // The I2C address of the RTC Module (if found)
uint8_t rtc_found; ScanI2C::DeviceAddress rtc_found = ScanI2C::ADDRESS_NONE;
// Keystore Chips
uint8_t keystore_found;
#if !defined(ARCH_PORTDUINO) && !defined(ARCH_STM32WL) #if !defined(ARCH_PORTDUINO) && !defined(ARCH_STM32WL)
ATECCX08A atecc; ATECCX08A atecc;
#endif #endif
@ -173,6 +175,9 @@ __attribute__((weak, noinline)) bool loopCanSleep()
void setup() void setup()
{ {
concurrency::hasBeenSetup = true; concurrency::hasBeenSetup = true;
meshtastic_Config_DisplayConfig_OledType screen_model =
meshtastic_Config_DisplayConfig_OledType::meshtastic_Config_DisplayConfig_OledType_OLED_AUTO;
OLEDDISPLAY_GEOMETRY screen_geometry = GEOMETRY_128_64;
#ifdef SEGGER_STDOUT_CH #ifdef SEGGER_STDOUT_CH
auto mode = false ? SEGGER_RTT_MODE_BLOCK_IF_FIFO_FULL : SEGGER_RTT_MODE_NO_BLOCK_TRIM; auto mode = false ? SEGGER_RTT_MODE_BLOCK_IF_FIFO_FULL : SEGGER_RTT_MODE_NO_BLOCK_TRIM;
@ -259,23 +264,118 @@ void setup()
#endif #endif
// Currently only the tbeam has a PMU // Currently only the tbeam has a PMU
// PMU initialization needs to be placed before scanI2Cdevice // PMU initialization needs to be placed before i2c scanning
power = new Power(); power = new Power();
power->setStatusHandler(powerStatus); power->setStatusHandler(powerStatus);
powerStatus->observe(&power->newStatus); powerStatus->observe(&power->newStatus);
power->setup(); // Must be after status handler is installed, so that handler gets notified of the initial configuration power->setup(); // Must be after status handler is installed, so that handler gets notified of the initial configuration
#ifdef LILYGO_TBEAM_S3_CORE // We need to scan here to decide if we have a screen for nodeDB.init() and because power has been applied to
// In T-Beam-S3-core, the I2C device cannot be scanned before power initialization, otherwise the device will be stuck // accessories
// PCF8563 RTC in tbeam-s3 uses Wire1 to share I2C bus auto i2cScanner = std::unique_ptr<ScanI2CTwoWire>(new ScanI2CTwoWire());
Wire1.beginTransmission(PCF8563_RTC);
if (Wire1.endTransmission() == 0) { LOG_INFO("Scanning for i2c devices...\n");
rtc_found = PCF8563_RTC;
LOG_INFO("PCF8563 RTC found\n"); #ifdef I2C_SDA1
Wire1.begin(I2C_SDA1, I2C_SCL1);
i2cScanner->scanPort(ScanI2C::I2CPort::WIRE1);
#endif
#ifdef I2C_SDA
Wire.begin(I2C_SDA, I2C_SCL);
i2cScanner->scanPort(ScanI2C::I2CPort::WIRE);
#elif HAS_WIRE
i2cScanner->scanPort(ScanI2C::I2CPort::WIRE);
#endif
auto i2cCount = i2cScanner->countDevices();
if (i2cCount == 0) {
LOG_INFO("No I2C devices found\n");
} else {
LOG_INFO("%i I2C devices found\n", i2cCount);
}
#ifdef ARCH_ESP32
// Don't init display if we don't have one or we are waking headless due to a timer event
if (wakeCause == ESP_SLEEP_WAKEUP_TIMER) {
LOG_DEBUG("suppress screen wake because this is a headless timer wakeup");
i2cScanner->setSuppressScreen();
} }
#endif #endif
// We need to scan here to decide if we have a screen for nodeDB.init()
scanI2Cdevice(); auto screenInfo = i2cScanner->firstScreen();
screen_found = screenInfo.type != ScanI2C::DeviceType::NONE ? screenInfo.address : ScanI2C::ADDRESS_NONE;
if (screen_found.port != ScanI2C::I2CPort::NO_I2C) {
switch (screenInfo.type) {
case ScanI2C::DeviceType::SCREEN_SH1106:
screen_model = meshtastic_Config_DisplayConfig_OledType::meshtastic_Config_DisplayConfig_OledType_OLED_SH1106;
break;
case ScanI2C::DeviceType::SCREEN_SSD1306:
screen_model = meshtastic_Config_DisplayConfig_OledType::meshtastic_Config_DisplayConfig_OledType_OLED_SSD1306;
break;
case ScanI2C::DeviceType::SCREEN_ST7567:
case ScanI2C::DeviceType::SCREEN_UNKNOWN:
default:
screen_model = meshtastic_Config_DisplayConfig_OledType::meshtastic_Config_DisplayConfig_OledType_OLED_AUTO;
}
}
#define UPDATE_FROM_SCANNER(FIND_FN)
auto rtc_info = i2cScanner->firstRTC();
rtc_found = rtc_info.type != ScanI2C::DeviceType::NONE ? rtc_info.address : rtc_found;
auto kb_info = i2cScanner->firstKeyboard();
if (kb_info.type != ScanI2C::DeviceType::NONE) {
cardkb_found = kb_info.address;
switch (kb_info.type) {
case ScanI2C::DeviceType::RAK14004:
kb_model = 0x02;
break;
case ScanI2C::DeviceType::CARDKB:
default:
// use this as default since it's also just zero
kb_model = 0x00;
}
}
pmu_found = i2cScanner->exists(ScanI2C::DeviceType::PMU_AXP192_AXP2101);
/*
* There are a bunch of sensors that have no further logic than to be found and stuffed into the
* nodeTelemetrySensorsMap singleton. This wraps that logic in a temporary scope to declare the temporary field
* "found".
*/
#define STRING(S) #S
#define SCANNER_TO_SENSORS_MAP(SCANNER_T, PB_T) \
{ \
auto found = i2cScanner->find(SCANNER_T); \
if (found.type != ScanI2C::DeviceType::NONE) { \
nodeTelemetrySensorsMap[PB_T] = found.address.address; \
LOG_DEBUG("found i2c sensor %s\n", STRING(PB_T)); \
} \
}
SCANNER_TO_SENSORS_MAP(ScanI2C::DeviceType::BME_680, meshtastic_TelemetrySensorType_BME680)
SCANNER_TO_SENSORS_MAP(ScanI2C::DeviceType::BME_280, meshtastic_TelemetrySensorType_BME280)
SCANNER_TO_SENSORS_MAP(ScanI2C::DeviceType::BMP_280, meshtastic_TelemetrySensorType_BMP280)
SCANNER_TO_SENSORS_MAP(ScanI2C::DeviceType::INA260, meshtastic_TelemetrySensorType_INA260)
SCANNER_TO_SENSORS_MAP(ScanI2C::DeviceType::INA219, meshtastic_TelemetrySensorType_INA219)
SCANNER_TO_SENSORS_MAP(ScanI2C::DeviceType::MCP9808, meshtastic_TelemetrySensorType_MCP9808)
SCANNER_TO_SENSORS_MAP(ScanI2C::DeviceType::MCP9808, meshtastic_TelemetrySensorType_MCP9808)
SCANNER_TO_SENSORS_MAP(ScanI2C::DeviceType::SHT31, meshtastic_TelemetrySensorType_SHT31)
SCANNER_TO_SENSORS_MAP(ScanI2C::DeviceType::SHTC3, meshtastic_TelemetrySensorType_SHTC3)
SCANNER_TO_SENSORS_MAP(ScanI2C::DeviceType::LPS22HB, meshtastic_TelemetrySensorType_LPS22)
SCANNER_TO_SENSORS_MAP(ScanI2C::DeviceType::QMC6310, meshtastic_TelemetrySensorType_QMC6310)
SCANNER_TO_SENSORS_MAP(ScanI2C::DeviceType::QMI8658, meshtastic_TelemetrySensorType_QMI8658)
SCANNER_TO_SENSORS_MAP(ScanI2C::DeviceType::QMC5883L, meshtastic_TelemetrySensorType_QMC5883L)
SCANNER_TO_SENSORS_MAP(ScanI2C::DeviceType::PMSA0031, meshtastic_TelemetrySensorType_PMSA003I)
i2cScanner.reset();
#ifdef HAS_SDCARD #ifdef HAS_SDCARD
setupSDCard(); setupSDCard();
@ -299,10 +399,6 @@ void setup()
LOG_INFO("Meshtastic hwvendor=%d, swver=%s\n", HW_VENDOR, optstr(APP_VERSION)); LOG_INFO("Meshtastic hwvendor=%d, swver=%s\n", HW_VENDOR, optstr(APP_VERSION));
#ifdef ARCH_ESP32 #ifdef ARCH_ESP32
// Don't init display if we don't have one or we are waking headless due to a timer event
if (wakeCause == ESP_SLEEP_WAKEUP_TIMER)
screen_found = 0; // forget we even have the hardware
esp32Setup(); esp32Setup();
#endif #endif
@ -324,7 +420,12 @@ void setup()
screen_model = config.display.oled; screen_model = config.display.oled;
#if defined(USE_SH1107) #if defined(USE_SH1107)
screen_model = Config_DisplayConfig_OledType_OLED_SH1107; // set dimension of 128x128 screen_model = meshtastic_Config_DisplayConfig_OledType_OLED_SH1107; // set dimension of 128x128
display_geometry = GEOMETRY_128_128;
#endif
#if defined(USE_SH1107_128_64)
screen_model = meshtastic_Config_DisplayConfig_OledType_OLED_SH1107; // keep dimension of 128x64
#endif #endif
// Init our SPI controller (must be before screen and lora) // Init our SPI controller (must be before screen and lora)
@ -338,7 +439,7 @@ void setup()
#endif #endif
// Initialize the screen first so we can show the logo while we start up everything else. // Initialize the screen first so we can show the logo while we start up everything else.
screen = new graphics::Screen(screen_found); screen = new graphics::Screen(screen_found, screen_model, screen_geometry);
readFromRTC(); // read the main CPU RTC at first (in case we can't get GPS time) readFromRTC(); // read the main CPU RTC at first (in case we can't get GPS time)
@ -367,7 +468,7 @@ void setup()
#if defined(ST7735_CS) || defined(USE_EINK) || defined(ILI9341_DRIVER) #if defined(ST7735_CS) || defined(USE_EINK) || defined(ILI9341_DRIVER)
screen->setup(); screen->setup();
#else #else
if (screen_found) if (screen_found.port != ScanI2C::I2CPort::NO_I2C)
screen->setup(); screen->setup();
#endif #endif

View File

@ -3,8 +3,10 @@
#include "GPSStatus.h" #include "GPSStatus.h"
#include "NodeStatus.h" #include "NodeStatus.h"
#include "PowerStatus.h" #include "PowerStatus.h"
#include "detect/ScanI2C.h"
#include "graphics/Screen.h" #include "graphics/Screen.h"
#include "memGet.h" #include "memGet.h"
#include "mesh/generated/meshtastic/config.pb.h"
#include "mesh/generated/meshtastic/telemetry.pb.h" #include "mesh/generated/meshtastic/telemetry.pb.h"
#include <map> #include <map>
#if !defined(ARCH_PORTDUINO) && !defined(ARCH_STM32WL) #if !defined(ARCH_PORTDUINO) && !defined(ARCH_STM32WL)
@ -19,12 +21,10 @@ extern NimbleBluetooth *nimbleBluetooth;
extern NRF52Bluetooth *nrf52Bluetooth; extern NRF52Bluetooth *nrf52Bluetooth;
#endif #endif
extern uint8_t screen_found; extern ScanI2C::DeviceAddress screen_found;
extern uint8_t screen_model; extern ScanI2C::DeviceAddress cardkb_found;
extern uint8_t cardkb_found;
extern uint8_t kb_model; extern uint8_t kb_model;
extern uint8_t rtc_found; extern ScanI2C::DeviceAddress rtc_found;
extern uint8_t keystore_found;
extern bool eink_found; extern bool eink_found;
extern bool pmu_found; extern bool pmu_found;

View File

@ -1,5 +1,6 @@
#include "configuration.h" #include "configuration.h"
#include "../detect/ScanI2C.h"
#include "Channels.h" #include "Channels.h"
#include "CryptoEngine.h" #include "CryptoEngine.h"
#include "FSCommon.h" #include "FSCommon.h"
@ -181,7 +182,7 @@ void NodeDB::installDefaultConfig()
#if defined(ST7735_CS) || defined(USE_EINK) || defined(ILI9341_DRIVER) #if defined(ST7735_CS) || defined(USE_EINK) || defined(ILI9341_DRIVER)
bool hasScreen = true; bool hasScreen = true;
#else #else
bool hasScreen = screen_found; bool hasScreen = screen_found.port != ScanI2C::I2CPort::NO_I2C;
#endif #endif
config.bluetooth.mode = hasScreen ? meshtastic_Config_BluetoothConfig_PairingMode_RANDOM_PIN config.bluetooth.mode = hasScreen ? meshtastic_Config_BluetoothConfig_PairingMode_RANDOM_PIN
: meshtastic_Config_BluetoothConfig_PairingMode_FIXED_PIN; : meshtastic_Config_BluetoothConfig_PairingMode_FIXED_PIN;

View File

@ -281,7 +281,7 @@ void printPacket(const char *prefix, const meshtastic_MeshPacket *p)
if (p->priority != 0) if (p->priority != 0)
out += DEBUG_PORT.mt_sprintf(" priority=%d", p->priority); out += DEBUG_PORT.mt_sprintf(" priority=%d", p->priority);
out + ")\n"; out += ")\n";
LOG_DEBUG("%s", out.c_str()); LOG_DEBUG("%s", out.c_str());
} }

View File

@ -212,9 +212,10 @@ template <typename T> void SX126xInterface<T>::startReceive()
setStandby(); setStandby();
// int err = lora.startReceive(); // We use a 16 bit preamble so this should save some power by letting radio sit in standby mostly.
int err = lora.startReceiveDutyCycleAuto(); // We use a 32 bit preamble so this should save some power by letting radio sit in // Furthermore, we need the HEADER_VALID IRQ flag to detect whether we are actively receiving
// standby mostly. int err =
lora.startReceiveDutyCycleAuto(preambleLength, 8, RADIOLIB_SX126X_IRQ_RX_DEFAULT | RADIOLIB_SX126X_IRQ_HEADER_VALID);
assert(err == RADIOLIB_ERR_NONE); assert(err == RADIOLIB_ERR_NONE);
isReceiving = true; isReceiving = true;
@ -224,7 +225,7 @@ template <typename T> void SX126xInterface<T>::startReceive()
#endif #endif
} }
/** Could we send right now (i.e. either not actively receving or transmitting)? */ /** Is the channel currently active? */
template <typename T> bool SX126xInterface<T>::isChannelActive() template <typename T> bool SX126xInterface<T>::isChannelActive()
{ {
// check if we can detect a LoRa preamble on the current channel // check if we can detect a LoRa preamble on the current channel
@ -245,17 +246,12 @@ template <typename T> bool SX126xInterface<T>::isActivelyReceiving()
{ {
// The IRQ status will be cleared when we start our read operation. Check if we've started a header, but haven't yet // The IRQ status will be cleared when we start our read operation. Check if we've started a header, but haven't yet
// received and handled the interrupt for reading the packet/handling errors. // received and handled the interrupt for reading the packet/handling errors.
// FIXME: it would be better to check for preamble, but we currently have our ISR not set to fire for packets that
// never even get a valid header, so we don't want preamble to get set and stay set due to noise on the network.
uint16_t irq = lora.getIrqStatus(); uint16_t irq = lora.getIrqStatus();
bool hasPreamble = (irq & RADIOLIB_SX126X_IRQ_HEADER_VALID); bool headerValid = (irq & RADIOLIB_SX126X_IRQ_HEADER_VALID);
// this is not correct - often always true - need to add an extra conditional // if (headerValid) LOG_DEBUG("rx headerValid\n");
// size_t bytesPending = lora.getPacketLength(); return headerValid;
// if (hasPreamble) LOG_DEBUG("rx hasPreamble\n");
return hasPreamble;
} }
template <typename T> bool SX126xInterface<T>::sleep() template <typename T> bool SX126xInterface<T>::sleep()

View File

@ -203,7 +203,9 @@ template <typename T> void SX128xInterface<T>::startReceive()
digitalWrite(SX128X_TXEN, LOW); digitalWrite(SX128X_TXEN, LOW);
#endif #endif
int err = lora.startReceive(); // We use the HEADER_VALID IRQ flag to detect whether we are actively receiving
int err =
lora.startReceive(RADIOLIB_SX128X_RX_TIMEOUT_INF, RADIOLIB_SX128X_IRQ_RX_DEFAULT | RADIOLIB_SX128X_IRQ_HEADER_VALID);
assert(err == RADIOLIB_ERR_NONE); assert(err == RADIOLIB_ERR_NONE);
@ -214,7 +216,7 @@ template <typename T> void SX128xInterface<T>::startReceive()
#endif #endif
} }
/** Could we send right now (i.e. either not actively receving or transmitting)? */ /** Is the channel currently active? */
template <typename T> bool SX128xInterface<T>::isChannelActive() template <typename T> bool SX128xInterface<T>::isChannelActive()
{ {
// check if we can detect a LoRa preamble on the current channel // check if we can detect a LoRa preamble on the current channel
@ -234,8 +236,8 @@ template <typename T> bool SX128xInterface<T>::isChannelActive()
template <typename T> bool SX128xInterface<T>::isActivelyReceiving() template <typename T> bool SX128xInterface<T>::isActivelyReceiving()
{ {
uint16_t irq = lora.getIrqStatus(); uint16_t irq = lora.getIrqStatus();
bool hasPreamble = (irq & RADIOLIB_SX128X_IRQ_HEADER_VALID); bool hasHeader = (irq & RADIOLIB_SX128X_IRQ_HEADER_VALID);
return hasPreamble; return hasHeader;
} }
template <typename T> bool SX128xInterface<T>::sleep() template <typename T> bool SX128xInterface<T>::sleep()

View File

@ -135,7 +135,7 @@ typedef struct _meshtastic_AdminMessage {
/* Tell the node to reboot into the OTA Firmware in this many seconds (or <0 to cancel reboot) /* Tell the node to reboot into the OTA Firmware in this many seconds (or <0 to cancel reboot)
Only Implemented for ESP32 Devices. This needs to be issued to send a new main firmware via bluetooth. */ Only Implemented for ESP32 Devices. This needs to be issued to send a new main firmware via bluetooth. */
int32_t reboot_ota_seconds; int32_t reboot_ota_seconds;
/* This message is only supported for the simulator porduino build. /* This message is only supported for the simulator Portduino build.
If received the simulator will exit successfully. */ If received the simulator will exit successfully. */
bool exit_simulator; bool exit_simulator;
/* Tell the node to reboot in this many seconds (or <0 to cancel reboot) */ /* Tell the node to reboot in this many seconds (or <0 to cancel reboot) */

View File

@ -152,7 +152,7 @@ typedef enum _meshtastic_Config_LoRaConfig_RegionCode {
meshtastic_Config_LoRaConfig_RegionCode_US = 1, meshtastic_Config_LoRaConfig_RegionCode_US = 1,
/* European Union 433mhz */ /* European Union 433mhz */
meshtastic_Config_LoRaConfig_RegionCode_EU_433 = 2, meshtastic_Config_LoRaConfig_RegionCode_EU_433 = 2,
/* European Union 433mhz */ /* European Union 868mhz */
meshtastic_Config_LoRaConfig_RegionCode_EU_868 = 3, meshtastic_Config_LoRaConfig_RegionCode_EU_868 = 3,
/* China */ /* China */
meshtastic_Config_LoRaConfig_RegionCode_CN = 4, meshtastic_Config_LoRaConfig_RegionCode_CN = 4,
@ -202,11 +202,11 @@ typedef enum _meshtastic_Config_LoRaConfig_ModemPreset {
} meshtastic_Config_LoRaConfig_ModemPreset; } meshtastic_Config_LoRaConfig_ModemPreset;
typedef enum _meshtastic_Config_BluetoothConfig_PairingMode { typedef enum _meshtastic_Config_BluetoothConfig_PairingMode {
/* Device generates a random pin that will be shown on the screen of the device for pairing */ /* Device generates a random PIN that will be shown on the screen of the device for pairing */
meshtastic_Config_BluetoothConfig_PairingMode_RANDOM_PIN = 0, meshtastic_Config_BluetoothConfig_PairingMode_RANDOM_PIN = 0,
/* Device requires a specified fixed pin for pairing */ /* Device requires a specified fixed PIN for pairing */
meshtastic_Config_BluetoothConfig_PairingMode_FIXED_PIN = 1, meshtastic_Config_BluetoothConfig_PairingMode_FIXED_PIN = 1,
/* Device requires no pin for pairing */ /* Device requires no PIN for pairing */
meshtastic_Config_BluetoothConfig_PairingMode_NO_PIN = 2 meshtastic_Config_BluetoothConfig_PairingMode_NO_PIN = 2
} meshtastic_Config_BluetoothConfig_PairingMode; } meshtastic_Config_BluetoothConfig_PairingMode;
@ -364,7 +364,7 @@ typedef struct _meshtastic_Config_DisplayConfig {
/* Lora Config */ /* Lora Config */
typedef struct _meshtastic_Config_LoRaConfig { typedef struct _meshtastic_Config_LoRaConfig {
/* When enabled, the `modem_preset` fields will be adheared to, else the `bandwidth`/`spread_factor`/`coding_rate` /* When enabled, the `modem_preset` fields will be adhered to, else the `bandwidth`/`spread_factor`/`coding_rate`
will be taked from their respective manually defined fields */ will be taked from their respective manually defined fields */
bool use_preset; bool use_preset;
/* Either modem_config or bandwidth/spreading/coding will be specified - NOT BOTH. /* Either modem_config or bandwidth/spreading/coding will be specified - NOT BOTH.
@ -395,12 +395,12 @@ typedef struct _meshtastic_Config_LoRaConfig {
/* Disable TX from the LoRa radio. Useful for hot-swapping antennas and other tests. /* Disable TX from the LoRa radio. Useful for hot-swapping antennas and other tests.
Defaults to false */ Defaults to false */
bool tx_enabled; bool tx_enabled;
/* If zero then, use default max legal continuous power (ie. something that won't /* If zero, then use default max legal continuous power (ie. something that won't
burn out the radio hardware) burn out the radio hardware)
In most cases you should use zero here. In most cases you should use zero here.
Units are in dBm. */ Units are in dBm. */
int8_t tx_power; int8_t tx_power;
/* This is controlling the actual hardware frequency the radio is transmitting on. /* This controls the actual hardware frequency the radio transmits on.
Most users should never need to be exposed to this field/concept. Most users should never need to be exposed to this field/concept.
A channel number between 1 and NUM_CHANNELS (whatever the max is in the current region). A channel number between 1 and NUM_CHANNELS (whatever the max is in the current region).
If ZERO then the rule is "use the old channel name hash based If ZERO then the rule is "use the old channel name hash based
@ -422,7 +422,7 @@ typedef struct _meshtastic_Config_LoRaConfig {
float override_frequency; float override_frequency;
/* For testing it is useful sometimes to force a node to never listen to /* For testing it is useful sometimes to force a node to never listen to
particular other nodes (simulating radio out of range). All nodenums listed particular other nodes (simulating radio out of range). All nodenums listed
in ignore_incoming will have packets they send droped on receive (by router.cpp) */ in ignore_incoming will have packets they send dropped on receive (by router.cpp) */
pb_size_t ignore_incoming_count; pb_size_t ignore_incoming_count;
uint32_t ignore_incoming[3]; uint32_t ignore_incoming[3];
} meshtastic_Config_LoRaConfig; } meshtastic_Config_LoRaConfig;
@ -432,7 +432,7 @@ typedef struct _meshtastic_Config_BluetoothConfig {
bool enabled; bool enabled;
/* Determines the pairing strategy for the device */ /* Determines the pairing strategy for the device */
meshtastic_Config_BluetoothConfig_PairingMode mode; meshtastic_Config_BluetoothConfig_PairingMode mode;
/* Specified pin for PairingMode.FixedPin */ /* Specified PIN for PairingMode.FixedPin */
uint32_t fixed_pin; uint32_t fixed_pin;
} meshtastic_Config_BluetoothConfig; } meshtastic_Config_BluetoothConfig;

View File

@ -27,9 +27,9 @@ typedef struct _meshtastic_WifiConnectionStatus {
/* Connection status */ /* Connection status */
bool has_status; bool has_status;
meshtastic_NetworkConnectionStatus status; meshtastic_NetworkConnectionStatus status;
/* WiFi access point ssid */ /* WiFi access point SSID */
char ssid[33]; char ssid[33];
/* Rssi of wireless connection */ /* RSSI of wireless connection */
int32_t rssi; int32_t rssi;
} meshtastic_WifiConnectionStatus; } meshtastic_WifiConnectionStatus;
@ -42,9 +42,9 @@ typedef struct _meshtastic_EthernetConnectionStatus {
/* Bluetooth connection status */ /* Bluetooth connection status */
typedef struct _meshtastic_BluetoothConnectionStatus { typedef struct _meshtastic_BluetoothConnectionStatus {
/* The pairing pin for bluetooth */ /* The pairing PIN for bluetooth */
uint32_t pin; uint32_t pin;
/* Rssi of bluetooth connection */ /* RSSI of bluetooth connection */
int32_t rssi; int32_t rssi;
/* Whether the device has an active connection or not */ /* Whether the device has an active connection or not */
bool is_connected; bool is_connected;
@ -52,7 +52,7 @@ typedef struct _meshtastic_BluetoothConnectionStatus {
/* Serial connection status */ /* Serial connection status */
typedef struct _meshtastic_SerialConnectionStatus { typedef struct _meshtastic_SerialConnectionStatus {
/* The serial baud rate */ /* Serial baud rate */
uint32_t baud; uint32_t baud;
/* Whether the device has an active connection or not */ /* Whether the device has an active connection or not */
bool is_connected; bool is_connected;

View File

@ -54,7 +54,7 @@ typedef struct _meshtastic_DeviceState {
/* Used only during development. /* Used only during development.
Indicates developer is testing and changes should never be saved to flash. */ Indicates developer is testing and changes should never be saved to flash. */
bool no_save; bool no_save;
/* Some GPSes seem to have bogus settings from the factory, so we always do one factory reset. */ /* Some GPS receivers seem to have bogus settings from the factory, so we always do one factory reset. */
bool did_gps_reset; bool did_gps_reset;
} meshtastic_DeviceState; } meshtastic_DeviceState;
@ -72,13 +72,13 @@ typedef struct _meshtastic_ChannelFile {
typedef PB_BYTES_ARRAY_T(2048) meshtastic_OEMStore_oem_icon_bits_t; typedef PB_BYTES_ARRAY_T(2048) meshtastic_OEMStore_oem_icon_bits_t;
typedef PB_BYTES_ARRAY_T(32) meshtastic_OEMStore_oem_aes_key_t; typedef PB_BYTES_ARRAY_T(32) meshtastic_OEMStore_oem_aes_key_t;
/* This can be used for customizing the firmware distribution. If populated, /* This can be used for customizing the firmware distribution. If populated,
show a secondary bootup screen with cuatom logo and text for 2.5 seconds. */ show a secondary bootup screen with custom logo and text for 2.5 seconds. */
typedef struct _meshtastic_OEMStore { typedef struct _meshtastic_OEMStore {
/* The Logo width in Px */ /* The Logo width in Px */
uint32_t oem_icon_width; uint32_t oem_icon_width;
/* The Logo height in Px */ /* The Logo height in Px */
uint32_t oem_icon_height; uint32_t oem_icon_height;
/* The Logo in xbm bytechar format */ /* The Logo in XBM bytechar format */
meshtastic_OEMStore_oem_icon_bits_t oem_icon_bits; meshtastic_OEMStore_oem_icon_bits_t oem_icon_bits;
/* Use this font for the OEM text. */ /* Use this font for the OEM text. */
meshtastic_ScreenFonts oem_font; meshtastic_ScreenFonts oem_font;

View File

@ -20,7 +20,7 @@
#include "mqtt/MQTT.h" #include "mqtt/MQTT.h"
#endif #endif
#define DEFAULT_REBOOT_SECONDS 5 #define DEFAULT_REBOOT_SECONDS 7
AdminModule *adminModule; AdminModule *adminModule;
bool hasOpenEditTransaction; bool hasOpenEditTransaction;

View File

@ -5,12 +5,19 @@
#include "MeshService.h" #include "MeshService.h"
#include "NodeDB.h" #include "NodeDB.h"
#include "PowerFSM.h" // neede for button bypass #include "PowerFSM.h" // neede for button bypass
#include "detect/ScanI2C.h"
#include "mesh/generated/meshtastic/cannedmessages.pb.h" #include "mesh/generated/meshtastic/cannedmessages.pb.h"
#include "main.h" // for cardkb_found
#ifdef OLED_RU #ifdef OLED_RU
#include "graphics/fonts/OLEDDisplayFontsRU.h" #include "graphics/fonts/OLEDDisplayFontsRU.h"
#endif #endif
#ifdef OLED_UA
#include "graphics/fonts/OLEDDisplayFontsUA.h"
#endif
#if defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ST7735_CS) #if defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ST7735_CS)
// The screen is bigger so use bigger fonts // The screen is bigger so use bigger fonts
#define FONT_SMALL ArialMT_Plain_16 #define FONT_SMALL ArialMT_Plain_16
@ -20,8 +27,12 @@
#ifdef OLED_RU #ifdef OLED_RU
#define FONT_SMALL ArialMT_Plain_10_RU #define FONT_SMALL ArialMT_Plain_10_RU
#else #else
#ifdef OLED_UA
#define FONT_SMALL ArialMT_Plain_10_UA
#else
#define FONT_SMALL ArialMT_Plain_10 #define FONT_SMALL ArialMT_Plain_10
#endif #endif
#endif
#define FONT_MEDIUM ArialMT_Plain_16 #define FONT_MEDIUM ArialMT_Plain_16
#define FONT_LARGE ArialMT_Plain_24 #define FONT_LARGE ArialMT_Plain_24
#endif #endif
@ -35,7 +46,7 @@
// Remove Canned message screen if no action is taken for some milliseconds // Remove Canned message screen if no action is taken for some milliseconds
#define INACTIVATE_AFTER_MS 20000 #define INACTIVATE_AFTER_MS 20000
extern uint8_t cardkb_found; extern ScanI2C::DeviceAddress cardkb_found;
static const char *cannedMessagesConfigFile = "/prefs/cannedConf.proto"; static const char *cannedMessagesConfigFile = "/prefs/cannedConf.proto";
@ -48,7 +59,7 @@ CannedMessageModule::CannedMessageModule()
{ {
if (moduleConfig.canned_message.enabled) { if (moduleConfig.canned_message.enabled) {
this->loadProtoForModule(); this->loadProtoForModule();
if ((this->splitConfiguredMessages() <= 0) && (cardkb_found != CARDKB_ADDR)) { if ((this->splitConfiguredMessages() <= 0) && (cardkb_found.address != CARDKB_ADDR)) {
LOG_INFO("CannedMessageModule: No messages are configured. Module is disabled\n"); LOG_INFO("CannedMessageModule: No messages are configured. Module is disabled\n");
this->runState = CANNED_MESSAGE_RUN_STATE_DISABLED; this->runState = CANNED_MESSAGE_RUN_STATE_DISABLED;
disable(); disable();

View File

@ -12,6 +12,10 @@
#include "graphics/fonts/OLEDDisplayFontsRU.h" #include "graphics/fonts/OLEDDisplayFontsRU.h"
#endif #endif
#ifdef OLED_UA
#include "graphics/fonts/OLEDDisplayFontsUA.h"
#endif
/* /*
AudioModule AudioModule
A interface to send raw codec2 audio data over the mesh network. Based on the example code from the ESP32_codec2 project. A interface to send raw codec2 audio data over the mesh network. Based on the example code from the ESP32_codec2 project.
@ -53,8 +57,12 @@ AudioModule *audioModule;
#ifdef OLED_RU #ifdef OLED_RU
#define FONT_SMALL ArialMT_Plain_10_RU #define FONT_SMALL ArialMT_Plain_10_RU
#else #else
#ifdef OLED_UA
#define FONT_SMALL ArialMT_Plain_10_UA
#else
#define FONT_SMALL ArialMT_Plain_10 #define FONT_SMALL ArialMT_Plain_10
#endif #endif
#endif
#define FONT_MEDIUM ArialMT_Plain_16 #define FONT_MEDIUM ArialMT_Plain_16
#define FONT_LARGE ArialMT_Plain_24 #define FONT_LARGE ArialMT_Plain_24
#endif #endif

View File

@ -30,12 +30,14 @@ class MQTT : private concurrency::OSThread
#if HAS_ETHERNET #if HAS_ETHERNET
EthernetClient mqttClient; EthernetClient mqttClient;
#endif #endif
#if !defined(DEBUG_HEAP_MQTT)
PubSubClient pubSub; PubSubClient pubSub;
// instead we supress sleep from our runOnce() callback
// CallbackObserver<MQTT, void *> preflightSleepObserver = CallbackObserver<MQTT, void *>(this, &MQTT::preflightSleepCb);
public: public:
#else
public:
PubSubClient pubSub;
#endif
MQTT(); MQTT();
/** /**

View File

@ -1,9 +1,6 @@
[env:heltec-v3] [env:heltec-v3]
platform = https://github.com/Baptou88/platform-espressif32.git
extends = esp32s3_base extends = esp32s3_base
board = heltec_wifi_lora_32_V3 board = heltec_wifi_lora_32_V3
# Temporary until espressif creates a release with this new target # Temporary until espressif creates a release with this new target
platform_packages =
framework-arduinoespressif32@https://github.com/espressif/arduino-esp32.git
build_flags = build_flags =
${esp32s3_base.build_flags} -D HELTEC_V3 -I variants/heltec_v3 ${esp32s3_base.build_flags} -D HELTEC_V3 -I variants/heltec_v3

View File

@ -1,9 +1,6 @@
[env:heltec-wsl-v3] [env:heltec-wsl-v3]
platform = https://github.com/Baptou88/platform-espressif32.git
extends = esp32s3_base extends = esp32s3_base
board = heltec_wifi_lora_32_V3 board = heltec_wifi_lora_32_V3
# Temporary until espressif creates a release with this new target # Temporary until espressif creates a release with this new target
platform_packages =
framework-arduinoespressif32@https://github.com/espressif/arduino-esp32.git
build_flags = build_flags =
${esp32s3_base.build_flags} -D HELTEC_WSL_V3 -I variants/heltec_wsl_v3 ${esp32s3_base.build_flags} -D HELTEC_WSL_V3 -I variants/heltec_wsl_v3

View File

@ -33,5 +33,4 @@
#define BATTERY_SENSE_SAMPLES 15 // Set the number of samples, It has an effect of increasing sensitivity. #define BATTERY_SENSE_SAMPLES 15 // Set the number of samples, It has an effect of increasing sensitivity.
#define ADC_MULTIPLIER 2 #define ADC_MULTIPLIER 2
//#define USE_SH1107 // Finally we will use SH1107 128x64 resolution driver, because SH1106 will shift the screen by 2 lines. #define USE_SH1107_128_64
#define USE_SH1106

View File

@ -13,6 +13,9 @@
#define I2C_SDA 18 // I2C pins for this board #define I2C_SDA 18 // I2C pins for this board
#define I2C_SCL 17 #define I2C_SCL 17
#define I2C_SDA1 43
#define I2C_SCL1 44
#define LED_PIN 37 // If defined we will blink this LED #define LED_PIN 37 // If defined we will blink this LED
#define BUTTON_PIN 0 // If defined, this will be used for user button presses, #define BUTTON_PIN 0 // If defined, this will be used for user button presses,
@ -28,26 +31,30 @@
#define RF95_MISO 3 #define RF95_MISO 3
#define RF95_MOSI 6 #define RF95_MOSI 6
#define RF95_NSS 7 #define RF95_NSS 7
#define LORA_RESET 8 #define LORA_RESET 8
#define LORA_DIO0 9
#define LORA_DIO1 9
#define LORA_DIO2 33 // SX1262 BUSY
#define LORA_DIO3 34 // Not connected on PCB, but internally on the TTGO SX1262, if DIO3 is high the TXCO is enabled
// per SX1276_Receive_Interrupt/utilities.h
#define LORA_DIO0 9
#define LORA_DIO1 33 // TCXO_EN ?
#define LORA_DIO2 34
#define LORA_RXEN 21
#define LORA_TXEN 10
// per SX1262_Receive_Interrupt/utilities.h
#ifdef USE_SX1262 #ifdef USE_SX1262
#define SX126X_CS RF95_NSS // FIXME - we really should define LORA_CS instead #define SX126X_CS RF95_NSS
#define SX126X_DIO1 33 #define SX126X_DIO1 33
#define SX126X_BUSY 34 #define SX126X_BUSY 34
#define SX126X_RESET LORA_RESET #define SX126X_RESET LORA_RESET
//#define SX126X_RXEN 21
//#define SX126X_TXEN 10
#define SX126X_E22 #define SX126X_E22
#endif #endif
// per SX128x_Receive_Interrupt/utilities.h
#ifdef USE_SX1280 #ifdef USE_SX1280
#define SX128X_CS RF95_NSS #define SX128X_CS RF95_NSS
#define SX128X_DIO1 LORA_DIO1 #define SX128X_DIO1 9
#define SX128X_DIO2 33
#define SX128X_DIO3 34
#define SX128X_BUSY 36 #define SX128X_BUSY 36
#define SX128X_RESET LORA_RESET #define SX128X_RESET LORA_RESET
#define SX128X_RXEN 21 #define SX128X_RXEN 21

View File

@ -1,4 +1,4 @@
[VERSION] [VERSION]
major = 2 major = 2
minor = 0 minor = 1
build = 24 build = 1