Add get leds and set leds on|off for Companion, repeater, room server and sensor builds. Preserve the setting across reboots and cover GPIO, RGB, Bluetooth, notification and expander indicators without changing radio amplifier controls or screen backlights. RAK Companions blink while advertising and keep the Bluetooth LED off once connected, including late timer callbacks. Adapted from meshcore-dev/MeshCore#3605 and #2694. Validated with host regressions and firmware builds for SenseCAP Solar, RAK4631, T096, Heltec V4, T-Beam, Xiao S3, Pico W and Wio E5 Mini. Co-authored-by: R0ck <develop@hectospark.co.uk> Co-authored-by: Nick Dunklee <nick@dunklee.org>
147 lines
4.4 KiB
C++
147 lines
4.4 KiB
C++
#include "HeltecTrackerV2Board.h"
|
|
#include <helpers/ESP32GpioHold.h>
|
|
|
|
void HeltecTrackerV2Board::begin() {
|
|
ESP32Board::begin();
|
|
|
|
pinMode(PIN_ADC_CTRL, OUTPUT);
|
|
digitalWrite(PIN_ADC_CTRL, LOW); // Initially inactive
|
|
|
|
loRaFEMControl.init();
|
|
|
|
esp_reset_reason_t reason = esp_reset_reason();
|
|
if (reason != ESP_RST_DEEPSLEEP) {
|
|
delay(1); // GC1109 startup time after cold power-on
|
|
}
|
|
|
|
periph_power.begin();
|
|
if (reason == ESP_RST_DEEPSLEEP) {
|
|
long wakeup_source = esp_sleep_get_ext1_wakeup_status();
|
|
if (wakeup_source & (1 << P_LORA_DIO_1)) { // received a LoRa packet (while in deep sleep)
|
|
startup_reason = BD_STARTUP_RX_PACKET;
|
|
}
|
|
|
|
mesh::esp32::releaseRtcGpioIfSupported((gpio_num_t)P_LORA_NSS);
|
|
mesh::esp32::deinitRtcGpioIfSupported((gpio_num_t)P_LORA_DIO_1);
|
|
}
|
|
}
|
|
|
|
void HeltecTrackerV2Board::onBeforeTransmit(void) {
|
|
if (mesh::leds::enabled()) digitalWrite(P_LORA_TX_LED, HIGH); // turn TX LED on
|
|
loRaFEMControl.setTxModeEnable();
|
|
}
|
|
|
|
void HeltecTrackerV2Board::onAfterTransmit(void) {
|
|
digitalWrite(P_LORA_TX_LED, LOW); // turn TX LED off
|
|
loRaFEMControl.setRxModeEnable();
|
|
}
|
|
|
|
void HeltecTrackerV2Board::shutdownPeripherals() {
|
|
ESP32Board::shutdownPeripherals();
|
|
// Turn off PA. Guarded because this board file is also compiled for the
|
|
// heltec_tracker_v1_1 envs, which do not define P_LORA_PA_POWER (it is set
|
|
// only in variants/heltec_tracker_v2/platformio.ini). Same guard idiom
|
|
// LoRaFEMControl.cpp already uses for this macro.
|
|
#if defined(P_LORA_PA_POWER)
|
|
mesh::esp32::holdOutputForDeepSleep((gpio_num_t)P_LORA_PA_POWER, LOW);
|
|
#endif
|
|
}
|
|
|
|
uint16_t HeltecTrackerV2Board::getBattMilliVolts() {
|
|
analogReadResolution(10);
|
|
digitalWrite(PIN_ADC_CTRL, HIGH);
|
|
delay(10);
|
|
uint32_t raw = 0;
|
|
for (int i = 0; i < 8; i++) {
|
|
raw += analogRead(PIN_VBAT_READ);
|
|
}
|
|
raw = raw / 8;
|
|
|
|
digitalWrite(PIN_ADC_CTRL, LOW);
|
|
|
|
return (5.42 * (3.3 / 1024.0) * raw) * 1000;
|
|
}
|
|
|
|
const char* HeltecTrackerV2Board::getManufacturerName() const {
|
|
// The v1.1 environment reuses this V2 board implementation (same variant
|
|
// dir), so report the correct identity per build flag -- this string feeds
|
|
// WebConfig and MQTT status/board metadata.
|
|
#ifdef HELTEC_TRACKER_V1_1
|
|
return "Heltec Tracker V1.1";
|
|
#else
|
|
return "Heltec Tracker V2";
|
|
#endif
|
|
}
|
|
|
|
bool HeltecTrackerV2Board::setLoRaFemLnaEnabled(bool enable) {
|
|
if (!loRaFEMControl.isLnaCanControl()) {
|
|
return false;
|
|
}
|
|
|
|
loRaFEMControl.setLNAEnable(enable);
|
|
loRaFEMControl.setRxModeEnable();
|
|
return true;
|
|
}
|
|
|
|
bool HeltecTrackerV2Board::canControlLoRaFemLna() const {
|
|
return loRaFEMControl.isLnaCanControl();
|
|
}
|
|
|
|
bool HeltecTrackerV2Board::isLoRaFemLnaEnabled() const {
|
|
return loRaFEMControl.isLNAEnabled();
|
|
}
|
|
|
|
void HeltecTrackerV2Board::attachDynamicPrefs(KeyValueStore* prefs) {
|
|
_prefs = prefs;
|
|
if (_prefs == nullptr) {
|
|
return;
|
|
}
|
|
|
|
char radio_fem_rxgain[8] = { 0 };
|
|
_prefs->getByKey("fem_rxgain", radio_fem_rxgain, 7); // get initial values
|
|
|
|
setLoRaFemLnaEnabled(strcmp(radio_fem_rxgain, "1") == 0);
|
|
}
|
|
|
|
bool HeltecTrackerV2Board::handleCommand(const char* command, uint32_t sender_timestamp, char* reply) {
|
|
(void)sender_timestamp;
|
|
if (command == nullptr || reply == nullptr) {
|
|
return false;
|
|
}
|
|
|
|
if (strcmp(command, "get radio.fem.rxgain") == 0) {
|
|
if (!loRaFEMControl.isLnaCanControl()) {
|
|
strcpy(reply, "Error: unsupported");
|
|
} else {
|
|
sprintf(reply, "> %s", isLoRaFemLnaEnabled() ? "on" : "off");
|
|
}
|
|
return true;
|
|
}
|
|
if (strncmp(command, "set radio.fem.rxgain ", 21) == 0) {
|
|
if (!loRaFEMControl.isLnaCanControl()) {
|
|
strcpy(reply, "Error: unsupported");
|
|
} else if (_prefs == nullptr) {
|
|
strcpy(reply, "Error: preferences unavailable");
|
|
} else if (strcmp(&command[21], "on") == 0) {
|
|
if (setLoRaFemLnaEnabled(true)) {
|
|
_prefs->setByKey("fem_rxgain", "1");
|
|
strcpy(reply, "OK - LoRa FEM RX gain on");
|
|
} else {
|
|
strcpy(reply, "Error: failed to apply LoRa FEM RX gain");
|
|
}
|
|
} else if (strcmp(&command[21], "off") == 0) {
|
|
if (setLoRaFemLnaEnabled(false)) {
|
|
_prefs->setByKey("fem_rxgain", "0");
|
|
strcpy(reply, "OK - LoRa FEM RX gain off");
|
|
} else {
|
|
strcpy(reply, "Error: failed to apply LoRa FEM RX gain");
|
|
}
|
|
} else {
|
|
strcpy(reply, "Error: state must be on or off");
|
|
}
|
|
return true;
|
|
}
|
|
|
|
return false; // not handled
|
|
}
|