[433Mhz Tx + LDR][433Mhz Rx + ENC28J60] : Rx problem after x minutes

Have set up the following:

Sensor/Transmitter:
LDR detecting blinking LED (domestic elec. meter) => triggers Arduino Nano interrupt ISR (pin 2) => blink counter incremented, milliseconds since last blink recorded => sent in payload struct via 433Mhz Transmitter (cheap type XD-FST).

Receiver/Storage:
Arduino Uno with 433Mhz Receiver (cheap type XY-MK-5V - data pin connected to Arduino D4 pin) receives message payload sent from XD-FST => sends data to webservice using HTTP POST via ENC28J60 => webservice stores info in db ready for online display etc.

I've fixed a 173mm wire antenna to both Tx and Rx modules. I'm getting a great range from ground floor to second floor of house.

I'm using the VirtualWire library for the 433Mhz comms, and the EtherCard library for the ENC28J60

All the above appears to work perfectly, and yet after some short while (a few minutes) the payload seen at the receiver seems to get corrupted....not complete garbage but just the same values repeated despite new messages continuing to be received.
Pressing RESET on Arduino Uno fixes the corruption, only for it to happen again after a similar length of time.

I'm trying to convince myself that this is something to do with the Arduino running out of memory....but I don't know enough about the idiosyncrasies of the cheap Tx/Rx modules to be sure if I'm not encountering some other common problem.

The behaviour does suggest a problem at the Rx end, since resetting the Arduino here sees 'normal' messages arriving again albeit for a short while.

I'd be very grateful for any thoughts on where I might be going wrong.

Happy to supply any further info you may need.

Here's my code - n.b. some portions commented out intentionally...just used for testing :

Transmitter:

#include <VirtualWire.h>

int last_blink_count_sent = 0;

struct payloadData
{
  int TX_ID;
  unsigned long blink_ms;
  int blinkCount;
  float inst_power;
  float kwh_consumed;
  float cost_consumed;
};

payloadData payload; 

const float METER_BLINKS_PER_KWH = 800.0;
const float KWH_PER_METER_BLINK = 1/METER_BLINKS_PER_KWH;
const float MILLIS_PER_HOUR = 3600000.0;
const float COST_PER_BILL_UNIT = 12.23;
const long BOUNCE_WINDOW_MS=450;
unsigned long prev_interrupt_ms = 0;
unsigned long interrupt_ms = 0;
unsigned long millis_since_last_blink = 0;
volatile unsigned long last_blink_ms = 0;
volatile int blinks = 0;
int interruptPinLDR = 2;

void onBlink()
{ 
  interrupt_ms = millis();
  millis_since_last_blink = (unsigned long)(interrupt_ms - prev_interrupt_ms); 
  if(millis_since_last_blink >= BOUNCE_WINDOW_MS)
  {
    last_blink_ms = millis_since_last_blink;
    blinks++;
    prev_interrupt_ms = interrupt_ms;
  }
}

void createPayload()
{
  payload.TX_ID = 99;
  payload.blink_ms = last_blink_ms;
  payload.blinkCount = blinks;
  payload.inst_power = MILLIS_PER_HOUR / ((float)last_blink_ms * METER_BLINKS_PER_KWH); // 3600000 / [X * 800]
  payload.kwh_consumed = blinks * KWH_PER_METER_BLINK;
  payload.cost_consumed = payload.kwh_consumed * COST_PER_BILL_UNIT / 100;
}

void transmitPayload()
{
  digitalWrite(13,HIGH);
  vw_send((uint8_t *)&payload, sizeof(payload));
  vw_wait_tx(); // Wait until the whole message is gone
  digitalWrite(13,LOW);
  free(&payload);
}  

void setup() 
{
  pinMode(13,OUTPUT);
  pinMode(interruptPinLDR,INPUT);
  attachInterrupt(0, onBlink, FALLING);
  
  vw_set_ptt_inverted(true); //
  vw_set_tx_pin(12);
  vw_setup(4000);// speed of data transfer Kbps
}

void loop()
{ 
  if(blinks > last_blink_count_sent)
  {
    last_blink_count_sent = blinks;
    createPayload(); 
    transmitPayload();
    delay(200);
  }
}

Receiver:

#include <EtherCard.h>
#include <VirtualWire.h>

struct payloadData
{
  int TX_ID;
  unsigned long blink_ms;
  int blinkCount;
  float inst_power;
  float kwh_consumed;
  float cost_consumed;
};

payloadData payload;
uint8_t pyldSize = 0;

char postData[50];
static byte mymac[] = { 0x74,0x69,0x69,0x2D,0x30,0x31 };
byte Ethernet::buffer[700];
char dataReceiveHost[] PROGMEM = "192.168.2.9";
uint8_t dataReceiveHostIP[4] = {192, 168, 2, 9};
int plen = 0;
uint16_t dat_p;

static void dataReceiveRequest_callback (byte status, word off, word len) 
{
  //Serial.println(F("Callback"));
  //Ethernet::buffer[off+300] = 0;
  //Serial.print((const char*) Ethernet::buffer + off);
  // Serial.println(F("..."));
}


void setup()
{

  Serial.begin(9600);
  if (ether.begin(sizeof Ethernet::buffer, mymac) == 0) 
    Serial.println( "Failed to access Ethernet controller");
  if (!ether.dhcpSetup())
    Serial.println("DHCP failed");
  ether.printIp("IP:  ", ether.myip);
  ether.printIp("GW:  ", ether.gwip);  
  ether.printIp("DNS: ", ether.dnsip); 
  ether.copyIp(ether.hisip, dataReceiveHostIP);
  ether.printIp("SRV: ", ether.hisip);

  pyldSize = (uint8_t)sizeof(payload);
  vw_set_ptt_inverted(true); // Required for DR3100
  vw_set_rx_pin(4);////////////////////////////////////////////////change from 12
  vw_setup(4000);  // Bits per sec
  vw_rx_start();
}

void loop()
{
  
  plen = ether.packetReceive();
  dat_p=ether.packetLoop(plen);

  if(vw_get_message((uint8_t *)&payload, &pyldSize))// Non-blocking
  { 
    if(payload.TX_ID == 99)
    {
        sprintf(postData, "data=%u:%lu", payload.blinkCount, payload.blink_ms);
        ether.httpPost(PSTR("/ArduinoWebServices/Service1.asmx/AcceptData"),dataReceiveHost,NULL,postData,dataReceiveRequest_callback);
    }  
  }
  free(&payload);
}

Please also note in the above code for the receiver that I'm not yet using all members of the payload struct...I intend to eventually. or possibly reduce the payload struct and do the calculations in the webservice.

Hmm, well, I believe I may have answered my own problem.... :blush:

In the Rx sketch, I'm setting the size of the payload once in setup()... but having browsed the source for VirtualWire.cpp I've found that vw_get_message() alters the value of its second argument - the idea presumably being to report the actual number of bytes contained in the message.
However, once I added a Serial.println() to report the value of my "pyldSize" variable, I found that it was starting life as 20 ...which is obtained by calling... (uint8_t)sizeof(payload).
....but after the first message was processed, pyldSize was reducing to 3, having been modified within vw_get_message().

I found a definition for VW_MAX_MESSAGE_LEN VirtualWire.h - which was set to 80 - so I decided to use that for assigning pyldSize instead:

pyldSize = VW_MAX_MESSAGE_LEN;

I also moved this assignment so it was performed on each iteration of loop(), so as to override whatever modification might have occurred within vw_get_message().

void loop()
{
  plen = ether.packetReceive();
  dat_p=ether.packetLoop(plen);
  pyldSize = VW_MAX_MESSAGE_LEN;//override vw_get_message() modification
  if(vw_get_message((uint8_t *)&payload, &pyldSize))// Non-blocking
  { 
    if(payload.TX_ID == 99)....................etc.
    {

My receiver's now been running for about 20 minutes with no problems.

Fingers crossed I've fixed things....!
:astonished: