Serial Driver Event Handling Example
Posted: Fri Feb 24, 2017 8:57 am
It was surprisingly difficult (for me at least to work out how to properly service serial driver events.
The main source of confusion was that event mask bits are entirely separate from event flags from the LLD.
I'm posting this to get feed back on it and to provide an example that may save others hours of head scratching.
This seems to work, but it was more effort than I'd expected.
Is there an easier way?
(note that this includes logic to suppress framing errors when they are immediately followed by line BREAK)
The main source of confusion was that event mask bits are entirely separate from event flags from the LLD.
I'm posting this to get feed back on it and to provide an example that may save others hours of head scratching.
This seems to work, but it was more effort than I'd expected.
Is there an easier way?
(note that this includes logic to suppress framing errors when they are immediately followed by line BREAK)
Code: Select all
/*
* This thread processes serial cmd port input
*/
static ThreadMain(cmdMain, arg)
{
(void) arg;
enum {
eid = EVENT_MASK(0),
ignore = CHN_OUTPUT_EMPTY | CHN_TRANSMISSION_END,
corruptInput =
SD_OVERRUN_ERROR | SD_FRAMING_ERROR | SD_PARITY_ERROR | SD_NOISE_ERROR
};
bool pendingFramingErr = false;
EventListener cmdListener;
flagsmask_t pending;
chEvtRegisterMaskWithFlags(&cmdSerial.event, &cmdListener, eid, ~ignore);
for(;;) {
chEvtWaitAny(eid);
pending = chEvtGetAndClearFlags(&cmdListener) & ~ignore;
do {
flagsmask_t reason = leastSetBit(pending);
pending &= ~reason;
switch (reason) {
case CHN_INPUT_AVAILABLE:
if (pending & corruptInput) {
if (pendingFramingErr) {
pendingFramingErr=false;
debugPuts("Serial FramingError");
}
goto flush;
}
debugPuts("Serial Input Available");
echoInput(&cmdSerial);
break;
case SD_OVERRUN_ERROR:
debugPuts("Serial Overrun!");
break;
case SD_BREAK_DETECTED:
pendingFramingErr=false;
debugPuts("Serial BREAK!");
flush:
chSysLock();
chIQResetI(&cmdSerial.iqueue);
chSysUnlock();
break;
case SD_FRAMING_ERROR:
//mark "pending" because framing err often preceeds line BREAK
pendingFramingErr = true;
goto flush;
case SD_PARITY_ERROR:
debugPuts("Serial Parity Error!");
goto flush;
case SD_NOISE_ERROR:
debugPuts("Serial Line Noise!");
goto flush;
case CHN_OUTPUT_EMPTY:
debugPuts("Serial Output Empty");
break;
case CHN_TRANSMISSION_END:
debugPuts("Serial Transmission End");
break;
case 0: //sometimes we get woken for no good reason
break;
default: //unhandled event
debugPrint("Unknown Serial Event (flags=0x%x)", reason);
msleep(50);
}
} while (pending);
}
}