New variant variants/m5stack_cardputer_adv for the Cardputer-Adv (ESP32-S3, 8 MB) with the Cap LoRa-1262 (SX1262 + GNSS): - Envs: companion_radio_ble, companion_radio_usb, repeater, room_server. - Board: enables the Cap's antenna path via the PI4IOE5V6408 on the internal I2C bus (Wire1, G8/G9); Wire stays on the Grove port. LoRa and microSD share FSPI because the display owns SPI3. TCXO 1.8 V. - Companion UI adapted from MultiMote/meshcore-cardputer-adv (MIT, LICENSE.MultiMote), running on the standard companion so the USB terminal CLI stays available. Contacts/identity stay in internal SPIFFS; the microSD card is optional (chat history, keyboard layouts). - Sticky Shift, one-shot Fn with Fn+letter shortcuts, top button (G0) sends a flood advert, brightness control. - Text size setting (Normal/Large/Extra large) with DejaVu Sans fonts generated by tools/gen_vlw_font.py; layouts derive from the font size. - Power save maps to the companion's powersaving pref; the UI vetoes light sleep while the screen is on. Low-battery power-off at 3.4 V. - win_long_cmdline.py: Windows-only -iprefix include shortening so the ESP32 compile command stays under the 32,767-character limit. Shared companion changes are guarded by CARDPUTER_ADV_UI: main.cpp selects CardputerDataStore/CardputerUITask/CardputerMesh, and MyMesh.h maps the_mesh to the subclass like the PSRAM storage path does. Tested on hardware (910.525 MHz mesh): radio RX/TX, USB CLI, BLE, UI. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
71 lines
1.7 KiB
C++
71 lines
1.7 KiB
C++
#include "CardputerKeyboard.h"
|
|
#include "globals.h"
|
|
#include <Wire.h>
|
|
|
|
bool CardputerKeyboard::isModifier(Keyboard::Key key) {
|
|
|
|
return key == Keyboard::KEY_SHIFT || key == Keyboard::KEY_OPT ||
|
|
key == Keyboard::KEY_ALT || key == Keyboard::KEY_CTRL ||
|
|
key == Keyboard::KEY_FN;
|
|
}
|
|
|
|
void CardputerKeyboard::updateModifier(Keyboard::Key key, bool down) {
|
|
switch (key) {
|
|
case Keyboard::KEY_SHIFT:
|
|
// Sticky: each press toggles (like caps lock), releases are ignored
|
|
if (down) modifiers.shift = !modifiers.shift;
|
|
break;
|
|
case Keyboard::KEY_OPT:
|
|
modifiers.opt = down;
|
|
break;
|
|
case Keyboard::KEY_ALT:
|
|
modifiers.alt = down;
|
|
break;
|
|
case Keyboard::KEY_CTRL:
|
|
modifiers.ctrl = down;
|
|
break;
|
|
case Keyboard::KEY_FN:
|
|
// One-shot: a press arms Fn for the next key (press again to cancel)
|
|
if (down) modifiers.fn = !modifiers.fn;
|
|
break;
|
|
}
|
|
}
|
|
|
|
void CardputerKeyboard::begin() {
|
|
tio.begin(KEYBOARD_I2C_ADDRESS, &Wire1);
|
|
tio.matrix(7, 8);
|
|
tio.flush();
|
|
tio.enableInterrupts();
|
|
}
|
|
|
|
Keyboard::Event CardputerKeyboard::poll() {
|
|
Keyboard::Event result;
|
|
result.changed = tio.available() > 0;
|
|
|
|
if (result.changed) {
|
|
uint8_t e = tio.getEvent();
|
|
bool down = (e & 0x80);
|
|
tio.writeRegister(TCA8418_REG_INT_STAT, 1);
|
|
|
|
e &= 0x7F;
|
|
|
|
// Normalize key code to remove gaps
|
|
uint8_t key_index = ((e - 1) / 10) * 8 + ((e - 1) % 10) + 1;
|
|
Keyboard::Key key = static_cast<Keyboard::Key>(key_index);
|
|
|
|
result.down = down;
|
|
|
|
if (isModifier(key)) {
|
|
updateModifier(key, down);
|
|
} else {
|
|
result.key = key;
|
|
}
|
|
}
|
|
|
|
result.modifiers = modifiers;
|
|
if (result.key != Keyboard::KEY_NONE && result.down) {
|
|
modifiers.fn = false; // Fn applies to this one key only
|
|
}
|
|
return result;
|
|
}
|