Root/atusb/fw/mac.c

Source at commit c6e776e714b6cb8c7a5ea1f2767ee6bab682298e created 3 years 8 months ago.
By Stefan Schmidt, atusb: fw: make the ifdefs in mac handling transceiver specific and not board specific
1/*
2 * fw/mac.c - HardMAC functions
3 *
4 * Written 2011, 2013 by Werner Almesberger
5 * Copyright 2011, 2013 Werner Almesberger
6 *
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.
11 */
12
13#include <stddef.h>
14#include <stdbool.h>
15#include <stdint.h>
16
17#include "usb.h"
18
19#include "at86rf230.h"
20#include "spi.h"
21#include "board.h"
22#include "mac.h"
23
24#define RX_BUFS 3
25
26
27bool (*mac_irq)(void) = NULL;
28
29
30static uint8_t rx_buf[RX_BUFS][MAX_PSDU+2]; /* PHDR+payload+LQ */
31static uint8_t tx_buf[MAX_PSDU];
32static uint8_t tx_size = 0;
33static bool txing = 0;
34static bool queued_tx_ack = 0;
35static uint8_t next_seq, this_seq, queued_seq;
36
37
38/* ----- Receive buffer management ----------------------------------------- */
39
40
41static uint8_t rx_in = 0, rx_out = 0;
42
43
44static inline void next_buf(uint8_t *index)
45{
46    *index = (*index+1) % RX_BUFS;
47}
48
49
50/* ----- Register access --------------------------------------------------- */
51
52
53static uint8_t reg_read(uint8_t reg)
54{
55    uint8_t value;
56
57    spi_begin();
58    spi_send(AT86RF230_REG_READ | reg);
59    value = spi_recv();
60    spi_end();
61
62    return value;
63}
64
65
66static void reg_write(uint8_t reg, uint8_t value)
67{
68    spi_begin();
69    spi_send(AT86RF230_REG_WRITE | reg);
70    spi_send(value);
71    spi_end();
72}
73
74
75/* ----- Interrupt handling ------------------------------------------------ */
76
77
78static void rx_done(void *user);
79static void tx_ack_done(void *user);
80
81
82static void usb_next(void)
83{
84    const uint8_t *buf;
85
86    if (rx_in != rx_out) {
87        buf = rx_buf[rx_out];
88        led(1);
89        usb_send(&eps[1], buf, buf[0]+2, rx_done, NULL);
90    }
91
92    if (queued_tx_ack) {
93        usb_send(&eps[1], &queued_seq, 1, tx_ack_done, NULL);
94        queued_tx_ack = 0;
95    }
96}
97
98
99static void tx_ack_done(void *user)
100{
101    usb_next();
102}
103
104static void change_state(uint8_t new)
105{
106    while ((reg_read(REG_TRX_STATUS) & TRX_STATUS_MASK) ==
107        TRX_STATUS_TRANSITION);
108    reg_write(REG_TRX_STATE, new);
109}
110
111static void rx_done(void *user)
112{
113    led(0);
114    next_buf(&rx_out);
115    usb_next();
116#ifdef AT86RF230
117    /* slap at86rf230 - reduce fragmentation issue */
118    change_state(TRX_STATUS_RX_AACK_ON);
119#endif
120}
121
122
123static void receive_frame(void)
124{
125    uint8_t size;
126    uint8_t *buf;
127
128    spi_begin();
129#ifdef AT86RF231
130    if (!(spi_io(AT86RF230_BUF_READ) & RX_CRC_VALID)) {
131        spi_end();
132        return;
133    }
134#endif
135#ifdef AT86RF230
136    spi_io(AT86RF230_BUF_READ);
137#endif
138
139    size = spi_recv();
140    if (!size || (size & 0x80)) {
141        spi_end();
142        return;
143    }
144
145    buf = rx_buf[rx_in];
146    spi_recv_block(buf+1, size+1);
147    spi_end();
148
149    buf[0] = size;
150    next_buf(&rx_in);
151
152    if (eps[1].state == EP_IDLE)
153        usb_next();
154}
155
156
157static bool handle_irq(void)
158{
159    uint8_t irq;
160
161    irq = reg_read(REG_IRQ_STATUS);
162    if (!(irq & IRQ_TRX_END))
163        return 1;
164
165    if (txing) {
166        if (eps[1].state == EP_IDLE) {
167            usb_send(&eps[1], &this_seq, 1, tx_ack_done, NULL);
168        } else {
169            queued_tx_ack = 1;
170            queued_seq = this_seq;
171        }
172        txing = 0;
173        return 1;
174    }
175
176    /* likely */
177    if (eps[1].state == EP_IDLE || rx_in != rx_out)
178        receive_frame();
179
180    return 1;
181}
182
183
184/* ----- TX/RX ------------------------------------------------------------- */
185
186
187bool mac_rx(int on)
188{
189    if (on) {
190        mac_irq = handle_irq;
191        reg_read(REG_IRQ_STATUS);
192        change_state(TRX_CMD_RX_AACK_ON);
193    } else {
194        mac_irq = NULL;
195        change_state(TRX_CMD_FORCE_TRX_OFF);
196        txing = 0;
197    }
198    return 1;
199}
200
201
202static void do_tx(void *user)
203{
204    uint16_t timeout = 0xffff;
205    uint8_t status;
206    uint8_t i;
207
208    /*
209     * If we time out here, the host driver will time out waiting for the
210     * TRX_END acknowledgement.
211     */
212    do {
213        if (!--timeout)
214            return;
215        status = reg_read(REG_TRX_STATUS) & TRX_STATUS_MASK;
216    }
217    while (status != TRX_STATUS_RX_ON && status != TRX_STATUS_RX_AACK_ON);
218
219#ifdef AT86RF231
220    /*
221     * We use TRX_CMD_FORCE_PLL_ON instead of TRX_CMD_PLL_ON because a new
222     * reception may have begun while we were still working on the previous
223     * one.
224     */
225    reg_write(REG_TRX_STATE, TRX_CMD_FORCE_PLL_ON);
226#endif
227#ifdef AT86RF230
228    /*
229     * at86rf230 doesn't support force change, nevetherless this works
230     * somehow
231     */
232    reg_write(REG_TRX_STATE, TRX_CMD_PLL_ON);
233#endif
234
235    handle_irq();
236
237    spi_begin();
238    spi_send(AT86RF230_BUF_WRITE);
239    spi_send(tx_size+2); /* CRC */
240    for (i = 0; i != tx_size; i++)
241        spi_send(tx_buf[i]);
242    spi_end();
243
244    slp_tr();
245
246    txing = 1;
247    this_seq = next_seq;
248
249    /*
250     * Wait until we reach BUSY_TX, so that we command the transition to
251     * RX_AACK_ON which will be executed upon TX completion.
252     */
253    change_state(TRX_CMD_RX_AACK_ON);
254}
255
256
257bool mac_tx(uint16_t flags, uint8_t seq, uint16_t len)
258{
259    if (len > MAX_PSDU)
260        return 0;
261    tx_size = len;
262    next_seq = seq;
263    usb_recv(&eps[0], tx_buf, len, do_tx, NULL);
264    return 1;
265}
266
267
268void mac_reset(void)
269{
270    mac_irq = NULL;
271    txing = 0;
272    queued_tx_ack = 0;
273    rx_in = rx_out = 0;
274    next_seq = this_seq = queued_seq = 0;
275
276    /* enable CRC and PHY_RSSI (with RX_CRC_VALID) in SPI status return */
277    reg_write(REG_TRX_CTRL_1,
278        TX_AUTO_CRC_ON | SPI_CMD_MODE_PHY_RSSI << SPI_CMD_MODE_SHIFT);
279}
280

Archive Download this file



interactive