Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 18 additions & 7 deletions docs/CLI_commands.md
Original file line number Diff line number Diff line change
Expand Up @@ -358,8 +358,9 @@ The observer role (ESP32, `boards/common/observer.conf`) has its own CLI and non
| `get owner.info` | Owner/contact info (pipes `\|` display as newlines) |
| `get int.thresh` | Interference threshold |
| `get leds` | *(ZephCore only)* LED master switch: `on` or `off` |
| `get leds.radio` | *(ZephCore only)* Activity-LED mode: `tx`, `rx`, `all` or `off`. Appends `(no radio LED on this board)` where the board has no `lora-tx-led` alias |
| `get leds.radio` | *(ZephCore only)* Activity-LED mode: `tx`, `rx`, `all` or `off`. Appends `(no radio LED on this board)` where the board has neither a `lora-tx-led` nor a `lora-tx-pwm-led` alias |
| `get leds.hb` | *(ZephCore only)* Heartbeat-LED mode: `all`, `hb`, `unread` or `off`. Appends `(no heartbeat LED on this board)` where the board has neither `led0` nor `led1` |
| `get leds.brightness` | *(ZephCore only)* Brightness of a PWM-capable heartbeat/activity LED, `0` to `100` as a percentage. Boards without a `heartbeat-pwm-led` / `lora-tx-pwm-led` alias still report a value (nothing reads it) |
| `get buzzer` | *(ZephCore only; room server only)* Buzzer/vibration mode as `<n> (<name>)`: `0 (silent)`, `1 (sound+vib)`, `2 (vibrate)`, `3 (sound)`. Compiled out on repeater builds (`#ifndef ZEPHCORE_REPEATER`) — a repeater answers `unknown config: buzzer`. |
| `get agc.reset.interval` | Removed — replies `Removed - Automatic AGC reset is on`. Periodic AGC recalibration was deleted (it reset the noise floor to its unseeded sentinel on every fire). Use `set rxduty` to cut RX current. |
| `get multi.acks` | Extra ACK transmit count (`0` or `1`) |
Expand Down Expand Up @@ -441,8 +442,9 @@ four radio parameters together, since they are one interop-critical set.
| `set int.thresh <value>` | | Interference detection threshold |
| `set buzzer <0\|1\|2\|3>` | or `off` / `on` / `vibrate` / `sound` | *(ZephCore only; room server only)* `0`/`off` silent, `1`/`on` sound + vibration, `2`/`vibrate` vibration only, `3`/`sound` sound only. Modes 2 and 3 need a vibration motor; without one the node replies `Error: no vibration motor on this board - use 0 or 1`. Applied live and persisted. Compiled out on repeater builds. |
| `set leds <on\|off\|1\|0>` | default **on** | *(ZephCore only)* Master switch for every LED on the node, applied live and persisted: heartbeat, unread-message and LoRa TX-activity LEDs, plus the message and shutdown flashes. Works on every role, including headless repeaters where the TX LED is the only one that ever lights. Does **not** cover the display backlight, which is a separate UI brightness setting. |
| `set leds.radio <tx\|rx\|all\|off>` | default **tx** | *(ZephCore only)* What the LoRa activity LED reacts to, applied live and persisted. `tx` lights it for the duration of each transmit (the behaviour before this setting existed), `rx` gives a 30 ms blink per valid packet received, `all` does both, `off` keeps it dark. Sits **below** `set leds` — the master switch off keeps it dark whatever this says. Only boards defining the `lora-tx-led` alias have this LED; elsewhere the value is stored but does nothing, and the reply says so. |
| `set leds.radio <tx\|rx\|all\|off>` | default **tx** | *(ZephCore only)* What the LoRa activity LED reacts to, applied live and persisted. `tx` lights it for the duration of each transmit (the behaviour before this setting existed), `rx` gives a 30 ms blink per valid packet received, `all` does both, `off` keeps it dark. Sits **below** `set leds`: the master switch off keeps it dark whatever this says. Only boards defining a `lora-tx-led` or `lora-tx-pwm-led` alias have this LED; elsewhere the value is stored but does nothing, and the reply says so. |
| `set leds.hb <hb\|unread\|all\|off>` | default **all** | *(ZephCore only)* What the heartbeat LED reacts to, applied live and persisted. `all` is the 4 s liveness tick that widens from 20 ms to 200 ms while messages are unread (the behaviour before this setting existed), `hb` never widens, `unread` stays dark until there are unread messages, `off` keeps it dark. Also sits below `set leds`. See the LED-topology notes below for what this does on single-LED boards. |
| `set leds.brightness <0-100>` | default **100** | *(ZephCore only)* Brightness of a PWM-capable heartbeat/activity LED, applied live and persisted, `%` suffix accepted. Only boards defining a `heartbeat-pwm-led` or `lora-tx-pwm-led` alias have a dimmable LED; elsewhere the value is stored but has no effect. Also sits below `set leds`. |
| `set agc.reset.interval <ms>` | Accepted, ignored | Removed — replies `Removed - Automatic AGC reset is on`. The prefs byte is still read and written so the on-flash layout stays byte-exact, but nothing acts on it. |
| `set multi.acks <0\|1>` | | Enable extra ACK transmits |
| `set path.hash.mode <mode>` | 0, 1, or 2 | Path hashing algorithm |
Expand Down Expand Up @@ -477,18 +479,27 @@ four radio parameters together, since they are one interop-critical set.

## Notes

- **LED topology differs by board, and it changes what `leds.radio` / `leds.hb` can do.** Two DT aliases
decide it: `lora-tx-led` drives the radio activity LED, and `led0` (falling back to `led1`) drives the
heartbeat. Of the 35 boards in tree:
- **LED topology differs by board, and it changes what `leds.radio` / `leds.hb` can do.** DT aliases
decide it: `lora-tx-led` or `lora-tx-pwm-led` drives the radio activity LED, and `led0` (falling back
to `led1`) drives the heartbeat. Of the 35 boards in tree:
- **Separate pins (6)** — `rak4631`, `sensecap_solar`, `thinknode_m1`, `thinknode_m6`, `lilygo_techo`,
`xiao_nrf52840`. Both settings are fully independent. `xiao_nrf52840` has three LEDs: blue heartbeat,
green unread, red radio.
- **One shared pin (8)** — `heltec_t114`, `heltec_t096`, `heltec_wireless_tracker_v2`, `ttgo_tbeam`,
`gat562_30s`, `rak3401_1watt`, `rak_wismesh_tag`, `lilygo_timpulse_plus`. Here `lora-tx-led` **is** the
heartbeat pin, so both settings drive one LED. Radio activity takes priority and the heartbeat yields
while the radio holds the pin, so a transmit is never blanked mid-packet by the heartbeat's off-timer
(and vice versa). Use `set leds.hb off` for an unambiguous radio indicator.
- **No radio LED (20)** — including `wio_tracker_l1`, `t1000_e`, `meshtracker_x1`, Heltec V3/V4/V43 and
(and vice versa). Use `set leds.hb off` for an unambiguous radio indicator. `heltec_t096` and
`heltec_wireless_tracker_v2` also alias the same LED to `heartbeat-pwm-led`/`lora-tx-pwm-led`, so it is
dimmable with `leds.brightness`.
- **One shared PWM-only pin (1)**: `heltec_wifi_lora32_v43` has no plain `lora-tx-led`, only
`lora-tx-pwm-led` aliased to the same PWM LED as the heartbeat: a radio LED that exists only through
the PWM path, dimmable with `leds.brightness` like the boards above. On ESP32, a board in either PWM
category must not configure that pin as plain GPIO in `main()`, or the GPIO matrix takes the pin back
from the LEDC peripheral and the PWM output goes dark; `src/server_main_common.cpp` and
`app/main_observer.cpp` skip it automatically (`ZEPHCORE_HAS_PWM_SHARED_LED`) whenever a PWM LED alias
is present.
- **No radio LED (19)**: including `wio_tracker_l1`, `t1000_e`, `meshtracker_x1`, Heltec V3/V4 and
both ProMicros. `set leds.radio` is accepted and stored (so the setting survives onto a board that does
have the LED) but does nothing; the reply says `(no radio LED on this board)`.
- **No heartbeat LED (1)** — `lilygo_t3s3` has `lora-tx-led` but neither `led0` nor `led1`, so `set leds.hb`
Expand Down
4 changes: 2 additions & 2 deletions tests/catalog.json
Original file line number Diff line number Diff line change
Expand Up @@ -374,7 +374,7 @@
},
{
"id": "UNIT-PREFS-001",
"name": "Companion prefs encode to the documented 272-byte layout",
"name": "Companion prefs encode to the documented 273-byte layout",
"source": "tests/unit/prefs_codec_tests.cpp"
},
{
Expand All @@ -399,7 +399,7 @@
},
{
"id": "UNIT-PREFS-006",
"name": "Server prefs encode to the documented 311-byte layout",
"name": "Server prefs encode to the documented 312-byte layout",
"source": "tests/unit/prefs_codec_tests.cpp"
},
{
Expand Down
18 changes: 9 additions & 9 deletions tests/unit/prefs_codec_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ namespace {
struct Field { size_t file_off; size_t size; size_t struct_off; };
#define F(off, member) { off, sizeof(NodePrefs::member), offsetof(NodePrefs, member) }

// Companion /lfs/new_prefs, 272 bytes. Pads at 36-39 and 79.
// Companion /lfs/new_prefs, 273 bytes. Pads at 36-39 and 79.
const Field kCompanion[] = {
F(0, airtime_factor), F(4, node_name), F(40, node_lat), F(48, node_lon), F(56, freq),
F(60, sf), F(61, cr), F(62, client_repeat), F(63, manual_add_contacts), F(64, bw),
Expand All @@ -30,10 +30,10 @@ const Field kCompanion[] = {
F(158, cad_busycap), F(159, adc_multiplier), F(163, extra_sf), F(166, v_contact_flags),
F(167, fem_rxgain), F(168, display_rotate), F(169, input_rotate), F(170, cad_base),
F(171, tz_offset), F(172, leds_radio_mode), F(173, leds_hb_mode), F(174, wifi_enabled),
F(175, wifi_ssid), F(208, wifi_pwd),
F(175, wifi_ssid), F(208, wifi_pwd), F(272, led_brightness),
};

// Server /lfs/repeater/prefs, 311 bytes. Offset 120 is leds_disabled as a
// Server /lfs/repeater/prefs, 312 bytes. Offset 120 is leds_disabled as a
// magic byte (checked separately); pads at 36-39, 79, 123, 127-151 (bridge),
// 153-155.
const Field kServer[] = {
Expand All @@ -50,7 +50,7 @@ const Field kServer[] = {
F(295, flood_max_advert), F(296, meshtimesync), F(297, cad_auto), F(298, cad_offset),
F(299, probe_interval), F(300, cad_busycap), F(301, extra_sf), F(304, fem_rxgain),
F(305, display_rotate), F(306, input_rotate), F(307, cad_base), F(308, tz_offset),
F(309, leds_radio_mode), F(310, leds_hb_mode),
F(309, leds_radio_mode), F(310, leds_hb_mode), F(311, led_brightness),
};
#undef F

Expand Down Expand Up @@ -80,7 +80,7 @@ NodePrefs sample() {
p.backoff_multiplier = 0.6f; p.allow_read_only = 1; p.multi_acks = 1;
p.flood_max = 20; p.flood_max_unscoped = 10; p.flood_max_advert = 4;
p.interference_threshold = 7; p.leds_disabled = 1; p.leds_radio_mode = LEDS_RADIO_RX;
p.leds_hb_mode = LEDS_HB_UNREAD; p.powersaving_enabled = 1; p.gps_enabled = 1;
p.leds_hb_mode = LEDS_HB_UNREAD; p.led_brightness = 42; p.powersaving_enabled = 1; p.gps_enabled = 1;
p.gps_interval = 600; p.advert_loc_policy = ADVERT_LOC_SHARE; p.discovery_mod_timestamp = 123456;
p.adc_multiplier = 1.25f; strcpy(p.owner_info, "owner info");
p.rx_boost = 0; p.fem_rxgain = 0; p.rx_duty_cycle = 1;
Expand Down Expand Up @@ -125,7 +125,7 @@ NodePrefs expectShort(const NodePrefs &file_p, size_t len, const Field (&table)[

} // namespace

TEST(prefs_companion_layout, "UNIT-PREFS-001", "Companion prefs encode to the documented 272-byte layout") {
TEST(prefs_companion_layout, "UNIT-PREFS-001", "Companion prefs encode to the documented 273-byte layout") {
NodePrefs p = sample();
uint8_t buf[COMPANION_PREFS_SIZE + 8];
std::memset(buf, 0xEE, sizeof(buf));
Expand Down Expand Up @@ -154,7 +154,7 @@ TEST(prefs_companion_short, "UNIT-PREFS-003", "Short companion files keep the ca
// Every field boundary: each length the format has had ends on one.
const size_t lens[] = { 91, 92, 93, 94, 95, 96, 127, 143, 144, 145, 146, 148, 150, 151,
152, 153, 155, 156, 157, 158, 159, 163, 166, 167, 168, 169, 170,
171, 172, 173, 174, 175, 208, 272 };
171, 172, 173, 174, 175, 208, 272, 273 };
for (size_t len : lens) {
NodePrefs got = defaults();
CHECK(companionPrefsDecode(got, full, len));
Expand Down Expand Up @@ -215,7 +215,7 @@ TEST(prefs_companion_corrupt, "UNIT-PREFS-005", "Corrupt companion bytes fall ba
CHECK(got.leds_radio_mode == 0);
}

TEST(prefs_server_layout, "UNIT-PREFS-006", "Server prefs encode to the documented 311-byte layout") {
TEST(prefs_server_layout, "UNIT-PREFS-006", "Server prefs encode to the documented 312-byte layout") {
NodePrefs p = sample();
uint8_t buf[SERVER_PREFS_SIZE + 8];
std::memset(buf, 0xEE, sizeof(buf));
Expand Down Expand Up @@ -248,7 +248,7 @@ TEST(prefs_server_short, "UNIT-PREFS-008", "Short server files keep the caller's
uint8_t full[SERVER_PREFS_SIZE];
serverPrefsEncode(p, full, sizeof(full));
// Every length the format has had.
const size_t lens[] = { 290, 292, 294, 296, 297, 300, 301, 304, 305, 307, 308, 309, 311 };
const size_t lens[] = { 290, 292, 294, 296, 297, 300, 301, 304, 305, 307, 308, 309, 311, 312 };
for (size_t len : lens) {
NodePrefs got = defaults();
serverPrefsDecode(got, full, len);
Expand Down
61 changes: 43 additions & 18 deletions zephcore/adapters/board/ZephyrBoard.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#include <zephyr/sys/reboot.h>
#include <zephyr/drivers/sensor.h>
#include <zephyr/drivers/gpio.h>
#include <zephyr/drivers/pwm.h>
#include <stdio.h>
#include <string.h>

Expand Down Expand Up @@ -57,33 +58,51 @@
#endif
#endif

/* LoRa radio activity LED (optional — defined per-board via DT alias). Still
* called tx_led after "set leds.radio" gave it an RX mode, because the DT alias
* it comes from is named lora-tx-led on every board that has one. */
#if DT_NODE_EXISTS(DT_ALIAS(lora_tx_led))
/* LoRa activity LED, optional per board. The PWM alias wins over the GPIO one. */
#if DT_NODE_EXISTS(DT_ALIAS(lora_tx_pwm_led))
static const struct pwm_dt_spec tx_led_pwm = PWM_DT_SPEC_GET(DT_ALIAS(lora_tx_pwm_led));
#define HAS_TX_LED_PWM 1
#define HAS_TX_LED 0
/* Initialised in tx_led_init() below, with the GPIO path. */
#elif DT_NODE_EXISTS(DT_ALIAS(lora_tx_led))
static const struct gpio_dt_spec tx_led =
GPIO_DT_SPEC_GET(DT_ALIAS(lora_tx_led), gpios);
#define HAS_TX_LED_PWM 0
#define HAS_TX_LED 1
#else
#define HAS_TX_LED_PWM 0
#define HAS_TX_LED 0
#endif

/* True when this board wires the activity LED to the same pin as the heartbeat
* (8 of the supported boards do). Only those pay for the arbitration hold in
* led_gate.c — everywhere else the two LEDs are independent and the calls
* compile out. led1 is checked as well because ui_common.c falls back to it
* when a board has no led0. */
/* Heartbeat and activity LED on one pin: only then is the arbitration hold in
* led_gate.c needed. led1 counts too, since ui_common.c falls back to it. */
#if HAS_TX_LED && DT_NODE_EXISTS(DT_ALIAS(led0)) && \
DT_SAME_NODE(DT_ALIAS(led0), DT_ALIAS(lora_tx_led))
#define ZEPHCORE_LED_PIN_SHARED 1
#elif HAS_TX_LED && !DT_NODE_EXISTS(DT_ALIAS(led0)) && \
DT_NODE_EXISTS(DT_ALIAS(led1)) && \
DT_SAME_NODE(DT_ALIAS(led1), DT_ALIAS(lora_tx_led))
#define ZEPHCORE_LED_PIN_SHARED 1
/* Same for one PWM LED node shared by both (T096, Wireless Tracker V2). */
#elif HAS_TX_LED_PWM && DT_NODE_EXISTS(DT_ALIAS(heartbeat_pwm_led)) && \
DT_SAME_NODE(DT_ALIAS(heartbeat_pwm_led), DT_ALIAS(lora_tx_pwm_led))
#define ZEPHCORE_LED_PIN_SHARED 1
#else
#define ZEPHCORE_LED_PIN_SHARED 0
#endif

#if HAS_TX_LED_PWM
static inline void tx_led_write(bool on)
{
zephcore_led_pwm_write(&tx_led_pwm, on);
}
#elif HAS_TX_LED
static inline void tx_led_write(bool on)
{
gpio_pin_set_dt(&tx_led, on ? 1 : 0);
}
#endif

#include <zephyr/logging/log.h>
LOG_MODULE_REGISTER(zephcore_board, CONFIG_ZEPHCORE_BOARD_LOG_LEVEL);

Expand Down Expand Up @@ -139,8 +158,8 @@ static const struct device *const pmic_charger_dev =
#define HAS_PMIC_CHARGER 0
#endif

/* Initialize activity LED GPIO at boot */
#if HAS_TX_LED
/* Initialize activity LED (PWM or GPIO) at boot */
#if HAS_TX_LED_PWM || HAS_TX_LED
/* Width of the receive blink. A transmit holds the LED for its whole airtime,
* but a receive is a single edge — the packet is over by the time the driver
* hands it up — so RX has to be a fixed one-shot. 30 ms is deliberately longer
Expand All @@ -165,17 +184,23 @@ static void rx_pulse_off_handler(struct k_work *work)
if (atomic_get(&s_tx_lit)) {
return;
}
gpio_pin_set_dt(&tx_led, 0);
tx_led_write(false);
#if ZEPHCORE_LED_PIN_SHARED
zephcore_led_radio_hold_pin(false);
#endif
}

static int tx_led_init(void)
{
#if HAS_TX_LED_PWM
if (device_is_ready(tx_led_pwm.dev)) {
pwm_set_pulse_dt(&tx_led_pwm, 0); /* start dark, same as GPIO_OUTPUT_INACTIVE */
}
#else
if (gpio_is_ready_dt(&tx_led)) {
gpio_pin_configure_dt(&tx_led, GPIO_OUTPUT_INACTIVE);
}
#endif
k_work_init_delayable(&s_rx_pulse_off, rx_pulse_off_handler);
return 0;
}
Expand Down Expand Up @@ -364,12 +389,12 @@ const char *ZephyrBoard::getManufacturerName() const

void ZephyrBoard::onBeforeTransmit()
{
#if HAS_TX_LED
/* Honour the LED master gate ("set leds off") and then the activity mode
* ("set leds.radio"). On a headless repeater this is the only LED that ever
* lights, so both have to be checked here and not just in the UI layer.
* onAfterTransmit() still clears the pin unconditionally, so a gate or mode
* flipped mid-transmit can't strand it lit. */
#if HAS_TX_LED_PWM || HAS_TX_LED
uint8_t mode = zephcore_leds_radio_mode();
if (!zephcore_leds_disabled() &&
(mode == LEDS_RADIO_TX || mode == LEDS_RADIO_ALL)) {
Expand All @@ -380,16 +405,16 @@ void ZephyrBoard::onBeforeTransmit()
#if ZEPHCORE_LED_PIN_SHARED
zephcore_led_radio_hold_pin(true);
#endif
gpio_pin_set_dt(&tx_led, 1);
tx_led_write(true);
}
#endif
}

void ZephyrBoard::onAfterTransmit()
{
#if HAS_TX_LED
#if HAS_TX_LED_PWM || HAS_TX_LED
atomic_set(&s_tx_lit, 0);
gpio_pin_set_dt(&tx_led, 0);
tx_led_write(false);
#if ZEPHCORE_LED_PIN_SHARED
zephcore_led_radio_hold_pin(false);
#endif
Expand All @@ -398,7 +423,7 @@ void ZephyrBoard::onAfterTransmit()

void ZephyrBoard::onPacketReceived()
{
#if HAS_TX_LED
#if HAS_TX_LED_PWM || HAS_TX_LED
uint8_t mode = zephcore_leds_radio_mode();
if (zephcore_leds_disabled() ||
(mode != LEDS_RADIO_RX && mode != LEDS_RADIO_ALL)) {
Expand All @@ -414,7 +439,7 @@ void ZephyrBoard::onPacketReceived()
#if ZEPHCORE_LED_PIN_SHARED
zephcore_led_radio_hold_pin(true);
#endif
gpio_pin_set_dt(&tx_led, 1);
tx_led_write(true);
/* Reschedule rather than schedule: back-to-back packets should extend the
* blink, not have the first one's handler cut the second one short. */
k_work_reschedule(&s_rx_pulse_off, K_MSEC(RX_PULSE_MS));
Expand Down
12 changes: 10 additions & 2 deletions zephcore/app/main_observer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,15 @@ LOG_MODULE_REGISTER(zephcore_observer_main, CONFIG_ZEPHCORE_MAIN_LOG_LEVEL);

/* ========== LED (optional) ========== */

#if DT_NODE_HAS_PROP(DT_ALIAS(led0), gpios)
/* True when a board aliases its heartbeat or TX-activity LED to a PWM node.
* On ESP32, configuring led0 as plain GPIO after the PWM driver has already
* routed the pin takes the pin back from the LEDC peripheral (the GPIO
* matrix only serves one signal at a time), so on those boards led0 must be
* left to the PWM driver instead of reconfigured here. */
#define ZEPHCORE_HAS_PWM_SHARED_LED \
(DT_NODE_EXISTS(DT_ALIAS(heartbeat_pwm_led)) || DT_NODE_EXISTS(DT_ALIAS(lora_tx_pwm_led)))

#if DT_NODE_HAS_PROP(DT_ALIAS(led0), gpios) && !ZEPHCORE_HAS_PWM_SHARED_LED
#include <zephyr/drivers/gpio.h>
#define LED0_NODE DT_ALIAS(led0)
static const struct gpio_dt_spec led0 = GPIO_DT_SPEC_GET(LED0_NODE, gpios);
Expand Down Expand Up @@ -320,7 +328,7 @@ int main(void)
LOG_INF("=== ZephCore Observer starting ===");

/* Configure LED */
#if DT_NODE_HAS_PROP(DT_ALIAS(led0), gpios)
#if DT_NODE_HAS_PROP(DT_ALIAS(led0), gpios) && !ZEPHCORE_HAS_PWM_SHARED_LED
if (gpio_is_ready_dt(&led0)) {
gpio_pin_configure_dt(&led0, GPIO_OUTPUT_INACTIVE);
}
Expand Down
3 changes: 3 additions & 0 deletions zephcore/boards/esp32/heltec_wifi_lora32_v43/board.conf
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,6 @@ CONFIG_ZEPHCORE_DEFAULT_TX_POWER_DBM=12
# board.overlay): the default 500ms double-press confirm window (shutdown/
# DFU/offgrid) is too short for two ~1s holds, see Kconfig help text.
CONFIG_ZEPHCORE_UI_CONFIRM_WINDOW_MS=3000

# PWM for LED brightness. Kept here, not in the defconfig: the defconfig is shared with mcuboot, which fails to link with it.
CONFIG_PWM=y
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,13 @@
led0 = &led0;
pwm-0 = &ledc0;
pwm-led0 = &pwm_led_white;
/* Single physical LED, shared between the heartbeat and LoRa TX
* activity roles (same node aliased twice), same pattern as T096 and
* Wireless Tracker V2 -- see helpers/ui/ui_common.c and
* adapters/board/ZephyrBoard.cpp (ZEPHCORE_LED_PIN_SHARED covers the
* arbitration between the two roles automatically). */
heartbeat-pwm-led = &pwm_led_white;
lora-tx-pwm-led = &pwm_led_white;
uart-0 = &uart0;
i2c-0 = &i2c0;
lora0 = &lora0;
Expand Down
Loading
Loading