This case study has not been published yet. The live site shows only the introduction, you're reading the full draft here. Content may still change before release. If you'd like to suggest changes, contact me.

Back to Archive

Safety System Products

Simplifier Gateway

The Simplifier Gateway sits between a distributed Safety Simplifier installation in the field and the higher-level safety controller that has to trust it. It gathers validated safety state from Simplifier devices and presents that system to a Siemens controller over PROFIsafe or to a Beckhoff controller over FSoE through one interface.

Simplifier Gateway industrial functional-safety communication device

I joined while the product was still in early development. The firmware itself mattered, but the bigger gap was everything around it: no tests, very little review discipline, IDE-bound builds, and weak traceability, all on a product that needed SIL 3 certification under IEC 61508.

Most of my contribution ended up there: verification infrastructure, certification-evidence automation, and the embedded DevOps backbone that turned the project from firmware that seemed correct into firmware that could be proven correct to a certifier.

Project Brief

My role
Safety-critical firmware, verification infrastructure, certification evidence
Product
Gateway for the Safety Simplifier system
Firmware scope
Bare-metal C on the safety cores, under MISRA C:2012
Architecture
Two STM32 safety cores plus a multi-core communication SoC
SIL 3IEC 61508 certified by RISE
100%statement and branch coverage, in-scope safety firmware
3processors in the device
2safety-bus variants from one shared architecture

What the Gateway is, and what I walked into

01 The wiring problem in distributed machine safety

A machine, cell, or production line carries safety points everywhere: guard doors, emergency stops, light curtains, guard locks, robot safe-torque-off inputs, contact mats, laser scanners. Connecting all of them to a central safety controller the traditional way meant extensive physical infrastructure: modules, terminals, junction boxes, cable runs, and extra cabinet space, each adding installation and commissioning risk. For linked machines it was worse, since safety signals were often exchanged through potential-free contacts wired from machine to machine, so every later change to the safety concept touched real wiring.

The Safety Simplifier moved evaluation out toward those points. Local devices on doors, at robot cells, next to light curtains evaluate the local safety function directly and can shut down drives or pneumatics through local safe outputs, while exchanging data across the Simplifier network over a mesh or Simple-CAN. For modular machines, that changed what it meant to expand: adding a station, a door, or a whole machine module no longer had to trigger a rewiring exercise across the entire safety concept.

02 What the Gateway adds

The Simplifier solved the field side. The Gateway solved the controller side. One Simplifier device forwards the relevant safety data to the Gateway, which converts it and presents it to a Siemens or Beckhoff safety controller over the selected safety protocol. In the publicly documented variant that means PROFINET and PROFIsafe, managed from TIA Portal.

In practice, that meant the machine builder did not need every field device to become its own safety-bus participant. The distributed Simplifier side could stay distributed, while the Siemens or Beckhoff side saw one clean gateway layer. That same architecture later carried into the FSoE-oriented variant, and it also made retrofits easier because existing safety devices could stay where they were instead of being pulled into a cabinet-heavy safety-bus redesign.

03 The state of the project when I joined

I joined in the early development phase, when the product direction was set but the engineering process around it was still immature. The firmware was moving forward, but there were no tests, very few reviews, builds still lived inside the IDE, and traceability was weak.

That would have been survivable on an ordinary embedded product. It was not survivable on one that needed SIL 3 certification. Very quickly the bottleneck stopped looking like firmware implementation and started looking like proof: how to show, repeatedly and traceably, that the firmware was doing the right thing.

1.Why proof became the real project

  1. 01 SIL 3 changed the definition of done

    IEC 61508 is the umbrella functional safety standard for electrical, electronic, and programmable electronic safety-related systems. SIL 3 is its second-highest integrity level. It governs how safety functions are implemented, and equally how they are specified, verified, and documented for an external assessor.

    For the Gateway, that gave every design and development decision a certification dimension. Writing correct firmware was only half the bar. The verification process also had to be defined, repeatable, and legible to the certification body.

  2. 02 My role naturally drifted toward verification

    My direct firmware scope was the safety-core firmware at the driver layer: bare-metal C running close to the hardware, subject to MISRA C:2012, with the deterministic behavior and continuous diagnostics SIL 3 software requires. But because I already had experience with unit testing and MISRA, and because setting up tools and frameworks comes naturally to me, I kept getting pulled toward the infrastructure around that firmware as well.

    That drift turned out to be useful. The product did not only need more firmware. It needed someone willing to automate the boring parts and make verification repeatable.

  3. 03 The process before and after

    Before that rebuild, reviews were rare and bulked together, testing was largely manual, builds were still tied to STM32CubeIDE, and evidence capture was exactly the kind of task everyone postponed. By the time formal proof was needed, much of the useful review and test history would already have been thin, scattered, or gone.

    Afterward, the project had CI, PR-based reviews, automated evidence generation, and builds that could run outside the IDE. The work itself did not become simpler. It became traceable.

  4. 04 Getting to 100% coverage was the hardest part

    The explicit verification target was 100% statement and branch coverage for the in-scope safety firmware, achieved through combined unit-test and HIL execution plus fault insertion. Pre-certified bus drivers and the communication core sat outside that boundary.

    The difficult part was not the happy path. It was the edge cases: the branches that only exist for rare faults, unusual timings, or hardware states nobody reaches in ordinary testing. Reaching those reliably is what turned verification from a testing task into an engineering project of its own.

2.The architecture we had to prove

Three processors, two domains

The device is built around two STM32 based safety cores and one separate communication core, the latter a multi-core SoC capable of common industrial fieldbuses such as PROFINET and EtherCAT. The safety cores own all safety-related processing, diagnostics, monitoring, and validation of the safety communication; the communication core handles the network-facing, non-safety traffic.

The hardware draws the same line between safety-critical and non-safety boards. That partitioning earns its keep at certification time: non-safety boards can be iterated without pulling the safety-relevant hardware back through recertification.

Cross-checking and hardware IPC

All three processors communicate through hardware IPC. Across the safety and communication domains, IPC carries validated safety-relevant state between the two sides.

Between the two safety processors, IPC carries the cross-verification work. Each core checks the other as part of the redundant safety architecture, so a fault in one is caught and acted on rather than silently trusted.

Continuous self-diagnostics

The safety firmware runs continuous self-tests throughout operation, watching its own execution environment for the faults a SIL 3 safety function is required to detect. That was central to the verification burden: these were not background nice-to-haves. They were behaviors that had to be exercised, observed, and proved.

  • Watchdog monitoring
  • RAM runtime tests
  • ROM and flash CRC tests
  • CPU register tests
  • Clock monitoring

What a safe state means here

The Gateway is a communication bridge, not a relay-output controller, so a detected fault does not necessarily drop a physical contact inside the box. When a safety failure is detected, the firmware drives the communicated safety state to a value the Siemens or Beckhoff safety controller reads as not-permissive: zero, invalid-safe, stop-equivalent. The controller then takes the machine to its configured safe condition.

This distinction sets what the verification work had to prove: that the firmware reaches the correct safe-state response, and reaches it reliably enough to satisfy a SIL 3 response-time budget.

3.Verifying an architecture that resists isolation

Why the architecture made testing hard

The same features that made the architecture suitable for SIL 3 also made it hard to isolate for testing: hardware IPC binding the safety cores together, peripheral-heavy drivers tightly coupled to the safety function, and real-time behavior that only meant something on the target hardware. Standard dependency injection and stub libraries did little against live IPC and peripheral behavior that had to run on target to be worth measuring.

IEC 61508 added a second constraint. Verification had to produce traceable evidence: every test run tied to the code it covered, and every result in a form an assessor could inspect. That ruled out anything that could not be run reproducibly and reported automatically, which is why ordinary embedded-testing shortcuts were not enough.

A small test header that grew into a framework

I did not begin with a grand plan to build a framework. I started with a very small header of assertion macros because I did not want to drag in a large testing library and then spend time fighting it. That small header kept growing as the needs of the codebase became clearer.

Over time it turned into a custom unit-test framework, shaped around this specific firmware rather than around generic embedded testing ideals. That was its advantage: the mechanics and usage matched the codebase we actually had, not the one a library assumed we had.

  • A structured hierarchy: assert, test, test group, test suite
  • Deterministic failure reports with file, line, and expected-versus-received detail
  • Cleanup-safe execution via BUILDUP / TEARDOWN with assert-driven jumps
  • On-target peripheral mocks by swapping peripheral instances in test builds

Mocking hardware behavior at link time

On-target peripheral swapping handled a large part of the isolation problem, but some driver and communication paths still needed more control than that. I added link-time substitution techniques so tests could drive fault paths and edge behavior without touching the production source.

That mattered most for exception and system-error handling. Some of the branches needed for full coverage only existed in failure conditions, so the test system had to reach those states deliberately instead of waiting for them to happen by chance.

4.Taking the process out of the IDE and out of people's heads

01 A build that runs outside the IDE

The test framework needed somewhere to run, and the first boring bottleneck was the build itself. The firmware had been built around STM32CubeIDE, which was fine for local bring-up and bad for almost everything that had to follow. I replaced that with a CMake-based build for the safety-core firmware.

That change looks smaller than it was. A firmware that builds reproducibly outside the IDE is the precondition for everything downstream: repeatable test execution, CI, and less manual handling around safety verification.

The migration also restructured the codebase for a better developer experience and easier onboarding, including container-based setups, and produced named build variants that automation could drive directly. The same deep dive into CMake later seeded my C C++ Toolkit VS Code extension.

  • Production builds
  • Combined unit-test / HIL builds
  • Fault-insertion variants
  • PROFIsafe and FSoE variants

02 CI tiered by event weight

Once the build could run outside the IDE, the rest followed from that. On a self-hosted runner I built CI pipelines for the embedded software, with the expensive checks separated from the cheap ones so the team was not paying the full verification cost on every ordinary change.

Version bumps and release tags were decided manually, so the workflow was organized around explicit release and review milestones rather than pretending every commit deserved the heaviest possible treatment.

Fault insertion scenarios, both software-injected and selected hardware-injected cases, ran as part of the heavier verification lane. They exercised the firmware's fault response systematically rather than leaving it to be inferred from normal test runs.

  • Per patch release: build, static analysis, MISRA checks
  • Per minor release: combined unit-test / HIL execution, including fault insertion
  • On demand: coverage collection, document generation, proof-of-review artifacts

03 Test results posted back into the review

At the pull-request milestone the runner compiled the unit-test builds, flashed both safety cores on the test harness, ran the suite through the custom framework, and posted the outcome back into the review itself. Because the tests exercised real peripheral interaction on the target, "combined unit-test / HIL" is the accurate description.

That closed an important loop. The code change, the review discussion, and the test outcome stopped living in separate places and started reinforcing each other.

5.Making evidence a byproduct of the work

Moving from bulk reviews to a PR-based flow

IEC 61508 wants credible evidence that a defined review process ran throughout development. A claim that reviews happened is not evidence. The existing practice, reviews in bulk before major releases, produced irregular, retrospective activity that was hard to document and easy to shortcut.

I pushed the team toward a pull-request-based review flow, a style I had already seen produce better discipline on the embedded side at MRS. Smaller, more regular reviews tied to concrete changes were easier to conduct, and they produced evidence that was far less brittle.

Capturing the review while it was still fresh

The strongest evidence was the pull-request discussion itself: the comments, responses, and surrounding diff hunks that showed review had shaped the code. The problem was that capturing this by hand had been the worst pain point in the process. People deferred it, and by the time formal evidence was needed, much of the history was gone.

A Python tool I wrote closed that gap. On merge, it collected the relevant review history and transformed it into traceable certification evidence automatically, so the paper trail got built while the engineering context was still fresh rather than weeks later when everyone had moved on.

Quantifying quality, release over release

Reviews captured the qualitative story of each code change. The code-analysis pipeline added the quantitative baseline. IEC 61508 expects a structured way to quantify software quality, so I selected an analysis tool and integrated it into the release pipeline, making each minor release produce and archive a report measured per function against defined acceptance criteria.

Each report showed where the code stood against those criteria, release over release, not only the raw values. The most useful thing it surfaced was complexity creeping up over time, caught before it became entrenched.

  • NLOC (non-comment lines of code)
  • Cyclomatic complexity (CCN)
  • Token count
  • Parameter count

MISRA: enforced, with one honest deviation

MISRA C:2012 is a coding standard for C that restricts or bans language features associated with undefined behavior, poor portability, or code that is difficult to analyze statically. In functional safety it is a baseline expectation. The firmware was held to it, with compliance enforced through static analysis in the release pipeline.

There was at least one required-rule deviation, justified on performance and code-simplicity grounds, with the associated risk mitigated through code reviews and static analysis. Deviations of this kind are a normal part of the standard; what matters is that each one is documented, justified, and reviewed rather than silently bypassed.

6.Outcome

Once that verification chain existed, it carried the product through certification. The PROFIsafe variant is certified to SIL 3 against IEC 61508:2010 by RISE and shipping in production. Just as important, the infrastructure built for certification did not become disposable project scaffolding once the certificate existed. It remained the way the firmware stayed traceable and auditable as the product evolved.

Certification also was not the end of the story. As the product moved into serial production, the next bottleneck became manufacturing proof instead of development proof, and that directly led to the production test cabinet I built afterward to screen every unit before it left the factory.

The architecture decisions made for the Gateway also paid off inside the product itself. The FSoE variant, Safety over EtherCAT, runs on the same hardware with different firmware, reuses almost all drivers unchanged, and selects the safety-bus protocol at build time through an abstracted interface. One architecture serves a second safety bus at minimal incremental cost instead of splitting into parallel codebases.

Service and maintenance needed their own tooling as well. I built the CAN-based field update utility used during service visits and deployed maintenance. It talks to the bootloader to update all three processors in sequence, with integrity validation on both the updater and the embedded side, so the whole device can be brought to a new firmware version in the field without disassembly.

7.Retrospective

By the end of the project, it was obvious which part of embedded work suited me best. I liked writing firmware, but I was more valuable where firmware met process: tests, analysis, review discipline, and the tooling that kept all of that repeatable. I had already started moving in that direction on the motion and light sensor work at MRS.

That is why the Gateway fit so well. The product needed someone willing to formalize the process around the firmware, automate the boring proof work, and keep pushing until the hard-to-reach edge cases stopped being theoretical and started being testable. Functional safety gave those habits a stricter standard and an audit trail.