Associate driver with address, writeback to file

This commit is contained in:
brentru 2025-03-25 10:52:55 -04:00
parent b7784dfe49
commit f13a706d93
6 changed files with 189 additions and 88 deletions

View file

@ -0,0 +1,19 @@
# 1 "/var/folders/ff/dmzflvf52tq9kzvt6g8jglxw0000gn/T/tmpjqartfsv"
#include <Arduino.h>
# 1 "/Users/brentrubell/Documents/Arduino/libraries/Adafruit_Wippersnapper_Arduino/src/Wippersnapper_demo.ino"
# 11 "/Users/brentrubell/Documents/Arduino/libraries/Adafruit_Wippersnapper_Arduino/src/Wippersnapper_demo.ino"
#include "ws_adapters.h"
ws_adapter_offline wipper;
#define WS_DEBUG
void setup();
void loop();
#line 17 "/Users/brentrubell/Documents/Arduino/libraries/Adafruit_Wippersnapper_Arduino/src/Wippersnapper_demo.ino"
void setup() {
Serial.begin(115200);
wipper.provision();
wipper.connect();
}
void loop() { wipper.run(); }

View file

@ -626,53 +626,36 @@ bool I2cController::Handle_I2cDeviceAddOrReplace(pb_istream_t *stream) {
drvBase *drv = nullptr;
if (strcmp(device_name, SCAN_DEVICE) == 0) {
WS_DEBUG_PRINTLN("Attempting to autoconfig device found in scan...");
// Get all possible driver candidates for this address
WS_DEBUG_PRINT("Getting drivers for address: ");
WS_DEBUG_PRINTLN(device_descriptor.i2c_device_address);
std::vector<const char *> candidate_drivers =
getDriversForAddress(device_descriptor.i2c_device_address);
// Print out all the candidates
// Probe each candidate to see if it communicates
for (const char *driverName : candidate_drivers) {
WS_DEBUG_PRINT("[i2c] Found a candidate driver: ");
WS_DEBUG_PRINT("[i2c] Attempting to initialize driver: ");
WS_DEBUG_PRINTLN(driverName);
}
// Check/probe each candidate to see if it communicates
for (const char *driverName : candidate_drivers) {
drv = CreateI2CDriverByName(
driverName, bus, device_descriptor.i2c_device_address,
device_descriptor.i2c_mux_channel, device_status);
// Probe the driver to check if it communicates its init. sequence
// properly
if (!drv->begin()) {
delete drv;
drv = nullptr;
} else {
WS_DEBUG_PRINT("[i2c] Device initialized: ");
WS_DEBUG_PRINT("[i2c] Driver successfully initialized: ");
WS_DEBUG_PRINTLN(driverName);
// TOdO: NOTE THAT WE MAY DOUBLE_INIT BELOW!!! AND CRASH
drv->SetSensorTypes(true);
drv->SetPeriod(0);
// TODO: Add driver information to FS
break;
}
}
} else {
WS_DEBUG_PRINTLN("Device was defined in config file, initializing...");
// TODO: Add more debug window here
drv = CreateI2CDriverByName(
device_name, bus, device_descriptor.i2c_device_address,
device_descriptor.i2c_mux_channel, device_status);
if (drv == nullptr) {
WS_DEBUG_PRINTLN(
"[i2c] ERROR: I2C driver type not found or unsupported!");
if (WsV2._sdCardV2->isModeOffline()) {
WsV2.haltErrorV2("[i2c] Driver failed to initialize!\n\tDid you set "
"the correct value for i2cDeviceName?\n\tDid you set "
"the correct value for"
"i2cDeviceAddress?",
WS_LED_STATUS_ERROR_RUNTIME, false);
}
}
}
// Attempt to initialize the driver
if (did_set_mux_ch) {
drv->SetMuxAddress(device_descriptor.i2c_mux_address);
WS_DEBUG_PRINTLN("[i2c] Set driver to use MUX");
@ -685,10 +668,12 @@ bool I2cController::Handle_I2cDeviceAddOrReplace(pb_istream_t *stream) {
WS_DEBUG_PRINTLN("[i2c] Set driver to use Alt I2C bus");
}
// Configure the driver
drv->EnableSensorReads(
drv->SetSensorTypes(
false,
_i2c_model->GetI2cDeviceAddOrReplaceMsg()->i2c_device_sensor_types,
_i2c_model->GetI2cDeviceAddOrReplaceMsg()->i2c_device_sensor_types_count);
drv->SetSensorPeriod(
_i2c_model->GetI2cDeviceAddOrReplaceMsg()
->i2c_device_sensor_types_count);
drv->SetPeriod(
_i2c_model->GetI2cDeviceAddOrReplaceMsg()->i2c_device_period);
if (!drv->begin()) {
if (WsV2._sdCardV2->isModeOffline()) {
@ -699,7 +684,7 @@ bool I2cController::Handle_I2cDeviceAddOrReplace(pb_istream_t *stream) {
WS_LED_STATUS_ERROR_RUNTIME, false);
}
}
}
_i2c_drivers.push_back(drv);
WS_DEBUG_PRINTLN("[i2c] Driver initialized and added to controller: ");
WS_DEBUG_PRINTLN(device_name);

View file

@ -112,6 +112,12 @@ protected:
NULL; ///< Holds data for the AHTX0's temperature sensor
Adafruit_Sensor *_aht_humidity =
NULL; ///< Holds data for the AHTX0's humidity sensor
wippersnapper_sensor_SensorType _default_sensor_types[3] = {
wippersnapper_sensor_SensorType_SENSOR_TYPE_AMBIENT_TEMPERATURE,
wippersnapper_sensor_SensorType_SENSOR_TYPE_AMBIENT_TEMPERATURE_FAHRENHEIT,
wippersnapper_sensor_SensorType_SENSOR_TYPE_RELATIVE_HUMIDITY}; ///< Default
///< sensor
///< types
};
#endif // drvAhtx0

View file

@ -20,6 +20,7 @@
#include <protos/i2c.pb.h>
#define NO_MUX_CH 0xFFFF; ///< No MUX channel specified
#define DEFAULT_SENSOR_PERIOD 30.0 ///< Default sensor period, in seconds
/**************************************************************************/
/*!
@ -161,8 +162,15 @@ public:
The number of active sensors to read from the device.
*/
/*******************************************************************************/
void EnableSensorReads(wippersnapper_sensor_SensorType *sensor_types,
size_t sensor_types_count) {
void SetSensorTypes(bool use_default_types = false,
wippersnapper_sensor_SensorType *sensor_types = nullptr,
size_t sensor_types_count = 0) {
if (use_default_types) {
sensor_types = _default_sensor_types;
// set sensor_types_count to # of elements within _default_sensor_types
sensor_types_count =
sizeof(_default_sensor_types) / sizeof(_default_sensor_types[0]);
}
_sensors_count = sensor_types_count;
for (size_t i = 0; i < _sensors_count; i++) {
_sensors[i] = sensor_types[i];
@ -193,11 +201,10 @@ public:
seconds.
*/
/*******************************************************************************/
void SetSensorPeriod(float period) {
if (period < 0) {
_sensor_period = 0;
return;
}
void SetPeriod(float period = DEFAULT_SENSOR_PERIOD) {
if (period < 0)
_sensor_period = DEFAULT_SENSOR_PERIOD;
_sensor_period = (unsigned long)(period * 1000.0f);
}
@ -219,6 +226,14 @@ public:
/*******************************************************************************/
ulong GetSensorPeriod() { return _sensor_period; }
/*******************************************************************************/
/*!
@brief Gets the sensor's types
@returns A pointer to an array of SensorTypes.
*/
/*******************************************************************************/
wippersnapper_sensor_SensorType *GetSensorTypes() { return _sensors; }
/*******************************************************************************/
/*!
@brief Gets the sensor's previous period.
@ -591,26 +606,6 @@ public:
return it->second(sensors_event);
}
/*******************************************************************************/
/*!
@brief Checks if an address found during an i2c scan belongs to the
sensor.
@param scan_address
The desired address to check, from an i2c scan
@returns True if the address belongs to the sensor, False otherwise
*/
/*******************************************************************************/
bool IsPotentialAddress(uint16_t scan_address) {
for (uint8_t i = 0;
i < sizeof(_potential_addresses) / sizeof(_potential_addresses[0]);
i++) {
if (scan_address == _potential_addresses[i]) {
return true;
}
}
return false; // nothing found
}
/*******************************************************************************/
/*!
@brief Function type for sensor event handlers
@ -735,8 +730,6 @@ protected:
TwoWire *_i2c; ///< Pointer to the I2C bus
bool _has_alt_i2c_bus; ///< True if the device is on an alternate I2C bus
uint16_t _address; ///< The device's I2C address.
uint16_t _potential_addresses[2]; ///< Potential I2C addresses for the device,
///< stored on the device driver
uint32_t _i2c_mux_addr; ///< The I2C MUX address, if applicable.
uint32_t _i2c_mux_channel; ///< The I2C MUX channel, if applicable.
char _name[15]; ///< The device's name.
@ -745,5 +738,7 @@ protected:
ulong _sensor_period; ///< The sensor's period, in milliseconds.
ulong _sensor_period_prv; ///< The sensor's previous period, in milliseconds.
size_t _sensors_count; ///< Number of sensors on the device.
wippersnapper_sensor_SensorType
_default_sensor_types[1]; ///< Default sensor types
};
#endif // DRV_BASE_H

View file

@ -473,8 +473,104 @@ bool Wippersnapper_FS::AddSDCSPinToFileConfig(uint8_t pin) {
return true;
}
bool Wippersnapper_FS::AddI2CDeviceToConfig(uint32_t address) { return true; }
// TODO: Add an inclusion for "i2cDeviceSensorTypes"
/********************************************************************************/
/*!
@brief Adds an I2C device to the `config.json` file.
@param address
The I2C device's address.
@param period
The period at which the device should be polled.
@param driver_name
The name of the driver.
@returns True if the device was successfully added, False otherwise.
*/
/********************************************************************************/
bool Wippersnapper_FS::AddI2cDeviceToFileConfig(uint32_t address, float period,
char *driver_name) {
if (!wipperFatFs_v2.exists("/config.json")) {
HaltFilesystem("ERROR: Could not find expected config.json file on the "
"WIPPER volume!");
return false;
}
File32 file_cfg = wipperFatFs_v2.open("/config.json", FILE_READ);
if (!file_cfg) {
WS_DEBUG_PRINTLN("ERROR: Could not open the config.json file for reading!");
return false;
}
// Parse the JSON document
JsonDocument doc;
DeserializationError error = deserializeJson(doc, file_cfg);
file_cfg.close();
if (error) {
WS_DEBUG_PRINT("JSON parse error: ");
WS_DEBUG_PRINTLN(error.c_str());
WS_DEBUG_PRINTLN(
"ERROR: Unable to parse config.json file - deserializeJson() failed!");
return false;
}
JsonObject new_component = doc["components"].add<JsonObject>();
new_component["name"] = driver_name;
new_component["componentAPI"] = "i2c";
new_component["i2cdevicei2cDeviceName"] = driver_name;
new_component["period"] = period;
// convert address to string
char address_str[10];
sprintf(address_str, "0x%02X", address);
new_component["i2cDeviceAddress"] = address_str;
// Handle the sensor types
// TODO: This is un-implemented because I'm unsure how to go from type->string
// representation without adding significant overhead...
/*
JsonArray new_component_types =
new_component["i2cDeviceSensorTypes"].to<JsonArray>();
new_component_types[0]["type"] = "relative-humidity";
new_component_types[1]["type"] = "ambient-temp";
new_component_types[2]["type"] = "ambient-temp-fahrenheit";
new_component_types[3]["type"] = "pressure";
new_component_types[4]["type"] = "altitude";
*/
doc.shrinkToFit();
// Remove the existing config.json file
wipperFatFs_v2.remove("/config.json");
flash_v2.syncBlocks();
wipperFatFs_v2.cacheClear();
// Write the updated doc back to new config.json file
file_cfg = wipperFatFs_v2.open("/config.json", FILE_WRITE);
if (!file_cfg) {
HaltFilesystem("ERROR: Could not open the config.json file for writing!");
return false;
}
serializeJsonPretty(doc, file_cfg);
// Flush and sync file
// TODO: Not sure if this is actually doing anything on RP2040, need to test
// in isolation
file_cfg.flush();
flash_v2.syncBlocks();
file_cfg.close();
// Force cache clear and sync
// TODO: Not sure if this is actually doing anything on RP2040, need to test
// in isolation
flash_v2.syncBlocks();
wipperFatFs_v2.cacheClear();
refreshMassStorage();
TinyUSBDevice.detach();
delay(150);
TinyUSBDevice.attach();
delay(1500);
return true;
}
/**************************************************************************/
/*!
@brief Checks if secrets.json file exists on the flash filesystem.

View file

@ -64,9 +64,9 @@ public:
#endif
// config.json
void CreateFileConfig();
bool AddSDCSPinToFileConfig(uint8_t pin);
void GetPinSDCS();
bool AddI2CDeviceToConfig(uint32_t address);
bool AddSDCSPinToFileConfig(uint8_t pin);
bool AddI2cDeviceToFileConfig(uint32_t address, float period, char *driver_name);
private:
bool _is_secrets_file_empty = false;