diff --git a/ADDING_SENSORS.md b/ADDING_SENSORS.md new file mode 100644 index 0000000..fdc43b9 --- /dev/null +++ b/ADDING_SENSORS.md @@ -0,0 +1,99 @@ +# OpenLog Artemis : How To Add A New Sensor + +These are _abbreviated_ instructions on how to add a new sensor to the OLA firmware. It's more of an aide-memoire really... Sorry about that. + +Caveat: this is _currently_ how a new sensor is added, for version v1.n of the OLA firmware using v1.2.n of the Apollo3 boards (the OLA code is compiled using the SparkFun RedBoard Artemis ATP (All The Pins) board). This will change, dramatically, when we upgrade to v2 of Apollo3 and integrate BLE support. + +## Use The Release Candidate Branch + +First up, please target any commits at the _**release_candidate**_ branch, so they can be tested before being merged into the _master_ branch. + +- https://github.com/sparkfun/OpenLog_Artemis/tree/release_candidate + +## OpenLog_Artemis.ino + +- [Add the new sensor to the comments at the start of the file](https://github.com/sparkfun/OpenLog_Artemis/commit/2a26acd279fa93cfe84f1bc518c0e7a041b3bc44#diff-7d096a133c17fd6db382abb9a3c6ea7b42ec505961876cecf404a55be5945347R71) + +- [#include the library .h file remembering to include the library manager helper link](https://github.com/sparkfun/OpenLog_Artemis/commit/2a26acd279fa93cfe84f1bc518c0e7a041b3bc44#diff-7d096a133c17fd6db382abb9a3c6ea7b42ec505961876cecf404a55be5945347R203) + +## Sensors.ino + +### gatherDeviceValues + +- This is where the sensor readings are actually read. [Add a case for the new sensor](https://github.com/sparkfun/OpenLog_Artemis/commit/2a26acd279fa93cfe84f1bc518c0e7a041b3bc44#diff-fba25af49a58a7a24fb75cb34321e25dd4a94a9d3515ac051fcaa4502e444f7fR725-R798) + +### printHelperText + +- [Add helper text for the sensor readings](https://github.com/sparkfun/OpenLog_Artemis/commit/2a26acd279fa93cfe84f1bc518c0e7a041b3bc44#diff-fba25af49a58a7a24fb75cb34321e25dd4a94a9d3515ac051fcaa4502e444f7fR1132-R1165) + +## autoDetect.ino + +### addDevice + +- This code is called to add the discovered device to the linked list of active devices. [Add a case for the new sensor](https://github.com/sparkfun/OpenLog_Artemis/commit/2a26acd279fa93cfe84f1bc518c0e7a041b3bc44#diff-68cc245ab0d3c1bed2bfc22b403edc3ed73d347a35a21179b3a6ec27a458803bR234-R239). The class name comes from the library. The config struct is defined in settings.h. + +### beginQwiicDevices + +- This is the code that is called to start (begin) the device. [Add a case for the new sensor](https://github.com/sparkfun/OpenLog_Artemis/commit/2a26acd279fa93cfe84f1bc518c0e7a041b3bc44#diff-68cc245ab0d3c1bed2bfc22b403edc3ed73d347a35a21179b3a6ec27a458803bR453-R461). Update _qwiicPowerOnDelayMillis_ if this device needs extra time to get its act together on power-up. + +### configureDevice + +- If the sensor needs to be configured before use, that gets done here. [Add a case for the new sensor, even if it doesn't need to be configured.](https://github.com/sparkfun/OpenLog_Artemis/commit/2a26acd279fa93cfe84f1bc518c0e7a041b3bc44#diff-68cc245ab0d3c1bed2bfc22b403edc3ed73d347a35a21179b3a6ec27a458803bR705-R707) + +### getConfigFunctionPtr + +- [Add a pointer to the sensor menu function (defined in menuAttachedDevices.ino)](https://github.com/sparkfun/OpenLog_Artemis/commit/2a26acd279fa93cfe84f1bc518c0e7a041b3bc44#diff-68cc245ab0d3c1bed2bfc22b403edc3ed73d347a35a21179b3a6ec27a458803bR795-R797) + +### swap + +- [Add the device's I2C address(es) here - just for reference (we don't use these #defines any longer)](https://github.com/sparkfun/OpenLog_Artemis/commit/2a26acd279fa93cfe84f1bc518c0e7a041b3bc44#diff-68cc245ab0d3c1bed2bfc22b403edc3ed73d347a35a21179b3a6ec27a458803bR929) + +### testDevice + +- This is the code used to detect the sensor. [Add a case for the new sensor](https://github.com/sparkfun/OpenLog_Artemis/commit/2a26acd279fa93cfe84f1bc518c0e7a041b3bc44#diff-68cc245ab0d3c1bed2bfc22b403edc3ed73d347a35a21179b3a6ec27a458803bR987-R994). Provide some indication of how robust the detection is. Confidence would be high if the .begin writes and reads unique data to/from the sensor. Confidence is low if .begin only uses the standard _isConnected_ I2C address test. + +### getDeviceName + +- This is where the sensor name is defined as text. [Add a case for the new sensor](https://github.com/sparkfun/OpenLog_Artemis/commit/2a26acd279fa93cfe84f1bc518c0e7a041b3bc44#diff-68cc245ab0d3c1bed2bfc22b403edc3ed73d347a35a21179b3a6ec27a458803bR1423-R1425). Keep it brief and follow the same format as the other sensors: usually _TYPE_ (PRESSURE, TEMPERATURE etc.) followed by the abbreviated manufacturer's part number + +## menuAttachedDevices.ino + +### menuAttachedDevices + +- This is the code which lists all the attached devices as a menu. [Add a case for the new sensor](https://github.com/sparkfun/OpenLog_Artemis/commit/2a26acd279fa93cfe84f1bc518c0e7a041b3bc44#diff-6174875faf8039f2627c16aaf48e4db57f5a2c8c883061ac97202d74e9a46ef8R309-R311) + +### menuConfigure_ + +- [Add a new menuConfigure_ for the new sensor](https://github.com/sparkfun/OpenLog_Artemis/commit/2a26acd279fa93cfe84f1bc518c0e7a041b3bc44#diff-6174875faf8039f2627c16aaf48e4db57f5a2c8c883061ac97202d74e9a46ef8R2026-R2141) +- Boolean settings are simple to toggle. [Make them exclusive if you need to](https://github.com/sparkfun/OpenLog_Artemis/commit/2a26acd279fa93cfe84f1bc518c0e7a041b3bc44#diff-6174875faf8039f2627c16aaf48e4db57f5a2c8c883061ac97202d74e9a46ef8R1942-R1948) +- _int64_t_ values are requested using _getNumber_ (defined in support.ino) +- _double_ values are requested using _getDouble_ (defined in support.ino) + +## nvm.ino + +### recordDeviceSettingsToFile + +- This function gets called to write the device settings to file. [Add a case for the new sensor](https://github.com/sparkfun/OpenLog_Artemis/commit/2a26acd279fa93cfe84f1bc518c0e7a041b3bc44#diff-629ae89c3c660583493d544d3a7902728f4a8eefb65800c3acb64aea37d5d88dR611-R629). Include all of the sensor settings. + +### parseDeviceLine + +- This function gets called when the device settings are read back from file. [Add a case for the new sensor](https://github.com/sparkfun/OpenLog_Artemis/commit/2a26acd279fa93cfe84f1bc518c0e7a041b3bc44#diff-629ae89c3c660583493d544d3a7902728f4a8eefb65800c3acb64aea37d5d88dR1116-R1150) + +## settings.h + +### enum + +- [Add the device to the enumerated sensors](https://github.com/sparkfun/OpenLog_Artemis/commit/2a26acd279fa93cfe84f1bc518c0e7a041b3bc44#diff-c853eddd04f78093fed5ec20b822c3c224bfa5f268738ce4c479b45667f86fe9R25). Insert the new one above _DEVICE_TOTAL_DEVICES_ + +### settings struct + +- [Add a settings struct for the new sensor](https://github.com/sparkfun/OpenLog_Artemis/commit/2a26acd279fa93cfe84f1bc518c0e7a041b3bc44#diff-c853eddd04f78093fed5ec20b822c3c224bfa5f268738ce4c479b45667f86fe9R265-R281). Include both _log_ and _powerOnDelayMillis_ + +## README.md + +- Add the new sensor to the list in [README.md](./README.md). Include a link to the product page +- Update the OLA product page on Sparkle - add the new sensor to the list + +## CHANGELOG.md + +- Update [CHANGELOG.md](./CHANGELOG.md). Start a new version if you need to. Add the new sensor to the change notes diff --git a/Binaries/OpenLog_Artemis-V10-v17.bin b/Binaries/OpenLog_Artemis-V10-v17.bin new file mode 100644 index 0000000..6f0287b Binary files /dev/null and b/Binaries/OpenLog_Artemis-V10-v17.bin differ diff --git a/Binaries/OpenLog_Artemis-X04-v17.bin b/Binaries/OpenLog_Artemis-X04-v17.bin new file mode 100644 index 0000000..9e5065b Binary files /dev/null and b/Binaries/OpenLog_Artemis-X04-v17.bin differ diff --git a/CHANGELOG.md b/CHANGELOG.md index a11853b..407f5a2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,15 @@ Change Log ====================== +v1.7 +--------- + +* Corrected the readVin after sleep bug [39](https://github.com/sparkfun/OpenLog_Artemis/issues/39) +* Corrected detection of the MCP9600 (Qwiic Thermocouple) [41](https://github.com/sparkfun/OpenLog_Artemis/issues/41) +* Added support for the MPR MicroPressure Sensor [35](https://github.com/sparkfun/OpenLog_Artemis/issues/35) +* Added support for the SN-GCJA5 Particle Sensor +* IMU full scale and Digital Low Pass Filter settings can now be configured via Menu 3 [42](https://github.com/sparkfun/OpenLog_Artemis/issues/42) + v1.6 --------- diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 246095f..34aceed 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,4 +1,4 @@ -### How to Contribute +# OpenLog Artemis : How to Contribute Thank you so *much* for offering to help out. We truly appreciate it. diff --git a/Firmware/OpenLog_Artemis/OpenLog_Artemis.ino b/Firmware/OpenLog_Artemis/OpenLog_Artemis.ino index 91e6915..7bc99ec 100644 --- a/Firmware/OpenLog_Artemis/OpenLog_Artemis.ino +++ b/Firmware/OpenLog_Artemis/OpenLog_Artemis.ino @@ -32,9 +32,9 @@ Find way to store device configs into EEPROM Log four pressure sensors and graph them on plotter (checked) Test GPS - not sure about %d with int32s. Does lat, long, and alt look correct? - Test NAU7802s - Test SCD30s - Add a 'does not like to be powered cycled' setting for each device type. + (done) Test NAU7802s + (done) Test SCD30s (Add an extended delay for the SCD30. (Issue #5)) + (won't do?) Add a 'does not like to be powered cycled' setting for each device type. I think this has been superceded by "Add individual power-on delays for each sensor type?. (done) Add support for logging VIN (done) Investigate error in time between logs (https://github.com/sparkfun/OpenLog_Artemis/issues/13) (done) Invesigate RTC reset issue (https://github.com/sparkfun/OpenLog_Artemis/issues/13 + https://forum.sparkfun.com/viewtopic.php?f=123&t=53157) @@ -44,8 +44,7 @@ (done) Add a fix so that the MS8607 does not also appear as an MS5637 (done) Add "set RTC from GPS" functionality (done) Add UTCoffset functionality (including support for negative numbers) - Figure out how to give the u-blox time to establish a fix if it has been powered down between log intervals. - Maybe add a waitForValidFix feature? Or maybe we can work around using a big value for "Set Qwiic bus power up delay"? + (done) Figure out how to give the u-blox time to establish a fix if it has been powered down between log intervals. The user can specify up to 60s for the Qwiic power-on delay. Add support for VREG_ENABLE (done) Add support for PWR_LED (done) Use the WDT to reset the Artemis when power is reconnected (previously the Artemis would have stayed in deep sleep) @@ -65,10 +64,15 @@ (done) Correct the measurement count misbehaviour (Issue #31) (done) Use the corrected IMU temperature calculation (Issue #28) (done) Add individual power-on delays for each sensor type. Add an extended delay for the SCD30. (Issue #5) + (done) v1.7: Fix readVin after sleep bug: https://github.com/sparkfun/OpenLog_Artemis/issues/39 + (done) Change detectQwiicDevices so that the MCP9600 (Qwiic Thermocouple) is detected correctly + (done) Add support for the MPRLS0025PA micro pressure sensor + (done) Add support for the SN-GCJA5 particle sensor + (done) Add IMU accelerometer and gyro full scale and digital low pass filter settings to menuIMU */ const int FIRMWARE_VERSION_MAJOR = 1; -const int FIRMWARE_VERSION_MINOR = 6; +const int FIRMWARE_VERSION_MINOR = 7; //Define the OLA board identifier: // This is an int which is unique to this variant of the OLA and which allows us @@ -78,7 +82,7 @@ const int FIRMWARE_VERSION_MINOR = 6; // the variant * 0x100 (OLA = 1; GNSS_LOGGER = 2; GEOPHONE_LOGGER = 3) // the major firmware version * 0x10 // the minor firmware version -#define OLA_IDENTIFIER 0x116 +#define OLA_IDENTIFIER 0x117 // Stored as 279 decimal in OLA_settings.txt #include "settings.h" @@ -195,6 +199,8 @@ ICM_20948_SPI myICM; #include "SparkFun_Qwiic_Humidity_AHT20.h" //Click here to get the library: http://librarymanager/All#Qwiic_Humidity_AHT20 by SparkFun #include "SparkFun_SHTC3.h" // Click here to get the library: http://librarymanager/All#SparkFun_SHTC3 #include "SparkFun_ADS122C04_ADC_Arduino_Library.h" // Click here to get the library: http://librarymanager/All#SparkFun_ADS122C04 +#include "SparkFun_MicroPressure.h" // Click here to get the library: http://librarymanager/All#SparkFun_MicroPressure +#include "SparkFun_Particle_Sensor_SN-GCJA5_Arduino_Library.h" // Click here to get the library: http://librarymanager/All#SparkFun_Particle_Sensor_SN-GCJA5 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- @@ -675,7 +681,35 @@ void beginIMU() checkBattery(); delay(1); } - + + //Update the full scale and DLPF settings + ICM_20948_Status_e retval = myICM.enableDLPF(ICM_20948_Internal_Acc, settings.imuAccDLPF); + if (retval != ICM_20948_Stat_Ok) + { + Serial.println(F("Error: Could not configure the IMU Accelerometer DLPF!")); + } + retval = myICM.enableDLPF(ICM_20948_Internal_Gyr, settings.imuGyroDLPF); + if (retval != ICM_20948_Stat_Ok) + { + Serial.println(F("Error: Could not configure the IMU Gyro DLPF!")); + } + ICM_20948_dlpcfg_t dlpcfg; + dlpcfg.a = settings.imuAccDLPFBW; + dlpcfg.g = settings.imuGyroDLPFBW; + retval = myICM.setDLPFcfg((ICM_20948_Internal_Acc | ICM_20948_Internal_Gyr), dlpcfg); + if (retval != ICM_20948_Stat_Ok) + { + Serial.println(F("Error: Could not configure the IMU DLPF BW!")); + } + ICM_20948_fss_t FSS; + FSS.a = settings.imuAccFSS; + FSS.g = settings.imuGyroFSS; + retval = myICM.setFullScale((ICM_20948_Internal_Acc | ICM_20948_Internal_Gyr), FSS); + if (retval != ICM_20948_Stat_Ok) + { + Serial.println(F("Error: Could not configure the IMU Full Scale!")); + } + online.IMU = true; } else diff --git a/Firmware/OpenLog_Artemis/Sensors.ino b/Firmware/OpenLog_Artemis/Sensors.ino index f8eb50b..a5b5c7e 100644 --- a/Firmware/OpenLog_Artemis/Sensors.ino +++ b/Firmware/OpenLog_Artemis/Sensors.ino @@ -678,6 +678,124 @@ void gatherDeviceValues() } } break; + case DEVICE_PRESSURE_MPR0025PA1: + { + SparkFun_MicroPressure *nodeDevice = (SparkFun_MicroPressure *)temp->classPtr; + struct_MPR0025PA1 *nodeSetting = (struct_MPR0025PA1 *)temp->configPtr; + if (nodeSetting->log == true) + { + if (nodeSetting->usePSI) + { + sprintf(tempData, "%.04f,", nodeDevice->readPressure()); + strcat(outputData, tempData); + } + if (nodeSetting->usePA) + { + sprintf(tempData, "%.01f,", nodeDevice->readPressure(PA)); + strcat(outputData, tempData); + } + if (nodeSetting->useKPA) + { + sprintf(tempData, "%.04f,", nodeDevice->readPressure(KPA)); + strcat(outputData, tempData); + } + if (nodeSetting->useTORR) + { + sprintf(tempData, "%.03f,", nodeDevice->readPressure(TORR)); + strcat(outputData, tempData); + } + if (nodeSetting->useINHG) + { + sprintf(tempData, "%.04f,", nodeDevice->readPressure(INHG)); + strcat(outputData, tempData); + } + if (nodeSetting->useATM) + { + sprintf(tempData, "%.06f,", nodeDevice->readPressure(ATM)); + strcat(outputData, tempData); + } + if (nodeSetting->useBAR) + { + sprintf(tempData, "%.06f,", nodeDevice->readPressure(BAR)); + strcat(outputData, tempData); + } + } + } + break; + case DEVICE_PARTICLE_SNGCJA5: + { + SFE_PARTICLE_SENSOR *nodeDevice = (SFE_PARTICLE_SENSOR *)temp->classPtr; + struct_SNGCJA5 *nodeSetting = (struct_SNGCJA5 *)temp->configPtr; + if (nodeSetting->log == true) + { + if (nodeSetting->logPM1) + { + sprintf(tempData, "%.02f,", nodeDevice->getPM1_0()); + strcat(outputData, tempData); + } + if (nodeSetting->logPM25) + { + sprintf(tempData, "%.02f,", nodeDevice->getPM2_5()); + strcat(outputData, tempData); + } + if (nodeSetting->logPM10) + { + sprintf(tempData, "%.02f,", nodeDevice->getPM10()); + strcat(outputData, tempData); + } + if (nodeSetting->logPC05) + { + sprintf(tempData, "%d,", nodeDevice->getPC0_5()); + strcat(outputData, tempData); + } + if (nodeSetting->logPC1) + { + sprintf(tempData, "%d,", nodeDevice->getPC1_0()); + strcat(outputData, tempData); + } + if (nodeSetting->logPC25) + { + sprintf(tempData, "%d,", nodeDevice->getPC2_5()); + strcat(outputData, tempData); + } + if (nodeSetting->logPC50) + { + sprintf(tempData, "%d,", nodeDevice->getPC5_0()); + strcat(outputData, tempData); + } + if (nodeSetting->logPC75) + { + sprintf(tempData, "%d,", nodeDevice->getPC7_5()); + strcat(outputData, tempData); + } + if (nodeSetting->logPC10) + { + sprintf(tempData, "%d,", nodeDevice->getPC10()); + strcat(outputData, tempData); + } + if (nodeSetting->logSensorStatus) + { + sprintf(tempData, "%d,", nodeDevice->getStatusSensors()); + strcat(outputData, tempData); + } + if (nodeSetting->logPDStatus) + { + sprintf(tempData, "%d,", nodeDevice->getStatusPD()); + strcat(outputData, tempData); + } + if (nodeSetting->logLDStatus) + { + sprintf(tempData, "%d,", nodeDevice->getStatusLD()); + strcat(outputData, tempData); + } + if (nodeSetting->logFanStatus) + { + sprintf(tempData, "%d,", nodeDevice->getStatusFan()); + strcat(outputData, tempData); + } + } + } + break; default: Serial.printf("printDeviceValue unknown device type: %s\r\n", getDeviceName(temp->deviceType)); break; @@ -989,6 +1107,62 @@ void printHelperText(bool terminalOnly) } } break; + case DEVICE_PRESSURE_MPR0025PA1: + { + struct_MPR0025PA1 *nodeSetting = (struct_MPR0025PA1 *)temp->configPtr; + if (nodeSetting->log) + { + if (nodeSetting->usePSI) + strcat(helperText, "PSI,"); + if (nodeSetting->usePA) + strcat(helperText, "Pa,"); + if (nodeSetting->useKPA) + strcat(helperText, "kPa,"); + if (nodeSetting->useTORR) + strcat(helperText, "torr,"); + if (nodeSetting->useINHG) + strcat(helperText, "inHg,"); + if (nodeSetting->useATM) + strcat(helperText, "atm,"); + if (nodeSetting->useBAR) + strcat(helperText, "bar,"); + } + } + break; + case DEVICE_PARTICLE_SNGCJA5: + { + struct_SNGCJA5 *nodeSetting = (struct_SNGCJA5 *)temp->configPtr; + if (nodeSetting->log) + { + if (nodeSetting->logPM1) + strcat(helperText, "PM1_0,"); + if (nodeSetting->logPM25) + strcat(helperText, "PM2_5,"); + if (nodeSetting->logPM10) + strcat(helperText, "PM10,"); + if (nodeSetting->logPC05) + strcat(helperText, "PC0_5,"); + if (nodeSetting->logPC1) + strcat(helperText, "PC1_0,"); + if (nodeSetting->logPC25) + strcat(helperText, "PC2_5,"); + if (nodeSetting->logPC50) + strcat(helperText, "PC5_0,"); + if (nodeSetting->logPC75) + strcat(helperText, "PC7_5,"); + if (nodeSetting->logPC10) + strcat(helperText, "PC10,"); + if (nodeSetting->logSensorStatus) + strcat(helperText, "Sensors,"); + if (nodeSetting->logPDStatus) + strcat(helperText, "PD,"); + if (nodeSetting->logLDStatus) + strcat(helperText, "LD,"); + if (nodeSetting->logFanStatus) + strcat(helperText, "Fan,"); + } + } + break; default: Serial.printf("\nprinterHelperText device not found: %d\r\n", temp->deviceType); break; diff --git a/Firmware/OpenLog_Artemis/autoDetect.ino b/Firmware/OpenLog_Artemis/autoDetect.ino index 42af1d6..4506a00 100644 --- a/Firmware/OpenLog_Artemis/autoDetect.ino +++ b/Firmware/OpenLog_Artemis/autoDetect.ino @@ -225,6 +225,18 @@ bool addDevice(deviceType_e deviceType, uint8_t address, uint8_t muxAddress, uin temp->configPtr = new struct_ADS122C04; } break; + case DEVICE_PRESSURE_MPR0025PA1: + { + temp->classPtr = new SparkFun_MicroPressure; + temp->configPtr = new struct_MPR0025PA1; + } + break; + case DEVICE_PARTICLE_SNGCJA5: + { + temp->classPtr = new SFE_PARTICLE_SENSOR; + temp->configPtr = new struct_SNGCJA5; + } + break; default: Serial.printf("addDevice Device type not found: %d\r\n", deviceType); break; @@ -428,6 +440,25 @@ bool beginQwiicDevices() temp->online = true; } break; + case DEVICE_PRESSURE_MPR0025PA1: + { + // TO DO: Figure out how to pass minimumPSI and maximumPSI when instantiating the sensor. Maybe add an update-_minPsi-and-_maxPsi function to the library? + SparkFun_MicroPressure *tempDevice = (SparkFun_MicroPressure *)temp->classPtr; + struct_MPR0025PA1 *nodeSetting = (struct_MPR0025PA1 *)temp->configPtr; //Create a local pointer that points to same spot as node does + if (nodeSetting->powerOnDelayMillis > qwiicPowerOnDelayMillis) qwiicPowerOnDelayMillis = nodeSetting->powerOnDelayMillis; // Increase qwiicPowerOnDelayMillis if required + if (tempDevice->begin(temp->address, qwiic) == true) //Address, Wire port. Returns true on success. + temp->online = true; + } + break; + case DEVICE_PARTICLE_SNGCJA5: + { + SFE_PARTICLE_SENSOR *tempDevice = (SFE_PARTICLE_SENSOR *)temp->classPtr; + struct_SNGCJA5 *nodeSetting = (struct_SNGCJA5 *)temp->configPtr; //Create a local pointer that points to same spot as node does + if (nodeSetting->powerOnDelayMillis > qwiicPowerOnDelayMillis) qwiicPowerOnDelayMillis = nodeSetting->powerOnDelayMillis; // Increase qwiicPowerOnDelayMillis if required + if (tempDevice->begin(qwiic) == true) //Wire port. Returns true on success. + temp->online = true; + } + break; default: Serial.printf("beginQwiicDevices: device type not found: %d\r\n", temp->deviceType); break; @@ -459,7 +490,7 @@ void printOnlineDevice() if (temp == NULL) { - printDebug(F("printOnlineDevice: No devices detected")); + printDebug(F("printOnlineDevice: No devices detected\r\n")); return; } @@ -668,6 +699,12 @@ void configureDevice(node * temp) sensor->configureADCmode(ADS122C04_2WIRE_HI_TEMP); } break; + case DEVICE_PRESSURE_MPR0025PA1: + //Nothing to configure + break; + case DEVICE_PARTICLE_SNGCJA5: + //Nothing to configure + break; default: Serial.printf("configureDevice: Unknown device type %d: %s\r\n", deviceType, getDeviceName((deviceType_e)deviceType)); break; @@ -752,6 +789,12 @@ FunctionPointer getConfigFunctionPtr(uint8_t nodeNumber) case DEVICE_ADC_ADS122C04: ptr = (FunctionPointer)menuConfigure_ADS122C04; break; + case DEVICE_PRESSURE_MPR0025PA1: + ptr = (FunctionPointer)menuConfigure_MPR0025PA1; + break; + case DEVICE_PARTICLE_SNGCJA5: + ptr = (FunctionPointer)menuConfigure_SNGCJA5; + break; default: Serial.println(F("getConfigFunctionPtr: Unknown device type")); Serial.flush(); @@ -880,8 +923,10 @@ void swap(struct node * a, struct node * b) // Available Qwiic devices //We no longer use defines in the search table. These are just here for reference. #define ADR_VEML6075 0x10 +#define ADR_MPR0025PA1 0x18 #define ADR_NAU7802 0x2A #define ADR_VL53L1X 0x29 +#define ADR_SNGCJA5 0x33 #define ADR_AHT20 0x38 #define ADR_MS8607 0x40 //Humidity portion of the MS8607 sensor #define ADR_UBLOX 0x42 //But can be set to any address @@ -913,6 +958,15 @@ deviceType_e testDevice(uint8_t i2cAddress, uint8_t muxAddress, uint8_t portNumb return (DEVICE_UV_VEML6075); } break; + case 0x18: + { + //Confidence: Medium - Checks the status byte power indication bit and three "always 0" bits + SparkFun_MicroPressure sensor; + if (sensor.begin(i2cAddress, qwiic) == true) //Address, Wire port + if ((sensor.readStatus() & 0x5A) == 0x40) // Mask the power indication bit and three "always 0" bits + return (DEVICE_PRESSURE_MPR0025PA1); + } + break; case 0x2A: { //Confidence: High - Checks 8 bit revision code (0x0F) @@ -930,6 +984,14 @@ deviceType_e testDevice(uint8_t i2cAddress, uint8_t muxAddress, uint8_t portNumb return (DEVICE_DISTANCE_VL53L1X); } break; + case 0x33: + { + //Confidence: low - basic isConnected test only... + SFE_PARTICLE_SENSOR sensor; + if (sensor.begin(qwiic) == true) //Wire port + return (DEVICE_PARTICLE_SNGCJA5); + } + break; case 0x38: { //Confidence: Medium - begin() does a variety of inits and checks @@ -1040,6 +1102,7 @@ deviceType_e testDevice(uint8_t i2cAddress, uint8_t muxAddress, uint8_t portNumb break; case 0x60: { + //Always do the MCP9600 first. It's fussy... //Confidence: High - Checks 8bit ID MCP9600 sensor; if (sensor.begin(i2cAddress, qwiic) == true) //Address, Wire port @@ -1053,6 +1116,7 @@ deviceType_e testDevice(uint8_t i2cAddress, uint8_t muxAddress, uint8_t portNumb break; case 0x61: { + //Always do the MCP9600 first. It's fussy... //Confidence: High - Checks 8bit ID MCP9600 sensor; if (sensor.begin(i2cAddress, qwiic) == true) //Address, Wire port @@ -1067,6 +1131,7 @@ deviceType_e testDevice(uint8_t i2cAddress, uint8_t muxAddress, uint8_t portNumb break; case 0x62: { + //Always do the MCP9600 first. It's fussy... //Confidence: High - Checks 8bit ID MCP9600 sensor; if (sensor.begin(i2cAddress, qwiic) == true) //Address, Wire port @@ -1075,6 +1140,7 @@ deviceType_e testDevice(uint8_t i2cAddress, uint8_t muxAddress, uint8_t portNumb break; case 0x63: { + //Always do the MCP9600 first. It's fussy... //Confidence: High - Checks 8bit ID MCP9600 sensor; if (sensor.begin(i2cAddress, qwiic) == true) //Address, Wire port @@ -1083,6 +1149,7 @@ deviceType_e testDevice(uint8_t i2cAddress, uint8_t muxAddress, uint8_t portNumb break; case 0x64: { + //Always do the MCP9600 first. It's fussy... //Confidence: High - Checks 8bit ID MCP9600 sensor; if (sensor.begin(i2cAddress, qwiic) == true) //Address, Wire port @@ -1091,6 +1158,7 @@ deviceType_e testDevice(uint8_t i2cAddress, uint8_t muxAddress, uint8_t portNumb break; case 0x65: { + //Always do the MCP9600 first. It's fussy... //Confidence: High - Checks 8bit ID MCP9600 sensor; if (sensor.begin(i2cAddress, qwiic) == true) //Address, Wire port @@ -1099,6 +1167,7 @@ deviceType_e testDevice(uint8_t i2cAddress, uint8_t muxAddress, uint8_t portNumb break; case 0x66: { + //Always do the MCP9600 first. It's fussy... //Confidence: High - Checks 8bit ID MCP9600 sensor; if (sensor.begin(i2cAddress, qwiic) == true) //Address, Wire port @@ -1107,6 +1176,7 @@ deviceType_e testDevice(uint8_t i2cAddress, uint8_t muxAddress, uint8_t portNumb break; case 0x67: { + //Always do the MCP9600 first. It's fussy... //Confidence: High - Checks 8bit ID MCP9600 sensor; if (sensor.begin(i2cAddress, qwiic) == true) //Address, Wire port @@ -1347,6 +1417,12 @@ const char* getDeviceName(deviceType_e deviceNumber) case DEVICE_ADC_ADS122C04: return "ADC-ADS122C04"; break; + case DEVICE_PRESSURE_MPR0025PA1: + return "Pressure-MPR"; + break; + case DEVICE_PARTICLE_SNGCJA5: + return "Particle-SNGCJA5"; + break; case DEVICE_UNKNOWN_DEVICE: return "Unknown device"; diff --git a/Firmware/OpenLog_Artemis/lowerPower.ino b/Firmware/OpenLog_Artemis/lowerPower.ino index 11d3edc..ad6fdd3 100644 --- a/Firmware/OpenLog_Artemis/lowerPower.ino +++ b/Firmware/OpenLog_Artemis/lowerPower.ino @@ -321,7 +321,14 @@ void wakeFromSleep() am_hal_stimer_config(AM_HAL_STIMER_HFRC_3MHZ); //Turn on ADC - ap3_adc_setup(); + uint32_t adcError = (uint32_t)ap3_adc_setup(); + if (settings.logA11 == true) adcError += (uint32_t)ap3_set_pin_to_analog(11); // Set _pad_ 11 to analog if enabled for logging + if (settings.logA12 == true) adcError += (uint32_t)ap3_set_pin_to_analog(12); // Set _pad_ 12 to analog if enabled for logging + if (settings.logA13 == true) adcError += (uint32_t)ap3_set_pin_to_analog(13); // Set _pad_ 13 to analog if enabled for logging + if (settings.logA32 == true) adcError += (uint32_t)ap3_set_pin_to_analog(32); // Set _pad_ 32 to analog if enabled for logging +#if(HARDWARE_VERSION_MAJOR >= 1) + adcError += (uint32_t)ap3_set_pin_to_analog(PIN_VIN_MONITOR); // Set _pad_ PIN_VIN_MONITOR to analog +#endif //Run setup again @@ -361,6 +368,10 @@ void wakeFromSleep() Serial.begin(settings.serialTerminalBaudRate); printDebug("wakeFromSleep: I'm awake!\r\n"); + printDebug("wakeFromSleep: adcError is " + (String)adcError + "."); + if (adcError > 0) + printDebug(" This indicates an error was returned by ap3_adc_setup or one of the calls to ap3_set_pin_to_analog."); + printDebug("\r\n"); beginQwiic(); //Power up Qwiic bus as early as possible diff --git a/Firmware/OpenLog_Artemis/menuAttachedDevices.ino b/Firmware/OpenLog_Artemis/menuAttachedDevices.ino index f2f4cee..fdfe834 100644 --- a/Firmware/OpenLog_Artemis/menuAttachedDevices.ino +++ b/Firmware/OpenLog_Artemis/menuAttachedDevices.ino @@ -42,25 +42,15 @@ bool detectQwiicDevices() waitForQwiicBusPowerDelay(); // Wait while the qwiic devices power up - //Do a prelim scan to see if anything is out there - for (uint8_t address = 1 ; address < 127 ; address++) - { - qwiic.beginTransmission(address); - if (qwiic.endTransmission() == 0) - { - somethingDetected = true; - if (settings.printDebugMessages == true) - Serial.printf("detectQwiicDevices: something detected at address 0x%02X\r\n", address); - break; - } - } - if (somethingDetected == false) return (false); + // Note: The MCP9600 (Qwiic Thermocouple) is a fussy device. If we use beginTransmission + endTransmission more than once + // the second and subsequent times will fail. The MCP9600 only ACKs the first time. The MCP9600 also appears to be able to + // lock up the I2C bus if you don't discover it and then begin it in one go... + // The following code has been restructured to try and keep the MCP9600 happy. - Serial.println(F("Identifying Qwiic Devices...")); + Serial.println(F("Identifying Qwiic Muxes...")); //First scan for Muxes. Valid addresses are 0x70 to 0x77 (112 to 119). //If any are found, they will be begin()'d causing their ports to turn off - printDebug("detectQwiicDevices: scanning for multiplexers\r\n"); uint8_t muxCount = 0; for (uint8_t address = 0x70 ; address < 0x78 ; address++) { @@ -72,6 +62,9 @@ bool detectQwiicDevices() // digitalWrite(PIN_LOGIC_DEBUG, LOW); // digitalWrite(PIN_LOGIC_DEBUG, HIGH); //} + somethingDetected = true; + if (settings.printDebugMessages == true) + Serial.printf("detectQwiicDevices: something detected at address 0x%02X\r\n", address); deviceType_e foundType = testMuxDevice(address, 0, 0); //No mux or port numbers for this test if (foundType == DEVICE_MULTIPLEXER) { @@ -82,6 +75,7 @@ bool detectQwiicDevices() } } } + if (muxCount > 0) { if (settings.printDebugMessages == true) @@ -92,17 +86,20 @@ bool detectQwiicDevices() else Serial.println(F(" multiplexers")); } - beginQwiicDevices(); //Because we are about to use a multiplexer, begin() the muxes. + beginQwiicDevices(); //begin() the muxes to disable their ports } - //Before going into sub branches, complete the scan of the main branch for all devices - printDebug("detectQwiicDevices: scanning main bus\r\n"); + //Before going into mux sub branches, scan the main branch for all remaining devices + Serial.println(F("Identifying Qwiic Devices...")); bool foundMS8607 = false; // The MS8607 appears as two devices (MS8607 and MS5637). We need to skip the MS5637 if we have found a MS8607. for (uint8_t address = 1 ; address < 127 ; address++) { qwiic.beginTransmission(address); if (qwiic.endTransmission() == 0) { + somethingDetected = true; + if (settings.printDebugMessages == true) + Serial.printf("detectQwiicDevices: something detected at address 0x%02X\r\n", address); deviceType_e foundType = testDevice(address, 0, 0); //No mux or port numbers for this test if (foundType != DEVICE_UNKNOWN_DEVICE) { @@ -112,7 +109,7 @@ bool detectQwiicDevices() } else { - if (addDevice(foundType, address, 0, 0) == true) //Records this device. //Returns false if device was already recorded. + if (addDevice(foundType, address, 0, 0) == true) //Records this device. //Returns false if mux/device was already recorded. { if (settings.printDebugMessages == true) Serial.printf("detectQwiicDevices: added %s at address 0x%02X\r\n", getDeviceName(foundType), address); @@ -126,6 +123,8 @@ bool detectQwiicDevices() } } + if (somethingDetected == false) return (false); + //If we have muxes, begin scanning their sub nets if (muxCount > 0) { @@ -164,6 +163,9 @@ bool detectQwiicDevices() qwiic.beginTransmission(address); if (qwiic.endTransmission() == 0) { + // We don't need to do anything special for the MCP9600 here, because we can guarantee that beginTransmission + endTransmission + // have only been used once for each MCP9600 address + somethingDetected = true; deviceType_e foundType = testDevice(address, muxNode->address, portNumber); @@ -301,6 +303,12 @@ void menuAttachedDevices() case DEVICE_ADC_ADS122C04: Serial.printf("%s ADS122C04 ADC (Qwiic PT100) %s\r\n", strDeviceMenu, strAddress); break; + case DEVICE_PRESSURE_MPR0025PA1: + Serial.printf("%s MPR MicroPressure Sensor %s\r\n", strDeviceMenu, strAddress); + break; + case DEVICE_PARTICLE_SNGCJA5: + Serial.printf("%s SN-GCJA5 Particle Sensor %s\r\n", strDeviceMenu, strAddress); + break; default: Serial.printf("Unknown device type %d in menuAttachedDevices\r\n", temp->deviceType); break; @@ -1854,3 +1862,280 @@ void menuConfigure_ADS122C04(void *configPtr) printUnknown(incoming); } } + +void menuConfigure_MPR0025PA1(void *configPtr) +{ + struct_MPR0025PA1 *sensorSetting = (struct_MPR0025PA1*)configPtr; + + while (1) + { + Serial.println(); + Serial.println(F("Menu: Configure MPR MicroPressure Sensor")); + + Serial.print(F("1) Sensor Logging: ")); + if (sensorSetting->log == true) Serial.println(F("Enabled")); + else Serial.println(F("Disabled")); + + if (sensorSetting->log == true) + { + Serial.printf("2) Minimum PSI: %d\r\n", sensorSetting->minimumPSI); + + Serial.printf("3) Maximum PSI: %d\r\n", sensorSetting->maximumPSI); + + Serial.print(F("4) Use PSI: ")); + if (sensorSetting->usePSI == true) Serial.println(F("Yes")); + else Serial.println(F("No")); + + Serial.print(F("5) Use Pa: ")); + if (sensorSetting->usePA == true) Serial.println(F("Yes")); + else Serial.println(F("No")); + + Serial.print(F("6) Use kPa: ")); + if (sensorSetting->useKPA == true) Serial.println(F("Yes")); + else Serial.println(F("No")); + + Serial.print(F("7) Use torr: ")); + if (sensorSetting->useTORR == true) Serial.println(F("Yes")); + else Serial.println(F("No")); + + Serial.print(F("8) Use inHg: ")); + if (sensorSetting->useINHG == true) Serial.println(F("Yes")); + else Serial.println(F("No")); + + Serial.print(F("9) Use atm: ")); + if (sensorSetting->useATM == true) Serial.println(F("Yes")); + else Serial.println(F("No")); + + Serial.print(F("10) Use bar: ")); + if (sensorSetting->useBAR == true) Serial.println(F("Yes")); + else Serial.println(F("No")); + + } + Serial.println(F("x) Exit")); + + int incoming = getNumber(menuTimeout); //Timeout after x seconds + + if (incoming == 1) + sensorSetting->log ^= 1; + else if (sensorSetting->log == true) + { + if (incoming == 2) + { + Serial.print(F("Enter the sensor minimum pressure in PSI (this should be 0 for the MPR0025PA): ")); + int minPSI = getNumber(menuTimeout); //x second timeout + if (minPSI < 0 || minPSI > 30) + Serial.println(F("Error: Out of range")); + else + sensorSetting->minimumPSI = minPSI; + } + else if (incoming == 3) + { + Serial.print(F("Enter the sensor maximum pressure in PSI (this should be 25 for the MPR0025PA): ")); + int maxPSI = getNumber(menuTimeout); //x second timeout + if (maxPSI < 0 || maxPSI > 30) + Serial.println(F("Error: Out of range")); + else + sensorSetting->maximumPSI = maxPSI; + } + else if (incoming == 4) + { + sensorSetting->usePSI = true; + sensorSetting->usePA = false; + sensorSetting->useKPA = false; + sensorSetting->useTORR = false; + sensorSetting->useINHG = false; + sensorSetting->useATM = false; + sensorSetting->useBAR = false; + } + else if (incoming == 5) + { + sensorSetting->usePSI = false; + sensorSetting->usePA = true; + sensorSetting->useKPA = false; + sensorSetting->useTORR = false; + sensorSetting->useINHG = false; + sensorSetting->useATM = false; + sensorSetting->useBAR = false; + } + else if (incoming == 6) + { + sensorSetting->usePSI = false; + sensorSetting->usePA = false; + sensorSetting->useKPA = true; + sensorSetting->useTORR = false; + sensorSetting->useINHG = false; + sensorSetting->useATM = false; + sensorSetting->useBAR = false; + } + else if (incoming == 7) + { + sensorSetting->usePSI = false; + sensorSetting->usePA = false; + sensorSetting->useKPA = false; + sensorSetting->useTORR = true; + sensorSetting->useINHG = false; + sensorSetting->useATM = false; + sensorSetting->useBAR = false; + } + else if (incoming == 8) + { + sensorSetting->usePSI = false; + sensorSetting->usePA = false; + sensorSetting->useKPA = false; + sensorSetting->useTORR = false; + sensorSetting->useINHG = true; + sensorSetting->useATM = false; + sensorSetting->useBAR = false; + } + else if (incoming == 9) + { + sensorSetting->usePSI = false; + sensorSetting->usePA = false; + sensorSetting->useKPA = false; + sensorSetting->useTORR = false; + sensorSetting->useINHG = false; + sensorSetting->useATM = true; + sensorSetting->useBAR = false; + } + else if (incoming == 10) + { + sensorSetting->usePSI = false; + sensorSetting->usePA = false; + sensorSetting->useKPA = false; + sensorSetting->useTORR = false; + sensorSetting->useINHG = false; + sensorSetting->useATM = false; + sensorSetting->useBAR = true; + } + else if (incoming == STATUS_PRESSED_X) + break; + else if (incoming == STATUS_GETNUMBER_TIMEOUT) + break; + else + printUnknown(incoming); + } + else if (incoming == STATUS_PRESSED_X) + break; + else if (incoming == STATUS_GETNUMBER_TIMEOUT) + break; + else + printUnknown(incoming); + } +} + +void menuConfigure_SNGCJA5(void *configPtr) +{ + struct_SNGCJA5 *sensorSetting = (struct_SNGCJA5*)configPtr; + + while (1) + { + Serial.println(); + Serial.println(F("Menu: Configure SNGCJA5 Particle Sensor")); + + Serial.print(F("1) Sensor Logging: ")); + if (sensorSetting->log == true) Serial.println(F("Enabled")); + else Serial.println(F("Disabled")); + + if (sensorSetting->log == true) + { + Serial.print(F("2) Log Particle Mass Density 1.0um (ug/m^3): ")); + if (sensorSetting->logPM1 == true) Serial.println(F("Enabled")); + else Serial.println(F("Disabled")); + + Serial.print(F("3) Log Particle Mass Density 2.5um (ug/m^3): ")); + if (sensorSetting->logPM25 == true) Serial.println(F("Enabled")); + else Serial.println(F("Disabled")); + + Serial.print(F("4) Log Particle Mass Density 10.0um (ug/m^3): ")); + if (sensorSetting->logPM10 == true) Serial.println(F("Enabled")); + else Serial.println(F("Disabled")); + + Serial.print(F("5) Log Particle Count 0.5um: ")); + if (sensorSetting->logPC05 == true) Serial.println(F("Enabled")); + else Serial.println(F("Disabled")); + + Serial.print(F("6) Log Particle Count 1.0um: ")); + if (sensorSetting->logPC1 == true) Serial.println(F("Enabled")); + else Serial.println(F("Disabled")); + + Serial.print(F("7) Log Particle Count 2.5um: ")); + if (sensorSetting->logPC25 == true) Serial.println(F("Enabled")); + else Serial.println(F("Disabled")); + + Serial.print(F("8) Log Particle Count 5.0um: ")); + if (sensorSetting->logPC50 == true) Serial.println(F("Enabled")); + else Serial.println(F("Disabled")); + + Serial.print(F("9) Log Particle Count 7.5um: ")); + if (sensorSetting->logPC75 == true) Serial.println(F("Enabled")); + else Serial.println(F("Disabled")); + + Serial.print(F("10) Log Particle Count 10.0um: ")); + if (sensorSetting->logPC10 == true) Serial.println(F("Enabled")); + else Serial.println(F("Disabled")); + + Serial.print(F("11) Log Combined Sensor Status: ")); + if (sensorSetting->logSensorStatus == true) Serial.println(F("Enabled")); + else Serial.println(F("Disabled")); + + Serial.print(F("12) Log PhotoDiode Status: ")); + if (sensorSetting->logPDStatus == true) Serial.println(F("Enabled")); + else Serial.println(F("Disabled")); + + Serial.print(F("13) Log LaserDiode Status: ")); + if (sensorSetting->logLDStatus == true) Serial.println(F("Enabled")); + else Serial.println(F("Disabled")); + + Serial.print(F("14) Log Fan Status: ")); + if (sensorSetting->logFanStatus == true) Serial.println(F("Enabled")); + else Serial.println(F("Disabled")); + } + Serial.println(F("x) Exit")); + + int incoming = getNumber(menuTimeout); //Timeout after x seconds + + if (incoming == 1) + sensorSetting->log ^= 1; + else if (sensorSetting->log == true) + { + if (incoming == 2) + sensorSetting->logPM1 ^= 1; + else if (incoming == 3) + sensorSetting->logPM25 ^= 1; + else if (incoming == 4) + sensorSetting->logPM10 ^= 1; + else if (incoming == 5) + sensorSetting->logPC05 ^= 1; + else if (incoming == 6) + sensorSetting->logPC1 ^= 1; + else if (incoming == 7) + sensorSetting->logPC25 ^= 1; + else if (incoming == 8) + sensorSetting->logPC50 ^= 1; + else if (incoming == 9) + sensorSetting->logPC75 ^= 1; + else if (incoming == 10) + sensorSetting->logPC10 ^= 1; + else if (incoming == 11) + sensorSetting->logSensorStatus ^= 1; + else if (incoming == 12) + sensorSetting->logPDStatus ^= 1; + else if (incoming == 13) + sensorSetting->logLDStatus ^= 1; + else if (incoming == 14) + sensorSetting->logFanStatus ^= 1; + else if (incoming == STATUS_PRESSED_X) + break; + else if (incoming == STATUS_GETNUMBER_TIMEOUT) + break; + else + printUnknown(incoming); + } + else if (incoming == STATUS_PRESSED_X) + break; + else if (incoming == STATUS_GETNUMBER_TIMEOUT) + break; + else + printUnknown(incoming); + } +} diff --git a/Firmware/OpenLog_Artemis/menuIMU.ino b/Firmware/OpenLog_Artemis/menuIMU.ino index e880c2f..c88fae4 100644 --- a/Firmware/OpenLog_Artemis/menuIMU.ino +++ b/Firmware/OpenLog_Artemis/menuIMU.ino @@ -11,27 +11,153 @@ void menuIMU() if (settings.enableIMU == true) { - Serial.print(F("2) Toggle Accelerometer Logging: ")); + Serial.print(F("2) Accelerometer Logging: ")); if (settings.logIMUAccel) Serial.println(F("Enabled")); else Serial.println(F("Disabled")); - Serial.print(F("3) Toggle Gyro Logging: ")); + Serial.print(F("3) Gyro Logging: ")); if (settings.logIMUGyro) Serial.println(F("Enabled")); else Serial.println(F("Disabled")); - Serial.print(F("4) Toggle Magnotometer Logging: ")); + Serial.print(F("4) Magnotometer Logging: ")); if (settings.logIMUMag) Serial.println(F("Enabled")); else Serial.println(F("Disabled")); - Serial.print(F("5) Toggle Temperature Logging: ")); + Serial.print(F("5) Temperature Logging: ")); if (settings.logIMUTemp) Serial.println(F("Enabled")); else Serial.println(F("Disabled")); + + if (online.IMU == true) + { + Serial.print(F("6) Accelerometer Full Scale: +/- ")); + switch (settings.imuAccFSS) + { + case 0: + Serial.println(F("2g")); + break; + case 1: + Serial.println(F("4g")); + break; + case 2: + Serial.println(F("8g")); + break; + case 3: + Serial.println(F("16g")); + break; + default: + Serial.println(F("UNKNOWN")); + break; + } + + Serial.print(F("7) Accelerometer Digital Low Pass Filter: ")); + if (settings.imuAccDLPF) + { + Serial.println(F("Enabled")); + Serial.print(F("8) Accelerometer DLPF Bandwidth (Hz): ")); + switch (settings.imuAccDLPFBW) + { + case 0: + Serial.println(F("246.0 (3dB) 265.0 (Nyquist)")); + break; + case 1: + Serial.println(F("246.0 (3dB) 265.0 (Nyquist)")); + break; + case 2: + Serial.println(F("111.4 (3dB) 136.0 (Nyquist)")); + break; + case 3: + Serial.println(F("50.4 (3dB) 68.8 (Nyquist)")); + break; + case 4: + Serial.println(F("23.9 (3dB) 34.4 (Nyquist)")); + break; + case 5: + Serial.println(F("11.5 (3dB) 17.0 (Nyquist)")); + break; + case 6: + Serial.println(F("5.7 (3dB) 8.3 (Nyquist)")); + break; + case 7: + Serial.println(F("473 (3dB) 499 (Nyquist)")); + break; + default: + Serial.println(F("UNKNOWN")); + break; + } + } + else + { + Serial.println(F("Disabled (Bandwidth is 1209 Hz (3dB) 1248 Hz (Nyquist))")); + } + + Serial.print(F("9) Gyro Full Scale: +/- ")); + switch (settings.imuGyroFSS) + { + case 0: + Serial.println(F("250dps")); + break; + case 1: + Serial.println(F("500dps")); + break; + case 2: + Serial.println(F("1000dps")); + break; + case 3: + Serial.println(F("2000dps")); + break; + default: + Serial.println(F("UNKNOWN")); + break; + } + + Serial.print(F("10) Gyro Digital Low Pass Filter: ")); + if (settings.imuGyroDLPF) + { + Serial.println(F("Enabled")); + Serial.print(F("11) Gyro DLPF Bandwidth (Hz): ")); + switch (settings.imuGyroDLPFBW) + { + case 0: + Serial.println(F("196.6 (3dB) 229.8 (Nyquist)")); + break; + case 1: + Serial.println(F("151.8 (3dB) 187.6 (Nyquist)")); + break; + case 2: + Serial.println(F("119.5 (3dB) 154.3 (Nyquist)")); + break; + case 3: + Serial.println(F("51.2 (3dB) 73.3 (Nyquist)")); + break; + case 4: + Serial.println(F("23.9 (3dB) 35.9 (Nyquist)")); + break; + case 5: + Serial.println(F("11.6 (3dB) 17.8 (Nyquist)")); + break; + case 6: + Serial.println(F("5.7 (3dB) 8.9 (Nyquist)")); + break; + case 7: + Serial.println(F("361.4 (3dB) 376.5 (Nyquist)")); + break; + default: + Serial.println(F("UNKNOWN")); + break; + } + } + else + { + Serial.println(F("Disabled (Bandwidth is 12106 Hz (3dB) 12316 Hz (Nyquist))")); + } + } } + Serial.println(F("x) Exit")); - byte incoming = getByteChoice(menuTimeout); //Timeout after x seconds + int incoming = getNumber(menuTimeout); //Timeout after x seconds - if (incoming == '1') + if (incoming == 1) { settings.enableIMU ^= 1; if (settings.enableIMU == true) beginIMU(); @@ -39,24 +165,142 @@ void menuIMU() } else if (settings.enableIMU == true) { - if (incoming == '2') + if (incoming == 2) settings.logIMUAccel ^= 1; - else if (incoming == '3') + else if (incoming == 3) settings.logIMUGyro ^= 1; - else if (incoming == '4') + else if (incoming == 4) settings.logIMUMag ^= 1; - else if (incoming == '5') + else if (incoming == 5) settings.logIMUTemp ^= 1; - else if (incoming == 'x') + else if ((incoming == 6) && (online.IMU == true)) + { + Serial.println(F("Enter Accelerometer Full Scale (0 to 3): ")); + Serial.println(F("0: +/- 2g")); + Serial.println(F("1: +/- 4g")); + Serial.println(F("2: +/- 8g")); + Serial.println(F("3: +/- 16g")); + int afs = getNumber(menuTimeout); //x second timeout + if (afs < 0 || afs > 3) + Serial.println(F("Error: Out of range")); + else + { + settings.imuAccFSS = afs; + ICM_20948_fss_t FSS; + FSS.a = settings.imuAccFSS; + FSS.g = settings.imuGyroFSS; + ICM_20948_Status_e retval = myICM.setFullScale((ICM_20948_Internal_Acc | ICM_20948_Internal_Gyr), FSS); + if (retval != ICM_20948_Stat_Ok) + { + Serial.println(F("Error: Could not configure the IMU!")); + } + } + } + else if ((incoming == 7) && (online.IMU == true)) + { + settings.imuAccDLPF ^= 1; + ICM_20948_Status_e retval = myICM.enableDLPF(ICM_20948_Internal_Acc, settings.imuAccDLPF); + if (retval != ICM_20948_Stat_Ok) + { + Serial.println(F("Error: Could not configure the IMU!")); + } + } + else if ((incoming == 8) && (online.IMU == true) && (settings.imuAccDLPF == true)) + { + Serial.println(F("Enter Accelerometer DLPF Bandwidth (0 to 7): ")); + Serial.println(F("0: 246.0 (3dB) 265.0 (Nyquist) (Hz)")); + Serial.println(F("1: 246.0 (3dB) 265.0 (Nyquist) (Hz)")); + Serial.println(F("2: 111.4 (3dB) 136.0 (Nyquist) (Hz)")); + Serial.println(F("3: 50.4 (3dB) 68.8 (Nyquist) (Hz)")); + Serial.println(F("4: 23.9 (3dB) 34.4 (Nyquist) (Hz)")); + Serial.println(F("5: 11.5 (3dB) 17.0 (Nyquist) (Hz)")); + Serial.println(F("6: 5.7 (3dB) 8.3 (Nyquist) (Hz)")); + Serial.println(F("7: 473 (3dB) 499 (Nyquist) (Hz)")); + int afbw = getNumber(menuTimeout); //x second timeout + if (afbw < 0 || afbw > 7) + Serial.println(F("Error: Out of range")); + else + { + settings.imuAccDLPFBW = afbw; + ICM_20948_dlpcfg_t dlpcfg; + dlpcfg.a = settings.imuAccDLPFBW; + dlpcfg.g = settings.imuGyroDLPFBW; + ICM_20948_Status_e retval = myICM.setDLPFcfg((ICM_20948_Internal_Acc | ICM_20948_Internal_Gyr), dlpcfg); + if (retval != ICM_20948_Stat_Ok) + { + Serial.println(F("Error: Could not configure the IMU!")); + } + } + } + else if ((incoming == 9) && (online.IMU == true)) + { + Serial.println(F("Enter Gyro Full Scale (0 to 3): ")); + Serial.println(F("0: +/- 250dps")); + Serial.println(F("1: +/- 500dps")); + Serial.println(F("2: +/- 1000dps")); + Serial.println(F("3: +/- 2000dps")); + int gfs = getNumber(menuTimeout); //x second timeout + if (gfs < 0 || gfs > 3) + Serial.println(F("Error: Out of range")); + else + { + settings.imuGyroFSS = gfs; + ICM_20948_fss_t FSS; + FSS.a = settings.imuAccFSS; + FSS.g = settings.imuGyroFSS; + ICM_20948_Status_e retval = myICM.setFullScale((ICM_20948_Internal_Acc | ICM_20948_Internal_Gyr), FSS); + if (retval != ICM_20948_Stat_Ok) + { + Serial.println(F("Error: Could not configure the IMU!")); + } + } + } + else if ((incoming == 10) && (online.IMU == true)) + { + settings.imuGyroDLPF ^= 1; + ICM_20948_Status_e retval = myICM.enableDLPF(ICM_20948_Internal_Gyr, settings.imuGyroDLPF); + if (retval != ICM_20948_Stat_Ok) + { + Serial.println(F("Error: Could not configure the IMU!")); + } + } + else if ((incoming == 11) && (online.IMU == true) && (settings.imuGyroDLPF == true)) + { + Serial.println(F("Enter Gyro DLPF Bandwidth (0 to 7): ")); + Serial.println(F("0: 196.6 (3dB) 229.8 (Nyquist) (Hz)")); + Serial.println(F("1: 151.8 (3dB) 187.6 (Nyquist) (Hz)")); + Serial.println(F("2: 119.5 (3dB) 154.3 (Nyquist) (Hz)")); + Serial.println(F("3: 51.2 (3dB) 73.3 (Nyquist) (Hz)")); + Serial.println(F("4: 23.9 (3dB) 35.9 (Nyquist) (Hz)")); + Serial.println(F("5: 11.6 (3dB) 17.8 (Nyquist) (Hz)")); + Serial.println(F("6: 5.7 (3dB) 8.9 (Nyquist) (Hz)")); + Serial.println(F("7: 361.4 (3dB) 376.5 (Nyquist) (Hz)")); + int gfbw = getNumber(menuTimeout); //x second timeout + if (gfbw < 0 || gfbw > 7) + Serial.println(F("Error: Out of range")); + else + { + settings.imuGyroDLPFBW = gfbw; + ICM_20948_dlpcfg_t dlpcfg; + dlpcfg.a = settings.imuAccDLPFBW; + dlpcfg.g = settings.imuGyroDLPFBW; + ICM_20948_Status_e retval = myICM.setDLPFcfg((ICM_20948_Internal_Acc | ICM_20948_Internal_Gyr), dlpcfg); + if (retval != ICM_20948_Stat_Ok) + { + Serial.println(F("Error: Could not configure the IMU!")); + } + } + } + else if (incoming == STATUS_PRESSED_X) break; - else if (incoming == STATUS_GETBYTE_TIMEOUT) + else if (incoming == STATUS_GETNUMBER_TIMEOUT) break; else printUnknown(incoming); } - else if (incoming == 'x') + else if (incoming == STATUS_PRESSED_X) break; - else if (incoming == STATUS_GETBYTE_TIMEOUT) + else if (incoming == STATUS_GETNUMBER_TIMEOUT) break; else printUnknown(incoming); diff --git a/Firmware/OpenLog_Artemis/nvm.ino b/Firmware/OpenLog_Artemis/nvm.ino index 5f8e2e1..8e9a58c 100644 --- a/Firmware/OpenLog_Artemis/nvm.ino +++ b/Firmware/OpenLog_Artemis/nvm.ino @@ -148,6 +148,12 @@ void recordSystemSettingsToFile() settingsFile.println("frequentFileAccessTimestamps=" + (String)settings.frequentFileAccessTimestamps); settingsFile.println("useGPIO11ForTrigger=" + (String)settings.useGPIO11ForTrigger); settingsFile.println("fallingEdgeTrigger=" + (String)settings.fallingEdgeTrigger); + settingsFile.println("imuAccDLPF=" + (String)settings.imuAccDLPF); + settingsFile.println("imuGyroDLPF=" + (String)settings.imuGyroDLPF); + settingsFile.println("imuAccFSS=" + (String)settings.imuAccFSS); + settingsFile.println("imuAccDLPFBW=" + (String)settings.imuAccDLPFBW); + settingsFile.println("imuGyroFSS=" + (String)settings.imuGyroFSS); + settingsFile.println("imuGyroDLPFBW=" + (String)settings.imuGyroDLPFBW); updateDataFileAccess(&settingsFile); // Update the file access time & date settingsFile.close(); } @@ -376,6 +382,18 @@ bool parseLine(char* str) { settings.useGPIO11ForTrigger = d; else if (strcmp(settingName, "fallingEdgeTrigger") == 0) settings.fallingEdgeTrigger = d; + else if (strcmp(settingName, "imuAccDLPF") == 0) + settings.imuAccDLPF = d; + else if (strcmp(settingName, "imuGyroDLPF") == 0) + settings.imuGyroDLPF = d; + else if (strcmp(settingName, "imuAccFSS") == 0) + settings.imuAccFSS = d; + else if (strcmp(settingName, "imuAccDLPFBW") == 0) + settings.imuAccDLPFBW = d; + else if (strcmp(settingName, "imuGyroFSS") == 0) + settings.imuGyroFSS = d; + else if (strcmp(settingName, "imuGyroDLPFBW") == 0) + settings.imuGyroDLPFBW = d; else Serial.printf("Unknown setting %s on line: %s\r\n", settingName, str); @@ -593,6 +611,40 @@ void recordDeviceSettingsToFile() settingsFile.println((String)base + "useTwoWireHighTemperatureMode=" + nodeSetting->useTwoWireHighTemperatureMode); } break; + case DEVICE_PRESSURE_MPR0025PA1: + { + struct_MPR0025PA1 *nodeSetting = (struct_MPR0025PA1 *)temp->configPtr; + settingsFile.println((String)base + "log=" + nodeSetting->log); + settingsFile.println((String)base + "minimumPSI=" + nodeSetting->minimumPSI); + settingsFile.println((String)base + "maximumPSI=" + nodeSetting->maximumPSI); + settingsFile.println((String)base + "usePSI=" + nodeSetting->usePSI); + settingsFile.println((String)base + "usePA=" + nodeSetting->usePA); + settingsFile.println((String)base + "useKPA=" + nodeSetting->useKPA); + settingsFile.println((String)base + "useTORR=" + nodeSetting->useTORR); + settingsFile.println((String)base + "useINHG=" + nodeSetting->useINHG); + settingsFile.println((String)base + "useATM=" + nodeSetting->useATM); + settingsFile.println((String)base + "useBAR=" + nodeSetting->useBAR); + } + break; + case DEVICE_PARTICLE_SNGCJA5: + { + struct_SNGCJA5 *nodeSetting = (struct_SNGCJA5 *)temp->configPtr; + settingsFile.println((String)base + "log=" + nodeSetting->log); + settingsFile.println((String)base + "logPM1=" + nodeSetting->logPM1); + settingsFile.println((String)base + "logPM25=" + nodeSetting->logPM25); + settingsFile.println((String)base + "logPM10=" + nodeSetting->logPM10); + settingsFile.println((String)base + "logPC05=" + nodeSetting->logPC05); + settingsFile.println((String)base + "logPC1=" + nodeSetting->logPC1); + settingsFile.println((String)base + "logPC25=" + nodeSetting->logPC25); + settingsFile.println((String)base + "logPC50=" + nodeSetting->logPC50); + settingsFile.println((String)base + "logPC75=" + nodeSetting->logPC75); + settingsFile.println((String)base + "logPC10=" + nodeSetting->logPC10); + settingsFile.println((String)base + "logSensorStatus=" + nodeSetting->logSensorStatus); + settingsFile.println((String)base + "logPDStatus=" + nodeSetting->logPDStatus); + settingsFile.println((String)base + "logLDStatus=" + nodeSetting->logLDStatus); + settingsFile.println((String)base + "logFanStatus=" + nodeSetting->logFanStatus); + } + break; default: Serial.printf("recordSettingsToFile Unknown device: %s\r\n", base); //settingsFile.println((String)base + "=UnknownDeviceSettings"); @@ -1052,6 +1104,68 @@ bool parseDeviceLine(char* str) { Serial.printf("Unknown device setting: %s\r\n", deviceSettingName); } break; + case DEVICE_PRESSURE_MPR0025PA1: + { + struct_MPR0025PA1 *nodeSetting = (struct_MPR0025PA1 *)deviceConfigPtr; //Create a local pointer that points to same spot as node does + if (strcmp(deviceSettingName, "log") == 0) + nodeSetting->log = d; + else if (strcmp(deviceSettingName, "minimumPSI") == 0) + nodeSetting->minimumPSI = d; + else if (strcmp(deviceSettingName, "maximumPSI") == 0) + nodeSetting->maximumPSI = d; + else if (strcmp(deviceSettingName, "usePSI") == 0) + nodeSetting->usePSI = d; + else if (strcmp(deviceSettingName, "usePA") == 0) + nodeSetting->usePA = d; + else if (strcmp(deviceSettingName, "useKPA") == 0) + nodeSetting->useKPA = d; + else if (strcmp(deviceSettingName, "useTORR") == 0) + nodeSetting->useTORR = d; + else if (strcmp(deviceSettingName, "useINHG") == 0) + nodeSetting->useINHG = d; + else if (strcmp(deviceSettingName, "useATM") == 0) + nodeSetting->useATM = d; + else if (strcmp(deviceSettingName, "useBAR") == 0) + nodeSetting->useBAR = d; + else + Serial.printf("Unknown device setting: %s\r\n", deviceSettingName); + } + break; + case DEVICE_PARTICLE_SNGCJA5: + { + struct_SNGCJA5 *nodeSetting = (struct_SNGCJA5 *)deviceConfigPtr; //Create a local pointer that points to same spot as node does + if (strcmp(deviceSettingName, "log") == 0) + nodeSetting->log = d; + else if (strcmp(deviceSettingName, "logPM1") == 0) + nodeSetting->logPM1 = d; + else if (strcmp(deviceSettingName, "logPM25") == 0) + nodeSetting->logPM25 = d; + else if (strcmp(deviceSettingName, "logPM10") == 0) + nodeSetting->logPM10 = d; + else if (strcmp(deviceSettingName, "logPC05") == 0) + nodeSetting->logPC05 = d; + else if (strcmp(deviceSettingName, "logPC1") == 0) + nodeSetting->logPC1 = d; + else if (strcmp(deviceSettingName, "logPC25") == 0) + nodeSetting->logPC25 = d; + else if (strcmp(deviceSettingName, "logPC50") == 0) + nodeSetting->logPC50 = d; + else if (strcmp(deviceSettingName, "logPC75") == 0) + nodeSetting->logPC75 = d; + else if (strcmp(deviceSettingName, "logPC10") == 0) + nodeSetting->logPC10 = d; + else if (strcmp(deviceSettingName, "logSensorStatus") == 0) + nodeSetting->logSensorStatus = d; + else if (strcmp(deviceSettingName, "logPDStatus") == 0) + nodeSetting->logPDStatus = d; + else if (strcmp(deviceSettingName, "logLDStatus") == 0) + nodeSetting->logLDStatus = d; + else if (strcmp(deviceSettingName, "logFanStatus") == 0) + nodeSetting->logFanStatus = d; + else + Serial.printf("Unknown device setting: %s\r\n", deviceSettingName); + } + break; default: Serial.printf("Unknown device type: %d\r\n", deviceType); Serial.flush(); diff --git a/Firmware/OpenLog_Artemis/settings.h b/Firmware/OpenLog_Artemis/settings.h index e3a4423..37d2dac 100644 --- a/Firmware/OpenLog_Artemis/settings.h +++ b/Firmware/OpenLog_Artemis/settings.h @@ -21,6 +21,8 @@ typedef enum DEVICE_HUMIDITY_AHT20, DEVICE_HUMIDITY_SHTC3, DEVICE_ADC_ADS122C04, + DEVICE_PRESSURE_MPR0025PA1, // 0-25 PSI, I2C Address 0x18 + DEVICE_PARTICLE_SNGCJA5, DEVICE_TOTAL_DEVICES, //Marks the end, used to iterate loops DEVICE_UNKNOWN_DEVICE, @@ -246,6 +248,39 @@ struct struct_ADS122C04 { unsigned long powerOnDelayMillis = minimumQwiicPowerOnDelay; // Wait for at least this many millis before communicating with this device. Increase if required! }; +struct struct_MPR0025PA1 { + bool log = true; + int minimumPSI = 0; + int maximumPSI = 25; + bool usePSI = true; + bool usePA = false; + bool useKPA = false; + bool useTORR = false; + bool useINHG = false; + bool useATM = false; + bool useBAR = false; + unsigned long powerOnDelayMillis = minimumQwiicPowerOnDelay; // Wait for at least this many millis before communicating with this device. Increase if required! +}; + +struct struct_SNGCJA5 { + bool log = true; + bool logPM1 = true; + bool logPM25 = true; + bool logPM10 = true; + bool logPC05 = true; + bool logPC1 = true; + bool logPC25 = true; + bool logPC50 = true; + bool logPC75 = true; + bool logPC10 = true; + bool logSensorStatus = false; + bool logPDStatus = true; + bool logLDStatus = true; + bool logFanStatus = true; + unsigned long powerOnDelayMillis = minimumQwiicPowerOnDelay; // Wait for at least this many millis before communicating with this device. Increase if required! +}; + + //This is all the settings that can be set on OpenLog. It's recorded to NVM and the config file. struct struct_settings { int sizeOfSettings = 0; //sizeOfSettings **must** be the first entry and must be int @@ -308,6 +343,12 @@ struct struct_settings { bool frequentFileAccessTimestamps = false; // If true, the log file access timestamps are updated every 500ms bool useGPIO11ForTrigger = false; // If true, use GPIO to trigger sensor logging bool fallingEdgeTrigger = true; // Default to falling-edge triggering (If false, triggering will be rising-edge) + bool imuAccDLPF = false; // IMU accelerometer Digital Low Pass Filter - default to disabled + bool imuGyroDLPF = false; // IMU gyro Digital Low Pass Filter - default to disabled + int imuAccFSS = 0; // IMU accelerometer full scale - default to gpm2 (ICM_20948_ACCEL_CONFIG_FS_SEL_e) + int imuAccDLPFBW = 7; // IMU accelerometer DLPF bandwidth - default to acc_d473bw_n499bw (ICM_20948_ACCEL_CONFIG_DLPCFG_e) + int imuGyroFSS = 0; // IMU gyro full scale - default to 250 degrees per second (ICM_20948_GYRO_CONFIG_1_FS_SEL_e) + int imuGyroDLPFBW = 7; // IMU gyro DLPF bandwidth - default to gyr_d361bw4_n376bw5 (ICM_20948_GYRO_CONFIG_1_DLPCFG_e) } settings; //These are the devices on board OpenLog that may be on or offline. diff --git a/README.md b/README.md index 19830ce..b025ae0 100644 --- a/README.md +++ b/README.md @@ -69,6 +69,7 @@ Documentation * **[UPGRADE.md](./UPGRADE.md)** - contains full instructions on how to upgrade the firmware on the OLA using the [Artemis Firmware Upload GUI](https://github.com/sparkfun/Artemis-Firmware-Upload-GUI). * **[CONTRIBUTING.md](./CONTRIBUTING.md)** - guidance on how to contribute to this library. * **[Installing an Arduino Library Guide](https://learn.sparkfun.com/tutorials/installing-an-arduino-library)** - OLA includes a large number of libraries that will need to be installed before compiling will work. +* **[ADDING_SENSORS.md](./ADDING_SENSORS.md)** - contains _abbreviated_ instructions on how to add a new sensor to the OLA firmware. It's more of an aide-memoire really... License Information -------------------