Project Oxygen & Ideo-LabIDEO LAB Dashboard 2026

đŸ›Ąïž Deterministic C – Safety-Critical Avionics

C “profilĂ©â€ pour systĂšmes critiques : dĂ©terminisme (temps/mĂ©moire/flux), MISRA-C, certification DO-178C, WCET, MC/DC, tooling qualifiĂ©.

Le “C avionique” n’est pas un langage diffĂ©rent



c’est une discipline : un sous-ensemble strict du C, un style de conception, des rùgles, des outils et un dossier de preuves qui rendent le logiciel audit-friendly et certifiable.

WCET / Timing bornĂ© MĂ©moire bornĂ©e MISRA / CERT C TraçabilitĂ© Req → Tests
Deterministic signifie : mĂȘmes entrĂ©es + mĂȘme Ă©tat ⇒ mĂȘme rĂ©sultat + temps bornĂ© + ressources bornĂ©es + absence de comportements indĂ©finis.
Deterministic C infographic (avionics)
1.1 Fondations

Définition : Deterministic C

DĂ©terminisme fonctionnel + temporel + mĂ©moire. Pourquoi l’avionique cherche l’auditabilitĂ© et la prĂ©visibilitĂ© avant la “flexibilitĂ©â€.

DeterminismBoundedAudit
1.2 RĂšgles

RĂšgles de codage : MISRA / CERT

Interdits usuels (malloc, rĂ©cursion, UB), typage strict, conversions explicites, conventions d’API, “no surprises”.

MISRA-CCERT CNo UB
1.3 Runtime

RTOS / Partitioning

ModĂšle temps rĂ©el : tĂąches, pĂ©riodes, prioritĂ©, jitter. Partitionnement type ARINC 653 (concept). Éviter l’imprĂ©visible.

RTOSSchedulingPartitioning
2.1 Critique

WCET & Worst-Case

Le vrai nerf : analyser/expliquer le pire cas. Boucles bornées, chemins bornés, latences IO maßtrisées.

WCETBounded loopsTiming
2.2 Preuves

V&V : tests, MC/DC, coverage

Unit, integration, system tests. Justifications. Couverture structurelle (dont MC/DC selon criticité). Rapports traçables.

MC/DCCoverageTraceability
2.3 Tooling

Outils qualifiés & pipeline

Analyse statique, rÚgles, build reproductible, tool qualification (selon usage), CI de conformité (style, warnings, reports).

Static analysisTool qualCI
3.1 Contexte

Domaines avionique

FCS, autopilot, navigation, engine control, braking. OĂč “deterministic C” est typiquement utilisĂ© (calculateurs embarquĂ©s).

FCSNavEngine
3.2 Cas

A320 vs 737 MAX (MCAS)

Lecture “engineering” : dĂ©pendance capteurs, gestion de modes, dĂ©gradation, alarmes, tolĂ©rance de panne. Sans sensationalisme.

A320 family737 MAXMCAS
3.3 Architecture

Patterns sûrs

State machine explicite, watchdogs, sanitization, “defensive design”, double validation, “safe defaults”, instrumentation.

FSMWatchdogDefensive
4.1 Pratique

Checklist “C dĂ©terministe”

Une checklist de revue : UB, overflow, conversions, bornes, reentrancy, ISR-safe, concurrency, logs, degradations.

ReviewBoundedSafety
4.2 Réfs

Références & ressources

Standards (DO-178C, DO-330, DO-331), MISRA, CERT C, concepts RTOS. Liens officiels / pages d’intro.

DO-178CDO-330MISRA
4.3 Atelier

Mini-projet : module “safe clamp”

Exemple concret : normalisation capteur, filtrage simple, clamp, diagnostics, tests unitaires, rapport couverture (structurel).

ExampleUnit testsDocs
1.1 DĂ©finition : “Deterministic C” (Safety-Critical)
Le déterminisme en 3 axes
AxeObjectifCe qu’on maütriseExemples
FonctionnelMĂȘmes entrĂ©es ⇒ mĂȘmes sortiesÉtats, modes, transitionsFSM explicite, invariants, “safe defaults”
TemporelTemps bornĂ© / prĂ©visibleChemins d’exĂ©cution, bouclesLoops bornĂ©es, WCET, budget CPU
MémoireRessources bornées / pas de surprisesStack, statique, buffersPas de malloc, buffers dimensionnés, pas de fragmentation
Diagramme (concept) : boucle de contrÎle temps réel
flowchart LR
  A[Read sensors] --> B[Validate / sanitize]
  B --> C[Compute control law]
  C --> D[Clamp & rate limit]
  D --> E[Output actuators]
  E --> F[Diagnostics / logging]
  F --> A
  note1([All steps are bounded in time & memory]):::note
classDef note fill=#0b1220,stroke=#334155,color=#cbd5e1;
        
Note : ce diagramme est “Mermaid-style”. Sur IDEO-Lab, tu peux soit l’afficher tel quel (code), soit intĂ©grer un renderer Mermaid si tu en utilises dĂ©jĂ .
Pourquoi le C reste un standard de fait en avionique
  • Mapping machine : relation directe avec l’exĂ©cution (stack, registres, mĂ©moire).
  • Toolchains robustes : compilateurs, linkers, debuggers, trace tools, coverage tools.
  • AuditabilitĂ© : le code est “explainable” au niveau machine (essentiel pour WCET / V&V).
  • MaĂźtrise des features : en imposant un profil strict (MISRA/CERT + rĂšgles internes), on neutralise les zones dangereuses.
Exemple minimaliste (style safety-critical)
#include 
#include 

#define ALT_MAX_FT (60000U)

static uint16_t g_altitude_ft = 0U;

bool set_altitude_ft(uint16_t new_alt_ft)
{
    if (new_alt_ft <= ALT_MAX_FT)
    {
        g_altitude_ft = new_alt_ft;
        return true;
    }
    return false; /* input out of range */
}
        
Anti-patterns “non dĂ©terministes” (Ă  Ă©viter)
  • Allocation dynamique dans la boucle temps rĂ©el : fragmentation, latence imprĂ©visible.
  • Boucles non bornĂ©es : `while(x) {...}` sans borne claire ⇒ WCET indĂ©montrable.
  • UB (Undefined Behavior) : overflow signĂ©, shifts hors bornes, aliasing agressif, non init.
  • Concurrence implicite : accĂšs partagĂ©s sans modĂšle clair (ISR/tasks).
RĂšgle d’or : si tu ne peux pas expliquer “pire-cas temps + pire-cas mĂ©moire + pire-cas Ă©tat”, le design est incomplet pour du safety-critical.
1.2 Rùgles de codage : MISRA-C / CERT C / “No UB”
Restrictions typiques (profil “Deterministic C”)
ZoneInterdit / limitéPourquoiAlternative sûre
Mémoiremalloc/free, realloclatence + fragmentationbuffers statiques, pools bornés (si autorisés)
Flowrécursion, goto (souvent), boucles non bornéesWCET incertainFSM, boucles bornées
Typescasts implicites, conversions silencieusesbugs “invisibles”casts explicites, types stdint.h
UBoverflow signĂ©, shift hors borne, non initcomportement non dĂ©finifonctions “safe”, checks, saturation
ConcurrenceaccÚs partagés non protégésrace conditionssections critiques, double-buffer, message passing
Exemple : boucle bornée + clamp + saturation
#include 
#include 

static int32_t clamp_i32(int32_t x, int32_t lo, int32_t hi)
{
    if (x < lo) { return lo; }
    if (x > hi) { return hi; }
    return x;
}

/* Bounded loop: always <= N iterations */
bool moving_average_i16(const int16_t *samples, uint16_t n, int16_t *out_avg)
{
    uint16_t i = 0U;
    int32_t acc = 0;

    if ((samples == (void*)0) || (out_avg == (void*)0) || (n == 0U) || (n > 64U))
    {
        return false;
    }

    for (i = 0U; i < n; i++)
    {
        acc += (int32_t)samples[i];
    }

    acc = acc / (int32_t)n;
    acc = clamp_i32(acc, -32768, 32767);
    *out_avg = (int16_t)acc;
    return true;
}
          
Points “review” sur cet exemple
  • Bornes : n ≀ 64 → timing bornĂ© (WCET plus simple).
  • Accumulateur : type Ă©largi int32_t pour Ă©viter overflow.
  • Checks : pointeurs & paramĂštres validĂ©s (defensive design).
  • Clamp : saturation explicite → Ă©vite UB, rĂ©sultats stables.
  • Style : simple, lisible, testable, audit-friendly.
Conseil : dans du safety-critical, chaque conversion mérite une intention explicite (type élargi, clamp, cast final).
1.3 RTOS / Scheduling / Partitioning (concepts avioniques)

Le “C dĂ©terministe” vit presque toujours dans un environnement temps rĂ©el : tĂąches pĂ©riodiques, contraintes de latence, prioritĂ©s, interruptions, et parfois partitionnement (ex: concepts ARINC 653).

Diagramme : tùches périodiques (concept)
sequenceDiagram
  participant Timer as RTOS Timer
  participant Task1 as Task@10ms
  participant Task2 as Task@50ms
  participant ISR as Sensor ISR

  Timer->>Task1: Wake up (10ms)
  Task1->>Task1: Read/Validate/Compute/Output
  ISR-->>Task1: New sample (interrupt)
  Timer->>Task2: Wake up (50ms)
  Task2->>Task2: Health monitoring / logging / built-in tests
      
Table : risques “non dĂ©terministes” typiques
RisqueEffetMitigation
Priority inversionlatence imprévisibleprotocoles (mutex prio-inherit), design sans lock sur boucle critique
ISR trop lourdejitter + WCET explosifISR minimale + buffer + traitement en task
Partage de donnéesraces / incohérencesdouble-buffer, messages, sections critiques bornées
2.1 WCET – Worst-Case Execution Time (le vrai “determinism gate”)
Ce qui rend le WCET prouvable
  • Chemins bornĂ©s : Ă©viter la combinatoire (Ă©tats/modes explicites).
  • Boucles bornĂ©es : pas de dĂ©pendance Ă  des entrĂ©es non bornĂ©es.
  • IO maĂźtrisĂ©es : appels systĂšme/driver bornĂ©s, pas de retries infinis.
  • Structure stable : code simple, branches limitĂ©es, tables prĂ©-calculĂ©es.
Exemple : boucle strictement bornée
#define N_MAX (32U)

/* Always executes at most N_MAX iterations */
int16_t dot_i16(const int16_t *a, const int16_t *b, uint16_t n)
{
    uint16_t i = 0U;
    int32_t acc = 0;

    if ((a == 0) || (b == 0) || (n == 0U) || (n > N_MAX)) { return 0; }

    for (i = 0U; i < n; i++)
    {
        acc += (int32_t)a[i] * (int32_t)b[i];
    }

    /* clamp to int16 range */
    if (acc > 32767) { acc = 32767; }
    if (acc < -32768) { acc = -32768; }
    return (int16_t)acc;
}
          
Ce qui casse le WCET (Ă  bannir en boucle critique)
PatternPourquoi
while(!done) ...Nombre d’itĂ©rations dĂ©pend d’entrĂ©es/Ă©tats, pire-cas indĂ©montrable
allocations / freeslatence et fragmentation imprévisibles
algos non bornĂ©sex: tri “variable”, recherche non bornĂ©e, parsing non bornĂ©
logs “lourds”IO variable, buffers, contention
Astuce avionique : séparer strictement la boucle de contrÎle (hard real-time) et les tùches de maintenance (health monitoring / logs / BIT) avec budgets et priorités dédiés.
2.2 V&V – Tests, MC/DC, couverture, traçabilitĂ©
Table : V&V “safety-critical” (lecture pratique)
NiveauObjectifArtefactsExemples
Unitprouver la logique localetests + rapportsclamp, filtrage, conversions, checks
Integrationinterfaces + timingsstubs/mocksdriver capteur → normalisation → loi de commande
Systemcomportement globalscénariosmodes, dégradations, alarmes, transitions
RobustnessentrĂ©es “hostiles”campagnesvaleurs extrĂȘmes, capteur incohĂ©rent, intermittence
Exemple “testable” (pseudo-framework)
/* Given: clamp_i32(x, lo, hi) */

TEST(clamp_i32, clamps_low)
{
    ASSERT_EQ(-10, clamp_i32(-999, -10, 10));
}

TEST(clamp_i32, clamps_high)
{
    ASSERT_EQ(10, clamp_i32(999, -10, 10));
}

TEST(clamp_i32, passes_through)
{
    ASSERT_EQ(3, clamp_i32(3, -10, 10));
}
        
MC/DC : l’idĂ©e (sans entrer dans la jungle)
MC/DC vise Ă  dĂ©montrer que chaque condition d’une dĂ©cision logique peut influencer indĂ©pendamment le rĂ©sultat. Ce n’est pas “plus de tests”, c’est des tests structurĂ©s pour lever les ambiguĂŻtĂ©s.
/* Decision: if (A && (B || C)) */

Case  A  B  C  Result
1     0  0  0  0
2     1  0  0  0
3     1  1  0  1
4     1  0  1  1

Goal: show each of A, B, C can independently change outcome.
        
Traceability : le “vrai livrable”
flowchart TB
  R[System Requirements] --> SR[Software Requirements]
  SR --> AD[Architecture / Design]
  AD --> SC[Source Code]
  SR --> UT[Unit Tests]
  SR --> IT[Integration Tests]
  SR --> ST[System Tests]
  SC --> COV[Coverage Reports]
  UT --> REP[Test Reports]
  IT --> REP
  ST --> REP
  COV --> PKG[Certification Data Package]
  REP --> PKG
        
Une fonctionnalitĂ© “non traçable” = un risque : on ne peut pas prouver qu’elle a Ă©tĂ© spĂ©cifiĂ©e, testĂ©e, ni couverte.
2.3 Tooling : analyse statique, builds reproductibles, qualification (selon usage)
Pipeline “deterministic C” (concept CI)
1) Build (warnings treated as errors)
2) Static analysis (MISRA/CERT rules + deviations justified)
3) Unit tests (host) + reports
4) Integration tests (target or HIL) + reports
5) Structural coverage (statement/branch/MC/DC as required)
6) Packaging: traceability matrices + evidence bundle
      
Table : catĂ©gories d’outils et rĂŽle
CatégorieObjectifSortie attendue
Static analysisdétecter UB, violations de rÚgles, code mortrapports + dérogations justifiées
Compiler / linkerbuild maßtrisé, flags stablesbinaires reproductibles
Coveragepreuve structurellerapports coverage par unité / module
Tracetiming/latence/jittermesures, logs bornés, profiling temps réel
Point d’attention : la “qualification d’outil” dĂ©pend de l’usage (outil qui peut masquer un dĂ©faut vs outil de confort). Dans un cadre avionique, on documente prĂ©cisĂ©ment l’outillage et ses limites.
3.1 Domaines d’application avionique (oĂč le C dĂ©terministe est typique)
Modules typiques (lecture “safety-critical”)
DomainePourquoi déterminisme ?Exemples de contraintes
Flight Controlcommande d’actionneurs, stabilitĂ©latence max, modes, dĂ©gradations
Autopilot / Navigationguidage, lois, modesgestion d’états, transitions sĂ»res
Engine control (FADEC)moteur = safety-criticalcalculs bornés, robustesse capteurs
Braking / steeringcontrÎle au sol / sécuritédétection défauts, fallback
Monitoringsurveillance & BITséparer hard RT vs maintenance
Pattern “capteur → normalisation → loi → clamp → diagnostic”
flowchart LR
  S[Sensor raw] --> V[Validate & plausibility]
  V --> N[Normalize / filter]
  N --> L[Control law]
  L --> C[Clamp / rate limit]
  C --> A[Actuator command]
  V --> D[Fault flags]
  N --> D
  L --> D
      
3.2 RĂ©fĂ©rences “avions” : A320 / 737 MAX (MCAS) – lecture engineering
Important : cette section vise Ă  illustrer des principes de conception safety-critical (capteurs, modes, dĂ©gradations, diagnostics), pas Ă  “refaire l’enquĂȘte”. On reste sur une lecture architecture & engineering patterns.
A320 (famille) – ce qu’on illustre cĂŽtĂ© software
  • Gestion de modes : “state machines” explicites, transitions contrĂŽlĂ©es.
  • Lois de commande : sĂ©paration des boucles, saturation, rate limiting.
  • Diagnostics : plausibility checks, flags dĂ©faut, dĂ©gradation contrĂŽlĂ©e.
Le point important ici : en avionique, un systĂšme est Ă©valuĂ© sur sa capacitĂ© Ă  se dĂ©grader proprement quand l’environnement n’est plus nominal.
737 MAX / MCAS – ce que ça illustre (au niveau conception)
  • DĂ©pendance capteurs : comment valider la plausibilitĂ©, gĂ©rer les incohĂ©rences et Ă©viter l’amplification d’une mesure erronĂ©e.
  • Modes & autoritĂ©s : “qui commande quoi”, quelles limites, quelles conditions d’activation/dĂ©sactivation.
  • Degraded modes : que fait le logiciel quand une entrĂ©e critique devient douteuse ? (fallback / safe mode / inhibit).
Dans une perspective “deterministic C”, on cherche : Ă©tats explicites, entrĂ©es validĂ©es, bornes strictes, et preuves V&V sur les transitions et les conditions limites.
Lessons “Deterministic” (transposables)
ProblĂšme Ă  maĂźtriserPattern deterministicPreuve attendue
EntrĂ©es capteurs “folles”sanitization + plausibility + clamptests robustesse + coverage
Transition de modesFSM explicite + invariantstests de transitions + MC/DC (si requis)
Autorité de commanderate limit + bounds + inhibitanalyses + campagnes de tests
3.3 Architecture : patterns sûrs (FSM, watchdog, safe defaults, diagnostics)
Pattern : machine Ă  Ă©tats (FSM) “mode-driven”
typedef enum
{
    MODE_OFF = 0,
    MODE_STANDBY,
    MODE_ACTIVE,
    MODE_DEGRADED,
    MODE_FAULT
} mode_t;

typedef struct
{
    mode_t mode;
    uint16_t fault_flags;
} ctx_t;

/* explicit transitions only */
static mode_t next_mode(mode_t cur, bool input_ok, bool health_ok)
{
    switch (cur)
    {
        case MODE_OFF:      return MODE_STANDBY;
        case MODE_STANDBY:  return input_ok ? MODE_ACTIVE : MODE_DEGRADED;
        case MODE_ACTIVE:   return health_ok ? MODE_ACTIVE : MODE_DEGRADED;
        case MODE_DEGRADED: return health_ok ? MODE_ACTIVE : MODE_FAULT;
        default:            return MODE_FAULT;
    }
}
          
Checklist design (vraiment avionique)
  • Chaque mode a des invariants (ce qui doit toujours ĂȘtre vrai).
  • Transitions explicites : pas de “magie” cachĂ©e dans 3 fonctions.
  • Safe defaults : en cas de doute → sortie bornĂ©e et neutre.
  • Diagnostics : flags, compteurs, dĂ©tection d’intermittence.
  • Watchdog : timeouts, supervision de boucle.
RĂšgle d’or : la sĂ»retĂ© se joue souvent plus dans la conception d’états et de dĂ©gradations que dans les formules.
4.1 Checklist “C dĂ©terministe” (revue de code & conception)
Checklist (copiable)
[Deterministic C Checklist]

A) Determinism
- [ ] All loops are bounded (explicit N_MAX, time budget)
- [ ] No dynamic allocation in real-time path
- [ ] No recursion, no hidden unbounded retries
- [ ] Worst-case state/mode transitions documented

B) Undefined Behavior / Types
- [ ] No signed overflow assumptions
- [ ] Shifts are guarded (0 <= shift < width)
- [ ] All variables initialized
- [ ] Explicit casts; no implicit narrowing conversions
- [ ] Use stdint.h fixed-width types everywhere

C) Interfaces / Defensive Design
- [ ] Input ranges validated (plausibility + sanity)
- [ ] Outputs clamped/rate-limited (safe defaults)
- [ ] Error handling returns explicit status codes
- [ ] Side effects are minimized and documented

D) Concurrency / Interrupts
- [ ] Shared data has a clear ownership model
- [ ] ISR is minimal; no heavy work; bounded time
- [ ] Critical sections are short and bounded
- [ ] No data races (double-buffer/message passing where possible)

E) Verification
- [ ] Unit tests cover normal + edge + invalid inputs
- [ ] Structural coverage measured (statement/branch/MC/DC as required)
- [ ] Static analysis clean; deviations justified
- [ ] Traceability exists Req -> Code -> Test -> Report
      
4.3 Mini-projet : module “Safe Sensor Normalize” (exemple complet)
Spécification (style requirement)
IDRequirementNotes “deterministic”
SSR-001Le module valide l’entrĂ©e capteur dans une plage plausible.EntrĂ©es invalides ⇒ status explicite
SSR-002Le module normalise en Q15 (fixed-point) et applique un clamp.pas de float obligatoire
SSR-003Le traitement est borné : O(1), pas de boucles non bornées.WCET simple
SSR-004Le module expose des diagnostics (flags + compteur).observabilité
Implémentation (exemple)
#include 
#include 

typedef struct
{
    uint16_t invalid_count;
    uint16_t flags;
} diag_t;

#define DIAG_INVALID_RANGE (1U << 0)

/* Normalize raw (e.g., 0..4095) into Q15 [-1..+1] */
bool sensor_normalize_q15(uint16_t raw,
                          uint16_t raw_min,
                          uint16_t raw_max,
                          int16_t *out_q15,
                          diag_t *diag)
{
    int32_t num, den, q15;

    if ((out_q15 == 0) || (diag == 0) || (raw_min >= raw_max))
    {
        return false;
    }

    /* plausibility check */
    if ((raw < raw_min) || (raw > raw_max))
    {
        diag->invalid_count++;
        diag->flags |= DIAG_INVALID_RANGE;
        *out_q15 = 0; /* safe default */
        return false;
    }

    /* map [raw_min..raw_max] -> [-32768..32767] */
    num = ((int32_t)raw - (int32_t)raw_min);
    den = ((int32_t)raw_max - (int32_t)raw_min);

    /* scale to [0..65535], then shift to [-32768..32767] */
    q15 = (num * 65535) / den;
    q15 = q15 - 32768;

    if (q15 > 32767) { q15 = 32767; }
    if (q15 < -32768) { q15 = -32768; }

    *out_q15 = (int16_t)q15;
    return true;
}
        
Pourquoi c’est “deterministic” : pas d’allocation, pas de boucle non bornĂ©e, types explicites, checks d’entrĂ©e, sortie bornĂ©e.
Tests recommandés (edge cases)
  • Range invalid : raw_min >= raw_max.
  • Below min / above max : status false + safe default + flags + compteur.
  • Nominal : raw = min, mid, max (valeurs attendues).
  • Overflow : vĂ©rifie qu’aucun calcul intermĂ©diaire ne dĂ©passe int32 (selon tes bornes).
TEST(sensor_normalize_q15, below_min_sets_safe_default)
{
    int16_t out = 123;
    diag_t d = {0};

    ASSERT_FALSE(sensor_normalize_q15(10, 100, 200, &out, &d));
    ASSERT_EQ(0, out);
    ASSERT_TRUE((d.flags & DIAG_INVALID_RANGE) != 0);
    ASSERT_EQ(1, d.invalid_count);
}
        
⚙ Quickstart : Ă©crire du C “deterministic-ready” (en 10 rĂšgles)
1) Always fixed-width types: uint16_t, int32_t, ...
2) No dynamic allocation in real-time path
3) No recursion; no unbounded loops
4) Validate all inputs + plausibility checks
5) Bound outputs (clamp + rate limit) + safe defaults
6) Avoid UB: signed overflow, invalid shifts, uninit vars
7) Keep functions small, single-responsibility, testable
8) Make state machines explicit (modes, transitions)
9) Separate control loop from monitoring/logging tasks
10) Evidence-driven: tests + coverage + static analysis + traceability
      
đŸ›Ąïž Certification & preuves : DO-178C (vue “engineering”)

La certification n’est pas “un label du langage”. C’est un processus + un dossier de preuves. Le C dĂ©terministe facilite la production de preuves (timing, absence d’UB, tests structurĂ©s, traçabilitĂ©).

Ce que cherche un auditeur
  • Exigences claires & traçables
  • Design explicite (modes / Ă©tats / interfaces)
  • V&V robuste : tests + couverture structurelle
  • Analyse statique + gestion des dĂ©rogations
  • Build reproductible + configuration maĂźtrisĂ©e
Diagramme : “evidence package”
flowchart LR
  Req[Requirements] --> Code[Deterministic C Implementation]
  Code --> SA[Static Analysis Reports]
  Code --> UT[Unit Tests + Reports]
  Code --> COV[Structural Coverage]
  Req --> TM[Traceability Matrix]
  SA --> PKG[Certification Evidence Package]
  UT --> PKG
  COV --> PKG
  TM --> PKG