Skip to content

Commit ed4a798

Browse files
jp-bennettthebenternCopilot
authored
Thinknode M3 support against master (#8630)
* Add variant_shutdown() as a week function in main-nrf52.cpp * Add Status LED module * Add Thinknode M3 support * Catch case of BLE disabled * Update src/modules/StatusLEDModule.cpp Co-authored-by: Copilot <[email protected]> * Update src/modules/StatusLEDModule.cpp Co-authored-by: Copilot <[email protected]> * Update variants/nrf52840/ELECROW-ThinkNode-M3/rfswitch.h Co-authored-by: Copilot <[email protected]> * Remove unused pin * M3 pairing LED only active for 30 seconds after state change * Thinknode M3 shutdown work --------- Co-authored-by: Ben Meadors <[email protected]> Co-authored-by: Copilot <[email protected]>
1 parent 1bfa9ed commit ed4a798

File tree

14 files changed

+471
-5
lines changed

14 files changed

+471
-5
lines changed

boards/ThinkNode-M3.json

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
{
2+
"build": {
3+
"arduino": {
4+
"ldscript": "nrf52840_s140_v6.ld"
5+
},
6+
"core": "nRF5",
7+
"cpu": "cortex-m4",
8+
"extra_flags": "-DNRF52840_XXAA",
9+
"f_cpu": "64000000L",
10+
"hwids": [
11+
["0x239A", "0x4405"],
12+
["0x239A", "0x0029"],
13+
["0x239A", "0x002A"]
14+
],
15+
"usb_product": "elecrow_eink",
16+
"mcu": "nrf52840",
17+
"variant": "ELECROW-ThinkNode-M3",
18+
"variants_dir": "variants",
19+
"bsp": {
20+
"name": "adafruit"
21+
},
22+
"softdevice": {
23+
"sd_flags": "-DS140",
24+
"sd_name": "s140",
25+
"sd_version": "6.1.1",
26+
"sd_fwid": "0x00B6"
27+
},
28+
"bootloader": {
29+
"settings_addr": "0xFF000"
30+
}
31+
},
32+
"connectivity": ["bluetooth"],
33+
"debug": {
34+
"jlink_device": "nRF52840_xxAA",
35+
"onboard_tools": ["jlink"],
36+
"svd_path": "nrf52840.svd",
37+
"openocd_target": "nrf52840-mdk-rs"
38+
},
39+
"frameworks": ["arduino"],
40+
"name": "elecrow nrf",
41+
"upload": {
42+
"maximum_ram_size": 248832,
43+
"maximum_size": 815104,
44+
"speed": 115200,
45+
"protocol": "nrfutil",
46+
"protocols": ["jlink", "nrfjprog", "nrfutil", "stlink"],
47+
"use_1200bps_touch": true,
48+
"require_upload_port": true,
49+
"wait_for_upload_port": true
50+
},
51+
"url": "",
52+
"vendor": "ELECROW"
53+
}

src/configuration.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -396,6 +396,13 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
396396
#define HAS_RGB_LED
397397
#endif
398398

399+
#ifndef LED_STATE_OFF
400+
#define LED_STATE_OFF 0
401+
#endif
402+
#ifndef LED_STATE_ON
403+
#define LED_STATE_ON 1
404+
#endif
405+
399406
// default mapping of pins
400407
#if defined(PIN_BUTTON2) && !defined(CANCEL_BUTTON_PIN)
401408
#define ALT_BUTTON_PIN PIN_BUTTON2

src/modules/Modules.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@
1313
#include "input/TrackballInterruptImpl1.h"
1414
#endif
1515

16+
#include "modules/StatusLEDModule.h"
17+
1618
#if !MESHTASTIC_EXCLUDE_I2C
1719
#include "input/cardKbI2cImpl.h"
1820
#endif
@@ -119,6 +121,10 @@ void setupModules()
119121
buzzerFeedbackThread = new BuzzerFeedbackThread();
120122
}
121123
#endif
124+
#if defined(LED_CHARGE) || defined(LED_PAIRING)
125+
statusLEDModule = new StatusLEDModule();
126+
#endif
127+
122128
#if !MESHTASTIC_EXCLUDE_ADMIN
123129
adminModule = new AdminModule();
124130
#endif

src/modules/SerialModule.cpp

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ SerialModule *serialModule;
6464
SerialModuleRadio *serialModuleRadio;
6565

6666
#if defined(TTGO_T_ECHO) || defined(CANARYONE) || defined(MESHLINK) || defined(ELECROW_ThinkNode_M1) || \
67-
defined(ELECROW_ThinkNode_M5) || defined(HELTEC_MESH_SOLAR) || defined(T_ECHO_LITE)
67+
defined(ELECROW_ThinkNode_M5) || defined(HELTEC_MESH_SOLAR) || defined(T_ECHO_LITE) || defined(ELECROW_ThinkNode_M3)
6868
SerialModule::SerialModule() : StreamAPI(&Serial), concurrency::OSThread("Serial")
6969
{
7070
api_type = TYPE_SERIAL;
@@ -204,7 +204,7 @@ int32_t SerialModule::runOnce()
204204
Serial.setTimeout(moduleConfig.serial.timeout > 0 ? moduleConfig.serial.timeout : TIMEOUT);
205205
}
206206
#elif !defined(TTGO_T_ECHO) && !defined(T_ECHO_LITE) && !defined(CANARYONE) && !defined(MESHLINK) && \
207-
!defined(ELECROW_ThinkNode_M1) && !defined(ELECROW_ThinkNode_M5)
207+
!defined(ELECROW_ThinkNode_M1) && !defined(ELECROW_ThinkNode_M3) && !defined(ELECROW_ThinkNode_M5)
208208
if (moduleConfig.serial.rxd && moduleConfig.serial.txd) {
209209
#ifdef ARCH_RP2040
210210
Serial2.setFIFOSize(RX_BUFFER);
@@ -261,7 +261,7 @@ int32_t SerialModule::runOnce()
261261
}
262262

263263
#if !defined(TTGO_T_ECHO) && !defined(T_ECHO_LITE) && !defined(CANARYONE) && !defined(MESHLINK) && \
264-
!defined(ELECROW_ThinkNode_M1) && !defined(ELECROW_ThinkNode_M5)
264+
!defined(ELECROW_ThinkNode_M1) && !defined(ELECROW_ThinkNode_M3) && !defined(ELECROW_ThinkNode_M5)
265265
else if ((moduleConfig.serial.mode == meshtastic_ModuleConfig_SerialConfig_Serial_Mode_WS85)) {
266266
processWXSerial();
267267

@@ -536,7 +536,8 @@ ParsedLine parseLine(const char *line)
536536
void SerialModule::processWXSerial()
537537
{
538538
#if !defined(TTGO_T_ECHO) && !defined(T_ECHO_LITE) && !defined(CANARYONE) && !defined(CONFIG_IDF_TARGET_ESP32C6) && \
539-
!defined(MESHLINK) && !defined(ELECROW_ThinkNode_M1) && !defined(ELECROW_ThinkNode_M5) && !defined(ARCH_STM32WL)
539+
!defined(MESHLINK) && !defined(ELECROW_ThinkNode_M1) && !defined(ELECROW_ThinkNode_M3) && !defined(ELECROW_ThinkNode_M5) && \
540+
!defined(ARCH_STM32WL)
540541
static unsigned int lastAveraged = 0;
541542
static unsigned int averageIntervalMillis = 300000; // 5 minutes hard coded.
542543
static double dir_sum_sin = 0;

src/modules/StatusLEDModule.cpp

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
#include "StatusLEDModule.h"
2+
#include "MeshService.h"
3+
#include "configuration.h"
4+
#include <Arduino.h>
5+
6+
/*
7+
StatusLEDModule manages the device's status LEDs, updating their states based on power and Bluetooth status.
8+
It reflects charging, charged, discharging, and Bluetooth connection states using the appropriate LEDs.
9+
*/
10+
StatusLEDModule *statusLEDModule;
11+
12+
StatusLEDModule::StatusLEDModule() : concurrency::OSThread("StatusLEDModule")
13+
{
14+
bluetoothStatusObserver.observe(&bluetoothStatus->onNewStatus);
15+
powerStatusObserver.observe(&powerStatus->onNewStatus);
16+
}
17+
18+
int StatusLEDModule::handleStatusUpdate(const meshtastic::Status *arg)
19+
{
20+
switch (arg->getStatusType()) {
21+
case STATUS_TYPE_POWER: {
22+
meshtastic::PowerStatus *powerStatus = (meshtastic::PowerStatus *)arg;
23+
if (powerStatus->getHasUSB()) {
24+
power_state = charging;
25+
if (powerStatus->getBatteryChargePercent() >= 100) {
26+
power_state = charged;
27+
}
28+
} else {
29+
power_state = discharging;
30+
}
31+
break;
32+
}
33+
case STATUS_TYPE_BLUETOOTH: {
34+
meshtastic::BluetoothStatus *bluetoothStatus = (meshtastic::BluetoothStatus *)arg;
35+
switch (bluetoothStatus->getConnectionState()) {
36+
case meshtastic::BluetoothStatus::ConnectionState::DISCONNECTED: {
37+
ble_state = unpaired;
38+
PAIRING_LED_starttime = millis();
39+
break;
40+
}
41+
case meshtastic::BluetoothStatus::ConnectionState::PAIRING: {
42+
ble_state = pairing;
43+
PAIRING_LED_starttime = millis();
44+
break;
45+
}
46+
case meshtastic::BluetoothStatus::ConnectionState::CONNECTED: {
47+
ble_state = connected;
48+
PAIRING_LED_starttime = millis();
49+
break;
50+
}
51+
}
52+
53+
break;
54+
}
55+
}
56+
return 0;
57+
};
58+
59+
int32_t StatusLEDModule::runOnce()
60+
{
61+
62+
if (power_state == charging) {
63+
CHARGE_LED_state = !CHARGE_LED_state;
64+
} else if (power_state == charged) {
65+
CHARGE_LED_state = LED_STATE_ON;
66+
} else {
67+
CHARGE_LED_state = LED_STATE_OFF;
68+
}
69+
70+
if (!config.bluetooth.enabled || PAIRING_LED_starttime + 30 * 1000 < millis()) {
71+
PAIRING_LED_state = LED_STATE_OFF;
72+
} else if (ble_state == unpaired) {
73+
if (slowTrack) {
74+
PAIRING_LED_state = !PAIRING_LED_state;
75+
slowTrack = false;
76+
} else {
77+
slowTrack = true;
78+
}
79+
} else if (ble_state == pairing) {
80+
PAIRING_LED_state = !PAIRING_LED_state;
81+
} else {
82+
PAIRING_LED_state = LED_STATE_ON;
83+
}
84+
85+
#ifdef LED_CHARGE
86+
digitalWrite(LED_CHARGE, CHARGE_LED_state);
87+
#endif
88+
// digitalWrite(green_LED_PIN, LED_STATE_OFF);
89+
#ifdef LED_PAIRING
90+
digitalWrite(LED_PAIRING, PAIRING_LED_state);
91+
#endif
92+
93+
return (my_interval);
94+
}

src/modules/StatusLEDModule.h

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
#pragma once
2+
3+
#include "BluetoothStatus.h"
4+
#include "MeshModule.h"
5+
#include "PowerStatus.h"
6+
#include "concurrency/OSThread.h"
7+
#include "configuration.h"
8+
#include <Arduino.h>
9+
#include <functional>
10+
11+
class StatusLEDModule : private concurrency::OSThread
12+
{
13+
bool slowTrack = false;
14+
15+
public:
16+
StatusLEDModule();
17+
18+
int handleStatusUpdate(const meshtastic::Status *);
19+
20+
protected:
21+
unsigned int my_interval = 1000; // interval in millisconds
22+
virtual int32_t runOnce() override;
23+
24+
CallbackObserver<StatusLEDModule, const meshtastic::Status *> bluetoothStatusObserver =
25+
CallbackObserver<StatusLEDModule, const meshtastic::Status *>(this, &StatusLEDModule::handleStatusUpdate);
26+
CallbackObserver<StatusLEDModule, const meshtastic::Status *> powerStatusObserver =
27+
CallbackObserver<StatusLEDModule, const meshtastic::Status *>(this, &StatusLEDModule::handleStatusUpdate);
28+
29+
private:
30+
bool CHARGE_LED_state = LED_STATE_OFF;
31+
bool PAIRING_LED_state = LED_STATE_OFF;
32+
33+
uint32_t PAIRING_LED_starttime = 0;
34+
35+
enum PowerState { discharging, charging, charged };
36+
37+
PowerState power_state = discharging;
38+
39+
enum BLEState { unpaired, pairing, connected };
40+
41+
BLEState ble_state = unpaired;
42+
};
43+
44+
extern StatusLEDModule *statusLEDModule;

src/modules/Telemetry/Sensor/AHT10.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ bool AHT10Sensor::getMetrics(meshtastic_Telemetry *measurement)
3535
// prefer other sensors like bmp280, bmp3xx
3636
if (!measurement->variant.environment_metrics.has_temperature) {
3737
measurement->variant.environment_metrics.has_temperature = true;
38-
measurement->variant.environment_metrics.temperature = temp.temperature;
38+
measurement->variant.environment_metrics.temperature = temp.temperature + AHT10_TEMP_OFFSET;
3939
}
4040

4141
if (!measurement->variant.environment_metrics.has_relative_humidity) {

src/modules/Telemetry/Sensor/AHT10.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,10 @@
66

77
#if !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR && __has_include(<Adafruit_AHTX0.h>)
88

9+
#ifndef AHT10_TEMP_OFFSET
10+
#define AHT10_TEMP_OFFSET 0
11+
#endif
12+
913
#include "../mesh/generated/meshtastic/telemetry.pb.h"
1014
#include "TelemetrySensor.h"
1115
#include <Adafruit_AHTX0.h>

src/platform/nrf52/architecture.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,8 @@
6868
#define HW_VENDOR meshtastic_HardwareModel_T_ECHO_LITE
6969
#elif defined(ELECROW_ThinkNode_M1)
7070
#define HW_VENDOR meshtastic_HardwareModel_THINKNODE_M1
71+
#elif defined(ELECROW_ThinkNode_M3)
72+
#define HW_VENDOR meshtastic_HardwareModel_THINKNODE_M3
7173
#elif defined(ELECROW_ThinkNode_M6)
7274
#define HW_VENDOR meshtastic_HardwareModel_THINKNODE_M6
7375
#elif defined(NANO_G2_ULTRA)
@@ -130,7 +132,9 @@
130132

131133
#endif
132134

135+
#ifdef PIN_LED1
133136
#define LED_PIN PIN_LED1 // LED1 on nrf52840-DK
137+
#endif
134138

135139
#ifdef PIN_BUTTON1
136140
#define BUTTON_PIN PIN_BUTTON1

src/platform/nrf52/main-nrf52.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,11 @@
3030
#include "BQ25713.h"
3131
#endif
3232

33+
// Weak empty variant initialization function.
34+
// May be redefined by variant files.
35+
void variant_shutdown() __attribute__((weak));
36+
void variant_shutdown() {}
37+
3338
static nrfx_wdt_t nrfx_wdt = NRFX_WDT_INSTANCE(0);
3439
static nrfx_wdt_channel_id nrfx_wdt_channel_id_nrf52_main;
3540

@@ -391,6 +396,7 @@ void cpuDeepSleep(uint32_t msecToWake)
391396
NRF_GPIO->DIRCLR = (1 << pin);
392397
}
393398
#endif
399+
variant_shutdown();
394400

395401
// Sleepy trackers or sensors can low power "sleep"
396402
// Don't enter this if we're sleeping portMAX_DELAY, since that's a shutdown event

0 commit comments

Comments
 (0)