ARA Functional Clusters — API & ARXML Deep Dive
About 5114 wordsAbout 17 min
2026-03-25
This file provides a complete reference for the seven most commonly used ARA Functional Clusters in production AUTOSAR Adaptive systems: COM, EXM, LOG, PHM, STM, DIAG, and PER. For each cluster:
- Full C++ API with annotated code examples
- ARXML configuration showing exactly how the AUTOSAR metamodel defines the service
- Relationship between ARXML elements and generated/runtime behaviour
How ARXML Defines ARA Services — Conceptual Overview
The AUTOSAR metamodel is the common language between tools, platform implementations, and application code. Every functional cluster is configured through a chain of ARXML elements:
ARXML Metamodel Chain
┌─────────────────────────────────────────────────────────────────┐
│ Software Design Tools (SystemDesk, AUTOSAR Builder) │
│ Developer declares: interface, ports, deployment parameters │
└────────────────────┬────────────────────────────────────────────┘
│ writes
▼
┌─────────────────────────────────────────────────────────────────┐
│ ARXML Files (XML, AUTOSAR schema-validated) │
│ ├── Application Manifest (design-time topology) │
│ ├── Execution Manifest (runtime process parameters) │
│ └── Service Instance Manifest (transport binding) │
└────────────────────┬────────────────────────────────────────────┘
│ read by
┌────────┴──────────────────────────┐
│ │
▼ ▼
┌───────────────────────┐ ┌───────────────────────────┐
│ Code Generator │ │ Platform Runtime (EM, CM, │
│ Produces: │ │ PHM, SM, UCM…) │
│ - Skeleton/Proxy .h │ │ Reads manifests at boot │
│ - Type headers │ │ to configure itself │
│ - Serialization code │ │ │
└───────────────────────┘ └───────────────────────────┘
│
▼
Application developer writes C++ that includes generated headers
and calls ara:: API.The key principle: ARXML is not just documentation — it is executable configuration. Changing an ARXML parameter (e.g., a SOME/IP port number, a log level, a supervision timeout) changes how the entire system behaves without touching application source code.
1. ara::com — Communication (COM)
Role
ara::com is the primary inter-application communication API. It abstracts the underlying transport (SOME/IP, DDS, IPC) and exposes a unified C++ interface based on Services containing Events, Methods, and Fields.
ARXML: ServiceInterface Definition
The ServiceInterface in ARXML is the contract between provider and consumer. Everything in the C++ generated API (Skeleton base class, Proxy class, all data types) is derived from this single ARXML element.
<!-- /Interfaces/RadarObjectService — the canonical service model -->
<SERVICE-INTERFACE>
<SHORT-NAME>RadarObjectService</SHORT-NAME>
<CATEGORY>SERVICE</CATEGORY>
<MAJOR-VERSION>1</MAJOR-VERSION>
<MINOR-VERSION>3</MINOR-VERSION>
<!-- ── Data Types ───────────────────────────────────────────── -->
<!-- (defined separately; referenced here) -->
<!-- /DataTypes/RadarObject, /DataTypes/ObjectList, etc. -->
<!-- ── Events ───────────────────────────────────────────────── -->
<!-- Fire-and-forget publish; Skeleton.Send() → all subscribers -->
<EVENTS>
<VARIABLE-DATA-PROTOTYPE>
<SHORT-NAME>DetectedObjects</SHORT-NAME>
<TYPE-TREF DEST="IMPLEMENTATION-DATA-TYPE">
/DataTypes/ObjectList
</TYPE-TREF>
<!-- Serialization transformer chain (optional E2E protection) -->
<TRANSFORMER-CHAIN-REF DEST="DATA-TRANSFORMATION-SET">
/Transformers/E2E_P04_ObjectList
</TRANSFORMER-CHAIN-REF>
</VARIABLE-DATA-PROTOTYPE>
</EVENTS>
<!-- ── Methods ──────────────────────────────────────────────── -->
<!-- Request-response; Proxy returns ara::core::Future<T> -->
<METHODS>
<CLIENT-SERVER-OPERATION>
<SHORT-NAME>ResetDetectionFilter</SHORT-NAME>
<ARGUMENTS>
<ARGUMENT-DATA-PROTOTYPE>
<SHORT-NAME>filter_mode</SHORT-NAME>
<TYPE-TREF DEST="IMPLEMENTATION-DATA-TYPE">
/DataTypes/FilterMode
</TYPE-TREF>
<DIRECTION>IN</DIRECTION>
</ARGUMENT-DATA-PROTOTYPE>
</ARGUMENTS>
<!-- Return type; wrapped in Future<> by generated code -->
<RETURN-VALUE>
<TYPE-TREF DEST="IMPLEMENTATION-DATA-TYPE">
/DataTypes/ErrorCode
</TYPE-TREF>
</RETURN-VALUE>
<!-- Fire-and-forget if set: no return value, no response -->
<FIRE-AND-FORGET>false</FIRE-AND-FORGET>
</CLIENT-SERVER-OPERATION>
</METHODS>
<!-- ── Fields ───────────────────────────────────────────────── -->
<!-- Combination: getter method + setter method + notifier event -->
<FIELDS>
<FIELD>
<SHORT-NAME>DetectionThreshold</SHORT-NAME>
<TYPE-TREF DEST="IMPLEMENTATION-DATA-TYPE">
/DataTypes/Float32
</TYPE-TREF>
<HAS-GETTER>true</HAS-GETTER>
<HAS-SETTER>true</HAS-SETTER>
<HAS-NOTIFIER>true</HAS-NOTIFIER> <!-- change notification event -->
</FIELD>
</FIELDS>
</SERVICE-INTERFACE>ARXML: SOME/IP Transport Binding — Provided Instance
The ProvidedSomeipServiceInstance element wires the abstract ServiceInterface to actual network parameters used by Communication Management on the server ECU:
<PROVIDED-SOMEIP-SERVICE-INSTANCE>
<SHORT-NAME>RadarService_Inst1_Provided</SHORT-NAME>
<!-- Which abstract interface this configures -->
<SERVICE-INTERFACE-REF DEST="SERVICE-INTERFACE">
/Interfaces/RadarObjectService
</SERVICE-INTERFACE-REF>
<!-- SOME/IP identifiers assigned by the system architect -->
<SERVICE-ID>0x0101</SERVICE-ID>
<INSTANCE-ID>0x0001</INSTANCE-ID>
<MAJOR-VERSION>1</MAJOR-VERSION>
<MINOR-VERSION>3</MINOR-VERSION>
<!-- Service Discovery timing -->
<SD-SERVER-CONFIG>
<INITIAL-OFFER-BEHAVIOR>
<OFFER-INITIAL-DELAY-MIN>100</OFFER-INITIAL-DELAY-MIN> <!-- ms -->
<OFFER-INITIAL-DELAY-MAX>200</OFFER-INITIAL-DELAY-MAX>
<OFFER-REPETITION-BASE-DELAY>200</OFFER-REPETITION-BASE-DELAY>
<OFFER-REPETITIONS-MAX>3</OFFER-REPETITIONS-MAX>
</INITIAL-OFFER-BEHAVIOR>
<OFFER-CYCLIC-DELAY>1000</OFFER-CYCLIC-DELAY> <!-- ms, main phase -->
<REQUEST-RESPONSE-DELAY>
<MIN-VALUE>10</MIN-VALUE>
<MAX-VALUE>100</MAX-VALUE>
</REQUEST-RESPONSE-DELAY>
</SD-SERVER-CONFIG>
<!-- Event group binding (maps to SOME/IP event group for Subscribe) -->
<EVENT-GROUP>
<SHORT-NAME>ObjectEventGroup</SHORT-NAME>
<EVENT-GROUP-ID>0x0001</EVENT-GROUP-ID>
<!-- Which events belong to this event group -->
<EVENT-REF DEST="VARIABLE-DATA-PROTOTYPE">
/Interfaces/RadarObjectService/DetectedObjects
</EVENT-REF>
<!-- UDP multicast used for event delivery -->
<MULTICAST-UDP-ADDRESS>239.0.0.1</MULTICAST-UDP-ADDRESS>
<MULTICAST-UDP-PORT>30501</MULTICAST-UDP-PORT>
<!-- Initial event sent on subscription (unicast) -->
<MULTICAST-THRESHOLD>0</MULTICAST-THRESHOLD>
</EVENT-GROUP>
<!-- Method binding -->
<METHOD-MAPPING>
<SHORT-NAME>ResetFilter_Mapping</SHORT-NAME>
<METHOD-REF DEST="CLIENT-SERVER-OPERATION">
/Interfaces/RadarObjectService/ResetDetectionFilter
</METHOD-REF>
<METHOD-ID>0x0001</METHOD-ID>
<TRANSPORT-PROTOCOL>TCP</TRANSPORT-PROTOCOL>
<SOMEIP-HEADER-DATA>
<SERVER-SERVICE-MINOR-VERSION>3</SERVER-SERVICE-MINOR-VERSION>
</SOMEIP-HEADER-DATA>
</METHOD-MAPPING>
</PROVIDED-SOMEIP-SERVICE-INSTANCE>
<!-- Required Instance (CLIENT ECU side) -->
<REQUIRED-SOMEIP-SERVICE-INSTANCE>
<SHORT-NAME>RadarService_Inst1_Required</SHORT-NAME>
<SERVICE-INTERFACE-REF DEST="SERVICE-INTERFACE">
/Interfaces/RadarObjectService
</SERVICE-INTERFACE-REF>
<SERVICE-ID>0x0101</SERVICE-ID>
<INSTANCE-ID>0x0001</INSTANCE-ID>
<!-- SD client configuration -->
<SD-CLIENT-CONFIG>
<INITIAL-FIND-BEHAVIOR>
<FIND-INITIAL-DELAY-MIN>10</FIND-INITIAL-DELAY-MIN>
<FIND-INITIAL-DELAY-MAX>100</FIND-INITIAL-DELAY-MAX>
<FIND-REPETITIONS-MAX>3</FIND-REPETITIONS-MAX>
<FIND-REPETITION-BASE-DELAY>200</FIND-REPETITION-BASE-DELAY>
</INITIAL-FIND-BEHAVIOR>
<TTL>3000</TTL> <!-- ms — subscription TTL before auto-renewal -->
</SD-CLIENT-CONFIG>
<!-- Which event groups to subscribe to -->
<CONSUMED-EVENT-GROUP>
<SHORT-NAME>ObjectEventGroup_Consumed</SHORT-NAME>
<EVENT-GROUP-ID>0x0001</EVENT-GROUP-ID>
</CONSUMED-EVENT-GROUP>
</REQUIRED-SOMEIP-SERVICE-INSTANCE>SOME/IP Transport Layer Breakdown (UDP vs TCP)
ara::com transport selection per element type:
Element Default Transport When to use TCP instead
────────────────────────────────────────────────────────────────────
Events UDP (unicast/mcast) TCP only if reliability required
and you can afford TCP overhead
Methods TCP Use UDP if response fits one MTU
(rare — default is TCP)
Fields Same as events Notifier: UDP; Get/Set: TCP
SD (discovery) UDP broadcast/mcast Always UDP; broadcast for initial
offer; unicast for targeted SD
SOME/IP over UDP constraints:
- Max payload: 1472 bytes (Ethernet MTU 1500 - 20 IP - 8 UDP - SOME/IP header)
- Larger payloads: use SOME/IP TP (Transport Protocol — segmentation)
→ SOME/IP TP adds 4-byte offset header; CM reassembles on receiver side
SOME/IP TP ARXML config:
<SOMEIP-TP-CONFIG>
<TP-SUPPORTED>true</TP-SUPPORTED>
<SEGMENT-LEN>1392</SEGMENT-LEN> <!-- max bytes per UDP segment -->
</SOMEIP-TP-CONFIG>C++ API: Full Event/Method/Field Usage
// ── Skeleton (Server) ─────────────────────────────────────────────────
class MyRadarSkeleton : public RadarObjectServiceSkeleton {
public:
MyRadarSkeleton()
: RadarObjectServiceSkeleton(ara::com::InstanceIdentifier("RADAR_01")) {}
// Method handler — pure virtual; must implement
ara::core::Future<ErrorCode> ResetDetectionFilter(
const FilterMode& filter_mode) override
{
ara::core::Promise<ErrorCode> promise;
filter_.Reset(filter_mode);
promise.set_value(ErrorCode::kOk);
return promise.get_future();
}
// Publish event from application loop
void PublishObjects(const ObjectList& objects) {
// Allocate zero-copy sample from the COM pool
auto sample = DetectedObjects.Allocate();
*sample = objects;
// Send to all subscribers; CM handles transport
auto result = DetectedObjects.Send(std::move(sample));
if (!result.HasValue()) {
logger_.LogError() << "Send failed: " << result.Error().Message();
}
}
// Update field value (notifier event fires automatically to subscribers)
void UpdateThreshold(float t) { DetectionThreshold.Update(t); }
private:
ara::log::Logger& logger_ =
ara::log::CreateLogger("RDAR", "Radar skeleton");
DetectionFilter filter_;
};
// ── Proxy (Client) ────────────────────────────────────────────────────
class ObjectConsumer {
public:
void Start() {
// Async find — callback fires when service appears/disappears
find_handle_ = RadarObjectServiceProxy::StartFindService(
[this](auto container, auto) {
if (!container.empty()) {
proxy_ = std::make_unique<RadarObjectServiceProxy>(
container.front());
SetupSubscriptions();
}
},
ara::com::InstanceIdentifier::Any);
}
void SetupSubscriptions() {
// Subscribe to DetectedObjects event; cache up to 10 samples
proxy_->DetectedObjects.Subscribe(10);
proxy_->DetectedObjects.SetReceiveHandler(
[this]() { OnNewObjects(); });
// Subscribe to field change notification
proxy_->DetectionThreshold.Changed.Subscribe(1);
proxy_->DetectionThreshold.Changed.SetReceiveHandler(
[this]() { OnThresholdChanged(); });
}
void OnNewObjects() {
// Drain the event cache; lambda called once per sample
proxy_->DetectedObjects.GetNewSamples(
[](ara::com::SamplePtr<ObjectList> sample) {
ProcessObjects(*sample);
});
}
void OnThresholdChanged() {
proxy_->DetectionThreshold.Changed.GetNewSamples(
[](auto sample) {
logger_.LogInfo() << "New threshold: " << *sample;
});
}
void CallMethod() {
auto future = proxy_->ResetDetectionFilter(FilterMode::kShortRange);
// Non-blocking callback when result arrives
std::move(future).then([](ara::core::Future<ErrorCode> f) {
auto result = f.get();
if (result.HasValue() && result.Value() == ErrorCode::kOk)
logger_.LogInfo() << "Filter reset ok";
});
}
// Field getter (async)
void ReadField() {
auto future = proxy_->DetectionThreshold.Get();
float t = future.get().Value(); // blocking for brevity
logger_.LogInfo() << "Current threshold: " << t;
}
// Field setter
void WriteField(float t) {
auto future = proxy_->DetectionThreshold.Set(t);
future.get(); // wait for ack
}
private:
ara::com::FindServiceHandle find_handle_;
std::unique_ptr<RadarObjectServiceProxy> proxy_;
};2. ara::exec — Execution Management (EXM)
Role
ara::exec (referred to as EXM) is the interface between an Adaptive Application and the Execution Management platform service. It has two responsibilities:
- Application lifecycle reporting: The application tells EM which state it has reached (
kRunning,kTerminating) - Execution client: Used by tools or orchestrators to query the state of other applications
ARXML: Execution Manifest Process Configuration
<EXECUTION-MANIFEST>
<SHORT-NAME>RadarApp_ExecManifest</SHORT-NAME>
<!-- ── Process definition ─────────────────────────────────── -->
<PROCESS>
<SHORT-NAME>RadarProc</SHORT-NAME>
<!-- Path to the ELF binary on target filesystem -->
<EXECUTABLE-REF DEST="EXECUTABLE">
/Executables/radar_proc
</EXECUTABLE-REF>
<!-- CLI arguments -->
<START-UP-OPTION>
<SHORT-NAME>Opt_Config</SHORT-NAME>
<OPTION-VALUE>--config=/etc/radar/cfg.json</OPTION-VALUE>
</START-UP-OPTION>
<!-- POSIX scheduling (mapped to sched_setscheduler by EM) -->
<SCHEDULING-POLICY>SCHED-FIFO</SCHEDULING-POLICY>
<SCHEDULING-PRIORITY>60</SCHEDULING-PRIORITY>
<!-- CPU core pinning (mapped to sched_setaffinity by EM) -->
<CORE-AFFINITY>
<ASSIGNED-PROCESSOR-ID>2</ASSIGNED-PROCESSOR-ID>
<ASSIGNED-PROCESSOR-ID>3</ASSIGNED-PROCESSOR-ID>
</CORE-AFFINITY>
<!-- Resource limits (mapped to cgroup v2 by EM on Linux) -->
<PROCESS-RESOURCE-MANAGEMENT>
<CPU-BUDGET>
<BUDGET>300000</BUDGET> <!-- µs per period -->
<PERIOD>1000000</PERIOD> <!-- µs = 30% CPU -->
</CPU-BUDGET>
<MEMORY-HARD-LIMIT>536870912</MEMORY-HARD-LIMIT> <!-- 512 MB -->
<MAX-FILE-DESCRIPTORS>512</MAX-FILE-DESCRIPTORS>
</PROCESS-RESOURCE-MANAGEMENT>
<!-- Linux capability whitelist (least privilege) -->
<REQUIRED-ENTER-EXIT-PERMISSION>
<PERMISSION>CAP-SYS-NICE</PERMISSION>
</REQUIRED-ENTER-EXIT-PERMISSION>
<!-- FunctionGroup membership: this process runs when ADASfg = Active -->
<FUNCTION-GROUP-STATE-IN-PROCESS-IREF>
<FUNCTION-GROUP-REF DEST="FUNCTION-GROUP">
/MachineDesign/FunctionGroups/ADASfg
</FUNCTION-GROUP-REF>
<FUNCTION-GROUP-STATE-REF DEST="FUNCTION-GROUP-STATE">
/MachineDesign/FunctionGroups/ADASfg/Active
</FUNCTION-GROUP-STATE-REF>
</FUNCTION-GROUP-STATE-IN-PROCESS-IREF>
<!-- Timeouts -->
<STARTUP-TIMEOUT>5000</STARTUP-TIMEOUT> <!-- ms: max time to reach kRunning -->
<SHUTDOWN-TIMEOUT>3000</SHUTDOWN-TIMEOUT> <!-- ms: max time after SIGTERM -->
<!-- Recovery policy on unexpected exit -->
<PROCESS-RECOVERY>
<RECOVERY-ACTION>RESTART</RECOVERY-ACTION>
<MAX-NUM-RESTART-ATTEMPTS>3</MAX-NUM-RESTART-ATTEMPTS>
<RESTART-STRATEGY>EXPONENTIAL</RESTART-STRATEGY>
<RESTART-INTERVAL>500</RESTART-INTERVAL> <!-- ms base delay -->
</PROCESS-RECOVERY>
</PROCESS>
</EXECUTION-MANIFEST>C++ API
#include <ara/exec/application_client.h>
#include <ara/exec/execution_client.h>
// ── ApplicationClient — used by the application itself ───────────────
int main() {
ara::exec::ApplicationClient app_client;
// ── Initializing phase ────────────────────────────────────────────
// App is alive but not yet ready to serve. EM waits up to
// STARTUP-TIMEOUT ms for kRunning. Don't call OfferService yet.
InitHardware();
ConnectToServices();
LoadCalibration();
// Signal running — EM records this and stops the startup timer
app_client.ReportApplicationState(ara::exec::ApplicationState::kRunning);
// ── Running phase ─────────────────────────────────────────────────
skeleton_.OfferService();
while (!stop_token.stop_requested()) {
DoMainWork();
}
// ── Terminating phase ─────────────────────────────────────────────
skeleton_.StopOfferService();
app_client.ReportApplicationState(ara::exec::ApplicationState::kTerminating);
FlushLogs();
return 0;
// Process exit → EM observes waitpid() return → marks Terminated
}
// ── ExecutionClient — used to query state of other processes ─────────
// (used by State Management or diagnostic tools)
ara::exec::ExecutionClient exec_client;
// Query all function groups and their current states
auto fg_states = exec_client.GetFunctionGroupStates().Value();
for (const auto& [fg, state] : fg_states) {
logger.LogInfo() << "FunctionGroup: " << fg << " State: " << state;
}
// ── FunctionGroup state from EM perspective ───────────────────────────
// Applications can also receive state change notifications:
ara::exec::FunctionGroupStateClient fg_client(
"/MachineDesign/FunctionGroups/ADASfg");
fg_client.SetStateChangeHandler([](const std::string& new_state) {
if (new_state == "Active") {
StartADASProcessing();
} else if (new_state == "Passive") {
SuspendActuation();
}
});3. ara::log — Diagnostic Log and Trace (DLT)
Role
ara::log is the logging framework for AUTOSAR Adaptive. Under the hood it uses DLT (Diagnostic Log and Trace) — the AUTOSAR standard for structured log message routing in vehicles. Log messages are forwarded by the DLT daemon to:
- A host-side DLT Viewer tool (via USB or Ethernet)
- A persistent file (for post-mortem analysis)
- A remote diagnostic tester (via DoIP/UDS)
ARXML: Logging Configuration
Logging is configured in the Application Manifest:
<LOG-AND-TRACE>
<SHORT-NAME>RadarApp_LogConfig</SHORT-NAME>
<!-- Application-level defaults -->
<LOG-MODE>kRemote</LOG-MODE> <!-- kRemote | kFile | kConsole | combination -->
<LOG-LEVEL>kInfo</LOG-LEVEL> <!-- default level; filters lower-severity msgs -->
<LOG-FILE-PATH>/var/log/ara/radar.dlt</LOG-FILE-PATH>
<!-- DLT Application ID (4-char ASCII, visible in DLT Viewer) -->
<APPLICATION-ID>RDAR</APPLICATION-ID>
<APPLICATION-DESCRIPTION>Radar Processing Application</APPLICATION-DESCRIPTION>
<!-- Named log contexts (one per component / thread) -->
<LOG-CONTEXT>
<SHORT-NAME>MainCtx</SHORT-NAME>
<CONTEXT-ID>MAIN</CONTEXT-ID> <!-- 4-char, shown in DLT Viewer -->
<CONTEXT-DESCRIPTION>Main loop</CONTEXT-DESCRIPTION>
<DEFAULT-LOG-LEVEL>kVerbose</DEFAULT-LOG-LEVEL>
</LOG-CONTEXT>
<LOG-CONTEXT>
<SHORT-NAME>FilterCtx</SHORT-NAME>
<CONTEXT-ID>FILT</CONTEXT-ID>
<CONTEXT-DESCRIPTION>Object filter pipeline</CONTEXT-DESCRIPTION>
<DEFAULT-LOG-LEVEL>kWarn</DEFAULT-LOG-LEVEL> <!-- filter noisy in production -->
</LOG-CONTEXT>
</LOG-AND-TRACE>C++ API
#include <ara/log/logging.h>
// ── Initialisation (called once in main()) ────────────────────────────
// Parameters must match the ARXML LOG-AND-TRACE configuration
ara::log::InitLogging(
"RDAR", // Application ID (matches ARXML)
"Radar Processing Application", // Description (matches ARXML)
ara::log::LogLevel::kInfo, // Default level
ara::log::LogMode::kRemote // kRemote | kFile | kConsole
| ara::log::LogMode::kFile,
"/var/log/ara/radar.dlt" // File path (if kFile mode)
);
// ── Create logger for a context (matches ARXML LOG-CONTEXT) ──────────
static auto& main_logger =
ara::log::CreateLogger("MAIN", // Context ID (4-char)
"Main loop",
ara::log::LogLevel::kVerbose);
static auto& filter_logger =
ara::log::CreateLogger("FILT", "Object filter pipeline",
ara::log::LogLevel::kWarn);
// ── Log level severity (descending) ──────────────────────────────────
// kFatal — unrecoverable error; application will terminate
// kError — recoverable error; operation failed
// kWarn — unexpected condition; may affect correctness
// kInfo — normal operational events (service start/stop, etc.)
// kDebug — internal state useful during development
// kVerbose — fine-grained trace (disabled in production builds)
void ProcessFrame(const RadarFrame& frame) {
main_logger.LogDebug() << "ProcessFrame: " << frame.id;
auto result = filter_.Apply(frame);
if (!result.HasValue()) {
filter_logger.LogError()
<< "Filter failed: " << result.Error().Message()
<< " frame_id=" << frame.id;
return;
}
main_logger.LogInfo() << "Objects detected: " << result.Value().size();
}
// ── Structured argument types (shown with units in DLT Viewer) ────────
main_logger.LogInfo()
<< ara::log::Arg("distance_m", 42.7f)
<< ara::log::Arg("velocity_ms", -3.2f);
// ── Fatal log (flushes immediately, before crash handler) ─────────────
void OnHardwareFault(uint32_t fault_code) {
main_logger.LogFatal()
<< "Hardware fault code=0x" << ara::log::HexFormat(fault_code)
<< " — entering safe state";
ara::exec::ApplicationClient{}.ReportApplicationState(
ara::exec::ApplicationState::kTerminating);
std::abort();
}
// ── Runtime log level change (can be pushed via DLT Viewer) ──────────
// DLT Viewer sends a "Set Log Level" message over DLT protocol.
// ara::log runtime processes it automatically — no code needed.
// ARXML controls the initial level; runtime changes are volatile.DLT Message Structure (Internal)
DLT message on wire (TCP/UDP to host DLT Viewer):
Byte Field
──── ─────────────────────────────────────────────────────
0 Header type bitmask (extended header, verbose mode…)
1 Message counter (per application)
2–3 Message length
4–7 ECU ID ("RDAR" or "ECU1" — configured in dlt.conf)
8–11 Session ID (process PID)
12–15 Timestamp (100µs resolution, from monotonic clock)
16–19 Message ID (if non-verbose) / Argument count (verbose)
20+ Application ID (4 ASCII bytes)
24+ Context ID (4 ASCII bytes)
28+ Message type (DLT_TYPE_LOG, control, etc.)
32+ Log level (FATAL/ERROR/WARN/INFO/DEBUG/VERBOSE)
36+ Payload: serialized argument values (type+length+data)
DLT Viewer decodes each argument's type (bool, uint32, float32, string…)
and displays with proper formatting.4. ara::phm — Platform Health Management (PHM)
Role
ara::phm monitors the runtime health of Adaptive Applications. If an application stops checking in, exceeds a timing deadline, or executes in the wrong sequence, PHM triggers a configured recovery action (restart, safe state, reboot).
ARXML: PHM Supervision Configuration
<!-- ── Supervised Entity declaration in Application Manifest ────── -->
<PHM-SUPERVISED-ENTITY-INTERFACE>
<SHORT-NAME>RadarMain_SE</SHORT-NAME>
<CATEGORY>ALIVE-SUPERVISION</CATEGORY>
</PHM-SUPERVISED-ENTITY-INTERFACE>
<!-- ── Supervision configuration in Execution Manifest ─────────── -->
<HEALTH-CHANNEL-INTERFACE>
<SHORT-NAME>RadarHealth</SHORT-NAME>
<!-- ── Alive Supervision ─────────────────────────────────────── -->
<ALIVE-SUPERVISION>
<SHORT-NAME>RadarAlive</SHORT-NAME>
<SUPERVISED-ENTITY-ID>RadarMain_SE</SUPERVISED-ENTITY-ID>
<!-- Checkpoint ID that counts as the "alive" signal -->
<EXPECTED-ALIVE-INDICATION-CHECKPOINT>0</EXPECTED-ALIVE-INDICATION-CHECKPOINT>
<!-- Expected number of checkpoints per reference cycle -->
<EXPECTED-ALIVE-INDICATIONS>1</EXPECTED-ALIVE-INDICATIONS>
<!-- Reference cycle (ms) -->
<ALIVE-REFERENCE-CYCLE>50</ALIVE-REFERENCE-CYCLE>
<!-- Allowed miss count before failure declared -->
<SUPERVISION-INTERVAL-TOLERANCE>2</SUPERVISION-INTERVAL-TOLERANCE>
<!-- How many consecutive failures before recovery action triggered -->
<FAILED-SUPERVISION-CYCLES-TOLERANCE>3</FAILED-SUPERVISION-CYCLES-TOLERANCE>
</ALIVE-SUPERVISION>
<!-- ── Deadline Supervision ──────────────────────────────────── -->
<DEADLINE-SUPERVISION>
<SHORT-NAME>FilterDeadline</SHORT-NAME>
<SUPERVISED-ENTITY-ID>RadarMain_SE</SUPERVISED-ENTITY-ID>
<!-- Checkpoint A (start) → Checkpoint B (end) must happen within window -->
<SUPERVISION-CHECKPOINT-FROM>1</SUPERVISION-CHECKPOINT-FROM>
<SUPERVISION-CHECKPOINT-TO>2</SUPERVISION-CHECKPOINT-TO>
<MIN-DEADLINE>10</MIN-DEADLINE> <!-- ms — too fast = error too -->
<MAX-DEADLINE>100</MAX-DEADLINE> <!-- ms — must finish before this -->
</DEADLINE-SUPERVISION>
<!-- ── Logical Supervision ───────────────────────────────────── -->
<LOGICAL-SUPERVISION>
<SHORT-NAME>PipelineSequence</SHORT-NAME>
<SUPERVISED-ENTITY-ID>RadarMain_SE</SUPERVISED-ENTITY-ID>
<!-- Valid checkpoint graph: 10→11→12→10 (circular) or 10→13 (abort) -->
<SUPERVISION-CHECKPOINT>
<CHECKPOINT-ID>10</CHECKPOINT-ID>
<VALID-NEXT-CHECKPOINT>11</VALID-NEXT-CHECKPOINT>
<VALID-NEXT-CHECKPOINT>13</VALID-NEXT-CHECKPOINT> <!-- error path -->
</SUPERVISION-CHECKPOINT>
<SUPERVISION-CHECKPOINT>
<CHECKPOINT-ID>11</CHECKPOINT-ID>
<VALID-NEXT-CHECKPOINT>12</VALID-NEXT-CHECKPOINT>
</SUPERVISION-CHECKPOINT>
<SUPERVISION-CHECKPOINT>
<CHECKPOINT-ID>12</CHECKPOINT-ID>
<VALID-NEXT-CHECKPOINT>10</VALID-NEXT-CHECKPOINT> <!-- loop back -->
</SUPERVISION-CHECKPOINT>
</LOGICAL-SUPERVISION>
<!-- ── Recovery Action (what PHM does on supervision failure) ── -->
<HEALTH-CHANNEL-ACTION-ITEM>
<SHORT-NAME>HealthRecover</SHORT-NAME>
<STATUS-INDICATOR>SUPERVISION-FAILURE</STATUS-INDICATOR>
<!-- Notify SM to request state change → triggers process restart -->
<RECOVERY-NOTIFICATION-TO-SM>
<FUNCTION-GROUP-REF>/FGS/ADASfg</FUNCTION-GROUP-REF>
<FUNCTION-GROUP-STATE-REF>/FGS/ADASfg/Off</FUNCTION-GROUP-STATE-REF>
</RECOVERY-NOTIFICATION-TO-SM>
</HEALTH-CHANNEL-ACTION-ITEM>
</HEALTH-CHANNEL-INTERFACE>C++ API
#include <ara/phm/supervised_entity.h>
#include <ara/phm/health_channel.h>
// ── Supervised Entity: alive supervision ─────────────────────────────
// Instance identifier matches SUPERVISED-ENTITY-ID in ARXML
ara::phm::SupervisedEntity se_alive(
ara::phm::SupervisedEntityId{"RadarMain_SE"});
void MainProcessingLoop() {
while (!stop) {
ProcessRadarData(); // < 50ms
// Alive checkpoint — must be called once per reference cycle (50ms)
// Checkpoint 0 = the alive signal configured in ARXML
se_alive.ReportCheckpoint(ara::phm::CheckpointId{0});
std::this_thread::sleep_for(std::chrono::milliseconds(50));
}
}
// ── Deadline supervision ─────────────────────────────────────────────
void RunFilterPipeline() {
// Checkpoint 1 = start of monitored operation
se_alive.ReportCheckpoint(ara::phm::CheckpointId{1});
RunComplexFilter(); // PHM measures: must be 10ms ≤ duration ≤ 100ms
// Checkpoint 2 = end; PHM calculates elapsed time
se_alive.ReportCheckpoint(ara::phm::CheckpointId{2});
}
// ── Logical supervision ───────────────────────────────────────────────
void Pipeline() {
se_alive.ReportCheckpoint(ara::phm::CheckpointId{10}); // Step A
StageA();
se_alive.ReportCheckpoint(ara::phm::CheckpointId{11}); // Step B
StageB();
se_alive.ReportCheckpoint(ara::phm::CheckpointId{12}); // End: back to 10
// Any other sequence (e.g., 10 → 12 skipping 11) → logical failure
}
// ── HealthChannel: report non-supervision health events ──────────────
// (e.g., hardware faults that don't directly map to a supervision)
ara::phm::HealthChannel health_channel(
ara::phm::HealthChannelId{"RadarHealth"});
void OnHardwareSensorFault() {
// Inform PHM/SM of a health event; SM can react with state transition
health_channel.ReportHealthStatus(
ara::phm::HealthStatus{"SENSOR_FAULT"});
}5. arastm — State Management (STM)
Role
ara::sm (State Management, also referred to as STM) is the API through which applications interact with the State Management Functional Cluster. It allows applications to:
- Request a Function Group or Machine State transition
- Receive notifications when state changes occur
- Trigger emergency transitions (e.g., safe state request)
ARXML: Machine Design and Function Groups
All states and their associated processes are defined in the Machine Design ARXML:
<MACHINE-DESIGN>
<SHORT-NAME>VehicleComputePlatform</SHORT-NAME>
<!-- ── Machine State (top-level system mode) ──────────────── -->
<MACHINE-STATE-MACHINE>
<SHORT-NAME>MachineFSM</SHORT-NAME>
<MACHINE-STATE>
<SHORT-NAME>Startup</SHORT-NAME>
<!-- No user processes in Startup — platform services only -->
</MACHINE-STATE>
<MACHINE-STATE>
<SHORT-NAME>Driving</SHORT-NAME>
</MACHINE-STATE>
<MACHINE-STATE>
<SHORT-NAME>Parking</SHORT-NAME>
</MACHINE-STATE>
<MACHINE-STATE>
<SHORT-NAME>OTA-Update</SHORT-NAME>
</MACHINE-STATE>
<MACHINE-STATE>
<SHORT-NAME>Shutdown</SHORT-NAME>
</MACHINE-STATE>
<!-- Valid transitions (SM enforces; invalid requests are rejected) -->
<MACHINE-STATE-TRANSITION>
<FROM-STATE-REF>/Machine/States/Startup</FROM-STATE-REF>
<TO-STATE-REF>/Machine/States/Driving</TO-STATE-REF>
</MACHINE-STATE-TRANSITION>
<MACHINE-STATE-TRANSITION>
<FROM-STATE-REF>/Machine/States/Driving</FROM-STATE-REF>
<TO-STATE-REF>/Machine/States/Parking</TO-STATE-REF>
</MACHINE-STATE-TRANSITION>
<MACHINE-STATE-TRANSITION>
<FROM-STATE-REF>/Machine/States/Driving</FROM-STATE-REF>
<TO-STATE-REF>/Machine/States/OTA-Update</TO-STATE-REF>
</MACHINE-STATE-TRANSITION>
</MACHINE-STATE-MACHINE>
<!-- ── Function Groups ──────────────────────────────────────── -->
<FUNCTION-GROUP>
<SHORT-NAME>ADASfg</SHORT-NAME>
<CATEGORY>FUNCTION-GROUP</CATEGORY>
<FUNCTION-GROUP-STATE>
<SHORT-NAME>Off</SHORT-NAME>
<!-- No processes assigned to Off state -->
</FUNCTION-GROUP-STATE>
<FUNCTION-GROUP-STATE>
<SHORT-NAME>Passive</SHORT-NAME>
<!-- Sensor fusion only; no actuation -->
</FUNCTION-GROUP-STATE>
<FUNCTION-GROUP-STATE>
<SHORT-NAME>Active</SHORT-NAME>
<!-- All ADAS processes running -->
</FUNCTION-GROUP-STATE>
<!-- Valid state transitions within this FunctionGroup -->
<FUNCTION-GROUP-STATE-TRANSITION>
<FROM-REF>/FGS/ADASfg/Off</FROM-REF>
<TO-REF>/FGS/ADASfg/Passive</TO-REF>
</FUNCTION-GROUP-STATE-TRANSITION>
<FUNCTION-GROUP-STATE-TRANSITION>
<FROM-REF>/FGS/ADASfg/Passive</FROM-REF>
<TO-REF>/FGS/ADASfg/Active</TO-REF>
</FUNCTION-GROUP-STATE-TRANSITION>
<FUNCTION-GROUP-STATE-TRANSITION>
<FROM-REF>/FGS/ADASfg/Active</FROM-REF>
<TO-REF>/FGS/ADASfg/Passive</TO-REF>
</FUNCTION-GROUP-STATE-TRANSITION>
</FUNCTION-GROUP>
<!-- ── Trigger Mappings: Machine State → FunctionGroup State ── -->
<!-- When Machine enters "Driving", ADASfg → Active -->
<MACHINE-STATE-TO-FG-STATE-MAPPING>
<SHORT-NAME>DrivingToADASActive</SHORT-NAME>
<MACHINE-STATE-REF>/Machine/States/Driving</MACHINE-STATE-REF>
<FG-STATE-MAPPING>
<FUNCTION-GROUP-REF>/FGS/ADASfg</FUNCTION-GROUP-REF>
<FUNCTION-GROUP-STATE-REF>/FGS/ADASfg/Active</FUNCTION-GROUP-STATE-REF>
</FG-STATE-MAPPING>
</MACHINE-STATE-TO-FG-STATE-MAPPING>
</MACHINE-DESIGN>C++ API
#include <ara/sm/state_client.h>
#include <ara/sm/trigger_client.h>
// ── StateClient — request and observe state changes ───────────────────
ara::sm::StateClient sm_client;
// Request FunctionGroup transition (non-blocking; response via Future)
auto future = sm_client.RequestStateTransition(
"/MachineDesign/FunctionGroups/ADASfg", // FunctionGroup path
"Active" // target state
);
auto result = future.get();
if (result.HasValue()) {
logger.LogInfo() << "ADASfg: Active";
} else {
// SM rejected the request: invalid transition, prerequisite not met, etc.
logger.LogError() << "State transition rejected: "
<< result.Error().Message();
}
// Subscribe to state change notifications (non-blocking)
sm_client.SetStateChangeHandler(
"/MachineDesign/FunctionGroups/ADASfg",
[](const std::string& new_state) {
logger.LogInfo() << "ADASfg state changed -> " << new_state;
if (new_state == "Active") {
skeleton_.OfferService();
} else {
skeleton_.StopOfferService();
}
});
// Query current state
auto state = sm_client.GetCurrentState(
"/MachineDesign/FunctionGroups/ADASfg").Value();
logger.LogInfo() << "ADASfg is: " << state;
// ── TriggerClient — request Machine State transitions ─────────────────
// (typically called by orchestration or diagnostic application)
ara::sm::TriggerClient trigger_client;
// Request machine-level shutdown
trigger_client.RequestMachineStateTransition("Shutdown");
// Request OTA update mode (stops all non-UCM applications)
trigger_client.RequestMachineStateTransition("OTA-Update");6. ara::diag — Diagnostics (DIAG)
Role
ara::diag is the AUTOSAR Adaptive API for implementing diagnostic services. It allows an Adaptive Application to:
- Register as a UDS diagnostic server (handles services like 0x22 ReadDataByIdentifier, 0x14 ClearDTC, 0x31 RoutineControl)
- Be reachable by DoIP (Diagnostics over IP) from an external diagnostic tester
- Provide DID (Data Identifier) handlers, DTC monitors, and Routine Control handlers
ARXML: Diagnostic Configuration
<!-- ── Diagnostic Contribution (what this AA contributes to the server) -->
<DIAGNOSTIC-CONTRIBUTION-SET>
<SHORT-NAME>RadarDiag_Contributions</SHORT-NAME>
<!-- ── DID (ReadDataByIdentifier — UDS 0x22) ────────────────── -->
<DIAGNOSTIC-DATA-IDENTIFIER>
<SHORT-NAME>RadarStatus_DID</SHORT-NAME>
<ID>0xF190</ID> <!-- e.g., 0xF190 = AsciiVin; custom DIDs: 0x0100–0xEFFF -->
<!-- Read access: 0x22 will call the registered getter -->
<READ-CLASS-REF DEST="DIAGNOSTIC-READ-DATA-BY-IDENTIFIER">
/Diag/ReadDataByIdentifier
</READ-CLASS-REF>
<!-- Data definition -->
<DATA-ELEMENT>
<SHORT-NAME>StatusByte</SHORT-NAME>
<TYPE-TREF>/DataTypes/uint8</TYPE-TREF>
</DATA-ELEMENT>
<DATA-ELEMENT>
<SHORT-NAME>ObjectCount</SHORT-NAME>
<TYPE-TREF>/DataTypes/uint16</TYPE-TREF>
</DATA-ELEMENT>
</DIAGNOSTIC-DATA-IDENTIFIER>
<!-- ── DTC (Fault memory) ────────────────────────────────────── -->
<DIAGNOSTIC-TROUBLE-CODE-OBD>
<SHORT-NAME>RadarHW_Fault</SHORT-NAME>
<DTC-VALUE>0xC0100F</DTC-VALUE> <!-- P-code or OBD format -->
<FUNCTIONAL-UNIT>0x01</FUNCTIONAL-UNIT>
<SEVERITY>WWH-OBD-DTC-SEVERITY-REPORT-CONDITIONALLY</SEVERITY>
</DIAGNOSTIC-TROUBLE-CODE-OBD>
<!-- ── Routine Control (UDS 0x31) ───────────────────────────── -->
<DIAGNOSTIC-ROUTINE>
<SHORT-NAME>CalibrateSensor_Routine</SHORT-NAME>
<ROUTINE-IDENTIFIER>0x0201</ROUTINE-IDENTIFIER> <!-- custom ID -->
<!-- Start/Stop/RequestResult sub-functions -->
<SUBFUNCTION>
<SUB-FUNCTION>START</SUB-FUNCTION>
<PARAMETERS>
<PARAMETER>
<SHORT-NAME>CalibMode</SHORT-NAME>
<TYPE-TREF>/DataTypes/uint8</TYPE-TREF>
<DIRECTION>IN</DIRECTION>
</PARAMETER>
</PARAMETERS>
</SUBFUNCTION>
<SUBFUNCTION>
<SUB-FUNCTION>REQUEST-RESULT</SUB-FUNCTION>
<RESULT-PARAMETERS>
<PARAMETER>
<SHORT-NAME>CalibResult</SHORT-NAME>
<TYPE-TREF>/DataTypes/uint8</TYPE-TREF>
</PARAMETER>
</RESULT-PARAMETERS>
</SUBFUNCTION>
</DIAGNOSTIC-ROUTINE>
</DIAGNOSTIC-CONTRIBUTION-SET>
<!-- ── DoIP configuration (how external tester reaches this ECU) ─── -->
<DIAGNOSTIC-ADDRESS>
<SHORT-NAME>RadarECU_DoIPAddress</SHORT-NAME>
<LOGICAL-ADDRESS>0x0101</LOGICAL-ADDRESS> <!-- tester uses this address -->
<DOIP-CONNECTION>
<PROTOCOL-VERSION>2</PROTOCOL-VERSION>
<ANNOUNCE-INTERVAL>1000</ANNOUNCE-INTERVAL> <!-- ms, vehicle announcement -->
<VEHICLE-IP-ADDRESS>192.168.1.101</VEHICLE-IP-ADDRESS>
<ACTIVATION-LINE-DEP>true</ACTIVATION-LINE-DEP> <!-- needs ignition active -->
</DOIP-CONNECTION>
</DIAGNOSTIC-ADDRESS>C++ API
#include <ara/diag/uds_transport_protocol_handler.h>
#include <ara/diag/generic_uds_service.h>
#include <ara/diag/dtc_information.h>
#include <ara/diag/routine_control.h>
// ── DID Handler: UDS 0x22 ReadDataByIdentifier ───────────────────────
class RadarDiagHandler {
public:
void RegisterDIDs() {
// Register DID 0xF190 read handler
did_manager_.Register(
0xF190,
ara::diag::AccessPermission::kReadOnly,
[this](ara::diag::MetaInfo meta) -> ara::diag::OperationOutput {
// Return current radar status
ara::diag::OperationOutput out;
out.responseData = {
static_cast<uint8_t>(radar_status_), // StatusByte
static_cast<uint8_t>(object_count_ >> 8), // ObjectCount H
static_cast<uint8_t>(object_count_ & 0xFF) // ObjectCount L
};
return out;
});
}
// ── DTC Reporting: UDS 0x19 ReadDTCInformation ──────────────────
void ReportFault(bool fault_active) {
ara::diag::DtcInformation dtc_info(0xC0100F); // matches ARXML DTC value
if (fault_active) {
// Set DTC confirmed, test failed bits
dtc_info.SetTestFailed(ara::diag::TestResult::kTestFailed);
dtc_info.SetConfirmedDtc(true);
} else {
dtc_info.SetTestFailed(ara::diag::TestResult::kTestPassed);
}
}
// ── Routine Control: UDS 0x31 ────────────────────────────────────
void RegisterRoutine() {
routine_manager_.Register(
0x0201, // routine ID matches ARXML
// Start handler
[this](const std::vector<uint8_t>& params,
ara::diag::MetaInfo meta) -> ara::diag::OperationOutput {
uint8_t calib_mode = params.empty() ? 0 : params[0];
StartCalibration(calib_mode);
return {0x01}; // routine started response byte
},
// Stop handler
[this](auto, auto) -> ara::diag::OperationOutput {
StopCalibration();
return {0x02};
},
// RequestResult handler
[this](auto, auto) -> ara::diag::OperationOutput {
return {static_cast<uint8_t>(calibration_result_)};
});
}
// ── Security Access: UDS 0x27 ────────────────────────────────────
// Sensitive DIDs and routines can require security level unlock.
// ara::diag::SecurityAccess handles seed/key exchange.
// Configured in ARXML via DIAGNOSTIC-ACCESS-PERMISSION elements.
private:
ara::diag::DIDManager did_manager_;
ara::diag::RoutineManager routine_manager_;
RadarStatus radar_status_ = RadarStatus::kOk;
uint16_t object_count_ = 0;
uint8_t calibration_result_ = 0;
};7. ara::per — Persistency (PER)
Role
ara::per provides persistent storage for Adaptive Applications — data that survives process restarts and machine reboots. Two storage backends are offered:
| Storage Type | Use Case | Analogy |
|---|---|---|
KeyValueStorage | Small configuration values, calibration, counters | AUTOSAR NvM (Classic) |
FileStorage | Larger binary blobs, HD maps, certificate stores | Filesystem with versioning |
ARXML: Persistency Deployment
<!-- ── PersistencyKeyValueStorageInterface (design-time) ──────── -->
<!-- Defined in the Application Component's Port Interface -->
<PERSISTENCY-KEY-VALUE-STORAGE-INTERFACE>
<SHORT-NAME>RadarConfig_KVSI</SHORT-NAME>
<!-- Named data elements stored in this KV storage -->
<KEY-VALUE-PAIR-PROTOTYPE>
<SHORT-NAME>DetectionThreshold</SHORT-NAME>
<TYPE-TREF>/DataTypes/Float32</TYPE-TREF>
<!-- Default value used on first access if key not yet stored -->
<INIT-VALUE>
<NUMERICAL-VALUE>0.75</NUMERICAL-VALUE>
</INIT-VALUE>
</KEY-VALUE-PAIR-PROTOTYPE>
<KEY-VALUE-PAIR-PROTOTYPE>
<SHORT-NAME>CalibrationVersion</SHORT-NAME>
<TYPE-TREF>/DataTypes/uint32</TYPE-TREF>
<INIT-VALUE><NUMERICAL-VALUE>0</NUMERICAL-VALUE></INIT-VALUE>
</KEY-VALUE-PAIR-PROTOTYPE>
<KEY-VALUE-PAIR-PROTOTYPE>
<SHORT-NAME>FilterMode</SHORT-NAME>
<TYPE-TREF>/DataTypes/uint8</TYPE-TREF>
<INIT-VALUE><NUMERICAL-VALUE>1</NUMERICAL-VALUE></INIT-VALUE>
</KEY-VALUE-PAIR-PROTOTYPE>
</PERSISTENCY-KEY-VALUE-STORAGE-INTERFACE>
<!-- ── PersistencyDeployment (system integration — maps to filesystem) -->
<PERSISTENCY-KEY-VALUE-STORAGE-DEPLOYMENT>
<SHORT-NAME>RadarConfig_Deploy</SHORT-NAME>
<!-- Which KV interface this deploys -->
<PERSISTENCY-KEY-VALUE-STORAGE-INTERFACE-REF DEST="PERSISTENCY-KEY-VALUE-STORAGE-INTERFACE">
/Interfaces/RadarConfig_KVSI
</PERSISTENCY-KEY-VALUE-STORAGE-INTERFACE-REF>
<!-- Filesystem path where the storage database is created -->
<URI>/opt/radar/per/radar_config</URI>
<!-- Redundancy: how many copies are maintained for data integrity -->
<MAXIMUM-ALLOWED-SIZE-OF-REDUNDANT-AREA>65536</MAXIMUM-ALLOWED-SIZE-OF-REDUNDANT-AREA>
<REDUNDANCY-HANDLING-CAPABILITIES>
<REDUNDANCY-ENUM>TRIPLE</REDUNDANCY-ENUM> <!-- 3× copy voting -->
</REDUNDANCY-HANDLING-CAPABILITIES>
<!-- CRC protection per key-value block -->
<KEY-VALUE-STORAGE-INTEGRITY>
<INTEGRITY-CONDITION>CRC32</INTEGRITY-CONDITION>
</KEY-VALUE-STORAGE-INTEGRITY>
</PERSISTENCY-KEY-VALUE-STORAGE-DEPLOYMENT>
<!-- ── File Storage deployment ──────────────────────────────────── -->
<PERSISTENCY-FILE-STORAGE-DEPLOYMENT>
<SHORT-NAME>RadarMap_Deploy</SHORT-NAME>
<URI>/opt/radar/per/maps</URI>
<!-- Maximum total size of all files in this storage -->
<MAXIMUM-ALLOWED-SIZE>1073741824</MAXIMUM-ALLOWED-SIZE> <!-- 1 GB -->
<!-- File elements listed (optional; for validated access) -->
<FILE-ELEMENT>
<SHORT-NAME>SensorCalibBlob</SHORT-NAME>
<CATEGORY>BINARY</CATEGORY>
<MAX-SIZE>65536</MAX-SIZE>
</FILE-ELEMENT>
</PERSISTENCY-FILE-STORAGE-DEPLOYMENT>C++ API
#include <ara/per/key_value_storage.h>
#include <ara/per/file_storage.h>
// ── KeyValueStorage ───────────────────────────────────────────────────
// Open returns a Result; always check for error
// Short-name matches PERSISTENCY-KEY-VALUE-STORAGE-INTERFACE SHORT-NAME
auto kvs_result = ara::per::OpenKeyValueStorage("RadarConfig_KVSI");
if (!kvs_result.HasValue()) {
logger.LogError() << "Cannot open KVS: " << kvs_result.Error().Message();
std::abort();
}
auto& kvs = kvs_result.Value();
// ── Read a value ──────────────────────────────────────────────────────
// GetValue<T> returns ara::core::Result<T>
auto threshold_result = kvs.GetValue<float>("DetectionThreshold");
if (threshold_result.HasValue()) {
float threshold = threshold_result.Value(); // 0.75 on first run (init value)
ApplyThreshold(threshold);
} else {
// Key not found — use the ARXML init value (platform handles fallback)
logger.LogWarn() << "DetectionThreshold not set; using default";
}
// ── Write a value ─────────────────────────────────────────────────────
// SetValue does NOT persist immediately — data goes to write-back cache
auto set_result = kvs.SetValue("DetectionThreshold", 0.85f);
if (!set_result.HasValue()) {
logger.LogError() << "SetValue failed: " << set_result.Error().Message();
}
// Persist the cache to storage (calls msync() / fsync() internally)
// Must be called; not calling it means data may be lost on power-off
auto sync_result = kvs.SyncToStorage();
if (!sync_result.HasValue()) {
logger.LogError() << "Sync failed: " << sync_result.Error().Message();
}
// ── Remove a key ─────────────────────────────────────────────────────
kvs.RemoveKey("OldCalibrationData");
// ── Iterate all keys ─────────────────────────────────────────────────
auto keys = kvs.GetAllKeys().Value();
for (const auto& key : keys) {
logger.LogDebug() << "KVS key: " << key;
}
// ── Recover from corruption ───────────────────────────────────────────
// If CRC check fails on a block, ara::per returns an error.
// Application can request recovery (restores from redundant copy)
// or reset to defaults.
if (kvs.RecoverKey("FilterMode") == ara::per::RecoverResult::kRecovered) {
logger.LogWarn() << "FilterMode recovered from redundant copy";
}
// ── FileStorage ───────────────────────────────────────────────────────
auto fs_result = ara::per::OpenFileStorage("RadarMap_Deploy");
auto& fs = fs_result.Value();
// Write binary blob (sensor calibration)
auto write_result = fs.WriteFile(
"SensorCalibBlob",
reinterpret_cast<const uint8_t*>(calib_data.data()),
calib_data.size());
// Read binary blob
auto read_result = fs.ReadFile("SensorCalibBlob");
if (read_result.HasValue()) {
auto& blob = read_result.Value();
LoadCalibration(blob.data(), blob.size());
}
// Delete a file from storage
fs.DeleteFile("OldCalibBlob");
// List files in storage
auto files = fs.GetAllFileNames().Value();ara::per Redundancy and Integrity
The ARXML REDUNDANCY-ENUM setting controls how ara::per protects data against storage corruption:
NONE No redundancy. Single copy. Fastest; no protection.
DUAL Two copies stored. On mismatch → error reported to application.
TRIPLE Three copies stored. On mismatch → majority vote wins; error to app
if no majority. Slowest; highest reliability.
CRC32 Each block has a CRC32 appended. Detects single-bit corruption.
CRC64 Stronger CRC — used for safety-relevant stored data.
On corruption detected:
ara::per::GetValue<T>() returns ara::core::Result with error code
kRecoveryFailed or kCorrupted.
Application may call RecoverKey() to restore from redundant copy
or ResetToDefault() to reload ARXML init value.ARXML → Runtime: Flow Summary for All Seven Clusters
ARXML Element Functional Cluster What it configures at runtime
───────────────────────────────────────────────────────────────────────────────────
SERVICE-INTERFACE COM / ara::com Generated Skeleton/Proxy class;
└─ EVENTS, METHODS, FIELDS event, method, field IDs
PROVIDED-SOMEIP-SERVICE-INSTANCE COM / ara::com SOME/IP Service ID, Instance ID,
└─ EVENT-GROUP Event Group ID, multicast addr,
└─ METHOD-MAPPING Method ID, TCP/UDP port
EXECUTION-MANIFEST EXM / ara::exec process binary path, scheduling
└─ PROCESS priority, CPU affinity, cgroup
└─ FUNCTION-GROUP-STATE-IREF limits, startup/shutdown timeouts
LOG-AND-TRACE LOG / ara::log Application ID, Context IDs,
└─ LOG-CONTEXT default log levels per context,
log output mode (DLT/file/console)
HEALTH-CHANNEL-INTERFACE PHM / ara::phm Supervision type (alive/deadline/
└─ ALIVE-SUPERVISION logical), timing thresholds,
└─ DEADLINE-SUPERVISION recovery action on failure
└─ LOGICAL-SUPERVISION
MACHINE-DESIGN STM / ara::sm Valid Machine States, valid
└─ MACHINE-STATE-MACHINE FunctionGroups, valid state
└─ FUNCTION-GROUP transitions, Machine State →
└─ MACHINE-STATE-TO-FG-MAPPING FunctionGroup mapping
DIAGNOSTIC-CONTRIBUTION-SET DIAG / ara::diag DIDs (0x22/0x2E), DTCs (0x19),
└─ DIAGNOSTIC-DATA-IDENTIFIER Routines (0x31), security access
└─ DIAGNOSTIC-TROUBLE-CODE levels, DoIP address/port
└─ DIAGNOSTIC-ROUTINE
PERSISTENCY-KEY-VALUE-STORAGE PER / ara::per Filesystem path, init values,
└─ KEY-VALUE-PAIR-PROTOTYPE CRC mode, redundancy level,
PERSISTENCY-FILE-STORAGE max size, file elements list