1616
1717/* ******************************************************************************/
1818/* !
19- @brief lambda function to create a drvBase driver instance
19+ @brief Lambda function to create a drvBase driver instance
2020 @param i2c
21- The I2C interface.
21+ The desired I2C interface.
2222 @param addr
23- 7-bit device address.
23+ The desired i2c device address.
2424 @param mux_channel
25- The I2C multiplexer channel.
25+ The desired I2C multiplexer channel.
2626 @param driver_name
27- The name of the driver.
27+ The i2c driver's name .
2828*/
2929/* ******************************************************************************/
3030using FnCreateI2CDriver =
3131 std::function<drvBase *(TwoWire *, uint16_t , uint32_t , const char *)>;
3232
33- // Map of sensor names to lambda functions that create an I2C device driver
33+ // Factory for creating a new I2C drivers
34+ // NOTE: When you add a new driver, make sure to add it to the factory!
3435static const std::map<std::string, FnCreateI2CDriver> I2cFactory = {
3536 {" bme280" ,
3637 [](TwoWire *i2c, uint16_t addr, uint32_t mux_channel,
@@ -359,7 +360,7 @@ static const std::map<std::string, FnCreateI2CDriver> I2cFactory = {
359360 @returns A pointer to the I2C driver.
360361*/
361362/* **********************************************************************/
362- drvBase *createI2CDriverByName (const char *driver_name, TwoWire *i2c,
363+ drvBase *CreateI2CDriverByName (const char *driver_name, TwoWire *i2c,
363364 uint16_t addr, uint32_t i2c_mux_channel,
364365 wippersnapper_i2c_I2cDeviceStatus &status) {
365366 auto it = I2cFactory.find (driver_name);
@@ -368,8 +369,8 @@ drvBase *createI2CDriverByName(const char *driver_name, TwoWire *i2c,
368369 wippersnapper_i2c_I2cDeviceStatus_I2C_DEVICE_STATUS_FAIL_UNSUPPORTED_SENSOR;
369370 return nullptr ;
370371 }
372+
371373 status = wippersnapper_i2c_I2cDeviceStatus_I2C_DEVICE_STATUS_SUCCESS;
372- // Call the lambda to create the driver
373374 return it->second (i2c, addr, i2c_mux_channel, driver_name);
374375}
375376
@@ -381,9 +382,9 @@ drvBase *createI2CDriverByName(const char *driver_name, TwoWire *i2c,
381382I2cController::I2cController () {
382383 _i2c_bus_alt = nullptr ;
383384 _i2c_model = new I2cModel ();
384- // Initialize a default I2C bus
385+ // Initialize the default I2C bus
385386 _i2c_bus_default = new I2cHardware ();
386- _i2c_bus_default->InitBus (true );
387+ _i2c_bus_default->InitBus (is_default = true );
387388}
388389
389390/* **********************************************************************/
@@ -401,20 +402,22 @@ I2cController::~I2cController() {
401402
402403/* ************************************************************************/
403404/* !
404- @brief Returns the status of the I2C bus
405+ @brief Returns if the I2C bus has been created successfully.
405406 @param is_alt_bus
406407 True if the alt. I2C bus is being queried, False otherwise.
407- @returns True if the I2C bus is operational , False otherwise.
408+ @returns True if the I2C bus has already been created , False otherwise.
408409*/
409410/* ************************************************************************/
410411bool I2cController::IsBusStatusOK (bool is_alt_bus) {
412+ bool is_ok = false ;
411413 if (is_alt_bus) {
412- return (_i2c_bus_alt->GetBusStatus () ==
413- wippersnapper_i2c_I2cBusStatus_I2C_BUS_STATUS_SUCCESS);
414+ is_ok = (_i2c_bus_alt->GetBusStatus () ==
415+ wippersnapper_i2c_I2cBusStatus_I2C_BUS_STATUS_SUCCESS);
416+ } else {
417+ is_ok = (_i2c_bus_default->GetBusStatus () ==
418+ wippersnapper_i2c_I2cBusStatus_I2C_BUS_STATUS_SUCCESS);
414419 }
415-
416- return (_i2c_bus_default->GetBusStatus () ==
417- wippersnapper_i2c_I2cBusStatus_I2C_BUS_STATUS_SUCCESS);
420+ return is_ok;
418421}
419422
420423/* **********************************************************************/
@@ -468,12 +471,50 @@ bool I2cController::Handle_I2cDeviceRemove(pb_istream_t *stream) {
468471 return false ;
469472 }
470473
471- // TODO: Implement the rest of this function
474+ // TODO [Online] : Implement the rest of this function
472475 WS_DEBUG_PRINTLN (" [i2c] I2cDeviceRemove message not yet implemented!" );
473476
474477 return true ;
475478}
476479
480+ /* **********************************************************************/
481+ /* !
482+ @brief Attempts to initialize a MUX on the bus.
483+ @param name
484+ The name of the MUX to initialize, used to set number
485+ of channels.
486+ @param address
487+ The MUX's I2C address.
488+ @param is_alt_bus
489+ True if the alternative I2C bus is being used, False
490+ otherwise.
491+ @returns True if the MUX was successfully initialized, False
492+ otherwise.
493+ */
494+ /* **********************************************************************/
495+ bool I2cController::InitMux (const char *name, uint32_t address,
496+ bool is_alt_bus) {
497+ if ((strcmp (name, " pca9546" ) != 0 ) || (strcmp (name, " pca9548" ) != 0 ))
498+ return false ; // bail out, mux not specified as a device_name
499+
500+ WS_DEBUG_PRINTLN (" [i2c] Creating new MUX..." );
501+ if (is_alt_bus) {
502+ if (!_i2c_bus_alt->HasMux ()) {
503+ if (!_i2c_bus_alt->AddMuxToBus (address, name)) {
504+ return false ;
505+ }
506+ }
507+ } else {
508+ if (!_i2c_bus_default->HasMux ()) {
509+ if (!_i2c_bus_default->AddMuxToBus (address, name)) {
510+ return false ;
511+ }
512+ }
513+ }
514+ // TODO [Online]: Publish back out to IO here!
515+ return true ;
516+ }
517+
477518/* **********************************************************************/
478519/* !
479520 @brief Implements handling for a I2cDeviceAddOrReplace message
@@ -493,16 +534,18 @@ bool I2cController::Handle_I2cDeviceAddOrReplace(pb_istream_t *stream) {
493534 " [i2c] ERROR: Unable to decode I2cDeviceAddOrReplace message!" );
494535 return false ;
495536 }
537+
496538 wippersnapper_i2c_I2cDeviceStatus device_status =
497539 wippersnapper_i2c_I2cDeviceStatus_I2C_DEVICE_STATUS_UNSPECIFIED;
498- wippersnapper_i2c_I2cDeviceDescriptor device_descriptor =
499- _i2c_model->GetI2cDeviceAddOrReplaceMsg ()->i2c_device_description ;
540+ // Parse out device name and descriptor
500541 char device_name[15 ];
501542 strcpy (device_name,
502543 _i2c_model->GetI2cDeviceAddOrReplaceMsg ()->i2c_device_name );
544+ wippersnapper_i2c_I2cDeviceDescriptor device_descriptor =
545+ _i2c_model->GetI2cDeviceAddOrReplaceMsg ()->i2c_device_description ;
503546
504- // TODO: Handle Replace messages by implementing a Remove handler first...then
505- // proceed to adding a new device
547+ // TODO [Online] : Handle Replace messages by implementing the Remove handler
548+ // first...then proceed to adding a new device
506549
507550 // Does the device's descriptor specify a different i2c bus?
508551 if (strcmp (device_descriptor.i2c_bus_scl , " default" ) != 0 ) {
@@ -518,68 +561,37 @@ bool I2cController::Handle_I2cDeviceAddOrReplace(pb_istream_t *stream) {
518561
519562 // Before we do anything on the bus - was the bus initialized correctly?
520563 if (!IsBusStatusOK (use_alt_bus)) {
521- WsV2.haltErrorV2 (" [i2c] I2C bus is stuck or not operational, reset the board!" , WS_LED_STATUS_ERROR_RUNTIME, false );
522- if (!PublishI2cDeviceAddedorReplaced (device_descriptor, device_status))
564+ WS_DEBUG_PRINTLN (
565+ " [i2c] I2C bus is stuck or not operational, reset the board!" );
566+ if (WsV2._sdCardV2 ->isModeOffline ()) {
567+ WsV2.haltErrorV2 (" " , WS_LED_STATUS_ERROR_RUNTIME,
568+ false ); // doesn't return, halts
569+ }
570+ if (!PublishI2cDeviceAddedorReplaced (device_descriptor, device_status)) {
571+ WS_DEBUG_PRINTLN (" [i2c] ERROR: Unable to publish message to IO!" );
523572 return false ;
573+ }
524574 return true ;
525575 }
526576
527- // Mux case #1 - We are creating a mux via I2cDeviceAddorReplace message
528- if ((strcmp (device_name, " pca9546" ) == 0 ) ||
529- (strcmp (device_name, " pca9548" ) == 0 )) {
530- WS_DEBUG_PRINTLN (" [i2c] Creating a new MUX driver obj" );
531- if (use_alt_bus) {
532- if (!_i2c_bus_alt->HasMux ()) {
533- WS_DEBUG_PRINT (" [i2c] Adding MUX to alternate bus..." );
534- _i2c_bus_alt->AddMuxToBus (device_descriptor.i2c_mux_address ,
535- device_name);
536- } else {
537- WsV2.haltErrorV2 (" [i2c] Unable to initialize I2C MUX!" , WS_LED_STATUS_ERROR_RUNTIME, false );
538- }
539- } else {
540- if (!_i2c_bus_default->HasMux ()) {
541- WS_DEBUG_PRINT (" [i2c] Adding MUX to default bus..." );
542- _i2c_bus_default->AddMuxToBus (device_descriptor.i2c_mux_address ,
543- device_name);
544- } else {
545- WsV2.haltErrorV2 (" [i2c] Unable to initialize I2C MUX!" , WS_LED_STATUS_ERROR_RUNTIME, false );
546- }
547- }
548- // TODO: Publish back out to IO instead of blindly returning true
549- return true ;
577+ // I2C MUX (Case #1) - We are creating an I2C mux via the
578+ // I2cDeviceAddorReplace message
579+ if (!InitMux (device_name, device_descriptor.i2c_mux_address , use_alt_bus)) {
580+ // TODO [Online]: Publish back out to IO here!
581+ WsV2.haltErrorV2 (" [i2c] Failed to initialize MUX driver!" ,
582+ WS_LED_STATUS_ERROR_RUNTIME, false );
550583 }
551584
552585 // Mux case #2 - We are creating a new driver that USES THE MUX via
553586 // I2cDeviceAddorReplace message
554587 if (device_descriptor.i2c_mux_address != 0x00 ) {
555- uint32_t mux_channel = device_descriptor.i2c_mux_channel ;
556- if (use_alt_bus) {
557- if (_i2c_bus_alt->HasMux ()) {
558- _i2c_bus_alt->SelectMuxChannel (mux_channel);
559- WS_DEBUG_PRINT (" [i2c] Selected MUX CH: " );
560- WS_DEBUG_PRINTLN (mux_channel);
561- did_set_mux_ch = true ;
562- } else {
563- WsV2.haltErrorV2 (" [i2c] Device requires a MUX but MUX not present within config.json!" , WS_LED_STATUS_ERROR_RUNTIME, false );
564- // TODO: Online mode needs the below implemented
565- // device_status = wippersnapper_i2c_I2cDeviceStatus_I2C_DEVICE_STATUS_FAIL_INIT;
566- // PublishI2cDeviceAddedorReplaced(device_descriptor, device_status);
567- return false ;
568- }
569- } else {
570- if (_i2c_bus_default->HasMux ()) {
571- _i2c_bus_default->SelectMuxChannel (mux_channel);
572- WS_DEBUG_PRINT (" [i2c] Selected MUX CH: " );
573- WS_DEBUG_PRINTLN (mux_channel);
574- did_set_mux_ch = true ;
575- } else {
576- WsV2.haltErrorV2 (" [i2c] Device requires a MUX but MUX not present within config.json!" , WS_LED_STATUS_ERROR_RUNTIME, false );
577- // TODO: Online mode needs the below implemented
578- // device_status = wippersnapper_i2c_I2cDeviceStatus_I2C_DEVICE_STATUS_FAIL_INIT;
579- // PublishI2cDeviceAddedorReplaced(device_descriptor, device_status);
580- return false ;
581- }
588+ if (!_i2c_bus_alt->HasMux () || !_i2c_bus_default->HasMux ()) {
589+ WsV2.haltErrorV2 (" [i2c] Device requires a MUX but MUX not present "
590+ " within config.json!" ,
591+ WS_LED_STATUS_ERROR_RUNTIME, false );
582592 }
593+ ConfigureMuxChannel (device_descriptor.i2c_mux_channel , use_alt_bus);
594+ did_set_mux_ch = true ;
583595 }
584596
585597 WS_DEBUG_PRINTLN (" Creating a new I2C driver obj" );
@@ -590,7 +602,7 @@ bool I2cController::Handle_I2cDeviceAddOrReplace(pb_istream_t *stream) {
590602 bus = _i2c_bus_default->GetBus ();
591603 }
592604
593- drvBase *drv = createI2CDriverByName (
605+ drvBase *drv = CreateI2CDriverByName (
594606 device_name, bus, device_descriptor.i2c_device_address ,
595607 device_descriptor.i2c_mux_channel , device_status);
596608
@@ -677,11 +689,11 @@ bool I2cController::Handle_I2cDeviceAddOrReplace(pb_istream_t *stream) {
677689/* *******************************************************************************/
678690void I2cController::ConfigureMuxChannel (uint32_t mux_channel, bool is_alt_bus) {
679691 if (is_alt_bus) {
680- _i2c_bus_alt->ClearMuxChannel (); // sanity-check, may not be required
692+ _i2c_bus_alt->ClearMuxChannel (); // sanity-check
681693 _i2c_bus_alt->SelectMuxChannel (mux_channel);
682694 return ;
683695 }
684- _i2c_bus_default->ClearMuxChannel (); // sanity-check, may not be required
696+ _i2c_bus_default->ClearMuxChannel (); // sanity-check
685697 _i2c_bus_default->SelectMuxChannel (mux_channel);
686698}
687699
0 commit comments