PDU Signal Interface
Overview
The middleware PDU signal interface maps typed signals to and from a PDU byte payload. A deployment defines each PDU’s payload size and signal bit layout.
The code generator also creates a typed reader that snapshots the shared-memory PDU, runs the configured qualifier on the snapshot, and returns all decoded signals together.
PDU Configuration
Each configured signal specifies its C++ type and bit
length. Only BigEndian byte order and MSB-first bit ordering
is supported at the moment.
pdus:
- name: SamplePdu
size: 2
namespace: example::signal
headers:
common: example/signal/SamplePduCommon.h
reader: example/signal/SamplePduReader.h
signals:
- name: checksum
type: uint8_t
bit_length: 8
- name: value
type: uint8_t
bit_length: 8
Supported datatypes
The following signal kinds are supported:
Kind |
|
Generated member |
|---|---|---|
Unsigned integer |
|
A member of that type. |
Boolean |
|
A single-bit flag ( |
Byte/word array |
|
|
Enum |
Name of an entry in the PDU’s |
A scoped |
Bitset |
Name of an entry in the PDU’s |
A generated class with one |
Signed integers and floating-point types are not supported.
Enum signals are converted with a plain static_cast. The raw value is not
checked against the declared enumerators, so a received value that is not
listed still yields an enum class object holding that number.
Phy translation of signals
An unsigned integer signal can carry an optional phy_translation that maps
the raw value to a physical value:
physical = raw * scaling_factor + offset
signals:
- name: temperature
type: uint16_t
bit_length: 12
phy_translation:
offset: -40.0
scaling_factor: 0.1
For every such signal the generated PDU struct gets a method
<signalName>ToPhysical() that returns a double:
auto const sample = reader.read();
if (qualifier.getQualification() == Qualifier::Qualification::Ok)
{
double const celsius = sample.temperatureToPhysical();
}
The signal member itself always keeps the raw value. The conversion is computed
on demand and applies no range check, so qualify the PDU before converting.
phy_translation is only available for unsigned integer signals, not for
arrays, enums or bitsets.
Signal Bit Mapping
bit_length is the number of bits in the signal.
Lengths are compile-time inputs to the generated read and write operations.
In a big-endian pdu, the most significant byte comes first as well as the signal bits inside each byte, i.e., bits go from the most-significant to the least-significant bit within each byte, then continue at the next byte.
For example, a 16-bit signal reads bytes AD BE as 0xADBE
in big-endian mode. A byte-array signal preserves the PDU’s byte sequence;
it is not converted to an integer or byte-swapped.
Generated Reader and Qualification
Each PDU has a generated reader named <PduName>Reader. Its constructor
takes the application’s middleware::core::IQualifier*. Its read()
method returns a snapshot of all decoded signals. Check the qualification
before using any returned signal value:
Qualifier qualifier;
SamplePduReader reader{&qualifier};
auto const result = reader.read();
if (qualifier.getQualification() != Qualifier::Qualification::Ok)
{
return;
}
use(result.value);
Unit testing with the reader mock
When a PDU is generated with generation_mode: mock (or the generator runs
with --generation-mode mock), <PduName>Reader forwards read() to a
GMock-based <PduName>ReaderMock. The mock lives in the same namespace as
the reader and registers itself as the active mock on construction:
NiceMock<SamplePduReaderMock> readerMock{};
SamplePduReader reader{&qualifier};
readerMock.ON_CALL_READ_RETURNS(SamplePduReaderMock::ReadResult{expected});
readerMock.EXPECT_READ();
auto const result = reader.read();