mirror of
https://gitlab.freedesktop.org/pipewire/pipewire.git
synced 2025-12-27 23:10:06 +01:00
Merge branch '5011_introduce_unsolicited_notififications' into 'master'
5011: module-avb: milan: aecp-aem handle de/registration for unsolicited... See merge request pipewire/pipewire!2619
This commit is contained in:
commit
d10b72f799
12 changed files with 440 additions and 7 deletions
|
|
@ -738,6 +738,9 @@ if build_module_avb
|
||||||
'module-avb/aecp-aem.c',
|
'module-avb/aecp-aem.c',
|
||||||
'module-avb/aecp-aem-cmds-resps/cmd-lock-entity.c',
|
'module-avb/aecp-aem-cmds-resps/cmd-lock-entity.c',
|
||||||
'module-avb/aecp-aem-cmds-resps/cmd-available.c',
|
'module-avb/aecp-aem-cmds-resps/cmd-available.c',
|
||||||
|
'module-avb/aecp-aem-cmds-resps/cmd-register-unsolicited-notifications.c',
|
||||||
|
'module-avb/aecp-aem-cmds-resps/cmd-deregister-unsolicited-notifications.c',
|
||||||
|
'module-avb/aecp-aem-cmds-resps/reply-unsol-helpers.c',
|
||||||
'module-avb/es-builder.c',
|
'module-avb/es-builder.c',
|
||||||
'module-avb/avdecc.c',
|
'module-avb/avdecc.c',
|
||||||
'module-avb/maap.c',
|
'module-avb/maap.c',
|
||||||
|
|
|
||||||
|
|
@ -47,7 +47,7 @@ int handle_cmd_entity_available_milan_v12(struct aecp *aecp, int64_t now, const
|
||||||
}
|
}
|
||||||
|
|
||||||
entity_state = desc->ptr;
|
entity_state = desc->ptr;
|
||||||
lock = &entity_state->lock_state;
|
lock = &entity_state->state.lock_state;
|
||||||
|
|
||||||
/* Forge the response for the entity that is locking the device */
|
/* Forge the response for the entity that is locking the device */
|
||||||
memcpy(buf, m, len);
|
memcpy(buf, m, len);
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,68 @@
|
||||||
|
/* AVB support */
|
||||||
|
/* SPDX-FileCopyrightText: Copyright © 2025 Kebag-Logic */
|
||||||
|
/* SPDX-FileCopyrightText: Copyright © 2025 Alex Malki <alexandre.malki@kebag-logic.com> */
|
||||||
|
/* SPDX-FileCopyrightText: Copyright © 2025 Simon Gapp <simon.gapp@kebag-logic.com> */
|
||||||
|
/* SPDX-License-Identifier: MIT */
|
||||||
|
|
||||||
|
#include <pipewire/log.h>
|
||||||
|
#include <inttypes.h>
|
||||||
|
|
||||||
|
#include "../aecp-aem.h"
|
||||||
|
#include "../aecp-aem-state.h"
|
||||||
|
#include "../aecp-aem-milan.h"
|
||||||
|
|
||||||
|
#include "cmd-deregister-unsolicited-notifications.h"
|
||||||
|
#include "cmd-resp-helpers.h"
|
||||||
|
|
||||||
|
int handle_cmd_deregister_unsol_notif_milan_v12(struct aecp *aecp, int64_t now,
|
||||||
|
const void *m, int len)
|
||||||
|
{
|
||||||
|
const struct avb_ethernet_header *h = m;
|
||||||
|
const struct avb_packet_aecp_aem *p = SPA_PTROFF(h, sizeof(*h), void);
|
||||||
|
struct descriptor *desc;
|
||||||
|
struct aecp_aem_entity_milan_state *entity_state;
|
||||||
|
struct aecp_aem_unsol_notification_state *unsol;
|
||||||
|
uint64_t controller_id = htobe64(p->aecp.controller_guid);
|
||||||
|
const uint32_t ctrler_max = AECP_AEM_MILAN_MAX_CONTROLLER;
|
||||||
|
uint16_t index;
|
||||||
|
|
||||||
|
desc = server_find_descriptor(aecp->server, AVB_AEM_DESC_ENTITY, 0);
|
||||||
|
if (desc == NULL)
|
||||||
|
return reply_status(aecp, AVB_AECP_AEM_STATUS_NO_SUCH_DESCRIPTOR, p, len);
|
||||||
|
|
||||||
|
entity_state = (struct aecp_aem_entity_milan_state *) desc->ptr;
|
||||||
|
unsol = entity_state->unsol_notif_state;
|
||||||
|
|
||||||
|
/** First check if the controller was already registered */
|
||||||
|
for (index = 0; index < ctrler_max; index++) {
|
||||||
|
uint64_t ctrl_eid = unsol[index].ctrler_entity_id;
|
||||||
|
bool ctrler_reged = unsol[index].is_registered;
|
||||||
|
|
||||||
|
if ((ctrl_eid == controller_id) && ctrler_reged) {
|
||||||
|
pw_log_debug("controller 0x%"PRIx64", already registered",
|
||||||
|
controller_id);
|
||||||
|
return reply_success(aecp, m, len);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** When one slot is in the array is available use it */
|
||||||
|
for (index = 0; index < ctrler_max; index++) {
|
||||||
|
if (!unsol[index].is_registered) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Reach the maximum controller allocated */
|
||||||
|
if (index == ctrler_max) {
|
||||||
|
return reply_no_resources(aecp, m, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsol[index].ctrler_entity_id = controller_id;
|
||||||
|
memcpy(unsol[index].ctrler_mac_addr, h->src, sizeof(h->src));
|
||||||
|
unsol[index].is_registered = true;
|
||||||
|
unsol[index].port_id = 0;
|
||||||
|
unsol[index].next_seq_id = 0;
|
||||||
|
|
||||||
|
pw_log_info("Unsol registration for 0x%"PRIx64, controller_id);
|
||||||
|
return reply_success(aecp, m, len);
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,23 @@
|
||||||
|
/* AVB support */
|
||||||
|
/* SPDX-FileCopyrightText: Copyright © 2025 Kebag-Logic */
|
||||||
|
/* SPDX-FileCopyrightText: Copyright © 2025 Alex Malki <alexandre.malki@kebag-logic.com> */
|
||||||
|
/* SPDX-FileCopyrightText: Copyright © 2025 Simon Gapp <simon.gapp@kebag-logic.com> */
|
||||||
|
/* SPDX-License-Identifier: MIT */
|
||||||
|
|
||||||
|
#ifndef __AVB_DEREGISTER_UNSOLICITED_NOTIFICATIONS_H__
|
||||||
|
#define __AVB_DEREGISTER_UNSOLICITED_NOTIFICATIONS_H__
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Command handling will generate the response to the
|
||||||
|
* received command when deregistering the a controller from
|
||||||
|
* the list of subscribed controller entities.
|
||||||
|
*
|
||||||
|
* @see IEEE1722.1-2021 Section 7.4.38 .
|
||||||
|
* @see Milan V1.2 Section 5.4.2.22.
|
||||||
|
*/
|
||||||
|
int handle_cmd_deregister_unsol_notif_milan_v12(struct aecp *aecp, int64_t now,
|
||||||
|
const void *m, int len);
|
||||||
|
|
||||||
|
#endif // __AVB_DEREGISTER_UNSOLICITED_NOTIFICATIONS_H__
|
||||||
|
|
@ -17,6 +17,59 @@
|
||||||
#include "cmd-lock-entity.h"
|
#include "cmd-lock-entity.h"
|
||||||
#include "cmd-resp-helpers.h"
|
#include "cmd-resp-helpers.h"
|
||||||
|
|
||||||
|
#include "reply-unsol-helpers.h"
|
||||||
|
|
||||||
|
static int handle_unsol_lock_common(struct aecp *aecp,
|
||||||
|
struct aecp_aem_lock_state *lock, bool internal)
|
||||||
|
{
|
||||||
|
uint8_t buf[512];
|
||||||
|
void *m = buf;
|
||||||
|
// struct aecp_aem_regis_unsols
|
||||||
|
struct avb_ethernet_header *h = m;
|
||||||
|
struct avb_packet_aecp_aem *p = SPA_PTROFF(h, sizeof(*h), void);
|
||||||
|
struct avb_packet_aecp_aem_lock *ae;
|
||||||
|
size_t len = sizeof(*h) + sizeof(*p) + sizeof(*ae);
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
memset(buf, 0, sizeof(buf));
|
||||||
|
ae = (struct avb_packet_aecp_aem_lock*)p->payload;
|
||||||
|
|
||||||
|
if (!lock->is_locked) {
|
||||||
|
ae->locked_guid = 0;
|
||||||
|
ae->flags = htonl(AECP_AEM_LOCK_ENTITY_FLAG_UNLOCK);
|
||||||
|
lock->is_locked = false;
|
||||||
|
lock->base_info.expire_timeout = LONG_MAX;
|
||||||
|
} else {
|
||||||
|
ae->locked_guid = htobe64(lock->locked_id);
|
||||||
|
ae->flags = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
AVB_PACKET_AEM_SET_COMMAND_TYPE(p, AVB_AECP_AEM_CMD_LOCK_ENTITY);
|
||||||
|
|
||||||
|
/** Setup the packet for the unsolicited notification*/
|
||||||
|
rc = reply_unsolicited_notifications(aecp, &lock->base_info, buf, len, internal);
|
||||||
|
if (rc) {
|
||||||
|
pw_log_error("Unsolicited notification failed \n");
|
||||||
|
}
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int handle_unsol_lock_entity_milanv12(struct aecp *aecp, struct descriptor *desc,
|
||||||
|
uint64_t ctrler_id)
|
||||||
|
{
|
||||||
|
int rc = -1;
|
||||||
|
struct aecp_aem_entity_milan_state *entity_state;
|
||||||
|
struct aecp_aem_lock_state *lock;
|
||||||
|
|
||||||
|
entity_state = desc->ptr;
|
||||||
|
lock = &entity_state->state.lock_state;
|
||||||
|
lock->base_info.controller_entity_id = ctrler_id;
|
||||||
|
rc = handle_unsol_lock_common(aecp, lock, false);
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* LOCK_ENTITY */
|
/* LOCK_ENTITY */
|
||||||
/* Milan v1.2, Sec. 5.4.2.2; IEEE 1722.1-2021, Sec. 7.4.2*/
|
/* Milan v1.2, Sec. 5.4.2.2; IEEE 1722.1-2021, Sec. 7.4.2*/
|
||||||
|
|
@ -49,7 +102,7 @@ int handle_cmd_lock_entity_milan_v12(struct aecp *aecp, int64_t now, const void
|
||||||
return reply_status(aecp, AVB_AECP_AEM_STATUS_NO_SUCH_DESCRIPTOR, p, len);
|
return reply_status(aecp, AVB_AECP_AEM_STATUS_NO_SUCH_DESCRIPTOR, p, len);
|
||||||
|
|
||||||
entity_state = desc->ptr;
|
entity_state = desc->ptr;
|
||||||
lock = &entity_state->lock_state;
|
lock = &entity_state->state.lock_state;
|
||||||
|
|
||||||
if (desc_type != AVB_AEM_DESC_ENTITY || desc_id != 0) {
|
if (desc_type != AVB_AEM_DESC_ENTITY || desc_id != 0) {
|
||||||
/*
|
/*
|
||||||
|
|
@ -117,5 +170,11 @@ int handle_cmd_lock_entity_milan_v12(struct aecp *aecp, int64_t now, const void
|
||||||
return reply_entity_locked(aecp, buf, len);
|
return reply_entity_locked(aecp, buf, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
return reply_success(aecp, buf, len);
|
if (reply_success(aecp, buf, len)) {
|
||||||
|
pw_log_debug("Failed sending success reply\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Then update the state using the system */
|
||||||
|
return handle_unsol_lock_entity_milanv12(aecp, desc, ctrler_id);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,68 @@
|
||||||
|
/* AVB support */
|
||||||
|
/* SPDX-FileCopyrightText: Copyright © 2025 Kebag-Logic */
|
||||||
|
/* SPDX-FileCopyrightText: Copyright © 2025 Alex Malki <alexandre.malki@kebag-logic.com> */
|
||||||
|
/* SPDX-FileCopyrightText: Copyright © 2025 Simon Gapp <simon.gapp@kebag-logic.com> */
|
||||||
|
/* SPDX-License-Identifier: MIT */
|
||||||
|
|
||||||
|
#include <pipewire/log.h>
|
||||||
|
#include <inttypes.h>
|
||||||
|
|
||||||
|
#include "../aecp-aem.h"
|
||||||
|
#include "../aecp-aem-state.h"
|
||||||
|
#include "../aecp-aem-milan.h"
|
||||||
|
|
||||||
|
#include "cmd-register-unsolicited-notifications.h"
|
||||||
|
#include "cmd-resp-helpers.h"
|
||||||
|
|
||||||
|
int handle_cmd_register_unsol_notif_milan_v12(struct aecp *aecp, int64_t now,
|
||||||
|
const void *m, int len)
|
||||||
|
{
|
||||||
|
const struct avb_ethernet_header *h = m;
|
||||||
|
const struct avb_packet_aecp_aem *p = SPA_PTROFF(h, sizeof(*h), void);
|
||||||
|
struct descriptor *desc;
|
||||||
|
struct aecp_aem_entity_milan_state *entity_state;
|
||||||
|
struct aecp_aem_unsol_notification_state *unsol;
|
||||||
|
uint64_t controller_id = htobe64(p->aecp.controller_guid);
|
||||||
|
const uint32_t ctrler_max = AECP_AEM_MILAN_MAX_CONTROLLER;
|
||||||
|
uint16_t index;
|
||||||
|
|
||||||
|
desc = server_find_descriptor(aecp->server, AVB_AEM_DESC_ENTITY, 0);
|
||||||
|
if (desc == NULL)
|
||||||
|
return reply_status(aecp, AVB_AECP_AEM_STATUS_NO_SUCH_DESCRIPTOR, p, len);
|
||||||
|
|
||||||
|
entity_state = (struct aecp_aem_entity_milan_state *) desc->ptr;
|
||||||
|
unsol = entity_state->unsol_notif_state;
|
||||||
|
|
||||||
|
/** First check if the controller was already registered */
|
||||||
|
for (index = 0; index < ctrler_max; index++) {
|
||||||
|
uint64_t ctrl_eid = unsol[index].ctrler_entity_id;
|
||||||
|
bool ctrler_reged = unsol[index].is_registered;
|
||||||
|
|
||||||
|
if ((ctrl_eid == controller_id) && ctrler_reged) {
|
||||||
|
pw_log_debug("controller 0x%"PRIx64", already registered",
|
||||||
|
controller_id);
|
||||||
|
return reply_success(aecp, m, len);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** When one slot is in the array is available use it */
|
||||||
|
for (index = 0; index < ctrler_max; index++) {
|
||||||
|
if (!unsol[index].is_registered) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Reach the maximum controller allocated */
|
||||||
|
if (index == ctrler_max) {
|
||||||
|
return reply_no_resources(aecp, m, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsol[index].ctrler_entity_id = controller_id;
|
||||||
|
memcpy(unsol[index].ctrler_mac_addr, h->src, sizeof(h->src));
|
||||||
|
unsol[index].is_registered = true;
|
||||||
|
unsol[index].port_id = 0;
|
||||||
|
unsol[index].next_seq_id = 0;
|
||||||
|
|
||||||
|
pw_log_info("Unsol registration for 0x%"PRIx64, controller_id);
|
||||||
|
return reply_success(aecp, m, len);
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,23 @@
|
||||||
|
/* AVB support */
|
||||||
|
/* SPDX-FileCopyrightText: Copyright © 2025 Kebag-Logic */
|
||||||
|
/* SPDX-FileCopyrightText: Copyright © 2025 Alex Malki <alexandre.malki@kebag-logic.com> */
|
||||||
|
/* SPDX-FileCopyrightText: Copyright © 2025 Simon Gapp <simon.gapp@kebag-logic.com> */
|
||||||
|
/* SPDX-License-Identifier: MIT */
|
||||||
|
|
||||||
|
#ifndef __AVB_REGISTER_UNSOLICITED_NOTIFICATIONS_H__
|
||||||
|
#define __AVB_REGISTER_UNSOLICITED_NOTIFICATIONS_H__
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Command handling will generate the response to the
|
||||||
|
* received command when registering the a controller from
|
||||||
|
* the list of subscribed entities.
|
||||||
|
*
|
||||||
|
* @see IEEE1722.1-2021 Section 7.4.37 .
|
||||||
|
* @see Milan V1.2 Section 5.4.2.21 .
|
||||||
|
*/
|
||||||
|
int handle_cmd_register_unsol_notif_milan_v12(struct aecp *aecp, int64_t now,
|
||||||
|
const void *m, int len);
|
||||||
|
|
||||||
|
#endif // __AVB_REGISTER_UNSOLICITED_NOTIFICATIONS_H__
|
||||||
153
src/modules/module-avb/aecp-aem-cmds-resps/reply-unsol-helpers.c
Normal file
153
src/modules/module-avb/aecp-aem-cmds-resps/reply-unsol-helpers.c
Normal file
|
|
@ -0,0 +1,153 @@
|
||||||
|
/* AVB support */
|
||||||
|
/* SPDX-FileCopyrightText: Copyright © 2025 Kebag-Logic */
|
||||||
|
/* SPDX-FileCopyrightText: Copyright © 2025 Alex Malki <alexandre.malki@kebag-logic.com> */
|
||||||
|
/* SPDX-License-Identifier: MIT */
|
||||||
|
|
||||||
|
#include "../aecp-aem.h"
|
||||||
|
#include "../aecp-aem-state.h"
|
||||||
|
#include "../internal.h"
|
||||||
|
|
||||||
|
#include "reply-unsol-helpers.h"
|
||||||
|
|
||||||
|
#include <pipewire/log.h>
|
||||||
|
|
||||||
|
#define AECP_UNSOL_BUFFER_SIZE (128U)
|
||||||
|
#define AECP_AEM_MIN_PACKET_LENGTH (64U)
|
||||||
|
|
||||||
|
static int reply_unsol_get_specific_info(struct aecp *aecp, struct descriptor *desc,
|
||||||
|
struct aecp_aem_unsol_notification_state **unsol_state, size_t *count)
|
||||||
|
{
|
||||||
|
enum avb_mode mode = aecp->server->avb_mode;
|
||||||
|
|
||||||
|
switch (mode) {
|
||||||
|
case AVB_MODE_LEGACY:
|
||||||
|
pw_log_error("Not implemented\n");
|
||||||
|
break;
|
||||||
|
case AVB_MODE_MILAN_V12:
|
||||||
|
struct aecp_aem_entity_milan_state *entity_state;
|
||||||
|
|
||||||
|
entity_state = desc->ptr;
|
||||||
|
*unsol_state = entity_state->unsol_notif_state;
|
||||||
|
*count = AECP_AEM_MILAN_MAX_CONTROLLER;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
default:
|
||||||
|
pw_log_error("Invalid avb_mode %d\n", mode);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int reply_unsol_send(struct aecp *aecp, uint64_t controller_id,
|
||||||
|
void *packet, size_t len, bool internal)
|
||||||
|
{
|
||||||
|
size_t ctrler_index;
|
||||||
|
int rc = 0;
|
||||||
|
struct avb_ethernet_header *h;
|
||||||
|
struct avb_packet_aecp_aem *p;
|
||||||
|
struct aecp_aem_unsol_notification_state *unsol_state;
|
||||||
|
struct descriptor *desc;
|
||||||
|
size_t max_ctrler;
|
||||||
|
|
||||||
|
desc = server_find_descriptor(aecp->server, AVB_AEM_DESC_ENTITY, 0);
|
||||||
|
if (desc == NULL) {
|
||||||
|
pw_log_error("Could not find the ENTITY descriptor 0");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = reply_unsol_get_specific_info(aecp, desc, &unsol_state, &max_ctrler);
|
||||||
|
if (rc) {
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
h = (struct avb_ethernet_header*) packet;
|
||||||
|
p = SPA_PTROFF(h, sizeof(*h), void);
|
||||||
|
|
||||||
|
/* Loop through all the unsol entities. */
|
||||||
|
for (ctrler_index = 0; ctrler_index < max_ctrler; ctrler_index++)
|
||||||
|
{
|
||||||
|
if (!unsol_state[ctrler_index].is_registered) {
|
||||||
|
pw_log_debug("Not registered %zu", ctrler_index);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((controller_id == unsol_state[ctrler_index].ctrler_entity_id)
|
||||||
|
&& !internal) {
|
||||||
|
/* Do not send unsolicited if that the one triggering
|
||||||
|
changes this is not a timeout. */
|
||||||
|
pw_log_debug("Do not send twice of %"PRIx64" %"PRIx64,
|
||||||
|
controller_id,
|
||||||
|
unsol_state[ctrler_index].ctrler_entity_id);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
p->aecp.controller_guid =
|
||||||
|
htobe64(unsol_state[ctrler_index].ctrler_entity_id);
|
||||||
|
|
||||||
|
p->aecp.sequence_id = htons(unsol_state[ctrler_index].next_seq_id);
|
||||||
|
|
||||||
|
unsol_state[ctrler_index].next_seq_id++;
|
||||||
|
rc = avb_server_send_packet(aecp->server,
|
||||||
|
unsol_state[ctrler_index].ctrler_mac_addr,
|
||||||
|
AVB_TSN_ETH, packet, len);
|
||||||
|
|
||||||
|
if (rc) {
|
||||||
|
pw_log_error("while sending packet to %"PRIx64,
|
||||||
|
unsol_state[ctrler_index].ctrler_entity_id);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void reply_unsol_notifications_prepare(struct aecp *aecp,
|
||||||
|
uint8_t *buf, void *packet, size_t len)
|
||||||
|
{
|
||||||
|
struct avb_ethernet_header *h;
|
||||||
|
struct avb_packet_aecp_aem *p;
|
||||||
|
size_t ctrl_data_length;
|
||||||
|
|
||||||
|
/* Here the value of 12 is the delta between the target_entity_id and
|
||||||
|
start of the AECP message specific data. */
|
||||||
|
ctrl_data_length = len - (sizeof(*h) + sizeof(*p)) +
|
||||||
|
AVB_PACKET_CONTROL_DATA_OFFSET;
|
||||||
|
|
||||||
|
h = (struct avb_ethernet_header*) packet;
|
||||||
|
p = SPA_PTROFF(h, sizeof(*h), void);
|
||||||
|
|
||||||
|
p->aecp.hdr.subtype = AVB_SUBTYPE_AECP;
|
||||||
|
AVB_PACKET_AECP_SET_MESSAGE_TYPE(&p->aecp, AVB_AECP_MESSAGE_TYPE_AEM_RESPONSE);
|
||||||
|
AVB_PACKET_SET_VERSION(&p->aecp.hdr, 0);
|
||||||
|
AVB_PACKET_AECP_SET_STATUS(&p->aecp, AVB_AECP_AEM_STATUS_SUCCESS);
|
||||||
|
AVB_PACKET_SET_LENGTH(&p->aecp.hdr, ctrl_data_length);
|
||||||
|
p->u = 1;
|
||||||
|
p->aecp.target_guid = htobe64(aecp->server->entity_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Sends unsolicited notifications. Does not sends information unless to
|
||||||
|
* the controller id unless an internal change has happenned (timeout, action
|
||||||
|
* etc)
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
int reply_unsolicited_notifications(struct aecp *aecp,
|
||||||
|
struct aecp_aem_base_info *b_state, void *packet, size_t len,
|
||||||
|
bool internal)
|
||||||
|
{
|
||||||
|
uint8_t buf[AECP_UNSOL_BUFFER_SIZE];
|
||||||
|
|
||||||
|
if (len < AECP_AEM_MIN_PACKET_LENGTH) {
|
||||||
|
memset(buf, 0, AECP_AEM_MIN_PACKET_LENGTH);
|
||||||
|
memcpy(buf, packet, len);
|
||||||
|
len = AECP_AEM_MIN_PACKET_LENGTH;
|
||||||
|
packet = buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Retrieve the entity descriptor */
|
||||||
|
reply_unsol_notifications_prepare(aecp, buf, packet, len);
|
||||||
|
|
||||||
|
return reply_unsol_send(aecp, b_state->controller_entity_id, packet, len,
|
||||||
|
internal);
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,23 @@
|
||||||
|
/* AVB support */
|
||||||
|
/* SPDX-FileCopyrightText: Copyright © 2025 Kebag-Logic */
|
||||||
|
/* SPDX-FileCopyrightText: Copyright © 2025 Alex Malki <alexandre.malki@kebag-logic.com> */
|
||||||
|
/* SPDX-License-Identifier: MIT */
|
||||||
|
|
||||||
|
#ifndef __AVB_REPLY_UNSOL_HELPER_H__
|
||||||
|
#define __AVB_REPLY_UNSOL_HELPER_H__
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <pipewire/log.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Sends unsolicited notifications. Does not sends information unless to
|
||||||
|
* the controller id unless an internal change has happenned (timeout, action
|
||||||
|
* etc)
|
||||||
|
* @see Milan V1.2 Section 5.4.2.21
|
||||||
|
* @see IEEE 1722.1-2021 7.5.2 ( Unsolicited Notifications )
|
||||||
|
*/
|
||||||
|
int reply_unsolicited_notifications(struct aecp *aecp,
|
||||||
|
struct aecp_aem_base_info *b_state, void *packet, size_t len,
|
||||||
|
bool internal);
|
||||||
|
|
||||||
|
#endif // __AVB_REPLY_UNSOL_HELPER_H__
|
||||||
|
|
@ -57,7 +57,7 @@ struct aecp_aem_unsol_notification_state {
|
||||||
/**
|
/**
|
||||||
* The controller is that is locking this system
|
* The controller is that is locking this system
|
||||||
*/
|
*/
|
||||||
uint64_t ctrler_endity_id;
|
uint64_t ctrler_entity_id;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* mac Address of the controller
|
* mac Address of the controller
|
||||||
|
|
@ -115,6 +115,7 @@ struct aecp_aem_lock_state {
|
||||||
*/
|
*/
|
||||||
struct aecp_aem_entity_state {
|
struct aecp_aem_entity_state {
|
||||||
struct avb_aem_desc_entity desc;
|
struct avb_aem_desc_entity desc;
|
||||||
|
struct aecp_aem_lock_state lock_state;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -122,7 +123,6 @@ struct aecp_aem_entity_state {
|
||||||
*/
|
*/
|
||||||
struct aecp_aem_entity_milan_state {
|
struct aecp_aem_entity_milan_state {
|
||||||
struct aecp_aem_entity_state state;
|
struct aecp_aem_entity_state state;
|
||||||
struct aecp_aem_lock_state lock_state;
|
|
||||||
struct aecp_aem_unsol_notification_state unsol_notif_state[AECP_AEM_MILAN_MAX_CONTROLLER];
|
struct aecp_aem_unsol_notification_state unsol_notif_state[AECP_AEM_MILAN_MAX_CONTROLLER];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,8 @@
|
||||||
/* The headers including the command and response of the system */
|
/* The headers including the command and response of the system */
|
||||||
#include "aecp-aem-cmds-resps/cmd-available.h"
|
#include "aecp-aem-cmds-resps/cmd-available.h"
|
||||||
#include "aecp-aem-cmds-resps/cmd-lock-entity.h"
|
#include "aecp-aem-cmds-resps/cmd-lock-entity.h"
|
||||||
|
#include "aecp-aem-cmds-resps/cmd-register-unsolicited-notifications.h"
|
||||||
|
#include "aecp-aem-cmds-resps/cmd-deregister-unsolicited-notifications.h"
|
||||||
|
|
||||||
|
|
||||||
/* ACQUIRE_ENTITY */
|
/* ACQUIRE_ENTITY */
|
||||||
|
|
@ -292,6 +294,15 @@ static const struct cmd_info cmd_info_milan_v12[] = {
|
||||||
|
|
||||||
AECP_AEM_HANDLE_CMD(AVB_AECP_AEM_CMD_READ_DESCRIPTOR, true,
|
AECP_AEM_HANDLE_CMD(AVB_AECP_AEM_CMD_READ_DESCRIPTOR, true,
|
||||||
handle_read_descriptor_common),
|
handle_read_descriptor_common),
|
||||||
|
|
||||||
|
AECP_AEM_HANDLE_CMD(AVB_AECP_AEM_CMD_REGISTER_UNSOLICITED_NOTIFICATION,
|
||||||
|
false, handle_cmd_register_unsol_notif_milan_v12),
|
||||||
|
|
||||||
|
AECP_AEM_HANDLE_CMD(AVB_AECP_AEM_CMD_DEREGISTER_UNSOLICITED_NOTIFICATION,
|
||||||
|
false, handle_cmd_deregister_unsol_notif_milan_v12),
|
||||||
|
|
||||||
|
AECP_AEM_HANDLE_CMD(AVB_AECP_AEM_CMD_GET_AVB_INFO, true,
|
||||||
|
handle_get_avb_info_common),
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct {
|
static const struct {
|
||||||
|
|
|
||||||
|
|
@ -229,9 +229,11 @@ struct avb_packet_aecp_aem {
|
||||||
uint8_t payload[0];
|
uint8_t payload[0];
|
||||||
} __attribute__ ((__packed__));
|
} __attribute__ ((__packed__));
|
||||||
|
|
||||||
#define AVB_PACKET_AEM_SET_COMMAND_TYPE(p,v) ((p)->cmd1 = ((v) >> 8),(p)->cmd2 = (v))
|
#define AVB_PACKET_CONTROL_DATA_OFFSET (12U)
|
||||||
|
|
||||||
#define AVB_PACKET_AEM_GET_COMMAND_TYPE(p) ((p)->cmd1 << 8 | (p)->cmd2)
|
#define AVB_PACKET_AEM_SET_COMMAND_TYPE(p,v) ((p)->cmd1 = ((v) >> 8),(p)->cmd2 = (v))
|
||||||
|
|
||||||
|
#define AVB_PACKET_AEM_GET_COMMAND_TYPE(p) ((p)->cmd1 << 8 | (p)->cmd2)
|
||||||
|
|
||||||
int avb_aecp_aem_handle_command(struct aecp *aecp, const void *m, int len);
|
int avb_aecp_aem_handle_command(struct aecp *aecp, const void *m, int len);
|
||||||
int avb_aecp_aem_handle_response(struct aecp *aecp, const void *m, int len);
|
int avb_aecp_aem_handle_response(struct aecp *aecp, const void *m, int len);
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue