Finally I have found a solution.
This was only possible using my trusty oscilloscope.
I could see infrequent, but comparable to the loss rate, timing jitter as the PLUGPACK processed the inbound messages.
It was clear the "shifting Arduino system timing interrupts (supporting millis())" rather than anything to do with Serial processing was the likely culprit.
We can't and don't want to change the Arduino system baseline code.
I can now achieve 3 messages lost in 6000 sent, spaced at 100mS, by adding a "duplicate send message" line of code to my SENSOR.
SENSOR code:
void radio_send_chirp_message() {
//
digitalWrite(OSCILLOSCOPE, HIGH);
Serial.print(send_string); Serial.print(" ");
Serial.print("tx at "); Serial.print(millis());
Serial.print(" chars="); Serial.print(send_length);
Serial.println();
//radio.sendWithRetry(PLUGPACK, send_buffer, send_length, 0); // 0 retries for dev+test, maybe for production ???
radio.send(PLUGPACK, send_buffer, send_length, false); // 0 retries for dev+test, maybe for production ???
radio.send(PLUGPACK, send_buffer, send_length, false); // 0 retries for dev+test, maybe for production ???
state_led_green = LED_GREEN_FLASH;
led_green_flash_start_time = millis(); // confirm chirp msg with green flash
digitalWrite(OSCILLOSCOPE, LOW);
}
Felix I looked at the RFM69 library , RFM69.cpp line 135, to find you had written:
attachInterrupt(_interruptNum, RFM69::isr0, RISING);
Arduino attachInterrupt(...) definition is here:
https://www.arduino.cc/reference/en/language/functions/external-interrupts/attachinterrupt/---------------------------------
Parameters
interrupt: the number of the interrupt (int)
pin: the pin number (Arduino Due, Zero, MKR1000 only)
ISR: the ISR to call when the interrupt occurs; this function must take no parameters and return nothing. This function is sometimes referred to as an interrupt service routine.
mode: defines when the interrupt should be triggered. Four constants are predefined as valid values:
LOW to trigger the interrupt whenever the pin is low,
CHANGE to trigger the interrupt whenever the pin changes value
RISING to trigger when the pin goes from low to high,
FALLING for when the pin goes from high to low.
The Due, Zero and MKR1000 boards allows also:
HIGH to trigger the interrupt whenever the pin is high.
--------------------------------------
Felix, would you consider changing your isr0() code in the library to use a
LOW or
CHANGE to "widen" the capture range of the receiveDone() trigger?.
It seems this would avoid missing the transient RISING trigger at the moment.
The application watching loop would catch the LOW/CHANGE soon after the Arduino system interrupt service was completed.
Looks to me like anyone's code could be a victim of what I have discovered but can now rectify ... with 1 loss in 2000 messages now acceptable/tolerable for my application.
SENSOR transmission time is an extra (duplicated) 10mS which my calulcations tell me is not a huge battery life price to pay for this "interrupt collision avoidance" strategy.
Moteino M0 event/message wakeup time is around 80 mS.
My preference would be to have the library avoid the collisions, rather than this workaround.
attachInterrupt(_interruptNum, RFM69::isr0, LOW or CHANGE);