Add drivers to module and make start/stop optional#580
Conversation
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (64)
🚧 Files skipped from review as they are similar to previous changes (63)
📝 WalkthroughWalkthroughThe module API now accepts optional lifecycle callbacks and null-terminated driver lists. Kernel start and stop operations construct, add, remove, and destruct registered drivers around optional callbacks. Device and driver modules were migrated from explicit lifecycle wiring to declarative driver arrays, while several device descriptors now use minimal initializers. Additional changes remove obsolete placeholders and headers, update selected device HAL properties, adjust power and event cleanup behavior, and revise related documentation. 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 5
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 310d2eb2-eba3-4769-8fea-f7e9cbc3886b
📒 Files selected for processing (131)
Devices/btt-panda-touch/source/module.cppDevices/cyd-2432s024c/source/module.cppDevices/cyd-2432s024r/source/module.cppDevices/cyd-2432s028r/source/module.cppDevices/cyd-2432s028rv3/source/module.cppDevices/cyd-2432s032c/source/module.cppDevices/cyd-3248s035c/source/module.cppDevices/cyd-4848s040c/source/module.cppDevices/cyd-8048s043c/source/module.cppDevices/cyd-e32r28t/source/module.cppDevices/cyd-e32r32p/source/module.cppDevices/elecrow-crowpanel-advance-28/source/module.cppDevices/elecrow-crowpanel-advance-35/source/module.cppDevices/elecrow-crowpanel-advance-50/source/module.cppDevices/elecrow-crowpanel-basic-28/source/module.cppDevices/elecrow-crowpanel-basic-35/source/module.cppDevices/elecrow-crowpanel-basic-50/source/module.cppDevices/es3c28p/source/module.cppDevices/generic-esp32/source/module.cppDevices/generic-esp32c6/source/module.cppDevices/generic-esp32p4/source/module.cppDevices/generic-esp32s3/source/module.cppDevices/guition-jc1060p470ciwy/source/module.cppDevices/guition-jc2432w328c/source/module.cppDevices/guition-jc8048w550c/source/module.cppDevices/heltec-wifi-lora-32-v3/source/module.cppDevices/lilygo-tdeck-max/source/module.cppDevices/lilygo-tdeck-plus/device.propertiesDevices/lilygo-tdeck-plus/source/module.cppDevices/lilygo-tdeck/device.propertiesDevices/lilygo-tdeck/source/module.cppDevices/lilygo-tdisplay-s3/source/module.cppDevices/lilygo-tdisplay/source/module.cppDevices/lilygo-tdongle-s3/source/module.cppDevices/lilygo-thmi/source/module.cppDevices/lilygo-tlora-pager/device.propertiesDevices/lilygo-tlora-pager/source/module.cppDevices/m5stack-cardputer-adv/source/module.cppDevices/m5stack-cardputer/source/module.cppDevices/m5stack-core2/source/module.cppDevices/m5stack-cores3/source/module.cppDevices/m5stack-papers3/source/module.cppDevices/m5stack-stackchan/source/module.cppDevices/m5stack-stickc-plus2/source/module.cppDevices/m5stack-sticks3/source/module.cppDevices/m5stack-tab5/Source/module.cppDevices/unphone/source/module.cppDevices/waveshare-esp32-s3-geek/source/module.cppDevices/waveshare-s3-lcd-13/source/module.cppDevices/waveshare-s3-touch-lcd-128/source/module.cppDevices/waveshare-s3-touch-lcd-147/source/module.cppDevices/waveshare-s3-touch-lcd-43/source/module.cppDevices/wireless-tag-wt32-sc01-plus/source/module.cppDocumentation/ideas.mdDrivers/EspLcdCompat/CMakeLists.txtDrivers/EspLcdCompat/README.mdDrivers/EspLcdCompat/Source/EspLcdDisplay.cppDrivers/EspLcdCompat/Source/EspLcdDisplay.hDrivers/EspLcdCompat/Source/EspLcdDisplayDriver.hDrivers/EspLcdCompat/Source/EspLcdDisplayV2.cppDrivers/EspLcdCompat/Source/EspLcdDisplayV2.hDrivers/EspLcdCompat/Source/EspLcdSpiDisplay.cppDrivers/EspLcdCompat/Source/EspLcdSpiDisplay.hDrivers/EspLcdCompat/Source/EspLcdTouch.cppDrivers/EspLcdCompat/Source/EspLcdTouch.hDrivers/EspLcdCompat/Source/EspLcdTouchDriver.cppDrivers/EspLcdCompat/Source/EspLcdTouchDriver.hDrivers/audio-codec-module/README.mdDrivers/audio-stream-module/source/module.cppDrivers/aw88298-module/source/module.cppDrivers/aw9523b-module/source/module.cppDrivers/axp192-module/source/module.cppDrivers/axp2101-module/source/module.cppDrivers/axs5106-module/source/module.cppDrivers/bm8563-module/source/module.cppDrivers/bmi270-module/source/module.cppDrivers/bq24295-module/source/module.cppDrivers/bq25896-module/source/module.cppDrivers/bq27220-module/source/module.cppDrivers/button-control-module/source/module.cppDrivers/ch422g-module/source/module.cppDrivers/cst328-module/source/module.cppDrivers/cst66xx-module/source/module.cppDrivers/cst816s-module/source/module.cppDrivers/cst816t-module/source/module.cppDrivers/drv2605-module/source/module.cppDrivers/dummy-i2s-amp-module/source/module.cppDrivers/es7210-module/source/module.cppDrivers/es8311-module/source/module.cppDrivers/es8388-module/source/module.cppDrivers/ft5x06-module/source/module.cppDrivers/ft6x36-module/source/module.cppDrivers/gc9a01-module/source/module.cppDrivers/gt911-module/source/module.cppDrivers/hx8357-module/source/module.cppDrivers/ili9341-module/source/module.cppDrivers/ili9488-module/source/module.cppDrivers/ili9881c-module/source/module.cppDrivers/ina226-module/source/module.cppDrivers/jd9165-module/source/module.cppDrivers/jd9853-module/source/module.cppDrivers/lilygo-module/source/module.cppDrivers/m5pm1-module/source/module.cppDrivers/m5stack-module/source/module.cppDrivers/mpu6886-module/source/module.cppDrivers/pdm-mic-module/source/module.cppDrivers/pi4ioe5v6408-module/source/module.cppDrivers/py32ioexpander-module/source/module.cppDrivers/qmi8658-module/source/module.cppDrivers/rgb-display-module/source/module.cppDrivers/rx8130ce-module/source/module.cppDrivers/sc2356-module/source/module.cppDrivers/ssd1306-module/source/module.cppDrivers/st7123-module/source/module.cppDrivers/st7701-module/source/module.cppDrivers/st7735-module/source/module.cppDrivers/st7789-i8080-module/source/module.cppDrivers/st7789-module/source/module.cppDrivers/st7796-i8080-module/source/module.cppDrivers/st7796-module/source/module.cppDrivers/sy6970-module/source/module.cppDrivers/tca8418-module/source/module.cppDrivers/tca9534-module/source/module.cppDrivers/tca95xx-16bit-module/source/module.cppDrivers/xl9555-module/source/module.cppDrivers/xpt2046-module/source/module.cppDrivers/xpt2046-softspi-module/source/module.cppModules/crypt-module/source/module.cppModules/hal-device-module/source/module.cppTactilityKernel/include/tactility/module.hTactilityKernel/source/module.cpp
💤 Files with no reviewable changes (15)
- Devices/lilygo-tdeck-plus/source/module.cpp
- Drivers/EspLcdCompat/Source/EspLcdDisplay.h
- Drivers/EspLcdCompat/CMakeLists.txt
- Drivers/EspLcdCompat/Source/EspLcdDisplayV2.cpp
- Drivers/EspLcdCompat/Source/EspLcdTouch.h
- Drivers/EspLcdCompat/Source/EspLcdTouchDriver.h
- Drivers/EspLcdCompat/Source/EspLcdDisplayDriver.h
- Drivers/EspLcdCompat/README.md
- Drivers/EspLcdCompat/Source/EspLcdSpiDisplay.h
- Devices/cyd-2432s024c/source/module.cpp
- Drivers/EspLcdCompat/Source/EspLcdSpiDisplay.cpp
- Drivers/EspLcdCompat/Source/EspLcdDisplayV2.h
- Drivers/EspLcdCompat/Source/EspLcdDisplay.cpp
- Drivers/EspLcdCompat/Source/EspLcdTouchDriver.cpp
- Drivers/EspLcdCompat/Source/EspLcdTouch.cpp
| if (module->start != nullptr) { | ||
| auto error = module->start(); | ||
| if (error != ERROR_NONE) { | ||
| return error; | ||
| } | ||
| } | ||
|
|
||
| if (module->drivers != nullptr) { | ||
| auto* driver_location = module->drivers; | ||
| while (*driver_location != nullptr) { | ||
| auto driver = *driver_location; | ||
| driver_construct_add(driver); | ||
| driver_location++; | ||
| } | ||
| } | ||
|
|
||
| internal->started = true; | ||
| return ERROR_NONE; | ||
| } |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Confirm the exact signatures of driver_construct_add / driver_remove_destruct
fd -e h -p 'driver.h' TactilityKernel
rg -n 'driver_construct_add|driver_remove_destruct' TactilityKernel/include/tactility/driver.h -A3 -B3Repository: TactilityProject/Tactility
Length of output: 687
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== module.h relevant lines =="
rg -n 'struct Module|drivers|struct Driver' TactilityKernel/include/tactility/module.h -A40 -B20
echo "== module.cpp relevant lines =="
sed -n '1,140p' TactilityKernel/source/module.cpp | cat -n
echo "== const Driver ** declarations/usages =="
rg -n 'const struct Driver\\*\\* drivers|Driver\\*\\*|drivers\\]' TactilityKernel -g '*.h' -g '*.c' -g '*.cpp' -g '*.hpp'Repository: TactilityProject/Tactility
Length of output: 15848
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== C++ const conversion compile probe =="
cat > /tmp/const_driver_probe.cpp <<'CPP'
struct Driver { int x = 0; };
extern "C" {
using error_t = int;
enum { ERROR_NONE = 0 };
error_t driver_construct_add(struct Driver* driver) { driver->x++; return ERROR_NONE; }
error_t driver_remove_destruct(struct Driver* driver) { driver->x--; return ERROR_NONE; }
error_t module_start() {
const struct Driver* driver_list[] = { nullptr };
for (const struct Driver** it = driver_list; *it != nullptr; it++) {
const struct Driver* driver = *it;
driver_construct_add(driver);
driver_remove_destruct(driver);
}
return ERROR_NONE;
}
}
int main() { return module_start(); }
CPP
if command -v c++ >/dev/null 2>&1; then
c++ -std=c++17 -Werror /tmp/const_driver_probe.cpp -o /tmp/const_driver_probe 2>&1
else
echo "c++ not available"
fi
echo "== module.h field type text =="
sed -n '35,65p' TactilityKernel/include/tactility/module.h | cat -nRepository: TactilityProject/Tactility
Length of output: 1535
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== driver.cpp lifecycle implementations =="
sed -n '31,96p' TactilityKernel/source/driver.cpp | cat -n
echo "== driver.h lifecycle signatures =="
sed -n '40,96p' TactilityKernel/include/tactility/driver.h | cat -n
echo "== all const_driver declarations/usages =="
rg -n 'const struct Driver' TactilityKernel -g '*.h' -g '*.c' -g '*.cpp' -g '*.hpp'Repository: TactilityProject/Tactility
Length of output: 4437
Propagate failures from the module driver lifecycle loops.
module_start() and module_stop() now discard the return codes from driver_construct_add() / driver_remove_destruct(), so construction/removal errors are ignored. In module_start(), the module is marked started and returns ERROR_NONE even if a driver failed; in module_stop(), module->stop() is called after driver removal and an early return can leave internal->started true. Capture these return values and return them so module start/stop status is not silently corrupted.
Also applies to: 94-101
| error_t module_stop(Module* module) { | ||
| LOG_I(TAG, "stop %s", module->name); | ||
|
|
||
| auto* internal = module->internal; | ||
| if (internal == nullptr) return ERROR_INVALID_STATE; | ||
| if (!internal->started) return ERROR_NONE; | ||
|
|
||
| error_t error = module->stop(); | ||
| if (error != ERROR_NONE) { | ||
| return error; | ||
| if (module->drivers != nullptr) { | ||
| auto* driver_location = module->drivers; | ||
| while (*driver_location != nullptr) { | ||
| auto driver = *driver_location; | ||
| driver_remove_destruct(driver); | ||
| driver_location++; | ||
| } | ||
| } | ||
|
|
||
| if (module->stop != nullptr) { | ||
| auto error = module->stop(); | ||
| if (error != ERROR_NONE) { | ||
| return error; | ||
| } | ||
|
|
||
| } | ||
|
|
||
| internal->started = false; | ||
| return error; | ||
| return ERROR_NONE; | ||
| } |
There was a problem hiding this comment.
🩺 Stability & Availability | 🔴 Critical | ⚡ Quick win
Double-destruct risk if module->stop() fails after drivers were already removed.
Drivers are removed/destructed first (lines 94-101), then module->stop() is conditionally invoked. If module->stop() returns an error, the function returns at line 106 before internal->started = false runs (line 111). internal->started stays true, so a later module_stop retry will pass the if (!internal->started) guard again and re-run driver_remove_destruct on pointers that were already destructed.
🐛 Proposed fix: mark stopped once drivers are torn down, independent of the stop callback's outcome
if (module->drivers != nullptr) {
auto* driver_location = module->drivers;
while (*driver_location != nullptr) {
auto driver = *driver_location;
driver_remove_destruct(driver);
driver_location++;
}
}
+ internal->started = false;
+
if (module->stop != nullptr) {
auto error = module->stop();
if (error != ERROR_NONE) {
return error;
}
-
}
- internal->started = false;
return ERROR_NONE;
}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| error_t module_stop(Module* module) { | |
| LOG_I(TAG, "stop %s", module->name); | |
| auto* internal = module->internal; | |
| if (internal == nullptr) return ERROR_INVALID_STATE; | |
| if (!internal->started) return ERROR_NONE; | |
| error_t error = module->stop(); | |
| if (error != ERROR_NONE) { | |
| return error; | |
| if (module->drivers != nullptr) { | |
| auto* driver_location = module->drivers; | |
| while (*driver_location != nullptr) { | |
| auto driver = *driver_location; | |
| driver_remove_destruct(driver); | |
| driver_location++; | |
| } | |
| } | |
| if (module->stop != nullptr) { | |
| auto error = module->stop(); | |
| if (error != ERROR_NONE) { | |
| return error; | |
| } | |
| } | |
| internal->started = false; | |
| return error; | |
| return ERROR_NONE; | |
| } | |
| error_t module_stop(Module* module) { | |
| LOG_I(TAG, "stop %s", module->name); | |
| auto* internal = module->internal; | |
| if (internal == nullptr) return ERROR_INVALID_STATE; | |
| if (!internal->started) return ERROR_NONE; | |
| if (module->drivers != nullptr) { | |
| auto* driver_location = module->drivers; | |
| while (*driver_location != nullptr) { | |
| auto driver = *driver_location; | |
| driver_remove_destruct(driver); | |
| driver_location++; | |
| } | |
| } | |
| internal->started = false; | |
| if (module->stop != nullptr) { | |
| auto error = module->stop(); | |
| if (error != ERROR_NONE) { | |
| return error; | |
| } | |
| } | |
| return ERROR_NONE; | |
| } |
Summary by CodeRabbit