Suggestions for Serial Buffer

I am really just looking at suggestions for saving data from a serial connection. The messages I am receiving are bigger than 63 bytes, and I have read about a serialEvent() as well as interrupts. I think these both might be able to help me store more data, but just want to know if anyone has any suggestions. The only way I can think of it know is to have to seperate buffers.

Right now I am just doing:

i = 0;
while(Serial.available() > 0)
     array[i++] = Serial.read();

I will say the only requirement is that bytes stay in order due to the fact that a CRC is involved.

I may be getting up to 200-300 bytes in a message. I will at least be getting 64 which is one above the 63 buffer.

I may be getting up to 200-300 bytes in a message.

So, you need a snippet of code that defines an array that can hold at least 300 characters.

I will at least be getting 64 which is one above the 63 buffer.

What 63 buffer are you concerned about? Get back to reading data before that buffer fills up, and its size won't matter.

You probably do NOT want to reset i to 0 before each while loop. You want to reset i to 0 only after the complete packet has arrived (and NO it will not arrive all at once or even in 64 byte chunks). You need to read and store the message until the end of the message, by whatever means you need to use to detect that the end of the message has arrived.

You can also change the size of the Arduino serial buffer by editing the file "HardwareSerial.cpp" and replacing
#define SERIAL_BUFFER_SIZE 64

by the number you want... This would avoid creating a second buffer for the same data.

Do you need to have the complete message in a buffer before you can use it or can you parse it in pieces as the data arrives?

I just need the entire message in one array, but it is all coming as one message from another machine. I send one command, and it responds with a long message.

but it is all coming as one message from another machine.

Do you have any control over the format of the response? If so, make sure that the message ends with some recognizable end-of-packet marker.

If not, you may be lucky in that it already ends with some recognizable marker, even if you don't (yet) recognize it.

array[BUFFER_SIZE] = {};

Where is array declared? Why are you setting the element just beyond the end of the array to something? (Or nothing, actually).

delay(500); //waiting for a response from machine

Wait for buffer to overflow, you mean.

napkinsterror:
but I can't not have a delay or else the reads get messed up when sending multiple messages.

It sounds like you might want to use time as the deliminator. Instead of delaying for an arbitrary amount of time, keep track of the time that you last received a character:

static unsigned long lastReceivedTime = 0;
static boolean receivingMsg = false;
if (Serial.available() > 0)
{
  char inByte = Serial.read();
  lastReceivedTime = millis();
  receivingMsg = true;
  // store the data in the buffer
}

Then, outside of any other conditions, and run as often as possible (no delay() calls), check how long it has been since you last received a character:

if (millis() - lastReceivedTime > someSetTimeoutPeriod)
{
  receivingMsg = false;
  // process the array and clear the buffer
}

You'll have to structure your loop() function to work more towards parallelism than sequentialism ( I don't care if that's not a word, firefox). To accomplish that, you can't think of what you want to do as a sequence of events, rather, as a collection of events that run independently and are flagged or signaled by each other.

Is this the literal string you get from the remote machine, colons and all?

0:38:FF:FF...

@PaulS My understanding is that in C, initializing an array assigned to {}, will assign all the elements to 0, which seems to be correct. This is done at the beginning of the loop(). That line of code was copied incorrectly, it should have been:

char array[BUFFER_SIZE] = {};

Well would this work better than a delay(), because I don't want it to hang just because it doesn't get a response, because sometimes the machine doesn't respond.

i = 0;
while(!Serial.available() && i++ < 500) {}

i = 0;
while(Serial.available() > 0)
    array[i++] = Serial.read();

EDIT: This method ^^ does not work, the message ends up overlapping, with and without the i++ < 500

@Arrch Okay I will look into that, I have never done that before

@wildbill No, its a for loop running through the entire array printing out in hex so with colons in between so I can read it, because most of the data is 1 to 4 bytes

napkinsterror:
I couldn't get it working even with the delimiter approach.

The code you posted shows no attempt at doing so.

@Arrch I just realized I posted the working code. You want me to put the delimiter code? I am moving stuff all around trying to see if it will work and comparing it to the working code, but if you need to see that I can post another 2 or 3 posts of code.

What I guess I realize I don't understand is directly after sending a message how can I, with or without the delimiter method, wait until receiving a message, so I don't need a delay and can use a Serial.read() and then not have anything left until later in the code when I send a new message.

napkinsterror:
@Arrch I just realized I posted the working code. You want me to put the delimiter code? I am moving stuff all around trying to see if it will work and comparing it to the working code, but if you need to see that I can post another 2 or 3 posts of code.

Using additional options, you can attach the code. You may be better off creating a new sketch and just start with the basics until you get it working, then add the rest of the unrelated code in.

What I guess I realize I don't understand is directly after sending a message how can I, with or without the delimiter method, wait until receiving a message, so I don't need a delay and can use a Serial.read() and then not have anything left until later in the code when I send a new message.

Then you need a state machine:

enum { IDLE, SEND, RECV, PROCESS } state = IDLE;
...
void loop()
{
  switch (state)
  {
    case IDLE:
      // do something and upon some condition, set state to SEND
      break;
    case SEND:
      // send the message
      state = RECV;
      break;
    case RECV:
      // code to read and store serial data
      // when you've gone long enough without receiving data, set state to PROCESS
      break;
    case PROCESS:
      // do something with the data received
      state = IDLE;
      break;
    default:
      break;
  }
}

I don't know what your message format is but presumably you do. How can you tell when you have received a complete message? It would be pretty bizarre to go to the trouble of CRC checking a message if you didn't already have an encoding scheme that let you know where the message started and ended.

napkinsterror:
but how do I wait after the SEND and before the RECV.

You don't. You sit in the RECV state until you're done receiving the message (which was determined by it being X amount of time since you last received a character). Keep in mind, that no delays are required for this approach, so you can still perform tasks as needed outside of the switch statement, which will be run regardless of the state. This is the nature of a state machine, something you should read up on.

};};};

What is this crap? ONE } per line is the limit. NEVER more than one.

Just read this:

This will not work at all well:

void loop() {
array[BUFFER_SIZE] = {};
byte i = 0;

//send message here

delay(500); //waiting for a response from machine
while(Serial.available() > 0)
     array[i++] = Serial.read();

If the delay is too small the you won't get all of the incoming data. If it is too large the 64-byte internal buffer will overflow. Just right? I doubt it. Forget this sort of loop and read the link above.

I've never encountered a communication protocol with CRC that didn't have a well-defined message length. That length is either a constant, or it's embedded in the early bytes of the message. I'm kind of suspicious of that "38" early in the response - as hex, it translates to 56, and it might be telling you the number of bytes between some header information and some end-of-message housekeeping, like the CRC.

What can you tell us about the communication protocol? What is the device? Be specific, please - one of us may have talked to it before.

If you can decipher the message length, it's fairly easy to just fetch bytes until you either get them all, or they stop coming and some software timer runs out

napkinsterror:
So I have to receive at least the first two bytes (so I know the second byte, length) to know how long the data of the message is, everything else is constant byte wise.

You've described it as a struct, but obviously that isn't a real struct definition - you'll need some other way to buffer the message.

The way I'd handle that is to use a finite state machine to receive and parse the incoming messages.

In the first state you are waiting for the start flag: read each character as it arrives; if it is the start byte then move to the next state.
In the second state you are waiting for the length field. When the next byte is available, read it and check whether it is a credible length value. If so, move on to the next state. If not, go back to the initial state.
In the third state you are receiving the variable length message body. When you enter this state you know the number of bytes remaining to be read. Each time a byte is available, append it to the receive buffer and decrement the remaining count. When the count reaches zero perform the CRC check on the buffer content and either process or discard the buffer. Then go back to the initial state.

The most natural way to implement that would be using an enumerated value to hold the current state, and a switch/case statement to execute the code associated with the current state.

if(Serial.available())
		{
			receiveMsg(&incoming);

...

void receiveMsg(MESSAGE_STRUCT* message)
{
	message->start_byte = Serial.read();
	message->length = Serial.read();
	message->address_1 = Serial.read();
	message->address_2 = Serial.read();

No. You know you have one byte and you read four. It won't work.

Read this, it describes a serial state machine: