diff --git a/RF24.cpp b/RF24.cpp index cb3d640..994d0ee 100644 --- a/RF24.cpp +++ b/RF24.cpp @@ -356,17 +356,8 @@ boolean RF24::write( const void* buf, uint8_t len ) { boolean result = false; - // Transmitter power-up - write_register(CONFIG, ( read_register(CONFIG) | _BV(PWR_UP) ) & ~_BV(PRIM_RX) ); - delay(2); - - // Send the payload - write_payload( buf, len ); - - // Allons! - ce(HIGH); - delayMicroseconds(15); - ce(LOW); + // Begin the write + startWrite(buf,len); // ------------ // At this point we could return from a non-blocking write, and then call @@ -379,7 +370,7 @@ boolean RF24::write( const void* buf, uint8_t len ) uint8_t observe_tx; uint8_t status; uint32_t sent_at = millis(); - const uint32_t timeout = 100; //ms to wait for timeout + const uint32_t timeout = 500; //ms to wait for timeout do { status = read_register(OBSERVE_TX,&observe_tx,1); @@ -420,6 +411,22 @@ boolean RF24::write( const void* buf, uint8_t len ) 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) ); + delay(2); + + // Send the payload + write_payload( buf, len ); + + // Allons! + ce(HIGH); + delayMicroseconds(15); + ce(LOW); +} /******************************************************************/ @@ -507,6 +514,8 @@ void RF24::whatHappened(bool& tx_ok,bool& tx_fail,bool& rx_ready) tx_ok = status & _BV(TX_DS); tx_fail = status & _BV(MAX_RT); rx_ready = status & _BV(RX_DR); + + //print_status(status); } /******************************************************************/ diff --git a/RF24.h b/RF24.h index eafadaf..b2b3b1c 100644 --- a/RF24.h +++ b/RF24.h @@ -252,9 +252,6 @@ public: * getPayloadSize(). However, you can write less, and the remainder * will just be filled with zeroes. * - * @todo Write a non-blocking write to support users who want to - * check on progress separately or use an interrupt. - * * @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 @@ -403,6 +400,21 @@ public: */ boolean 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 ); + /** * Enable custom payloads on the acknowledge packets * diff --git a/examples/pingpair_irq/pingpair_irq.pde b/examples/pingpair_irq/pingpair_irq.pde index b014e9b..abe7da0 100644 --- a/examples/pingpair_irq/pingpair_irq.pde +++ b/examples/pingpair_irq/pingpair_irq.pde @@ -7,12 +7,10 @@ */ /** - * Example of using Ack Payloads + * Example of using interrupts * - * 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. + * 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 @@ -58,6 +56,13 @@ const char* role_friendly_name[] = { "invalid", "Sender", "Receiver"}; // The role of the current running sketch role_e role; +// Message buffer to allow interrupt handler to print messages +bool message_ready; +char message[100]; + +// Interrupt handler, check the radio because we got an IRQ +void check_radio(void); + void setup(void) { // @@ -81,9 +86,15 @@ void setup(void) Serial.begin(57600); printf_begin(); - printf("\n\rRF24/examples/pingpair_pl/\n\r"); + printf("\n\rRF24/examples/pingpair_irq/\n\r"); printf("ROLE: %s\n\r",role_friendly_name[role]); + // + // Attach interrupt handler to interrupt #0 (using pin 2) + // + + attachInterrupt(0, check_radio, FALLING); + // // Setup and configure rf radio // @@ -93,6 +104,9 @@ void setup(void) // We will be using the Ack Payload feature, so please enable it radio.enableAckPayload(); + // Pick a high channel + radio.setChannel(110); + // // Open pipes to other nodes for communication // @@ -123,9 +137,10 @@ void setup(void) radio.printDetails(); } +static uint32_t message_count = 0; + void loop(void) { - static uint32_t message_count = 0; // // Sender role. Repeatedly send the current time @@ -133,17 +148,10 @@ void loop(void) if (role == role_sender) { - // Take the time, and send it. This will block until complete + // Take the time, and send it. 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"); + radio.startWrite( &time, sizeof(unsigned long) ); // Try again soon delay(2000); @@ -176,5 +184,47 @@ void loop(void) ++message_count; } } + + // + // Message handler. Display messages from the interrupt + // + if ( message_ready ) + { + message_ready = false; + Serial.println(message); + } } + +void check_radio(void) +{ + // What happened? + bool tx,fail,rx; + radio.whatHappened(tx,fail,rx); + + char *messageptr = message; + message_ready = true; + sprintf(message,"Unknown"); + + if ( tx ) + { + radio.powerDown(); + sprintf(messageptr,"Send:OK "); + messageptr += strlen(messageptr); + } + + if ( fail ) + { + radio.powerDown(); + sprintf(messageptr,"Send:Failed "); + messageptr += strlen(messageptr); + } + + if ( rx ) + { + radio.read(&message_count,sizeof(message_count)); + sprintf(messageptr,"Ack:%lu ",message_count); + messageptr += strlen(messageptr); + } +} + // vim:ai:cin:sts=2 sw=2 ft=cpp