Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
0a05ff9
Add M5Stack Cardputer board definition
kucharz96 Apr 23, 2026
805cb7b
Add M5Cardputer display driver header
kucharz96 Apr 23, 2026
93f529c
Add M5Cardputer display driver implementation stub
kucharz96 Apr 23, 2026
af63151
Add Cardputer board implementation
kucharz96 Apr 23, 2026
adc5525
Add Cardputer target header
kucharz96 Apr 23, 2026
e410dca
Add Cardputer target implementation using ui-new flow
kucharz96 Apr 23, 2026
40d9a8d
Add Cardputer PlatformIO environments with ui-new
kucharz96 Apr 23, 2026
5b346c8
Add GitHub Actions workflow for Cardputer ADV builds
kucharz96 Apr 23, 2026
fbd7c87
Trigger Cardputer ADV build workflow on PRs too
kucharz96 Apr 23, 2026
617848c
Fix GPS pin macro names for Cardputer build
kucharz96 Apr 23, 2026
3235a3b
Harden Cardputer GPS manager settings and state handling
kucharz96 Apr 23, 2026
0bb1a7c
Fix Cardputer GPS behavior and reduce unnecessary work when GPS is off
kucharz96 Apr 23, 2026
4bd077a
Add real powerOff behavior for Cardputer deep sleep shutdown
kucharz96 Apr 23, 2026
806bea2
Trim unnecessary sensor build and improve BLE battery behavior
kucharz96 Apr 23, 2026
710580d
Align Cardputer GPS UART setup with official MeshCore pattern
kucharz96 Apr 23, 2026
2d22b9f
Reduce Cardputer startup power usage and sleep display before deep sleep
kucharz96 Apr 23, 2026
8b5d7ec
Restore startup reason after deep sleep wake on Cardputer
kucharz96 Apr 23, 2026
1f99c6d
Align Cardputer GPS telemetry and start sequence with official manager
kucharz96 Apr 24, 2026
14f3585
Track current background color in Cardputer display driver
kucharz96 Apr 24, 2026
b26ab49
Make Cardputer GPS UART pin mapping explicit to avoid RX/TX ambiguity
kucharz96 Apr 24, 2026
0fba9a2
Add GPS baud fallback and runtime diagnostics for Cardputer
kucharz96 Apr 24, 2026
5abddaa
Merge pull request #1 from kucharz96/cardputer-ui-new-port
kucharz96 Apr 24, 2026
89693f0
Fix Cardputer ADV LoRa cap power and RF switch expander setup
kucharz96 Apr 24, 2026
90072bf
Apply SX1262 PA config after init for Cardputer ADV LoRa cap
kucharz96 Apr 24, 2026
1a086f2
Enable periodic AGC reset tuning for Cardputer ADV
kucharz96 Apr 24, 2026
8392f18
Add low-risk periodic AGC reset tuning hook
kucharz96 Apr 24, 2026
1037877
Revert Cardputer AGC reset interval test
kucharz96 Apr 24, 2026
ae5ac95
Revert low-risk periodic AGC reset tuning hook
kucharz96 Apr 24, 2026
3f21d62
Merge pull request #2 from kucharz96/cardputer-ui-new-port
kucharz96 Apr 24, 2026
bd942d0
Add Cardputer RF LinkScore diagnostics
kucharz96 Apr 25, 2026
ede72fa
Add Cardputer keyboard menu navigation
kucharz96 Apr 25, 2026
df7f92c
Enable Cardputer keyboard menu navigation
kucharz96 Apr 25, 2026
aabc9e5
Use Cardputer arrow-marked keys for menu navigation
kucharz96 Apr 25, 2026
308efb1
Add Cardputer RF stability mode
kucharz96 Apr 25, 2026
991c2cf
Improve Cardputer RF link stability
kucharz96 Apr 25, 2026
a778b94
Merge pull request #3 from kucharz96/cardputer-rf-diagnostics
kucharz96 Apr 25, 2026
fffbc83
Add Cardputer RX capture guard
kucharz96 Apr 25, 2026
ce39e58
Add Cardputer RX watchdog and receive priority suite
kucharz96 Apr 25, 2026
3458c3c
Improve Cardputer RX diagnostics overlay
kucharz96 Apr 25, 2026
e66d61e
Merge pull request #4 from kucharz96/cardputer-rf-diagnostics
kucharz96 Apr 25, 2026
085bc4d
Reduce Cardputer RF timing interference
kucharz96 Apr 28, 2026
c443fc0
Avoid drawing Cardputer RF overlay during normal UI frames
kucharz96 Apr 28, 2026
a05626d
Merge branch 'meshcore-dev:main' into main
kucharz96 Apr 28, 2026
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
42 changes: 42 additions & 0 deletions .github/workflows/build-cardputer-adv.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
name: Build Cardputer ADV

on:
push:
branches:
- cardputer-ui-new-port
paths:
- 'boards/**'
- 'src/**'
- 'examples/**'
- 'variants/**'
- '.github/workflows/build-cardputer-adv.yml'
pull_request:
branches:
- main
paths:
- 'boards/**'
- 'src/**'
- 'examples/**'
- 'variants/**'
- '.github/workflows/build-cardputer-adv.yml'
workflow_dispatch:

jobs:
build-cardputer:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
environment:
- M5stack_cardputer_cap_lora1262_companion_radio_ble
- M5stack_cardputer_cap_lora1262_companion_radio_usb

steps:
- name: Clone Repo
uses: actions/checkout@v4

- name: Setup Build Environment
uses: ./.github/actions/setup-build-environment

- name: Build ${{ matrix.environment }}
run: pio run -e ${{ matrix.environment }}
41 changes: 41 additions & 0 deletions boards/m5stack_cardputer.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
{
"build": {
"arduino": {
"ldscript": "esp32s3_out.ld",
"partitions": "default_8MB.csv",
"memory_type": "qio_opi"
},
"core": "esp32",
"extra_flags": [
"-DARDUINO_M5STACK_CARDPUTER",
"-DBOARD_HAS_PSRAM",
"-DARDUINO_USB_CDC_ON_BOOT=1",
"-DARDUINO_USB_MODE=1",
"-DARDUINO_RUNNING_CORE=1",
"-DARDUINO_EVENT_RUNNING_CORE=1"
],
"f_cpu": "240000000L",
"f_flash": "80000000L",
"flash_mode": "qio",
"hwids": [["0x303A", "0x1001"]],
"mcu": "esp32s3",
"variant": "esp32s3"
},
"connectivity": ["wifi", "bluetooth"],
"debug": {
"default_tool": "esp-builtin",
"onboard_tools": ["esp-builtin"],
"openocd_target": "esp32s3.cfg"
},
"frameworks": ["arduino", "espidf"],
"name": "M5Stack Cardputer-Adv (8M Flash 8M PSRAM)",
"upload": {
"flash_size": "8MB",
"maximum_ram_size": 327680,
"maximum_size": 8388608,
"require_upload_port": true,
"speed": 1500000
},
"url": "https://shop.m5stack.com/products/m5stack-cardputer-adv",
"vendor": "M5Stack"
}
3 changes: 3 additions & 0 deletions src/helpers/ui/M5CardputerDisplay.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
#include "M5CardputerDisplay.h"

// Most functionality is inline in the header.
158 changes: 158 additions & 0 deletions src/helpers/ui/M5CardputerDisplay.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
#pragma once

#include <M5Cardputer.h>
#include "DisplayDriver.h"

#ifndef TFT_BLACK
#define TFT_BLACK 0x0000
#define TFT_WHITE 0xFFFF
#define TFT_RED 0xF800
#define TFT_GREEN 0x07E0
#define TFT_BLUE 0x001F
#define TFT_YELLOW 0xFFE0
#define TFT_ORANGE 0xFD20
#endif

#ifdef CARDPUTER_RF_DIAG_OVERLAY
class M5CardputerDisplay;
void cardputerDrawRfOverlay(M5CardputerDisplay& disp);
#endif

class M5CardputerDisplay : public DisplayDriver {
private:
bool _isOn = false;
uint16_t cursor_x = 0;
uint16_t cursor_y = 0;
uint16_t text_size = 1;
uint16_t _color = TFT_WHITE;
uint16_t _light_color = TFT_WHITE;
uint16_t _dark_color = TFT_BLACK;
uint16_t _bg_color = TFT_BLACK;
static const uint16_t SCREEN_WIDTH = 240;
static const uint16_t SCREEN_HEIGHT = 135;
static const uint8_t CHAR_WIDTH = 6;
static const uint8_t CHAR_HEIGHT = 8;

public:
M5CardputerDisplay() : DisplayDriver(SCREEN_WIDTH, SCREEN_HEIGHT) {}

bool begin() {
_isOn = true;
_bg_color = TFT_BLACK;
M5.Display.setRotation(1);
M5.Display.fillScreen(_bg_color);
M5.Display.setTextColor(TFT_WHITE, _bg_color);
M5.Display.setTextSize(1);
return true;
}

bool isOn() override { return _isOn; }

void turnOn() override {
if (!_isOn) {
M5.Display.wakeup();
M5.Display.setTextColor(_color, _bg_color);
_isOn = true;
}
}

void turnOff() override {
if (_isOn) {
M5.Display.sleep();
_isOn = false;
}
}

void clear() override {
if (!_isOn) return;
M5.Display.fillScreen(_bg_color);
cursor_x = 0;
cursor_y = 0;
}

void startFrame(Color bkg = DARK) override {
if (!_isOn) return;

switch (bkg) {
case DARK: _bg_color = _dark_color; break;
case LIGHT: _bg_color = _light_color; break;
case RED: _bg_color = TFT_RED; break;
case GREEN: _bg_color = TFT_GREEN; break;
case BLUE: _bg_color = TFT_BLUE; break;
case YELLOW: _bg_color = TFT_YELLOW; break;
case ORANGE: _bg_color = TFT_ORANGE; break;
default: _bg_color = _dark_color; break;
}

M5.Display.fillScreen(_bg_color);
M5.Display.setTextColor(_color, _bg_color);
cursor_x = 0;
cursor_y = 0;
}

void setTextSize(int sz) override {
text_size = sz;
M5.Display.setTextSize(sz);
}

void setColor(Color c) override {
switch (c) {
case DARK: _color = _dark_color; break;
case LIGHT: _color = _light_color; break;
case RED: _color = TFT_RED; break;
case GREEN: _color = TFT_GREEN; break;
case BLUE: _color = TFT_BLUE; break;
case YELLOW: _color = TFT_YELLOW; break;
case ORANGE: _color = TFT_ORANGE; break;
default: _color = _light_color; break;
}
M5.Display.setTextColor(_color, _bg_color);
}

void setCursor(int x, int y) override {
cursor_x = x;
cursor_y = y;
M5.Display.setCursor(x, y);
}

void print(const char* str) override {
if (!_isOn) return;
M5.Display.print(str);
}

void fillRect(int x, int y, int w, int h) override {
if (!_isOn) return;
M5.Display.fillRect(x, y, w, h, _color);
}

void drawRect(int x, int y, int w, int h) override {
if (!_isOn) return;
M5.Display.drawRect(x, y, w, h, _color);
}

void drawXbm(int x, int y, const uint8_t* bits, int w, int h) override {
if (!_isOn) return;
for (int yy = 0; yy < h; yy++) {
for (int xx = 0; xx < w; xx++) {
int byte_idx = (yy * ((w + 7) / 8)) + (xx / 8);
int bit_idx = xx % 8;
if (bits[byte_idx] & (1 << bit_idx)) {
M5.Display.drawPixel(x + xx, y + yy, _color);
}
}
}
}

uint16_t getTextWidth(const char* str) override {
return strlen(str) * CHAR_WIDTH * text_size;
}

void endFrame() override {
if (!_isOn) return;
}
};

inline void drawTextLine(M5CardputerDisplay& disp, int y, const char* str) {
disp.setCursor(0, y);
disp.print(str);
}
64 changes: 64 additions & 0 deletions src/helpers/ui/MomentaryButton.cpp
Original file line number Diff line number Diff line change
@@ -1,7 +1,64 @@
#include "MomentaryButton.h"

#if defined(M5STACK_CARDPUTER) && defined(CARDPUTER_KEYBOARD_UI_NAV)
#include <M5Cardputer.h>
#endif

#define MULTI_CLICK_WINDOW_MS 280

#if defined(M5STACK_CARDPUTER) && defined(CARDPUTER_KEYBOARD_UI_NAV)
static bool cardputerWordHas(const Keyboard_Class::KeysState& keys, char a, char b = 0, char c = 0, char d = 0) {
for (char ch : keys.word) {
if (ch == a || (b != 0 && ch == b) || (c != 0 && ch == c) || (d != 0 && ch == d)) {
return true;
}
}
return false;
}

static int cardputerKeyboardNavEvent() {
static bool was_pressed = false;
static uint32_t last_event_ms = 0;

M5Cardputer.update();
M5Cardputer.Keyboard.updateKeyList();
M5Cardputer.Keyboard.updateKeysState();

auto& keys = M5Cardputer.Keyboard.keysState();

// Cardputer uses the punctuation keys with arrow legends for navigation:
// left: ',' / '<'
// right: '/' / '?' ('.' / '>' is also accepted on layouts that mark it as right)
// enter: physical Enter
bool left = cardputerWordHas(keys, ',', '<');
bool right = cardputerWordHas(keys, '/', '?', '.', '>');
bool enter = keys.enter;
bool any = left || right || enter;

if (!any) {
was_pressed = false;
return BUTTON_EVENT_NONE;
}

if (was_pressed) {
return BUTTON_EVENT_NONE;
}

uint32_t now = millis();
if ((uint32_t)(now - last_event_ms) < 120UL) {
return BUTTON_EVENT_NONE;
}

was_pressed = true;
last_event_ms = now;

if (enter) return BUTTON_EVENT_LONG_PRESS; // existing UI maps long press to KEY_ENTER
if (left) return BUTTON_EVENT_DOUBLE_CLICK; // existing UI maps double click to KEY_PREV
if (right) return BUTTON_EVENT_CLICK; // existing UI maps click to KEY_NEXT
return BUTTON_EVENT_NONE;
}
#endif

MomentaryButton::MomentaryButton(int8_t pin, int long_press_millis, bool reverse, bool pulldownup, bool multiclick) {
_pin = pin;
_reverse = reverse;
Expand Down Expand Up @@ -65,6 +122,13 @@ bool MomentaryButton::isPressed(int level) const {
int MomentaryButton::check(bool repeat_click) {
if (_pin < 0) return BUTTON_EVENT_NONE;

#if defined(M5STACK_CARDPUTER) && defined(CARDPUTER_KEYBOARD_UI_NAV) && defined(PIN_USER_BTN)
if (_pin == PIN_USER_BTN && _threshold == 0) {
int keyboard_event = cardputerKeyboardNavEvent();
if (keyboard_event != BUTTON_EVENT_NONE) return keyboard_event;
}
#endif

int event = BUTTON_EVENT_NONE;
int btn = _threshold > 0 ? (analogRead(_pin) < _threshold) : digitalRead(_pin);
if (btn != prev) {
Expand Down
Loading