Sensor Basics Utility Library
The
Sensor Basics utility library provides small validation and conversion helpers shared by the sensor drivers and the main application. These are basic features that could be used if required...required, Butbut was somethingwere made in "spare time".
Source Code Location
Files:
components/sensor_board/sensor_basics/sensor_basics.h- Function(function declarations anddocumentationdocumentation)components/sensor_board/sensor_basics/sensor_basics.c- Implementation(implementation)
Dependencies:
result.h- Standard(standard result/error code definitions and the TRY macro)stdint.h- Integer(integer typedefinitionsdefinitions)
pH Sensor FunctionsValidation
validate_ph_value()
Validates ifthat a pH value is within the acceptable range (0-14).
/**
* @brief Validates if a pH value is within the acceptable range (0-14).
* @param ph_value The pH value0 to validate.
* @return RESULT_OK if the value is valid, RESULT_ERR_INVALID_DATA otherwise.
*/
result_t validate_ph_value(float ph_value);Implementation:14).
result_t validate_ph_value(float ph_value) {
if (ph_value >= 0.0f && ph_value <= 14.0f) {
return RESULT_OK;
}
return RESULT_ERR_INVALID_DATA;
}
Parameters:Return values:
ph_value-RESULT_OKFloatwhen the valueto validate (typical range: 0.0 to 14.0)
Return Values:
RESULT_OK- Valueis withinvalidrange,rangeRESULT_ERR_INVALID_DATA- Value is outside 0-14 range
Usage Example:
float ph_reading = ph_sensor.ph_value;
if (validate_ph_value(ph_reading) == RESULT_OK) {
LOG_INFO("pH sensor valid: %.2f", ph_reading);
diagnostics.ph_sensor.state = SENSOR_OPERATING;
} else {
LOG_ERROR("pH out of range: %.2f", ph_reading);
diagnostics.ph_sensor.state = SENSOR_ERROR;
diagnostics.ph_sensor.error_code = PHErrorCode_PH_INVALID_DATA;
}Temperature Conversion Functions
celsius_to_fahrenheit()
Converts temperature from Celsius to Fahrenheit.
/**
* @brief Converts temperature from Celsius to Fahrenheit.
* @param celsius The temperature in Celsius.
* @param fahrenheit Pointer to a float where the converted Fahrenheit temperature will be stored.
* @return RESULT_OK on success, or RESULT_ERR_INVALID_ARG if fahrenheit is NULL.
*/
result_t celsius_to_fahrenheit(float celsius, float *fahrenheit);Conversion Formula: °F = (°C × 9/5) + 32otherwise.
Parameters:Note:
celsius-ph_sensor_update()InputalreadytemperatureclampsinitsCelsiusfahrenheit- Pointeroutput tooutput0..14,variableso(mustthisnotcheckbeonlyNULL)
Returnfor Values:
thatRESULT_OK- Conversion successfulRESULT_ERR_INVALID_ARG- fahrenheit pointer is NULL
Status: Currently commented out in implementation
Usage Example:
float temp_celsius = 25.0f;
float temp_fahrenheit;
if (celsius_to_fahrenheit(temp_celsius, &temp_fahrenheit) == RESULT_OK) {
LOG_INFO("Temperature: %.1f°C = %.1f°F", temp_celsius, temp_fahrenheit);
}fahrenheit_to_celsius()
Converts temperature from Fahrenheit to Celsius.
/**
* @brief Converts temperature from Fahrenheit to Celsius.
* @param fahrenheit The temperature in Fahrenheit.
* @param celsius Pointer to a float wherebypass the converted Celsius temperature will be stored.
* @return RESULT_OK on success, or RESULT_ERR_INVALID_ARG if celsius is NULL.
*/
result_t fahrenheit_to_celsius(float fahrenheit, float *celsius);Conversion Formula: °C =driver (°Ffor -example 32)raw ×values 5/9received over the network).
Status: Currently commented out in implementation
IMU (Accelerometer) FunctionsValidation
validate_accelerometer_value()
Validates ifone accelerometer axis. Valid range is -160.0 to +160.0 m/s², which corresponds to a single accelerometer value is within the typical range.
/**g * @brief Validates if an accelerometer value is within the typicalsensor range.
* @param accel_value The accelerometer value to validate.
* @return RESULT_OK if the value is valid, RESULT_ERR_INVALID_DATA otherwise.
*/
result_t validate_accelerometer_value(float accel_value);Implementation:
result_t validate_accelerometer_value(float accel_value) {
if (accel_value >= -160.0f && accel_value <= 160.0f) {
return RESULT_OK;
}
return RESULT_ERR_INVALID_DATA;
}
Parameters:
accel_value- Single axis acceleration value in m/s²
Valid Range: -160.0 to +160.0 m/s² (typical ±16g sensor range)
Return Values:
RESULT_OK- Value is within valid rangeRESULT_ERR_INVALID_DATA- Value exceeds acceptable limits
Usage Example:
float accel_x = imu_data.accel[0];
if (validate_accelerometer_value(accel_x) == RESULT_OK) {
LOG_DEBUG("Accel X valid: %.2f m/s²", accel_x);
} else {
LOG_ERROR("Accel X out of range: %.2f m/s²", accel_x);
}validate_imu_data()
Validates all three axes of accelerometer data simultaneously.
/**
* @brief Validates all three axes ofat accelerometeronce data.using *the @paramTRY accel_x The acceleration valuemacro for theearly X-axis.return * @param accel_y The acceleration value foron the Y-first invalid axis.
* @param accel_z The acceleration value for the Z-axis.
* @return RESULT_OK if all values are valid, RESULT_ERR_INVALID_DATA otherwise.
*/
result_t validate_imu_data(float accel_x, float accel_y, float accel_z);Implementation:
result_t validate_imu_data(float accel_x, float accel_y, float accel_z) {
TRY(validate_accelerometer_value(accel_x));
TRY(validate_accelerometer_value(accel_y));
TRY(validate_accelerometer_value(accel_z));
return RESULT_OK;
}
Parameters:Note: the IMU driver has its own richer validators (imu_validate_accelerometer_range, imu_validate_gyroscope_range, imu_validate_magnetometer_range) which the main loop uses. See the imu component.
accel_x- X-axis acceleration (m/s²)accel_y- Y-axis acceleration (m/s²)accel_z- Z-axis acceleration (m/s²)
Return Values:
RESULT_OK- All three axes within valid rangeRESULT_ERR_INVALID_DATA- Any axis exceeds acceptable limits
Usage Example:
if (validate_imu_data(imu_data.accel[0], imu_data.accel[1], imu_data.accel[2]) == RESULT_OK) {
LOG_INFO("IMU acceleration valid");
diagnostics.imu_sensor.state = SENSOR_OPERATING;
} else {
LOG_ERROR("IMU acceleration out of range");
diagnostics.imu_sensor.state = SENSOR_ERROR;
}Pressure Conversion Functions (declared, currently inactive)
bar_to_psi()
The
Convertsheader pressuredeclares fromfour barunit toconversion psihelpers. (poundsTheir perimplementations squareexist inch).in sensor_basics.c but are commented out, so linking against them fails until they are re-enabled.
/** Temperature: F = C * @brief9/5 Converts+ pressure32, fromC = (F - 32) * 5/9 */
result_t celsius_to_fahrenheit(float celsius, float *fahrenheit);
result_t fahrenheit_to_celsius(float fahrenheit, float *celsius);
/* Pressure: psi = bar to psi.
* @param14.5038, bar The pressure in bar.
* @param= psi Pointer/ to a float where the converted psi pressure will be stored.
* @return RESULT_OK on success, or RESULT_ERR_INVALID_ARG if psi is NULL.14.5038 */
result_t bar_to_psi(float bar, float *psi);Conversion Formula: psi = bar × 14.5038
Parameters:
bar- Pressure in barpsi- Pointer to output variable (must not be NULL)
Return Values:
RESULT_OK- Conversion successfulRESULT_ERR_INVALID_ARG- psi pointer is NULL
Status: Currently commented out in implementation
Usage Example:
float pressure_bar = 5.0f;
float pressure_psi;
if (bar_to_psi(pressure_bar, &pressure_psi) == RESULT_OK) {
LOG_INFO("Pressure: %.2f bar = %.2f psi", pressure_bar, pressure_psi);
}psi_to_bar()
Converts pressure from psi to bar.
/**
* @brief Converts pressure from psi to bar.
* @param psi The pressure in psi.
* @param bar Pointer to a float where the converted bar pressure will be stored.
* @return RESULT_OK on success, or RESULT_ERR_INVALID_ARG if bar is NULL.
*/
result_t psi_to_bar(float psi, float *bar);
ConversionEach Formula:returns barRESULT_OK =on psisuccess ÷or 14.5038RESULT_ERR_INVALID_ARG when the output pointer is NULL.
Implementation Status
Status:Currently implemented (active):
- validate_ph_value()
- validate_accelerometer_value()
- validate_imu_data()
Currently commented out in implementation
GPS Functions
validate_gps_latitude()
Validates GPS latitude value is within valid range.
/**
* @brief Validates GPS latitude value.
* @param latitude The latitude value to validate (-90 to +90 degrees).
* @return RESULT_OK if the value is valid, RESULT_ERR_INVALID_DATA otherwise.
*/
result_t validate_gps_latitude(double latitude);Implementation:
result_t validate_gps_latitude(double latitude) {
if (latitude >= -90.0 && latitude <= 90.0) {
return RESULT_OK;
}
return RESULT_ERR_INVALID_DATA;
}Parameters:inactive):
latitude- Latitude in degrees (double precision)celsius_to_fahrenheit()- fahrenheit_to_celsius()
- bar_to_psi()
- psi_to_bar()
Valid Range:Note: -90.0earlier to +90.0 degrees
Negative = SouthPositive = North0° = Equator
Return Values:
RESULT_OK- Value is within valid rangeRESULT_ERR_INVALID_DATA- Value outside ±90 degrees
validate_gps_longitude()
Validates GPS longitude value is within valid range.
/**
* @brief Validates GPS longitude value.
* @param longitude The longitude value to validate (-180 to +180 degrees).
* @return RESULT_OK if the value is valid, RESULT_ERR_INVALID_DATA otherwise.
*/
result_t validate_gps_longitude(double longitude);Implementation:
result_t validate_gps_longitude(double longitude) {
if (longitude >= -180.0 && longitude <= 180.0) {
return RESULT_OK;
}
return RESULT_ERR_INVALID_DATA;
}Parameters:
longitude- Longitude in degrees (double precision)
Valid Range: -180.0 to +180.0 degrees
Negative = WestPositive = East0° = Prime Meridian±180° = International Date Line
Return Values:
RESULT_OK- Value is within valid rangeRESULT_ERR_INVALID_DATA- Value outside ±180 degrees
validate_gps_hdop()
Validates GPS Horizontal Dilutiondrafts of Precisionthis (HDOP)page value.
/**
* @brief Validates GPS HDOP value.
* @param hdop The HDOP value to validate (0-50 typical range).
* @return RESULT_OK if the value is valid, RESULT_ERR_INVALID_DATA otherwise.
*/
result_t validate_gps_hdop(float hdop);Implementation:
result_t validate_gps_hdop(float hdop) {
if (hdop >= 0.0f && hdop <= 50.0f) {
return RESULT_OK;
}
return RESULT_ERR_INVALID_DATA;
}Parameters:
hdop- Horizontal dilution of precision value
Valid Range: 0.0 to 50.0
HDOP Quality Interpretation:
<1 - Ideal1-2 - Excellent2-5 - Good5-10 - Moderate10-20 - Fair>20 - Poor
Return Values:
RESULT_OK- Value is within valid rangeRESULT_ERR_INVALID_DATA- Value exceeds acceptable limits
validate_gps_satellite_count()
Validates GPS satellite count is within valid range.
/**
* @brief Validates GPS satellite count.
* @param satellites The number of satellites to validate.
* @return RESULT_OK if the value is valid, RESULT_ERR_INVALID_DATA otherwise.
*/
result_t validate_gps_satellite_count(int32_t satellites);Implementation:
result_t validate_gps_satellite_count(int32_t satellites) {
if (satellites >= 0 && satellites <= 30) {
return RESULT_OK;
}
return RESULT_ERR_INVALID_DATA;
}Parameters:
satellites- Number of satellites in view
Valid Range: 0 to 30 satellites
Satellite Count Guidance:
0-3 - No/poor fix possible4-5 - 3D fix possible6-9 - Good coverage10+ - Excellent coverage
Return Values:
RESULT_OK- Value is within valid rangeRESULT_ERR_INVALID_DATA- Negative value or exceeds 30
Usage Example (Full GPS Validation):
if (validate_gps_latitude(gps_data.latitude) == RESULT_OK &&
validate_gps_longitude(gps_data.longitude) == RESULT_OK &&
validate_gps_hdop(gps_data.hdop) == RESULT_OK &&
validate_gps_satellite_count(gps_data.satellites) == RESULT_OK) {
LOG_INFO("GPS fix valid: %.6f, %.6f (sats=%d)",
gps_data.latitude, gps_data.longitude, gps_data.satellites);
diagnostics.gps_sensor_1.state = SENSOR_OPERATING;
} else {
LOG_WARNING("GPS validation failed");helpers diagnostics.gps_sensor_1.state(latitude, =longitude, SENSOR_ERROR;HDOP, }satellite count). These functions do not exist in the current library since there is no GPS driver on the sensor board.
Error Handling Pattern
All validation functions follow athe consistentsame pattern:pattern used across the firmware:
// Check sensor data
if (validate_<sensor>_<field>(value)validate_ph_value(ph_value) == RESULT_OK) {
// Data is valid - use it
diagnostics.<sensor>.ph_sensor.state = SENSOR_OPERATING;SensorState_SENSOR_OPERATING;
diagnostics.ph_sensor.error_code = PHErrorCode_PH_NO_ERROR;
} else {
// Data is invalid - set error state
diagnostics.<sensor>.ph_sensor.state = SENSOR_ERROR;SensorState_SENSOR_ERROR;
diagnostics.<sensor>.ph_sensor.error_code = <ERROR_CODE>_INVALID_DATA;PHErrorCode_PH_INVALID_DATA;
}TRY Macro Usage:
The implementation uses a TRY() macro for error propagation (from result.h):
// In validate_imu_data()
result_t validate_imu_data(float accel_x, float accel_y, float accel_z) {
TRY(validate_accelerometer_value(accel_x)); // Return on error
TRY(validate_accelerometer_value(accel_y)); // Return on error
TRY(validate_accelerometer_value(accel_z)); // Return on error
return RESULT_OK;
}Implementation Status
Currently Implemented (Active):
✓ validate_ph_value()✓ validate_accelerometer_value()✓ validate_imu_data()✓ validate_gps_latitude()✓ validate_gps_longitude()✓ validate_gps_hdop()✓ validate_gps_satellite_count()
Currently Commented Out (Inactive):
⊘ celsius_to_fahrenheit() - Declared but not implemented⊘ fahrenheit_to_celsius() - Declared but not implemented⊘ bar_to_psi() - Declared but not implemented⊘ psi_to_bar() - Declared but not implemented
Note: Temperature and pressure conversions are stubbed out in the current implementation. They can be enabled by uncommenting the implementation in sensor_basics.c if needed for future features.
Testing
Test Suitesuite Location:location: test/sensor_board/test_sensor_basics/
Building Tests:
//# Run allonly the sensor_basics tests
pio test -e sensor_board -f test_sensor_basics
//# Run with verbose output
pio test -e sensor_board -f test_sensor_basics -v
TestCurrent Coverage:
Boundaryaccelerometervalueboundarytestingvalues (min/max ranges)Edge cases (±160.0values,accepted,extreme±160.1values)Validrejected)rangeandacceptanceInvalidmulti-axisrangecombination.rejectionNULLThepointertemperaturehandlingandforpressure conversionfunctions
Integrationexist in Mainthe Application
file Typicalbut Usageare incommented main.c:out together with their implementations.
// After polling a sensor
result_t poll_result = poll_gps_sensor(&gps_data);
if (poll_result == RESULT_OK) {
// Validate all GPS fields before using
if (validate_gps_latitude(gps_data.latitude) == RESULT_OK &&
validate_gps_longitude(gps_data.longitude) == RESULT_OK) {
diagnostics.gps_sensor_1.state = SENSOR_OPERATING;
// Safe to use: gps_data.latitude, gps_data.longitude
} else {
diagnostics.gps_sensor_1.state = SENSOR_ERROR;
diagnostics.gps_sensor_1.error_code = GPS_INVALID_DATA;
}
} else if (poll_result == RESULT_ERR_COMMS) {
diagnostics.gps_sensor_1.state = SENSOR_ERROR;
diagnostics.gps_sensor_1.error_code = GPS_COMMUNICATION_FAILURE;
}