-
-
Notifications
You must be signed in to change notification settings - Fork 2.6k
feat: Support Elecrow ThinkNode M9 #10908
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: develop
Are you sure you want to change the base?
Changes from 47 commits
089ad58
7960144
c85f2a2
9009bbd
86a0d94
d71a380
7088470
9d885ad
d4d4b2c
8e6df32
12ca206
affbf05
813c990
3d0b2ca
d56d5db
ae34cce
8e75a76
071d7e1
280a701
2c23a2a
fa5ff1e
7886e55
25c055a
000120f
402c6f0
8f18dce
a0c9736
c4e50c8
36a6b27
0d0aa7d
79ab3eb
fefb268
bbbd963
9fe9c31
5352260
2fc1d87
79ffa5c
269f21b
7b62dd3
58b6f8e
e384f28
fd9bb08
4e96f7d
a3b0d2d
37ad16b
ddc4fb5
f0ec12b
6024804
4dbd3a6
363b642
e33cc4c
fc7cae7
c831343
8df1ab1
336097e
3691565
9e39aea
6fbd32f
c6341ea
f1d410e
e5287f3
76c457f
5f9a69b
61ec082
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -26,6 +26,11 @@ void Lock::lock() | |||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| bool Lock::lock(uint32_t timeout) | ||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||
| return xSemaphoreTake(handle, pdMS_TO_TICKS(timeout)) == pdTRUE; | ||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||
|
Comment on lines
+29
to
+32
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🎯 Functional Correctness | 🔴 Critical | ⚡ Quick win Provide a non-FreeRTOS definition for the new overload.
Proposed fix `#else`
Lock::Lock() {}
Lock::~Lock() {}
void Lock::lock() {}
+
+bool Lock::lock(uint32_t) { return true; }
void Lock::unlock() {}
`#endif`📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| void Lock::unlock() | ||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||
| if (xSemaphoreGive(handle) == false) { | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,155 @@ | ||||||||||||||||||
| #include "STC8HKeyboard.h" | ||||||||||||||||||
|
|
||||||||||||||||||
| #if defined(ELECROW_ThinkNode_M9) | ||||||||||||||||||
| #include "cardKbI2cImpl.h" | ||||||||||||||||||
|
|
||||||||||||||||||
| #include "configuration.h" | ||||||||||||||||||
|
|
||||||||||||||||||
| // --------------------------------------------------------------------------- | ||||||||||||||||||
| // STC8H companion-MCU keypad driver (ThinkNode-M9). | ||||||||||||||||||
| // | ||||||||||||||||||
| // The original STC8HKeyboard.cpp was lost from the reference source tree, so | ||||||||||||||||||
| // this was recovered from the linked reference firmware.elf (the .o was an LTO | ||||||||||||||||||
| // object with no machine code; the final ELF had the real inlined bodies). | ||||||||||||||||||
| // | ||||||||||||||||||
| // How the hardware works: | ||||||||||||||||||
| // - The STC8H raises KB_INT (rising edge, idle-low) when a key is pressed. The ISR | ||||||||||||||||||
| // latches key_event; is_key_event() just returns that flag. | ||||||||||||||||||
| // - The pressed key code is read over I2C from register 0x05. | ||||||||||||||||||
| // - is_key_state() polls KB_INT directly to keep the backlight lit while a | ||||||||||||||||||
| // key is held. | ||||||||||||||||||
| // - Battery voltage lives in registers 0x01..0x04, little-endian. | ||||||||||||||||||
| // - Sleep is requested by writing 0x01 to the STATE register (0x06). | ||||||||||||||||||
| // - The keypad backlight (KB_LED) and torch (PIN_LED) are plain host GPIOs, | ||||||||||||||||||
| // not I2C commands. | ||||||||||||||||||
| // --------------------------------------------------------------------------- | ||||||||||||||||||
|
|
||||||||||||||||||
| STC8HKeyboard Stc8HKeyBoard; | ||||||||||||||||||
|
|
||||||||||||||||||
| // ISR latched on each KB_INT rising edge (a key was pressed). | ||||||||||||||||||
| static void has_key_event() | ||||||||||||||||||
| { | ||||||||||||||||||
| Stc8HKeyBoard.key_event = true; | ||||||||||||||||||
| if (cardKbI2cImpl) { | ||||||||||||||||||
| cardKbI2cImpl->setIntervalFromNow(0); | ||||||||||||||||||
| // runASAP = true; | ||||||||||||||||||
| BaseType_t higherWake = 0; | ||||||||||||||||||
| concurrency::mainDelay.interruptFromISR(&higherWake); | ||||||||||||||||||
| } | ||||||||||||||||||
| } | ||||||||||||||||||
|
|
||||||||||||||||||
| void STC8HKeyboard::writeRegister(uint8_t reg, uint8_t val) | ||||||||||||||||||
| { | ||||||||||||||||||
| _pWire->beginTransmission(_I2C_addr); | ||||||||||||||||||
| _pWire->write(reg); | ||||||||||||||||||
| _pWire->write(val); | ||||||||||||||||||
| _pWire->endTransmission(); | ||||||||||||||||||
| } | ||||||||||||||||||
|
|
||||||||||||||||||
| uint8_t STC8HKeyboard::readRegister(uint8_t reg) | ||||||||||||||||||
| { | ||||||||||||||||||
| _pWire->beginTransmission(_I2C_addr); | ||||||||||||||||||
| _pWire->write(reg); | ||||||||||||||||||
| if (_pWire->endTransmission(false) != 0) | ||||||||||||||||||
| return 0xFF; | ||||||||||||||||||
| if (_pWire->requestFrom(_I2C_addr, (uint8_t)1) != 1) | ||||||||||||||||||
| return 0xFF; | ||||||||||||||||||
| return _pWire->read(); | ||||||||||||||||||
| } | ||||||||||||||||||
|
|
||||||||||||||||||
| void STC8HKeyboard::begin(uint8_t addr, TwoWire *wire) | ||||||||||||||||||
| { | ||||||||||||||||||
| LOG_DEBUG("STC8HKeyboard::begin() addr=0x%02x", addr); | ||||||||||||||||||
| _I2C_addr = addr; | ||||||||||||||||||
| _pWire = wire; | ||||||||||||||||||
| pinMode(KB_INT, INPUT); | ||||||||||||||||||
| #ifdef KB_LED | ||||||||||||||||||
| pinMode(KB_LED, OUTPUT); | ||||||||||||||||||
| #endif | ||||||||||||||||||
| #ifdef PIN_LED | ||||||||||||||||||
| pinMode(PIN_LED, OUTPUT); | ||||||||||||||||||
| #endif | ||||||||||||||||||
| attachInterrupt(KB_INT, has_key_event, RISING); | ||||||||||||||||||
| _pWire->begin(); | ||||||||||||||||||
| Keyboard_state = true; | ||||||||||||||||||
| #ifdef ARCH_ESP32 | ||||||||||||||||||
| // Detach/reattach the key interrupt around ESP32 light sleep | ||||||||||||||||||
| lsObserver.observe(¬ifyLightSleep); | ||||||||||||||||||
| lsEndObserver.observe(¬ifyLightSleepEnd); | ||||||||||||||||||
| #endif | ||||||||||||||||||
| } | ||||||||||||||||||
|
|
||||||||||||||||||
| bool STC8HKeyboard::is_Keyboard_begin() | ||||||||||||||||||
| { | ||||||||||||||||||
| return Keyboard_state; | ||||||||||||||||||
| } | ||||||||||||||||||
|
|
||||||||||||||||||
| // A key is currently active (KB_INT held); used to wake the keypad backlight. | ||||||||||||||||||
| bool STC8HKeyboard::is_key_state() | ||||||||||||||||||
| { | ||||||||||||||||||
| return digitalRead(KB_INT); | ||||||||||||||||||
| } | ||||||||||||||||||
|
|
||||||||||||||||||
| // A key-press interrupt has been latched since the flag was last cleared. | ||||||||||||||||||
| bool STC8HKeyboard::is_key_event() | ||||||||||||||||||
| { | ||||||||||||||||||
| return key_event; | ||||||||||||||||||
| } | ||||||||||||||||||
|
|
||||||||||||||||||
| uint8_t STC8HKeyboard::bsp_get_key_value() | ||||||||||||||||||
| { | ||||||||||||||||||
| return readRegister(0x01); | ||||||||||||||||||
| } | ||||||||||||||||||
|
Comment on lines
+99
to
+102
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win Read the matrix-key register, not the battery register.
Proposed fix uint8_t STC8HKeyboard::bsp_get_key_value()
{
- return readRegister(0x01);
+ return readRegister(STC8_REG_ADDR_MATRIX_KEY);
}📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||
|
|
||||||||||||||||||
| // Battery millivolts: registers 0x01..0x04 read little-endian, low 16 bits. | ||||||||||||||||||
| uint16_t STC8HKeyboard::bsp_get_battery_voltage() | ||||||||||||||||||
| { | ||||||||||||||||||
| if (!Keyboard_state) | ||||||||||||||||||
| return 0; | ||||||||||||||||||
| uint32_t voltage = 0; | ||||||||||||||||||
| for (uint8_t i = 0; i < 4; i++) | ||||||||||||||||||
| voltage |= (uint32_t)readRegister(STC8_REG_ADDR_BATTERY + i) << (i * 8); | ||||||||||||||||||
| return voltage > 0xFFFF ? 0xFFFF : (uint16_t)voltage; | ||||||||||||||||||
| } | ||||||||||||||||||
|
|
||||||||||||||||||
| void STC8HKeyboard::set_keyboard_blight(bool state) | ||||||||||||||||||
| { | ||||||||||||||||||
| #ifdef KB_LED | ||||||||||||||||||
| digitalWrite(KB_LED, state); | ||||||||||||||||||
| #else | ||||||||||||||||||
| (void)state; // KB_LED pin not defined for this board | ||||||||||||||||||
| #endif | ||||||||||||||||||
| } | ||||||||||||||||||
|
|
||||||||||||||||||
| void STC8HKeyboard::switch_flashlight() | ||||||||||||||||||
| { | ||||||||||||||||||
| #ifdef PIN_LED | ||||||||||||||||||
| digitalWrite(PIN_LED, !digitalRead(PIN_LED)); | ||||||||||||||||||
| #endif | ||||||||||||||||||
| // else: torch pin unresolved on this board (old board used PIN_LED 13, | ||||||||||||||||||
| // which the current variant assigns to BATTERY_PIN) -- see variant.h. | ||||||||||||||||||
| } | ||||||||||||||||||
|
|
||||||||||||||||||
| void STC8HKeyboard::set_sleep_status(void) | ||||||||||||||||||
| { | ||||||||||||||||||
| writeRegister(STC8_REG_ADDR_STATE, 0x01); | ||||||||||||||||||
| _pWire->end(); | ||||||||||||||||||
| } | ||||||||||||||||||
|
|
||||||||||||||||||
| #ifdef ARCH_ESP32 | ||||||||||||||||||
| // Detach the key interrupt before ESP32 light sleep, so it can't fire while asleep. | ||||||||||||||||||
| int STC8HKeyboard::beforeLightSleep(void *unused) | ||||||||||||||||||
| { | ||||||||||||||||||
| detachInterrupt(KB_INT); | ||||||||||||||||||
| return 0; // Indicates success | ||||||||||||||||||
| } | ||||||||||||||||||
|
|
||||||||||||||||||
| // Reattach the key interrupt after waking from light sleep. | ||||||||||||||||||
| int STC8HKeyboard::afterLightSleep(esp_sleep_wakeup_cause_t cause) | ||||||||||||||||||
| { | ||||||||||||||||||
| attachInterrupt(KB_INT, has_key_event, RISING); | ||||||||||||||||||
| return 0; // Indicates success | ||||||||||||||||||
| } | ||||||||||||||||||
| #endif | ||||||||||||||||||
|
|
||||||||||||||||||
| #endif // ELECROW_ThinkNode_M9 | ||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
Do not classify every GPIO wake as a keyboard press.
With
KB_INTbut noBUTTON_PIN, this setspressed = truefor unrelated GPIO wakes; with both defined,#elifignores a keyboard wake. Check each configured pin’s active level and retainEVENT_WAKE_TIMERfor unrecognized GPIO sources.Proposed fix
case ESP_SLEEP_WAKEUP_GPIO: { bool pressed = false; `#if` defined(BUTTON_PIN) - pressed = !digitalRead(config.device.button_gpio ? config.device.button_gpio : BUTTON_PIN); -#elif defined(KB_INT) - // keyboard press (probably) triggered GPIO interrupt - pressed = true; + pressed |= !digitalRead(config.device.button_gpio ? config.device.button_gpio : BUTTON_PIN); +#endif +#if defined(KB_INT) +#if KB_INT_WAKE_ON_HIGH + pressed |= digitalRead(KB_INT); +#else + pressed |= !digitalRead(KB_INT); +#endif `#endif` if (pressed) { powerFSM.trigger(EVENT_PRESS); + } else { + powerFSM.trigger(EVENT_WAKE_TIMER); } break; }📝 Committable suggestion
🤖 Prompt for AI Agents