Project 7.05 Section 7 ⚡ Embedded Relevance: Critical Safety Critical Fail-Safe Threshold Monitoring MISRA C++ ADC

7.05 Real-Time Sensor Monitoring, Emergency Thresholds & Hardware Fail-Safe States

Executive Summary: Building a safety-critical fuel level monitoring system with custom exception triggers. We analyze how embedded systems implement fail-safe latching, hardware interrupt watchdog trips, and safety state machines (e.g. ISO 26262 ASIL-D and IEC 61508 SIL-3).

💻 1. Annotated Source Code

#include <iostream>
#include <stdexcept>
#include "FuelLevelCritical.h"
using namespace std;

void checkFuelLevel(int percentage);

int main() {

	cout << "Fuel Monitor Starting..." << endl;

	try {
		for (int i = 100; i >= 0; i -= 10) {
			checkFuelLevel(i);
		}
	}
	catch (const FuelLevelCritical& err) {
		cout << "ALERT: " << err.what() << endl;
	}

	return 0;
}

void checkFuelLevel(int percentage) {
	if (percentage < 10) {
		throw FuelLevelCritical();
	}

	cout << "Fuel level at " << percentage << "% - within safe operating range." << endl;
}
#ifndef FUEL_LEVEL_CRITICAL_H
#define FUEL_LEVEL_CRITICAL_H

#include <stdexcept>
using namespace std;

class FuelLevelCritical : public runtime_error {

	public:
		FuelLevelCritical() : 
			runtime_error("Fuel level is critically low! Ship must refuel immediately!") {

		}
};

#endif 

📐 2. Architecture & UML Class Model

📐 LowFuelException & Fuel Tank Safety Invariants Model
+ Public - Private # Protected
<<class>> std::runtime_error Base Exception
(none / stateless)
+what() : const char*[virtual, noexcept]
<<class>> LowFuelException Domain Fault Exception
-remainingGallons : double
+LowFuelException(gallons: double)
+getRemainingGallons() : double const
+what() : const char*[override, noexcept]
<<class>> FuelTank Tank Monitor
-capacityGallons : double = 15.0
-currentFuel : double
-MIN_SAFE_FUEL : constexpr double = 2.0
+FuelTank(initialFuel: double)
+consumeFuel(gallons: double) : void[throws LowFuelException]
+addFuel(gallons: double) : void
+getCurrentFuel() : double const
🔗 Architectural Relationships & Hierarchy
LowFuelException ──▷ inherits ──▷ std::runtime_error
FuelTank ─ ─ > throws on low level ─ ─ > LowFuelException

📚 3. Core C++ Concepts Deep-Dive

1. Domain-Specific Alert Hierarchies

Critical systems define distinct exception/alert tiers (e.g., FuelWarning vs FuelLevelCritical). Each tier enforces appropriate escalation behavior.

2. Exception-Driven Control Flow Hazards

Using exceptions for ordinary control flow (e.g. routine sensor polling) is an anti-pattern. Exceptions should only be reserved for truly exceptional, unrecoverable system faults.

⚡ 4. Embedded Systems & Hardware Reality

1. Safety State Machines (ISO 26262 & IEC 61508)

In safety-critical automotive/aerospace firmware, when a sensor reading breaches a critical safety envelope:

  • Fail-Safe State Transition: The system immediately switches to a predefined safe state (e.g., cutting fuel pump power, opening safety contactors, engaging mechanical brakes).
  • Fault Latching: The fault is latched in non-volatile memory and cannot be cleared until a full self-test or authorized service reset.

2. Hardware Analog Watchdog (AWD) in STM32 / NXP

Instead of software polling, modern microcontrollers provide hardware Analog Watchdogs on ADC channels that fire a dedicated hardware interrupt within sub-microsecond latency if voltage crosses high/low thresholds.

💡 5. Production-Ready Embedded Refactoring

Here is an embedded safety-critical monitor using a deterministic state machine with hysteresis:

💡 Production-Ready Refactor
#include <cstdint>

enum class SafetyState : uint8_t {
    Nominal = 0,
    Warning,
    CriticalShutdown,
    FaultLatched
};

class FuelSafetyMonitor {
private:
    static constexpr uint16_t CRITICAL_THRESHOLD = 50;  // 5.0 Liters
    static constexpr uint16_t WARNING_THRESHOLD  = 150; // 15.0 Liters
    static constexpr uint16_t HYSTERESIS         = 10;  // Prevents state fluttering
    
    SafetyState state_{SafetyState::Nominal};
    bool latch_engaged_{false};

public:
    SafetyState update(uint16_t raw_sensor_level) noexcept {
        if (latch_engaged_) return SafetyState::FaultLatched;

        if (raw_sensor_level <= CRITICAL_THRESHOLD) {
            state_ = SafetyState::CriticalShutdown;
            latch_engaged_ = true;
            trigger_hardware_shutdown();
        } else if (raw_sensor_level <= WARNING_THRESHOLD) {
            state_ = SafetyState::Warning;
        } else if (raw_sensor_level > (WARNING_THRESHOLD + HYSTERESIS)) {
            state_ = SafetyState::Nominal;
        }
        return state_;
    }

private:
    void trigger_hardware_shutdown() noexcept {
        // Assert GPIO pin to trip physical safety relay
    }
};

📝 Knowledge Verification Quiz

Test your understanding of the C++ concepts and embedded microcontroller trade-offs covered in this guide. Click any option for instant feedback.

Q1. What is 'hysteresis' and why is it essential in embedded threshold monitoring?
A A tolerance band that prevents rapid, oscillating state changes when a noisy sensor signal fluctuates near a threshold
B A technique to accelerate floating-point arithmetic
C A method for encrypting sensor telemetry over CAN bus
D A software pattern that forces memory allocation onto the heap
Detailed Explanation: Hysteresis introduces different switching thresholds for rising vs falling signals, preventing noisy analog sensor inputs from rapidly toggling actuators on and off.
Q2. Why is using C++ exceptions for routine, expected conditions (e.g. low fuel warning) considered bad practice?
A Exceptions incur massive performance penalties during unwinding and obscure normal control flow logic
B Exceptions cannot be caught more than once
C Exceptions automatically erase flash memory
D Exceptions disable the microcontroller ADC peripheral
Detailed Explanation: Exceptions should represent exceptional/catastrophic conditions. Using them for regular state transitions causes high stack unwinding overhead and makes code harder to verify.
Q3. What is the purpose of an Analog Watchdog (AWD) peripheral on microcontrollers like STM32?
A It continuously monitors ADC conversion values in hardware and triggers an instant interrupt if thresholds are violated
B It resets the microcontroller if the real-time clock loses power
C It prevents battery overcharging through USB
D It simulates analog signals for unit testing
Detailed Explanation: The hardware Analog Watchdog checks converted ADC values against high/low register limits in hardware, generating an immediate interrupt without CPU polling overhead.
Q4. What does a 'fail-safe state' guarantee according to functional safety standards (ISO 26262)?
A The system transitions to a predetermined state that minimizes risk of harm upon critical component failure
B The system attempts to reboot continuously until hardware fixes itself
C The system ignores sensor failures and continues full power operation
D The system executes all pending dynamic memory allocations
Detailed Explanation: A fail-safe state ensures that when an unrecoverable fault occurs, all actuators and power stages default to their safest possible configuration (e.g. de-energized).