aboutsummaryrefslogtreecommitdiff
path: root/projects/hsm/hsm.c
diff options
context:
space:
mode:
authorPaul Selkirk <paul@psgd.org>2017-04-17 08:45:46 -0400
committerPaul Selkirk <paul@psgd.org>2017-04-17 13:34:08 -0400
commit76a993b74cfccb01ad6397772396cf0dbad808aa (patch)
tree45e48b8ebfb159cd85a2097702c195087045d6aa /projects/hsm/hsm.c
parentbb6d9e870fb51833137e82063a3ab08930820a2d (diff)
parent2b6b9f89cc83ee2412166045e839da61be976564 (diff)
Merge remote-tracking branch 'origin/uart_rx_thread' into ksng
Diffstat (limited to 'projects/hsm/hsm.c')
-rw-r--r--projects/hsm/hsm.c106
1 files changed, 60 insertions, 46 deletions
diff --git a/projects/hsm/hsm.c b/projects/hsm/hsm.c
index 60e35fc..c5af86d 100644
--- a/projects/hsm/hsm.c
+++ b/projects/hsm/hsm.c
@@ -117,59 +117,71 @@ void hal_ks_lock(void) { osMutexWait(ks_mutex, osWaitForever); }
void hal_ks_unlock(void) { osMutexRelease(ks_mutex); }
#endif
-static uint8_t uart_rx[2]; /* current character received from UART */
-
-/* Callback for HAL_UART_Receive_DMA().
- * With multiple worker threads, we can't do a blocking receive, because
- * that prevents other threads from sending RPC responses (because they
- * both want to lock the UART - see stm32f4xx_hal_uart.c). So we have to
- * do a non-blocking receive with a callback routine.
- * Even with only one worker thread, context-switching to the CLI thread
- * causes HAL_UART_Receive to miss input.
+/* A ring buffer for the UART DMA receiver. In theory, it should get at most
+ * 92 characters per 1ms tick, but we're going to up-size it for safety.
*/
-static void RxCallback(uint8_t c)
-{
- /* current RPC input buffer */
- static rpc_buffer_t *ibuf = NULL;
- int complete;
-
- if (ibuf == NULL) {
- if ((ibuf = (rpc_buffer_t *)osMailAlloc(ibuf_queue, 0)) == NULL)
- /* This could happen if all dispatch threads are busy, and
- * there are NUM_RPC_TASK requests already queued. We'd like
- * to to send a "server busy" error, but we've just received
- * the first byte of the request, so we don't yet have enough
- * context to craft a response.
- */
- return;
- ibuf->len = 0;
- }
+#ifndef RPC_UART_RECVBUF_SIZE
+#define RPC_UART_RECVBUF_SIZE 256 /* must be a power of 2 */
+#endif
+#define RPC_UART_RECVBUF_MASK (RPC_UART_RECVBUF_SIZE - 1)
- if (hal_slip_process_char(c, ibuf->buf, &ibuf->len, sizeof(ibuf->buf), &complete) != LIBHAL_OK)
- Error_Handler();
+typedef struct {
+ uint32_t ridx;
+ uint8_t buf[RPC_UART_RECVBUF_SIZE];
+} uart_ringbuf_t;
- if (complete) {
- if (osMailPut(ibuf_queue, (void *)ibuf) != osOK)
- Error_Handler();
- ibuf = NULL;
- }
-}
+volatile uart_ringbuf_t uart_ringbuf = {0, {0}};
-void HAL_UART2_RxHalfCpltCallback(UART_HandleTypeDef *huart)
-{
- RxCallback(uart_rx[0]);
-}
+#define RINGBUF_RIDX(rb) (rb.ridx & RPC_UART_RECVBUF_MASK)
+#define RINGBUF_WIDX(rb) (sizeof(rb.buf) - __HAL_DMA_GET_COUNTER(huart_user.hdmarx))
+#define RINGBUF_COUNT(rb) ((unsigned)(RINGBUF_WIDX(rb) - RINGBUF_RIDX(rb)))
+#define RINGBUF_READ(rb, dst) {dst = rb.buf[RINGBUF_RIDX(rb)]; rb.ridx++;}
-void HAL_UART2_RxCpltCallback(UART_HandleTypeDef *huart)
+/* Thread entry point for the UART DMA monitor.
+ */
+void uart_rx_thread(void const *args)
{
- RxCallback(uart_rx[1]);
-}
+ /* current RPC input buffer */
+ rpc_buffer_t *ibuf = NULL;
-void HAL_UART_ErrorCallback(UART_HandleTypeDef *huart)
-{
- /* I dunno, just trap it for now */
- Error_Handler();
+ /* I wanted to call osThreadYield(), but the documentation is misleading,
+ * and it only yields to the next ready thread of the same priority, so
+ * this high-priority thread wouldn't let anything else run. osDelay(1)
+ * reschedules this thread for the next tick, which is what we want.
+ */
+ for ( ; ; osDelay(1)) {
+ if (ibuf == NULL) {
+ if ((ibuf = (rpc_buffer_t *)osMailAlloc(ibuf_queue, 0)) == NULL)
+ /* This could happen if all dispatch threads are busy, and
+ * there are NUM_RPC_TASK requests already queued. We could
+ * send a "server busy" error, or we could just try again on
+ * the next tick.
+ */
+ continue;
+ ibuf->len = 0;
+ }
+
+ while (RINGBUF_COUNT(uart_ringbuf)) {
+ uint8_t c;
+ int complete;
+
+ RINGBUF_READ(uart_ringbuf, c);
+ if (hal_slip_process_char(c, ibuf->buf, &ibuf->len, sizeof(ibuf->buf), &complete) != LIBHAL_OK)
+ Error_Handler();
+
+ if (complete) {
+ if (osMailPut(ibuf_queue, (void *)ibuf) != osOK)
+ Error_Handler();
+ ibuf = NULL;
+ /* Yield, to allow one of the dispatch threads to pick up this
+ * new request.
+ */
+ break;
+ }
+ }
+ }
}
+osThreadDef(uart_rx_thread, osPriorityHigh, DEFAULT_STACK_SIZE);
hal_error_t hal_serial_send_char(uint8_t c)
{
@@ -297,7 +309,9 @@ int main()
}
/* Start the UART receiver. */
- if (HAL_UART_Receive_DMA(&huart_user, uart_rx, 2) != CMSIS_HAL_OK)
+ if (HAL_UART_Receive_DMA(&huart_user, (uint8_t *) uart_ringbuf.buf, sizeof(uart_ringbuf.buf)) != CMSIS_HAL_OK)
+ Error_Handler();
+ if (osThreadCreate(osThread(uart_rx_thread), NULL) == NULL)
Error_Handler();
/* Launch other threads (csprng warm-up thread?)