Contiki-NG
Loading...
Searching...
No Matches
nrf-ipc-mac.c
Go to the documentation of this file.
1/*
2 * Copyright (c) 2026, RISE Research Institutes of Sweden AB.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the copyright holder nor the names of its
14 * contributors may be used to endorse or promote products derived
15 * from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
20 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
21 * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
26 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
28 * OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30/*---------------------------------------------------------------------------*/
31/**
32 * \file
33 * IPC MAC driver for the nRF5340 network core.
34 *
35 * This MAC driver runs on the network core and forwards received
36 * frames to the application core via the IPC shared memory. It
37 * replaces NULLMAC for the net core, enabling fully interrupt-driven
38 * frame reception: the radio ISR triggers the radio driver process,
39 * which reads the frame and calls this MAC's input function.
40 *
41 * \author
42 * Nicolas Tsiftes <nicolas.tsiftes@ri.se>
43 */
44/*---------------------------------------------------------------------------*/
45#include "contiki.h"
46#include "net/mac/mac.h"
47#include "net/netstack.h"
48#include "net/packetbuf.h"
49#include "nrf-ipc.h"
50
51#include <inttypes.h>
52#include <string.h>
53/*---------------------------------------------------------------------------*/
54#include "sys/log.h"
55#define LOG_MODULE "IPC MAC"
56#define LOG_LEVEL LOG_LEVEL_INFO
57/*---------------------------------------------------------------------------*/
58static volatile struct nrf_ipc_shared_mem *shm = NRF_IPC_SHARED_MEM;
59/*---------------------------------------------------------------------------*/
60static uint32_t rx_drop_count;
61/*---------------------------------------------------------------------------*/
62/**
63 * 802.15.4 ACK frame constants.
64 */
65#define ACK_FRAME_LEN 3
66#define FCF_ACK_REQUEST_BIT 0x20
67#define FRAME802154_ACKFRAME 0x02
68/*---------------------------------------------------------------------------*/
69/**
70 * Send a software ACK for a received frame if the ACK request bit is set.
71 */
72static void
73send_ack_if_needed(const uint8_t *frame, int len)
74{
75 uint8_t ack[ACK_FRAME_LEN];
76 radio_value_t tx_mode;
77
78 if(len < ACK_FRAME_LEN) {
79 return;
80 }
81
82 /*
83 * The net core's nRF radio has no hardware auto-ACK and does not
84 * report RADIO_RX_MODE_AUTOACK via get_value(), so the IPC MAC must
85 * generate the link-layer ACK in software for every unicast frame
86 * that requests one (checked below via the ACK request bit). The
87 * app core's CSMA relies on these ACKs to confirm its transmissions.
88 */
89
90 /* Do not ACK frames that are themselves ACKs. */
91 if((frame[0] & 0x07) == FRAME802154_ACKFRAME) {
92 return;
93 }
94
95 /* Check the ACK request bit (bit 5 of FCF byte 0). */
96 if(!(frame[0] & FCF_ACK_REQUEST_BIT)) {
97 return;
98 }
99
100 /* Build ACK: [Frame Control = ACK type, 0x00, Sequence Number]. */
101 ack[0] = FRAME802154_ACKFRAME;
102 ack[1] = 0;
103 ack[2] = frame[2]; /* DSN is byte 2 of the received frame. */
104
105 /*
106 * 802.15.4 requires ACKs to be sent without CCA. Clear only the
107 * SEND_ON_CCA bit and restore the previous TX mode afterwards, so
108 * any other (current or future) TX mode flags are preserved.
109 */
110 if(NETSTACK_RADIO.get_value(RADIO_PARAM_TX_MODE, &tx_mode) != RADIO_RESULT_OK) {
112 }
113 NETSTACK_RADIO.set_value(RADIO_PARAM_TX_MODE,
114 tx_mode & ~RADIO_TX_MODE_SEND_ON_CCA);
115 NETSTACK_RADIO.send(ack, ACK_FRAME_LEN);
116 NETSTACK_RADIO.set_value(RADIO_PARAM_TX_MODE, tx_mode);
117}
118/*---------------------------------------------------------------------------*/
119static void
120init(void)
121{
122}
123/*---------------------------------------------------------------------------*/
124static void
125send_packet(mac_callback_t sent, void *ptr)
126{
127}
128/*---------------------------------------------------------------------------*/
129/**
130 * Called by the radio driver process when a frame has been received.
131 * The frame is in packetbuf. We send a software ACK, then forward the
132 * raw frame to the application core via shared memory.
133 */
134static void
136{
137 const uint8_t *frame;
138 int len;
139
140 frame = packetbuf_dataptr();
141 len = packetbuf_datalen();
142
143 /* Use heartbeat field as RX frame counter (readable via debugger). */
144 shm->heartbeat++;
145
146 if(len <= 0 || len > NRF_IPC_MAX_FRAME_LEN) {
147 return;
148 }
149
150 /*
151 * Sort incoming frames into ACK vs data paths. ACK frames (3 bytes,
152 * frame type 0x02) go to shm->rx_ack for CSMA's tight ACK detection
153 * loop. All other frames go to shm->rx for delivery via the process
154 * thread. This separation prevents CSMA's RTIMER_BUSYWAIT from
155 * consuming and discarding data frames while checking for ACKs.
156 */
157 if(len == ACK_FRAME_LEN && (frame[0] & 0x07) == FRAME802154_ACKFRAME) {
158 /* ACK frame — goes to the dedicated ACK slot. */
159 if(!shm->rx_ack.pending) {
160 memcpy((void *)shm->rx_ack.data, frame, ACK_FRAME_LEN);
161 __DMB();
162 shm->rx_ack.pending = 1;
163 }
165 return;
166 }
167
168 /* Send a software ACK for non-ACK frames, before forwarding. */
169 send_ack_if_needed(frame, len);
170
171 /* Data frame — goes to the main RX slot. */
172 if(shm->rx.pending) {
173 rx_drop_count++;
174 if((rx_drop_count % 100) == 1) {
175 LOG_WARN("RX drop (app core busy), total drops: %" PRIu32 "\n",
176 rx_drop_count);
177 }
178 return;
179 }
180
181 shm->rx.len = len;
182 memcpy((void *)shm->rx.data, frame, len);
183 shm->rx.rssi = (int8_t)packetbuf_attr(PACKETBUF_ATTR_RSSI);
184 shm->rx.lqi = (uint8_t)packetbuf_attr(PACKETBUF_ATTR_LINK_QUALITY);
185
186 __DMB();
187
188 shm->rx.pending = 1;
189
191}
192/*---------------------------------------------------------------------------*/
193static int
194on(void)
195{
196 return NETSTACK_RADIO.on();
197}
198/*---------------------------------------------------------------------------*/
199static int
200off(void)
201{
202 return NETSTACK_RADIO.off();
203}
204/*---------------------------------------------------------------------------*/
205static int
206max_payload(void)
207{
209}
210/*---------------------------------------------------------------------------*/
211const struct mac_driver ipc_mac_driver = {
212 "ipc-mac",
213 init,
216 on,
217 off,
219};
220/*---------------------------------------------------------------------------*/
#define NRF_IPC_MAX_FRAME_LEN
Maximum 802.15.4 frame size carried over IPC.
Definition nrf-ipc.h:75
void nrf_ipc_signal(void)
Send an IPC signal to the other core.
#define NRF_IPC_SHARED_MEM
Get a pointer to the shared memory structure.
Definition nrf-ipc.h:212
void * packetbuf_dataptr(void)
Get a pointer to the data in the packetbuf.
Definition packetbuf.c:143
uint16_t packetbuf_datalen(void)
Get the length of the data in the packetbuf.
Definition packetbuf.c:155
#define RADIO_TX_MODE_SEND_ON_CCA
Radio TX mode control / retrieval.
Definition radio.h:474
int radio_value_t
Each radio has a set of parameters that designate the current configuration and state of the radio.
Definition radio.h:88
@ RADIO_RESULT_OK
The parameter was set/read successfully.
Definition radio.h:480
@ RADIO_PARAM_TX_MODE
Radio transmission mode determines if the radio has send on CCA (RADIO_TX_MODE_SEND_ON_CCA) enabled o...
Definition radio.h:180
static void send_packet(void)
This function is called by the 6lowpan code to send out a packet.
Header file for the logging system.
MAC driver header file.
Include file for the Contiki low-layer network stack (NETSTACK)
#define ACK_FRAME_LEN
802.15.4 ACK frame constants.
Definition nrf-ipc-mac.c:65
static void packet_input(void)
Called by the radio driver process when a frame has been received.
static void send_ack_if_needed(const uint8_t *frame, int len)
Send a software ACK for a received frame if the ACK request bit is set.
Definition nrf-ipc-mac.c:73
IPC protocol definitions for nRF5340 dual-core communication.
Header file for the Packet buffer (packetbuf) management.
The structure of a MAC protocol driver in Contiki.
Definition mac.h:68
int(* on)(void)
Turn the MAC layer on.
Definition mac.h:81
int(* max_payload)(void)
Read out estimated max payload size based on payload in packetbuf.
Definition mac.h:87
int(* off)(void)
Turn the MAC layer off.
Definition mac.h:84
void(* init)(void)
Initialize the MAC driver.
Definition mac.h:72
Shared memory layout between the application core and the network core.
Definition nrf-ipc.h:154
volatile uint32_t heartbeat
Heartbeat counter (used as IPC MAC RX frame counter).
Definition nrf-ipc.h:190
struct nrf_ipc_shared_mem::@7 rx
Received data frame (net -> app, asynchronous).
struct nrf_ipc_shared_mem::@8 rx_ack
Received ACK frame (net -> app, asynchronous).