We do this to, what you should do is use itty (interrupt based serial).
What I do is run an ESP 'expect send pairs' type arrangment. This way you can have a dedicated RX_TASK which pass's messages back via a message queue. I have developed a full set of routines which we can quickly put into anything that requires two way comm's which works well.
The core of what you are asking happens here:
inside ESP_Function()...
//Get start time so we know where we are _time_get(&StartTime); //DEBUG, Display time. printf("Start Seconds %u MilliSeconds %u \n", StartTime.SECONDS, StartTime.MILLISECONDS); //Run this until we get a message from the TX routines while(_msgq_peek(ps_User_Comm_ESP->QID_of_TX_Task) == NULL) { _time_get(&CurrentTime); _time_diff(&StartTime, &CurrentTime, &TimeDifference); if((TimeDifference.SECONDS >= ps_User_Comm_ESP->tCommandTimeOut.SECONDS) && (TimeDifference.MILLISECONDS >= ps_User_Comm_ESP->tCommandTimeOut.MILLISECONDS)) { //DEBUG printf("Timer Experied in ESP while waiting for message from TX queue\n"); return ESPR_Timeout; } } //DEBUG, Display time it took to get message. printf("Time Taken = %u.%u Seconds \n", TimeDifference.SECONDS, TimeDifference.MILLISECONDS); //Get the message that we recieved (from above peek) msg_ptr = _msgq_receive(ps_User_Comm_ESP->QID_of_TX_Task, 0);
Obviously this is only the part of the code which allows you to create your little timeout / error / ok messages.
Hope this gives you some ideas to move forward