Skip to content

Commit 43b35cb

Browse files
authored
Add UART passthrough (#146)
1 parent ebd168f commit 43b35cb

File tree

4 files changed

+762
-0
lines changed

4 files changed

+762
-0
lines changed

src/system/bus/uart.c

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,10 +41,12 @@ struct UART_Handle {
4141
UART_Bus bus_id;
4242
CircularBuffer *rx_buffer;
4343
CircularBuffer *tx_buffer;
44+
CircularBuffer *original_tx_buffer; /* Stored during passthrough */
4445
uint32_t volatile rx_dma_head;
4546
UART_RxCallback rx_callback;
4647
uint32_t rx_threshold;
4748
bool initialized;
49+
UART_Handle *passthrough_target;
4850
};
4951

5052
/* Global array to keep track of active UART handles */
@@ -260,10 +262,12 @@ UART_Handle *UART_init(
260262
handle->bus_id = bus_id;
261263
handle->rx_buffer = rx_buffer;
262264
handle->tx_buffer = tx_buffer;
265+
handle->original_tx_buffer = nullptr;
263266
handle->rx_dma_head = 0;
264267
handle->rx_callback = nullptr;
265268
handle->rx_threshold = 0;
266269
handle->initialized = false;
270+
handle->passthrough_target = nullptr;
267271

268272
/* Initialize hardware layer */
269273
UART_LL_init(bus_id, rx_buffer->buffer, rx_buffer->size);
@@ -289,6 +293,11 @@ void UART_deinit(UART_Handle *handle)
289293
return;
290294
}
291295

296+
/* Cannot deinit while passthrough is active */
297+
if (handle->passthrough_target) {
298+
THROW(ERROR_RESOURCE_BUSY);
299+
}
300+
292301
/* Deinitialize hardware layer */
293302
UART_LL_deinit(handle->bus_id);
294303

@@ -470,3 +479,80 @@ void UART_set_rx_callback(
470479
handle->rx_callback(handle, rx_buffer_available(handle));
471480
}
472481
}
482+
483+
/**
484+
* @brief Passthrough callback function.
485+
*
486+
* This callback is triggered when data is received on a UART bus in passthrough
487+
* mode. It starts transmission on the target bus to forward the received data.
488+
*
489+
* @param handle UART handle of the receiving bus
490+
* @param bytes_available Number of bytes available (unused)
491+
*/
492+
static void passthrough_callback(UART_Handle *handle, uint32_t bytes_available)
493+
{
494+
(void)bytes_available; /* Unused parameter */
495+
496+
if (!handle || !handle->passthrough_target) {
497+
return;
498+
}
499+
500+
/* Start transmission on the target bus */
501+
start_transmission(handle->passthrough_target);
502+
}
503+
504+
void UART_enable_passthrough(UART_Handle *handle1, UART_Handle *handle2)
505+
{
506+
if (!handle1 || !handle1->initialized || !handle2 ||
507+
!handle2->initialized) {
508+
THROW(ERROR_DEVICE_NOT_READY);
509+
}
510+
511+
// Check that handles are different
512+
if (handle1 == handle2) {
513+
THROW(ERROR_INVALID_ARGUMENT);
514+
}
515+
516+
// Check if either handle is already in passthrough mode
517+
if (handle1->passthrough_target || handle2->passthrough_target) {
518+
THROW(ERROR_RESOURCE_BUSY);
519+
}
520+
521+
// Set up shared buffers:
522+
// - Store normal tx_buffers in each handle
523+
// - Redirect each handle's rx_buffer to the other handle's tx_buffer
524+
handle1->original_tx_buffer = handle1->tx_buffer;
525+
handle2->original_tx_buffer = handle2->tx_buffer;
526+
handle1->tx_buffer = handle2->rx_buffer;
527+
handle2->tx_buffer = handle1->rx_buffer;
528+
529+
// Set up passthrough targets
530+
handle1->passthrough_target = handle2;
531+
handle2->passthrough_target = handle1;
532+
533+
// Set up RX callbacks to trigger transmission on the other bus
534+
UART_set_rx_callback(handle1, passthrough_callback, 1);
535+
UART_set_rx_callback(handle2, passthrough_callback, 1);
536+
}
537+
538+
void UART_disable_passthrough(UART_Handle *handle1, UART_Handle *handle2)
539+
{
540+
if (handle1->passthrough_target != handle2 ||
541+
handle2->passthrough_target != handle1) {
542+
THROW(ERROR_INVALID_ARGUMENT);
543+
}
544+
545+
/* Disable passthrough callbacks */
546+
UART_set_rx_callback(handle1, nullptr, 0);
547+
UART_set_rx_callback(handle2, nullptr, 0);
548+
549+
/* Restore original TX buffers */
550+
handle1->tx_buffer = handle1->original_tx_buffer;
551+
handle2->tx_buffer = handle2->original_tx_buffer;
552+
handle1->original_tx_buffer = nullptr;
553+
handle2->original_tx_buffer = nullptr;
554+
555+
/* Clear passthrough targets */
556+
handle1->passthrough_target = nullptr;
557+
handle2->passthrough_target = nullptr;
558+
}

src/system/bus/uart.h

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,8 @@ UART_Handle *UART_init(
102102
/**
103103
* @brief Deinitialize the UART peripheral.
104104
*
105+
* @note Bus cannot be deinitialized while passthrough mode is active.
106+
*
105107
* @param handle Pointer to UART handle structure
106108
*/
107109
void UART_deinit(UART_Handle *handle);
@@ -190,6 +192,37 @@ uint32_t UART_tx_free_space(UART_Handle *handle);
190192
*/
191193
bool UART_tx_busy(UART_Handle *handle);
192194

195+
/**
196+
* @brief Enable UART passthrough mode.
197+
*
198+
* This function enables passthrough mode for the specified UART buses,
199+
* forwarding data received on one bus to the other bus.
200+
*
201+
* @warning Do not call UART operations on either handle while passthrough is
202+
* active.
203+
*
204+
* @note While passthrough is active, neither bus can be deinitialized.
205+
* @note RX callbacks, if any, will be disabled and must be manually re-enabled
206+
* after disabling passthrough.
207+
*
208+
* @param handle1 First UART bus instance
209+
* @param handle2 Second UART bus instance
210+
*/
211+
void UART_enable_passthrough(UART_Handle *handle1, UART_Handle *handle2);
212+
213+
/**
214+
* @brief Disable UART passthrough mode.
215+
*
216+
* This function disables passthrough mode for the specified UART buses,
217+
* restoring normal operation.
218+
*
219+
* @note Previous RX callbacks, if any, must be manually re-enabled.
220+
*
221+
* @param handle1 First UART bus instance
222+
* @param handle2 Second UART bus instance
223+
*/
224+
void UART_disable_passthrough(UART_Handle *handle1, UART_Handle *handle2);
225+
193226
#ifdef __cplusplus
194227
}
195228
#endif

tests/test_headers/opaque.h

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111

1212
#include <stdint.h>
1313

14+
#include "platform/uart_ll.h"
15+
#include "system/bus/uart.h"
1416
#include "system/bus/usb.h"
1517
#include "system/instrument/dmm.h"
1618
#include "system/instrument/dso.h"
@@ -20,6 +22,21 @@
2022
extern "C" {
2123
#endif
2224

25+
/**
26+
* @brief UART handle structure (concrete definition for testing)
27+
*/
28+
struct UART_Handle {
29+
UART_Bus bus_id;
30+
CircularBuffer *rx_buffer;
31+
CircularBuffer *tx_buffer;
32+
CircularBuffer *original_tx_buffer; /* Stored during passthrough */
33+
uint32_t volatile rx_dma_head;
34+
UART_RxCallback rx_callback;
35+
uint32_t rx_threshold;
36+
bool initialized;
37+
UART_Handle *passthrough_target;
38+
};
39+
2340
/**
2441
* @brief DMM handle structure (concrete definition for testing)
2542
*/

0 commit comments

Comments
 (0)