This is the mail archive of the
ecos-discuss@sources.redhat.com
mailing list for the eCos project.
Re: hal_diag serial driver: using XON/XOFF flow control?
I now believe the simple answer to my question is: "Implement the
XON/XOFF flow control inside the HAL driver."
Because some people were asking, I'm posting my implementation.
// Theory of XON/XOFF support in the HAL diag driver
// Even if the HAL driver has interrupts enabled, they're only for CTRLC character reception.
// They can not be used to buffer incoming text characters, because /dev/haldiag isn't made
// to do that.
// So if you activate interrupts for the hal diag driver, it means that you will lose incoming
// text characters. If you do want them, don't activate interrupts, but poll instead. (maybe
// a CTRLC check is needed in the polling routine? Didn't check that.)
// This also means that we can receive XON/XOFF characters here and let the HAL driver itself do
// flow control for transferred data (instead of inside the serial device driver).
#define HAL_IO_SERIAL_FLOW_CONTROL_XON_CHAR 17
#define HAL_IO_SERIAL_FLOW_CONTROL_XOFF_CHAR 19
typedef struct {
cyg_int32 msec_timeout;
int isr_vector_rx;
volatile bool throttle_tx;
} channel_data_t;
static int cyg_hal_plf_serial_control(void *__ch_data, __comm_control_cmd_t __func, ...);
static cyg_bool cyg_hal_plf_serial_getc_nonblock(void* __ch_data, cyg_uint8* ch);
void
cyg_hal_plf_serial_putc(void *__ch_data, char c)
{
channel_data_t* chan = (channel_data_t*)__ch_data;
CYGARC_HAL_SAVE_GP();
if(chan->throttle_tx==true)
{
// Wait for XON. To be safe against race conditions, turn off interrupts
// and poll RX from here.
char chdum;
cyg_hal_plf_serial_control(__ch_data, __COMMCTL_IRQ_DISABLE);
while(chan->throttle_tx==true)
cyg_hal_plf_serial_getc_nonblock(__ch_data, &chdum);
cyg_hal_plf_serial_control(__ch_data, __COMMCTL_IRQ_ENABLE);
};
// Write to UART
while(!(uartRegisterRead(LSR)&LSRTHR));
uartRegisterWrite(THR, (cyg_uint32)c);
CYGARC_HAL_RESTORE_GP();
}
static cyg_bool
cyg_hal_plf_serial_getc_nonblock(void* __ch_data, cyg_uint8* ch)
{
channel_data_t* chan = (channel_data_t*)__ch_data;
bool success=false;
if(uartRegisterRead(LSR)&LSRDR)
{
*ch=((unsigned char)uartRegisterRead(RBR)&0xff);
if (*ch==HAL_IO_SERIAL_FLOW_CONTROL_XON_CHAR)
chan->throttle_tx=false;
else if (*ch==HAL_IO_SERIAL_FLOW_CONTROL_XOFF_CHAR)
chan->throttle_tx=true;
success=true;
};
return success;
}
--
Before posting, please read the FAQ: http://ecos.sourceware.org/fom/ecos
and search the list archive: http://ecos.sourceware.org/ml/ecos-discuss