at86rf2xx.c
6.95 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
/*
* Copyright (C) 2013 Alaeddine Weslati <alaeddine.weslati@inria.fr>
* Copyright (C) 2015 Freie Universität Berlin
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup drivers_at86rf2xx
* @{
*
* @file
* @brief Implementation of public functions for AT86RF2xx drivers
*
* @author Alaeddine Weslati <alaeddine.weslati@inria.fr>
* @author Thomas Eichinger <thomas.eichinger@fu-berlin.de>
* @author Hauke Petersen <hauke.petersen@fu-berlin.de>
* @author Kaspar Schleiser <kaspar@schleiser.de>
* @author Oliver Hahm <oliver.hahm@inria.fr>
*
* @}
*/
#include "periph/cpuid.h"
#include "byteorder.h"
#include "net/ieee802154.h"
#include "net/gnrc.h"
#include "at86rf2xx_registers.h"
#include "at86rf2xx_internal.h"
#include "at86rf2xx_netdev.h"
#define ENABLE_DEBUG (0)
#include "debug.h"
void at86rf2xx_setup(at86rf2xx_t *dev, const at86rf2xx_params_t *params)
{
netdev2_t *netdev = (netdev2_t *)dev;
netdev->driver = &at86rf2xx_driver;
/* initialize device descriptor */
memcpy(&dev->params, params, sizeof(at86rf2xx_params_t));
dev->idle_state = AT86RF2XX_STATE_TRX_OFF;
dev->state = AT86RF2XX_STATE_SLEEP;
dev->pending_tx = 0;
/* initialise SPI */
spi_init_master(dev->params.spi, SPI_CONF_FIRST_RISING, params->spi_speed);
}
void at86rf2xx_reset(at86rf2xx_t *dev)
{
#if CPUID_LEN
/* make sure that the buffer is always big enough to store a 64bit value */
# if CPUID_LEN < IEEE802154_LONG_ADDRESS_LEN
uint8_t cpuid[IEEE802154_LONG_ADDRESS_LEN];
# else
uint8_t cpuid[CPUID_LEN];
#endif
eui64_t addr_long;
#endif
at86rf2xx_hardware_reset(dev);
/* Reset state machine to ensure a known state */
at86rf2xx_reset_state_machine(dev);
/* reset options and sequence number */
dev->netdev.seq = 0;
dev->netdev.flags = 0;
/* set short and long address */
#if CPUID_LEN
/* in case CPUID_LEN < 8, fill missing bytes with zeros */
memset(cpuid, 0, CPUID_LEN);
cpuid_get(cpuid);
#if CPUID_LEN > IEEE802154_LONG_ADDRESS_LEN
for (int i = IEEE802154_LONG_ADDRESS_LEN; i < CPUID_LEN; i++) {
cpuid[i & 0x07] ^= cpuid[i];
}
#endif
/* make sure we mark the address as non-multicast and not globally unique */
cpuid[0] &= ~(0x01);
cpuid[0] |= 0x02;
/* copy and set long address */
memcpy(&addr_long, cpuid, IEEE802154_LONG_ADDRESS_LEN);
at86rf2xx_set_addr_long(dev, NTOHLL(addr_long.uint64.u64));
at86rf2xx_set_addr_short(dev, NTOHS(addr_long.uint16[0].u16));
#else
at86rf2xx_set_addr_long(dev, AT86RF2XX_DEFAULT_ADDR_LONG);
at86rf2xx_set_addr_short(dev, AT86RF2XX_DEFAULT_ADDR_SHORT);
#endif
/* set default PAN id */
at86rf2xx_set_pan(dev, AT86RF2XX_DEFAULT_PANID);
/* set default channel */
at86rf2xx_set_chan(dev, AT86RF2XX_DEFAULT_CHANNEL);
/* set default TX power */
at86rf2xx_set_txpower(dev, AT86RF2XX_DEFAULT_TXPOWER);
/* set default options */
at86rf2xx_set_option(dev, AT86RF2XX_OPT_AUTOACK, true);
at86rf2xx_set_option(dev, AT86RF2XX_OPT_CSMA, true);
at86rf2xx_set_option(dev, AT86RF2XX_OPT_TELL_RX_START, false);
at86rf2xx_set_option(dev, AT86RF2XX_OPT_TELL_RX_END, true);
#ifdef MODULE_NETSTATS_L2
at86rf2xx_set_option(dev, AT86RF2XX_OPT_TELL_TX_END, true);
#endif
/* set default protocol */
#ifdef MODULE_GNRC_SIXLOWPAN
dev->netdev.proto = GNRC_NETTYPE_SIXLOWPAN;
#elif MODULE_GNRC
dev->netdev.proto = GNRC_NETTYPE_UNDEF;
#endif
/* enable safe mode (protect RX FIFO until reading data starts) */
at86rf2xx_reg_write(dev, AT86RF2XX_REG__TRX_CTRL_2,
AT86RF2XX_TRX_CTRL_2_MASK__RX_SAFE_MODE);
#ifdef MODULE_AT86RF212B
at86rf2xx_set_page(dev, 0);
#endif
/* don't populate masked interrupt flags to IRQ_STATUS register */
uint8_t tmp = at86rf2xx_reg_read(dev, AT86RF2XX_REG__TRX_CTRL_1);
tmp &= ~(AT86RF2XX_TRX_CTRL_1_MASK__IRQ_MASK_MODE);
at86rf2xx_reg_write(dev, AT86RF2XX_REG__TRX_CTRL_1, tmp);
/* disable clock output to save power */
tmp = at86rf2xx_reg_read(dev, AT86RF2XX_REG__TRX_CTRL_0);
tmp &= ~(AT86RF2XX_TRX_CTRL_0_MASK__CLKM_CTRL);
tmp &= ~(AT86RF2XX_TRX_CTRL_0_MASK__CLKM_SHA_SEL);
tmp |= (AT86RF2XX_TRX_CTRL_0_CLKM_CTRL__OFF);
at86rf2xx_reg_write(dev, AT86RF2XX_REG__TRX_CTRL_0, tmp);
/* enable interrupts */
at86rf2xx_reg_write(dev, AT86RF2XX_REG__IRQ_MASK,
AT86RF2XX_IRQ_STATUS_MASK__TRX_END);
/* clear interrupt flags */
at86rf2xx_reg_read(dev, AT86RF2XX_REG__IRQ_STATUS);
/* go into RX state */
at86rf2xx_set_state(dev, AT86RF2XX_STATE_RX_AACK_ON);
DEBUG("at86rf2xx_reset(): reset complete.\n");
}
bool at86rf2xx_cca(at86rf2xx_t *dev)
{
uint8_t tmp;
uint8_t status;
at86rf2xx_assert_awake(dev);
/* trigger CCA measurment */
tmp = at86rf2xx_reg_read(dev, AT86RF2XX_REG__PHY_CC_CCA);
tmp &= AT86RF2XX_PHY_CC_CCA_MASK__CCA_REQUEST;
at86rf2xx_reg_write(dev, AT86RF2XX_REG__PHY_CC_CCA, tmp);
/* wait for result to be ready */
do {
status = at86rf2xx_reg_read(dev, AT86RF2XX_REG__TRX_STATUS);
} while (!(status & AT86RF2XX_TRX_STATUS_MASK__CCA_DONE));
/* return according to measurement */
if (status & AT86RF2XX_TRX_STATUS_MASK__CCA_STATUS) {
return true;
}
else {
return false;
}
}
size_t at86rf2xx_send(at86rf2xx_t *dev, uint8_t *data, size_t len)
{
/* check data length */
if (len > AT86RF2XX_MAX_PKT_LENGTH) {
DEBUG("[at86rf2xx] Error: data to send exceeds max packet size\n");
return 0;
}
at86rf2xx_tx_prepare(dev);
at86rf2xx_tx_load(dev, data, len, 0);
at86rf2xx_tx_exec(dev);
return len;
}
void at86rf2xx_tx_prepare(at86rf2xx_t *dev)
{
uint8_t state;
dev->pending_tx++;
/* make sure ongoing transmissions are finished */
do {
state = at86rf2xx_get_status(dev);
} while (state == AT86RF2XX_STATE_BUSY_RX_AACK ||
state == AT86RF2XX_STATE_BUSY_TX_ARET);
if (state != AT86RF2XX_STATE_TX_ARET_ON) {
dev->idle_state = state;
}
at86rf2xx_set_state(dev, AT86RF2XX_STATE_TX_ARET_ON);
dev->tx_frame_len = IEEE802154_FCS_LEN;
}
size_t at86rf2xx_tx_load(at86rf2xx_t *dev, uint8_t *data,
size_t len, size_t offset)
{
dev->tx_frame_len += (uint8_t)len;
at86rf2xx_sram_write(dev, offset + 1, data, len);
return offset + len;
}
void at86rf2xx_tx_exec(at86rf2xx_t *dev)
{
netdev2_t *netdev = (netdev2_t *)dev;
/* write frame length field in FIFO */
at86rf2xx_sram_write(dev, 0, &(dev->tx_frame_len), 1);
/* trigger sending of pre-loaded frame */
at86rf2xx_reg_write(dev, AT86RF2XX_REG__TRX_STATE,
AT86RF2XX_TRX_STATE__TX_START);
if (netdev->event_callback &&
(dev->netdev.flags & AT86RF2XX_OPT_TELL_TX_START)) {
netdev->event_callback(netdev, NETDEV2_EVENT_TX_STARTED);
}
}