Compare commits
25
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b01079a281 | ||
|
|
b9a0100c0d | ||
|
|
65c7112a39 | ||
|
|
6c23fcddf0 | ||
|
|
4d7d021ef5 | ||
|
|
025c6854e8 | ||
|
|
ec80eb7d66 | ||
|
|
da1ec940dd | ||
|
|
b6caf1e6e7 | ||
|
|
cb867cc6c8 | ||
|
|
8e4ea08b98 | ||
|
|
f6c9b9aab0 | ||
|
|
7a3b4395f2 | ||
|
|
0abd202b82 | ||
|
|
8049d77522 | ||
|
|
0ee360295b | ||
|
|
1c0182f329 | ||
|
|
472b14c4e4 | ||
|
|
3851fbfec3 | ||
|
|
8b22448285 | ||
|
|
73e79797b2 | ||
|
|
a96f83fd01 | ||
|
|
0f761d930b | ||
|
|
4d4906772f | ||
|
|
711abb56f3 |
@@ -333,6 +333,7 @@ jobs:
|
||||
prerelease: true
|
||||
name: Meshtastic Firmware ${{ needs.version.outputs.long }} Alpha
|
||||
tag_name: v${{ needs.version.outputs.long }}
|
||||
target_commitish: ${{ github.sha }}
|
||||
body: ${{ steps.release_notes.outputs.notes }}
|
||||
|
||||
- name: Download source deb
|
||||
|
||||
@@ -17,7 +17,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Stale PR+Issues
|
||||
uses: actions/stale@v10.2.0
|
||||
uses: actions/stale@v10.3.0
|
||||
with:
|
||||
days-before-stale: 45
|
||||
stale-issue-message: This issue has not had any comment or update in the last month. If it is still relevant, please post update comments. If no comments are made, this issue will be closed automagically in 7 days.
|
||||
|
||||
+1
-1
@@ -16,7 +16,7 @@ lint:
|
||||
- bandit@1.9.4
|
||||
- trivy@0.70.0
|
||||
- taplo@0.10.0
|
||||
- ruff@0.15.13
|
||||
- ruff@0.15.14
|
||||
- isort@8.0.1
|
||||
- markdownlint@0.48.0
|
||||
- oxipng@10.1.1
|
||||
|
||||
@@ -87,6 +87,9 @@
|
||||
</screenshots>
|
||||
|
||||
<releases>
|
||||
<release version="2.7.25" date="2026-05-23">
|
||||
<url type="details">https://github.com/meshtastic/firmware/releases?q=tag%3Av2.7.25</url>
|
||||
</release>
|
||||
<release version="2.7.24" date="2026-05-08">
|
||||
<url type="details">https://github.com/meshtastic/firmware/releases?q=tag%3Av2.7.24</url>
|
||||
</release>
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
{
|
||||
"build": {
|
||||
"arduino": {
|
||||
"ldscript": "esp32s3_out.ld",
|
||||
"memory_type": "qio_opi"
|
||||
},
|
||||
"core": "esp32",
|
||||
"extra_flags": [
|
||||
"-D BOARD_HAS_PSRAM",
|
||||
"-D ARDUINO_USB_CDC_ON_BOOT=1",
|
||||
"-D ARDUINO_USB_MODE=1",
|
||||
"-D ARDUINO_RUNNING_CORE=1",
|
||||
"-D ARDUINO_EVENT_RUNNING_CORE=1"
|
||||
],
|
||||
"f_cpu": "240000000L",
|
||||
"f_flash": "80000000L",
|
||||
"flash_mode": "qio",
|
||||
"psram_type": "opi",
|
||||
"hwids": [["0x303A", "0x1001"]],
|
||||
"mcu": "esp32s3",
|
||||
"variant": "esp32s3"
|
||||
},
|
||||
"connectivity": ["wifi", "bluetooth", "lora"],
|
||||
"debug": {
|
||||
"default_tool": "esp-builtin",
|
||||
"onboard_tools": ["esp-builtin"],
|
||||
"openocd_target": "esp32s3.cfg"
|
||||
},
|
||||
"frameworks": ["arduino", "espidf"],
|
||||
"name": "seeed_wio_tracker_L2 (16 MB FLASH, 8 MB PSRAM)",
|
||||
"upload": {
|
||||
"flash_size": "16MB",
|
||||
"maximum_ram_size": 327680,
|
||||
"maximum_size": 16777216,
|
||||
"use_1200bps_touch": true,
|
||||
"wait_for_upload_port": true,
|
||||
"require_upload_port": true,
|
||||
"speed": 921600
|
||||
},
|
||||
"url": "https://www.seeedstudio.com/",
|
||||
"vendor": "Seeed Studio"
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
{
|
||||
"build": {
|
||||
"arduino": {
|
||||
"ldscript": "nrf52840_s140_v6.ld"
|
||||
},
|
||||
"core": "nRF5",
|
||||
"cpu": "cortex-m4",
|
||||
"extra_flags": "-DARDUINO_NRF52840_T_IMPULSE_PLUS -DNRF52840_XXAA",
|
||||
"f_cpu": "64000000L",
|
||||
"hwids": [["0x239A", "0x8029"]],
|
||||
"usb_product": "T-Impulse-Plus-nRF52840",
|
||||
"mcu": "nrf52840",
|
||||
"variant": "t-impulse-plus",
|
||||
"variants_dir": "variants",
|
||||
"bsp": {
|
||||
"name": "adafruit"
|
||||
},
|
||||
"softdevice": {
|
||||
"sd_flags": "-DS140",
|
||||
"sd_name": "s140",
|
||||
"sd_version": "6.1.1",
|
||||
"sd_fwid": "0x00B6"
|
||||
},
|
||||
"bootloader": {
|
||||
"settings_addr": "0xFF000"
|
||||
}
|
||||
},
|
||||
"connectivity": ["bluetooth"],
|
||||
"debug": {
|
||||
"jlink_device": "nRF52840_xxAA",
|
||||
"onboard_tools": ["jlink"],
|
||||
"svd_path": "nrf52840.svd"
|
||||
},
|
||||
"frameworks": ["arduino"],
|
||||
"name": "Lilygo T-Impulse-Plus-nRF52840",
|
||||
"upload": {
|
||||
"maximum_ram_size": 248832,
|
||||
"maximum_size": 815104,
|
||||
"require_upload_port": true,
|
||||
"speed": 115200,
|
||||
"protocol": "nrfutil",
|
||||
"protocols": [
|
||||
"jlink",
|
||||
"nrfjprog",
|
||||
"nrfutil",
|
||||
"stlink",
|
||||
"cmsis-dap",
|
||||
"blackmagic"
|
||||
]
|
||||
},
|
||||
"url": "https://www.lilygo.cc/",
|
||||
"vendor": "Lilygo"
|
||||
}
|
||||
Vendored
+6
@@ -1,3 +1,9 @@
|
||||
meshtasticd (2.7.25.0) unstable; urgency=medium
|
||||
|
||||
* Version 2.7.25
|
||||
|
||||
-- GitHub Actions <github-actions[bot]@users.noreply.github.com> Sat, 23 May 2026 01:16:20 +0000
|
||||
|
||||
meshtasticd (2.7.24.0) unstable; urgency=medium
|
||||
|
||||
* Version 2.7.24
|
||||
|
||||
+2
-2
@@ -68,7 +68,7 @@ monitor_speed = 115200
|
||||
monitor_filters = direct
|
||||
lib_deps =
|
||||
# renovate: datasource=git-refs depName=meshtastic-esp8266-oled-ssd1306 packageName=https://github.com/meshtastic/esp8266-oled-ssd1306 gitBranch=master
|
||||
https://github.com/meshtastic/esp8266-oled-ssd1306/archive/6bfd1f135e1ebe37afd6050bb4b9964cea3fcfda.zip
|
||||
https://github.com/meshtastic/esp8266-oled-ssd1306/archive/2e26010040e028baee72e2093402fa7b3c59e430.zip
|
||||
# renovate: datasource=git-refs depName=meshtastic-OneButton packageName=https://github.com/meshtastic/OneButton gitBranch=master
|
||||
https://github.com/meshtastic/OneButton/archive/fa352d668c53f290cfa480a5f79ad422cd828c70.zip
|
||||
# renovate: datasource=git-refs depName=meshtastic-arduino-fsm packageName=https://github.com/meshtastic/arduino-fsm gitBranch=master
|
||||
@@ -126,7 +126,7 @@ lib_deps =
|
||||
[device-ui_base]
|
||||
lib_deps =
|
||||
# renovate: datasource=git-refs depName=meshtastic/device-ui packageName=https://github.com/meshtastic/device-ui gitBranch=master
|
||||
https://github.com/meshtastic/device-ui/archive/4bf593a82100b911ff816dddf7158ffdee2114cd.zip
|
||||
https://github.com/meshtastic/device-ui/archive/c23fdc22f2ba949829661fdf851846fcf7433d89.zip
|
||||
|
||||
; Common libs for environmental measurements in telemetry module
|
||||
[environmental_base]
|
||||
|
||||
+1
-1
@@ -307,7 +307,7 @@ void fsInit()
|
||||
*/
|
||||
void setupSDCard()
|
||||
{
|
||||
#if defined(HAS_SDCARD) && !defined(SDCARD_USE_SOFT_SPI)
|
||||
#if defined(HAS_SDCARD) && !defined(SDCARD_USE_SOFT_SPI) && !defined(HAS_SD_MMC)
|
||||
concurrency::LockGuard g(spiLock);
|
||||
SDHandler.begin(SPI_SCK, SPI_MISO, SPI_MOSI);
|
||||
if (!SD.begin(SDCARD_CS, SDHandler, SD_SPI_FREQUENCY)) {
|
||||
|
||||
+181
@@ -23,6 +23,7 @@
|
||||
#include "main.h"
|
||||
#include "meshUtils.h"
|
||||
#include "power/PowerHAL.h"
|
||||
#include "power/SGM41562.h"
|
||||
#include "sleep.h"
|
||||
|
||||
#if defined(ARCH_PORTDUINO)
|
||||
@@ -30,6 +31,10 @@
|
||||
#include "input/LinuxInputImpl.h"
|
||||
#endif
|
||||
|
||||
#ifdef HAS_ADS1115
|
||||
#include <Adafruit_ADS1X15.h>
|
||||
#endif
|
||||
|
||||
// Working USB detection for powered/charging states on the RAK platform
|
||||
#ifdef NRF_APM
|
||||
#include "nrfx_power.h"
|
||||
@@ -453,6 +458,10 @@ class AnalogBatteryLevel : public HasBatteryLevel
|
||||
/// source
|
||||
virtual bool isVbusIn() override
|
||||
{
|
||||
#ifdef HAS_SGM41562
|
||||
if (sgm41562 && sgm41562->refresh())
|
||||
return sgm41562->isInputPowerGood();
|
||||
#endif
|
||||
#ifdef EXT_PWR_DETECT
|
||||
#if defined(HELTEC_CAPSULE_SENSOR_V3) || defined(HELTEC_SENSOR_HUB)
|
||||
// if external powered that pin will be pulled down
|
||||
@@ -483,6 +492,10 @@ class AnalogBatteryLevel : public HasBatteryLevel
|
||||
/// we can't be smart enough to say 'full'?
|
||||
virtual bool isCharging() override
|
||||
{
|
||||
#ifdef HAS_SGM41562
|
||||
if (sgm41562 && sgm41562->refresh())
|
||||
return sgm41562->isCharging();
|
||||
#endif
|
||||
#if HAS_TELEMETRY && !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR && defined(HAS_RAKPROT) && !defined(HAS_PMU)
|
||||
if (hasRAK()) {
|
||||
return (rak9154Sensor.isCharging()) ? OptTrue : OptFalse;
|
||||
@@ -607,6 +620,164 @@ class AnalogBatteryLevel : public HasBatteryLevel
|
||||
|
||||
static AnalogBatteryLevel analogLevel;
|
||||
|
||||
#ifdef HAS_ADS1115
|
||||
#include "SPILock.h"
|
||||
// AW35615 USB-C CC controller register constants (Arduino Wire, no ESP-IDF dependency)
|
||||
static constexpr uint8_t AW35615_ADDR = 0x22;
|
||||
static constexpr uint8_t AW35615_REG_DEVID = 0x01; // Device ID (probe)
|
||||
static constexpr uint8_t AW35615_REG_ST1A = 0x3D; // STATUS1A: TOGSS[5:3]
|
||||
static constexpr uint8_t AW35615_REG_ST0 = 0x40; // STATUS0: VBUSOK[7]
|
||||
static constexpr uint8_t AW35615_VBUSOK = (1 << 7);
|
||||
static constexpr uint8_t AW35615_TOGSS_MASK = 0x38;
|
||||
static constexpr uint8_t AW35615_TOGSS_SHIFT = 3;
|
||||
static constexpr uint8_t AW35615_TOGSS_SNK_CC1 = 5; // device is sink on CC1
|
||||
static constexpr uint8_t AW35615_TOGSS_SNK_CC2 = 6; // device is sink on CC2
|
||||
|
||||
/**
|
||||
* Battery level sensor using an ADS1115 16-bit ADC on I2C (address 0x48).
|
||||
* Channel 0 is battery voltage through a ×2 resistive divider, so the
|
||||
* measured voltage is multiplied by 2.0 to recover the true cell voltage.
|
||||
* USB/charging state is read from the AW35615 USB-C CC controller (0x22)
|
||||
* when present; falls back to a voltage threshold when not.
|
||||
*/
|
||||
class ADS1115BatteryLevel : public AnalogBatteryLevel
|
||||
{
|
||||
public:
|
||||
bool init()
|
||||
{
|
||||
concurrency::LockGuard guard(spiLock);
|
||||
// Wire is already configured (SDA=47, SCL=48) and the ADC-enable
|
||||
// expander pin (pin 15) is already HIGH from initVariant().
|
||||
if (!_ads.begin(ADS1115_ADDR, &Wire)) {
|
||||
LOG_WARN("ADS1115 not found on I2C bus — battery sensor unavailable");
|
||||
return false;
|
||||
}
|
||||
_ads.setGain(GAIN_TWO); // ±2.048 V FSR matches the voltage-divider ratio
|
||||
initialized = true;
|
||||
LOG_INFO("[ADS1115] battery sensor initialized");
|
||||
|
||||
// Probe and configure AW35615 USB-C CC controller for VBUS / charging detection
|
||||
uint8_t devId = 0;
|
||||
if (aw35615Read(AW35615_REG_DEVID, devId)) {
|
||||
aw35615_initialized = true;
|
||||
LOG_INFO("[AW35615] found at 0x22, DEVICE_ID=0x%02x", devId);
|
||||
// Enable all internal power blocks
|
||||
aw35615Write(0x0B, 0x0F); // POWER = 0x0F
|
||||
// Put Rd (pull-down) resistors on both CC pins → device acts as USB-C sink
|
||||
aw35615Write(0x02, 0x03); // SWITCHES0: PDWN1|PDWN2
|
||||
// Enable sink toggle so the chip detects CC attachment and sets VBUSOK
|
||||
aw35615Write(0x08, 0x05); // CONTROL2: MODE=SINK (2<<1) | TOGGLE=1
|
||||
} else {
|
||||
LOG_WARN("[AW35615] not found at 0x22, falling back to voltage threshold for USB detection");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual uint16_t getBattVoltage() override
|
||||
{
|
||||
if (!initialized) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
concurrency::LockGuard guard(spiLock);
|
||||
static constexpr uint32_t MIN_READ_INTERVAL_MS = 30000;
|
||||
if (!initial_read_done || !Throttle::isWithinTimespanMs(last_read_ms, MIN_READ_INTERVAL_MS)) {
|
||||
last_read_ms = millis();
|
||||
float sum = 0;
|
||||
for (int i = 0; i < SAMPLE_COUNT; i++) {
|
||||
int16_t raw = _ads.readADC_SingleEnded(0);
|
||||
float v = _ads.computeVolts(raw);
|
||||
sum += v;
|
||||
}
|
||||
// Channel 0 sees battery/2 (resistive divider); multiply back, convert to mV
|
||||
float v = (sum / SAMPLE_COUNT) * 2.0f * 1000.0f;
|
||||
if (!initial_read_done) {
|
||||
cached_mv = (uint16_t)v;
|
||||
initial_read_done = true;
|
||||
} else {
|
||||
cached_mv = (uint16_t)(cached_mv + (v - cached_mv) * 0.5f);
|
||||
}
|
||||
}
|
||||
return cached_mv;
|
||||
}
|
||||
|
||||
virtual bool isVbusIn() override
|
||||
{
|
||||
concurrency::LockGuard guard(spiLock);
|
||||
if (aw35615_initialized) {
|
||||
uint8_t st0 = 0;
|
||||
if (aw35615Read(AW35615_REG_ST0, st0)) {
|
||||
bool vbus = (st0 & AW35615_VBUSOK) != 0;
|
||||
//LOG_DEBUG("[AW35615] STATUS0=0x%02x VBUSOK=%d", st0, (int)vbus);
|
||||
return vbus;
|
||||
}
|
||||
}
|
||||
// Fallback: CV-phase voltage threshold
|
||||
static constexpr uint16_t CHARGING_THRESH_MV = (4190 + 10) * NUM_CELLS;
|
||||
return getBattVoltage() > CHARGING_THRESH_MV;
|
||||
}
|
||||
|
||||
virtual bool isCharging() override
|
||||
{
|
||||
if (!isBatteryConnect())
|
||||
return false;
|
||||
if (aw35615_initialized) {
|
||||
concurrency::LockGuard guard(spiLock);
|
||||
uint8_t st1a = 0;
|
||||
if (aw35615Read(AW35615_REG_ST1A, st1a)) {
|
||||
uint8_t togss = (st1a & AW35615_TOGSS_MASK) >> AW35615_TOGSS_SHIFT;
|
||||
bool charging = (togss == AW35615_TOGSS_SNK_CC1 || togss == AW35615_TOGSS_SNK_CC2);
|
||||
//LOG_DEBUG("[AW35615] STATUS1A=0x%02x TOGSS=%d charging=%d", st1a, (int)togss, (int)charging);
|
||||
return charging;
|
||||
}
|
||||
}
|
||||
return isVbusIn();
|
||||
}
|
||||
|
||||
private:
|
||||
// arduino Wire helpers for AW35615 register access
|
||||
bool aw35615Read(uint8_t reg, uint8_t &val)
|
||||
{
|
||||
Wire.beginTransmission(AW35615_ADDR);
|
||||
Wire.write(reg);
|
||||
if (Wire.endTransmission(false) != 0)
|
||||
return false;
|
||||
if (Wire.requestFrom(AW35615_ADDR, (uint8_t)1) != 1)
|
||||
return false;
|
||||
val = Wire.read();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool aw35615Write(uint8_t reg, uint8_t val)
|
||||
{
|
||||
Wire.beginTransmission(AW35615_ADDR);
|
||||
Wire.write(reg);
|
||||
Wire.write(val);
|
||||
return Wire.endTransmission() == 0;
|
||||
}
|
||||
|
||||
static constexpr uint8_t SAMPLE_COUNT = 3;
|
||||
Adafruit_ADS1115 _ads;
|
||||
bool initialized = false;
|
||||
bool aw35615_initialized = false;
|
||||
bool initial_read_done = false;
|
||||
uint16_t cached_mv = 0;
|
||||
uint32_t last_read_ms = 0;
|
||||
};
|
||||
|
||||
static ADS1115BatteryLevel ads1115BattLevel;
|
||||
|
||||
bool Power::ads1115Init()
|
||||
{
|
||||
if (ads1115BattLevel.init()) {
|
||||
batteryLevel = &ads1115BattLevel;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
#endif // HAS_ADS1115
|
||||
|
||||
Power::Power() : OSThread("Power")
|
||||
{
|
||||
statusHandler = {};
|
||||
@@ -697,6 +868,12 @@ bool Power::analogInit()
|
||||
*/
|
||||
bool Power::setup()
|
||||
{
|
||||
#ifdef HAS_SGM41562
|
||||
// Initialize the charger early so AnalogBatteryLevel can read charging
|
||||
// state from it. The charger does not provide battery voltage / percent —
|
||||
// those still come from the platform ADC via analogInit() below.
|
||||
initSGM41562(SGM41562_WIRE);
|
||||
#endif
|
||||
bool found = false;
|
||||
if (axpChipInit()) {
|
||||
found = true;
|
||||
@@ -710,6 +887,10 @@ bool Power::setup()
|
||||
found = true;
|
||||
} else if (meshSolarInit()) {
|
||||
found = true;
|
||||
#ifdef HAS_ADS1115
|
||||
} else if (ads1115Init()) {
|
||||
found = true;
|
||||
#endif
|
||||
} else if (analogInit()) {
|
||||
found = true;
|
||||
} else {
|
||||
|
||||
+9
-1
@@ -293,6 +293,13 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
// -----------------------------------------------------------------------------
|
||||
#define NCP5623_ADDR 0x38
|
||||
#define LP5562_ADDR 0x30
|
||||
#define LP5814_ADDR 0x2C
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Audio Codec
|
||||
// -----------------------------------------------------------------------------
|
||||
#define ES8311_ADDR 0x18 // same address as MCP9808_ADDR / STK8BXX_ADDR / LIS3DH_ADDR
|
||||
#define ES7243E_ADDR 0x14
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Security
|
||||
@@ -307,10 +314,11 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
// -----------------------------------------------------------------------------
|
||||
// Touchscreen
|
||||
// -----------------------------------------------------------------------------
|
||||
#define FT6336U_ADDR 0x48
|
||||
#define FT6336U_ADDR 0x48 // same address as ADS1115
|
||||
#define CST328_ADDR 0x1A // same address as CST226SE
|
||||
#define CHSC6X_ADDR 0x2E
|
||||
#define CST226SE_ADDR_ALT 0x5A
|
||||
#define GT911_ADDR 0x5D // same address as SFA30_ADDR / LPS22HB_ADDR_ALT
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// RAK12035VB Soil Monitor (using RAK12023 up to 3 RAK12035 monitors can be connected)
|
||||
|
||||
@@ -48,6 +48,7 @@ class ScanI2C
|
||||
BMA423,
|
||||
BQ24295,
|
||||
LSM6DS3,
|
||||
AW35615,
|
||||
TCA9535,
|
||||
TCA9555,
|
||||
VEML7700,
|
||||
@@ -97,6 +98,10 @@ class ScanI2C
|
||||
CW2015,
|
||||
SCD30,
|
||||
ADS1115,
|
||||
GT911,
|
||||
LP5814,
|
||||
ES8311,
|
||||
ES7243E,
|
||||
} DeviceType;
|
||||
|
||||
// typedef uint8_t DeviceAddress;
|
||||
|
||||
+111
-10
@@ -85,8 +85,9 @@ ScanI2C::DeviceType ScanI2CTwoWire::probeOLED(ScanI2C::DeviceAddress addr) const
|
||||
|
||||
return o_probe;
|
||||
}
|
||||
|
||||
uint16_t ScanI2CTwoWire::getRegisterValue(const ScanI2CTwoWire::RegisterLocation ®isterLocation,
|
||||
ScanI2CTwoWire::ResponseWidth responseWidth, bool zeropad = false) const
|
||||
ScanI2CTwoWire::ResponseWidth responseWidth, bool zeropad) const
|
||||
{
|
||||
uint16_t value = 0x00;
|
||||
TwoWire *i2cBus = fetchI2CBus(registerLocation.i2cAddress);
|
||||
@@ -175,6 +176,62 @@ String readSEN5xProductName(TwoWire *i2cBus, uint8_t address)
|
||||
return String(productName);
|
||||
}
|
||||
|
||||
#if HAS_TELEMETRY && !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR
|
||||
static uint8_t crcSHT2X(const uint8_t *data, uint8_t len)
|
||||
{
|
||||
uint8_t crc = 0;
|
||||
for (uint8_t i = 0; i < len; i++) {
|
||||
crc ^= data[i];
|
||||
for (uint8_t bit = 0; bit < 8; bit++) {
|
||||
crc = (crc & 0x80) ? (crc << 1) ^ 0x31 : crc << 1;
|
||||
}
|
||||
}
|
||||
return crc;
|
||||
}
|
||||
|
||||
bool detectSHT21SerialNumber(TwoWire *i2cBus, uint8_t address)
|
||||
{
|
||||
uint8_t serialA[8] = {0};
|
||||
uint8_t serialB[6] = {0};
|
||||
|
||||
i2cBus->beginTransmission(address);
|
||||
i2cBus->write(0xFA);
|
||||
i2cBus->write(0x0F);
|
||||
|
||||
if (i2cBus->endTransmission() != 0)
|
||||
return false;
|
||||
|
||||
if (i2cBus->requestFrom(address, (uint8_t)sizeof(serialA)) != sizeof(serialA))
|
||||
return false;
|
||||
|
||||
for (uint8_t i = 0; i < sizeof(serialA); i++) {
|
||||
if (!i2cBus->available())
|
||||
return false;
|
||||
serialA[i] = i2cBus->read();
|
||||
}
|
||||
|
||||
i2cBus->beginTransmission(address);
|
||||
i2cBus->write(0xFC);
|
||||
i2cBus->write(0xC9);
|
||||
|
||||
if (i2cBus->endTransmission() != 0)
|
||||
return false;
|
||||
|
||||
if (i2cBus->requestFrom(address, (uint8_t)sizeof(serialB)) != sizeof(serialB))
|
||||
return false;
|
||||
|
||||
for (uint8_t i = 0; i < sizeof(serialB); i++) {
|
||||
if (!i2cBus->available())
|
||||
return false;
|
||||
serialB[i] = i2cBus->read();
|
||||
}
|
||||
|
||||
return crcSHT2X(&serialA[0], 1) == serialA[1] && crcSHT2X(&serialA[2], 1) == serialA[3] &&
|
||||
crcSHT2X(&serialA[4], 1) == serialA[5] && crcSHT2X(&serialA[6], 1) == serialA[7] &&
|
||||
crcSHT2X(&serialB[0], 2) == serialB[2] && crcSHT2X(&serialB[3], 2) == serialB[5];
|
||||
}
|
||||
#endif
|
||||
|
||||
#define SCAN_SIMPLE_CASE(ADDR, T, ...) \
|
||||
case ADDR: \
|
||||
logFoundDevice(__VA_ARGS__); \
|
||||
@@ -305,7 +362,14 @@ void ScanI2CTwoWire::scanPort(I2CPort port, uint8_t *address, uint8_t asize)
|
||||
#ifdef HAS_LP5562
|
||||
SCAN_SIMPLE_CASE(LP5562_ADDR, LP5562, "LP5562", (uint8_t)addr.address);
|
||||
#endif
|
||||
case XPOWERS_AXP192_AXP2101_ADDRESS:
|
||||
#ifdef HAS_LP5814
|
||||
SCAN_SIMPLE_CASE(LP5814_ADDR, LP5814, "LP5814", (uint8_t)addr.address);
|
||||
#endif
|
||||
#ifdef HAS_ES7243E
|
||||
SCAN_SIMPLE_CASE(ES7243E_ADDR, ES7243E, "ES7243E", (uint8_t)addr.address);
|
||||
#endif
|
||||
case XPOWERS_AXP192_AXP2101_ADDRESS:
|
||||
#ifndef SEEED_WIO_TRACKER_L2 // false positive
|
||||
// Do we have the axp2101/192 or the TCA8418
|
||||
registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0x90), 1);
|
||||
if (registerValue == 0x0) {
|
||||
@@ -315,6 +379,7 @@ void ScanI2CTwoWire::scanPort(I2CPort port, uint8_t *address, uint8_t asize)
|
||||
logFoundDevice("AXP192/AXP2101", (uint8_t)addr.address);
|
||||
type = PMU_AXP192_AXP2101;
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
case BME_ADDR:
|
||||
case BME_ADDR_ALTERNATE:
|
||||
@@ -422,6 +487,13 @@ void ScanI2CTwoWire::scanPort(I2CPort port, uint8_t *address, uint8_t asize)
|
||||
// We need to check for STK8BAXX first, since register 0x07 is new data flag for the z-axis and can produce some
|
||||
// weird result. and register 0x00 doesn't seems to be colliding with MCP9808 and LIS3DH chips.
|
||||
{
|
||||
// Check register 0xFD for 0x83 to ID ES8311 audio codec.
|
||||
registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0xFD), 1);
|
||||
if (registerValue == 0x83) {
|
||||
type = ES8311;
|
||||
logFoundDevice("ES8311", (uint8_t)addr.address);
|
||||
break;
|
||||
}
|
||||
#ifdef HAS_STK8XXX
|
||||
// Check register 0x00 for 0x8700 response to ID STK8BA53 chip.
|
||||
registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0x00), 2);
|
||||
@@ -478,6 +550,22 @@ void ScanI2CTwoWire::scanPort(I2CPort port, uint8_t *address, uint8_t asize)
|
||||
break;
|
||||
|
||||
case LPS22HB_ADDR_ALT:
|
||||
// GT911 touchscreen: product ID register 0x8140 returns "911"
|
||||
{
|
||||
uint8_t gt911_reg[] = {0x81, 0x40};
|
||||
uint8_t gt911_buf[4] = {0};
|
||||
i2cBus->beginTransmission(addr.address);
|
||||
i2cBus->write(gt911_reg, 2);
|
||||
if (i2cBus->endTransmission() == 0) {
|
||||
i2cBus->requestFrom((int)addr.address, 4);
|
||||
i2cBus->readBytes(gt911_buf, 4);
|
||||
if (gt911_buf[0] == '9' && gt911_buf[1] == '1' && gt911_buf[2] == '1') {
|
||||
type = GT911;
|
||||
logFoundDevice("GT911", (uint8_t)addr.address);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
// SFA30 detection: send 2-byte command 0xD060 (Get Device Marking) and check for 48-byte response
|
||||
if (i2cCommandResponseLength(addr, 0xD060, 48)) {
|
||||
type = SFA30;
|
||||
@@ -534,9 +622,18 @@ void ScanI2CTwoWire::scanPort(I2CPort port, uint8_t *address, uint8_t asize)
|
||||
logFoundDevice("BMA423", (uint8_t)addr.address);
|
||||
}
|
||||
break;
|
||||
case RAK120353_ADDR: { // AW35615 USB-C CC controller — must be checked before
|
||||
// RAK120353_ADDR which shares 0x22 but is a TCA9535 variant
|
||||
registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0x01), 1);
|
||||
if ((registerValue & 0xF0) == 0x90) { // DEVICE_ID upper nibble = 0x9 for AW35615
|
||||
type = AW35615;
|
||||
logFoundDevice("AW35615", (uint8_t)addr.address);
|
||||
break;
|
||||
}
|
||||
// Fall through to TCA9535/RAK check
|
||||
}
|
||||
case TCA9535_ADDR:
|
||||
case RAK120352_ADDR:
|
||||
case RAK120353_ADDR:
|
||||
registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0x02), 1);
|
||||
if (registerValue == addr.address) { // RAK12035 returns its I2C address at 0x02 (eg 0x20)
|
||||
type = RAK12035;
|
||||
@@ -740,6 +837,17 @@ void ScanI2CTwoWire::scanPort(I2CPort port, uint8_t *address, uint8_t asize)
|
||||
break;
|
||||
|
||||
case 0x48: {
|
||||
// Check for ADS1115 FIRST — the SE050 probe below writes 5 bytes
|
||||
// to the device, which corrupts the ADS1115 Lo_thresh register and
|
||||
// leaves its pointer off register 0x01, making the later config-
|
||||
// register read return 0xC000 instead of the expected 0x8583.
|
||||
registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0x01), 2);
|
||||
if (registerValue == 0x8583 || registerValue == 0x8580) {
|
||||
type = ADS1115;
|
||||
logFoundDevice("ADS1115 ADC", (uint8_t)addr.address);
|
||||
break;
|
||||
}
|
||||
|
||||
i2cBus->beginTransmission(addr.address);
|
||||
uint8_t getInfo[] = {0x5A, 0xC0, 0x00, 0xFF, 0xFC};
|
||||
uint8_t expectedInfo[] = {0xa5, 0xE0, 0x00, 0x3F, 0x19};
|
||||
@@ -754,13 +862,6 @@ void ScanI2CTwoWire::scanPort(I2CPort port, uint8_t *address, uint8_t asize)
|
||||
break;
|
||||
}
|
||||
|
||||
registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0x01), 2);
|
||||
if (registerValue == 0x8583 || registerValue == 0x8580) {
|
||||
type = ADS1115;
|
||||
logFoundDevice("ADS1115 ADC", (uint8_t)addr.address);
|
||||
break;
|
||||
}
|
||||
|
||||
LOG_INFO("FT6336U touchscreen found");
|
||||
type = FT6336U;
|
||||
break;
|
||||
|
||||
@@ -53,7 +53,7 @@ class ScanI2CTwoWire : public ScanI2C
|
||||
|
||||
concurrency::Lock lock;
|
||||
|
||||
uint16_t getRegisterValue(const RegisterLocation &, ResponseWidth, bool) const;
|
||||
uint16_t getRegisterValue(const RegisterLocation &, ResponseWidth, bool = false) const;
|
||||
|
||||
bool i2cCommandResponseLength(DeviceAddress addr, uint16_t command, uint8_t expectedLength) const;
|
||||
|
||||
|
||||
@@ -142,8 +142,9 @@ void VirtualKeyboard::draw(OLEDDisplay *display, int16_t offsetX, int16_t offset
|
||||
if (keyboardStartY < 0)
|
||||
keyboardStartY = 0;
|
||||
} else {
|
||||
// Default (non-wide, non-64px) behavior: use key height heuristic and place at bottom
|
||||
cellH = KEY_HEIGHT;
|
||||
// Default (non-wide, non-64px) e.g. SH1107 128x128:
|
||||
// cellH = FONT_HEIGHT_SMALL - 2 so rows are tighter while still hosting the font
|
||||
cellH = std::max((int)KEY_HEIGHT, FONT_HEIGHT_SMALL - 2);
|
||||
int keyboardHeight = KEYBOARD_ROWS * cellH;
|
||||
keyboardStartY = screenH - keyboardHeight;
|
||||
if (keyboardStartY < 0)
|
||||
@@ -446,11 +447,8 @@ void VirtualKeyboard::drawKey(OLEDDisplay *display, const VirtualKey &key, bool
|
||||
if (textX < x)
|
||||
textX = x; // guard
|
||||
} else {
|
||||
if (display->getHeight() <= 64 && (key.character >= '0' && key.character <= '9')) {
|
||||
textX = x + (width - textWidth + 1) / 2;
|
||||
} else {
|
||||
textX = x + (width - textWidth) / 2;
|
||||
}
|
||||
// Use ceil rounding for all screens (consistent with 128x64 behavior for numbers)
|
||||
textX = x + (width - textWidth + 1) / 2;
|
||||
}
|
||||
int contentTop = y;
|
||||
int contentH = height;
|
||||
@@ -746,4 +744,4 @@ bool VirtualKeyboard::isTimedOut() const
|
||||
}
|
||||
|
||||
} // namespace graphics
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -183,9 +183,13 @@ void drawDigitalClockFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int1
|
||||
static float segmentHeight = SEGMENT_HEIGHT * 0.75f;
|
||||
|
||||
if (!scaleInitialized) {
|
||||
#ifdef DISPLAY_FORCE_SMALL_FONTS
|
||||
float screenwidth_target_ratio = 0.70f; // Target 70% of display width (adjustable)
|
||||
#else
|
||||
float screenwidth_target_ratio = 0.80f; // Target 80% of display width (adjustable)
|
||||
float max_scale = 3.5f; // Safety limit to avoid runaway scaling
|
||||
float step = 0.05f; // Step increment per iteration
|
||||
#endif
|
||||
float max_scale = 3.5f; // Safety limit to avoid runaway scaling
|
||||
float step = 0.05f; // Step increment per iteration
|
||||
|
||||
float target_width = display->getWidth() * screenwidth_target_ratio;
|
||||
float target_height =
|
||||
|
||||
@@ -0,0 +1,97 @@
|
||||
#include "HapticFeedback.h"
|
||||
|
||||
#ifdef HAPTIC_FEEDBACK_PIN
|
||||
|
||||
#include <Arduino.h>
|
||||
|
||||
#ifdef HAPTIC_FEEDBACK_ACTIVE_LOW
|
||||
#define HAPTIC_FEEDBACK_ON_STATE LOW
|
||||
#define HAPTIC_FEEDBACK_OFF_STATE HIGH
|
||||
#else
|
||||
#define HAPTIC_FEEDBACK_ON_STATE HIGH
|
||||
#define HAPTIC_FEEDBACK_OFF_STATE LOW
|
||||
#endif
|
||||
|
||||
HapticFeedback *hapticFeedback = nullptr;
|
||||
|
||||
void initHapticFeedback()
|
||||
{
|
||||
if (!hapticFeedback)
|
||||
hapticFeedback = new HapticFeedback();
|
||||
}
|
||||
|
||||
HapticFeedback::HapticFeedback() : concurrency::OSThread("Haptic")
|
||||
{
|
||||
pinMode(HAPTIC_FEEDBACK_PIN, OUTPUT);
|
||||
digitalWrite(HAPTIC_FEEDBACK_PIN, HAPTIC_FEEDBACK_OFF_STATE);
|
||||
}
|
||||
|
||||
void HapticFeedback::motorWrite(bool on)
|
||||
{
|
||||
digitalWrite(HAPTIC_FEEDBACK_PIN, on ? HAPTIC_FEEDBACK_ON_STATE : HAPTIC_FEEDBACK_OFF_STATE);
|
||||
}
|
||||
|
||||
void HapticFeedback::pulse(uint16_t durationMs)
|
||||
{
|
||||
motorWrite(true);
|
||||
pulseOffAt = millis() + durationMs;
|
||||
if (pulseOffAt == 0) // 0 is the "no pulse" sentinel
|
||||
pulseOffAt = 1;
|
||||
scheduleNext();
|
||||
}
|
||||
|
||||
void HapticFeedback::armDelayedPulse(uint16_t delayMs, uint16_t durationMs)
|
||||
{
|
||||
delayedPulseAt = millis() + delayMs;
|
||||
if (delayedPulseAt == 0)
|
||||
delayedPulseAt = 1;
|
||||
delayedPulseDuration = durationMs;
|
||||
scheduleNext();
|
||||
}
|
||||
|
||||
void HapticFeedback::cancelDelayedPulse()
|
||||
{
|
||||
delayedPulseAt = 0;
|
||||
}
|
||||
|
||||
void HapticFeedback::scheduleNext()
|
||||
{
|
||||
uint32_t now = millis();
|
||||
uint32_t next = 0;
|
||||
if (pulseOffAt != 0)
|
||||
next = pulseOffAt;
|
||||
if (delayedPulseAt != 0 && (next == 0 || (int32_t)(delayedPulseAt - next) < 0))
|
||||
next = delayedPulseAt;
|
||||
if (next == 0)
|
||||
return;
|
||||
int32_t delay = (int32_t)(next - now);
|
||||
setIntervalFromNow(delay > 0 ? (unsigned long)delay : 0);
|
||||
}
|
||||
|
||||
int32_t HapticFeedback::runOnce()
|
||||
{
|
||||
uint32_t now = millis();
|
||||
|
||||
if (pulseOffAt != 0 && (int32_t)(now - pulseOffAt) >= 0) {
|
||||
motorWrite(false);
|
||||
pulseOffAt = 0;
|
||||
}
|
||||
|
||||
if (delayedPulseAt != 0 && (int32_t)(now - delayedPulseAt) >= 0) {
|
||||
uint16_t dur = delayedPulseDuration;
|
||||
delayedPulseAt = 0;
|
||||
pulse(dur);
|
||||
}
|
||||
|
||||
uint32_t next = 0;
|
||||
if (pulseOffAt != 0)
|
||||
next = pulseOffAt;
|
||||
if (delayedPulseAt != 0 && (next == 0 || (int32_t)(delayedPulseAt - next) < 0))
|
||||
next = delayedPulseAt;
|
||||
if (next == 0)
|
||||
return 60 * 1000;
|
||||
int32_t delay = (int32_t)(next - now);
|
||||
return delay > 0 ? delay : 0;
|
||||
}
|
||||
|
||||
#endif // HAPTIC_FEEDBACK_PIN
|
||||
@@ -0,0 +1,35 @@
|
||||
#pragma once
|
||||
|
||||
#include "configuration.h"
|
||||
|
||||
#ifdef HAPTIC_FEEDBACK_PIN
|
||||
|
||||
#include "concurrency/OSThread.h"
|
||||
#include <stdint.h>
|
||||
|
||||
// Non-blocking pulses on a GPIO vibration motor. HAPTIC_FEEDBACK_ACTIVE_LOW inverts polarity.
|
||||
class HapticFeedback : public concurrency::OSThread
|
||||
{
|
||||
public:
|
||||
HapticFeedback();
|
||||
void pulse(uint16_t durationMs = 30);
|
||||
void armDelayedPulse(uint16_t delayMs, uint16_t durationMs = 30);
|
||||
void cancelDelayedPulse();
|
||||
|
||||
protected:
|
||||
int32_t runOnce() override;
|
||||
|
||||
private:
|
||||
uint32_t pulseOffAt = 0;
|
||||
uint32_t delayedPulseAt = 0;
|
||||
uint16_t delayedPulseDuration = 0;
|
||||
|
||||
void motorWrite(bool on);
|
||||
// Reschedule to the soonest pending event so later arms don't clobber earlier wakes.
|
||||
void scheduleNext();
|
||||
};
|
||||
|
||||
extern HapticFeedback *hapticFeedback;
|
||||
void initHapticFeedback();
|
||||
|
||||
#endif // HAPTIC_FEEDBACK_PIN
|
||||
@@ -2,6 +2,7 @@
|
||||
#include "PowerFSM.h" // needed for event trigger
|
||||
#include "configuration.h"
|
||||
#include "graphics/Screen.h"
|
||||
#include "input/HapticFeedback.h"
|
||||
#include "modules/ExternalNotificationModule.h"
|
||||
|
||||
#if ARCH_PORTDUINO
|
||||
@@ -237,6 +238,16 @@ void InputBroker::Init()
|
||||
}
|
||||
touchBacklightActive = false;
|
||||
};
|
||||
#endif
|
||||
#if defined(HAPTIC_FEEDBACK_PIN)
|
||||
// Blip on touch, second blip when long-press fires (500 ms = touchConfig.longPressTime default).
|
||||
touchConfig.suppressLeadUpSound = true;
|
||||
initHapticFeedback();
|
||||
touchConfig.onPress = []() {
|
||||
hapticFeedback->pulse(80);
|
||||
hapticFeedback->armDelayedPulse(500, 80);
|
||||
};
|
||||
touchConfig.onRelease = []() { hapticFeedback->cancelDelayedPulse(); };
|
||||
#endif
|
||||
TouchButtonThread->initButton(touchConfig);
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
#include "MeshLED.h"
|
||||
|
||||
// Default global instance: no-op dummy. Replace in variant initVariant() for device-specific behaviour.
|
||||
std::shared_ptr<MeshLED> meshLED = std::make_shared<MeshLED>();
|
||||
@@ -0,0 +1,19 @@
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
|
||||
/**
|
||||
* Interface for a "mesh activity" LED that lights while the LoRa radio is transmitting.
|
||||
* The default implementation is a no-op; device variants may replace the global instance
|
||||
* with a concrete subclass.
|
||||
*/
|
||||
class MeshLED
|
||||
{
|
||||
public:
|
||||
virtual ~MeshLED() = default;
|
||||
virtual void init() {}
|
||||
virtual void on() {}
|
||||
virtual void off() {}
|
||||
};
|
||||
|
||||
extern std::shared_ptr<MeshLED> meshLED;
|
||||
+1
-1
@@ -696,7 +696,7 @@ void NodeDB::installDefaultConfig(bool preserveKey = false)
|
||||
strncpy(config.network.ntp_server, "meshtastic.pool.ntp.org", 32);
|
||||
|
||||
#if (defined(T_DECK) || defined(T_WATCH_S3) || defined(UNPHONE) || defined(PICOMPUTER_S3) || defined(SENSECAP_INDICATOR) || \
|
||||
defined(ELECROW_PANEL) || defined(HELTEC_V4_TFT) || defined(HELTEC_V4_R8_TFT)) && \
|
||||
defined(ELECROW_PANEL) || defined(HELTEC_V4_TFT) || defined(HELTEC_V4_R8_TFT) || defined(SEEED_WIO_TRACKER_L2)) && \
|
||||
HAS_TFT
|
||||
// switch BT off by default; use TFT programming mode or hotkey to enable
|
||||
config.bluetooth.enabled = false;
|
||||
|
||||
@@ -4,17 +4,19 @@
|
||||
|
||||
#include <Arduino.h>
|
||||
|
||||
uint32_t getPositionPrecisionForChannel(uint8_t channelIndex)
|
||||
uint32_t getPositionPrecisionForChannel(const meshtastic_Channel &channel)
|
||||
{
|
||||
const meshtastic_Channel &channel = channels.getByIndex(channelIndex);
|
||||
|
||||
if (channel.settings.has_module_settings) {
|
||||
return channel.settings.module_settings.position_precision;
|
||||
} else if (channel.role == meshtastic_Channel_Role_PRIMARY) {
|
||||
return 32;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
// No module settings: fail closed. A PRIMARY channel used to default to 32
|
||||
// here, leaking an exact position on a sharing-disabled channel. See #10509.
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t getPositionPrecisionForChannel(uint8_t channelIndex)
|
||||
{
|
||||
return getPositionPrecisionForChannel(channels.getByIndex(channelIndex));
|
||||
}
|
||||
|
||||
static int32_t truncateCoordinate(int32_t coordinate, uint32_t precision)
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
#pragma once
|
||||
|
||||
#include "meshtastic/channel.pb.h"
|
||||
#include "meshtastic/mesh.pb.h"
|
||||
#include <stdint.h>
|
||||
|
||||
uint32_t getPositionPrecisionForChannel(const meshtastic_Channel &channel);
|
||||
uint32_t getPositionPrecisionForChannel(uint8_t channelIndex);
|
||||
void applyPositionPrecision(meshtastic_Position &position, uint32_t precision);
|
||||
bool applyPositionPrecision(meshtastic_MeshPacket &packet, uint32_t precision);
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#include "RadioLibInterface.h"
|
||||
#include "MeshLED.h"
|
||||
#include "MeshTypes.h"
|
||||
#include "NodeDB.h"
|
||||
#include "PowerMon.h"
|
||||
@@ -425,6 +426,7 @@ void RadioLibInterface::completeSending()
|
||||
auto p = sendingPacket;
|
||||
sendingPacket = NULL;
|
||||
|
||||
meshLED->off();
|
||||
if (p) {
|
||||
// Packet has been sent, count it toward our TX airtime utilization.
|
||||
uint32_t xmitMsec = getPacketTime(p);
|
||||
@@ -596,6 +598,7 @@ bool RadioLibInterface::startSend(meshtastic_MeshPacket *txp)
|
||||
powerMon->clearState(meshtastic_PowerMon_State_Lora_TXOn); // Transmitter off now
|
||||
startReceive(); // Restart receive mode (because startTransmit failed to put us in xmit mode)
|
||||
} else {
|
||||
meshLED->on();
|
||||
// Must be done AFTER, starting transmit, because startTransmit clears (possibly stale) interrupt pending register
|
||||
// bits
|
||||
enableInterrupt(isrTxLevel0);
|
||||
|
||||
+8
-4
@@ -351,10 +351,14 @@ ErrorCode Router::send(meshtastic_MeshPacket *p)
|
||||
}
|
||||
|
||||
fixPriority(p); // Before encryption, fix the priority if it's unset
|
||||
if (!applyPositionPrecisionForChannel(*p, p->channel)) {
|
||||
LOG_ERROR("Dropping malformed position packet before send");
|
||||
packetPool.release(p);
|
||||
return meshtastic_Routing_Error_BAD_REQUEST;
|
||||
// Position precision is an originator-only privacy policy. Relays keep
|
||||
// p->from as the original sender, so do not rewrite their POSITION_APP payload.
|
||||
if (isFromUs(p)) {
|
||||
if (!applyPositionPrecisionForChannel(*p, p->channel)) {
|
||||
LOG_ERROR("Dropping malformed position packet before send");
|
||||
packetPool.release(p);
|
||||
return meshtastic_Routing_Error_BAD_REQUEST;
|
||||
}
|
||||
}
|
||||
|
||||
// If the packet is not yet encrypted, do so now
|
||||
|
||||
@@ -52,8 +52,8 @@ template <typename T> bool SX126xInterface<T>::init()
|
||||
|
||||
#ifdef SX126X_POWER_EN // Perhaps add RADIOLIB_NC check, and beforehand define as such if it is undefined, but it is not commonly
|
||||
// used and not part of the 'default' set of pin definitions.
|
||||
digitalWrite(SX126X_POWER_EN, HIGH);
|
||||
pinMode(SX126X_POWER_EN, OUTPUT);
|
||||
digitalWrite(SX126X_POWER_EN, HIGH);
|
||||
#endif
|
||||
|
||||
#if HAS_LORA_FEM
|
||||
@@ -65,8 +65,8 @@ template <typename T> bool SX126xInterface<T>::init()
|
||||
#endif
|
||||
|
||||
#ifdef RF95_FAN_EN
|
||||
digitalWrite(RF95_FAN_EN, HIGH);
|
||||
pinMode(RF95_FAN_EN, OUTPUT);
|
||||
digitalWrite(RF95_FAN_EN, HIGH);
|
||||
#endif
|
||||
|
||||
#if ARCH_PORTDUINO
|
||||
|
||||
@@ -987,11 +987,11 @@ bool AdminModule::handleSetModuleConfig(const meshtastic_ModuleConfig &c)
|
||||
case meshtastic_ModuleConfig_neighbor_info_tag:
|
||||
LOG_INFO("Set module config: Neighbor Info");
|
||||
moduleConfig.has_neighbor_info = true;
|
||||
moduleConfig.neighbor_info = c.payload_variant.neighbor_info;
|
||||
if (moduleConfig.neighbor_info.update_interval < min_neighbor_info_broadcast_secs) {
|
||||
LOG_DEBUG("Tried to set update_interval too low, setting to %d", default_neighbor_info_broadcast_secs);
|
||||
moduleConfig.neighbor_info.update_interval = default_neighbor_info_broadcast_secs;
|
||||
}
|
||||
moduleConfig.neighbor_info = c.payload_variant.neighbor_info;
|
||||
break;
|
||||
case meshtastic_ModuleConfig_detection_sensor_tag:
|
||||
LOG_INFO("Set module config: Detection Sensor");
|
||||
|
||||
@@ -85,8 +85,12 @@
|
||||
#define HW_VENDOR meshtastic_HardwareModel_T_ECHO
|
||||
#elif defined(T_ECHO_LITE)
|
||||
#define HW_VENDOR meshtastic_HardwareModel_T_ECHO_LITE
|
||||
#elif defined(T_ECHO_CARD)
|
||||
#define HW_VENDOR meshtastic_HardwareModel_T_ECHO_CARD
|
||||
#elif defined(TTGO_T_ECHO_PLUS)
|
||||
#define HW_VENDOR meshtastic_HardwareModel_T_ECHO_PLUS
|
||||
#elif defined(T_IMPULSE_PLUS)
|
||||
#define HW_VENDOR meshtastic_HardwareModel_T_IMPULSE_PLUS
|
||||
#elif defined(ELECROW_ThinkNode_M1)
|
||||
#define HW_VENDOR meshtastic_HardwareModel_THINKNODE_M1
|
||||
#elif defined(ELECROW_ThinkNode_M3)
|
||||
|
||||
@@ -121,6 +121,10 @@ class Power : public concurrency::OSThread
|
||||
bool meshSolarInit();
|
||||
/// Setup a serial battery sensor
|
||||
bool serialBatteryInit();
|
||||
#ifdef HAS_ADS1115
|
||||
/// Setup ADS1115 I2C battery level sensor
|
||||
bool ads1115Init();
|
||||
#endif
|
||||
|
||||
private:
|
||||
void shutdown();
|
||||
|
||||
@@ -0,0 +1,109 @@
|
||||
#include "SGM41562.h"
|
||||
|
||||
#ifdef HAS_SGM41562
|
||||
|
||||
#include <Arduino.h>
|
||||
|
||||
SGM41562 *sgm41562 = nullptr;
|
||||
|
||||
bool initSGM41562(TwoWire &wire)
|
||||
{
|
||||
if (sgm41562)
|
||||
return true;
|
||||
sgm41562 = new SGM41562();
|
||||
if (!sgm41562->begin(wire)) {
|
||||
delete sgm41562;
|
||||
sgm41562 = nullptr;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SGM41562::readReg(uint8_t reg, uint8_t &value)
|
||||
{
|
||||
wire_->beginTransmission(address_);
|
||||
wire_->write(reg);
|
||||
if (wire_->endTransmission(false) != 0)
|
||||
return false;
|
||||
if (wire_->requestFrom((int)address_, 1) != 1)
|
||||
return false;
|
||||
value = wire_->read();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SGM41562::writeReg(uint8_t reg, uint8_t value)
|
||||
{
|
||||
wire_->beginTransmission(address_);
|
||||
wire_->write(reg);
|
||||
wire_->write(value);
|
||||
return wire_->endTransmission() == 0;
|
||||
}
|
||||
|
||||
bool SGM41562::updateReg(uint8_t reg, uint8_t mask, uint8_t value)
|
||||
{
|
||||
uint8_t cur;
|
||||
if (!readReg(reg, cur))
|
||||
return false;
|
||||
cur = (cur & ~mask) | (value & mask);
|
||||
return writeReg(reg, cur);
|
||||
}
|
||||
|
||||
bool SGM41562::begin(TwoWire &wire, uint8_t address)
|
||||
{
|
||||
wire_ = &wire;
|
||||
address_ = address;
|
||||
|
||||
uint8_t id;
|
||||
if (!readReg(REG_DEVICE_ID, id)) {
|
||||
LOG_WARN("SGM41562: I2C read failed at 0x%02X", address_);
|
||||
return false;
|
||||
}
|
||||
if (id != DEVICE_ID_EXPECTED) {
|
||||
LOG_WARN("SGM41562: unexpected device ID 0x%02X (expected 0x%02X)", id, DEVICE_ID_EXPECTED);
|
||||
return false;
|
||||
}
|
||||
LOG_INFO("SGM41562: detected at 0x%02X (id 0x%02X)", address_, id);
|
||||
|
||||
// Mirror the vendor reference init sequence: PCB OTP off, NTC off,
|
||||
// watchdog off, charger enabled. These match LilyGo's stock firmware
|
||||
// for the T-Impulse Plus.
|
||||
delay(120);
|
||||
writeReg(REG_SYS_VOLTAGE_REG, 0xB7);
|
||||
writeReg(REG_MISC_OP_CONTROL, 0x40);
|
||||
writeReg(REG_CHARGE_TERM_TIMER, 0x1A);
|
||||
writeReg(REG_POWER_ON_CFG, 0xA4);
|
||||
|
||||
return refresh();
|
||||
}
|
||||
|
||||
bool SGM41562::refresh()
|
||||
{
|
||||
uint32_t now = millis();
|
||||
if (lastRefreshMs_ != 0 && (now - lastRefreshMs_) < 250)
|
||||
return true; // cached
|
||||
lastRefreshMs_ = now == 0 ? 1 : now;
|
||||
|
||||
uint8_t status, fault;
|
||||
if (!readReg(REG_SYSTEM_STATUS, status))
|
||||
return false;
|
||||
if (!readReg(REG_FAULT, fault))
|
||||
return false;
|
||||
|
||||
chargeStatus_ = static_cast<ChargeStatus>((status >> SYS_STATUS_CHRG_SHIFT) & SYS_STATUS_CHRG_MASK);
|
||||
inputPowerGood_ = (status & SYS_STATUS_PG) != 0;
|
||||
thermalReg_ = (status & SYS_STATUS_THERM_REG) != 0;
|
||||
faultMask_ = fault & 0x3F; // bits [7:6] are enter_ship_time config, not faults
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SGM41562::setChargeEnable(bool enable)
|
||||
{
|
||||
return updateReg(REG_POWER_ON_CFG, POWER_ON_CFG_CHG_DISABLE, enable ? 0x00 : POWER_ON_CFG_CHG_DISABLE);
|
||||
}
|
||||
|
||||
bool SGM41562::setShippingModeEnable(bool enable)
|
||||
{
|
||||
return updateReg(REG_MISC_OP_CONTROL, MISC_OP_SHIPPING_MODE, enable ? MISC_OP_SHIPPING_MODE : 0x00);
|
||||
}
|
||||
|
||||
#endif // HAS_SGM41562
|
||||
@@ -0,0 +1,102 @@
|
||||
#pragma once
|
||||
|
||||
#include "configuration.h"
|
||||
|
||||
#ifdef HAS_SGM41562
|
||||
|
||||
#include <Wire.h>
|
||||
#include <stdint.h>
|
||||
|
||||
// SG Micro SGM41562 — single-cell Li-ion buck charger, I²C-controlled, no
|
||||
// fuel gauge. This driver exposes status (charging / input good / fault),
|
||||
// charge enable, and shipping-mode control. Battery voltage/percent still
|
||||
// come from the platform ADC path; the charger is plumbed in as a
|
||||
// side-channel for isCharging()/isVbusIn() in AnalogBatteryLevel.
|
||||
//
|
||||
// Reference: SGM41562 datasheet (Cmd map + bit fields cross-verified against
|
||||
// LilyGo's `Cpp_Bus_Driver::Sgm41562xx` driver, which is what their vendor
|
||||
// example for this board uses).
|
||||
|
||||
#ifndef SGM41562_ADDR
|
||||
#define SGM41562_ADDR 0x03 // Per datasheet — unusual but correct
|
||||
#endif
|
||||
|
||||
#ifndef SGM41562_WIRE
|
||||
#define SGM41562_WIRE Wire1 // Most boards put the PMU on the secondary bus
|
||||
#endif
|
||||
|
||||
class SGM41562
|
||||
{
|
||||
public:
|
||||
enum class ChargeStatus : uint8_t {
|
||||
NotCharging = 0b00,
|
||||
Precharge = 0b01,
|
||||
FastCharge = 0b10,
|
||||
ChargeDone = 0b11,
|
||||
};
|
||||
|
||||
bool begin(TwoWire &wire, uint8_t address = SGM41562_ADDR);
|
||||
|
||||
// Re-read the system status + fault registers. Throttled internally to
|
||||
// at most one I²C transaction per 250 ms — call as often as you like.
|
||||
bool refresh();
|
||||
|
||||
// Status — cached from the most recent refresh().
|
||||
ChargeStatus chargeStatus() const { return chargeStatus_; }
|
||||
bool isCharging() const { return chargeStatus_ == ChargeStatus::Precharge || chargeStatus_ == ChargeStatus::FastCharge; }
|
||||
bool isChargeDone() const { return chargeStatus_ == ChargeStatus::ChargeDone; }
|
||||
bool isInputPowerGood() const { return inputPowerGood_; }
|
||||
bool isThermalRegulation() const { return thermalReg_; }
|
||||
uint8_t faultMask() const { return faultMask_; }
|
||||
|
||||
// Control.
|
||||
bool setChargeEnable(bool enable);
|
||||
bool setShippingModeEnable(bool enable);
|
||||
|
||||
private:
|
||||
TwoWire *wire_ = nullptr;
|
||||
uint8_t address_ = SGM41562_ADDR;
|
||||
uint32_t lastRefreshMs_ = 0;
|
||||
|
||||
ChargeStatus chargeStatus_ = ChargeStatus::NotCharging;
|
||||
bool inputPowerGood_ = false;
|
||||
bool thermalReg_ = false;
|
||||
uint8_t faultMask_ = 0;
|
||||
|
||||
bool readReg(uint8_t reg, uint8_t &value);
|
||||
bool writeReg(uint8_t reg, uint8_t value);
|
||||
bool updateReg(uint8_t reg, uint8_t mask, uint8_t value);
|
||||
|
||||
// SGM41562 register addresses
|
||||
static constexpr uint8_t REG_INPUT_SOURCE = 0x00;
|
||||
static constexpr uint8_t REG_POWER_ON_CFG = 0x01;
|
||||
static constexpr uint8_t REG_CHARGE_CURRENT = 0x02;
|
||||
static constexpr uint8_t REG_DISCHARGE_TERM_CURRENT = 0x03;
|
||||
static constexpr uint8_t REG_CHARGE_VOLTAGE = 0x04;
|
||||
static constexpr uint8_t REG_CHARGE_TERM_TIMER = 0x05;
|
||||
static constexpr uint8_t REG_MISC_OP_CONTROL = 0x06;
|
||||
static constexpr uint8_t REG_SYS_VOLTAGE_REG = 0x07;
|
||||
static constexpr uint8_t REG_SYSTEM_STATUS = 0x08;
|
||||
static constexpr uint8_t REG_FAULT = 0x09;
|
||||
static constexpr uint8_t REG_I2C_ADDR_MISC = 0x0A;
|
||||
static constexpr uint8_t REG_DEVICE_ID = 0x0B;
|
||||
|
||||
// Bit positions in REG_POWER_ON_CFG.
|
||||
static constexpr uint8_t POWER_ON_CFG_CHG_DISABLE = 0x08; // bit 3: 1 = charging disabled
|
||||
// Bit positions in REG_MISC_OP_CONTROL.
|
||||
static constexpr uint8_t MISC_OP_SHIPPING_MODE = 0x20; // bit 5: 1 = enter shipping mode
|
||||
// Bit positions in REG_SYSTEM_STATUS.
|
||||
static constexpr uint8_t SYS_STATUS_CHRG_SHIFT = 3;
|
||||
static constexpr uint8_t SYS_STATUS_CHRG_MASK = 0x03;
|
||||
static constexpr uint8_t SYS_STATUS_PG = 0x02; // bit 1: input power good
|
||||
static constexpr uint8_t SYS_STATUS_THERM_REG = 0x01; // bit 0: thermal regulation
|
||||
|
||||
static constexpr uint8_t DEVICE_ID_EXPECTED = 0x04;
|
||||
};
|
||||
|
||||
extern SGM41562 *sgm41562;
|
||||
|
||||
// Lazy-instantiate the global on the supplied wire. Returns true on success.
|
||||
bool initSGM41562(TwoWire &wire);
|
||||
|
||||
#endif // HAS_SGM41562
|
||||
@@ -19,6 +19,16 @@ static meshtastic_Position makePosition()
|
||||
return position;
|
||||
}
|
||||
|
||||
static meshtastic_Channel makeChannel(meshtastic_Channel_Role role, bool hasModuleSettings, uint32_t positionPrecision)
|
||||
{
|
||||
meshtastic_Channel channel = meshtastic_Channel_init_default;
|
||||
channel.has_settings = true;
|
||||
channel.role = role;
|
||||
channel.settings.has_module_settings = hasModuleSettings;
|
||||
channel.settings.module_settings.position_precision = positionPrecision;
|
||||
return channel;
|
||||
}
|
||||
|
||||
static void test_applyPositionPrecision_clampsLatLonAndSetsPrecisionBits()
|
||||
{
|
||||
meshtastic_Position position = makePosition();
|
||||
@@ -80,6 +90,35 @@ static void test_applyPositionPrecision_reencodesPositionPacket()
|
||||
TEST_ASSERT_EQUAL_UINT32(16, decoded.precision_bits);
|
||||
}
|
||||
|
||||
static void test_getPositionPrecisionForChannel_explicitPrecisionIsHonored()
|
||||
{
|
||||
meshtastic_Channel channel = makeChannel(meshtastic_Channel_Role_PRIMARY, true, 16);
|
||||
|
||||
TEST_ASSERT_EQUAL_UINT32(16, getPositionPrecisionForChannel(channel));
|
||||
}
|
||||
|
||||
static void test_getPositionPrecisionForChannel_explicitZeroDisablesPrimary()
|
||||
{
|
||||
meshtastic_Channel channel = makeChannel(meshtastic_Channel_Role_PRIMARY, true, 0);
|
||||
|
||||
TEST_ASSERT_EQUAL_UINT32(0, getPositionPrecisionForChannel(channel));
|
||||
}
|
||||
|
||||
static void test_getPositionPrecisionForChannel_primaryWithoutModuleSettingsFailsClosed()
|
||||
{
|
||||
// Regression guard for #10509: precision 32 below must be ignored (no module settings).
|
||||
meshtastic_Channel channel = makeChannel(meshtastic_Channel_Role_PRIMARY, false, 32);
|
||||
|
||||
TEST_ASSERT_EQUAL_UINT32(0, getPositionPrecisionForChannel(channel));
|
||||
}
|
||||
|
||||
static void test_getPositionPrecisionForChannel_secondaryWithoutModuleSettingsFailsClosed()
|
||||
{
|
||||
meshtastic_Channel channel = makeChannel(meshtastic_Channel_Role_SECONDARY, false, 32);
|
||||
|
||||
TEST_ASSERT_EQUAL_UINT32(0, getPositionPrecisionForChannel(channel));
|
||||
}
|
||||
|
||||
void setUp(void) {}
|
||||
|
||||
void tearDown(void) {}
|
||||
@@ -93,6 +132,10 @@ void setup()
|
||||
RUN_TEST(test_applyPositionPrecision_fullPrecisionKeepsLatLon);
|
||||
RUN_TEST(test_applyPositionPrecision_zeroScrubsLocationButKeepsTime);
|
||||
RUN_TEST(test_applyPositionPrecision_reencodesPositionPacket);
|
||||
RUN_TEST(test_getPositionPrecisionForChannel_explicitPrecisionIsHonored);
|
||||
RUN_TEST(test_getPositionPrecisionForChannel_explicitZeroDisablesPrimary);
|
||||
RUN_TEST(test_getPositionPrecisionForChannel_primaryWithoutModuleSettingsFailsClosed);
|
||||
RUN_TEST(test_getPositionPrecisionForChannel_secondaryWithoutModuleSettingsFailsClosed);
|
||||
exit(UNITY_END());
|
||||
}
|
||||
|
||||
|
||||
@@ -72,7 +72,7 @@ lib_deps =
|
||||
# renovate: datasource=custom.pio depName=NimBLE-Arduino packageName=h2zero/library/NimBLE-Arduino
|
||||
h2zero/NimBLE-Arduino@1.4.3
|
||||
# renovate: datasource=git-refs depName=libpax packageName=https://github.com/dbinfrago/libpax gitBranch=master
|
||||
https://github.com/dbinfrago/libpax/archive/df424747f9acb86ab07c5a206ded1e8e3650726a.zip
|
||||
https://github.com/dbinfrago/libpax/archive/17302340f100efbc4bee5022ecc72047d6d93ed4.zip
|
||||
# renovate: datasource=custom.pio depName=XPowersLib packageName=lewisxhe/library/XPowersLib
|
||||
lewisxhe/XPowersLib@0.3.3
|
||||
# renovate: datasource=custom.pio depName=rweather/Crypto packageName=rweather/library/Crypto
|
||||
|
||||
@@ -21,4 +21,4 @@ build_src_filter =
|
||||
lib_deps =
|
||||
${esp32s3_base.lib_deps}
|
||||
# renovate: datasource=github-tags depName=ESP32-CH390 packageName=meshtastic/ESP32-CH390
|
||||
https://github.com/meshtastic/ESP32-CH390/archive/refs/tags/v1.0.1.zip
|
||||
https://github.com/meshtastic/ESP32-CH390/archive/v1.1.0.zip
|
||||
|
||||
@@ -20,4 +20,4 @@ build_src_filter =
|
||||
lib_deps =
|
||||
${esp32s3_base.lib_deps}
|
||||
# renovate: datasource=github-tags depName=ESP32-CH390 packageName=meshtastic/ESP32-CH390
|
||||
https://github.com/meshtastic/ESP32-CH390/archive/refs/tags/v1.0.1.zip
|
||||
https://github.com/meshtastic/ESP32-CH390/archive/v1.1.0.zip
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
#ifndef Pins_Arduino_h
|
||||
#define Pins_Arduino_h
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
|
||||
static const uint8_t SDA = 47;
|
||||
static const uint8_t SCL = 48;
|
||||
|
||||
// Default SPI will be mapped to Radio
|
||||
static const uint8_t SS = 21;
|
||||
static const uint8_t MOSI = 6;
|
||||
static const uint8_t MISO = 5;
|
||||
static const uint8_t SCK = 4;
|
||||
|
||||
#endif /* Pins_Arduino_h */
|
||||
@@ -0,0 +1,69 @@
|
||||
[env:seeed_wio_tracker_L2]
|
||||
custom_meshtastic_hw_model = 99 ; TODO: assign a unique number to this hardware model
|
||||
custom_meshtastic_hw_model_slug = SEEED_WIO_TRACKER_L2
|
||||
custom_meshtastic_architecture = esp32s3
|
||||
custom_meshtastic_actively_supported = true
|
||||
custom_meshtastic_support_level = 1
|
||||
custom_meshtastic_display_name = Seeed Wio Tracker L2
|
||||
custom_meshtastic_images = wio_tracker_l2_case.svg
|
||||
custom_meshtastic_tags = Seeed
|
||||
custom_meshtastic_requires_dfu = true
|
||||
|
||||
board = seeed_wio_tracker_L2
|
||||
board_level = pr
|
||||
extends = esp32s3_base
|
||||
board_check = true
|
||||
upload_protocol = esptool
|
||||
board_build.partitions = default_16MB.csv
|
||||
build_flags = ${esp32s3_base.build_flags}
|
||||
-I variants/esp32s3/seeed_wio_tracker_L2
|
||||
-D SEEED_WIO_TRACKER_L2
|
||||
-D CONFIG_ARDUHAL_ESP_LOG
|
||||
-D CONFIG_ARDUHAL_LOG_COLORS=1
|
||||
-D CONFIG_DISABLE_HAL_LOCKS=1
|
||||
-D MESHTASTIC_EXCLUDE_WEBSERVER=1
|
||||
-D LV_LVGL_H_INCLUDE_SIMPLE
|
||||
-D LV_CONF_INCLUDE_SIMPLE
|
||||
-D LV_COMP_CONF_INCLUDE_SIMPLE
|
||||
-D INPUTDRIVER_BUTTON_TYPE=0
|
||||
-D LV_USE_LOG=0
|
||||
-D LV_BUILD_TEST=0
|
||||
-D USE_LOG_DEBUG
|
||||
-D LOG_DEBUG_INC=\"DebugConfiguration.h\"
|
||||
-D RADIOLIB_SPI_PARANOID=0
|
||||
-D HAS_SCREEN=0
|
||||
-D HAS_TFT=1
|
||||
-D USE_I2S_BUZZER
|
||||
-D HAS_SDCARD
|
||||
-D HAS_SD_MMC ; SDIO mode 1-bit
|
||||
-D SD_SCLK_PIN=2
|
||||
-D SD_MOSI_PIN=3 ; CMD
|
||||
-D SD_MISO_PIN=1 ; D0
|
||||
-D SDCARD_CS=-1
|
||||
-D RAM_SIZE=5120
|
||||
-D LGFX_BUFSIZE=153600
|
||||
-D LV_CACHE_DEF_SIZE=2097152
|
||||
-D DISPLAY_SIZE=320x240 ; landscape mode
|
||||
-D LGFX_DRIVER=LGFX_WIO_TRACKER_L2
|
||||
-D GFX_DRIVER_INC=\"graphics/LGFX/LGFX_WIO_TRACKER_L2.h\"
|
||||
-D VIEW_320x240
|
||||
-D MAP_FULL_REDRAW
|
||||
-D USE_PACKET_API
|
||||
|
||||
|
||||
build_src_filter = ${esp32s3_base.build_src_filter} +<../variants/esp32s3/seeed_wio_tracker_L2>
|
||||
lib_deps =
|
||||
${esp32s3_base.lib_deps}
|
||||
${device-ui_base.lib_deps}
|
||||
# renovate: datasource=git-refs depName=ESP8266Audio packageName=https://github.com/meshtastic/ESP8266Audio gitBranch=meshtastic-2.0.0-dacfix
|
||||
https://github.com/meshtastic/ESP8266Audio/archive/343024632ee78d6216907b2353fc943a62422d80.zip
|
||||
# renovate: datasource=custom.pio depName=ESP8266SAM packageName=earlephilhower/library/ESP8266SAM
|
||||
earlephilhower/ESP8266SAM@1.1.0
|
||||
# renovate: datasource=github-tags depName=pschatzmann_arduino-audio-driver packageName=pschatzmann/arduino-audio-driver
|
||||
https://github.com/pschatzmann/arduino-audio-driver/archive/v0.2.1.zip
|
||||
# renovate: datasource=github-tags depName=RobTillaart_TCA9555 packageName=RobTillaart/TCA9555
|
||||
https://github.com/RobTillaart/TCA9555/archive/refs/tags/0.4.4.zip
|
||||
# renovate: datasource=github-tags depName=LovyanGFX packageName=lovyan03/LovyanGFX
|
||||
https://github.com/lovyan03/LovyanGFX/archive/29c590749059be69698eaeccaf4da6596755455d.zip
|
||||
# renovate: datasource=github-tags depName=Adafruit_ADS1X15 packageName=adafruit/Adafruit_ADS1X15
|
||||
https://github.com/adafruit/Adafruit_ADS1X15/archive/refs/tags/2.6.2.zip
|
||||
@@ -0,0 +1,107 @@
|
||||
#include "variant.h"
|
||||
#include "TCA9555.h"
|
||||
#include "AudioBoard.h"
|
||||
#include "DebugConfiguration.h"
|
||||
#include "mesh/MeshLED.h"
|
||||
|
||||
TCA9535 ioExpander(0x21);
|
||||
DriverPins PinsAudioBoardES8311;
|
||||
AudioBoard board(AudioDriverES8311, PinsAudioBoardES8311);
|
||||
|
||||
class WioTrackerMeshLED : public MeshLED
|
||||
{
|
||||
public:
|
||||
void init() override { ioExpander.write1(10, LOW); } // ensure LED starts off
|
||||
void on() override { ioExpander.write1(10, HIGH); }
|
||||
void off() override { ioExpander.write1(10, LOW); }
|
||||
};
|
||||
|
||||
static bool initOK = false;
|
||||
|
||||
void initVariant()
|
||||
{
|
||||
Wire.begin(I2C_SDA, I2C_SCL);
|
||||
if (ioExpander.begin()) {
|
||||
ioExpander.pinMode1(0, INPUT); // wakeup button
|
||||
ioExpander.pinMode1(1, INPUT); // IIC IRQ
|
||||
ioExpander.pinMode1(2, INPUT); // SD detect
|
||||
|
||||
ioExpander.pinMode1(11, OUTPUT); // OTG EN
|
||||
ioExpander.write1(11, LOW); // OTG EN low
|
||||
delay(10);
|
||||
ioExpander.pinMode1(12, OUTPUT); // PA EN
|
||||
ioExpander.write1(12, HIGH); // PA EN high
|
||||
delay(10);
|
||||
ioExpander.pinMode1(14, OUTPUT); // TF EN
|
||||
ioExpander.write1(14, HIGH); // TF EN high
|
||||
delay(10);
|
||||
ioExpander.pinMode1(15, OUTPUT); // BAT ADC EN
|
||||
ioExpander.write1(15, HIGH); // BAT ADC EN high
|
||||
delay(10);
|
||||
ioExpander.pinMode1(13, OUTPUT); // GNSS EN
|
||||
ioExpander.write1(13, HIGH); // GNSS EN high
|
||||
delay(10);
|
||||
ioExpander.pinMode1(9, OUTPUT); // GNSS RST (active HIGH on this board)
|
||||
// Expander output defaults to HIGH, so module is already in reset.
|
||||
// Hold reset for 10ms, then release LOW so the module starts running.
|
||||
delay(10);
|
||||
ioExpander.write1(9, LOW); // release reset - module starts running
|
||||
ioExpander.pinMode1(10, OUTPUT); // User LED / GNSS wakeup
|
||||
ioExpander.write1(10, LOW); // User LED / GNSS wakeup low
|
||||
delay(10);
|
||||
ioExpander.pinMode1(7, OUTPUT); // GROVE EN
|
||||
ioExpander.write1(7, HIGH); // GROVE EN high
|
||||
delay(10);
|
||||
|
||||
ioExpander.pinMode1(5, OUTPUT); // LCD EN
|
||||
ioExpander.write1(5, HIGH); // LCD EN high
|
||||
delay(50);
|
||||
ioExpander.pinMode1(6, OUTPUT); // LCD RST
|
||||
ioExpander.write1(6, HIGH); // LCD RST high
|
||||
delay(5);
|
||||
ioExpander.write1(6, LOW); // LCD RST low
|
||||
delay(10);
|
||||
ioExpander.write1(6, HIGH); // LCD RST high
|
||||
delay(500);
|
||||
ioExpander.pinMode1(4, OUTPUT); // LCD CS
|
||||
ioExpander.write1(4, HIGH); // LCD CS high
|
||||
delay(10);
|
||||
|
||||
ioExpander.pinMode1(8, OUTPUT); // TP RST
|
||||
ioExpander.write1(8, LOW); // TP RST low
|
||||
ioExpander.pinMode1(3, OUTPUT); // TP INT
|
||||
ioExpander.write1(3, LOW); // TP INT low
|
||||
delay(10);
|
||||
ioExpander.write1(3, LOW); // TP INT low
|
||||
delay(1);
|
||||
ioExpander.write1(8, HIGH); // TP RST high
|
||||
delay(60);
|
||||
initOK = true;
|
||||
|
||||
meshLED = std::make_shared<WioTrackerMeshLED>();
|
||||
meshLED->init();
|
||||
}
|
||||
}
|
||||
|
||||
void lateInitVariant()
|
||||
{
|
||||
if (!initOK) {
|
||||
LOG_ERROR("TCA9535 initialization failed");
|
||||
return;
|
||||
}
|
||||
// AudioDriverLogger.begin(Serial, AudioDriverLogLevel::Debug);
|
||||
// I2C: function, scl, sda
|
||||
PinsAudioBoardES8311.addI2C(PinFunction::CODEC, Wire);
|
||||
// I2S: function, mclk, bck, ws, data_out, data_in
|
||||
PinsAudioBoardES8311.addI2S(PinFunction::CODEC, DAC_I2S_MCLK, DAC_I2S_BCK, DAC_I2S_WS, DAC_I2S_DOUT, DAC_I2S_DIN);
|
||||
|
||||
// configure codec
|
||||
CodecConfig cfg;
|
||||
cfg.input_device = ADC_INPUT_LINE1;
|
||||
cfg.output_device = DAC_OUTPUT_ALL;
|
||||
cfg.i2s.bits = BIT_LENGTH_16BITS;
|
||||
cfg.i2s.rate = RATE_44K;
|
||||
board.begin(cfg);
|
||||
board.setVolume(75); // 75% volume
|
||||
LOG_INFO("ES8311 Audio board initialized");
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
#pragma once
|
||||
|
||||
#define BUTTON_PIN 0
|
||||
|
||||
#define I2C_SDA 47
|
||||
#define I2C_SCL 48
|
||||
|
||||
#define USE_POWERSAVE
|
||||
#define SLEEP_TIME 120
|
||||
|
||||
#define HAS_ADS1115
|
||||
#define ADS1115_ADDR 0x48
|
||||
|
||||
// LED controller
|
||||
#define HAS_LP5814
|
||||
|
||||
// ES8311 DAC / AMP
|
||||
#define HAS_I2S
|
||||
|
||||
#define HAS_ES8311
|
||||
#define DAC_I2S_BCK 11 // SCLK
|
||||
#define DAC_I2S_WS 12 // LRLK
|
||||
#define DAC_I2S_DOUT 16
|
||||
#define DAC_I2S_DIN -1
|
||||
#define DAC_I2S_MCLK 10
|
||||
|
||||
#define HAS_ES7243E
|
||||
#define ADC_I2S_BCK 11
|
||||
#define ADC_I2S_WS 12
|
||||
#define ADC_I2S_DOUT -1
|
||||
#define ADC_I2S_DIN 15
|
||||
#define ADC_I2S_MCLK 10
|
||||
|
||||
// SX1262 LoRa Module Pins
|
||||
#define USE_SX1262
|
||||
#define LORA_SCK 4
|
||||
#define LORA_MISO 5
|
||||
#define LORA_MOSI 6
|
||||
#define LORA_CS 21
|
||||
#define LORA_RESET 7
|
||||
|
||||
#define LORA_DIO1 9
|
||||
#define LORA_DIO0 -1
|
||||
#define LORA_DIO2 8
|
||||
#define LORA_DIO3
|
||||
|
||||
#define SX126X_CS LORA_CS
|
||||
#define SX126X_DIO1 LORA_DIO1
|
||||
#define SX126X_BUSY LORA_DIO2
|
||||
#define SX126X_RESET LORA_RESET
|
||||
#define SX126X_DIO3_TCXO_VOLTAGE 1.8
|
||||
#define SX126X_DIO2_AS_RF_SWITCH
|
||||
|
||||
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
// GPS L76KB
|
||||
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
#define GPS_L76K
|
||||
#ifdef GPS_L76K
|
||||
#define GPS_TX_PIN 17
|
||||
#define GPS_RX_PIN 18
|
||||
#define HAS_GPS 1
|
||||
#define GPS_THREAD_INTERVAL 50
|
||||
//#define GPS_EN // TODO: add GPS enable pin control via io/expander
|
||||
#endif
|
||||
|
||||
@@ -6,7 +6,6 @@ debug_tool = jlink
|
||||
|
||||
build_flags = ${nrf52840_base.build_flags}
|
||||
-I variants/nrf52840/t-echo-card
|
||||
-D PRIVATE_HW
|
||||
-D T_ECHO_CARD
|
||||
|
||||
build_src_filter = ${nrf52_base.build_src_filter} +<../variants/nrf52840/t-echo-card>
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
[env:t-impulse-plus]
|
||||
custom_meshtastic_hw_model = 135
|
||||
custom_meshtastic_hw_model_slug = T_IMPULSE_PLUS
|
||||
custom_meshtastic_architecture = nrf52840
|
||||
custom_meshtastic_actively_supported = true
|
||||
custom_meshtastic_support_level = 1
|
||||
custom_meshtastic_display_name = LILYGO T-Impulse Plus
|
||||
custom_meshtastic_tags = LilyGo
|
||||
custom_meshtastic_requires_dfu = true
|
||||
|
||||
extends = nrf52840_base
|
||||
board = t-impulse-plus
|
||||
board_level = pr
|
||||
|
||||
build_flags = ${nrf52840_base.build_flags}
|
||||
-I variants/nrf52840/t-impulse-plus
|
||||
-D T_IMPULSE_PLUS
|
||||
|
||||
build_src_filter = ${nrf52_base.build_src_filter} +<../variants/nrf52840/t-impulse-plus>
|
||||
@@ -0,0 +1,91 @@
|
||||
/*
|
||||
* variant.cpp - Digital pin mapping for LilyGo T-Impulse Plus
|
||||
*
|
||||
* Board: T-Impulse Plus V1.0 (nRF52840)
|
||||
* Hardware:
|
||||
* - SSD1315 OLED
|
||||
* - SX1262 (S62F)
|
||||
* - MIA-M10Q GPS
|
||||
* - ICM20948 IMU
|
||||
* - ZD25WQ32C Flash
|
||||
* - TTP223 Touch Button
|
||||
* - Vibration Motor
|
||||
*/
|
||||
|
||||
#include "variant.h"
|
||||
#include "nrf.h"
|
||||
#include "wiring_constants.h"
|
||||
#include "wiring_digital.h"
|
||||
|
||||
extern "C" {
|
||||
const uint32_t g_ADigitalPinMap[] = {
|
||||
// D0-D6: LoRa SX1262 (S62F module) SPI + control
|
||||
2, // D0 P0.02 SX1262_RST
|
||||
29, // D1 P0.29 SX1262_DIO1
|
||||
31, // D2 P0.31 SX1262_BUSY
|
||||
46, // D3 P1.14 SX1262_CS
|
||||
3, // D4 P0.03 SPI_SCK
|
||||
30, // D5 P0.30 SPI_MISO
|
||||
28, // D6 P0.28 SPI_MOSI
|
||||
|
||||
// D7-D8: RF switch control
|
||||
45, // D7 P1.13 SX1262_RF_VC1 (TXEN)
|
||||
39, // D8 P1.07 SX1262_RF_VC2 (RXEN)
|
||||
|
||||
// D9-D11: GPS (u-blox MIA-M10Q)
|
||||
44, // D9 P1.12 GPS_TX (MCU TX -> GPS RX)
|
||||
43, // D10 P1.11 GPS_RX (MCU RX <- GPS TX)
|
||||
42, // D11 P1.10 GPS_EN
|
||||
|
||||
// D12-D13: Display I2C (SSD1315)
|
||||
20, // D12 P0.20 SCREEN_SDA
|
||||
15, // D13 P0.15 SCREEN_SCL
|
||||
|
||||
// D14-D15: Sensor I2C (ICM20948, SGM41562)
|
||||
40, // D14 P1.08 IMU_SDA
|
||||
11, // D15 P0.11 IMU_SCL
|
||||
|
||||
// D16-D17: Battery management
|
||||
5, // D16 P0.05 BATTERY_ADC
|
||||
25, // D17 P0.25 BATTERY_MEASUREMENT_CONTROL
|
||||
|
||||
// D18: Touch button (TTP223)
|
||||
36, // D18 P1.04 TTP223_KEY
|
||||
|
||||
// D19: Vibration motor
|
||||
22, // D19 P0.22 VIBRATION_MOTOR
|
||||
|
||||
// D20: LDO enable
|
||||
14, // D20 P0.14 RT9080_EN
|
||||
|
||||
// D21-D26: Flash QSPI (ZD25WQ32C)
|
||||
12, // D21 P0.12 FLASH_CS
|
||||
4, // D22 P0.04 FLASH_SCLK
|
||||
6, // D23 P0.06 FLASH_IO0
|
||||
41, // D24 P1.09 FLASH_IO1
|
||||
8, // D25 P0.08 FLASH_IO2
|
||||
26, // D26 P0.26 FLASH_IO3
|
||||
|
||||
// D27-D28: Interrupt lines
|
||||
7, // D27 P0.07 ICM20948_INT
|
||||
16, // D28 P0.16 SGM41562_INT
|
||||
|
||||
// D29: Boot button
|
||||
24, // D29 P0.24 BOOT
|
||||
};
|
||||
}
|
||||
|
||||
void initVariant()
|
||||
{
|
||||
// Flash CS high (deselect)
|
||||
pinMode(PIN_QSPI_CS, OUTPUT);
|
||||
digitalWrite(PIN_QSPI_CS, HIGH);
|
||||
|
||||
// Enable battery voltage measurement
|
||||
pinMode(BAT_READ, OUTPUT);
|
||||
digitalWrite(BAT_READ, HIGH);
|
||||
|
||||
// Enable RT9080 LDO
|
||||
pinMode(D20, OUTPUT);
|
||||
digitalWrite(D20, HIGH);
|
||||
}
|
||||
@@ -0,0 +1,181 @@
|
||||
#ifndef _T_IMPULSE_PLUS_H_
|
||||
#define _T_IMPULSE_PLUS_H_
|
||||
#include "WVariant.h"
|
||||
|
||||
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
// Clock Configuration
|
||||
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
#define VARIANT_MCK (64000000ul)
|
||||
#define USE_LFXO
|
||||
|
||||
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
// Pin Capacity Definitions
|
||||
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
#define PINS_COUNT (30u)
|
||||
#define NUM_DIGITAL_PINS (30u)
|
||||
#define NUM_ANALOG_INPUTS (1u)
|
||||
#define NUM_ANALOG_OUTPUTS (0u)
|
||||
|
||||
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
// Digital Pin Mapping
|
||||
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
#define D0 0 // P0.02 SX1262_RST
|
||||
#define D1 1 // P0.29 SX1262_DIO1
|
||||
#define D2 2 // P0.31 SX1262_BUSY
|
||||
#define D3 3 // P1.14 SX1262_CS
|
||||
#define D4 4 // P0.03 SPI_SCK
|
||||
#define D5 5 // P0.30 SPI_MISO
|
||||
#define D6 6 // P0.28 SPI_MOSI
|
||||
#define D7 7 // P1.13 RF_VC1 (TXEN)
|
||||
#define D8 8 // P1.07 RF_VC2 (RXEN)
|
||||
#define D9 9 // P1.12 GPS module TX → MCU RX
|
||||
#define D10 10 // P1.11 GPS module RX ← MCU TX
|
||||
#define D11 11 // P1.10 GPS_EN (active LOW)
|
||||
#define D12 12 // P0.20 SCREEN_SDA
|
||||
#define D13 13 // P0.15 SCREEN_SCL
|
||||
#define D14 14 // P1.08 IMU_SDA
|
||||
#define D15 15 // P0.11 IMU_SCL
|
||||
#define D16 16 // P0.05 BATTERY_ADC
|
||||
#define D17 17 // P0.25 BATTERY_CTL
|
||||
#define D18 18 // P1.04 TTP223_KEY
|
||||
#define D19 19 // P0.22 VIBRATION_MOTOR
|
||||
#define D20 20 // P0.14 RT9080_EN
|
||||
#define D21 21 // P0.12 FLASH_CS
|
||||
#define D22 22 // P0.04 FLASH_SCLK
|
||||
#define D23 23 // P0.06 FLASH_IO0
|
||||
#define D24 24 // P1.09 FLASH_IO1
|
||||
#define D25 25 // P0.08 FLASH_IO2
|
||||
#define D26 26 // P0.26 FLASH_IO3
|
||||
#define D27 27 // P0.07 ICM20948_INT
|
||||
#define D28 28 // P0.16 SGM41562_INT
|
||||
#define D29 29 // P0.24 BOOT
|
||||
|
||||
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
// LED Configuration (no physical LED)
|
||||
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
#define LED_STATE_ON 1
|
||||
|
||||
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
// Button Configuration (TTP223 capacitive touch)
|
||||
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
#define PIN_BUTTON_TOUCH D18
|
||||
#define BUTTON_TOUCH_ACTIVE_LOW true
|
||||
#define BUTTON_TOUCH_ACTIVE_PULLUP false
|
||||
|
||||
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
// Analog Pin Definitions
|
||||
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
#define PIN_VBAT D16 // P0.05 Battery voltage sense
|
||||
|
||||
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
// I2C Configuration
|
||||
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
// Primary I2C: Display (SSD1315)
|
||||
#define PIN_WIRE_SDA D12 // P0.20
|
||||
#define PIN_WIRE_SCL D13 // P0.15
|
||||
|
||||
// Secondary I2C: IMU (ICM20948) + PMU (SGM41562)
|
||||
#define WIRE_INTERFACES_COUNT 2
|
||||
#define PIN_WIRE1_SDA D14 // P1.08
|
||||
#define PIN_WIRE1_SCL D15 // P0.11
|
||||
#define I2C_NO_RESCAN
|
||||
|
||||
static const uint8_t SDA = PIN_WIRE_SDA;
|
||||
static const uint8_t SCL = PIN_WIRE_SCL;
|
||||
|
||||
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
// Display (SSD1315, compatible with SSD1306 driver)
|
||||
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
#define HAS_SCREEN 1
|
||||
#define USE_SSD1306 1
|
||||
#define OLED_TINY
|
||||
#define OLED_GEOMETRY_OVERRIDE GEOMETRY_64_32
|
||||
|
||||
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
// SPI Configuration (SX1262 LoRa)
|
||||
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
#define SPI_INTERFACES_COUNT 1
|
||||
#define PIN_SPI_SCK D4 // P0.03
|
||||
#define PIN_SPI_MISO D5 // P0.30
|
||||
#define PIN_SPI_MOSI D6 // P0.28
|
||||
|
||||
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
// SX1262 LoRa (S62F module)
|
||||
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
#define USE_SX1262
|
||||
#define SX126X_CS D3
|
||||
#define SX126X_DIO1 D1
|
||||
#define SX126X_BUSY D2
|
||||
#define SX126X_RESET D0
|
||||
#define SX126X_DIO3_TCXO_VOLTAGE 1.8
|
||||
#define SX126X_TXEN D7 // RF_VC1
|
||||
#define SX126X_RXEN D8 // RF_VC2
|
||||
|
||||
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
// Power Management
|
||||
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
#define BAT_READ D17 // P0.25 Battery measurement control (HIGH = enable)
|
||||
#define BATTERY_PIN PIN_VBAT
|
||||
#define BATTERY_SENSE_RESOLUTION_BITS 12
|
||||
#define ADC_MULTIPLIER 2.0
|
||||
#define AREF_VOLTAGE 3.6
|
||||
|
||||
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
// GPS (u-blox MIA-M10Q)
|
||||
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
#define GPS_UBLOX
|
||||
#define HAS_GPS 1
|
||||
#define GPS_RX_PIN D9 // P1.12 — MCU RX, wired to GPS module TX
|
||||
#define GPS_TX_PIN D10 // P1.11 — MCU TX, wired to GPS module RX
|
||||
#define PIN_GPS_EN D11 // P1.10
|
||||
#define GPS_EN_ACTIVE LOW
|
||||
#define GPS_BAUDRATE 38400
|
||||
#define GPS_THREAD_INTERVAL 50
|
||||
#define PIN_SERIAL1_TX GPS_TX_PIN
|
||||
#define PIN_SERIAL1_RX GPS_RX_PIN
|
||||
|
||||
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
// On-board QSPI Flash (ZD25WQ32CEIGR)
|
||||
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
#define PIN_QSPI_SCK D22 // P0.04
|
||||
#define PIN_QSPI_CS D21 // P0.12
|
||||
#define PIN_QSPI_IO0 D23 // P0.06
|
||||
#define PIN_QSPI_IO1 D24 // P1.09
|
||||
#define PIN_QSPI_IO2 D25 // P0.08
|
||||
#define PIN_QSPI_IO3 D26 // P0.26
|
||||
|
||||
#define EXTERNAL_FLASH_DEVICES W25Q32JV_IQ
|
||||
#define EXTERNAL_FLASH_USE_QSPI
|
||||
|
||||
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
// Vibration Motor (GPIO active-high)
|
||||
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
#define LED_NOTIFICATION D19 // P0.22
|
||||
#define HAPTIC_FEEDBACK_PIN LED_NOTIFICATION
|
||||
|
||||
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
// IMU (ICM20948 on Wire1)
|
||||
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
#define HAS_ICM20948
|
||||
|
||||
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
// Charger (SGM41562 on Wire1 @ 0x03)
|
||||
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
#define HAS_SGM41562
|
||||
#define SGM41562_WIRE Wire1
|
||||
|
||||
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
// Compatibility Definitions
|
||||
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define PIN_SERIAL2_RX (-1)
|
||||
#define PIN_SERIAL2_TX (-1)
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // _T_IMPULSE_PLUS_H_
|
||||
@@ -2,7 +2,7 @@
|
||||
extends = arduino_base
|
||||
platform =
|
||||
# renovate: datasource=custom.pio depName=platformio/ststm32 packageName=platformio/platform/ststm32
|
||||
platformio/ststm32@19.5.0
|
||||
platformio/ststm32@19.6.0
|
||||
platform_packages =
|
||||
# renovate: datasource=github-tags depName=Arduino_Core_STM32 packageName=stm32duino/Arduino_Core_STM32
|
||||
platformio/framework-arduinoststm32@https://github.com/stm32duino/Arduino_Core_STM32/archive/2.10.1.zip
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
[VERSION]
|
||||
major = 2
|
||||
minor = 7
|
||||
build = 24
|
||||
build = 25
|
||||
|
||||
Reference in New Issue
Block a user