mrf24j40.c
5.2 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
/*
* Copyright (C) 2017 Neo Nenaco <neo@nenaco.de>
* Copyright (C) 2017 Koen Zandberg <koen@bergzand.net>
*
* 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_mrf24j40
* @{
*
* @file
* @brief Implementation of public functions for MRF24J40 drivers
*
* @author Koen Zandberg <koen@bergzand.net>
* @author Neo Nenaco <neo@nenaco.de>
*
* @}
*/
#include "luid.h"
#include "byteorder.h"
#include "net/gnrc.h"
#include "mrf24j40_registers.h"
#include "mrf24j40_internal.h"
#include "mrf24j40_netdev.h"
#include "xtimer.h"
#define ENABLE_DEBUG (0)
#include "debug.h"
void mrf24j40_setup(mrf24j40_t *dev, const mrf24j40_params_t *params)
{
netdev_t *netdev = (netdev_t *)dev;
netdev->driver = &mrf24j40_driver;
/* initialize device descriptor */
memcpy(&dev->params, params, sizeof(mrf24j40_params_t));
}
void mrf24j40_reset(mrf24j40_t *dev)
{
eui64_t addr_long;
mrf24j40_init(dev);
/* reset options and sequence number */
dev->netdev.seq = 0;
dev->netdev.flags = 0;
/* get an 8-byte unique ID to use as hardware address */
luid_get(addr_long.uint8, IEEE802154_LONG_ADDRESS_LEN);
addr_long.uint8[0] &= ~(0x01);
addr_long.uint8[0] |= (0x02);
/* set short and long address */
mrf24j40_set_addr_long(dev, ntohll(addr_long.uint64.u64));
mrf24j40_set_addr_short(dev, ntohs(addr_long.uint16[0].u16));
/* set default PAN id */
mrf24j40_set_pan(dev, IEEE802154_DEFAULT_PANID);
mrf24j40_set_chan(dev, IEEE802154_DEFAULT_CHANNEL);
/* configure Immediate Sleep and Wake-Up mode */
mrf24j40_reg_write_short(dev, MRF24J40_REG_WAKECON, MRF24J40_WAKECON_IMMWAKE);
/* set default options */
mrf24j40_set_option(dev, IEEE802154_FCF_PAN_COMP, true);
mrf24j40_set_option(dev, NETDEV_IEEE802154_SRC_MODE_LONG, true);
mrf24j40_set_option(dev, NETDEV_IEEE802154_ACK_REQ, true);
mrf24j40_set_option(dev, MRF24J40_OPT_CSMA, true);
mrf24j40_set_option(dev, MRF24J40_OPT_TELL_RX_START, false);
mrf24j40_set_option(dev, MRF24J40_OPT_TELL_RX_END, true);
#ifdef MODULE_NETSTATS_L2
mrf24j40_set_option(dev, MRF24J40_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
/* go into RX state */
mrf24j40_reset_tasks(dev);
dev->state = 0;
mrf24j40_set_state(dev, MRF24J40_PSEUDO_STATE_IDLE);
DEBUG("mrf24j40_reset(): reset complete.\n");
}
bool mrf24j40_cca(mrf24j40_t *dev)
{
uint8_t tmp_ccaedth;
uint8_t status;
uint8_t tmp_rssi;
mrf24j40_assert_awake(dev);
/* trigger CCA measurment */
/* take a look onto datasheet chapter 3.6.1 */
mrf24j40_reg_write_short(dev, MRF24J40_REG_BBREG6, MRF24J40_BBREG6_RSSIMODE1);
/* wait for result to be ready */
do {
status = mrf24j40_reg_read_short(dev, MRF24J40_REG_BBREG6);
} while (!(status & MRF24J40_BBREG2_RSSIRDY));
mrf24j40_assert_sleep(dev);
/* return according to measurement */
tmp_ccaedth = mrf24j40_reg_read_short(dev, MRF24J40_REG_CCAEDTH); /* Energy detection threshold */
tmp_rssi = mrf24j40_reg_read_long(dev, MRF24J40_REG_RSSI);
if (tmp_rssi < tmp_ccaedth) {
/* channel is clear */
return true; /* idle */
}
else {
/* channel is busy */
return false;
}
}
void mrf24j40_tx_prepare(mrf24j40_t *dev)
{
DEBUG("[mrf24j40] TX_Prepare, Current state: %x\n", dev->state);
do {
mrf24j40_update_tasks(dev);
} while (!(dev->pending & MRF24J40_TASK_TX_DONE));
mrf24j40_assert_awake(dev);
dev->pending &= ~(MRF24J40_TASK_TX_DONE);
dev->tx_frame_len = IEEE802154_FCS_LEN;
}
size_t mrf24j40_tx_load(mrf24j40_t *dev, uint8_t *data, size_t len, size_t offset)
{
DEBUG("[mrf24j40] TX_load, Current state: %x\n", dev->state);
dev->tx_frame_len += (uint8_t)len;
mrf24j40_tx_normal_fifo_write(dev, MRF24J40_TX_NORMAL_FIFO + offset + 2, data, len);
return offset + len;
}
void mrf24j40_tx_exec(mrf24j40_t *dev)
{
netdev_t *netdev = (netdev_t *)dev;
dev->tx_frame_len = dev->tx_frame_len - IEEE802154_FCS_LEN;
/* write frame length field in FIFO */
mrf24j40_tx_normal_fifo_write(dev, MRF24J40_TX_NORMAL_FIFO + 1, &(dev->tx_frame_len), 1);
/* write header length to FIFO address 0x00 */
/* from figure 3-11 datasheet: header length = 2 Bytes Frame Control
* + 1 Byte Seq. No.
* + 4 to 20 Bytes Addressing Fields
*/
mrf24j40_reg_write_long(dev, MRF24J40_TX_NORMAL_FIFO, dev->header_len);
if (dev->netdev.flags & NETDEV_IEEE802154_ACK_REQ) {
mrf24j40_reg_write_short(dev, MRF24J40_REG_TXNCON, MRF24J40_TXNCON_TXNACKREQ | MRF24J40_TXNCON_TXNTRIG);
}
else {
mrf24j40_reg_write_short(dev, MRF24J40_REG_TXNCON, MRF24J40_TXNCON_TXNTRIG);
}
if (netdev->event_callback && (dev->netdev.flags & MRF24J40_OPT_TELL_TX_START)) {
netdev->event_callback(netdev, NETDEV_EVENT_TX_STARTED);
}
}