This commit is contained in:
WillyJL 2025-10-26 18:22:30 +08:00 committed by GitHub
commit d840ed40ba
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 422 additions and 0 deletions

View File

@ -0,0 +1,208 @@
#if defined(M5STACK_CARDPUTER_ADV)
#include "CardputerAdvKeyboard.h"
#include "main.h"
#define _TCA8418_COLS 8
#define _TCA8418_ROWS 7
#define _TCA8418_NUM_KEYS 56
#define _TCA8418_MULTI_TAP_THRESHOLD 1500
using Key = TCA8418KeyboardBase::TCA8418Key;
constexpr uint8_t modifierShiftKey = 7 - 1; // keynum -1
constexpr uint8_t modifierRightShift = 0b0001;
constexpr uint8_t modifierFnKey = 3 - 1;
constexpr uint8_t modifierFn = 0b0010;
constexpr uint8_t modifierCtrlKey = 4 - 1;
constexpr uint8_t modifierOptKey = 8 - 1;
constexpr uint8_t modifierAltKey = 12 - 1;
// Num chars per key, Modulus for rotating through characters
// https://m5stack-doc.oss-cn-shenzhen.aliyuncs.com/1178/Sch_M5CardputerAdv_v1.0_2025_06_20_17_19_58_page_02.png
static uint8_t CardputerAdvTapMod[_TCA8418_NUM_KEYS] = {3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3};
static unsigned char CardputerAdvTapMap[_TCA8418_NUM_KEYS][3] = {{'`', '~', Key::ESC},
{Key::TAB, 0x00, 0x00},
{0x00, 0x00, 0x00}, // Fn
{0x00, 0x00, 0x00}, // ctrl
{'1', '!', 0x00},
{'q', 'Q', Key::REBOOT},
{0x00, 0x00, 0x00}, // shift
{0x00, 0x00, 0x00}, // opt
{'2', '@', 0x00},
{'w', 'W', 0x00},
{'a', 'A', 0x00},
{0x00, 0x00, 0x00}, // alt
{'3', '#', 0x00},
{'e', 'E', 0x00},
{'s', 'S', 0x00},
{'z', 'Z', 0x00},
{'4', '$', 0x00},
{'r', 'R', 0x00},
{'d', 'D', 0x00},
{'x', 'X', 0x00},
{'5', '%', 0x00},
{'t', 'T', 0x00},
{'f', 'F', 0x00},
{'c', 'C', 0x00},
{'6', '^', 0x00},
{'y', 'Y', 0x00},
{'g', 'G', Key::GPS_TOGGLE},
{'v', 'V', 0x00},
{'7', '&', 0x00},
{'u', 'U', 0x00},
{'h', 'H', 0x00},
{'b', 'B', Key::BT_TOGGLE},
{'8', '*', 0x00},
{'i', 'I', 0x00},
{'j', 'J', 0x00},
{'n', 'N', 0x00},
{'9', '(', 0x00},
{'o', 'O', 0x00},
{'k', 'K', 0x00},
{'m', 'M', Key::MUTE_TOGGLE},
{'0', ')', 0x00},
{'p', 'P', Key::SEND_PING},
{'l', 'L', 0x00},
{',', '<', Key::LEFT},
{'_', '-', 0x00},
{'[', '{', 0x00},
{';', ':', Key::UP},
{'.', '>', Key::DOWN},
{'=', '+', 0x00},
{']', '}', 0x00},
{'\'', '"', 0x00},
{'/', '?', Key::RIGHT},
{Key::BSP, 0x00, 0x00},
{'\\', '|', 0x00},
{Key::SELECT, 0x00, 0x00}, // Enter
{' ', ' ', ' '}}; // Space
CardputerAdvKeyboard::CardputerAdvKeyboard()
: TCA8418KeyboardBase(_TCA8418_ROWS, _TCA8418_COLS), modifierFlag(0), last_modifier_time(0), last_key(-1), next_key(-1),
last_tap(0L), char_idx(0), tap_interval(0)
{
reset();
}
void CardputerAdvKeyboard::reset(void)
{
TCA8418KeyboardBase::reset();
}
// handle multi-key presses (shift and alt)
void CardputerAdvKeyboard::trigger()
{
uint8_t count = keyCount();
if (count == 0)
return;
for (uint8_t i = 0; i < count; ++i) {
uint8_t k = readRegister(TCA8418_REG_KEY_EVENT_A + i);
uint8_t key = k & 0x7F;
if (k & 0x80) {
pressed(key);
} else {
released();
state = Idle;
}
}
}
void CardputerAdvKeyboard::pressed(uint8_t key)
{
if (state == Init || state == Busy) {
return;
}
if (modifierFlag && (millis() - last_modifier_time > _TCA8418_MULTI_TAP_THRESHOLD)) {
modifierFlag = 0;
}
uint8_t next_key = 0;
int row = (key - 1) / 10;
int col = (key - 1) % 10;
if (row >= _TCA8418_ROWS || col >= _TCA8418_COLS) {
return; // Invalid key
}
next_key = row * _TCA8418_COLS + col;
state = Held;
uint32_t now = millis();
tap_interval = now - last_tap;
updateModifierFlag(next_key);
if (isModifierKey(next_key)) {
last_modifier_time = now;
}
if (tap_interval < 0) {
last_tap = 0;
state = Busy;
return;
}
if (next_key != last_key || tap_interval > _TCA8418_MULTI_TAP_THRESHOLD) {
char_idx = 0;
} else {
char_idx += 1;
}
last_key = next_key;
last_tap = now;
}
void CardputerAdvKeyboard::released()
{
if (state != Held) {
return;
}
if (last_key < 0 || last_key >= _TCA8418_NUM_KEYS) {
last_key = -1;
state = Idle;
return;
}
uint32_t now = millis();
last_tap = now;
if (CardputerAdvTapMap[last_key][modifierFlag % CardputerAdvTapMod[last_key]] == Key::BL_TOGGLE) {
return;
}
queueEvent(CardputerAdvTapMap[last_key][modifierFlag % CardputerAdvTapMod[last_key]]);
if (isModifierKey(last_key) == false)
modifierFlag = 0;
}
void CardputerAdvKeyboard::updateModifierFlag(uint8_t key)
{
if (key == modifierShiftKey) {
modifierFlag ^= modifierRightShift;
} else if (key == modifierFnKey) {
modifierFlag ^= modifierFn;
} else if (key == modifierCtrlKey) {
// modifierFlag ^= modifierCtrl;
} else if (key == modifierOptKey) {
// modifierFlag ^= modifierOpt;
} else if (key == modifierAltKey) {
// modifierFlag ^= modifierAlt;
}
}
bool CardputerAdvKeyboard::isModifierKey(uint8_t key)
{
return (key == modifierShiftKey || key == modifierFnKey);
}
#endif

View File

@ -0,0 +1,26 @@
#include "TCA8418KeyboardBase.h"
class CardputerAdvKeyboard : public TCA8418KeyboardBase
{
public:
CardputerAdvKeyboard();
void reset(void);
void trigger(void) override;
virtual ~CardputerAdvKeyboard() {}
protected:
void pressed(uint8_t key) override;
void released(void) override;
void updateModifierFlag(uint8_t key);
bool isModifierKey(uint8_t key);
private:
uint8_t modifierFlag; // Flag to indicate if a modifier key is pressed
uint32_t last_modifier_time; // Timestamp of the last modifier key press
int8_t last_key;
int8_t next_key;
uint32_t last_tap;
uint8_t char_idx;
int32_t tap_interval;
};

View File

@ -7,6 +7,8 @@
#include "TDeckProKeyboard.h"
#elif defined(T_LORA_PAGER)
#include "TLoraPagerKeyboard.h"
#elif defined(M5STACK_CARDPUTER_ADV)
#include "CardputerAdvKeyboard.h"
#else
#include "TCA8418Keyboard.h"
#endif
@ -20,6 +22,8 @@ KbI2cBase::KbI2cBase(const char *name)
TCAKeyboard(*(new TDeckProKeyboard()))
#elif defined(T_LORA_PAGER)
TCAKeyboard(*(new TLoraPagerKeyboard()))
#elif defined(M5STACK_CARDPUTER_ADV)
TCAKeyboard(*(new CardputerAdvKeyboard()))
#else
TCAKeyboard(*(new TCA8418Keyboard()))
#endif

View File

@ -201,6 +201,8 @@
#define HW_VENDOR meshtastic_HardwareModel_HELTEC_V4
#elif defined(M5STACK_UNITC6L)
#define HW_VENDOR meshtastic_HardwareModel_M5STACK_C6L
#elif defined(M5STACK_CARDPUTER_ADV)
#define HW_VENDOR meshtastic_HardwareModel_M5STACK_CARDPUTER_ADV
#elif defined(HELTEC_WIRELESS_TRACKER_V2)
#define HW_VENDOR meshtastic_HardwareModel_HELTEC_WIRELESS_TRACKER_V2
#endif

View File

@ -0,0 +1,33 @@
#ifndef Pins_Arduino_h
#define Pins_Arduino_h
#include "soc/soc_caps.h"
#include <stdint.h>
#define USB_VID 0x303a
#define USB_PID 0x1001
// Some boards have too low voltage on this pin (board design bug)
// Use different pin with 3V and connect with 48
// and change this setup for the chosen pin (for example 38)
// static const uint8_t LED_BUILTIN = SOC_GPIO_PIN_COUNT + 48;
// #define BUILTIN_LED LED_BUILTIN // backward compatibility
// #define LED_BUILTIN LED_BUILTIN
// #define RGB_BUILTIN LED_BUILTIN
// #define RGB_BRIGHTNESS 64
static const uint8_t TXD2 = 13;
static const uint8_t RXD2 = 15;
static const uint8_t SDA = 8;
static const uint8_t SCL = 9;
// external & microSD
static const uint8_t SS = 5; // external SS
static const uint8_t MOSI = 14;
static const uint8_t MISO = 39;
static const uint8_t SCK = 40;
static const uint8_t ADC = 10;
#endif /* Pins_Arduino_h */

View File

@ -0,0 +1,23 @@
; M5stack Cardputer ADV
[env:m5stack-cardputer-adv]
extends = esp32s3_base
board = m5stack-stamps3
board_check = true
board_build.partitions = default_8MB.csv
upload_protocol = esptool
build_flags =
${esp32_base.build_flags}
;-D PRIVATE_HW
-D M5STACK_CARDPUTER_ADV
-D ARDUINO_USB_CDC_ON_BOOT=1
-D GPS_POWER_TOGGLE
;-D HAS_SDCARD
;-D SDCARD_USE_SPI1
-I variants/esp32s3/m5stack_cardputer_adv
lib_deps = ${esp32_base.lib_deps}
adafruit/Adafruit NeoPixel @ ^1.12.0
https://github.com/meshtastic/st7789/archive/bd33ea58ddfe4a5e4a66d53300ccbd38d66ac21f.zip
;lovyan03/LovyanGFX@1.2.7
earlephilhower/ESP8266Audio@1.9.9
earlephilhower/ESP8266SAM@1.0.1
https://github.com/pschatzmann/arduino-audio-driver/archive/refs/tags/v0.1.3.zip

View File

@ -0,0 +1,126 @@
// I2C
#define I2C_SDA SDA
#define I2C_SCL SCL
// Custom port I2C1 or UART
#define G1 1
#define G2 2
// Neopixel LED, PWR_EN Pin same as TFT Backlight GPIO38
#define HAS_NEOPIXEL // Enable the use of neopixels
#define NEOPIXEL_COUNT 1 // How many neopixels are connected
#define NEOPIXEL_DATA 21 // gpio pin used to send data to the neopixels
#define NEOPIXEL_TYPE (NEO_GRB + NEO_KHZ800) // type of neopixels in use
// Button
#define BUTTON_PIN 0
// Battery
#define BATTERY_PIN 10
#define ADC_CHANNEL ADC1_GPIO10_CHANNEL
// IR LED
#define IR_LED 44 // Not used, information only
// TCA8418 keyboard
#define TCA8418_INT 11
// #define KB_BL_PIN -1 // No keyboard backlight
#define I2C_NO_RESCAN
#define KB_INT TCA8418_INT
#define CANNED_MESSAGE_MODULE_ENABLE 1
// GPS
#define HAS_GPS 1
#define GPS_RX_PIN RXD2
#define GPS_TX_PIN TXD2
#define GPS_BAUDRATE 115200
// BMI270
#define USE_BMI270 // INFO | ??:??:?? 0 BMX160 found at address 0x69
// SD CARD
#define SPI_MOSI MOSI
#define SPI_SCK SCK
#define SPI_MISO MISO
#define SPI_CS 12
#define SDCARD_CS SPI_CS
#define SD_SPI_FREQUENCY 75000000U
// audio codec ES8311
#define HAS_I2S
#define DAC_I2S_BCK 41
#define DAC_I2S_WS 43
#define DAC_I2S_DOUT 46
#define DAC_I2S_DIN 42
#define DAC_I2S_MCLK -1 //???
// lovyan
#if 0
// ST7789 TFT LCD
#define ST7789_CS 37
#define ST7789_RS 34 // DC
#define ST7789_SDA 35 // MOSI
#define ST7789_SCK 36
#define ST7789_RESET 33
#define ST7789_MISO -1
#define ST7789_BUSY -1
#define ST7789_BL 38
#define ST7789_SPI_HOST SPI2_HOST
#define TFT_BL 38
#define SPI_FREQUENCY 40000000
#define SPI_READ_FREQUENCY 16000000
#define TFT_HEIGHT 135
#define TFT_WIDTH 240
#define TFT_OFFSET_X 0
#define TFT_OFFSET_Y 0
#define TFT_OFFSET_ROTATION 2
#define SCREEN_ROTATE
#define SCREEN_TRANSITION_FRAMERATE 5 // fps
#endif
// github.com/meshtastic/st7789
#if 1
// Display (TFT)
#define USE_ST7789
#define ST7789_NSS 37
#define ST7789_RS 34 // DC
#define ST7789_SDA 35 // MOSI
#define ST7789_SCK 36
#define ST7789_RESET 33
#define ST7789_MISO -1
#define ST7789_BUSY -1
#define VTFT_CTRL 38
#define VTFT_LEDA 38
#define TFT_BACKLIGHT_ON HIGH
#define ST7789_SPI_HOST SPI2_HOST
#define SPI_FREQUENCY 40000000
#define SPI_READ_FREQUENCY 16000000
#define TFT_HEIGHT 135
#define TFT_WIDTH 240
#define TFT_OFFSET_X 0
#define TFT_OFFSET_Y 0
#define BRIGHTNESS_DEFAULT 100 // Medium Low Brightnes
#endif
// LoRa
#define USE_SX1262 // Currently only SX1262 CAP is available
#define USE_RF95 // Test
#define LORA_SCK SCK
#define LORA_MISO MISO
#define LORA_MOSI MOSI
#define LORA_CS SS // NSS
// SX127X/RFM95
#define LORA_DIO0 4 // RF95 IRQ, SX1262 not connected
#define LORA_DIO1 6 // RF95 BUSY
#define LORA_RESET 3
// SX126X
#define SX126X_CS LORA_CS
#define SX126X_DIO1 4 // IRQ
#define SX126X_BUSY 6 // BUSY, LORA_DIO2
#define SX126X_RESET LORA_RESET
#define SX126X_DIO2_AS_RF_SWITCH
#define TCXO_OPTIONAL
#define SX126X_DIO3_TCXO_VOLTAGE 1.8 // Check the correct value!