I am a bit unsure about this question, but I constantly running into troubles with my current design, and would be really greatful, if someone could show be a different approach to this.
My program writes async commands to a device via rs232, while constantly reading and reacting to received data.
This works all nice and neat, but during my init-phase, I have to send a bunch of commands, which would have to wait for a response, before letting the program countinue.
Now, this part I have to do in plain C, and all I could come up with was to use global vars and while loops. But I find this really not pretty.
Take this as an pseudo-code example:
OnReceive(data){
switch determineCommand(data)
case CMD1:
config.value1 = data.value1
case CMD2:
config.value2 = data.value2
default:
print data
}
DoCommandChain(){
Send(CMD1)
If("Send(CMD1)" got its response){
Send(CMD2)
}
}
Now, the problem is “If XY got its response” – because I don’t want to use some vars to detect this and I can’t rely on a return value for Send(CMD1), because this is just an indicator, that CMD1 was send – not there was something corresponding received.
I am asking here, because I would like to know what I could search for / read about, to solve this mess in a nice way.
Right now, my best idea for this would be to somehow setup a timer-guarded-function to monitor, if a specific response is received. Then, depending on the status of this response, go to the next Send or retry the last.
Like this:
Instead of `Send(CMD1)` -> `DoUntilResponse(Send(CMD1),Timeout,NumberOfRetries)`
DoUntilResponse(function,Timeout,NumberOfRetries){
registerExpectedResponse(CMD1, gotResponse) //awaiting some response for CMD1
for(i=0 ; i!=Numberofretries; i++){
if (Send(CMD1) == successfulSend ){
while(not timeout){
if gotResponse then break;
}
if gotResponse then break;
}
}
}
Edit:
Just to clarify: I am not worried about the serial-connection, or about how to fire the OnReceive function – this is all working already. What I can’t get a clear idea of, is how to solve the above pseudo-code without the use of polling and preferably in pure C.
Assuming that write and read operations are executed in different threads, use the following algorithm:
Write thread. Register expected response. Send packet to the device Wait for Received event with timeout. If event is set, continue. Timeout - report error and exit (or make additional trial). Read thread. For every received packet: Add it to the input buffer. Analyze buffer. If it contains valid response, set "Received" event, releasing the Write thread, clear input buffer, and continue reading. If input buffer contains unrecognized data, report error, clear buffer and continue reading. If input buffer contains the beginning of expected response, continue reading.Threading and event notification is OS-specific. If your C++ compiler doesn’t support multithreading, use portable library like Boost, or use OS-specific API. Notice that Read thread implements stream parsing logic, since serial communication is stream-oriented.
Edit.
“Register expected response” means: set some program variable(s) than mean “Command of type X is sent to device”. According to this variable, Read thread expects to receive the packet, which should be sent by device according to communication protocol (application-specific). Another received packet, which may be generally valid, should be treated as error, because this is not response to the command just sent to device.
Another way: Set expected response size. In this case, once Read thread received expected amount of data, it sets Received event, leaving packet recognition task to the sender.