-
-
Notifications
You must be signed in to change notification settings - Fork 15
I2C support and IMU driver #124
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
Changes from 8 commits
5e3d35b
66f1d6d
48e3647
77d11ec
c73ab86
62de264
001daad
0c8be14
bc015c2
13dd504
5d4ce24
6604c2a
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 | ||||||
|---|---|---|---|---|---|---|---|---|
|
|
@@ -14,6 +14,8 @@ | |||||||
|
|
||||||||
| #if FT_MOONBASE == 1 | ||||||||
|
|
||||||||
| #include <Wire.h> // for i2C | ||||||||
|
|
||||||||
| #include "MoonBase/Module.h" | ||||||||
| #include "driver/uart.h" | ||||||||
|
|
||||||||
|
|
@@ -216,6 +218,16 @@ class ModuleIO : public Module { | |||||||
| addControl(rows, "Level", "text", 0, 32, true); // ro | ||||||||
| addControl(rows, "DriveCap", "text", 0, 32, true); // ro | ||||||||
| } | ||||||||
|
|
||||||||
| control = addControl(controls, "i2cFreq", "number", 10, 1000, false, "kHz"); | ||||||||
| control["default"] = 100; // 100 kHz standard mode | ||||||||
|
|
||||||||
| control = addControl(controls, "i2cBus", "rows"); | ||||||||
| control["crud"] = "r"; | ||||||||
| rows = control["n"].to<JsonArray>(); | ||||||||
| { | ||||||||
| addControl(rows, "address", "number", 0, 255, true); // ro | ||||||||
| } | ||||||||
| } | ||||||||
|
|
||||||||
| class PinAssigner { | ||||||||
|
|
@@ -565,6 +577,23 @@ class ModuleIO : public Module { | |||||||
| pinAssigner.assignPin(16, pin_LED); | ||||||||
| #endif | ||||||||
|
|
||||||||
| #ifdef CONFIG_IDF_TARGET_ESP32 | ||||||||
| pinAssigner.assignPin(21, pin_I2C_SDA); // ESP32 classic | ||||||||
| pinAssigner.assignPin(22, pin_I2C_SCL); | ||||||||
| #elif defined(CONFIG_IDF_TARGET_ESP32S2) || defined(CONFIG_IDF_TARGET_ESP32S3) || defined(CONFIG_IDF_TARGET_ESP32C3) | ||||||||
| pinAssigner.assignPin(8, pin_I2C_SDA); // ESP32-C3 | ||||||||
| pinAssigner.assignPin(9, pin_I2C_SCL); | ||||||||
| #elif defined(CONFIG_IDF_TARGET_ESP32C6) | ||||||||
| pinAssigner.assignPin(23, pin_I2C_SDA); // ESP32-C6 | ||||||||
| pinAssigner.assignPin(22, pin_I2C_SCL); | ||||||||
| #elif defined(CONFIG_IDF_TARGET_ESP32P4) | ||||||||
| pinAssigner.assignPin(7, pin_I2C_SDA); // ESP32-P4 (common board default) | ||||||||
| pinAssigner.assignPin(8, pin_I2C_SCL); | ||||||||
| #else | ||||||||
| pinAssigner.assignPin(21, pin_I2C_SDA); // Fallback | ||||||||
| pinAssigner.assignPin(22, pin_I2C_SCL); | ||||||||
| #endif | ||||||||
|
|
||||||||
| // trying to add more pins, but these pins not liked by esp32-d0-16MB ... 🚧 | ||||||||
| // pinAssigner.assignPin(4, pin_LED_02; | ||||||||
| // pinAssigner.assignPin(5, pin_LED_03; | ||||||||
|
|
@@ -609,6 +638,8 @@ class ModuleIO : public Module { | |||||||
| newState["modded"] = true; | ||||||||
| } else if (updatedItem.name == "usage") { | ||||||||
| newState["modded"] = true; | ||||||||
| } else if (updatedItem.name == "i2cFreq") { | ||||||||
| Wire.setClock(updatedItem.value.as<uint16_t>() * 1000); | ||||||||
|
coderabbitai[bot] marked this conversation as resolved.
Outdated
|
||||||||
| } | ||||||||
|
|
||||||||
| if (newState.size()) update(newState, ModuleState::update, _moduleName); // if changes made then update | ||||||||
|
|
@@ -701,6 +732,9 @@ class ModuleIO : public Module { | |||||||
| #endif // ethernet | ||||||||
|
|
||||||||
| #if FT_BATTERY | ||||||||
| pinVoltage = UINT8_MAX; | ||||||||
| pinCurrent = UINT8_MAX; | ||||||||
| pinBattery = UINT8_MAX; | ||||||||
| for (JsonObject pinObject : _state.data["pins"].as<JsonArray>()) { | ||||||||
| uint8_t usage = pinObject["usage"]; | ||||||||
| if (usage == pin_Voltage) { | ||||||||
|
|
@@ -790,7 +824,39 @@ class ModuleIO : public Module { | |||||||
| } | ||||||||
| #endif | ||||||||
| } | ||||||||
| } | ||||||||
|
|
||||||||
| pinI2CSDA = UINT8_MAX; | ||||||||
| pinI2CSCL = UINT8_MAX; | ||||||||
| for (JsonObject pinObject : _state.data["pins"].as<JsonArray>()) { | ||||||||
| uint8_t usage = pinObject["usage"]; | ||||||||
| if (usage == pin_I2C_SDA) { | ||||||||
| pinI2CSDA = pinObject["GPIO"]; | ||||||||
| EXT_LOGD(ML_TAG, "I2CSDA found %d", pinI2CSDA); | ||||||||
| } | ||||||||
| if (usage == pin_I2C_SCL) { | ||||||||
| pinI2CSCL = pinObject["GPIO"]; | ||||||||
| EXT_LOGD(ML_TAG, "I2CSCL found %d", pinI2CSCL); | ||||||||
| } | ||||||||
| } | ||||||||
|
|
||||||||
| if (pinI2CSCL != UINT8_MAX && pinI2CSDA != UINT8_MAX) { | ||||||||
| Wire.end(); // Clean up any previous I2C initialization | ||||||||
| delay(100); | ||||||||
|
coderabbitai[bot] marked this conversation as resolved.
Outdated
|
||||||||
| uint16_t frequency = _state.data["i2cFreq"]; | ||||||||
| if (Wire.begin(pinI2CSDA, pinI2CSCL, frequency * 1000)) { | ||||||||
| EXT_LOGI(ML_TAG, "initI2C Wire sda:%d scl:%d freq:%d kHz", pinI2CSDA, pinI2CSCL, frequency); | ||||||||
| // delay(200); // Give I2C bus time to stabilize | ||||||||
| // Wire.setClock(50000); // Explicitly set to 100kHz | ||||||||
| _state.data["I2CReady"] = true; | ||||||||
|
coderabbitai[bot] marked this conversation as resolved.
Outdated
|
||||||||
| updateDevices(); | ||||||||
| } else | ||||||||
| _state.data["I2CReady"] = false; | ||||||||
| EXT_LOGE(ML_TAG, "initI2C Wire failed"); | ||||||||
| } | ||||||||
|
coderabbitai[bot] marked this conversation as resolved.
|
||||||||
| } // readPins | ||||||||
|
|
||||||||
| uint8_t pinI2CSDA = UINT8_MAX; | ||||||||
| uint8_t pinI2CSCL = UINT8_MAX; | ||||||||
|
|
||||||||
| #if FT_BATTERY | ||||||||
| uint8_t pinVoltage = UINT8_MAX; | ||||||||
|
|
@@ -867,6 +933,32 @@ class ModuleIO : public Module { | |||||||
| #endif | ||||||||
| } | ||||||||
|
|
||||||||
| void updateDevices() { | ||||||||
| JsonDocument doc; | ||||||||
| doc["i2cBus"].to<JsonArray>(); | ||||||||
| JsonObject newState = doc.as<JsonObject>(); | ||||||||
|
|
||||||||
| EXT_LOGI(ML_TAG, "Scanning I2C bus..."); | ||||||||
| byte count = 0; | ||||||||
| for (byte i = 1; i < 127; i++) { | ||||||||
| Wire.beginTransmission(i); | ||||||||
| if (Wire.endTransmission() == 0) { | ||||||||
| JsonObject i2cDevice = newState["i2cBus"].as<JsonArray>().add<JsonObject>(); | ||||||||
| i2cDevice["address"] = i; | ||||||||
|
|
||||||||
| EXT_LOGI(ML_TAG, "Found I2C device at address 0x%02X", i); | ||||||||
| count++; | ||||||||
| } | ||||||||
| } | ||||||||
| EXT_LOGI(ML_TAG, "Found %d device(s)", count); | ||||||||
| JsonObject i2cDevice = newState["i2cBus"].as<JsonArray>().add<JsonObject>(); | ||||||||
| i2cDevice["address"] = 255; | ||||||||
|
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. Sentinel entry with address 255 pollutes the device list. A fake device at address 255 is appended after the real scan results. This is not a valid I2C address (7-bit range is 0–127) and will appear as a spurious device in the UI. If this is meant to ensure the Proposed fix: remove the sentinel EXT_LOGI(ML_TAG, "Found %d device(s)", count);
- JsonObject i2cDevice = newState["i2cBus"].as<JsonArray>().add<JsonObject>();
- i2cDevice["address"] = 255;📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||
|
|
||||||||
| doc["i2cFreq"] = Wire.getClock() / 1000; | ||||||||
|
|
||||||||
| update(newState, ModuleState::update, _moduleName); | ||||||||
|
coderabbitai[bot] marked this conversation as resolved.
Outdated
|
||||||||
| } | ||||||||
|
|
||||||||
| private: | ||||||||
| ESP32SvelteKit* _sveltekit; | ||||||||
| uint8_t current_board_id = UINT8_MAX; | ||||||||
|
|
||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -264,6 +264,9 @@ class NodeManager : public Module { | |
| if (nodeClass != nullptr) { | ||
| nodeClass->on = updatedItem.value.as<bool>(); // set nodeclass on/off | ||
| // EXT_LOGD(ML_TAG, " nodeclass 🔘:%d 🚥:%d 💎:%d", nodeClass->on, nodeClass->hasOnLayout(), nodeClass->hasModifier()); | ||
| xSemaphoreTake(*nodeClass->layerMutex, portMAX_DELAY); | ||
| nodeClass->onUpdate(updatedItem.oldValue, nodeState); // custom onUpdate for the node | ||
|
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. Inconsistent mutex handling and argument semantics for Two observations:
+ xSemaphoreTake(*nodeClass->layerMutex, portMAX_DELAY);
nodeClass->onUpdate(updatedItem.oldValue, nodeState); // custom onUpdate for the node
+ xSemaphoreGive(*nodeClass->layerMutex);
🤖 Prompt for AI Agents |
||
| xSemaphoreGive(*nodeClass->layerMutex); | ||
| nodeClass->requestMappings(); | ||
| } else | ||
| EXT_LOGW(ML_TAG, "Nodeclass %s not found", nodeState["name"].as<const char*>()); | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -344,6 +344,8 @@ static struct SharedData { | |
| size_t connectedClients; | ||
| size_t activeClients; | ||
| size_t clientListSize; | ||
|
|
||
| Coord3D gravity; | ||
|
Comment on lines
+347
to
+348
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.
As noted in the D_IMU.h review, the MPU6050 gravity vector contains float values in the range [–1.0, 1.0]. If 🤖 Prompt for AI Agents |
||
| } sharedData; | ||
|
|
||
| /** | ||
|
|
@@ -360,6 +362,7 @@ static struct SharedData { | |
| #include "MoonLight/Nodes/Drivers/D_FastLED.h" | ||
| #include "MoonLight/Nodes/Drivers/D_Hub75.h" | ||
| #include "MoonLight/Nodes/Drivers/D_Infrared.h" | ||
| #include "MoonLight/Nodes/Drivers/D_IMU.h" | ||
| #include "MoonLight/Nodes/Drivers/D_ParallelLEDDriver.h" | ||
| #include "MoonLight/Nodes/Drivers/D__Sandbox.h" | ||
| #include "MoonLight/Nodes/Effects/E_FastLED.h" | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -344,7 +344,12 @@ class FastLEDDriver : public DriverNode { | |
| // FastLED.setMaxPowerInMilliWatts(1000 * layerP.maxPower); // 5v, 2000mA, to protect usb while developing | ||
| } | ||
|
|
||
| ~FastLEDDriver() override { FastLED.reset(ResetFlags::CHANNELS); } | ||
| ~FastLEDDriver() override { | ||
| auto& events = FastLED.channelEvents(); | ||
| events.onChannelCreated.clear(); | ||
| events.onChannelEnqueued.clear(); | ||
| FastLED.reset(ResetFlags::CHANNELS); // global: ensure only one FastLEDDriver instance exists. If multiple driver nodes are possible, this destructor will tear down channels for all of them. If singleton is guaranteed by design, consider documenting that assumption at the class level. | ||
| } | ||
|
Comment on lines
+347
to
+353
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. 🧩 Analysis chain🏁 Script executed: #!/bin/bash
# First, examine the FastLEDDriver class definition to check for singleton enforcement
# (deleted copy constructor, private constructor, etc.)
grep -n "class FastLEDDriver" src/MoonLight/Nodes/Drivers/D_FastLED.hRepository: MoonModules/MoonLight Length of output: 109 🏁 Script executed: #!/bin/bash
# Check if there are explicit singleton guards or design patterns in the class
head -100 src/MoonLight/Nodes/Drivers/D_FastLED.h | tail -50Repository: MoonModules/MoonLight Length of output: 1977 🏁 Script executed: #!/bin/bash
# Look at the setup() method where listeners are added to understand the pattern
sed -n '60,100p' src/MoonLight/Nodes/Drivers/D_FastLED.hRepository: MoonModules/MoonLight Length of output: 1707 🏁 Script executed: #!/bin/bash
# Search for how many FastLEDDriver instances are created in the codebase
rg "FastLEDDriver" --type=cpp -B2 -A2 | head -50Repository: MoonModules/MoonLight Length of output: 2211 🏁 Script executed: #!/bin/bash
# Check the full destructor context and any comments about singleton design
sed -n '340,360p' src/MoonLight/Nodes/Drivers/D_FastLED.hRepository: MoonModules/MoonLight Length of output: 680
Lines 349–350 clear every subscriber on If a second Store the listener handles returned by 🤖 Prompt for AI Agents |
||
| }; | ||
|
|
||
| #endif | ||
Uh oh!
There was an error while loading. Please reload this page.