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.
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.
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.
@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
@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.
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.