@@ -344,6 +344,71 @@ static const std::map<std::string, FnCreateI2CSensorDriver> I2cFactorySensor = {
344344 return new drvVl6180x (i2c, addr, mux_channel, driver_name);
345345 }}}; // /< I2C driver factory
346346
347+ static const std::unordered_map<uint16_t , std::vector<const char *>>
348+ map_address_to_drivers = {
349+ {0x0B , {" lc709203f" }},
350+ {0x12 , {" pmsa003i" }},
351+ {0x13 , {" vncl4020" }},
352+ {0x18 , {" ds2484" , " mcp9808" , " mprls" }},
353+ {0x19 , {" mcp9808" }},
354+ {0x1A , {" mcp9808" }},
355+ {0x1B , {" mcp9808" }},
356+ {0x1C , {" mcp9808" }},
357+ {0x1D , {" mcp9808" }},
358+ {0x1E , {" mcp9808" }},
359+ {0x1F , {" mcp9808" }},
360+ {0x23 , {" bh1750" }},
361+ {0x28 , {" pct2075" }},
362+ {0x29 ,
363+ {" ltr303" , " pct2075" , " tsl2591" , " veml7700" , " vl53l1x" , " vl53l4cd" ,
364+ " vl53l4cx" , " vl6180x" }},
365+ {0x2A , {" nau7802" }},
366+ {0x38 , {" aht20" , " max17048" }},
367+ {0x39 , {" tsl2591" }},
368+ {0x40 ,
369+ {" htu21d" , " htu31d" , " ina219" , " ina260" , " ms8607" , " si7021" ,
370+ " stemma_soil" }},
371+ {0x41 , {" htu31d" , " ina219" , " ina260" }},
372+ {0x44 , {" hdc302x" , " ina260" , " sht3x" , " sht4x" }},
373+ {0x45 , {" hdc302x" , " ina260" , " sht3x" }},
374+ {0x46 , {" hdc302x" }},
375+ {0x47 , {" hdc302x" }},
376+ {0x48 , {" adt7410" , " pct2075" , " tmp117" }},
377+ {0x49 , {" adt7410" , " pct2075" , " tmp117" , " tsl2591" }},
378+ {0x4A , {" adt7410" , " pct2075" , " tmp117" }},
379+ {0x4B , {" adt7410" , " pct2075" , " tmp117" }},
380+ {0x4C , {" pct2075" }},
381+ {0x4D , {" pct2075" }},
382+ {0x4E , {" pct2075" }},
383+ {0x4F , {" pct2075" }},
384+ {0x51 , {" vcnl4200" }},
385+ {0x52 , {" ens160" }},
386+ {0x53 , {" ens160" , " ltr390" }},
387+ {0x58 , {" sgp30" }},
388+ {0x59 , {" sgp40" }},
389+ {0x5C ,
390+ {" bh1750" , " lps22hb" , " lps25hb" , " lps28dfw" , " lps33hw" , " lps35hw" }},
391+ {0x5D , {" lps22hb" , " lps25hb" , " lps28dfw" , " lps33hw" , " lps35hw" }},
392+ {0x5F , {" hts2221" }},
393+ {0x60 , {" mpl115a2" , " vncl4040" }},
394+ {0x61 , {" scd30" }},
395+ {0x62 , {" scd40" }},
396+ {0x68 , {" mcp3421" }},
397+ {0x69 , {" sen55" }},
398+ {0x6B , {" sen66" }},
399+ {0x70 , {" pct2075" , " shtc3" }},
400+ {0x71 , {" pct2075" }},
401+ {0x72 , {" pct2075" }},
402+ {0x73 , {" pct2075" }},
403+ {0x74 , {" pct2075" }},
404+ {0x75 , {" pct2075" }},
405+ {0x76 ,
406+ {" bme280" , " bme680" , " bmp280" , " bmp388" , " bmp390" , " dps310" , " ms8607" ,
407+ " pct2075" }},
408+ {0x77 ,
409+ {" bme280" , " bme680" , " bmp280" , " bmp388" , " bmp390" , " dps310" ,
410+ " pct2075" }}}; // /< I2C address to driver map
411+
347412/* !
348413 @brief Lambda function to create a drvOutputBase instance
349414 @param i2c
@@ -438,6 +503,26 @@ drvOutputBase *CreateI2cOutputDrv(const char *driver_name, TwoWire *i2c,
438503 return it->second (i2c, addr, i2c_mux_channel, driver_name);
439504}
440505
506+ /* **********************************************************************/
507+ /* !
508+ @brief Obtains possible candidate drivers for a given I2C address.
509+ @param addr
510+ The desired I2C address.
511+ @returns A vector of pointers to candidate drivers.
512+ */
513+ /* **********************************************************************/
514+ std::vector<const char *> GetDriversForAddress (uint16_t addr) {
515+ std::vector<const char *> candidates;
516+ std::unordered_map<uint16_t , std::vector<const char *>>::const_iterator
517+ candidate = map_address_to_drivers.find (addr);
518+
519+ if (candidate != map_address_to_drivers.end ()) {
520+ candidates = candidate->second ;
521+ }
522+
523+ return candidates;
524+ }
525+
441526/* !
442527 @brief I2cController constructor
443528*/
@@ -882,6 +967,12 @@ bool I2cController::Handle_I2cDeviceAddOrReplace(pb_istream_t *stream) {
882967
883968 // Is this a i2c GPS?
884969 bool is_gps = _i2c_model->GetI2cDeviceAddOrReplaceMsg ()->is_gps ;
970+ WS_DEBUG_PRINT (" [i2c] Device name: " );
971+ WS_DEBUG_PRINTLN (device_name);
972+ WS_DEBUG_PRINT (" [i2c] Device address: 0x" );
973+ WS_DEBUG_PRINTLN (device_descriptor.i2c_device_address , HEX);
974+ WS_DEBUG_PRINT (" [i2c] Is GPS? " );
975+ WS_DEBUG_PRINTLN (is_gps ? " Yes" : " No" );
885976
886977 // TODO [Online]: Handle Replace messages by implementing the Remove handler
887978 // first...then proceed to adding a new device
@@ -956,7 +1047,58 @@ bool I2cController::Handle_I2cDeviceAddOrReplace(pb_istream_t *stream) {
9561047 drvOutputBase *drv_out = nullptr ;
9571048 GPSController *drv_uart_gps = nullptr ;
9581049
959- if (is_output) {
1050+ if (strcmp (device_name, " UNKNOWN_SCAN" ) == 0 ) {
1051+ WS_DEBUG_PRINTLN (" Attempting to autoconfig device found in scan..." );
1052+ if (device_descriptor.i2c_device_address == 0x68 ||
1053+ device_descriptor.i2c_device_address == 0x70 ) {
1054+ WS_DEBUG_PRINTLN (" [i2c] Device address is shared with RTC/MUX, can not "
1055+ " auto-init, skipping!" );
1056+ return true ;
1057+ }
1058+ // Get all possible driver candidates for this address
1059+ WS_DEBUG_PRINT (" [i2c] Obtaining driver candidates @ 0x" );
1060+ WS_DEBUG_PRINTLN (device_descriptor.i2c_device_address , HEX);
1061+
1062+ // Probe each candidate to see if it communicates
1063+ bool did_find_driver = false ;
1064+ for (const char *driverName :
1065+ GetDriversForAddress (device_descriptor.i2c_device_address )) {
1066+ WS_DEBUG_PRINT (" [i2c] Attempting to initialize candidate: " );
1067+ WS_DEBUG_PRINTLN (driverName);
1068+ drv = CreateI2cSensorDrv (
1069+ driverName, bus, device_descriptor.i2c_device_address ,
1070+ device_descriptor.i2c_mux_channel , device_status);
1071+ // Probe the driver to check if it communicates its init. sequence
1072+ if (!drv->begin ()) {
1073+ WS_DEBUG_PRINTLN (" [i2c] Failed to initialize candidate: " );
1074+ WS_DEBUG_PRINTLN (driverName);
1075+ delete drv;
1076+ drv = nullptr ;
1077+ } else {
1078+ WS_DEBUG_PRINT (" [i2c] Successfully initialized candidate: " );
1079+ WS_DEBUG_PRINTLN (driverName);
1080+ // set device_name to driverName
1081+ strcpy (device_name, driverName);
1082+ // Use the "default" types from the sensor driver
1083+ drv->EnableSensorReads (true );
1084+ drv->SetSensorPeriod (DEFAULT_SENSOR_PERIOD);
1085+ #ifndef OFFLINE_MODE_WOKWI
1086+ WsV2._fileSystemV2 ->AddI2cDeviceToFileConfig (
1087+ device_descriptor.i2c_device_address , driverName,
1088+ drv->GetSensorTypeStrings (), drv->GetNumSensorTypes ());
1089+ #endif
1090+ did_find_driver = true ;
1091+ _i2c_drivers.push_back (drv);
1092+ return true ;
1093+ }
1094+ }
1095+ if (!did_find_driver) {
1096+ WS_DEBUG_PRINTLN (" [i2c] ERROR - Candidates exhausted, driver not found!" );
1097+ return true ; // dont cause an error in the app
1098+ }
1099+ }
1100+
1101+ else if (is_output) {
9601102 WS_DEBUG_PRINT (" [i2c] Creating an I2C output driver..." );
9611103 drv_out = CreateI2cOutputDrv (
9621104 device_name, bus, device_descriptor.i2c_device_address ,
@@ -1023,11 +1165,12 @@ bool I2cController::Handle_I2cDeviceAddOrReplace(pb_istream_t *stream) {
10231165 }
10241166 WS_DEBUG_PRINTLN (" [i2c] Set driver to use Alt I2C bus" );
10251167 }
1026- // Configure the driver
10271168
1169+ // Configure the driver
10281170 if (!is_output) {
10291171 // Configure Input-driver settings
10301172 drv->EnableSensorReads (
1173+ false ,
10311174 _i2c_model->GetI2cDeviceAddOrReplaceMsg ()->i2c_device_sensor_types ,
10321175 _i2c_model->GetI2cDeviceAddOrReplaceMsg ()
10331176 ->i2c_device_sensor_types_count );
0 commit comments