Serial.print and Serial.write problem

(please be gentle this is my first time posting here)

Hi Guys I am not sure if I am doing something stupid or not.

I am reading an array of characters from memory here is the data in hex.

0x48 0x45 0x4C 0x4C 0x4F 0x5F 0x57 0x4F 0x52 0x4C 0x44 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0

I read the data out and store in in an array with the following function

void readFromEeprom(int start, int stop, char *array) {
 	for (int i = start; i < stop; i++)
	 		array[i] = (char)EEPROM.read(i);
}

If I step through and print each element to serial I get the correct output (“HELLO_WORLD”)

if I do the following

Serial.write(arrayData);

or

Serial.print(arrayData);

I get blank output.

Show your whole code. please. If we have the full code, we can copy to our IDE and run the code to test solutions. Serial.write is for one character (byte). For print (println) the array needs a null terminator ('\0') to tell print where the array ends.

Hi yes thank you there is a null terminator at the end 0x00 = ‘\0’ (please look at the hex that I posted)

#define EEPROM_SITE_NAME_START 8
#define EEPROM_SITE_NAME_STOP 48
#define EEPROM_SITE_NAME_SIZE 40

//Some other code
void readFromEeprom(int start, int stop, char *array) {
 	for (int i = start; i < stop; i++)
	 		array[i] = (char)EEPROM.read(i);
}
//Some other code
void FsiteName () {
	if (!INPUT_BUFFER_HAS_ARGS) {
		Serial.println(message.updatingLive);
		readFromEeprom(EEPROM_SITE_NAME_START,EEPROM_SITE_NAME_STOP,siteInfo.name);
		Serial.println(message.done);
	 	Serial.print("\n\rSite name :");
	 	Serial.println(siteInfo.name);
		return;
	}

	memset(siteInfo.name,'\0',EEPROM_SITE_NAME_SIZE);
	int tst = getStringFromStack(EEPROM_SITE_NAME_SIZE,siteInfo.name);

	Serial.println();
	if (0 <= tst) {
		Serial.print("\n\rWriting new site name: ");
		Serial.print(siteInfo.name);
		writeToEeprom(EEPROM_SITE_NAME_START,EEPROM_SITE_NAME_STOP,siteInfo.name);
		Serial.println(message.done);
	}
	else if (GET_PAR_RETVAL_SPACE == tst)
		Serial.println(message.toManyArgs);
	else if ( GET_PAR_RETVAL_MAX == tst)
		Serial.println(message.argTooLong);
}

//some other code

this is what I use to verify the contents of the ROM

void FromRead() {
	int i;

	char temp;
	Serial.println("\r\nReading from rom");
	for (i = 0; i <1024;i++) {
		if (!(i % 16)) {
			Serial.println();
			Serial.print(i);
			Serial.print(" ->");
		}
		temp = EEPROM.read(i);
		Serial.print(" 0x");
		Serial.print ((uint8_t)temp,HEX);
	}
}

That's not your whole code... And if you think the whole code is to complex, make a smaller sketch with just the problem/error that at least compiles (or compiles with the same error).

Because for a start we now have no idea where and how "siteInfo" is defined and declared...

PS In C++ const are preferred over macro's :wink:

Hi Septillion
I will start a new sketch ....... why is a CONST preferred over a macro in C++?

Code Craft: When #define Is Considered Harmful | Hackaday :slight_smile:

Hi yes thank you there is a null terminator at the end 0x00 = '\0' (please look at the hex that I posted)

I did look at the hex. Without knowing the values of start and stop I can't know how many bytes that you are getting from the EEPROM and therefore if the null was read.

Maybe this will help http://snippets-r-us.com/

Here is all the applicable code id does run.
I still need to implement circular buffers, interrupts and proper error checking.

#include <avr/wdt.h>
#include <EEPROM.h>

//===========================================================//
//Key code defines
//===========================================================//
#define CR 0xD
#define SPACE 0x20
#define BREAK 0x3
#define BACKSPACE 0x7F

#define GET_PAR_RETVAL_SPACE -200
#define GET_PAR_RETVAL_MAX -201

//===========================================================//
//error code defines
//===========================================================//
#define ERROR_BUFFER_OVERFLOW -100
#define ERROR_BUFFER_UNDERFLOW -101

#define ERROR_ARGUMENTS_T0_MANY -110
#define ERROR_ARGUMENTS_TO_FEW -111

//===========================================================//
//EEPROM locations
//===========================================================//
#define EEPROM_SITE_NAME_START 8
#define EEPROM_SITE_NAME_STOP 48
#define EEPROM_SITE_NAME_SIZE 40
//===========================================================//
//buffer stuffs
//===========================================================//
#define BUFFER_INPUT_SIZE 30
#define INPUT_BUFFER_HAS_ARGS (SPACE == inputBuffer.data[inputBuffer.ARGlocation])

struct structInputBuffer {
	int token = 0;
	char data[BUFFER_INPUT_SIZE];
	int ARGlocation = 0;

}inputBuffer;

struct structSiteInfo {
	char name[EEPROM_SITE_NAME_SIZE];
} siteInfo;

struct structMessage {
	char *toManyArgs = {"To many arguments."};
	char *argTooLong = {"Argument too long."};
	char *done 			= {" done."};
	char *updatingLive = {"\r\nUpdating live info from rom"};
} message;

void readFromEeprom(int start, int stop, char *array) {
 	for (int i = start; i < stop; i++)
	 		array[i] = (char)EEPROM.read(i);
}

void writeToEeprom(int start, int stop, char *array) {
	int j = 0;
	for (int i = start; i < stop; i++) {
		EEPROM.write(i,array[j]);
		j++;
	}
}

int getStringFromStack(int max, char *array) {

	inputBuffer.ARGlocation++;
	int i = 0;
	char test;
	while (1) {
		test = inputBuffer.data[i+inputBuffer.ARGlocation];
		if ('\0' == test) {
			inputBuffer.ARGlocation += i;
			return i;
		}
		if (SPACE == test)
			return GET_PAR_RETVAL_SPACE;
		array[i] = test;
		i++;
		if (max <= i)
			return GET_PAR_RETVAL_MAX;
	}
}

void Freset() {
	Serial.print("\n\rResetting using the WDT. ");
	wdt_enable(WDTO_15MS);
  	while(1) {
  	}
}

void FsiteName () {
	if (!INPUT_BUFFER_HAS_ARGS) {
		Serial.println(message.updatingLive);
		readFromEeprom(EEPROM_SITE_NAME_START,EEPROM_SITE_NAME_STOP,siteInfo.name);
		Serial.println(message.done);
	 	Serial.print("\n\rSite name :");
	 	Serial.println(siteInfo.name);
		return;
	}

	memset(siteInfo.name,'\0',EEPROM_SITE_NAME_SIZE);
	int tst = getStringFromStack(EEPROM_SITE_NAME_SIZE,siteInfo.name);

	Serial.println();
	if (0 <= tst) {
		Serial.print("\n\rWriting new site name: ");
		Serial.print(siteInfo.name);
		writeToEeprom(EEPROM_SITE_NAME_START,EEPROM_SITE_NAME_STOP,siteInfo.name);
		Serial.println(message.done);
	}
	else if (GET_PAR_RETVAL_SPACE == tst)
		Serial.println(message.toManyArgs);
	else if ( GET_PAR_RETVAL_MAX == tst)
		Serial.println(message.argTooLong);
}

void FromRead() {
	int i;

	char temp;
	Serial.println("\r\nReading from rom");
	for (i = 0; i <1024;i++) {
		if (!(i % 16)) {
			Serial.println();
			Serial.print(i);
			Serial.print(" ->");
		}
		temp = EEPROM.read(i);
		Serial.print(" 0x");
		Serial.print ((uint8_t)temp,HEX);
	}
}

void (*jumpTableCli[])() = {Freset,FsiteName, FromRead};

char *commandTABLE[] = {
	"reset\0",
	"siteName\0",
	"romRead\0",
	"\e"
};

void setup() {
	Serial.begin(9600);
	bufferInputReset();
}

void loop() {
	if (Serial) {
		if (Serial.available()) {
			byte myInput=Serial.read();
			switch (myInput) {
			    case CR:
			    	if (0 < inputBuffer.token) {
						int i = 0;
						while ((commandTABLE[i][0])!='\e') {
							int j =0;
							while (1) {
								if (((inputBuffer.data[j]=='\0')||(inputBuffer.data[j]==SPACE))&&((commandTABLE[i][j])=='\0')) {
									inputBuffer.ARGlocation = j;
									jumpTableCli[(i)]();
									goto HAPPY;
								}
								if (inputBuffer.data[j]!=commandTABLE[i][j]) break;
								j++;
							}
							i++;
						}
					}
			    case BREAK:
			    	HAPPY:
			    	bufferInputReset();
			    	Serial.print("\n\r>");
			    	break;
			    case BACKSPACE:
			    	bufferInputPoP();
			    	Serial.print('\b');
			    	break;
			    default:
					Serial.print((char)myInput);
					bufferInputPush((char)myInput);
			    	break;
			  }
		}
	}
	delay(20);
}

void bufferInputReset() {
	inputBuffer.token=0;
	for (int i = 0;i <BUFFER_INPUT_SIZE; i++) {
		inputBuffer.data[i]='\0';
	}
}

byte bufferInputPush(char myChar) {
	inputBuffer.data[inputBuffer.token] = myChar;
	if ( BUFFER_INPUT_SIZE < ++inputBuffer.token) return ERROR_BUFFER_OVERFLOW;
	inputBuffer.data[inputBuffer.token] = '\0';
	return 0;
};

byte bufferInputPoP() {
	if (0  == inputBuffer.token) return ERROR_BUFFER_UNDERFLOW;
	inputBuffer.token--;
	inputBuffer.data[inputBuffer.token] = '\0';
	return 0;
}

Septillion ... I had a look at the link that you posted and I still don't see why it is better to use a const versus the MACRO

Because macros can get you in all sorts of weird and wonderful trouble. C++ has all kind of tools (like const) which offer a more save (and thus cleaner) way of doing it.

It’s like using a hammer for everything. While it might get the job done, if it’s a bolt it’s cleaner to just use a wrench :wink:

And I don’t see the error right away. But it would be a lot saver to read just EEPROM_SITE_NAME_SIZE -1 bytes from eeprom and add a ‘\0’ yourself so you know for sure it’s terminated.

And a little tip, you can save a heck of a lot of ram by putting your strings into flash :slight_smile:

You're happily reading the eeprom from 8 to 48 and storing that in elements (with the same index) of an array.

So array[8] is the first one that you readwrite and array[47] the last one

Now there is one minor problem and that is that your array does not have elements with an index above 39.

Ahhh, yes. And there is the problem. Now the first char in the array is a ‘\0’ so the printing stops

Try

void readFromEeprom(byte start, byte stop, char *array) {
 	for (byte /*no reason for a signed type here*/ i = 0; i < (stop - start); i++)
			array[i] = (char)EEPROM.read(start + i);
}

sorted thanx guys ... that was a pretty stupid one

septillion ... I will definitely move the strings to flash tnx, but i am still not convinced about the define const thing sorry

septillion:
Because macros can get you in all sorts of weird and wonderful trouble.

Examples of dangers for the way OP uses #define would be helpful. This is what the article says for the basic macro usage

This type of macro usage doesn’t pose much of a threat that problems will arise.

Now the only thing that worries me is the "doesn't pose much of a threat". So it poses a threat but the author can not tell us when.

aargh:
hmmm this is interesting if i change the space where the data is stored to 0 in the eeprom it outputs the values fine.

Of course it will because now you also store the value that you read in locations in the array starting at 0 and you're not exceeding the end boundary by trying to store something in element 48..

For a constant (with a real constant in it) it's not that dangerous.

But a thing I saw last month was along the lines of

#define ONE 3
#define TWO 7
#define SUM ONE+TWO

Now in a lot of cases that works great.

Serial.print(SUM);

will return 10 as expected.

So you go on and program ahead but now you want to do

Serial.print(15 - LENGTH);

And you expect it to print 5. But it will not...

And of course, if you know all about macros you can fix that. It's nicely done with INPUT_BUFFER_HAS_ARGS. But I would call that dangerous! Because from looking at Serial.print(15 - LENGTH); you should not expect that. And if you use const it would not have happened!

The fixing of the macro is a bit like putting a rag around the hammer to not cause that much damage while removing that bolt. But it's still way more elegant (and less prone to damage) to use a wrench :smiley:

Another small example.You have a macro of a negative constant. Now you want to subtract that from 5 but you miss the - sign.

#define NEG_VALUE -3
Serial.print(5  NEG_VALUE);

Instead of giving you a compiler error because you missed the operator it will compile fine. Which might leave you with a hard to find bug...

And you can try to wrap the macro in brackets as well. Now it will give you an error but the first error and error location is by far not where the problem is...

So yeah, dangerous might be a big word and yes a macro can work (that's how it's done in C etc) but C++ offers you more saver options. Why not use them?

Thanks, that last example makes it a little clearer to me.

The fixing of the macro is a bit like putting a rag around the hammer to not cause that much damage while removing that bolt.

I usually do that :smiley: :smiley: