Skip to content

Commit 44c947e

Browse files
rlubosnashif
authored andcommitted
drivers: ieee802154_kw41z: Create a fake ACK frame for upper layers
Upper layers like OpenThread expect the radio driver to forward ACK frame received by the radio. Simulate this behavior on kw41z by recreating the ACK frame from the available data. Signed-off-by: Robert Lubos <[email protected]>
1 parent 6b2a371 commit 44c947e

File tree

1 file changed

+50
-0
lines changed

1 file changed

+50
-0
lines changed

drivers/ieee802154/ieee802154_kw41z.c

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,8 @@ struct kw41z_context {
155155

156156
u32_t rx_warmup_time;
157157
u32_t tx_warmup_time;
158+
159+
bool frame_pending; /* FP bit state from the most recent ACK frame. */
158160
};
159161

160162
static struct kw41z_context kw41z_context_data;
@@ -569,6 +571,47 @@ static inline void kw41z_rx(struct kw41z_context *kw41z, u8_t len)
569571
}
570572
}
571573

574+
#define ACK_FRAME_LEN 3
575+
#define ACK_FRAME_TYPE (2 << 0)
576+
#define ACK_FRAME_PENDING_BIT (1 << 4)
577+
578+
static void handle_ack(struct kw41z_context *kw41z, u8_t seq_number)
579+
{
580+
struct net_pkt *ack_pkt;
581+
u8_t ack_psdu[ACK_FRAME_LEN];
582+
583+
ack_pkt = net_pkt_alloc_with_buffer(kw41z->iface, ACK_FRAME_LEN,
584+
AF_UNSPEC, 0, K_NO_WAIT);
585+
if (!ack_pkt) {
586+
LOG_ERR("No free packet available.");
587+
return;
588+
}
589+
590+
/* Re-create ACK frame. */
591+
ack_psdu[0] = kw41z_context_data.frame_pending ?
592+
ACK_FRAME_TYPE | ACK_FRAME_PENDING_BIT : ACK_FRAME_TYPE;
593+
ack_psdu[1] = 0;
594+
ack_psdu[2] = seq_number;
595+
596+
if (net_pkt_write(ack_pkt, ack_psdu, sizeof(ack_psdu)) < 0) {
597+
LOG_ERR("Failed to write to a packet.");
598+
goto out;
599+
}
600+
601+
/* Use some fake values for LQI and RSSI. */
602+
(void)net_pkt_set_ieee802154_lqi(ack_pkt, 80);
603+
(void)net_pkt_set_ieee802154_rssi(ack_pkt, -40);
604+
605+
net_pkt_cursor_init(ack_pkt);
606+
607+
if (ieee802154_radio_handle_ack(kw41z->iface, ack_pkt) != NET_OK) {
608+
LOG_INF("ACK packet not handled - releasing.");
609+
}
610+
611+
out:
612+
net_pkt_unref(ack_pkt);
613+
}
614+
572615
static int kw41z_tx(struct device *dev, struct net_pkt *pkt,
573616
struct net_buf *frag)
574617
{
@@ -653,6 +696,10 @@ static int kw41z_tx(struct device *dev, struct net_pkt *pkt,
653696
irq_unlock(key);
654697
k_sem_take(&kw41z->seq_sync, K_FOREVER);
655698

699+
if ((kw41z->seq_retval == 0) && ieee802154_is_ar_flag_set(frag)) {
700+
handle_ack(kw41z, frag->data[2]);
701+
}
702+
656703
LOG_DBG("seq_retval: %d", kw41z->seq_retval);
657704
return kw41z->seq_retval;
658705
}
@@ -795,6 +842,9 @@ static void kw41z_isr(int unused)
795842
case KW41Z_STATE_TXRX:
796843
LOG_DBG("TXRX seq done");
797844
kw41z_tmr3_disable();
845+
/* Store the frame pending bit status. */
846+
kw41z_context_data.frame_pending =
847+
irqsts & ZLL_IRQSTS_RX_FRM_PEND_MASK;
798848
case KW41Z_STATE_TX:
799849
LOG_DBG("TX seq done");
800850
KW_DBG_TRACE(KW41_DBG_TRACE_TX, irqsts,

0 commit comments

Comments
 (0)