From ff34ced6ccf9af12779c8afaec3fdd203b08c0b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Sousa?= Date: Mon, 12 May 2014 14:15:04 +0100 Subject: [PATCH 1/3] initial import --- README.md | 11 + RF24.cpp | 985 ------------------ RF24.h | 819 --------------- RF24_config.h | 65 -- examples/GettingStarted/GettingStarted.pde | 227 ---- examples/GettingStarted/Jamfile | 210 ---- examples/GettingStarted/printf.h | 37 - examples/led_remote/Jamfile | 206 ---- examples/led_remote/led_remote.pde | 255 ----- examples/led_remote/printf.h | 37 - examples/nordic_fob/Jamfile | 219 ---- examples/nordic_fob/nordic_fob.pde | 142 --- examples/nordic_fob/printf.h | 37 - examples/pingpair/Jamfile | 219 ---- examples/pingpair/pingpair.pde | 220 ---- examples/pingpair/printf.h | 37 - examples/pingpair_dyn/Jamfile | 206 ---- examples/pingpair_dyn/pingpair_dyn.pde | 232 ----- examples/pingpair_dyn/printf.h | 37 - examples/pingpair_irq/Jamfile | 219 ---- examples/pingpair_irq/pingpair_irq.pde | 216 ---- examples/pingpair_irq/printf.h | 37 - examples/pingpair_maple/Jamfile | 182 ---- examples/pingpair_maple/main.cpp | 87 -- examples/pingpair_maple/pingpair_maple.pde | 242 ----- examples/pingpair_pl/Jamfile | 206 ---- examples/pingpair_pl/pingpair_pl.pde | 180 ---- examples/pingpair_pl/printf.h | 37 - examples/pingpair_sleepy/Jamfile | 206 ---- examples/pingpair_sleepy/pingpair_sleepy.pde | 288 ----- examples/pingpair_sleepy/printf.h | 37 - examples/scanner/Jamfile | 210 ---- examples/scanner/output/core.a | Bin 187630 -> 0 bytes examples/scanner/output/scanner.cpp | 128 --- examples/scanner/output/scanner.elf | Bin 100436 -> 0 bytes examples/scanner/output/scanner.hex | 325 ------ examples/scanner/printf.h | 31 - examples/scanner/scanner.pde | 124 --- examples/starping/Jamfile | 206 ---- examples/starping/printf.h | 37 - examples/starping/starping.pde | 293 ------ nRF24L01.h | 125 --- tests/README | 7 - tests/native/Jamfile | 300 ------ tests/native/pingpair_irq.pde | 223 ---- tests/native/printf.h | 33 - tests/pingpair_blocking/Jamfile | 219 ---- tests/pingpair_blocking/pingpair_blocking.pde | 273 ----- tests/pingpair_blocking/printf.h | 37 - tests/pingpair_blocking/runtest.py | 25 - tests/pingpair_blocking/runtests.sh | 5 - tests/pingpair_blocking/test.ex | 11 - tests/pingpair_test/Jamfile | 219 ---- tests/pingpair_test/pingpair_test.pde | 435 -------- tests/pingpair_test/printf.h | 37 - tests/pingpair_test/runtest.py | 25 - tests/pingpair_test/runtests.sh | 21 - tests/pingpair_test/test.ex | 11 - 58 files changed, 11 insertions(+), 9487 deletions(-) delete mode 100644 RF24.cpp delete mode 100644 RF24.h delete mode 100644 RF24_config.h delete mode 100644 examples/GettingStarted/GettingStarted.pde delete mode 100644 examples/GettingStarted/Jamfile delete mode 100644 examples/GettingStarted/printf.h delete mode 100644 examples/led_remote/Jamfile delete mode 100644 examples/led_remote/led_remote.pde delete mode 100644 examples/led_remote/printf.h delete mode 100644 examples/nordic_fob/Jamfile delete mode 100644 examples/nordic_fob/nordic_fob.pde delete mode 100644 examples/nordic_fob/printf.h delete mode 100644 examples/pingpair/Jamfile delete mode 100644 examples/pingpair/pingpair.pde delete mode 100644 examples/pingpair/printf.h delete mode 100644 examples/pingpair_dyn/Jamfile delete mode 100644 examples/pingpair_dyn/pingpair_dyn.pde delete mode 100644 examples/pingpair_dyn/printf.h delete mode 100644 examples/pingpair_irq/Jamfile delete mode 100644 examples/pingpair_irq/pingpair_irq.pde delete mode 100644 examples/pingpair_irq/printf.h delete mode 100644 examples/pingpair_maple/Jamfile delete mode 100644 examples/pingpair_maple/main.cpp delete mode 100644 examples/pingpair_maple/pingpair_maple.pde delete mode 100644 examples/pingpair_pl/Jamfile delete mode 100644 examples/pingpair_pl/pingpair_pl.pde delete mode 100644 examples/pingpair_pl/printf.h delete mode 100644 examples/pingpair_sleepy/Jamfile delete mode 100644 examples/pingpair_sleepy/pingpair_sleepy.pde delete mode 100644 examples/pingpair_sleepy/printf.h delete mode 100644 examples/scanner/Jamfile delete mode 100644 examples/scanner/output/core.a delete mode 100644 examples/scanner/output/scanner.cpp delete mode 100755 examples/scanner/output/scanner.elf delete mode 100644 examples/scanner/output/scanner.hex delete mode 100644 examples/scanner/printf.h delete mode 100644 examples/scanner/scanner.pde delete mode 100644 examples/starping/Jamfile delete mode 100644 examples/starping/printf.h delete mode 100644 examples/starping/starping.pde delete mode 100644 nRF24L01.h delete mode 100644 tests/README delete mode 100644 tests/native/Jamfile delete mode 100644 tests/native/pingpair_irq.pde delete mode 100644 tests/native/printf.h delete mode 100644 tests/pingpair_blocking/Jamfile delete mode 100644 tests/pingpair_blocking/pingpair_blocking.pde delete mode 100644 tests/pingpair_blocking/printf.h delete mode 100755 tests/pingpair_blocking/runtest.py delete mode 100755 tests/pingpair_blocking/runtests.sh delete mode 100755 tests/pingpair_blocking/test.ex delete mode 100644 tests/pingpair_test/Jamfile delete mode 100644 tests/pingpair_test/pingpair_test.pde delete mode 100644 tests/pingpair_test/printf.h delete mode 100755 tests/pingpair_test/runtest.py delete mode 100755 tests/pingpair_test/runtests.sh delete mode 100755 tests/pingpair_test/test.ex diff --git a/README.md b/README.md index c0e71c09..e2582d67 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,14 @@ +MSP-remote-RF24 +=============== + +Source code for a remote controller using a msp430g2553 and a nrf24l01 from nordic, + +* [Original Repo.](http://maniacbug.github.com/RF24) +* [LIBEMB Repo.](https://github.com/wendlers/libemb/tree/msp430-port) +This library was precompiled and is included in this project just for the serial communication task. +Some changes were done in order to allow serial compatibilty for every msp430 clock freqencies. (Most recent commit already has this change). + + # Arduino driver for nRF24L01 2.4GHz Wireless Transceiver Design Goals: This library is designed to be... diff --git a/RF24.cpp b/RF24.cpp deleted file mode 100644 index 9471583d..00000000 --- a/RF24.cpp +++ /dev/null @@ -1,985 +0,0 @@ -/* - Copyright (C) 2011 J. Coliz - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - version 2 as published by the Free Software Foundation. - */ - -#include "nRF24L01.h" -#include "RF24_config.h" -#include "RF24.h" - -/****************************************************************************/ - -void RF24::csn(int mode) -{ - // Minimum ideal SPI bus speed is 2x data rate - // If we assume 2Mbs data rate and 16Mhz clock, a - // divider of 4 is the minimum we want. - // CLK:BUS 8Mhz:2Mhz, 16Mhz:4Mhz, or 20Mhz:5Mhz -#ifdef ARDUINO - SPI.setBitOrder(MSBFIRST); - SPI.setDataMode(SPI_MODE0); - SPI.setClockDivider(SPI_CLOCK_DIV4); -#endif - digitalWrite(csn_pin,mode); -} - -/****************************************************************************/ - -void RF24::ce(int level) -{ - digitalWrite(ce_pin,level); -} - -/****************************************************************************/ - -uint8_t RF24::read_register(uint8_t reg, uint8_t* buf, uint8_t len) -{ - uint8_t status; - - csn(LOW); - status = SPI.transfer( R_REGISTER | ( REGISTER_MASK & reg ) ); - while ( len-- ) - *buf++ = SPI.transfer(0xff); - - csn(HIGH); - - return status; -} - -/****************************************************************************/ - -uint8_t RF24::read_register(uint8_t reg) -{ - csn(LOW); - SPI.transfer( R_REGISTER | ( REGISTER_MASK & reg ) ); - uint8_t result = SPI.transfer(0xff); - - csn(HIGH); - return result; -} - -/****************************************************************************/ - -uint8_t RF24::write_register(uint8_t reg, const uint8_t* buf, uint8_t len) -{ - uint8_t status; - - csn(LOW); - status = SPI.transfer( W_REGISTER | ( REGISTER_MASK & reg ) ); - while ( len-- ) - SPI.transfer(*buf++); - - csn(HIGH); - - return status; -} - -/****************************************************************************/ - -uint8_t RF24::write_register(uint8_t reg, uint8_t value) -{ - uint8_t status; - - IF_SERIAL_DEBUG(printf_P(PSTR("write_register(%02x,%02x)\r\n"),reg,value)); - - csn(LOW); - status = SPI.transfer( W_REGISTER | ( REGISTER_MASK & reg ) ); - SPI.transfer(value); - csn(HIGH); - - return status; -} - -/****************************************************************************/ - -uint8_t RF24::write_payload(const void* buf, uint8_t len) -{ - uint8_t status; - - const uint8_t* current = reinterpret_cast(buf); - - uint8_t data_len = min(len,payload_size); - uint8_t blank_len = dynamic_payloads_enabled ? 0 : payload_size - data_len; - - //printf("[Writing %u bytes %u blanks]",data_len,blank_len); - - csn(LOW); - status = SPI.transfer( W_TX_PAYLOAD ); - while ( data_len-- ) - SPI.transfer(*current++); - while ( blank_len-- ) - SPI.transfer(0); - csn(HIGH); - - return status; -} - -/****************************************************************************/ - -uint8_t RF24::read_payload(void* buf, uint8_t len) -{ - uint8_t status; - uint8_t* current = reinterpret_cast(buf); - - uint8_t data_len = min(len,payload_size); - uint8_t blank_len = dynamic_payloads_enabled ? 0 : payload_size - data_len; - - //printf("[Reading %u bytes %u blanks]",data_len,blank_len); - - csn(LOW); - status = SPI.transfer( R_RX_PAYLOAD ); - while ( data_len-- ) - *current++ = SPI.transfer(0xff); - while ( blank_len-- ) - SPI.transfer(0xff); - csn(HIGH); - - return status; -} - -/****************************************************************************/ - -uint8_t RF24::flush_rx(void) -{ - uint8_t status; - - csn(LOW); - status = SPI.transfer( FLUSH_RX ); - csn(HIGH); - - return status; -} - -/****************************************************************************/ - -uint8_t RF24::flush_tx(void) -{ - uint8_t status; - - csn(LOW); - status = SPI.transfer( FLUSH_TX ); - csn(HIGH); - - return status; -} - -/****************************************************************************/ - -uint8_t RF24::get_status(void) -{ - uint8_t status; - - csn(LOW); - status = SPI.transfer( NOP ); - csn(HIGH); - - return status; -} - -/****************************************************************************/ - -void RF24::print_status(uint8_t status) -{ - printf_P(PSTR("STATUS\t\t = 0x%02x RX_DR=%x TX_DS=%x MAX_RT=%x RX_P_NO=%x TX_FULL=%x\r\n"), - status, - (status & _BV(RX_DR))?1:0, - (status & _BV(TX_DS))?1:0, - (status & _BV(MAX_RT))?1:0, - ((status >> RX_P_NO) & B111), - (status & _BV(TX_FULL))?1:0 - ); -} - -/****************************************************************************/ - -void RF24::print_observe_tx(uint8_t value) -{ - printf_P(PSTR("OBSERVE_TX=%02x: POLS_CNT=%x ARC_CNT=%x\r\n"), - value, - (value >> PLOS_CNT) & B1111, - (value >> ARC_CNT) & B1111 - ); -} - -/****************************************************************************/ - -void RF24::print_byte_register(const char* name, uint8_t reg, uint8_t qty) -{ - char extra_tab = strlen_P(name) < 8 ? '\t' : 0; - printf_P(PSTR(PRIPSTR"\t%c ="),name,extra_tab); - while (qty--) - printf_P(PSTR(" 0x%02x"),read_register(reg++)); - printf_P(PSTR("\r\n")); -} - -/****************************************************************************/ - -void RF24::print_address_register(const char* name, uint8_t reg, uint8_t qty) -{ - char extra_tab = strlen_P(name) < 8 ? '\t' : 0; - printf_P(PSTR(PRIPSTR"\t%c ="),name,extra_tab); - - while (qty--) - { - uint8_t buffer[5]; - read_register(reg++,buffer,sizeof buffer); - - printf_P(PSTR(" 0x")); - uint8_t* bufptr = buffer + sizeof buffer; - while( --bufptr >= buffer ) - printf_P(PSTR("%02x"),*bufptr); - } - - printf_P(PSTR("\r\n")); -} - -/****************************************************************************/ - -RF24::RF24(uint8_t _cepin, uint8_t _cspin): - ce_pin(_cepin), csn_pin(_cspin), wide_band(true), p_variant(false), - payload_size(32), ack_payload_available(false), dynamic_payloads_enabled(false), - pipe0_reading_address(0) -{ -} - -/****************************************************************************/ - -void RF24::setChannel(uint8_t channel) -{ - // TODO: This method could take advantage of the 'wide_band' calculation - // done in setChannel() to require certain channel spacing. - - const uint8_t max_channel = 127; - write_register(RF_CH,min(channel,max_channel)); -} - -/****************************************************************************/ - -void RF24::setPayloadSize(uint8_t size) -{ - const uint8_t max_payload_size = 32; - payload_size = min(size,max_payload_size); -} - -/****************************************************************************/ - -uint8_t RF24::getPayloadSize(void) -{ - return payload_size; -} - -/****************************************************************************/ - -static const char rf24_datarate_e_str_0[] PROGMEM = "1MBPS"; -static const char rf24_datarate_e_str_1[] PROGMEM = "2MBPS"; -static const char rf24_datarate_e_str_2[] PROGMEM = "250KBPS"; -static const char * const rf24_datarate_e_str_P[] PROGMEM = { - rf24_datarate_e_str_0, - rf24_datarate_e_str_1, - rf24_datarate_e_str_2, -}; -static const char rf24_model_e_str_0[] PROGMEM = "nRF24L01"; -static const char rf24_model_e_str_1[] PROGMEM = "nRF24L01+"; -static const char * const rf24_model_e_str_P[] PROGMEM = { - rf24_model_e_str_0, - rf24_model_e_str_1, -}; -static const char rf24_crclength_e_str_0[] PROGMEM = "Disabled"; -static const char rf24_crclength_e_str_1[] PROGMEM = "8 bits"; -static const char rf24_crclength_e_str_2[] PROGMEM = "16 bits" ; -static const char * const rf24_crclength_e_str_P[] PROGMEM = { - rf24_crclength_e_str_0, - rf24_crclength_e_str_1, - rf24_crclength_e_str_2, -}; -static const char rf24_pa_dbm_e_str_0[] PROGMEM = "PA_MIN"; -static const char rf24_pa_dbm_e_str_1[] PROGMEM = "PA_LOW"; -static const char rf24_pa_dbm_e_str_2[] PROGMEM = "LA_MED"; -static const char rf24_pa_dbm_e_str_3[] PROGMEM = "PA_HIGH"; -static const char * const rf24_pa_dbm_e_str_P[] PROGMEM = { - rf24_pa_dbm_e_str_0, - rf24_pa_dbm_e_str_1, - rf24_pa_dbm_e_str_2, - rf24_pa_dbm_e_str_3, -}; - -void RF24::printDetails(void) -{ - print_status(get_status()); - - print_address_register(PSTR("RX_ADDR_P0-1"),RX_ADDR_P0,2); - print_byte_register(PSTR("RX_ADDR_P2-5"),RX_ADDR_P2,4); - print_address_register(PSTR("TX_ADDR"),TX_ADDR); - - print_byte_register(PSTR("RX_PW_P0-6"),RX_PW_P0,6); - print_byte_register(PSTR("EN_AA"),EN_AA); - print_byte_register(PSTR("EN_RXADDR"),EN_RXADDR); - print_byte_register(PSTR("RF_CH"),RF_CH); - print_byte_register(PSTR("RF_SETUP"),RF_SETUP); - print_byte_register(PSTR("CONFIG"),CONFIG); - print_byte_register(PSTR("DYNPD/FEATURE"),DYNPD,2); - - printf_P(PSTR("Data Rate\t = %S\r\n"),pgm_read_word(&rf24_datarate_e_str_P[getDataRate()])); - printf_P(PSTR("Model\t\t = %S\r\n"),pgm_read_word(&rf24_model_e_str_P[isPVariant()])); - printf_P(PSTR("CRC Length\t = %S\r\n"),pgm_read_word(&rf24_crclength_e_str_P[getCRCLength()])); - printf_P(PSTR("PA Power\t = %S\r\n"),pgm_read_word(&rf24_pa_dbm_e_str_P[getPALevel()])); -} - -/****************************************************************************/ - -void RF24::begin(void) -{ - // Initialize pins - pinMode(ce_pin,OUTPUT); - pinMode(csn_pin,OUTPUT); - - // Initialize SPI bus - SPI.begin(); - - ce(LOW); - csn(HIGH); - - // Must allow the radio time to settle else configuration bits will not necessarily stick. - // This is actually only required following power up but some settling time also appears to - // be required after resets too. For full coverage, we'll always assume the worst. - // Enabling 16b CRC is by far the most obvious case if the wrong timing is used - or skipped. - // Technically we require 4.5ms + 14us as a worst case. We'll just call it 5ms for good measure. - // WARNING: Delay is based on P-variant whereby non-P *may* require different timing. - delay( 5 ) ; - - // Set 1500uS (minimum for 32B payload in ESB@250KBPS) timeouts, to make testing a little easier - // WARNING: If this is ever lowered, either 250KBS mode with AA is broken or maximum packet - // sizes must never be used. See documentation for a more complete explanation. - write_register(SETUP_RETR,(B0100 << ARD) | (B1111 << ARC)); - - // Restore our default PA level - setPALevel( RF24_PA_MAX ) ; - - // Determine if this is a p or non-p RF24 module and then - // reset our data rate back to default value. This works - // because a non-P variant won't allow the data rate to - // be set to 250Kbps. - if( setDataRate( RF24_250KBPS ) ) - { - p_variant = true ; - } - - // Then set the data rate to the slowest (and most reliable) speed supported by all - // hardware. - setDataRate( RF24_1MBPS ) ; - - // Initialize CRC and request 2-byte (16bit) CRC - setCRCLength( RF24_CRC_16 ) ; - - // Disable dynamic payloads, to match dynamic_payloads_enabled setting - write_register(DYNPD,0); - - // Reset current status - // Notice reset and flush is the last thing we do - write_register(STATUS,_BV(RX_DR) | _BV(TX_DS) | _BV(MAX_RT) ); - - // Set up default configuration. Callers can always change it later. - // This channel should be universally safe and not bleed over into adjacent - // spectrum. - setChannel(76); - - // Flush buffers - flush_rx(); - flush_tx(); -} - -/****************************************************************************/ - -void RF24::startListening(void) -{ - write_register(CONFIG, read_register(CONFIG) | _BV(PWR_UP) | _BV(PRIM_RX)); - write_register(STATUS, _BV(RX_DR) | _BV(TX_DS) | _BV(MAX_RT) ); - - // Restore the pipe0 adddress, if exists - if (pipe0_reading_address) - write_register(RX_ADDR_P0, reinterpret_cast(&pipe0_reading_address), 5); - - // Flush buffers - flush_rx(); - flush_tx(); - - // Go! - ce(HIGH); - - // wait for the radio to come up (130us actually only needed) - delayMicroseconds(130); -} - -/****************************************************************************/ - -void RF24::stopListening(void) -{ - ce(LOW); - flush_tx(); - flush_rx(); -} - -/****************************************************************************/ - -void RF24::powerDown(void) -{ - write_register(CONFIG,read_register(CONFIG) & ~_BV(PWR_UP)); -} - -/****************************************************************************/ - -void RF24::powerUp(void) -{ - write_register(CONFIG,read_register(CONFIG) | _BV(PWR_UP)); -} - -/******************************************************************/ - -bool RF24::write( const void* buf, uint8_t len ) -{ - bool result = false; - - // Begin the write - startWrite(buf,len); - - // ------------ - // At this point we could return from a non-blocking write, and then call - // the rest after an interrupt - - // Instead, we are going to block here until we get TX_DS (transmission completed and ack'd) - // or MAX_RT (maximum retries, transmission failed). Also, we'll timeout in case the radio - // is flaky and we get neither. - - // IN the end, the send should be blocking. It comes back in 60ms worst case, or much faster - // if I tighted up the retry logic. (Default settings will be 1500us. - // Monitor the send - uint8_t observe_tx; - uint8_t status; - uint32_t sent_at = millis(); - const uint32_t timeout = 500; //ms to wait for timeout - do - { - status = read_register(OBSERVE_TX,&observe_tx,1); - IF_SERIAL_DEBUG(Serial.print(observe_tx,HEX)); - } - while( ! ( status & ( _BV(TX_DS) | _BV(MAX_RT) ) ) && ( millis() - sent_at < timeout ) ); - - // The part above is what you could recreate with your own interrupt handler, - // and then call this when you got an interrupt - // ------------ - - // Call this when you get an interrupt - // The status tells us three things - // * The send was successful (TX_DS) - // * The send failed, too many retries (MAX_RT) - // * There is an ack packet waiting (RX_DR) - bool tx_ok, tx_fail; - whatHappened(tx_ok,tx_fail,ack_payload_available); - - //printf("%u%u%u\r\n",tx_ok,tx_fail,ack_payload_available); - - result = tx_ok; - IF_SERIAL_DEBUG(Serial.print(result?"...OK.":"...Failed")); - - // Handle the ack packet - if ( ack_payload_available ) - { - ack_payload_length = getDynamicPayloadSize(); - IF_SERIAL_DEBUG(Serial.print("[AckPacket]/")); - IF_SERIAL_DEBUG(Serial.println(ack_payload_length,DEC)); - } - - // Yay, we are done. - - // Power down - powerDown(); - - // Flush buffers (Is this a relic of past experimentation, and not needed anymore??) - flush_tx(); - - return result; -} -/****************************************************************************/ - -void RF24::startWrite( const void* buf, uint8_t len ) -{ - // Transmitter power-up - write_register(CONFIG, ( read_register(CONFIG) | _BV(PWR_UP) ) & ~_BV(PRIM_RX) ); - delayMicroseconds(150); - - // Send the payload - write_payload( buf, len ); - - // Allons! - ce(HIGH); - delayMicroseconds(15); - ce(LOW); -} - -/****************************************************************************/ - -uint8_t RF24::getDynamicPayloadSize(void) -{ - uint8_t result = 0; - - csn(LOW); - SPI.transfer( R_RX_PL_WID ); - result = SPI.transfer(0xff); - csn(HIGH); - - return result; -} - -/****************************************************************************/ - -bool RF24::available(void) -{ - return available(NULL); -} - -/****************************************************************************/ - -bool RF24::available(uint8_t* pipe_num) -{ - uint8_t status = get_status(); - - // Too noisy, enable if you really want lots o data!! - //IF_SERIAL_DEBUG(print_status(status)); - - bool result = ( status & _BV(RX_DR) ); - - if (result) - { - // If the caller wants the pipe number, include that - if ( pipe_num ) - *pipe_num = ( status >> RX_P_NO ) & B111; - - // Clear the status bit - - // ??? Should this REALLY be cleared now? Or wait until we - // actually READ the payload? - - write_register(STATUS,_BV(RX_DR) ); - - // Handle ack payload receipt - if ( status & _BV(TX_DS) ) - { - write_register(STATUS,_BV(TX_DS)); - } - } - - return result; -} - -/****************************************************************************/ - -bool RF24::read( void* buf, uint8_t len ) -{ - // Fetch the payload - read_payload( buf, len ); - - // was this the last of the data available? - return read_register(FIFO_STATUS) & _BV(RX_EMPTY); -} - -/****************************************************************************/ - -void RF24::whatHappened(bool& tx_ok,bool& tx_fail,bool& rx_ready) -{ - // Read the status & reset the status in one easy call - // Or is that such a good idea? - uint8_t status = write_register(STATUS,_BV(RX_DR) | _BV(TX_DS) | _BV(MAX_RT) ); - - // Report to the user what happened - tx_ok = status & _BV(TX_DS); - tx_fail = status & _BV(MAX_RT); - rx_ready = status & _BV(RX_DR); -} - -/****************************************************************************/ - -void RF24::openWritingPipe(uint64_t value) -{ - // Note that AVR 8-bit uC's store this LSB first, and the NRF24L01(+) - // expects it LSB first too, so we're good. - - write_register(RX_ADDR_P0, reinterpret_cast(&value), 5); - write_register(TX_ADDR, reinterpret_cast(&value), 5); - - const uint8_t max_payload_size = 32; - write_register(RX_PW_P0,min(payload_size,max_payload_size)); -} - -/****************************************************************************/ - -static const uint8_t child_pipe[] PROGMEM = -{ - RX_ADDR_P0, RX_ADDR_P1, RX_ADDR_P2, RX_ADDR_P3, RX_ADDR_P4, RX_ADDR_P5 -}; -static const uint8_t child_payload_size[] PROGMEM = -{ - RX_PW_P0, RX_PW_P1, RX_PW_P2, RX_PW_P3, RX_PW_P4, RX_PW_P5 -}; -static const uint8_t child_pipe_enable[] PROGMEM = -{ - ERX_P0, ERX_P1, ERX_P2, ERX_P3, ERX_P4, ERX_P5 -}; - -void RF24::openReadingPipe(uint8_t child, uint64_t address) -{ - // If this is pipe 0, cache the address. This is needed because - // openWritingPipe() will overwrite the pipe 0 address, so - // startListening() will have to restore it. - if (child == 0) - pipe0_reading_address = address; - - if (child <= 6) - { - // For pipes 2-5, only write the LSB - if ( child < 2 ) - write_register(pgm_read_byte(&child_pipe[child]), reinterpret_cast(&address), 5); - else - write_register(pgm_read_byte(&child_pipe[child]), reinterpret_cast(&address), 1); - - write_register(pgm_read_byte(&child_payload_size[child]),payload_size); - - // Note it would be more efficient to set all of the bits for all open - // pipes at once. However, I thought it would make the calling code - // more simple to do it this way. - write_register(EN_RXADDR,read_register(EN_RXADDR) | _BV(pgm_read_byte(&child_pipe_enable[child]))); - } -} - -/****************************************************************************/ - -void RF24::toggle_features(void) -{ - csn(LOW); - SPI.transfer( ACTIVATE ); - SPI.transfer( 0x73 ); - csn(HIGH); -} - -/****************************************************************************/ - -void RF24::enableDynamicPayloads(void) -{ - // Enable dynamic payload throughout the system - write_register(FEATURE,read_register(FEATURE) | _BV(EN_DPL) ); - - // If it didn't work, the features are not enabled - if ( ! read_register(FEATURE) ) - { - // So enable them and try again - toggle_features(); - write_register(FEATURE,read_register(FEATURE) | _BV(EN_DPL) ); - } - - IF_SERIAL_DEBUG(printf("FEATURE=%i\r\n",read_register(FEATURE))); - - // Enable dynamic payload on all pipes - // - // Not sure the use case of only having dynamic payload on certain - // pipes, so the library does not support it. - write_register(DYNPD,read_register(DYNPD) | _BV(DPL_P5) | _BV(DPL_P4) | _BV(DPL_P3) | _BV(DPL_P2) | _BV(DPL_P1) | _BV(DPL_P0)); - - dynamic_payloads_enabled = true; -} - -/****************************************************************************/ - -void RF24::enableAckPayload(void) -{ - // - // enable ack payload and dynamic payload features - // - - write_register(FEATURE,read_register(FEATURE) | _BV(EN_ACK_PAY) | _BV(EN_DPL) ); - - // If it didn't work, the features are not enabled - if ( ! read_register(FEATURE) ) - { - // So enable them and try again - toggle_features(); - write_register(FEATURE,read_register(FEATURE) | _BV(EN_ACK_PAY) | _BV(EN_DPL) ); - } - - IF_SERIAL_DEBUG(printf("FEATURE=%i\r\n",read_register(FEATURE))); - - // - // Enable dynamic payload on pipes 0 & 1 - // - - write_register(DYNPD,read_register(DYNPD) | _BV(DPL_P1) | _BV(DPL_P0)); -} - -/****************************************************************************/ - -void RF24::writeAckPayload(uint8_t pipe, const void* buf, uint8_t len) -{ - const uint8_t* current = reinterpret_cast(buf); - - csn(LOW); - SPI.transfer( W_ACK_PAYLOAD | ( pipe & B111 ) ); - const uint8_t max_payload_size = 32; - uint8_t data_len = min(len,max_payload_size); - while ( data_len-- ) - SPI.transfer(*current++); - - csn(HIGH); -} - -/****************************************************************************/ - -bool RF24::isAckPayloadAvailable(void) -{ - bool result = ack_payload_available; - ack_payload_available = false; - return result; -} - -/****************************************************************************/ - -bool RF24::isPVariant(void) -{ - return p_variant ; -} - -/****************************************************************************/ - -void RF24::setAutoAck(bool enable) -{ - if ( enable ) - write_register(EN_AA, B111111); - else - write_register(EN_AA, 0); -} - -/****************************************************************************/ - -void RF24::setAutoAck( uint8_t pipe, bool enable ) -{ - if ( pipe <= 6 ) - { - uint8_t en_aa = read_register( EN_AA ) ; - if( enable ) - { - en_aa |= _BV(pipe) ; - } - else - { - en_aa &= ~_BV(pipe) ; - } - write_register( EN_AA, en_aa ) ; - } -} - -/****************************************************************************/ - -bool RF24::testCarrier(void) -{ - return ( read_register(CD) & 1 ); -} - -/****************************************************************************/ - -bool RF24::testRPD(void) -{ - return ( read_register(RPD) & 1 ) ; -} - -/****************************************************************************/ - -void RF24::setPALevel(rf24_pa_dbm_e level) -{ - uint8_t setup = read_register(RF_SETUP) ; - setup &= ~(_BV(RF_PWR_LOW) | _BV(RF_PWR_HIGH)) ; - - // switch uses RAM (evil!) - if ( level == RF24_PA_MAX ) - { - setup |= (_BV(RF_PWR_LOW) | _BV(RF_PWR_HIGH)) ; - } - else if ( level == RF24_PA_HIGH ) - { - setup |= _BV(RF_PWR_HIGH) ; - } - else if ( level == RF24_PA_LOW ) - { - setup |= _BV(RF_PWR_LOW); - } - else if ( level == RF24_PA_MIN ) - { - // nothing - } - else if ( level == RF24_PA_ERROR ) - { - // On error, go to maximum PA - setup |= (_BV(RF_PWR_LOW) | _BV(RF_PWR_HIGH)) ; - } - - write_register( RF_SETUP, setup ) ; -} - -/****************************************************************************/ - -rf24_pa_dbm_e RF24::getPALevel(void) -{ - rf24_pa_dbm_e result = RF24_PA_ERROR ; - uint8_t power = read_register(RF_SETUP) & (_BV(RF_PWR_LOW) | _BV(RF_PWR_HIGH)) ; - - // switch uses RAM (evil!) - if ( power == (_BV(RF_PWR_LOW) | _BV(RF_PWR_HIGH)) ) - { - result = RF24_PA_MAX ; - } - else if ( power == _BV(RF_PWR_HIGH) ) - { - result = RF24_PA_HIGH ; - } - else if ( power == _BV(RF_PWR_LOW) ) - { - result = RF24_PA_LOW ; - } - else - { - result = RF24_PA_MIN ; - } - - return result ; -} - -/****************************************************************************/ - -bool RF24::setDataRate(rf24_datarate_e speed) -{ - bool result = false; - uint8_t setup = read_register(RF_SETUP) ; - - // HIGH and LOW '00' is 1Mbs - our default - wide_band = false ; - setup &= ~(_BV(RF_DR_LOW) | _BV(RF_DR_HIGH)) ; - if( speed == RF24_250KBPS ) - { - // Must set the RF_DR_LOW to 1; RF_DR_HIGH (used to be RF_DR) is already 0 - // Making it '10'. - wide_band = false ; - setup |= _BV( RF_DR_LOW ) ; - } - else - { - // Set 2Mbs, RF_DR (RF_DR_HIGH) is set 1 - // Making it '01' - if ( speed == RF24_2MBPS ) - { - wide_band = true ; - setup |= _BV(RF_DR_HIGH); - } - else - { - // 1Mbs - wide_band = false ; - } - } - write_register(RF_SETUP,setup); - - // Verify our result - if ( read_register(RF_SETUP) == setup ) - { - result = true; - } - else - { - wide_band = false; - } - - return result; -} - -/****************************************************************************/ - -rf24_datarate_e RF24::getDataRate( void ) -{ - rf24_datarate_e result ; - uint8_t dr = read_register(RF_SETUP) & (_BV(RF_DR_LOW) | _BV(RF_DR_HIGH)); - - // switch uses RAM (evil!) - // Order matters in our case below - if ( dr == _BV(RF_DR_LOW) ) - { - // '10' = 250KBPS - result = RF24_250KBPS ; - } - else if ( dr == _BV(RF_DR_HIGH) ) - { - // '01' = 2MBPS - result = RF24_2MBPS ; - } - else - { - // '00' = 1MBPS - result = RF24_1MBPS ; - } - return result ; -} - -/****************************************************************************/ - -void RF24::setCRCLength(rf24_crclength_e length) -{ - uint8_t config = read_register(CONFIG) & ~( _BV(CRCO) | _BV(EN_CRC)) ; - - // switch uses RAM (evil!) - if ( length == RF24_CRC_DISABLED ) - { - // Do nothing, we turned it off above. - } - else if ( length == RF24_CRC_8 ) - { - config |= _BV(EN_CRC); - } - else - { - config |= _BV(EN_CRC); - config |= _BV( CRCO ); - } - write_register( CONFIG, config ) ; -} - -/****************************************************************************/ - -rf24_crclength_e RF24::getCRCLength(void) -{ - rf24_crclength_e result = RF24_CRC_DISABLED; - uint8_t config = read_register(CONFIG) & ( _BV(CRCO) | _BV(EN_CRC)) ; - - if ( config & _BV(EN_CRC ) ) - { - if ( config & _BV(CRCO) ) - result = RF24_CRC_16; - else - result = RF24_CRC_8; - } - - return result; -} - -/****************************************************************************/ - -void RF24::disableCRC( void ) -{ - uint8_t disable = read_register(CONFIG) & ~_BV(EN_CRC) ; - write_register( CONFIG, disable ) ; -} - -/****************************************************************************/ -void RF24::setRetries(uint8_t delay, uint8_t count) -{ - write_register(SETUP_RETR,(delay&0xf)< - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - version 2 as published by the Free Software Foundation. - */ - -/** - * @file RF24.h - * - * Class declaration for RF24 and helper enums - */ - -#ifndef __RF24_H__ -#define __RF24_H__ - -#include - -/** - * Power Amplifier level. - * - * For use with setPALevel() - */ -typedef enum { RF24_PA_MIN = 0,RF24_PA_LOW, RF24_PA_HIGH, RF24_PA_MAX, RF24_PA_ERROR } rf24_pa_dbm_e ; - -/** - * Data rate. How fast data moves through the air. - * - * For use with setDataRate() - */ -typedef enum { RF24_1MBPS = 0, RF24_2MBPS, RF24_250KBPS } rf24_datarate_e; - -/** - * CRC Length. How big (if any) of a CRC is included. - * - * For use with setCRCLength() - */ -typedef enum { RF24_CRC_DISABLED = 0, RF24_CRC_8, RF24_CRC_16 } rf24_crclength_e; - -/** - * Driver for nRF24L01(+) 2.4GHz Wireless Transceiver - */ - -class RF24 -{ -private: - uint8_t ce_pin; /**< "Chip Enable" pin, activates the RX or TX role */ - uint8_t csn_pin; /**< SPI Chip select */ - bool wide_band; /* 2Mbs data rate in use? */ - bool p_variant; /* False for RF24L01 and true for RF24L01P */ - uint8_t payload_size; /**< Fixed size of payloads */ - bool ack_payload_available; /**< Whether there is an ack payload waiting */ - bool dynamic_payloads_enabled; /**< Whether dynamic payloads are enabled. */ - uint8_t ack_payload_length; /**< Dynamic size of pending ack payload. */ - uint64_t pipe0_reading_address; /**< Last address set on pipe 0 for reading. */ - -protected: - /** - * @name Low-level internal interface. - * - * Protected methods that address the chip directly. Regular users cannot - * ever call these. They are documented for completeness and for developers who - * may want to extend this class. - */ - /**@{*/ - - /** - * Set chip select pin - * - * Running SPI bus at PI_CLOCK_DIV2 so we don't waste time transferring data - * and best of all, we make use of the radio's FIFO buffers. A lower speed - * means we're less likely to effectively leverage our FIFOs and pay a higher - * AVR runtime cost as toll. - * - * @param mode HIGH to take this unit off the SPI bus, LOW to put it on - */ - void csn(int mode); - - /** - * Set chip enable - * - * @param level HIGH to actively begin transmission or LOW to put in standby. Please see data sheet - * for a much more detailed description of this pin. - */ - void ce(int level); - - /** - * Read a chunk of data in from a register - * - * @param reg Which register. Use constants from nRF24L01.h - * @param buf Where to put the data - * @param len How many bytes of data to transfer - * @return Current value of status register - */ - uint8_t read_register(uint8_t reg, uint8_t* buf, uint8_t len); - - /** - * Read single byte from a register - * - * @param reg Which register. Use constants from nRF24L01.h - * @return Current value of register @p reg - */ - uint8_t read_register(uint8_t reg); - - /** - * Write a chunk of data to a register - * - * @param reg Which register. Use constants from nRF24L01.h - * @param buf Where to get the data - * @param len How many bytes of data to transfer - * @return Current value of status register - */ - uint8_t write_register(uint8_t reg, const uint8_t* buf, uint8_t len); - - /** - * Write a single byte to a register - * - * @param reg Which register. Use constants from nRF24L01.h - * @param value The new value to write - * @return Current value of status register - */ - uint8_t write_register(uint8_t reg, uint8_t value); - - /** - * Write the transmit payload - * - * The size of data written is the fixed payload size, see getPayloadSize() - * - * @param buf Where to get the data - * @param len Number of bytes to be sent - * @return Current value of status register - */ - uint8_t write_payload(const void* buf, uint8_t len); - - /** - * Read the receive payload - * - * The size of data read is the fixed payload size, see getPayloadSize() - * - * @param buf Where to put the data - * @param len Maximum number of bytes to read - * @return Current value of status register - */ - uint8_t read_payload(void* buf, uint8_t len); - - /** - * Empty the receive buffer - * - * @return Current value of status register - */ - uint8_t flush_rx(void); - - /** - * Empty the transmit buffer - * - * @return Current value of status register - */ - uint8_t flush_tx(void); - - /** - * Retrieve the current status of the chip - * - * @return Current value of status register - */ - uint8_t get_status(void); - - /** - * Decode and print the given status to stdout - * - * @param status Status value to print - * - * @warning Does nothing if stdout is not defined. See fdevopen in stdio.h - */ - void print_status(uint8_t status); - - /** - * Decode and print the given 'observe_tx' value to stdout - * - * @param value The observe_tx value to print - * - * @warning Does nothing if stdout is not defined. See fdevopen in stdio.h - */ - void print_observe_tx(uint8_t value); - - /** - * Print the name and value of an 8-bit register to stdout - * - * Optionally it can print some quantity of successive - * registers on the same line. This is useful for printing a group - * of related registers on one line. - * - * @param name Name of the register - * @param reg Which register. Use constants from nRF24L01.h - * @param qty How many successive registers to print - */ - void print_byte_register(const char* name, uint8_t reg, uint8_t qty = 1); - - /** - * Print the name and value of a 40-bit address register to stdout - * - * Optionally it can print some quantity of successive - * registers on the same line. This is useful for printing a group - * of related registers on one line. - * - * @param name Name of the register - * @param reg Which register. Use constants from nRF24L01.h - * @param qty How many successive registers to print - */ - void print_address_register(const char* name, uint8_t reg, uint8_t qty = 1); - - /** - * Turn on or off the special features of the chip - * - * The chip has certain 'features' which are only available when the 'features' - * are enabled. See the datasheet for details. - */ - void toggle_features(void); - /**@}*/ - -public: - /** - * @name Primary public interface - * - * These are the main methods you need to operate the chip - */ - /**@{*/ - - /** - * Constructor - * - * Creates a new instance of this driver. Before using, you create an instance - * and send in the unique pins that this chip is connected to. - * - * @param _cepin The pin attached to Chip Enable on the RF module - * @param _cspin The pin attached to Chip Select - */ - RF24(uint8_t _cepin, uint8_t _cspin); - - /** - * Begin operation of the chip - * - * Call this in setup(), before calling any other methods. - */ - void begin(void); - - /** - * Start listening on the pipes opened for reading. - * - * Be sure to call openReadingPipe() first. Do not call write() while - * in this mode, without first calling stopListening(). Call - * isAvailable() to check for incoming traffic, and read() to get it. - */ - void startListening(void); - - /** - * Stop listening for incoming messages - * - * Do this before calling write(). - */ - void stopListening(void); - - /** - * Write to the open writing pipe - * - * Be sure to call openWritingPipe() first to set the destination - * of where to write to. - * - * This blocks until the message is successfully acknowledged by - * the receiver or the timeout/retransmit maxima are reached. In - * the current configuration, the max delay here is 60ms. - * - * The maximum size of data written is the fixed payload size, see - * getPayloadSize(). However, you can write less, and the remainder - * will just be filled with zeroes. - * - * @param buf Pointer to the data to be sent - * @param len Number of bytes to be sent - * @return True if the payload was delivered successfully false if not - */ - bool write( const void* buf, uint8_t len ); - - /** - * Test whether there are bytes available to be read - * - * @return True if there is a payload available, false if none is - */ - bool available(void); - - /** - * Read the payload - * - * Return the last payload received - * - * The size of data read is the fixed payload size, see getPayloadSize() - * - * @note I specifically chose 'void*' as a data type to make it easier - * for beginners to use. No casting needed. - * - * @param buf Pointer to a buffer where the data should be written - * @param len Maximum number of bytes to read into the buffer - * @return True if the payload was delivered successfully false if not - */ - bool read( void* buf, uint8_t len ); - - /** - * Open a pipe for writing - * - * Only one pipe can be open at once, but you can change the pipe - * you'll listen to. Do not call this while actively listening. - * Remember to stopListening() first. - * - * Addresses are 40-bit hex values, e.g.: - * - * @code - * openWritingPipe(0xF0F0F0F0F0); - * @endcode - * - * @param address The 40-bit address of the pipe to open. This can be - * any value whatsoever, as long as you are the only one writing to it - * and only one other radio is listening to it. Coordinate these pipe - * addresses amongst nodes on the network. - */ - void openWritingPipe(uint64_t address); - - /** - * Open a pipe for reading - * - * Up to 6 pipes can be open for reading at once. Open all the - * reading pipes, and then call startListening(). - * - * @see openWritingPipe - * - * @warning Pipes 1-5 should share the first 32 bits. - * Only the least significant byte should be unique, e.g. - * @code - * openReadingPipe(1,0xF0F0F0F0AA); - * openReadingPipe(2,0xF0F0F0F066); - * @endcode - * - * @warning Pipe 0 is also used by the writing pipe. So if you open - * pipe 0 for reading, and then startListening(), it will overwrite the - * writing pipe. Ergo, do an openWritingPipe() again before write(). - * - * @todo Enforce the restriction that pipes 1-5 must share the top 32 bits - * - * @param number Which pipe# to open, 0-5. - * @param address The 40-bit address of the pipe to open. - */ - void openReadingPipe(uint8_t number, uint64_t address); - - /**@}*/ - /** - * @name Optional Configurators - * - * Methods you can use to get or set the configuration of the chip. - * None are required. Calling begin() sets up a reasonable set of - * defaults. - */ - /**@{*/ - /** - * Set the number and delay of retries upon failed submit - * - * @param delay How long to wait between each retry, in multiples of 250us, - * max is 15. 0 means 250us, 15 means 4000us. - * @param count How many retries before giving up, max 15 - */ - void setRetries(uint8_t delay, uint8_t count); - - /** - * Set RF communication channel - * - * @param channel Which RF channel to communicate on, 0-127 - */ - void setChannel(uint8_t channel); - - /** - * Set Static Payload Size - * - * This implementation uses a pre-stablished fixed payload size for all - * transmissions. If this method is never called, the driver will always - * transmit the maximum payload size (32 bytes), no matter how much - * was sent to write(). - * - * @todo Implement variable-sized payloads feature - * - * @param size The number of bytes in the payload - */ - void setPayloadSize(uint8_t size); - - /** - * Get Static Payload Size - * - * @see setPayloadSize() - * - * @return The number of bytes in the payload - */ - uint8_t getPayloadSize(void); - - /** - * Get Dynamic Payload Size - * - * For dynamic payloads, this pulls the size of the payload off - * the chip - * - * @return Payload length of last-received dynamic payload - */ - uint8_t getDynamicPayloadSize(void); - - /** - * Enable custom payloads on the acknowledge packets - * - * Ack payloads are a handy way to return data back to senders without - * manually changing the radio modes on both units. - * - * @see examples/pingpair_pl/pingpair_pl.pde - */ - void enableAckPayload(void); - - /** - * Enable dynamically-sized payloads - * - * This way you don't always have to send large packets just to send them - * once in a while. This enables dynamic payloads on ALL pipes. - * - * @see examples/pingpair_pl/pingpair_dyn.pde - */ - void enableDynamicPayloads(void); - - /** - * Determine whether the hardware is an nRF24L01+ or not. - * - * @return true if the hardware is nRF24L01+ (or compatible) and false - * if its not. - */ - bool isPVariant(void) ; - - /** - * Enable or disable auto-acknowlede packets - * - * This is enabled by default, so it's only needed if you want to turn - * it off for some reason. - * - * @param enable Whether to enable (true) or disable (false) auto-acks - */ - void setAutoAck(bool enable); - - /** - * Enable or disable auto-acknowlede packets on a per pipeline basis. - * - * AA is enabled by default, so it's only needed if you want to turn - * it off/on for some reason on a per pipeline basis. - * - * @param pipe Which pipeline to modify - * @param enable Whether to enable (true) or disable (false) auto-acks - */ - void setAutoAck( uint8_t pipe, bool enable ) ; - - /** - * Set Power Amplifier (PA) level to one of four levels. - * Relative mnemonics have been used to allow for future PA level - * changes. According to 6.5 of the nRF24L01+ specification sheet, - * they translate to: RF24_PA_MIN=-18dBm, RF24_PA_LOW=-12dBm, - * RF24_PA_MED=-6dBM, and RF24_PA_HIGH=0dBm. - * - * @param level Desired PA level. - */ - void setPALevel( rf24_pa_dbm_e level ) ; - - /** - * Fetches the current PA level. - * - * @return Returns a value from the rf24_pa_dbm_e enum describing - * the current PA setting. Please remember, all values represented - * by the enum mnemonics are negative dBm. See setPALevel for - * return value descriptions. - */ - rf24_pa_dbm_e getPALevel( void ) ; - - /** - * Set the transmission data rate - * - * @warning setting RF24_250KBPS will fail for non-plus units - * - * @param speed RF24_250KBPS for 250kbs, RF24_1MBPS for 1Mbps, or RF24_2MBPS for 2Mbps - * @return true if the change was successful - */ - bool setDataRate(rf24_datarate_e speed); - - /** - * Fetches the transmission data rate - * - * @return Returns the hardware's currently configured datarate. The value - * is one of 250kbs, RF24_1MBPS for 1Mbps, or RF24_2MBPS, as defined in the - * rf24_datarate_e enum. - */ - rf24_datarate_e getDataRate( void ) ; - - /** - * Set the CRC length - * - * @param length RF24_CRC_8 for 8-bit or RF24_CRC_16 for 16-bit - */ - void setCRCLength(rf24_crclength_e length); - - /** - * Get the CRC length - * - * @return RF24_DISABLED if disabled or RF24_CRC_8 for 8-bit or RF24_CRC_16 for 16-bit - */ - rf24_crclength_e getCRCLength(void); - - /** - * Disable CRC validation - * - */ - void disableCRC( void ) ; - - /**@}*/ - /** - * @name Advanced Operation - * - * Methods you can use to drive the chip in more advanced ways - */ - /**@{*/ - - /** - * Print a giant block of debugging information to stdout - * - * @warning Does nothing if stdout is not defined. See fdevopen in stdio.h - */ - void printDetails(void); - - /** - * Enter low-power mode - * - * To return to normal power mode, either write() some data or - * startListening, or powerUp(). - */ - void powerDown(void); - - /** - * Leave low-power mode - making radio more responsive - * - * To return to low power mode, call powerDown(). - */ - void powerUp(void) ; - - /** - * Test whether there are bytes available to be read - * - * Use this version to discover on which pipe the message - * arrived. - * - * @param[out] pipe_num Which pipe has the payload available - * @return True if there is a payload available, false if none is - */ - bool available(uint8_t* pipe_num); - - /** - * Non-blocking write to the open writing pipe - * - * Just like write(), but it returns immediately. To find out what happened - * to the send, catch the IRQ and then call whatHappened(). - * - * @see write() - * @see whatHappened() - * - * @param buf Pointer to the data to be sent - * @param len Number of bytes to be sent - * @return True if the payload was delivered successfully false if not - */ - void startWrite( const void* buf, uint8_t len ); - - /** - * Write an ack payload for the specified pipe - * - * The next time a message is received on @p pipe, the data in @p buf will - * be sent back in the acknowledgement. - * - * @warning According to the data sheet, only three of these can be pending - * at any time. I have not tested this. - * - * @param pipe Which pipe# (typically 1-5) will get this response. - * @param buf Pointer to data that is sent - * @param len Length of the data to send, up to 32 bytes max. Not affected - * by the static payload set by setPayloadSize(). - */ - void writeAckPayload(uint8_t pipe, const void* buf, uint8_t len); - - /** - * Determine if an ack payload was received in the most recent call to - * write(). - * - * Call read() to retrieve the ack payload. - * - * @warning Calling this function clears the internal flag which indicates - * a payload is available. If it returns true, you must read the packet - * out as the very next interaction with the radio, or the results are - * undefined. - * - * @return True if an ack payload is available. - */ - bool isAckPayloadAvailable(void); - - /** - * Call this when you get an interrupt to find out why - * - * Tells you what caused the interrupt, and clears the state of - * interrupts. - * - * @param[out] tx_ok The send was successful (TX_DS) - * @param[out] tx_fail The send failed, too many retries (MAX_RT) - * @param[out] rx_ready There is a message waiting to be read (RX_DS) - */ - void whatHappened(bool& tx_ok,bool& tx_fail,bool& rx_ready); - - /** - * Test whether there was a carrier on the line for the - * previous listening period. - * - * Useful to check for interference on the current channel. - * - * @return true if was carrier, false if not - */ - bool testCarrier(void); - - /** - * Test whether a signal (carrier or otherwise) greater than - * or equal to -64dBm is present on the channel. Valid only - * on nRF24L01P (+) hardware. On nRF24L01, use testCarrier(). - * - * Useful to check for interference on the current channel and - * channel hopping strategies. - * - * @return true if signal => -64dBm, false if not - */ - bool testRPD(void) ; - - /** - * Test whether this is a real radio, or a mock shim for - * debugging. Setting either pin to 0xff is the way to - * indicate that this is not a real radio. - * - * @return true if this is a legitimate radio - */ - bool isValid() { return ce_pin != 0xff && csn_pin != 0xff; } - - /**@}*/ -}; - -/** - * @example GettingStarted.pde - * - * This is an example which corresponds to my "Getting Started" blog post: - * Getting Started with nRF24L01+ on Arduino. - * - * It is an example of how to use the RF24 class. Write this sketch to two - * different nodes. Put one of the nodes into 'transmit' mode by connecting - * with the serial monitor and sending a 'T'. The ping node sends the current - * time to the pong node, which responds by sending the value back. The ping - * node can then see how long the whole cycle took. - */ - -/** - * @example nordic_fob.pde - * - * This is an example of how to use the RF24 class to receive signals from the - * Sparkfun Nordic FOB. See http://www.sparkfun.com/products/8602 . - * Thanks to Kirk Mower for providing test hardware. - */ - -/** - * @example led_remote.pde - * - * This is an example of how to use the RF24 class to control a remote - * bank of LED's using buttons on a remote control. - * - * Every time the buttons change on the remote, the entire state of - * buttons is send to the led board, which displays the state. - */ - -/** - * @example pingpair.pde - * - * This is an example of how to use the RF24 class. Write this sketch to two - * different nodes, connect the role_pin to ground on one. The ping node sends - * the current time to the pong node, which responds by sending the value back. - * The ping node can then see how long the whole cycle took. - */ - -/** - * @example pingpair_maple.pde - * - * This is an example of how to use the RF24 class on the Maple. For a more - * detailed explanation, see my blog post: - * nRF24L01+ Running on Maple - * - * It will communicate well to an Arduino-based unit as well, so it's not for only Maple-to-Maple communication. - * - * Write this sketch to two different nodes, - * connect the role_pin to ground on one. The ping node sends the current time to the pong node, - * which responds by sending the value back. The ping node can then see how long the whole cycle - * took. - */ - -/** - * @example starping.pde - * - * This sketch is a more complex example of using the RF24 library for Arduino. - * Deploy this on up to six nodes. Set one as the 'pong receiver' by tying the - * role_pin low, and the others will be 'ping transmit' units. The ping units - * unit will send out the value of millis() once a second. The pong unit will - * respond back with a copy of the value. Each ping unit can get that response - * back, and determine how long the whole cycle took. - * - * This example requires a bit more complexity to determine which unit is which. - * The pong receiver is identified by having its role_pin tied to ground. - * The ping senders are further differentiated by a byte in eeprom. - */ - -/** - * @example pingpair_pl.pde - * - * This is an example of how to do two-way communication without changing - * transmit/receive modes. Here, a payload is set to the transmitter within - * the Ack packet of each transmission. Note that the payload is set BEFORE - * the sender's message arrives. - */ - -/** - * @example pingpair_irq.pde - * - * This is an example of how to user interrupts to interact with the radio. - * It builds on the pingpair_pl example, and uses ack payloads. - */ - -/** - * @example pingpair_sleepy.pde - * - * This is an example of how to use the RF24 class to create a battery- - * efficient system. It is just like the pingpair.pde example, but the - * ping node powers down the radio and sleeps the MCU after every - * ping/pong cycle. - */ - -/** - * @example scanner.pde - * - * Example to detect interference on the various channels available. - * This is a good diagnostic tool to check whether you're picking a - * good channel for your application. - * - * Inspired by cpixip. - * See http://arduino.cc/forum/index.php/topic,54795.0.html - */ - -/** - * @mainpage Driver for nRF24L01(+) 2.4GHz Wireless Transceiver - * - * @section Goals Design Goals - * - * This library is designed to be... - * @li Maximally compliant with the intended operation of the chip - * @li Easy for beginners to use - * @li Consumed with a public interface that's similiar to other Arduino standard libraries - * - * @section News News - * - * NOW COMPATIBLE WITH ARDUINO 1.0 - The 'master' branch and all examples work with both Arduino 1.0 and earlier versions. - * Please open an issue if you find any problems using it with any version of Arduino. - * - * NOW COMPATIBLE WITH MAPLE - RF24 has been tested with the - * Maple Native, - * and should work with any Maple board. See the pingpair_maple example. - * Note that only the pingpair_maple example has been tested on Maple, although - * the others can certainly be adapted. - * - * @section Useful Useful References - * - * Please refer to: - * - * @li Documentation Main Page - * @li RF24 Class Documentation - * @li Source Code - * @li Downloads Page - * @li Chip Datasheet - * - * This chip uses the SPI bus, plus two chip control pins. Remember that pin 10 must still remain an output, or - * the SPI hardware will go into 'slave' mode. - * - * @section More More Information - * - * @subpage FAQ - * - * @section Projects Projects - * - * Stuff I have built with RF24 - * - * RF24 Getting Started - Finished Product - * - * Getting Started with nRF24L01+ on Arduino - * - * Nordic FOB and nRF24L01+ - * - * Using the Sparkfun Nordic FOB - * - * RF Duinode V3 (2V4) - * - * Low-Power Wireless Sensor Node - * - * nRF24L01+ connected to Leaf Labs Maple Native - * - * nRF24L01+ Running on Maple - */ - -#endif // __RF24_H__ -// vim:ai:cin:sts=2 sw=2 ft=cpp - diff --git a/RF24_config.h b/RF24_config.h deleted file mode 100644 index fc7397fb..00000000 --- a/RF24_config.h +++ /dev/null @@ -1,65 +0,0 @@ - -/* - Copyright (C) 2011 J. Coliz - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - version 2 as published by the Free Software Foundation. - */ - -#ifndef __RF24_CONFIG_H__ -#define __RF24_CONFIG_H__ - -#if ARDUINO < 100 -#include -#else -#include -#endif - -#include - -// Stuff that is normally provided by Arduino -#ifdef ARDUINO -#include -#else -#include -#include -#include -extern HardwareSPI SPI; -#define _BV(x) (1<<(x)) -#endif - -#undef SERIAL_DEBUG -#ifdef SERIAL_DEBUG -#define IF_SERIAL_DEBUG(x) ({x;}) -#else -#define IF_SERIAL_DEBUG(x) -#endif - -// Avoid spurious warnings -#if 1 -#if ! defined( NATIVE ) && defined( ARDUINO ) -#undef PROGMEM -#define PROGMEM __attribute__(( section(".progmem.data") )) -#undef PSTR -#define PSTR(s) (__extension__({static const char __c[] PROGMEM = (s); &__c[0];})) -#endif -#endif - -// Progmem is Arduino-specific -#ifdef ARDUINO -#include -#define PRIPSTR "%S" -#else -typedef char const char; -typedef uint16_t prog_uint16_t; -#define PSTR(x) (x) -#define printf_P printf -#define strlen_P strlen -#define PROGMEM -#define pgm_read_word(p) (*(p)) -#define PRIPSTR "%s" -#endif - -#endif // __RF24_CONFIG_H__ -// vim:ai:cin:sts=2 sw=2 ft=cpp diff --git a/examples/GettingStarted/GettingStarted.pde b/examples/GettingStarted/GettingStarted.pde deleted file mode 100644 index bf1851ac..00000000 --- a/examples/GettingStarted/GettingStarted.pde +++ /dev/null @@ -1,227 +0,0 @@ -/* - Copyright (C) 2011 J. Coliz - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - version 2 as published by the Free Software Foundation. - */ - -/** - * Example for Getting Started with nRF24L01+ radios. - * - * This is an example of how to use the RF24 class. Write this sketch to two - * different nodes. Put one of the nodes into 'transmit' mode by connecting - * with the serial monitor and sending a 'T'. The ping node sends the current - * time to the pong node, which responds by sending the value back. The ping - * node can then see how long the whole cycle took. - */ - -#include -#include "nRF24L01.h" -#include "RF24.h" -#include "printf.h" - -// -// Hardware configuration -// - -// Set up nRF24L01 radio on SPI bus plus pins 9 & 10 - -RF24 radio(9,10); - -// -// Topology -// - -// Radio pipe addresses for the 2 nodes to communicate. -const uint64_t pipes[2] = { 0xF0F0F0F0E1LL, 0xF0F0F0F0D2LL }; - -// -// Role management -// -// Set up role. This sketch uses the same software for all the nodes -// in this system. Doing so greatly simplifies testing. -// - -// The various roles supported by this sketch -typedef enum { role_ping_out = 1, role_pong_back } role_e; - -// The debug-friendly names of those roles -const char* role_friendly_name[] = { "invalid", "Ping out", "Pong back"}; - -// The role of the current running sketch -role_e role = role_pong_back; - -void setup(void) -{ - // - // Print preamble - // - - Serial.begin(57600); - printf_begin(); - printf("\n\rRF24/examples/GettingStarted/\n\r"); - printf("ROLE: %s\n\r",role_friendly_name[role]); - printf("*** PRESS 'T' to begin transmitting to the other node\n\r"); - - // - // Setup and configure rf radio - // - - radio.begin(); - - // optionally, increase the delay between retries & # of retries - radio.setRetries(15,15); - - // optionally, reduce the payload size. seems to - // improve reliability - //radio.setPayloadSize(8); - - // - // Open pipes to other nodes for communication - // - - // This simple sketch opens two pipes for these two nodes to communicate - // back and forth. - // Open 'our' pipe for writing - // Open the 'other' pipe for reading, in position #1 (we can have up to 5 pipes open for reading) - - //if ( role == role_ping_out ) - { - //radio.openWritingPipe(pipes[0]); - radio.openReadingPipe(1,pipes[1]); - } - //else - { - //radio.openWritingPipe(pipes[1]); - //radio.openReadingPipe(1,pipes[0]); - } - - // - // Start listening - // - - radio.startListening(); - - // - // Dump the configuration of the rf unit for debugging - // - - radio.printDetails(); -} - -void loop(void) -{ - // - // Ping out role. Repeatedly send the current time - // - - if (role == role_ping_out) - { - // First, stop listening so we can talk. - radio.stopListening(); - - // Take the time, and send it. This will block until complete - unsigned long time = millis(); - printf("Now sending %lu...",time); - bool ok = radio.write( &time, sizeof(unsigned long) ); - - if (ok) - printf("ok..."); - else - printf("failed.\n\r"); - - // Now, continue listening - radio.startListening(); - - // Wait here until we get a response, or timeout (250ms) - unsigned long started_waiting_at = millis(); - bool timeout = false; - while ( ! radio.available() && ! timeout ) - if (millis() - started_waiting_at > 200 ) - timeout = true; - - // Describe the results - if ( timeout ) - { - printf("Failed, response timed out.\n\r"); - } - else - { - // Grab the response, compare, and send to debugging spew - unsigned long got_time; - radio.read( &got_time, sizeof(unsigned long) ); - - // Spew it - printf("Got response %lu, round-trip delay: %lu\n\r",got_time,millis()-got_time); - } - - // Try again 1s later - delay(1000); - } - - // - // Pong back role. Receive each packet, dump it out, and send it back - // - - if ( role == role_pong_back ) - { - // if there is data ready - if ( radio.available() ) - { - // Dump the payloads until we've gotten everything - unsigned long got_time; - bool done = false; - while (!done) - { - // Fetch the payload, and see if this was the last one. - done = radio.read( &got_time, sizeof(unsigned long) ); - - // Spew it - printf("Got payload %lu...",got_time); - - // Delay just a little bit to let the other unit - // make the transition to receiver - delay(20); - } - - // First, stop listening so we can talk - radio.stopListening(); - - // Send the final one back. - radio.write( &got_time, sizeof(unsigned long) ); - printf("Sent response.\n\r"); - - // Now, resume listening so we catch the next packets. - radio.startListening(); - } - } - - // - // Change roles - // - - if ( Serial.available() ) - { - char c = toupper(Serial.read()); - if ( c == 'T' && role == role_pong_back ) - { - printf("*** CHANGING TO TRANSMIT ROLE -- PRESS 'R' TO SWITCH BACK\n\r"); - - // Become the primary transmitter (ping out) - role = role_ping_out; - radio.openWritingPipe(pipes[0]); - radio.openReadingPipe(1,pipes[1]); - } - else if ( c == 'R' && role == role_ping_out ) - { - printf("*** CHANGING TO RECEIVE ROLE -- PRESS 'T' TO SWITCH BACK\n\r"); - - // Become the primary receiver (pong back) - role = role_pong_back; - radio.openWritingPipe(pipes[1]); - radio.openReadingPipe(1,pipes[0]); - } - } -} -// vim:cin:ai:sts=2 sw=2 ft=cpp diff --git a/examples/GettingStarted/Jamfile b/examples/GettingStarted/Jamfile deleted file mode 100644 index 9a5f2c47..00000000 --- a/examples/GettingStarted/Jamfile +++ /dev/null @@ -1,210 +0,0 @@ -# (1) Project Information - -PROJECT_LIBS = SPI RF24 ; - -# (2) Board Information - -UPLOAD_PROTOCOL ?= arduino ; -UPLOAD_SPEED ?= 57600 ; -MCU ?= atmega328p ; -F_CPU ?= 16000000 ; -CORE ?= arduino ; -VARIANT ?= standard ; -ARDUINO_VERSION ?= 100 ; - -# (3) USB Ports - -PORTS = p4 p6 p9 u0 u1 u2 ; -PORT_p6 = /dev/tty.usbserial-A600eHIs ; -PORT_p4 = /dev/tty.usbserial-A40081RP ; -PORT_p9 = /dev/tty.usbserial-A9007LmI ; -PORT_u0 = /dev/ttyUSB0 ; -PORT_u1 = /dev/ttyUSB1 ; -PORT_u2 = /dev/ttyUSB2 ; - -# (4) Location of AVR tools -# -# This configuration assumes using avr-tools that were obtained separate from the Arduino -# distribution. - -if $(OS) = MACOSX -{ - AVR_BIN = /usr/local/avrtools/bin ; - AVR_ETC = /usr/local/avrtools/etc ; - AVR_INCLUDE = /usr/local/avrtools/include ; -} -else -{ - AVR_BIN ?= /usr/bin ; - AVR_INCLUDE ?= /usr/lib/avr/include ; - AVR_ETC = /etc ; -} - -# (5) Directories where Arduino core and libraries are located - -ARDUINO_DIR ?= /opt/Arduino ; -ARDUINO_CORE = $(ARDUINO_DIR)/hardware/arduino/cores/$(CORE) $(ARDUINO_DIR)/hardware/arduino/variants/$(VARIANT) ; -ARDUINO_LIB = $(ARDUINO_DIR)/libraries ; -SKETCH_LIB = $(HOME)/Source/Arduino/libraries ; - -# -# -------------------------------------------------- -# Below this line usually never needs to be modified -# - -# Tool locations - -CC = $(AVR_BIN)/avr-gcc ; -C++ = $(AVR_BIN)/avr-g++ ; -LINK = $(AVR_BIN)/avr-gcc ; -OBJCOPY = $(AVR_BIN)/avr-objcopy ; -AVRDUDE = $(AVR_BIN)/avrdude ; - -# Flags - -DEFINES += F_CPU=$(F_CPU)L ARDUINO=$(ARDUINO_VERSION) VERSION_H ; -OPTIM = -Os ; -CCFLAGS = -Wall -Wextra -mmcu=$(MCU) -ffunction-sections -fdata-sections ; -C++FLAGS = $(CCFLAGS) -fno-exceptions -fno-strict-aliasing ; -LINKFLAGS = $(OPTIM) -lm -Wl,--gc-sections -mmcu=$(MCU) ; -AVRDUDEFLAGS = -V -F -D -C $(AVR_ETC)/avrdude.conf -p $(MCU) -c $(UPLOAD_PROTOCOL) -b $(UPLOAD_SPEED) ; - -# Search everywhere for headers - -HDRS = $(PWD) $(AVR_INCLUDE) $(ARDUINO_CORE) $(ARDUINO_LIB)/$(PROJECT_LIBS) $(ARDUINO_LIB)/$(PROJECT_LIBS)/utility $(SKETCH_LIB)/$(PROJECT_LIBS) ; - -# Output locations - -LOCATE_TARGET = $(F_CPU) ; -LOCATE_SOURCE = $(F_CPU) ; - -# -# Custom rules -# - -rule GitVersion -{ - Always $(<) ; - Depends all : $(<) ; -} - -actions GitVersion -{ - echo "const char program_version[] = \"\\" > $(<) - git log -1 --pretty=format:%h >> $(<) - echo "\";" >> $(<) -} - -GitVersion version.h ; - -rule Pde -{ - Depends $(<) : $(>) ; - MakeLocate $(<) : $(LOCATE_SOURCE) ; - Clean clean : $(<) ; -} - -if ( $(ARDUINO_VERSION) < 100 ) -{ - ARDUINO_H = WProgram.h ; -} -else -{ - ARDUINO_H = Arduino.h ; -} - -actions Pde -{ - echo "#include <$(ARDUINO_H)>" > $(<) - echo "#line 1 \"$(>)\"" >> $(<) - cat $(>) >> $(<) -} - -rule C++Pde -{ - local _CPP = $(>:B).cpp ; - Pde $(_CPP) : $(>) ; - C++ $(<) : $(_CPP) ; -} - -rule UserObject -{ - switch $(>:S) - { - case .ino : C++Pde $(<) : $(>) ; - case .pde : C++Pde $(<) : $(>) ; - } -} - -rule Objects -{ - local _i ; - - for _i in [ FGristFiles $(<) ] - { - local _b = $(_i:B)$(SUFOBJ) ; - local _o = $(_b:G=$(SOURCE_GRIST:E)) ; - Object $(_o) : $(_i) ; - Depends obj : $(_o) ; - } -} - -rule Main -{ - MainFromObjects $(<) : $(>:B)$(SUFOBJ) ; - Objects $(>) ; -} - -rule Hex -{ - Depends $(<) : $(>) ; - MakeLocate $(<) : $(LOCATE_TARGET) ; - Depends hex : $(<) ; - Clean clean : $(<) ; -} - -actions Hex -{ - $(OBJCOPY) -O ihex -R .eeprom $(>) $(<) -} - -rule Upload -{ - Depends $(1) : $(2) ; - Depends $(2) : $(3) ; - NotFile $(1) ; - Always $(1) ; - Always $(2) ; - UploadAction $(2) : $(3) ; -} - -actions UploadAction -{ - $(AVRDUDE) $(AVRDUDEFLAGS) -P $(<) $(AVRDUDE_WRITE_FLASH) -U flash:w:$(>):i -} - -# -# Targets -# - -# Grab everything from the core directory -CORE_MODULES = [ GLOB $(ARDUINO_CORE) : *.c *.cpp ] ; - -# Grab everything from libraries. To avoid this "grab everything" behaviour, you -# can specify specific modules to pick up in PROJECT_MODULES -LIB_MODULES = [ GLOB $(ARDUINO_LIB)/$(PROJECT_LIBS) $(ARDUINO_LIB)/$(PROJECT_LIBS)/utility $(SKETCH_LIB)/$(PROJECT_LIBS) : *.cpp *.c ] ; - -# Grab everything from the current dir -PROJECT_MODULES += [ GLOB $(PWD) : *.c *.cpp *.pde *.ino ] ; - -# Main output executable -MAIN = $(PWD:B).elf ; - -Main $(MAIN) : $(CORE_MODULES) $(LIB_MODULES) $(PROJECT_MODULES) ; -Hex $(MAIN:B).hex : $(MAIN) ; - -# Upload targets -for _p in $(PORTS) -{ - Upload $(_p) : $(PORT_$(_p)) : $(MAIN:B).hex ; -} diff --git a/examples/GettingStarted/printf.h b/examples/GettingStarted/printf.h deleted file mode 100644 index b2efd56b..00000000 --- a/examples/GettingStarted/printf.h +++ /dev/null @@ -1,37 +0,0 @@ -/* - Copyright (C) 2011 J. Coliz - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - version 2 as published by the Free Software Foundation. - */ - -/** - * @file printf.h - * - * Setup necessary to direct stdout to the Arduino Serial library, which - * enables 'printf' - */ - -#ifndef __PRINTF_H__ -#define __PRINTF_H__ - -#ifdef ARDUINO - -int serial_putc( char c, FILE * ) -{ - Serial.write( c ); - - return c; -} - -void printf_begin(void) -{ - fdevopen( &serial_putc, 0 ); -} - -#else -#error This example is only for use on Arduino. -#endif // ARDUINO - -#endif // __PRINTF_H__ diff --git a/examples/led_remote/Jamfile b/examples/led_remote/Jamfile deleted file mode 100644 index 901f8da8..00000000 --- a/examples/led_remote/Jamfile +++ /dev/null @@ -1,206 +0,0 @@ -PROJECT_NAME = $(PWD:B) ; -PROJECT_DIR = . ; -PROJECT_LIBS = SPI RF24 ; - -OUT_DIR = ojam ; -F_CPU = 16000000 ; -MCU = atmega328p ; -PORTS = /dev/tty.usbserial-A600eHIs /dev/tty.usbserial-A40081RP /dev/tty.usbserial-A9007LmI ; - -UPLOAD_RATE = 57600 ; -AVRDUDE_PROTOCOL = stk500v1 ; -COM = 33 ; - -# Host-specific overrides for locations -if $(OS) = MACOSX -{ -ARDUINO_VERSION = 22 ; -OLD_DIR = /opt/arduino-0021 ; -AVR_TOOLS_PATH = $(OLD_DIR)/hardware/tools/avr/bin ; -AVRDUDECONFIG_PATH = $(OLD_DIR)/hardware/tools/avr/etc ; -ARDUINO_DIR = /opt/Arduino ; -ARDUINO_AVR = /usr/lib/avr/include ; -} - -# Where is everything? -ARDUINO_VERSION ?= 22 ; -AVR_TOOLS_PATH ?= /usr/bin ; -ARDUINO_DIR ?= /opt/arduino-00$(ARDUINO_VERSION) ; -ARDUINO_AVR ?= $(ARDUINO_DIR)/hardware/tools/avr/avr/include/avr ; -AVRDUDECONFIG_PATH ?= $(ARDUINO_DIR)/hardware/tools ; -ARDUINO_CORE = $(ARDUINO_DIR)/hardware/arduino/cores/arduino ; -ARDUINO_LIB = $(ARDUINO_DIR)/libraries ; -SKETCH_LIB = $(HOME)/Source/Arduino/libraries ; -AVR_CC = $(AVR_TOOLS_PATH)/avr-gcc ; -AVR_CXX = $(AVR_TOOLS_PATH)/avr-g++ ; -AVR_LD = $(AVR_TOOLS_PATH)/avr-gcc ; -AVR_OBJCOPY = $(AVR_TOOLS_PATH)/avr-objcopy ; -AVRDUDE = $(AVR_TOOLS_PATH)/avrdude ; - -DEFINES = F_CPU=$(F_CPU)L ARDUINO=$(ARDUINO_VERSION) VERSION_H ; -CTUNING = -ffunction-sections -fdata-sections ; -CXXTUNING = -fno-exceptions -fno-strict-aliasing ; -CFLAGS = -Os -Wall -Wextra -mmcu=$(MCU) $(CTUNING) ; -CXXFLAGS = $(CFLAGS) $(CXXTUNING) ; -LDFLAGS = -Os -lm -Wl,--gc-sections -mmcu=atmega328p ; - -# Search everywhere for headers -HDRS = $(PROJECT_DIR) $(ARDUINO_AVR) $(ARDUINO_CORE) [ GLOB $(ARDUINO_LIB) $(SKETCH_LIB) : [^.]* ] ; - -# Grab everything from the core directory -CORE_MODULES = [ GLOB $(ARDUINO_CORE) : *.c *.cpp ] ; - -# Grab everything from libraries. To avoid this "grab everything" behaviour, you -# can specify specific modules to pick up in PROJECT_MODULES -LIB_MODULES = [ GLOB $(ARDUINO_LIB)/$(PROJECT_LIBS) $(SKETCH_LIB)/$(PROJECT_LIBS) : *.cpp ] ; - -# In addition to explicitly-specified program modules, pick up anything from the current -# dir. -PROJECT_MODULES += [ GLOB $(PROJECT_DIR) : *.c *.cpp *.pde ] ; - -# Shortcut for the out files -OUT = $(OUT_DIR)/$(PROJECT_NAME) ; - -# AvrDude setup -AVRDUDE_FLAGS = -V -F -D -C $(AVRDUDECONFIG_PATH)/avrdude.conf -p $(MCU) -c $(AVRDUDE_PROTOCOL) -b $(UPLOAD_RATE) ; - -rule GitVersion -{ - Always $(<) ; - Depends all : $(<) ; -} - -actions GitVersion -{ - echo "const char program_version[] = \"\\" > $(<) - git log -1 --pretty=format:%h >> $(<) - echo "\";" >> $(<) -} - -GitVersion version.h ; - -rule AvrCc -{ - Depends $(<) : $(>) ; - Depends $(<) : $(<:D) ; - Clean clean : $(<) ; - - CCHDRS on $(<) = [ on $(<) FIncludes $(HDRS) ] ; - CCDEFS on $(<) = [ on $(<) FDefines $(DEFINES) ] ; -} - -actions AvrCc -{ - $(AVR_CC) -c -o $(<) $(CCHDRS) $(CCDEFS) $(CFLAGS) $(>) -} - -rule AvrC++ -{ - Depends $(<) : $(>) ; - Depends $(<) : $(<:D) ; - Clean clean : $(<) ; - - CCHDRS on $(<) = [ on $(<) FIncludes $(HDRS) ] ; - CCDEFS on $(<) = [ on $(<) FDefines $(DEFINES) ] ; -} - -actions AvrC++ -{ - $(AVR_CXX) -c -o $(<) $(CCHDRS) $(CCDEFS) $(CXXFLAGS) $(>) -} - -rule Pde -{ - Depends $(<) : $(>) ; - Depends $(<) : $(<:D) ; - Clean clean : $(<) ; - -} - -actions Pde -{ - echo "#include " > $(<) - echo "#line 1 \"$(>)\"" >> $(<) - cat $(>) >> $(<) -} - -rule AvrPde -{ - local _CPP = $(OUT_DIR)/$(_I:B).cpp ; - Pde $(_CPP) : $(>) ; - AvrC++ $(<) : $(_CPP) ; -} - -rule AvrObject -{ - switch $(>:S) - { - case .c : AvrCc $(<) : $(>) ; - case .cpp : AvrC++ $(<) : $(>) ; - case .pde : AvrPde $(<) : $(>) ; - } -} - -rule AvrObjects -{ - for _I in $(<) - { - AvrObject $(OUT_DIR)/$(_I:B).o : $(_I) ; - } -} - -rule AvrMainFromObjects -{ - Depends $(<) : $(>) ; - Depends $(<) : $(<:D) ; - MkDir $(<:D) ; - Depends all : $(<) ; - Clean clean : $(<) ; -} - -actions AvrMainFromObjects -{ - $(AVR_LD) $(LDFLAGS) -o $(<) $(>) -} - -rule AvrMain -{ - AvrMainFromObjects $(<) : $(OUT_DIR)/$(>:B).o ; - AvrObjects $(>) ; -} - -rule AvrHex -{ - Depends $(<) : $(>) ; - Depends $(<) : $(<:D) ; - Depends hex : $(<) ; - Clean clean : $(<) ; -} - -actions AvrHex -{ - $(AVR_OBJCOPY) -O ihex -R .eeprom $(>) $(<) -} - -rule AvrUpload -{ - Depends $(1) : $(2) ; - Depends $(2) : $(3) ; - NotFile $(1) ; - Always $(1) ; - Always $(2) ; - AvrUploadAction $(2) : $(3) ; -} - -actions AvrUploadAction -{ - $(AVRDUDE) $(AVRDUDE_FLAGS) -P $(<) $(AVRDUDE_WRITE_FLASH) -U flash:w:$(>):i -} - -AvrMain $(OUT).elf : $(CORE_MODULES) $(LIB_MODULES) $(PROJECT_MODULES) ; -AvrHex $(OUT).hex : $(OUT).elf ; - -AvrUpload p6 : /dev/tty.usbserial-A600eHIs : $(OUT).hex ; -AvrUpload p4 : /dev/tty.usbserial-A40081RP : $(OUT).hex ; -AvrUpload p9 : /dev/tty.usbserial-A9007LmI : $(OUT).hex ; - diff --git a/examples/led_remote/led_remote.pde b/examples/led_remote/led_remote.pde deleted file mode 100644 index 80e29557..00000000 --- a/examples/led_remote/led_remote.pde +++ /dev/null @@ -1,255 +0,0 @@ -/* - Copyright (C) 2011 J. Coliz - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - version 2 as published by the Free Software Foundation. - */ - -/** - * Example LED Remote - * - * This is an example of how to use the RF24 class to control a remote - * bank of LED's using buttons on a remote control. - * - * On the 'remote', connect any number of buttons or switches from - * an arduino pin to ground. Update 'button_pins' to reflect the - * pins used. - * - * On the 'led' board, connect the same number of LED's from an - * arduino pin to a resistor to ground. Update 'led_pins' to reflect - * the pins used. Also connect a separate pin to ground and change - * the 'role_pin'. This tells the sketch it's running on the LED board. - * - * Every time the buttons change on the remote, the entire state of - * buttons is send to the led board, which displays the state. - */ - -#include -#include "nRF24L01.h" -#include "RF24.h" -#include "printf.h" - -// -// Hardware configuration -// - -// Set up nRF24L01 radio on SPI bus plus pins 9 & 10 - -RF24 radio(9,10); - -// sets the role of this unit in hardware. Connect to GND to be the 'led' board receiver -// Leave open to be the 'remote' transmitter -const int role_pin = A4; - -// Pins on the remote for buttons -const uint8_t button_pins[] = { 2,3,4,5,6,7 }; -const uint8_t num_button_pins = sizeof(button_pins); - -// Pins on the LED board for LED's -const uint8_t led_pins[] = { 2,3,4,5,6,7 }; -const uint8_t num_led_pins = sizeof(led_pins); - -// -// Topology -// - -// Single radio pipe address for the 2 nodes to communicate. -const uint64_t pipe = 0xE8E8F0F0E1LL; - -// -// Role management -// -// Set up role. This sketch uses the same software for all the nodes in this -// system. Doing so greatly simplifies testing. The hardware itself specifies -// which node it is. -// -// This is done through the role_pin -// - -// The various roles supported by this sketch -typedef enum { role_remote = 1, role_led } role_e; - -// The debug-friendly names of those roles -const char* role_friendly_name[] = { "invalid", "Remote", "LED Board"}; - -// The role of the current running sketch -role_e role; - -// -// Payload -// - -uint8_t button_states[num_button_pins]; -uint8_t led_states[num_led_pins]; - -// -// Setup -// - -void setup(void) -{ - // - // Role - // - - // set up the role pin - pinMode(role_pin, INPUT); - digitalWrite(role_pin,HIGH); - delay(20); // Just to get a solid reading on the role pin - - // read the address pin, establish our role - if ( digitalRead(role_pin) ) - role = role_remote; - else - role = role_led; - - // - // Print preamble - // - - Serial.begin(57600); - printf_begin(); - printf("\n\rRF24/examples/led_remote/\n\r"); - printf("ROLE: %s\n\r",role_friendly_name[role]); - - // - // Setup and configure rf radio - // - - radio.begin(); - - // - // Open pipes to other nodes for communication - // - - // This simple sketch opens a single pipes for these two nodes to communicate - // back and forth. One listens on it, the other talks to it. - - if ( role == role_remote ) - { - radio.openWritingPipe(pipe); - } - else - { - radio.openReadingPipe(1,pipe); - } - - // - // Start listening - // - - if ( role == role_led ) - radio.startListening(); - - // - // Dump the configuration of the rf unit for debugging - // - - radio.printDetails(); - - // - // Set up buttons / LED's - // - - // Set pull-up resistors for all buttons - if ( role == role_remote ) - { - int i = num_button_pins; - while(i--) - { - pinMode(button_pins[i],INPUT); - digitalWrite(button_pins[i],HIGH); - } - } - - // Turn LED's ON until we start getting keys - if ( role == role_led ) - { - int i = num_led_pins; - while(i--) - { - pinMode(led_pins[i],OUTPUT); - led_states[i] = HIGH; - digitalWrite(led_pins[i],led_states[i]); - } - } - -} - -// -// Loop -// - -void loop(void) -{ - // - // Remote role. If the state of any button has changed, send the whole state of - // all buttons. - // - - if ( role == role_remote ) - { - // Get the current state of buttons, and - // Test if the current state is different from the last state we sent - int i = num_button_pins; - bool different = false; - while(i--) - { - uint8_t state = ! digitalRead(button_pins[i]); - if ( state != button_states[i] ) - { - different = true; - button_states[i] = state; - } - } - - // Send the state of the buttons to the LED board - if ( different ) - { - printf("Now sending..."); - bool ok = radio.write( button_states, num_button_pins ); - if (ok) - printf("ok\n\r"); - else - printf("failed\n\r"); - } - - // Try again in a short while - delay(20); - } - - // - // LED role. Receive the state of all buttons, and reflect that in the LEDs - // - - if ( role == role_led ) - { - // if there is data ready - if ( radio.available() ) - { - // Dump the payloads until we've gotten everything - bool done = false; - while (!done) - { - // Fetch the payload, and see if this was the last one. - done = radio.read( button_states, num_button_pins ); - - // Spew it - printf("Got buttons\n\r"); - - // For each button, if the button now on, then toggle the LED - int i = num_led_pins; - while(i--) - { - if ( button_states[i] ) - { - led_states[i] ^= HIGH; - digitalWrite(led_pins[i],led_states[i]); - } - } - } - } - } -} -// vim:ai:cin:sts=2 sw=2 ft=cpp diff --git a/examples/led_remote/printf.h b/examples/led_remote/printf.h deleted file mode 100644 index b2efd56b..00000000 --- a/examples/led_remote/printf.h +++ /dev/null @@ -1,37 +0,0 @@ -/* - Copyright (C) 2011 J. Coliz - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - version 2 as published by the Free Software Foundation. - */ - -/** - * @file printf.h - * - * Setup necessary to direct stdout to the Arduino Serial library, which - * enables 'printf' - */ - -#ifndef __PRINTF_H__ -#define __PRINTF_H__ - -#ifdef ARDUINO - -int serial_putc( char c, FILE * ) -{ - Serial.write( c ); - - return c; -} - -void printf_begin(void) -{ - fdevopen( &serial_putc, 0 ); -} - -#else -#error This example is only for use on Arduino. -#endif // ARDUINO - -#endif // __PRINTF_H__ diff --git a/examples/nordic_fob/Jamfile b/examples/nordic_fob/Jamfile deleted file mode 100644 index ec519f7c..00000000 --- a/examples/nordic_fob/Jamfile +++ /dev/null @@ -1,219 +0,0 @@ -# (1) Project Information - -PROJECT_LIBS = RF24 SPI ; -PROJECT_DIRS = $(PWD) ; - -# (2) Board Information - -UPLOAD_PROTOCOL ?= stk500v1 ; -UPLOAD_SPEED ?= 115200 ; -MCU ?= atmega328p ; -F_CPU ?= 16000000 ; -CORE ?= arduino ; -VARIANT ?= standard ; -ARDUINO_VERSION ?= 100 ; - -# (3) USB Ports - -PORTS = p4 p6 p9 u0 u1 u2 ; -PORT_p6 = /dev/tty.usbserial-A600eHIs ; -PORT_p4 = /dev/tty.usbserial-A40081RP ; -PORT_p9 = /dev/tty.usbserial-A9007LmI ; -PORT_u0 = /dev/ttyUSB0 ; -PORT_u1 = /dev/ttyUSB1 ; -PORT_u2 = /dev/ttyUSB2 ; - -# (4) Location of AVR tools -# -# This configuration assumes using avr-tools that were obtained separate from the Arduino -# distribution. - -if $(OS) = MACOSX -{ - AVR_BIN = /usr/local/avrtools/bin ; - AVR_ETC = /usr/local/avrtools/etc ; - AVR_INCLUDE = /usr/local/avrtools/include ; -} -else -{ - AVR_BIN = /usr/bin ; - AVR_INCLUDE = /usr/lib/avr/include ; - AVR_ETC = /etc ; -} - -# (5) Directories where Arduino core and libraries are located - -ARDUINO_DIR ?= /opt/Arduino ; -ARDUINO_CORE = $(ARDUINO_DIR)/hardware/arduino/cores/$(CORE) $(ARDUINO_DIR)/hardware/arduino/variants/$(VARIANT) ; -ARDUINO_LIB = $(ARDUINO_DIR)/libraries ; -SKETCH_LIB = $(HOME)/Source/Arduino/libraries ; - -# -# -------------------------------------------------- -# Below this line usually never needs to be modified -# - -# Tool locations - -CC = $(AVR_BIN)/avr-gcc ; -C++ = $(AVR_BIN)/avr-g++ ; -LINK = $(AVR_BIN)/avr-gcc ; -AR = $(AVR_BIN)/avr-ar rcs ; -RANLIB = ; -OBJCOPY = $(AVR_BIN)/avr-objcopy ; -AVRDUDE = $(AVR_BIN)/avrdude ; - -# Flags - -DEFINES += F_CPU=$(F_CPU)L ARDUINO=$(ARDUINO_VERSION) VERSION_H ; -OPTIM = -Os ; -CCFLAGS = -Wall -Wextra -Wno-strict-aliasing -mmcu=$(MCU) -ffunction-sections -fdata-sections ; -C++FLAGS = $(CCFLAGS) -fno-exceptions -fno-strict-aliasing ; -LINKFLAGS = $(OPTIM) -lm -Wl,--gc-sections -mmcu=$(MCU) ; -AVRDUDEFLAGS = -V -F -D -C $(AVR_ETC)/avrdude.conf -p $(MCU) -c $(UPLOAD_PROTOCOL) -b $(UPLOAD_SPEED) ; - -# Search everywhere for headers - -HDRS = $(PROJECT_DIRS) $(AVR_INCLUDE) $(ARDUINO_CORE) $(ARDUINO_LIB)/$(PROJECT_LIBS) $(ARDUINO_LIB)/$(PROJECT_LIBS)/utility $(SKETCH_LIB)/$(PROJECT_LIBS) ; - -# Output locations - -LOCATE_TARGET = $(F_CPU) ; -LOCATE_SOURCE = $(F_CPU) ; - -# -# Custom rules -# - -rule GitVersion -{ - Always $(<) ; - Depends all : $(<) ; -} - -actions GitVersion -{ - echo "const char program_version[] = \"\\" > $(<) - git log -1 --pretty=format:%h >> $(<) - echo "\";" >> $(<) -} - -GitVersion version.h ; - -rule Pde -{ - Depends $(<) : $(>) ; - MakeLocate $(<) : $(LOCATE_SOURCE) ; - Clean clean : $(<) ; -} - -if ( $(ARDUINO_VERSION) < 100 ) -{ - ARDUINO_H = WProgram.h ; -} -else -{ - ARDUINO_H = Arduino.h ; -} - -actions Pde -{ - echo "#include <$(ARDUINO_H)>" > $(<) - echo "#line 1 \"$(>)\"" >> $(<) - cat $(>) >> $(<) -} - -rule C++Pde -{ - local _CPP = $(>:B).cpp ; - Pde $(_CPP) : $(>) ; - C++ $(<) : $(_CPP) ; -} - -rule UserObject -{ - switch $(>:S) - { - case .ino : C++Pde $(<) : $(>) ; - case .pde : C++Pde $(<) : $(>) ; - } -} - -rule Objects -{ - local _i ; - - for _i in [ FGristFiles $(<) ] - { - local _b = $(_i:B)$(SUFOBJ) ; - local _o = $(_b:G=$(SOURCE_GRIST:E)) ; - Object $(_o) : $(_i) ; - Depends obj : $(_o) ; - } -} - -rule Library -{ - LibraryFromObjects $(<) : $(>:B)$(SUFOBJ) ; - Objects $(>) ; -} - -rule Main -{ - MainFromObjects $(<) : $(>:B)$(SUFOBJ) ; - Objects $(>) ; -} - -rule Hex -{ - Depends $(<) : $(>) ; - MakeLocate $(<) : $(LOCATE_TARGET) ; - Depends hex : $(<) ; - Clean clean : $(<) ; -} - -actions Hex -{ - $(OBJCOPY) -O ihex -R .eeprom $(>) $(<) -} - -rule Upload -{ - Depends $(1) : $(2) ; - Depends $(2) : $(3) ; - NotFile $(1) ; - Always $(1) ; - Always $(2) ; - UploadAction $(2) : $(3) ; -} - -actions UploadAction -{ - $(AVRDUDE) $(AVRDUDEFLAGS) -P $(<) $(AVRDUDE_WRITE_FLASH) -U flash:w:$(>):i -} - -rule Arduino -{ - LINKFLAGS on $(<) = $(LINKFLAGS) -Wl,-Map=$(LOCATE_TARGET)/$(<:B).map ; - Main $(<) : $(>) ; - LinkLibraries $(<) : libs core ; - Hex $(<:B).hex : $(<) ; - for _p in $(PORTS) - { - Upload $(_p) : $(PORT_$(_p)) : $(<:B).hex ; - } -} - -# -# Targets -# - -# Grab everything from the core directory -Library core : [ GLOB $(ARDUINO_CORE) : *.c *.cpp ] ; - -# Grab everything from libraries. To avoid this "grab everything" behaviour, you -# can specify specific modules to pick up in PROJECT_MODULES -Library libs : [ GLOB $(ARDUINO_LIB)/$(PROJECT_LIBS) $(ARDUINO_LIB)/$(PROJECT_LIBS)/utility $(SKETCH_LIB)/$(PROJECT_LIBS) : *.cpp *.c ] ; - -# Main output executable -Arduino $(PWD:B).elf : $(PROJECT_MODULES) [ GLOB $(PROJECT_DIRS) : *.c *.cpp *.pde *.ino ] ; diff --git a/examples/nordic_fob/nordic_fob.pde b/examples/nordic_fob/nordic_fob.pde deleted file mode 100644 index 5a316a0f..00000000 --- a/examples/nordic_fob/nordic_fob.pde +++ /dev/null @@ -1,142 +0,0 @@ -/* - Copyright (C) 2012 J. Coliz - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - version 2 as published by the Free Software Foundation. - */ - -/** - * Example Nordic FOB Receiver - * - * This is an example of how to use the RF24 class to receive signals from the - * Sparkfun Nordic FOB. Thanks to Kirk Mower for providing test hardware. - * - * See blog post at http://maniacbug.wordpress.com/2012/01/08/nordic-fob/ - */ - -#include -#include -#include "nRF24L01.h" -#include "printf.h" - -// -// Hardware configuration -// - -// Set up nRF24L01 radio on SPI bus plus pins 9 & 10 - -RF24 radio(9,10); - -// -// Payload -// - -struct payload_t -{ - uint8_t buttons; - uint16_t id; - uint8_t empty; -}; - -const char* button_names[] = { "Up", "Down", "Left", "Right", "Center" }; -const int num_buttons = 5; - -// -// Forward declarations -// - -uint16_t flip_endian(uint16_t in); - -// -// Setup -// - -void setup(void) -{ - // - // Print preamble - // - - Serial.begin(57600); - printf_begin(); - printf("\r\nRF24/examples/nordic_fob/\r\n"); - - // - // Setup and configure rf radio according to the built-in parameters - // of the FOB. - // - - radio.begin(); - radio.setChannel(2); - radio.setPayloadSize(4); - radio.setAutoAck(false); - radio.setCRCLength(RF24_CRC_8); - radio.openReadingPipe(1,0xE7E7E7E7E7LL); - - // - // Start listening - // - - radio.startListening(); - - // - // Dump the configuration of the rf unit for debugging - // - - radio.printDetails(); -} - -// -// Loop -// - -void loop(void) -{ - // - // Receive each packet, dump it out - // - - // if there is data ready - if ( radio.available() ) - { - // Get the packet from the radio - payload_t payload; - radio.read( &payload, sizeof(payload) ); - - // Print the ID of this message. Note that the message - // is sent 'big-endian', so we have to flip it. - printf("#%05u Buttons ",flip_endian(payload.id)); - - // Print the name of each button - int i = num_buttons; - while (i--) - { - if ( ! ( payload.buttons & _BV(i) ) ) - { - printf("%s ",button_names[i]); - } - } - - // If no buttons, print None - if ( payload.buttons == _BV(num_buttons) - 1 ) - printf("None"); - - printf("\r\n"); - } -} - -// -// Helper functions -// - -// Change a big-endian word into a little-endian -uint16_t flip_endian(uint16_t in) -{ - uint16_t low = in >> 8; - uint16_t high = in << 8; - - return high | low; -} - -// vim:cin:ai:sts=2 sw=2 ft=cpp diff --git a/examples/nordic_fob/printf.h b/examples/nordic_fob/printf.h deleted file mode 100644 index b2efd56b..00000000 --- a/examples/nordic_fob/printf.h +++ /dev/null @@ -1,37 +0,0 @@ -/* - Copyright (C) 2011 J. Coliz - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - version 2 as published by the Free Software Foundation. - */ - -/** - * @file printf.h - * - * Setup necessary to direct stdout to the Arduino Serial library, which - * enables 'printf' - */ - -#ifndef __PRINTF_H__ -#define __PRINTF_H__ - -#ifdef ARDUINO - -int serial_putc( char c, FILE * ) -{ - Serial.write( c ); - - return c; -} - -void printf_begin(void) -{ - fdevopen( &serial_putc, 0 ); -} - -#else -#error This example is only for use on Arduino. -#endif // ARDUINO - -#endif // __PRINTF_H__ diff --git a/examples/pingpair/Jamfile b/examples/pingpair/Jamfile deleted file mode 100644 index 18244ec8..00000000 --- a/examples/pingpair/Jamfile +++ /dev/null @@ -1,219 +0,0 @@ -# (1) Project Information - -PROJECT_LIBS = SPI RF24 ; -PROJECT_DIRS = $(PWD) ; - -# (2) Board Information - -UPLOAD_PROTOCOL ?= arduino ; -UPLOAD_SPEED ?= 115200 ; -MCU ?= atmega328p ; -F_CPU ?= 16000000 ; -CORE ?= arduino ; -VARIANT ?= standard ; -ARDUINO_VERSION ?= 100 ; - -# (3) USB Ports - -PORTS = p4 p6 p9 u0 u1 u2 ; -PORT_p6 = /dev/tty.usbserial-A600eHIs ; -PORT_p4 = /dev/tty.usbserial-A40081RP ; -PORT_p9 = /dev/tty.usbserial-A9007LmI ; -PORT_u0 = /dev/ttyUSB0 ; -PORT_u1 = /dev/ttyUSB1 ; -PORT_u2 = /dev/ttyUSB2 ; - -# (4) Location of AVR tools -# -# This configuration assumes using avr-tools that were obtained separate from the Arduino -# distribution. - -if $(OS) = MACOSX -{ - AVR_BIN ?= /usr/local/avrtools/bin ; - AVR_ETC = /usr/local/avrtools/etc ; - AVR_INCLUDE = /usr/local/avrtools/include ; -} -else -{ - AVR_BIN ?= /usr/bin ; - AVR_INCLUDE = /usr/lib/avr/include ; - AVR_ETC = /etc ; -} - -# (5) Directories where Arduino core and libraries are located - -ARDUINO_DIR ?= /opt/Arduino ; -ARDUINO_CORE = $(ARDUINO_DIR)/hardware/arduino/cores/$(CORE) $(ARDUINO_DIR)/hardware/arduino/variants/$(VARIANT) ; -ARDUINO_LIB = $(ARDUINO_DIR)/libraries ; -SKETCH_LIB = $(HOME)/Source/Arduino/libraries ; - -# -# -------------------------------------------------- -# Below this line usually never needs to be modified -# - -# Tool locations - -CC = $(AVR_BIN)/avr-gcc ; -C++ = $(AVR_BIN)/avr-g++ ; -LINK = $(AVR_BIN)/avr-gcc ; -AR = $(AVR_BIN)/avr-ar rcs ; -RANLIB = ; -OBJCOPY = $(AVR_BIN)/avr-objcopy ; -AVRDUDE ?= $(AVR_BIN)/avrdude ; - -# Flags - -DEFINES += F_CPU=$(F_CPU)L ARDUINO=$(ARDUINO_VERSION) VERSION_H ; -OPTIM = -Os ; -CCFLAGS = -Wall -Wextra -Wno-strict-aliasing -mmcu=$(MCU) -ffunction-sections -fdata-sections ; -C++FLAGS = $(CCFLAGS) -fno-exceptions -fno-strict-aliasing ; -LINKFLAGS = $(OPTIM) -lm -Wl,--gc-sections -mmcu=$(MCU) ; -AVRDUDEFLAGS = -V -F -D -C $(AVR_ETC)/avrdude.conf -p $(MCU) -c $(UPLOAD_PROTOCOL) -b $(UPLOAD_SPEED) ; - -# Search everywhere for headers - -HDRS = $(PROJECT_DIRS) $(AVR_INCLUDE) $(ARDUINO_CORE) $(ARDUINO_LIB)/$(PROJECT_LIBS) $(ARDUINO_LIB)/$(PROJECT_LIBS)/utility $(SKETCH_LIB)/$(PROJECT_LIBS) ; - -# Output locations - -LOCATE_TARGET = $(F_CPU) ; -LOCATE_SOURCE = $(F_CPU) ; - -# -# Custom rules -# - -rule GitVersion -{ - Always $(<) ; - Depends all : $(<) ; -} - -actions GitVersion -{ - echo "const char program_version[] = \"\\" > $(<) - git log -1 --pretty=format:%h >> $(<) - echo "\";" >> $(<) -} - -GitVersion version.h ; - -rule Pde -{ - Depends $(<) : $(>) ; - MakeLocate $(<) : $(LOCATE_SOURCE) ; - Clean clean : $(<) ; -} - -if ( $(ARDUINO_VERSION) < 100 ) -{ - ARDUINO_H = WProgram.h ; -} -else -{ - ARDUINO_H = Arduino.h ; -} - -actions Pde -{ - echo "#include <$(ARDUINO_H)>" > $(<) - echo "#line 1 \"$(>)\"" >> $(<) - cat $(>) >> $(<) -} - -rule C++Pde -{ - local _CPP = $(>:B).cpp ; - Pde $(_CPP) : $(>) ; - C++ $(<) : $(_CPP) ; -} - -rule UserObject -{ - switch $(>:S) - { - case .ino : C++Pde $(<) : $(>) ; - case .pde : C++Pde $(<) : $(>) ; - } -} - -rule Objects -{ - local _i ; - - for _i in [ FGristFiles $(<) ] - { - local _b = $(_i:B)$(SUFOBJ) ; - local _o = $(_b:G=$(SOURCE_GRIST:E)) ; - Object $(_o) : $(_i) ; - Depends obj : $(_o) ; - } -} - -rule Library -{ - LibraryFromObjects $(<) : $(>:B)$(SUFOBJ) ; - Objects $(>) ; -} - -rule Main -{ - MainFromObjects $(<) : $(>:B)$(SUFOBJ) ; - Objects $(>) ; -} - -rule Hex -{ - Depends $(<) : $(>) ; - MakeLocate $(<) : $(LOCATE_TARGET) ; - Depends hex : $(<) ; - Clean clean : $(<) ; -} - -actions Hex -{ - $(OBJCOPY) -O ihex -R .eeprom $(>) $(<) -} - -rule Upload -{ - Depends $(1) : $(2) ; - Depends $(2) : $(3) ; - NotFile $(1) ; - Always $(1) ; - Always $(2) ; - UploadAction $(2) : $(3) ; -} - -actions UploadAction -{ - $(AVRDUDE) $(AVRDUDEFLAGS) -P $(<) $(AVRDUDE_WRITE_FLASH) -U flash:w:$(>):i -} - -rule Arduino -{ - LINKFLAGS on $(<) = $(LINKFLAGS) -Wl,-Map=$(LOCATE_TARGET)/$(<:B).map ; - Main $(<) : $(>) ; - LinkLibraries $(<) : core libs ; - Hex $(<:B).hex : $(<) ; - for _p in $(PORTS) - { - Upload $(_p) : $(PORT_$(_p)) : $(<:B).hex ; - } -} - -# -# Targets -# - -# Grab everything from the core directory -Library core : [ GLOB $(ARDUINO_CORE) : *.c *.cpp ] ; - -# Grab everything from libraries. To avoid this "grab everything" behaviour, you -# can specify specific modules to pick up in PROJECT_MODULES -Library libs : [ GLOB $(ARDUINO_LIB)/$(PROJECT_LIBS) $(ARDUINO_LIB)/$(PROJECT_LIBS)/utility $(SKETCH_LIB)/$(PROJECT_LIBS) : *.cpp *.c ] ; - -# Main output executable -Arduino $(PWD:B).elf : $(PROJECT_MODULES) [ GLOB $(PROJECT_DIRS) : *.c *.cpp *.pde *.ino ] ; diff --git a/examples/pingpair/pingpair.pde b/examples/pingpair/pingpair.pde deleted file mode 100644 index 3a57a679..00000000 --- a/examples/pingpair/pingpair.pde +++ /dev/null @@ -1,220 +0,0 @@ -/* - Copyright (C) 2011 J. Coliz - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - version 2 as published by the Free Software Foundation. - */ - -/** - * Example RF Radio Ping Pair - * - * This is an example of how to use the RF24 class. Write this sketch to two different nodes, - * connect the role_pin to ground on one. The ping node sends the current time to the pong node, - * which responds by sending the value back. The ping node can then see how long the whole cycle - * took. - */ - -#include -#include "nRF24L01.h" -#include "RF24.h" -#include "printf.h" - -// -// Hardware configuration -// - -// Set up nRF24L01 radio on SPI bus plus pins 9 & 10 - -RF24 radio(9,10); - -// sets the role of this unit in hardware. Connect to GND to be the 'pong' receiver -// Leave open to be the 'ping' transmitter -const int role_pin = 7; - -// -// Topology -// - -// Radio pipe addresses for the 2 nodes to communicate. -const uint64_t pipes[2] = { 0xF0F0F0F0E1LL, 0xF0F0F0F0D2LL }; - -// -// Role management -// -// Set up role. This sketch uses the same software for all the nodes -// in this system. Doing so greatly simplifies testing. The hardware itself specifies -// which node it is. -// -// This is done through the role_pin -// - -// The various roles supported by this sketch -typedef enum { role_ping_out = 1, role_pong_back } role_e; - -// The debug-friendly names of those roles -const char* role_friendly_name[] = { "invalid", "Ping out", "Pong back"}; - -// The role of the current running sketch -role_e role; - -void setup(void) -{ - // - // Role - // - - // set up the role pin - pinMode(role_pin, INPUT); - digitalWrite(role_pin,HIGH); - delay(20); // Just to get a solid reading on the role pin - - // read the address pin, establish our role - if ( ! digitalRead(role_pin) ) - role = role_ping_out; - else - role = role_pong_back; - - // - // Print preamble - // - - Serial.begin(57600); - printf_begin(); - printf("\n\rRF24/examples/pingpair/\n\r"); - printf("ROLE: %s\n\r",role_friendly_name[role]); - - // - // Setup and configure rf radio - // - - radio.begin(); - - // optionally, increase the delay between retries & # of retries - radio.setRetries(15,15); - - // optionally, reduce the payload size. seems to - // improve reliability - radio.setPayloadSize(8); - - // - // Open pipes to other nodes for communication - // - - // This simple sketch opens two pipes for these two nodes to communicate - // back and forth. - // Open 'our' pipe for writing - // Open the 'other' pipe for reading, in position #1 (we can have up to 5 pipes open for reading) - - if ( role == role_ping_out ) - { - radio.openWritingPipe(pipes[0]); - radio.openReadingPipe(1,pipes[1]); - } - else - { - radio.openWritingPipe(pipes[1]); - radio.openReadingPipe(1,pipes[0]); - } - - // - // Start listening - // - - radio.startListening(); - - // - // Dump the configuration of the rf unit for debugging - // - - radio.printDetails(); -} - -void loop(void) -{ - // - // Ping out role. Repeatedly send the current time - // - - if (role == role_ping_out) - { - // First, stop listening so we can talk. - radio.stopListening(); - - // Take the time, and send it. This will block until complete - unsigned long time = millis(); - printf("Now sending %lu...",time); - bool ok = radio.write( &time, sizeof(unsigned long) ); - - if (ok) - printf("ok..."); - else - printf("failed.\n\r"); - - // Now, continue listening - radio.startListening(); - - // Wait here until we get a response, or timeout (250ms) - unsigned long started_waiting_at = millis(); - bool timeout = false; - while ( ! radio.available() && ! timeout ) - if (millis() - started_waiting_at > 200 ) - timeout = true; - - // Describe the results - if ( timeout ) - { - printf("Failed, response timed out.\n\r"); - } - else - { - // Grab the response, compare, and send to debugging spew - unsigned long got_time; - radio.read( &got_time, sizeof(unsigned long) ); - - // Spew it - printf("Got response %lu, round-trip delay: %lu\n\r",got_time,millis()-got_time); - } - - // Try again 1s later - delay(1000); - } - - // - // Pong back role. Receive each packet, dump it out, and send it back - // - - if ( role == role_pong_back ) - { - // if there is data ready - if ( radio.available() ) - { - // Dump the payloads until we've gotten everything - unsigned long got_time; - bool done = false; - while (!done) - { - // Fetch the payload, and see if this was the last one. - done = radio.read( &got_time, sizeof(unsigned long) ); - - // Spew it - printf("Got payload %lu...",got_time); - - // Delay just a little bit to let the other unit - // make the transition to receiver - delay(20); - } - - // First, stop listening so we can talk - radio.stopListening(); - - // Send the final one back. - radio.write( &got_time, sizeof(unsigned long) ); - printf("Sent response.\n\r"); - - // Now, resume listening so we catch the next packets. - radio.startListening(); - } - } -} -// vim:cin:ai:sts=2 sw=2 ft=cpp diff --git a/examples/pingpair/printf.h b/examples/pingpair/printf.h deleted file mode 100644 index b2efd56b..00000000 --- a/examples/pingpair/printf.h +++ /dev/null @@ -1,37 +0,0 @@ -/* - Copyright (C) 2011 J. Coliz - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - version 2 as published by the Free Software Foundation. - */ - -/** - * @file printf.h - * - * Setup necessary to direct stdout to the Arduino Serial library, which - * enables 'printf' - */ - -#ifndef __PRINTF_H__ -#define __PRINTF_H__ - -#ifdef ARDUINO - -int serial_putc( char c, FILE * ) -{ - Serial.write( c ); - - return c; -} - -void printf_begin(void) -{ - fdevopen( &serial_putc, 0 ); -} - -#else -#error This example is only for use on Arduino. -#endif // ARDUINO - -#endif // __PRINTF_H__ diff --git a/examples/pingpair_dyn/Jamfile b/examples/pingpair_dyn/Jamfile deleted file mode 100644 index 901f8da8..00000000 --- a/examples/pingpair_dyn/Jamfile +++ /dev/null @@ -1,206 +0,0 @@ -PROJECT_NAME = $(PWD:B) ; -PROJECT_DIR = . ; -PROJECT_LIBS = SPI RF24 ; - -OUT_DIR = ojam ; -F_CPU = 16000000 ; -MCU = atmega328p ; -PORTS = /dev/tty.usbserial-A600eHIs /dev/tty.usbserial-A40081RP /dev/tty.usbserial-A9007LmI ; - -UPLOAD_RATE = 57600 ; -AVRDUDE_PROTOCOL = stk500v1 ; -COM = 33 ; - -# Host-specific overrides for locations -if $(OS) = MACOSX -{ -ARDUINO_VERSION = 22 ; -OLD_DIR = /opt/arduino-0021 ; -AVR_TOOLS_PATH = $(OLD_DIR)/hardware/tools/avr/bin ; -AVRDUDECONFIG_PATH = $(OLD_DIR)/hardware/tools/avr/etc ; -ARDUINO_DIR = /opt/Arduino ; -ARDUINO_AVR = /usr/lib/avr/include ; -} - -# Where is everything? -ARDUINO_VERSION ?= 22 ; -AVR_TOOLS_PATH ?= /usr/bin ; -ARDUINO_DIR ?= /opt/arduino-00$(ARDUINO_VERSION) ; -ARDUINO_AVR ?= $(ARDUINO_DIR)/hardware/tools/avr/avr/include/avr ; -AVRDUDECONFIG_PATH ?= $(ARDUINO_DIR)/hardware/tools ; -ARDUINO_CORE = $(ARDUINO_DIR)/hardware/arduino/cores/arduino ; -ARDUINO_LIB = $(ARDUINO_DIR)/libraries ; -SKETCH_LIB = $(HOME)/Source/Arduino/libraries ; -AVR_CC = $(AVR_TOOLS_PATH)/avr-gcc ; -AVR_CXX = $(AVR_TOOLS_PATH)/avr-g++ ; -AVR_LD = $(AVR_TOOLS_PATH)/avr-gcc ; -AVR_OBJCOPY = $(AVR_TOOLS_PATH)/avr-objcopy ; -AVRDUDE = $(AVR_TOOLS_PATH)/avrdude ; - -DEFINES = F_CPU=$(F_CPU)L ARDUINO=$(ARDUINO_VERSION) VERSION_H ; -CTUNING = -ffunction-sections -fdata-sections ; -CXXTUNING = -fno-exceptions -fno-strict-aliasing ; -CFLAGS = -Os -Wall -Wextra -mmcu=$(MCU) $(CTUNING) ; -CXXFLAGS = $(CFLAGS) $(CXXTUNING) ; -LDFLAGS = -Os -lm -Wl,--gc-sections -mmcu=atmega328p ; - -# Search everywhere for headers -HDRS = $(PROJECT_DIR) $(ARDUINO_AVR) $(ARDUINO_CORE) [ GLOB $(ARDUINO_LIB) $(SKETCH_LIB) : [^.]* ] ; - -# Grab everything from the core directory -CORE_MODULES = [ GLOB $(ARDUINO_CORE) : *.c *.cpp ] ; - -# Grab everything from libraries. To avoid this "grab everything" behaviour, you -# can specify specific modules to pick up in PROJECT_MODULES -LIB_MODULES = [ GLOB $(ARDUINO_LIB)/$(PROJECT_LIBS) $(SKETCH_LIB)/$(PROJECT_LIBS) : *.cpp ] ; - -# In addition to explicitly-specified program modules, pick up anything from the current -# dir. -PROJECT_MODULES += [ GLOB $(PROJECT_DIR) : *.c *.cpp *.pde ] ; - -# Shortcut for the out files -OUT = $(OUT_DIR)/$(PROJECT_NAME) ; - -# AvrDude setup -AVRDUDE_FLAGS = -V -F -D -C $(AVRDUDECONFIG_PATH)/avrdude.conf -p $(MCU) -c $(AVRDUDE_PROTOCOL) -b $(UPLOAD_RATE) ; - -rule GitVersion -{ - Always $(<) ; - Depends all : $(<) ; -} - -actions GitVersion -{ - echo "const char program_version[] = \"\\" > $(<) - git log -1 --pretty=format:%h >> $(<) - echo "\";" >> $(<) -} - -GitVersion version.h ; - -rule AvrCc -{ - Depends $(<) : $(>) ; - Depends $(<) : $(<:D) ; - Clean clean : $(<) ; - - CCHDRS on $(<) = [ on $(<) FIncludes $(HDRS) ] ; - CCDEFS on $(<) = [ on $(<) FDefines $(DEFINES) ] ; -} - -actions AvrCc -{ - $(AVR_CC) -c -o $(<) $(CCHDRS) $(CCDEFS) $(CFLAGS) $(>) -} - -rule AvrC++ -{ - Depends $(<) : $(>) ; - Depends $(<) : $(<:D) ; - Clean clean : $(<) ; - - CCHDRS on $(<) = [ on $(<) FIncludes $(HDRS) ] ; - CCDEFS on $(<) = [ on $(<) FDefines $(DEFINES) ] ; -} - -actions AvrC++ -{ - $(AVR_CXX) -c -o $(<) $(CCHDRS) $(CCDEFS) $(CXXFLAGS) $(>) -} - -rule Pde -{ - Depends $(<) : $(>) ; - Depends $(<) : $(<:D) ; - Clean clean : $(<) ; - -} - -actions Pde -{ - echo "#include " > $(<) - echo "#line 1 \"$(>)\"" >> $(<) - cat $(>) >> $(<) -} - -rule AvrPde -{ - local _CPP = $(OUT_DIR)/$(_I:B).cpp ; - Pde $(_CPP) : $(>) ; - AvrC++ $(<) : $(_CPP) ; -} - -rule AvrObject -{ - switch $(>:S) - { - case .c : AvrCc $(<) : $(>) ; - case .cpp : AvrC++ $(<) : $(>) ; - case .pde : AvrPde $(<) : $(>) ; - } -} - -rule AvrObjects -{ - for _I in $(<) - { - AvrObject $(OUT_DIR)/$(_I:B).o : $(_I) ; - } -} - -rule AvrMainFromObjects -{ - Depends $(<) : $(>) ; - Depends $(<) : $(<:D) ; - MkDir $(<:D) ; - Depends all : $(<) ; - Clean clean : $(<) ; -} - -actions AvrMainFromObjects -{ - $(AVR_LD) $(LDFLAGS) -o $(<) $(>) -} - -rule AvrMain -{ - AvrMainFromObjects $(<) : $(OUT_DIR)/$(>:B).o ; - AvrObjects $(>) ; -} - -rule AvrHex -{ - Depends $(<) : $(>) ; - Depends $(<) : $(<:D) ; - Depends hex : $(<) ; - Clean clean : $(<) ; -} - -actions AvrHex -{ - $(AVR_OBJCOPY) -O ihex -R .eeprom $(>) $(<) -} - -rule AvrUpload -{ - Depends $(1) : $(2) ; - Depends $(2) : $(3) ; - NotFile $(1) ; - Always $(1) ; - Always $(2) ; - AvrUploadAction $(2) : $(3) ; -} - -actions AvrUploadAction -{ - $(AVRDUDE) $(AVRDUDE_FLAGS) -P $(<) $(AVRDUDE_WRITE_FLASH) -U flash:w:$(>):i -} - -AvrMain $(OUT).elf : $(CORE_MODULES) $(LIB_MODULES) $(PROJECT_MODULES) ; -AvrHex $(OUT).hex : $(OUT).elf ; - -AvrUpload p6 : /dev/tty.usbserial-A600eHIs : $(OUT).hex ; -AvrUpload p4 : /dev/tty.usbserial-A40081RP : $(OUT).hex ; -AvrUpload p9 : /dev/tty.usbserial-A9007LmI : $(OUT).hex ; - diff --git a/examples/pingpair_dyn/pingpair_dyn.pde b/examples/pingpair_dyn/pingpair_dyn.pde deleted file mode 100644 index 7108f3bf..00000000 --- a/examples/pingpair_dyn/pingpair_dyn.pde +++ /dev/null @@ -1,232 +0,0 @@ -/* - Copyright (C) 2011 J. Coliz - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - version 2 as published by the Free Software Foundation. - */ - -/** - * Example using Dynamic Payloads - * - * This is an example of how to use payloads of a varying (dynamic) size. - */ - -#include -#include "nRF24L01.h" -#include "RF24.h" -#include "printf.h" - -// -// Hardware configuration -// - -// Set up nRF24L01 radio on SPI bus plus pins 9 & 10 - -RF24 radio(9,10); - -// sets the role of this unit in hardware. Connect to GND to be the 'pong' receiver -// Leave open to be the 'ping' transmitter -const int role_pin = 7; - -// -// Topology -// - -// Radio pipe addresses for the 2 nodes to communicate. -const uint64_t pipes[2] = { 0xF0F0F0F0E1LL, 0xF0F0F0F0D2LL }; - -// -// Role management -// -// Set up role. This sketch uses the same software for all the nodes -// in this system. Doing so greatly simplifies testing. The hardware itself specifies -// which node it is. -// -// This is done through the role_pin -// - -// The various roles supported by this sketch -typedef enum { role_ping_out = 1, role_pong_back } role_e; - -// The debug-friendly names of those roles -const char* role_friendly_name[] = { "invalid", "Ping out", "Pong back"}; - -// The role of the current running sketch -role_e role; - -// -// Payload -// - -const int min_payload_size = 4; -const int max_payload_size = 32; -const int payload_size_increments_by = 2; -int next_payload_size = min_payload_size; - -char receive_payload[max_payload_size+1]; // +1 to allow room for a terminating NULL char - -void setup(void) -{ - // - // Role - // - - // set up the role pin - pinMode(role_pin, INPUT); - digitalWrite(role_pin,HIGH); - delay(20); // Just to get a solid reading on the role pin - - // read the address pin, establish our role - if ( digitalRead(role_pin) ) - role = role_ping_out; - else - role = role_pong_back; - - // - // Print preamble - // - - Serial.begin(57600); - printf_begin(); - printf("\n\rRF24/examples/pingpair_dyn/\n\r"); - printf("ROLE: %s\n\r",role_friendly_name[role]); - - // - // Setup and configure rf radio - // - - radio.begin(); - - // enable dynamic payloads - radio.enableDynamicPayloads(); - - // optionally, increase the delay between retries & # of retries - radio.setRetries(15,15); - - // - // Open pipes to other nodes for communication - // - - // This simple sketch opens two pipes for these two nodes to communicate - // back and forth. - // Open 'our' pipe for writing - // Open the 'other' pipe for reading, in position #1 (we can have up to 5 pipes open for reading) - - if ( role == role_ping_out ) - { - radio.openWritingPipe(pipes[0]); - radio.openReadingPipe(1,pipes[1]); - } - else - { - radio.openWritingPipe(pipes[1]); - radio.openReadingPipe(1,pipes[0]); - } - - // - // Start listening - // - - radio.startListening(); - - // - // Dump the configuration of the rf unit for debugging - // - - radio.printDetails(); -} - -void loop(void) -{ - // - // Ping out role. Repeatedly send the current time - // - - if (role == role_ping_out) - { - // The payload will always be the same, what will change is how much of it we send. - static char send_payload[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ789012"; - - // First, stop listening so we can talk. - radio.stopListening(); - - // Take the time, and send it. This will block until complete - printf("Now sending length %i...",next_payload_size); - radio.write( send_payload, next_payload_size ); - - // Now, continue listening - radio.startListening(); - - // Wait here until we get a response, or timeout - unsigned long started_waiting_at = millis(); - bool timeout = false; - while ( ! radio.available() && ! timeout ) - if (millis() - started_waiting_at > 500 ) - timeout = true; - - // Describe the results - if ( timeout ) - { - printf("Failed, response timed out.\n\r"); - } - else - { - // Grab the response, compare, and send to debugging spew - uint8_t len = radio.getDynamicPayloadSize(); - radio.read( receive_payload, len ); - - // Put a zero at the end for easy printing - receive_payload[len] = 0; - - // Spew it - printf("Got response size=%i value=%s\n\r",len,receive_payload); - } - - // Update size for next time. - next_payload_size += payload_size_increments_by; - if ( next_payload_size > max_payload_size ) - next_payload_size = min_payload_size; - - // Try again 1s later - delay(1000); - } - - // - // Pong back role. Receive each packet, dump it out, and send it back - // - - if ( role == role_pong_back ) - { - // if there is data ready - if ( radio.available() ) - { - // Dump the payloads until we've gotten everything - uint8_t len; - bool done = false; - while (!done) - { - // Fetch the payload, and see if this was the last one. - len = radio.getDynamicPayloadSize(); - done = radio.read( receive_payload, len ); - - // Put a zero at the end for easy printing - receive_payload[len] = 0; - - // Spew it - printf("Got payload size=%i value=%s\n\r",len,receive_payload); - } - - // First, stop listening so we can talk - radio.stopListening(); - - // Send the final one back. - radio.write( receive_payload, len ); - printf("Sent response.\n\r"); - - // Now, resume listening so we catch the next packets. - radio.startListening(); - } - } -} -// vim:cin:ai:sts=2 sw=2 ft=cpp diff --git a/examples/pingpair_dyn/printf.h b/examples/pingpair_dyn/printf.h deleted file mode 100644 index b2efd56b..00000000 --- a/examples/pingpair_dyn/printf.h +++ /dev/null @@ -1,37 +0,0 @@ -/* - Copyright (C) 2011 J. Coliz - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - version 2 as published by the Free Software Foundation. - */ - -/** - * @file printf.h - * - * Setup necessary to direct stdout to the Arduino Serial library, which - * enables 'printf' - */ - -#ifndef __PRINTF_H__ -#define __PRINTF_H__ - -#ifdef ARDUINO - -int serial_putc( char c, FILE * ) -{ - Serial.write( c ); - - return c; -} - -void printf_begin(void) -{ - fdevopen( &serial_putc, 0 ); -} - -#else -#error This example is only for use on Arduino. -#endif // ARDUINO - -#endif // __PRINTF_H__ diff --git a/examples/pingpair_irq/Jamfile b/examples/pingpair_irq/Jamfile deleted file mode 100644 index 97237bc8..00000000 --- a/examples/pingpair_irq/Jamfile +++ /dev/null @@ -1,219 +0,0 @@ -# (1) Project Information - -PROJECT_LIBS = SPI RF24 ; -PROJECT_DIRS = $(PWD) ; - -# (2) Board Information - -UPLOAD_PROTOCOL ?= arduino ; -UPLOAD_SPEED ?= 115200 ; -MCU ?= atmega328p ; -F_CPU ?= 16000000 ; -CORE ?= arduino ; -VARIANT ?= standard ; -ARDUINO_VERSION ?= 100 ; - -# (3) USB Ports - -PORTS = p4 p6 p9 u0 u1 u2 ; -PORT_p6 = /dev/tty.usbserial-A600eHIs ; -PORT_p4 = /dev/tty.usbserial-A40081RP ; -PORT_p9 = /dev/tty.usbserial-A9007LmI ; -PORT_u0 = /dev/ttyUSB0 ; -PORT_u1 = /dev/ttyUSB1 ; -PORT_u2 = /dev/ttyUSB2 ; - -# (4) Location of AVR tools -# -# This configuration assumes using avr-tools that were obtained separate from the Arduino -# distribution. - -if $(OS) = MACOSX -{ - AVR_BIN ?= /usr/local/avrtools/bin ; - AVR_ETC = /usr/local/avrtools/etc ; - AVR_INCLUDE = /usr/local/avrtools/include ; -} -else -{ - AVR_BIN ?= /usr/bin ; - AVR_INCLUDE ?= /usr/lib/avr/include ; - AVR_ETC = /etc ; -} - -# (5) Directories where Arduino core and libraries are located - -ARDUINO_DIR ?= /opt/Arduino ; -ARDUINO_CORE = $(ARDUINO_DIR)/hardware/arduino/cores/$(CORE) $(ARDUINO_DIR)/hardware/arduino/variants/$(VARIANT) ; -ARDUINO_LIB = $(ARDUINO_DIR)/libraries ; -SKETCH_LIB = $(HOME)/Source/Arduino/libraries ; - -# -# -------------------------------------------------- -# Below this line usually never needs to be modified -# - -# Tool locations - -CC = $(AVR_BIN)/avr-gcc ; -C++ = $(AVR_BIN)/avr-g++ ; -LINK = $(AVR_BIN)/avr-gcc ; -AR = $(AVR_BIN)/avr-ar rcs ; -RANLIB = ; -OBJCOPY = $(AVR_BIN)/avr-objcopy ; -AVRDUDE ?= $(AVR_BIN)/avrdude ; - -# Flags - -DEFINES += F_CPU=$(F_CPU)L ARDUINO=$(ARDUINO_VERSION) VERSION_H ; -OPTIM = -Os ; -CCFLAGS = -Wall -Wextra -Wno-strict-aliasing -mmcu=$(MCU) -ffunction-sections -fdata-sections ; -C++FLAGS = $(CCFLAGS) -fno-exceptions -fno-strict-aliasing ; -LINKFLAGS = $(OPTIM) -lm -Wl,--gc-sections -mmcu=$(MCU) ; -AVRDUDEFLAGS = -V -F -D -C $(AVR_ETC)/avrdude.conf -p $(MCU) -c $(UPLOAD_PROTOCOL) -b $(UPLOAD_SPEED) ; - -# Search everywhere for headers - -HDRS = $(PROJECT_DIRS) $(AVR_INCLUDE) $(ARDUINO_CORE) $(ARDUINO_LIB)/$(PROJECT_LIBS) $(ARDUINO_LIB)/$(PROJECT_LIBS)/utility $(SKETCH_LIB)/$(PROJECT_LIBS) ; - -# Output locations - -LOCATE_TARGET = $(F_CPU) ; -LOCATE_SOURCE = $(F_CPU) ; - -# -# Custom rules -# - -rule GitVersion -{ - Always $(<) ; - Depends all : $(<) ; -} - -actions GitVersion -{ - echo "const char program_version[] = \"\\" > $(<) - git log -1 --pretty=format:%h >> $(<) - echo "\";" >> $(<) -} - -GitVersion version.h ; - -rule Pde -{ - Depends $(<) : $(>) ; - MakeLocate $(<) : $(LOCATE_SOURCE) ; - Clean clean : $(<) ; -} - -if ( $(ARDUINO_VERSION) < 100 ) -{ - ARDUINO_H = WProgram.h ; -} -else -{ - ARDUINO_H = Arduino.h ; -} - -actions Pde -{ - echo "#include <$(ARDUINO_H)>" > $(<) - echo "#line 1 \"$(>)\"" >> $(<) - cat $(>) >> $(<) -} - -rule C++Pde -{ - local _CPP = $(>:B).cpp ; - Pde $(_CPP) : $(>) ; - C++ $(<) : $(_CPP) ; -} - -rule UserObject -{ - switch $(>:S) - { - case .ino : C++Pde $(<) : $(>) ; - case .pde : C++Pde $(<) : $(>) ; - } -} - -rule Objects -{ - local _i ; - - for _i in [ FGristFiles $(<) ] - { - local _b = $(_i:B)$(SUFOBJ) ; - local _o = $(_b:G=$(SOURCE_GRIST:E)) ; - Object $(_o) : $(_i) ; - Depends obj : $(_o) ; - } -} - -rule Library -{ - LibraryFromObjects $(<) : $(>:B)$(SUFOBJ) ; - Objects $(>) ; -} - -rule Main -{ - MainFromObjects $(<) : $(>:B)$(SUFOBJ) ; - Objects $(>) ; -} - -rule Hex -{ - Depends $(<) : $(>) ; - MakeLocate $(<) : $(LOCATE_TARGET) ; - Depends hex : $(<) ; - Clean clean : $(<) ; -} - -actions Hex -{ - $(OBJCOPY) -O ihex -R .eeprom $(>) $(<) -} - -rule Upload -{ - Depends $(1) : $(2) ; - Depends $(2) : $(3) ; - NotFile $(1) ; - Always $(1) ; - Always $(2) ; - UploadAction $(2) : $(3) ; -} - -actions UploadAction -{ - $(AVRDUDE) $(AVRDUDEFLAGS) -P $(<) $(AVRDUDE_WRITE_FLASH) -U flash:w:$(>):i -} - -rule Arduino -{ - LINKFLAGS on $(<) = $(LINKFLAGS) -Wl,-Map=$(LOCATE_TARGET)/$(<:B).map ; - Main $(<) : $(>) ; - LinkLibraries $(<) : core libs ; - Hex $(<:B).hex : $(<) ; - for _p in $(PORTS) - { - Upload $(_p) : $(PORT_$(_p)) : $(<:B).hex ; - } -} - -# -# Targets -# - -# Grab everything from the core directory -Library core : [ GLOB $(ARDUINO_CORE) : *.c *.cpp ] ; - -# Grab everything from libraries. To avoid this "grab everything" behaviour, you -# can specify specific modules to pick up in PROJECT_MODULES -Library libs : [ GLOB $(ARDUINO_LIB)/$(PROJECT_LIBS) $(ARDUINO_LIB)/$(PROJECT_LIBS)/utility $(SKETCH_LIB)/$(PROJECT_LIBS) : *.cpp *.c ] ; - -# Main output executable -Arduino $(PWD:B).elf : $(PROJECT_MODULES) [ GLOB $(PROJECT_DIRS) : *.c *.cpp *.pde *.ino ] ; diff --git a/examples/pingpair_irq/pingpair_irq.pde b/examples/pingpair_irq/pingpair_irq.pde deleted file mode 100644 index 47084a1f..00000000 --- a/examples/pingpair_irq/pingpair_irq.pde +++ /dev/null @@ -1,216 +0,0 @@ -/* - Copyright (C) 2011 J. Coliz - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - version 2 as published by the Free Software Foundation. - */ - -/** - * Example of using interrupts - * - * This is an example of how to user interrupts to interact with the radio. - * It builds on the pingpair_pl example, and uses ack payloads. - */ - -#include -#include "nRF24L01.h" -#include "RF24.h" -#include "printf.h" - -// -// Hardware configuration -// - -// Set up nRF24L01 radio on SPI bus plus pins 9 & 10 - -RF24 radio(8,9); - -// sets the role of this unit in hardware. Connect to GND to be the 'pong' receiver -// Leave open to be the 'ping' transmitter -const short role_pin = 7; - -// -// Topology -// - -// Single radio pipe address for the 2 nodes to communicate. -const uint64_t pipe = 0xE8E8F0F0E1LL; - -// -// Role management -// -// Set up role. This sketch uses the same software for all the nodes in this -// system. Doing so greatly simplifies testing. The hardware itself specifies -// which node it is. -// -// This is done through the role_pin -// - -// The various roles supported by this sketch -typedef enum { role_sender = 1, role_receiver } role_e; - -// The debug-friendly names of those roles -const char* role_friendly_name[] = { "invalid", "Sender", "Receiver"}; - -// The role of the current running sketch -role_e role; - -// Interrupt handler, check the radio because we got an IRQ -void check_radio(void); - -void setup(void) -{ - // - // Role - // - - // set up the role pin - pinMode(role_pin, INPUT); - digitalWrite(role_pin,HIGH); - delay(20); // Just to get a solid reading on the role pin - - // read the address pin, establish our role - if ( digitalRead(role_pin) ) - role = role_sender; - else - role = role_receiver; - - // - // Print preamble - // - - Serial.begin(57600); - printf_begin(); - printf("\n\rRF24/examples/pingpair_irq/\n\r"); - printf("ROLE: %s\n\r",role_friendly_name[role]); - - // - // Setup and configure rf radio - // - - radio.begin(); - - // We will be using the Ack Payload feature, so please enable it - radio.enableAckPayload(); - - // - // Open pipes to other nodes for communication - // - - // This simple sketch opens a single pipe for these two nodes to communicate - // back and forth. One listens on it, the other talks to it. - - if ( role == role_sender ) - { - radio.openWritingPipe(pipe); - } - else - { - radio.openReadingPipe(1,pipe); - } - - // - // Start listening - // - - if ( role == role_receiver ) - radio.startListening(); - - // - // Dump the configuration of the rf unit for debugging - // - - radio.printDetails(); - - // - // Attach interrupt handler to interrupt #0 (using pin 2) - // on BOTH the sender and receiver - // - - attachInterrupt(0, check_radio, FALLING); -} - -static uint32_t message_count = 0; - -void loop(void) -{ - // - // Sender role. Repeatedly send the current time - // - - if (role == role_sender) - { - // Take the time, and send it. - unsigned long time = millis(); - printf("Now sending %lu\n\r",time); - radio.startWrite( &time, sizeof(unsigned long) ); - - // Try again soon - delay(2000); - } - - // - // Receiver role: Does nothing! All the work is in IRQ - // - -} - -void check_radio(void) -{ - // What happened? - bool tx,fail,rx; - radio.whatHappened(tx,fail,rx); - - // Have we successfully transmitted? - if ( tx ) - { - if ( role == role_sender ) - printf("Send:OK\n\r"); - - if ( role == role_receiver ) - printf("Ack Payload:Sent\n\r"); - } - - // Have we failed to transmit? - if ( fail ) - { - if ( role == role_sender ) - printf("Send:Failed\n\r"); - - if ( role == role_receiver ) - printf("Ack Payload:Failed\n\r"); - } - - // Transmitter can power down for now, because - // the transmission is done. - if ( ( tx || fail ) && ( role == role_sender ) ) - radio.powerDown(); - - // Did we receive a message? - if ( rx ) - { - // If we're the sender, we've received an ack payload - if ( role == role_sender ) - { - radio.read(&message_count,sizeof(message_count)); - printf("Ack:%lu\n\r",message_count); - } - - // If we're the receiver, we've received a time message - if ( role == role_receiver ) - { - // Get this payload and dump it - static unsigned long got_time; - radio.read( &got_time, sizeof(got_time) ); - printf("Got payload %lu\n\r",got_time); - - // Add an ack packet for the next time around. This is a simple - // packet counter - radio.writeAckPayload( 1, &message_count, sizeof(message_count) ); - ++message_count; - } - } -} - -// vim:ai:cin:sts=2 sw=2 ft=cpp diff --git a/examples/pingpair_irq/printf.h b/examples/pingpair_irq/printf.h deleted file mode 100644 index b2efd56b..00000000 --- a/examples/pingpair_irq/printf.h +++ /dev/null @@ -1,37 +0,0 @@ -/* - Copyright (C) 2011 J. Coliz - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - version 2 as published by the Free Software Foundation. - */ - -/** - * @file printf.h - * - * Setup necessary to direct stdout to the Arduino Serial library, which - * enables 'printf' - */ - -#ifndef __PRINTF_H__ -#define __PRINTF_H__ - -#ifdef ARDUINO - -int serial_putc( char c, FILE * ) -{ - Serial.write( c ); - - return c; -} - -void printf_begin(void) -{ - fdevopen( &serial_putc, 0 ); -} - -#else -#error This example is only for use on Arduino. -#endif // ARDUINO - -#endif // __PRINTF_H__ diff --git a/examples/pingpair_maple/Jamfile b/examples/pingpair_maple/Jamfile deleted file mode 100644 index 798096cc..00000000 --- a/examples/pingpair_maple/Jamfile +++ /dev/null @@ -1,182 +0,0 @@ -MCU = cortex-m3 ; -CHIP = STM32F103ZE ; -BOARD = maple_native ; - -#CHIP = at91sam3u4 ; -#BOARD = sam3u-ek ; - -if ! $(TOOLSET) -{ - TOOLSET = devkit ; - Echo "Assuming TOOLSET=devkit" ; -} - -if $(TOOLSET) = yagarto -{ - TOOLS_PATH = ~/Source/yagarto-4.6.2/bin ; - TOOLS_ARCH = arm-none-eabi- ; -} -if $(TOOLSET) = yagarto-install -{ - TOOLS_PATH = ~/Source/yagarto/install/bin ; - TOOLS_ARCH = arm-none-eabi- ; -} -else if $(TOOLSET) = devkit -{ - TOOLS_PATH = /opt/devkitARM/bin ; - TOOLS_ARCH = arm-eabi- ; -} -else if $(TOOLSET) = maple -{ - TOOLS_PATH = /opt/Maple/Resources/Java/hardware/tools/arm/bin ; - TOOLS_ARCH = arm-none-eabi- ; -} -else if $(TOOLSET) = ports -{ - TOOLS_PATH = /opt/local/bin ; - TOOLS_ARCH = arm-none-eabi- ; -} - -CC = $(TOOLS_PATH)/$(TOOLS_ARCH)gcc ; -C++ = $(TOOLS_PATH)/$(TOOLS_ARCH)g++ ; -AS = $(TOOLS_PATH)/$(TOOLS_ARCH)gcc -c ; -LINK = $(TOOLS_PATH)/$(TOOLS_ARCH)g++ ; -OBJCOPY = $(TOOLS_PATH)/$(TOOLS_ARCH)objcopy ; -DFU = dfu-util ; - -DEFINES += VECT_TAB_FLASH BOARD_$(BOARD) MCU_$(CHIP) ERROR_LED_PORT=GPIOC ERROR_LED_PIN=15 STM32_HIGH_DENSITY MAPLE_IDE ; -OPTIM = -Os ; -MFLAGS = cpu=$(MCU) thumb arch=armv7-m ; -CCFLAGS = -Wall -m$(MFLAGS) -g -nostdlib -ffunction-sections -fdata-sections -Wl,--gc-sections ; -C++FLAGS = $(CCFLAGS) -fno-rtti -fno-exceptions ; -LINKFLAGS += -m$(MFLAGS) -Xlinker --gc-sections ; -DFUFLAGS = -a1 -d 0x1eaf:0x0003 -R ; - -MAPLE_DIR = $(HOME)/Source/SAM3U/libmaple ; -MAPLE_LIBS = Servo LiquidCrystal Wire FreeRTOS ; -MAPLE_SUBDIRS = wirish wirish/comm wirish/boards libmaple libmaple/usb libmaple/usb/usb_lib ; - -SKETCH_DIR = $(HOME)/Source/Arduino ; -SKETCH_LIBS = RF24 ; - -MODULE_DIRS = . $(MAPLE_DIR)/$(MAPLE_SUBDIRS) $(MAPLE_DIR)/libraries/$(MAPLE_LIBS) $(SKETCH_DIR)/libraries/$(SKETCH_LIBS) ; -HDRS = $(MODULE_DIRS) ; -LOCATE_TARGET = out/$(TOOLSET) ; -LOCATE_SOURCE = $(LOCATE_TARGET) ; - -rule Pde -{ - Depends $(<) : $(>) ; - MakeLocate $(<) : $(LOCATE_SOURCE) ; - Clean clean : $(<) ; -} - -if ( $(ARDUINO_VERSION) < 100 ) -{ - ARDUINO_H = WProgram.h ; -} -else -{ - ARDUINO_H = Arduino.h ; -} - -actions Pde -{ - echo "#include <$(ARDUINO_H)>" > $(<) - echo "#line 1 \"$(>)\"" >> $(<) - cat $(>) >> $(<) -} - -rule C++Pde -{ - local _CPP = $(>:B).cpp ; - Pde $(_CPP) : $(>) ; - C++ $(<) : $(_CPP) ; -} - -rule Hex -{ - Depends $(<) : $(>) ; - MakeLocate $(<) : $(LOCATE_TARGET) ; - Depends hex : $(<) ; - Clean clean : $(<) ; -} - -actions Hex -{ - $(OBJCOPY) -O ihex $(>) $(<) -} - -rule Binary -{ - Depends $(<) : $(>) ; - MakeLocate $(<) : $(LOCATE_TARGET) ; - Depends binary : $(<) ; - Clean clean : $(<) ; -} - -actions Binary -{ - $(OBJCOPY) -O binary $(>) $(<) -} - -rule UserObject -{ - switch $(>:S) - { - case .S : As $(<) : $(>) ; - case .ino : C++Pde $(<) : $(>) ; - case .pde : C++Pde $(<) : $(>) ; - } -} - -rule Upload -{ - Depends up : $(<) ; - NotFile up ; - Always $(<) ; - Always up ; -} - -actions Upload -{ - $(DFU) $(DFUFLAGS) -D $(<) -} - -# Override base objects rule, so all output can go in the output dir -rule Objects -{ - local _i ; - - for _i in [ FGristFiles $(<) ] - { - local _b = $(_i:B)$(SUFOBJ) ; - local _o = $(_b:G=$(SOURCE_GRIST:E)) ; - Object $(_o) : $(_i) ; - Depends obj : $(_o) ; - } -} - -# Override base main rule, so all output can go in the output dir -rule Main -{ - MainFromObjects $(<) : $(>:B)$(SUFOBJ) ; - Objects $(>) ; -} - -# Modules -MODULES = [ GLOB $(MODULE_DIRS) : *.pde *.c *.cpp *.S ] ; - -# Main output executable -MAIN = $(PWD:B).elf ; - -# Linker script -LINK_DIR = $(MAPLE_DIR)/support/ld ; -LINKSCRIPT = $(LINK_DIR)/$(BOARD)/flash.ld ; - -# Bring in the map and link script -LINKFLAGS += -Wl,-Map=$(LOCATE_TARGET)/$(MAIN:B).map -T$(LINKSCRIPT) -L$(LINK_DIR) ; - -Main $(MAIN) : $(MODULES) ; -Binary $(MAIN:B).bin : $(MAIN) ; -Upload $(MAIN:B).bin ; diff --git a/examples/pingpair_maple/main.cpp b/examples/pingpair_maple/main.cpp deleted file mode 100644 index b4f976d3..00000000 --- a/examples/pingpair_maple/main.cpp +++ /dev/null @@ -1,87 +0,0 @@ -#ifdef MAPLE_IDE - -#include -#include "wirish.h" - -extern void setup(void); -extern void loop(void); - -void board_start(const char* program_name) -{ - // Set up the LED to steady on - pinMode(BOARD_LED_PIN, OUTPUT); - digitalWrite(BOARD_LED_PIN, HIGH); - - // Setup the button as input - pinMode(BOARD_BUTTON_PIN, INPUT); - digitalWrite(BOARD_BUTTON_PIN, HIGH); - - SerialUSB.begin(); - SerialUSB.println("Press BUT"); - - // Wait for button press - while ( !isButtonPressed() ) - { - } - - SerialUSB.println("Welcome!"); - SerialUSB.println(program_name); - - int i = 11; - while (i--) - { - toggleLED(); - delay(50); - } -} - -/** - * Custom version of _write, which will print to the USB. - * In order to use it you MUST ADD __attribute__((weak)) - * to _write in libmaple/syscalls.c -*/ -extern "C" int _write (int file, char * ptr, int len) -{ - if ( (file != 1) && (file != 2) ) - return 0; - else - SerialUSB.write(ptr,len); - return len; -} - -/** - * Re-entrant version of _write. Yagarto and Devkit now use - * the re-entrant newlib, so these get called instead of the - * non_r versions. - */ -extern "C" int _write_r (void*, int file, char * ptr, int len) -{ - return _write( file, ptr, len); -} - -__attribute__((constructor)) __attribute__ ((weak)) void premain() -{ - init(); -} - -__attribute__((weak)) void setup(void) -{ - board_start("No program defined"); -} - -__attribute__((weak)) void loop(void) -{ -} - -__attribute__((weak)) int main(void) -{ - setup(); - - while (true) - { - loop(); - } - return 0; -} -#endif // ifdef MAPLE_IDE -// vim:cin:ai:sts=2 sw=2 ft=cpp diff --git a/examples/pingpair_maple/pingpair_maple.pde b/examples/pingpair_maple/pingpair_maple.pde deleted file mode 100644 index 2d3925b7..00000000 --- a/examples/pingpair_maple/pingpair_maple.pde +++ /dev/null @@ -1,242 +0,0 @@ -/* - Copyright (C) 2011 J. Coliz - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - version 2 as published by the Free Software Foundation. - */ - -/** - * Example RF Radio Ping Pair ... for Maple - * - * This is an example of how to use the RF24 class. Write this sketch to two different nodes, - * connect the role_pin to ground on one. The ping node sends the current time to the pong node, - * which responds by sending the value back. The ping node can then see how long the whole cycle - * took. - */ - -#include "WProgram.h" -#include -#include "nRF24L01.h" -#include "RF24.h" - -// -// Maple specific setup. Other than this section, the sketch is the same on Maple as on -// Arduino -// - -#ifdef MAPLE_IDE - -// External startup function -extern void board_start(const char* program_name); - -// Use SPI #2. -HardwareSPI SPI(2); - -#else -#define board_startup printf -#define toggleLED(x) (x) -#endif - -// -// Hardware configuration -// - -// Set up nRF24L01 radio on SPI bus plus pins 7 & 6 -// (This works for the Getting Started board plugged into the -// Maple Native backwards.) - -RF24 radio(7,6); - -// sets the role of this unit in hardware. Connect to GND to be the 'pong' receiver -// Leave open to be the 'ping' transmitter -const int role_pin = 10; - -// -// Topology -// - -// Radio pipe addresses for the 2 nodes to communicate. -const uint64_t pipes[2] = { 0xF0F0F0F0E1LL, 0xF0F0F0F0D2LL }; - -// -// Role management -// -// Set up role. This sketch uses the same software for all the nodes -// in this system. Doing so greatly simplifies testing. The hardware itself specifies -// which node it is. -// -// This is done through the role_pin -// - -// The various roles supported by this sketch -typedef enum { role_ping_out = 1, role_pong_back } role_e; - -// The debug-friendly names of those roles -const char* role_friendly_name[] = { "invalid", "Ping out", "Pong back"}; - -// The role of the current running sketch -role_e role; - -void setup(void) -{ - // - // Role - // - - // set up the role pin - pinMode(role_pin, INPUT); - digitalWrite(role_pin,HIGH); - delay(20); // Just to get a solid reading on the role pin - - // read the address pin, establish our role - if ( digitalRead(role_pin) ) - role = role_ping_out; - else - role = role_pong_back; - - // - // Print preamble - // - - board_start("\n\rRF24/examples/pingpair/\n\r"); - printf("ROLE: %s\n\r",role_friendly_name[role]); - - // - // Setup and configure rf radio - // - - radio.begin(); - - // optionally, increase the delay between retries & # of retries - radio.setRetries(15,15); - - // optionally, reduce the payload size. seems to - // improve reliability - radio.setPayloadSize(8); - - // - // Open pipes to other nodes for communication - // - - // This simple sketch opens two pipes for these two nodes to communicate - // back and forth. - // Open 'our' pipe for writing - // Open the 'other' pipe for reading, in position #1 (we can have up to 5 pipes open for reading) - - if ( role == role_ping_out ) - { - radio.openWritingPipe(pipes[0]); - radio.openReadingPipe(1,pipes[1]); - } - else - { - radio.openWritingPipe(pipes[1]); - radio.openReadingPipe(1,pipes[0]); - } - - // - // Start listening - // - - radio.startListening(); - - // - // Dump the configuration of the rf unit for debugging - // - - radio.printDetails(); -} - -void loop(void) -{ - // - // Ping out role. Repeatedly send the current time - // - - if (role == role_ping_out) - { - toggleLED(); - - // First, stop listening so we can talk. - radio.stopListening(); - - // Take the time, and send it. This will block until complete - unsigned long time = millis(); - printf("Now sending %lu...",time); - bool ok = radio.write( &time, sizeof(unsigned long) ); - - if (ok) - printf("ok...\r\n"); - else - printf("failed.\r\n"); - - // Now, continue listening - radio.startListening(); - - // Wait here until we get a response, or timeout (250ms) - unsigned long started_waiting_at = millis(); - bool timeout = false; - while ( ! radio.available() && ! timeout ) - if (millis() - started_waiting_at > 200 ) - timeout = true; - - // Describe the results - if ( timeout ) - { - printf("Failed, response timed out.\r\n"); - } - else - { - // Grab the response, compare, and send to debugging spew - unsigned long got_time; - radio.read( &got_time, sizeof(unsigned long) ); - - // Spew it - printf("Got response %lu, round-trip delay: %lu\r\n",got_time,millis()-got_time); - } - - toggleLED(); - - // Try again 1s later - delay(1000); - } - - // - // Pong back role. Receive each packet, dump it out, and send it back - // - - if ( role == role_pong_back ) - { - // if there is data ready - if ( radio.available() ) - { - // Dump the payloads until we've gotten everything - unsigned long got_time; - bool done = false; - while (!done) - { - // Fetch the payload, and see if this was the last one. - done = radio.read( &got_time, sizeof(unsigned long) ); - - // Spew it - printf("Got payload %lu...",got_time); - - // Delay just a little bit to let the other unit - // make the transition to receiver - delay(20); - } - - // First, stop listening so we can talk - radio.stopListening(); - - // Send the final one back. - radio.write( &got_time, sizeof(unsigned long) ); - printf("Sent response.\r\n"); - - // Now, resume listening so we catch the next packets. - radio.startListening(); - } - } -} -// vim:cin:ai:sts=2 sw=2 ft=cpp diff --git a/examples/pingpair_pl/Jamfile b/examples/pingpair_pl/Jamfile deleted file mode 100644 index 901f8da8..00000000 --- a/examples/pingpair_pl/Jamfile +++ /dev/null @@ -1,206 +0,0 @@ -PROJECT_NAME = $(PWD:B) ; -PROJECT_DIR = . ; -PROJECT_LIBS = SPI RF24 ; - -OUT_DIR = ojam ; -F_CPU = 16000000 ; -MCU = atmega328p ; -PORTS = /dev/tty.usbserial-A600eHIs /dev/tty.usbserial-A40081RP /dev/tty.usbserial-A9007LmI ; - -UPLOAD_RATE = 57600 ; -AVRDUDE_PROTOCOL = stk500v1 ; -COM = 33 ; - -# Host-specific overrides for locations -if $(OS) = MACOSX -{ -ARDUINO_VERSION = 22 ; -OLD_DIR = /opt/arduino-0021 ; -AVR_TOOLS_PATH = $(OLD_DIR)/hardware/tools/avr/bin ; -AVRDUDECONFIG_PATH = $(OLD_DIR)/hardware/tools/avr/etc ; -ARDUINO_DIR = /opt/Arduino ; -ARDUINO_AVR = /usr/lib/avr/include ; -} - -# Where is everything? -ARDUINO_VERSION ?= 22 ; -AVR_TOOLS_PATH ?= /usr/bin ; -ARDUINO_DIR ?= /opt/arduino-00$(ARDUINO_VERSION) ; -ARDUINO_AVR ?= $(ARDUINO_DIR)/hardware/tools/avr/avr/include/avr ; -AVRDUDECONFIG_PATH ?= $(ARDUINO_DIR)/hardware/tools ; -ARDUINO_CORE = $(ARDUINO_DIR)/hardware/arduino/cores/arduino ; -ARDUINO_LIB = $(ARDUINO_DIR)/libraries ; -SKETCH_LIB = $(HOME)/Source/Arduino/libraries ; -AVR_CC = $(AVR_TOOLS_PATH)/avr-gcc ; -AVR_CXX = $(AVR_TOOLS_PATH)/avr-g++ ; -AVR_LD = $(AVR_TOOLS_PATH)/avr-gcc ; -AVR_OBJCOPY = $(AVR_TOOLS_PATH)/avr-objcopy ; -AVRDUDE = $(AVR_TOOLS_PATH)/avrdude ; - -DEFINES = F_CPU=$(F_CPU)L ARDUINO=$(ARDUINO_VERSION) VERSION_H ; -CTUNING = -ffunction-sections -fdata-sections ; -CXXTUNING = -fno-exceptions -fno-strict-aliasing ; -CFLAGS = -Os -Wall -Wextra -mmcu=$(MCU) $(CTUNING) ; -CXXFLAGS = $(CFLAGS) $(CXXTUNING) ; -LDFLAGS = -Os -lm -Wl,--gc-sections -mmcu=atmega328p ; - -# Search everywhere for headers -HDRS = $(PROJECT_DIR) $(ARDUINO_AVR) $(ARDUINO_CORE) [ GLOB $(ARDUINO_LIB) $(SKETCH_LIB) : [^.]* ] ; - -# Grab everything from the core directory -CORE_MODULES = [ GLOB $(ARDUINO_CORE) : *.c *.cpp ] ; - -# Grab everything from libraries. To avoid this "grab everything" behaviour, you -# can specify specific modules to pick up in PROJECT_MODULES -LIB_MODULES = [ GLOB $(ARDUINO_LIB)/$(PROJECT_LIBS) $(SKETCH_LIB)/$(PROJECT_LIBS) : *.cpp ] ; - -# In addition to explicitly-specified program modules, pick up anything from the current -# dir. -PROJECT_MODULES += [ GLOB $(PROJECT_DIR) : *.c *.cpp *.pde ] ; - -# Shortcut for the out files -OUT = $(OUT_DIR)/$(PROJECT_NAME) ; - -# AvrDude setup -AVRDUDE_FLAGS = -V -F -D -C $(AVRDUDECONFIG_PATH)/avrdude.conf -p $(MCU) -c $(AVRDUDE_PROTOCOL) -b $(UPLOAD_RATE) ; - -rule GitVersion -{ - Always $(<) ; - Depends all : $(<) ; -} - -actions GitVersion -{ - echo "const char program_version[] = \"\\" > $(<) - git log -1 --pretty=format:%h >> $(<) - echo "\";" >> $(<) -} - -GitVersion version.h ; - -rule AvrCc -{ - Depends $(<) : $(>) ; - Depends $(<) : $(<:D) ; - Clean clean : $(<) ; - - CCHDRS on $(<) = [ on $(<) FIncludes $(HDRS) ] ; - CCDEFS on $(<) = [ on $(<) FDefines $(DEFINES) ] ; -} - -actions AvrCc -{ - $(AVR_CC) -c -o $(<) $(CCHDRS) $(CCDEFS) $(CFLAGS) $(>) -} - -rule AvrC++ -{ - Depends $(<) : $(>) ; - Depends $(<) : $(<:D) ; - Clean clean : $(<) ; - - CCHDRS on $(<) = [ on $(<) FIncludes $(HDRS) ] ; - CCDEFS on $(<) = [ on $(<) FDefines $(DEFINES) ] ; -} - -actions AvrC++ -{ - $(AVR_CXX) -c -o $(<) $(CCHDRS) $(CCDEFS) $(CXXFLAGS) $(>) -} - -rule Pde -{ - Depends $(<) : $(>) ; - Depends $(<) : $(<:D) ; - Clean clean : $(<) ; - -} - -actions Pde -{ - echo "#include " > $(<) - echo "#line 1 \"$(>)\"" >> $(<) - cat $(>) >> $(<) -} - -rule AvrPde -{ - local _CPP = $(OUT_DIR)/$(_I:B).cpp ; - Pde $(_CPP) : $(>) ; - AvrC++ $(<) : $(_CPP) ; -} - -rule AvrObject -{ - switch $(>:S) - { - case .c : AvrCc $(<) : $(>) ; - case .cpp : AvrC++ $(<) : $(>) ; - case .pde : AvrPde $(<) : $(>) ; - } -} - -rule AvrObjects -{ - for _I in $(<) - { - AvrObject $(OUT_DIR)/$(_I:B).o : $(_I) ; - } -} - -rule AvrMainFromObjects -{ - Depends $(<) : $(>) ; - Depends $(<) : $(<:D) ; - MkDir $(<:D) ; - Depends all : $(<) ; - Clean clean : $(<) ; -} - -actions AvrMainFromObjects -{ - $(AVR_LD) $(LDFLAGS) -o $(<) $(>) -} - -rule AvrMain -{ - AvrMainFromObjects $(<) : $(OUT_DIR)/$(>:B).o ; - AvrObjects $(>) ; -} - -rule AvrHex -{ - Depends $(<) : $(>) ; - Depends $(<) : $(<:D) ; - Depends hex : $(<) ; - Clean clean : $(<) ; -} - -actions AvrHex -{ - $(AVR_OBJCOPY) -O ihex -R .eeprom $(>) $(<) -} - -rule AvrUpload -{ - Depends $(1) : $(2) ; - Depends $(2) : $(3) ; - NotFile $(1) ; - Always $(1) ; - Always $(2) ; - AvrUploadAction $(2) : $(3) ; -} - -actions AvrUploadAction -{ - $(AVRDUDE) $(AVRDUDE_FLAGS) -P $(<) $(AVRDUDE_WRITE_FLASH) -U flash:w:$(>):i -} - -AvrMain $(OUT).elf : $(CORE_MODULES) $(LIB_MODULES) $(PROJECT_MODULES) ; -AvrHex $(OUT).hex : $(OUT).elf ; - -AvrUpload p6 : /dev/tty.usbserial-A600eHIs : $(OUT).hex ; -AvrUpload p4 : /dev/tty.usbserial-A40081RP : $(OUT).hex ; -AvrUpload p9 : /dev/tty.usbserial-A9007LmI : $(OUT).hex ; - diff --git a/examples/pingpair_pl/pingpair_pl.pde b/examples/pingpair_pl/pingpair_pl.pde deleted file mode 100644 index 70aed6e5..00000000 --- a/examples/pingpair_pl/pingpair_pl.pde +++ /dev/null @@ -1,180 +0,0 @@ -/* - Copyright (C) 2011 J. Coliz - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - version 2 as published by the Free Software Foundation. - */ - -/** - * Example of using Ack Payloads - * - * This is an example of how to do two-way communication without changing - * transmit/receive modes. Here, a payload is set to the transmitter within - * the Ack packet of each transmission. Note that the payload is set BEFORE - * the sender's message arrives. - */ - -#include -#include "nRF24L01.h" -#include "RF24.h" -#include "printf.h" - -// -// Hardware configuration -// - -// Set up nRF24L01 radio on SPI bus plus pins 9 & 10 - -RF24 radio(9,10); - -// sets the role of this unit in hardware. Connect to GND to be the 'pong' receiver -// Leave open to be the 'ping' transmitter -const short role_pin = 7; - -// -// Topology -// - -// Single radio pipe address for the 2 nodes to communicate. -const uint64_t pipe = 0xE8E8F0F0E1LL; - -// -// Role management -// -// Set up role. This sketch uses the same software for all the nodes in this -// system. Doing so greatly simplifies testing. The hardware itself specifies -// which node it is. -// -// This is done through the role_pin -// - -// The various roles supported by this sketch -typedef enum { role_sender = 1, role_receiver } role_e; - -// The debug-friendly names of those roles -const char* role_friendly_name[] = { "invalid", "Sender", "Receiver"}; - -// The role of the current running sketch -role_e role; - -void setup(void) -{ - // - // Role - // - - // set up the role pin - pinMode(role_pin, INPUT); - digitalWrite(role_pin,HIGH); - delay(20); // Just to get a solid reading on the role pin - - // read the address pin, establish our role - if ( digitalRead(role_pin) ) - role = role_sender; - else - role = role_receiver; - - // - // Print preamble - // - - Serial.begin(57600); - printf_begin(); - printf("\n\rRF24/examples/pingpair_pl/\n\r"); - printf("ROLE: %s\n\r",role_friendly_name[role]); - - // - // Setup and configure rf radio - // - - radio.begin(); - - // We will be using the Ack Payload feature, so please enable it - radio.enableAckPayload(); - - // - // Open pipes to other nodes for communication - // - - // This simple sketch opens a single pipes for these two nodes to communicate - // back and forth. One listens on it, the other talks to it. - - if ( role == role_sender ) - { - radio.openWritingPipe(pipe); - } - else - { - radio.openReadingPipe(1,pipe); - } - - // - // Start listening - // - - if ( role == role_receiver ) - radio.startListening(); - - // - // Dump the configuration of the rf unit for debugging - // - - radio.printDetails(); -} - -void loop(void) -{ - static uint32_t message_count = 0; - - // - // Sender role. Repeatedly send the current time - // - - if (role == role_sender) - { - // Take the time, and send it. This will block until complete - unsigned long time = millis(); - printf("Now sending %lu...",time); - radio.write( &time, sizeof(unsigned long) ); - - if ( radio.isAckPayloadAvailable() ) - { - radio.read(&message_count,sizeof(message_count)); - printf("Ack: [%lu] ",message_count); - } - printf("OK\n\r"); - - // Try again soon - delay(2000); - } - - // - // Receiver role. Receive each packet, dump it out, add ack payload for next time - // - - if ( role == role_receiver ) - { - // if there is data ready - if ( radio.available() ) - { - // Dump the payloads until we've gotten everything - static unsigned long got_time; - bool done = false; - while (!done) - { - // Fetch the payload, and see if this was the last one. - done = radio.read( &got_time, sizeof(unsigned long) ); - - // Spew it - printf("Got payload %lu\n",got_time); - } - - // Add an ack packet for the next time around. This is a simple - // packet counter - radio.writeAckPayload( 1, &message_count, sizeof(message_count) ); - ++message_count; - } - } -} -// vim:ai:cin:sts=2 sw=2 ft=cpp diff --git a/examples/pingpair_pl/printf.h b/examples/pingpair_pl/printf.h deleted file mode 100644 index b2efd56b..00000000 --- a/examples/pingpair_pl/printf.h +++ /dev/null @@ -1,37 +0,0 @@ -/* - Copyright (C) 2011 J. Coliz - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - version 2 as published by the Free Software Foundation. - */ - -/** - * @file printf.h - * - * Setup necessary to direct stdout to the Arduino Serial library, which - * enables 'printf' - */ - -#ifndef __PRINTF_H__ -#define __PRINTF_H__ - -#ifdef ARDUINO - -int serial_putc( char c, FILE * ) -{ - Serial.write( c ); - - return c; -} - -void printf_begin(void) -{ - fdevopen( &serial_putc, 0 ); -} - -#else -#error This example is only for use on Arduino. -#endif // ARDUINO - -#endif // __PRINTF_H__ diff --git a/examples/pingpair_sleepy/Jamfile b/examples/pingpair_sleepy/Jamfile deleted file mode 100644 index 901f8da8..00000000 --- a/examples/pingpair_sleepy/Jamfile +++ /dev/null @@ -1,206 +0,0 @@ -PROJECT_NAME = $(PWD:B) ; -PROJECT_DIR = . ; -PROJECT_LIBS = SPI RF24 ; - -OUT_DIR = ojam ; -F_CPU = 16000000 ; -MCU = atmega328p ; -PORTS = /dev/tty.usbserial-A600eHIs /dev/tty.usbserial-A40081RP /dev/tty.usbserial-A9007LmI ; - -UPLOAD_RATE = 57600 ; -AVRDUDE_PROTOCOL = stk500v1 ; -COM = 33 ; - -# Host-specific overrides for locations -if $(OS) = MACOSX -{ -ARDUINO_VERSION = 22 ; -OLD_DIR = /opt/arduino-0021 ; -AVR_TOOLS_PATH = $(OLD_DIR)/hardware/tools/avr/bin ; -AVRDUDECONFIG_PATH = $(OLD_DIR)/hardware/tools/avr/etc ; -ARDUINO_DIR = /opt/Arduino ; -ARDUINO_AVR = /usr/lib/avr/include ; -} - -# Where is everything? -ARDUINO_VERSION ?= 22 ; -AVR_TOOLS_PATH ?= /usr/bin ; -ARDUINO_DIR ?= /opt/arduino-00$(ARDUINO_VERSION) ; -ARDUINO_AVR ?= $(ARDUINO_DIR)/hardware/tools/avr/avr/include/avr ; -AVRDUDECONFIG_PATH ?= $(ARDUINO_DIR)/hardware/tools ; -ARDUINO_CORE = $(ARDUINO_DIR)/hardware/arduino/cores/arduino ; -ARDUINO_LIB = $(ARDUINO_DIR)/libraries ; -SKETCH_LIB = $(HOME)/Source/Arduino/libraries ; -AVR_CC = $(AVR_TOOLS_PATH)/avr-gcc ; -AVR_CXX = $(AVR_TOOLS_PATH)/avr-g++ ; -AVR_LD = $(AVR_TOOLS_PATH)/avr-gcc ; -AVR_OBJCOPY = $(AVR_TOOLS_PATH)/avr-objcopy ; -AVRDUDE = $(AVR_TOOLS_PATH)/avrdude ; - -DEFINES = F_CPU=$(F_CPU)L ARDUINO=$(ARDUINO_VERSION) VERSION_H ; -CTUNING = -ffunction-sections -fdata-sections ; -CXXTUNING = -fno-exceptions -fno-strict-aliasing ; -CFLAGS = -Os -Wall -Wextra -mmcu=$(MCU) $(CTUNING) ; -CXXFLAGS = $(CFLAGS) $(CXXTUNING) ; -LDFLAGS = -Os -lm -Wl,--gc-sections -mmcu=atmega328p ; - -# Search everywhere for headers -HDRS = $(PROJECT_DIR) $(ARDUINO_AVR) $(ARDUINO_CORE) [ GLOB $(ARDUINO_LIB) $(SKETCH_LIB) : [^.]* ] ; - -# Grab everything from the core directory -CORE_MODULES = [ GLOB $(ARDUINO_CORE) : *.c *.cpp ] ; - -# Grab everything from libraries. To avoid this "grab everything" behaviour, you -# can specify specific modules to pick up in PROJECT_MODULES -LIB_MODULES = [ GLOB $(ARDUINO_LIB)/$(PROJECT_LIBS) $(SKETCH_LIB)/$(PROJECT_LIBS) : *.cpp ] ; - -# In addition to explicitly-specified program modules, pick up anything from the current -# dir. -PROJECT_MODULES += [ GLOB $(PROJECT_DIR) : *.c *.cpp *.pde ] ; - -# Shortcut for the out files -OUT = $(OUT_DIR)/$(PROJECT_NAME) ; - -# AvrDude setup -AVRDUDE_FLAGS = -V -F -D -C $(AVRDUDECONFIG_PATH)/avrdude.conf -p $(MCU) -c $(AVRDUDE_PROTOCOL) -b $(UPLOAD_RATE) ; - -rule GitVersion -{ - Always $(<) ; - Depends all : $(<) ; -} - -actions GitVersion -{ - echo "const char program_version[] = \"\\" > $(<) - git log -1 --pretty=format:%h >> $(<) - echo "\";" >> $(<) -} - -GitVersion version.h ; - -rule AvrCc -{ - Depends $(<) : $(>) ; - Depends $(<) : $(<:D) ; - Clean clean : $(<) ; - - CCHDRS on $(<) = [ on $(<) FIncludes $(HDRS) ] ; - CCDEFS on $(<) = [ on $(<) FDefines $(DEFINES) ] ; -} - -actions AvrCc -{ - $(AVR_CC) -c -o $(<) $(CCHDRS) $(CCDEFS) $(CFLAGS) $(>) -} - -rule AvrC++ -{ - Depends $(<) : $(>) ; - Depends $(<) : $(<:D) ; - Clean clean : $(<) ; - - CCHDRS on $(<) = [ on $(<) FIncludes $(HDRS) ] ; - CCDEFS on $(<) = [ on $(<) FDefines $(DEFINES) ] ; -} - -actions AvrC++ -{ - $(AVR_CXX) -c -o $(<) $(CCHDRS) $(CCDEFS) $(CXXFLAGS) $(>) -} - -rule Pde -{ - Depends $(<) : $(>) ; - Depends $(<) : $(<:D) ; - Clean clean : $(<) ; - -} - -actions Pde -{ - echo "#include " > $(<) - echo "#line 1 \"$(>)\"" >> $(<) - cat $(>) >> $(<) -} - -rule AvrPde -{ - local _CPP = $(OUT_DIR)/$(_I:B).cpp ; - Pde $(_CPP) : $(>) ; - AvrC++ $(<) : $(_CPP) ; -} - -rule AvrObject -{ - switch $(>:S) - { - case .c : AvrCc $(<) : $(>) ; - case .cpp : AvrC++ $(<) : $(>) ; - case .pde : AvrPde $(<) : $(>) ; - } -} - -rule AvrObjects -{ - for _I in $(<) - { - AvrObject $(OUT_DIR)/$(_I:B).o : $(_I) ; - } -} - -rule AvrMainFromObjects -{ - Depends $(<) : $(>) ; - Depends $(<) : $(<:D) ; - MkDir $(<:D) ; - Depends all : $(<) ; - Clean clean : $(<) ; -} - -actions AvrMainFromObjects -{ - $(AVR_LD) $(LDFLAGS) -o $(<) $(>) -} - -rule AvrMain -{ - AvrMainFromObjects $(<) : $(OUT_DIR)/$(>:B).o ; - AvrObjects $(>) ; -} - -rule AvrHex -{ - Depends $(<) : $(>) ; - Depends $(<) : $(<:D) ; - Depends hex : $(<) ; - Clean clean : $(<) ; -} - -actions AvrHex -{ - $(AVR_OBJCOPY) -O ihex -R .eeprom $(>) $(<) -} - -rule AvrUpload -{ - Depends $(1) : $(2) ; - Depends $(2) : $(3) ; - NotFile $(1) ; - Always $(1) ; - Always $(2) ; - AvrUploadAction $(2) : $(3) ; -} - -actions AvrUploadAction -{ - $(AVRDUDE) $(AVRDUDE_FLAGS) -P $(<) $(AVRDUDE_WRITE_FLASH) -U flash:w:$(>):i -} - -AvrMain $(OUT).elf : $(CORE_MODULES) $(LIB_MODULES) $(PROJECT_MODULES) ; -AvrHex $(OUT).hex : $(OUT).elf ; - -AvrUpload p6 : /dev/tty.usbserial-A600eHIs : $(OUT).hex ; -AvrUpload p4 : /dev/tty.usbserial-A40081RP : $(OUT).hex ; -AvrUpload p9 : /dev/tty.usbserial-A9007LmI : $(OUT).hex ; - diff --git a/examples/pingpair_sleepy/pingpair_sleepy.pde b/examples/pingpair_sleepy/pingpair_sleepy.pde deleted file mode 100644 index 49daa693..00000000 --- a/examples/pingpair_sleepy/pingpair_sleepy.pde +++ /dev/null @@ -1,288 +0,0 @@ -/* - Copyright (C) 2011 J. Coliz - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - version 2 as published by the Free Software Foundation. - */ - -/** - * Example RF Radio Ping Pair which Sleeps between Sends - * - * This is an example of how to use the RF24 class to create a battery- - * efficient system. It is just like the pingpair.pde example, but the - * ping node powers down the radio and sleeps the MCU after every - * ping/pong cycle. - * - * As with the pingpair.pde example, write this sketch to two different nodes, - * connect the role_pin to ground on one. The ping node sends the current - * time to the pong node, which responds by sending the value back. The ping - * node can then see how long the whole cycle took. - */ - -#include -#include -#include -#include "nRF24L01.h" -#include "RF24.h" -#include "printf.h" - -// -// Hardware configuration -// - -// Set up nRF24L01 radio on SPI bus plus pins 9 & 10 - -RF24 radio(9,10); - -// sets the role of this unit in hardware. Connect to GND to be the 'pong' receiver -// Leave open to be the 'ping' transmitter -const int role_pin = 7; - -// -// Topology -// - -// Radio pipe addresses for the 2 nodes to communicate. -const uint64_t pipes[2] = { 0xF0F0F0F0E1LL, 0xF0F0F0F0D2LL }; - -// -// Role management -// -// Set up role. This sketch uses the same software for all the nodes -// in this system. Doing so greatly simplifies testing. The hardware itself specifies -// which node it is. -// -// This is done through the role_pin -// - -// The various roles supported by this sketch -typedef enum { role_ping_out = 1, role_pong_back } role_e; - -// The debug-friendly names of those roles -const char* role_friendly_name[] = { "invalid", "Ping out", "Pong back"}; - -// The role of the current running sketch -role_e role; - -// -// Sleep declarations -// - -typedef enum { wdt_16ms = 0, wdt_32ms, wdt_64ms, wdt_128ms, wdt_250ms, wdt_500ms, wdt_1s, wdt_2s, wdt_4s, wdt_8s } wdt_prescalar_e; - -void setup_watchdog(uint8_t prescalar); -void do_sleep(void); - -const short sleep_cycles_per_transmission = 4; -volatile short sleep_cycles_remaining = sleep_cycles_per_transmission; - -// -// Normal operation -// - -void setup(void) -{ - // - // Role - // - - // set up the role pin - pinMode(role_pin, INPUT); - digitalWrite(role_pin,HIGH); - delay(20); // Just to get a solid reading on the role pin - - // read the address pin, establish our role - if ( digitalRead(role_pin) ) - role = role_ping_out; - else - role = role_pong_back; - - // - // Print preamble - // - - Serial.begin(57600); - printf_begin(); - printf("\n\rRF24/examples/pingpair_sleepy/\n\r"); - printf("ROLE: %s\n\r",role_friendly_name[role]); - - // - // Prepare sleep parameters - // - - // Only the ping out role sleeps. Wake up every 4s to send a ping - if ( role == role_ping_out ) - setup_watchdog(wdt_1s); - - // - // Setup and configure rf radio - // - - radio.begin(); - - // - // Open pipes to other nodes for communication - // - - // This simple sketch opens two pipes for these two nodes to communicate - // back and forth. - // Open 'our' pipe for writing - // Open the 'other' pipe for reading, in position #1 (we can have up to 5 pipes open for reading) - - if ( role == role_ping_out ) - { - radio.openWritingPipe(pipes[0]); - radio.openReadingPipe(1,pipes[1]); - } - else - { - radio.openWritingPipe(pipes[1]); - radio.openReadingPipe(1,pipes[0]); - } - - // - // Start listening - // - - radio.startListening(); - - // - // Dump the configuration of the rf unit for debugging - // - - radio.printDetails(); -} - -void loop(void) -{ - // - // Ping out role. Repeatedly send the current time - // - - if (role == role_ping_out) - { - // First, stop listening so we can talk. - radio.stopListening(); - - // Take the time, and send it. This will block until complete - unsigned long time = millis(); - printf("Now sending %lu...",time); - radio.write( &time, sizeof(unsigned long) ); - - // Now, continue listening - radio.startListening(); - - // Wait here until we get a response, or timeout (250ms) - unsigned long started_waiting_at = millis(); - bool timeout = false; - while ( ! radio.available() && ! timeout ) - if (millis() - started_waiting_at > 250 ) - timeout = true; - - // Describe the results - if ( timeout ) - { - printf("Failed, response timed out.\n\r"); - } - else - { - // Grab the response, compare, and send to debugging spew - unsigned long got_time; - radio.read( &got_time, sizeof(unsigned long) ); - - // Spew it - printf("Got response %lu, round-trip delay: %lu\n\r",got_time,millis()-got_time); - } - - // - // Shut down the system - // - - // Experiment with some delay here to see if it has an effect - delay(500); - - // Power down the radio. Note that the radio will get powered back up - // on the next write() call. - radio.powerDown(); - - // Sleep the MCU. The watchdog timer will awaken in a short while, and - // continue execution here. - while( sleep_cycles_remaining ) - do_sleep(); - - sleep_cycles_remaining = sleep_cycles_per_transmission; - } - - // - // Pong back role. Receive each packet, dump it out, and send it back - // - // This is untouched from the pingpair example. - // - - if ( role == role_pong_back ) - { - // if there is data ready - if ( radio.available() ) - { - // Dump the payloads until we've gotten everything - unsigned long got_time; - bool done = false; - while (!done) - { - // Fetch the payload, and see if this was the last one. - done = radio.read( &got_time, sizeof(unsigned long) ); - - // Spew it. Include our time, because the ping_out millis counter is unreliable - // due to it sleeping - printf("Got payload %lu @ %lu...",got_time,millis()); - } - - // First, stop listening so we can talk - radio.stopListening(); - - // Send the final one back. - radio.write( &got_time, sizeof(unsigned long) ); - printf("Sent response.\n\r"); - - // Now, resume listening so we catch the next packets. - radio.startListening(); - } - } -} - -// -// Sleep helpers -// - -// 0=16ms, 1=32ms,2=64ms,3=125ms,4=250ms,5=500ms -// 6=1 sec,7=2 sec, 8=4 sec, 9= 8sec - -void setup_watchdog(uint8_t prescalar) -{ - prescalar = min(9,prescalar); - uint8_t wdtcsr = prescalar & 7; - if ( prescalar & 8 ) - wdtcsr |= _BV(WDP3); - - MCUSR &= ~_BV(WDRF); - WDTCSR = _BV(WDCE) | _BV(WDE); - WDTCSR = _BV(WDCE) | wdtcsr | _BV(WDIE); -} - -ISR(WDT_vect) -{ - --sleep_cycles_remaining; -} - -void do_sleep(void) -{ - set_sleep_mode(SLEEP_MODE_PWR_DOWN); // sleep mode is set here - sleep_enable(); - - sleep_mode(); // System sleeps here - - sleep_disable(); // System continues execution here when watchdog timed out -} - -// vim:ai:cin:sts=2 sw=2 ft=cpp diff --git a/examples/pingpair_sleepy/printf.h b/examples/pingpair_sleepy/printf.h deleted file mode 100644 index b2efd56b..00000000 --- a/examples/pingpair_sleepy/printf.h +++ /dev/null @@ -1,37 +0,0 @@ -/* - Copyright (C) 2011 J. Coliz - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - version 2 as published by the Free Software Foundation. - */ - -/** - * @file printf.h - * - * Setup necessary to direct stdout to the Arduino Serial library, which - * enables 'printf' - */ - -#ifndef __PRINTF_H__ -#define __PRINTF_H__ - -#ifdef ARDUINO - -int serial_putc( char c, FILE * ) -{ - Serial.write( c ); - - return c; -} - -void printf_begin(void) -{ - fdevopen( &serial_putc, 0 ); -} - -#else -#error This example is only for use on Arduino. -#endif // ARDUINO - -#endif // __PRINTF_H__ diff --git a/examples/scanner/Jamfile b/examples/scanner/Jamfile deleted file mode 100644 index 1bf541e6..00000000 --- a/examples/scanner/Jamfile +++ /dev/null @@ -1,210 +0,0 @@ -# (1) Project Information - -PROJECT_LIBS = SPI RF24 ; - -# (2) Board Information - -UPLOAD_PROTOCOL ?= stk500v1 ; -UPLOAD_SPEED ?= 57600 ; -MCU ?= atmega328p ; -F_CPU ?= 16000000 ; -CORE ?= arduino ; -VARIANT ?= standard ; -ARDUINO_VERSION ?= 100 ; - -# (3) USB Ports - -PORTS = p4 p6 p9 u0 u1 u2 ; -PORT_p6 = /dev/tty.usbserial-A600eHIs ; -PORT_p4 = /dev/tty.usbserial-A40081RP ; -PORT_p9 = /dev/tty.usbserial-A9007LmI ; -PORT_u0 = /dev/ttyUSB0 ; -PORT_u1 = /dev/ttyUSB1 ; -PORT_u2 = /dev/ttyUSB2 ; - -# (4) Location of AVR tools -# -# This configuration assumes using avr-tools that were obtained separate from the Arduino -# distribution. - -if $(OS) = MACOSX -{ - AVR_BIN = /usr/local/avrtools/bin ; - AVR_ETC = /usr/local/avrtools/etc ; - AVR_INCLUDE = /usr/local/avrtools/include ; -} -else -{ - AVR_BIN = /usr/bin ; - AVR_INCLUDE = /usr/lib/avr/include ; - AVR_ETC = /etc ; -} - -# (5) Directories where Arduino core and libraries are located - -ARDUINO_DIR ?= /opt/Arduino ; -ARDUINO_CORE = $(ARDUINO_DIR)/hardware/arduino/cores/$(CORE) $(ARDUINO_DIR)/hardware/arduino/variants/$(VARIANT) ; -ARDUINO_LIB = $(ARDUINO_DIR)/libraries ; -SKETCH_LIB = $(HOME)/Source/Arduino/libraries ; - -# -# -------------------------------------------------- -# Below this line usually never needs to be modified -# - -# Tool locations - -CC = $(AVR_BIN)/avr-gcc ; -C++ = $(AVR_BIN)/avr-g++ ; -LINK = $(AVR_BIN)/avr-gcc ; -OBJCOPY = $(AVR_BIN)/avr-objcopy ; -AVRDUDE = $(AVR_BIN)/avrdude ; - -# Flags - -DEFINES += F_CPU=$(F_CPU)L ARDUINO=$(ARDUINO_VERSION) VERSION_H ; -OPTIM = -Os ; -CCFLAGS = -Wall -Wextra -mmcu=$(MCU) -ffunction-sections -fdata-sections ; -C++FLAGS = $(CCFLAGS) -fno-exceptions -fno-strict-aliasing ; -LINKFLAGS = $(OPTIM) -lm -Wl,--gc-sections -mmcu=$(MCU) ; -AVRDUDEFLAGS = -V -F -D -C $(AVR_ETC)/avrdude.conf -p $(MCU) -c $(UPLOAD_PROTOCOL) -b $(UPLOAD_SPEED) ; - -# Search everywhere for headers - -HDRS = $(PWD) $(AVR_INCLUDE) $(ARDUINO_CORE) $(ARDUINO_LIB)/$(PROJECT_LIBS) $(ARDUINO_LIB)/$(PROJECT_LIBS)/utility $(SKETCH_LIB)/$(PROJECT_LIBS) ; - -# Output locations - -LOCATE_TARGET = $(F_CPU) ; -LOCATE_SOURCE = $(F_CPU) ; - -# -# Custom rules -# - -rule GitVersion -{ - Always $(<) ; - Depends all : $(<) ; -} - -actions GitVersion -{ - echo "const char program_version[] = \"\\" > $(<) - git log -1 --pretty=format:%h >> $(<) - echo "\";" >> $(<) -} - -GitVersion version.h ; - -rule Pde -{ - Depends $(<) : $(>) ; - MakeLocate $(<) : $(LOCATE_SOURCE) ; - Clean clean : $(<) ; -} - -if ( $(ARDUINO_VERSION) < 100 ) -{ - ARDUINO_H = WProgram.h ; -} -else -{ - ARDUINO_H = Arduino.h ; -} - -actions Pde -{ - echo "#include <$(ARDUINO_H)>" > $(<) - echo "#line 1 \"$(>)\"" >> $(<) - cat $(>) >> $(<) -} - -rule C++Pde -{ - local _CPP = $(>:B).cpp ; - Pde $(_CPP) : $(>) ; - C++ $(<) : $(_CPP) ; -} - -rule UserObject -{ - switch $(>:S) - { - case .ino : C++Pde $(<) : $(>) ; - case .pde : C++Pde $(<) : $(>) ; - } -} - -rule Objects -{ - local _i ; - - for _i in [ FGristFiles $(<) ] - { - local _b = $(_i:B)$(SUFOBJ) ; - local _o = $(_b:G=$(SOURCE_GRIST:E)) ; - Object $(_o) : $(_i) ; - Depends obj : $(_o) ; - } -} - -rule Main -{ - MainFromObjects $(<) : $(>:B)$(SUFOBJ) ; - Objects $(>) ; -} - -rule Hex -{ - Depends $(<) : $(>) ; - MakeLocate $(<) : $(LOCATE_TARGET) ; - Depends hex : $(<) ; - Clean clean : $(<) ; -} - -actions Hex -{ - $(OBJCOPY) -O ihex -R .eeprom $(>) $(<) -} - -rule Upload -{ - Depends $(1) : $(2) ; - Depends $(2) : $(3) ; - NotFile $(1) ; - Always $(1) ; - Always $(2) ; - UploadAction $(2) : $(3) ; -} - -actions UploadAction -{ - $(AVRDUDE) $(AVRDUDEFLAGS) -P $(<) $(AVRDUDE_WRITE_FLASH) -U flash:w:$(>):i -} - -# -# Targets -# - -# Grab everything from the core directory -CORE_MODULES = [ GLOB $(ARDUINO_CORE) : *.c *.cpp ] ; - -# Grab everything from libraries. To avoid this "grab everything" behaviour, you -# can specify specific modules to pick up in PROJECT_MODULES -LIB_MODULES = [ GLOB $(ARDUINO_LIB)/$(PROJECT_LIBS) $(ARDUINO_LIB)/$(PROJECT_LIBS)/utility $(SKETCH_LIB)/$(PROJECT_LIBS) : *.cpp *.c ] ; - -# Grab everything from the current dir -PROJECT_MODULES += [ GLOB $(PWD) : *.c *.cpp *.pde *.ino ] ; - -# Main output executable -MAIN = $(PWD:B).elf ; - -Main $(MAIN) : $(CORE_MODULES) $(LIB_MODULES) $(PROJECT_MODULES) ; -Hex $(MAIN:B).hex : $(MAIN) ; - -# Upload targets -for _p in $(PORTS) -{ - Upload $(_p) : $(PORT_$(_p)) : $(MAIN:B).hex ; -} diff --git a/examples/scanner/output/core.a b/examples/scanner/output/core.a deleted file mode 100644 index 6ae105d90023b9ce818bcb755ee9245f24c98185..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 187630 zcmeFa3w%|@xi-F55<(L0SCQ)uBA{Y!L_|ak2ndRj0$xhdu#;@a)+9S7JBZXuKt!-! zasj2*daLzVk5#lkz_G^Ft z|G?yZ=AC!mxvrU6GqYyr&yF@$)y&B&jHH_4=|wZ9&zwv?K#xy18a`<1PpNBga1M{Irn1*o^D~FR-ICyo`Sw+t6Iw6kA;HMeC!riM7jOYhsPD z`l^_?D;m=n%VN=L@w=cgo{V`7iN<6_GEq^NsE$>XpLtHeNHixKnv*H4c)fC}<7?x| zXl+G9yq-y7lzzp^;*#okQ?#-+wu1Sp z0cS>iVnw1p2B`Tv*=DE&MYeWrZA`LbvRq<{lI5r}ELxTwG?gZ)=aM=t4|;{7MJA{b zHL8l!R9ScEU(`eN#i_iyXq}09P&`f0@|K-FV|fz3YeVVcV&ipg zb6sVuaX}r^m8z#U-i=k)opnifR!w(SygRGPVV!J}Qd_@ZT^MD+b0ZCyZnOc@jW}SY zlv}{}OhSDbGvI&AmFGrh+36_w3v z&^fV0ic1$o8>=smHpZ668spL0GfEbe7Z^pHJjD?U7J z-I8%qWo&J{enDMNN~g!_t8I0rC*hRnx@f$XPkzt-r46yzrM-AHqBri@>!dZc%}q7E z_}M3@#UV(O5y*$1_5^91Km#$6qGLN6}Dk+XP&8@mr!p%*sF&lV> zY3~(@%BEQ3x>!YWy)6RkSzxUI zs;S-;v{?^Rw4kQ^>~*F(tfG@-gjf?pgpIK#M^*7DEY6AsTLcxgvHG=1X(%>q5lW## zQW}=POw*v4t!}(Vmsecks$WpF$tfFUO|-r~R_oMBakrF|pY0~*q(nok{sIg_ zsG{r z)PxDKk4#G8+a@?4^OJb3+a7{PPoEwEhuQ2^JB=x1Fn`^qfgG3^$ z^Dd8@-dbi-1&PAE)E=E2kueigxFf+^PDvzkQc*GV&)}a(aZ%BX(o(oi))-djZCtQq zq3`>6*|Em=mV2Sg^RDdYdDp^n2>0#dW#-tB z8PJ&nrzoN`w>0qeygWF9Ncx2i3ij`Z1P=A7ae#%MH!uu57C9O;*<*@@Raoa#4P%|tQk^HNvp>VqoPo4hoyRVK(}prJ8Sg;u(m-x< zC})z9Dt8Oytdb(i(WE)OK<9r1vL~g=22O8)RiR2|rOE|PG??Yfz06sEU@8Z(LcbfswONT%MQGA64;@X-cB+O%~L!Ye7S8st{Rl z;ETS&{6!uGl?ojtbVM2*E$*Yz_`}4l{^~wDO>U&PhX@^?=8u#djbvq*it+tF4IB`Z zKkCEtZfd`y{h{`!+h1&dwS76C1kL47z;6>hgxN`zL*U zQq2F8|E0D^+q}*Phd-Uwnf=3Tf4|q6v*WI@50Cx#u|FJpecQJD?IZlXz4?2cHoVB~ zk8~AvG0s2v-)Z|1w7%?r-@k6a=f^!T?i=H79C1gVJNrJ|*WX)Mar)AwODmRc+hnyf zwNtxFeyOQlec@$GZd!WBQa10sxfz~~(ueQF} z`gH3K_RoUhrq3WYzc{2F_IDduvh|c>KJ|4!^3yukP?; z9ZqN~=X;;j01i}E&tZG!hGABA_@Clg>I}DeezJt5Na0l0)?WOvM;SN`S zZHHeM=4Uh%*iNPnqy;Wr&!gtCu+}$=PGj8GsJwJ~=DFuZ&WM<<6MbA1t9*6Q^|gsa zLz9P&F*&m$iFfm8b#)^a+%At-Cu_XgME%-``NPRT05ma2(9ag8b+gU&P4Tt$vFb<_ zI(*N?VVr>sBTsdJQ#`|@7kzniZPGJp&RM*Csm<9rTp=@SVMbj_;IswDV3E=QtXlTE zoSCw0S>Ie|i|(AI%NLs!IIN6%UP03pb;)QYXtL4L8b!(2`lMG-jW=nppt7k6Fjm>T zwjx?t*%({r6*OYOQdsf&HHj2PZM;4v3~DLR3UC9hX^hsXkkyR$@)Ru%&6V|#LCj8E zQLM(TP2(xcszLhGThhVYW8lfo%}gvo?OZ$zp&eho$eFq4LFA^uj}yd0$#KS_x&ckR z?-PhoztiDXOs{Eh@F`QHezU*`pD*B{=)sYQqrmSYejFb-H`XwK-sd3m1&5*VZ1}nQ z29NN(pMpnyoITTz`l7H5qvbaPk-1N|>RSaFSKnLE$GlKquJ}X2AI%)-t5PL!6Vfsb+U5bhyYQmI_M%3EkUGWh zRiiLo0+VS(lQ8k}9e{1Z)mMrLUI0&x>QlE;m!IYBJD_~h%#@O$+f51GndV)D&zv>; z4sfbEN1f0&5%@I6eFAXUXY4yLJ@6ygcOdooO;3+o1B{wD(I|@MH?$Ppy{ZTHo&F~n`wT*;9F5qhaJoKbfl`eI=&9uj!p5>VAC-i zl5M}}vqOU6^XU&a(9{I+C*T}MzIjdcynJGLlb%WpnOi|m6wL8zmf-6_7YcqBbh+Sf zfUXo=1{xLodr;2&sj~!>eJC;OXr16!KsO6s40;1GR-S0uV2N4x|3b_Pgn0m#dYHej z5rfa{d|mjTg8X-cKNVaH-(`13ZTqI{y=Rz9YX#Z~^$A5P61OC75B? z5F_j_fony+9JoO+pPeg2o?)*R`S*dh37>k}h0k!ih>`xg!M{!LeZXHLMt-U1A!5XP zALygPr=D*LzYFx+#L)8u_|FLL1b&`a^!$VvdPZe<-YdeVo;QVG2L7Lge?Dj~+zk5~ zWTpw80RCdZeStqExER>fDcm%sPLUoOF1~0TTT_qF!?I-@ z)YAfdis0*j=L)_Xc(GuXgQ-WzcLIM>_&)}Y3jR58Trk_`WrEqJOg$njp9PNpxuft0 zCIXu$n0d(M00P5jIZtpAa0bH804;^($}aQ8c0Uy3FwG*^p?uh3E`-hHYZMHh>pa1H zmKnAMl>IPut^-ZNl0O`2+bVpP&o<$+9NLA?XJ?1-DSxNn`#>LrrB0UNH-*nK`H}D` z|AydB(05@q{ajDg^bZAQdRT75A>$9i9~c%B>r0K|Ea9_UhY6+(=O&by4a%}r`Qrt% z{AkH91!Wl$vz(U-W;ricKGIVu_zBQ8f|-x?f|d2eE4l`PigSpelZGmY8J8?d z*h5m-j5_pQR8djHm_zSHeLF98FKWCu=C8UJmAVt9TTh5Ir?(xe+|(T_?n*fuSUvAc zVIC0fEd6zMriOPrBJ75By(sw}+E1yE8OfsP60Ji+ik4-3L;C-7gv^{-LJJ z(ln{0?lh@}i6W=|V~)^$%pv3})BJTuO4ET9b0*g74pd7Ax}}}F3U4g(_TFB8OG67@ zd^YdgHfYcFz1^pRE0x3Rib|otp}6I_(})&Q9NqKfUcKaa;=?b70QBTz4njYMebM z--|0(sc+^}>N3>#s@0wCVGk-E?l)w6H7RbDONk?@-0r(P*g#6z^-10J2*aiC?xgN| zs9Z{{HGe(s`A}tt8NT1Oz?FVFnw`G#qSYRIcI)K1pqP1Gv~K4BHDo;YjxvDJX$s=|_E0SnAXAn})~~gB|Ew1?=kEj|F^&XZpBO zt@^G6cJ-A&-+b`Y(2wSFSXUp8!+Ddyqdra@RbM->t8X3jb%Lix^>OXe)i(+Hroof? zI4f0s_W(1D*6$2tR&{_K;7$jVKNE6g1Y$HUu6rt`S2-3g7J)KezW-^wW^Dj&HS3{| z?|EtzJ`aYgZx{5v4^QetlL+*^4y<7Sy+=@~D+$D?-_PK7^|fL)r1gd-5$O8^u!f+9_nMA@`!tOV?rFeb-?#5Th$*!1KpFmqY5IS?H^q_- zO{QttuA410G?}Jlxo*}_XfnOg-Z`PuJa?Z2C76#l;&Ggf_ zaBe1(HY<(%vFuXzx6n5=fycJ$1G9ng`SIBiz~sZG>~BG4KX@mS5Bx1qj(fz5Ko<&T z-)7cr!M`1t{TgL{0~!@fS|j*H(1c*t%R0e71Kli`&+&F*S!=sNF!S^|V(5Ps^ghAo zgW?S;SigQ;FxvXOh1W^pC{S{QoSt6LgqwbyfpU z6#NMA6k^Cz{|SPp0v8cOC(WsXKMTBo81cRgY}Rlg!~E5V%nsns3N8fZc@XNM{`-kp znJ{}{b&c`^Vkx%_$_UOAoCSZb`;*V|97~M;l!kpTF}hYW9uwyPmkOW#Jo|C-Cj-wH zTmZa8a0&1V!DYZEUyx^AtRY{@vtBS4?$!yW*HwbqEVl|~es2`K2>52f=K|j@cp31$ zf-eMqP%!(JuL)iQ{7u0Pz~2?T0r&;MTY!Ho_(tHL3uaxsDfo8acLd)9{GQ@?rfE&jMxr5wo0U2xcB!sZOnep+%qUoG|C5M? zKb06|OH&G~eCAQxC;e0=OK=WoKL=9rcEO#Xj|c_{&JeIY zeoOeo-xd56=*xmx#y=N)7U(YpF9UsB@Cwkqg4quD3tkQSC&3M%2LvZUv*r2P0&My; z6v8&(A;RAQJVNj;VAH=r<{sdP@E-uyzIr#X_SMX5HteDHhelBb^+FSY)q0^@`(e{& zGRU!gsJ26vm-f9#R-k9N;Q63NKRsc_!cu=HXv$Xvhw;tR^pfHkW}6A$R2}M@r@_eh zHHf1Wmb3rCcoTEJc^c|d;E29>3ipNhol#%=^-)f^YeR0XetndekB^fI!O{JrK8uIR zw$5tQnk~p)wsqVs9e=}gBtOIFql*2*@arT0$|dwT(yx#3MNG!5YY{T9FI%)xn{g@` z{VbkM+&`ON#AKXCJRo;2{&vFV@lO`ky!*1#@G{rIhZyLMZ zE-~`COv4zIhfzID!e8YVfTeo-0b9L0{e?a9A23@+uDqG`{F8oobMVh>QXUzzQR94g z!?|Ctn+@>8fH}qEK3B2g7igmMD1tc z`LX89AhtnQ!{a~T(lg^+-ZU$%|Kl*jQ)~b0aGeV@*dWr@Y=Z-F)4Thn9HcwDyMOpj zf#`yyIq~%tR~kPho;1HOj&4~$lEvDz+6`8c&6;rcRb+Qj`lGEs8=b)#^I^Ht(3n_T7ps#G1Duoj;c@-H={fw1(N@rwg7p_Wj<5w;LqD2)SoWN{PScy* zWXNb3Kr=3FB@m;2r@*b4UQfdEu~MUu@o-F5GZ=j&-?IjSfn~~I?TT|14MW-ScvAVk zr$*rdFkF4>F|gym(bre}=sq8oVPq=c6(i#-;Z~#i;$SGI-)ABB6%}&)s)5~jw>a_U zi67&=Lc$b*(#%94o~u(sNXyp{tqb~XM`3Is5TijzH4pS^MJ4j=5T`-Z!8CEok_+qV ziy%?I15b_WQ@2u=|54W9829O_3~OlY+vhm$iNL2hZg%Ej+xvT;4`)qu!9=LG*0 z^xJ}0gZ?KmJ2;qEV40rN5%$-_;Il347e0uYr;yJ!rSDC{fSEq>*`CZ=5cKf*nJ0X< zE3^Is{+Yllh0pfIbZfbpGH2%mW6#X-<_2pHb!P6A>4*O=GZUSX`z~`V-pHMInIpNs zA@vYkq#u{-vcoqU%b7rVBTq7y zNO+YP3-BMNmzOenxi4lJf4yrVsMMgUIRqk{#|Vw-zd;cw;^F(( zfa`@fV5fpR1!&qXantrYI0n`=d461DL2E`VmvY9DZI8YTcH{9ceH=m9Zy9s2_`IPh z0qYMhkS6nTH%0N zBbimpKF(o#D>0MEFiZXaq(=mCfCRa8Us0XcPdN=&CRES!>FGN?9jETzXnMGGIh?AK z7?ulF&3f)GJ%nluL#|E>sTwq-y7la#^7Uk4ca5JBjhQh`o$AoA>h4Xao=(ifbl;ws z)DVZOA^ipn4W~C`XzIgqxK3iykSd}1J3;)z5MLLLN@xg;OHXyCyETUNI?`NgsVFUy zcvO#4jaTKgjF3W3X?k7$n9x3`ebCniwGWw8*l~KtO&xc1Jk;@Y2TxqK!rlqH8@346 zzxl3l505*h@WhG}Pxkhnc!70CIy{f(HCtitgxyUyq}|X~GF|HFwujp8XuGNH^tQsb zL9K(nIjD6)>!_VKJ^ucVh{RY1S`K^D)4X>hXXhO~_-%dczR!D|H=Q2d@Nvh}D+#LSK4X*BE^X=(DNb`1F&7 zUoPBLxNXYTL2ct$0+n6c27PYA{S&@E;Sy+j3b%tC=t0k$M$eu=&w)VCjiTrEK+mtC zXX}_-`faet@d+ckJ|%cjl1meU1}`2B`x3w*i^ zqWrIar93xG%O;$4y?Su_zvE;sr*^%aNo|E6{ncn*}b3+zLuG&t>(wrsh69COO=6go{QC!w4pb-y{u$P8r`$Bl6ssctx6ur z4Owz?%ir%rty|>Ixmn3l3dh{^>~L(Iq%%@lZh<+PYuYYvVJYajA-G-|u_J8@(Z*vJ zXa6CN>Ea7B_8yqk%Y#vx_JGijCLfkq*ZX>tn*y1`S@WGH`aq1KzNH!&utKi$DW)L5 z*Jh`rM*U`i5%v%05xB96#2y2JWlrPAF@WjispO#-WJhgWMJBVu)u&d9**^D>9WBRy`s`}OgyZZJ+pZ0R_3iLHe81iV|fW9J7 z>f@`b>bnlu)i)TGqrD}(0)1RVanmKll{7!IBq`qA76>!zZzvgTM zsG1xs@6NG$yV;s!_iZ09W5CC}Mc(W1ph> z%vzxa2F-xbBFC-z&P>x+14Y{Y#yR>{Lr%j`%~{Y_Mj%H0c;AJazNes%ZHVc^qY|XA zUi9(Vp}7wFxbCTjkd|#MQ<GEIYFQSB-ET2QIa zfu~0GsavVb|0sJWXdWqhC&S>Lqsp?{>bJJzHo#{#`q6Ps92!>rz1k-Oo4k$qP-Ud2(DgTYhLV&8b`0&6XFMOpL0_ zL#JsMm1*wF#N7(Y^UppH$nLf5Odt)yn~p18rv@M^PsF(;u}F% z3jQ%@RB#O_EoGhrbC1!j10Wmvw z815Glvk!We82U+nP0S7n<{emKX5XAAhWu>czP^=byyom3_{0II84!npMX_yDhd7qxkTrQYpYtBX^?8Cqu(6sO3Xro`3bD<&%H)0ZRTyk6x%0wGUy)#vuv@jY~+i8a|KhsX%Emd6WDwU z1k7h5Uu4RFSw@U&K5((%6~Lzm-T-Xc24vW7c~D8)q-hV*J~^h7k1Uz{?}*t3E)_nD zu1PTS@@c^=+iQsVpu^nYV0>O}_|$36+(U*sza)I>{EA@ed`vK(qi+aiS$#+FLg42G zvn~CE7;Tc~Rl(H%w%}~weS&j<|0tNRFRUwu9Sv;mc>0Q}U-*od z*K||nT;S<~%Yjc7yc+ln!Ii*g3%&%H>o5%40Br7#0&WDZ68^2gmkPccxJmH6z@HYp z8~AF$j{x65EbV`%gTElyl)2#kkpGHcGzsr9!K{m?i3wo7=inCwgLpp?%<_CyF!lUO zFoW+A%(DH1;7Py-1hYK*V#3F`ihu_Ro&kK6;4+?>SS9Xrp{%8sq=hd>04F`W*V3`@+n^_nDVuPK};K>4CR?Om0vHI@_Ys~J$ZsD z&pOlepa~ir$V+;Ryy!Rbk{%-uOnH`JCZ6lbpe(}-!Se;r0#!YLHeS)GdYDHPjY&Us zQcos4`3y#2GX%42iD!edY$LoH9{QOlG1wLGbxZG~akHfmt0llVr#TR?XS z=JWobgQ+V6&l-Z5IVCa622I)XSr{-R+W$`?7C!T%eQ&A5pGhqJC(BLc7ZEcem=&M#(zJEZu(L`Xi4VZQUoir>vt!vXxSg>L^hS8Y%6`TXNwmtUs#7qyPVI9#> z1u>s9mY2p$H!<6MgjmurN$?|}CT-I8rjZX!eMQ8Qwo<|CKnsf^Ddv#plZt1S+5m_C z)?yVFyRJbTjE^ZBhgR_s&nG#*FQdOMV-G3y4Sz_c_j5_k2_V#aUKoT2iFg`GF80DQ zPIwRqYk%R7&G0v7oJ+&pvq;c5SdShJ8HAt8;jhmOwdaS@&mOralUOq&`rxb+I@jJ# zN*xuZjh~T>vLBZm9VUj{(fV=8n0yrT*w9mc+U6;=Kim5L{%4rXPusBe{RO`NIZ!O= z!ZDvsQ_tJ*^~oBXqWK~m_F^w{i5B@Bp7c(wHT`hh-t)~RV|;u(KcA}l;r3n6pUA)i z$fe;K9V-%904JU^NSlCuWhgZ}kjkeNTCD0M3gx&~W>rj~T(-Tl$K}XoV-Wvm5yGkq zZZK1PRIJ}U#MjiHoL?^lJTvpJAz2}{w$%(QyLTMV&( z{A)iC=@B>36%^LC`Tr!C6Q6I$+Vgh7(mp;9dW)-cZ|pwS=5-4@7wJ}g0_)vpevgrF_`a%kL$X9OA^2o_x|1PkJJ%H+m>J zE_c{-X05%%teQ1uJ-e0p^hOP;UP|>cKNVHJ($giXLnTh5K9pRTi3bjm3Du-2%e?0! zXJTbqCXfg|R=u7*TU1!y^{o7&)TFku^766|{4H(Uj`8=tg`4@_8FXL*Z|CE0Me$dr zc>3%5w#d%S$6ViW$J6#S*!69jPq403U8=QIwC-s895i^H6QTPU-0C+8cm3sqPBeG@ zO$M4`xRhyWYw>QnT zeh}nc(fl_4O4grzn_m9v)ZZ@6+Y4LG2{ikQUMyvlE@Iq*GRg<#{fV}R@9nJD5>&1k z0YGVX!@BN!4cGqZ;dGS4a-fFk@s`3G^;POfIj{%ckkx~Z%Fs7}AqxYjH9f?Teih=W zkVJP4(}^CO6Fzit=0=wXF$PONXfJQ!q(&J0{Z12zV}%Wl&|+B1G%Q^jw^S|X(0|=8 zBKbW|a6HKDtKfu}{EicTCboX*nlCQ`rL3BK+LP9K>wMo02>r(CNX z4ifG;r11Pw5P><~q(2Bnho;5(uqe1FFt~`&B+Gmano{EPgJQ=N(n+DB?rRMCDo4S9zBTWBLXPCJEphn^8 zU?`^Fzrew+L5=#&0>fdO-&2~}$DXGEF@Ee@%V9MPptlyU-~Vm93_1h9vw>ZGvoY1Y z6LQ?8<~u0;s4ogjeNbaeS*~4Q5oe%p6&S9*SFljG8a(PlkU(D&*wuGEJhkV7SD-H; zVaTJIJ;5{kh17?4`as|Hz^=a8cpG+mK>E>K3+tvY8430ARYddqMPLmB=)D1bWdveW z2iN@+)9ZnJyU)w?@l`|hnYBL(h?#`M?@Fyl_3ekga(Gf7mb3zW-*LhKdc#mj zY(r{PUndx@zWK-4`lLRrs08|62G%fu-ZJPbA`qi~{{^?JuN?X)M|~s2kL~3hSPcW{ zZ3dHTZfex;Z7^JYEzq|bJnG{X1^uY+Ls*8b#Bn6$oDDZlVEFv1|nD^g;xp%|yK*Rp8 zV5%~GALKFg*}Wg&4}eD?4CN`K=PKZ3?;sR;v-czN=G-RIfUeFvO~Q@_o-6ox;IoJ& z>?*;GD-AWAo#o%8r@|5Ad5Lym9iJ_nJy9EybeVmvBCd}6b z^V$0$F?7xc{sl3@vdqmH2w;}mAoSZBc9>w6iTPa^$;%Y-fti<+9GO!DbN^_b$grHx zapcYU2BeKL6(S!2u5ske`3BMd8S;_l3m|i?$g^xeEBGql+Z@dK7Sn$t_+KWLG=E(% z)BJ+Sv;+UA;JbnUM`T!@za&Py&EWsWkum2Opr7Tr-;vM4z{a?Erp26HU`GfujC^3W z-{Xj(a~p7h$g}+C3ugJ7a|sf5xrAl;uM!!S=UTzc%VosS$>-*BN1kWw886Fui^wzV zO@bNr3y#cPf+OJH@5n#q$UjYtxc&_?-xv7;;O7Nz2L8E&Ul+Us{9h4EUF;)BGM^Is3GnL#{~Y}51Q&yUo8T(o2L)q+&7QSFozeUW zR{IC`M~eFiW|J4OCt;AaF^1HUA=7Wk)vIUnc}%;)hf!8Zc$72FQ|zF@WoP8gY< zn*nnK-ww>Xr^&w?*!(UP@IAnsPm<5)$owu9@B_d_!ru)%i&&l=)BgxIXZ3(tKFdUg z<->g@%13}J1+z>p5nKS=Ecjet(-%SheBf(@UkPl^T7l1T&z!XaZU8oCt$^19e@Wyw z1Dmr};NJ~w&RPL8U)iv^Y+x`suz7-+?p#h^%HD2o1c$pN9mvQl4)ybfYi+8C$2s%~xSAm*%!Drfvgg+a! zRPe>1GX+zg&j$6djm;50+t@t8Y-0-rQ=ZQT<=Ixt1z!ldN-$+A1+!i*arljbH-K)1 z)jM3b0qY&Et-#FV-JpNfazkOWjj^mUfvMk=74T-@BG?Szb3sj60ha-rvI4FIW;s%Z z@+>RrVIJoRzX8;g75M9cSqCb=1eo${!z%={%vKAg&NYHr{`C%jonV&jb+Ebl_yco2 zY@XoTfEm}_pu=JH9LXqRv_l%U8RfGa_*~O4zshHR^;xE$hRqVpI^o=l{E?u1t0A5U zI$kjIO*i?>H|J8sMWB4ABWC%{CzdoU5={M^bC4ea{gmLXpp}9j1Z7!KW;ZD33dB1= zuMo^~*hY*pp|E-3T8XGUogv?<1WKSK))fF>G`%`#`TO~>frcF zdCL5c;G03SiTmRZjEk8>mI;liFDa7<+?sy+9qt(;mbuX>dQ5wevNHPV2{RU!`kCen z7S|_Zjg8F>$tH7w(V@-;oiyX{fA6m=C-rPl1aCzj_iT_JzUe!{n}QND*0}c$WzK0qtl1e` z@wcy^gLI%Crx-$r!wx?J;i?bV(@0?Q_{X2pg1>U(j&S%SX5&Y%VjaF7NV(kA^#S~? z=;hSq*LeMGjK6ZFg!fyQ*Pjn2KcE}HKin?vYg)NKi67D1i*p9?gFSOo`9JCJ=D80} zx0`WfyQiTszAl=K74)*}KMN&;LcrQ%D%JZUzT=MbR;@92A99=={OKv z0JHrBe{WYCrp~arI}fz&Y13<4Hnt_&D%zH&UElJz(~P!&KCRb#M;3}dh%uA#m-1>> z0;Idu&)I$M8Loh&?bi57D~Hf%G8wI^3C0JHolA8rmB&sZ{G!bph@gS91b#B9GKf8W$CG3mxxy{Y_6{=Pd4H@izH!q$%NTBHQTT$JFxDSa&uFx zF*OjkWqaGYh2PAIq-XY_Lm7rJQ3YjG>=u_1q>Q^cd?dTfseKYO*^&L+<~r}tSM^p$ zlTnYiJa`560*7d2Wn*le{7{=^#p~B3QW&-I`dG?Oxuvxkck?x^={R0aarDG3G07@G zeoO`Y!|l-W^^l`kwzSyNw3bUhntWJdEWsGlo7@!mV(N5AIWsI5Ic|;jbnq0@ z`#o4b;=%Xfc%3#dk6`u=PLFT3+a-@*20i;)QJBB)dK z@x94SUo~cHi@;<0IP0Mw`@bt;8Aj{la(HN019qVAa$r~A1JK8Akow&H*;^!x>iYr$ zxm}f}uRTp4U&v;QK6iiiD{1=v(2KtN()7)C^l^&Mv@^fogmv4?Cs0{#zBGL=K~6EC zw*qqI1Y$JI58zfzul0y`H7LskRT#wkIa~Gca6zKZQQ6H^4yOyTBTT zI-ZBV3kk%i-|ygd^+iV5a$x%SZc0Cv3-?Yn44mGvs6f8ws!>0F3+(Ef27Ov@d~Z^H zW770p1bs!S3{>^;D6*@s2Kv^+pXnP7tNM-;eX8RI=;MBl8baD3u-a$P?*TkK>32Ag zPgy&J(}gucHaal44z2MH2IjNk>gz&d`WNujI7v{Jp)UWU>&8Dm2)BO4P`^0>5LX&A$Yg{*5ZfG*i zih%284TdHYZ}H1Rr+M$MOmkl*?uDS-N8Tjv$;RE!!+h5m_GR4ny)DI!+De^Ie4I^R z9lH;HH$wWHEqzYs%o75LMuEpBbw3uHJS)KCbHmfQKLs`Wv21WKY-cI^v5 zz5#TWV75Q@RpiG(mkRz5(DMb)1HDM_t)SI{*MYJQ7?yoG-NX^l>jd+8WIgCQ&`!au zv%82PKh(Fs`=|TKyM@0R^jm@%?#F^b%q4cZhV&Zwh=}#hzEgF6DEKR&W>1C%24nh7 zV780Fh@0|H03Ssx&DivXz?7LGGSh(P5n~*s*$b;{S050|T9>(dK``$pCZEq7^GVDx zfqQer>@&GkK+OK&c)m(eq(_$%v!C; zFbzq;EVrwOrF_g@G4Mq2ZxlY$bF<)?z_$x#`P@e=<@Qy<4EuG#4ErB~8TJQ)88(9! ziJTA0F)dfhmg&wDJW^zId{Oza;AcXR`i&msaT0Jg-I8~%@DMY<)X%kQCKbeB@~KDT zWgHqWb!AB!rV2*V?fN>(hj}S-WJ(!9r;LkjEJ7@CO%hDL ztYS6Q#MdObIDE*p;gT7p5n~Sh-RM*#{u;!=x?u|#gVcS*wPE+e%J8E4?9?S-enTo> zfM%dx_}g8<2cfyH2ED`{%{=_dl0m$wXxp~rv)IZpMd-n}>$N@I6Mq;BzoMd#jpT$N z8m#X=j~JO0&kw#gJh-#3`GhbK&WU^eG(KYHjuWUE;~N(_Fo?mb8>8HVJK1@7{#X^J z_Hov+1F6pNUZS`E-tY79*JnQb!nq9%wehNGGM=b!DxBL`jYI5-f@niS;TZ`mSJWq) z3YW#263vZOv8KYaqU)lCHPOcE%cG64!ek;*+f*1`*H~B?uP-bpD6EZF7Ot(TGOW^q z=>;WZ2LCA-udk|Y#+Lv`u!fS>>btG%;!W7L0p!P`IYQNaw77=})kRYM2uZ2(2Z)@m z`l76aQy^5`dSCX?G|j3hUGu>1nlX~2Uf5^*{+|ZoXYr(7;Ktn}?Ju^!+PMJM z2^}wXyxQ?r!FvUd7JRSkrLK&^!ClvOJyY<*XW#XMC@7=gw<)Ua~X8 z+!6hR-@m}?Y~HzcXWovC{n3USPaL=dCtyyDc3HaG(EMBO*z@A)|J~Q$|7zQdZ4=rC zwH;{P)B0-bi>*($=Il&Q!TSZ-g>MuL?qV8l>H0q6Zz;6;-a$HUGBMojPaAVuKd+Ow zMjwx~;I3@LXKKh}YDS&VQmFCYg!q4o_%{`%r{LiCK5s#>^@ml{q5w2yQT1ZS!$9Z$ zV&ALi?pv)a-)wxUOTt#FJKI~`;YYDwBgXeuD^!}2jviuK6AJba)=5VXd5CIQE>PL0 zU>eerfXj>#OYs3Rdnn^rTyLZ&1)^ET%|BZNwFo^NqB_x^HOD+02VL4&9c%QeY7D7mn%rsOz>V18tS}cUr3rvgE9}YBB%+ zYpl{JIh+O08!+c9cZeT}`f*)DG5P-omJf#-g|om2p9I{wi#gjp@MOn~p!J|HRjkQ_AmsisgLt%`Z2%TU^NV&_XIqO2*jw4tKn8muNur-DMx(+U{&9( zz^=Zx;PHF#)Tkfdn_Ydopsxj<)WboCU!vK0eLuH*nAV&SZ1h=bi6ei%zAN6tS zt@@q@)-Zrx4hnKAff)6B5^h)DBZb zdwUqvtRv!?p~;6$Sx1BnpZ^od2WG#?{+>7j%IA!D1*lm^1ilUUeBl>>nsr3*w*yxT zKMH!OVD3d-Cb$KZap)Srm4aC(EN{ledTb|VCSc577WhX2-vvuP*L3bB1|N@`Ia^2m zY+%z*0j~spQDi{uZ=%c#Q)iuRm5i`LsdtiyV#_+Onx+d`Pz=Nn0xD42=YXY+# zxc@>vr@vDK*8mp^ZU8=6Fw1!^v6KV9V<2XK#`E&TV}U;@cp`9AFw+nhTmXET;Dx|f z2xggY5?l?uU2rXMo8T7Usjyu0D+4Wo<(l72P_{ktOF`!d|6I`dg3khF`=AWtT?RXp z0|5-r2ef#-(HK?zu5b#+JuM3}b z@}}Sfh6d+n`{<8r4h!PymlD_T)KysLH#oVZIx=iza-7w6$7Jl>x- zI=rZFjQ)Bk@4=Hi^OC%A_UgRxl2%;ONA3hY*c-`5JID_`?bUe`T}DP8zBaPwd?)Ei z<74$a@Z?aEa^Aam1+cBrt_QPub~8pG}6&2;p%}Ey^=Gn z%nZJ}d6`*=LPK1|$0sw(dgK_7%pBvgCxwl2f5Wkm!VkOIw?EG}KUHdC@vo#;?ko6{ zhlSdWivjvspH1b!0#62n821Ayw$%~a9*S)jF%E?`;1@zq14XsVmN3hMFt>+cZa1E} z*9LxH4*d)ieJ)${eK81ge;DR|tM4a)-(#Vlfuhf4TYcj3wNUX8=3Q;<9pR%X7N^eh#mP2DgBcx!_o%RS?yV#jW@MtO(ew9l zoT9P5?`n3Ay2-N5Uw{9oI{=QpAAitoT2q5J$fKVG4zhXlx8XYaMdKZa@mtEHUrQ1D z4aMF|75g5<#@N&G0Ja2N)tusu;Xbl8f%;!iJ@1MfbEbL*eq&HzV=ff-m?{Bba`}nz zm<<{%%-P8Zcl7o2yhS|&oeApX-Z0IWuL=ltKFwgyYA~m4_#NPwUj!cBSaav!4yel; z#~R|C1$X|D(a+-9#Qn$GJO79WOke|g1}Ng?8}a%71&8mC`v%AaYWbz(x$s@<`7($V zU&O8n;^a)E0>5kwIren_F>D!@J+~xePs*4H$1&7yJ?GIaVJv5Xqs4L-Itnc3%x<9; zbqlq)Td1>~P$q*vK-|aj5BGHXPA2u6UWMD{VcgdNEjLMMxgJ|dhW!chf3}@1GY6__ zXy8cW{*Ev1TxhDmHk;Xt>*ZU8%r9a@up3^w&7>b0=)HgXbFg~fUphr|5e=FD9VpY? zGTp;cs>(GoZObEIyinrQV`xB4H7YI+VO zr~XGOzv2+(qUEDh%TL`}PU_Zls9R}oaw@NS)vfu^@LGNo($cH`s$ca?6*=|S9~SPd z{8hikuTSpzV0r8{Ga?NKEJ$RoK#o*ZZUVy?5;KI=i~|cI{}pX-`WBUh@mN zUAjrOD<`xa$+s+bLg#K+@0PpzJlrSzuBByDE4bUI;OB8ciB)pc$fL7IXOGFw+Mn*@ z-*Q*(!?{e6`@_c`E|0`A5mI>QFJ%hbPj9biPqc4rzp4F>_J`V2H<(|=7Bh|ry!8Cz zKY#qb!ZH4FSI@fo?5kIq6kd0fzn^8YqSgNJvDbMg(qTD;dzOvl_d=VxE*$CaZSVS| zah(_O_j;YfpBnL${kdTK6T!z97Ipp6=M|f8w1wAgUemUtjd^0;BKRrdKjKPGVy|;> zdkbo46KZUew+;1W(I$hAT-R>sdKkKPdz+!bwgc*V*gH~P7kub-UMCyh%;~#b70A2S zS?q6{^tnl^yBc4+?pLi{_xK$?Yvz;wCH_{w+0WVWTF$;4KX*uO;hxt=?#uG~3_+Xl zPiaBVC_DPPPE;+4D|H`0Ce_ds=!8e@)kcJ$pj=y_K(R_*L)HEVHeMV@p>`N$mZu z|Ck@?D(x!kDmRA{QpA9bI>Itwi~oHn?%u39V>_+c(|1>0dWJwMm}q z{WtBoW6wi-o<`3xvH$e35BtpdahqmsI(yTqO>6;E-HGf6{%c(qqm*r{VLpEK zRQhw>(pGO;X+3hbw|%?U)xOQ^E|V}a3CMJzAM5VlVEh~4&l<%~o|}I!w!NBm(Bq-j zJ6dmQ-PoFFt!O>HwGanC@WV7*$LZ}J)_L%gWg{TZD@b!ck>;L;d8wL|GZ8gCaC>0+ zUR1eCovTqD82UPzxk71-A8eE;$IJHY4`wSP+gsM*FYoX}cdEbgd;Ur740BtN%2;~H z{5r``fldzeUCv8U7H~Dfo`1>vZ^aE`y|}}#=382M-!~UEsLRllf(lAfMgDms;Aw5VFu=Trw;--8RmYp6m9?=I@j9Hq;p#_yg0B`H z*EWK4`6qk#z?mdJ7vbc`4U>trYinZ_Rf%RSctt`!UO_5&(VBN!Dz7fubg8#gdBqhe z;iDlx2;Y>-GvTjMUP)^BTS9&i{>!O66P|f5g|(#+b}aMg0mHtChJ6r?+xJ+`;s5Qa zoUk~^k4cZ<6k}oVs#meHlyy*ZNge9KDSJ~fQg6h(1-L1=GC8;`*{RNk##mETv^Ls^ z!&gmS#meFmw;j|t2dKE1Sz$6_nRH9Of^s&W)}C-e#2nmoeNBl6N3hKKDor11&#E=o z_PK|x!b4d>NJh%TThmeL;ps4P^+G@AzCQ{U&wyZXm9n`-*(AEeT##%Ur<-A~y1CID zW3`D-Yg#5jDQQW&e$XVM{LFLA6EZKh7Dw1jY{g-0M0$I+;UfDe`wEtjDFG*dDYZ3? zvCEoc^;K7>s+1Zx_b@v-GC?X<&ajOD9o8YQW&W7o26t~V&cQP$AuhLKU92jZXskHd z{m9s9)9$a*r{vc42pU~F(-c9-OzU1;j~-Omno3iV)(k=wPAf`hS`|E$SWvNY$tl{} z@f~(UV`6PxtggU*nr-f@w%=i|X^htCch{DKbC4+?W;Zlf)D}GGhdRSNAaxislf>)rg3E0)Q3;I@r zM}62Z3(|KZu&Zwq^ywG}uRz~+2}2&u`_LCbKI!vjX;egT}WPyJlE_j{0Y)2m^I0Ho{d zDc;FF$f*uD-cx&!>nYw9J;?PGFVCN(r?01Y&9`qzh+ED*$+d$?zQ(l%_0f}@xet*U z6H@~@ZbzumJl%=Fis^SJ9_ZDeQ(?!#(vR)_afuhum?xlbp(Yj_O~WH;`gk~{1xl!o z`y{IGdujUqG91sSDsl9ED@|X^9Gf2Mi#YmTNz=!BxM#v&jjH}hn!f9ykLO9KZz8Ow z&)o5-fk9_OANvC}s_!>x`ksM4_7T)K30C#}1#%3dI%=VBgH|H=^rJX)y417Q^%Q){~da$o8{BboT(y@`S!85xIzT1o1<`O zj{Gd>&@eDira4s{vbuk#ZgzJAflPDSEpQ_IQK18<`*-YISr1KSxL0bJndbI<*Ppc! znoPU9889-vNPr14?apGr%QP)LaKeAG`CvskY=>8=1C;I?#61s`XInWQ(Qqu~Syt{{ ztD*ek;&=j--_d_d+-&DVP#!-PH=l_iIHmTcxLJQgaPs;+adRvjiV+T5Qh}j<-jA(@ zZvC#n>Kp2D&sq)rb)VYmA7*}Mp8i&TgtuPgt^Y`GTUz+mH1}<3ZuZ}57$5sp8k^rC z-gi^n=sZ{81+#z~k00j>fz-J%TqVUiRZe{|Jop_0-QPl-SC5nEr|RTn5KRVm_A(1atiTgy40+7YjZgI41Z-P_Dc(>^b0HE|}vvb&>xh=rw|8 zfZr;3AMl-m`{6buh@L&K%M0O!Qtn^Px<^7hnVsahtJP?m4BMU zU*z!3xna>??eH5M`A<9i8yx;FhyP`V|ER<7bof7T`2X$j-*EWv3g+F`e-wNl^8IJx zfdDW*%8qy*@Bm_@pJiz7mW}|xOb~t@@MOUW(Bp~a{7Zpg_POSsY3O0SEFeE(=Mv_g zY0-b4@Xv(2xn~-BvVboZJsd^q1hdb&OfaT8-a2CFVLfgZ%=&5^~y;EeEmuHD1w*9^+{Mn%Vtt0Yp^l-Lb`1d0{Zwddq z;Qvnew*vn`_F~d#@vyQuq>aA4!>3KX7G0iz75#iksrZ+- z@I#LLR|T`I{+$>y%OUfO@b3ZtIl+$roBQ%1vj#G62>%7}-xB;5@b8Hup0@=ue-X^z zJjg`-G4GV`EBIyL5yTN&&trwpx`+t=3vh|Zd=Gl~tsM1?M%m65TncRN-G`oELS~uB z{~7oKN8a4WkFb1ajEfBGwn1b#7f1?b-E9_`sgSvqc#?fS?iI|j|NDZgfZr6%KHz=9 zgOLVYp=-h-E8bDW?6hI>h5u9F0%DmS&JjN6HfIy_L4zq5{zB-yh*+kJmBRlM;!O~b zvhqpcPlNm>VwpZ}6+Vy6br6rX^1Fo3zVJ)LGCjUu`1}ow$BAWH`J(XIPyY|`c&q1^ z!cW4vkC=lP%-gW+<7oaDR{K5Hv0{!@#Q1M+#3W{MjTC+ac)Z}_fmxT7DFQAKJR6wf z6Z!Li%ZR0KJXyq-!=B0us0yha}yk_ixOabsU;3ov%3~a_1$grP$mVC5Zn*S0!1Gq~t`;fN;vv1ie zm~p)?nEeJPvD9-up!ppG;ERFTM#*mkHe(Gi>nP z5m3rxNxzf_%x|LD4=@bBq2jYoclLPvfx)Bb^%czSQp1upl!0I-!w%&_4a_9iEa_LL z3P#iLrU_D5`9yU|rY9(LFxgB^Y%9ds# zY$ocC-4?#Z= z%&~)R%CkSugH`$Qz|_fcWFjnOICe}GKHvE`&r|+P;q#q{?|=+D2b6Bgu>a&cpz5y? z8OD2wgV#GU*9)KTb{uo5hhx+2!e`h!9sD4$>i?GTIj(*emSH(IJu8@F7ROnpll&hE zpX1Ie4(8aZI)}oK@}odU!cylUf{|SF{zVzEyszO8<7L=yQAXzQ-xbWT z&kAPP7X*WNFXNAfeVu&t&opleX4qc~X4rQGgLog{kA~%Y88OS5N%tq<4-C2hGiN5A zL@fNN#L{nF}IS;u}`JnBBId-vcr+(tQ1s@Oj2Oa!~VCwm4q=ypUm|>B z_Vd)qKF6%r37#u_mLdCd$`G?ZCuY9Pdl_&g!d3{M&+lb|`TRBu=DhM+!F*;vEBHsi zTz8{RKEHPf-Ve-oV2#)8g-X0!>mk1dRNuK+KED$F`@p{uJRIrd8W82@BMaQuBj&ti zuwb^e;esbap6fD{*#W-!jY{DAfw@LQ{%ydg3w{8Y>oVlCeO=&$c5}zXi-boHFkNKPvcT;3ouk0dp-zWqu&|FW|Eu zC!g`Moe?u$uFDWl1AbfZJYcTTkk2(7AN4^zAK0w90Z#@#TKEh*)sdMdm~+4Bf*J40 zf*Ef%(sU%>%tt6c6n|i*!ZJN-bnODw7p!Bj-(ep`(;rs*EA}Zpi z`~+x(SmK%_nC-tV8m~W+Z||oU$*1>+@$LO?=)VSWmBKQ&M`1MR>D&A8bNkHjb9+oY zGY8J=*srhMJa4<<4G z`m9a%5E#EUEWzIlpXKjm*e|;??3djc_RDU)3Un?6*xR9eGpCV=!Kb`^=N5Sx(-U9} z>^ryE%P1ur)OT))mvIu|;J$OGdl@qbhxDCW>SdfvIJEEFle~^bGS%f3ZZOj?w?(BcMD?CkulMfv)D90f>9G9~{!sLGTXgfUQ75lC1`Z#d+O!fOS zNb;4T*YCpk<%L?W(>zPPeb2zhjngLEirxT9!ZP6?_SIb)m~r!uJfVTRClDTlHRoUJ z<&Z2Lp;yYe)FU}n9F(ixiWq1z=X6c#O*BD#fdDz~iQUxmzb5#h51{^4exk;t(mfT~ z{V?U<;qWAvM)*LR-T>70UtyJ+haJv*SYiwZ#`GpP1-|S@4kgFlLv>Rj^;HsxQNPpS zR!py(VcAO6s2}H-rZW?d>O6awKDPnb;n9y{N;#~C0rWP&G2LM(Grz|vo=|{^j+D7T| z8#um0AV%XQMUe$&5gPZMV2%W5I4t8G49hxn^}Pkg72v5+ed<=~^8deZhD`HKdgN!s zhMD&O)xmNo8=6ibn9(HEpJBDG1|Y*15{iPt(k}6jQItPz5p5cELH(WR3Geaj4%Vm~qPCzfb%Y5C46_+=69Z6mScczCN&d^hy2sf$Y?4vHGUmp5=z)?-T@YD9-N`1ea_f zkzYX-+8RI7mys;LF52MvY`5NY{t<)MiZ258Sr0$un}PNtI!!A>{hdnv$4Vq5i0CDd zK9|EU;Im0WcsBnAOkfCem8VY){0M0J)H)7*l@bLetR|nrP*8?&HYdjhJ|fN)x%5)t zjf+oa{zk3pbR-V?vc=0KmLB4I30^I6s=vfP+CSc}+kVydo3`(|;gX|2oqK)m7ji2{ zH|1@~+nJ}ACcHlCe{-^ON95k;-{SKn?)U+xj$1PBqH+J`KkFa-1NNoz346}YhOU`~ zk*>-UnojtEpR-ecN#WD}^?r23WqmgFY3t+fk8~B8PxHM_#-g!3;Qs)h>EGsm#biU~89Xy);^2K{ihac}St<`eR@9;0^@GtD} zKN)gO028LN!>{V_5{=d7SZ?6p`aeEvtWMOKV^adzms_|z z7OOTXVk4H3)42JE4+4$lhcA_sr7^=2sN2Ae$H(}CGwDTP(k@B;Tp6D!3mOv&Mt^rn)G?{+*V9+~gJ{W9yUn@YX5ZZY-qQ{U|vo z`<}VAsqECMJ@~@Y|BJ79?Ry6MA2U$_Elq36^rOj#CD!-t-sC>cTGSnkNQ}mtz83X= z;Ln~wjl%S`s3pU&_lf6t0tEZOX2EidDu>lDfM!2wp~FykHvAYy%~R<0xqm}_2V0Bc z-nVum46FK90lWI%8fn*Ds1M5)LHe2`jMfLg9oFs$UV*-?X>u1sj^nf%jrR^Ph*e)L zM^)oecXf5ZjpgC-rc~iz9Q)3yCLHyU=z3yOouZF%>P^J$}C#a7<0&5xoy;?M; zMNWmN-+l>08JfM&ccHXDP8b+3+aKQ(Gz^^Hqi9T@BoL#1e4W#@(reLZ8=mQd>OkN4 zG=2OoeGvnQQGG|J>01GPDQnl_?Tdmfm?p3s{MO&A;)vB#g`&Vn-P+PUt@;%SY zIrq-JZ-QvsUw_~K`zE>XJagvEnKS#`x%bX+s;&B&=iU;Q*3pnR-f^qEAu)M3K;8}D zqdcx%sJ!vuW0+E0G}|E0-YZ!*{dmRK1}{gWm_ZLQ3TZpp?{!CInGZq=bf{qB1u1Q9 zusPTBeh0c5m8WjCUHaEq8^jW6LipUbt! zQ`8eS{a41^>^Esxhxk3`7UQygXD-rzmAEGx|Bhy@Tu4UV?c!jc$L}>C6gT6_MJ;|( z+_XrO1*`w;;-)*NaX#t`zv+uiaU2IGH{onjCzBzi9=_2jOp~43+3_T@Zi=FO7s)m2 zrodd&WL?*9Ir53!byM&#f4Kg{2dm82iGm-3eK@fUXh#WV880A~YPEr@og9{VCW#5c(Y0Hwx|xo4V?H=UswXpMFh@ zxc(0NX=231urCOH1$GOusTlT|8ZndkDd`BCi^iUbi+Bp`j>M3|dfH7e`xEx(q_fY> zCuYXOaD9oG^|wrTt^z)o7&7@zDc@URSjsW)EddV&=KChP&OJvk>-l`)XGe4*G30E3 z&5f@q=PK}=CiLfFpDFZzfNtJl0?)I+n}iPNZ6oeRgzxJFGh40_p8J7sBt~5Ak-2R5 zx;8wYSn3ALm3S2F2EnAQ5X?GrHZdn1FyFqk`F);I*Jj{PCcxqm;ekeXba0Ynz zzB1{|!y|CzvNFRQhby<2fo7dP0sT{Ol9U9do^*(QN-!+bei-j~;FobJZV_AooBfXF?LQrC>I^Fe%zmsVz|4<> z9Bld!&^Zt1+>SiNrVjz8+U$?CjHU}_`Lj>aGCEFhA?QmS+$eY==^2JS1Nzkt zzD{r{=yyB#e!*-P>}ymG-%Tg(2l_jLi-A9I_}PzW-RLBk`XAunUV@q4QU{j{Mpl@7 z`O5F)F(6D4F3l^ZP4zeR&8@eHkH*wn!P#)L+-Y)f5pRY~(OT|oX4qZ=zE%wSy9jrnZ!6x~c40jAiBM!ebc6`sWnD;r%lB1QA%=jyzGh}R(w z#z)N#^Co%4(A4kSsauC6PPCcjADz_&H8kPA$EWZ2A(igQI(nQ-R>Dtq>d=92{jnaj z>li#>8`XX&X71VHv$(N2$TTE__I&<F9H%$UrqKEAq(c#GU2X(VCc8~BgzJ2%g zryIHZu_p9jE>Ju==VE`VoGr9JpGMj=9uPjK#64X2loD^Gkv}{{=pYS~K>qg%L($ng z3`b`we0h@2e8-8F*T+5dhp8*D$Nm($bk1oc9sTq;p8k4PQc;2l1DQ@}CMg+M7fQ!{C5nSL+PL zWH2&wQT+S-(d3^ip(J1!);a@|Y9-8RouMpX;Ct<@L@_jAxTtl8VFANktuvTTlV#}h z^9YH;C?@$ZoD%-T#C=8vTTNVs(PS_ZxM4&q62_3hWYobSgPT$2dH*qB@{ensfg_7& z7{1*)!?=KfA1SqxQLHyshX+FjQ*|YohXxG)C(2;I;1jO#0aq4A+g9S45HRqKc84J% zW@5l~WXR=eGbvzbiZVpROb)nsR*w^zR`MwU!@W_4h?v93#S-0C__Yv!^yP@mp?z`a;w>lfPs5DNMgwl5pzVqb#=g{ zxxssX8^r@@en$mt-;1B92JJ67s$fF4mhIMH^{+C=#L4w zRIgd|GhNZQ0>4OCG@A^oaQUl429`mjAm)HzxvmenDAvm2>Hzw^0PqI&8KGLIUw|O^J%5=oDq7a<AQKqSzNxM;SX5v_Qc49s6$?E2>hjV|j68HyHqaR_m@$m_uDVR=dXgyhX z{5zxEOFVx%lW)1F8}6R0hW;yQjFahW84dJ$vPS#axaD!;U*P$N9uqJgY9+El`DIZ? zL|x51u@b8-BL}18VaiD0d!0Cc%3~W>gID6d4KK4eWl~L#Ufg-w&o}jn?mRYlH3;!Q zT8Q5C^^4fhX~b!oJl%P0>S`e1gERp)%Hd&@>^{^W#E_hHB|X2GWSSHXXDnsz8`Fu+ zB(Gys!V~EdkZ;$qw$WIXuVZDP$zQN+q37SgK#2`L#s5$_`&3FQ$>-m6Ggu1F0I8sf zKXvphjIi7t_xAd-SpSHC{rJ-xA8fYEV_%{M2~J^cK2|DF_jpyps(ZXCYKAI0-%$#| zD-e9Z#X=i!m4Y8BR}m|v8t|_o|DToZBL$x;R~|bjPw2K>>?jTY*O zYrs%Y&Ywa2>4TqGp`H}?_VU=vsX-*KAy71uUMRus(GuLQS>)xhqg8|8}JV-K;uBSgiC_fpoXF_-7X^r{I(M zQ)8ubh*AUTPozsnXWAULZVq~C!2i#5{wB{~Lb5ToL35l@gFq9zw3b1eqg8OTCc(?& zP^SjLuWU8=Im&NyAaEACHPl~Ukily459Yv!HU~Hkt6_@Lr6UJcayX%}(#?6mbVl39 z8R=Dvb38SW{ufLKqjkdyypN**jX006E^i=h|Cj1(oxjnVILP=uPTw5&CBtZ&*l{r; zjcYboBJgg5Cws|9G)i+2yYaQLy`UKz&B@=V<)l}{VNeYcdtfe_a<0$@@Dyp90ezLL zm~#g;;E!eu+uY@vaGNdmcw>YpbYt?bEa-}u3bOgL+swDU_i#Is@Q%hLBldFmgocLt zx@vReNRz%LUR>4CP%>%hlIGea%}phZ!B3* zx1^-FxTL;rLCK=(YC|#yu#g!1ld*0|b^S7I6+9$!2B93h*PPR0GMrc1#b<)p zDmxy#y2IG-kq~;;WpWd?D7A@MCwBZD``lO%6`EWd1U)|%G>or7d^8`@({S9Ea?JWt zj;b~|G&Z%9b(+{Au@I`C+F=TgiE*l|kmJZN6)uSv5Nw7X zEp|HZ6XFxp+kfJ%0vkx9)DvE{)hesnnjz}eNIHugJwaCK$@hXNZV(n_)x&GUyj(6E z8i@)CIc^n>LMRR|Z@=2yQlRse-Z&=pl`R|mzxdvc{EJ@j-`({2CV%4xt6PTb z^!M4ec=f^p|KnFSJ!uYD48Iq#VNUnoMyTKUCvW<;9}k&-aq8kQ;2RH9W76_csrgqoZjlLtAFJ`V7@_FT=IzjDKyHz=o5eK z>TRoc_V|4}?*rA0@?Y8bB;wfH?{==dxbvN#ZvEqfogaAo!8{yjdb&Sh-*04AWuAg> zXvV)@(K5fKp@rYl@Y@z|2aiFW<4-I;x^Q9PsfB(^mzJE)2ldYGxc@=F^6&Jo@i!YC zKlSIY$=cP#!S8hXqSsqFpXD8b z<58>fPRV=D|AlW4#;x~v_WXUex8raAdmVQlG=BBrrQXNmkN0*=Kkn%MQ@^O#R$H>H z3$X@UwKiOvc3DV=w&~D-!h~-Ec==gmXH0eM@#4uD`m@!xzA;X3$G}o*a_Vkx$C0l^OQFj)Z`%i3TeiNM zw=2&-sOv#b_|#;eDIvEWgthc^{}SKp|H8^K(?2{$VSZ$9v)s(Nok1=|Yx)Lgb&~&H;qJn_{Ob%)$QjmSw{0-QBgKCx z{IW2u$Ng2P(O6GHyzdqM?(>$d{~Wycx;}#Z{6pcdK7VTKyMw>jW4J5Q4s8x=$L8W+ z`}dmqt%v907Ukn7{CKVC@sBRsdVJPpoBi&s^7S7TdOP^tnsLAOjX$v@F7yd5i-%I%)JmItT+cLELl)%G$N%MBNvMGU7O8iaXU7zpR z`tsl>&?o!=HPcGeaFn6(U$PbP1pTU(`hy#JaILnx*2~RIFU=3uS=v0$miN^3SHoLK z*NuC*h zh?dd3{A#>5olyxIs~_%{<3RPz@$C1k_N!8*svWOsS>B0T{FA~O6?bd6wzRk998JH5 z$?~EflE&R3Uo^KvdQ@)f-<8J8It(4HgI_gv=X2M16nm$LZ?-{Jb&MTv7kjHyynU(A zwo0Y-Z)saAtJagE^5gn_Rd*<7?@BnH(P8+1TUq{FOC{QihuTI{8}E&kul3SX-*{e! z^u3cFKjppkUa9RK_3Pz$TWO87rf4U=cZ&JuC34LKV}JeD)KmzsTdDwa{*ZLj{ty8rwI0LR9`DD^ClvrM|7vIS)ui8nskL1sUykPzGw{sAETE4Wb82HVtjKt@TF;WsYZ!r=d9L7j|7#Jh*37$(jtbS=# zv&ScIF4g1HDVKm0(fkINEjPS|A*NJpeL{%{jN$Dh4R0f9c>74h+eRARF4ELn%Y0Hn z$lF4iVr!Z0_y~FXN5k7b8om9B+q|u#;q4p^Z{uiq`$nVu*7bkKZ{@K^jj)fSMlY&u zp15q`!rI0u*utZ7dGmt$%7*5~%I4D=a4O@mN6iqvk#$RIYFEr$IHj69eFWsuP0JSG zH5okDLhz*xwT)HHOB?gYc_5ukzTu`)jBH>dtY0!^mWm7gh8w>rHFaKNEqBAKK`RV| z;$d1f5~Z zh^432HcqN)s-3djk=k$s)QdC6MMV-ns&+|@(Jd`tm|NbNHlMKvNpocb62ll{xpHEi zt6>n9+L-vH2+DA{=%mF}jT0Iht4^CzVGF{Fl1yA|1jVEyjrFxl7TFxs{I5O5>a4rw z21*S#J?fN-8P!2?jzw`UHRTxUE)mw(!D~AD*D$;-&N`!s)*US`rf7Cqq&&)5Q*1e? zZi|}J^3$zmZkCM3u8Af~nx~vtZ95=mQ(<=eP)y}UGS<;pQ@l7*xFc#$SyolwWK{`v z5N=+2bOUNRE00&rvcM+BVQq6`TU2XV-YXxN%|ai|o;?UCbd)F$ensvAm5!h%sm= zp;A&EBuj0nn{FkRM07=!%h3lGSD2}T77|*p=>ff<$MmFWf0g~JjZAy+a9A_zrLHWo zlMq&{ApPGuo?C<3N^Vn!u{9`xpl5ZPzBEoLDy{xYB$D*7XvLbZgT{GM5dt=mW;-dV zp~Fq9k2YI&PeJ2=mu)|xsv;*G0!*Wd6dvMKZR=KGK&e@}Y(af(pxhzjOm`otL()vA zFIs}V2u+`EI`ObxdUlE!B&V#*_}NA<a`)pe5APzkTH zx~ie7x~}=OF#SPM*}hTZ99_NiWQ+^7bCw2;UNYHafuqO>+cuH4K@dt8?h&@hS|JPA zKQ%9|YYOsiTq}y8KMArW&rf!X;UZ!}>0M=?q z>mAm@)|k@jNNY?|pOJ}s@I|ZHgD)EG9(>U(_uz|KvWcg13>Z zz`u=z1^(=s_Nd>U%O{Z2MivGBZDdm5-$pjY$F(VA}%L*U=Il>0wpSGPHH zZSNuBYHAlOTU438;s5{p_Fc0#diDlM?xDQ?aPlQryz*v@-fW2zFXLM?7?xsE$XDkG zRKG)Gd{=;nO9Euq$s4 z;T6ccH^z50`1A(d<@+fdZoEH1yoI1m z#)ajJAl_Gi-E{m7^7KX@UO~JsN*K~;o`t-%uqlsvX5eBz^P^x_-ax$WstX424&?17 zF9~AiEei9Q)kfu+eM;cge3=G$y70iDjEjcf9J}%wAdmV?#?>8{${Qck??lKegufb< z$4`}Ad1pBCxbUFzPKe370P^Zp7;KftkDFb2>mhF%{3qjL{Ze^n#N_=Q^7_GFjmqQa z(5}3v9Q_Uev&zFeGe!r^zZ42X7iK6^jG;Nc?-h zsDq~W0m##ZD_0&r|911Q)R9-{$Qv1x_hB399U7B2&5_6Yp!#voKv%zPyhGkv{_#9D zSHJm=ydp>5SuuIN+K{(0CU1o!k8jkgejEo}{mLPaV~861(OeRfx6zR|82&2n!I-=g zA#aqCV1HEJy)k(=IPzFuRo*Kxc~?W8E;Lf2%6l;;ZwKUYi-gJG;W(o5k{D1KM(fMH zsStx4$opqZ-p;zPzhZq=dHFGUJ0P#M^34Mu!>D-{^0a-hzN)+lA`j6U^Lz^5ObVu@ z=^Y!B_YUM0!hbR@mY>S|rpN=yn3j}h&JYx5pwpa~ye=oAAA%B;$MREoC&lE=?}Kk8 zIZ%pG{T9aLjY6lJjrD!X(>VtF|I=ggE*@g{2a3z%nW)r3&3JqY!|;^Hod;CEjWKyM zOYFW&8cy{)FDCB@$V3?d>e^t!=otS$|%+2`@4afgn)Ysd@ZPQn7&XJ`*$J~6>*QaCQ?XwcQ4qZ8W z)|9E0cq&slyP|TMf+Gx=G^xVa%_lchHr6gOcx7$l(!jB&!>xkFMQ1fHon{|>L{?NI z4;j+djh*F5T_Uxi)0XYR$n2^gmWwJYm%01TMi&j;1yPCCE_+9`Yh|h3F6lT%E~n*F{lZnYbd~v> zCR|OctgK#9RoSqtv9@w~U1Kwz-Ld|&eMI&H9)vjzCNZ3s_`pYDj)7ZW&zB)1pIC-V z_EqG03^w<+BIZ8u69kuHA~H?zk3m0D@IGj3#|l0M^eVyYpv+>yJbQ7e;Gcu%48fN} zpVfk=0-rB97d)2d=-VPq;;BPsY{jc(0EchhY zw+en6I@~3AEAoN&&E)TjG`=91`@?=Dcsum}Oz_`ev%e+(T+z z0%6w)egHgI3LXx9t`p1;upe^hzY^RZdHAM7e^>C^&^;S^FfPjJBzP0#6bn8Ayyb#- z0MB&jM+?q}Zp$3{>4JZYcrSA3mkH*X_V)`u0QSRze*`%%2)-Hm{88`&(DUzte+Zde zpry_)K_Be*XfWydf>(lfg5WDaXPqWL=ROM@`eMO9fc*7>mmur~g5L-KwSq?@t{(}W zj{M&txC%Uv2tEsPUKTtU_G^OAK-hl@Zh`y^gr`0?A|FzMXCQ1p!6RUg6`T+LiGm+R z{v0p388WK{-vJ%gIP~ubu7S)S3Lb~}ZxIZ3Z8E9=S75lQt(NT`G!M(NAPpd zGl@2@{QC$V2mihfeURW^A)lu@^dkj-1NziC^reCe5bt>oeUso(;Qz5hzg;lf-;)mg zIl*T$p9S9yoj(!05cE#CQKkN*cNbiQv=4IVWrCT$BOUr|!K{Nz9r`lCCm|m;IrNJK zb4~YlhklP>?k4w~Lw`x|$B^@hL;pf>2k`HYiKFV@TQK)BK2&fIq_ILUw}3lQ@c)6# zZwqb#-tN$Ebm$K`^k*IV+YbE;hu*D&)ra!?3BCvAGS;D25O;!NFmnW#0?&7N>WKRr z7LVsH6LZdgHgRW5KSwb8lg-3~u*QIRFC_;5e9*5HdLGjLBcX2x{T89$1NuEee+u-U z6LaDZ^DDu0J|p~;|FZCNz3(rAQ^0>E=7a_2Gr_!%%ghON>qN}7fd4?j^MQ*5ZwDSp zEVuRt3+DaaRN_H4jTOTG6VQ(r%<+7I@U%eBdZ8bM_HwS^df<)3kUtr^Z54bR@a=+M z1HMb}=fH0ecLRWVTW~MnzY&W*yNQvm??QeK=4HeW17k~K!$W-z6#Cyl?@Qd>i1Y>s z?gQs&;pv4sGg0se;2DD1-yThj=YKTc6kG^gCp?#dr%~`7z^4o57`u*`H(xN{5nK+Q6GJBNd4DB%BJk_PY=AIt3hoE|2{H1=L;K|t z4{=Z6eFTpO?nc}b{xCfR7XkMd9*&u%f>!~L7R-6+B;x%|P;aW>VmN0LOB#)RgnV+8sKieG-exl4Hz~51DGjJ|3;-$zwz9staA z!R5e56N~;Q5F@S^A?GB)+&Z~Ico^48q0a?gLkyXW>s-Mp;A@C^;{tQNVCL2B#1hy2 z#E9!m$az%ob->RMQ(>6j31-;Wi6!hi!v6sHKNHNcIva}kcy>XPBbZ@(5=+>8;{KQu zfxlRAKa6q1gokMyC-ljnPbE%42+Rz@BY=+)ewNXE;Xe-iCktK++$cPhd4|w$0(~8E zifbcikAm3`{D3$g0Op5++5i8PSoD8@xIdmfL(Z=Se-8YV@G!0yg?<3W%-4w_lX1N% zxDc4w<&BlO2WKUC;^mN8xE zJZt_ap*JC}c|y;_SbDtBw?UuNh@l(X!nXxa2Hq}s9`I#?8-agJ3_UsK-!AmKLBC5d z`}6yWkuIK3@QCnNga1k4c?vww2z~?j1L6Vzn2!acS$G-9NXB&@!gdsV4e)+~Id@1A zGm~Ko1+yLwCYHP%F8sd-|3txD3z#ZA%+GHKy*KE`5<@0+I6*LidJB+`KGH-}PmI2U zrdcqZ=6O0m3V5y1`vGqdTnc;nKLCo9}Il6(8+(NV9rB!5TkC<>=aCu zxS=@d)PdtPG1*=tMxN4e?UR^s@p&{cyV<`BW*?P+Fw!RioAW4u=K!1gbmRq19(jPd zx?L!kb*4n{TwwFu89c`UA1d_k0#6luIq*!ucLET%iAiL!`x+p+1*`7%uIl}Suo4@PQm2oy(oG50PiH0`M^_x$^U|2=Al_D z01vAo@3(ah@S$L4-QNXMegbulJVn6m1s4P73LXk<))v4s5x7w3vw#N+J{GuK@Cm?U z1#`Y}7_rO^juMP1ls8u}h7!9L0Up-R#iUa)mijKYDh5+6m|;&6 z%&^>MojeR{)>42Ob{*+5ww^DTVYdlp*zXHw*dGXH*jtEG05Eq6X5D*8a3A1D1+$EP zD|iI(OT_sAFs}<{*mngN0{>O;K;SO~j{Mo@KC|5 zw_^l10#6itCh*~c&jFq#cq{O+g0};kH6JAKYTy%vem8KV;GMuL1wRG6PVgJR=L=>( zvrVvvzUBLZIbL5+TmS}`TO53sU}T5)pkS8Qqr`>eMm`HB{UyOH$JYh39RDJi<;b>| zlyQV262SO3bBm;m5o}ipV0L9aap`$kEZ1CSILvrlJX4EJZz3@YbS~@)T)B)0W)7|- z=_&T^5wg&bSxX91EdQs>tu>XjQ^w(g2h)d-&9~qW;&h+zaF6zrG z7jzn?Ay@ivs^wxFp=0`!exN6TPk=ob7wPN+ONBlQ_93`5Uiztg6Bh-;FfWvc(JN*? zE2f^R1Ir>;`Z^O<^h`N)b}`D|$DtcJEL<2@j-jJmTBVDgE`KjDs%}P4(I@55nLny0 z+h^_+{J=1O5>V<0*yC}joVmbB(3ikwx#k{*AD9MQ`yP&UUBsx^jm;idfP<*`YHlb#BHssB)O^oL|wfT$H|;Sn6K0LtjBm1!30W zQvUVCGH==H(6`4cYX ze~Vbg@sAz)r^IYPFy?(;$!D&A>G<27So5El4Faanp%)R$xXF2;@{b};ff;79L!U;R zZ|QR!`aEK(Gc^uIQV11lw;~Z7XTQZSHX6~d`Jl<-P8f0o3fUEbu4*g z>@#I8_z0nMyqGVTa!gqZPlFTIlr`u_foGM_iPs9A1H4^uPvFZ09|p|zQ*Fz42%Zf3 z4hR22@KD$<2nLJyvS5}opYKu*vAK5xo(r6juyo>V!R&+0vsCa9_Y(SJz~;c|=*$j@izjEnqS^VN9GeU`}QSVTJc&3%^ebNyHQO!M3p z6_Pw$3s(9V!K{AfehNIqhYOwY9_Qfsf>WS#9a-g=dnkm(zqeNC#Onn!UUT0hef5>3 z1G5X|`m*-ncME3y=ZR9J6aQQ=io<)-!OsY0SIGmW$WQ!d!71RsI`}ieeLy$Qi$$ND z3>%jD-_yZ)f~hChvUN-`&ym5*bd47}@npdZfVtkS{Kq*wd@f5m`5Off1zzjm^@7KM zeu;xG7knb$Xoe#=90d%gd>sXl~ znDv3{>`KoQ%(5c7^( z>jhK)OB{T;;8M`J?yqw06wJIbhjd|XL;Q%)sSnrpb#BAcW{6Xu^EfZX?+G3VI-db3 zf0kh84^M9)ow%!DR)d2a%=a_MQw;hr2agm?{UjDRF7EGP_yg~W-{s%Gn`CLKgat{k8{Rsy@Etqon>_PeY?h!Hh`HVs5 zehCaX#H4p}aIRp=;d2P(AL#J#IfT-uIdnd6@KXo~GhZ&8|GZx>t+I-gbeDFB$C2xk4c-@!WsGhRNE@bk%yzDqFslRr85Ey1i0d~Tuqe0iRj z<=f7|9R!a6ozF9rzn9lA1jzi8&52A z#mRyh&op8wiz5Wr!>%Bfbq4A|+z<9VVkQFSI9$ZkaXzukJ!%BAZ&^$%WkB5C8E;A1sFZ8UhLw&OHfls^ z`LI-Kcxf5DM(`(9R$4luyd3t(QNu=<0AGI2`TBgUlOqo16H8+lYRA_+<(#L9+oQm< zB1eI{hlJxXf<5dz+a73+SK@dYdQaT7wYP!Fb9i)k2R$-9$DUc3FY0 z59scq2XuGU1G;nLXPkG-g9i4v_3o||p1;0tr~=!^eql0fx_X3!;GlJ!WqxQ*GMlLg zX!}R_rgw95;DEp{6a22vfvx&rC<^F|K|^3_INY2G-%F2k?;Y}`%=z-E@Mv`NQf;ym zwd4WpeZq6larzTa9;c5DRmc<6Z6Wmy&uQ;hi~=anu`K=Nko8Q;D&jH5=HPRTx}gf; zaqWY`$aqIEIC{AHka9UP9S5MhN2!Ab&q2{9RLhIE=;;yqB{*FJYPzCqbT< zVQ}onFnpbJ+fBga8Kscd>Jjd8;5$@B=kXMN?AKeF0}Ub3CBc^N--Dla^!2l!$8UCD z{CN9hq%MTTSNY-LTYt1e6Qo1pWl(dDzz<$M!{pa5IRK1i=<-Vm69wWb8wvkp!74kh z`9rPqY~SmA3_J#cwF`gF!b`;M%+S;=BSo!-CGoxte;~<@K^c9RdpKe~*&Y5~MgdR9 zP84K_v(P%T#M#$6v&GrZI@^o0zjfw_vxq546m$~j0PE~5&Vkn1MVy1Iv#U4k8fcY(8}MINOBdR-a35;=z<;Q-@Z6C^5U0AFqcM^{^3mQYfyDgq}Y3 zUGw}u8_zX?r+lI3e?U5OA7>pWhd_{jeHzbS9iB|X^XoL8e>yxFhUfi|heZ#`Qfm@j zvJ68P6r)YJcc5k9sAn|s41?qflZ+=e{7GaT$XdXB>PEm?pc!0Aaed(9drCSrAY~W9 zL(-gO#&}ILE0cd|z^FWCyceDf!^5REk-xvuGs}$q!joxuUJrTlEKds2GHI5_cD z$Q*?Hp2Pg689Ypw>F|#oz;{0ejK|NAIe|wpKZH>OA&W7LlrTb?QbwO;w-PUR8H5NNnm<${a~->g>hUc>lknMj87! zHOP%au}Z_4xM!*u!7%>#51Sqf$V@Z+Uz|WHjCKB!!Hh}TTca}eb!s5CE={ag#vV@% zST?l6!VXUjSZ-;Bh5elxuyDmGs{e5H9f6vX;cHdFY=qsQ8U*c#kv|&LD`Q8f1}tOK zSVlr&|<}a|6cHq#>^@(eqVn87nBE-<7c#66Y29Wv=+oLhOt15>7X-> z;s+bjh*#-hDc%#Pm?P5aN1~GxF-fW6}vpnu5GNVsyE+V zBQM)JDm2C&KQR>Bj@DM4Y!4De$8Rf~ugCe-2u05qOyZfQ<~|4c4D|VU{VS37#!wn1Low0vsAc- zQ{n$E`wUSU@pIj&%@Z(tZ|=Og^PQbHcP%X0a_E+sTQ1yk#g_NC?A|hd(<5HXCcM>v ztL&mH{E|~k8_F(T1=mJgMLkBh^FL^*_+b3_HKkiHsl&B<)BBsQ*mU8hnVSyXRI;h_ z#?B9P-q?F%&utgtlsoray;pGJ=Hqw$@vhJPRV^D^HmzB;rfJQBHAkz(`2Ij^1b+&RBE=el#wJ?H#&tIoS%-Rko$TzB?)@zWe{*?1vNi~CQ@zh(1-v2!}@ z`Hg=l9ACQny?O0cwJgT90{QWW!e_Q_YWZRDt%KiM_u0BXr2G$l>9=2x(=$7NuXp>c ziH}#Uncs3+%lWTwZ1Hwc*BE{EN*AdifQltu9-=dDGdOTIPK){_GxG+W8-synpEX-j3Hgf7E-`>Y@^A=7xF2zxkL4 zXAapkc2idq1EsefwxsgVnT&JDma$vX)=%mUhUv>9K5!L($<*YbItEM z^Sj#oW^d!f<;zVDSa!qso_|(hPRhK$si77C&|l4bfIYcCjQP)rx%E(Sz#RKE^A0@>5$!5IM)& zI8e3n%_9Wka-jOAAJ+7LbK3s(Ly*FJ+q=X1eD8P-qW0crdFw|H#lyEHSLwcaCZsN7 z@2!X|FIpRh;U30Ls9SKG#dQcAic(vRQ%x$%MtNKth)&MOjETBE-uXvKX)L@ekFzYO zT~xQkI}A6PaUU+{@lH2RuUcMJS6{{b@p+RQ_id=HJ;~#(ZQKL54mBQcXyYCW>z6ex z_ISS<_pv+Z^S0C8zIcxVHm=YkBbeXyxNNq`5(V7sD{1DN-_T~CNW;F6hJ7Fn`#zd! z)-umE3E9WdxP6HM( zNoCcNn#!75oR71t+PF)-1y##xDsi4eGfxCD2OzX^3c|7ljg9r5{f(9dH*P8`kJ5&l zg2Sl*(E~j~;XL=EsczAd+L{#4H{huixP7#-n=>(*nFgK&Q#OJ}>2N8}oE=aZrl+>D z!K-XsQC(Myg6D7K+y+~Do6tyVD@_!wB&rp~^#~4AS6fNh=%9)tbyUloNW}9FpnufU z7K1$u0iNX)i9idMF0GdXAezxyAOu;v*r~fg4Bl5c#3Nb&=59X750m~%u4^JiqH8%D z9n@J?-PBlReiwL)*$$UA)f!e-3x_`_QY$Py>r`N+m1wL5EFf)@;UOMr)x{Lnl#@ME z>aFCu=3OgZ!_XHY8MddWFsGyF0YW?iN+UO2jN5J6T(6vZ#LS5ku&>;7N72ekY|XY5 zr?{P_oy-5!Q4>zL9^Jt|o@0}SPN^s>a}roFck%3DmBIgFn%F4-X)?JILP+W@XUJ4#gpwy@zmy^R80><W`ILgDDC4oHiUJu-=A0L0thg*%xy9)$Y-cCmzpTX0Q`A6kk z{pLfS&b!2$miG@_uDlk=y8|@p$5+i%UjLZ9S>3|<8`y&U>jOSl-qx{pK1X@TqCno% zn7r#CPv?QIyv7*cPVl*P8s5g79E7}Pl@|qF}unu2A|u% zd8*f%bHGLY@^Ptt=G!H>RbG3% z$Jm-YK5=yAUF*mzaO82nUey6)FAwr|5QtG3+_OS4y*`CJe(Og4`r=akE{(~18S=Qd zq#BLuqL@5yJXW8jZ`7vQ^-9sT>UgRSzOjLF+D*)!h+Qr-|p-fJSSRAdyPvNy%@ zk21UBa>(ALz3~1s!m81DX**?-L7{sQbU+tj@+S1 znvvIaGgm^BG$Wtu=ExPAq#1c!H%lorNzd&e7(Y`VnxuI<)^)o*GWpq)h9-%gutJ>8 zuoI?dbp4r|p-Fo360nfc_pi?nnSqjCLCnn>6Pl!by(J(dJ+`#aBuz_k-K^=MNqQw- zZRj-bels0vSTEOzV*zaL7tfdaXx8HDiu8QXxIAw@Z0;Zbw7A(P=Hu^8anFa%{p3?p zIX*P*&K|$HRm1qEi+c`mE@G$_cOT>K=B*KTxp8+l`ym0Ev6%bCb6lli$>rkrIdQWd zW4C#4m$+FIx_T+^Q*py-(%;@`bJU05!m6Qrn7D2F3d~+bu77L|>|fs~y|w!oY@NNd zvU+L5X_Y)04y#CX*4I`wR^p~6vhEn(;IwjAzIXSh+$uZm2B4K{IN_&HeK(SRn=K$Pb zV|%lS{hYaa|Jdqgp6FYJ|qkB7ZlF!w$_NAQ7= zxk)g;VZT@~)AX>z^P1oR;D1l>-H`LS;A4ULk~npE40f^L)$lj>2cZ8LJadKqBy64& zL4Njc&4RB05Bn3+Ie*zK_#^OKCHQ*S=9_%*{0a02h0brZo)G+9*nbereazk!yc+y` zse$r|D+Keq_ql=}gxw^VdxozQ+yb8S1fK}}L%~ePEy@G?alylpSI-FMTydA+eL??J z@J8rh_6vhP%>Vu2N8Q-xntj25p9PQE|4VR{@Q{9*VCrV}9|zAy;O`5aI$R@oEaEhK zj)R9fn?1*Ye++ECEeEDvQGtb9*}_r7v>?$)O@!L`LBaNSLlmS z7J0;=cL2^8dWDC30ihoXda2MWfyW4)VJ8ZmZFdGS2XB~}g69C6J<3Ig8VS1+VV4jy z^I;kV_W?HFGYkK@!hbdRHxYL??A|uP<#1j_Ed1ts<`nkq1^*qS;~tIXZo%x2f8p>y zPMktsg5P}G4E|#9JTLr{f&U~t+)MC%VlFnod?c9jq20uyLw2^6`33mRcg{TwySE?d z!2RItLoEDe&-9dSv*U!$H^e6rQ#j0Ff}4ToI`m@&H-c`yc^3X=hkhS1;;M(tM~T@G zV4e^<`+=8;aX&_LCfxen<9cFgU+j;F8HHK10j8*{h0c8Yk>Ihww+WsIe6L`(yN3lY z0R9cJw7X{o<2KXow*q<};6DkS`Sy-rekSv=V8;8o;Gw`~9~OkgvZI%SGNAl1z}*E? zH?wah=)4~*6#7Kq!GaG1HhZ#whdQ&*rJVV|hY?F#Hftcj)Y*(XzX{t0lA;GMvwg8v9SO7Mrk6Nz&HV9cH`z);1TCG-^Vv4WXz3k1&sK2h)-V6zvD z^f_jn6?`svfO~=GLcx82zen610LJX0DflL#vwY3IFrb$L-!JrX;75q1|M{(he=nGM z{;FW|>s~P9fp-a={m*BDrvWE3AXECEP7dBrFui&SX8H1y8}>Og{A7Zd`F612Jm5)! z3xQ_{X1b0hrVyC<4mNWJ&^fm>`(^@@&Fq^AKsjrKpLuegVAiEAf|-^}1!=~P(GabxR@=u1%a!GWzV_zXK zztCe?*0Y3+xeT8KCO?YAOQNoV&BUDmrY_7|(z9XHX#OXF+e!Xs0cW6MV@NQ2ClJ%H zzGg|8QhqzZP|@(CnVGoAPkE*;0b>ei>k@DVFrqR181hY7lAm#o5IR@ZSiYoFPv!|R zZ!-@Q+#dE(f_XbROE7huCzv{(AQ(fBsRNY5d^l0)C^ECgOFGj*lgWaDp{|+8D;nyT zNd;l3Q|3qmP5xv`AIP{frN3g_naq3`#+S(o0Apm1ws?;+g~!MgY-9>HG6gdl{f3{a zbB;k%h)d~3#LNVka$HIuMNDBZlW{418Zk2mW)3c;GjDYqsd4Cwi6tMJ9r_AlDhRU{ zm&#dBEP1unp>HRayt>w*-#{#7afd^{o46-_#4znBN|VpTbAYK9aS?2aAf5-C_avGp zC4yOJ4|cG51}yWI*$)3Pf+5PQ7CaR8BEhVWrwfLKkAQ7ltheV0W_7wy@Lbr}2!`cd zFPL@YcEM~DcL_cgHt&&C|0e}!znnbo-luU2%VT8y^?1>Fz>sRpRXJeGk*>h%>0=onEAtdGv)u5VCK&v!OWkN1T%kl z|EBzAZ3Oa}KNkv}`NL~AR8%#(rHUals;v}H3l2Hp>J-VAnA>$Hvg7&M3xwOMn~HoiaUXsp?w_jNGW-AL~PI?Mil z>%Kft&GV5?8rC_*Ob`1X8usnP3t*#41#Ppt;Q6rGwP~Hq6HI!FSo-He!5_kA{nN4@ zESP0lN-Sl{@*rj&jv{7+Fl-OR^dC)T};C5JGw+S1?lQI(WU0fULe>qBoCR>E!@k4 z&hDYFZ0&IbYA*g^GSGk78caK45OIIb3%hU^a`m%rHS%&7fQhQab&8%P=zNb2+m zxs7~sLQ?MR**gbc`NH5F8y>EB4 zZDb!?pnghyps7!Mw)4N@Q|hG+%_S4;SIi}NdE9)&te-W!h^7wigNj$ZVuhjx0(d_2Tm(C4!OPVU>%W3O%Ohx0;MUCc@XVcX9 zG=^EG--C`e&u1_y#_W(|ocP4Q994J7c~~2qAqQ%OiC@FE9jks=9seX)L$oDf|5!Sd zA3E%hbhr6k>V}_Qc>0E)Wp7(w;D5Z~r>hotJ3#q1DVP0p%URn8T?RDxr=v=SH4Hv$ z=%BGb8}ieQE&Mu<*XoAiv(6rLJ~+;AscPx86?1Q~zbp3nE%SwLZKWfostrHGZw+Iz zV|82K&#}|XVcCh{T*h^y1CF@+#N3BSI9kqEKMqs|hZO%7=mPNA8pKC=>@!jKCe>Fp zHH{g=uWiaB6nw2Qv95V$V@++N$8IX*h0kO>xIc1fO|4nTj`&QfUs`?A z^tGQ$@YOfajJ}*sSdBOVvc`-LfXpHqW(`drYdNp?2;pm3HMPxE)r+SuX|8Q-T-JbZ zKaM?WlL!{nKWgw`37YaK0%53MARD9 z+*q}wX<=<6_+5GORzdW$7vtgpyWq6u+Sms&u`f29l$Q;UJ>Mgc5-vo0@%%s)?TcrxpqafS8QHP;Y;;^wF{Ols;pYDps{v&6ylGDN>&?%f#3&e4gip&v~?E@CsggxwZj zfB3Oe`7%B;wE~|S$}85$fEAkc9%X{P03Pg6)hHj=8p3W3`(I*~#aT1ob>R$`ejEcT zaA_Do?=~pPXJKm8Zw3giypM73wHTh1$BD4YGxtz%o2fT!?oFWenJ?uRv<7MZp@m>Z@T~%H-fOg&>2k|}-c_P0$NENj zs5*f>zCWX3DB^llrtt(~)NgW3-j$H2`HZ9o@{W(mdlT|TsW8|oZ(dB^TadRA{?w1t zJx#A!--Ejp7fo*z;%*fJHz6cOh`t_wCxvek?S* zb~Eooo&MeLG`lUF`Og{_nxx$!Gaw}GzL<`iIUSm$z0VB@>F+$V=7uI|R_k3iYffnR zj`NhzY07m@%v~*R_6>YTc)7Tl@44u~v~4k^xk%s5;?F*d?*u;~ZkACl()YT!X)$$w ziMc-&H_N0eIdtAwSvh;wl&O`Kcm;NLMddUF_;M7KNs}s!-F$LGWn=9kgICrzE)5)e ze5cl#<%O@I29tvL9Ar-usEA)H^A6WPm~7zI*4!=B)GexOuBtx<-@VqFn*el$(RV{p zeD9fj0UemnS=b-w`d~gWALhXn;UW*8BX9wSn9oW$?h>=DvVS6;3!a&RTVT%>%r*bx z1wReDMlhd8oFcd$n0113I3}GVcp&Io1YZsOJ;B$*W*s4aU)XmDJ_S7Y35Ml8B)C23 zI|UDi&HBW!tUE6Weh~I+f-eI9TY`TE{Fz|Zlyfm?`w3nOJb<_p0L&1< z*}w-AcQ$1EJO-F;V1|UPhJ7@#G{GujX})|%l9+9T>14bo0Iwrv#|-lw!E86%gy;9L zuONm@_P^#C3?qfPg>+!HtA~aE@35Z`yb1OU^xL{-&G%Au4ZW0D(m2Y&;{~(cO%u$t z&mxwz^JZ5u=XSZjr0G1J&6n5v#ZEcvk3!5aiq{#L;ZdpWV>$#o9CSulIhI|ZkJ z9}vuZ+es|>W1cw)enIGrt3@zXdP^{dR__DBDd0~97XfoHq|8!4JyUB0a2KJE1@0-B zWdZ2%98RW%@$r04W;OFDHy=MROoQU?4$dR)gC7` z=M|=}W55_@7)_%|FC&3T;nI3#(kuG2oFY22Kwyl{f>|yqlTi|rX5te0CZBp`Np!NKCBy4rc}(Dd1Uz5=F6VhV88wmd;83$CniSg5C_Yf z8suS?_%)x|M4!<__vhDVG--SDr#*COueXm7r+6`#VA5JRnq4cW*~0Ve1obooof89Wjw7Ghg!&4+Z)e2iyTG%f`eyXb#r$ zw*j=HkDtv7=Ivt{I4SUa$0M875S>zDF@D)(y~NK+O1_Gp9Bj7%H=&t4B%UsRYOC`q@_!mYnL=P zmCUMbTDq*U8V^?v#|AdxbD3srcY{r5mp7Iys9RD}TwH>uFeQtss|~5Vcv$gJ5`%v- z)-9>7Ush8~j_4LR;R77omj!*AJjP+*+S-Q3rQC=XS?501k>1Zd&A}RvZ9Bo!nuCRs zk+@Y*PqB5&)eJxRTRiKF2OJ*+OzsY(>E5Av;;GM63YFPUzWHrO7VAly4^Te)p0}g% zXH`G@^paIS&E7^=?|bPU|Fh0_e!BJVmwa|f=LgI-f;o`V)-w*y0qC#B)Le1IA4Mon zmS?vISGU^EQw$}=Sr3DU&0$V>dg8L#FAp@#W;{#dRP))J$9AQq3n?7fq@UBsg4(DLzC)ea7OYg0w$}VSf@xQoj9nG4#snbkiH=de{-9;!`Z7K<^f=)uk86Nx6vo%hdH=?yt41O3-#M36^8&_Zev`sEG?u81 zAN!dKTp9+@I|Yim-#@G04EVY7et{vK<1OW3X)=&k1{&LN7S&K zj!_3}x)+L@ZIJ8HXNsGB2luGhE^g*YSKiM=#@zql5^}2pXWOHt43u`=L$aB5gYSl> zjP4e{0c_TISy5o}aYfd6!O!=}d1u71H^CkwxEMC`ll0SI&lJpdFjw#d*k+9vJUf7E zgwEToI>8(dmJ4o%eTLvCU|%eFHtg>UE`UDw35I3gr-%G+0>3Nt1+aNLOWiud=JP#W zlVNybmNB2xk!LKhS*w&P#Xf@c^Fg0V3_9yTg@gsPH*XNae60~4_A|?g(cWoR3TD`I zh$XIz1ylZ2#E?G;*sMu{hyBrA5*Ei>pd z<_Xp18@@CKOI#cibnT0Ls(+zFFCrFxz<`H3k)QFpVY#kBI@8N?QXckyidhCKbE;sb zg=zaL@3MnEC<~*Hlndi#Tr|{=m`)a<#%t1!bW!(NhYc+cSM+e6X4-k1_S8*1Z?k;# zsPfVj&6mH2edWC9nqDQ|01wvm4(!y`pXDE&)deX}IB#NyFJEWq3S4GCD4ONIqTP;O z$Y{IXwvWE0-9EbXhm||$4QyTd!}1-Ea_pG)dNy9Oj+}0Zh8+=LU(fCmqoFCqkJiMp zo+D^z2OAJ8d-kNs?hy&oyD5X5$jPNfyfCiRJsixLY2GX66B2tcCs!#+)0Bosb1D_{ z7hQ6+Ym*1+njuz(!xckx*<{mGGJ8c&tL&|(Ri^Z`%6t_XzK`BV1#=yY1!`JAT2?17vk zLnlTGM*$>wG@P0iILGJ_um|fAuw#Wm-tQk5IuA8R%z6bFer*qtfzB~HwWT{S^3r}% zUg5Xz?q?(>gCSE^gOMZXQ&)0kBQN|%-|e^lt52oBea+ucG8P{JiiLHABCcH`BXJF! z=2S@Io%!tTaPQ-1?c--7x$Ni)=R)lcM)gELlDakPWM0RtZu}5}1FDy`uSr;e z$4`OTXIZB&&K}m85NA(L{t^XAaqe$@GsJm7z46V&qIGrC5--anC*i*cJxqjtj?o;x zwRnx6(Ixy(VxHZN(phFgZlwDKs09+7gq(Iz-KIu(r%;mRof73Wdu$?6GeeG3q8vG# zK}Dot1W;+)W4w$*MOKGw+;m73F);`rOpO`sIXqFI?{iT*m}l z(jv3I2>iYs_~nGf!udVwO;=<2+_gX=sV7~0i>&Vhp|7c*F3U*E@^X|#1x&HNe~upFaX24`cuWySI(s&-5+X?AQ+aCA>x^X9048>m^2-9`^uNSN|FBtX4ul!&nTn zZ=lzUq1E8o*Nt%YK0#>aTv2~vstIntCXM%Zd*IDyUGQIZB=6JCKEt+&p+^CK{8vrU zFZA+RKm4~yqk%5PX(7Bq7LL!?PpknK_g(5km&qi8zWnizOt2Cdlh4NQ?^GuO{V*+1 zKl=JRsSHhj?5XGZk3ECwKqdmilz2dZZw`v`xwsVu_Dt&yV1EOKS}NBaXhfMq}eKT!65)}Vt3X%N$Q)56;nA7tti znF`q={O}cM1S;Am9;qG2$C}#8K!b4f0|T*<&B&~wVEZpF@`aV=6_1j2(j6Q?xWo=;Pm_ag;{%y-fviVDzsf zD-8rKZ$r@4tqb~r3gYnVZ?R&GpaJ2*(-d&}cLDN)}>b%rTu=#FTuP9d>*KtPOYzg)HF zM9=5?mod=(L4=6qKVDn~k49KxSJ7|X1eXk#M^M#xx`M0=IPf3&N6>>7+ zAM0{moX(Zc>5l)Rqu{U8m~2MAs5$55b6W0Ccf!oY0#9pYFnW^1`W zM76cKKSV2-&HcdFCapx7qe&b3FofGwM3YvoN#ktV|Hv(Y#x8MvYzcf6RB3hBOA!p$ zqBs~qZGG<)44vKx`uczMZ^N>ooupXGC;nYA%4h!l0mUoiZG!)ttJyPYn%QyvIbS<% zJFY($Xgbow{eo$HHr78FzXV>t&F4Jce_wS+HCli*?r2GjGU0d813_$7f2dh)oqyGG zv2(GH-wLKtmhj0JF~X<0K_V^3KYGLn|ICXKcIO9#(PqY%@JGZbN&ny&CCeWlqqOs< z#3=3kV`G$#er1f($*+k~y83l7N_T%rjMBqj6Qdm9Z;w$9^1mNYyfMtyMr8EC{K@e4 zNwh2E-K*cntpazZ6;X74**`MBEac6t&)4;>K^cGYB?4wd1@LayuW|+4jN*(|5?cwY zd>wafC9H~7!fK}yHfklbjio8Z+HBm#k%{xk{$@n%OrE3Z-V{-L%ne8{=kq2n$9vgS z+7NlCV2A^}?4K)vg#UQ0xyFD8+PMuoF)p^OvBR+>+9q( zi~%w{taXMb$ICvPJdD9%B)4H?B{GbiyzC|=vK|>?u9v+Y*!r;ku#Yi5nO^qQ^a*~( zPAK)-4Z8+BoyJZm^V*dYb{;!nsMl^dVVAMktfJir!meYnSw*{%gt=p}Sw*{1gx$ts zvx;`33A>NQW)r1{H&v*-=6b!!QIZSt#dd@M3FtjY>y{6jeOCC$($`50E$tt#>0>JFJ-63zp} z?jpAClM!-0E|zhK=hOAf)L>NBH+NwvgZaqssK1X4mcbc=LMXRSRiA4;G>15 z!5pP83YeUTuE2*sHg7b9dUkDtj_6)Z#sfLgTp4(3-ay+eK@og~Xx zC-BbjD?{>a0Xd%O8U6xc>lU*i?bba6s}^?6+4TH8LpZd#L*Vpyxn%g$gbTh{v9=X3 z!#`Y*N`>!a_0=R~_%oG1k;EG%8ukc5nxOxuy>o%DsyfsDJ~@bp6fmMjMF>}eT#`Vf zfT&yo0&+=_B2r2&BuFqqgn($#CIkgrpxi}k6)mlocBplv(3Vl`I6^C;t&ZAOCF1>3 zg(*^Rt@Aummumg*L{&Orz;WVdpi|OvVy_vB^f^DQ!(C zStGSf+TQYEXH@eijSN$&8&`i@i^2SsU6b41j+>q4^h`e*zA5?VwHvkfMg11P zS4ej@IT*z26Yu`SYn#+EleV|4MEB9-=J%5FP?M2Fjl~-hlaTli6QRI-s^l7ZNjz^gD+Pd(!@LFy9Y<;^8oj0tC9qU)?ekJb)_xHnC zUETb?)b6~l-MY`#w%YXm`cU)94F@;88#^_(MeYav4)rT(sCN3NRcFoZ^e05BYphQnohSY#(cyiJk2+*~+XPbiS&6nYFM^ zJK84l*tkC1t!uSucDLB!(uPT|1ba#whPf6RZNcA&v2|zVw#p4^Zu~6R^KyqHEn$}T;Yn{)q=|bede7Uj zj9d$snzLZf%0yr3g1!ii@UDc`udeFwlTS*OAf?Bwmp9l^nj}=lcZ`@Ddb3m z44Hj8St@Ktjmz6o+G)of=oPmo+R{xMnk(&x*FU-b;QDBp_wvfTD)zH}Z!h~~S)2N^ z>igASSU+aPWh>Acj~KZn|OlieS&t zhGVDUhx+%_HOx6JcJ!UThZ`D-4i9@QR#LY;HnF&PQjdmU&+EBSX%|6ty2#hjZG8v7i?1tlcf0TW`!bI<{_1@3HmNWtd(~)cL`+ zPp*9!?Tx*YZLQsUwzgHSZuZ44f7y@crn+9>>d7Q`g#;$1ip?XL9_}9c*qYqKHp<#Q!hK7gw zHI9Av`t9pay7_s;zPeHDZB9AsxTa&TN|c4_ERnBhS=?0T=Zi-h=jBTD^#2Y!$x))Y zGO2F3yI*y~&i~djDSg@6#}~^>Sf6DW;r@|urC+%06yHA>uHqjG$2h}(*57zm3VZ8M z)L&P{IO8jI{hKp8Bbx>8OPpQUOX{4SKO5W^D{q+eK98ZNH{fQxBmZw`k#o3kgjf|T zX}H+gNrt#5b}>exedz7sxo4m2;~yqcw(QNdE<|W0I?je;MOEzEG0uj@In6T6AKC7i zlE-4ZVw2pA^;p7UyZ5h;wc7Y{$0Hpdi_K}cTdg1~7iZMNv7*|AvBPz_wKd0L_4PQ< z9DXcuzJJW6>{x7hJ#Cf9eo4a^k(EKHhnY~r58TZBJ~uN@j(k=V`00gMM!dywCuN@8 z;gnNbpV;P0ZQD&AT|9D3_W9X8^7=1n{iR^k#Nx@*h8Gr2P7w_sp7c(hR$O#xaZx@b zc}o;ZvOHe~V>}v6nN}=&c}oHap-X>p(SU?@inxD@*qKNK2_vO?syvK1m^9*&QIn^R zDxNa!d>$W?T{LO@CB-8rPC38FlI-D=M+y=Ak}1QdeDxA(!F=IlsvxO_5H87{Fnn6^ zWEYA#E1oz>M@N5k{CFS?z_r2ld4IzKkBvBehNELxZsuA7d_SLg^!-yJel)a{f6sn2{-_^I1S#PQBKDTXQ;#o*93LI=AAsLn^fyjg2J<$==5I(mS@1ul_eJAL z`&%pFZw;9#+s6_wCz~XQ=GqQ?4%Ma$DE*JZM5Agtd}``j1|=I}rRgf-^Tt!PA$Dcs z@Lm>UL8)cj_AP_*4Y7)3D3^+;zc_i^!o`BJB+fLned97H+Ypl|Gw| zqfD=twhW>*@xLT!^v8%=254WG`_%wHTAh`(?PKokbLWe>kJ8%#iPE&9XbFDa`Yt!q zUPLL;C!RD;QAj6ET1pr-(dTU(|62>p%E2pH6Mf#I`TN6&XE+v=m~GpCjy{)Eot*|v z^m!B8xE^P2h@~CH5>44Vzch{|+PcwgDwEwNP4?0hLey$gd1_9cQW2k{r8kvxubdNw zkc>NeR%mKO^v(h$7TWe{$|YI|ErayQ%hJg(97e*#q@D&(4pzlBWUPu~I}Y3NDFa*k z=)nw2lkFQPq^TVKy>j{-IsBp#HcnXj5=vw?;iSE z8UrTEQsW8dO@31`4K$JrG>#V7T4HOJGSxvNNj=!8kz}A5nJI6C^Tl>Jn(r?38d?oFr4jxU_j#mrbbi=H8y**mpy>Uer zHlMTc0|k7Qln;9j8N$B-UlR4ad=E7A;;TSKrPox=FD<{M^4f}kuY86FE>AtcH#@@v zl?#W@x4ECc)S{4Y^y1rU$(Gf!QzVInk50>-1HAEtSPNov@qbi zn4uUi-Se%=(6g{+e)aguh4>v)eE2QkJCstwd;5GNGW5A0c1)%t;A@ZJk(&9JUtU#F zJi7vs;CCGZzH%5IaX&X%9cH!|Z?s)rGbiAygW*x+w^%9TtA3$ycGaSVbC?IdwC9T! zED8AfU1P%mU#1Ji;g3%$Li`*`svIxnFqaDgzWo&jKwS)9R5Ksh3iw7=D8%o#s)+f% zRaC~er9xTt{HrS#6wbeTUch&w5(Y=kDV;a3qAK9KP@ynPRw8=7@Dv`HUtKZpQhaa# z(d7Emayn8z03RSsYMNoR;}`-E~v zJsH0SYEkpOn`DT9FS~?Z*SHGtQL@Uag~1}czYvPUFOKnrh|rIUTu_s2MSRgAJm50# zI#U6L)v&v?u+EkE5kq9qIa@$MZ*dOI&p9qu(Q%QAj*B&Prk@jf-G|YM?sXgNx#&d4 z#U{GwzSc>@x6O%#@^kTsj*B#O7N6}=JkD`Zh>nXvboLg8=~;N&bCHLRi#v2&)S=^I z4&CT*m-ujpy#Igq|8NOJyBdC$uF21vEW$`WumC@P8+Mz>DFGo1*sH?dyDeIb&+WOd z!KE8#oA`0v;#mvv#gm|#!%gas{+jXpg4Di@PvCjOWYR2uh&S^4xh`@2XH|@<#1Wj^ zqGtvdSU=$Fbn^$NNjf6*&Sl})#-IFkAqLqA0$T2eiS5AP#IQZ8Xiivs-hi0+R$z3< zbw7q&R#iIh3Z9?>J6XBpn`!+LaM8sqaKG}>e3a0_KQ1RNWa2H zu?Z&1oz0}ko7p776r>)&rw(UV&Yo}Q{KwaiiMp6ktBMlzDpGOHe@oo#7qDQ zvBc#MNHL8gvlcB_fZvJ_!WNAAj2}hvdqjy@MZ(g+==mMS!a1Kx$utMxreSl0lJNo*4O~@W~!ptTO}4JyFuGU`K{63ym$2v__-x9G0*Y)tS7LPD)bw9akGT zQ*5T5osr0BKV>7S#^*)#6ZwhMMB7S$e(Og0=6`Aazx3T#SFj`dk3!Q-e5o~*7-MtN})x^$Xp&Kl{|8jS+!lp>>cI+b+O zgLHb)_;`j&rUDvD%P!67^@NVurVYk>wFUBy4fYrq{0KT+FEwX27(Tf$ zgl{KfO=WzC@b}S?ba#x)J>#%h7+~ad)kpMx13g=&^6l~YB|m*L@G~;hWBRb7nMmI@u%EtX zVXq}*<}APe27#~l0`zS8jJl@x9}&G*p*MvJa;Enu`2Fd6f3f#Af!~cRJy>{N4w9 zwyX+q!rm(pdmBA_XL|q#BIJ5Uk#9k5XS^4$$?6t=Ef?=$^?1w#DPNz|`$6xni8JVkry)p2x{Q6?E^5b1Q z-(Gh_*4hGLZ}xgd?Cpj<8=rGMdlyIS^=rc3=!m_2o<06tx25ljh`m9uXSW-eOiSPF zh`ncE52r$x-vOSz)e(DRV9#z_`1V#t?7i!iAAe)b(zi2W?=IN0+aJEY2O{gKjJIjOpKUcMz1I z4>G@B!Djj08L{^&CNDG7%6 z&)(l;&*oH>_ndhey zuzAHAY?+Vix8os{GkfN@y)XYqzUjuXo#SEXj(m19-~#jFn{FM!=X?GhU^G#=BcE|@ zkaR~rOTAwG@BXHnet{t`);q;I^drC%SK4QWPGaprhd~?!J1K6vc5S+zT&;lJJ{YsQ=f& zJF%hLyY_HAIuy?%?2Bw4{4~WjF#9O|_}wn|twq!42f}aj^uG;1)7(M&{I1yz-f@1R z_$u%Cd+^Wmj<>^LQ3^kYY{tjyt{Gs9Z!-KGuPl8v@Q;Gu;@b>AYt8(-;O`1Q*Bof? z5Ac)OlIi~xemXlI`oh2Q;3D6PIC-W{y0|;j`u=G7PfQ*J#ZiC0iz9yD#od`KDT%ug z()aUBl63KuFD%kNOD5^!_?l@aZ%}0&_Ko<5%HI~p_)W%fDgM^MH2FDq;x`%>%Fp(e ziCS7CKTi>vSoykN{wdDiF5u7Lnq&OW%D)kuiSg!r`8l#>qE`4>26NPJ%@aFZ82>3j zclmQ5%fxsyKz`~_e^SIhU;epH|McKH@^eii6XVg3JRPs8GBF<6FFf;{mWlDG3o8yTw0~YOSpG2n z^Mk1={tE+sn1qhk1erK1td+k2vP_IGcgfE=c_w<|FXiW)Iure8zx=epG(QvZzZLNx zr*r;j7k+GzEx(2DFF)tRndpC`BgfsN9QsQ4f8mRv)9tB-G`AE-4dCxs7bjFAcN4?I z$r}mbodEe8-8o3=>5g=G!y#%taVsQ!xV4t@oYvoeq`^WpeH-62^3!y*@X3nV#YKsf zHG0U%f`_;3%PTLhtSPO!6c0taN3g=D0vbI^Wr30pJSCqjY5cfG^4Ph2=%Z@>tSbsD z7gv^7Eb#N*#KTe+ReqX#`H5pq+`vy9PrYkzV*gfsMCR_#n=H*u`NW}gcj6NV8{M+@ zo`^}k=Wan#Z?vb8CLeH1xutHJk^ATgaif&Do9BtcY3`UOjzw=RVc;> zXoGQL&Mn>jN!YA_%~_IPfUx`oALHuQ3cp(;=C#;b@g0cw4skB*Y!`nMb{-X%AL0x{6u%9F5mlH1({}u94 zV!l5$L;O|PDHCr6Un{-~IkZ%!xjP%?tE<>7sDrOx$DQ4UFck##2c|&|R^H@$5%xwg*G9i5 zhKgH9XS@w4pFNV_3_E+pe3$Gc@mq-ZHSvewPsLpMh{G=JJPG~N#ZSX#wzxC&`-}S_ z++Z>9-CQhYz9x%jBF$Hd--gW^@gRh~QCtI^)neYm*e>o2o4l4{dS=7s>>G&9JWDX{9hr}Ge-yGQlWg^V<0K#6UUc6LF21zF3B^Tk|4 z;J9FRmP`L}$ZwLo4eD-#Uz3pru6Z7i{9M$_ z^OCnkoxVkeP3ruad>R1mFJfLxACLUdP8aC67jv!bEOM4p54wn17k$Y}!$9emLjOYP zAX~vmG3|eye0pf7RGb6vm1NmjOhy`Rf}L+j&USc%BN=uWZ?>567LYpu;0B3lzmP2Z6UeYX5q2g^PWv+?Ukt7w!w&6NifR8k zvX<%V#I(PfEc=_uuzwTmd{=VX|AFK@A8seZ4(&f6rv1mr*#NlTh-<;ml4buO8TKEA zo%h7=g8wS!8esf&+plivwfZ;`D(~>CBF-8ez4?R6C6QC zyJg-lC1;0o+pmeoKwd58I94Mr2d^Y|0l=*ibG>j2S$VvZj5L3Mxb7F9g|s~^{wnxU z>9cGPNWKvArzK||UzD8Z!$XoYkMBzU5cr7X%;P7L{}u8U7^s*>=H+y83Ai5_>7NSj zFD?U*CU*tEjT0Awr;?SgVlwi@^XEMAAn-!za6G?Ga;`-#lbm^6B{|QTo5+ZZef$=2 zckp(P9}xG0d@s2h0Pb;d2k>)brLBRCw5@>s*Cgljgoh>PocXV0Mg+&}8}c;pm&men zDj9bE1^Q=7-Ur-M^4Gw%`Q*$L^Za>2TZBcq^#EsyCxFi)qik7LXG?wsG7t7lY@KRbN+=Ct_X)n@c5UJ6s|841Qk)CkBOTW1ZzP`p`O{?BbnQ^gq5EBr4~rS~ahUhTdWUH^LCiWmg{-`EB2Ns0 z64>ueW`V%virH4r^Yja)zXbY4E5cdBj`O_`XuF#Mv zzZ&wkWazVgPnZ00$UBi?zZ~|viVuN%OFsu~b)fY7V2m6p`H#>h$C58*%5YAVoX<~w zjXW-tmqd^32L^x4K96?6XZ z2eNKkza-|pnzyAx`+p|G{(Z3Xq2$k^U$;C7a@AdXGIV|iol_+L1bOK!`D>8pk;jMk zmxqgaZ+Wu#LGUc`HgJvj4)6`)+rT%ASAy>q-vIul_$u%d;(6eM;!^Mt@eFW0GfWTf zik>1K1wLDx4<0P;3cgs3rW1T!3=FO#k0xO)MZ5sKnmjqY?%Pa8`S9Fz2O0W2H+^4> z(?swP`62+^uf#NafIK<0^Bfs=egHcS(&-1CSH*+CpOMD^;NrMuA|C*^BTo+PWRYR# z3E0UI^G8YsiO<5gd%pD9X2y!S<}^*r@phKGQ`6!3bou3_E!nD{Qqv!HXIcs=+5@kTJ8xwdOnu9uOq3-*hd zwr9jFlb6Ue2*-6CGIqgHF?Bu@v)oQVJFsiglf=|HUCb)zB0d$|OPmeP7w3R^J!99T ze9oCneO{lCd5)MW?h2kIW}kA;J45Fj@Dj=UgKrRXEL|_=`TADzF!0^t5#XPQ(WHaj z;&EWE`7#aYO77VOGV91acMRq@^SX5Af)A5*-TH}`?ZG`)3_05;*CnZw3Cr>YCTrunAYH&)9^H1PU| zVHxjV#mw*VI6v8SZaXpUb3SUFiP;8tofgXu-*MO{?gRP1i~E5O ziid#T6%PX+6^{mgDjoxF*)p^_9^6)31U^+f1>8+M9qiUNvrz`%0g{)4&lk@Dj}k8c zPY~CFFC}*Yz`3~W zgC7wy?@x%C_vggS`$6$k@H^sZ;6ICJfxo@>o;;W_!RN=;LcPAt^WFw^IG*1pW;=K5s7wId!<2*DgZGM=7q0J9&U$=K%pknpqdX7%hL~;jeKG6K zt*JtXb@Z9!EPvilvg_Xt9(NRD7jzdh&HczM9Js+A4;Nz>j1^P=67t#9M%jupz_Y}x zFJ5y}hxuJZ&H=z(CuaG$wN}VkcdI4O2HzrPJ>DsXT5zwJb@$I=*4@KmmepP{$M)Zf zS*I_G+5X=U4+Fn19tZx5nEf|~YcsnRZX;$~9mFjEj$(%GE}jAIBVG(1NInMucY&B? zI9kkpJyFaunI>l2;B_g(vV7)<*-qTrEaWU7UW-yE2V5(LH(aL$6oA)D&NSaf?hSyu z+hey*3pu)Luv7BZ;77O3RP0>2<;yXB7#QlDvfSIl^iiYJ3V6|=3jL?m_{ z&1+yX%i&Zp^WI6!yyu9s!FggfUAKOVuq=mRlC!?Xh*=IrVz!OxV)m&rG1EC$JO;c# z%ycd#(;(amG3|UuOglG=*#_Q5bmg${q9pS%d-WpIjO_4a%;R`mdUA<4*fS|L7WV2XLLZC-^4uQ1Ci&3HTN< z?_J(0=JN^nithpcRLplmelFe*enk8(_}AjD7|4Dr&H?{kJOuo*nD5-YC9VM<5%XH) zBk_;Hu{L4Z?g5`5eieL@nD>0$S~1GABj&$dB+mo)63+nVi@6qY9(gnh4bH70gIj_p zO3r$BYsiqF0WOuCeX~l;W?Um?{Vo-=ewT~c7u*^$>=c4GN?8_I4X=k#SZGO7A1Y9OA1J4!D1}_lL179m<-j|7&g1;rc z5xhyvzOz+)EBGGqHt_x8UEp2f1K<|eGEnKQuxEX@93S4#Wj>D=vo15ghCgsDQ|cVU zp8C`wb1cii^)kz0oVXBs)+^=Hu)iLg*mrb2o7K@Zk#C3TH=8c~+2Q<<<8=m@<>bl-JRZz? zii3w?&+?)U%V#P!%FD5zDV~l!+bDHde)F(dT#e%G;>8PQyhE_X!HIam!yt3Px37IEuBnv z91Wa@TwcJ8hk2o#X<$8Nfcs$2c5Y!=&Y6(YIl0)i|6XAkvrH}hF7GNsbdMm82w9&l z4Pd5$@tOS$G7|;Y3Y&2Uvhu=mGdV>WNF>uso0;febp5cIj!Uz`j_~9Y$&&l!!(xs1 z4f~oaA24n7mz=g)UKxlCyVWa#I_H!h!#eN>P z6E4OdxN2;z#n*$WzY+W8*i7d}Plv~>UT&w(IQ)UzimkQyKCtEY7i6TL?jdX^jCC07 z!LGIVH(~@&Y#MkQ=bk z4(FU~ALLiD=SF@Vd(N%RP9~V?r!MEF)Zuff+-Uzc$g{w-Pwon~uzY9P($D!T!}4A^ zH}Wv-M`NR%l?XcqOgrQmV6#&$of{yZEgf>Tr&CK-d*eKq_HV?V8+j%6Yp^k{s}PpY zxH2yCHn7FT=U=JAzOr39;q;R$OFL^c05_>=bWBl z`OYLa@)Yc+W22o>2s;BzJ7nIQFgwf1vcqcthW!@y+{ml2=e-Hq;eE7?VA>(y12#Ln z2Vr*hfEo5z*mEQEzQk{^(N0%{-4CW6as$}x@E(NO;WY-sevCagGT-COh=+D~tEdH- zcF0*^v(tyHeDRuuVf$mxja-2J5Nu2j-B2*?&=rBrP8;|$zv0Agj55xqoC6HpIoND$ z$M6?qE~QlG{p&*Jcx7|TVdSzJM zcXAH?z`3-^P67Ou=Aq|(!V-xTPE(@F8XJp<@&LXh; ziOjpn2a$PFf-A&ka+nV6{@@f(K8?(Y9vt&%`g6!9Q;KU+Y$j)Z?Oxt;Prj0jdvkOf zv6=oBau%iGIl$!iz;E~69waNjyU1tY58R{JOumn-xy>`4{CTp<{8dl>CRy{$qn`Xj zvdX*##wN4himbN8^N7i_$k_-4*WHunkh_HP0#81OtoByu$;Xhph5A!G`80C(P+soI z=a74Z@)}RRgxoWfFZbjt$?7{BJ^2=LPN=`llix$ee3kA&Pri%Hjs^FqC*Mcz9m=2a zeT`WqQ)iIJ9CIkAei2!HaEiDk_9Y&d zi`!tognSbIz%9i_X1dmr)i*baDc|bxHZjw)%aiXGGv3F^>dQ}xssD;6e?we={V}rU zr5}rFr!DJFa?ZQREDt^}ZhgOpnCZ;-_*^mLM{yD#WyNmB)+3JU{Rm zaT`PU?gyFWd5gz2O{|I}Gcd-vG}6 z^O<$Z+1)C|dEiB2b~pF#5_ATFZ;+gPlXwQ0&$!bL<#&4W`^g%U9~86wbB;tgnR6pD z+tu^rjsUn9#4P_eJ$_frz7@nn{Tv|YLJT_u%xA)EY(Gs*JKa1!Tg>+9p3T6yfKj{m zq`)i__iTpF1(T@{rk$A{yLYA_ryV|1P955D?@xhghtG)Hxx@X|9L^)ObBp9;zWYQS z+HvnvfoW%lEuNmjg*GJG=&M z`aUOV)$JdA#K+b2@W7(L`g869#@D*KGL;D$kh43G)6| zLt>ESaYu1a$h&#$o*_Y4wxt1*v;DYdNFZmM87VpWBJmKgdxiu$78HZ6W8o0Ve-9G4=O*{FJBfo)uvy zf_sH>a7VCvRz&<~$)`c?-oKOniLF9?<|WhPQ^o9$e8<4%_PxZkf3C;wxsjZ3PRjQX zO#dsM&NPo_h}n1Cvm!a+7(QQemM7mauxp29V)mCc9=mt+aD7n&Io~}n{rkjdM!`NY z$DjRTwt?3?eoMR5Ga*0C<1@u<8+>oU^aqGpk3&4RXFph;e4l~(wd|}4~nVJcM?qBJ>vm= zwuh%BCqF070rR~D(|=n`o5wuYwiMSz^{Z-+7>Y#%0fVu;1}r z1-qsjDQ5Xk^7s<*-ykpcc$S!Jx_r06?0iE!5BkeIzENBY`FfAt`+8_d%OU@s0v<hA*LGNudr+CdQXS%TA2L1o}BMa z*tPa{G5g~$Jbp;L0CP;fM?rnY^{jXhnD0?g&N0NE$9M|-f#hU+9)tNk4xNVjWP2Wi z?c@~6$@V-(2b4n($;tLS2G<_Wm7F|S%=PC{9*-4gW?;VL@nvGJD^z$~DdybYz0)@u ziGi!59E|D@R(rfoTn+gT$QMx?=M-^U@D7iEE-r+e?>X2Sg?k2LOgOK2QF5Hx!e=lb z-w*!4)Bi}^3G(B<6xt!5AZD`pzJ%HDBF=_9$76d2<1xtHdwhs%BKSh-YzMn{`XDEd zll&Lpme^uQ2c6ID;g2!na2&I2EhU@GgK#<6Yz-ujoJpzHShRLA41QaGK=g?9EHt>4*zB5aEjb&1;I?4ne3EV}HkhQ*laHG6gh`dTq9$%b7ceh9Q=WM6Pulb4wL&(iu*6v zY|Q6aX5&>WGCL+*doubLT^4zC$k}AI&m8iYP|m+Bx31W?5HlIA#5BulrcMF&S>j>X zvsfvosci8$>{%R?vn}P3v%_m5h9~p*AZ)Sha85W>+z)%&Vwoejd%l58{UXU(6dY?P zr+$g}0_@Ah%<>#D?Ny1#W50x)6NX(X=Ga~=w7eeh*oFq9xX5S&L=UoH@LfP4_SJGGH+@ig!-GOj7;3dJnXG31_39E=xJUPL}S zlur@2hj$v81q;Xf%jD_c5^^sm4$8%g;hjT1CzMx-+2*Usy+e78nDH(l_X*`o#Y}%K zxo;?6E~b1XnH>slm6-F8wPcMg8^s0C*+SMhbDNmYMs6ju1Hx?+F96>|*7);dG1cxT NkD<2iO@I%8{}ZTDOPT-x diff --git a/examples/scanner/output/scanner.cpp b/examples/scanner/output/scanner.cpp deleted file mode 100644 index 5eb1627a..00000000 --- a/examples/scanner/output/scanner.cpp +++ /dev/null @@ -1,128 +0,0 @@ -#include -#line 1 "scanner.pde" - -/* - Copyright (C) 2011 James Coliz, Jr. - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - version 2 as published by the Free Software Foundation. - */ - -/** - * Channel scanner - * - * Example to detect interference on the various channels available. - * This is a good diagnostic tool to check whether you're picking a - * good channel for your application. - * - * Inspired by cpixip. - * See http://arduino.cc/forum/index.php/topic,54795.0.html - */ - -#include -#include "nRF24L01.h" -#include "RF24.h" -#include "printf.h" - -// -// Hardware configuration -// - -// Set up nRF24L01 radio on SPI bus plus pins 8 & 9 - -RF24 radio(8,9); - -// -// Channel info -// - -const short num_channels = 128; -short values[num_channels]; - -// -// Setup -// - -void setup(void) -{ - // - // Print preamble - // - - Serial.begin(57600); - printf_begin(); - printf("\n\rRF24/examples/scanner/\n\r"); - - // - // Setup and configure rf radio - // - - radio.begin(); - radio.setAutoAck(false); - - // Get into standby mode - radio.startListening(); - radio.stopListening(); - - // Print out header, high then low digit - int i = 0; - while ( i < num_channels ) - { - printf("%x",i>>4); - ++i; - } - printf("\n\r"); - i = 0; - while ( i < num_channels ) - { - printf("%x",i&0xf); - ++i; - } - printf("\n\r"); -} - -// -// Loop -// - -const short num_reps = 100; - -void loop(void) -{ - // Clear measurement values - memset(values,0,num_channels); - - // Scan all channels num_reps times - int rep_counter = num_reps; - while (rep_counter--) - { - int i = num_channels; - while (i--) - { - // Select this channel - radio.setChannel(i); - - // Listen for a little - radio.startListening(); - delayMicroseconds(128); - radio.stopListening(); - - // Did we get a carrier? - if ( radio.testCarrier() ) - ++values[i]; - } - } - - // Print out channel measurements, clamped to a single hex digit - int i = 0; - while ( i < num_channels ) - { - printf("%x",min(0xf,values[i]&0xf)); - ++i; - } - printf("\n\r"); -} - - -// vim:ai:cin:sts=2 sw=2 ft=cpp diff --git a/examples/scanner/output/scanner.elf b/examples/scanner/output/scanner.elf deleted file mode 100755 index 5e0f4b153bcd3684fc9008dac0bf38d4a5fbfd97..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 100436 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 ZC5_yqj3YXVcR0Mu?yd|2_9q0v{|C_~feiov diff --git a/examples/scanner/output/scanner.hex b/examples/scanner/output/scanner.hex deleted file mode 100644 index 00a3175e..00000000 --- a/examples/scanner/output/scanner.hex +++ /dev/null @@ -1,325 +0,0 @@ -:100000000C9463000C948B000C948B000C948B006C -:100010000C948B000C948B000C948B000C948B0034 -:100020000C948B000C948B000C948B000C948B0024 -:100030000C948B000C948B000C948B000C948B0014 -:100040000C948F050C948B000C9423060C948B005D -:100050000C948B000C948B000C948B000C948B00F4 -:100060000C948B000C948B000000000024002700EF -:100070002A0000000000250028002B0000000000DE -:1000800023002600290004040404040404040202DA -:100090000202020203030303030301020408102007 -:1000A0004080010204081020010204081020000012 -:1000B0000007000201000003040600000000000029 -:1000C000000090043B0711241FBECFEFD8E0DEBF35 -:1000D000CDBF11E0A0E0B1E0E6EFF3E102C0059092 -:1000E0000D92AA33B107D9F712E0AAE3B1E001C03B -:1000F0001D92A13FB107E1F710E0C6ECD0E004C0CB -:100100002297FE010E94F509C23CD107C9F70E945F -:100110001C060C94F9090C9400000F931F93CF93C5 -:10012000DF938C01EB01009731F46115710519F42F -:1001300020E030E038C081E090E06EE070E00E94A6 -:10014000CB02FC019C01009771F180E8838320972A -:1001500071F0D387C28781E883838091E702909111 -:10016000E802892B21F4F093E802E093E7020115FD -:100170001105C9F011870087838182608383809194 -:10018000E9029091EA02892B71F4F093EA02E0937C -:10019000E9028091EB029091EC02892B21F4F0931B -:1001A000EC02E093EB02C901DF91CF911F910F9117 -:1001B0000895A0E0B0E0EFEDF0E00C94CC09FE0172 -:1001C0003596619171918091E9029091EA02AF01B7 -:1001D0000E94EE002096E2E00C94E809ABE0B0E06B -:1001E000E4EFF0E00C94BC093C012B015A01FC0146 -:1001F00017821682838181FD03C06FEF7FEFC6C136 -:100200009AE0892E1E010894211C311CF3012381E0 -:10021000F20123FD859123FF81912F01882309F4A9 -:10022000B2C1853239F423FD859123FF81912F01DD -:10023000853229F490E0B3010E940604E7CF982F9D -:10024000FF24EE249924FFE1FF15D0F09B3269F0E2 -:100250009C3228F4903259F0933291F40EC09D32C2 -:1002600049F0903369F441E024C052E0F52A84E07B -:10027000F82A28C098E0F92A25C0E0E1FE2A22C029 -:10028000F7FC29C0892F80538A3070F4F6FE05C030 -:10029000989C902C1124980E15C0E89CE02C1124F9 -:1002A000E80EF0E2FF2A0EC09E3229F4F6FC6BC184 -:1002B00040E4F42A07C09C3619F450E8F52A02C03D -:1002C000983649F4F20123FD959123FF91912F0176 -:1002D000992309F0B8CF892F8554833018F08052C4 -:1002E000833038F444E050E0A40EB51E5FE3598338 -:1002F0000FC0933631F0933779F0933509F056C03B -:1003000020C0F5018081898342E050E0A40EB51E33 -:10031000610101E010E012C0F501C080D180F6FC5F -:1003200003C06FEF7FEF02C0692D70E042E050E044 -:10033000A40EB51EC6010E94FB038C015FE7F522E7 -:1003400014C0F501C080D180F6FC03C06FEF7FEFD1 -:1003500002C0692D70E042E050E0A40EB51EC60157 -:100360000E94E9038C0150E8F52AF3FE07C01AC089 -:1003700080E290E0B3010E940604EA948E2D90E0A2 -:1003800008171907A8F30EC0F601F7FC8591F7FED0 -:1003900081916F0190E0B3010E940604E110EA949C -:1003A000015010400115110579F7EAC0943611F09B -:1003B000993669F5F7FE08C0F50120813181428147 -:1003C000538184E090E00AC0F501808191819C0115 -:1003D000442737FD4095542F82E090E0A80EB91EC7 -:1003E0009FE6F92257FF09C0509540953095219519 -:1003F0003F4F4F4F5F4FE0E8FE2ACA01B901A1010C -:100400002AE030E00E943204D82ED21840C095373E -:1004100029F41F2D1F7E2AE030E01DC01F2D197FFB -:100420009F3661F0903720F4983509F0ACC00FC0CA -:10043000903739F0983709F0A6C004C028E030E0C2 -:100440000AC0106114FD146020E130E004C014FD06 -:10045000166020E132E017FF08C0F501608171816C -:100460008281938144E050E008C0F5018081918150 -:10047000BC0180E090E042E050E0A40EB51EA10176 -:100480000E943204D82ED2188FE7F82EF122F6FE01 -:100490000BC05EEFF522D91438F4F4FE07C0F2FC6D -:1004A00005C08FEEF82202C01D2D01C0192DF4FEEB -:1004B0000DC0FE01ED0DF11D8081803319F499EE20 -:1004C000F92208C01F5FF2FE05C003C08F2D867899 -:1004D00009F01F5F0F2DF3FC14C0F0FE0FC01E15B6 -:1004E00010F09D2C0BC09D2C9E0C911A1E2D06C049 -:1004F00080E290E0B3010E9406041F5F1E15C0F366 -:1005000004C01E1510F4E11A01C0EE2404FF0FC050 -:1005100080E390E0B3010E94060402FF1DC001FDCC -:1005200003C088E790E00EC088E590E00BC0802F04 -:10053000867891F001FF02C08BE201C080E2F7FCF7 -:100540008DE290E0B3010E94060406C080E390E0D3 -:10055000B3010E9406049A94D914C0F3DA94F1010D -:10056000ED0DF11D808190E0B3010E940604DD20B5 -:10057000A9F706C080E290E0B3010E940604EA9465 -:10058000EE20C1F743CEF30166817781CB012B9634 -:10059000E2E10C94D8090F931F93CF93DF93689FE8 -:1005A0008001699F100D789F100D1124C8010E94D1 -:1005B000E702EC01009729F060E070E0A8010E94DA -:1005C000F403CE01DF91CF911F910F910895CF9346 -:1005D000DF93BC018230910510F462E070E0A091DD -:1005E000EF02B091F002ED01E0E0F0E040E050E019 -:1005F00021C0888199818617970769F48A819B8138 -:10060000309719F09383828304C09093F002809313 -:10061000EF02FE0134C06817790738F4411551051F -:1006200019F08417950708F4AC01FE018A819B81BB -:100630009C01E9012097E9F641155105A9F1CA018C -:10064000861B970B049708F4BA01E0E0F0E02AC09B -:100650008D919C91119784179507F9F4641775078C -:1006600081F412968D919C911397309719F0938392 -:10067000828304C09093F0028093EF02FD013296D2 -:100680004CC0CA01861B970BFD01E80FF91F61934F -:10069000719302978D939C9340C0FD018281938159 -:1006A0009C01D9011097A1F68091ED029091EE0284 -:1006B000892B41F480912301909124019093EE02C3 -:1006C0008093ED024091250150912601411551057D -:1006D00041F44DB75EB78091210190912201481BF2 -:1006E000590B2091ED023091EE02CA01821B930B4F -:1006F0008617970780F0AB014E5F5F4F8417950711 -:1007000050F0420F531F5093EE024093ED02F90157 -:100710006193719302C0E0E0F0E0CF01DF91CF91EF -:100720000895CF93DF93009709F450C0EC0122970E -:100730001B821A82A091EF02B091F002109709F18A -:1007400040E050E0AC17BD0708F1BB83AA83FE016F -:1007500021913191E20FF31FAE17BF0779F48D910C -:100760009C911197280F391F2E5F3F4F39832883A3 -:1007700012968D919C9113979B838A834115510505 -:1007800071F4D093F002C093EF0220C012968D91C5 -:100790009C911397AD01009711F0DC01D3CFFA01C2 -:1007A000D383C28321913191E20FF31FCE17DF076C -:1007B00069F488819981280F391F2E5F3F4FFA0114 -:1007C000318320838A819B8193838283DF91CF91C0 -:1007D0000895FC010590615070400110D8F7809594 -:1007E00090958E0F9F1F0895DC0101C06D934150BD -:1007F0005040E0F70895FC016150704001900110F5 -:10080000D8F7809590958E0F9F1F08950F931F9393 -:10081000CF93DF938C01EB018B8181FF1BC082FFA3 -:100820000DC02E813F818C819D812817390764F48A -:10083000E881F9810193F983E88306C0E885F985A9 -:10084000802F0995892B31F48E819F8101969F839A -:100850008E8302C00FEF1FEFC801DF91CF911F9170 -:100860000F910895FA01AA27283051F1203181F122 -:10087000E8946F936E7F6E5F7F4F8F4F9F4FAF4FA8 -:10088000B1E03ED0B4E03CD0670F781F891F9A1FBB -:10089000A11D680F791F8A1F911DA11D6A0F711D6F -:1008A000811D911DA11D20D009F468943F912AE07B -:1008B000269F11243019305D3193DEF6CF01089563 -:1008C000462F4770405D4193B3E00FD0C9F7F6CF94 -:1008D000462F4F70405D4A3318F0495D31FD40525C -:1008E000419302D0A9F7EACFB4E0A69597958795F2 -:1008F00077956795BA95C9F70097610571050895D1 -:100900009B01AC010A2E069457954795379527957C -:10091000BA95C9F7620F731F841F951FA01D089514 -:100920008AE391E068E049E00E9475070895FF922C -:100930000F931F93CF93DF9380E8E7E4F1E0DF01AB -:100940001D928A95E9F704E610E021C08AE391E060 -:100950006F2D0E94F2078AE391E00E94840880E8EC -:1009600090E00E94D7058AE391E00E947C078AE329 -:1009700091E00E944608882329F088819981019698 -:10098000998388832297FA94BFEFFB16F9F60150FA -:100990001040EFEF0F3F1E0729F0C5E4D2E08FE7CC -:1009A000F82ED4CFC7E4D1E000E011E000D000D0B1 -:1009B000ADB7BEB712961C930E931197899199917A -:1009C0008F70907014969C938E9313970E94D90009 -:1009D0000F900F900F900F90B2E0C734DB0731F704 -:1009E00000D083E091E0EDB7FEB7928381830E944F -:1009F000D9000F900F90DF91CF911F910F91FF9031 -:100A0000089580E895E060E070E00E948D00089510 -:100A10000F931F93CF93DF9384ED92E040E051EE6C -:100A200060E070E00E9454060E94010500D086E05C -:100A300091E0EDB7FEB7928381830E94D9000F90B9 -:100A40000F908AE391E00E944B088AE391E060E016 -:100A50000E94E8078AE391E00E9484088AE391E01B -:100A60000E947C07C0E0D0E000E011E000D000D0A0 -:100A7000EDB7FEB712830183CE0124E095958795EB -:100A80002A95E1F7948383830E94D90021960F90E1 -:100A90000F900F900F90C038D10541F700D083E040 -:100AA00091E0EDB7FEB7928381830E94D900C0E048 -:100AB000D0E00F900F9000D000D0EDB7FEB70183CB -:100AC0001283CE018F709070948383830E94D9002B -:100AD00021960F900F900F900F90C038D10559F7C5 -:100AE00000D083E091E0EDB7FEB7928381830E944E -:100AF000D9000F900F90DF91CF911F910F91089522 -:100B00000F931F93082F84ED92E0602F0E94280717 -:100B1000112707FD1095C8011F910F9108951F928D -:100B20000F920FB60F9211242F933F938F939F93A1 -:100B3000AF93BF9380914B0290914C02A0914D02D4 -:100B4000B0914E0230914F020196A11DB11D232F8D -:100B50002D5F2D3720F02D570196A11DB11D20933B -:100B60004F0280934B0290934C02A0934D02B0939E -:100B70004E028091470290914802A0914902B091A3 -:100B80004A020196A11DB11D80934702909348022D -:100B9000A0934902B0934A02BF91AF919F918F9168 -:100BA0003F912F910F900FBE0F901F9018950197B6 -:100BB00039F0880F991F880F991F02970197F1F755 -:100BC0000895789484B5826084BD84B5816084BDC5 -:100BD00085B5826085BD85B5816085BDEEE6F0E0B6 -:100BE000808181608083E1E8F0E010828081826012 -:100BF0008083808181608083E0E8F0E08081816093 -:100C00008083E1EBF0E0808184608083E0EBF0E0C2 -:100C1000808181608083EAE7F0E080818460808366 -:100C20008081826080838081816080838081806810 -:100C300080831092C10008950E94E1050E9408057A -:100C40000E949704FDCF1F920F920FB60F921124AE -:100C50002F933F934F938F939F93EF93FF934091E5 -:100C6000C600E091D002F091D10231969F012F771A -:100C7000307031978091D2029091D30228173907B2 -:100C800039F0E05BFD4F40833093D1022093D002D6 -:100C9000FF91EF919F918F914F913F912F910F90E5 -:100CA0000FBE0F901F901895AF92BF92DF92EF92F8 -:100CB000FF920F931F93CF93DF93EC017A018B0187 -:100CC000DD24403081EE580780E0680780E0780737 -:100CD00011F0DD24D39491E0A92EB12CE885F9859B -:100CE000DD2069F0C5010A8802C0880F991F0A94A7 -:100CF000E2F7808360E079E08DE390E005C0108248 -:100D000060E874E88EE190E0A80197010E949A09DA -:100D10002150304040405040569547953795279593 -:100D200080E12030380720F0DD2011F0DD24D6CF1F -:100D3000EC81FD813083EE81FF812083EA85FB8594 -:100D4000208141E050E0CA010E8402C0880F991F43 -:100D50000A94E2F7282B2083EA85FB852081CA01CB -:100D60000F8402C0880F991F0A94E2F7282B208372 -:100D7000EA85FB858081088802C0440F551F0A94CC -:100D8000E2F7842B8083DF91CF911F910F91FF9029 -:100D9000EF90DF90BF90AF900895DC011296ED9137 -:100DA000FC911397E058FF4F2191319180819181FF -:100DB000281B390B2F773070C9010895DC0112967A -:100DC000ED91FC911397EE57FF4F20813181929165 -:100DD0008291E058F0408217930719F42FEF3FEF0C -:100DE00005C0E20FF31F8081282F30E0C90108956C -:100DF000DC011296ED91FC911397DF01AE57BF4FC6 -:100E00002D913C911197E058FF4F80819181E058DE -:100E1000F0408217930719F42FEF3FEF0BC0E20F5A -:100E2000F31F80812F5F3F4F2F7730702D933C93BE -:100E3000282F30E0C9010895DC011296ED91FC9154 -:100E40001397EE57FF4F808191819293829308957B -:100E5000FC01A085B18521898C9190E0022E02C011 -:100E6000959587950A94E2F780FFF6CF0484F5857F -:100E7000E02D608308958BE291E09093D5028093FA -:100E8000D40280E592E09093D7028093D60285EC5D -:100E900090E09093D9028093D80284EC90E09093F4 -:100EA000DB028093DA0280EC90E09093DD02809385 -:100EB000DC0281EC90E09093DF028093DE0286EC0E -:100EC00090E09093E1028093E00284E08093E2025C -:100ED00083E08093E30287E08093E40285E08093DF -:100EE000E50281E08093E6020895FC01608341837E -:100EF00080E2828313820895FC01808160E00E9479 -:100F0000CD080895FF920F931F938C01F62E80E079 -:100F10000E94650985E00E946A09F80181816F2DB0 -:100F20000E94CD081F910F91FF9008951F93CF93BA -:100F3000DF93EC0160E070E00E94820781EE8EBDDD -:100F40000DB407FEFDCF1EB5CE0161E070E00E943A -:100F50008207812FDF91CF911F9108951F93CF9327 -:100F6000DF93EC0160E070E00E94820782EE8EBDAC -:100F70000DB407FEFDCF1EB5CE0161E070E00E940A -:100F80008207812FDF91CF911F9108950F931F93B7 -:100F9000CF93DF93EC01162F042F60E070E00E94E6 -:100FA00082071F7110621EBD0DB407FEFDCF1EB576 -:100FB0000EBD0DB407FEFDCF8EB5CE0161E070E031 -:100FC0000E948207812FDF91CF911F910F91089589 -:100FD000662319F061E04FE302C061E040E00E9447 -:100FE000C6070895462F603808F04FE765E00E9475 -:100FF000C6070895EF92FF920F931F93CF93DF934D -:101000007C01162FEA01022F60E070E00E94820747 -:101010001F7110621EBD0DB407FEFDCF1EB508C0C6 -:1010200088818EBD0DB407FEFDCF21968EB501508F -:101030000023B1F7C70161E070E00E948207812FB1 -:10104000DF91CF911F910F91FF90EF9008951F9323 -:10105000CF93DF93EC01162F60E070E00E948207CF -:101060001F711EBD0DB407FEFDCF8EB58FEF8EBD77 -:101070000DB407FEFDCF1EB5CE0161E070E00E9409 -:101080008207812FDF91CF911F91089569E00E941F -:101090002708817008950F931F938C01FC018081B4 -:1010A00061E00E94A708F801818161E00E94A70821 -:1010B000F801808160E00E94CD08C80161E070E025 -:1010C0000E9482070E947B0981E00E945C0980E007 -:1010D0000E94650985E00E946A09C80164E04FEF3B -:1010E0000E94C607C80167E040E70E94C607C80122 -:1010F0000E94AE07C8010E949607C80161E00E94E5 -:10110000F2071F910F9108950F931F938C0160E0D8 -:101110004BE00E94C607C80167E040E70E94C6078F -:10112000A8014B5F5F4FC8016AE025E00E94FA0703 -:10113000C8010E94AE07F801808161E00E94CD08DD -:1011400082E890E00E94D7051F910F910895482FE3 -:1011500050E0CA0186569F4FFC0124914A575F4FC9 -:10116000FA0184918823C1F0E82FF0E0EE0FFF1F11 -:10117000E859FF4FA591B491662341F49FB7F894C5 -:101180008C91209582238C939FBF08959FB7F894EC -:101190008C91822B8C939FBF0895482F50E0CA01F9 -:1011A00082559F4FFC012491CA0186569F4FFC0136 -:1011B00034914A575F4FFA019491992309F444C03E -:1011C000222351F1233071F0243028F42130A1F092 -:1011D000223011F514C02630B1F02730C1F0243090 -:1011E000D9F404C0809180008F7703C08091800083 -:1011F0008F7D8093800010C084B58F7702C084B546 -:101200008F7D84BD09C08091B0008F7703C080912D -:10121000B0008F7D8093B000E92FF0E0EE0FFF1F4C -:10122000EE58FF4FA591B491662341F49FB7F8940F -:101230008C91309583238C939FBF08959FB7F8942A -:101240008C91832B8C939FBF08950F931F93CF9303 -:10125000DF938C01EB0109C02196D801ED91FC913F -:101260000190F081E02DC801099568816623A1F7FE -:10127000DF91CF911F910F910895EF92FF920F93FD -:101280001F93CF93DF938C017B01EA010CC0D70140 -:101290006D917D01D801ED91FC910190F081E02DDF -:1012A000C80109952197209791F7DF91CF911F9160 -:1012B0000F91FF90EF900895882319F48CB5806208 -:1012C00002C08CB58F7D8CBD08959CB5937F982B03 -:1012D0009CBD08952CB5382F33702C7F322B3CBD2C -:1012E0002DB590E0959587959595879581702E7F82 -:1012F000822B8DBD08958DE061E00E94A7088BE0F0 -:1013000061E00E94A7088AE061E00E94A7088DE0E2 -:1013100060E00E94CD088BE060E00E94CD088AE08A -:1013200061E00E94CD088CB580618CBD8CB5806475 -:101330008CBD0895A1E21A2EAA1BBB1BFD010DC096 -:10134000AA1FBB1FEE1FFF1FA217B307E407F50775 -:1013500020F0A21BB30BE40BF50B661F771F881F51 -:10136000991F1A9469F760957095809590959B01E7 -:10137000AC01BD01CF0108952F923F924F925F9231 -:101380006F927F928F929F92AF92BF92CF92DF9295 -:10139000EF92FF920F931F93CF93DF93CDB7DEB7FA -:1013A000CA1BDB0B0FB6F894DEBF0FBECDBF09948E -:1013B0002A88398848885F846E847D848C849B84E5 -:1013C000AA84B984C884DF80EE80FD800C811B81F3 -:1013D000AA81B981CE0FD11D0FB6F894DEBF0FBE22 -:1013E000CDBFED010895EE0FFF1F0590F491E02DA4 -:0613F0000994F894FFCF00 -:1013F6002578000A0D000A0D524632342F657861B1 -:101406006D706C65732F7363616E6E65722F0A0D56 -:10141600002000F102000000000000280725093D19 -:0A14260009CD06F806DE061C0700DB -:00000001FF diff --git a/examples/scanner/printf.h b/examples/scanner/printf.h deleted file mode 100644 index 66f64384..00000000 --- a/examples/scanner/printf.h +++ /dev/null @@ -1,31 +0,0 @@ -/* - Copyright (C) 2011 J. Coliz - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - version 2 as published by the Free Software Foundation. - */ - -/** - * @file printf.h - * - * Setup necessary to direct stdout to the Arduino Serial library, which - * enables 'printf' - */ - -#ifndef __PRINTF_H__ -#define __PRINTF_H__ - -int serial_putc( char c, FILE * ) -{ - Serial.write( c ); - - return c; -} - -void printf_begin(void) -{ - fdevopen( &serial_putc, 0 ); -} - -#endif // __PRINTF_H__ diff --git a/examples/scanner/scanner.pde b/examples/scanner/scanner.pde deleted file mode 100644 index 1a43d728..00000000 --- a/examples/scanner/scanner.pde +++ /dev/null @@ -1,124 +0,0 @@ -/* - Copyright (C) 2011 J. Coliz - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - version 2 as published by the Free Software Foundation. - */ - -/** - * Channel scanner - * - * Example to detect interference on the various channels available. - * This is a good diagnostic tool to check whether you're picking a - * good channel for your application. - * - * Inspired by cpixip. - * See http://arduino.cc/forum/index.php/topic,54795.0.html - */ - -#include -#include "nRF24L01.h" -#include "RF24.h" -#include "printf.h" - -// -// Hardware configuration -// - -// Set up nRF24L01 radio on SPI bus plus pins 9 & 10 - -RF24 radio(9,10); - -// -// Channel info -// - -const uint8_t num_channels = 128; -uint8_t values[num_channels]; - -// -// Setup -// - -void setup(void) -{ - // - // Print preamble - // - - Serial.begin(57600); - printf_begin(); - printf("\n\rRF24/examples/scanner/\n\r"); - - // - // Setup and configure rf radio - // - - radio.begin(); - radio.setAutoAck(false); - - // Get into standby mode - radio.startListening(); - radio.stopListening(); - - // Print out header, high then low digit - int i = 0; - while ( i < num_channels ) - { - printf("%x",i>>4); - ++i; - } - printf("\n\r"); - i = 0; - while ( i < num_channels ) - { - printf("%x",i&0xf); - ++i; - } - printf("\n\r"); -} - -// -// Loop -// - -const int num_reps = 100; - -void loop(void) -{ - // Clear measurement values - memset(values,0,sizeof(values)); - - // Scan all channels num_reps times - int rep_counter = num_reps; - while (rep_counter--) - { - int i = num_channels; - while (i--) - { - // Select this channel - radio.setChannel(i); - - // Listen for a little - radio.startListening(); - delayMicroseconds(128); - radio.stopListening(); - - // Did we get a carrier? - if ( radio.testCarrier() ) - ++values[i]; - } - } - - // Print out channel measurements, clamped to a single hex digit - int i = 0; - while ( i < num_channels ) - { - printf("%x",min(0xf,values[i]&0xf)); - ++i; - } - printf("\n\r"); -} - -// vim:ai:cin:sts=2 sw=2 ft=cpp diff --git a/examples/starping/Jamfile b/examples/starping/Jamfile deleted file mode 100644 index de9b1f67..00000000 --- a/examples/starping/Jamfile +++ /dev/null @@ -1,206 +0,0 @@ -PROJECT_NAME = $(PWD:B) ; -PROJECT_DIR = . ; -PROJECT_LIBS = EEPROM SPI RF24 ; - -OUT_DIR = ojam ; -F_CPU = 16000000 ; -MCU = atmega328p ; -PORTS = /dev/tty.usbserial-A600eHIs /dev/tty.usbserial-A40081RP /dev/tty.usbserial-A9007LmI ; - -UPLOAD_RATE = 57600 ; -AVRDUDE_PROTOCOL = stk500v1 ; -COM = 33 ; - -# Host-specific overrides for locations -if $(OS) = MACOSX -{ -ARDUINO_VERSION = 22 ; -OLD_DIR = /opt/arduino-0021 ; -AVR_TOOLS_PATH = $(OLD_DIR)/hardware/tools/avr/bin ; -AVRDUDECONFIG_PATH = $(OLD_DIR)/hardware/tools/avr/etc ; -ARDUINO_DIR = /opt/Arduino ; -ARDUINO_AVR = /usr/lib/avr/include ; -} - -# Where is everything? -ARDUINO_VERSION ?= 22 ; -AVR_TOOLS_PATH ?= /usr/bin ; -ARDUINO_DIR ?= /opt/arduino-00$(ARDUINO_VERSION) ; -ARDUINO_AVR ?= $(ARDUINO_DIR)/hardware/tools/avr/avr/include/avr ; -AVRDUDECONFIG_PATH ?= $(ARDUINO_DIR)/hardware/tools ; -ARDUINO_CORE = $(ARDUINO_DIR)/hardware/arduino/cores/arduino ; -ARDUINO_LIB = $(ARDUINO_DIR)/libraries ; -SKETCH_LIB = $(HOME)/Source/Arduino/libraries ; -AVR_CC = $(AVR_TOOLS_PATH)/avr-gcc ; -AVR_CXX = $(AVR_TOOLS_PATH)/avr-g++ ; -AVR_LD = $(AVR_TOOLS_PATH)/avr-gcc ; -AVR_OBJCOPY = $(AVR_TOOLS_PATH)/avr-objcopy ; -AVRDUDE = $(AVR_TOOLS_PATH)/avrdude ; - -DEFINES = F_CPU=$(F_CPU)L ARDUINO=$(ARDUINO_VERSION) VERSION_H ; -CTUNING = -ffunction-sections -fdata-sections ; -CXXTUNING = -fno-exceptions -fno-strict-aliasing ; -CFLAGS = -Os -Wall -Wextra -mmcu=$(MCU) $(CTUNING) ; -CXXFLAGS = $(CFLAGS) $(CXXTUNING) ; -LDFLAGS = -Os -lm -Wl,--gc-sections -mmcu=atmega328p ; - -# Search everywhere for headers -HDRS = $(PROJECT_DIR) $(ARDUINO_AVR) $(ARDUINO_CORE) [ GLOB $(ARDUINO_LIB) $(SKETCH_LIB) : [^.]* ] ; - -# Grab everything from the core directory -CORE_MODULES = [ GLOB $(ARDUINO_CORE) : *.c *.cpp ] ; - -# Grab everything from libraries. To avoid this "grab everything" behaviour, you -# can specify specific modules to pick up in PROJECT_MODULES -LIB_MODULES = [ GLOB $(ARDUINO_LIB)/$(PROJECT_LIBS) $(SKETCH_LIB)/$(PROJECT_LIBS) : *.cpp ] ; - -# In addition to explicitly-specified program modules, pick up anything from the current -# dir. -PROJECT_MODULES += [ GLOB $(PROJECT_DIR) : *.c *.cpp *.pde ] ; - -# Shortcut for the out files -OUT = $(OUT_DIR)/$(PROJECT_NAME) ; - -# AvrDude setup -AVRDUDE_FLAGS = -V -F -D -C $(AVRDUDECONFIG_PATH)/avrdude.conf -p $(MCU) -c $(AVRDUDE_PROTOCOL) -b $(UPLOAD_RATE) ; - -rule GitVersion -{ - Always $(<) ; - Depends all : $(<) ; -} - -actions GitVersion -{ - echo "const char program_version[] = \"\\" > $(<) - git log -1 --pretty=format:%h >> $(<) - echo "\";" >> $(<) -} - -GitVersion version.h ; - -rule AvrCc -{ - Depends $(<) : $(>) ; - Depends $(<) : $(<:D) ; - Clean clean : $(<) ; - - CCHDRS on $(<) = [ on $(<) FIncludes $(HDRS) ] ; - CCDEFS on $(<) = [ on $(<) FDefines $(DEFINES) ] ; -} - -actions AvrCc -{ - $(AVR_CC) -c -o $(<) $(CCHDRS) $(CCDEFS) $(CFLAGS) $(>) -} - -rule AvrC++ -{ - Depends $(<) : $(>) ; - Depends $(<) : $(<:D) ; - Clean clean : $(<) ; - - CCHDRS on $(<) = [ on $(<) FIncludes $(HDRS) ] ; - CCDEFS on $(<) = [ on $(<) FDefines $(DEFINES) ] ; -} - -actions AvrC++ -{ - $(AVR_CXX) -c -o $(<) $(CCHDRS) $(CCDEFS) $(CXXFLAGS) $(>) -} - -rule Pde -{ - Depends $(<) : $(>) ; - Depends $(<) : $(<:D) ; - Clean clean : $(<) ; - -} - -actions Pde -{ - echo "#include " > $(<) - echo "#line 1 \"$(>)\"" >> $(<) - cat $(>) >> $(<) -} - -rule AvrPde -{ - local _CPP = $(OUT_DIR)/$(_I:B).cpp ; - Pde $(_CPP) : $(>) ; - AvrC++ $(<) : $(_CPP) ; -} - -rule AvrObject -{ - switch $(>:S) - { - case .c : AvrCc $(<) : $(>) ; - case .cpp : AvrC++ $(<) : $(>) ; - case .pde : AvrPde $(<) : $(>) ; - } -} - -rule AvrObjects -{ - for _I in $(<) - { - AvrObject $(OUT_DIR)/$(_I:B).o : $(_I) ; - } -} - -rule AvrMainFromObjects -{ - Depends $(<) : $(>) ; - Depends $(<) : $(<:D) ; - MkDir $(<:D) ; - Depends all : $(<) ; - Clean clean : $(<) ; -} - -actions AvrMainFromObjects -{ - $(AVR_LD) $(LDFLAGS) -o $(<) $(>) -} - -rule AvrMain -{ - AvrMainFromObjects $(<) : $(OUT_DIR)/$(>:B).o ; - AvrObjects $(>) ; -} - -rule AvrHex -{ - Depends $(<) : $(>) ; - Depends $(<) : $(<:D) ; - Depends hex : $(<) ; - Clean clean : $(<) ; -} - -actions AvrHex -{ - $(AVR_OBJCOPY) -O ihex -R .eeprom $(>) $(<) -} - -rule AvrUpload -{ - Depends $(1) : $(2) ; - Depends $(2) : $(3) ; - NotFile $(1) ; - Always $(1) ; - Always $(2) ; - AvrUploadAction $(2) : $(3) ; -} - -actions AvrUploadAction -{ - $(AVRDUDE) $(AVRDUDE_FLAGS) -P $(<) $(AVRDUDE_WRITE_FLASH) -U flash:w:$(>):i -} - -AvrMain $(OUT).elf : $(CORE_MODULES) $(LIB_MODULES) $(PROJECT_MODULES) ; -AvrHex $(OUT).hex : $(OUT).elf ; - -AvrUpload p6 : /dev/tty.usbserial-A600eHIs : $(OUT).hex ; -AvrUpload p4 : /dev/tty.usbserial-A40081RP : $(OUT).hex ; -AvrUpload p9 : /dev/tty.usbserial-A9007LmI : $(OUT).hex ; - diff --git a/examples/starping/printf.h b/examples/starping/printf.h deleted file mode 100644 index b2efd56b..00000000 --- a/examples/starping/printf.h +++ /dev/null @@ -1,37 +0,0 @@ -/* - Copyright (C) 2011 J. Coliz - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - version 2 as published by the Free Software Foundation. - */ - -/** - * @file printf.h - * - * Setup necessary to direct stdout to the Arduino Serial library, which - * enables 'printf' - */ - -#ifndef __PRINTF_H__ -#define __PRINTF_H__ - -#ifdef ARDUINO - -int serial_putc( char c, FILE * ) -{ - Serial.write( c ); - - return c; -} - -void printf_begin(void) -{ - fdevopen( &serial_putc, 0 ); -} - -#else -#error This example is only for use on Arduino. -#endif // ARDUINO - -#endif // __PRINTF_H__ diff --git a/examples/starping/starping.pde b/examples/starping/starping.pde deleted file mode 100644 index 4813a779..00000000 --- a/examples/starping/starping.pde +++ /dev/null @@ -1,293 +0,0 @@ -/* - Copyright (C) 2011 J. Coliz - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - version 2 as published by the Free Software Foundation. - */ - -/** - * Example RF Radio Ping Star Group - * - * This sketch is a more complex example of using the RF24 library for Arduino. - * Deploy this on up to six nodes. Set one as the 'pong receiver' by tying the - * role_pin low, and the others will be 'ping transmit' units. The ping units - * unit will send out the value of millis() once a second. The pong unit will - * respond back with a copy of the value. Each ping unit can get that response - * back, and determine how long the whole cycle took. - * - * This example requires a bit more complexity to determine which unit is which. - * The pong receiver is identified by having its role_pin tied to ground. - * The ping senders are further differentiated by a byte in eeprom. - */ - -#include -#include -#include "nRF24L01.h" -#include "RF24.h" -#include "printf.h" - -// -// Hardware configuration -// - -// Set up nRF24L01 radio on SPI bus plus pins 9 & 10 - -RF24 radio(9,10); - -// sets the role of this unit in hardware. Connect to GND to be the 'pong' receiver -// Leave open to be the 'pong' receiver. -const int role_pin = 7; - -// -// Topology -// - -// Radio pipe addresses for the nodes to communicate. Only ping nodes need -// dedicated pipes in this topology. Each ping node has a talking pipe -// that it will ping into, and a listening pipe that it will listen for -// the pong. The pong node listens on all the ping node talking pipes -// and sends the pong back on the sending node's specific listening pipe. - -const uint64_t talking_pipes[5] = { 0xF0F0F0F0D2LL, 0xF0F0F0F0C3LL, 0xF0F0F0F0B4LL, 0xF0F0F0F0A5LL, 0xF0F0F0F096LL }; -const uint64_t listening_pipes[5] = { 0x3A3A3A3AD2LL, 0x3A3A3A3AC3LL, 0x3A3A3A3AB4LL, 0x3A3A3A3AA5LL, 0x3A3A3A3A96LL }; - -// -// Role management -// -// Set up role. This sketch uses the same software for all the nodes -// in this system. Doing so greatly simplifies testing. The hardware itself specifies -// which node it is. -// -// This is done through the role_pin -// - -// The various roles supported by this sketch -typedef enum { role_invalid = 0, role_ping_out, role_pong_back } role_e; - -// The debug-friendly names of those roles -const char* role_friendly_name[] = { "invalid", "Ping out", "Pong back"}; - -// The role of the current running sketch -role_e role; - -// -// Address management -// - -// Where in EEPROM is the address stored? -const uint8_t address_at_eeprom_location = 0; - -// What is our address (SRAM cache of the address from EEPROM) -// Note that zero is an INVALID address. The pong back unit takes address -// 1, and the rest are 2-6 -uint8_t node_address; - -void setup(void) -{ - // - // Role - // - - // set up the role pin - pinMode(role_pin, INPUT); - digitalWrite(role_pin,HIGH); - delay(20); // Just to get a solid reading on the role pin - - // read the address pin, establish our role - if ( digitalRead(role_pin) ) - role = role_ping_out; - else - role = role_pong_back; - - // - // Address - // - - if ( role == role_pong_back ) - node_address = 1; - else - { - // Read the address from EEPROM - uint8_t reading = EEPROM.read(address_at_eeprom_location); - - // If it is in a valid range for node addresses, it is our - // address. - if ( reading >= 2 && reading <= 6 ) - node_address = reading; - - // Otherwise, it is invalid, so set our address AND ROLE to 'invalid' - else - { - node_address = 0; - role = role_invalid; - } - } - - // - // Print preamble - // - - Serial.begin(57600); - printf_begin(); - printf("\n\rRF24/examples/starping/\n\r"); - printf("ROLE: %s\n\r",role_friendly_name[role]); - printf("ADDRESS: %i\n\r",node_address); - - // - // Setup and configure rf radio - // - - radio.begin(); - - // - // Open pipes to other nodes for communication - // - - // The pong node listens on all the ping node talking pipes - // and sends the pong back on the sending node's specific listening pipe. - if ( role == role_pong_back ) - { - radio.openReadingPipe(1,talking_pipes[0]); - radio.openReadingPipe(2,talking_pipes[1]); - radio.openReadingPipe(3,talking_pipes[2]); - radio.openReadingPipe(4,talking_pipes[3]); - radio.openReadingPipe(5,talking_pipes[4]); - } - - // Each ping node has a talking pipe that it will ping into, and a listening - // pipe that it will listen for the pong. - if ( role == role_ping_out ) - { - // Write on our talking pipe - radio.openWritingPipe(talking_pipes[node_address-2]); - // Listen on our listening pipe - radio.openReadingPipe(1,listening_pipes[node_address-2]); - } - - // - // Start listening - // - - radio.startListening(); - - // - // Dump the configuration of the rf unit for debugging - // - - radio.printDetails(); - - // - // Prompt the user to assign a node address if we don't have one - // - - if ( role == role_invalid ) - { - printf("\n\r*** NO NODE ADDRESS ASSIGNED *** Send 1 through 6 to assign an address\n\r"); - } -} - -void loop(void) -{ - // - // Ping out role. Repeatedly send the current time - // - - if (role == role_ping_out) - { - // First, stop listening so we can talk. - radio.stopListening(); - - // Take the time, and send it. This will block until complete - unsigned long time = millis(); - printf("Now sending %lu...",time); - radio.write( &time, sizeof(unsigned long) ); - - // Now, continue listening - radio.startListening(); - - // Wait here until we get a response, or timeout (250ms) - unsigned long started_waiting_at = millis(); - bool timeout = false; - while ( ! radio.available() && ! timeout ) - if (millis() - started_waiting_at > 250 ) - timeout = true; - - // Describe the results - if ( timeout ) - { - printf("Failed, response timed out.\n\r"); - } - else - { - // Grab the response, compare, and send to debugging spew - unsigned long got_time; - radio.read( &got_time, sizeof(unsigned long) ); - - // Spew it - printf("Got response %lu, round-trip delay: %lu\n\r",got_time,millis()-got_time); - } - - // Try again 1s later - delay(1000); - } - - // - // Pong back role. Receive each packet, dump it out, and send it back - // - - if ( role == role_pong_back ) - { - // if there is data ready - uint8_t pipe_num; - if ( radio.available(&pipe_num) ) - { - // Dump the payloads until we've gotten everything - unsigned long got_time; - bool done = false; - while (!done) - { - // Fetch the payload, and see if this was the last one. - done = radio.read( &got_time, sizeof(unsigned long) ); - - // Spew it - printf("Got payload %lu from node %i...",got_time,pipe_num+1); - } - - // First, stop listening so we can talk - radio.stopListening(); - - // Open the correct pipe for writing - radio.openWritingPipe(listening_pipes[pipe_num-1]); - - // Retain the low 2 bytes to identify the pipe for the spew - uint16_t pipe_id = listening_pipes[pipe_num-1] & 0xffff; - - // Send the final one back. - radio.write( &got_time, sizeof(unsigned long) ); - printf("Sent response to %04x.\n\r",pipe_id); - - // Now, resume listening so we catch the next packets. - radio.startListening(); - } - } - - // - // Listen for serial input, which is how we set the address - // - if (Serial.available()) - { - // If the character on serial input is in a valid range... - char c = Serial.read(); - if ( c >= '1' && c <= '6' ) - { - // It is our address - EEPROM.write(address_at_eeprom_location,c-'0'); - - // And we are done right now (no easy way to soft reset) - printf("\n\rManually reset address to: %c\n\rPress RESET to continue!",c); - while(1) ; - } - } -} -// vim:ai:ci sts=2 sw=2 ft=cpp diff --git a/nRF24L01.h b/nRF24L01.h deleted file mode 100644 index 2012ce6e..00000000 --- a/nRF24L01.h +++ /dev/null @@ -1,125 +0,0 @@ -/* - Copyright (c) 2007 Stefan Engelke - - Permission is hereby granted, free of charge, to any person - obtaining a copy of this software and associated documentation - files (the "Software"), to deal in the Software without - restriction, including without limitation the rights to use, copy, - modify, merge, publish, distribute, sublicense, and/or sell copies - of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be - included in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT - HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, - WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - DEALINGS IN THE SOFTWARE. -*/ - -/* Memory Map */ -#define CONFIG 0x00 -#define EN_AA 0x01 -#define EN_RXADDR 0x02 -#define SETUP_AW 0x03 -#define SETUP_RETR 0x04 -#define RF_CH 0x05 -#define RF_SETUP 0x06 -#define STATUS 0x07 -#define OBSERVE_TX 0x08 -#define CD 0x09 -#define RX_ADDR_P0 0x0A -#define RX_ADDR_P1 0x0B -#define RX_ADDR_P2 0x0C -#define RX_ADDR_P3 0x0D -#define RX_ADDR_P4 0x0E -#define RX_ADDR_P5 0x0F -#define TX_ADDR 0x10 -#define RX_PW_P0 0x11 -#define RX_PW_P1 0x12 -#define RX_PW_P2 0x13 -#define RX_PW_P3 0x14 -#define RX_PW_P4 0x15 -#define RX_PW_P5 0x16 -#define FIFO_STATUS 0x17 -#define DYNPD 0x1C -#define FEATURE 0x1D - -/* Bit Mnemonics */ -#define MASK_RX_DR 6 -#define MASK_TX_DS 5 -#define MASK_MAX_RT 4 -#define EN_CRC 3 -#define CRCO 2 -#define PWR_UP 1 -#define PRIM_RX 0 -#define ENAA_P5 5 -#define ENAA_P4 4 -#define ENAA_P3 3 -#define ENAA_P2 2 -#define ENAA_P1 1 -#define ENAA_P0 0 -#define ERX_P5 5 -#define ERX_P4 4 -#define ERX_P3 3 -#define ERX_P2 2 -#define ERX_P1 1 -#define ERX_P0 0 -#define AW 0 -#define ARD 4 -#define ARC 0 -#define PLL_LOCK 4 -#define RF_DR 3 -#define RF_PWR 6 -#define RX_DR 6 -#define TX_DS 5 -#define MAX_RT 4 -#define RX_P_NO 1 -#define TX_FULL 0 -#define PLOS_CNT 4 -#define ARC_CNT 0 -#define TX_REUSE 6 -#define FIFO_FULL 5 -#define TX_EMPTY 4 -#define RX_FULL 1 -#define RX_EMPTY 0 -#define DPL_P5 5 -#define DPL_P4 4 -#define DPL_P3 3 -#define DPL_P2 2 -#define DPL_P1 1 -#define DPL_P0 0 -#define EN_DPL 2 -#define EN_ACK_PAY 1 -#define EN_DYN_ACK 0 - -/* Instruction Mnemonics */ -#define R_REGISTER 0x00 -#define W_REGISTER 0x20 -#define REGISTER_MASK 0x1F -#define ACTIVATE 0x50 -#define R_RX_PL_WID 0x60 -#define R_RX_PAYLOAD 0x61 -#define W_TX_PAYLOAD 0xA0 -#define W_ACK_PAYLOAD 0xA8 -#define FLUSH_TX 0xE1 -#define FLUSH_RX 0xE2 -#define REUSE_TX_PL 0xE3 -#define NOP 0xFF - -/* Non-P omissions */ -#define LNA_HCURR 0 - -/* P model memory Map */ -#define RPD 0x09 - -/* P model bit Mnemonics */ -#define RF_DR_LOW 5 -#define RF_DR_HIGH 3 -#define RF_PWR_LOW 1 -#define RF_PWR_HIGH 2 diff --git a/tests/README b/tests/README deleted file mode 100644 index 43ceaf54..00000000 --- a/tests/README +++ /dev/null @@ -1,7 +0,0 @@ -The sketches in this directory are intended to be checkin tests. -No code should be pushed to github without these tests passing. - -See "runtests.sh" script inside each sketch dir. This script is fully compatible with -git bisest. - -Note that this requires python and py-serial diff --git a/tests/native/Jamfile b/tests/native/Jamfile deleted file mode 100644 index 10d0336c..00000000 --- a/tests/native/Jamfile +++ /dev/null @@ -1,300 +0,0 @@ -PROJECT_NAME = $(PWD:B) ; -PROJECT_DIR = . ; -PROJECT_LIBS = RF24 ; - -OUT_DIR = ojam ; -F_CPU = 16000000 ; -MCU = atmega328p ; -PORTS = /dev/tty.usbserial-A600eHIs /dev/tty.usbserial-A40081RP /dev/tty.usbserial-A9007LmI ; - -UPLOAD_RATE = 57600 ; -AVRDUDE_PROTOCOL = stk500v1 ; -COM = 33 ; - -# Host-specific overrides for locations -if $(OS) = MACOSX -{ -ARDUINO_VERSION = 22 ; -OLD_DIR = /opt/arduino-0021 ; -AVR_TOOLS_PATH = $(OLD_DIR)/hardware/tools/avr/bin ; -AVRDUDECONFIG_PATH = $(OLD_DIR)/hardware/tools/avr/etc ; -ARDUINO_DIR = /opt/Arduino ; -ARDUINO_AVR = /usr/lib/avr/include ; -} - -# Where is everything? -ARDUINO_VERSION ?= 22 ; -SKETCH_DIR = $(HOME)/Source/Arduino ; -AVR_TOOLS_PATH ?= /usr/bin ; -ARDUINO_DIR ?= /opt/arduino-00$(ARDUINO_VERSION) ; -ARDUINO_AVR ?= $(ARDUINO_DIR)/hardware/tools/avr/avr/include/avr ; -AVRDUDECONFIG_PATH ?= $(ARDUINO_DIR)/hardware/tools ; -ARDUINO_CORE = $(ARDUINO_DIR)/hardware/arduino/cores/arduino ; -ARDUINO_LIB = $(ARDUINO_DIR)/libraries ; -SKETCH_LIB = $(SKETCH_DIR)/libraries ; -AVR_AS = $(AVR_TOOLS_PATH)/avr-as ; -AVR_CC = $(AVR_TOOLS_PATH)/avr-gcc ; -AVR_CXX = $(AVR_TOOLS_PATH)/avr-g++ ; -AVR_LD = $(AVR_TOOLS_PATH)/avr-gcc ; -AVR_OBJCOPY = $(AVR_TOOLS_PATH)/avr-objcopy ; -AVRDUDE = $(AVR_TOOLS_PATH)/avrdude ; - -DEFINES = F_CPU=$(F_CPU)L ARDUINO=$(ARDUINO_VERSION) VERSION_H HAL=1 ; -CTUNING = -ffunction-sections -fdata-sections ; -CXXTUNING = -fno-exceptions -fno-strict-aliasing ; -ASFLAGS = -mmcu=$(MCU) ; -CFLAGS = -Os -Wall -Wextra $(ASFLAGS) $(CTUNING) ; -CXXFLAGS = $(CFLAGS) $(CXXTUNING) ; -LDFLAGS = -Os -lm -Wl,--gc-sections -mmcu=atmega328p ; - -# Search everywhere for headers -HDRS = $(PROJECT_DIR) $(ARDUINO_AVR) $(ARDUINO_CORE) [ GLOB $(ARDUINO_LIB) $(SKETCH_LIB) : [^.]* ] ; -HDRS += [ GLOB $(HDRS) : utility ] ; - -# Grab everything from the core directory -CORE_MODULES = [ GLOB $(ARDUINO_CORE) : *.c *.cpp ] ; - -# Grab everything from libraries. To avoid this "grab everything" behaviour, you -# can specify specific modules to pick up in PROJECT_MODULES -LIB_MODULES = [ GLOB $(ARDUINO_LIB)/$(PROJECT_LIBS) $(ARDUINO_LIB)/$(PROJECT_LIBS)/utility $(SKETCH_LIB)/$(PROJECT_LIBS) : *.cpp *.c ] ; - -# In addition to explicitly-specified program modules, pick up anything from the current -# dir. -PROJECT_MODULES += [ GLOB $(PROJECT_DIR) : *.c *.cpp *.pde ] ; - -# Shortcut for the out files -OUT = $(OUT_DIR)/$(PROJECT_NAME) ; - -# AvrDude setup -AVRDUDE_FLAGS = -V -F -D -C $(AVRDUDECONFIG_PATH)/avrdude.conf -p $(MCU) -c $(AVRDUDE_PROTOCOL) -b $(UPLOAD_RATE) ; - -rule GitVersion -{ - Always $(<) ; - Depends all : $(<) ; -} - -actions GitVersion -{ - echo "const char program_version[] = \"\\" > $(<) - git log -1 --pretty=format:%h >> $(<) - echo "\";" >> $(<) -} - -# GitVersion version.h ; - -rule AvrAsm -{ - Depends $(<) : $(>) ; - Depends $(<) : $(<:D) ; - Clean clean : $(<) ; - - CCHDRS on $(<) = [ on $(<) FIncludes $(HDRS) ] ; - CCDEFS on $(<) = [ on $(<) FDefines $(DEFINES) ] ; -} - -actions AvrAsm -{ - $(AVR_AS) $(ASFLAGS) -o $(<) $(>) -} - -rule AvrCc -{ - Depends $(<) : $(>) ; - Depends $(<) : $(<:D) ; - Clean clean : $(<) ; - - CCHDRS on $(<) = [ on $(<) FIncludes $(HDRS) ] ; - CCDEFS on $(<) = [ on $(<) FDefines $(DEFINES) ] ; -} - -actions AvrCc -{ - $(AVR_CC) -c -o $(<) $(CCHDRS) $(CCDEFS) $(CFLAGS) $(>) -} - -rule AvrC++ -{ - Depends $(<) : $(>) ; - Depends $(<) : $(<:D) ; - Clean clean : $(<) ; - - CCHDRS on $(<) = [ on $(<) FIncludes $(HDRS) ] ; - CCDEFS on $(<) = [ on $(<) FDefines $(DEFINES) ] ; -} - -actions AvrC++ -{ - $(AVR_CXX) -c -o $(<) $(CCHDRS) $(CCDEFS) $(CXXFLAGS) $(>) -} - -rule AvrAsmFromC++ -{ - Depends $(<) : $(>) ; - Depends $(<) : $(<:D) ; - Clean clean : $(<) ; - - CCHDRS on $(<) = [ on $(<) FIncludes $(HDRS) ] ; - CCDEFS on $(<) = [ on $(<) FDefines $(DEFINES) ] ; -} - -actions AvrAsmFromC++ -{ - $(AVR_CXX) -S -fverbose-asm -o $(<) $(CCHDRS) $(CCDEFS) $(CXXFLAGS) $(>) -} - -rule Pde -{ - Depends $(<) : $(>) ; - Depends $(<) : $(<:D) ; - Clean clean : $(<) ; -} - -actions Pde -{ - echo "#include " > $(<) - echo "#line 1 \"$(>)\"" >> $(<) - cat $(>) >> $(<) -} - -rule AvrPde -{ - local _CPP = $(OUT_DIR)/$(_I:B).cpp ; - Pde $(_CPP) : $(>) ; - AvrC++ $(<) : $(_CPP) ; -} - -rule AvrObject -{ - switch $(>:S) - { - case .S : AvrAsm $(<) : $(>) ; - case .c : AvrCc $(<) : $(>) ; - case .cpp : AvrC++ $(<) : $(>) ; - case .pde : AvrPde $(<) : $(>) ; - } -} - -rule AvrObjects -{ - for _I in $(<) - { - AvrObject $(OUT_DIR)/$(_I:B).o : $(_I) ; - } -} - -rule AvrMainFromObjects -{ - Depends $(<) : $(>) ; - Depends $(<) : $(<:D) ; - MkDir $(<:D) ; - Depends all : $(<) ; - Clean clean : $(<) ; -} - -actions AvrMainFromObjects -{ - $(AVR_LD) $(LDFLAGS) -o $(<) $(>) -} - -rule AvrMain -{ - AvrMainFromObjects $(<) : $(OUT_DIR)/$(>:B).o ; - AvrObjects $(>) ; -} - -rule AvrHex -{ - Depends $(<) : $(>) ; - Depends $(<) : $(<:D) ; - Depends hex : $(<) ; - Clean clean : $(<) ; -} - -actions AvrHex -{ - $(AVR_OBJCOPY) -O ihex -R .eeprom $(>) $(<) -} - -rule AvrUpload -{ - Depends $(1) : $(2) ; - Depends $(2) : $(3) ; - NotFile $(1) ; - Always $(1) ; - Always $(2) ; - AvrUploadAction $(2) : $(3) ; -} - -actions AvrUploadAction -{ - $(AVRDUDE) $(AVRDUDE_FLAGS) -P $(<) $(AVRDUDE_WRITE_FLASH) -U flash:w:$(>):i -} - -AvrMain $(OUT).elf : $(CORE_MODULES) $(LIB_MODULES) $(PROJECT_MODULES) -AvrHex $(OUT).hex : $(OUT).elf ; - -AvrUpload p6 : /dev/tty.usbserial-A600eHIs : $(OUT).hex ; -AvrUpload p4 : /dev/tty.usbserial-A40081RP : $(OUT).hex ; -AvrUpload p9 : /dev/tty.usbserial-A9007LmI : $(OUT).hex ; - -# -# Native -# - -OUT_DIR_NATIVE = out_native ; -OUT_NATIVE = $(OUT_DIR_NATIVE)/$(PROJECT_NAME) ; -NATIVE_CORE = $(SKETCH_DIR)/hardware/native ; -HDRS = $(NATIVE_CORE) $(HDRS) ; -NATIVE_CORE_MODULES = [ GLOB $(NATIVE_CORE) : *.c *.cpp ] ; -NATIVE_MODULES = ; -DEFINES += NATIVE ; - -rule NativePde -{ - local _CPP = $(OUT_DIR_NATIVE)/$(_I:B).cpp ; - Pde $(_CPP) : $(>) ; - C++ $(<) : $(_CPP) ; -} - -rule UserObject -{ - switch $(>) - { - case *.pde : NativePde $(<) : $(>) ; - } -} - -rule Objects -{ - for _I in $(<) - { - local _O = $(OUT_DIR_NATIVE)/$(_I:B).o ; - Object $(_O) : $(_I) ; - } -} - -rule Main -{ - MainFromObjects $(<) : $(OUT_DIR_NATIVE)/$(>:B).o ; - Objects $(>) ; -} - -actions C++ -{ - c++ -c -o $(<) $(CCHDRS) $(CCDEFS) $(>) -} - -actions Link -{ - c++ -o $(<) $(>) -} - - - -MkDir $(OUT_DIR_NATIVE) ; -Depends $(OUT_NATIVE) : $(OUT_DIR_NATIVE) ; -Main $(OUT_NATIVE) : $(NATIVE_CORE_MODULES) $(NATIVE_MODULES) $(LIB_MODULES) $(PROJECT_MODULES) ; - -Depends native : $(OUT_NATIVE) ; - diff --git a/tests/native/pingpair_irq.pde b/tests/native/pingpair_irq.pde deleted file mode 100644 index 99c2cdf9..00000000 --- a/tests/native/pingpair_irq.pde +++ /dev/null @@ -1,223 +0,0 @@ -/* - Copyright (C) 2011 James Coliz, Jr. - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - version 2 as published by the Free Software Foundation. - */ - -/** - * Interrupt-driven test for native target - * - * This example is the friendliest for the native target because it doesn't do - * any polling. Made a slight change to call done() at the end of setup. - */ - -#include -#include "nRF24L01.h" -#include "RF24.h" -#include "printf.h" - -// -// Hardware configuration -// - -// Set up nRF24L01 radio on SPI bus plus pins 8 & 9 - -RF24 radio(8,9); - -// sets the role of this unit in hardware. Connect to GND to be the 'pong' receiver -// Leave open to be the 'ping' transmitter -const short role_pin = 7; - -// -// Topology -// - -// Single radio pipe address for the 2 nodes to communicate. -const uint64_t pipe = 0xE8E8F0F0E1LL; - -// -// Role management -// -// Set up role. This sketch uses the same software for all the nodes in this -// system. Doing so greatly simplifies testing. The hardware itself specifies -// which node it is. -// -// This is done through the role_pin -// - -// The various roles supported by this sketch -typedef enum { role_sender = 1, role_receiver } role_e; - -// The debug-friendly names of those roles -const char* role_friendly_name[] = { "invalid", "Sender", "Receiver"}; - -// The role of the current running sketch -role_e role; - -// Interrupt handler, check the radio because we got an IRQ -void check_radio(void); - -void setup(void) -{ - // - // Role - // - - // set up the role pin - pinMode(role_pin, INPUT); - digitalWrite(role_pin,HIGH); - delay(20); // Just to get a solid reading on the role pin - - // read the address pin, establish our role - if ( digitalRead(role_pin) ) - role = role_sender; - else - role = role_receiver; - - // - // Print preamble - // - - Serial.begin(57600); - printf_begin(); - printf("\n\rRF24/examples/pingpair_irq/\n\r"); - printf("ROLE: %s\n\r",role_friendly_name[role]); - - // - // Setup and configure rf radio - // - - radio.begin(); - - // We will be using the Ack Payload feature, so please enable it - radio.enableAckPayload(); - - // - // Open pipes to other nodes for communication - // - - // This simple sketch opens a single pipe for these two nodes to communicate - // back and forth. One listens on it, the other talks to it. - - if ( role == role_sender ) - { - radio.openWritingPipe(pipe); - } - else - { - radio.openReadingPipe(1,pipe); - } - - // - // Start listening - // - - if ( role == role_receiver ) - radio.startListening(); - - // - // Dump the configuration of the rf unit for debugging - // - - radio.printDetails(); - - // - // Attach interrupt handler to interrupt #0 (using pin 2) - // on BOTH the sender and receiver - // - - attachInterrupt(0, check_radio, FALLING); - - // - // On the native target, this is as far as we get - // -#if NATIVE - done(); -#endif -} - -static uint32_t message_count = 0; - -void loop(void) -{ - // - // Sender role. Repeatedly send the current time - // - - if (role == role_sender) - { - // Take the time, and send it. - unsigned long time = millis(); - printf("Now sending %lu\n\r",time); - radio.startWrite( &time, sizeof(unsigned long) ); - - // Try again soon - delay(2000); - } - - // - // Receiver role: Does nothing! All the work is in IRQ - // - -} - -void check_radio(void) -{ - // What happened? - bool tx,fail,rx; - radio.whatHappened(tx,fail,rx); - - // Have we successfully transmitted? - if ( tx ) - { - if ( role == role_sender ) - printf("Send:OK\n\r"); - - if ( role == role_receiver ) - printf("Ack Payload:Sent\n\r"); - } - - // Have we failed to transmit? - if ( fail ) - { - if ( role == role_sender ) - printf("Send:Failed\n\r"); - - if ( role == role_receiver ) - printf("Ack Payload:Failed\n\r"); - } - - // Transmitter can power down for now, because - // the transmission is done. - if ( ( tx || fail ) && ( role == role_sender ) ) - radio.powerDown(); - - // Did we receive a message? - if ( rx ) - { - // If we're the sender, we've received an ack payload - if ( role == role_sender ) - { - radio.read(&message_count,sizeof(message_count)); - printf("Ack:%lu\n\r",(unsigned long)message_count); - } - - // If we're the receiver, we've received a time message - if ( role == role_receiver ) - { - // Get this payload and dump it - static unsigned long got_time; - radio.read( &got_time, sizeof(got_time) ); - printf("Got payload %lu\n\r",got_time); - - // Add an ack packet for the next time around. This is a simple - // packet counter - radio.writeAckPayload( 1, &message_count, sizeof(message_count) ); - ++message_count; - } - } -} - -// vim:ai:cin:sts=2 sw=2 ft=cpp diff --git a/tests/native/printf.h b/tests/native/printf.h deleted file mode 100644 index df6c46ae..00000000 --- a/tests/native/printf.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - Copyright (C) 2011 James Coliz, Jr. - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - version 2 as published by the Free Software Foundation. - */ - -/** - * @file printf.h - * - * Setup necessary to direct stdout to the Arduino Serial library, which - * enables 'printf' - */ - -#ifndef __PRINTF_H__ -#define __PRINTF_H__ - -#include "WProgram.h" - -int serial_putc( char c, FILE * ) -{ - Serial.write( c ); - - return c; -} - -void printf_begin(void) -{ - fdevopen( &serial_putc, 0 ); -} - -#endif // __PRINTF_H__ diff --git a/tests/pingpair_blocking/Jamfile b/tests/pingpair_blocking/Jamfile deleted file mode 100644 index 18244ec8..00000000 --- a/tests/pingpair_blocking/Jamfile +++ /dev/null @@ -1,219 +0,0 @@ -# (1) Project Information - -PROJECT_LIBS = SPI RF24 ; -PROJECT_DIRS = $(PWD) ; - -# (2) Board Information - -UPLOAD_PROTOCOL ?= arduino ; -UPLOAD_SPEED ?= 115200 ; -MCU ?= atmega328p ; -F_CPU ?= 16000000 ; -CORE ?= arduino ; -VARIANT ?= standard ; -ARDUINO_VERSION ?= 100 ; - -# (3) USB Ports - -PORTS = p4 p6 p9 u0 u1 u2 ; -PORT_p6 = /dev/tty.usbserial-A600eHIs ; -PORT_p4 = /dev/tty.usbserial-A40081RP ; -PORT_p9 = /dev/tty.usbserial-A9007LmI ; -PORT_u0 = /dev/ttyUSB0 ; -PORT_u1 = /dev/ttyUSB1 ; -PORT_u2 = /dev/ttyUSB2 ; - -# (4) Location of AVR tools -# -# This configuration assumes using avr-tools that were obtained separate from the Arduino -# distribution. - -if $(OS) = MACOSX -{ - AVR_BIN ?= /usr/local/avrtools/bin ; - AVR_ETC = /usr/local/avrtools/etc ; - AVR_INCLUDE = /usr/local/avrtools/include ; -} -else -{ - AVR_BIN ?= /usr/bin ; - AVR_INCLUDE = /usr/lib/avr/include ; - AVR_ETC = /etc ; -} - -# (5) Directories where Arduino core and libraries are located - -ARDUINO_DIR ?= /opt/Arduino ; -ARDUINO_CORE = $(ARDUINO_DIR)/hardware/arduino/cores/$(CORE) $(ARDUINO_DIR)/hardware/arduino/variants/$(VARIANT) ; -ARDUINO_LIB = $(ARDUINO_DIR)/libraries ; -SKETCH_LIB = $(HOME)/Source/Arduino/libraries ; - -# -# -------------------------------------------------- -# Below this line usually never needs to be modified -# - -# Tool locations - -CC = $(AVR_BIN)/avr-gcc ; -C++ = $(AVR_BIN)/avr-g++ ; -LINK = $(AVR_BIN)/avr-gcc ; -AR = $(AVR_BIN)/avr-ar rcs ; -RANLIB = ; -OBJCOPY = $(AVR_BIN)/avr-objcopy ; -AVRDUDE ?= $(AVR_BIN)/avrdude ; - -# Flags - -DEFINES += F_CPU=$(F_CPU)L ARDUINO=$(ARDUINO_VERSION) VERSION_H ; -OPTIM = -Os ; -CCFLAGS = -Wall -Wextra -Wno-strict-aliasing -mmcu=$(MCU) -ffunction-sections -fdata-sections ; -C++FLAGS = $(CCFLAGS) -fno-exceptions -fno-strict-aliasing ; -LINKFLAGS = $(OPTIM) -lm -Wl,--gc-sections -mmcu=$(MCU) ; -AVRDUDEFLAGS = -V -F -D -C $(AVR_ETC)/avrdude.conf -p $(MCU) -c $(UPLOAD_PROTOCOL) -b $(UPLOAD_SPEED) ; - -# Search everywhere for headers - -HDRS = $(PROJECT_DIRS) $(AVR_INCLUDE) $(ARDUINO_CORE) $(ARDUINO_LIB)/$(PROJECT_LIBS) $(ARDUINO_LIB)/$(PROJECT_LIBS)/utility $(SKETCH_LIB)/$(PROJECT_LIBS) ; - -# Output locations - -LOCATE_TARGET = $(F_CPU) ; -LOCATE_SOURCE = $(F_CPU) ; - -# -# Custom rules -# - -rule GitVersion -{ - Always $(<) ; - Depends all : $(<) ; -} - -actions GitVersion -{ - echo "const char program_version[] = \"\\" > $(<) - git log -1 --pretty=format:%h >> $(<) - echo "\";" >> $(<) -} - -GitVersion version.h ; - -rule Pde -{ - Depends $(<) : $(>) ; - MakeLocate $(<) : $(LOCATE_SOURCE) ; - Clean clean : $(<) ; -} - -if ( $(ARDUINO_VERSION) < 100 ) -{ - ARDUINO_H = WProgram.h ; -} -else -{ - ARDUINO_H = Arduino.h ; -} - -actions Pde -{ - echo "#include <$(ARDUINO_H)>" > $(<) - echo "#line 1 \"$(>)\"" >> $(<) - cat $(>) >> $(<) -} - -rule C++Pde -{ - local _CPP = $(>:B).cpp ; - Pde $(_CPP) : $(>) ; - C++ $(<) : $(_CPP) ; -} - -rule UserObject -{ - switch $(>:S) - { - case .ino : C++Pde $(<) : $(>) ; - case .pde : C++Pde $(<) : $(>) ; - } -} - -rule Objects -{ - local _i ; - - for _i in [ FGristFiles $(<) ] - { - local _b = $(_i:B)$(SUFOBJ) ; - local _o = $(_b:G=$(SOURCE_GRIST:E)) ; - Object $(_o) : $(_i) ; - Depends obj : $(_o) ; - } -} - -rule Library -{ - LibraryFromObjects $(<) : $(>:B)$(SUFOBJ) ; - Objects $(>) ; -} - -rule Main -{ - MainFromObjects $(<) : $(>:B)$(SUFOBJ) ; - Objects $(>) ; -} - -rule Hex -{ - Depends $(<) : $(>) ; - MakeLocate $(<) : $(LOCATE_TARGET) ; - Depends hex : $(<) ; - Clean clean : $(<) ; -} - -actions Hex -{ - $(OBJCOPY) -O ihex -R .eeprom $(>) $(<) -} - -rule Upload -{ - Depends $(1) : $(2) ; - Depends $(2) : $(3) ; - NotFile $(1) ; - Always $(1) ; - Always $(2) ; - UploadAction $(2) : $(3) ; -} - -actions UploadAction -{ - $(AVRDUDE) $(AVRDUDEFLAGS) -P $(<) $(AVRDUDE_WRITE_FLASH) -U flash:w:$(>):i -} - -rule Arduino -{ - LINKFLAGS on $(<) = $(LINKFLAGS) -Wl,-Map=$(LOCATE_TARGET)/$(<:B).map ; - Main $(<) : $(>) ; - LinkLibraries $(<) : core libs ; - Hex $(<:B).hex : $(<) ; - for _p in $(PORTS) - { - Upload $(_p) : $(PORT_$(_p)) : $(<:B).hex ; - } -} - -# -# Targets -# - -# Grab everything from the core directory -Library core : [ GLOB $(ARDUINO_CORE) : *.c *.cpp ] ; - -# Grab everything from libraries. To avoid this "grab everything" behaviour, you -# can specify specific modules to pick up in PROJECT_MODULES -Library libs : [ GLOB $(ARDUINO_LIB)/$(PROJECT_LIBS) $(ARDUINO_LIB)/$(PROJECT_LIBS)/utility $(SKETCH_LIB)/$(PROJECT_LIBS) : *.cpp *.c ] ; - -# Main output executable -Arduino $(PWD:B).elf : $(PROJECT_MODULES) [ GLOB $(PROJECT_DIRS) : *.c *.cpp *.pde *.ino ] ; diff --git a/tests/pingpair_blocking/pingpair_blocking.pde b/tests/pingpair_blocking/pingpair_blocking.pde deleted file mode 100644 index 1501d37c..00000000 --- a/tests/pingpair_blocking/pingpair_blocking.pde +++ /dev/null @@ -1,273 +0,0 @@ -/* - Copyright (C) 2011 James Coliz, Jr. - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - version 2 as published by the Free Software Foundation. - */ - -#include -#include "nRF24L01.h" -#include "RF24.h" -#include "printf.h" - -// -// Test version of RF24, exposes some protected interface -// - -class RF24Test: public RF24 -{ -public: RF24Test(int a, int b): RF24(a,b) {} -}; - - -// -// Hardware configuration -// - -// Set up nRF24L01 radio on SPI bus plus pins 8 & 9 - -RF24Test radio(8,9); - -// sets the role of this unit in hardware. Connect to GND to be the 'pong' receiver -// Leave open to be the 'ping' transmitter -const int role_pin = 7; - -// -// Topology -// - -// Radio pipe addresses for the 2 nodes to communicate. -const uint64_t pipes[2] = { 0xF0F0F0F0E1LL, 0xF0F0F0F0D2LL }; - -// -// Role management -// -// Set up role. This sketch uses the same software for all the nodes -// in this system. Doing so greatly simplifies testing. The hardware itself specifies -// which node it is. -// -// This is done through the role_pin -// - -// The various roles supported by this sketch -typedef enum { role_ping_out = 1, role_pong_back } role_e; - -// The debug-friendly names of those roles -const char* role_friendly_name[] = { "invalid", "Ping out", "Pong back"}; - -// The role of the current running sketch -role_e role; - -// -// Test state -// - -bool done; //*< Are we done with the test? */ -bool passed; //*< Have we passed the test? */ -bool notified; //*< Have we notified the user we're done? */ -const int num_needed = 10; //*< How many success/failures until we're done? */ -int receives_remaining = num_needed; //*< How many ack packets until we declare victory? */ -int failures_remaining = num_needed; //*< How many more failed sends until we declare failure? */ -const int interval = 100; //*< ms to wait between sends */ - -char configuration = '1'; //*< Configuration key, one char sent in by the test framework to tell us how to configure, this is the default */ - -void one_ok(void) -{ - // Have we received enough yet? - if ( ! --receives_remaining ) - { - done = true; - passed = true; - } -} - -void one_failed(void) -{ - // Have we failed enough yet? - if ( ! --failures_remaining ) - { - done = true; - passed = false; - } -} - -void setup(void) -{ - // - // Role - // - - // set up the role pin - pinMode(role_pin, INPUT); - digitalWrite(role_pin,HIGH); - delay(20); // Just to get a solid reading on the role pin - - // read the address pin, establish our role - if ( digitalRead(role_pin) ) - role = role_ping_out; - else - role = role_pong_back; - - // - // Print preamble - // - - Serial.begin(57600); - printf_begin(); - printf("\n\rRF24/tests/pingpair_blocking/\n\r"); - printf("ROLE: %s\n\r",role_friendly_name[role]); - - // - // get test config - // - - printf("+READY press any key to start\n\r\n\r"); - - while (! Serial.available() ) {} - configuration = Serial.read(); - printf("Configuration\t = %c\n\r",configuration); - - // - // Setup and configure rf radio - // - - radio.begin(); - - // - // Open pipes to other nodes for communication - // - - // This simple sketch opens two pipes for these two nodes to communicate - // back and forth. - // Open 'our' pipe for writing - // Open the 'other' pipe for reading, in position #1 (we can have up to 5 pipes open for reading) - - if ( role == role_ping_out ) - { - radio.openWritingPipe(pipes[0]); - radio.openReadingPipe(1,pipes[1]); - } - else - { - radio.openWritingPipe(pipes[1]); - radio.openReadingPipe(1,pipes[0]); - } - - // - // Start listening - // - - radio.startListening(); - - // - // Dump the configuration of the rf unit for debugging - // - - radio.printDetails(); - - if ( role == role_pong_back ) - printf("\n\r+OK "); -} - -void loop(void) -{ - // - // Ping out role. Repeatedly send the current time - // - - if (role == role_ping_out) - { - // First, stop listening so we can talk. - radio.stopListening(); - - // Take the time, and send it. This will block until complete - unsigned long time = millis(); - printf("Now sending %lu...",time); - radio.write( &time, sizeof(unsigned long) ); - - // Now, continue listening - radio.startListening(); - - // Wait here until we get a response, or timeout (250ms) - unsigned long started_waiting_at = millis(); - bool timeout = false; - while ( ! radio.available() && ! timeout ) - if (millis() - started_waiting_at > 200 ) - timeout = true; - - // Describe the results - if ( timeout ) - { - printf("Failed, response timed out.\n\r"); - one_failed(); - } - else - { - // Grab the response, compare, and send to debugging spew - unsigned long got_time; - radio.read( &got_time, sizeof(unsigned long) ); - - // Spew it - printf("Got response %lu, round-trip delay: %lu\n\r",got_time,millis()-got_time); - one_ok(); - } - - // Try again later - delay(250); - } - - // - // Pong back role. Receive each packet, dump it out, and send it back - // - - if ( role == role_pong_back ) - { - // if there is data ready - if ( radio.available() ) - { - // Dump the payloads until we've gotten everything - unsigned long got_time; - bool done = false; - while (!done) - { - // Fetch the payload, and see if this was the last one. - done = radio.read( &got_time, sizeof(unsigned long) ); - - // Spew it - printf("Got payload %lu...",got_time); - - // Delay just a little bit to let the other unit - // make the transition to receiver - delay(20); - } - - // First, stop listening so we can talk - radio.stopListening(); - - // Send the final one back. - radio.write( &got_time, sizeof(unsigned long) ); - printf("Sent response.\n\r"); - - // Now, resume listening so we catch the next packets. - radio.startListening(); - - } - } - - // - // Stop the test if we're done and report results - // - if ( done && ! notified ) - { - notified = true; - - printf("\n\r+OK "); - if ( passed ) - printf("PASS\n\r\n\r"); - else - printf("FAIL\n\r\n\r"); - } -} -// vim:cin:ai:sts=2 sw=2 ft=cpp diff --git a/tests/pingpair_blocking/printf.h b/tests/pingpair_blocking/printf.h deleted file mode 100644 index b2efd56b..00000000 --- a/tests/pingpair_blocking/printf.h +++ /dev/null @@ -1,37 +0,0 @@ -/* - Copyright (C) 2011 J. Coliz - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - version 2 as published by the Free Software Foundation. - */ - -/** - * @file printf.h - * - * Setup necessary to direct stdout to the Arduino Serial library, which - * enables 'printf' - */ - -#ifndef __PRINTF_H__ -#define __PRINTF_H__ - -#ifdef ARDUINO - -int serial_putc( char c, FILE * ) -{ - Serial.write( c ); - - return c; -} - -void printf_begin(void) -{ - fdevopen( &serial_putc, 0 ); -} - -#else -#error This example is only for use on Arduino. -#endif // ARDUINO - -#endif // __PRINTF_H__ diff --git a/tests/pingpair_blocking/runtest.py b/tests/pingpair_blocking/runtest.py deleted file mode 100755 index 0772f950..00000000 --- a/tests/pingpair_blocking/runtest.py +++ /dev/null @@ -1,25 +0,0 @@ -#!/usr/bin/python - -import sys,serial - -def read_until(token): - while 1: - line = ser.readline(None) - sys.stdout.write(line) - - if (line.startswith(token)): - break - return line - - -ser = serial.Serial(sys.argv[1], 57600, timeout=5, dsrdtr=False, rtscts=False) - -read_until("+READY") -ser.write(sys.argv[2]) - -line = read_until("+OK") -ser.close() -if (line.find("PASS") != -1): - sys.exit(0) -else: - sys.exit(1) diff --git a/tests/pingpair_blocking/runtests.sh b/tests/pingpair_blocking/runtests.sh deleted file mode 100755 index e1064487..00000000 --- a/tests/pingpair_blocking/runtests.sh +++ /dev/null @@ -1,5 +0,0 @@ -#!/bin/sh - -# Connect u0 to receiver, u1 to sender - -jam u0 u1 && expect test.ex diff --git a/tests/pingpair_blocking/test.ex b/tests/pingpair_blocking/test.ex deleted file mode 100755 index ea992add..00000000 --- a/tests/pingpair_blocking/test.ex +++ /dev/null @@ -1,11 +0,0 @@ -#/usr/bin/expect - -set timeout 100 -spawn picocom -b 57600 /dev/ttyUSB0 -expect "+READY" -send "1" -expect "+OK" -spawn picocom -b 57600 /dev/ttyUSB1 -expect "+READY" -send "1" -expect "+OK" diff --git a/tests/pingpair_test/Jamfile b/tests/pingpair_test/Jamfile deleted file mode 100644 index 18244ec8..00000000 --- a/tests/pingpair_test/Jamfile +++ /dev/null @@ -1,219 +0,0 @@ -# (1) Project Information - -PROJECT_LIBS = SPI RF24 ; -PROJECT_DIRS = $(PWD) ; - -# (2) Board Information - -UPLOAD_PROTOCOL ?= arduino ; -UPLOAD_SPEED ?= 115200 ; -MCU ?= atmega328p ; -F_CPU ?= 16000000 ; -CORE ?= arduino ; -VARIANT ?= standard ; -ARDUINO_VERSION ?= 100 ; - -# (3) USB Ports - -PORTS = p4 p6 p9 u0 u1 u2 ; -PORT_p6 = /dev/tty.usbserial-A600eHIs ; -PORT_p4 = /dev/tty.usbserial-A40081RP ; -PORT_p9 = /dev/tty.usbserial-A9007LmI ; -PORT_u0 = /dev/ttyUSB0 ; -PORT_u1 = /dev/ttyUSB1 ; -PORT_u2 = /dev/ttyUSB2 ; - -# (4) Location of AVR tools -# -# This configuration assumes using avr-tools that were obtained separate from the Arduino -# distribution. - -if $(OS) = MACOSX -{ - AVR_BIN ?= /usr/local/avrtools/bin ; - AVR_ETC = /usr/local/avrtools/etc ; - AVR_INCLUDE = /usr/local/avrtools/include ; -} -else -{ - AVR_BIN ?= /usr/bin ; - AVR_INCLUDE = /usr/lib/avr/include ; - AVR_ETC = /etc ; -} - -# (5) Directories where Arduino core and libraries are located - -ARDUINO_DIR ?= /opt/Arduino ; -ARDUINO_CORE = $(ARDUINO_DIR)/hardware/arduino/cores/$(CORE) $(ARDUINO_DIR)/hardware/arduino/variants/$(VARIANT) ; -ARDUINO_LIB = $(ARDUINO_DIR)/libraries ; -SKETCH_LIB = $(HOME)/Source/Arduino/libraries ; - -# -# -------------------------------------------------- -# Below this line usually never needs to be modified -# - -# Tool locations - -CC = $(AVR_BIN)/avr-gcc ; -C++ = $(AVR_BIN)/avr-g++ ; -LINK = $(AVR_BIN)/avr-gcc ; -AR = $(AVR_BIN)/avr-ar rcs ; -RANLIB = ; -OBJCOPY = $(AVR_BIN)/avr-objcopy ; -AVRDUDE ?= $(AVR_BIN)/avrdude ; - -# Flags - -DEFINES += F_CPU=$(F_CPU)L ARDUINO=$(ARDUINO_VERSION) VERSION_H ; -OPTIM = -Os ; -CCFLAGS = -Wall -Wextra -Wno-strict-aliasing -mmcu=$(MCU) -ffunction-sections -fdata-sections ; -C++FLAGS = $(CCFLAGS) -fno-exceptions -fno-strict-aliasing ; -LINKFLAGS = $(OPTIM) -lm -Wl,--gc-sections -mmcu=$(MCU) ; -AVRDUDEFLAGS = -V -F -D -C $(AVR_ETC)/avrdude.conf -p $(MCU) -c $(UPLOAD_PROTOCOL) -b $(UPLOAD_SPEED) ; - -# Search everywhere for headers - -HDRS = $(PROJECT_DIRS) $(AVR_INCLUDE) $(ARDUINO_CORE) $(ARDUINO_LIB)/$(PROJECT_LIBS) $(ARDUINO_LIB)/$(PROJECT_LIBS)/utility $(SKETCH_LIB)/$(PROJECT_LIBS) ; - -# Output locations - -LOCATE_TARGET = $(F_CPU) ; -LOCATE_SOURCE = $(F_CPU) ; - -# -# Custom rules -# - -rule GitVersion -{ - Always $(<) ; - Depends all : $(<) ; -} - -actions GitVersion -{ - echo "const char program_version[] = \"\\" > $(<) - git log -1 --pretty=format:%h >> $(<) - echo "\";" >> $(<) -} - -GitVersion version.h ; - -rule Pde -{ - Depends $(<) : $(>) ; - MakeLocate $(<) : $(LOCATE_SOURCE) ; - Clean clean : $(<) ; -} - -if ( $(ARDUINO_VERSION) < 100 ) -{ - ARDUINO_H = WProgram.h ; -} -else -{ - ARDUINO_H = Arduino.h ; -} - -actions Pde -{ - echo "#include <$(ARDUINO_H)>" > $(<) - echo "#line 1 \"$(>)\"" >> $(<) - cat $(>) >> $(<) -} - -rule C++Pde -{ - local _CPP = $(>:B).cpp ; - Pde $(_CPP) : $(>) ; - C++ $(<) : $(_CPP) ; -} - -rule UserObject -{ - switch $(>:S) - { - case .ino : C++Pde $(<) : $(>) ; - case .pde : C++Pde $(<) : $(>) ; - } -} - -rule Objects -{ - local _i ; - - for _i in [ FGristFiles $(<) ] - { - local _b = $(_i:B)$(SUFOBJ) ; - local _o = $(_b:G=$(SOURCE_GRIST:E)) ; - Object $(_o) : $(_i) ; - Depends obj : $(_o) ; - } -} - -rule Library -{ - LibraryFromObjects $(<) : $(>:B)$(SUFOBJ) ; - Objects $(>) ; -} - -rule Main -{ - MainFromObjects $(<) : $(>:B)$(SUFOBJ) ; - Objects $(>) ; -} - -rule Hex -{ - Depends $(<) : $(>) ; - MakeLocate $(<) : $(LOCATE_TARGET) ; - Depends hex : $(<) ; - Clean clean : $(<) ; -} - -actions Hex -{ - $(OBJCOPY) -O ihex -R .eeprom $(>) $(<) -} - -rule Upload -{ - Depends $(1) : $(2) ; - Depends $(2) : $(3) ; - NotFile $(1) ; - Always $(1) ; - Always $(2) ; - UploadAction $(2) : $(3) ; -} - -actions UploadAction -{ - $(AVRDUDE) $(AVRDUDEFLAGS) -P $(<) $(AVRDUDE_WRITE_FLASH) -U flash:w:$(>):i -} - -rule Arduino -{ - LINKFLAGS on $(<) = $(LINKFLAGS) -Wl,-Map=$(LOCATE_TARGET)/$(<:B).map ; - Main $(<) : $(>) ; - LinkLibraries $(<) : core libs ; - Hex $(<:B).hex : $(<) ; - for _p in $(PORTS) - { - Upload $(_p) : $(PORT_$(_p)) : $(<:B).hex ; - } -} - -# -# Targets -# - -# Grab everything from the core directory -Library core : [ GLOB $(ARDUINO_CORE) : *.c *.cpp ] ; - -# Grab everything from libraries. To avoid this "grab everything" behaviour, you -# can specify specific modules to pick up in PROJECT_MODULES -Library libs : [ GLOB $(ARDUINO_LIB)/$(PROJECT_LIBS) $(ARDUINO_LIB)/$(PROJECT_LIBS)/utility $(SKETCH_LIB)/$(PROJECT_LIBS) : *.cpp *.c ] ; - -# Main output executable -Arduino $(PWD:B).elf : $(PROJECT_MODULES) [ GLOB $(PROJECT_DIRS) : *.c *.cpp *.pde *.ino ] ; diff --git a/tests/pingpair_test/pingpair_test.pde b/tests/pingpair_test/pingpair_test.pde deleted file mode 100644 index 6acbf51d..00000000 --- a/tests/pingpair_test/pingpair_test.pde +++ /dev/null @@ -1,435 +0,0 @@ -/* - Copyright (C) 2011 James Coliz, Jr. - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - version 2 as published by the Free Software Foundation. - */ - -/** - * Full test on single RF pair - * - * This sketches uses as many RF24 methods as possible in a single test. - * - * To operate: - * Upload this sketch on two nodes, each with IRQ -> pin 2 - * One node needs pin 7 -> GND, the other NC. That's the receiving node - * Monitor the sending node's serial output - * Look for "+OK PASS" or "+OK FAIL" - */ - -#include -#include "nRF24L01.h" -#include "RF24.h" -#include "printf.h" - -// -// Hardware configuration -// - -// Set up nRF24L01 radio on SPI bus plus pins 8 & 9 - -RF24 radio(8,9); - -// sets the role of this unit in hardware. Connect to GND to be the 'pong' receiver -// Leave open to be the 'ping' transmitter -const short role_pin = 7; - -// -// Topology -// - -// Single radio pipe address for the 2 nodes to communicate. -const uint64_t pipe = 0xE8E8F0F0E1LL; - -// -// Role management -// -// Set up role. This sketch uses the same software for all the nodes in this -// system. Doing so greatly simplifies testing. The hardware itself specifies -// which node it is. -// -// This is done through the role_pin -// - -// The various roles supported by this sketch -typedef enum { role_sender = 1, role_receiver } role_e; - -// The debug-friendly names of those roles -const char* role_friendly_name[] = { "invalid", "Sender", "Receiver"}; - -// The role of the current running sketch -role_e role; - -// Interrupt handler, check the radio because we got an IRQ -void check_radio(void); - -// -// Payload -// - -const int min_payload_size = 4; -const int max_payload_size = 32; -int payload_size_increments_by = 2; -int next_payload_size = min_payload_size; - -char receive_payload[max_payload_size+1]; // +1 to allow room for a terminating NULL char - -// -// Test state -// - -bool done; //*< Are we done with the test? */ -bool passed; //*< Have we passed the test? */ -bool notified; //*< Have we notified the user we're done? */ -const int num_needed = 10; //*< How many success/failures until we're done? */ -int receives_remaining = num_needed; //*< How many ack packets until we declare victory? */ -int failures_remaining = num_needed; //*< How many more failed sends until we declare failure? */ -const int interval = 100; //*< ms to wait between sends */ - -char configuration = '1'; //*< Configuration key, one char sent in by the test framework to tell us how to configure, this is the default */ - -uint8_t pipe_number = 1; // Which pipe to send on. - -void one_ok(void) -{ - // Have we received enough yet? - if ( ! --receives_remaining ) - { - done = true; - passed = true; - } -} - -void one_failed(void) -{ - // Have we failed enough yet? - if ( ! --failures_remaining ) - { - done = true; - passed = false; - } -} - -// -// Setup -// - -void setup(void) -{ - // - // Role - // - - // set up the role pin - pinMode(role_pin, INPUT); - digitalWrite(role_pin,HIGH); - delay(20); // Just to get a solid reading on the role pin - - // read the address pin, establish our role - if ( digitalRead(role_pin) ) - role = role_sender; - else - role = role_receiver; - - // - // Print preamble - // - - Serial.begin(57600); - printf_begin(); - printf("\n\rRF24/tests/pingpair_test/\n\r"); - printf("ROLE: %s\n\r",role_friendly_name[role]); - - // - // Read configuration from serial - // - // It would be a much better test if this program could accept configuration - // from the serial port. Then it would be possible to run the same test under - // lots of different circumstances. - // - // The idea is that we will print "+READY" at this point. The python script - // will wait for it, and then send down a configuration script that we - // execute here and then run with. - // - // The test controller will need to configure the receiver first, then go run - // the test on the sender. - // - - printf("+READY press any key to start\n\r\n\r"); - - while (! Serial.available() ) {} - configuration = Serial.read(); - printf("Configuration\t = %c\n\r",configuration); - - // - // Setup and configure rf radio - // - - radio.begin(); - - // We will be using the Ack Payload feature, so please enable it - radio.enableAckPayload(); - - // Config 2 is special radio config - if (configuration=='2') - { - radio.setCRCLength(RF24_CRC_8); - radio.setDataRate(RF24_250KBPS); - radio.setChannel(10); - } - else - { - //Otherwise, default radio config - - // Optional: Increase CRC length for improved reliability - radio.setCRCLength(RF24_CRC_16); - - // Optional: Decrease data rate for improved reliability - radio.setDataRate(RF24_1MBPS); - - // Optional: Pick a high channel - radio.setChannel(90); - } - - // Config 3 is static payloads only - if (configuration == '3') - { - next_payload_size = 16; - payload_size_increments_by = 0; - radio.setPayloadSize(next_payload_size); - } - else - { - // enable dynamic payloads - radio.enableDynamicPayloads(); - } - - // Config 4 tests out a higher pipe ## - if (configuration == '4' && role == role_sender) - { - // Set top 4 bytes of the address in pipe 1 - radio.openReadingPipe(1,pipe & 0xFFFFFFFF00ULL); - - // indicate the pipe to use - pipe_number = 5; - } - else if ( role == role_sender ) - { - radio.openReadingPipe(5,0); - } - - // - // Open pipes to other nodes for communication - // - - // This simple sketch opens a single pipe for these two nodes to communicate - // back and forth. One listens on it, the other talks to it. - - if ( role == role_sender ) - { - radio.openWritingPipe(pipe); - } - else - { - radio.openReadingPipe(pipe_number,pipe); - } - - // - // Start listening - // - - if ( role == role_receiver ) - radio.startListening(); - - // - // Dump the configuration of the rf unit for debugging - // - - radio.printDetails(); - - // - // Attach interrupt handler to interrupt #0 (using pin 2) - // on BOTH the sender and receiver - // - - attachInterrupt(0, check_radio, FALLING); - - if ( role == role_receiver ) - printf("\n\r+OK "); -} - -// -// Print buffer -// -// Printing from the interrupt handler is a bad idea, so we print from there -// to this intermediate buffer -// - -char prbuf[1000]; -char *prbuf_end = prbuf + sizeof(prbuf); -char *prbuf_in = prbuf; -char *prbuf_out = prbuf; - -// -// Loop -// - -static uint32_t message_count = 0; -static uint32_t last_message_count = 0; - -void loop(void) -{ - // - // Sender role. Repeatedly send the current time - // - - if (role == role_sender && !done) - { - // The payload will always be the same, what will change is how much of it we send. - static char send_payload[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ789012"; - - // First, stop listening so we can talk. - radio.stopListening(); - - // Send it. This will block until complete - printf("\n\rNow sending length %i...",next_payload_size); - radio.startWrite( send_payload, next_payload_size ); - - // Update size for next time. - next_payload_size += payload_size_increments_by; - if ( next_payload_size > max_payload_size ) - next_payload_size = min_payload_size; - - // Try again soon - delay(interval); - - // Timeout if we have not received anything back ever - if ( ! last_message_count && millis() > interval * 100 ) - { - printf("No responses received. Are interrupts connected??\n\r"); - done = true; - } - } - - // - // Receiver role: Does nothing! All the work is in IRQ - // - - // - // Spew print buffer - // - - size_t write_length = prbuf_in - prbuf_out; - if ( write_length ) - { - Serial.write(reinterpret_cast(prbuf_out),write_length); - prbuf_out += write_length; - } - - // - // Stop the test if we're done and report results - // - if ( done && ! notified ) - { - notified = true; - - printf("\n\r+OK "); - if ( passed ) - printf("PASS\n\r\n\r"); - else - printf("FAIL\n\r\n\r"); - } - -} - -void check_radio(void) -{ - // What happened? - bool tx,fail,rx; - radio.whatHappened(tx,fail,rx); - - // Have we successfully transmitted? - if ( tx ) - { - if ( role == role_sender ) - prbuf_in += sprintf(prbuf_in,"Send:OK "); - - if ( role == role_receiver ) - prbuf_in += sprintf(prbuf_in,"Ack Payload:Sent\n\r"); - } - - // Have we failed to transmit? - if ( fail ) - { - if ( role == role_sender ) - { - prbuf_in += sprintf(prbuf_in,"Send:Failed "); - - // log status of this line - one_failed(); - } - - if ( role == role_receiver ) - prbuf_in += sprintf(prbuf_in,"Ack Payload:Failed\n\r"); - } - - // Transmitter can power down for now, because - // the transmission is done. - if ( ( tx || fail ) && ( role == role_sender ) ) - radio.powerDown(); - - // Did we receive a message? - if ( rx ) - { - // If we're the sender, we've received an ack payload - if ( role == role_sender ) - { - radio.read(&message_count,sizeof(message_count)); - prbuf_in += sprintf(prbuf_in,"Ack:%lu ",message_count); - - // is this ack what we were expecting? to account - // for failures, we simply want to make sure we get a - // DIFFERENT ack every time. - if ( ( message_count != last_message_count ) || ( configuration=='3' && message_count == 16 ) ) - { - prbuf_in += sprintf(prbuf_in,"OK "); - one_ok(); - } - else - { - prbuf_in += sprintf(prbuf_in,"FAILED "); - one_failed(); - } - last_message_count = message_count; - } - - // If we're the receiver, we've received a time message - if ( role == role_receiver ) - { - // Get this payload and dump it - size_t len = max_payload_size; - memset(receive_payload,0,max_payload_size); - - if ( configuration == '3' ) - len = next_payload_size; - else - len = radio.getDynamicPayloadSize(); - - radio.read( receive_payload, len ); - - // Put a zero at the end for easy printing - receive_payload[len] = 0; - - // Spew it - prbuf_in += sprintf(prbuf_in,"Recv size=%i val=%s len=%u\n\r",len,receive_payload,strlen(receive_payload)); - - // Add an ack packet for the next time around. - // Here we will report back how many bytes we got this time. - radio.writeAckPayload( pipe_number, &len, sizeof(len) ); - ++message_count; - } - } -} - -// vim:ai:cin:sts=2 sw=2 ft=cpp diff --git a/tests/pingpair_test/printf.h b/tests/pingpair_test/printf.h deleted file mode 100644 index b2efd56b..00000000 --- a/tests/pingpair_test/printf.h +++ /dev/null @@ -1,37 +0,0 @@ -/* - Copyright (C) 2011 J. Coliz - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - version 2 as published by the Free Software Foundation. - */ - -/** - * @file printf.h - * - * Setup necessary to direct stdout to the Arduino Serial library, which - * enables 'printf' - */ - -#ifndef __PRINTF_H__ -#define __PRINTF_H__ - -#ifdef ARDUINO - -int serial_putc( char c, FILE * ) -{ - Serial.write( c ); - - return c; -} - -void printf_begin(void) -{ - fdevopen( &serial_putc, 0 ); -} - -#else -#error This example is only for use on Arduino. -#endif // ARDUINO - -#endif // __PRINTF_H__ diff --git a/tests/pingpair_test/runtest.py b/tests/pingpair_test/runtest.py deleted file mode 100755 index 45fb65ce..00000000 --- a/tests/pingpair_test/runtest.py +++ /dev/null @@ -1,25 +0,0 @@ -#!/opt/local/bin/python - -import sys,serial - -def read_until(token): - while 1: - line = ser.readline(None,"\r") - sys.stdout.write(line) - - if (line.startswith(token)): - break - return line - - -ser = serial.Serial(sys.argv[1], 57600, timeout=5, dsrdtr=False, rtscts=False) - -read_until("+READY") -ser.write(sys.argv[2]) - -line = read_until("+OK") -ser.close() -if (line.find("PASS") != -1): - sys.exit(0) -else: - sys.exit(1) diff --git a/tests/pingpair_test/runtests.sh b/tests/pingpair_test/runtests.sh deleted file mode 100755 index 4d02310b..00000000 --- a/tests/pingpair_test/runtests.sh +++ /dev/null @@ -1,21 +0,0 @@ -#!/bin/sh - -# Connect u0 to receiver, u0 to sender -# WARNING: Test config 2 only works with PLUS units. - -jam u0 u1 && expect test.ex 1 -sleep 1 -stty 57600 raw ignbrk hup < /dev/ttyUSB0 -sleep 1 -stty 57600 raw ignbrk hup < /dev/ttyUSB1 -expect test.ex 2 -sleep 1 -stty 57600 raw ignbrk hup < /dev/ttyUSB0 -sleep 1 -stty 57600 raw ignbrk hup < /dev/ttyUSB1 -expect test.ex 3 -sleep 1 -stty 57600 raw ignbrk hup < /dev/ttyUSB0 -sleep 1 -stty 57600 raw ignbrk hup < /dev/ttyUSB1 -expect test.ex 4 diff --git a/tests/pingpair_test/test.ex b/tests/pingpair_test/test.ex deleted file mode 100755 index a14ffef0..00000000 --- a/tests/pingpair_test/test.ex +++ /dev/null @@ -1,11 +0,0 @@ -#/usr/bin/expect - -set timeout 100 -spawn picocom -b 57600 /dev/ttyUSB0 -expect "+READY" -send [lindex $argv 0] -expect "+OK" -spawn picocom -b 57600 /dev/ttyUSB1 -expect "+READY" -send [lindex $argv 0] -expect "+OK" From b9aaa6b6a99fc5676b06003d2c543746ec7fe019 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Sousa?= Date: Mon, 12 May 2014 14:15:12 +0100 Subject: [PATCH 2/3] initial import --- .directory | 6 + flash.cpp | 61 ++ flash.h | 18 + include/libemb/conio/conio.h | 76 ++ include/libemb/nrf24l01/nrf24l01.h | 261 +++++++ include/libemb/nrf24l01/nrf24l01_hw.h | 46 ++ include/libemb/nrf24l01/nrf24l01_regs.h | 349 +++++++++ include/libemb/serial/serial.h | 59 ++ include/libemb/serial/serial_rb.h | 107 +++ include/libemb/shell/shell.h | 173 +++++ lib/libconio.a | Bin 0 -> 8212 bytes lib/libnrf24l01.a | Bin 0 -> 23918 bytes lib/libnrf24l01_meta.a | Bin 0 -> 26070 bytes lib/libserial.a | Bin 0 -> 8516 bytes lib/libshell.a | Bin 0 -> 5552 bytes main.cpp | 126 +++ remote_defines.h | 47 ++ rf24/RF24.cpp | 992 ++++++++++++++++++++++++ rf24/RF24.h | 816 +++++++++++++++++++ rf24/RF24_config.h | 112 +++ rf24/nRF24L01.h | 125 +++ rf24/spi-msp430.c | 91 +++ rf24/spi.h | 26 + rf24/spi_msp430.h | 35 + timer_msp.c | 80 ++ timer_msp.h | 28 + 26 files changed, 3634 insertions(+) create mode 100644 .directory create mode 100755 flash.cpp create mode 100755 flash.h create mode 100755 include/libemb/conio/conio.h create mode 100755 include/libemb/nrf24l01/nrf24l01.h create mode 100755 include/libemb/nrf24l01/nrf24l01_hw.h create mode 100755 include/libemb/nrf24l01/nrf24l01_regs.h create mode 100755 include/libemb/serial/serial.h create mode 100755 include/libemb/serial/serial_rb.h create mode 100755 include/libemb/shell/shell.h create mode 100755 lib/libconio.a create mode 100755 lib/libnrf24l01.a create mode 100755 lib/libnrf24l01_meta.a create mode 100755 lib/libserial.a create mode 100755 lib/libshell.a create mode 100755 main.cpp create mode 100755 remote_defines.h create mode 100644 rf24/RF24.cpp create mode 100644 rf24/RF24.h create mode 100644 rf24/RF24_config.h create mode 100644 rf24/nRF24L01.h create mode 100755 rf24/spi-msp430.c create mode 100755 rf24/spi.h create mode 100755 rf24/spi_msp430.h create mode 100755 timer_msp.c create mode 100755 timer_msp.h diff --git a/.directory b/.directory new file mode 100644 index 00000000..156022d6 --- /dev/null +++ b/.directory @@ -0,0 +1,6 @@ +[Dolphin] +Timestamp=2014,5,12,14,1,15 +Version=3 + +[Settings] +HiddenFilesShown=true diff --git a/flash.cpp b/flash.cpp new file mode 100755 index 00000000..e4835372 --- /dev/null +++ b/flash.cpp @@ -0,0 +1,61 @@ +/* + * flash.cpp + * + * Created on: Jun 10, 2013 + * Author: joao + */ +#include +#include "flash.h" + +void flash_init(void) +{ + FCTL2 = FWKEY + FSSEL0 + FN1; // MCLK/3 for Flash Timing Generator +} + +void write_SegC (unsigned char values[], uint8_t dim) +{ + char *Flash_ptr; // Flash pointer + unsigned int i; + + Flash_ptr = (char *) 0x1040; // Initialize Flash pointer + FCTL1 = FWKEY + ERASE; // Set Erase bit + FCTL3 = FWKEY; // Clear Lock bit + *Flash_ptr = 0; // Dummy write to erase Flash segment + + FCTL1 = FWKEY + WRT; // Set WRT bit for write operation + + for (i=0; i<64; i++) + { + if(i < dim) + { + *Flash_ptr++ = values[i]; // Write value to flash + } + else + { + *Flash_ptr++ = 0; + } + } + + FCTL1 = FWKEY; // Clear WRT bit + FCTL3 = FWKEY + LOCK; // Set LOCK bit +} + +void read_SegC (unsigned char values[], uint8_t dim, uint8_t offset) +{ + char *Flash_ptr; // Flash pointer + unsigned int i; + + if(64 - offset - dim > 0) + { + Flash_ptr = (char *) (0x1040 + offset); // Initialize Flash pointer + FCTL1 = FWKEY + ERASE; // Set Erase bit + FCTL3 = FWKEY; // Clear Lock bit + + for (i=0; i + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef __CONIO_H_ +#define __CONIO_H_ + +/** + * Print a character to the console. + * + * @param[in] c character to print + */ +void cio_printc(char c); + +/** + * Print a string to the console. + * + * @param[in] *line string to print + */ +void cio_print(char *line); + +/** + * Print an integer to the console. + * + * @param[in] n number to print + */ +void cio_printi(int n); + +/** + * Print a number in binary to the console. + * + * @param[in] n number to print + * @param[in] size number of bits to use + */ +void cio_printb(int n, int size); + +/** + * Print a formated string. The following formt specifiers could + * be used in the format string: + *
+ * String			%s
+ * Char          	%c
+ * Integer       	%i
+ * Unsigned      	%u
+ * Long          	%l
+ * unsigned long 	%n
+ * heX          	%x
+ * 
+ * @param[in] *format the format string + * @param[in] ... the values to put into the format string + */ +void cio_printf(char *format, ...); + +/** + * Read a character form the console. + * + * @return character read from the console + */ +char cio_getc(); + +#endif diff --git a/include/libemb/nrf24l01/nrf24l01.h b/include/libemb/nrf24l01/nrf24l01.h new file mode 100755 index 00000000..cf079f58 --- /dev/null +++ b/include/libemb/nrf24l01/nrf24l01.h @@ -0,0 +1,261 @@ +/* + * This file is part of the libemb project. + * + * Copyright (C) 2011 Stefan Wendler + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef __NRF24L01_H_ +#define __NRF24L01_H_ + +#include "nrf24l01_hw.h" +#include "nrf24l01_regs.h" + +/** + * Maximum payload size the NRF is able to send in bytes. + */ +#define NRF_MAX_PAYLOAD 32 + +/** + * Primery mode TX + */ +#define NRF_MODE_PTX 0 + +/** + * Primery mode RX + */ +#define NRF_MODE_PRX 1 + +/** + * Retry delay for auto retransmit 250us + */ +#define NRF_RT_DELAY_250 0 + +/** + * Retry delay for auto retransmit 500us + */ +#define NRF_RT_DELAY_500 1 + +/** + * Retry delay for auto retransmit 750us + */ +#define NRF_RT_DELAY_750 2 + +/** + * Retry delay for auto retransmit 1000us + */ +#define NRF_RT_DELAY_1000 3 + +/** + * Retry delay for auto retransmit 1250us + */ +#define NRF_RT_DELAY_1250 4 + +/** + * Retry delay for auto retransmit 1500us + */ +#define NRF_RT_DELAY_1500 5 + +/** + * Retry delay for auto retransmit 1750us + */ +#define NRF_RT_DELAY_1750 6 + +/** + * Retry delay for auto retransmit 2000us + */ +#define NRF_RT_DELAY_2000 7 + +/** + * Retry delay for auto retransmit 2250us + */ +#define NRF_RT_DELAY_2250 8 + +/** + * Retry delay for auto retransmit 2500us + */ +#define NRF_RT_DELAY_2500 9 + +/** + * Retry delay for auto retransmit 2750us + */ +#define NRF_RT_DELAY_2750 10 + +/** + * Retry delay for auto retransmit 3000us + */ +#define NRF_RT_DELAY_3000 11 + +/** + * Retry delay for auto retransmit 3250us + */ +#define NRF_RT_DELAY_3250 12 + +/** + * Retry delay for auto retransmit 3500us + */ +#define NRF_RT_DELAY_3500 13 + +/** + * Retry delay for auto retransmit 3750us + */ +#define NRF_RT_DELAY_3750 14 + +/** + * Retry delay for auto retransmit 4000us + */ +#define NRF_RT_DELAY_4000 15 + +/** + * Error code for max retry reached + */ +#define NRF_ERR_MAX_RT (-1) + +/** + * Error code for TX buffer full + */ +#define NRF_ERR_TX_FULL (-2) + +/** + * Error code for RX buffer full + */ +#define NRF_ERR_RX_FULL (-3) + +/** + * Definition of payload send through the device. + */ +typedef struct { + + /** + * Payload size in bytes (must not exceed NRF_MAX_PAYLOAD]). + */ + unsigned char size; + + /** + * The payload. + */ + unsigned char data[NRF_MAX_PAYLOAD]; +} nrf_payload; + +/** + * Read contents of a register form the nRF24l01. + * + * @param[in] reg register to read (see NRF_REG_* form nrf24l01_regs.h) + * @param[out] *buf the value(s) read from the register + * @return number of bytes read from the register + */ +int nrf_read_reg(unsigned char reg, nrf_reg_buf *buf); + +/** + * Write contents of a register to the nRF24l01. + * + * @param[in] reg register to write (see NRF_REG_* form nrf24l01_regs.h) + * @param[in] *buf the value(s) to write the register + * @return number of bytes written to the register + */ +int nrf_write_reg(unsigned char reg, nrf_reg_buf *buf); + +/** + * Send payload non-blocking through the nRF24l01. + * + * @param[in] *payload the payload to send + * @return number of bytes sent or NRF_ERR_TX_FULL if TX buffer is full + * or NRF_ERR_MAX_RT if auto ACK with retry was enabled and + * payload was not delivered after configured retrys + */ +int nrf_send(nrf_payload *payload); + +/** + * Send payload blocking through the nRF24l01. + * + * @param[in] *payload the payload to send + * @return number of bytes sent or NRF_ERR_TX_FULL if TX buffer is full + * or NRF_ERR_MAX_RT if auto ACK with retry was enabled and + * payload was not delivered after configured retrys + */ +int nrf_send_blocking(nrf_payload *payload); + +/** + * Receive payload non-blocking from nRF24l01. + * + * @param *payload the payload received, "size" member of payload + * must be set to correct payload size (as configured for nRF) + * @return number of bytes received or NRF_ERR_RX_FULL when RX buffer is full +d + */ +int nrf_receive(nrf_payload *payload); + +/** + * Receive payload blocking from nRF24l01. + * + * @param *payload the payload received, "size" member of payload + * must be set to correct payload size (as configured for nRF) + * @return number of bytes received or NRF_ERR_RX_FULL when RX buffer is full + */ +int nrf_receive_blocking(nrf_payload *payload); + +/** + * Set ACK payload for a given pipe to be sent back in ESB mode with ACK-payload. + * + * @param[in] *payload ACK payload to send back on next RX + * @return number of bytes sent + */ +int nrf_write_ack_pl(nrf_payload *payload, unsigned char pipe); + +/** + * Read ACK payload received as response to the last TX request (only ESB mode with + * ACK-payload enabled). + * + * @param[out] *payload ACK payload received + * @return number of bytes received + */ +int nrf_read_ack_pl(nrf_payload *payload); + +/** + * Preset configuration to configure the nRF24l01 into SB (Shock Burst) mode. + * + * @param[in] mode primery device mode: NRF_MODE_PRX for RX, or NRF_MODE_PTX for TX + * @param[in] rf_ch RF channel to use + * @param[in] pw payload width in bytes (must not exceed NRF_MAX_PAYLOAD) + * @param[in] *addr Address to use for TX and RX on pipe 0 + */ +void nrf_preset_sb(unsigned char mode, unsigned char rf_ch, unsigned char pw, nrf_reg_buf *addr); + +/** + * Preset configuration to configure the nRF24l01 into ESB (Enhenced Shock Burst) mode. + * + * @param[in] mode primery device mode: NRF_MODE_PRX for RX, or NRF_MODE_PTX for TX + * @param[in] rf_ch RF channel to use + * @param[in] pw payload width in bytes (must not exceed NRF_MAX_PAYLOAD) + * @param[in] rert number of retrys for receiving ACK + * @param[in] delay delay to wait before next retry (one of NRF_RT_DELAY_*) + * @param[in] *addr Address to use for TX and RX on pipe 0 + */ +void nrf_preset_esb(unsigned char mode, unsigned char rf_ch, unsigned char pw, unsigned char retr, unsigned char delay, nrf_reg_buf *addr); + +/** + * Preset configuration to configure the nRF24l01 into ESB (Enhenced Shock Burst) mode with + * enabled ACL payload. + * + * @param[in] mode primery device mode: NRF_MODE_PRX for RX, or NRF_MODE_PTX for TX + * @param[in] rf_ch RF channel to use + * @param[in] pw payload width in bytes (must not exceed NRF_MAX_PAYLOAD) + * @param[in] rert number of retrys for receiving ACK + * @param[in] delay delay to wait before next retry (one of NRF_RT_DELAY_*) + * @param[in] *addr Address to use for TX and RX on pipe 0 + */ +void nrf_preset_esbpl(unsigned char mode, unsigned char rf_ch, unsigned char pw, unsigned char retr, unsigned char delay, nrf_reg_buf *addr); + +#endif diff --git a/include/libemb/nrf24l01/nrf24l01_hw.h b/include/libemb/nrf24l01/nrf24l01_hw.h new file mode 100755 index 00000000..5c29eef3 --- /dev/null +++ b/include/libemb/nrf24l01/nrf24l01_hw.h @@ -0,0 +1,46 @@ +/* + * This file is part of the libemb project. + * + * Copyright (C) 2011 Stefan Wendler + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef __NRF24L01HW_H_ +#define __NRF24L01HW_H_ + +/** + * Initialize HW interface (SPI) to nRF24l01. + */ +void nrf_init(void); + +/** + * Drive CS high. + */ +void nrf_spi_csh(void); + +/** + * Drive CS low. + */ +void nrf_spi_csl(void); + +/** + * Write-/Read one byte of data to/from the nRF through the SPI bus. + * + * @param[in] data byte to send + * @return byte received + */ +unsigned char nrf_spi_xfer_byte(unsigned char data); + +#endif diff --git a/include/libemb/nrf24l01/nrf24l01_regs.h b/include/libemb/nrf24l01/nrf24l01_regs.h new file mode 100755 index 00000000..df4c4b13 --- /dev/null +++ b/include/libemb/nrf24l01/nrf24l01_regs.h @@ -0,0 +1,349 @@ +/* + * This file is part of the libemb project. + * + * Copyright (C) 2011 Stefan Wendler + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef __NRF24L01REGS_H_ +#define __NRF24L01REGS_H_ + +/* + * Setting this to 1 enables compilation of meta information + * for the registers. Meta information contains readable register + * names which could be used for debugging or displaying. + *

+ * NOTE: Use "-DNRF_REG_DEF_META" compiler switch from makefile + * is the preferred way to set this flag. + */ +// #define NRF_REG_DEF_META 1 + +/** + * Maximum number of bytes needed to store register information (largest + * block of data to be read from nNRF is the address register with 5 bytes). + */ +#define NRF_MAX_REG_BUF 5 + +/* + * NRF2041 Registers + */ + +#define NRF_REG_CONFIG 0x00 +#define NRF_REG_EN_AA 0x01 +#define NRF_REG_EN_RXADDR 0x02 +#define NRF_REG_SETUP_AW 0x03 +#define NRF_REG_SETUP_RETR 0x04 +#define NRF_REG_RF_CH 0x05 +#define NRF_REG_RF_SETUP 0x06 +#define NRF_REG_STATUS 0x07 +#define NRF_REG_OBSERVE_TX 0x08 +#define NRF_REG_CD 0x09 +#define NRF_REG_RX_ADDR_P0 0x0A +#define NRF_REG_RX_ADDR_P1 0x0B +#define NRF_REG_RX_ADDR_P2 0x0C +#define NRF_REG_RX_ADDR_P3 0x0D +#define NRF_REG_RX_ADDR_P4 0x0E +#define NRF_REG_RX_ADDR_P5 0x1F +#define NRF_REG_TX_ADDR 0x10 +#define NRF_REG_RX_PW_P0 0x11 +#define NRF_REG_RX_PW_P1 0x12 +#define NRF_REG_RX_PW_P2 0x13 +#define NRF_REG_RX_PW_P3 0x14 +#define NRF_REG_RX_PW_P4 0x15 +#define NRF_REG_RX_PW_P5 0x16 +#define NRF_REG_FIFO_STATUS 0x17 +// N/A 0x18 +// N/A 0x19 +// N/A 0x1A +// N/A 0x1B +#define NRF_REG_DYNPD 0x1C +#define NRF_REG_FEATURE 0x1D + +/* + * NRF2401 Register Fields + */ + +// CONFIG +#define NRF_REGF_PRIM_RX 0 +#define NRF_REGF_PWR_UP 1 +#define NRF_REGF_CRCO 2 +#define NRF_REGF_EN_CRC 3 +#define NRF_REGF_MASK_MAX_RT 4 +#define NRF_REGF_MASK_TX_DS 5 +#define NRF_REGF_MASK_RX_DR 6 + +// EN_AA +#define NRF_REGF_ENAA_P0 0 +#define NRF_REGF_ENAA_P1 1 +#define NRF_REGF_ENAA_P2 2 +#define NRF_REGF_ENAA_P3 3 +#define NRF_REGF_ENAA_P4 4 +#define NRF_REGF_ENAA_P5 5 + +// EN_RXADDR +#define NRF_REGF_ERX_P0 0 +#define NRF_REGF_ERX_P1 1 +#define NRF_REGF_ERX_P2 2 +#define NRF_REGF_ERX_P3 3 +#define NRF_REGF_ERX_P4 4 +#define NRF_REGF_ERX_P5 5 + +// SETUP_AW +#define NRF_REGF_AW 0 + +// SETUP_RETR +#define NRF_REGF_ARC 0 +#define NRF_REGF_ARD 1 + +// RF_CH +#define NRF_REGF_RF_CH 0 + +// RF_SETUP +#define NRF_REGF_LNA_HCURR 0 +#define NRF_REGF_RF_PWR 1 +#define NRF_REGF_RF_DR 2 +#define NRF_REGF_PLL_LOCK 3 + +// STATUS +#define NRF_REGF_TX_FULL 0 +#define NRF_REGF_RX_P_NO 1 +#define NRF_REGF_MAX_RT 2 +#define NRF_REGF_TX_DS 3 +#define NRF_REGF_RX_DR 4 + +// OBSERVE_TX +#define NRF_REGF_ARC_CNT 0 +#define NRF_REGF_PLOS_CNT 1 + +// CD +#define NRF_REGF_CD 0 + +// ADDR +#define NRF_REGF_ADDR_A 0 +#define NRF_REGF_ADDR_B 1 +#define NRF_REGF_ADDR_C 2 +#define NRF_REGF_ADDR_D 3 +#define NRF_REGF_ADDR_E 4 + +// RX_PW +#define NRF_REGF_PW 0 + +// FIFO_STATUS +#define NRF_REGF_FIFO_RX_EMPTY 0 +#define NRF_REGF_FIFO_RX_FULL 1 +#define NRF_REGF_FIFO_TX_EMPTY 4 +#define NRF_REGF_FIFO_TX_FULL 5 +#define NRF_REGF_FIFO_TX_REUSE 6 + +// DYNPD +#define NRF_REGF_DPL_P0 0 +#define NRF_REGF_DPL_P1 1 +#define NRF_REGF_DPL_P2 2 +#define NRF_REGF_DPL_P3 3 +#define NRF_REGF_DPL_P4 4 +#define NRF_REGF_DPL_P5 5 + +// FEATURE +#define NRF_REGF_EN_DYN_ACK 0 +#define NRF_REGF_EN_ACK_PAY 1 +#define NRF_REGF_EN_DPL 2 + +/** + * Defines how many bits make up a certain value in the register. + */ +typedef struct { +#ifdef NRF_REG_DEF_META + /** + * If META is enabled, the readable name for the bit fiels. + */ + char *name; +#endif + /** + * Number of bits which make up that field. + */ + unsigned char size; +#ifdef NRF_REG_DEF_META + /** + * Defines if the bit field is read-/writable. If set to 1, + * it means read+write access is allowd, otherwise only read + * access is possible to that field. + */ + unsigned char rw; +#endif +} nrf_reg_bits; + +typedef struct { + unsigned char count; + nrf_reg_bits data[]; +} nrf_reg_fields; + +/** + * Definitoin of a register. + */ +typedef struct { +#ifdef NRF_REG_DEF_META + /** + * If META is enabled, the readable name for the register. + */ + char *name; +#endif + /** + * Size of the register in bytes. + */ + unsigned char size; + + /** + * Array of bit-fields which make up this register. + */ + nrf_reg_fields *fields; +} nrf_reg; + +/** + * Definition of all available registers on the nRF24l01. + */ +typedef struct { + /** + * Number of registers in the "data" array. + */ + unsigned char count; + + /** + * Array with registers on the nRF24l01. + */ + nrf_reg data[]; +} nrf_regs; + +/** + * Buffer used to store the data for reading/writing a register. + */ +typedef struct { + /** + * Number of bytes to read/write from/to the + * "data" array. + */ + unsigned char size; + + /** + * The data to read/write to/from the register. + */ + unsigned char data[NRF_MAX_REG_BUF]; +} nrf_reg_buf; + +/** + * Fields of the CONFIG register. + */ +extern nrf_reg_fields nrf_reg_config_fields; + +/** + * Fields of the ENAA register. + */ +extern nrf_reg_fields nrf_reg_enaa_fields; + +/** + * Fields of the EN_RXADDR register. + */ +extern nrf_reg_fields nrf_reg_enrxaddr_fields; + +/** + * Fields of the SETUP_AW register. + */ +extern nrf_reg_fields nrf_reg_setupaw_fields; + +/** + * Fields of the SETUP_RETR register. + */ +extern nrf_reg_fields nrf_reg_setupretr_fields; + +/** + * Fields of the RF_CH register. + */ +extern nrf_reg_fields nrf_reg_rfch_fields; + +/** + * Fields of the RF_SETUP register. + */ +extern nrf_reg_fields nrf_reg_rfsetup_fields; + +/** + * Fields of the STATUS register. + */ +extern nrf_reg_fields nrf_reg_status_fields; + +/** + * Fields of the OBSERVE_TX register. + */ +extern nrf_reg_fields nrf_reg_observetx_fields; + +/** + * Fields of the CD register. + */ +extern nrf_reg_fields nrf_reg_cd_fields; + +/** + * Fields of the ADDR register. + */ +extern nrf_reg_fields nrf_reg_addr_fields; + +/** + * Fields of the RX_PW register. + */ +extern nrf_reg_fields nrf_reg_rxpw_fields; + +/** + * Fields of the FIFO_STAT register. + */ +extern nrf_reg_fields nrf_reg_fifostat_fields; + +/** + * Fields of the DYNPD register. + */ +extern nrf_reg_fields nrf_reg_dynpd_fields; + +/** + * Fields of the FEATURE register. + */ +extern nrf_reg_fields nrf_reg_feature_fields; + +/** + * Complete register definition for the nNRF24l01. + */ +extern nrf_regs nrf_reg_def; + +/** + * Extract the value of a given field for a given register out of the + * given buffer and return it. The buffer has to be read by nrf_read_reg + * first. + * + * @param[in] reg the register definition to use for extracting (one of NRF_REG_*) + * @param[in] regf the field definition to use for extracting (one of NRF_REGF_*) + * @param[in] *buf the buffer containing the content of the register + * @return the value extracted for the field + */ +unsigned char nrf_get_reg_field(unsigned char reg, unsigned char regf, nrf_reg_buf *buf); + +/** + * Write a value to a given field for a given register into the + * given buffer. The buffer has to be read by nrf_read_reg + * first, and written back by nrf_write_reg. + * + * @param[in] reg the register definition to use for extracting (one of NRF_REG_*) + * @param[in] regf the field definition to use for extracting (one of NRF_REGF_*) + * @param[out] *buf the buffer to write the field value to + * @param[in] value the value to write to the field + * @return the value extracted for the field + */ +void nrf_set_reg_field(unsigned char reg, unsigned char regf, nrf_reg_buf *buf, unsigned char value); + +#endif diff --git a/include/libemb/serial/serial.h b/include/libemb/serial/serial.h new file mode 100755 index 00000000..bcbfc972 --- /dev/null +++ b/include/libemb/serial/serial.h @@ -0,0 +1,59 @@ +/* + * This file is part of the libemb project. + * + * Copyright (C) 2011 Stefan Wendler + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef __SERIAL_H_ +#define __SERIAL_H_ + +/** + * Initialize the default USART with the given baudrate. + * + * @param[in] baudrate the baudrate of the USART + */ +void serial_init(unsigned int baudrate); + +/** + * Send a byte non-blocking through the default USART. + * + * @param[in] data byte to send + */ +void serial_send(unsigned char data); + +/** + * Send a byte blocking through the default USART. + * + * @param[in] data byte to send + */ +void serial_send_blocking(unsigned char data); + +/** + * Receive a byte non-blocking from the default USART (makes + * only sense when used in an ISR). + * + * @return byte received + */ +unsigned char serial_recv(); + +/** + * Receive a byte blocking from the default USART. + * + * @return byte received + */ +unsigned char serial_recv_blocking(); + +#endif diff --git a/include/libemb/serial/serial_rb.h b/include/libemb/serial/serial_rb.h new file mode 100755 index 00000000..30191559 --- /dev/null +++ b/include/libemb/serial/serial_rb.h @@ -0,0 +1,107 @@ +/* + * This file is part of the libemb project. + * + * Copyright (C) 2011 Stefan Wendler + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef _SERIALRB_H_ +#define _SERIALRB_H_ + +/** + * Type of elements to be enqued in the ringbuffer. + */ +#define SERIAL_RB_Q unsigned char + +/** + * Definiton of a ringbuffer. + */ +typedef struct { + /** + * Pointer to the memory where the buffer resides. + */ + SERIAL_RB_Q *buffer; + + /** + * Pointer to the current read position within the buffer. + */ + SERIAL_RB_Q *read; + + /** + * Pointer to the current write position within the buffer. + */ + SERIAL_RB_Q *write; + + /** + * Max. number of elements that fit into buffer (buffer size). + */ + unsigned short elements; + + /** + * Number of elements currently queued in the buffer. + */ + unsigned short entries; +} serial_rb; + +/** + * Return the number of free elements in a given buffer. + * + * @return number of free elements in the buffer + */ +unsigned short serial_rb_free(serial_rb *rb); + +/** + * Check if given buffer is full (out of free elements). + * + * @return 1 if full, 0 otherwise + */ +int serial_rb_full(serial_rb *rb); + +/** + * Check if given buffer is empty. + * + * @return 1 if empty, 0 otherwise + */ +int serial_rb_empty(serial_rb *rb); + +/** + * Initialize a given ringbuffer by assigning the given buffer with the number + * of given elements. + * + * @param *rb the ringbuffer to initialize + * @param[in] *buffer the buffer to assign to this rb (must be allocated!) + * @param[in] elements number of elements which could be stored in buffer + */ +void serial_rb_init(serial_rb *rb, SERIAL_RB_Q *buffer, unsigned short elements); + +/** + * Write a given element to a given buffer. Check if buffer has space left + * before adding a new element with {@link serial_rb_full). + * + * @param *rb the ringbuffer to initialize + * @param[in] element the element to add + */ +void serial_rb_write(serial_rb *rb, SERIAL_RB_Q element); + +/** + * Read element from a given buffer. Check if buffer has elements stored + * before reading with {@link serial_rb_empty). + * + * @param *rb the ringbuffer to initialize + * @param[in] element the element to add + */ +SERIAL_RB_Q serial_rb_read(serial_rb *rb); + +#endif // _SERIALRB_H_ diff --git a/include/libemb/shell/shell.h b/include/libemb/shell/shell.h new file mode 100755 index 00000000..4d7473df --- /dev/null +++ b/include/libemb/shell/shell.h @@ -0,0 +1,173 @@ +/* + * This file is part of the libemb project. + * + * Copyright (C) 2011 Stefan Wendler + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef __SHELL_H_ +#define __SHELL_H_ + +/** + * max number of character for a command line passed to the shell + */ +#define SHELL_MAX_CMD_LINE 90 + +/** + * max number of arguments passed with one command to the shell + */ +#define SHELL_MAX_ARGS 5 + +/** + * max number of character for a single argument form a command line passed to the shell + */ +#define SHELL_MAX_ARG_LEN 15 + +/** + * return code given when processing of a command line was OK + */ +#define SHELL_PROCESS_OK 0 + +/** + * ERROR maximum number of arguments was reached + */ +#define SHELL_PROCESS_ERR_ARGS_MAX 0xfff0 + +/** + * ERROR maximum number of chars for an argument was reached + */ +#define SHELL_PROCESS_ERR_ARGS_LEN 0xfff1 + +/** + * ERROR unknown command + */ +#define SHELL_PROCESS_ERR_CMD_UNKN 0xfff2 + +/** + * Single command argument + */ +typedef struct { + /** + * Value representing the argument + */ + char val[SHELL_MAX_ARG_LEN]; +} shell_cmd_arg; + +/** + * All arguments from a single command line + */ +typedef struct { + /** + * Number of arguments + */ + unsigned char count; + + /** + * The arguments + */ + shell_cmd_arg args[SHELL_MAX_ARGS]; +} shell_cmd_args; + +/** + * Definition of a single shell command + */ +typedef struct { + /** + * Name of the command + */ + const char *cmd; + + /** + * Description of the command + */ + const char *desc; + + /** + * Functino called when executing the commmand + */ + int (*func)(shell_cmd_args *args); +} shell_cmd; + +/** + * All shell commands knwon by the shell + */ +typedef struct { + /** + * Number of commands + */ + unsigned char count; + + /** + * The commands + */ + shell_cmd cmds[]; +} shell_cmds; + +/** + * Return the length of a given string. + * + * @param[in] str string for which to calculate the length + * @return length of str + */ +int shell_str_len(char *str); + +/** + * Comapre str1 with given length len1 to str2 with given length len2. + * + * @param[in] str1 first string + * @param[in] str2 second string + * @param[in] len1 length of first string + * @param[in] len2 length of second string + * @return 0 if str1 euqals str2, 1 if len1 != len2, 2 if str1 != str2 + */ +int shell_str_cmp(char *str1, char *str2, int len1, int len2); + +/** + * Parse the integer value from str and return it. + * + * @param[in] str from which to parse the integer value. + * @return the integer value of str + */ +int shell_parse_int(char *str); + +/** + * Process a command line string given in cmd_line against the + * commands given by cmds. If the command form cmd_line matches + * against a command string defined in cmds, the function callback + * for that command is executet. + *
+ * Note: the arguments form the command line are passed to the command + * function, but the command function is responsible for checkeing the arguemts. + * + * @param[in] *cmds pointer to shell commands structure + * @param[in] *cmd_line pointer to command line string + * @return SHELL_PROCESS_OK if command and arguments where understood, + * SHELL_PROCESS_ERR_ARGS_MAX if to many arguments are given, + * SHELL_PROCESS_ERR_ARGS_LEN if an argument string was too long, + * SHELL_PROCESS_ERR_CMD_UNK if the command was unknown + */ +int shell_process_cmds(shell_cmds *cmds, char *cmd_line); + +/** + * Process a command line. For details see {@link shell_process_cmds}. + * This method has to be implemented by a specific shell. The implementation + * must pass a valid {@link shell_cmds} struct to {@link shell_process_cmds}. + * + * @param[in] *cmd_line see {@link shell_process_cmds} + * @return see {@link shell_process_cmds} + */ +int shell_process(char *cmd_line); + +#endif diff --git a/lib/libconio.a b/lib/libconio.a new file mode 100755 index 0000000000000000000000000000000000000000..8e91c35914102fad406507b32b74015386960579 GIT binary patch literal 8212 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 TJ%{4@TJr~ieZ0LEYaRS=dh92y literal 0 HcmV?d00001 diff --git a/lib/libnrf24l01_meta.a b/lib/libnrf24l01_meta.a new file mode 100755 index 0000000000000000000000000000000000000000..6a6c741d1777910736ed2f8b8d20f5878f125bde GIT binary patch literal 26070 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 Cib`An literal 0 HcmV?d00001 diff --git a/lib/libserial.a b/lib/libserial.a new file mode 100755 index 0000000000000000000000000000000000000000..5862ddd4c8727c6b0a1c254305b4dc93ffd42a8a GIT binary patch literal 8516 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 literal 0 HcmV?d00001 diff --git a/main.cpp b/main.cpp new file mode 100755 index 00000000..4a2bce79 --- /dev/null +++ b/main.cpp @@ -0,0 +1,126 @@ +/* + * main.cpp + * + * Created on: May 6, 2013 + * Author: joao + */ + + +#include "rf24/RF24.h" +#include +#include "remote_defines.h" +#include "flash.h" +#include + +extern "C" +{ +#include "conio/conio.h" +#include "serial/serial.h" +#include "timer_msp.h" +} + +#define BLINK_RED_LED P2OUT ^= BIT1; + + +unsigned long int last_blink_millis = 0; + +typedef struct +{ + uint8_t var1; + uint8_t var2; + uint8_t var3; + uint8_t var4; + +}payload; + +payload var; + +// main loop +int main(void) +{ + WDTCTL = WDTPW + WDTHOLD; + + BCSCTL1 = CALBC1_8MHZ; // Set DCO to 1MHz + DCOCTL = CALDCO_8MHZ; + + uint32_t last_millis = 0; + + P2DIR |= BIT1 + BIT0; +// +// serial_init(9600); + + default_timer(); + __bis_SR_register(GIE); + + RF24 radio = RF24(); + + var.var1 = 20; + + + while(millis() < 1000); + + // Radio pipe addresses for the 2 nodes to communicate. + const uint64_t pipes[] = { 0xF0F0F0F0E1LL, 0xF0F0F0F0D2LL }; + + // Setup and configure rf radio + radio.begin(); + + // optionally, increase the delay between retries & # of retries + radio.setRetries(15,1); + + // optionally, reduce the payload size. seems to + // improve reliability + radio.setPayloadSize(sizeof(payload)); + + radio.setDataRate(RF24_250KBPS); + + radio.setChannel(100); + radio.setPALevel(RF24_PA_LOW); + + // Open pipes to other nodes for communication + radio.openWritingPipe(pipes[0]); + radio.openReadingPipe(1,pipes[1]); + + + + // Start listening + radio.startListening(); + + // Dump the configuration of the rf unit for debugging + radio.printDetails(); + + uint32_t dif = 0; + var.var3 = dif/10; + + //radio.setPALevel(RF24_PA_MAX); + while(1) + { + + + if( millis()- last_millis > 100) + { + last_millis = millis(); + BLINK_RED_LED; + + radio.startListening(); + radio.stopListening(); + + var.var2 = last_millis / 1000; + + + radio.write(&var, sizeof(payload)); + + dif = (millis()- last_millis) / 10; + var.var3 = dif; + + } + + } + + + + return 0; + + +} + diff --git a/remote_defines.h b/remote_defines.h new file mode 100755 index 00000000..d96e3e7b --- /dev/null +++ b/remote_defines.h @@ -0,0 +1,47 @@ +/* + * remote_defines.h + * + * Created on: May 9, 2013 + * Author: joao + */ + +#ifndef REMOTE_DEFINES_H_ +#define REMOTE_DEFINES_H_ + +#define COM_DRV_ZERO 690 +#define COM_DRV_FRONT 784 +#define COM_DRV_REAR 598 +#define COM_SERVO_ZERO 645 +#define COM_SERVO_RIGHT 733 +#define COM_SERVO_LEFT 537 +#define ADC_TH 10 + +#define DRV_ZERO 0 +#define DRV_REAR -99 +#define DRV_FRONT 99 + +#define ADC_ANALOG_LEFT 3 +#define ADC_ANALOG_RIGHT 0 + +#define SEND_MSG_TIME 80 + +#define ASK_BIT 0x10 + +typedef struct ROSpberryRemote +{ + int16_t linear; + int16_t steer; + uint8_t buttons; + +}RC_remote; + + +typedef struct Analog_properties +{ + int max; + int min; + int center; + int deadzone; +}Analog; + +#endif /* REMOTE_DEFINES_H_ */ diff --git a/rf24/RF24.cpp b/rf24/RF24.cpp new file mode 100644 index 00000000..68d3668e --- /dev/null +++ b/rf24/RF24.cpp @@ -0,0 +1,992 @@ +/* + Copyright (C) 2011 J. Coliz + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + version 2 as published by the Free Software Foundation. + */ + +#include "nRF24L01.h" +#include "RF24_config.h" +#include "RF24.h" + +extern "C" { +#include "spi.h" +} + +#define LOW 0 +#define HIGH 1 + +/****************************************************************************/ + +void RF24::csn(int mode) +{ + // Minimum ideal SPI bus speed is 2x data rate + // If we assume 2Mbs data rate and 16Mhz clock, a + // divider of 4 is the minimum we want. + // CLK:BUS 8Mhz:2Mhz, 16Mhz:4Mhz, or 20Mhz:5Mhz + //TODO: change speed if necessary + + if (mode) + spi_cs_high(); + else + spi_cs_low(); + +} + +/****************************************************************************/ + +void RF24::ce(int level) +{ + if(level) + spi_ce_high(); + else + spi_ce_low(); +} + +/****************************************************************************/ + +uint8_t RF24::read_register(uint8_t reg, uint8_t* buf, uint8_t len) +{ + uint8_t status; + + csn(LOW); + status = spi_transferByte( R_REGISTER | ( REGISTER_MASK & reg ) ); + while ( len-- ) + *buf++ = spi_transferByte(0xff); + + csn(HIGH); + + return status; +} + +/****************************************************************************/ + +uint8_t RF24::read_register(uint8_t reg) +{ + csn(LOW); + spi_transferByte( R_REGISTER | ( REGISTER_MASK & reg ) ); + uint8_t result = spi_transferByte(0xff); + + csn(HIGH); + return result; +} + +/****************************************************************************/ + +uint8_t RF24::write_register(uint8_t reg, const uint8_t* buf, uint8_t len) +{ + uint8_t status; + + csn(LOW); + status = spi_transferByte( W_REGISTER | ( REGISTER_MASK & reg ) ); + while ( len-- ) + spi_transferByte(*buf++); + + csn(HIGH); + + return status; +} + +/****************************************************************************/ + +uint8_t RF24::write_register(uint8_t reg, uint8_t value) +{ + uint8_t status; + + IF_SERIAL_DEBUG(printf_P(PSTR("write_register(%02x,%02x)\r\n"),reg,value)); + + csn(LOW); + status = spi_transferByte( W_REGISTER | ( REGISTER_MASK & reg ) ); + spi_transferByte(value); + csn(HIGH); + + return status; +} + +/****************************************************************************/ + +uint8_t RF24::write_payload(const void* buf, uint8_t len) +{ + uint8_t status; + + const uint8_t* current = reinterpret_cast(buf); + + uint8_t data_len = min(len,payload_size); + uint8_t blank_len = dynamic_payloads_enabled ? 0 : payload_size - data_len; + + //printf("[Writing %u bytes %u blanks]",data_len,blank_len); + + csn(LOW); + status = spi_transferByte( W_TX_PAYLOAD ); + while ( data_len-- ) + spi_transferByte(*current++); + while ( blank_len-- ) + spi_transferByte(0); + csn(HIGH); + + return status; +} + +/****************************************************************************/ + +uint8_t RF24::read_payload(void* buf, uint8_t len) +{ + uint8_t status; + uint8_t* current = reinterpret_cast(buf); + + uint8_t data_len = min(len,payload_size); + uint8_t blank_len = dynamic_payloads_enabled ? 0 : payload_size - data_len; + + //printf("[Reading %u bytes %u blanks]",data_len,blank_len); + + csn(LOW); + status = spi_transferByte( R_RX_PAYLOAD ); + while ( data_len-- ) + *current++ = spi_transferByte(0xff); + while ( blank_len-- ) + spi_transferByte(0xff); + csn(HIGH); + + return status; +} + +/****************************************************************************/ + +uint8_t RF24::flush_rx(void) +{ + uint8_t status; + + csn(LOW); + status = spi_transferByte( FLUSH_RX ); + csn(HIGH); + + return status; +} + +/****************************************************************************/ + +uint8_t RF24::flush_tx(void) +{ + uint8_t status; + + csn(LOW); + status = spi_transferByte( FLUSH_TX ); + csn(HIGH); + + return status; +} + +/****************************************************************************/ + +uint8_t RF24::get_status(void) +{ + uint8_t status; + + csn(LOW); + status = spi_transferByte( NOP ); + csn(HIGH); + + return status; +} + +/****************************************************************************/ + +void RF24::print_status(uint8_t status) +{ + printf_P(PSTR("STATUS\t\t = 0x%02x RX_DR=%x TX_DS=%x MAX_RT=%x RX_P_NO=%x TX_FULL=%x\r\n"), + status, + (status & _BV(RX_DR))?1:0, + (status & _BV(TX_DS))?1:0, + (status & _BV(MAX_RT))?1:0, + ((status >> RX_P_NO) & 0b111), + (status & _BV(TX_FULL))?1:0 + ); +} + +/****************************************************************************/ + +void RF24::print_observe_tx(uint8_t value) +{ + printf_P(PSTR("OBSERVE_TX=%02x: POLS_CNT=%x ARC_CNT=%x\r\n"), + value, + (value >> PLOS_CNT) & 0b1111, + (value >> ARC_CNT) & 0b1111 + ); +} + +/****************************************************************************/ + +void RF24::print_byte_register(const char* name, uint8_t reg, uint8_t qty) +{ + char extra_tab = strlen_P(name) < 8 ? '\t' : 0; + printf_P(PSTR(PRIPSTR"\t%c ="),name,extra_tab); + while (qty--) + printf_P(PSTR(" 0x%02x"),read_register(reg++)); + printf_P(PSTR("\r\n")); +} + +/****************************************************************************/ + +void RF24::print_address_register(const char* name, uint8_t reg, uint8_t qty) +{ + char extra_tab = strlen_P(name) < 8 ? '\t' : 0; + printf_P(PSTR(PRIPSTR"\t%c ="),name,extra_tab); + + while (qty--) + { + uint8_t buffer[5]; + read_register(reg++,buffer,sizeof buffer); + + printf_P(PSTR(" 0x")); + uint8_t* bufptr = buffer + sizeof buffer; + while( --bufptr >= buffer ) + printf_P(PSTR("%02x"),*bufptr); + } + + printf_P(PSTR("\r\n")); +} + +/****************************************************************************/ + +RF24::RF24(): + wide_band(true), p_variant(false), + payload_size(32), ack_payload_available(false), dynamic_payloads_enabled(false), + pipe0_reading_address(0) +{ +} + +/****************************************************************************/ + +void RF24::setChannel(uint8_t channel) +{ + // TODO: This method could take advantage of the 'wide_band' calculation + // done in setChannel() to require certain channel spacing. + + const uint8_t max_channel = 127; + write_register(RF_CH,min(channel,max_channel)); +} + +/****************************************************************************/ + +void RF24::setPayloadSize(uint8_t size) +{ + const uint8_t max_payload_size = 32; + payload_size = min(size,max_payload_size); +} + +/****************************************************************************/ + +uint8_t RF24::getPayloadSize(void) +{ + return payload_size; +} + +/****************************************************************************/ + +static const char rf24_datarate_e_str_0[] PROGMEM = "1MBPS"; +static const char rf24_datarate_e_str_1[] PROGMEM = "2MBPS"; +static const char rf24_datarate_e_str_2[] PROGMEM = "250KBPS"; +static const char * const rf24_datarate_e_str_P[] PROGMEM = { + rf24_datarate_e_str_0, + rf24_datarate_e_str_1, + rf24_datarate_e_str_2, +}; +static const char rf24_model_e_str_0[] PROGMEM = "nRF24L01"; +static const char rf24_model_e_str_1[] PROGMEM = "nRF24L01+"; +static const char * const rf24_model_e_str_P[] PROGMEM = { + rf24_model_e_str_0, + rf24_model_e_str_1, +}; +static const char rf24_crclength_e_str_0[] PROGMEM = "Disabled"; +static const char rf24_crclength_e_str_1[] PROGMEM = "8 bits"; +static const char rf24_crclength_e_str_2[] PROGMEM = "16 bits" ; +static const char * const rf24_crclength_e_str_P[] PROGMEM = { + rf24_crclength_e_str_0, + rf24_crclength_e_str_1, + rf24_crclength_e_str_2, +}; +static const char rf24_pa_dbm_e_str_0[] PROGMEM = "PA_MIN"; +static const char rf24_pa_dbm_e_str_1[] PROGMEM = "PA_LOW"; +static const char rf24_pa_dbm_e_str_2[] PROGMEM = "LA_MED"; +static const char rf24_pa_dbm_e_str_3[] PROGMEM = "PA_HIGH"; +static const char * const rf24_pa_dbm_e_str_P[] PROGMEM = { + rf24_pa_dbm_e_str_0, + rf24_pa_dbm_e_str_1, + rf24_pa_dbm_e_str_2, + rf24_pa_dbm_e_str_3, +}; + +void RF24::printDetails(void) +{ + print_status(get_status()); + + print_address_register(PSTR("RX_ADDR_P0-1"),RX_ADDR_P0,2); + print_byte_register(PSTR("RX_ADDR_P2-5"),RX_ADDR_P2,4); + print_address_register(PSTR("TX_ADDR"),TX_ADDR); + + print_byte_register(PSTR("RX_PW_P0-6"),RX_PW_P0,6); + print_byte_register(PSTR("EN_AA"),EN_AA); + print_byte_register(PSTR("EN_RXADDR"),EN_RXADDR); + print_byte_register(PSTR("RF_CH"),RF_CH); + print_byte_register(PSTR("RF_SETUP"),RF_SETUP); + print_byte_register(PSTR("CONFIG"),CONFIG); + print_byte_register(PSTR("DYNPD/FEATURE"),DYNPD,2); + + printf_P(PSTR("Data Rate\t = %s\r\n"),pgm_read_word(&rf24_datarate_e_str_P[getDataRate()])); + printf_P(PSTR("Model\t\t = %s\r\n"),pgm_read_word(&rf24_model_e_str_P[isPVariant()])); + printf_P(PSTR("CRC Length\t = %s\r\n"),pgm_read_word(&rf24_crclength_e_str_P[getCRCLength()])); + printf_P(PSTR("PA Power\t = %s\r\n"),pgm_read_word(&rf24_pa_dbm_e_str_P[getPALevel()])); +} + +/****************************************************************************/ + +void RF24::begin(void) +{ + // Initialize SPI bus , CS and CE pins + spi_init(1000000,8); + + ce(LOW); + csn(HIGH); + + // Must allow the radio time to settle else configuration bits will not necessarily stick. + // This is actually only required following power up but some settling time also appears to + // be required after resets too. For full coverage, we'll always assume the worst. + // Enabling 16b CRC is by far the most obvious case if the wrong timing is used - or skipped. + // Technically we require 4.5ms + 14us as a worst case. We'll just call it 5ms for good measure. + // WARNING: Delay is based on P-variant whereby non-P *may* require different timing. + delay( 5 ) ; + + // Set 1500uS (minimum for 32B payload in ESB@250KBPS) timeouts, to make testing a little easier + // WARNING: If this is ever lowered, either 250KBS mode with AA is broken or maximum packet + // sizes must never be used. See documentation for a more complete explanation. + write_register(SETUP_RETR,(0b0100 << ARD) | (0b1111 << ARC)); + + // Restore our default PA level + setPALevel( RF24_PA_MAX ) ; + + // Determine if this is a p or non-p RF24 module and then + // reset our data rate back to default value. This works + // because a non-P variant won't allow the data rate to + // be set to 250Kbps. + if( setDataRate( RF24_250KBPS ) ) + { + p_variant = true ; + } + + // Then set the data rate to the slowest (and most reliable) speed supported by all + // hardware. + setDataRate( RF24_1MBPS ) ; + + // Initialize CRC and request 2-byte (16bit) CRC + setCRCLength( RF24_CRC_16 ) ; + + // Disable dynamic payloads, to match dynamic_payloads_enabled setting + write_register(DYNPD,0); + + // Reset current status + // Notice reset and flush is the last thing we do + write_register(STATUS,_BV(RX_DR) | _BV(TX_DS) | _BV(MAX_RT) ); + + // Set up default configuration. Callers can always change it later. + // This channel should be universally safe and not bleed over into adjacent + // spectrum. + setChannel(76); + + // Flush buffers + flush_rx(); + flush_tx(); +} + +/****************************************************************************/ + +void RF24::startListening(void) +{ + write_register(CONFIG, read_register(CONFIG) | _BV(PWR_UP) | _BV(PRIM_RX)); + write_register(STATUS, _BV(RX_DR) | _BV(TX_DS) | _BV(MAX_RT) ); + + // Restore the pipe0 adddress, if exists + if (pipe0_reading_address) + write_register(RX_ADDR_P0, reinterpret_cast(&pipe0_reading_address), 5); + + // Flush buffers + flush_rx(); + flush_tx(); + + // Go! + ce(HIGH); + + // wait for the radio to come up (130us actually only needed) + delayMicroseconds(130); +} + +/****************************************************************************/ + +void RF24::stopListening(void) +{ + ce(LOW); + flush_tx(); + flush_rx(); +} + +/****************************************************************************/ + +void RF24::powerDown(void) +{ + write_register(CONFIG,read_register(CONFIG) & ~_BV(PWR_UP)); +} + +/****************************************************************************/ + +void RF24::powerUp(void) +{ + write_register(CONFIG,read_register(CONFIG) | _BV(PWR_UP)); +} + +/******************************************************************/ + +bool RF24::write( const void* buf, uint8_t len ) +{ + bool result = false; + + // Begin the write + startWrite(buf,len); + + // ------------ + // At this point we could return from a non-blocking write, and then call + // the rest after an interrupt + + // Instead, we are going to block here until we get TX_DS (transmission completed and ack'd) + // or MAX_RT (maximum retries, transmission failed). Also, we'll timeout in case the radio + // is flaky and we get neither. + + // IN the end, the send should be blocking. It comes back in 60ms worst case, or much faster + // if I tighted up the retry logic. (Default settings will be 1500us. + // Monitor the send + uint8_t observe_tx; + uint8_t status; + uint32_t sent_at = millis(); + const uint32_t timeout = 500; //ms to wait for timeout + do + { + status = read_register(OBSERVE_TX,&observe_tx,1); + IF_SERIAL_DEBUG(Serial.print(observe_tx,HEX)); + } + while( ! ( status & ( _BV(TX_DS) | _BV(MAX_RT) ) ) && ( millis() - sent_at < timeout ) ); + + // The part above is what you could recreate with your own interrupt handler, + // and then call this when you got an interrupt + // ------------ + + // Call this when you get an interrupt + // The status tells us three things + // * The send was successful (TX_DS) + // * The send failed, too many retries (MAX_RT) + // * There is an ack packet waiting (RX_DR) + bool tx_ok, tx_fail; + whatHappened(tx_ok,tx_fail,ack_payload_available); + + //printf("%u%u%u\r\n",tx_ok,tx_fail,ack_payload_available); + + result = tx_ok; + IF_SERIAL_DEBUG(Serial.print(result?"...OK.":"...Failed")); + + // Handle the ack packet + if ( ack_payload_available ) + { + ack_payload_length = getDynamicPayloadSize(); + IF_SERIAL_DEBUG(Serial.print("[AckPacket]/")); + IF_SERIAL_DEBUG(Serial.println(ack_payload_length,DEC)); + } + + // Yay, we are done. + + // Power down + powerDown(); + + // Flush buffers (Is this a relic of past experimentation, and not needed anymore??) + flush_tx(); + + return result; +} +/****************************************************************************/ + +void RF24::startWrite( const void* buf, uint8_t len ) +{ + // Transmitter power-up + write_register(CONFIG, ( read_register(CONFIG) | _BV(PWR_UP) ) & ~_BV(PRIM_RX) ); + delayMicroseconds(150); + + // Send the payload + write_payload( buf, len ); + + // Allons! + ce(HIGH); + delayMicroseconds(15); + ce(LOW); +} + +/****************************************************************************/ + +uint8_t RF24::getDynamicPayloadSize(void) +{ + uint8_t result = 0; + + csn(LOW); + spi_transferByte( R_RX_PL_WID ); + result = spi_transferByte(0xff); + csn(HIGH); + + return result; +} + +/****************************************************************************/ + +bool RF24::available(void) +{ + return available(NULL); +} + +/****************************************************************************/ + +bool RF24::available(uint8_t* pipe_num) +{ + uint8_t status = get_status(); + + // Too noisy, enable if you really want lots o data!! + //IF_SERIAL_DEBUG(print_status(status)); + + bool result = ( status & _BV(RX_DR) ); + + if (result) + { + // If the caller wants the pipe number, include that + if ( pipe_num ) + *pipe_num = ( status >> RX_P_NO ) & 0b111; + + // Clear the status bit + + // ??? Should this REALLY be cleared now? Or wait until we + // actually READ the payload? + + write_register(STATUS,_BV(RX_DR) ); + + // Handle ack payload receipt + if ( status & _BV(TX_DS) ) + { + write_register(STATUS,_BV(TX_DS)); + } + } + + return result; +} + +/****************************************************************************/ + +bool RF24::read( void* buf, uint8_t len ) +{ + // Fetch the payload + read_payload( buf, len ); + + // was this the last of the data available? + return read_register(FIFO_STATUS) & _BV(RX_EMPTY); +} + +/****************************************************************************/ + +void RF24::whatHappened(bool& tx_ok,bool& tx_fail,bool& rx_ready) +{ + // Read the status & reset the status in one easy call + // Or is that such a good idea? + uint8_t status = write_register(STATUS,_BV(RX_DR) | _BV(TX_DS) | _BV(MAX_RT) ); + + // Report to the user what happened + tx_ok = status & _BV(TX_DS); + tx_fail = status & _BV(MAX_RT); + rx_ready = status & _BV(RX_DR); +} + +/****************************************************************************/ + +void RF24::openWritingPipe(uint64_t value) +{ + // Note that AVR 8-bit uC's store this LSB first, and the NRF24L01(+) + // expects it LSB first too, so we're good. + + write_register(RX_ADDR_P0, reinterpret_cast(&value), 5); + write_register(TX_ADDR, reinterpret_cast(&value), 5); + + const uint8_t max_payload_size = 32; + write_register(RX_PW_P0,min(payload_size,max_payload_size)); +} + +/****************************************************************************/ + +static const uint8_t child_pipe[] PROGMEM = +{ + RX_ADDR_P0, RX_ADDR_P1, RX_ADDR_P2, RX_ADDR_P3, RX_ADDR_P4, RX_ADDR_P5 +}; +static const uint8_t child_payload_size[] PROGMEM = +{ + RX_PW_P0, RX_PW_P1, RX_PW_P2, RX_PW_P3, RX_PW_P4, RX_PW_P5 +}; +static const uint8_t child_pipe_enable[] PROGMEM = +{ + ERX_P0, ERX_P1, ERX_P2, ERX_P3, ERX_P4, ERX_P5 +}; + +void RF24::openReadingPipe(uint8_t child, uint64_t address) +{ + // If this is pipe 0, cache the address. This is needed because + // openWritingPipe() will overwrite the pipe 0 address, so + // startListening() will have to restore it. + if (child == 0) + pipe0_reading_address = address; + + if (child <= 6) + { + // For pipes 2-5, only write the LSB + if ( child < 2 ) + write_register(child_pipe[child], reinterpret_cast(&address), 5); + else + write_register(child_pipe[child], reinterpret_cast(&address), 1); + + write_register(child_payload_size[child],payload_size); + + // Note it would be more efficient to set all of the bits for all open + // pipes at once. However, I thought it would make the calling code + // more simple to do it this way. + write_register(EN_RXADDR,read_register(EN_RXADDR) | (1<(buf); + + csn(LOW); + spi_transferByte( W_ACK_PAYLOAD | ( pipe & 0b111 ) ); + const uint8_t max_payload_size = 32; + uint8_t data_len = min(len,max_payload_size); + while ( data_len-- ) + spi_transferByte(*current++); + + csn(HIGH); +} + +/****************************************************************************/ + +bool RF24::isAckPayloadAvailable(void) +{ + bool result = ack_payload_available; + ack_payload_available = false; + return result; +} + +/****************************************************************************/ + +bool RF24::isPVariant(void) +{ + return p_variant ; +} + +/****************************************************************************/ + +void RF24::setAutoAck(bool enable) +{ + if ( enable ) + write_register(EN_AA, 0b111111); + else + write_register(EN_AA, 0); +} + +/****************************************************************************/ + +void RF24::setAutoAck( uint8_t pipe, bool enable ) +{ + if ( pipe <= 6 ) + { + uint8_t en_aa = read_register( EN_AA ) ; + if( enable ) + { + en_aa |= _BV(pipe) ; + } + else + { + en_aa &= ~_BV(pipe) ; + } + write_register( EN_AA, en_aa ) ; + } +} + +/****************************************************************************/ + +bool RF24::testCarrier(void) +{ + return ( read_register(CD) & 1 ); +} + +/****************************************************************************/ + +bool RF24::testRPD(void) +{ + return ( read_register(RPD) & 1 ) ; +} + +/****************************************************************************/ + +void RF24::setPALevel(rf24_pa_dbm_e level) +{ + uint8_t setup = read_register(RF_SETUP) ; + setup &= ~(_BV(RF_PWR_LOW) | _BV(RF_PWR_HIGH)) ; + + // switch uses RAM (evil!) + if ( level == RF24_PA_MAX ) + { + setup |= (_BV(RF_PWR_LOW) | _BV(RF_PWR_HIGH)) ; + } + else if ( level == RF24_PA_HIGH ) + { + setup |= _BV(RF_PWR_HIGH) ; + } + else if ( level == RF24_PA_LOW ) + { + setup |= _BV(RF_PWR_LOW); + } + else if ( level == RF24_PA_MIN ) + { + // nothing + } + else if ( level == RF24_PA_ERROR ) + { + // On error, go to maximum PA + setup |= (_BV(RF_PWR_LOW) | _BV(RF_PWR_HIGH)) ; + } + + write_register( RF_SETUP, setup ) ; +} + +/****************************************************************************/ + +rf24_pa_dbm_e RF24::getPALevel(void) +{ + rf24_pa_dbm_e result = RF24_PA_ERROR ; + uint8_t power = read_register(RF_SETUP) & (_BV(RF_PWR_LOW) | _BV(RF_PWR_HIGH)) ; + + // switch uses RAM (evil!) + if ( power == (_BV(RF_PWR_LOW) | _BV(RF_PWR_HIGH)) ) + { + result = RF24_PA_MAX ; + } + else if ( power == _BV(RF_PWR_HIGH) ) + { + result = RF24_PA_HIGH ; + } + else if ( power == _BV(RF_PWR_LOW) ) + { + result = RF24_PA_LOW ; + } + else + { + result = RF24_PA_MIN ; + } + + return result ; +} + +/****************************************************************************/ + +bool RF24::setDataRate(rf24_datarate_e speed) +{ + bool result = false; + uint8_t setup = read_register(RF_SETUP) ; + + // HIGH and LOW '00' is 1Mbs - our default + wide_band = false ; + setup &= ~(_BV(RF_DR_LOW) | _BV(RF_DR_HIGH)) ; + if( speed == RF24_250KBPS ) + { + // Must set the RF_DR_LOW to 1; RF_DR_HIGH (used to be RF_DR) is already 0 + // Making it '10'. + wide_band = false ; + setup |= _BV( RF_DR_LOW ) ; + } + else + { + // Set 2Mbs, RF_DR (RF_DR_HIGH) is set 1 + // Making it '01' + if ( speed == RF24_2MBPS ) + { + wide_band = true ; + setup |= _BV(RF_DR_HIGH); + } + else + { + // 1Mbs + wide_band = false ; + } + } + write_register(RF_SETUP,setup); + + // Verify our result + if ( read_register(RF_SETUP) == setup ) + { + result = true; + } + else + { + wide_band = false; + } + + return result; +} + +/****************************************************************************/ + +rf24_datarate_e RF24::getDataRate( void ) +{ + rf24_datarate_e result ; + uint8_t dr = read_register(RF_SETUP) & (_BV(RF_DR_LOW) | _BV(RF_DR_HIGH)); + + // switch uses RAM (evil!) + // Order matters in our case below + if ( dr == _BV(RF_DR_LOW) ) + { + // '10' = 250KBPS + result = RF24_250KBPS ; + } + else if ( dr == _BV(RF_DR_HIGH) ) + { + // '01' = 2MBPS + result = RF24_2MBPS ; + } + else + { + // '00' = 1MBPS + result = RF24_1MBPS ; + } + return result ; +} + +/****************************************************************************/ + +void RF24::setCRCLength(rf24_crclength_e length) +{ + uint8_t config = read_register(CONFIG) & ~( _BV(CRCO) | _BV(EN_CRC)) ; + + // switch uses RAM (evil!) + if ( length == RF24_CRC_DISABLED ) + { + // Do nothing, we turned it off above. + } + else if ( length == RF24_CRC_8 ) + { + config |= _BV(EN_CRC); + } + else + { + config |= _BV(EN_CRC); + config |= _BV( CRCO ); + } + write_register( CONFIG, config ) ; +} + +/****************************************************************************/ + +rf24_crclength_e RF24::getCRCLength(void) +{ + rf24_crclength_e result = RF24_CRC_DISABLED; + uint8_t config = read_register(CONFIG) & ( _BV(CRCO) | _BV(EN_CRC)) ; + + if ( config & _BV(EN_CRC ) ) + { + if ( config & _BV(CRCO) ) + result = RF24_CRC_16; + else + result = RF24_CRC_8; + } + + return result; +} + +/****************************************************************************/ + +void RF24::disableCRC( void ) +{ + uint8_t disable = read_register(CONFIG) & ~_BV(EN_CRC) ; + write_register( CONFIG, disable ) ; +} + +/****************************************************************************/ +void RF24::setRetries(uint8_t delay, uint8_t count) +{ + write_register(SETUP_RETR,(delay&0xf)< + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + version 2 as published by the Free Software Foundation. + */ + +/** + * @file RF24.h + * + * Class declaration for RF24 and helper enums + */ + +#ifndef __RF24_H__ +#define __RF24_H__ + +#include + +/** + * Power Amplifier level. + * + * For use with setPALevel() + */ +typedef enum { RF24_PA_MIN = 0,RF24_PA_LOW, RF24_PA_HIGH, RF24_PA_MAX, RF24_PA_ERROR } rf24_pa_dbm_e ; + +/** + * Data rate. How fast data moves through the air. + * + * For use with setDataRate() + */ +typedef enum { RF24_1MBPS = 0, RF24_2MBPS, RF24_250KBPS } rf24_datarate_e; + +/** + * CRC Length. How big (if any) of a CRC is included. + * + * For use with setCRCLength() + */ +typedef enum { RF24_CRC_DISABLED = 0, RF24_CRC_8, RF24_CRC_16 } rf24_crclength_e; + +/** + * Driver for nRF24L01(+) 2.4GHz Wireless Transceiver + */ + +class RF24 +{ +private: + uint8_t ce_pin; /**< "Chip Enable" pin, activates the RX or TX role */ + uint8_t csn_pin; /**< SPI Chip select */ + bool wide_band; /* 2Mbs data rate in use? */ + bool p_variant; /* False for RF24L01 and true for RF24L01P */ + uint8_t payload_size; /**< Fixed size of payloads */ + bool ack_payload_available; /**< Whether there is an ack payload waiting */ + bool dynamic_payloads_enabled; /**< Whether dynamic payloads are enabled. */ + uint8_t ack_payload_length; /**< Dynamic size of pending ack payload. */ + uint64_t pipe0_reading_address; /**< Last address set on pipe 0 for reading. */ + +protected: + /** + * @name Low-level internal interface. + * + * Protected methods that address the chip directly. Regular users cannot + * ever call these. They are documented for completeness and for developers who + * may want to extend this class. + */ + /**@{*/ + + /** + * Set chip select pin + * + * Running SPI bus at PI_CLOCK_DIV2 so we don't waste time transferring data + * and best of all, we make use of the radio's FIFO buffers. A lower speed + * means we're less likely to effectively leverage our FIFOs and pay a higher + * AVR runtime cost as toll. + * + * @param mode HIGH to take this unit off the SPI bus, LOW to put it on + */ + void csn(int mode); + + /** + * Set chip enable + * + * @param level HIGH to actively begin transmission or LOW to put in standby. Please see data sheet + * for a much more detailed description of this pin. + */ + void ce(int level); + + /** + * Read a chunk of data in from a register + * + * @param reg Which register. Use constants from nRF24L01.h + * @param buf Where to put the data + * @param len How many bytes of data to transfer + * @return Current value of status register + */ + uint8_t read_register(uint8_t reg, uint8_t* buf, uint8_t len); + + /** + * Read single byte from a register + * + * @param reg Which register. Use constants from nRF24L01.h + * @return Current value of register @p reg + */ + uint8_t read_register(uint8_t reg); + + /** + * Write a chunk of data to a register + * + * @param reg Which register. Use constants from nRF24L01.h + * @param buf Where to get the data + * @param len How many bytes of data to transfer + * @return Current value of status register + */ + uint8_t write_register(uint8_t reg, const uint8_t* buf, uint8_t len); + + /** + * Write a single byte to a register + * + * @param reg Which register. Use constants from nRF24L01.h + * @param value The new value to write + * @return Current value of status register + */ + uint8_t write_register(uint8_t reg, uint8_t value); + + /** + * Write the transmit payload + * + * The size of data written is the fixed payload size, see getPayloadSize() + * + * @param buf Where to get the data + * @param len Number of bytes to be sent + * @return Current value of status register + */ + uint8_t write_payload(const void* buf, uint8_t len); + + /** + * Read the receive payload + * + * The size of data read is the fixed payload size, see getPayloadSize() + * + * @param buf Where to put the data + * @param len Maximum number of bytes to read + * @return Current value of status register + */ + uint8_t read_payload(void* buf, uint8_t len); + + /** + * Empty the receive buffer + * + * @return Current value of status register + */ + uint8_t flush_rx(void); + + /** + * Empty the transmit buffer + * + * @return Current value of status register + */ + uint8_t flush_tx(void); + + /** + * Retrieve the current status of the chip + * + * @return Current value of status register + */ + uint8_t get_status(void); + + /** + * Decode and print the given status to stdout + * + * @param status Status value to print + * + * @warning Does nothing if stdout is not defined. See fdevopen in stdio.h + */ + void print_status(uint8_t status); + + /** + * Decode and print the given 'observe_tx' value to stdout + * + * @param value The observe_tx value to print + * + * @warning Does nothing if stdout is not defined. See fdevopen in stdio.h + */ + void print_observe_tx(uint8_t value); + + /** + * Print the name and value of an 8-bit register to stdout + * + * Optionally it can print some quantity of successive + * registers on the same line. This is useful for printing a group + * of related registers on one line. + * + * @param name Name of the register + * @param reg Which register. Use constants from nRF24L01.h + * @param qty How many successive registers to print + */ + void print_byte_register(const char* name, uint8_t reg, uint8_t qty = 1); + + /** + * Print the name and value of a 40-bit address register to stdout + * + * Optionally it can print some quantity of successive + * registers on the same line. This is useful for printing a group + * of related registers on one line. + * + * @param name Name of the register + * @param reg Which register. Use constants from nRF24L01.h + * @param qty How many successive registers to print + */ + void print_address_register(const char* name, uint8_t reg, uint8_t qty = 1); + + /** + * Turn on or off the special features of the chip + * + * The chip has certain 'features' which are only available when the 'features' + * are enabled. See the datasheet for details. + */ + void toggle_features(void); + /**@}*/ + +public: + /** + * @name Primary public interface + * + * These are the main methods you need to operate the chip + */ + /**@{*/ + + /** + * Constructor + * + * Creates a new instance of this driver. Before using, you create an instance. + * + */ + RF24(); + + /** + * Begin operation of the chip + * + * Call this in setup(), before calling any other methods. + */ + void begin(void); + + /** + * Start listening on the pipes opened for reading. + * + * Be sure to call openReadingPipe() first. Do not call write() while + * in this mode, without first calling stopListening(). Call + * isAvailable() to check for incoming traffic, and read() to get it. + */ + void startListening(void); + + /** + * Stop listening for incoming messages + * + * Do this before calling write(). + */ + void stopListening(void); + + /** + * Write to the open writing pipe + * + * Be sure to call openWritingPipe() first to set the destination + * of where to write to. + * + * This blocks until the message is successfully acknowledged by + * the receiver or the timeout/retransmit maxima are reached. In + * the current configuration, the max delay here is 60ms. + * + * The maximum size of data written is the fixed payload size, see + * getPayloadSize(). However, you can write less, and the remainder + * will just be filled with zeroes. + * + * @param buf Pointer to the data to be sent + * @param len Number of bytes to be sent + * @return True if the payload was delivered successfully false if not + */ + bool write( const void* buf, uint8_t len ); + + /** + * Test whether there are bytes available to be read + * + * @return True if there is a payload available, false if none is + */ + bool available(void); + + /** + * Read the payload + * + * Return the last payload received + * + * The size of data read is the fixed payload size, see getPayloadSize() + * + * @note I specifically chose 'void*' as a data type to make it easier + * for beginners to use. No casting needed. + * + * @param buf Pointer to a buffer where the data should be written + * @param len Maximum number of bytes to read into the buffer + * @return True if the payload was delivered successfully false if not + */ + bool read( void* buf, uint8_t len ); + + /** + * Open a pipe for writing + * + * Only one pipe can be open at once, but you can change the pipe + * you'll listen to. Do not call this while actively listening. + * Remember to stopListening() first. + * + * Addresses are 40-bit hex values, e.g.: + * + * @code + * openWritingPipe(0xF0F0F0F0F0); + * @endcode + * + * @param address The 40-bit address of the pipe to open. This can be + * any value whatsoever, as long as you are the only one writing to it + * and only one other radio is listening to it. Coordinate these pipe + * addresses amongst nodes on the network. + */ + void openWritingPipe(uint64_t address); + + /** + * Open a pipe for reading + * + * Up to 6 pipes can be open for reading at once. Open all the + * reading pipes, and then call startListening(). + * + * @see openWritingPipe + * + * @warning Pipes 1-5 should share the first 32 bits. + * Only the least significant byte should be unique, e.g. + * @code + * openReadingPipe(1,0xF0F0F0F0AA); + * openReadingPipe(2,0xF0F0F0F066); + * @endcode + * + * @warning Pipe 0 is also used by the writing pipe. So if you open + * pipe 0 for reading, and then startListening(), it will overwrite the + * writing pipe. Ergo, do an openWritingPipe() again before write(). + * + * @todo Enforce the restriction that pipes 1-5 must share the top 32 bits + * + * @param number Which pipe# to open, 0-5. + * @param address The 40-bit address of the pipe to open. + */ + void openReadingPipe(uint8_t number, uint64_t address); + + /**@}*/ + /** + * @name Optional Configurators + * + * Methods you can use to get or set the configuration of the chip. + * None are required. Calling begin() sets up a reasonable set of + * defaults. + */ + /**@{*/ + /** + * Set the number and delay of retries upon failed submit + * + * @param delay How long to wait between each retry, in multiples of 250us, + * max is 15. 0 means 250us, 15 means 4000us. + * @param count How many retries before giving up, max 15 + */ + void setRetries(uint8_t delay, uint8_t count); + + /** + * Set RF communication channel + * + * @param channel Which RF channel to communicate on, 0-127 + */ + void setChannel(uint8_t channel); + + /** + * Set Static Payload Size + * + * This implementation uses a pre-stablished fixed payload size for all + * transmissions. If this method is never called, the driver will always + * transmit the maximum payload size (32 bytes), no matter how much + * was sent to write(). + * + * @todo Implement variable-sized payloads feature + * + * @param size The number of bytes in the payload + */ + void setPayloadSize(uint8_t size); + + /** + * Get Static Payload Size + * + * @see setPayloadSize() + * + * @return The number of bytes in the payload + */ + uint8_t getPayloadSize(void); + + /** + * Get Dynamic Payload Size + * + * For dynamic payloads, this pulls the size of the payload off + * the chip + * + * @return Payload length of last-received dynamic payload + */ + uint8_t getDynamicPayloadSize(void); + + /** + * Enable custom payloads on the acknowledge packets + * + * Ack payloads are a handy way to return data back to senders without + * manually changing the radio modes on both units. + * + * @see examples/pingpair_pl/pingpair_pl.pde + */ + void enableAckPayload(void); + + /** + * Enable dynamically-sized payloads + * + * This way you don't always have to send large packets just to send them + * once in a while. This enables dynamic payloads on ALL pipes. + * + * @see examples/pingpair_pl/pingpair_dyn.pde + */ + void enableDynamicPayloads(void); + + /** + * Determine whether the hardware is an nRF24L01+ or not. + * + * @return true if the hardware is nRF24L01+ (or compatible) and false + * if its not. + */ + bool isPVariant(void) ; + + /** + * Enable or disable auto-acknowlede packets + * + * This is enabled by default, so it's only needed if you want to turn + * it off for some reason. + * + * @param enable Whether to enable (true) or disable (false) auto-acks + */ + void setAutoAck(bool enable); + + /** + * Enable or disable auto-acknowlede packets on a per pipeline basis. + * + * AA is enabled by default, so it's only needed if you want to turn + * it off/on for some reason on a per pipeline basis. + * + * @param pipe Which pipeline to modify + * @param enable Whether to enable (true) or disable (false) auto-acks + */ + void setAutoAck( uint8_t pipe, bool enable ) ; + + /** + * Set Power Amplifier (PA) level to one of four levels. + * Relative mnemonics have been used to allow for future PA level + * changes. According to 6.5 of the nRF24L01+ specification sheet, + * they translate to: RF24_PA_MIN=-18dBm, RF24_PA_LOW=-12dBm, + * RF24_PA_MED=-6dBM, and RF24_PA_HIGH=0dBm. + * + * @param level Desired PA level. + */ + void setPALevel( rf24_pa_dbm_e level ) ; + + /** + * Fetches the current PA level. + * + * @return Returns a value from the rf24_pa_dbm_e enum describing + * the current PA setting. Please remember, all values represented + * by the enum mnemonics are negative dBm. See setPALevel for + * return value descriptions. + */ + rf24_pa_dbm_e getPALevel( void ) ; + + /** + * Set the transmission data rate + * + * @warning setting RF24_250KBPS will fail for non-plus units + * + * @param speed RF24_250KBPS for 250kbs, RF24_1MBPS for 1Mbps, or RF24_2MBPS for 2Mbps + * @return true if the change was successful + */ + bool setDataRate(rf24_datarate_e speed); + + /** + * Fetches the transmission data rate + * + * @return Returns the hardware's currently configured datarate. The value + * is one of 250kbs, RF24_1MBPS for 1Mbps, or RF24_2MBPS, as defined in the + * rf24_datarate_e enum. + */ + rf24_datarate_e getDataRate( void ) ; + + /** + * Set the CRC length + * + * @param length RF24_CRC_8 for 8-bit or RF24_CRC_16 for 16-bit + */ + void setCRCLength(rf24_crclength_e length); + + /** + * Get the CRC length + * + * @return RF24_DISABLED if disabled or RF24_CRC_8 for 8-bit or RF24_CRC_16 for 16-bit + */ + rf24_crclength_e getCRCLength(void); + + /** + * Disable CRC validation + * + */ + void disableCRC( void ) ; + + /**@}*/ + /** + * @name Advanced Operation + * + * Methods you can use to drive the chip in more advanced ways + */ + /**@{*/ + + /** + * Print a giant block of debugging information to stdout + * + * @warning Does nothing if stdout is not defined. See fdevopen in stdio.h + */ + void printDetails(void); + + /** + * Enter low-power mode + * + * To return to normal power mode, either write() some data or + * startListening, or powerUp(). + */ + void powerDown(void); + + /** + * Leave low-power mode - making radio more responsive + * + * To return to low power mode, call powerDown(). + */ + void powerUp(void) ; + + /** + * Test whether there are bytes available to be read + * + * Use this version to discover on which pipe the message + * arrived. + * + * @param[out] pipe_num Which pipe has the payload available + * @return True if there is a payload available, false if none is + */ + bool available(uint8_t* pipe_num); + + /** + * Non-blocking write to the open writing pipe + * + * Just like write(), but it returns immediately. To find out what happened + * to the send, catch the IRQ and then call whatHappened(). + * + * @see write() + * @see whatHappened() + * + * @param buf Pointer to the data to be sent + * @param len Number of bytes to be sent + * @return True if the payload was delivered successfully false if not + */ + void startWrite( const void* buf, uint8_t len ); + + /** + * Write an ack payload for the specified pipe + * + * The next time a message is received on @p pipe, the data in @p buf will + * be sent back in the acknowledgement. + * + * @warning According to the data sheet, only three of these can be pending + * at any time. I have not tested this. + * + * @param pipe Which pipe# (typically 1-5) will get this response. + * @param buf Pointer to data that is sent + * @param len Length of the data to send, up to 32 bytes max. Not affected + * by the static payload set by setPayloadSize(). + */ + void writeAckPayload(uint8_t pipe, const void* buf, uint8_t len); + + /** + * Determine if an ack payload was received in the most recent call to + * write(). + * + * Call read() to retrieve the ack payload. + * + * @warning Calling this function clears the internal flag which indicates + * a payload is available. If it returns true, you must read the packet + * out as the very next interaction with the radio, or the results are + * undefined. + * + * @return True if an ack payload is available. + */ + bool isAckPayloadAvailable(void); + + /** + * Call this when you get an interrupt to find out why + * + * Tells you what caused the interrupt, and clears the state of + * interrupts. + * + * @param[out] tx_ok The send was successful (TX_DS) + * @param[out] tx_fail The send failed, too many retries (MAX_RT) + * @param[out] rx_ready There is a message waiting to be read (RX_DS) + */ + void whatHappened(bool& tx_ok,bool& tx_fail,bool& rx_ready); + + /** + * Test whether there was a carrier on the line for the + * previous listening period. + * + * Useful to check for interference on the current channel. + * + * @return true if was carrier, false if not + */ + bool testCarrier(void); + + /** + * Test whether a signal (carrier or otherwise) greater than + * or equal to -64dBm is present on the channel. Valid only + * on nRF24L01P (+) hardware. On nRF24L01, use testCarrier(). + * + * Useful to check for interference on the current channel and + * channel hopping strategies. + * + * @return true if signal => -64dBm, false if not + */ + bool testRPD(void) ; + + /** + * Test whether this is a real radio, or a mock shim for + * debugging. Setting either pin to 0xff is the way to + * indicate that this is not a real radio. + * + * @return true if this is a legitimate radio + */ + bool isValid() { return ce_pin != 0xff && csn_pin != 0xff; } + + /**@}*/ +}; + +/** + * @example GettingStarted.pde + * + * This is an example which corresponds to my "Getting Started" blog post: + * Getting Started with nRF24L01+ on Arduino. + * + * It is an example of how to use the RF24 class. Write this sketch to two + * different nodes. Put one of the nodes into 'transmit' mode by connecting + * with the serial monitor and sending a 'T'. The ping node sends the current + * time to the pong node, which responds by sending the value back. The ping + * node can then see how long the whole cycle took. + */ + +/** + * @example nordic_fob.pde + * + * This is an example of how to use the RF24 class to receive signals from the + * Sparkfun Nordic FOB. See http://www.sparkfun.com/products/8602 . + * Thanks to Kirk Mower for providing test hardware. + */ + +/** + * @example led_remote.pde + * + * This is an example of how to use the RF24 class to control a remote + * bank of LED's using buttons on a remote control. + * + * Every time the buttons change on the remote, the entire state of + * buttons is send to the led board, which displays the state. + */ + +/** + * @example pingpair.pde + * + * This is an example of how to use the RF24 class. Write this sketch to two + * different nodes, connect the role_pin to ground on one. The ping node sends + * the current time to the pong node, which responds by sending the value back. + * The ping node can then see how long the whole cycle took. + */ + +/** + * @example pingpair_maple.pde + * + * This is an example of how to use the RF24 class on the Maple. For a more + * detailed explanation, see my blog post: + * nRF24L01+ Running on Maple + * + * It will communicate well to an Arduino-based unit as well, so it's not for only Maple-to-Maple communication. + * + * Write this sketch to two different nodes, + * connect the role_pin to ground on one. The ping node sends the current time to the pong node, + * which responds by sending the value back. The ping node can then see how long the whole cycle + * took. + */ + +/** + * @example starping.pde + * + * This sketch is a more complex example of using the RF24 library for Arduino. + * Deploy this on up to six nodes. Set one as the 'pong receiver' by tying the + * role_pin low, and the others will be 'ping transmit' units. The ping units + * unit will send out the value of millis() once a second. The pong unit will + * respond back with a copy of the value. Each ping unit can get that response + * back, and determine how long the whole cycle took. + * + * This example requires a bit more complexity to determine which unit is which. + * The pong receiver is identified by having its role_pin tied to ground. + * The ping senders are further differentiated by a byte in eeprom. + */ + +/** + * @example pingpair_pl.pde + * + * This is an example of how to do two-way communication without changing + * transmit/receive modes. Here, a payload is set to the transmitter within + * the Ack packet of each transmission. Note that the payload is set BEFORE + * the sender's message arrives. + */ + +/** + * @example pingpair_irq.pde + * + * This is an example of how to user interrupts to interact with the radio. + * It builds on the pingpair_pl example, and uses ack payloads. + */ + +/** + * @example pingpair_sleepy.pde + * + * This is an example of how to use the RF24 class to create a battery- + * efficient system. It is just like the pingpair.pde example, but the + * ping node powers down the radio and sleeps the MCU after every + * ping/pong cycle. + */ + +/** + * @example scanner.pde + * + * Example to detect interference on the various channels available. + * This is a good diagnostic tool to check whether you're picking a + * good channel for your application. + * + * Inspired by cpixip. + * See http://arduino.cc/forum/index.php/topic,54795.0.html + */ + +/** + * @mainpage Driver for nRF24L01(+) 2.4GHz Wireless Transceiver + * + * @section Goals Design Goals + * + * This library is designed to be... + * @li Maximally compliant with the intended operation of the chip + * @li Easy for beginners to use + * @li Consumed with a public interface that's similiar to other Arduino standard libraries + * + * @section News News + * + * NOW COMPATIBLE WITH ARDUINO 1.0 - The 'master' branch and all examples work with both Arduino 1.0 and earlier versions. + * Please open an issue if you find any problems using it with any version of Arduino. + * + * NOW COMPATIBLE WITH MAPLE - RF24 has been tested with the + * Maple Native, + * and should work with any Maple board. See the pingpair_maple example. + * Note that only the pingpair_maple example has been tested on Maple, although + * the others can certainly be adapted. + * + * @section Useful Useful References + * + * Please refer to: + * + * @li Documentation Main Page + * @li RF24 Class Documentation + * @li Source Code + * @li Downloads Page + * @li Chip Datasheet + * + * This chip uses the SPI bus, plus two chip control pins. Remember that pin 10 must still remain an output, or + * the SPI hardware will go into 'slave' mode. + * + * @section More More Information + * + * @subpage FAQ + * + * @section Projects Projects + * + * Stuff I have built with RF24 + * + * RF24 Getting Started - Finished Product + * + * Getting Started with nRF24L01+ on Arduino + * + * Nordic FOB and nRF24L01+ + * + * Using the Sparkfun Nordic FOB + * + * RF Duinode V3 (2V4) + * + * Low-Power Wireless Sensor Node + * + * nRF24L01+ connected to Leaf Labs Maple Native + * + * nRF24L01+ Running on Maple + */ + +#endif // __RF24_H__ +// vim:ai:cin:sts=2 sw=2 ft=cpp + diff --git a/rf24/RF24_config.h b/rf24/RF24_config.h new file mode 100644 index 00000000..4ff19fbd --- /dev/null +++ b/rf24/RF24_config.h @@ -0,0 +1,112 @@ + +/* + Copyright (C) 2011 J. Coliz + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + version 2 as published by the Free Software Foundation. + */ + +#ifndef __RF24_CONFIG_H__ +#define __RF24_CONFIG_H__ + +#include + +// Stuff that is normally provided by Arduino +#ifdef ARDUINO +#include +#if ARDUINO < 100 +#include +#else +#include +#endif +#elif defined(MSP430) +#include +extern "C"{ +#include "conio/conio.h" +#include "timer_msp.h" +} +#include +#include +#include +//extern HardwareSPI SPI; +#define _BV(x) (1<<(x)) +#else +#include +#include +#include +//extern HardwareSPI SPI; +#define _BV(x) (1<<(x)) +#endif + +#undef SERIAL_DEBUG +#ifdef SERIAL_DEBUG +#define IF_SERIAL_DEBUG(x) ({x;}) +#else +#define IF_SERIAL_DEBUG(x) +#endif + +// Avoid spurious warnings +#if 1 +#if ! defined( NATIVE ) && defined( ARDUINO ) +#undef PROGMEM +#define PROGMEM __attribute__(( section(".progmem.data") )) +#undef PSTR +#define PSTR(s) (__extension__({static const char __c[] PROGMEM = (s); &__c[0];})) +#endif +#endif + +// Progmem is Arduino-specific +#ifdef ARDUINO +#include +#define PRIPSTR "%S" +#elif defined(STELLARIS) +extern "C"{ +#include "utils/uartstdio.h" +extern uint32_t millis(); +#define printf_P UARTprintf +} +typedef uint16_t prog_uint16_t; +#define PSTR(x) (x) +#define strlen_P strlen +#define PROGMEM +#define pgm_read_word(p) (*(p)) +#define PRIPSTR "%s" + +#elif defined(MSP430) + +//extern unsigned long int millis(); +#define PSTR(x) (x) //ver isto +#define strlen_P strlen +#define printf_P cio_printf +#define PROGMEM +#define pgm_read_word(p) (*(p)) +#define PRIPSTR "%s" + +#else +typedef char const char; +typedef uint16_t prog_uint16_t; +#define PSTR(x) (x) +#define printf_P printf +#define strlen_P strlen +#define PROGMEM +#define pgm_read_word(p) (*(p)) +#define PRIPSTR "%s" +#endif + +#ifndef ARDUINO + +#define max(a,b) \ + ({ __typeof__ (a) _a = (a); \ + __typeof__ (b) _b = (b); \ + _a > _b ? _a : _b; }) + +#define min(a,b) \ + ({ __typeof__ (a) _a = (a); \ + __typeof__ (b) _b = (b); \ + _a < _b ? _a : _b; }) + +#endif + +#endif // __RF24_CONFIG_H__ +// vim:ai:cin:sts=2 sw=2 ft=cpp diff --git a/rf24/nRF24L01.h b/rf24/nRF24L01.h new file mode 100644 index 00000000..2012ce6e --- /dev/null +++ b/rf24/nRF24L01.h @@ -0,0 +1,125 @@ +/* + Copyright (c) 2007 Stefan Engelke + + Permission is hereby granted, free of charge, to any person + obtaining a copy of this software and associated documentation + files (the "Software"), to deal in the Software without + restriction, including without limitation the rights to use, copy, + modify, merge, publish, distribute, sublicense, and/or sell copies + of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. +*/ + +/* Memory Map */ +#define CONFIG 0x00 +#define EN_AA 0x01 +#define EN_RXADDR 0x02 +#define SETUP_AW 0x03 +#define SETUP_RETR 0x04 +#define RF_CH 0x05 +#define RF_SETUP 0x06 +#define STATUS 0x07 +#define OBSERVE_TX 0x08 +#define CD 0x09 +#define RX_ADDR_P0 0x0A +#define RX_ADDR_P1 0x0B +#define RX_ADDR_P2 0x0C +#define RX_ADDR_P3 0x0D +#define RX_ADDR_P4 0x0E +#define RX_ADDR_P5 0x0F +#define TX_ADDR 0x10 +#define RX_PW_P0 0x11 +#define RX_PW_P1 0x12 +#define RX_PW_P2 0x13 +#define RX_PW_P3 0x14 +#define RX_PW_P4 0x15 +#define RX_PW_P5 0x16 +#define FIFO_STATUS 0x17 +#define DYNPD 0x1C +#define FEATURE 0x1D + +/* Bit Mnemonics */ +#define MASK_RX_DR 6 +#define MASK_TX_DS 5 +#define MASK_MAX_RT 4 +#define EN_CRC 3 +#define CRCO 2 +#define PWR_UP 1 +#define PRIM_RX 0 +#define ENAA_P5 5 +#define ENAA_P4 4 +#define ENAA_P3 3 +#define ENAA_P2 2 +#define ENAA_P1 1 +#define ENAA_P0 0 +#define ERX_P5 5 +#define ERX_P4 4 +#define ERX_P3 3 +#define ERX_P2 2 +#define ERX_P1 1 +#define ERX_P0 0 +#define AW 0 +#define ARD 4 +#define ARC 0 +#define PLL_LOCK 4 +#define RF_DR 3 +#define RF_PWR 6 +#define RX_DR 6 +#define TX_DS 5 +#define MAX_RT 4 +#define RX_P_NO 1 +#define TX_FULL 0 +#define PLOS_CNT 4 +#define ARC_CNT 0 +#define TX_REUSE 6 +#define FIFO_FULL 5 +#define TX_EMPTY 4 +#define RX_FULL 1 +#define RX_EMPTY 0 +#define DPL_P5 5 +#define DPL_P4 4 +#define DPL_P3 3 +#define DPL_P2 2 +#define DPL_P1 1 +#define DPL_P0 0 +#define EN_DPL 2 +#define EN_ACK_PAY 1 +#define EN_DYN_ACK 0 + +/* Instruction Mnemonics */ +#define R_REGISTER 0x00 +#define W_REGISTER 0x20 +#define REGISTER_MASK 0x1F +#define ACTIVATE 0x50 +#define R_RX_PL_WID 0x60 +#define R_RX_PAYLOAD 0x61 +#define W_TX_PAYLOAD 0xA0 +#define W_ACK_PAYLOAD 0xA8 +#define FLUSH_TX 0xE1 +#define FLUSH_RX 0xE2 +#define REUSE_TX_PL 0xE3 +#define NOP 0xFF + +/* Non-P omissions */ +#define LNA_HCURR 0 + +/* P model memory Map */ +#define RPD 0x09 + +/* P model bit Mnemonics */ +#define RF_DR_LOW 5 +#define RF_DR_HIGH 3 +#define RF_PWR_LOW 1 +#define RF_PWR_HIGH 2 diff --git a/rf24/spi-msp430.c b/rf24/spi-msp430.c new file mode 100755 index 00000000..65510e23 --- /dev/null +++ b/rf24/spi-msp430.c @@ -0,0 +1,91 @@ +/* + * spi.c + * + * Created on: Apr 21, 2013 + * Author: bgouveia + */ + +#include + +#include "spi.h" +#include "spi_msp430.h" + + + + + +void spi_init(unsigned long bitrate,unsigned long datawidth){ + //SSI + + + UCB0CTL1 = UCSWRST; + + CS_DIR |= CS_PIN; + CS_PORT |= CS_PIN; + CE_DIR |= CE_PIN; + CE_PORT|= CE_PIN; + + IRQ_DIR &= ~IRQ_PIN; + + + P1SEL |= SOMI_PIN + SIMO_PIN + SCLK_PIN; + P1SEL2 |= SOMI_PIN + SIMO_PIN + SCLK_PIN; + + // 3-pin, 8-bit SPI master + UCB0CTL0 |= UCCKPH + UCMSB + UCMST + UCSYNC; + UCB0CTL1 |= UCSSEL_2; // SMCLK + + UCB0CTL1 &= ~UCSWRST; + + +} + +void spi_cs_low() +{ + CS_PORT &= ~CS_PIN; + +} + +void spi_cs_high() +{ + CS_PORT |= CS_PIN; +} + +void spi_ce_low() +{ + CE_PORT &= ~CE_PIN; + +} + +void spi_ce_high() +{ + CE_PORT |= CE_PIN; +} + + +uint8_t spi_transferByte(uint8_t data) +{ + + UCB0TXBUF = data; + + // wait for TX + while (!(IFG2 & UCB0TXIFG)); + + return UCB0RXBUF; + +} + +/*void delay(unsigned long msec) +{ + while(msec--) + { + __delay_cycles(1000); + } +} +void delayMicroseconds(unsigned long usec) +{ + while(usec--) + { + __delay_cycles(1); + } +}*/ diff --git a/rf24/spi.h b/rf24/spi.h new file mode 100755 index 00000000..8f114c78 --- /dev/null +++ b/rf24/spi.h @@ -0,0 +1,26 @@ +/* + * spi.h + * + * Created on: Apr 21, 2013 + * Author: bgouveia + */ + +#ifndef SPI_H_ +#define SPI_H_ + +#include + +void spi_init(unsigned long bitrate,unsigned long datawidth); +uint8_t spi_transferByte(uint8_t data); + +void spi_cs_low(); +void spi_cs_high(); + +void spi_ce_low(); +void spi_ce_high(); + +void delay(unsigned long msec); +void delayMicroseconds(unsigned long usec); + + +#endif /* SPI_H_ */ diff --git a/rf24/spi_msp430.h b/rf24/spi_msp430.h new file mode 100755 index 00000000..46ba141f --- /dev/null +++ b/rf24/spi_msp430.h @@ -0,0 +1,35 @@ +/* + * spi_msp430.h + * + * Created on: May 29, 2013 + * Author: joao + */ + +#ifndef SPI_MSP430_H_ +#define SPI_MSP430_H_ + +#include + +//#define CS_PIN_BASE P1OUT +#define CS_PORT P2OUT +#define CS_DIR P2DIR +#define CS_PIN BIT2 + +#define SIMO_PIN BIT7 +#define SOMI_PIN BIT6 +#define SCLK_PIN BIT5 + +//#define CE_PIN_BASE P1OUT +#define CE_PIN BIT3 +#define CE_PORT P2OUT +#define CE_DIR P2DIR + +#define IRQ_PIN BIT3 +#define IRQ_PORT P1OUT +#define IRQ_DIR P1DIR + +#define POWER_DIR P1DIR +#define POWER_PORT P1OUT +#define POWER_PIN BIT1 + +#endif /* SPI_MSP430_H_ */ diff --git a/timer_msp.c b/timer_msp.c new file mode 100755 index 00000000..9f15db8e --- /dev/null +++ b/timer_msp.c @@ -0,0 +1,80 @@ +/* + * timer_msp.c + * + * Created on: 30 de Dez de 2012 + * Author: Asus + */ + +#include "timer_msp.h" +#include "msp430g2553.h" + +struct timer_msp timer0; + +void default_timer(void) +{ + timer0.s = 0; + timer0.ms = 0; + + if(BCSCTL1 == CALBC1_1MHZ ) + { + timer0.millis_var = 1000; + } + else if(BCSCTL1 == CALBC1_8MHZ) + { + timer0.millis_var = 8000; + } + else if(BCSCTL1 == CALBC1_12MHZ) + { + timer0.millis_var = 12000; + } + else if(BCSCTL1 == CALBC1_16MHZ) + { + timer0.millis_var = 16000; + } + + CCR0 = timer0.millis_var; + TACTL = TASSEL_2 + MC_1; + CCTL0 = CCIE; // CCR0 interrupt enabled +} + + + +unsigned long int millis(void) +{ + return(timer0.ms + timer0.s*1000L); +} + +#ifdef DELAY_MSP430 +void delay(unsigned long msec) +{ + while(msec--) + { + __delay_cycles(1000); + } +} +void delayMicroseconds(unsigned long usec) +{ + while(usec--) + { + __delay_cycles(1); + } +} +#endif + +//=========================================================================== +// Timer A0 interrupt service routine +#pragma vector=TIMER0_A0_VECTOR +__interrupt void Timer_A (void) +{ + timer0.ms++; + + + if(timer0.ms >= 1000) + { + timer0.s += 1; + timer0.ms -= 1000; + + } + //__bic_SR_register_on_exit(CPUOFF); + +} diff --git a/timer_msp.h b/timer_msp.h new file mode 100755 index 00000000..b452c1d9 --- /dev/null +++ b/timer_msp.h @@ -0,0 +1,28 @@ +/* + * timer_msp.h + * + * Created on: 30 de Dez de 2012 + * Author: Asus + */ + +#ifndef TIMER_MSP_H_ +#define TIMER_MSP_H_ + +struct timer_msp +{ + unsigned long int ms; + unsigned long int s; + unsigned int millis_var; +}; + +void default_timer(void); +unsigned long int millis(void); + +#ifndef DELAY_MSP430 +void delay(unsigned long msec); +void delayMicroseconds(unsigned long usec); +#endif + +extern struct timer_msp timer0; + +#endif /* TIMER_MSP_H_ */ From 924cd4f00aef6f7be9f7bd53b043c8a35662bd80 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Sousa?= Date: Mon, 12 May 2014 14:30:07 +0100 Subject: [PATCH 3/3] readme changed --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index e2582d67..dc8fa315 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -MSP-remote-RF24 +MSP-RF24 =============== Source code for a remote controller using a msp430g2553 and a nrf24l01 from nordic,