REKLAMA

RadioHead-1.41.zip

Arduino Pro Mini - Zdalne sterowanie RF do samochodu.

Porobiłem parę testów- statyczne przed pętlą odczytu sygnału wariują, umieszczone w pętli również. Pomogło usunięcie static. Czy u Ciebie w ogóle działa zatrzymanie przy braku odczytu? else { //jesi nie odczytuje sygnalu to wylacz silnik digitalWrite(pwm, LOW); } U mnie w ogóle to nie działa, ani na statycznych, ani bez. Biblioteka o której pisałem wcześniej. Jeszcze jej nie testowałem. http://randomnerdtutorials.com/rf-433mhz-transmitter-receiver-module-with-arduino/


Pobierz plik - link do postu
  • RadioHead-1.41.zip
    • RH_TCP.cpp
    • RH_ASK.cpp
    • RH_RF95.h
    • RHutil
      • simulator.h
      • atomic.h
    • RHGenericDriver.cpp
    • RHMesh.cpp
    • RHGenericSPI.cpp
    • RHSoftwareSPI.h
    • RHReliableDatagram.h
    • RHHardwareSPI.cpp
    • RH_TCP.h
    • RHTcpProtocol.h
    • RH_ASK.h
    • RHHardwareSPI.h
    • examples
      • serial
        • serial_reliable_datagram_server
          • serial_reliable_datagram_server.pde
        • serial_reliable_datagram_client
          • serial_reliable_datagram_client.pde
      • ask
        • ask_transmitter
          • ask_transmitter.pde
        • ask_receiver
          • ask_receiver.pde
        • ask_reliable_datagram_client
          • ask_reliable_datagram_client.pde
        • ask_reliable_datagram_server
          • ask_reliable_datagram_server.pde
      • simulator
        • simulator_reliable_datagram_client
          • simulator_reliable_datagram_client.pde
        • simulator_reliable_datagram_server
          • simulator_reliable_datagram_server.pde
      • nrf905
        • nrf905_reliable_datagram_server
          • nrf905_reliable_datagram_server.pde
        • nrf905_client
          • nrf905_client.pde
        • nrf905_server
          • nrf905_server.pde
        • nrf905_reliable_datagram_client
          • nrf905_reliable_datagram_client.pde
      • rf95
        • rf95_client
          • rf95_client.pde
        • rf95_server
          • rf95_server.pde
        • rf95_reliable_datagram_client
          • rf95_reliable_datagram_client.pde
        • rf95_reliable_datagram_server
          • rf95_reliable_datagram_server.pde
      • rf24
        • rf24_client
          • rf24_client.pde
        • rf24_reliable_datagram_client
          • rf24_reliable_datagram_client.pde
        • rf24_reliable_datagram_server
          • rf24_reliable_datagram_server.pde
        • rf24_server
          • rf24_server.pde
      • rf22
        • rf22_server
          • rf22_server.pde
        • rf22_router_server3
          • rf22_router_server3.pde
        • rf22_router_test
          • rf22_router_test.pde
        • rf22_mesh_client
          • rf22_mesh_client.pde
        • rf22_router_client
          • rf22_router_client.pde
        • rf22_client
          • rf22_client.pde
        • rf22_mesh_server1
          • rf22_mesh_server1.pde
        • rf22_mesh_server3
          • rf22_mesh_server3.pde
        • rf22_reliable_datagram_client
          • rf22_reliable_datagram_client.pde
        • rf22_reliable_datagram_server
          • rf22_reliable_datagram_server.pde
        • rf22_router_server2
          • rf22_router_server2.pde
        • rf22_router_server1
          • rf22_router_server1.pde
        • rf22_mesh_server2
          • rf22_mesh_server2.pde
      • rf69
        • rf69_server
          • rf69_server.pde
        • rf69_reliable_datagram_server
          • rf69_reliable_datagram_server.pde
        • rf69_reliable_datagram_client
          • rf69_reliable_datagram_client.pde
        • rf69_client
          • rf69_client.pde
      • nrf24
        • nrf24_client
          • nrf24_client.pde
        • nrf24_reliable_datagram_client
          • nrf24_reliable_datagram_client.pde
        • nrf24_reliable_datagram_server
          • nrf24_reliable_datagram_server.pde
        • nrf24_server
          • nrf24_server.pde
    • RHCRC.h
    • RHDatagram.h
    • RH_NRF24.cpp
    • tools
      • chain.conf
      • simBuild
      • etherSimulator.pl
      • simMain.cpp
    • MANIFEST
    • LICENSE
    • RH_RF69.cpp
    • STM32ArduinoCompat
      • wirish.h
      • README
      • HardwareSerial.cpp
      • HardwareSerial.h
      • wirish.cpp
      • HardwareSPI.h
      • HardwareSPI.cpp
    • RHRouter.h
    • RH_RF22.h
    • RHGenericDriver.h
    • RHNRFSPIDriver.h
    • Makefile
    • RH_Serial.cpp
    • RHReliableDatagram.cpp
    • RH_RF24.h
    • radio_config_Si4460.h
    • RH_RF95.cpp
    • RH_RF69.h
    • RHSoftwareSPI.cpp
    • RH_Serial.h
    • RH_RF22.cpp
    • RHCRC.cpp
    • RHSPIDriver.cpp
    • RHRouter.cpp
    • Array
    • RHGenericSPI.h
    • project.cfg
    • RadioHead.h
    • RH_RF24.cpp
    • RHNRFSPIDriver.cpp
    • RH_NRF24.h
    • RH_NRF905.cpp
    • RHDatagram.cpp
    • RH_NRF905.h
    • RHMesh.h
    • RHSPIDriver.h


RadioHead-1.41.zip > RHHardwareSPI.h

// RHHardwareSPI.h
// Author: Mike McCauley (mikem@airspayce.com)
// Copyright (C) 2011 Mike McCauley
// Contributed by Joanna Rutkowska
// $Id: RHHardwareSPI.h,v 1.9 2014/08/12 00:54:52 mikem Exp $

#ifndef RHHardwareSPI_h
#define RHHardwareSPI_h

#include & lt; RHGenericSPI.h & gt;

/////////////////////////////////////////////////////////////////////
/// \class RHHardwareSPI RHHardwareSPI.h & lt; RHHardwareSPI.h & gt;
/// \brief Encapsulate a hardware SPI bus interface
///
/// This concrete subclass of GenericSPIClass encapsulates the standard Arduino hardware and other
/// hardware SPI interfaces.
class RHHardwareSPI : public RHGenericSPI
{
#ifdef RH_HAVE_HARDWARE_SPI
public:
/// Constructor
/// Creates an instance of a hardware SPI interface, using whatever SPI hardware is available on
/// your processor platform. On Arduino and Uno32, uses SPI. On Maple, uses HardwareSPI.
/// \param[in] frequency One of RHGenericSPI::Frequency to select the SPI bus frequency. The frequency
/// is mapped to the closest available bus frequency on the platform.
/// \param[in] bitOrder Select the SPI bus bit order, one of RHGenericSPI::BitOrderMSBFirst or
/// RHGenericSPI::BitOrderLSBFirst.
/// \param[in] dataMode Selects the SPI bus data mode. One of RHGenericSPI::DataMode
RHHardwareSPI(Frequency frequency = Frequency1MHz, BitOrder bitOrder = BitOrderMSBFirst, DataMode dataMode = DataMode0);

/// Transfer a single octet to and from the SPI interface
/// \param[in] data The octet to send
/// \return The octet read from SPI while the data octet was sent
uint8_t transfer(uint8_t data);

// SPI Configuration methods
/// Enable SPI interrupts
/// This can be used in an SPI slave to indicate when an SPI message has been received
/// It will cause the SPI_STC_vect interrupt vectr to be executed
void attachInterrupt();

/// Disable SPI interrupts
/// This can be used to diable the SPI interrupt in slaves where that is supported.
void detachInterrupt();

/// Initialise the SPI library
/// Call this after configuring the SPI interface and before using it to transfer data.
/// Initializes the SPI bus by setting SCK, MOSI, and SS to outputs, pulling SCK and MOSI low, and SS high.
void begin();

/// Disables the SPI bus (leaving pin modes unchanged).
/// Call this after you have finished using the SPI interface.
void end();
#else
// not supported on ATTiny etc
uint8_t transfer(uint8_t data) {return 0;}
void begin(){}
void end(){}

#endif
};

// Built in default instance
extern RHHardwareSPI hardware_spi;

#endif


RadioHead-1.41.zip > RH_TCP.cpp

// RH_TCP.cpp
//
// Copyright (C) 2014 Mike McCauley
// $Id: RH_TCP.cpp,v 1.3 2014/05/30 19:30:54 mikem Exp $

#include & lt; RadioHead.h & gt;

// This can only build on Linux and compatible systems
#if (RH_PLATFORM == RH_PLATFORM_SIMULATOR)

#include & lt; RH_TCP.h & gt;
#include & lt; sys/types.h & gt;
#include & lt; errno.h & gt;
#include & lt; sys/socket.h & gt;
#include & lt; netinet/in.h & gt;
#include & lt; arpa/inet.h & gt;
#include & lt; unistd.h & gt;
#include & lt; sys/ioctl.h & gt;
#include & lt; netdb.h & gt;
#include & lt; string & gt;

RH_TCP::RH_TCP(const char* server)
: _server(server),
_rxBufLen(0),
_rxBufValid(false),
_socket(-1)
{
}

bool RH_TCP::init()
{
if (!connectToServer())
return false;
return sendThisAddress(_thisAddress);
}

bool RH_TCP::connectToServer()
{
struct addrinfo hints;
struct addrinfo *result, *rp;
int sfd, s;
struct sockaddr_storage peer_addr;
socklen_t peer_addr_len;

memset( & hints, 0, sizeof(struct addrinfo));
hints.ai_family = AF_UNSPEC; // Allow IPv4 or IPv6
hints.ai_socktype = SOCK_STREAM; // Stream socket
hints.ai_flags = AI_PASSIVE; // For wildcard IP address
hints.ai_protocol = 0; // Any protocol
hints.ai_canonname = NULL;
hints.ai_addr = NULL;
hints.ai_next = NULL;

std::string server(_server);
std::string port( " 4000 " );
size_t indexOfSeparator = server.find_first_of(':');
if (indexOfSeparator != std::string::npos)
{
port = server.substr(indexOfSeparator+1);
server.erase(indexOfSeparator);
}

s = getaddrinfo(server.c_str(), port.c_str(), & hints, & result);
if (s != 0)
{
fprintf(stderr, " RH_TCP::connect getaddrinfo failed: %s\n " , gai_strerror(s));
return false;
}

// getaddrinfo() returns a list of address structures.
// Try each address until we successfully connect(2).
// If socket(2) (or connect(2)) fails, we (close the socket
// and) try the next address. */

for (rp = result; rp != NULL; rp = rp- & gt; ai_next)
{
_socket = socket(rp- & gt; ai_family, rp- & gt; ai_socktype, rp- & gt; ai_protocol);
if (_socket == -1)
continue;

if (connect(_socket, rp- & gt; ai_addr, rp- & gt; ai_addrlen) == 0)
break; /* Success */

close(_socket);
}

if (rp == NULL)
{ /* No address succeeded */
fprintf(stderr, " RH_TCP::connect could not connect to %s\n " , _server);
return false;
}

freeaddrinfo(result); /* No longer needed */

// Now make the socket non-blocking
int on = 1;
int rc = ioctl(_socket, FIONBIO, (char *) & on);
if (rc & lt; 0)
{
fprintf(stderr, " RH_TCP::init failed to set socket non-blocking: %s\n " , strerror(errno));
close(_socket);
_socket = -1;
return false;
}
return true;
}

void RH_TCP::clearRxBuf()
{
_rxBufValid = false;
_rxBufLen = 0;
}

void RH_TCP::checkForEvents()
{
#define RH_TCP_SOCKETBUF_LEN 500
static uint8_t socketBuf[RH_TCP_SOCKETBUF_LEN]; // Room for several messages
static uint16_t socketBufLen = 0;

// Read at most the amount of space we have left in the buffer
ssize_t count = read(_socket, socketBuf + socketBufLen, sizeof(socketBuf) - socketBufLen);
if (count & lt; 0)
{
if (errno != EAGAIN)
{
fprintf(stderr, " RH_TCP::checkForEvents read error: %s\n " , strerror(errno));
exit(1);
}
}
else if (count == 0)
{
// End of file
fprintf(stderr, " RH_TCP::checkForEvents unexpected end of file on read\n " );
exit(1);
}
else
{
socketBufLen += count;
while (socketBufLen & gt; = 5)
{
RHTcpTypeMessage* message = ((RHTcpTypeMessage*)socketBuf);
uint32_t len = ntohl(message- & gt; length);
uint32_t messageLen = len + sizeof(message- & gt; length);
if (len & gt; sizeof(socketBuf) - sizeof(message- & gt; length))
{
// Bogus length
fprintf(stderr, " RH_TCP::checkForEvents read ridiculous length: %d. Corrupt message stream? Aborting\n " , len);
exit(1);
}
if (socketBufLen & gt; = len + sizeof(message- & gt; length))
{
// Got at least all of this message
if (message- & gt; type == RH_TCP_MESSAGE_TYPE_PACKET & & len & gt; = 5)
{
// REVISIT: need to check if we are actually receiving?
// Its a new packet, extract the headers and payload
RHTcpPacket* packet = ((RHTcpPacket*)socketBuf);
_rxHeaderTo = packet- & gt; to;
_rxHeaderFrom = packet- & gt; from;
_rxHeaderId = packet- & gt; id;
_rxHeaderFlags = packet- & gt; flags;
uint32_t payloadLen = len - 5;
if (payloadLen & lt; = sizeof(_rxBuf))
{
// Enough room in our receiver buffer
memcpy(_rxBuf, packet- & gt; payload, payloadLen);
_rxBufLen = payloadLen;
_rxBufFull = true;
}
}
// check for other message types here
// Now remove the used message by copying the trailing bytes (maybe start of a new message?)
// to the top of the buffer
memcpy(socketBuf, socketBuf + messageLen, sizeof(socketBuf) - messageLen);
socketBufLen -= messageLen;
}
}
}
}

void RH_TCP::validateRxBuf()
{
// The headers have already been extracted
if (_promiscuous ||
_rxHeaderTo == _thisAddress ||
_rxHeaderTo == RH_BROADCAST_ADDRESS)
{
_rxGood++;
_rxBufValid = true;
}
}

bool RH_TCP::available()
{
if (_socket & lt; 0)
return false;
checkForEvents();
if (_rxBufFull)
{
validateRxBuf();
_rxBufFull= false;
}
return _rxBufValid;
}

bool RH_TCP::recv(uint8_t* buf, uint8_t* len)
{
if (!available())
return false;

if (buf & & len)
{
if (*len & gt; _rxBufLen)
*len = _rxBufLen;
memcpy(buf, _rxBuf, *len);
}
clearRxBuf();
return true;
}

bool RH_TCP::send(const uint8_t* data, uint8_t len)
{
bool ret = sendPacket(data, len);
delay(10); // Wait for transmit to succeed. REVISIT: depends on length and speed
return ret;
}

uint8_t RH_TCP::maxMessageLength()
{
return RH_TCP_MAX_MESSAGE_LEN;
}

void RH_TCP::setThisAddress(uint8_t address)
{
RHGenericDriver::setThisAddress(address);
sendThisAddress(_thisAddress);
}

bool RH_TCP::sendThisAddress(uint8_t thisAddress)
{
if (_socket & lt; 0)
return false;
RHTcpThisAddress m;
m.length = htonl(2);
m.type = RH_TCP_MESSAGE_TYPE_THISADDRESS;
m.thisAddress = thisAddress;
ssize_t sent = write(_socket, & m, sizeof(m));
return sent & gt; 0;
}

bool RH_TCP::sendPacket(const uint8_t* data, uint8_t len)
{
if (_socket & lt; 0)
return false;
RHTcpPacket m;
m.length = htonl(len + 4);
m.type = RH_TCP_MESSAGE_TYPE_PACKET;
m.to = _txHeaderTo;
m.from = _txHeaderFrom;
m.id = _txHeaderId;
m.flags = _txHeaderFlags;
memcpy(m.payload, data, len);
ssize_t sent = write(_socket, & m, len + 8);
return sent & gt; 0;
}

#endif


RadioHead-1.41.zip > RH_ASK.cpp

// RH_ASK.cpp
//
// Copyright (C) 2014 Mike McCauley
// $Id: RH_ASK.cpp,v 1.15 2015/03/09 06:04:26 mikem Exp $

#include & lt; RH_ASK.h & gt;
#include & lt; RHCRC.h & gt;

#if (RH_PLATFORM == RH_PLATFORM_STM32) // Maple etc
HardwareTimer timer(MAPLE_TIMER);
#endif

// RH_ASK on Arduino uses Timer 1 to generate interrupts 8 times per bit interval
// Define RH_ASK_ARDUINO_USE_TIMER2 if you want to use Timer 2 instead of Timer 1 on Arduino
// You may need this to work around other librraies that insist on using timer 1
// Should be moved to header file
//#define RH_ASK_ARDUINO_USE_TIMER2

// Interrupt handler uses this to find the most recently initialised instance of this driver
static RH_ASK* thisASKDriver;

// 4 bit to 6 bit symbol converter table
// Used to convert the high and low nybbles of the transmitted data
// into 6 bit symbols for transmission. Each 6-bit symbol has 3 1s and 3 0s
// with at most 3 consecutive identical bits
static uint8_t symbols[] =
{
0xd, 0xe, 0x13, 0x15, 0x16, 0x19, 0x1a, 0x1c,
0x23, 0x25, 0x26, 0x29, 0x2a, 0x2c, 0x32, 0x34
};

// This is the value of the start symbol after 6-bit conversion and nybble swapping
#define RH_ASK_START_SYMBOL 0xb38

RH_ASK::RH_ASK(uint16_t speed, uint8_t rxPin, uint8_t txPin, uint8_t pttPin, bool pttInverted)
:
_speed(speed),
_rxPin(rxPin),
_txPin(txPin),
_pttPin(pttPin),
_pttInverted(pttInverted)
{
// Initialise the first 8 nibbles of the tx buffer to be the standard
// preamble. We will append messages after that. 0x38, 0x2c is the start symbol before
// 6-bit conversion to RH_ASK_START_SYMBOL
uint8_t preamble[RH_ASK_PREAMBLE_LEN] = {0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x38, 0x2c};
memcpy(_txBuf, preamble, sizeof(preamble));
}

bool RH_ASK::init()
{
if (!RHGenericDriver::init())
return false;
thisASKDriver = this;

#if (RH_PLATFORM == RH_PLATFORM_GENERIC_AVR8)
#ifdef RH_ASK_PTT_PIN
RH_ASK_PTT_DDR |= (1 & lt; & lt; RH_ASK_PTT_PIN);
RH_ASK_TX_DDR |= (1 & lt; & lt; RH_ASK_TX_PIN);
RH_ASK_RX_DDR & = ~(1 & lt; & lt; RH_ASK_RX_PIN);
#else
RH_ASK_TX_DDR |= (1 & lt; & lt; RH_ASK_TX_PIN);
RH_ASK_RX_DDR & = ~(1 & lt; & lt; RH_ASK_RX_PIN);
#endif
#else
// Set up digital IO pins for arduino
pinMode(_txPin, OUTPUT);
pinMode(_rxPin, INPUT);
pinMode(_pttPin, OUTPUT);
#endif

// Ready to go
setModeIdle();

timerSetup();

return true;
}

// Put these prescaler structs in PROGMEM, not on the stack
#if (RH_PLATFORM == RH_PLATFORM_ARDUINO) || (RH_PLATFORM == RH_PLATFORM_GENERIC_AVR8)
#if defined(RH_ASK_ARDUINO_USE_TIMER2)
// Timer 2 has different prescalers
PROGMEM static const uint16_t prescalers[] = {0, 1, 8, 32, 64, 128, 256, 3333};
#else
PROGMEM static const uint16_t prescalers[] = {0, 1, 8, 64, 256, 1024, 3333};
#endif
#define NUM_PRESCALERS (sizeof(prescalers) / sizeof( uint16_t))
#endif

// Common function for setting timer ticks @ prescaler values for speed
// Returns prescaler index into {0, 1, 8, 64, 256, 1024} array
// and sets nticks to compare-match value if lower than max_ticks
// returns 0 & nticks = 0 on fault
uint8_t RH_ASK::timerCalc(uint16_t speed, uint16_t max_ticks, uint16_t *nticks)
{
#if (RH_PLATFORM == RH_PLATFORM_ARDUINO) || (RH_PLATFORM == RH_PLATFORM_GENERIC_AVR8)
// Clock divider (prescaler) values - 0/3333: error flag
uint8_t prescaler; // index into array & return bit value
unsigned long ulticks; // calculate by ntick overflow

// Div-by-zero protection
if (speed == 0)
{
// signal fault
*nticks = 0;
return 0;
}

// test increasing prescaler (divisor), decreasing ulticks until no overflow
// 1/Fraction of second needed to xmit one bit
unsigned long inv_bit_time = ((unsigned long)speed) * 8;
for (prescaler=1; prescaler & lt; NUM_PRESCALERS; prescaler += 1)
{
// Integer arithmetic courtesy Jim Remington
// 1/Amount of time per CPU clock tick (in seconds)
uint16_t prescalerValue;
memcpy_P( & prescalerValue, & prescalers[prescaler], sizeof(uint16_t));
unsigned long inv_clock_time = F_CPU / ((unsigned long)prescalerValue);
// number of prescaled ticks needed to handle bit time @ speed
ulticks = inv_clock_time / inv_bit_time;

// Test if ulticks fits in nticks bitwidth (with 1-tick safety margin)
if ((ulticks & gt; 1) & & (ulticks & lt; max_ticks))
break; // found prescaler

// Won't fit, check with next prescaler value
}


// Check for error
if ((prescaler == 6) || (ulticks & lt; 2) || (ulticks & gt; max_ticks))
{
// signal fault
*nticks = 0;
return 0;
}

*nticks = ulticks;
return prescaler;
#else
return 0; // not implemented or needed on other platforms
#endif
}

// The idea here is to get 8 timer interrupts per bit period
void RH_ASK::timerSetup()
{
#if (RH_PLATFORM == RH_PLATFORM_GENERIC_AVR8)
uint16_t nticks;
uint8_t prescaler = timerCalc(_speed, (uint16_t)-1, & nticks);
if (!prescaler) return;
_COMB(TCCR,RH_ASK_TIMER_INDEX,A)= 0;
_COMB(TCCR,RH_ASK_TIMER_INDEX,B)= _BV(WGM12);
_COMB(TCCR,RH_ASK_TIMER_INDEX,B)|= prescaler;
_COMB(OCR,RH_ASK_TIMER_INDEX,A)= nticks;
_COMB(TI,MSK,RH_ASK_TIMER_INDEX)|= _BV(_COMB(OCIE,RH_ASK_TIMER_INDEX,A));

#elif (RH_PLATFORM == RH_PLATFORM_MSP430) // LaunchPad specific
// Calculate the counter overflow count based on the required bit speed
// and CPU clock rate
uint16_t ocr1a = (F_CPU / 8UL) / _speed;

// This code is for Energia/MSP430
TA0CCR0 = ocr1a; // Ticks for 62,5 us
TA0CTL = TASSEL_2 + MC_1; // SMCLK, up mode
TA0CCTL0 |= CCIE; // CCR0 interrupt enabled

#elif (RH_PLATFORM == RH_PLATFORM_ARDUINO) // Arduino specific
uint16_t nticks; // number of prescaled ticks needed
uint8_t prescaler; // Bit values for CS0[2:0]

#ifdef RH_PLATFORM_ATTINY
// figure out prescaler value and counter match value
// REVISIT: does not correctly handle 1MHz clock speeds, only works with 8MHz clocks
// At 1MHz clock, get 1/8 of the expected baud rate
prescaler = timerCalc(_speed, (uint8_t)-1, & nticks);
if (!prescaler)
return; // fault

TCCR0A = 0;
TCCR0A = _BV(WGM01); // Turn on CTC mode / Output Compare pins disconnected

// convert prescaler index to TCCRnB prescaler bits CS00, CS01, CS02
TCCR0B = 0;
TCCR0B = prescaler; // set CS00, CS01, CS02 (other bits not needed)


// Number of ticks to count before firing interrupt
OCR0A = uint8_t(nticks);

// Set mask to fire interrupt when OCF0A bit is set in TIFR0
#ifdef TIMSK0
// ATtiny84
TIMSK0 |= _BV(OCIE0A);
#else
// ATtiny85
TIMSK |= _BV(OCIE0A);
#endif


#elif defined(__arm__) & & defined(CORE_TEENSY)
// on Teensy 3.0 (32 bit ARM), use an interval timer
IntervalTimer *t = new IntervalTimer();
void TIMER1_COMPA_vect(void);
t- & gt; begin(TIMER1_COMPA_vect, 125000 / _speed);

#elif defined(__arm__)
// Arduino Due
// Due has 9 timers in 3 blocks of 3.
// We use timer 1 TC1_IRQn on TC0 channel 1, since timers 0, 2, 3, 4, 5 are used by the Servo library
#define RH_ASK_DUE_TIMER TC0
#define RH_ASK_DUE_TIMER_CHANNEL 1
#define RH_ASK_DUE_TIMER_IRQ TC1_IRQn
pmc_set_writeprotect(false);
pmc_enable_periph_clk(RH_ASK_DUE_TIMER_IRQ);

// Clock speed 4 can handle all reasonable _speeds we might ask for. Its divisor is 128
// and we want 8 interrupts per bit
uint32_t rc = (VARIANT_MCK / _speed) / 128 / 8;
TC_Configure(RH_ASK_DUE_TIMER, RH_ASK_DUE_TIMER_CHANNEL,
TC_CMR_WAVE | TC_CMR_WAVSEL_UP_RC | TC_CMR_TCCLKS_TIMER_CLOCK4);
TC_SetRC(RH_ASK_DUE_TIMER, RH_ASK_DUE_TIMER_CHANNEL, rc);
// Enable the RC Compare Interrupt
RH_ASK_DUE_TIMER- & gt; TC_CHANNEL[RH_ASK_DUE_TIMER_CHANNEL].TC_IER = TC_IER_CPCS;
NVIC_ClearPendingIRQ(RH_ASK_DUE_TIMER_IRQ);
NVIC_EnableIRQ(RH_ASK_DUE_TIMER_IRQ);
TC_Start(RH_ASK_DUE_TIMER, RH_ASK_DUE_TIMER_CHANNEL);

#else
// This is the path for most Arduinos
// figure out prescaler value and counter match value
#if defined(RH_ASK_ARDUINO_USE_TIMER2)
prescaler = timerCalc(_speed, (uint8_t)-1, & nticks);
if (!prescaler)
return; // fault
// Use timer 2
TCCR2A = _BV(WGM21); // Turn on CTC mode)
// convert prescaler index to TCCRnB prescaler bits CS10, CS11, CS12
TCCR2B = prescaler;

// Caution: special procedures for setting 16 bit regs
// is handled by the compiler
OCR2A = nticks;
// Enable interrupt
#ifdef TIMSK2
// atmega168
TIMSK2 |= _BV(OCIE2A);
#else
// others
TIMSK |= _BV(OCIE2A);
#endif // TIMSK2
#else
// Use timer 1
prescaler = timerCalc(_speed, (uint16_t)-1, & nticks);
if (!prescaler)
return; // fault
TCCR1A = 0; // Output Compare pins disconnected
TCCR1B = _BV(WGM12); // Turn on CTC mode

// convert prescaler index to TCCRnB prescaler bits CS10, CS11, CS12
TCCR1B |= prescaler;

// Caution: special procedures for setting 16 bit regs
// is handled by the compiler
OCR1A = nticks;
// Enable interrupt
#ifdef TIMSK1
// atmega168
TIMSK1 |= _BV(OCIE1A);
#else
// others
TIMSK |= _BV(OCIE1A);
#endif // TIMSK1
#endif
#endif

#elif (RH_PLATFORM == RH_PLATFORM_STM32) // Maple etc
// Pause the timer while we're configuring it
timer.pause();
timer.setPeriod((1000000/8)/_speed);
// Set up an interrupt on channel 1
timer.setChannel1Mode(TIMER_OUTPUT_COMPARE);
timer.setCompare(TIMER_CH1, 1); // Interrupt 1 count after each update
void interrupt(); // defined below
timer.attachCompare1Interrupt(interrupt);

// Refresh the timer's count, prescale, and overflow
timer.refresh();

// Start the timer counting
timer.resume();

#elif (RH_PLATFORM == RH_PLATFORM_UNO32)
// ON Uno32 we use timer1
OpenTimer1(T1_ON | T1_PS_1_1 | T1_SOURCE_INT, (F_CPU / 8) / _speed);
ConfigIntTimer1(T1_INT_ON | T1_INT_PRIOR_1);
#endif

}

void RH_ASK::setModeIdle()
{
if (_mode != RHModeIdle)
{
// Disable the transmitter hardware
writePtt(LOW);
writeTx(LOW);
_mode = RHModeIdle;
}
}

void RH_ASK::setModeRx()
{
if (_mode != RHModeRx)
{
// Disable the transmitter hardware
writePtt(LOW);
writeTx(LOW);
_mode = RHModeRx;
}
}

void RH_ASK::setModeTx()
{
if (_mode != RHModeTx)
{
// PRepare state varibles for a new transmission
_txIndex = 0;
_txBit = 0;
_txSample = 0;

// Enable the transmitter hardware
writePtt(HIGH);

_mode = RHModeTx;
}
}

// Call this often
bool RH_ASK::available()
{
if (_mode == RHModeTx)
return false;
setModeRx();
if (_rxBufFull)
{
validateRxBuf();
_rxBufFull= false;
}
return _rxBufValid;
}

bool RH_ASK::recv(uint8_t* buf, uint8_t* len)
{
if (!available())
return false;

if (buf & & len)
{
// Skip the length and 4 headers that are at the beginning of the rxBuf
// and drop the trailing 2 bytes of FCS
uint8_t message_len = _rxBufLen-RH_ASK_HEADER_LEN - 3;
if (*len & gt; message_len)
*len = message_len;
memcpy(buf, _rxBuf+RH_ASK_HEADER_LEN+1, *len);
}
_rxBufValid = false; // Got the most recent message, delete it
// printBuffer( " recv: " , buf, *len);
return true;
}

// Caution: this may block
bool RH_ASK::send(const uint8_t* data, uint8_t len)
{
uint8_t i;
uint16_t index = 0;
uint16_t crc = 0xffff;
uint8_t *p = _txBuf + RH_ASK_PREAMBLE_LEN; // start of the message area
uint8_t count = len + 3 + RH_ASK_HEADER_LEN; // Added byte count and FCS and headers to get total number of bytes

if (len & gt; RH_ASK_MAX_MESSAGE_LEN)
return false;

// Wait for transmitter to become available
waitPacketSent();

// Encode the message length
crc = RHcrc_ccitt_update(crc, count);
p[index++] = symbols[count & gt; & gt; 4];
p[index++] = symbols[count & 0xf];

// Encode the headers
crc = RHcrc_ccitt_update(crc, _txHeaderTo);
p[index++] = symbols[_txHeaderTo & gt; & gt; 4];
p[index++] = symbols[_txHeaderTo & 0xf];
crc = RHcrc_ccitt_update(crc, _txHeaderFrom);
p[index++] = symbols[_txHeaderFrom & gt; & gt; 4];
p[index++] = symbols[_txHeaderFrom & 0xf];
crc = RHcrc_ccitt_update(crc, _txHeaderId);
p[index++] = symbols[_txHeaderId & gt; & gt; 4];
p[index++] = symbols[_txHeaderId & 0xf];
crc = RHcrc_ccitt_update(crc, _txHeaderFlags);
p[index++] = symbols[_txHeaderFlags & gt; & gt; 4];
p[index++] = symbols[_txHeaderFlags & 0xf];

// Encode the message into 6 bit symbols. Each byte is converted into
// 2 6-bit symbols, high nybble first, low nybble second
for (i = 0; i & lt; len; i++)
{
crc = RHcrc_ccitt_update(crc, data[i]);
p[index++] = symbols[data[i] & gt; & gt; 4];
p[index++] = symbols[data[i] & 0xf];
}

// Append the fcs, 16 bits before encoding (4 6-bit symbols after encoding)
// Caution: VW expects the _ones_complement_ of the CCITT CRC-16 as the FCS
// VW sends FCS as low byte then hi byte
crc = ~crc;
p[index++] = symbols[(crc & gt; & gt; 4) & 0xf];
p[index++] = symbols[crc & 0xf];
p[index++] = symbols[(crc & gt; & gt; 12) & 0xf];
p[index++] = symbols[(crc & gt; & gt; 8) & 0xf];

// Total number of 6-bit symbols to send
_txBufLen = index + RH_ASK_PREAMBLE_LEN;

// Start the low level interrupt handler sending symbols
setModeTx();

// FIXME
thisASKDriver = this;

return true;
}

// Read the RX data input pin, taking into account platform type and inversion.
bool RH_ASK::readRx()
{
bool value;
#if (RH_PLATFORM == RH_PLATFORM_GENERIC_AVR8)
value = ((RH_ASK_RX_PORT & (1 & lt; & lt; RH_ASK_RX_PIN)) ? 1 : 0);
#else
value = digitalRead(_rxPin);
#endif
return value ^ _rxInverted;
}

// Write the TX output pin, taking into account platform type.
void RH_ASK::writeTx(bool value)
{
#if (RH_PLATFORM == RH_PLATFORM_GENERIC_AVR8)
((value) ? (RH_ASK_TX_PORT |= (1 & lt; & lt; RH_ASK_TX_PIN)) : (RH_ASK_TX_PORT & = ~(1 & lt; & lt; RH_ASK_TX_PIN)));
#else
digitalWrite(_txPin, value);
#endif
}

// Write the PTT output pin, taking into account platform type and inversion.
void RH_ASK::writePtt(bool value)
{
#if (RH_PLATFORM == RH_PLATFORM_GENERIC_AVR8)
#if RH_ASK_PTT_PIN
((value) ? (RH_ASK_PTT_PORT |= (1 & lt; & lt; RH_ASK_PTT_PIN)) : (RH_ASK_PTT_PORT & = ~(1 & lt; & lt; RH_ASK_PTT_PIN)));
#else
((value) ? (RH_ASK_TX_PORT |= (1 & lt; & lt; RH_ASK_TX_PIN)) : (RH_ASK_TX_PORT & = ~(1 & lt; & lt; RH_ASK_TX_PIN)));
#endif
#else
digitalWrite(_pttPin, value ^ _pttInverted);
#endif
}

uint8_t RH_ASK::maxMessageLength()
{
return RH_ASK_MAX_MESSAGE_LEN;
}

#if (RH_PLATFORM == RH_PLATFORM_ARDUINO)
#if defined(RH_PLATFORM_ATTINY)
#define RH_ASK_TIMER_VECTOR TIM0_COMPA_vect
#else // Assume Arduino Uno (328p or similar)
#if defined(RH_ASK_ARDUINO_USE_TIMER2)
#define RH_ASK_TIMER_VECTOR TIMER2_COMPA_vect
#else
#define RH_ASK_TIMER_VECTOR TIMER1_COMPA_vect
#endif
#endif
#elif (RH_ASK_PLATFORM == RH_ASK_PLATFORM_GENERIC_AVR8)
#define __COMB(a,b,c) (a##b##c)
#define _COMB(a,b,c) __COMB(a,b,c)
#define RH_ASK_TIMER_VECTOR _COMB(TIMER,RH_ASK_TIMER_INDEX,_COMPA_vect)
#endif

#if (RH_PLATFORM == RH_PLATFORM_ARDUINO) & & defined(__arm__) & & defined(CORE_TEENSY)
void TIMER1_COMPA_vect(void)
{
thisASKDriver- & gt; handleTimerInterrupt();
}

#elif (RH_PLATFORM == RH_PLATFORM_ARDUINO) & & defined(__arm__)
// Arduino Due
void TC1_Handler()
{
TC_GetStatus(TC0, 1);
thisASKDriver- & gt; handleTimerInterrupt();
}

#elif (RH_PLATFORM == RH_PLATFORM_ARDUINO) || (RH_PLATFORM == RH_PLATFORM_GENERIC_AVR8)
// This is the interrupt service routine called when timer1 overflows
// Its job is to output the next bit from the transmitter (every 8 calls)
// and to call the PLL code if the receiver is enabled
//ISR(SIG_OUTPUT_COMPARE1A)
ISR(RH_ASK_TIMER_VECTOR)
{
thisASKDriver- & gt; handleTimerInterrupt();
}

#elif (RH_PLATFORM == RH_PLATFORM_MSP430) || (RH_PLATFORM == RH_PLATFORM_STM32)
// LaunchPad, Maple
void interrupt()
{
thisASKDriver- & gt; handleTimerInterrupt();
}

#elif (RH_PLATFORM == RH_PLATFORM_MSP430)
interrupt(TIMER0_A0_VECTOR) Timer_A_int(void)
{
thisASKDriver- & gt; handleTimerInterrupt();
};

#elif (RH_PLATFORM == RH_PLATFORM_UNO32)
extern " C "
{
void __ISR(_TIMER_1_VECTOR, ipl1) timerInterrupt(void)
{
thisASKDriver- & gt; handleTimerInterrupt();
mT1ClearIntFlag(); // Clear timer 1 interrupt flag
}
}
#endif

// Convert a 6 bit encoded symbol into its 4 bit decoded equivalent
uint8_t RH_ASK::symbol_6to4(uint8_t symbol)
{
uint8_t i;
uint8_t count;

// Linear search :-( Could have a 64 byte reverse lookup table?
// There is a little speedup here courtesy Ralph Doncaster:
// The shortcut works because bit 5 of the symbol is 1 for the last 8
// symbols, and it is 0 for the first 8.
// So we only have to search half the table
for (i = (symbol & gt; & gt; 2) & 8, count=8; count-- ; i++)
if (symbol == symbols[i]) return i;

return 0; // Not found
}

// Check whether the latest received message is complete and uncorrupted
// We should always check the FCS at user level, not interrupt level
// since it is slow
void RH_ASK::validateRxBuf()
{
uint16_t crc = 0xffff;
// The CRC covers the byte count, headers and user data
for (uint8_t i = 0; i & lt; _rxBufLen; i++)
crc = RHcrc_ccitt_update(crc, _rxBuf[i]);
if (crc != 0xf0b8) // CRC when buffer and expected CRC are CRC'd
{
// Reject and drop the message
_rxBad++;
_rxBufValid = false;
return;
}

// Extract the 4 headers that follow the message length
_rxHeaderTo = _rxBuf[1];
_rxHeaderFrom = _rxBuf[2];
_rxHeaderId = _rxBuf[3];
_rxHeaderFlags = _rxBuf[4];
if (_promiscuous ||
_rxHeaderTo == _thisAddress ||
_rxHeaderTo == RH_BROADCAST_ADDRESS)
{
_rxGood++;
_rxBufValid = true;
}
}

void RH_ASK::receiveTimer()
{
bool rxSample = readRx();

// Integrate each sample
if (rxSample)
_rxIntegrator++;

if (rxSample != _rxLastSample)
{
// Transition, advance if ramp & gt; 80, retard if & lt; 80
_rxPllRamp += ((_rxPllRamp & lt; RH_ASK_RAMP_TRANSITION)
? RH_ASK_RAMP_INC_RETARD
: RH_ASK_RAMP_INC_ADVANCE);
_rxLastSample = rxSample;
}
else
{
// No transition
// Advance ramp by standard 20 (== 160/8 samples)
_rxPllRamp += RH_ASK_RAMP_INC;
}
if (_rxPllRamp & gt; = RH_ASK_RX_RAMP_LEN)
{
// Add this to the 12th bit of _rxBits, LSB first
// The last 12 bits are kept
_rxBits & gt; & gt; = 1;

// Check the integrator to see how many samples in this cycle were high.
// If & lt; 5 out of 8, then its declared a 0 bit, else a 1;
if (_rxIntegrator & gt; = 5)
_rxBits |= 0x800;

_rxPllRamp -= RH_ASK_RX_RAMP_LEN;
_rxIntegrator = 0; // Clear the integral for the next cycle

if (_rxActive)
{
// We have the start symbol and now we are collecting message bits,
// 6 per symbol, each which has to be decoded to 4 bits
if (++_rxBitCount & gt; = 12)
{
// Have 12 bits of encoded message == 1 byte encoded
// Decode as 2 lots of 6 bits into 2 lots of 4 bits
// The 6 lsbits are the high nybble
uint8_t this_byte =
(symbol_6to4(_rxBits & 0x3f)) & lt; & lt; 4
| symbol_6to4(_rxBits & gt; & gt; 6);

// The first decoded byte is the byte count of the following message
// the count includes the byte count and the 2 trailing FCS bytes
// REVISIT: may also include the ACK flag at 0x40
if (_rxBufLen == 0)
{
// The first byte is the byte count
// Check it for sensibility. It cant be less than 7, since it
// includes the byte count itself, the 4 byte header and the 2 byte FCS
_rxCount = this_byte;
if (_rxCount & lt; 7 || _rxCount & gt; RH_ASK_MAX_PAYLOAD_LEN)
{
// Stupid message length, drop the whole thing
_rxActive = false;
_rxBad++;
return;
}
}
_rxBuf[_rxBufLen++] = this_byte;

if (_rxBufLen & gt; = _rxCount)
{
// Got all the bytes now
_rxActive = false;
_rxBufFull = true;
setModeIdle();
}
_rxBitCount = 0;
}
}
// Not in a message, see if we have a start symbol
else if (_rxBits == RH_ASK_START_SYMBOL)
{
// Have start symbol, start collecting message
_rxActive = true;
_rxBitCount = 0;
_rxBufLen = 0;
}
}
}

void RH_ASK::transmitTimer()
{
if (_txSample++ == 0)
{
// Send next bit
// Symbols are sent LSB first
// Finished sending the whole message? (after waiting one bit period
// since the last bit)
if (_txIndex & gt; = _txBufLen)
{
setModeIdle();
_txGood++;
}
else
{
writeTx(_txBuf[_txIndex] & (1 & lt; & lt; _txBit++));
if (_txBit & gt; = 6)
{
_txBit = 0;
_txIndex++;
}
}
}

if (_txSample & gt; 7)
_txSample = 0;
}

void RH_ASK::handleTimerInterrupt()
{
if (_mode == RHModeRx)
receiveTimer(); // Receiving
else if (_mode == RHModeTx)
transmitTimer(); // Transmitting
}


RadioHead-1.41.zip > RH_RF95.h

// RH_RF95.h
//
// Definitions for HopeRF LoRa radios per:
// http://www.hoperf.com/upload/rf/RFM95_96_97_98W.pdf
// http://www.hoperf.cn/upload/rfchip/RF96_97_98.pdf
//
// Author: Mike McCauley (mikem@airspayce.com)
// Copyright (C) 2014 Mike McCauley
// $Id: RH_RF95.h,v 1.6 2015/01/02 21:38:24 mikem Exp $
//

#ifndef RH_RF95_h
#define RH_RF95_h

#include & lt; RHSPIDriver.h & gt;

// This is the maximum number of interrupts the driver can support
// Most Arduinos can handle 2, Megas can handle more
#define RH_RF95_NUM_INTERRUPTS 3

// Max number of octets the LORA Rx/Tx FIFO can hold
#define RH_RF95_FIFO_SIZE 255

// This is the maximum number of bytes that can be carried by the LORA.
// We use some for headers, keeping fewer for RadioHead messages
#define RH_RF95_MAX_PAYLOAD_LEN RH_RF95_FIFO_SIZE

// The length of the headers we add.
// The headers are inside the LORA's payload
#define RH_RF95_HEADER_LEN 4

// This is the maximum message length that can be supported by this driver.
// Can be pre-defined to a smaller size (to save SRAM) prior to including this header
// Here we allow for 1 byte message length, 4 bytes headers, user data and 2 bytes of FCS
#ifndef RH_RF95_MAX_MESSAGE_LEN
#define RH_RF95_MAX_MESSAGE_LEN (RH_RF95_MAX_PAYLOAD_LEN - RH_RF95_HEADER_LEN)
#endif

// The crystal oscillator frequency of the module
#define RH_RF95_FXOSC 32000000.0

// The Frequency Synthesizer step = RH_RF95_FXOSC / 2^^19
#define RH_RF95_FSTEP (RH_RF95_FXOSC / 524288)


// Register names (LoRa Mode, from table 85)
#define RH_RF95_REG_00_FIFO 0x00
#define RH_RF95_REG_01_OP_MODE 0x01
#define RH_RF95_REG_02_RESERVED 0x02
#define RH_RF95_REG_03_RESERVED 0x03
#define RH_RF95_REG_04_RESERVED 0x04
#define RH_RF95_REG_05_RESERVED 0x05
#define RH_RF95_REG_06_FRF_MSB 0x06
#define RH_RF95_REG_07_FRF_MID 0x07
#define RH_RF95_REG_08_FRF_LSB 0x08
#define RH_RF95_REG_09_PA_CONFIG 0x09
#define RH_RF95_REG_0A_PA_RAMP 0x0a
#define RH_RF95_REG_0B_OCP 0x0b
#define RH_RF95_REG_0C_LNA 0x0c
#define RH_RF95_REG_0D_FIFO_ADDR_PTR 0x0d
#define RH_RF95_REG_0E_FIFO_TX_BASE_ADDR 0x0e
#define RH_RF95_REG_0F_FIFO_RX_BASE_ADDR 0x0f
#define RH_RF95_REG_10_FIFO_RX_CURRENT_ADDR 0x10
#define RH_RF95_REG_11_IRQ_FLAGS_MASK 0x11
#define RH_RF95_REG_12_IRQ_FLAGS 0x12
#define RH_RF95_REG_13_RX_NB_BYTES 0x13
#define RH_RF95_REG_14_RX_HEADER_CNT_VALUE_MSB 0x14
#define RH_RF95_REG_15_RX_HEADER_CNT_VALUE_LSB 0x15
#define RH_RF95_REG_16_RX_PACKET_CNT_VALUE_MSB 0x16
#define RH_RF95_REG_17_RX_PACKET_CNT_VALUE_LSB 0x17
#define RH_RF95_REG_18_MODEM_STAT 0x18
#define RH_RF95_REG_19_PKT_SNR_VALUE 0x19
#define RH_RF95_REG_1A_PKT_RSSI_VALUE 0x1a
#define RH_RF95_REG_1B_RSSI_VALUE 0x1b
#define RH_RF95_REG_1C_HOP_CHANNEL 0x1c
#define RH_RF95_REG_1D_MODEM_CONFIG1 0x1d
#define RH_RF95_REG_1E_MODEM_CONFIG2 0x1e
#define RH_RF95_REG_1F_SYMB_TIMEOUT_LSB 0x1f
#define RH_RF95_REG_20_PREAMBLE_MSB 0x20
#define RH_RF95_REG_21_PREAMBLE_LSB 0x21
#define RH_RF95_REG_22_PAYLOAD_LENGTH 0x22
#define RH_RF95_REG_23_MAX_PAYLOAD_LENGTH 0x23
#define RH_RF95_REG_24_HOP_PERIOD 0x24
#define RH_RF95_REG_25_FIFO_RX_BYTE_ADDR 0x25
#define RH_RF95_REG_26_MODEM_CONFIG3 0x26

#define RH_RF95_REG_40_DIO_MAPPING1 0x40
#define RH_RF95_REG_41_DIO_MAPPING2 0x41
#define RH_RF95_REG_42_VERSION 0x42

#define RH_RF95_REG_4B_TCXO 0x4b
#define RH_RF95_REG_4D_PA_DAC 0x4d
#define RH_RF95_REG_5B_FORMER_TEMP 0x5b
#define RH_RF95_REG_61_AGC_REF 0x61
#define RH_RF95_REG_62_AGC_THRESH1 0x62
#define RH_RF95_REG_63_AGC_THRESH2 0x63
#define RH_RF95_REG_64_AGC_THRESH3 0x64

// RH_RF95_REG_01_OP_MODE 0x01
#define RH_RF95_LONG_RANGE_MODE 0x80
#define RH_RF95_ACCESS_SHARED_REG 0x40
#define RH_RF95_MODE 0x07
#define RH_RF95_MODE_SLEEP 0x00
#define RH_RF95_MODE_STDBY 0x01
#define RH_RF95_MODE_FSTX 0x02
#define RH_RF95_MODE_TX 0x03
#define RH_RF95_MODE_FSRX 0x04
#define RH_RF95_MODE_RXCONTINUOUS 0x05
#define RH_RF95_MODE_RXSINGLE 0x06
#define RH_RF95_MODE_CAD 0x07

// RH_RF95_REG_09_PA_CONFIG 0x09
#define RH_RF95_PA_SELECT 0x80
#define RH_RF95_OUTPUT_POWER 0x0f

// RH_RF95_REG_0A_PA_RAMP 0x0a
#define RH_RF95_LOW_PN_TX_PLL_OFF 0x10
#define RH_RF95_PA_RAMP 0x0f
#define RH_RF95_PA_RAMP_3_4MS 0x00
#define RH_RF95_PA_RAMP_2MS 0x01
#define RH_RF95_PA_RAMP_1MS 0x02
#define RH_RF95_PA_RAMP_500US 0x03
#define RH_RF95_PA_RAMP_250US 0x0
#define RH_RF95_PA_RAMP_125US 0x05
#define RH_RF95_PA_RAMP_100US 0x06
#define RH_RF95_PA_RAMP_62US 0x07
#define RH_RF95_PA_RAMP_50US 0x08
#define RH_RF95_PA_RAMP_40US 0x09
#define RH_RF95_PA_RAMP_31US 0x0a
#define RH_RF95_PA_RAMP_25US 0x0b
#define RH_RF95_PA_RAMP_20US 0x0c
#define RH_RF95_PA_RAMP_15US 0x0d
#define RH_RF95_PA_RAMP_12US 0x0e
#define RH_RF95_PA_RAMP_10US 0x0f

// RH_RF95_REG_0B_OCP 0x0b
#define RH_RF95_OCP_ON 0x20
#define RH_RF95_OCP_TRIM 0x1f

// RH_RF95_REG_0C_LNA 0x0c
#define RH_RF95_LNA_GAIN 0xe0
#define RH_RF95_LNA_BOOST 0x03
#define RH_RF95_LNA_BOOST_DEFAULT 0x00
#define RH_RF95_LNA_BOOST_150PC 0x11

// RH_RF95_REG_11_IRQ_FLAGS_MASK 0x11
#define RH_RF95_RX_TIMEOUT_MASK 0x80
#define RH_RF95_RX_DONE_MASK 0x40
#define RH_RF95_PAYLOAD_CRC_ERROR_MASK 0x20
#define RH_RF95_VALID_HEADER_MASK 0x10
#define RH_RF95_TX_DONE_MASK 0x08
#define RH_RF95_CAD_DONE_MASK 0x04
#define RH_RF95_FHSS_CHANGE_CHANNEL_MASK 0x02
#define RH_RF95_CAD_DETECTED_MASK 0x01

// RH_RF95_REG_12_IRQ_FLAGS 0x12
#define RH_RF95_RX_TIMEOUT 0x80
#define RH_RF95_RX_DONE 0x40
#define RH_RF95_PAYLOAD_CRC_ERROR 0x20
#define RH_RF95_VALID_HEADER 0x10
#define RH_RF95_TX_DONE 0x08
#define RH_RF95_CAD_DONE 0x04
#define RH_RF95_FHSS_CHANGE_CHANNEL 0x02
#define RH_RF95_CAD_DETECTED 0x01

// RH_RF95_REG_18_MODEM_STAT 0x18
#define RH_RF95_RX_CODING_RATE 0xe0
#define RH_RF95_MODEM_STATUS_CLEAR 0x10
#define RH_RF95_MODEM_STATUS_HEADER_INFO_VALID 0x08
#define RH_RF95_MODEM_STATUS_RX_ONGOING 0x04
#define RH_RF95_MODEM_STATUS_SIGNAL_SYNCHRONIZED 0x02
#define RH_RF95_MODEM_STATUS_SIGNAL_DETECTED 0x01

// RH_RF95_REG_1C_HOP_CHANNEL 0x1c
#define RH_RF95_PLL_TIMEOUT 0x80
#define RH_RF95_RX_PAYLOAD_CRC_IS_ON 0x40
#define RH_RF95_FHSS_PRESENT_CHANNEL 0x3f

// RH_RF95_REG_1D_MODEM_CONFIG1 0x1d
#define RH_RF95_BW 0xc0
#define RH_RF95_BW_125KHZ 0x00
#define RH_RF95_BW_250KHZ 0x40
#define RH_RF95_BW_500KHZ 0x80
#define RH_RF95_BW_RESERVED 0xc0
#define RH_RF95_CODING_RATE 0x38
#define RH_RF95_CODING_RATE_4_5 0x00
#define RH_RF95_CODING_RATE_4_6 0x08
#define RH_RF95_CODING_RATE_4_7 0x10
#define RH_RF95_CODING_RATE_4_8 0x18
#define RH_RF95_IMPLICIT_HEADER_MODE_ON 0x04
#define RH_RF95_RX_PAYLOAD_CRC_ON 0x02
#define RH_RF95_LOW_DATA_RATE_OPTIMIZE 0x01

// RH_RF95_REG_1E_MODEM_CONFIG2 0x1e
#define RH_RF95_SPREADING_FACTOR 0xf0
#define RH_RF95_SPREADING_FACTOR_64CPS 0x60
#define RH_RF95_SPREADING_FACTOR_128CPS 0x70
#define RH_RF95_SPREADING_FACTOR_256CPS 0x80
#define RH_RF95_SPREADING_FACTOR_512CPS 0x90
#define RH_RF95_SPREADING_FACTOR_1024CPS 0xa0
#define RH_RF95_SPREADING_FACTOR_2048CPS 0xb0
#define RH_RF95_SPREADING_FACTOR_4096CPS 0xc0
#define RH_RF95_TX_CONTINUOUS_MOE 0x08
#define RH_RF95_AGC_AUTO_ON 0x04
#define RH_RF95_SYM_TIMEOUT_MSB 0x03

// RH_RF95_REG_4D_PA_DAC 0x4d
#define RH_RF95_PA_DAC_DISABLE 0x04
#define RH_RF95_PA_DAC_ENABLE 0x07

/////////////////////////////////////////////////////////////////////
/// \class RH_RF95 RH_RF95.h & lt; RH_RF95.h & gt;
/// \brief Driver to send and receive unaddressed, unreliable datagrams via a LoRa
/// capable radio transceiver.
///
/// For Semtech SX1276/77/78 and HopeRF RFM95/96/97/98 and other similar LoRa capable radios.
/// Based on http://www.hoperf.com/upload/rf/RFM95_96_97_98W.pdf
/// and http://www.hoperf.cn/upload/rfchip/RF96_97_98.pdf
/// and http://www.semtech.com/images/datasheet/LoraDesignGuide_STD.pdf
/// and http://www.semtech.com/images/datasheet/sx1276.pdf
/// FSK/GFSK/OOK modes are not (yet) supported.
///
/// Works with
/// - the excellent MiniWirelessLoRa from Anarduino http://www.anarduino.com/miniwireless
///
/// \par Overview
///
/// This class provides basic functions for sending and receiving unaddressed,
/// unreliable datagrams of arbitrary length to 251 octets per packet.
///
/// Manager classes may use this class to implement reliable, addressed datagrams and streams,
/// mesh routers, repeaters, translators etc.
///
/// Naturally, for any 2 radios to communicate that must be configured to use the same frequency and
/// modulation scheme.
///
/// This Driver provides an object-oriented interface for sending and receiving data messages with Hope-RF
/// RFM95/96/97/98(W) and compatible radio modules in LoRa mode.
///
/// The Hope-RF (http://www.hoperf.com) RFM95/96/97/98(W) is a low-cost ISM transceiver
/// chip. It supports FSK, GFSK, OOK over a wide range of frequencies and
/// programmable data rates, and it also supports the proprietary LoRA (Long Range) mode, which
/// is the only mode supported in this RadioHead driver.
///
/// This Driver provides functions for sending and receiving messages of up
/// to 251 octets on any frequency supported by the radio, in a range of
/// predefined Bandwidths, Spreading Factors and Coding Rates. Frequency can be set with
/// 61Hz precision to any frequency from 240.0MHz to 960.0MHz. Caution: most modules only support a more limited
/// range of frequencies due to antenna tuning.
///
/// Up to 2 RFM95/96/97/98(W) modules can be connected to an Arduino (3 on a Mega),
/// permitting the construction of translators and frequency changers, etc.
///
/// Support for other features such as transmitter power control etc is
/// also provided.
///
/// Tested on MinWirelessLoRa with arduino-1.0.5
/// on OpenSuSE 13.1
///
/// \par Packet Format
///
/// All messages sent and received by this RH_RF95 Driver conform to this packet format:
///
/// - LoRa mode:
/// - 8 symbol PREAMBLE
/// - Explicit header with header CRC (handled internally by the radio)
/// - 4 octets HEADER: (TO, FROM, ID, FLAGS)
/// - 0 to 251 octets DATA
/// - CRC (handled internally by the radio)
///
/// \par Connecting RFM95/96/97/98 to Arduino
///
/// We tested with Anarduino MiniWirelessLoRA, which is an Arduino Duemilanove compatible with a RFM96W
/// module on-board. Therefore it needs no connections other than the USB
/// programming connection and an antenna to make it work.
///
/// If you have a bare RFM95/96/97/98 that you want to connect to an Arduino, you
/// might use these connections (untested): CAUTION: you must use a 3.3V type
/// Arduino, otherwise you will also need voltage level shifters between the
/// Arduino and the RFM95. CAUTION, you must also ensure you connect an
/// antenna.
///
/// \code
/// Arduino RFM95/96/97/98
/// GND----------GND (ground in)
/// 3V3----------3.3V (3.3V in)
/// interrupt 0 pin D2-----------DIO0 (interrupt request out)
/// SS pin D10----------NSS (chip select in)
/// SCK pin D13----------SCK (SPI clock in)
/// MOSI pin D11----------MOSI (SPI Data in)
/// MISO pin D12----------MISO (SPI Data out)
/// \endcode
///
/// With these connections, you can then use the default constructor RH_RF95().
/// You can override the default settings for the SS pin and the interrupt in
/// the RH_RF95 constructor if you wish to connect the slave select SS to other
/// than the normal one for your Arduino (D10 for Diecimila, Uno etc and D53
/// for Mega) or the interrupt request to other than pin D2 (Caution,
/// different processors have different constraints as to the pins available
/// for interrupts).
///
/// It is possible to have 2 or more radios connected to one Arduino, provided
/// each radio has its own SS and interrupt line (SCK, SDI and SDO are common
/// to all radios)
///
/// Caution: on some Arduinos such as the Mega 2560, if you set the slave
/// select pin to be other than the usual SS pin (D53 on Mega 2560), you may
/// need to set the usual SS pin to be an output to force the Arduino into SPI
/// master mode.
///
/// Caution: Power supply requirements of the RFM module may be relevant in some circumstances:
/// RFM95/96/97/98 modules are capable of pulling 120mA+ at full power, where Arduino's 3.3V line can
/// give 50mA. You may need to make provision for alternate power supply for
/// the RFM module, especially if you wish to use full transmit power, and/or you have
/// other shields demanding power. Inadequate power for the RFM is likely to cause symptoms such as:
/// - reset's/bootups terminate with " init failed " messages
/// - random termination of communication after 5-30 packets sent/received
/// - " fake ok " state, where initialization passes fluently, but communication doesn't happen
/// - shields hang Arduino boards, especially during the flashing
///
/// \par Interrupts
///
/// The RH_RF95 driver uses interrupts to react to events in the RFM module,
/// such as the reception of a new packet, or the completion of transmission
/// of a packet. The RH_RF95 driver interrupt service routine reads status from
/// and writes data to the the RFM module via the SPI interface. It is very
/// important therefore, that if you are using the RH_RF95 driver with another
/// SPI based deviced, that you disable interrupts while you transfer data to
/// and from that other device. Use cli() to disable interrupts and sei() to
/// reenable them.
///
/// \par Memory
///
/// The RH_RF95 driver requires non-trivial amounts of memory. The sample
/// programs all compile to about 8kbytes each, which will fit in the
/// flash proram memory of most Arduinos. However, the RAM requirements are
/// more critical. Therefore, you should be vary sparing with RAM use in
/// programs that use the RH_RF95 driver.
///
/// It is often hard to accurately identify when you are hitting RAM limits on Arduino.
/// The symptoms can include:
/// - Mysterious crashes and restarts
/// - Changes in behaviour when seemingly unrelated changes are made (such as adding print() statements)
/// - Hanging
/// - Output from Serial.print() not appearing
///
/// \par Range
///
/// We have made some simple range tests under the following conditions:
/// - rf95_client base station connected to a VHF discone antenna at 8m height above ground
/// - rf95_server mobile connected to 17.3cm 1/4 wavelength antenna at 1m height, no ground plane.
/// - Both configured for 13dBm, 434MHz, Bw = 125 kHz, Cr = 4/8, Sf = 4096chips/symbol, CRC on. Slow+long range
/// - Minimum reported RSSI seen for successful comms was about -91
/// - Range over flat ground through heavy trees and vegetation approx 2km.
/// - At 20dBm (100mW) otherwise identical conditions approx 3km.
/// - At 20dBm, along salt water flat sandy beach, 3.2km.
///
/// It should be noted that at this data rate, a 12 octet message takes 2 seconds to transmit.
///
/// At 20dBm (100mW) with Bw = 125 kHz, Cr = 4/5, Sf = 128chips/symbol, CRC on.
/// (Default medium range) in the conditions described above.
/// - Range over flat ground through heavy trees and vegetation approx 2km.
///
/// \par Transmitter Power
///
/// You can control the transmitter power on the RF transceiver
/// with the RH_RF95::setTxPower() function. The argument can be any of
/// +5 to +23
/// The default is 13. Eg:
/// \code
/// driver.setTxPower(10);
/// \endcode
///
/// We have made some actual power measurements against
/// programmed power for Anarduino MiniWirelessLoRa (which has RFM96W-433Mhz installed)
/// - MiniWirelessLoRa RFM96W-433Mhz, USB power
/// - 30cm RG316 soldered direct to RFM96W module ANT and GND
/// - SMA connector
/// - 12db attenuator
/// - SMA connector
/// - MiniKits AD8307 HF/VHF Power Head (calibrated against Rohde & Schwartz 806.2020 test set)
/// - Tektronix TDS220 scope to measure the Vout from power head
/// \code
/// Program power Measured Power
/// dBm dBm
/// 5 5
/// 7 7
/// 9 8
/// 11 11
/// 13 13
/// 15 15
/// 17 16
/// 19 18
/// 20 20
/// 21 21
/// 22 22
/// 23 23
/// \endcode
/// (Caution: we dont claim laboratory accuracy for these measurements)
/// You would not expect to get anywhere near these powers to air with a simple 1/4 wavelength wire antenna.
class RH_RF95 : public RHSPIDriver
{
public:
/// \brief Defines register values for a set of modem configuration registers
///
/// Defines register values for a set of modem configuration registers
/// that can be passed to setModemRegisters() if none of the choices in
/// ModemConfigChoice suit your need setModemRegisters() writes the
/// register values from this structure to the appropriate registers
/// to set the desired spreading factor, coding rate and bandwidth
typedef struct
{
uint8_t reg_1d; /// & lt; Value for register RH_RF95_REG_1D_MODEM_CONFIG1
uint8_t reg_1e; /// & lt; Value for register RH_RF95_REG_1E_MODEM_CONFIG2
uint8_t reg_26; /// & lt; Value for register RH_RF95_REG_26_MODEM_CONFIG3
} ModemConfig;

/// Choices for setModemConfig() for a selected subset of common
/// data rates. If you need another configuration,
/// determine the necessary settings and call setModemRegisters() with your
/// desired settings. It might be helpful to use the LoRa calculator mentioned in
/// http://www.semtech.com/images/datasheet/LoraDesignGuide_STD.pdf
/// These are indexes into MODEM_CONFIG_TABLE. We strongly recommend you use these symbolic
/// definitions and not their integer equivalents: its possible that new values will be
/// introduced in later versions (though we will try to avoid it).
typedef enum
{
Bw125Cr45Sf128 = 0, /// & lt; Bw = 125 kHz, Cr = 4/5, Sf = 128chips/symbol, CRC on. Default medium range
Bw500Cr45Sf128, /// & lt; Bw = 500 kHz, Cr = 4/5, Sf = 128chips/symbol, CRC on. Fast+short range
Bw31_25Cr48Sf512, /// & lt; Bw = 31.25 kHz, Cr = 4/8, Sf = 512chips/symbol, CRC on. Slow+long range
Bw125Cr48Sf4096, /// & lt; Bw = 125 kHz, Cr = 4/8, Sf = 4096chips/symbol, CRC on. Slow+long range
} ModemConfigChoice;

/// Constructor. You can have multiple instances, but each instance must have its own
/// interrupt and slave select pin. After constructing, you must call init() to initialise the interface
/// and the radio module. A maximum of 3 instances can co-exist on one processor, provided there are sufficient
/// distinct interrupt lines, one for each instance.
/// \param[in] slaveSelectPin the Arduino pin number of the output to use to select the RH_RF22 before
/// accessing it. Defaults to the normal SS pin for your Arduino (D10 for Diecimila, Uno etc, D53 for Mega, D10 for Maple)
/// \param[in] interruptPin The interrupt Pin number that is connected to the RFM DIO0 interrupt line.
/// Defaults to pin 2, as required by Anarduino MinWirelessLoRa module.
/// Caution: You must specify an interrupt capable pin.
/// On many Arduino boards, there are limitations as to which pins may be used as interrupts.
/// On Leonardo pins 0, 1, 2 or 3. On Mega2560 pins 2, 3, 18, 19, 20, 21. On Due and Teensy, any digital pin.
/// On other Arduinos pins 2 or 3.
/// See http://arduino.cc/en/Reference/attachInterrupt for more details.
/// On Chipkit Uno32, pins 38, 2, 7, 8, 35.
/// On other boards, any digital pin may be used.
/// \param[in] spi Pointer to the SPI interface object to use.
/// Defaults to the standard Arduino hardware SPI interface
RH_RF95(uint8_t slaveSelectPin = SS, uint8_t interruptPin = 2, RHGenericSPI & spi = hardware_spi);

/// Initialise the Driver transport hardware and software.
/// Make sure the Driver is properly configured before calling init().
/// \return true if initialisation succeeded.
virtual bool init();

/// Prints the value of all chip registers
/// to the Serial device if RH_HAVE_SERIAL is defined for the current platform
/// For debugging purposes only.
/// \return true on success
bool printRegisters();

/// Sets all the registered required to configure the data modem in the RF95/96/97/98, including the bandwidth,
/// spreading factor etc. You can use this to configure the modem with custom configurations if none of the
/// canned configurations in ModemConfigChoice suit you.
/// \param[in] config A ModemConfig structure containing values for the modem configuration registers.
void setModemRegisters(const ModemConfig* config);

/// Select one of the predefined modem configurations. If you need a modem configuration not provided
/// here, use setModemRegisters() with your own ModemConfig.
/// \param[in] index The configuration choice.
/// \return true if index is a valid choice.
bool setModemConfig(ModemConfigChoice index);

/// Tests whether a new message is available
/// from the Driver.
/// On most drivers, this will also put the Driver into RHModeRx mode until
/// a message is actually received by the transport, when it wil be returned to RHModeIdle.
/// This can be called multiple times in a timeout loop
/// \return true if a new, complete, error-free uncollected message is available to be retreived by recv()
virtual bool available();

/// Turns the receiver on if it not already on.
/// If there is a valid message available, copy it to buf and return true
/// else return false.
/// If a message is copied, *len is set to the length (Caution, 0 length messages are permitted).
/// You should be sure to call this function frequently enough to not miss any messages
/// It is recommended that you call it in your main loop.
/// \param[in] buf Location to copy the received message
/// \param[in,out] len Pointer to available space in buf. Set to the actual number of octets copied.
/// \return true if a valid message was copied to buf
virtual bool recv(uint8_t* buf, uint8_t* len);

/// Waits until any previous transmit packet is finished being transmitted with waitPacketSent().
/// Then loads a message into the transmitter and starts the transmitter. Note that a message length
/// of 0 is permitted.
/// \param[in] data Array of data to be sent
/// \param[in] len Number of bytes of data to send
/// \return true if the message length was valid and it was correctly queued for transmit
virtual bool send(const uint8_t* data, uint8_t len);

/// Sets the length of the preamble
/// in bytes.
/// Caution: this should be set to the same
/// value on all nodes in your network. Default is 8.
/// Sets the message preamble length in RH_RF95_REG_??_PREAMBLE_?SB
/// \param[in] bytes Preamble length in bytes.
void setPreambleLength(uint16_t bytes);

/// Returns the maximum message length
/// available in this Driver.
/// \return The maximum legal message length
virtual uint8_t maxMessageLength();

/// Sets the transmitter and receiver
/// centre frequency
/// \param[in] centre Frequency in MHz. 137.0 to 1020.0. Caution: RFM95/96/97/98 comes in several
/// different frequency ranges, and setting a frequency outside that range of your radio will probably not work
/// \return true if the selected frquency centre is within range
bool setFrequency(float centre);

/// If current mode is Rx or Tx changes it to Idle. If the transmitter or receiver is running,
/// disables them.
void setModeIdle();

/// If current mode is Tx or Idle, changes it to Rx.
/// Starts the receiver in the RF95/96/97/98.
void setModeRx();

/// If current mode is Rx or Idle, changes it to Rx. F
/// Starts the transmitter in the RF95/96/97/98.
void setModeTx();

/// Sets the transmitter power output level.
/// Be a good neighbour and set the lowest power level you need.
/// Caution: legal power limits may apply in certain countries. At powers above 20dBm, PA_DAC is enabled.
/// After init(), the power will be set to 13dBm.
/// \param[in] power Transmitter power level in dBm. For RFM95/96/97/98 LORA, valid values are from +5 to +23
void setTxPower(int8_t power);

/// Sets the radio into low-power sleep mode.
/// If successful, the transport will stay in sleep mode until woken by
/// changing mode it idle, transmit or receive (eg by calling send(), recv(), available() etc)
/// Caution: there is a time penalty as the radio takes a finite time to wake from sleep mode.
/// \return true if sleep mode was successfully entered.
virtual bool sleep();

protected:
/// This is a low level function to handle the interrupts for one instance of RH_RF95.
/// Called automatically by isr*()
/// Should not need to be called by user code.
void handleInterrupt();

/// Examine the revceive buffer to determine whether the message is for this node
void validateRxBuf();

/// Clear our local receive buffer
void clearRxBuf();

private:
/// Low level interrupt service routine for device connected to interrupt 0
static void isr0();

/// Low level interrupt service routine for device connected to interrupt 1
static void isr1();

/// Low level interrupt service routine for device connected to interrupt 1
static void isr2();

/// Array of instances connected to interrupts 0 and 1
static RH_RF95* _deviceForInterrupt[];

/// Index of next interrupt number to use in _deviceForInterrupt
static uint8_t _interruptCount;

/// The configured interrupt pin connected to this instance
uint8_t _interruptPin;

/// The index into _deviceForInterrupt[] for this device (if an interrupt is already allocated)
/// else 0xff
uint8_t _myInterruptIndex;

/// Number of octets in the buffer
volatile uint8_t _bufLen;

/// The receiver/transmitter buffer
uint8_t _buf[RH_RF95_MAX_PAYLOAD_LEN];

/// True when there is a valid message in the buffer
volatile bool _rxBufValid;
};

/// @example rf95_client.pde
/// @example rf95_server.pde
/// @example rf95_reliable_datagram_client.pde
/// @example rf95_reliable_datagram_server.pde

#endif


RadioHead-1.41.zip > atomic.h

/*
* This is port of Dean Camera's ATOMIC_BLOCK macros for AVR to ARM Cortex M3
* v1.0
* Mark Pendrith, Nov 27, 2012.
*
* From Mark:
* & gt; When I ported the macros I emailed Dean to ask what attribution would be
* & gt; appropriate, and here is his response:
* & gt;
* & gt; & gt; Mark,
* & gt; & gt; I think it's great that you've ported the macros; consider them
* & gt; & gt; public domain, to do with whatever you wish. I hope you find them & gt; useful .
* & gt; & gt;
* & gt; & gt; Cheers!
* & gt; & gt; - Dean
*/

#ifdef __arm__
#ifndef _CORTEX_M3_ATOMIC_H_
#define _CORTEX_M3_ATOMIC_H_

static __inline__ uint32_t __get_primask(void) \
{ uint32_t primask = 0; \
__asm__ volatile ( " MRS %[result], PRIMASK\n\t " :[result] " =r " (primask)::); \
return primask; } // returns 0 if interrupts enabled, 1 if disabled

static __inline__ void __set_primask(uint32_t setval) \
{ __asm__ volatile ( " MSR PRIMASK, %[value]\n\t " " dmb\n\t " " dsb\n\t " " isb\n\t " ::[value] " r " (setval):);
__asm__ volatile ( " " ::: " memory " );}

static __inline__ uint32_t __iSeiRetVal(void) \
{ __asm__ volatile ( " CPSIE i\n\t " " dmb\n\t " " dsb\n\t " " isb\n\t " ); \
__asm__ volatile ( " " ::: " memory " ); return 1; }

static __inline__ uint32_t __iCliRetVal(void) \
{ __asm__ volatile ( " CPSID i\n\t " " dmb\n\t " " dsb\n\t " " isb\n\t " ); \
__asm__ volatile ( " " ::: " memory " ); return 1; }

static __inline__ void __iSeiParam(const uint32_t *__s) \
{ __asm__ volatile ( " CPSIE i\n\t " " dmb\n\t " " dsb\n\t " " isb\n\t " ); \
__asm__ volatile ( " " ::: " memory " ); (void)__s; }

static __inline__ void __iCliParam(const uint32_t *__s) \
{ __asm__ volatile ( " CPSID i\n\t " " dmb\n\t " " dsb\n\t " " isb\n\t " ); \
__asm__ volatile ( " " ::: " memory " ); (void)__s; }

static __inline__ void __iRestore(const uint32_t *__s) \
{ __set_primask(*__s); __asm__ volatile ( " dmb\n\t " " dsb\n\t " " isb\n\t " ); \
__asm__ volatile ( " " ::: " memory " ); }


#define ATOMIC_BLOCK(type) \
for ( type, __ToDo = __iCliRetVal(); __ToDo ; __ToDo = 0 )

#define ATOMIC_RESTORESTATE \
uint32_t primask_save __attribute__((__cleanup__(__iRestore))) = __get_primask()

#define ATOMIC_FORCEON \
uint32_t primask_save __attribute__((__cleanup__(__iSeiParam))) = 0

#define NONATOMIC_BLOCK(type) \
for ( type, __ToDo = __iSeiRetVal(); __ToDo ; __ToDo = 0 )

#define NONATOMIC_RESTORESTATE \
uint32_t primask_save __attribute__((__cleanup__(__iRestore))) = __get_primask()

#define NONATOMIC_FORCEOFF \
uint32_t primask_save __attribute__((__cleanup__(__iCliParam))) = 0

#endif
#endif


RadioHead-1.41.zip > RHGenericDriver.cpp

// RHGenericDriver.cpp
//
// Copyright (C) 2014 Mike McCauley
// $Id: RHGenericDriver.cpp,v 1.18 2015/01/02 21:38:24 mikem Exp $

#include & lt; RHGenericDriver.h & gt;

RHGenericDriver::RHGenericDriver()
:
_mode(RHModeInitialising),
_thisAddress(RH_BROADCAST_ADDRESS),
_txHeaderTo(RH_BROADCAST_ADDRESS),
_txHeaderFrom(RH_BROADCAST_ADDRESS),
_txHeaderId(0),
_txHeaderFlags(0),
_rxBad(0),
_rxGood(0),
_txGood(0)
{
}

bool RHGenericDriver::init()
{
return true;
}

// Blocks until a valid message is received
void RHGenericDriver::waitAvailable()
{
while (!available())
YIELD;
}

// Blocks until a valid message is received or timeout expires
// Return true if there is a message available
// Works correctly even on millis() rollover
bool RHGenericDriver::waitAvailableTimeout(uint16_t timeout)
{
unsigned long starttime = millis();
while ((millis() - starttime) & lt; timeout)
{
if (available())
return true;
YIELD;
}
return false;
}

bool RHGenericDriver::waitPacketSent()
{
while (_mode == RHModeTx)
YIELD; // Wait for any previous transmit to finish
return true;
}

bool RHGenericDriver::waitPacketSent(uint16_t timeout)
{
unsigned long starttime = millis();
while ((millis() - starttime) & lt; timeout)
{
if (_mode != RHModeTx) // Any previous transmit finished?
return true;
YIELD;
}
return false;
}

void RHGenericDriver::setPromiscuous(bool promiscuous)
{
_promiscuous = promiscuous;
}

void RHGenericDriver::setThisAddress(uint8_t address)
{
_thisAddress = address;
}

void RHGenericDriver::setHeaderTo(uint8_t to)
{
_txHeaderTo = to;
}

void RHGenericDriver::setHeaderFrom(uint8_t from)
{
_txHeaderFrom = from;
}

void RHGenericDriver::setHeaderId(uint8_t id)
{
_txHeaderId = id;
}

void RHGenericDriver::setHeaderFlags(uint8_t set, uint8_t clear)
{
_txHeaderFlags & = ~clear;
_txHeaderFlags |= set;
}

uint8_t RHGenericDriver::headerTo()
{
return _rxHeaderTo;
}

uint8_t RHGenericDriver::headerFrom()
{
return _rxHeaderFrom;
}

uint8_t RHGenericDriver::headerId()
{
return _rxHeaderId;
}

uint8_t RHGenericDriver::headerFlags()
{
return _rxHeaderFlags;
}

int8_t RHGenericDriver::lastRssi()
{
return _lastRssi;
}

RHGenericDriver::RHMode RHGenericDriver::mode()
{
return _mode;
}

void RHGenericDriver::setMode(RHMode mode)
{
_mode = mode;
}

bool RHGenericDriver::sleep()
{
return false;
}

// Diagnostic help
void RHGenericDriver::printBuffer(const char* prompt, const uint8_t* buf, uint8_t len)
{
uint8_t i;

#ifdef RH_HAVE_SERIAL
Serial.println(prompt);
for (i = 0; i & lt; len; i++)
{
if (i % 16 == 15)
Serial.println(buf[i], HEX);
else
{
Serial.print(buf[i], HEX);
Serial.print(' ');
}
}
Serial.println( " " );
#endif
}

uint16_t RHGenericDriver::rxBad()
{
return _rxBad;
}

uint16_t RHGenericDriver::rxGood()
{
return _rxGood;
}

uint16_t RHGenericDriver::txGood()
{
return _txGood;
}

#if (RH_PLATFORM == RH_PLATFORM_ARDUINO) & & defined(RH_PLATFORM_ATTINY)
// Tinycore does not have __cxa_pure_virtual, so without this we
// get linking complaints from the default code generated for pure virtual functions
extern " C " void __cxa_pure_virtual()
{
while (1);
}
#endif


RadioHead-1.41.zip > RHMesh.cpp

// RHMesh.cpp
//
// Define addressed datagram
//
// Part of the Arduino RH library for operating with HopeRF RH compatible transceivers
// (see http://www.hoperf.com)
// RHDatagram will be received only by the addressed node or all nodes within range if the
// to address is RH_BROADCAST_ADDRESS
//
// Author: Mike McCauley (mikem@airspayce.com)
// Copyright (C) 2011 Mike McCauley
// $Id: RHMesh.cpp,v 1.7 2014/08/10 20:55:17 mikem Exp $

#include & lt; RHMesh.h & gt;

uint8_t RHMesh::_tmpMessage[RH_ROUTER_MAX_MESSAGE_LEN];

////////////////////////////////////////////////////////////////////
// Constructors
RHMesh::RHMesh(RHGenericDriver & driver, uint8_t thisAddress)
: RHRouter(driver, thisAddress)
{
}

////////////////////////////////////////////////////////////////////
// Public methods

////////////////////////////////////////////////////////////////////
// Discovers a route to the destination (if necessary), sends and
// waits for delivery to the next hop (but not for delivery to the final destination)
uint8_t RHMesh::sendtoWait(uint8_t* buf, uint8_t len, uint8_t address, uint8_t flags)
{
if (len & gt; RH_MESH_MAX_MESSAGE_LEN)
return RH_ROUTER_ERROR_INVALID_LENGTH;

if (address != RH_BROADCAST_ADDRESS)
{
RoutingTableEntry* route = getRouteTo(address);
if (!route & & !doArp(address))
return RH_ROUTER_ERROR_NO_ROUTE;
}

// Now have a route. Contruct an application layer message and send it via that route
MeshApplicationMessage* a = (MeshApplicationMessage*) & _tmpMessage;
a- & gt; header.msgType = RH_MESH_MESSAGE_TYPE_APPLICATION;
memcpy(a- & gt; data, buf, len);
return RHRouter::sendtoWait(_tmpMessage, sizeof(RHMesh::MeshMessageHeader) + len, address, flags);
}

////////////////////////////////////////////////////////////////////
bool RHMesh::doArp(uint8_t address)
{
// Need to discover a route
// Broadcast a route discovery message with nothing in it
MeshRouteDiscoveryMessage* p = (MeshRouteDiscoveryMessage*) & _tmpMessage;
p- & gt; header.msgType = RH_MESH_MESSAGE_TYPE_ROUTE_DISCOVERY_REQUEST;
p- & gt; destlen = 1;
p- & gt; dest = address; // Who we are looking for
uint8_t error = RHRouter::sendtoWait((uint8_t*)p, sizeof(RHMesh::MeshMessageHeader) + 2, RH_BROADCAST_ADDRESS);
if (error != RH_ROUTER_ERROR_NONE)
return false;

// Wait for a reply, which will be unicast back to us
// It will contain the complete route to the destination
uint8_t messageLen = sizeof(_tmpMessage);
// FIXME: timeout should be configurable
unsigned long starttime = millis();
while ((millis() - starttime) & lt; 4000)
{
if (RHRouter::recvfromAck(_tmpMessage, & messageLen))
{
if ( messageLen & gt; 1
& & p- & gt; header.msgType == RH_MESH_MESSAGE_TYPE_ROUTE_DISCOVERY_RESPONSE)
{
// Got a reply, now add the next hop to the dest to the routing table
// The first hop taken is the first octet
addRouteTo(address, headerFrom());
return true;
}
}
YIELD;
}
return false;
}

////////////////////////////////////////////////////////////////////
// Called by RHRouter::recvfromAck whenever a message goes past
void RHMesh::peekAtMessage(RoutedMessage* message, uint8_t messageLen)
{
MeshMessageHeader* m = (MeshMessageHeader*)message- & gt; data;
if ( messageLen & gt; 1
& & m- & gt; msgType == RH_MESH_MESSAGE_TYPE_ROUTE_DISCOVERY_RESPONSE)
{
// This is a unicast RH_MESH_MESSAGE_TYPE_ROUTE_DISCOVERY_RESPONSE messages
// being routed back to the originator here. Want to scrape some routing data out of the response
// We can find the routes to all the nodes between here and the responding node
MeshRouteDiscoveryMessage* d = (MeshRouteDiscoveryMessage*)message- & gt; data;
addRouteTo(d- & gt; dest, headerFrom());
uint8_t numRoutes = messageLen - sizeof(RoutedMessageHeader) - sizeof(MeshMessageHeader) - 2;
uint8_t i;
// Find us in the list of nodes that were traversed to get to the responding node
for (i = 0; i & lt; numRoutes; i++)
if (d- & gt; route[i] == _thisAddress)
break;
i++;
while (i++ & lt; numRoutes)
addRouteTo(d- & gt; route[i], headerFrom());
}
else if ( messageLen & gt; 1
& & m- & gt; msgType == RH_MESH_MESSAGE_TYPE_ROUTE_FAILURE)
{
MeshRouteFailureMessage* d = (MeshRouteFailureMessage*)message- & gt; data;
deleteRouteTo(d- & gt; dest);
}
}

////////////////////////////////////////////////////////////////////
// This is called when a message is to be delivered to the next hop
uint8_t RHMesh::route(RoutedMessage* message, uint8_t messageLen)
{
uint8_t from = headerFrom(); // Might get clobbered during call to superclass route()
uint8_t ret = RHRouter::route(message, messageLen);
if ( ret == RH_ROUTER_ERROR_NO_ROUTE
|| ret == RH_ROUTER_ERROR_UNABLE_TO_DELIVER)
{
// Cant deliver to the next hop. Delete the route
deleteRouteTo(message- & gt; header.dest);
if (message- & gt; header.source != _thisAddress)
{
// This is being proxied, so tell the originator about it
MeshRouteFailureMessage* p = (MeshRouteFailureMessage*) & _tmpMessage;
p- & gt; header.msgType = RH_MESH_MESSAGE_TYPE_ROUTE_FAILURE;
p- & gt; dest = message- & gt; header.dest; // Who you were trying to deliver to
// Make sure there is a route back towards whoever sent the original message
addRouteTo(message- & gt; header.source, from);
ret = RHRouter::sendtoWait((uint8_t*)p, sizeof(RHMesh::MeshMessageHeader) + 1, message- & gt; header.source);
}
}
return ret;
}

////////////////////////////////////////////////////////////////////
// Subclasses may want to override
bool RHMesh::isPhysicalAddress(uint8_t* address, uint8_t addresslen)
{
// Can only handle physical addresses 1 octet long, which is the physical node address
return addresslen == 1 & & address[0] == _thisAddress;
}

////////////////////////////////////////////////////////////////////
bool RHMesh::recvfromAck(uint8_t* buf, uint8_t* len, uint8_t* source, uint8_t* dest, uint8_t* id, uint8_t* flags)
{
uint8_t tmpMessageLen = sizeof(_tmpMessage);
uint8_t _source;
uint8_t _dest;
uint8_t _id;
uint8_t _flags;
if (RHRouter::recvfromAck(_tmpMessage, & tmpMessageLen, & _source, & _dest, & _id, & _flags))
{
MeshMessageHeader* p = (MeshMessageHeader*) & _tmpMessage;

if ( tmpMessageLen & gt; = 1
& & p- & gt; msgType == RH_MESH_MESSAGE_TYPE_APPLICATION)
{
MeshApplicationMessage* a = (MeshApplicationMessage*)p;
// Handle application layer messages, presumably for our caller
if (source) *source = _source;
if (dest) *dest = _dest;
if (id) *id = _id;
if (flags) *flags = _flags;
uint8_t msgLen = tmpMessageLen - sizeof(MeshMessageHeader);
if (*len & gt; msgLen)
*len = msgLen;
memcpy(buf, a- & gt; data, *len);

return true;
}
else if ( _dest == RH_BROADCAST_ADDRESS
& & tmpMessageLen & gt; 1
& & p- & gt; msgType == RH_MESH_MESSAGE_TYPE_ROUTE_DISCOVERY_REQUEST)
{
MeshRouteDiscoveryMessage* d = (MeshRouteDiscoveryMessage*)p;
// Handle Route discovery requests
// Message is an array of node addresses the route request has already passed through
// If it originally came from us, ignore it
if (_source == _thisAddress)
return false;

uint8_t numRoutes = tmpMessageLen - sizeof(MeshMessageHeader) - 2;
uint8_t i;
// Are we already mentioned?
for (i = 0; i & lt; numRoutes; i++)
if (d- & gt; route[i] == _thisAddress)
return false; // Already been through us. Discard

// Hasnt been past us yet, record routes back to the earlier nodes
addRouteTo(_source, headerFrom()); // The originator
for (i = 0; i & lt; numRoutes; i++)
addRouteTo(d- & gt; route[i], headerFrom());
if (isPhysicalAddress( & d- & gt; dest, d- & gt; destlen))
{
// This route discovery is for us. Unicast the whole route back to the originator
// as a RH_MESH_MESSAGE_TYPE_ROUTE_DISCOVERY_RESPONSE
// We are certain to have a route there, becuase we just got it
d- & gt; header.msgType = RH_MESH_MESSAGE_TYPE_ROUTE_DISCOVERY_RESPONSE;
RHRouter::sendtoWait((uint8_t*)d, tmpMessageLen, _source);
}
else if (i & lt; _max_hops)
{
// Its for someone else, rebroadcast it, after adding ourselves to the list
d- & gt; route[numRoutes] = _thisAddress;
tmpMessageLen++;
// Have to impersonate the source
// REVISIT: if this fails what can we do?
RHRouter::sendtoFromSourceWait(_tmpMessage, tmpMessageLen, RH_BROADCAST_ADDRESS, _source);
}
}
}
return false;
}

////////////////////////////////////////////////////////////////////
bool RHMesh::recvfromAckTimeout(uint8_t* buf, uint8_t* len, uint16_t timeout, uint8_t* from, uint8_t* to, uint8_t* id, uint8_t* flags)
{
unsigned long starttime = millis();
while ((millis() - starttime) & lt; timeout)
{
if (recvfromAck(buf, len, from, to, id, flags))
return true;
YIELD;
}
return false;
}


RadioHead-1.41.zip > RHGenericSPI.cpp

// RHGenericSPI.cpp
// Author: Mike McCauley (mikem@airspayce.com)
// Copyright (C) 2011 Mike McCauley
// Contributed by Joanna Rutkowska
// $Id: RHGenericSPI.cpp,v 1.2 2014/04/12 05:26:05 mikem Exp $

#include & lt; RHGenericSPI.h & gt;

RHGenericSPI::RHGenericSPI(Frequency frequency, BitOrder bitOrder, DataMode dataMode)
:
_frequency(frequency),
_bitOrder(bitOrder),
_dataMode(dataMode)
{
}

void RHGenericSPI::setBitOrder(BitOrder bitOrder)
{
_bitOrder = bitOrder;
}

void RHGenericSPI::setDataMode(DataMode dataMode)
{
_dataMode = dataMode;
}

void RHGenericSPI::setFrequency(Frequency frequency)
{
_frequency = frequency;
}


RadioHead-1.41.zip > RHSoftwareSPI.h

// SoftwareSPI.h
// Author: Chris Lapa (chris@lapa.com.au)
// Copyright (C) 2014 Chris Lapa
// Contributed by Chris Lapa

#ifndef RHSoftwareSPI_h
#define RHSoftwareSPI_h

#include & lt; RHGenericSPI.h & gt;

/////////////////////////////////////////////////////////////////////
/// \class RHSoftwareSPI RHSoftwareSPI.h & lt; RHSoftwareSPI.h & gt;
/// \brief Encapsulate a software SPI interface
///
/// This concrete subclass of RHGenericSPI enapsulates a bit-banged software SPI interface.
/// Caution: this software SPI interface will be much slower than hardware SPI on most
/// platforms.
///
/// \par Usage
///
/// Usage varies slightly depending on what driver you are using.
///
/// For RF22, for example:
/// \code
/// #include & lt; RHSoftwareSPI.h & gt;
/// RHSoftwareSPI spi;
/// RH_RF22 driver(SS, 2, spi);
/// RHReliableDatagram(driver, CLIENT_ADDRESS);
/// void setup()
/// {
/// spi.setPins(6, 5, 7); // Or whatever SPI pins you need
/// ....
/// }
/// \endcode
class RHSoftwareSPI : public RHGenericSPI
{
public:

/// Constructor
/// Creates an instance of a bit-banged software SPI interface.
/// Sets the SPI pins to the defaults of
/// MISO = 12, MOSI = 11, SCK = 13. If you need other assigments, call setPins() before
/// calling manager.init() or driver.init().
/// \param[in] frequency One of RHGenericSPI::Frequency to select the SPI bus frequency. The frequency
/// is mapped to the closest available bus frequency on the platform. CAUTION: the achieved
/// frequency will almost certainly be very much slower on most platforms. eg on Arduino Uno, the
/// the clock rate is likely to be at best around 46kHz.
/// \param[in] bitOrder Select the SPI bus bit order, one of RHGenericSPI::BitOrderMSBFirst or
/// RHGenericSPI::BitOrderLSBFirst.
/// \param[in] dataMode Selects the SPI bus data mode. One of RHGenericSPI::DataMode
RHSoftwareSPI(Frequency frequency = Frequency1MHz, BitOrder bitOrder = BitOrderMSBFirst, DataMode dataMode = DataMode0);

/// Transfer a single octet to and from the SPI interface
/// \param[in] data The octet to send
/// \return The octet read from SPI while the data octet was sent.
uint8_t transfer(uint8_t data);

/// Initialise the software SPI library
/// Call this after configuring the SPI interface and before using it to transfer data.
/// Initializes the SPI bus by setting SCK, MOSI, and SS to outputs, pulling SCK and MOSI low, and SS high.
void begin();

/// Disables the SPI bus usually, in this case
/// there is no hardware controller to disable.
void end();

/// Sets the pins used by this SoftwareSPIClass instance.
/// The defaults are: MISO = 12, MOSI = 11, SCK = 13.
/// \param[in] miso master in slave out pin used
/// \param[in] mosi master out slave in pin used
/// \param[in] sck clock pin used
void setPins(uint8_t miso = 12, uint8_t mosi = 11, uint8_t sck = 13);

private:

/// Delay routine for bus timing.
void delayPeriod();

private:
uint8_t _miso;
uint8_t _mosi;
uint8_t _sck;
uint8_t _bitOrder;
uint8_t _delayCounts;
uint8_t _clockPolarity;
uint8_t _clockPhase;
};

#endif


RadioHead-1.41.zip > RHReliableDatagram.h

// RHReliableDatagram.h
//
// Author: Mike McCauley (mikem@airspayce.com)
// Copyright (C) 2011 Mike McCauley
// $Id: RHReliableDatagram.h,v 1.15 2015/01/02 21:38:24 mikem Exp $

#ifndef RHReliableDatagram_h
#define RHReliableDatagram_h

#include & lt; RHDatagram.h & gt;

// The acknowledgement bit in the FLAGS
// The top 4 bits of the flags are reserved for RadioHead. The lower 4 bits are reserved
// for application layer use.
#define RH_FLAGS_ACK 0x80

/// the default retry timeout in milliseconds
#define RH_DEFAULT_TIMEOUT 200

/// The default number of retries
#define RH_DEFAULT_RETRIES 3

/////////////////////////////////////////////////////////////////////
/// \class RHReliableDatagram RHReliableDatagram.h & lt; RHReliableDatagram.h & gt;
/// \brief RHDatagram subclass for sending addressed, acknowledged, retransmitted datagrams.
///
/// Manager class that extends RHDatagram to define addressed, reliable datagrams with acknowledgement and retransmission.
/// Based on RHDatagram, adds flags and sequence numbers. RHReliableDatagram is reliable in the sense
/// that messages are acknowledged by the recipient, and unacknowledged messages are retransmitted until acknowledged or the
/// retries are exhausted.
/// When addressed messages are sent (by sendtoWait()), it will wait for an ack, and retransmit
/// after timeout until an ack is received or retries are exhausted.
/// When addressed messages are collected by the application (by recvfromAck()),
/// an acknowledgement is automatically sent to the sender.
///
/// You can use RHReliableDatagram to send broadcast messages, with a TO address of RH_BROADCAST_ADDRESS,
/// however broadcasts are not acknowledged or retransmitted and are therefore NOT actually reliable.
///
/// The retransmit timeout is randomly varied between timeout and timeout*2 to prevent collisions on all
/// retries when 2 nodes happen to start sending at the same time .
///
/// Each new message sent by sendtoWait() has its ID incremented.
///
/// An ack consists of a message with:
/// - TO set to the from address of the original message
/// - FROM set to this node address
/// - ID set to the ID of the original message
/// - FLAGS with the RH_FLAGS_ACK bit set
/// - 1 octet of payload containing ASCII '!' (since some drivers cannot handle 0 length payloads)
///
/// \par Media Access Strategy
///
/// RHReliableDatagram and the underlying drivers always transmit as soon as
/// sendtoWait() is called. RHReliableDatagram waits for an acknowledgement,
/// and if one is not received after a timeout period the message is
/// transmitted again. If no acknowledgement is received after several
/// retries, the transmissions is deemed to have failed.
/// No contention for media is detected.
/// This will be recognised as " pure ALOHA " .
/// The addition of Clear Channel Assessment (CCA) is desirable and planned.
///
/// There is no message queuing or threading in RHReliableDatagram.
/// sendtoWait() waits until an acknowledgement is received, retransmitting
/// up to (by default) 3 retries time with a default 200ms timeout.
/// During this transmit-acknowledge phase, any received message (other than the expected
/// acknowledgement) will be ignored. Your sketch will be unresponsive to new messages
/// until an acknowledgement is received or the retries are exhausted.
/// Central server-type sketches should be very cautious about their
/// retransmit strategy and configuration lest they hang for a long time
/// trying to reply to clients that are unreachable.
class RHReliableDatagram : public RHDatagram
{
public:
/// Constructor.
/// \param[in] driver The RadioHead driver to use to transport messages.
/// \param[in] thisAddress The address to assign to this node. Defaults to 0
RHReliableDatagram(RHGenericDriver & driver, uint8_t thisAddress = 0);

/// Sets the minimum retransmit timeout. If sendtoWait is waiting for an ack
/// longer than this time (in milliseconds),
/// it will retransmit the message. Defaults to 200ms. The timeout is measured from the end of
/// transmission of the message. It must be at least longer than the the transmit
/// time of the acknowledgement (preamble+6 octets) plus the latency/poll time of the receiver.
/// For fast modulation schemes you can considerably shorten this time.
/// The actual timeout is randomly varied between timeout and timeout*2.
/// \param[in] timeout The new timeout period in milliseconds
void setTimeout(uint16_t timeout);

/// Sets the maximum number of retries. Defaults to 3 at construction time.
/// If set to 0, each message will only ever be sent once.
/// sendtoWait will give up and return false if there is no ack received after all transmissions time out
/// and the retries count is exhausted.
/// param[in] retries The maximum number a retries.
void setRetries(uint8_t retries);

/// Returns the currently configured maximum retries count.
/// Can be changed with setRetries().
/// \return The currently configured maximum number of retries.
uint8_t retries();

/// Send the message (with retries) and waits for an ack. Returns true if an acknowledgement is received.
/// Synchronous: any message other than the desired ACK received while waiting is discarded.
/// Blocks until an ACK is received or all retries are exhausted (ie up to retries*timeout milliseconds).
/// If the destination address is the broadcast address RH_BROADCAST_ADDRESS (255), the message will
/// be sent as a broadcast, but receiving nodes do not acknowledge, and sendtoWait() returns true immediately
/// without waiting for any acknowledgements.
/// \param[in] address The address to send the message to.
/// \param[in] buf Pointer to the binary message to send
/// \param[in] len Number of octets to send
/// \return true if the message was transmitted and an acknowledgement was received.
bool sendtoWait(uint8_t* buf, uint8_t len, uint8_t address);

/// If there is a valid message available for this node, send an acknowledgement to the SRC
/// address (blocking until this is complete), then copy the message to buf and return true
/// else return false.
/// If a message is copied, *len is set to the length..
/// If from is not NULL, the SRC address is placed in *from.
/// If to is not NULL, the DEST address is placed in *to.
/// This is the preferred function for getting messages addressed to this node.
/// If the message is not a broadcast, acknowledge to the sender before returning.
/// You should be sure to call this function frequently enough to not miss any messages
/// It is recommended that you call it in your main loop.
/// \param[in] buf Location to copy the received message
/// \param[in,out] len Available space in buf. Set to the actual number of octets copied.
/// \param[in] from If present and not NULL, the referenced uint8_t will be set to the SRC address
/// \param[in] to If present and not NULL, the referenced uint8_t will be set to the DEST address
/// \param[in] id If present and not NULL, the referenced uint8_t will be set to the ID
/// \param[in] flags If present and not NULL, the referenced uint8_t will be set to the FLAGS
/// (not just those addressed to this node).
/// \return true if a valid message was copied to buf
bool recvfromAck(uint8_t* buf, uint8_t* len, uint8_t* from = NULL, uint8_t* to = NULL, uint8_t* id = NULL, uint8_t* flags = NULL);

/// Similar to recvfromAck(), this will block until either a valid message available for this node
/// or the timeout expires. Starts the receiver automatically.
/// You should be sure to call this function frequently enough to not miss any messages
/// It is recommended that you call it in your main loop.
/// \param[in] buf Location to copy the received message
/// \param[in,out] len Available space in buf. Set to the actual number of octets copied.
/// \param[in] timeout Maximum time to wait in milliseconds
/// \param[in] from If present and not NULL, the referenced uint8_t will be set to the SRC address
/// \param[in] to If present and not NULL, the referenced uint8_t will be set to the DEST address
/// \param[in] id If present and not NULL, the referenced uint8_t will be set to the ID
/// \param[in] flags If present and not NULL, the referenced uint8_t will be set to the FLAGS
/// (not just those addressed to this node).
/// \return true if a valid message was copied to buf
bool recvfromAckTimeout(uint8_t* buf, uint8_t* len, uint16_t timeout, uint8_t* from = NULL, uint8_t* to = NULL, uint8_t* id = NULL, uint8_t* flags = NULL);

/// Returns the number of retransmissions
/// we have had to send since starting or since the last call to resetRetransmissions().
/// \return The number of retransmissions since initialisation.
uint32_t retransmissions();

/// Resets the count of the number of retransmissions
/// to 0.
void resetRetransmissions();

protected:
/// Send an ACK for the message id to the given from address
/// Blocks until the ACK has been sent
void acknowledge(uint8_t id, uint8_t from);

/// Checks whether the message currently in the Rx buffer is a new message, not previously received
/// based on the from address and the sequence. If it is new, it is acknowledged and returns true
/// \return true if there is a message received and it is a new message
bool haveNewMessage();

private:
/// Count of retransmissions we have had to send
uint32_t _retransmissions;

/// The last sequence number to be used
/// Defaults to 0
uint8_t _lastSequenceNumber;

// Retransmit timeout (milliseconds)
/// Defaults to 200
uint16_t _timeout;

// Retries (0 means one try only)
/// Defaults to 3
uint8_t _retries;

/// Array of the last seen sequence number indexed by node address that sent it
/// It is used for duplicate detection. Duplicated messages are re-acknowledged when received
/// (this is generally due to lost ACKs, causing the sender to retransmit, even though we have already
/// received that message)
uint8_t _seenIds[256];
};

/// @example rf22_reliable_datagram_client.pde
/// @example rf22_reliable_datagram_server.pde

#endif


RadioHead-1.41.zip > RHTcpProtocol.h

// RH_TcpProtocol.h
// Author: Mike McCauley (mikem@aierspayce.com)
// Definition of protocol messages sent and received by RH_TCP
// Copyright (C) 2014 Mike McCauley
// $Id: RHTcpProtocol.h,v 1.3 2014/05/22 06:07:09 mikem Exp $

/// This file contains the definitions of message structures passed between
/// RH_TCP and the etherSimulator
#ifndef RH_TcpProtocol_h
#define RH_TcpProtocol_h

#define RH_TCP_MESSAGE_TYPE_NOP 0
#define RH_TCP_MESSAGE_TYPE_THISADDRESS 1
#define RH_TCP_MESSAGE_TYPE_PACKET 2

// Maximum message length (including the headers) we are willing to support
#define RH_TCP_MAX_PAYLOAD_LEN 255

// The length of the headers we add.
// The headers are inside the RF69's payload and are therefore encrypted if encryption is enabled
#define RH_TCP_HEADER_LEN 4


// This is the maximum message length that can be supported by this protocol.
#define RH_TCP_MAX_MESSAGE_LEN (RH_TCP_MAX_PAYLOAD_LEN - RH_TCP_HEADER_LEN)

#pragma pack(push, 1) // No padding

/// \brief Generic RH_TCP simulator message structure
typedef struct
{
uint32_t length; /// & lt; Number of octets following, in network byte order
uint8_t payload[RH_TCP_MAX_PAYLOAD_LEN + 1]; /// & lt; Payload
} RHTcpMessage;

/// \brief Generic RH_TCP message structure with message type
typedef struct
{
uint32_t length; /// & lt; Number of octets following, in network byte order
uint8_t type; /// & lt; One of RH_TCP_MESSAGE_TYPE_*
uint8_t payload[RH_TCP_MAX_PAYLOAD_LEN]; /// & lt; Payload
} RHTcpTypeMessage;

/// \brief RH_TCP message Notifies the server of thisAddress of this client
typedef struct
{
uint32_t length; /// & lt; Number of octets following, in network byte order
uint8_t type; /// & lt; == RH_TCP_MESSAGE_TYPE_THISADDRESS
uint8_t thisAddress; /// & lt; Node address
} RHTcpThisAddress;

/// \brief RH_TCP radio message passed to or from the simulator
typedef struct
{
uint32_t length; /// & lt; Number of octets following, in network byte order
uint8_t type; /// & lt; == RH_TCP_MESSAGE_TYPE_PACKET
uint8_t to; /// & lt; Node address of the recipient
uint8_t from; /// & lt; Node address of the sender
uint8_t id; /// & lt; Message sequence number
uint8_t flags; /// & lt; Message flags
uint8_t payload[RH_TCP_MAX_MESSAGE_LEN]; /// & lt; 0 or more, length deduced from length above
} RHTcpPacket;

#pragma pack(pop)

#endif