Please clarify Serial.read()

I'm trying to send a text-file from Terminal.exe to the Arduino, one line at a time. This is because I decode the line into X- and Y-moves and want those to finish before tackling the next line of commands.

When I receive a CR (carriage-return) I send an XOFF then process the line, act on it, and send an XON. Which appears to work for small files, < 180 bytes or so.

Does the Serial.read buffer clear out 'old stuff' as it is read? I thought I understood that the buffer is 126 bytes (or thereabouts) and none of my lines of text are anywhere near that long - all are less than 20 characters.

I send an XON, expecting this to start sending the next chunk from the text file, so Serial.available() becomes true. Then read each character into a string, expecting that character to be removed from the buffer, and the next character, and the next, until I get a CR then send XOFF. So Serial.available should become false? And the data in the buffer should all transfer to my string, whilst emptying the buffer?

void loop() 
{
	myString = "  ";
	if(byteCounter > 124)
		{
			Serial.println("Buffer Full");
			Serial.write(XOFF);
			byteCounter =0;
			Serial.flush();
			delay(2500);
			Serial.write(XON);
		}

	if (Serial.available() > 0 && carryOn == true && goSub ==false) 
		{
			int strLength =0;
			incomingByte = Serial.read();
			// try to build One Line of 'commands' e.g. G1 or M99
			while( incomingByte != CR && incomingByte != LF && incomingByte != EOF)
				{
					if (Serial.available() > 0)
						{
							incomingByte = Serial.read();
							myString += char(incomingByte);
							byteCounter ++;
							strLength = myString.length();
						}
				}

			if ( (incomingByte == CR || incomingByte ==LF || incomingByte == EOF) && (strLength !=0))
				{
				 	Serial.write(XOFF);
					decodeSuccess = decodeCommandString(myString);
					// Special for Arcs
					if(decodeSuccess == true  && doingRadius == true)	// we've decoded one line, now action it
						{
							carryOn = false;
							if(quarter == 1 || quarter ==3)
								carryOn = DriveRadiusQ1_3( Radius, quarter);
							else if(quarter == 2 || quarter ==4)
								carryOn = DriveRadiusQ2_4( Radius, quarter);
							done();
						}
					// Normal X, Y moves
					else if(decodeSuccess == true )	// we've decoded one line, now action it
						{
							carryOn = false;
							carryOn = interpolateDriveMotors((NewXpos - OldXpos), (NewYpos - OldYpos));
							done();
						}
					else
						{
							Serial.println("DecodeSuccess is FALSE");
							carryOn = false;
						}
					decodeSuccess = false;
				}
		}
}					
// end the loop for now

//-----------------------------------------------------------------------
void done()
{
		delay(1000);
		myString = " ";
		if(carryOn == true)
			{
				Serial.write(XON);
			}
		byteCounter =0;
}

but I cannot persuade it to read to the end of any file longer than about 180 bytes. What baffles me is that this suggests it is 'storing' (buffering?) more than one-line of commands. This file works fine, right to the end:

(W)
 G90
 G21
 G92 X0 Y0
 G51 S0.67
 G1 X2
 G1 Y-10
 G4
 F45
 G1 X0 Y0
    X-3 Y-10
    X-5 Y0
    X-8 Y-10
 G4
 G1 X0
 G1 Y0
 G92 X0 Y0
 M30

No one line of which is longer than 12 bytes + CR. (The total file length is 165 bytes)
but this one does not:

(letter W)
 G90
 G21
 G92 X0 Y0
 G51 S0.67
 G1 X2
 G1 Y-10
 G4
 G4
 G4
 F45
 G1 X0 Y0
    X-3 Y-10
    X-5 Y0
    X-8 Y-10
 G4
 G4
 G1 X0
 G1 Y0
 G92 X0 Y0
 M30

This is the same code but 'padded' with a few extra characters, total length of 185 bytes.

Reading the "Serial.read() - Arduino Reference" offers no help - I've been there.

Someone on this forum stated that he can send/receive files of many thousands of bytes, so I'm baffled that I can't seem to get past this small (180 bytes) limit.

Does the buffer 'fill' from both directions? I.e. Serial.read()obviously fills it, but does Serial.write (or Serial.print) also use the same buffer?

Geoff

Serial.read has absolutely nothing to do with Serial.write.
Serial.write (before 1.0) blocks and does not buffer.
If you read a character, it is removed from the buffer.
However, remember that sending XOFF takes the same amount of time to transmit as it takes the remote end to send the next character that it was going to send anyway.

I think I'd be more concerned about your use of the String class, and probable memory fragmentation.

Thanks AWOL,
You've lost me here:

I think I'd be more concerned about your use of the String class, and probable memory fragmentation.

I thought that re-setting by myString = " "; at the start of each time round the loop() should clear it, and I don't think it is used elsewhere.

And it still doesn't help me figure why I appear to be limited to only sending very small files?

Geoff

I thought that re-setting by myString = " "; at the start of each time round the loop() should clear it,

I don't know about "reset" - it looks to me like you're putting a space into it.

			Serial.flush();

This dumps all data in the incoming buffer. It does not force the send of all data in the output buffer (there is no output buffer). Get rid of it.

I thought that re-setting by myString = " "; at the start of each time round the loop() should clear it, and I don't think it is used elsewhere.

Look at the code for the string class. Specifically, the += operator as you use it here:

	myString += char(incomingByte);

What happens here is that the current length of myString is determined, the length of the String to add is determined (it's only 1), and memory is allocated. The old data in myString is copied to the new memory location. The data in the new String is copied to the new memory location, after the old data. Then, the old memory location is freed.

Suppose that myString was 10 bytes long. You want to add a character to it, so 11 bytes are allocated, the data is copied, and the 10 bytes freed.

Now you want to add another character. The 10 bytes freed from the last step are not big enough to hold the 11+1 characters, so a different location is located, and the current 11 bytes freed.

Now you have a 10 byte block and an 11 byte block of memory available. They may or may not be contiguous.

When you want to add another character, you need space for 13. Suppose that the 10 and 11 are contiguous. 13 of those 21 bytes are allocated, leaving 8. Then 12 are freed. They may, or may not be contiguous with the 8 from the 10+11.

After a while, you have all this space available, but in little tiny, non-contiguous block.

If you know that a record will never exceed 80 characters, a static allocation of 80 characters means that only 80 characters will ever be used to receive the data. Not 1 + 2 + 3 + 4 + 5 + 6 + ... + 80.