The steps shown here are not limited to Poky — they transfer directly to your own images, for example on SoC platforms like i.MX. The workflow for building, booting and testing stays essentially the same; only the target machine and additional layers differ.
These characteristics make Poky an ideal starting point for gaining hands-on experience with emulators and integrating automated tests into the development process. This article covers the full workflow: from downloading the sources, through the image build, to booting in QEMU and running tests.
Prerequisites
git clone git://git.yoctoproject.org/poky
cd poky
Optionally, check out a stable branch, e.g. scarthgap:
git checkout scarthgap
source oe-init-build-env
This creates the build/ directory. Settings in conf/local.conf can be adjusted, for example the number of parallel jobs:
BB_NUMBER_THREADS = "8"
PARALLEL_MAKE = "-j 8"
A minimal image:
bitbake core-image-minimal
Depending on your hardware the build can take several hours. The output is located at:
build/tmp/deploy/images/qemux86-64/
Poky ships a launch script:
runqemu qemux86-64
This boots a virtual system via QEMU. A login shell appears (default user: root, no password).
The Yocto Project supports a test infrastructure (oeqa). Custom tests can be added as Python test cases under meta/lib/oeqa/runtime/. Here is an example ping test:
from oeqa.runtime.case import OERuntimeTestCase
from oeqa.core.decorator.oetimeout import OETimeout
class PingTest(OERuntimeTestCase):
@OETimeout(60)
def test_ping(self):
status, output = self.target.run("ping -c 3 8.8.8.8")
self.assertEqual(status, 0, msg="Ping failed:\n%s" % output)
If tests fail:
build/tmp/log/oeqa/runqemubuild/tmp/work/.../temp/log.do_*QEMU provides a flexible way to boot embedded Linux images quickly and independently of real hardware. Developers can use it to trace the boot process, verify functionality and run automated tests. Poky is used here purely as an example for image creation — the same workflow applies equally to custom or board-specific builds, such as for i.MX.
This makes QEMU a valuable tool in embedded development: for early prototyping, continuous testing and stable release processes.
]]>Whether you are developing an insulin pump or a pressure regulator for a nuclear power plant, writing software requirements for safety-critical applications demands a disciplined approach. This article shows how to formulate precise, unambiguous and verifiable requirements that satisfy industry standards and support certification.
Most requirements are still written in natural language (NL). NL is flexible and easy to understand, but prone to ambiguity. A phrase like "when needed" can be interpreted in multiple ways — and thereby cause critical defects. Safety-related development therefore needs rules and structure even in NL. A good software requirement is:
Example structure:
The operator shall be able to [action] on the [object] in order to achieve [desired state].
Every requirement should define:
A well-formulated requirement typically follows a Subject–Predicate–Object (S-P-O) pattern:
| Subject | Predicate | Object |
|---|---|---|
| The system | shall display | the current heart rate. |
ISO/IEC/IEEE 29148:2018 describes how to write clear and testable requirements and standardises the use of modal verbs:
Best practice: use "shall" only once per requirement. Avoid compound requirements joined with "and", "or" or "with". Combining actions makes the requirement untestable and creates multiple requirements in one. Words like "is", "are", "was" or "must" are suitable for descriptive or introductory sections.
Every requirement should describe what the system must do, not how it is to be implemented. This is crucial for testability and traceability. Example:
The system shall use a MySQL database to store ECG data.
This describes the how, not the what. The choice of database is a design decision that belongs in downstream documents such as the Software Architecture Document (SAD) or Detailed Design Document (DDD).
One way to reduce ambiguity is to introduce a controlled language — a simplified subset of English for technical documentation. In aerospace, for example, ASD-STE100 (Simplified Technical English) is used.
Controlled language enforces:
A style guide for controlled language enables consistent and easily verifiable requirements across multiple documents and roles.
Ambiguity can arise from lexical, syntactic or semantic issues:
Ambiguity often creeps in through vague terms, passive constructions or unclear references. Example:
"The system shall activate the warning signal shortly after fault detection."
What does "shortly" mean? Who activates the signal? Questions like these are red flags in a safety-critical context.
Avoid:
Every requirement must be atomic, verifiable and unambiguous.
For higher safety integrity levels it becomes necessary to formalise requirements — translating them into a formal language such as PSL (Property Specification Language) or LTL (Linear Temporal Logic) that tools can check and simulate.
Formalisation enables:
"The system should deliver the correct dose at the correct rate."
Problems: vague terms such as "correct dose" and "correct rate". No subject defined. Not testable.
"When the infusion programme is started, the control unit shall deliver the programmed medication volume at a flow rate between 0.1 and 10.0 ml/h with an accuracy of ±5 %."
"The system must trigger an alarm when the heart rate is abnormal."
Problems: what does "abnormal" mean? How loud or fast must the alarm be? When exactly should it trigger?
"When the patient's heart rate falls below 40 bpm or exceeds 180 bpm and this condition persists for more than 3 seconds, the alarm controller shall activate a 90 dB alarm within 1 second."
"The system shall activate the beam when the operator starts treatment."
Problems: no mention of safety interlocks or conditions. "Activate" is unclear — switch on physically or merely prepare?
"The system shall activate the radiation beam only when the gantry is in the correct position, the hardware interlock is closed, and the treatment console receives a valid 'Start' command from the operator."
Developing a safety-critical product is rarely the work of a single person. Before proceeding to the next steps in the V-model, the software requirements must be reviewed. But that is a topic for another time.
As engineers and software developers we are trained to think in terms of structure, reliability and traceability. This mindset aligns closely with the philosophy of IEC 62304.
Functional safety ensures that a system responds correctly to its inputs, particularly in failure situations. In the medical domain this means: the software must not endanger patients or users, even in the event of foreseeable failures.
For example, a software-controlled infusion pump administering medication must handle sensor faults, communication failures and user errors in a way that prevents hazardous events. This is where functional safety comes in.
IEC 62304 defines three software safety classes:
Depending on the classification, the scope of testing and verification activities increases substantially. For Class C software, comprehensive test strategies must be implemented — including unit tests, integration tests and system verification with traceability to risk controls.
Testing in the context of IEC 62304 is not just about finding defects — it is about demonstrating that the software meets its safety requirements under all foreseeable conditions. Testing must therefore be:
Typical testing activities include:
Precision and rigorous documentation are well-known strengths of good engineering teams — and here they pay off. IEC 62304 demands traceability across the entire software lifecycle. Every requirement must be linked to:
Tools such as Polarion, Codebeamer or open-source alternatives like ReqView and Robot Framework can support this rigour.
Testing for functional safety cannot happen in isolation. It must be aligned with related standards, including:
For example, a Class C software system might include a software-based failsafe that activates when a hardware sensor reports inconsistent data. This behaviour must be verified both in software (simulated sensor fault) and in system testing (actual fault injection).
Testing for functional safety to IEC 62304 is not just a regulatory checkbox — it is a mindset. It requires a deep understanding of both the software architecture and the clinical risks involved.
A focus on process discipline, risk management and technical integrity provides a solid foundation for developing safe and reliable medical software.
In the end, good testing is not about covering every line of code — it is about being able to sleep soundly knowing that the software will not harm anyone.
]]>A good unit test satisfies at least one of these conditions:
assertEquals(42, obj.getValue()) just because getValue() happens to return 42, build a scenario that makes business sense.shouldRejectInvalidPassword() is also documentation.Trivial:
TEST(UserTest, GetNameReturnsName) {
User u("Alice");
EXPECT_EQ("Alice", u.getName());
}
No real value — it only confirms that getName() returns what was set in the constructor.
Valuable:
TEST(PasswordTest, RejectsShortPasswords) {
User u("Alice");
EXPECT_THROW(u.setPassword("123"), std::invalid_argument);
}
This test verifies a business rule: passwords must meet minimum requirements.
Unit tests that add value focus on behaviour, rules and robustness. Their job is not to mirror the implementation but to build confidence and preserve knowledge. Poor tests are dead weight; good tests are investments in quality and maintainability.
]]>