forked from benlaurie/arduino--
-
Notifications
You must be signed in to change notification settings - Fork 0
/
rf12jeelabs.h
144 lines (127 loc) · 4.51 KB
/
rf12jeelabs.h
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
// -*- mode: c++; indent-tabs-mode: nil; -*-
// 2009-02-09 <[email protected]> http://opensource.org/licenses/mit-license.php
// 2011-12-28 Ben Laurie <[email protected]>
// Jeelabs RF12B driver compatible upper layer.
/*
* Packets look like:
*
* SYNC1 SYNC2 HDR LEN ... CRC1 CRC2
*
* SYNC1 is 2d
* SYNC2 is the group, which is d4 by default
* HDR is
* bit 7 CTL
* bit 6 DST
* bit 5 ACK
* bit 4-0 ID
* LEN is the length of the data
* ... is the data
* CRC is a CRC over SYNC2 onwards
*
* Nodes can only send to other nodes in the same group (nominally you
* can send outside the group, but the chip recognises the group code,
* so you can only receive messages with your group number on them).
*
* If DST=1, then ID is the id of the destination, otherwise it is the
* ID of the source.
*
* A packet with ACK=1 and CTL=0 wants an ack.
* An ack depends on DST in the received packet
* DST=1 -> CTL=1 DST=0 ACK=0 ID=sender ID (== destination
* ID of original packet)
* DST=0 -> CTL=1 DST=1 ACK=0 ID=source ID of original packet
*
* It is not clear how the recipient, in the first case, knows the ack
* is theirs?
*
* A packet with CTL=1 is an ack. If DST=1, then ID is the id of the
* node the ack is aimed at.
*
*/
#include "rf12base.h"
#define RF12_HDR_CTL 0x80
#define RF12_HDR_DST 0x40
#define RF12_HDR_ACK 0x20
#define RF12_HDR_MASK 0x1F
template <class RFM_IRQ, class SelectPin> class RF12BJeelabs
: public _RF12Base<RFM_IRQ, SelectPin>
{
static uint8_t _nodeid; // address of this node
static long _seq; // seq number of encrypted packet (or -1)
static uint32_t _seqNum; // encrypted send sequence number
static uint32_t _cryptKey[4]; // encryption key to use
static void (*_crypter)(uint8_t); // does en-/decryption (null
// if disabled)
public:
// call this once with the node ID, frequency band, and optional group
static void init(uint8_t id, uint8_t band, uint8_t group = 0xD4)
{
_nodeid = id;
_RF12Base<RFM_IRQ, SelectPin>::init(band, (_nodeid & NODE_ID) != 0,
group);
}
static byte header() { return _RF12Base<RFM_IRQ, SelectPin>::header(); }
static void setHeader(byte hdr)
{ _RF12Base<RFM_IRQ, SelectPin>::setHeader(hdr); }
static bool goodCRC() { return _RF12Base<RFM_IRQ, SelectPin>::goodCRC(); }
// call this frequently, returns true if a packet has been received
static bool recvDone(void)
{
if (!_RF12Base<RFM_IRQ, SelectPin>::recvDone())
return false;
if (!(header() & RF12_HDR_DST) || (_nodeid & NODE_ID) == 31 ||
(header() & RF12_HDR_MASK) == (_nodeid & NODE_ID))
{
if (goodCRC() && _crypter != 0)
_crypter(0);
else
_seq = -1;
return true; // it's a broadcast packet or it's addressed
// to this node
}
return false;
}
// returns true if the buffer currently contains a packet that
// needs ACKing.
static bool wantsAck()
{
return (header() & RF12_HDR_ACK) && !(header() & RF12_HDR_CTL);
}
// Send an ack reply to the packet in the buffer (wantsAck() must be true)
static void sendAckReply()
{
byte hdr;
if (header() & RF12_HDR_DST)
hdr = RF12_HDR_CTL;
else
hdr = RF12_HDR_CTL | RF12_HDR_DST | (header() & RF12_HDR_MASK);
sendStart(hdr, 0, 0);
}
static bool isAckReply() { return (header() & RF12_HDR_CTL) != 0; }
// call this only when rf12_recvDone() or rf12_canSend() return true
static void sendStart(uint8_t hdr)
{
sendStart(hdr, NULL, 0);
}
static void sendStart(uint8_t hdr, const void* ptr, uint8_t len)
{
setHeader(hdr & RF12_HDR_DST ? hdr :
(hdr & ~RF12_HDR_MASK) + (_nodeid & NODE_ID));
if (_crypter != 0)
_crypter(1);
_RF12Base<RFM_IRQ, SelectPin>::sendStart(ptr, len);
}
};
template <class RFM_IRQ, class SelectPin>
byte RF12BJeelabs<RFM_IRQ, SelectPin>::_nodeid;
template <class RFM_IRQ, class SelectPin>
long RF12BJeelabs<RFM_IRQ, SelectPin>::_seq;
template <class RFM_IRQ, class SelectPin>
void (*RF12BJeelabs<RFM_IRQ, SelectPin>::_crypter)(byte);
// Setup for Jeenodes and Wi/Nanodes.
typedef RF12BJeelabs<Pin::D2, Pin::B2> RF12B;
// FIXME: this should be in rf12base.
SIGNAL(INT0_vect)
{
RF12B::interrupt();
}