Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Fetching contributors…

Cannot retrieve contributors at this time

179 lines (154 sloc) 4.972 kB
// Streaming I/O layer on top of RF12 driver
// 2009-05-07 <jc@wippler.nl> http://opensource.org/licenses/mit-license.php
#include <JeeLib.h>
#include <RF12sio.h>
#if ARDUINO>=100
#include <Arduino.h> // Arduino 1.0
#else
#include <WProgram.h> // Arduino 0022
#endif
#define DEBUG 0
void RF12::initBuf(uint8_t base) {
txbase = base;
txfill = base + 8; // at most 15 fields
txfields = 0;
txbuf[txbase] = 0;
}
void RF12::addToBuf(uint8_t type, const void *ptr, uint8_t len) {
if (txfields < 15) {
uint8_t* p = txbuf + txbase + (++txfields >> 1);
if (txfields & 1)
*p |= type << 4;
else
*p = type;
memcpy(txbuf + txfill, ptr, len);
txfill += len;
}
}
RF12& RF12::put(const void* ptr, char len) {
char type = len;
if (len < 0)
if (len == F_STR)
len = strlen((const char*) ptr) + 1;
else
len = 1 << ~len;
else if (len > 7) {
put(&len, F_1);
type = F_EXT;
}
addToBuf(type & 0x0F, ptr, len);
return *this;
}
uint8_t RF12::nextSize() {
uint8_t type = rf12_buf[2 + (rxfield>>1)];
if (rxfield & 1)
type >>= 4;
else
type &= 0x0F;
switch (type) {
case F_1 & 0x0F: return 1;
case F_2 & 0x0F: return 2;
case F_4 & 0x0F: return 4;
case F_8 & 0x0F: return 8;
case F_STR & 0x0F: return strlen((char*) rf12_buf + rxpos) + 1;
case F_EXT & 0x0F: return rf12_buf[rxpos];
}
return type;
}
RF12& RF12::get(void* ptr, char len) {
uint8_t size = nextSize();
if (len < 0)
if (len > F_STR) {
len = 1 << ~len;
if (len > size) {
// this sign-extend logic only works on little-endian machines
memset(ptr, rf12_buf[rxpos+size-1] >> 7, len);
len = size;
}
} else
len = size;
else if (size > 7)
++rxpos;
memcpy(ptr, (char*) rf12_buf + rxpos, len);
rxpos += size;
++rxfield;
return *this;
}
void RF12::send(uint8_t v) {
// rearrange buf so packet contents is:
// - field nibbles
// - command byte
// - argument data
// the first nibble is adjusted to contain the field count
uint8_t args = txbase + 8; // at most 15 fields
txbuf[txbase] |= txfields;
txbase += (txfields >> 1) + 1;
txbuf[txbase++] = v;
memcpy(txbuf + txbase, txbuf + args, txfill - args);
initBuf(txbase + (txfill - args));
if (sendTimer.idle())
sendTimer.set(3); // start sending within 3 msecs
}
uint8_t RF12::poll() {
// TODO - check for more packets still pending in rf12_buf
if (ackHead && rf12_canSend()) {
// Serial.print(" -> ack ");
// Serial.println(ackData, DEC);
rf12_sendStart(ackHead, &ackData, 1);
ackHead = 0;
return 0;
}
if (rf12_recvDone() && rf12_crc == 0) {
uint8_t len = rf12_len;
if (DEBUG) {
Serial.print("OK");
for (uint8_t i = 0; i < len + 2 && i < 25; ++i) {
if (i <= 2)
Serial.print(" # "[i]);
Serial.print(rf12_buf[i] >> 4, HEX);
Serial.print(rf12_buf[i] & 0x0F, HEX);
}
Serial.println();
}
if ((rf12_hdr & RF12_HDR_CTL) && len == 1) {
// last send acked, move any remaining in-progress tx data to head
uint8_t num = rf12_buf[2];
txfill -= num;
memcpy(txbuf, txbuf + num, txfill);
txbase -= num;
// FIXME what if txbase > 0 at this point?
ackTimer.set(0);
return 0;
}
if ((rf12_hdr & ~RF12_HDR_MASK) == RF12_HDR_ACK) {
// save details to send an ack on next poll
ackHead = RF12_HDR_CTL | RF12_HDR_DST | (rf12_hdr & RF12_HDR_MASK);
ackData = len;
}
rxfield = 0;
uint8_t nf = rf12_buf[2] & 0x0F;
rf12_buf[2] |= 0x0F; // command code is returned as first 1-byte value
rxpos = (nf >> 1) + 3;
return nf + 1;
}
if (ackTimer.poll() && sendTimer.idle())
sendTimer.set(500); // got no ack, schedule resend in 500 ms
if (sendTimer.poll() && txbase > 0)
txPending = 1;
if (txPending && rf12_canSend()) {
if (DEBUG) {
Serial.print(" -> #");
Serial.print(txbase, HEX);
Serial.print(' ');
for (uint8_t i = 0; i < txbase; ++i) {
Serial.print(txbuf[i] >> 4, HEX);
Serial.print(txbuf[i] & 0x0F, HEX);
}
Serial.println();
}
txPending = 0;
rf12_sendStart(RF12_HDR_ACK, txbuf, txbase); // send data, request ack
ackTimer.set(50); // send again if no ack within 50 ms
}
return 0;
}
Jump to Line
Something went wrong with that request. Please try again.