Boron snprintf string issues

Hi All,

I am using snprintf in an attempt to move away from using Strings as much as possible. The trouble is I am still using a string for an rfid variable. Here is my snprintf:

	const char* timeStamp = Time.format(Time.now(), "%Y-%m-%d %H:%M:%S");
	const char* visitStartTime = visitStartTimeString.c_str();
	String rfid = data.substring(0,16);      // taking substring as data has a CR at position 17

	if(tareCheck) {
		rfid = "idle";
	}

	char s[300];
	snprintf(s, sizeof(s)
			, "{\"Em\": \"%s\", \"L1\": \"%.2f\", \"L2\": \"%.2f\", \"L3\": \"%.2f\", \"L4\": \"%.2f\", \"L5\": \"%.2f\", \"rf\": \"%s\", \"t\": \"%s\", \"std\": \"%.2f\", \"visit\": \"%d\", \"visitStartTime\": \"%s\", \"arrayFillTime\": \"%d\" }"
			,Em
			, LC1
			, LC2
			, LC3
			, LC4
			, LC5
			, rfid.c_str()
			, timeStamp
			, stdDev
			, visit
			, visitStartTime
			, arrayFillTime);

The issue I am seeing is the rfid.c_str() is also populating the timestamp variable string. Does anyone have any pointers of where my issue lies?

I am pretty sure the rfid variable is the one that I am having issues with. My code is long and ugly but here are some snippets on how the rfid variable should be assigned a value.

char rfidData[40];
String data = "";

int Read_RFID_Tag(int scanTime){
  digitalWrite(RFIDON, HIGH);
  long setime = millis();
  char offset = 0;
  byte C = 0;
  Serial1.println(F("SRA"));
  while(millis() - setime < scanTime){ // for the first two seconds
		if (C == 13 && offset == 17){  // if the rfid is a certain length and ends in a CR (C==13) then assume data is good.
		  data = rfidData;
		  Serial1.println(F("SRD"));
		  Serial.print(" ");
		  digitalWrite(RFIDON, LOW);
		  return 1;
		}
		rfidData[0] = 0;         // Clear the buffer
		offset = 0;         // Offset into buffer      
		while (Serial1.available()) {
			C = Serial1.read();
			rfidData[offset] = C;
			Serial.print(C);
			delay(1);
			offset++;
		}
	}
	Serial1.println(F("SRD"));
	digitalWrite(RFIDON, LOW);
	data = "unknown";
	return 0;

The rfid includes a carriage return which is why I use substring prior to my snprintf.

ok so I think I have it sorted, a solution always appears after I make a topic.

I now ignore byte C if it represents a CR.

int Read_RFID_Tag(int scanTime){
  digitalWrite(RFIDON, HIGH);
  long setime = millis();
  char offset = 0;
  byte C = 0;
  Serial1.println(F("SRA"));
  while(millis() - setime < scanTime){ // for the first two seconds
		if (C == 13 && offset == 16){
		  Serial1.println(F("SRD"));
		  Serial.print(" ");
		  digitalWrite(RFIDON, LOW);
		  return 1;
		}
		rfidData[0] = 0;         // Clear the buffer
		offset = 0;         // Offset into buffer      
		while (Serial1.available()) {
			C = Serial1.read();
			if(C!=13){
				rfidData[offset] = C;
				offset++;
			}
			Serial.print(C);
			delay(1);	
		}
	}
	Serial1.println(F("SRD"));
	digitalWrite(RFIDON, LOW);
	strcpy(rfidData, "unknown");
	return 0;
}

Then in my function that creates the snprintf I used the following:

char *rfid = rfidData;
	if(tareCheck) {
		rfid = "idle";
	}

This seemed to fix the issue. I would still appreciate some feedback on my approach if anyone thinks I am doing anything stupid here.

I haven’t completely unpacked your code above, so my suggestion may not fit your needs.
However, I’m not entirely sure why you need your String data at all and don’t just stick with char[] entirely.
Also, when you have a string you want to only use part of in snprintf() you can use this

  char data[32] = "Some long string: Here it is!";
  char msg[128]; 
  snprintf(msg, sizeof(msg)
          , "Title  : %.16s\r\n"
            "Content: %s\r\n"
          , data
          , &data[18]
          );
  Serial.println(msg);

The fist string is limited to 16 characters of the long source string.
The second takes the rest of the long string starting with the character at position 18 up to the zero-terminator.

This way you could do away with your intermediate String rfid = data.substring(0,16);

You can even make the length dynamic like this

  char c = 'g';
  snprintf(msg, sizeof(msg)
          , "Cropped after first occurance of '%c': %.*s\r\n"
          , c                                       // which character to find 
          , (long)strchr(data, c) - (long)data + 1  // calculate position after fist occurance of that
          , data
          );

BTW, did you know that there are some extra function you could use to read data from Serial1 that could help simplify your Read_RFID_Tag() function?
Since Serial1 inherits from Stream you can use all these too
image

4 Likes

Lots of good info here, thanks for your help !

2 Likes

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