Sensor Basics Utility Library


These are basic features that could be used if required... But was something made in "spare time"

Source Code Location

Files:

Dependencies:


pH Sensor Functions

validate_ph_value()

Validates if 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 value to validate.
 * @return RESULT_OK if the value is valid, RESULT_ERR_INVALID_DATA otherwise.
 */
result_t validate_ph_value(float ph_value);

Implementation:

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:

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) + 32

Parameters:

Return Values:

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 where 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 = (°F - 32) × 5/9

Status: Currently commented out in implementation


IMU (Accelerometer) Functions

validate_accelerometer_value()

Validates if a single accelerometer value is within the typical range.

/**
 * @brief Validates if an accelerometer value is within the typical 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:

Valid Range: -160.0 to +160.0 m/s² (typical ±16g sensor range)

Return Values:

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 of accelerometer data.
 * @param accel_x The acceleration value for the X-axis.
 * @param accel_y The acceleration value for the Y-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:

Return Values:

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

bar_to_psi()

Converts pressure from bar to psi (pounds per square inch).

/**
 * @brief Converts pressure from bar to psi.
 * @param 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.
 */
result_t bar_to_psi(float bar, float *psi);

Conversion Formula: psi = bar × 14.5038

Parameters:

Return Values:

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);

Conversion Formula: bar = psi ÷ 14.5038

Status: 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:

Valid Range: -90.0 to +90.0 degrees

Return Values:

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:

Valid Range: -180.0 to +180.0 degrees

Return Values:

validate_gps_hdop()

Validates GPS Horizontal Dilution of Precision (HDOP) 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:

Valid Range: 0.0 to 50.0

HDOP Quality Interpretation:

Return Values:

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:

Valid Range: 0 to 30 satellites

Satellite Count Guidance:

Return Values:

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");
    diagnostics.gps_sensor_1.state = SENSOR_ERROR;
}

Error Handling Pattern

All validation functions follow a consistent pattern:

// Check sensor data
if (validate_<sensor>_<field>(value) == RESULT_OK) {
    // Data is valid - use it
    diagnostics.<sensor>.state = SENSOR_OPERATING;
} else {
    // Data is invalid - set error state
    diagnostics.<sensor>.state = SENSOR_ERROR;
    diagnostics.<sensor>.error_code = <ERROR_CODE>_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):

Currently Commented Out (Inactive):

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 Suite Location: test/sensor_board/test_sensor_basics/

Building Tests:

// Run all 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

Test Coverage:


Integration in Main Application

Typical Usage in main.c:

// 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;
}

Revision #2
Created 2026-04-14 17:10:12 UTC by Shishir Nambiar
Updated 2026-04-14 17:17:39 UTC by Shishir Nambiar