diff --git a/usermods/mpu6050_imu/usermod_mpu6050_imu.h b/usermods/mpu6050_imu/usermod_mpu6050_imu.h index 897f03cd..18f7688e 100644 --- a/usermods/mpu6050_imu/usermod_mpu6050_imu.h +++ b/usermods/mpu6050_imu/usermod_mpu6050_imu.h @@ -94,17 +94,23 @@ class MPU6050Driver : public Usermod { private: MPU6050 mpu; bool enabled = true; + bool initDone = false; unsigned long lastUMRun = millis(); // MPU control/status vars - bool dmpReady = false; // set true if DMP init was successful uint8_t mpuIntStatus; // holds actual interrupt status byte from MPU uint8_t devStatus; // return status after each device operation (0 = success, !0 = error) uint16_t packetSize; // expected DMP packet size (default is 42 bytes) uint16_t fifoCount; // count of all bytes currently in FIFO uint8_t fifoBuffer[64]; // FIFO storage buffer + // strings to reduce flash memory usage (used more than twice) + static const char _name[]; + static const char _enabled[]; + static const char _INT_pin[]; + public: + bool dmpReady = false; // set true if DMP init was successful // WLEDMM expose this info in public interface // orientation/motion vars Quaternion qat; // [w, x, y, z] quaternion container VectorInt16 aa; // [x, y, z] accel sensor measurements @@ -123,6 +129,10 @@ class MPU6050Driver : public Usermod { void setup() { // WLEDMM begin + if (!enabled) { + dmpReady = false; + return; + } USER_PRINTLN(F("mpu setup")); PinManagerPinType pins[2] = { { i2c_scl, true }, { i2c_sda, true } }; if ((i2c_scl < 0) || (i2c_sda < 0)) { @@ -171,16 +181,26 @@ class MPU6050Driver : public Usermod { // initialize device DEBUG_PRINT_IMULN(F("Initializing I2C devices...")); // WLEDMM begin - if (!pinManager.allocatePin(INTERRUPT_PIN, false, PinOwner::UM_Unspecified)) + if ((INTERRUPT_PIN < 0) || (!pinManager.isPinINT(INTERRUPT_PIN))) { + //enabled = false; + USER_PRINTF("mpu6050: warning - interrupt GPIO %d does not support interrupts.\n", INTERRUPT_PIN); + //INTERRUPT_PIN = -1; + //return; + } + if ((INTERRUPT_PIN >= 0) && (pinManager.getPinOwner(INTERRUPT_PIN) != PinOwner::UM_IMU) // only allocate pin if we don't ownn it already + && !pinManager.allocatePin(INTERRUPT_PIN, false, PinOwner::UM_IMU)) { //enabled = false; USER_PRINTF("mpu6050: warning - failed to allocate interrupt GPIO %d\n", INTERRUPT_PIN); + //INTERRUPT_PIN = -1; //return; } // WLEDMM end mpu.initialize(); - pinMode(INTERRUPT_PIN, INPUT); + if (INTERRUPT_PIN >= 0) { // WLEDMM only if pin is valid + pinMode(INTERRUPT_PIN, INPUT); + } // verify connection DEBUG_PRINT_IMULN(F("Testing device connections...")); @@ -214,11 +234,13 @@ class MPU6050Driver : public Usermod { DEBUG_PRINT_IMULN(F("Enabling DMP...")); mpu.setDMPEnabled(true); - // enable Arduino interrupt detection - DEBUG_PRINT_IMU(F("Enabling interrupt detection (Arduino external interrupt ")); - DEBUG_PRINT_IMU(digitalPinToInterrupt(INTERRUPT_PIN)); - DEBUG_PRINT_IMULN(F(")...")); - attachInterrupt(digitalPinToInterrupt(INTERRUPT_PIN), dmpDataReady, RISING); + if (INTERRUPT_PIN >= 0) { + // enable Arduino interrupt detection + DEBUG_PRINT_IMU(F("Enabling interrupt detection (Arduino external interrupt ")); + DEBUG_PRINT_IMU(digitalPinToInterrupt(INTERRUPT_PIN)); + DEBUG_PRINT_IMULN(F(")...")); + attachInterrupt(digitalPinToInterrupt(INTERRUPT_PIN), dmpDataReady, RISING); + } mpuIntStatus = mpu.getIntStatus(); // set our DMP Ready flag so the main loop() function knows it's okay to use it @@ -235,7 +257,9 @@ class MPU6050Driver : public Usermod { DEBUG_PRINT(F("DMP Initialization failed (code ")); DEBUG_PRINT(devStatus); DEBUG_PRINTLN(")"); + dmpReady = false; } + initDone = true; } void connected() { @@ -244,6 +268,7 @@ class MPU6050Driver : public Usermod { void loop() { // if programming failed, don't try to do anything + if (!initDone) return; if (!enabled || (strip.isUpdating() && (millis() - lastUMRun < 2))) return; // be nice, but not too nice lastUMRun = millis(); // update time keeping @@ -265,6 +290,8 @@ class MPU6050Driver : public Usermod { void addToJsonInfo(JsonObject& root) { + if (!initDone) return; + if (!enabled && !dmpReady) return; // WLEDMM no info when usermod disabled JsonObject user = root["u"]; if (user.isNull()) user = root.createNestedObject("u"); @@ -328,29 +355,67 @@ class MPU6050Driver : public Usermod { //{ //} - // void addToConfig(JsonObject& root) - // { - // JsonObject top = root.createNestedObject("MPU6050"); - // top[FPSTR("enabled")] = enabled; + void addToConfig(JsonObject& root) + { + JsonObject top = root.createNestedObject(FPSTR(_name)); + top[FPSTR(_enabled)] = enabled; + //JsonObject interruptPin = top.createNestedObject(FPSTR(_INT_pin)); + //interruptPin["pin"] = INTERRUPT_PIN; + DEBUG_PRINTLN(F("MPU6050 IMU config saved.")); + } - // JsonObject interruptPin = top.createNestedObject(FPSTR("interruptPin")); - // interruptPin["pin"] = interruptPin; - // } + //WLEDMM: add appendConfigData + void appendConfigData() + { + oappend(SET_F("addHB('MPU6050 Motion Sensor (IMU)');")); + /* + #ifdef MPU6050_INT_GPIO + oappend(SET_F("xOpt('mpu6050-IMU:interrupt_pin',0,' ⎌',")); oappendi(MPU6050_INT_GPIO); oappend(");"); + #endif + //WLEDMM add errorMessage to um settings + if (strcmp(errorMessage, "") != 0) { + oappend(SET_F("addInfo('errorMessage', 0, 'error: ")); oappend(errorMessage); oappend("! Correct and reboot');"); + } + */ + } - // bool readFromConfig(JsonObject& root) - // { - // JsonObject top = root[FPSTR("MPU6050")]; - // bool configComplete = !top.isNull(); + bool readFromConfig(JsonObject& root) + { + JsonObject top = root[FPSTR(_name)]; - // configComplete &= getJsonValue(top[FPSTR("enabled")], enabled); - // configComplete &= getJsonValue(top[FPSTR("interruptPin")]["pin"], interruptPin); + if (top.isNull()) { + DEBUG_PRINT(FPSTR(_name)); + DEBUG_PRINTLN(F(": No config found. (Using defaults.)")); + return false; + } - // return configComplete; - // } + bool configComplete = !top.isNull(); + configComplete &= getJsonValue(top[FPSTR(_enabled)], enabled); + //configComplete &= getJsonValue(top[FPSTR(_INT_pin)]["pin"], INTERRUPT_PIN); + + DEBUG_PRINT(FPSTR(_name)); + if (!initDone) { + // first run: reading from cfg.json + DEBUG_PRINTLN(F(" config loaded.")); + } else { + DEBUG_PRINTLN(F(" config (re)loaded.")); + if (enabled || dmpReady) setup(); // re-run setup if user has checked "enabled" + if (!enabled) dmpReady = false; // not enabled inplies "no DMP data ready" + } + + return configComplete; + // use "return !top["newestParameter"].isNull();" when updating Usermod with new features + //return !top[FPSTR(_INT_pin)].isNull(); + } uint16_t getId() { return USERMOD_ID_IMU; } -}; \ No newline at end of file +}; + +// strings to reduce flash memory usage (used more than twice) +const char MPU6050Driver::_name[] PROGMEM = "mpu6050-IMU"; +const char MPU6050Driver::_enabled[] PROGMEM = "enabled"; +const char MPU6050Driver::_INT_pin[] PROGMEM = "interrupt_pin"; diff --git a/usermods/usermod_v2_games/usermod_v2_games.h b/usermods/usermod_v2_games/usermod_v2_games.h index 5256f5c5..0c23ce59 100644 --- a/usermods/usermod_v2_games/usermod_v2_games.h +++ b/usermods/usermod_v2_games/usermod_v2_games.h @@ -183,7 +183,7 @@ uint16_t mode_IMUTest(void) { uint8_t y = 0; - if (IMU != nullptr) { + if ((IMU != nullptr) && (IMU->dmpReady)) { SEGMENT.setPixelColorXY(SEGMENT.virtualWidth() * (IMU->aa.x+INT16_MAX)/(2*INT16_MAX), y+=1, BLUE); SEGMENT.setPixelColorXY(SEGMENT.virtualWidth() * (IMU->aa.y+INT16_MAX)/(2*INT16_MAX), y+=1, BLUE); SEGMENT.setPixelColorXY(SEGMENT.virtualWidth() * (IMU->aa.z+INT16_MAX)/(2*INT16_MAX), y+=1, BLUE); @@ -280,7 +280,7 @@ uint16_t mode_3DIMUCube(void) { float roll = 0; #ifdef USERMOD_MPU6050_IMU - if (IMU != nullptr) { + if ((IMU != nullptr) && (IMU->dmpReady)) { yaw = -IMU->ypr[0]; pitch = IMU->ypr[1]; roll = IMU->ypr[2]; diff --git a/wled00/pin_manager.cpp b/wled00/pin_manager.cpp index 3bc423f0..b5822455 100644 --- a/wled00/pin_manager.cpp +++ b/wled00/pin_manager.cpp @@ -49,6 +49,7 @@ String PinManagerClass::getOwnerText(PinOwner tag) { case PinOwner::UM_Audioreactive : return(F("AudioReactive (UM)")); break; // audioreative usermod - analog or digital audio input case PinOwner::UM_Temperature : return(F("Temperature (UM)")); break; // "usermod_temperature.h" case PinOwner::UM_PIR : return(F("PIR (UM)")); break; // "usermod_PIR_sensor_switch.h" + case PinOwner::UM_IMU : return(F("IMU mpu6050 (UM)")); break; // "usermod_mpu6050_imu.h" case PinOwner::UM_FourLineDisplay : return(F("4Line Display (UM)")); break; // "usermod_v2_four_line_display.h -- May use "standard" HW_I2C pins case PinOwner::UM_RotaryEncoderUI : return(F("Rotary Enc. (UM)")); break; // "usermod_v2_rotary_encoder_ui.h" case PinOwner::UM_MultiRelay : return(F("Multi Relay (UM)")); break; // "usermod_multi_relay.h" diff --git a/wled00/pin_manager.h b/wled00/pin_manager.h index e3f2011e..a3bdba5f 100644 --- a/wled00/pin_manager.h +++ b/wled00/pin_manager.h @@ -41,7 +41,7 @@ enum struct PinOwner : uint8_t { UM_Temperature = USERMOD_ID_TEMPERATURE, // 0x03 // Usermod "usermod_temperature.h" // #define USERMOD_ID_FIXNETSERVICES // 0x04 // Usermod "usermod_Fix_unreachable_netservices.h" -- Does not allocate pins UM_PIR = USERMOD_ID_PIRSWITCH, // 0x05 // Usermod "usermod_PIR_sensor_switch.h" - // #define USERMOD_ID_IMU // 0x06 // Usermod "usermod_mpu6050_imu.h" -- Uses "standard" HW_I2C pins + UM_IMU = USERMOD_ID_IMU, // 0x06 // Usermod "usermod_mpu6050_imu.h" -- Uses "standard" HW_I2C pins UM_FourLineDisplay = USERMOD_ID_FOUR_LINE_DISP, // 0x07 // Usermod "usermod_v2_four_line_display.h -- May use "standard" HW_I2C pins UM_RotaryEncoderUI = USERMOD_ID_ROTARY_ENC_UI, // 0x08 // Usermod "usermod_v2_rotary_encoder_ui.h" // #define USERMOD_ID_AUTO_SAVE // 0x09 // Usermod "usermod_v2_auto_save.h" -- Does not allocate pins diff --git a/wled00/wled.h b/wled00/wled.h index 24e71a5d..1e8d81e9 100644 --- a/wled00/wled.h +++ b/wled00/wled.h @@ -8,7 +8,7 @@ */ // version code in format yymmddb (b = daily build) -#define VERSION 2303130 +#define VERSION 2303141 //uncomment this if you have a "my_config.h" file you'd like to use //#define WLED_USE_MY_CONFIG