diff --git a/.gitattributes b/.gitattributes index 412eeda..e01356c 100644 --- a/.gitattributes +++ b/.gitattributes @@ -20,3 +20,7 @@ *.PDF diff=astextplain *.rtf diff=astextplain *.RTF diff=astextplain + +# doxygen generated files +docs/html/ +docs/xml/ \ No newline at end of file diff --git a/.github/workflows/doxygen.yml b/.github/workflows/doxygen.yml index 252bfa1..d261f04 100644 --- a/.github/workflows/doxygen.yml +++ b/.github/workflows/doxygen.yml @@ -17,7 +17,6 @@ jobs: uses: actions/checkout@v2 - name: overwrite doxygen tags run: | - mkdir docs touch doxygenAction echo "PROJECT_NUMBER = v1.0.${GITHUB_SHA:0:7}" >> doxygenAction echo "@INCLUDE = doxygenAction" >> Doxyfile diff --git a/.gitignore b/.gitignore index 33ea988..935c88d 100644 --- a/.gitignore +++ b/.gitignore @@ -215,4 +215,5 @@ pip-log.txt .mr.developer.cfg # ignore docs folder -docs/ +docs/html/ +docs/xml/ diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..3a08eba --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,9 @@ +These are the current requirements for getting your code included in RF24: + +* Try your best to follow the rest of the code, if you're unsure then the NASA C style can help as it's closest to the current style: https://ntrs.nasa.gov/archive/nasa/casi.ntrs.nasa.gov/19950022400.pdf + +* Definetly follow [PEP-8](https://www.python.org/dev/peps/pep-0008/) if it's Python code. + +* Follow the [Arduino IDE formatting style](https://www.arduino.cc/en/Reference/StyleGuide) for Arduino examples + +* Add [doxygen-compatible documentation](https://www.doxygen.nl/manual/docblocks.html) to any new functions you add, or update existing documentation if you change behaviour diff --git a/Doxyfile b/Doxyfile index 6940ebc..1bf5f27 100644 --- a/Doxyfile +++ b/Doxyfile @@ -734,7 +734,8 @@ WARN_LOGFILE = # spaces. # Note: If this tag is empty the current directory is searched. -INPUT = +INPUT = ./ \ + ./docs/ # This tag can be used to specify the character encoding of the source files # that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses @@ -755,13 +756,15 @@ INPUT_ENCODING = UTF-8 # *.qsf, *.as and *.js. FILE_PATTERNS = *.h \ + *.cpp \ + *.md \ FAQ # The RECURSIVE tag can be used to specify whether or not subdirectories should # be searched for input files as well. # The default value is: NO. -RECURSIVE = YES +RECURSIVE = NO # The EXCLUDE tag can be used to specify files and/or directories that should be # excluded from the INPUT source files. This way you can easily exclude a @@ -786,7 +789,7 @@ EXCLUDE_SYMLINKS = NO # Note that the wildcards are matched against the file with absolute path, so to # exclude all test directories for example use the pattern */test/* -EXCLUDE_PATTERNS = +EXCLUDE_PATTERNS = *README* # The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names # (namespaces, classes, functions, etc.) that should be excluded from the @@ -871,7 +874,7 @@ FILTER_SOURCE_PATTERNS = # (index.html). This can be useful if you have a project on for instance GitHub # and want to reuse the introduction page also for the doxygen output. -USE_MDFILE_AS_MAINPAGE = +USE_MDFILE_AS_MAINPAGE = ./docs/main_page.md #--------------------------------------------------------------------------- # Configuration options related to source browsing diff --git a/RF24Audio.cpp b/RF24Audio.cpp index 386c2d3..81eefc2 100644 --- a/RF24Audio.cpp +++ b/RF24Audio.cpp @@ -1,5 +1,8 @@ - - +/** + * @file RF24Audio.cpp + * + * class & function definitions for RF24Audio library + */ #if ARDUINO < 100 #include @@ -15,12 +18,12 @@ //******* General Variables ************************ -volatile boolean buffEmpty[2] = {true,true}, whichBuff = false, a, lCntr=0, streaming = 0, transmitting = 0; +volatile boolean buffEmpty[2] = {true, true}, whichBuff = false, a, lCntr=0, streaming = 0, transmitting = 0; volatile byte buffCount = 0; volatile byte pauseCntr = 0; unsigned int intCount = 0; -byte txCmd[2] = {'r','R'}; -byte buffer[2][buffSize+1]; +byte txCmd[2] = {'r', 'R'}; +byte buffer[2][buffSize + 1]; char volMod = -1; byte bitPos = 0, bytePos = 25; byte bytH; @@ -32,7 +35,7 @@ byte radioIdentifier; #endif unsigned long volTime = 0; -RF24 radi(0,0); +RF24 radi(0, 0); #if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) || (__AVR_ATmega32U4__) || (__AVR_AT90USB646__) || defined(__AVR_AT90USB1286__) || (__AVR_ATmega128__) ||defined(__AVR_ATmega1281__)||defined(__AVR_ATmega2561__) #define rampMega @@ -43,389 +46,402 @@ const byte broadcastVal = 255; // The value for broadcasting to all nodes using /*****************************************************************************************************************************/ /************************************************* General Section ***********************************************************/ -RF24Audio::RF24Audio(RF24& _radio, byte radioNum): radio(_radio){ - radi = radio; - radioIdentifier = radioNum; +RF24Audio::RF24Audio(RF24& _radio, byte radioNum): radio(_radio) +{ + radi = radio; + radioIdentifier = radioNum; } -void RF24Audio::begin(){ - - radio.begin(); - //delay(500); - // Set the defined input pins as inputs with pullups high. See http://arduino.cc/en/Tutorial/InputPullupSerial - #if defined (ENABLE_LED) - pinMode(ledPin,OUTPUT); - #endif - pinMode(speakerPin,OUTPUT); pinMode(speakerPin2,OUTPUT); - pinMode(TX_PIN,INPUT_PULLUP); pinMode(VOL_UP_PIN,INPUT_PULLUP); - pinMode(VOL_DN_PIN,INPUT_PULLUP); pinMode(REMOTE_TX_PIN,INPUT_PULLUP); - pinMode(REMOTE_RX_PIN,INPUT_PULLUP); - - if(SAMPLE_RATE < 16000){ - volMod = 3; - }else{ - #if !defined (tenBit) - volMod = 2; +void RF24Audio::begin() +{ + radio.begin(); + //delay(500); + // Set the defined input pins as inputs with pullups high. See http://arduino.cc/en/Tutorial/InputPullupSerial + #if defined (ENABLE_LED) + pinMode(ledPin,OUTPUT); #endif - } - - + pinMode(speakerPin, OUTPUT); + pinMode(speakerPin2, OUTPUT); + pinMode(TX_PIN, INPUT_PULLUP); + pinMode(VOL_UP_PIN, INPUT_PULLUP); + pinMode(VOL_DN_PIN, INPUT_PULLUP); + pinMode(REMOTE_TX_PIN, INPUT_PULLUP); + pinMode(REMOTE_RX_PIN, INPUT_PULLUP); + + if (SAMPLE_RATE < 16000) { + volMod = 3; + } + else { + #if !defined (tenBit) + volMod = 2; + #endif + } - radio.setChannel(1); // Set RF channel to 1 - radio.setAutoAck(0); // Disable ACKnowledgement packets - radio.setDataRate(RF_SPEED); // Set data rate as specified in user options - radio.setCRCLength(RF24_CRC_8); - radio.openWritingPipe(pipes[0]); // Set up reading and writing pipes. All of the radios write via multicast on the same pipe - radio.openReadingPipe(1,pipes[1]); // All of the radios listen by default to the same multicast pipe - radio.openReadingPipe(2,pipes[radioIdentifier + 2]); // Every radio also has its own private listening pipe + radio.setChannel(1); // Set RF channel to 1 + radio.setAutoAck(0); // Disable ACKnowledgement packets + radio.setDataRate(RF_SPEED); // Set data rate as specified in user options + radio.setCRCLength(RF24_CRC_8); // Set CRC to 1 byte for speed + radio.openWritingPipe(pipes[0]); // Set up reading and writing pipes. All of the radios write via multicast on the same pipe + radio.openReadingPipe(1, pipes[1]); // All of the radios listen by default to the same multicast pipe + radio.openReadingPipe(2, pipes[radioIdentifier + 2]); // Every radio also has its own private listening pipe - radio.startListening(); // NEED to start listening after opening a reading pipe - timerStart(); // Get the timer running - RX(); // Start listening for transmissions + radio.startListening(); // NEED to start listening after opening a reading pipe + timerStart(); // Get the timer running + RX(); // Start listening for transmissions - #if !defined (MANUAL_BUTTON_HANDLING) - TIMSK0 |= _BV(OCIE0B); - #endif + #if !defined (MANUAL_BUTTON_HANDLING) + TIMSK0 |= _BV(OCIE0B); + #endif } //General functions for volume control -void vol(bool upDn){ - if(upDn==1){ volMod++;} - else{ volMod--; } +void vol(bool upDn) +{ + if (upDn==1) + volMod++; + else + volMod--; } -void RF24Audio::volume(bool upDn){ - vol(upDn); +void RF24Audio::volume(bool upDn) +{ + vol(upDn); } -void RF24Audio::setVolume(char vol) { - volMod = vol - 4 ; +void RF24Audio::setVolume(char vol) +{ + volMod = vol - 4; } -void RF24Audio::timerStart(){ - ICR1 = 10 * (1600000/SAMPLE_RATE); //Timer will count up to this value from 0; +void RF24Audio::timerStart() +{ + ICR1 = 10 * (1600000 / SAMPLE_RATE); //Timer will count up to this value from 0; TCCR1A = _BV(COM1A1) | _BV(COM1B0) | _BV(COM1B1); //Enable the timer port/pin as output - TCCR1A |= _BV(WGM11); //WGM11,12,13 all set to 1 = fast PWM/w ICR TOP - TCCR1B = _BV(WGM13) | _BV(WGM12) | _BV(CS10); //CS10 = no prescaling - + TCCR1A |= _BV(WGM11); //WGM11,12,13 all set to 1 = fast PWM/w ICR TOP + TCCR1B = _BV(WGM13) | _BV(WGM12) | _BV(CS10); //CS10 = no prescaling } #if !defined (MANUAL_BUTTON_HANDLING) -void handleButtons(){ +void handleButtons() +{ + boolean state = digitalRead(TX_PIN); //Get the state of the transmitting pin - boolean state = digitalRead(TX_PIN); //Get the state of the transmitting pin + if (!state) { //If the pin is low, start transmitting + #if !defined (RX_ONLY) + if (!transmitting) { //Only do this if not already transmitting + transmitting = 1; //Set the transmitting variable + TX(); //Switch to TX mode + } + } + else { //If the TX pin is low + #endif // !defined (RX_ONLY) + if (transmitting) { //If still in transmitting mode + RX(); + transmitting = 0; //Start receiving/Stop transmitting + } + } - if(!state){ //If the pin is low, start transmitting -#if !defined (RX_ONLY) - if(!transmitting){ //Only do this if not already transmitting - transmitting = 1; //Set the transmitting variable - TX(); //Switch to TX mode + if (!digitalRead(VOL_UP_PIN)) { //If the volume pin is high, raise the volume + if (millis() - volTime > 200) { //De-bounce of buttons by 200ms + vol(1); + volTime = millis(); + } } - }else{ //If the TX pin is low -#endif - if(transmitting){ //If still in transmitting mode - RX(); transmitting = 0; //Start receiving/Stop transmitting + else if (!digitalRead(VOL_DN_PIN)) { + if (millis() - volTime > 200) { + vol(0); + volTime = millis(); + } } - } - - if(!digitalRead(VOL_UP_PIN)){ //If the volume pin is high, raise the volume - if(millis()-volTime > 200){ //De-bounce of buttons by 200ms - vol(1); volTime = millis(); - } - }else - if(!digitalRead(VOL_DN_PIN)){ - if(millis()-volTime > 200){ - vol(0); volTime = millis(); + + if (!digitalRead(REMOTE_TX_PIN)) { //Start remote recording and transmission of audio + if (!transmitting) { //If not transmitting already + radi.stopListening(); //Stop listening and write the request twice for good measure + radi.write(&txCmd, 2); + radi.write(&txCmd, 2); + radi.startListening(); + } + delay(200); //Delay as a simple button debounce } - } - - if(!digitalRead(REMOTE_TX_PIN)){ //Start remote recording and transmission of audio - if(!transmitting){ //If not transmitting already - radi.stopListening(); //Stop listening and write the request twice for good measure - radi.write(&txCmd,2); - radi.write(&txCmd,2); - radi.startListening();} - delay(200); //Delay as a simple button debounce - }else - if(!digitalRead(REMOTE_RX_PIN)){ //With TX timeout enabled, this will stop remote recording by stopping transmission for 2 seconds + else if (!digitalRead(REMOTE_RX_PIN)) { //With TX timeout enabled, this will stop remote recording by stopping transmission for 2 seconds delay(2000); - } - - - + } } - #endif //Manual button handling override - -void rampDown(){ - int current = OCR1A; - if(current > 0){ - for(int i=0; i < ICR1; i++){ - #if defined(rampMega) - OCR1B = constrain((current + i),0,ICR1); - OCR1A = constrain((current - i),0,ICR1); - #else - OCR1B = constrain((current - i),0,ICR1); - OCR1A = constrain((current - i),0,ICR1); - #endif - //for(int i=0; i<10; i++){ while(TCNT1 < ICR1-50){} } - delayMicroseconds(100); - } - } - +void rampDown() +{ + int current = OCR1A; + if (current > 0) { + for (int i = 0; i < ICR1; i++) { + #if defined(rampMega) + OCR1B = constrain((current + i), 0, ICR1); + OCR1A = constrain((current - i), 0, ICR1); + #else + OCR1B = constrain((current - i), 0, ICR1); + OCR1A = constrain((current - i), 0, ICR1); + #endif + // for(int i = 0; i < 10; i++) { while (TCNT1 < ICR1-50) {} } + delayMicroseconds(100); + } // end for + } // end if } - -void rampUp(byte nextVal){ - - /*int current = OCR1A; - if(current > 0){ - for(int i=0; i < ICR1; i++){ - #if defined(rampMega) - OCR1B = constrain((current - i),0,ICR1/2); - OCR1A = constrain((current + i),0,ICR1/2); - #else - OCR1B = constrain((current + i),0,ICR1/2); - OCR1A = constrain((current + i),0,ICR1/2); - #endif - //for(int i=0; i<10; i++){ while(TCNT1 < ICR1-50){} } - delayMicroseconds(100); - } - }*/ - - //digitalWrite(12,HIGH); - - - #if defined(rampMega) - unsigned int resolution = ICR1; - - OCR1A = 0; OCR1B = resolution; - for(int i=0; i < resolution; ++i){ - - OCR1B = constrain(resolution-i,0,resolution); - - //if(bitRead(*TCCRnB[tt],0)){ - // for(int i=0; i<10; i++){ - // while(*TCNT[tt] < resolution-50){} - // } - //}else{ - //delayMicroseconds(10); - //__asm__("nop\n\t""nop\n\t""nop\n\t""nop\n\t"); - - //} - } - - #endif - - - byte tmp = 200; - unsigned int mod; - if(volMod > 0){ mod = OCR1A >> volMod; }else{ mod = OCR1A << (volMod*-1); } - if(tmp > mod){ - for(unsigned int i=0; i 0) { + for(int i = 0; i < ICR1; i++) { + #if defined(rampMega) + OCR1B = constrain((current - i),0,ICR1/2); + OCR1A = constrain((current + i),0,ICR1/2); + #else + OCR1B = constrain((current + i),0,ICR1/2); + OCR1A = constrain((current + i),0,ICR1/2); + #endif + // for(int i=0; i<10; i++) { while(TCNT1 < ICR1-50) {} } + delayMicroseconds(100); + } // end for + }*/ + + //digitalWrite(12,HIGH); + + #if defined(rampMega) + unsigned int resolution = ICR1; + + OCR1A = 0; OCR1B = resolution; + for (int i = 0; i < resolution; ++i) { + + OCR1B = constrain(resolution - i, 0, resolution); + + // if (bitRead(*TCCRnB[tt], 0)) { + // for (int i = 0; i < 10; i++) { + // while(*TCNT[tt] < resolution - 50) {} + // } + // } + // else{ + // delayMicroseconds(10); + // __asm__("nop\n\t""nop\n\t""nop\n\t""nop\n\t"); + // } + } + #endif // defined(rampMega) + + + byte tmp = 200; + unsigned int mod; + if (volMod > 0) { mod = OCR1A >> volMod; } + else { mod = OCR1A << (volMod*-1); } + if (tmp > mod) { + for (unsigned int i = 0; i < buffSize; i++) { mod = constrain(mod + 1, mod, tmp); buffer[0][i] = mod; } + for (unsigned int i = 0; i < buffSize; i++) { mod = constrain(mod + 1, mod, tmp); buffer[1][i] = mod; } + }else{ + for (unsigned int i = 0; i < buffSize; i++) { mod = constrain(mod - 1, tmp, mod); buffer[0][i] = mod; } + for (unsigned int i = 0; i < buffSize; i++) { mod = constrain(mod - 1, tmp, mod); buffer[1][i] = mod; } + } + whichBuff = 0; buffEmpty[0] = 0; buffEmpty[1] = 0; buffCount = 0; } -void RF24Audio::transmit(){ - TX(); +void RF24Audio::transmit() +{ + TX(); } -void RF24Audio::receive(){ - RX(); + +void RF24Audio::receive() +{ + RX(); } -#if !defined MANUAL_BUTTON_HANDLING // Allows users to totally customize button handling or disable it - ISR(TIMER0_COMPB_vect){ // Non-blocking interrupt vector for button management. Is triggered ~1000 times/second by default on Arduino - handleButtons(); // Check for external button presses at the default timer0 rate - } +// Allows users to totally customize button handling or disable it +#if !defined MANUAL_BUTTON_HANDLING + ISR(TIMER0_COMPB_vect) { // Non-blocking interrupt vector for button management. Is triggered ~1000 times/second by default on Arduino + handleButtons(); // Check for external button presses at the default timer0 rate + } #endif -uint64_t RF24Audio::getAddress(byte addressNo){ - - return pipes[addressNo]; - +uint64_t RF24Audio::getAddress(byte addressNo) +{ + return pipes[addressNo]; } + /*****************************************************************************************************************************/ /****************************************** Reception (RX) Section ***********************************************************/ +void handleRadio() +{ + if (buffEmpty[!whichBuff] && streaming) { // If in RX mode and a buffer is empty, load it + if (radi.available()) { + boolean n=!whichBuff; // Grab the changing value of which buffer is not being read before enabling nested interrupts + TIMSK1 &= ~_BV(ICIE1); // Disable this interrupt so it is not triggered while still running (this may take a while) + sei(); // Enable nested interrupts (Other interrupts can interrupt this one) + radi.read(&buffer[n],32); // Read the payload from the radio + buffEmpty[n] = 0; // Indicate that a buffer is now full and ready to play + pauseCntr = 0; // For disabling speaker when no data is being received + + TIMSK1 |= _BV(ICIE1); // Finished, re-enable the interrupt vector that runs this function + } + else { + pauseCntr++; // No payload available, keep track of how many for disabling the speaker + } -void handleRadio(){ - - - if(buffEmpty[!whichBuff] && streaming){ // If in RX mode and a buffer is empty, load it - if(radi.available() ){ - boolean n=!whichBuff; // Grab the changing value of which buffer is not being read before enabling nested interrupts - TIMSK1 &= ~_BV(ICIE1); // Disable this interrupt so it is not triggered while still running (this may take a while) - sei(); // Enable nested interrupts (Other interrupts can interrupt this one) - radi.read(&buffer[n],32); // Read the payload from the radio - buffEmpty[n] = 0; // Indicate that a buffer is now full and ready to play - pauseCntr = 0; // For disabling speaker when no data is being received - - TIMSK1 |= _BV(ICIE1); // Finished, re-enable the interrupt vector that runs this function - }else{ pauseCntr++; } // No payload available, keep track of how many for disabling the speaker - if(pauseCntr > 50){ // If we failed to get a payload 250 times, disable the speaker output - pauseCntr = 0; // Reset the failure counter - rampDown(); // Ramp down the speaker (prevention of popping sounds) - streaming = 0; // Indicate that streaming is stopped - TIMSK1 &= ~(_BV(TOIE1) ); // Disable the TIMER1 overflow vector (playback) - #if defined (ENABLE_LED) - TCCR0A &= ~_BV(COM0A1); // Disable the TIMER0 LED visualization - #endif - TCCR1A &= ~(_BV(COM1A1) | _BV(COM1B1) | _BV(COM1B0)); // Disable speaker output - } - }else - - if(!streaming){ // If not actively reading a stream, read commands instead - if(radi.available() ){ // If a payload is available - TIMSK1 &= ~_BV(ICIE1); // Since this is called from an interrupt, disable it - sei(); // Enable global interrupts (nested interrupts) Other interrupts can interrupt this one - radi.read(&buffer[0],32); // Read the payload into the buffer - switch(buffer[0][0]){ // Additional commands can be added here for controlling other things via radio command - #if !defined (RX_ONLY) - case 'r': if(buffer[0][1] == 'R' && radioIdentifier < 2){ //Switch to TX mode if we received the remote tx command and this is radio 0 or 1 - TX(); - } - break; - #endif - default: streaming= 1; // If not a command, treat as audio data, enable streaming - - - TCCR1A |= _BV(COM1A1) | _BV(COM1B1) | _BV(COM1B0); //Enable output to speaker pin - rampUp(buffer[0][31]); // Ramp up the speakers to prevent popping - //buffEmpty[0] = false; // Set the status of the memory buffers - //buffEmpty[1] = true; - TIMSK1 |= _BV(TOIE1); // Enable the overflow vector - #if defined (ENABLE_LED) - TCCR0A |= _BV(COM0A1); // Enable the LED visualization output - #endif - break; + if (pauseCntr > 50) { // If we failed to get a payload 250 times, disable the speaker output + pauseCntr = 0; // Reset the failure counter + rampDown(); // Ramp down the speaker (prevention of popping sounds) + streaming = 0; // Indicate that streaming is stopped + TIMSK1 &= ~(_BV(TOIE1)); // Disable the TIMER1 overflow vector (playback) + #if defined (ENABLE_LED) + TCCR0A &= ~_BV(COM0A1); // Disable the TIMER0 LED visualization + #endif + TCCR1A &= ~(_BV(COM1A1) | _BV(COM1B1) | _BV(COM1B0)); // Disable speaker output + } + } + else if (!streaming) { // If not actively reading a stream, read commands instead + if (radi.available()) { // If a payload is available + TIMSK1 &= ~_BV(ICIE1); // Since this is called from an interrupt, disable it + sei(); // Enable global interrupts (nested interrupts) Other interrupts can interrupt this one + radi.read(&buffer[0], 32); // Read the payload into the buffer + switch(buffer[0][0]) { // Additional commands can be added here for controlling other things via radio command + #if !defined (RX_ONLY) + case 'r': + if (buffer[0][1] == 'R' && radioIdentifier < 2) { //Switch to TX mode if we received the remote tx command and this is radio 0 or 1 + TX(); + } + break; + #endif + default: + streaming= 1; // If not a command, treat as audio data, enable streaming + + + TCCR1A |= _BV(COM1A1) | _BV(COM1B1) | _BV(COM1B0); //Enable output to speaker pin + rampUp(buffer[0][31]); // Ramp up the speakers to prevent popping + //buffEmpty[0] = false; // Set the status of the memory buffers + //buffEmpty[1] = true; + TIMSK1 |= _BV(TOIE1); // Enable the overflow vector + #if defined (ENABLE_LED) + TCCR0A |= _BV(COM0A1); // Enable the LED visualization output + #endif + break; + } + TIMSK1 |= _BV(ICIE1); // Finished: Re-enable the interrupt that runs this function. } - TIMSK1 |= _BV(ICIE1); // Finished: Re-enable the interrupt that runs this function. } - } } -void RX(){ // Start Receiving - - TIMSK1 &= ~_BV(OCIE1B) | _BV(OCIE1A); // Disable the transmit interrupts - ADCSRA = 0; ADCSRB = 0; // Disable Analog to Digital Converter (ADC) - buffEmpty[0] = 1; buffEmpty[1] = 1; // Set the buffers to empty - #if defined (oversampling) // If running the timer at double the sample rate - ICR1 = 10 * (800000/SAMPLE_RATE); // Set timer top for 2X oversampling - #else - ICR1 = 10 * (1600000/SAMPLE_RATE); // Timer running at normal sample rate speed - #endif - - radi.openWritingPipe(pipes[0]); // Set up reading and writing pipes - radi.openReadingPipe(1,pipes[1]); - radi.startListening(); // Exit sending mode - TIMSK1 = _BV(ICIE1); // Enable the capture interrupt vector (handles buffering and starting of playback) - - +void RX() +{ + // Start Receiving + TIMSK1 &= ~_BV(OCIE1B) | _BV(OCIE1A); // Disable the transmit interrupts + ADCSRA = 0; ADCSRB = 0; // Disable Analog to Digital Converter (ADC) + buffEmpty[0] = 1; buffEmpty[1] = 1; // Set the buffers to empty + #if defined (oversampling) // If running the timer at double the sample rate + ICR1 = 10 * (800000/SAMPLE_RATE); // Set timer top for 2X oversampling + #else + ICR1 = 10 * (1600000/SAMPLE_RATE); // Timer running at normal sample rate speed + #endif + radi.openWritingPipe(pipes[0]); // Set up reading and writing pipes + radi.openReadingPipe(1,pipes[1]); + radi.startListening(); // Exit sending mode + TIMSK1 = _BV(ICIE1); // Enable the capture interrupt vector (handles buffering and starting of playback) } boolean nn = 0; volatile byte bufCtr = 0; volatile unsigned int visCtr = 0; -ISR(TIMER1_CAPT_vect){ // This interrupt checks for data at 1/16th the sample rate. Since there are 32 bytes per payload, it gets two chances for every payload +ISR(TIMER1_CAPT_vect) { // This interrupt checks for data at 1/16th the sample rate. Since there are 32 bytes per payload, it gets two chances for every payload -bufCtr++; visCtr++; // Keep track of how many times the interrupt has been triggered + bufCtr++; visCtr++; // Keep track of how many times the interrupt has been triggered -if(bufCtr >= 16){ // Every 16 times, do this - handleRadio(); // Check for incoming radio data if not transmitting - - bufCtr = 0; // Reset this counter - - if(visCtr >= 32 && streaming){ // Run the visualisation at a much slower speed so we can see the changes better - OCR0A = buffer[whichBuff][0] << 2; // Adjust the TIMER0 compare match to change the PWM duty and thus the brightess of the LED - visCtr = 0; // Reset the visualization counter - } - -} + if (bufCtr >= 16) { // Every 16 times, do this + handleRadio(); // Check for incoming radio data if not transmitting + bufCtr = 0; // Reset this counter + if (visCtr >= 32 && streaming) { // Run the visualisation at a much slower speed so we can see the changes better + OCR0A = buffer[whichBuff][0] << 2; // Adjust the TIMER0 compare match to change the PWM duty and thus the brightess of the LED + visCtr = 0; // Reset the visualization counter + } + } } // Receiving interrupt -ISR(TIMER1_OVF_vect){ // This interrupt vector loads received audio samples into the timer register +ISR(TIMER1_OVF_vect) { + // This interrupt vector loads received audio samples into the timer register + if (buffEmpty[whichBuff]) { // Return if both buffers are empty + whichBuff = !whichBuff; + } + else{ - if(buffEmpty[whichBuff] ){ whichBuff=!whichBuff; }else{ // Return if both buffers are empty - - #if defined (oversampling) // If running the timers at 2X speed, only load a new sample every 2nd time - if(lCntr){lCntr = !lCntr;return;} lCntr=!lCntr; + #if defined (oversampling) + // If running the timers at 2X speed, only load a new sample every 2nd time + if (lCntr) {lCntr = !lCntr; return; } lCntr = !lCntr; #endif - #if !defined (tenBit) -/*************** Standard 8-Bit Audio Playback ********************/ - if(volMod < 0 ){ //Load an audio sample into the timer compare register - OCR1A = OCR1B = (buffer[whichBuff][intCount] >> volMod*-1); //Output to speaker at a set volume - }else{ - OCR1A = OCR1B = buffer[whichBuff][intCount] << volMod; - } - - intCount++; //Keep track of how many samples have been loaded + #if !defined (tenBit) + /*************** Standard 8-Bit Audio Playback ********************/ + if (volMod < 0 ) { //Load an audio sample into the timer compare register + OCR1A = OCR1B = (buffer[whichBuff][intCount] >> volMod * -1); //Output to speaker at a set volume + } + else{ + OCR1A = OCR1B = buffer[whichBuff][intCount] << volMod; + } - if(intCount >= buffSize){ //If the buffer is empty, do the following - intCount = 0; //Reset the sample count - buffEmpty[whichBuff] = true; //Indicate which buffer is empty - whichBuff = !whichBuff; //Switch buffers to read from - } + intCount++; //Keep track of how many samples have been loaded -/*************** 10 - bit Audio *************************************/ - #else + if (intCount >= buffSize) { //If the buffer is empty, do the following + intCount = 0; //Reset the sample count + buffEmpty[whichBuff] = true; //Indicate which buffer is empty + whichBuff = !whichBuff; //Switch buffers to read from + } - sampl = buffer[whichBuff][intCount]; // Load 8bits of the sample into a temporary buffer - bitWrite( sampl, 8, bitRead( buffer[whichBuff][bytePos],bitPos)); // Read the 9th bit, and write it to the temporary buffer - bitPos++; // Keep track of the bit-position, since bits are loaded in bytes 25-31 - bitWrite(sampl, 9, bitRead(buffer[whichBuff][bytePos],bitPos)); // Read the 10th bit, and write it to the temporary buffer - bitPos++; // Keep track of the bit-position + #else + /*************** 10 - bit Audio *************************************/ + sampl = buffer[whichBuff][intCount]; // Load 8bits of the sample into a temporary buffer + bitWrite(sampl, 8, bitRead(buffer[whichBuff][bytePos], bitPos)); // Read the 9th bit, and write it to the temporary buffer + bitPos++; // Keep track of the bit-position, since bits are loaded in bytes 25-31 + bitWrite(sampl, 9, bitRead(buffer[whichBuff][bytePos], bitPos)); // Read the 10th bit, and write it to the temporary buffer + bitPos++; // Keep track of the bit-position - if(volMod < 0 ){ // Load an audio sample into the timer compare register - OCR1A = OCR1B = sampl >> (volMod*-1); // Output to speaker at a set volume - }else{ - OCR1A = OCR1B = sampl << volMod; - } + if (volMod < 0) { // Load an audio sample into the timer compare register + OCR1A = OCR1B = sampl >> (volMod * -1); // Output to speaker at a set volume + } + else{ + OCR1A = OCR1B = sampl << volMod; + } - if(bitPos >=8){ // If 8 bits have been read, reset the counter and switch to the next byte - bitPos = 0; - bytePos = bytePos+1; - } + if (bitPos >=8) { // If 8 bits have been read, reset the counter and switch to the next byte + bitPos = 0; + bytePos = bytePos + 1; + } - intCount++; // Keep track of how many samples have been loaded + intCount++; // Keep track of how many samples have been loaded - if(intCount >= 25){ // If the buffer is empty, do the following - bytePos = 25; - bitPos = 0; - intCount = 0; // Reset the sample count - buffEmpty[whichBuff] = true; // Indicate which buffer is empty - whichBuff = !whichBuff; // Switch buffers to read from - } + if (intCount >= 25) { // If the buffer is empty, do the following + bytePos = 25; + bitPos = 0; + intCount = 0; // Reset the sample count + buffEmpty[whichBuff] = true; // Indicate which buffer is empty + whichBuff = !whichBuff; // Switch buffers to read from + } - #endif - } + #endif + } } @@ -433,165 +449,155 @@ ISR(TIMER1_OVF_vect){ // This interrupt /*****************************************************************************************************************************/ /*************************************** Transmission (TX) Section ***********************************************************/ -#if !defined (RX_ONLY) //If TX is enabled: - -void RF24Audio::broadcast(byte radioID){ +#if !defined (RX_ONLY) // If TX is enabled: - if(radioID == radioIdentifier){ return; } // If trying to send to our own address, return +void RF24Audio::broadcast(byte radioID) +{ + if (radioID == radioIdentifier) { return; } // If trying to send to our own address, return - noInterrupts(); // Disable interrupts during change of transmission address + noInterrupts(); // Disable interrupts during change of transmission address - if(radioID == broadcastVal){ - radio.openWritingPipe(pipes[1]); // Use the public multicast pipe - }else{ - radio.openWritingPipe(pipes[radioID + 2]); // Open a pipe to the specified radio(s). If two or more radios share the same ID, - } // they will receive the same single broadcasts, but will not be able to initiate - interrupts(); // private communication betwen each other + if (radioID == broadcastVal) { + radio.openWritingPipe(pipes[1]); // Use the public multicast pipe + }else{ + radio.openWritingPipe(pipes[radioID + 2]); // Open a pipe to the specified radio(s). If two or more radios share the same ID, + } // they will receive the same single broadcasts, but will not be able to initiate + interrupts(); // private communication betwen each other } - //Transmission sending interrupt - ISR(TIMER1_COMPA_vect){ // This interrupt vector sends the samples when a buffer is filled - if(buffEmpty[!whichBuff] == 0){ // If a buffer is ready to be sent - a = !whichBuff; // Get the buffer # before allowing nested interrupts - TIMSK1 &= ~(_BV(OCIE1A)); // Disable this interrupt vector - sei(); // Allow other interrupts to interrupt this vector (nested interrupts) - //radi.startFastWrite(&buffer[a],32); - radi.writeFast(&buffer[a],32); - buffEmpty[a] = 1; // Mark the buffer as empty - TIMSK1 |= _BV(OCIE1A); // Re-enable this interrupt vector - } - - } - - +//Transmission sending interrupt +ISR(TIMER1_COMPA_vect) { // This interrupt vector sends the samples when a buffer is filled + if (buffEmpty[!whichBuff] == 0) { // If a buffer is ready to be sent + a = !whichBuff; // Get the buffer # before allowing nested interrupts + TIMSK1 &= ~(_BV(OCIE1A)); // Disable this interrupt vector + sei(); // Allow other interrupts to interrupt this vector (nested interrupts) + //radi.startFastWrite(&buffer[a], 32); + radi.writeFast(&buffer[a], 32); + buffEmpty[a] = 1; // Mark the buffer as empty + TIMSK1 |= _BV(OCIE1A); // Re-enable this interrupt vector + } +} - //Transmission buffering interrupt - ISR(TIMER1_COMPB_vect){ // This interrupt vector captures the ADC values and stores them in a buffer +//Transmission buffering interrupt +ISR(TIMER1_COMPB_vect) { // This interrupt vector captures the ADC values and stores them in a buffer - #if !defined (tenBit) // 8-bit samples + #if !defined (tenBit) + // 8-bit samples + buffer[whichBuff][buffCount] = bytH = ADCH; // Read the high byte of the ADC register into the buffer for 8-bit samples + + #if defined (speakerTX) + // If output to speaker while transmitting is enabled + if (volMod < 0 ) { OCR1A = bytH >> (volMod * -1); } // Output to speaker at a set volume if defined + else { OCR1A = bytH << volMod; } + #endif // defined (speakerTX) + + #else // 10-bit samples are a little more complicated, but offer better quality for lower sample rates + buffer[whichBuff][buffCount] = bytL = ADCL; // In 10-bit mode, the ADC register is right-adjusted, we need to read the low, then high byte each time + bytH = ADCH; + bitWrite(buffer[whichBuff][bytePos], bitPos, bitRead(bytH, 0)); // The low bytes are stored in the first 25 bytes of the payload. The additional 2 bits are stored in + bitWrite(buffer[whichBuff][bytePos], bitPos + 1, bitRead(bytH, 1)); // pairs in the remaining bytes #25 to 31. Read the first and 2nd bits of the high register into the payload. + bitPos+=2; + if (bitPos >= 8) { bitPos = 0; bytePos = bytePos + 1; } // Every time a byte is full, increase byte position by 1 and reset the bit count. + + #if defined (speakerTX) + // If output to speaker while transmitting is enabled + sampl = bytL; // Load the two bytes into the 2-byte unsigned integer. Low byte first + sampl |= bytH << 8; // Shift the high byte 8bits and load it into the unsigned int using an OR comparison + if (volMod < 0 ) { OCR1A = sampl >> (volMod*-1); } // Output to speaker at a set volume if defined + else { OCR1A = sampl << volMod; } + #endif // defined (speakerTX) + #endif // defined (tenBit) + + buffCount++; // Keep track of how many samples have been loaded - buffer[whichBuff][buffCount] = bytH = ADCH; // Read the high byte of the ADC register into the buffer for 8-bit samples + #if !defined (tenBit) + if (buffCount >= 32) { // In 8-bit mode, do this every 32 samples - #if defined (speakerTX) // If output to speaker while transmitting is enabled - if(volMod < 0 ){ OCR1A = bytH >> (volMod*-1); // Output to speaker at a set volume if defined - }else{ OCR1A = bytH << volMod; - } - #endif + #else // 10-bit mode + if (buffCount >= 25) { // In 10-bit mode, do this every 25 samples + bytePos = 25; // Reset the position for the extra 2 bits to the 25th byte + bitPos = 0; // Reset the bit position for the extra 2 bits + #endif - #else // 10-bit samples are a little more complicated, but offer better quality for lower sample rates - buffer[whichBuff][buffCount] = bytL = ADCL; // In 10-bit mode, the ADC register is right-adjusted, we need to read the low, then high byte each time - bytH = ADCH; - bitWrite(buffer[whichBuff][bytePos],bitPos, bitRead(bytH,0)); // The low bytes are stored in the first 25 bytes of the payload. The additional 2 bits are stored in - bitWrite(buffer[whichBuff][bytePos],bitPos+1, bitRead(bytH,1));// pairs in the remaining bytes #25 to 31. Read the first and 2nd bits of the high register into the payload. - bitPos+=2; - if(bitPos >= 8){ bitPos = 0; bytePos = bytePos+1; } // Every time a byte is full, increase byte position by 1 and reset the bit count. + //Both modes + buffCount = 0; // Reset the sample counter + buffEmpty[!whichBuff] = 0; // Indicate which bufffer is ready to send + whichBuff = !whichBuff; // Switch buffers and load the other one + } +} - #if defined (speakerTX) // If output to speaker while transmitting is enabled - sampl = bytL; // Load the two bytes into the 2-byte unsigned integer. Low byte first - sampl |= bytH << 8; // Shift the high byte 8bits and load it into the unsigned int using an OR comparison - if(volMod < 0 ){ OCR1A = sampl >> (volMod*-1); // Output to speaker at a set volume if defined - }else{ OCR1A = sampl << volMod; - } - #endif +void TX() +{ + TIMSK1 &= ~(_BV(ICIE1) | _BV(TOIE1)); // Disable the receive interrupts + #if defined (ENABLE_LED) + TCCR0A &= ~_BV(COM0A1); // Disable LED visualization #endif + radi.openWritingPipe(pipes[1]); // Set up reading and writing pipes + radi.openReadingPipe(1,pipes[0]); + radi.stopListening(); // Enter transmit mode on the radio + streaming = 0; buffCount = 0; buffEmpty[0] = 1; buffEmpty[1] = 1; //Set some variables + byte pin = ANALOG_PIN; + /*** This section taken from wiring_analog.c to translate between pins and channel numbers ***/ + #if defined(analogPinToChannel) + #if defined(__AVR_ATmega32U4__) + if (pin >= 18) pin -= 18; // allow for channel or pin numbers + #endif + pin = analogPinToChannel(pin); + #elif defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) + if (pin >= 54) pin -= 54; // allow for channel or pin numbers + #elif defined(__AVR_ATmega32U4__) + if (pin >= 18) pin -= 18; // allow for channel or pin numbers + #elif defined(__AVR_ATmega1284__) || defined(__AVR_ATmega1284P__) || defined(__AVR_ATmega644__) || defined(__AVR_ATmega644A__) || defined(__AVR_ATmega644P__) || defined(__AVR_ATmega644PA__) + if (pin >= 24) pin -= 24; // allow for channel or pin numbers + #else + if (pin >= 14) pin -= 14; // allow for channel or pin numbers + #endif - buffCount++; // Keep track of how many samples have been loaded - - #if !defined (tenBit) // 8-bit mode - if(buffCount >= 32){ // In 8-bit mode, do this every 32 samples + #if defined(ADCSRB) && defined(MUX5) + // the MUX5 bit of ADCSRB selects whether we're reading from channels + // 0 to 7 (MUX5 low) or 8 to 15 (MUX5 high). + ADCSRB = (ADCSRB & ~(1 << MUX5)) | (((pin >> 3) & 0x01) << MUX5); + #endif - #else // 10-bit mode - if(buffCount >= 25){ // In 10-bit mode, do this every 25 samples - bytePos = 25; // Reset the position for the extra 2 bits to the 25th byte - bitPos = 0; // Reset the bit position for the extra 2 bits + #if defined(ADMUX) + ADMUX = (pin & 0x07) | _BV(REFS0); //Enable the ADC PIN and set 5v Analog Reference #endif - //Both modes - buffCount = 0; // Reset the sample counter - buffEmpty[!whichBuff] = 0; // Indicate which bufffer is ready to send - whichBuff = !whichBuff; // Switch buffers and load the other one - } - } - - -void TX(){ - - TIMSK1 &= ~(_BV(ICIE1) | _BV(TOIE1)); // Disable the receive interrupts - #if defined (ENABLE_LED) - TCCR0A &= ~_BV(COM0A1); // Disable LED visualization - #endif - radi.openWritingPipe(pipes[1]); // Set up reading and writing pipes - radi.openReadingPipe(1,pipes[0]); - radi.stopListening(); // Enter transmit mode on the radio - - - streaming = 0; - buffCount = 0; buffEmpty[0] = 1; buffEmpty[1] = 1; //Set some variables - - - byte pin = ANALOG_PIN; - /*** This section taken from wiring_analog.c to translate between pins and channel numbers ***/ - #if defined(analogPinToChannel) - #if defined(__AVR_ATmega32U4__) - if (pin >= 18) pin -= 18; // allow for channel or pin numbers - #endif - pin = analogPinToChannel(pin); - #elif defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) - if (pin >= 54) pin -= 54; // allow for channel or pin numbers - #elif defined(__AVR_ATmega32U4__) - if (pin >= 18) pin -= 18; // allow for channel or pin numbers - #elif defined(__AVR_ATmega1284__) || defined(__AVR_ATmega1284P__) || defined(__AVR_ATmega644__) || defined(__AVR_ATmega644A__) || defined(__AVR_ATmega644P__) || defined(__AVR_ATmega644PA__) - if (pin >= 24) pin -= 24; // allow for channel or pin numbers - #else - if (pin >= 14) pin -= 14; // allow for channel or pin numbers - #endif - - #if defined(ADCSRB) && defined(MUX5) - // the MUX5 bit of ADCSRB selects whether we're reading from channels - // 0 to 7 (MUX5 low) or 8 to 15 (MUX5 high). - ADCSRB = (ADCSRB & ~(1 << MUX5)) | (((pin >> 3) & 0x01) << MUX5); - #endif - - #if defined(ADMUX) - ADMUX = (pin & 0x07) | _BV(REFS0); //Enable the ADC PIN and set 5v Analog Reference - #endif - - ICR1 = 10 * (1600000/SAMPLE_RATE); //Timer counts from 0 to this value - - #if !defined (speakerTX) //If disabling/enabling the speaker, ramp it down - rampDown(); - TCCR1A &= ~(_BV(COM1A1)); //Disable output to speaker + ICR1 = 10 * (1600000 / SAMPLE_RATE); //Timer counts from 0 to this value - #endif - TCCR1A &= ~(_BV(COM1B1) |_BV(COM1B0) ); + #if !defined (speakerTX) + //If disabling/enabling the speaker, ramp it down + rampDown(); + TCCR1A &= ~(_BV(COM1A1)); //Disable output to speaker + #endif - #if !defined (tenBit) - ADMUX |= _BV(ADLAR); //Left-shift result so only high byte needs to be read - #else - ADMUX &= ~_BV(ADLAR); //Don't left-shift result in 10-bit mode - #endif + TCCR1A &= ~(_BV(COM1B1) |_BV(COM1B0) ); - ADCSRB |= _BV(ADTS0) | _BV(ADTS0) | _BV(ADTS2); //Attach ADC start to TIMER1 Capture interrupt flag - byte prescaleByte = 0; + #if !defined (tenBit) + ADMUX |= _BV(ADLAR); //Left-shift result so only high byte needs to be read + #else + ADMUX &= ~_BV(ADLAR); //Don't left-shift result in 10-bit mode + #endif - if( SAMPLE_RATE < 8900){ prescaleByte = B00000111;} //128 - else if( SAMPLE_RATE < 18000){ prescaleByte = B00000110;} //ADC division factor 64 (16MHz / 64 / 13clock cycles = 19230 Hz Max Sample Rate ) - else if( SAMPLE_RATE < 27000){ prescaleByte = B00000101;} //32 (38461Hz Max) - else if( SAMPLE_RATE < 65000){ prescaleByte = B00000100;} //16 (76923Hz Max) - else { prescaleByte = B00000011;} //8 (fast as hell) + ADCSRB |= _BV(ADTS0) | _BV(ADTS0) | _BV(ADTS2); //Attach ADC start to TIMER1 Capture interrupt flag + byte prescaleByte = 0; - ADCSRA = prescaleByte; //Adjust sampling rate of ADC depending on sample rate - ADCSRA |= _BV(ADEN) | _BV(ADATE); //ADC Enable, Auto-trigger enable + if ( SAMPLE_RATE < 8900) { prescaleByte = B00000111; } //128 + else if (SAMPLE_RATE < 18000) { prescaleByte = B00000110; } //ADC division factor 64 (16MHz / 64 / 13clock cycles = 19230 Hz Max Sample Rate ) + else if (SAMPLE_RATE < 27000) { prescaleByte = B00000101; } //32 (38461Hz Max) + else if (SAMPLE_RATE < 65000) { prescaleByte = B00000100; } //16 (76923Hz Max) + else { prescaleByte = B00000011; } //8 (fast as hell) + ADCSRA = prescaleByte; //Adjust sampling rate of ADC depending on sample rate + ADCSRA |= _BV(ADEN) | _BV(ADATE); //ADC Enable, Auto-trigger enable - TIMSK1 = _BV(OCIE1B) | _BV(OCIE1A); //Enable the TIMER1 COMPA and COMPB interrupts + TIMSK1 = _BV(OCIE1B) | _BV(OCIE1A); //Enable the TIMER1 COMPA and COMPB interrupts } - -#endif \ No newline at end of file +#endif // !defined (RX_ONLY) // If TX is enabled diff --git a/RF24Audio.h b/RF24Audio.h index 1d6e0fc..85ecd5e 100644 --- a/RF24Audio.h +++ b/RF24Audio.h @@ -1,19 +1,18 @@ - -/* RFAudio Library: by TMRh20 2011-2014*/ - -#ifndef __RF24Audio_H__ -#define __RF24Audio_H__ - /** * @file RF24Audio.h * * Class declaration for RF24Audio Library + * + * RFAudio Library: by TMRh20 2011-2014 */ +#ifndef __RF24Audio_H__ +#define __RF24Audio_H__ + class RF24; /** - * TMRh20 2014 - RF24Audio: Arduino Realtime Audio Streaming library + * @brief Arduino Realtime Audio Streaming library * * This class implements an Audio Streaming library using nRF24L01(+) radios driven * by the [Optimized RF24 library](https://github.com/TMRh20/RF24). @@ -23,103 +22,103 @@ class RF24Audio { public: - /** - * Setup the radio and radio identifier - * @note Changing radioNum is only required if utilizing private node-to-node communication as - * opposed to broadcasting to the entire radio group - * - * @code - * RF24 radio(48, 49); // Initialize the radio driver - * RF24Audio rfAudio(radio, 0); // Initialize the audio driver - * @endcode - * - * @param _radio The underlying radio driver instance - * @param radioNum The radio identifier - */ + /** + * Setup the radio and radio identifier + * @note Changing radioNum is only required if utilizing private node-to-node communication as + * opposed to broadcasting to the entire radio group + * + * @code + * RF24 radio(48, 49); // Initialize the radio driver + * RF24Audio rfAudio(radio, 0); // Initialize the audio driver + * @endcode + * + * @param _radio The underlying radio driver instance + * @param radioNum The radio identifier + */ RF24Audio(RF24& _radio, byte radioNum); - /** - * Initialize the radio and audio library - * - * Generally called in setup to initialize the radio - * @code - * rfAudio.begin(); - * @endcode - */ + /** + * Initialize the radio and audio library + * + * Generally called in setup to initialize the radio + * @code + * rfAudio.begin(); + * @endcode + */ void begin(); - /** - * Volume Control - * @code - * rfAudio.volume(1); // Raise the volume - * @endcode - * @param upDn Set 0 to lower volume, 1 to raise volume - * - */ + /** + * Volume Control + * @code + * rfAudio.volume(1); // Raise the volume + * @endcode + * @param upDn Set 0 to lower volume, 1 to raise volume + * + */ void volume(bool upDn); - /** - * Volume Control - * @code - * rfAudio.setVolume(4); // Set the volume to mid-level - * @endcode - * @param vol Set at 0 to 7 for range of volume control - * - */ + /** + * Volume Control + * @code + * rfAudio.setVolume(4); // Set the volume to mid-level + * @endcode + * @param vol Set at 0 to 7 for range of volume control + * + */ void setVolume(char vol); - /** - * Control transmission through code - * @code - * rfAudio.transmit(); // Begin realtime audio streaming - * @endcode - * Call this function to begin transmission - * - */ + /** + * Control transmission through code + * @code + * rfAudio.transmit(); // Begin realtime audio streaming + * @endcode + * Call this function to begin transmission + * + */ void transmit(); - /** - * Stop transmission through code - * @code - * rfAudio.receive(); // Stop audio streaming - * @endcode - * Call this function to stop transmission - * - */ + /** + * Stop transmission through code + * @code + * rfAudio.receive(); // Stop audio streaming + * @endcode + * Call this function to stop transmission + * + */ void receive(); - /** - * Control of Private or Public Communication - * - * Call this function to establish private communication between nodes - * in a radio group, or to switch back to public transmission. - * @note Using a radioID of 255 will disable private communication and broadcast to all nodes - * - * @code - * rfAudio.broadcast(1); // Only transmit audio to radio number 1 - * rfAudio.broadcast(255); // Transmit audio to all radios in the group - * @endcode - * @param radioID Set the radioID of the radio to communicate privately with. - */ + /** + * Control of Private or Public Communication + * + * Call this function to establish private communication between nodes + * in a radio group, or to switch back to public transmission. + * @note Using a radioID of 255 will disable private communication and broadcast to all nodes + * + * @code + * rfAudio.broadcast(1); // Only transmit audio to radio number 1 + * rfAudio.broadcast(255); // Transmit audio to all radios in the group + * @endcode + * @param radioID Set the radioID of the radio to communicate privately with. + */ void broadcast(byte radioID); - /** - * Get any of the preset radio addresses - * - * Useful for listening nodes who wish to create private or additional radio groups - * The library has 14 predefined radio addreses. All radios listen/write on the first - * two addresses (0, 1), and engage a private channel based on the radio number. - * Radio 0 listens on address 2, Radio 1 on address 3, etc. - * - * @code - * uint64_t newAddress = rfAudio.getAddress(3); // Gets the 3rd defined radio address - * OR - * radio.openReadingPipe(0, rfAudio.getAddress(7)); // Listens on the 7th defined radio address - * @endcode - * @param addressNo Numbers 0 through 14 to access any part of the defined address array - * @return RadioAddress: Returns the requested predefined radio address - */ - uint64_t getAddress(byte addressNo); + /** + * Get any of the preset radio addresses + * + * Useful for listening nodes who wish to create private or additional radio groups + * The library has 14 predefined radio addreses. All radios listen/write on the first + * two addresses (0, 1), and engage a private channel based on the radio number. + * Radio 0 listens on address 2, Radio 1 on address 3, etc. + * + * @code + * uint64_t newAddress = rfAudio.getAddress(3); // Gets the 3rd defined radio address + * OR + * radio.openReadingPipe(0, rfAudio.getAddress(7)); // Listens on the 7th defined radio address + * @endcode + * @param addressNo Numbers 0 through 14 to access any part of the defined address array + * @return RadioAddress: Returns the requested predefined radio address + */ + uint64_t getAddress(byte addressNo); private: @@ -141,14 +140,12 @@ void TX(); */ void RX(); -#endif +#endif // __RF24Audio_H__ /** * @example GettingStarted.ino - * * This sketch is intended to demonstrate the basic functionality of the audio library. - * */ /** @@ -159,100 +156,20 @@ void RX(); /** * @example PrivateChannels.ino * This sketch is demonstrates the use of private channels (node-to-node) in a multi-radio group. - * */ /** * @example PrivateGroups.ino * This sketch is demonstrates the use of private groups (node-to-custom_groups) in a multi-radio group. - * */ /** * @example USB_Audio.ino * This sketch is demonstrates how to interact with the audio library directly using the core * RF24 radio library: http://nRF24.github.io/RF24/ - * */ /** - * @mainpage RF24Audio - Realtime Audio Streaming Library for Arduino - * - * This class implements a realtime audio streaming solution using nRF24L01(+) radios driven - * by the newly [optimized RF24 library fork](http://nRF24.github.com/RF24/). - * - * @section Features Features - * - User friendly setup and configuration: For beginners too: Just connect a radio module, microphone, and speaker. The library handles the rest. - * - Recording and broadcasting of audio to multiple devices using only Arduino, RF24 modules and input/output (speaker/microphone) devices - * - Multicast: Enables broadcasting to all nodes, single nodes, or partial groups of nodes - * - External controls: Use external buttons or code to control audio streaming - * - Volume control: Use external buttons or code to control audio volume on receiving devices. - * - Remote control: Start recording remotely via radio commands (Currently cannot stop remote recording) - * - LED Indicator/Visualization: Indicates audio playback and amplitude. - * - Customization: Using the underlying RF24 core library allows custom interaction with audio devices running this library. Receive audio data - * and stream it to a PC over USB, create and broadcast computer generated audio in realtime, and more! See the [USB_Audio example](USB_Audio_8ino-example.html) for more info. - * - Create additional node groups: Allows nodes to join private broadcast groups, and multicast only within their group as desired. See advanced section below. - * - * @section More How to learn more - * - * - [RF24Audio Library Class Documentation](classRF24Audio.html) - * - [RF24: Underlying radio driver (2014 - Newly Optimized)](http://nRF24.github.io/RF24/) - * - [My Blog: RF24 Optimization Overview](http://tmrh20.blogspot.com/2014/03/high-speed-data-transfers-and-wireless.html) - * - [My Blog: RF24 Wireless Audio](http://tmrh20.blogspot.com/2014/03/arduino-radiointercomwireless-audio.html) - * - [Download Current RF24Audio Driver](https://github.com/TMRh20/RF24Audio/archive/master.zip) - * - [Download Optimized RF24 Radio Driver](https://github.com/TMRh20/RF24/archive/master.zip) - * - [Newly Optimized RF24Network Class](http://nRF24.github.io/RF24Network/) - * - * @section Config Configuration and Setup - * - * The settings for the library will generally be detected automatically. To change from the default pin assignments etc, edit the - * userConfig.h file. The mandatory user options in the configuration file are shown below: - * @code - * #define SAMPLE_RATE 24000 // The sample rate to use for transferring audio samples Note: 44khz+ sample rate requires 8-bits per sample - * #define RF_SPEED RF24_1MBPS // RF24_250KBPS will do 13-20khz+ sample rate, RF24_1MBPS up to 24-44khz+, RF24_2MBPS for higher. These are not limits, just a guide. - * #define ANALOG_PIN A0 // The pin that analog readings will be taken from (microphone pin) - * @endcode - * - * Pin Assignments: See [the Setup page](Setup.html) for wiring diagrams - * - Speakers: Arduino Uno,Nano,etc: pins 9, 10 Arduino Mega: 11, 12 (Timer pins cannot be changed, but can use 1 pin and ground) - * - pin A0: Microphone/Input pin - * - pin A1: Transmission/Recording Start pin - * - pin A2: Volume Up - * - pin A3: Volume Down - * - pin A4: Trigger remote recording (Only working with dual devices) - * - Cannot be changed: LED Pin: Uno,Nano,etc: pin 6 Mega 2560: pin 13 (main LED pin) - * - * - * See http://arduino.cc/en/Tutorial/InputPullupSerial for info on how to wire the buttons to the pins - * See userConfig.h to change default pin assignments and options. - * - * @section Advanced Advanced Usage - * - * The radio pipes are defined as follows. For more complex multicast scenarios, radios can listen on any combination of pipes.
- * Use the getAddress(); function to access the address array.
- * @code - * const uint64_t pipes[14] = {0xABCDABCD71LL, - * 0x544d52687CLL, - * 0x544d526832LL, - * 0x544d52683CLL, - * 0x544d526846LL, - * 0x544d526850LL, - * 0x544d52685ALL, - * 0x544d526820LL, - * 0x544d52686ELL, - * 0x544d52684BLL, - * 0x544d526841LL, - * 0x544d526855LL, - * 0x544d52685FLL, - * 0x544d526869LL - * }; - * @endcode - * By default, all radios will open the same reading & writing pipes on the first two addresses.
- * Any radio that wishes to transmit, will reverse the addresses on the first two pipes, and begin to transmit to all the other nodes.
- * Every radio will automatically be assigned the first two addresses, then one of the remaining addresses as a private channel, based on its radio number:
(0 = pipes[2], 1 = pipes[3])
- * - * Additional addresses can be added by modifying the address array listed in userConfig.h - * * @page Setup Boards & Wiring * @section Board Wiring * This page displays different options for wiring/board configuration. @@ -264,5 +181,4 @@ void RX(); * @image html "images/RF24AudioBasic_SmallAntenna.jpg" height=45% width=45% * Wiring diagram for SD streaming/multicast using TMRpcm library: * @image html "images/RF24Audio_FullSD.jpg" height=65% width=65% - * */ \ No newline at end of file diff --git a/docs/README.md b/docs/README.md new file mode 100644 index 0000000..1fa6589 --- /dev/null +++ b/docs/README.md @@ -0,0 +1 @@ +These markdown files (*.md) contain relative hyperlinks. Any relative hyperlinks will not work when viewing these markdown files in github. \ No newline at end of file diff --git a/docs/main_page.md b/docs/main_page.md new file mode 100644 index 0000000..92ad09e --- /dev/null +++ b/docs/main_page.md @@ -0,0 +1,74 @@ +# RF24Audio - Realtime Audio Streaming Library for Arduino +This class implements a realtime audio streaming solution using nRF24L01(+) radios driven +by the newly [optimized RF24 library fork](http://nRF24.github.com/RF24/). + +## Features +- User friendly setup and configuration: For beginners too: Just connect a radio module, microphone, and speaker. The library handles the rest. +- Recording and broadcasting of audio to multiple devices using only Arduino, RF24 modules and input/output (speaker/microphone) devices +- Multicast: Enables broadcasting to all nodes, single nodes, or partial groups of nodes +- External controls: Use external buttons or code to control audio streaming +- Volume control: Use external buttons or code to control audio volume on receiving devices. +- Remote control: Start recording remotely via radio commands (Currently cannot stop remote recording) +- LED Indicator/Visualization: Indicates audio playback and amplitude. +- Customization: Using the underlying RF24 core library allows custom interaction with audio devices running this library. Receive audio data + and stream it to a PC over USB, create and broadcast computer generated audio in realtime, and more! See the [USB_Audio example](USB_Audio_8ino-example.html) for more info. +- Create additional node groups: Allows nodes to join private broadcast groups, and multicast only within their group as desired. See advanced section below. + +## How to learn more +- [RF24Audio Library Class Documentation](classRF24Audio.html) +- [RF24: Underlying radio driver (2014 - Newly Optimized)](http://nRF24.github.io/RF24/) +- [My Blog: RF24 Optimization Overview](http://tmrh20.blogspot.com/2014/03/high-speed-data-transfers-and-wireless.html) +- [My Blog: RF24 Wireless Audio](http://tmrh20.blogspot.com/2014/03/arduino-radiointercomwireless-audio.html) +- [Download Current RF24Audio Driver](https://github.com/TMRh20/RF24Audio/archive/master.zip) +- [Download Optimized RF24 Radio Driver](https://github.com/TMRh20/RF24/archive/master.zip) +- [Newly Optimized RF24Network Class](http://nRF24.github.io/RF24Network/) + +## Configuration and Setup +The settings for the library will generally be detected automatically. To change from the default pin assignments etc, edit the +userConfig.h file. The mandatory user options in the configuration file are shown below: + +```cpp +#define SAMPLE_RATE 24000 // The sample rate to use for transferring audio samples Note: 44khz+ sample rate requires 8-bits per sample +#define RF_SPEED RF24_1MBPS // RF24_250KBPS will do 13-20khz+ sample rate, RF24_1MBPS up to 24-44khz+, RF24_2MBPS for higher. These are not limits, just a guide. +#define ANALOG_PIN A0 // The pin that analog readings will be taken from (microphone pin) +``` + +### Pin Assignments +@see [the Setup page](Setup.html) for wiring diagrams + +- Speakers: Arduino Uno,Nano,etc: pins 9, 10 Arduino Mega: 11, 12 (Timer pins cannot be changed, but can use 1 pin and ground) +- pin A0: Microphone/Input pin +- pin A1: Transmission/Recording Start pin +- pin A2: Volume Up +- pin A3: Volume Down +- pin A4: Trigger remote recording (Only working with dual devices) +- Cannot be changed: LED Pin: Uno,Nano,etc: pin 6 Mega 2560: pin 13 (main LED pin) + +See http://arduino.cc/en/Tutorial/InputPullupSerial for info on how to wire the buttons to the pins +See userConfig.h to change default pin assignments and options. + +## Advanced Usage +The radio pipes are defined as follows. For more complex multicast scenarios, radios can listen on any combination of pipes.
+Use the getAddress(); function to access the address array. + +```cpp +const uint64_t pipes[14] = {0xABCDABCD71LL, + 0x544d52687CLL, + 0x544d526832LL, + 0x544d52683CLL, + 0x544d526846LL, + 0x544d526850LL, + 0x544d52685ALL, + 0x544d526820LL, + 0x544d52686ELL, + 0x544d52684BLL, + 0x544d526841LL, + 0x544d526855LL, + 0x544d52685FLL, + 0x544d526869LL}; +``` +By default, all radios will open the same reading & writing pipes on the first two addresses.
+Any radio that wishes to transmit, will reverse the addresses on the first two pipes, and begin to transmit to all the other nodes.
+Every radio will automatically be assigned the first two addresses, then one of the remaining addresses as a private channel, based on its radio number:
(0 = pipes[2], 1 = pipes[3])
+ +Additional addresses can be added by modifying the address array listed in userConfig.h diff --git a/examples/GettingStarted/printf.h b/examples/GettingStarted/printf.h deleted file mode 100644 index b2efd56..0000000 --- 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/Minimal/printf.h b/examples/Minimal/printf.h deleted file mode 100644 index b2efd56..0000000 --- a/examples/Minimal/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/PrivateChannels/printf.h b/examples/PrivateChannels/printf.h deleted file mode 100644 index b2efd56..0000000 --- a/examples/PrivateChannels/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/PrivateGroups/printf.h b/examples/PrivateGroups/printf.h deleted file mode 100644 index b2efd56..0000000 --- a/examples/PrivateGroups/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/USB_Audio/printf.h b/examples/USB_Audio/printf.h deleted file mode 100644 index b2efd56..0000000 --- a/examples/USB_Audio/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/library.properties b/library.properties new file mode 100644 index 0000000..51b3868 --- /dev/null +++ b/library.properties @@ -0,0 +1,9 @@ +name=RF24Audio +version=1.0 +author=TMRh20 +maintainer=TMRh20 +sentence=Arduino Wireless Audio Data Library +paragraph=This library allows streaming of audio data from analog inputs via nRF24L01 radio modules +category=Communication +url=https://nRF24.github.io/RF24Audio/ +architectures=avr diff --git a/userConfig.h b/userConfig.h index 9079171..fa398f2 100644 --- a/userConfig.h +++ b/userConfig.h @@ -1,13 +1,31 @@ - +/** + * @file userConfig.h + * + * macros for customization of RF24Audio + */ /************ MANDATORY User Variables ************/ - -// Maximum Range: Sample rate 16000, RF_SPEED RF24_250KBPS -// Maximum Quality: Sample rate 44000, RF_SPEED RF24_2MBPS - -#define SAMPLE_RATE 24000 // The sample rate to use for transferring audio samples Note: 44khz+ sample rate requires 8-bits per sample -#define RF_SPEED RF24_1MBPS // RF24_250KBPS will do 13-20khz+ sample rate, RF24_1MBPS up to 24-44khz+, RF24_2MBPS for higher. These are not limits, just a guide. -#define ANALOG_PIN A0 // The pin that analog readings will be taken from (microphone pin) +/** + * @brief The sample rate to use for transferring audio samples + * + * Maximum Range: Sample rate 16000, RF_SPEED RF24_250KBPS
+ * Maximum Quality: Sample rate 44000, RF_SPEED RF24_2MBPS + * @note 44khz+ sample rate requires 8-bits per sample + */ +#define SAMPLE_RATE 24000 + +/** + * @brief configure the RF data rate + * + * These are not limits, just a guide: + * - RF24_250KBPS will do 13-20khz+ sample rate + * - RF24_1MBPS up to 24-44khz+ + * - RF24_2MBPS for higher. + */ +#define RF_SPEED RF24_1MBPS + +/** @brief The pin that analog readings will be taken from (microphone pin) */ +#define ANALOG_PIN A0 /************ OverRides ************/ @@ -17,82 +35,96 @@ //#define speakerPin 9 // If using a non-standard board, override the timer1 pins //#define speakerPin 10 -#define ENABLE_LED // Indicator pin. Using pin 6 on Uno enables audio visualization. Pin 13 on Mega 2560 (TIMER0 COMPA) The pin# cannot be changed. + +/** + * @brief Indicator pin + * + * Using pin 6 on Uno enables audio visualization. Pin 13 on Mega 2560 (TIMER0 COMPA) + * @note The pin number cannot be changed. + */ +#define ENABLE_LED /************ Optional/Advanced User Variables ************/ //#define MANUAL_BUTTON_HANDLING // Disables button handling via timer0. Allow users to customize button handling -#define TX_PIN A1 // Button pin to trigger recording & transmission -#define VOL_UP_PIN A2 // Pin for external volume control -#define VOL_DN_PIN A3 // Pin for external volume control -#define REMOTE_TX_PIN A4 // Pin for externally triggering remote recording -#define REMOTE_RX_PIN 4 // Pin for externally stopping remote recording (needs timeout enabled) -#define buffSize 32 // The size of the memory buffer to use. Not really configurable. -//#define speakerTX // Whether to output to speaker while transmitting -//#define oversampling // Oversampling is recommended for low sample rates only. This only affects playback. -//#define RX_ONLY -//#define TX_ONLY // Not functional yet +/** Button pin to trigger recording & transmission */ +#define TX_PIN A1 +/** Pin for external volume control */ +#define VOL_UP_PIN A2 -/************ Automated pin selections, override by defining above ************/ +/** Pin for external volume control */ +#define VOL_DN_PIN A3 -#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) || (__AVR_ATmega32U4__) || (__AVR_AT90USB646__) || defined(__AVR_AT90USB1286__) || (__AVR_ATmega128__) ||defined(__AVR_ATmega1281__)||defined(__AVR_ATmega2561__) - #define rampMega - - #if !defined (speakerPin) // Speaker pin selection for mega etc - #define speakerPin 11 // The pins to output audio on. (11,12 on Mega 2560) - #endif - #if !defined (speakerPin2) - #define speakerPin2 12 - #endif - #if defined (ENABLE_LED) - #define ledPin 13 - #endif - -#else //Speaker selection for Uno,Nano, etc - - #if !defined (speakerPin) - #define speakerPin 9 // The pin used to output audio on UNO - #endif - #if !defined (speakerPin2) - #define speakerPin2 10 // The pin used to output audio on Nano - #endif - - #if defined (ENABLE_LED) - #define ledPin 6 - #endif -#endif +/** Pin for externally triggering remote recording */ +#define REMOTE_TX_PIN A4 +/** Pin for externally stopping remote recording (needs timeout enabled) */ +#define REMOTE_RX_PIN 4 -//********Radio Defines **************************** -// Radio pipe addresses for the 2 nodes to communicate. -const uint64_t pipes[14] = {0xABCDABCD71LL, - 0x544d52687CLL, - 0x544d526832LL, - 0x544d52683CLL, - 0x544d526846LL, - 0x544d526850LL, - 0x544d52685ALL, - 0x544d526820LL, - 0x544d52686ELL, - 0x544d52684BLL, - 0x544d526841LL, - 0x544d526855LL, - 0x544d52685FLL, - 0x544d526869LL - }; - +/** The size of the memory buffer to use. Not really configurable (set to maximum by default). */ +#define buffSize 32 +//#define speakerTX // Whether to output to speaker while transmitting +//#define oversampling // Oversampling is recommended for low sample rates only. This only affects playback. +//#define RX_ONLY +//#define TX_ONLY // Not functional yet +/************ Automated pin selections, override by defining above ************/ +#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) || (__AVR_ATmega32U4__) || (__AVR_AT90USB646__) || defined(__AVR_AT90USB1286__) || (__AVR_ATmega128__) ||defined(__AVR_ATmega1281__)||defined(__AVR_ATmega2561__) + #define rampMega + // Speaker pin selection for mega etc + #if !defined (speakerPin) + #define speakerPin 11 // The pins to output audio on. (11,12 on Mega 2560) + #endif + #if !defined (speakerPin2) + #define speakerPin2 12 + #endif + #if defined (ENABLE_LED) + #define ledPin 13 + #endif +#else + //Speaker selection for Uno,Nano, etc + #if !defined (speakerPin) + /** The pin used to output audio on UNO */ + #define speakerPin 9 + #endif + #if !defined (speakerPin2) + /** The pin used to output audio on Nano */ + #define speakerPin2 10 + #endif + #if defined (ENABLE_LED) + #define ledPin 6 + #endif +#endif +//********Radio Defines **************************** +/** Radio pipe addresses for the 2 nodes to communicate. */ +const uint64_t pipes[14] = +{ + 0xABCDABCD71LL, + 0x544d52687CLL, + 0x544d526832LL, + 0x544d52683CLL, + 0x544d526846LL, + 0x544d526850LL, + 0x544d52685ALL, + 0x544d526820LL, + 0x544d52686ELL, + 0x544d52684BLL, + 0x544d526841LL, + 0x544d526855LL, + 0x544d52685FLL, + 0x544d526869LL +};