COSA
An Object-Oriented Platform for Arduino Programming
RFM69.cpp
Go to the documentation of this file.
1 
21 #include "RFM69.hh"
22 
23 #if !defined(BOARD_ATTINYX5)
24 
25 #include "Cosa/Power.hh"
26 #include "Cosa/RTT.hh"
27 
28 // Device configuration support macros
29 #define REG_VALUE8(reg,value) (reg), (uint8_t) (value)
30 #define REG_VALUE16(reg,value) \
31  REG_VALUE8(reg,value >> 8), \
32  REG_VALUE8(reg+1,value)
33 #define REG_VALUE24(reg,value) \
34  REG_VALUE8(reg,value >> 16), \
35  REG_VALUE8(reg+1,value >> 8), \
36  REG_VALUE8(reg+2,value)
37 
38 // Crystal Oscillator Frequency/Step; 32 MHz/61.0 Hz
39 #define FXOSC 32000000L
40 #define FSTEP (FXOSC >> 19)
41 
42 // RF Carrier Frequency, 24-bit (RF / FSTEP)
43 #define FRF_315_MHZ 0x4EC000L
44 #define FRF_434_MHZ 0x6C8000L
45 #define FRF_868_MHZ 0xD90000L
46 #define FRF_915_MHZ 0xE4C000L
47 #define FRF_SETTING FRF_868_MHZ
48 
49 // Bitrates, 16-bit (FSOSC / BITRATE)
50 #define BITRATE_1200_BPS 0x682B
51 #define BITRATE_2400_BPS 0x3415
52 #define BITRATE_4800_BPS 0x1A0B
53 #define BITRATE_9600_BPS 0x0D05
54 #define BITRATE_19200_BPS 0x0683
55 #define BITRATE_38400_BPS 0x0341
56 #define BITRATE_57600_BPS 0x022C
57 #define BITRATE_76800_BPS 0x01A1
58 #define BITRATE_115200_BPS 0x0116
59 #define BITRATE_153600_BPS 0x00D0
60 #define BITRATE_SETTING BITRATE_4800_BPS
61 
62 // Frequency deviation, 16-bit (FDEV / FSTEP); 5 KHz
63 #define FDEV_SETTING 0x0052
64 
72 const uint8_t RFM69::config[] __PROGMEM = {
73  // Common Configuration Registers
74  REG_VALUE8(OP_MODE, SEQUENCER_ON | LISTEN_OFF | STANDBY_MODE),
75  REG_VALUE8(DATA_MODUL, PACKET_MODE | FSK_MODULATION | FSK_NO_SHAPING),
76  REG_VALUE16(BITRATE, BITRATE_SETTING),
79  REG_VALUE8(AFC_CTRL, AFC_LOW_BETA_OFF),
80  // Transmitter Registers
81  REG_VALUE8(PA_LEVEL, PA0_ON | PA1_OFF | PA2_OFF | FULL_OUTPUT_POWER),
82  REG_VALUE8(PA_RAMP, 9),
83  REG_VALUE8(OCP, OCP_ON | 10),
84  REG_VALUE8(LNA, ZIN_200_OHM | (1 << CURRENT_GAIN)),
85  // Receiver Registers
86  REG_VALUE8(RX_BW, (2 << DCC_FREQ) | BW_MANT_24 | (5 << BW_EXP)),
87  // IRQ and Pin Mapping Registers
88  REG_VALUE8(DIO_MAPPING1, 0x0),
89  REG_VALUE8(DIO_MAPPING2, 0x7),
90  REG_VALUE8(RSSI_THRESH, 220),
91  // Packet Engine Registers
92  REG_VALUE16(PREAMBLE, 3),
93  REG_VALUE8(SYNC_CONFIG, SYNC_ON | FIFO_FILL_AUTO
94  | ((sizeof(int16_t) - 1) << SYNC_SIZE)),
95  REG_VALUE8(PACKET_CONFIG1, VARIABLE_LENGTH | WHITENING
96  | CRC_ON | CRC_AUTO_CLEAR_ON
97  | ADDR_FILTER_ON),
98  REG_VALUE8(PAYLOAD_LENGTH, 66),
99  REG_VALUE8(BROADCAST_ADDR, BROADCAST),
100  REG_VALUE8(FIFO_THRESHOLD, TX_START_NOT_EMPTY | 15),
101  REG_VALUE8(PACKET_CONFIG2, (1 << INTER_PACKET_RX_DELAY)
102  | AUTO_RX_RESTART_ON
103  | AES_OFF),
104  REG_VALUE8(TEST_PA1, TEST_PA1_NORMAL_MODE),
105  REG_VALUE8(TEST_PA2, TEST_PA2_NORMAL_MODE),
106  REG_VALUE8(TEST_DAGC, TEST_DAGC_IMPROVED_MARGIN_AFC_LOG_BETA_OFF),
107  0
108 };
109 
110 RFM69::RFM69(uint16_t net, uint8_t dev,
111  Board::DigitalPin csn,
113  SPI::Driver(csn, SPI::ACTIVE_LOW, SPI::DIV4_CLOCK, 0, SPI::MSB_ORDER, &m_irq),
114  Wireless::Driver(net, dev),
115  m_irq(irq, ExternalInterrupt::ON_RISING_MODE, this)
116 {
117 }
118 
119 void
120 RFM69::IRQPin::on_interrupt(uint16_t arg)
121 {
122  UNUSED(arg);
123 
124  // The interrupt handler is called on rising signal (RFM69:DIO0).
125  // This occures on TX: PACKET_SENT and RX: CRC_OK
126  if (UNLIKELY(m_rf == 0)) return;
127  if (m_rf->m_opmode == RECEIVER_MODE)
128  m_rf->m_avail = true;
129  else if (m_rf->m_opmode == TRANSMITTER_MODE)
130  m_rf->m_done = true;
131 }
132 
133 void
134 RFM69::set(Mode mode)
135 {
136  write(OP_MODE, (read(OP_MODE) & ~MODE_MASK) | mode);
137  while ((read(IRQ_FLAGS1) & MODE_READY) == 0x00) DELAY(10);
138  m_opmode = mode;
139 }
140 
141 bool
142 RFM69::begin(const void* config)
143 {
144  // Wait for the transceiver to become ready
145  do write(SYNC_VALUE1, 0xaa); while (read(SYNC_VALUE1) != 0xaa);
146  do write(SYNC_VALUE1, 0x55); while (read(SYNC_VALUE1) != 0x55);
147 
148  // Upload the configuration. Check for default configuration
149  const uint8_t* cp = RFM69::config;
150  Reg reg;
151  if (config != NULL) cp = (const uint8_t*) config;
152  while ((reg = (Reg) pgm_read_byte(cp++)) != 0)
153  write(reg, pgm_read_byte(cp++));
154 
155  // Adjust configuration with instance specific state
156  uint16_t sync = hton(m_addr.network);
157  write(SYNC_VALUE1, &sync, sizeof(sync));
158  write(NODE_ADDR, m_addr.device);
159 
160  // Set standby mode and calibrate RC oscillator
161  recalibrate();
162 
163  // Initiate device driver state and enable interrupt handler
164  m_avail = false;
165  m_done = true;
166  spi.attach(this);
167  m_irq.enable();
168  return (true);
169 }
170 
171 bool
173 {
174  m_irq.disable();
175  powerdown();
176  return (true);
177 }
178 
179 int
180 RFM69::send(uint8_t dest, uint8_t port, const iovec_t* vec)
181 {
182  // Sanity check the payload size
183  if (UNLIKELY(vec == NULL)) return (EINVAL);
184  size_t len = iovec_size(vec);
185  if (UNLIKELY(len > PAYLOAD_MAX)) return (EMSGSIZE);
186 
187  // Check if a packet available. Should receive before send
188  if (UNLIKELY(m_avail)) return (ENXIO);
189 
190  // Write frame header(length, dest, src, port) and payload
191  spi.acquire(this);
192  spi.begin();
193  spi.transfer(REG_WRITE | FIFO);
194  spi.transfer(len + HEADER_MAX);
195  spi.transfer(dest);
197  spi.transfer(port);
198  spi.write(vec);
199  spi.end();
200  spi.release();
201 
202  // Trigger the transmit and await completion. Set standby mode
203  m_done = false;
204  set(TRANSMITTER_MODE);
205  while (!m_done) yield();
206  set(STANDBY_MODE);
207 
208  // Return total length of payload
209  return (len);
210 }
211 
212 int
213 RFM69::send(uint8_t dest, uint8_t port, const void* buf, size_t len)
214 {
215  iovec_t vec[2];
216  iovec_t* vp = vec;
217  iovec_arg(vp, buf, len);
218  iovec_end(vp);
219  return (send(dest, port, vec));
220 }
221 
222 int
223 RFM69::recv(uint8_t& src, uint8_t& port, void* buf, size_t len, uint32_t ms)
224 {
225  // Set receive mode and wait for a message
226  set(RECEIVER_MODE);
227  uint32_t start = RTT::millis();
228  while (!m_avail && ((ms == 0) || (RTT::since(start) < ms))) yield();
229 
230  // Set standby and check if a message was received
231  set(STANDBY_MODE);
232  if (!m_avail) return (ETIME);
233  m_avail = false;
234 
235  // Read the payload size and check size
236  spi.acquire(this);
237  spi.begin();
238  spi.transfer(REG_READ | FIFO);
239  uint8_t size = spi.transfer(0);
240  size = size - HEADER_MAX;
241  if (size > len) {
242  spi.end();
243  spi.release();
244  return (EMSGSIZE);
245  }
246  // Read the frame (dest, src, payload)
247  m_dest = spi.transfer(0);
248  src = spi.transfer(0);
249  port = spi.transfer(0);
250  spi.read(buf, size);
251  spi.end();
252  spi.release();
253 
254  return (size);
255 }
256 
257 void
259 {
260  set(SLEEP_MODE);
261 }
262 
263 void
265 {
266  // Fix: Use LISTEN_ON instead
267  set(STANDBY_MODE);
268 }
269 
270 void
272 {
273  // Fix: High power level setting for RFM69HW
274  if (dBm < -18) dBm = -18; else if (dBm > 13) dBm = 13;
275  uint8_t level = (dBm + 18) & OUTPUT_POWER_MASK;
276  uint8_t pa_level = read(PA_LEVEL) & ~OUTPUT_POWER_MASK;
277  write(PA_LEVEL, pa_level | level);
278 }
279 
280 int
282 {
283  return ((-read(RSSI_VALUE)) >> 1);
284 }
285 
286 int
288 {
289  set(STANDBY_MODE);
290  write(TEMP1, TEMP_MEAS_START);
291  while (read(TEMP1) & TEMP_MEAS_RUNNING) DELAY(100);
292  return (-read(TEMP2));
293 }
294 
296 {
297  set(STANDBY_MODE);
298  write(OSC1, RC_CAL_START);
299  while ((read(OSC1) & RC_CAL_DONE) == 0x00) DELAY(100);
300 }
301 
302 #endif
addr_t m_addr
Current network and device address.
Definition: Wireless.hh:299
#define EINVAL
Definition: Errno.h:49
uint8_t transfer(uint8_t data)
Definition: SOFT_SPI.cpp:87
#define BITRATE_SETTING
Definition: RFM69.cpp:60
#define REG_VALUE16(reg, value)
Definition: RFM69.cpp:30
virtual bool end()
Definition: RFM69.cpp:172
Definition: SPI.hh:57
void acquire(Driver *dev)
Definition: SOFT_SPI.cpp:43
#define NULL
Definition: Types.h:101
#define EMSGSIZE
Definition: Errno.h:117
int temperature()
Definition: RFM69.cpp:287
volatile bool m_avail
Message available. May be set by ISR.
Definition: Wireless.hh:300
static const size_t PAYLOAD_MAX
Definition: RFM69.hh:67
void read(void *buf, size_t count)
Definition: SPI.hh:308
uint8_t m_dest
Latest message destination device address.
Definition: Wireless.hh:301
Definition: Types.h:391
#define FDEV_SETTING
Definition: RFM69.cpp:63
#define ETIME
Definition: Errno.h:89
#define DELAY(us)
Definition: Types.h:280
uint8_t device
Device address (LSB).
Definition: Wireless.hh:41
static uint32_t since(uint32_t start)
Definition: RTT.hh:107
#define ENXIO
Definition: Errno.h:33
int16_t network
Network address.
Definition: Wireless.hh:42
const uint8_t RFM69::config[] __PROGMEM
Definition: RFM69.cpp:72
static uint32_t millis()
Definition: RTT.cpp:121
void write(const void *buf, size_t count)
Definition: SPI.hh:321
ExternalInterruptPin
Definition: ATmega1284P.hh:190
void(* yield)()
virtual void output_power_level(int8_t dBm)
Definition: RFM69.cpp:271
virtual int send(uint8_t dest, uint8_t port, const iovec_t *vec)
Definition: RFM69.cpp:180
RFM69(uint16_t net, uint8_t dev, Board::DigitalPin csn=Board::D10, Board::ExternalInterruptPin irq=Board::EXT0)
Definition: RFM69.cpp:110
void begin()
Definition: SPI.hh:216
void end()
Definition: SPI.hh:226
#define UNUSED(x)
Definition: ATmega328P.hh:31
virtual bool begin(const void *config=NULL)
Definition: RFM69.cpp:142
virtual void wakeup_on_radio()
Definition: RFM69.cpp:264
bool attach(Driver *dev)
Definition: SOFT_SPI.cpp:78
#define REG_VALUE24(reg, value)
Definition: RFM69.cpp:33
static const size_t HEADER_MAX
Definition: RFM69.hh:61
void recalibrate()
Definition: RFM69.cpp:295
virtual int input_power_level()
Definition: RFM69.cpp:281
SPI spi
Definition: SPI.cpp:29
#define hton
Definition: Types.h:584
virtual int recv(uint8_t &src, uint8_t &port, void *buf, size_t len, uint32_t ms=0L)
Definition: RFM69.cpp:223
void release()
Definition: SOFT_SPI.cpp:64
virtual void powerdown()
Definition: RFM69.cpp:258
#define UNLIKELY(x)
Definition: Types.h:153
#define FRF_SETTING
Definition: RFM69.cpp:47
void iovec_arg(iovec_t *&vp, const void *buf, size_t size)
Definition: Types.h:430
void iovec_end(iovec_t *&vp)
Definition: Types.h:449
size_t iovec_size(const iovec_t *vec)
Definition: Types.h:407
#define REG_VALUE8(reg, value)
Definition: RFM69.cpp:29