2025-11-27 09:38:35 +01:00
|
|
|
|
/* AVB support */
|
|
|
|
|
|
/* SPDX-FileCopyrightText: Copyright © 2025 Alexandre Malki <alexandre.malki@kebag-logic.com> */
|
|
|
|
|
|
/* SPDX-License-Identifier: MIT */
|
|
|
|
|
|
|
|
|
|
|
|
#ifndef AVB_AECP_AEM_STATE_H
|
|
|
|
|
|
#define AVB_AECP_AEM_STATE_H
|
|
|
|
|
|
|
2025-12-07 09:14:17 +01:00
|
|
|
|
#include <stdint.h>
|
|
|
|
|
|
#include <stdbool.h>
|
|
|
|
|
|
|
2025-11-27 09:38:35 +01:00
|
|
|
|
#include "aecp-aem-descriptors.h"
|
2025-11-30 09:20:24 +01:00
|
|
|
|
#include "aecp-aem-milan.h"
|
2025-12-07 09:14:17 +01:00
|
|
|
|
#include "stream.h"
|
2025-11-27 09:38:35 +01:00
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* The way structure are organised in a "derived" manner.
|
|
|
|
|
|
* Each of the state structure must directly "castable" into the descriptor
|
|
|
|
|
|
* that the state variable relies upon.
|
|
|
|
|
|
*
|
|
|
|
|
|
* For instance, if a stream_input descriptor is created, the state structure
|
|
|
|
|
|
* stream_input_state needs to be created as follow:
|
|
|
|
|
|
*
|
|
|
|
|
|
* struct stream_input_state {
|
|
|
|
|
|
* struct stream_input_desc ...
|
|
|
|
|
|
* ...
|
|
|
|
|
|
* This way it's possible to get directly from the AEM command the descriptor
|
|
|
|
|
|
* and the state without having to create a mechanism for this.
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* \brief The base information would be required
|
|
|
|
|
|
* for descriptor that needs to udpate for unsollictied
|
|
|
|
|
|
* notificaction.
|
|
|
|
|
|
*/
|
|
|
|
|
|
struct aecp_aem_state_base {
|
2026-01-19 09:39:49 +01:00
|
|
|
|
uint64_t controller_entity_id;
|
2025-11-27 09:38:35 +01:00
|
|
|
|
|
2026-01-19 09:39:49 +01:00
|
|
|
|
int64_t last_update;
|
2025-11-27 09:38:35 +01:00
|
|
|
|
|
2026-01-19 09:39:49 +01:00
|
|
|
|
/** timeout absolute time*/
|
|
|
|
|
|
int64_t expire_timeout;
|
2025-11-27 09:38:35 +01:00
|
|
|
|
};
|
|
|
|
|
|
|
2025-11-30 09:20:24 +01:00
|
|
|
|
/**
|
|
|
|
|
|
* \brief the structure keeps track of the registered controller entities
|
|
|
|
|
|
*/
|
|
|
|
|
|
struct aecp_aem_unsol_notification_state {
|
2026-01-19 09:39:49 +01:00
|
|
|
|
uint64_t ctrler_entity_id;
|
2025-11-30 09:20:24 +01:00
|
|
|
|
|
2026-01-19 09:39:49 +01:00
|
|
|
|
uint8_t ctrler_mac_addr[6];
|
2025-11-30 09:20:24 +01:00
|
|
|
|
|
2026-01-19 09:39:49 +01:00
|
|
|
|
uint8_t port_id;
|
2025-11-30 09:20:24 +01:00
|
|
|
|
|
|
|
|
|
|
|
2026-01-19 09:39:49 +01:00
|
|
|
|
uint16_t next_seq_id;
|
|
|
|
|
|
bool is_registered;
|
2025-11-30 09:20:24 +01:00
|
|
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
2025-11-30 12:11:56 +01:00
|
|
|
|
struct aecp_aem_base_info {
|
2026-01-19 09:39:49 +01:00
|
|
|
|
uint64_t controller_entity_id;
|
2025-11-30 12:11:56 +01:00
|
|
|
|
|
2026-01-19 09:39:49 +01:00
|
|
|
|
int64_t last_update;
|
2025-11-30 12:11:56 +01:00
|
|
|
|
|
2026-01-19 09:39:49 +01:00
|
|
|
|
/** timeout absolute time*/
|
|
|
|
|
|
int64_t expire_timeout;
|
2025-11-30 12:11:56 +01:00
|
|
|
|
};
|
|
|
|
|
|
|
2025-11-30 09:20:24 +01:00
|
|
|
|
struct aecp_aem_lock_state {
|
2025-11-30 12:11:56 +01:00
|
|
|
|
struct aecp_aem_base_info base_info;
|
2025-11-30 09:20:24 +01:00
|
|
|
|
/**
|
|
|
|
|
|
* the entity id that is locking this system
|
|
|
|
|
|
*/
|
|
|
|
|
|
uint64_t locked_id;
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* actual value of the lock
|
|
|
|
|
|
*/
|
|
|
|
|
|
bool is_locked;
|
|
|
|
|
|
};
|
|
|
|
|
|
|
2026-04-25 09:18:34 +02:00
|
|
|
|
/**
|
|
|
|
|
|
* \brief Milan v1.2 Section 5.4.2.25 / Tables 5.13–5.14 — AVB Interface counters.
|
|
|
|
|
|
* LINK_UP / LINK_DOWN / GPTP_GM_CHANGED are mandatory; controllers infer the
|
|
|
|
|
|
* current link state from (LINK_UP > LINK_DOWN). We don't (yet) hook netlink
|
|
|
|
|
|
* for runtime up/down events, so link_up is seeded to 1 at descriptor
|
|
|
|
|
|
* creation — the interface is up by the time the daemon successfully binds. */
|
|
|
|
|
|
struct aecp_aem_avb_interface_counters {
|
|
|
|
|
|
uint32_t link_up;
|
|
|
|
|
|
uint32_t link_down;
|
|
|
|
|
|
uint32_t gptp_gm_changed;
|
|
|
|
|
|
};
|
|
|
|
|
|
|
2026-03-15 08:48:49 +01:00
|
|
|
|
struct aecp_aem_avb_interface_state {
|
2026-03-15 10:22:48 +01:00
|
|
|
|
struct avb_msrp_attribute domain_attr;
|
|
|
|
|
|
|
|
|
|
|
|
struct avb_mvrp_attribute vlan_attr;
|
2026-04-25 09:18:34 +02:00
|
|
|
|
|
|
|
|
|
|
struct aecp_aem_avb_interface_counters counters;
|
|
|
|
|
|
|
|
|
|
|
|
/* Milan Section 5.4.5: emit unsolicited GET_COUNTERS when any counter is
|
|
|
|
|
|
* updated, max once per second per descriptor. counters_dirty is set
|
|
|
|
|
|
* by the writer; AECP's periodic emits when dirty AND the rate-limit
|
|
|
|
|
|
* has elapsed, then clears dirty and updates last_counters_emit_ns. */
|
|
|
|
|
|
bool counters_dirty;
|
|
|
|
|
|
int64_t last_counters_emit_ns;
|
2026-03-15 08:48:49 +01:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
2025-11-30 09:20:24 +01:00
|
|
|
|
/**
|
|
|
|
|
|
* \brief the generic entity state common for all flavor of AVB
|
|
|
|
|
|
*/
|
|
|
|
|
|
struct aecp_aem_entity_state {
|
2025-12-03 09:11:17 +01:00
|
|
|
|
struct aecp_aem_lock_state lock_state;
|
2025-11-30 09:20:24 +01:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* \brief Milan implementation of the entity
|
|
|
|
|
|
*/
|
|
|
|
|
|
struct aecp_aem_entity_milan_state {
|
|
|
|
|
|
struct aecp_aem_entity_state state;
|
|
|
|
|
|
struct aecp_aem_unsol_notification_state unsol_notif_state[AECP_AEM_MILAN_MAX_CONTROLLER];
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* \brief Legacy AVB implementation of the entity
|
|
|
|
|
|
*/
|
|
|
|
|
|
struct aecp_aem_entity_legacy_avb_state {
|
|
|
|
|
|
struct aecp_aem_entity_state state;
|
|
|
|
|
|
};
|
2025-11-27 09:38:35 +01:00
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* \brief The stream inputs are specified as in the IEEE-1722.1-2021
|
|
|
|
|
|
* Table 7-156
|
|
|
|
|
|
*/
|
|
|
|
|
|
struct aecp_aem_stream_input_counters {
|
2026-01-19 09:39:49 +01:00
|
|
|
|
struct aecp_aem_state_base base_state;
|
2025-11-27 09:38:35 +01:00
|
|
|
|
|
2026-01-19 09:39:49 +01:00
|
|
|
|
uint32_t media_locked;
|
|
|
|
|
|
uint32_t media_unlocked;
|
|
|
|
|
|
uint32_t stream_interrupted;
|
|
|
|
|
|
uint32_t seq_mistmatch;
|
|
|
|
|
|
uint32_t media_reset;
|
|
|
|
|
|
/** Timestamp Uncertain */
|
|
|
|
|
|
uint32_t tu;
|
|
|
|
|
|
uint32_t unsupported_format;
|
|
|
|
|
|
uint32_t late_timestamp;
|
|
|
|
|
|
uint32_t early_timestamp;
|
|
|
|
|
|
uint32_t frame_rx;
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
struct stream_common {
|
|
|
|
|
|
struct stream stream;
|
2026-03-15 10:22:48 +01:00
|
|
|
|
|
|
|
|
|
|
struct avb_msrp_attribute lstream_attr;
|
|
|
|
|
|
struct avb_msrp_attribute tastream_attr;
|
|
|
|
|
|
struct avb_msrp_attribute tfstream_attr;
|
2025-11-27 09:38:35 +01:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
struct aecp_aem_stream_input_state {
|
2026-01-19 09:39:49 +01:00
|
|
|
|
struct aecp_aem_stream_input_counters counters;
|
|
|
|
|
|
struct stream_common common;
|
2026-03-15 10:22:48 +01:00
|
|
|
|
struct avb_mvrp_attribute mvrp_attr;
|
2026-04-25 09:18:34 +02:00
|
|
|
|
|
|
|
|
|
|
/** Milan v1.2 Section 5.3.8.7: started/stopped state of the bound Stream Input.
|
|
|
|
|
|
* Toggled by START_STREAMING / STOP_STREAMING. Defaults to started.
|
|
|
|
|
|
* Undefined when the Stream Input is not bound. */
|
|
|
|
|
|
bool started;
|
|
|
|
|
|
|
|
|
|
|
|
bool stream_info_dirty;
|
|
|
|
|
|
|
|
|
|
|
|
/* Milan Section 5.4.5 counter unsolicited rate-limit (see avb_interface_state). */
|
|
|
|
|
|
bool counters_dirty;
|
|
|
|
|
|
int64_t last_counters_emit_ns;
|
2026-04-26 16:19:29 +02:00
|
|
|
|
|
|
|
|
|
|
/* Milan Section 5.4.5.3 / Table 5.16: MEDIA_LOCKED ticks on the first valid
|
|
|
|
|
|
* AVTPDU after a silence gap; MEDIA_UNLOCKED ticks when the gap
|
|
|
|
|
|
* exceeds AVB_MEDIA_UNLOCK_TIMEOUT_NS. last_frame_rx_ns tracks the
|
|
|
|
|
|
* most recent valid PDU; media_locked_state is the current edge. */
|
|
|
|
|
|
int64_t last_frame_rx_ns;
|
|
|
|
|
|
bool media_locked_state;
|
2026-01-19 09:39:49 +01:00
|
|
|
|
};
|
|
|
|
|
|
|
2026-04-18 16:39:56 +02:00
|
|
|
|
struct acmp_stream_status_milan_v12 {
|
|
|
|
|
|
uint64_t controller_entity_id;
|
|
|
|
|
|
uint32_t acmp_flags;
|
2026-01-19 09:39:49 +01:00
|
|
|
|
uint8_t probing_status;
|
|
|
|
|
|
uint8_t acmp_status;
|
|
|
|
|
|
uint32_t fsm_acmp_state;
|
2026-04-18 18:42:23 +02:00
|
|
|
|
int64_t last_probe_rx_time;
|
2026-01-19 09:39:49 +01:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* \brief The Milan v1.2 stream structure needs more information
|
|
|
|
|
|
* about the different protocol*/
|
|
|
|
|
|
struct aecp_aem_stream_input_state_milan_v12 {
|
|
|
|
|
|
struct aecp_aem_stream_input_state stream_in_sta;
|
2026-04-18 16:39:56 +02:00
|
|
|
|
struct acmp_stream_status_milan_v12 acmp_sta;
|
2025-11-27 09:38:35 +01:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
struct aecp_aem_stream_output_counters {
|
2026-01-19 09:39:49 +01:00
|
|
|
|
struct aecp_aem_state_base base_state;
|
2025-11-27 09:38:35 +01:00
|
|
|
|
|
2026-01-19 09:39:49 +01:00
|
|
|
|
uint32_t stream_start;
|
|
|
|
|
|
uint32_t stream_stop;
|
|
|
|
|
|
uint32_t media_reset;
|
|
|
|
|
|
uint32_t tu;
|
|
|
|
|
|
uint32_t frame_tx;
|
2025-11-27 09:38:35 +01:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
struct aecp_aem_stream_output_state {
|
2026-01-19 09:39:49 +01:00
|
|
|
|
struct aecp_aem_stream_output_counters counters;
|
|
|
|
|
|
struct stream_common common;
|
2026-04-18 18:44:02 +02:00
|
|
|
|
|
|
|
|
|
|
/** Milan v1.2 Section 4.3.3.1: absolute time of last PROBE_TX_COMMAND received.
|
|
|
|
|
|
* 0 = never received. Reset to 0 when SRP is deactivated. */
|
|
|
|
|
|
int64_t last_probe_rx_time;
|
2026-04-25 09:18:34 +02:00
|
|
|
|
|
|
|
|
|
|
/** Milan v1.2 Section 4.3.3.1: a Listener MSRP attribute matching this Stream
|
|
|
|
|
|
* Output's stream_id is currently registered (foreign declaration
|
|
|
|
|
|
* observed via MRP). Maintained by notify_listener() in msrp.c. */
|
|
|
|
|
|
bool listener_observed;
|
|
|
|
|
|
|
|
|
|
|
|
/** Milan v1.2 Section 5.3.7.6: Presentation time offset, in nanoseconds.
|
|
|
|
|
|
* Default 2_000_000 (2 ms). Settable via SET_STREAM_INFO with the
|
|
|
|
|
|
* MSRP_ACC_LAT_VALID flag. Range 0 .. 0x7FFFFFFF. */
|
|
|
|
|
|
uint32_t presentation_time_offset_ns;
|
|
|
|
|
|
|
2026-04-26 14:57:24 +02:00
|
|
|
|
/** IEEE 1722.1-2021 Section 7.4.39 max_transit_time, nanoseconds. The maximum
|
|
|
|
|
|
* time between an AVTP frame's transmission by this Talker and its
|
|
|
|
|
|
* consumption by any Listener. Read by stream_activate() to seed
|
|
|
|
|
|
* stream->mtt (the per-PDU presentation_time = txtime + mtt) and by
|
|
|
|
|
|
* GET_MAX_TRANSIT_TIME; updated by SET_MAX_TRANSIT_TIME. Default
|
|
|
|
|
|
* 2_000_000 (2 ms) — kept in sync with presentation_time_offset_ns
|
|
|
|
|
|
* until the two opcodes are wired up to set them independently. */
|
|
|
|
|
|
uint64_t max_transit_time_ns;
|
|
|
|
|
|
|
2026-04-25 09:18:34 +02:00
|
|
|
|
bool stream_info_dirty;
|
|
|
|
|
|
|
|
|
|
|
|
/* Milan Section 5.4.5 counter unsolicited rate-limit (see avb_interface_state). */
|
|
|
|
|
|
bool counters_dirty;
|
|
|
|
|
|
int64_t last_counters_emit_ns;
|
2025-11-27 09:38:35 +01:00
|
|
|
|
};
|
|
|
|
|
|
|
2026-04-18 18:42:23 +02:00
|
|
|
|
struct aecp_aem_stream_output_state_milan_v12 {
|
|
|
|
|
|
struct aecp_aem_stream_output_state stream_out_sta;
|
|
|
|
|
|
struct acmp_stream_status_milan_v12 acmp_sta;
|
|
|
|
|
|
};
|
|
|
|
|
|
|
2025-11-27 09:38:35 +01:00
|
|
|
|
#endif // AVB_AECP_AEM_STATE_H
|