2 * fw/mac.c - HardMAC functions
4 * Written 2011, 2013 by Werner Almesberger
5 * Copyright 2011, 2013 Werner Almesberger
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
19 #include "at86rf230.h"
27 bool (*mac_irq)(void) = NULL;
30 static uint8_t rx_buf[RX_BUFS][MAX_PSDU+2]; /* PHDR+payload+LQ */
31 static uint8_t tx_buf[MAX_PSDU];
32 static uint8_t tx_size = 0;
33 static bool txing = 0;
34 static bool queued_tx_ack = 0;
35 static uint8_t next_seq, this_seq, queued_seq;
38 /* ----- Receive buffer management ----------------------------------------- */
41 static uint8_t rx_in = 0, rx_out = 0;
44 static inline void next_buf(uint8_t *index)
46 *index = (*index+1) % RX_BUFS;
50 /* ----- Interrupt handling ------------------------------------------------ */
53 static void rx_done(void *user);
54 static void tx_ack_done(void *user);
57 static void usb_next(void)
61 if (rx_in != rx_out) {
64 usb_send(&eps[1], buf, buf[0]+2, rx_done, NULL);
68 usb_send(&eps[1], &queued_seq, 1, tx_ack_done, NULL);
74 static void tx_ack_done(void *user)
79 static void rx_done(void *user)
85 /* slap at86rf230 - reduce fragmentation issue */
86 change_state(TRX_STATUS_RX_AACK_ON);
91 static void receive_frame(void)
97 spi_io(AT86RF230_BUF_READ);
100 if (!size || (size & 0x80)) {
106 spi_recv_block(buf+1, size+1);
112 if (eps[1].state == EP_IDLE)
117 static bool handle_irq(void)
121 irq = reg_read(REG_IRQ_STATUS);
122 if (!(irq & IRQ_TRX_END))
126 if (eps[1].state == EP_IDLE) {
127 usb_send(&eps[1], &this_seq, 1, tx_ack_done, NULL);
130 queued_seq = this_seq;
137 if (eps[1].state == EP_IDLE || rx_in != rx_out)
144 /* ----- TX/RX ------------------------------------------------------------- */
150 mac_irq = handle_irq;
151 reg_read(REG_IRQ_STATUS);
152 change_state(TRX_CMD_RX_AACK_ON);
155 change_state(TRX_CMD_FORCE_TRX_OFF);
162 static void do_tx(void *user)
164 uint16_t timeout = 0xffff;
169 * If we time out here, the host driver will time out waiting for the
170 * TRX_END acknowledgement.
175 status = reg_read(REG_TRX_STATUS) & TRX_STATUS_MASK;
177 while (status != TRX_STATUS_RX_ON && status != TRX_STATUS_RX_AACK_ON);
181 * We use TRX_CMD_FORCE_PLL_ON instead of TRX_CMD_PLL_ON because a new
182 * reception may have begun while we were still working on the previous
185 reg_write(REG_TRX_STATE, TRX_CMD_FORCE_PLL_ON);
189 * at86rf230 doesn't support force change, nevetherless this works
192 reg_write(REG_TRX_STATE, TRX_CMD_PLL_ON);
196 * We use TRX_CMD_FORCE_PLL_ON instead of TRX_CMD_PLL_ON because a new
197 * reception may have begun while we were still working on the previous
200 reg_write(REG_TRX_STATE, TRX_CMD_FORCE_PLL_ON);
206 spi_send(AT86RF230_BUF_WRITE);
207 spi_send(tx_size+2); /* CRC */
208 for (i = 0; i != tx_size; i++)
212 change_state(TRX_STATUS_TX_ARET_ON);
220 * Wait until we reach BUSY_TX_ARET, so that we command the transition to
221 * RX_AACK_ON which will be executed upon TX completion.
223 change_state(TRX_CMD_PLL_ON);
224 change_state(TRX_CMD_RX_AACK_ON);
228 bool mac_tx(uint16_t flags, uint8_t seq, uint16_t len)
234 usb_recv(&eps[0], tx_buf, len, do_tx, NULL);
245 next_seq = this_seq = queued_seq = 0;
247 /* enable CRC and PHY_RSSI (with RX_CRC_VALID) in SPI status return */
248 reg_write(REG_TRX_CTRL_1,
249 TX_AUTO_CRC_ON | SPI_CMD_MODE_PHY_RSSI << SPI_CMD_MODE_SHIFT);