Possible Memory Fragmentation w/ RFID

I am writing a program to control door access to certain room. I am using a RobotGeek RFIDuino hat and antenna to scan new tags. The issue I am running isn't with the MQTT, WIFI, or even the RFIDuino library, but somewhere in between. After 2.5 to 3 minutes of running, the program is unable to properly store the incoming MQTT signal. It will still output the correct message, and it receives receives the response. However, it does not store this message, instead defaulting to it's most recent/previous value. I am thinking that this is due to possible memory fragmentation caused by use of strings, so I have converted everything I could think of to char arrays, but the issue persists. Seen below is the already char updated script. I can post the original string based one upon request.

NOTE: When broken, the MQTT response message isn't stored, but it can still store and recognize different tag values. Each tag scan renders the correct number values, even with multiple tags. Each tag value is 3 numbers anywhere from 1 to 999.

Here is the code:

//------------------------------------------------------------------// User Modified Code
int roomNumber = 224;

//------------------------------------------------------------------// Imports
#include <WiFiS3.h> //Includes the WiFiS2 Library
#include <ArduinoMqttClient.h>  //Includes the MQTTClient Library

#include "wifi_bits.h" //Includes document for Wifi/Network data

//------------------------------------------------------------------// Variables
//Wifi Variables
char ssid[] = NET_SSID;        // your network SSID (name)
char pass[] = NET_PASSWORD;    // your network password (use for WPA, or use as key for WEP)
int status = WL_IDLE_STATUS;     // the WiFi radio's status

WiFiClient wifiClient;

//MQTT Variable
MqttClient mqttClient(wifiClient);

//MQTT Broker Variables
const char broker[] = "local.host";
int        port     = 1883;
const char OPNRQST[]  = "test/topic";

bool msgReceived = false;
char *message[6];    //Message to broadcast
char buffer[10];

//String door = "";   //Door Command applies to
//String OpnClse = "";  //Open or Close Command
char messageR[23];   //Recieved Message
//char messageRChar[] = messageR;            

//RFIDuino Variables
byte tagData[5];  //Holds the ID numbers from the tag
int i = 0;  //Counting variable for counter function
boolean goodScan = false; //true if tag scan and secondary(check) tag scan matches
boolean tagCheck = false; //true when a tag has been read, false otherwise

//RFIDuino Library Variables
int buzzer = 5;
int led1 = 3;
int led2 = 2;
int demodOut = 8;
int shd = 7;
int mod = 6;
int rdyClk = 4;

//------------------------------------------------------------------// Definitions
#define SERIAL_PORT Serial  //Serial port definition for Geekduino, Arduino Uno, and most Arduino Boards
#define RELAY 9  //the relay PinOut

#define DELAYVAL 320  //384 //standard delay for manchster decode
#define TIMEOUT 1000  //standard timeout for manchester decode

//------------------------------------------------------------------// Setup() - Begin Program 
void setup() {               //Setup Code
  //Begin Serial
  SERIAL_PORT.begin(19200);  //Declare Baud rate for Arduino at 19200
  Serial.println("Begin");
  
  itoa(roomNumber, buffer, 10);
  message[0] = buffer;

  //Pin Declarations
  pinMode(RELAY, OUTPUT);  //The relay must be manuualy initalized as an output

  //set pin modes on RFID pins
  pinMode(mod, OUTPUT);
  pinMode(shd, OUTPUT);
  pinMode(demodOut, INPUT);
  pinMode(rdyClk, INPUT);

  //set pins for User Acccessible Output
  pinMode(buzzer, OUTPUT);
  pinMode(led1, OUTPUT);
  pinMode(led2, OUTPUT);

  //set user outputs to LOW
  digitalWrite(buzzer, LOW);
  digitalWrite(led1, LOW);
  digitalWrite(led2, LOW);

  //set shd and MOD low to prepare for reading
  digitalWrite(shd, LOW);
  digitalWrite(mod, LOW);

  //Wifi Processes
  if (WiFi.status() == WL_NO_MODULE) {
    Serial.println("Communication with WiFi module failed!");
    //don't continue
    while (true);
  }

  String fv = WiFi.firmwareVersion();
  if (fv < WIFI_FIRMWARE_LATEST_VERSION) {
    Serial.println("Please upgrade the firmware");
  }

  // attempt to connect to WiFi network:
  while (status != WL_CONNECTED) {
    Serial.print("Attempting to connect to WPA SSID: ");
    Serial.println(ssid);
    // Connect to WPA/WPA2 network:
    status = WiFi.begin(ssid, pass);

    // wait 1 seconds for connection:
    delay(50);
  }

  // you're connected now, so print out the data:
  Serial.print("You're connected to the network ");
  printCurrentNet();
  printWifiData();

  //MQTT Setup
  Serial.println("Connecting to MQTT Broker");

  while (!mqttClient.connect(broker, port)) {
    Serial.print("MQTT connection failed! Error code = ");
    Serial.println(mqttClient.connectError());

    delay(1000);
  }

  Serial.println("Connected to Broker");

  //Signify Setup() is completed
  beep(2, 2);  //Beep the Arduino twice
}

//------------------------------------------------------------------// Loop() - Infinite Loop
void loop() {     
  goodScan = false;
  msgReceived = false;

  //tagCheck = decodeTag(tagData);  //run the decodetag to check for the tag. If a tag is read then the function will return 'true' and load the data into 'tagData'
  if(i > 10000){  //Counting function to possibly delay/prevent system breakdown
    Serial.println("1K Reset");
    i = 0;
  }
  if (tagCheck = decodeTag(tagData)) {                    //if a 'true' is returned from the decodetag function, a tag was succesffuly scanned
    check();                                 //Transfer to Scan Function
    tagCheck = false;
    delay(500);
  }
  delay(2);
  i++;
}

//------------------------------------------------------------------// Function - Check
void check() {  // Compares tag vs valid tags
  if (tagData[0] != 0) {

    Serial.println(
    String(message[0]) + "_" + 
    String(tagData[0]) + "_" + 
    String(tagData[1]) + "_" + 
    String(tagData[2]) + "_" + 
    String(tagData[3]) + "_" + 
    String(tagData[4]));

    mqttClient.beginMessage(OPNRQST);
    mqttClient.print(
    String(message[0]) + "_" + 
    String(tagData[0]) + "_" + 
    String(tagData[1]) + "_" + 
    String(tagData[2]) + "_" + 
    String(tagData[3]) + "_" + 
    String(tagData[4]));
    mqttClient.endMessage();

    mqttClient.subscribe(OPNRQST);  // Subscribe to the topic
    
    int wait = 0;
    beep(1, 2);  // Beep the Arduino once

    while (!msgReceived) {
      int messageSize = mqttClient.parseMessage();
      if (wait > 30) {
        msgReceived = true;
      }
      if (messageSize) {
        // Received a message
        //messageR = "";
        int n = 0;
        while (mqttClient.available()) {
          messageR[n] = ((char)mqttClient.read());
          n++;
        }
        Serial.println(messageR[4]);
        
        // Handle received message (e.g., checking if it matches criteria)
        if ((String(messageR[4]) == "O" && String(messageR[5]) == "P")) {
          goodScan = true;
          msgReceived = true;
        }else{
          msgReceived = true;
        }
      }
      wait++;
      delay(1);  // Short delay to avoid rapid looping
    }

    Serial.print(String(messageR[0]));
    Serial.print(String(messageR[1]));
    Serial.print(String(messageR[2]));
    Serial.print(String(messageR[3]));
    Serial.print(String(messageR[4]));
    Serial.println(String(messageR[5]));

    mqttClient.unsubscribe(OPNRQST);  // Unsubscribe from the topic

    if (goodScan) {
      Serial.println("Open.");
      beep(1, 1);
      digitalWrite(RELAY, HIGH);  // Turn the relay on
      delay(1500);                // Wait 1.5 seconds
      digitalWrite(RELAY, LOW);   // Turn the relay off
    } else {
      beep(1, 0);
    }
  }
}


//------------------------------------------------------------------// Function - Print Wifi Data
void printWifiData() {
  // print your board's IP address:
  IPAddress ip = WiFi.localIP();
  Serial.print("IP Address: ");
  
  Serial.println(ip);

  /*// print your MAC address:
  byte mac[6];
  WiFi.macAddress(mac);
  Serial.print("MAC address: ");
  printMacAddress(mac);
  */
}

//------------------------------------------------------------------// Function - Print Currect Network
void printCurrentNet() {
  // print the SSID of the network you're attached to:
  Serial.print("SSID: ");
  Serial.println(WiFi.SSID());

  /*// print the MAC address of the router you're attached to:
  byte bssid[6];
  WiFi.BSSID(bssid);
  Serial.print("BSSID: ");
  printMacAddress(bssid);
  */
  // print the received signal strength:
  long rssi = WiFi.RSSI();
  Serial.print("signal strength (RSSI):");
  Serial.println(rssi);

  /*// print the encryption type:
  byte encryption = WiFi.encryptionType();
  Serial.print("Encryption Type:");
  Serial.println(encryption, HEX);
  Serial.println();
  */
}

//------------------------------------------------------------------// Function - Beep
void beep(int bp, int gb) {  //Makes it beep
  int tkn = 0;
  /*
  if (gb == 1) {
    successSound();
  } else if (gb == 0) {
    errorSound();
  } else {
    for (tkn; tkn < bp; tkn++) {  //beeps inputed (bp) amount of time
      digitalWrite(buzzer, HIGH);
      delay(100);
      digitalWrite(buzzer, LOW);
      delay(100);
    }
  }
  */
}

//------------------------------------------------------------------// Function - Flash
void flash(int fls) {  //Makes it Flash
  int tkn = 0;
  for (tkn; tkn < fls; tkn++) {  //beeps inputed (bp) amount of time
    digitalWrite(led2, HIGH);
    delay(50);
    digitalWrite(led2, LOW);
    delay(50);
  }
}

//------------------------------------------------------------------// RFIDuino Modified Library
bool decodeTag(unsigned char *buf) {
  unsigned char i = 0;
  unsigned short timeCount;
  unsigned char timeOutFlag = 0;
  unsigned char row, col;
  unsigned char row_parity;
  unsigned char col_parity[5];
  unsigned char dat;
  unsigned char searchCount = 0;
  unsigned char j;
  while (true) {
    timeCount = 0;
    if (0 == digitalRead(demodOut))  //watch for demodOut to go low
    {
      break;
    }

    if (timeCount >= 600) {
      return false;
    }
    timeCount = 0;

    delayMicroseconds(DELAYVAL);
    if (digitalRead(demodOut)) {
      for (i = 0; i < 8; i++)  // 9 header bits
      {
        timeCount = 0;                      //restart counting
        while (1 == digitalRead(demodOut))  //while DEMOD out is high
        {
          if (timeCount == TIMEOUT) {
            timeOutFlag = 1;
            break;
          } else {
            timeCount++;
          }
        }

        if (timeOutFlag) {
          break;
        } else {
          delayMicroseconds(DELAYVAL);
          if (0 == digitalRead(demodOut)) {
            break;
          }
        }
      }  //end for loop

      if (timeOutFlag) {
        timeOutFlag = 0;
        return false;
      }

      if (i == 8)  //Receive the data
      {
        timeOutFlag = 0;
        timeCount = 0;
        while (1 == digitalRead(demodOut)) {
          if (timeCount == TIMEOUT) {
            timeOutFlag = 1;
            break;
          } else {
            timeCount++;
          }

          if (timeOutFlag) {
            timeOutFlag = 0;
            return false;
          }
        }

        col_parity[0] = col_parity[1] = col_parity[2] = col_parity[3] = col_parity[4] = 0;
        for (row = 0; row < 11; row++) {
          row_parity = 0;
          j = row >> 1;

          for (col = 0, row_parity = 0; col < 5; col++) {
            delayMicroseconds(DELAYVAL);
            if (digitalRead(demodOut)) {
              dat = 1;
            } else {
              dat = 0;
            }

            if (col < 4 && row < 10) {
              buf[j] <<= 1;
              buf[j] |= dat;
            }

            row_parity += dat;
            col_parity[col] += dat;
            timeCount = 0;
            while (digitalRead(demodOut) == dat) {
              if (timeCount ==  TIMEOUT) {
                timeOutFlag = 1;
                break;
              } else {
                timeCount++;
              }
            }
            if (timeOutFlag) {
              break;
            }
          }

          if (row < 10) {
            if ((row_parity & 0x01) || timeOutFlag)  //Row parity
            {
              timeOutFlag = 1;
              break;
            }
          }
        }

        if (timeOutFlag || (col_parity[0] & 0x01) || (col_parity[1] & 0x01) || (col_parity[2] & 0x01) || (col_parity[3] & 0x01))  //Column parity
        {
          timeOutFlag = 0;
          return false;
        } else {
          return true;
        }

      }  //end if(i==8)

      return false;

    }  //if(digitalRead(demodOut))
  }    //while(1)
};

//use the tone() function to play an 'error' sound, a single tone repeated 3 times
void errorSound() {
  tone(buzzer, 1300, 500);
  delay(250);
  noTone(buzzer);
  delay(250);

  tone(buzzer, 1300, 1000);
  delay(250);
  noTone(buzzer);
  delay(250);

  tone(buzzer, 1300, 1000);
  delay(250);
  noTone(buzzer);
  delay(250);
};

//use the tone() function to play an 'success' sound, 3 ascending tones
void successSound() {
  tone(buzzer, 3500, 1000);
  delay(165);
  noTone(buzzer);

  tone(buzzer, 4000, 1000);
  delay(165);
  noTone(buzzer);

  tone(buzzer, 4500, 1000);
  delay(165);
  noTone(buzzer);
  delay(165);
};

//function to compare 2 byte arrays. Returns true if the two arrays match, false of any numbers do not match
bool compareTagData(byte *tagData1, byte *tagData2) {
  for (int j = 0; j < 5; j++) {
    if (tagData1[j] != tagData2[j]) {
      return false;  //if any of the ID numbers are not the same, return a false
    }
  }

  return true;  //all id numbers have been verified
}

//function to transfer one byte array to a secondary byte array.
//source -> tagData
//destination -> tagDataBuffer
void transferToBuffer(byte *tagData, byte *tagDataBuffer) {
  for (int j = 0; j < 5; j++) {
    tagDataBuffer[j] = tagData[j];
  }
}

bool scanForTag(byte *tagData) {
  static byte tagDataBuffer[5];  //A Buffer for verifying the tag data. 'static' so that the data is maintained the next time the loop is called
  static int readCount = 0;      //the number of times a tag has been read. 'static' so that the data is maintained the next time the loop is called
  boolean verifyRead = false;    //true when a tag's ID matches a previous read, false otherwise
  boolean tagCheck = false;      //true when a tag has been read, false otherwise

  tagCheck = decodeTag(tagData);  //run the decodetag to check for the tag
  if (tagCheck == true)           //if 'true' is returned from the decodetag function, a tag was succesfully scanned
  {
    readCount++;  //increase count since we've seen a tag

    if (readCount == 1)  //if have read a tag only one time, proceed
    {
      transferToBuffer(tagData, tagDataBuffer);  //place the data from the current tag read into the buffer for the next read
    } else if (readCount == 2)                   //if we see a tag a second time, proceed
    {
      verifyRead = compareTagData(tagData, tagDataBuffer);  //run the checkBuffer function to compare the data in the buffer (the last read) with the data from the current read

      if (verifyRead == true)  //if a 'true' is returned by compareTagData, the current read matches the last read
      {
        readCount = 0;  //because a tag has been succesfully verified, reset the readCount to '0' for the next tag
        return true;
      }
    }
  } else {
    return false;
  }
}

It looks like you didn't remove all your Strings. You do not need to convert your char arrays into one complete String to then pass to .print(). Just make your code a series of .print() statements

This helped fix it. I had to throw a function in there also to keep it scanning false values after a period of inactivity as well.

Good that it's working. But it repeatedly subscribes and unsubscribes to the same topic. It does this after posting to that topic. That's not how MQTT is intended to work.

Unsubscribe is for when you "no longer" want to get messages for a topic. Not to temporarily stop messages "for a while". (Who is sending those messages you're not expecting, anyway?) It takes time and potentially causes "churn" like memory fragmentation to repeatedly setup and teardown the subscription.

Consider how a basic chat room would work with MQTT: everyone posts to a topic. You get the messages of others, and your own messages. If you were blocking certain people, those messages would still be sent and received, but the chat program would check to see if the sender is on your block-list and not show them.

You can also use multiple topics within a single application. Each topic is devoted to a role. One or more workers subscribe to a topic for things to do. Each worker subscribes to one or more topics for different things it can do. Each topic's expected payload would be in a format appropriate for that task. Of course, you don't want too many topics/subscriptions.

In this case, you have (at least) two topics.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.