Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
86 changes: 86 additions & 0 deletions src/system/bus/uart.c
Original file line number Diff line number Diff line change
Expand Up @@ -41,10 +41,12 @@ struct UART_Handle {
UART_Bus bus_id;
CircularBuffer *rx_buffer;
CircularBuffer *tx_buffer;
CircularBuffer *original_tx_buffer; /* Stored during passthrough */
uint32_t volatile rx_dma_head;
UART_RxCallback rx_callback;
uint32_t rx_threshold;
bool initialized;
UART_Handle *passthrough_target;
};

/* Global array to keep track of active UART handles */
Expand Down Expand Up @@ -260,10 +262,12 @@ UART_Handle *UART_init(
handle->bus_id = bus_id;
handle->rx_buffer = rx_buffer;
handle->tx_buffer = tx_buffer;
handle->original_tx_buffer = nullptr;
handle->rx_dma_head = 0;
handle->rx_callback = nullptr;
handle->rx_threshold = 0;
handle->initialized = false;
handle->passthrough_target = nullptr;

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

/* Cannot deinit while passthrough is active */
if (handle->passthrough_target) {
THROW(ERROR_RESOURCE_BUSY);
}

/* Deinitialize hardware layer */
UART_LL_deinit(handle->bus_id);

Expand Down Expand Up @@ -470,3 +479,80 @@ void UART_set_rx_callback(
handle->rx_callback(handle, rx_buffer_available(handle));
}
}

/**
* @brief Passthrough callback function.
*
* This callback is triggered when data is received on a UART bus in passthrough
* mode. It starts transmission on the target bus to forward the received data.
*
* @param handle UART handle of the receiving bus
* @param bytes_available Number of bytes available (unused)
*/
static void passthrough_callback(UART_Handle *handle, uint32_t bytes_available)
{
(void)bytes_available; /* Unused parameter */

if (!handle || !handle->passthrough_target) {
return;
}

/* Start transmission on the target bus */
start_transmission(handle->passthrough_target);
}

void UART_enable_passthrough(UART_Handle *handle1, UART_Handle *handle2)
{
if (!handle1 || !handle1->initialized || !handle2 ||
!handle2->initialized) {
THROW(ERROR_DEVICE_NOT_READY);
}

// Check that handles are different
if (handle1 == handle2) {
THROW(ERROR_INVALID_ARGUMENT);
}

// Check if either handle is already in passthrough mode
if (handle1->passthrough_target || handle2->passthrough_target) {
THROW(ERROR_RESOURCE_BUSY);
}

// Set up shared buffers:
// - Store normal tx_buffers in each handle
// - Redirect each handle's rx_buffer to the other handle's tx_buffer
handle1->original_tx_buffer = handle1->tx_buffer;
handle2->original_tx_buffer = handle2->tx_buffer;
handle1->tx_buffer = handle2->rx_buffer;
handle2->tx_buffer = handle1->rx_buffer;

// Set up passthrough targets
handle1->passthrough_target = handle2;
handle2->passthrough_target = handle1;

// Set up RX callbacks to trigger transmission on the other bus
UART_set_rx_callback(handle1, passthrough_callback, 1);
UART_set_rx_callback(handle2, passthrough_callback, 1);
}

void UART_disable_passthrough(UART_Handle *handle1, UART_Handle *handle2)
{
if (handle1->passthrough_target != handle2 ||
handle2->passthrough_target != handle1) {
THROW(ERROR_INVALID_ARGUMENT);
}

/* Disable passthrough callbacks */
UART_set_rx_callback(handle1, nullptr, 0);
UART_set_rx_callback(handle2, nullptr, 0);

/* Restore original TX buffers */
handle1->tx_buffer = handle1->original_tx_buffer;
handle2->tx_buffer = handle2->original_tx_buffer;
handle1->original_tx_buffer = nullptr;
handle2->original_tx_buffer = nullptr;

/* Clear passthrough targets */
handle1->passthrough_target = nullptr;
handle2->passthrough_target = nullptr;
}
33 changes: 33 additions & 0 deletions src/system/bus/uart.h
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,8 @@ UART_Handle *UART_init(
/**
* @brief Deinitialize the UART peripheral.
*
* @note Bus cannot be deinitialized while passthrough mode is active.
*
* @param handle Pointer to UART handle structure
*/
void UART_deinit(UART_Handle *handle);
Expand Down Expand Up @@ -190,6 +192,37 @@ uint32_t UART_tx_free_space(UART_Handle *handle);
*/
bool UART_tx_busy(UART_Handle *handle);

/**
* @brief Enable UART passthrough mode.
*
* This function enables passthrough mode for the specified UART buses,
* forwarding data received on one bus to the other bus.
*
* @warning Do not call UART operations on either handle while passthrough is
* active.
*
* @note While passthrough is active, neither bus can be deinitialized.
* @note RX callbacks, if any, will be disabled and must be manually re-enabled
* after disabling passthrough.
*
* @param handle1 First UART bus instance
* @param handle2 Second UART bus instance
*/
void UART_enable_passthrough(UART_Handle *handle1, UART_Handle *handle2);

/**
* @brief Disable UART passthrough mode.
*
* This function disables passthrough mode for the specified UART buses,
* restoring normal operation.
*
* @note Previous RX callbacks, if any, must be manually re-enabled.
*
* @param handle1 First UART bus instance
* @param handle2 Second UART bus instance
*/
void UART_disable_passthrough(UART_Handle *handle1, UART_Handle *handle2);

#ifdef __cplusplus
}
#endif
Expand Down
17 changes: 17 additions & 0 deletions tests/test_headers/opaque.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@

#include <stdint.h>

#include "platform/uart_ll.h"
#include "system/bus/uart.h"
#include "system/bus/usb.h"
#include "system/instrument/dmm.h"
#include "system/instrument/dso.h"
Expand All @@ -20,6 +22,21 @@
extern "C" {
#endif

/**
* @brief UART handle structure (concrete definition for testing)
*/
struct UART_Handle {
UART_Bus bus_id;
CircularBuffer *rx_buffer;
CircularBuffer *tx_buffer;
CircularBuffer *original_tx_buffer; /* Stored during passthrough */
uint32_t volatile rx_dma_head;
UART_RxCallback rx_callback;
uint32_t rx_threshold;
bool initialized;
UART_Handle *passthrough_target;
};

/**
* @brief DMM handle structure (concrete definition for testing)
*/
Expand Down
Loading
Loading