Variable with dynamic memory

Hello,

My name is TougHD, I am new to programming and I am in dire need of Your programming skills!

So I need to send a 10 bytes(char) long data (which is read from an RFID tag) from one Nano to another and it would be efficient if the reading routine would start only if there is 10 bytes of usefull data. If there is less then 10 bytes then it should ignore.

I have tried to make a char tagValue[10]; and load the data read to it but despite of having a garbage data(not enough bytes, wrong reading) it will fill up the rest memory with '0' 's and the other side still reads 10 bytes of data.

I thought that Dynamic Memory could be a solution for this problem but I am new to programming and if You could help me this in any way(example code or anything that could be useful) I would highly appreciate it.

Thank you in advance! :slight_smile:

I thought that Dynamic Memory could be a solution for this problem

No, it won't.

Post your code.

You CAN do nothing until there are n bytes of serial data to read:

void loop()
{
   if(Serial.available() >= 10)
   {
      // There are at least 10 bytes to read
   }

   // Rest of the code goes here
}

You appear to have forgotten to post your code.

How are the two Nano's connected?

Which nano is parsing the data from the RFID reader?

Being able to see your sketches and your wiring diagram would probably help with providing detailed help.

The 2 devices are using i2c(TwoWire).
The Slave code:

#include <Wire.h>
void requestCallback()
{
  tagValue[10] = '\0';
  Serial.print("tagValueREAD : ");
  Serial.println(tagValue);
  Wire.write(tagValue);
  tagValue[0] = '\0';
}
char tagValue[10];

void rfidRead() {
  byte i = 0;
  byte val = 0;
  byte code[6];
  byte bytesread = 0;
  byte tempbyte = 0;
  byte checksum = 0;

  if (Serial.available() > 0) {
    if ((val = Serial.read()) == 2) {                 // check for header
      bytesread = 0;
      while (bytesread < 12) {                        // read 10 digit code + 2 digit checksum
        if ( Serial.available() > 0) {
          val = Serial.read();

          // Append the first 10 bytes (0 to 9) to the raw tag value
          if (bytesread < 10)
          {
            tagValue[bytesread] = val;
          }

          if ((val == 0x0D) || (val == 0x0A) || (val == 0x03) || (val == 0x02)) { // if header or stop bytes before the 10 digit reading
            break;                                    // stop reading
          }

          // Do Ascii/Hex conversion:
          if ((val >= '0') && (val <= '9')) {
            val = val - '0';
          } else if ((val >= 'A') && (val <= 'F')) {
            val = 10 + val - 'A';
          }

          // Every two hex-digits, add byte to code:
          if (bytesread & 1 == 1) {
            // make some space for this hex-digit by
            // shifting the previous hex-digit with 4 bits to the left:
            code[bytesread >> 1] = (val | (tempbyte << 4));

            if (bytesread >> 1 != 5) {                // If we're at the checksum byte,
              checksum ^= code[bytesread >> 1];       // Calculate the checksum... (XOR)
            };
          } else {
            tempbyte = val;                           // Store the first hex digit first...
          };

          bytesread++;                                // ready to read next digit
        }
      }

      // Output to Serial:

      if (bytesread == 12) {                          // if 12 digit read is complete
        tagValue[10] = '\0';                        // Null-terminate the string
        requestedValue = tagValue;
        Serial.print("strlen requestedValue: ");
        Serial.println(strlen(requestedValue), DEC);
        Serial.print("sizeof requestedValue: ");
        Serial.println(sizeof(requestedValue), DEC);
        Serial.print("requestedValue =  ");
        Serial.println(sizeof(requestedValue), DEC);
        Serial.print("5-byte code: ");
        for (i = 0; i < 5; i++) {
          if (code[i] < 16) Serial.print("0");        
          Serial.print(code[i], HEX);
          Serial.print(" ");
        }
        Serial.println();

        Serial.print("Checksum: ");
        Serial.print(code[5], HEX);

        Serial.println(code[5] == checksum ? " -- passed." : " -- error.");
        Serial.println();
        Serial.println(checksum, HEX);
        if (code[5] == checksum && checksum >= 1 ) {
          Serial.println("Checksum: Barom ");
        }

        // Show the raw tag value
        Serial.print("VALUE: ");
        Serial.println(tagValue);

      }

      bytesread = 0;
    }
  }

}
void setup() {
  Serial.begin(9600);                                 // connect to the serial port
  // Start I²C bus as a slave
  Wire.begin(SlaveDeviceId);
  // Set the callback to call when data is requested.
  Wire.onRequest(requestCallback);
  // Set the callback to call when data is requested.
  Wire.onReceive(receiveCallback);
}
void loop () {
  unsigned long currentMillis = millis();
  rfidRead(); 
}

And the Master reader condition is here:

void setup() {
  Wire.begin();        // join i2c bus (address optional for master)
  Serial.begin(9600);  // start serial for output
}
void loop() {
  unsigned long currentMillis = millis();
  int receivedValue;
  char val;
  byte bytesread = 0;
  char tagValue[10];

  // request 10 bytes from slave device #1

    int available= Wire.requestFrom(SlaveDeviceId, BytesRequested, true );
    Serial.print("available : ");
    Serial.println(available);

    if (available== BytesRequested)  // THIS PART HERE IS ALWAYS TRUE!!!
    {
      while (Wire.available()) {      // slave may send less than requested

        val = Wire.read();              // receive a byte as character
        tagValue[bytesread] = val;
        bytesread++;                                // ready to read next digit
      }
      tagValue[bytesread] = '\0';                  
      Serial.print("tagValueREAD : ");
      Serial.println(tagValue);
    }

}
  Wire.write(tagValue);

That is going to write ONE byte.

  Wire.write(tagValue, 10);

will write all 10 bytes.

You need to post ALL of your code, not just some snippets. We can't see the array sizes or types of variables.

I hope it is more clear now :slight_smile:

Slave sender:

#include <Wire.h>
char tagValue[10];
void requestCallback()
{
  tagValue[10] = '\0';
  Serial.print("tagValueREAD : ");
  Serial.println(tagValue);
  Wire.write(tagValue);
  tagValue[0] = '\0';
}

void rfidRead() {
  byte i = 0;
  byte val = 0;
  byte code[6];
  byte bytesread = 0;
  byte tempbyte = 0;
  byte checksum = 0;

  if (Serial.available() > 0) {
    if ((val = Serial.read()) == 2) {                 // check for header
      bytesread = 0;
      while (bytesread < 12) {                        // read 10 digit code + 2 digit checksum
        if ( Serial.available() > 0) {
          val = Serial.read();

          // Append the first 10 bytes (0 to 9) to the raw tag value
          if (bytesread < 10)
          {
            tagValue[bytesread] = val;
          }

          if ((val == 0x0D) || (val == 0x0A) || (val == 0x03) || (val == 0x02)) { // if header or stop bytes before the 10 digit reading
            break;                                    // stop reading
          }

          // Do Ascii/Hex conversion:
          if ((val >= '0') && (val <= '9')) {
            val = val - '0';
          } else if ((val >= 'A') && (val <= 'F')) {
            val = 10 + val - 'A';
          }

          // Every two hex-digits, add byte to code:
          if (bytesread & 1 == 1) {
            // make some space for this hex-digit by
            // shifting the previous hex-digit with 4 bits to the left:
            code[bytesread >> 1] = (val | (tempbyte << 4));

            if (bytesread >> 1 != 5) {                // If we're at the checksum byte,
              checksum ^= code[bytesread >> 1];       // Calculate the checksum... (XOR)
            };
          } else {
            tempbyte = val;                           // Store the first hex digit first...
          };

          bytesread++;                                // ready to read next digit
        }
      }

      // Output to Serial:

      if (bytesread == 12) {                          // if 12 digit read is complete
        tagValue[10] = '\0';                        // Null-terminate the string
        requestedValue = tagValue;
        Serial.print("strlen requestedValue: ");
        Serial.println(strlen(requestedValue), DEC);
        Serial.print("sizeof requestedValue: ");
        Serial.println(sizeof(requestedValue), DEC);
        Serial.print("requestedValue =  ");
        Serial.println(sizeof(requestedValue), DEC);
        Serial.print("5-byte code: ");
        for (i = 0; i < 5; i++) {
          if (code[i] < 16) Serial.print("0");       
          Serial.print(code[i], HEX);
          Serial.print(" ");
        }
        Serial.println();

        Serial.print("Checksum: ");
        Serial.print(code[5], HEX);

        Serial.println(code[5] == checksum ? " -- passed." : " -- error.");
        Serial.println();
        Serial.println(checksum, HEX);
        if (code[5] == checksum && checksum >= 1 ) {
          Serial.println("Checksum: Barom ");
        }

        // Show the raw tag value
        Serial.print("VALUE: ");
        Serial.println(tagValue);

      }

      bytesread = 0;
    }
  }

}

void setup() {
  Serial.begin(9600);                                 // connect to the serial port
  // Start I²C bus as a slave
  Wire.begin(SlaveDeviceId);
  // Set the callback to call when data is requested.
  Wire.onRequest(requestCallback);
}

void loop () {
  unsigned long currentMillis = millis();
  rfidRead();
}

And the Master reader:

#include <Wire.h>
byte SlaveDeviceId =1;
#define BytesRequested 10

void setup() {
  Wire.begin();        // join i2c bus (address optional for master)
  Serial.begin(9600);  // start serial for output
}

void loop() {
  unsigned long currentMillis = millis();
  int receivedValue;
  char val;
  byte bytesread = 0;
  char tagValue[10];

  // request 10 bytes from slave device #1

    int available= Wire.requestFrom(SlaveDeviceId, BytesRequested, true );
    Serial.print("available : ");
    Serial.println(available);

    if (available== BytesRequested)  // THIS PART HERE IS ALWAYS TRUE!!!
    {
      while (Wire.available()) {      // slave may send less than requested

        val = Wire.read();              // receive a byte as character
        tagValue[bytesread] = val;
        bytesread++;                                // ready to read next digit
      }
      tagValue[bytesread] = '\0';                 
      Serial.print("tagValueREAD : ");
      Serial.println(tagValue);
    }

}
char tagValue[10];
void requestCallback()
{
  tagValue[10] = '\0';

A 10 element array does not have a [10] position to be written to. You've just trashed memory you don't own, so ANYTHING can happen after this.

        val = Wire.read();              // receive a byte as character
        tagValue[bytesread] = val;

Why not

        tagValue[bytesread] = Wire.read();

val is non-val(ue)-added.

Your slave could be in the middle of reading a tag when the master wants data. That arrangement of master and slave seems backwards. The slave knows when to push data. The master has no idea when the slave has data.

Reverse the roles. Make the one with the RFID reader the master. Have the master send the data to the slave when the master has new data to push.

The master is going to have other time sensitive tasks to perform, it is not allowed to be interrupted and the RFID data can be delayed or tried a few times, so this was the role arrangement I saw working.

As for the program I understand now why someone said that C lets you shoot yourself in the foot...I will change it to char tagValue[11];

What do you think how can we make the master to jump into "if (available== BytesRequested)" only if we have a correct 10 byte read at the slave part?
It would be too expensive to go through the whole program unnecessary.

What do you think how can we make the master to jump into "if (available== BytesRequested)" only if we have a correct 10 byte read at the slave part?
It would be too expensive to go through the whole program unnecessary.

You need to have one array that the code that reads from the RFID writes to, and another array that the slave code sends back.

Only copy the data from the RFID array to the slave send array when there are 10 bytes.

PaulS:
You need to have one array that the code that reads from the RFID writes to, and another array that the slave code sends back.

Only copy the data from the RFID array to the slave send array when there are 10 bytes.

I see and share your point of view PaulS, and the thing is no matter how much array I made, even if I'm using a dynamic array, I cant change the fact that Wire.available() always reads 10 bytes.

I am pretty much clueless what could have gone wrong.

Do you have any idea how can we fix this?

Thank you for your time and I highly appreciate any help.

TougHD:
the thing is no matter how much array I made I cant change the fact that Wire.available() always reads 10 bytes.

Even if you request more than 10 bytes? What happens if you change BytesRequested to 15?

    int available= Wire.requestFrom(SlaveDeviceId, BytesRequested, true );

johnwasser:
Even if you request more than 10 bytes? What happens if you change BytesRequested to 15?

    int available= Wire.requestFrom(SlaveDeviceId, BytesRequested, true );

If I change BytesRequested to 15, it will change the Wire.available() to 15, also if I use Wire.requestFrom(SlaveDeviceId, BytesRequested), I still get 15 from Wire.available().

Any clue what is going on here?

Any clue what is going on here?

Regardless of the problem with Wire.available(), you have some code that is supposed to respond to a request for the last tag id.

You have some code that is reading a tag being scanned.

Suppose that you have two tags with strings "1111111111" and "2222222222".

The code to read the tag CAN be interrupted. Suppose that you scan the first tag. The array contains "1111111111". Now, you can the second tag. Part way through reading the tag, the master requests data. You might have read 4 of the 10 bytes when the interrupt happens. So, you (happily, stupidly, blithely, you choose) return "2222111111".

Is that smart? NOT in my book. You need to have two arrays. Initially both will contain "". When you scan a tag, the first array will contain "1", then "11", then "111", etc. If, at any point before you complete reading a tag, you get a request of data, you return the second array, which contains "".

When the COMPLETE tag has been read, disable interrupts (so the master can NOT interfere), copy the first array, containing "1111111111" to the second array, and re-enable interrupts (so the master can ask for data again).

While the second tag is being read, the first array will change to "2111111111", to "2211111111", to "2221111111", etc.

At any time before the second tag has been completely read, if the master asks for the last scanned tag, you will reply with "1111111111".

Thank you PaulS!

You pointed directly, where I wanted to get. It works fine.

The only question remains the one with the Wire.available(). It is necessary to optimize the system so it can do other tasks as well, like reading sensor data and communicating with a PC.

#define MaxSlave 6
#define BytesRequested 10
for (byte SlaveDeviceId = 1; SlaveDeviceId <= MaxSlave; SlaveDeviceId ++) {
Wire.requestFrom(SlaveDeviceId, BytesRequested, true );
Serial.println( Wire.available() );
}

So what do You think, what can cause the reading Wire.available() to always give us the value of BytesRequested?

So what do You think, what can cause the reading Wire.available() to always give us the value of BytesRequested?

Why shouldn't the two values be the same?

It seems to me that you expect each slave to always return the same number of bytes. Is that reasonable?

If not, you need to make two requests to each slave. The first request will be for one byte. That value will be the number of bytes that that particular slave will return. Then, ask that slave for that number of bytes.

The only question remains the one with the Wire.available().

See Nck Gammon's tutorial on i2c on the master requesting data from the slave.Gammon Forum : Electronics : Microprocessors : I2C - Two-Wire Peripheral Interface - for Arduino

Important! You do not need to test for Wire.available here. The Wire.requestFrom function does not return until either the requested data is fully available, or an error occurred. Building in a wait for Wire.available simply makes it possible for the code to hang forever if the data is not available.

See Reply #10 below. Wire.requestFrom() will either return zero, or the number of bytes requested. If there is doubt as to whether all of the requested bytes were received do a data integrity check on the received bytes.