Skip to content

Commit 7d8a7dd

Browse files
Steven Boyenclaude
authored andcommitted
Add M5Stack Cardputer Advanced (Cap LoRa-1262) companion support
Adds full companion firmware support for the M5Stack Cardputer Advanced with Cap LoRa-1262 (SX1262, EU868). Tested and verified building against v1.15.0 on hardware. New files: - boards/m5stack_cardputer.json: PlatformIO board definition (ESP32-S3, 8MB flash/PSRAM) - variants/m5stack_cardputer/: Hardware variant (SX1262 pinout, TCXO, GPS support) - src/helpers/ui/M5CardputerDisplay.{h,cpp}: LVGL display driver for Cardputer screen - examples/companion_radio/ui-keyboard/: Keyboard-driven UI (contacts, channels, chat, settings) - examples/companion_radio/UITask.h: Dispatcher selecting ui-keyboard when HEADLESS_UI=1 Companion radio changes: - NodePrefs: add screen_timeout_seconds (0=never, 10/30/60/120/300s) - MyMesh: expose saveContacts(), saveChannels(), factoryReset() as public - MyMesh: add queueOutgoingMessageForBLE() for outgoing message BLE sync Build target: env:M5stack_cardputer_cap_lora1262_companion RAM: 49.9% | Flash: 42.2% of 8MB partition Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent dee3e26 commit 7d8a7dd

15 files changed

Lines changed: 5459 additions & 3 deletions

File tree

boards/m5stack_cardputer.json

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
{
2+
"build": {
3+
"arduino": {
4+
"ldscript": "esp32s3_out.ld",
5+
"partitions": "default_8MB.csv",
6+
"memory_type": "qio_opi"
7+
},
8+
"core": "esp32",
9+
"extra_flags": [
10+
"-DARDUINO_M5STACK_CARDPUTER",
11+
"-DBOARD_HAS_PSRAM",
12+
"-DARDUINO_USB_CDC_ON_BOOT=1",
13+
"-DARDUINO_USB_MODE=1",
14+
"-DARDUINO_RUNNING_CORE=1",
15+
"-DARDUINO_EVENT_RUNNING_CORE=1"
16+
],
17+
"f_cpu": "240000000L",
18+
"f_flash": "80000000L",
19+
"flash_mode": "qio",
20+
"hwids": [["0x303A", "0x1001"]],
21+
"mcu": "esp32s3",
22+
"variant": "esp32s3"
23+
},
24+
"connectivity": ["wifi", "bluetooth"],
25+
"debug": {
26+
"default_tool": "esp-builtin",
27+
"onboard_tools": ["esp-builtin"],
28+
"openocd_target": "esp32s3.cfg"
29+
},
30+
"frameworks": ["arduino", "espidf"],
31+
"name": "M5Stack Cardputer-Adv (8M Flash 8M PSRAM)",
32+
"upload": {
33+
"flash_size": "8MB",
34+
"maximum_ram_size": 327680,
35+
"maximum_size": 8388608,
36+
"require_upload_port": true,
37+
"speed": 1500000
38+
},
39+
"url": "https://shop.m5stack.com/products/m5stack-cardputer-adv",
40+
"vendor": "M5Stack"
41+
}

examples/companion_radio/MyMesh.cpp

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2191,3 +2191,44 @@ bool MyMesh::advert() {
21912191
return false;
21922192
}
21932193
}
2194+
2195+
void MyMesh::queueOutgoingMessageForBLE(const ContactInfo* contact, const ChannelDetails* channel,
2196+
const char* from_name, const char* text, uint32_t timestamp) {
2197+
int i = 0;
2198+
uint8_t frame[MAX_FRAME_SIZE];
2199+
bool is_channel = (channel != NULL);
2200+
2201+
if (is_channel) {
2202+
if (app_target_ver >= 3) {
2203+
frame[i++] = RESP_CODE_CHANNEL_MSG_RECV_V3;
2204+
frame[i++] = 0; frame[i++] = 0; frame[i++] = 0;
2205+
} else {
2206+
frame[i++] = RESP_CODE_CHANNEL_MSG_RECV;
2207+
}
2208+
uint8_t channel_idx = findChannelIdx(channel->channel);
2209+
frame[i++] = channel_idx;
2210+
frame[i++] = 0xFF;
2211+
frame[i++] = TXT_TYPE_PLAIN;
2212+
memcpy(&frame[i], &timestamp, 4); i += 4;
2213+
int name_len = strlen(from_name);
2214+
if (name_len > 30) name_len = 30;
2215+
memcpy(&frame[i], from_name, name_len); i += name_len;
2216+
frame[i++] = ':'; frame[i++] = ' ';
2217+
} else if (contact) {
2218+
if (app_target_ver >= 3) {
2219+
frame[i++] = RESP_CODE_CONTACT_MSG_RECV_V3;
2220+
frame[i++] = 0; frame[i++] = 0; frame[i++] = 0;
2221+
} else {
2222+
frame[i++] = RESP_CODE_CONTACT_MSG_RECV;
2223+
}
2224+
memcpy(&frame[i], contact->id.pub_key, 6); i += 6;
2225+
frame[i++] = 0xFF;
2226+
frame[i++] = TXT_TYPE_PLAIN;
2227+
memcpy(&frame[i], &timestamp, 4); i += 4;
2228+
}
2229+
2230+
int text_len = strlen(text);
2231+
if (i + text_len > MAX_FRAME_SIZE) text_len = MAX_FRAME_SIZE - i;
2232+
memcpy(&frame[i], text, text_len); i += text_len;
2233+
addToOfflineQueue(frame, i);
2234+
}

examples/companion_radio/MyMesh.h

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,12 @@ class MyMesh : public BaseChatMesh, public DataStoreHost {
100100
bool advert();
101101
void enterCLIRescue();
102102

103+
void factoryReset() { _store->formatFileSystem(); }
104+
void saveContacts() { _store->saveContacts(this); }
105+
void saveChannels() { _store->saveChannels(this); }
106+
void queueOutgoingMessageForBLE(const ContactInfo* contact, const ChannelDetails* channel,
107+
const char* from_name, const char* text, uint32_t timestamp);
108+
103109
int getRecentlyHeard(AdvertPath dest[], int max_num);
104110

105111
protected:
@@ -196,9 +202,7 @@ class MyMesh : public BaseChatMesh, public DataStoreHost {
196202
void checkSerialInterface();
197203
bool isValidClientRepeatFreq(uint32_t f) const;
198204

199-
// helpers, short-cuts
200-
void saveChannels() { _store->saveChannels(this); }
201-
void saveContacts() { _store->saveContacts(this); }
205+
// helpers, short-cuts (public versions above)
202206

203207
DataStore* _store;
204208
NodePrefs _prefs;

examples/companion_radio/NodePrefs.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ struct NodePrefs { // persisted to file
2525
uint32_t ble_pin;
2626
uint8_t advert_loc_policy;
2727
uint8_t buzzer_quiet;
28+
uint16_t screen_timeout_seconds; // 0=Never, 10, 30, 60, 120, 300
2829
uint8_t gps_enabled; // GPS enabled flag (0=disabled, 1=enabled)
2930
uint32_t gps_interval; // GPS read interval in seconds
3031
uint8_t autoadd_config; // bitmask for auto-add contacts config

examples/companion_radio/UITask.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
#pragma once
2+
3+
// Conditional include based on UI mode
4+
#ifdef HEADLESS_UI
5+
#include "ui-keyboard/UITask.h"
6+
#else
7+
#include "ui-new/UITask.h"
8+
#endif

0 commit comments

Comments
 (0)