Skip to content

Commit ebe5341

Browse files
committed
Add UART passthrough
1 parent a60c944 commit ebe5341

File tree

4 files changed

+731
-0
lines changed

4 files changed

+731
-0
lines changed

src/system/bus/uart.c

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,11 +49,15 @@ struct UART_Handle {
4949
UART_RxCallback rx_callback;
5050
uint32_t rx_threshold;
5151
bool initialized;
52+
UART_Handle *passthrough_target;
5253
};
5354

5455
/* Global array to keep track of active UART handles */
5556
static UART_Handle *g_active_handles[UART_BUS_COUNT] = { nullptr };
5657

58+
/* Store disabled TX buffers during passthrough */
59+
static CircularBuffer *g_disabled_tx_buffers[2] = { nullptr };
60+
5761
/**
5862
* @brief Get the number of available UART bus instances.
5963
*
@@ -276,6 +280,7 @@ UART_Handle *UART_init(
276280
handle->rx_callback = nullptr;
277281
handle->rx_threshold = 0;
278282
handle->initialized = false;
283+
handle->passthrough_target = nullptr;
279284

280285
/* Initialize hardware layer */
281286
UART_LL_init(bus_id, rx_buffer->buffer, rx_buffer->size);
@@ -301,6 +306,11 @@ void UART_deinit(UART_Handle *handle)
301306
return;
302307
}
303308

309+
/* Cannot deinit while passthrough is active */
310+
if (handle->passthrough_target) {
311+
THROW(ERROR_RESOURCE_BUSY);
312+
}
313+
304314
/* Deinitialize hardware layer */
305315
UART_LL_deinit(handle->bus_id);
306316

@@ -482,3 +492,76 @@ void UART_set_rx_callback(
482492
handle->rx_callback(handle, rx_buffer_available(handle));
483493
}
484494
}
495+
496+
/**
497+
* @brief Passthrough callback function.
498+
*
499+
* This callback is triggered when data is received on a UART bus in passthrough
500+
* mode. It starts transmission on the target bus to forward the received data.
501+
*
502+
* @param handle UART handle of the receiving bus
503+
* @param bytes_available Number of bytes available (unused)
504+
*/
505+
static void passthrough_callback(UART_Handle *handle, uint32_t bytes_available)
506+
{
507+
(void)bytes_available; /* Unused parameter */
508+
509+
if (!handle || !handle->passthrough_target) {
510+
return;
511+
}
512+
513+
/* Start transmission on the target bus */
514+
start_transmission(handle->passthrough_target);
515+
}
516+
517+
void UART_enable_passthrough(UART_Handle *handle1, UART_Handle *handle2)
518+
{
519+
// Only one passthrough pair is allowed at a time
520+
if ((g_disabled_tx_buffers[0] != nullptr) ||
521+
(g_disabled_tx_buffers[1] != nullptr)) {
522+
THROW(ERROR_RESOURCE_BUSY);
523+
}
524+
525+
if (!handle1 || !handle1->initialized || !handle2 ||
526+
!handle2->initialized) {
527+
THROW(ERROR_DEVICE_NOT_READY);
528+
}
529+
530+
// Set up shared buffers:
531+
// - Normal tx_buffers are temporarily disabled
532+
// - Redirect each handle's rx_buffer to the other handle's tx_buffer
533+
g_disabled_tx_buffers[0] = handle1->tx_buffer;
534+
g_disabled_tx_buffers[1] = handle2->tx_buffer;
535+
handle1->tx_buffer = handle2->rx_buffer;
536+
handle2->tx_buffer = handle1->rx_buffer;
537+
538+
// Set up passthrough targets
539+
handle1->passthrough_target = handle2;
540+
handle2->passthrough_target = handle1;
541+
542+
// Set up RX callbacks to trigger transmission on the other bus
543+
UART_set_rx_callback(handle1, passthrough_callback, 1);
544+
UART_set_rx_callback(handle2, passthrough_callback, 1);
545+
}
546+
547+
void UART_disable_passthrough(UART_Handle *handle1, UART_Handle *handle2)
548+
{
549+
if (handle1->passthrough_target != handle2 ||
550+
handle2->passthrough_target != handle1) {
551+
THROW(ERROR_INVALID_ARGUMENT);
552+
}
553+
554+
/* Restore original TX buffers */
555+
handle1->tx_buffer = g_disabled_tx_buffers[0];
556+
handle2->tx_buffer = g_disabled_tx_buffers[1];
557+
g_disabled_tx_buffers[0] = nullptr;
558+
g_disabled_tx_buffers[1] = nullptr;
559+
560+
/* Clear passthrough targets */
561+
handle1->passthrough_target = nullptr;
562+
handle2->passthrough_target = nullptr;
563+
564+
/* Disable RX callbacks */
565+
UART_set_rx_callback(handle1, nullptr, 0);
566+
UART_set_rx_callback(handle2, nullptr, 0);
567+
}

src/system/bus/uart.h

Lines changed: 34 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,38 @@ 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 Passthrough can only be enabled for one pair of UART buses at a time.
205+
* @note While passthrough is active, neither bus can be deinitialized.
206+
* @note RX callbacks, if any, will be disabled and must be manually re-enabled
207+
* after disabling passthrough.
208+
*
209+
* @param handle1 First UART bus instance
210+
* @param handle2 Second UART bus instance
211+
*/
212+
void UART_enable_passthrough(UART_Handle *handle1, UART_Handle *handle2);
213+
214+
/**
215+
* @brief Disable UART passthrough mode.
216+
*
217+
* This function disables passthrough mode for the specified UART buses,
218+
* restoring normal operation.
219+
*
220+
* @note Previous RX callbacks, if any, must be manually re-enabled.
221+
*
222+
* @param handle1 First UART bus instance
223+
* @param handle2 Second UART bus instance
224+
*/
225+
void UART_disable_passthrough(UART_Handle *handle1, UART_Handle *handle2);
226+
193227
#ifdef __cplusplus
194228
}
195229
#endif

tests/test_headers/opaque.h

Lines changed: 16 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,20 @@
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+
uint32_t volatile rx_dma_head;
33+
UART_RxCallback rx_callback;
34+
uint32_t rx_threshold;
35+
bool initialized;
36+
UART_Handle *passthrough_target;
37+
};
38+
2339
/**
2440
* @brief DMM handle structure (concrete definition for testing)
2541
*/

0 commit comments

Comments
 (0)