The link model needs to define a structure that represents all kinds of messages that can be sent over the link.
This structure should “inherit” from link_message_t, by placing it first in the struct (so that a pointer to a datagram_link_message_t can be cast to a link_message_t pointer).
typedef struct {
link_message_t common; /* should always be first */
/* The actual data in the message - in our case an allocated
byte string owned by this structure. */
bytes_t payload;
} datagram_link_message_t;
New messages are allocated with MM_MALLOC(), and SIMLINK_init_message() is used to fill in the “common” part:
static link_message_t *
new_datagram_message(const uint8 *data, size_t len)
{
datagram_link_message_t *m = MM_MALLOC(1, datagram_link_message_t);
SIMLINK_init_message(&m->common);
uint8 *d = MM_MALLOC(len, uint8);
memcpy(d, data, len);
m->payload = (bytes_t){.data = d, .len = len};
return &m->common;
}
Finally, the message is dispatched using the SIMLINK_send_message() or SIMLINK_send_message_multi() functions.
static void
receive(conf_object_t *NOTNULL ep, bytes_t msg)
{
SIMLINK_send_message(ep, LINK_BROADCAST_ID,
new_datagram_message(msg.data, msg.len));
}
Messages are delivered to the endpoints’ deliver() callback registered by the link.
The callback is responsible for translating the message into something the receiving device will understand.
static void
deliver(conf_object_t *ep, const link_message_t *lm)
{
const datagram_link_message_t *m =
(const datagram_link_message_t *)lm;
conf_object_t *dev = SIMLINK_endpoint_device(ep);
const char *port = SIMLINK_endpoint_port(ep);
const datagram_link_interface_t *dli =
SIM_c_get_port_interface(dev, "datagram_link", port);
if (dli)
dli->receive(dev, m->payload);
else
SIM_LOG_ERROR(ep, 0, "Device does not implement"
" datagram_link interface");
}