Skip to content

Commit a756f0f

Browse files
committed
Refactor mux handling within handleI2cDeviceAddOrReplace
1 parent 71aa594 commit a756f0f

File tree

4 files changed

+102
-129
lines changed

4 files changed

+102
-129
lines changed

src/components/i2c/controller.cpp

Lines changed: 89 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -16,21 +16,22 @@
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
/*******************************************************************************/
3030
using 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!
3435
static 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,
381382
I2cController::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
/*************************************************************************/
410411
bool 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
/********************************************************************************/
678690
void 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

src/components/i2c/controller.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ class I2cController {
8484
void update();
8585
// Routing //
8686
bool Handle_I2cDeviceAddOrReplace(pb_istream_t *stream);
87-
// TODO: These are for Online mode
87+
// TODO [Online]: These are for Online mode and not yet implemented
8888
bool Handle_I2cDeviceRemove(pb_istream_t *stream);
8989
// bool Handle_I2cBusScan(pb_istream_t *stream);
9090
// Publishing //
@@ -93,6 +93,7 @@ class I2cController {
9393
const wippersnapper_i2c_I2cDeviceStatus &device_status);
9494
// Helpers //
9595
bool IsBusStatusOK(bool is_alt_bus);
96+
bool InitMux(const char *name, uint32_t address, bool is_alt_bus);
9697
void ConfigureMuxChannel(uint32_t mux_channel, bool is_alt_bus);
9798
private:
9899
I2cModel *_i2c_model; ///< Pointer to an I2C model object

src/components/i2c/hardware.cpp

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -159,8 +159,6 @@ bool I2cHardware::AddMuxToBus(uint32_t address_register, const char *name) {
159159
} else if (strcmp(name, "pca9548") == 0) {
160160
_mux_max_channels = 4; // PCA9548 supports 4 channels
161161
} else {
162-
WS_DEBUG_PRINTLN(
163-
"ERROR: No mux type found"); // DEBUG ONLY, REMOVE FOR PROD!
164162
return false;
165163
}
166164
_mux_address_register = address_register;

0 commit comments

Comments
 (0)