HAL_ChibiOS: implement uart receive timestamp API

This commit is contained in:
Andrew Tridgell 2018-05-16 10:42:31 +10:00
parent f7a239d833
commit 7005383f82
2 changed files with 61 additions and 4 deletions

View File

@ -348,6 +348,9 @@ void UARTDriver::rxbuff_full_irq(void* self, uint32_t flags)
return;
}
uart_drv->_readbuf.write(uart_drv->rx_bounce_buf, len);
uart_drv->receive_timestamp_update();
//restart the DMA transfers
dmaStreamSetMemory0(uart_drv->rxdma, uart_drv->rx_bounce_buf);
dmaStreamSetTransactionSize(uart_drv->rxdma, RX_BOUNCE_BUFSIZE);
@ -705,8 +708,6 @@ void UARTDriver::write_pending_bytes(void)
*/
void UARTDriver::_timer_tick(void)
{
int ret;
if (!_initialised) return;
if (sdef.dma_rx && rxdma) {
@ -718,6 +719,9 @@ void UARTDriver::_timer_tick(void)
uint8_t len = RX_BOUNCE_BUFSIZE - rxdma->stream->NDTR;
if (len != 0) {
_readbuf.write(rx_bounce_buf, len);
receive_timestamp_update();
if (_wait.thread_ctx && _readbuf.available() >= _wait.n) {
chEvtSignal(_wait.thread_ctx, EVT_DATA);
}
@ -755,14 +759,13 @@ void UARTDriver::_timer_tick(void)
const auto n_vec = _readbuf.reserve(vec, _readbuf.space());
for (int i = 0; i < n_vec; i++) {
int ret = 0;
//Do a non-blocking read
if (sdef.is_usb) {
ret = 0;
#ifdef HAVE_USB_SERIAL
ret = chnReadTimeout((SerialUSBDriver*)sdef.serial, vec[i].data, vec[i].len, TIME_IMMEDIATE);
#endif
} else {
ret = 0;
#if HAL_USE_SERIAL == TRUE
ret = chnReadTimeout((SerialDriver*)sdef.serial, vec[i].data, vec[i].len, TIME_IMMEDIATE);
#endif
@ -772,6 +775,8 @@ void UARTDriver::_timer_tick(void)
}
_readbuf.commit((unsigned)ret);
receive_timestamp_update();
/* stop reading as we read less than we asked for */
if ((unsigned)ret < vec[i].len) {
break;
@ -945,4 +950,35 @@ void UARTDriver::set_stop_bits(int n)
}
// record timestamp of new incoming data
void UARTDriver::receive_timestamp_update(void)
{
_receive_timestamp[_receive_timestamp_idx^1] = AP_HAL::micros64();
_receive_timestamp_idx ^= 1;
}
/*
return timestamp estimate in microseconds for when the start of
a nbytes packet arrived on the uart. This should be treated as a
time constraint, not an exact time. It is guaranteed that the
packet did not start being received after this time, but it
could have been in a system buffer before the returned time.
This takes account of the baudrate of the link. For transports
that have no baudrate (such as USB) the time estimate may be
less accurate.
A return value of zero means the HAL does not support this API
*/
uint64_t UARTDriver::receive_time_constraint_us(uint16_t nbytes) const
{
uint64_t last_receive_us = _receive_timestamp[_receive_timestamp_idx];
if (_baudrate > 0 && !sdef.is_usb) {
// assume 10 bits per byte. For USB we assume zero transport delay
uint32_t transport_time_us = (1000000UL * 10UL / _baudrate) * nbytes;
last_receive_us -= transport_time_us;
}
return last_receive_us;
}
#endif //CONFIG_HAL_BOARD == HAL_BOARD_CHIBIOS

View File

@ -80,6 +80,21 @@ public:
void configure_parity(uint8_t v) override;
void set_stop_bits(int n) override;
/*
return timestamp estimate in microseconds for when the start of
a nbytes packet arrived on the uart. This should be treated as a
time constraint, not an exact time. It is guaranteed that the
packet did not start being received after this time, but it
could have been in a system buffer before the returned time.
This takes account of the baudrate of the link. For transports
that have no baudrate (such as USB) the time estimate may be
less accurate.
A return value of zero means the HAL does not support this API
*/
uint64_t receive_time_constraint_us(uint16_t nbytes) const override;
private:
bool tx_bounce_buf_ready;
@ -131,6 +146,10 @@ private:
Shared_DMA *dma_handle;
static const SerialDef _serial_tab[];
// timestamp for receiving data on the UART, avoiding a lock
uint64_t _receive_timestamp[2];
uint8_t _receive_timestamp_idx;
// handling of flow control
enum flow_control _flow_control = FLOW_CONTROL_DISABLE;
bool _rts_is_active;
@ -153,6 +172,8 @@ private:
void write_pending_bytes_NODMA(uint32_t n);
void write_pending_bytes(void);
void receive_timestamp_update(void);
void thread_init();
static void uart_thread(void *);
};