commit 1cda81a2dd2938598a8049808ab197ef8c1af45d Author: Mohamed Salem Date: Mon Apr 13 03:51:40 2026 +0200 Initial: HAL_COM function-pointer transport dispatch with multi-channel diff --git a/cfg/HAL_COM_cfg.c b/cfg/HAL_COM_cfg.c new file mode 100644 index 0000000..72c3456 --- /dev/null +++ b/cfg/HAL_COM_cfg.c @@ -0,0 +1,106 @@ +/****************************************************************************** + * File: HAL_COM_cfg.c + * Component: HAL_COM + * Description: Configuration implementation for the HAL_COM abstraction. + * Defines the channel config array that wires each HAL_COM + * channel to a specific MCU-level transport driver via function + * pointers. Also contains thin wrapper functions to normalize + * driver signatures that don't match the generic prototype + * (e.g., MCU_USB which has no instance parameter). + * + * Layer: HAL - configuration + *****************************************************************************/ + +#include "HAL_COM.h" +#include "HAL_COM_cfg.h" + +/* MCU drivers that channels may be wired to */ +#include "MCU_USB.h" +#include "MCU_UART.h" + +/* ------------------------------------------------------------------------ */ +/* SIGNATURE NORMALIZATION WRAPPERS */ +/* ------------------------------------------------------------------------ */ + +/** + * @brief Wrapper for MCU_USB_enuSendByte to match HAL_COM_tpfSendByte. + * + * MCU_USB has only one instance (the RP2040's single USB peripheral), + * so its public API does not take a u8Instance parameter. This wrapper + * adds the parameter and ignores it, making the signature compatible + * with HAL_COM's generic function pointer type. + */ +static STD_tenuResult vUsbSendByte(u8 u8Instance, u8 u8Byte) +{ + (void)u8Instance; + return MCU_USB_enuSendByte(u8Byte); +} + +/** + * @brief Wrapper for MCU_USB_enuSendBuffer to match HAL_COM_tpfSendBuffer. + * + * Same rationale as vUsbSendByte — normalizes the missing instance + * parameter so USB can be plugged into a HAL_COM channel. + */ +static STD_tenuResult vUsbSendBuffer(u8 u8Instance, const u8 *pu8Data, u16 u16Length) +{ + (void)u8Instance; + return MCU_USB_enuSendBuffer(pu8Data, u16Length); +} + +/* MCU_UART already matches the HAL_COM function pointer signatures + * (u8 u8Instance as the first parameter), so no wrapper is needed + * for TX or RX. Its functions can be assigned directly. */ + +/* --- USB RX wrappers (normalize missing instance parameter) --- */ + +static STD_tenuResult vUsbReadByte(u8 u8Instance, u8 *pu8Byte) +{ + (void)u8Instance; + return MCU_USB_enuReadByte(pu8Byte); +} + +static STD_tenuResult vUsbReadBuffer(u8 u8Instance, u8 *pu8Data, u16 u16MaxLength, u16 *pu16Read) +{ + (void)u8Instance; + return MCU_USB_enuReadBuffer(pu8Data, u16MaxLength, pu16Read); +} + +static STD_tBool vUsbIsRxDataAvailable(u8 u8Instance) +{ + (void)u8Instance; + return MCU_USB_bIsRxDataAvailable(); +} + +/* ------------------------------------------------------------------------ */ +/* CHANNEL CONFIGURATION ARRAY */ +/* ------------------------------------------------------------------------ */ + +/** + * @brief Per-channel config, indexed by HAL_COM_tenuChannel. + * + * [HAL_COM_CHANNEL_0] = USB-CDC (primary communication path). + * + * To add a UART channel: + * 1. Add HAL_COM_CHANNEL_1 to the enum in HAL_COM_cfg.h + * 2. Add an entry here with MCU_UART functions (no wrapper needed): + * [HAL_COM_CHANNEL_1] = { + * .pfSendByte = MCU_UART_enuSendByte, + * .pfSendBuffer = MCU_UART_enuSendBuffer, + * .pfReceiveByte = MCU_UART_enuReceiveByte, + * .pfIsRxDataAvailable = MCU_UART_bIsRxDataAvailable, + * .u8Instance = 0U, + * }, + */ +const HAL_COM_tstrChannelConfig HAL_COM_astrChannelConfig[HAL_COM_NUM_CHANNELS] = +{ + [HAL_COM_CHANNEL_0] = + { + .pfSendByte = vUsbSendByte, + .pfSendBuffer = vUsbSendBuffer, + .pfReadByte = vUsbReadByte, + .pfReadBuffer = vUsbReadBuffer, + .pfIsRxDataAvailable = vUsbIsRxDataAvailable, + .u8Instance = 0U, + }, +}; diff --git a/cfg/HAL_COM_cfg.h b/cfg/HAL_COM_cfg.h new file mode 100644 index 0000000..8af7c77 --- /dev/null +++ b/cfg/HAL_COM_cfg.h @@ -0,0 +1,39 @@ +/****************************************************************************** + * File: HAL_COM_cfg.h + * Component: HAL_COM + * Description: Configuration header for the HAL_COM abstraction. + * Defines the communication channels and which MCU-level + * transport each one routes through via function pointers. + * Adding a new channel or swapping a transport is a config-only + * change — no code in HAL_COM_prg.c needs to be modified. + * + * Layer: HAL - configuration + *****************************************************************************/ + +#ifndef HAL_COM_CFG_H +#define HAL_COM_CFG_H + +#include "STD_TYPES.h" + +/* ------------------------------------------------------------------------ */ +/* CHANNEL ENUMERATION */ +/* ------------------------------------------------------------------------ */ + +/** + * @brief Enumeration of configured HAL_COM channels. + * + * Each channel is one logical communication path wired to a specific + * MCU-level driver. The enumerator values are used as array indices + * into HAL_COM_astrChannelConfig[]. + * + * To add a channel: add an enumerator before HAL_COM_NUM_CHANNELS, + * define its function pointer macros below, and add an entry in + * HAL_COM_cfg.c. + */ +typedef enum +{ + HAL_COM_CHANNEL_0 = 0U, /**< Primary channel (USB-CDC by default) */ + HAL_COM_NUM_CHANNELS +} HAL_COM_tenuChannel; + +#endif /* HAL_COM_CFG_H */ diff --git a/inc/HAL_COM.h b/inc/HAL_COM.h new file mode 100644 index 0000000..3b0750b --- /dev/null +++ b/inc/HAL_COM.h @@ -0,0 +1,151 @@ +/****************************************************************************** + * File: HAL_COM.h + * Component: HAL_COM + * Description: Public interface for the HAL communication abstraction layer. + * Provides a transport-agnostic, multi-channel API for sending + * and receiving bytes. Each channel is independently configured + * with function pointers to an MCU-level driver (USB, UART, + * SPI, I2C, or any future transport that matches the function + * signatures). + * + * Higher layers (e.g. APP_CLSW) call HAL_COM_* with a channel + * number and stay unaware of which physical transport is in use. + * Adding a new transport requires zero changes to this file or + * to HAL_COM_prg.c — only the config needs a new channel entry. + * + * Layer: HAL (hardware abstraction, one level above MCU drivers) + *****************************************************************************/ + +#ifndef HAL_COM_H +#define HAL_COM_H + +#include "STD_TYPES.h" +#include "HAL_COM_cfg.h" + +/* ------------------------------------------------------------------------ */ +/* TRANSPORT FUNCTION POINTER TYPES */ +/* ------------------------------------------------------------------------ */ + +/** + * @brief Generic send-byte function pointer type. + * + * Any MCU driver that can send a single byte and matches this signature + * can be plugged into a HAL_COM channel. The u8Instance parameter + * identifies the peripheral instance within that driver (e.g., UART0 + * vs UART1). Drivers that have only one instance (e.g., MCU_USB) use + * a thin wrapper that ignores the parameter. + * + * @param u8Instance Peripheral instance index within the driver. + * @param u8Byte The byte to transmit. + * @return STD_tenuResult + */ +typedef STD_tenuResult (*HAL_COM_tpfSendByte)(u8 u8Instance, u8 u8Byte); + +/** + * @brief Generic send-buffer function pointer type. + * + * Same concept as HAL_COM_tpfSendByte but for multi-byte transfers. + * + * @param u8Instance Peripheral instance index within the driver. + * @param pu8Data Pointer to the byte buffer. + * @param u16Length Number of bytes to transmit. + * @return STD_tenuResult + */ +typedef STD_tenuResult (*HAL_COM_tpfSendBuffer)(u8 u8Instance, const u8 *pu8Data, u16 u16Length); + +/** + * @brief Generic read-byte function pointer type (non-blocking). + */ +typedef STD_tenuResult (*HAL_COM_tpfReadByte)(u8 u8Instance, u8 *pu8Byte); + +/** + * @brief Generic read-buffer function pointer type (non-blocking). + */ +typedef STD_tenuResult (*HAL_COM_tpfReadBuffer)(u8 u8Instance, u8 *pu8Data, u16 u16MaxLength, u16 *pu16Read); + +/** + * @brief Generic RX-data-available check function pointer type. + */ +typedef STD_tBool (*HAL_COM_tpfIsRxDataAvailable)(u8 u8Instance); + +/* ------------------------------------------------------------------------ */ +/* CONFIGURATION STRUCTURE */ +/* ------------------------------------------------------------------------ */ + +/** + * @brief Per-channel communication configuration. + * + * One entry per HAL_COM channel, stored in HAL_COM_astrChannelConfig[]. + * The array index is the channel number passed to all public functions. + * + * Each channel is wired to exactly one MCU-level transport by holding + * function pointers to that driver's send functions + the instance index + * to pass through. To route through a different transport, just change + * the function pointers in the config — no code changes needed. + */ +typedef struct +{ + HAL_COM_tpfSendByte pfSendByte; /**< Driver's send-byte function */ + HAL_COM_tpfSendBuffer pfSendBuffer; /**< Driver's send-buffer function */ + HAL_COM_tpfReadByte pfReadByte; /**< Driver's read-byte function */ + HAL_COM_tpfReadBuffer pfReadBuffer; /**< Driver's read-buffer function */ + HAL_COM_tpfIsRxDataAvailable pfIsRxDataAvailable; /**< Driver's RX-available check */ + u8 u8Instance; /**< Peripheral instance to pass through */ +} HAL_COM_tstrChannelConfig; + +/* ------------------------------------------------------------------------ */ +/* PUBLIC API */ +/* ------------------------------------------------------------------------ */ + +/** + * @brief Initialize the HAL communication layer's own internal state. + * + * Does NOT initialize the underlying MCU drivers — SYS_ECU owns the init + * sequence and calls each driver's enuInit() before calling this. + * + * @return STD_OK on success, STD_NOK on failure. + */ +STD_tenuResult HAL_COM_enuInit(void); + +/** + * @brief Send a single byte through the specified channel. + * + * @param u8Channel Channel index (from HAL_COM_cfg.h channel enum). + * @param u8Byte The byte to transmit. + * @return STD_OK on success, STD_NOK on failure. + */ +STD_tenuResult HAL_COM_enuSendByte(u8 u8Channel, u8 u8Byte); + +/** + * @brief Send a buffer through the specified channel. + * + * The underlying driver may be blocking or non-blocking depending on the + * MCU driver wired to this channel. When non-blocking (e.g., MCU_UART + * with DMA), the caller must keep the buffer valid until the transfer + * completes. + * + * @param u8Channel Channel index. + * @param pu8Data Pointer to the byte buffer. Must not be NULL. + * @param u16Length Number of bytes to transmit. + * @return STD_OK on success, + * STD_NULL_POINTER_ERROR if pu8Data is NULL, + * STD_NOK on failure. + */ +STD_tenuResult HAL_COM_enuSendBuffer(u8 u8Channel, const u8 *pu8Data, u16 u16Length); + +/** + * @brief Read one byte from the specified channel (non-blocking). + */ +STD_tenuResult HAL_COM_enuReadByte(u8 u8Channel, u8 *pu8Byte); + +/** + * @brief Read up to u16MaxLength bytes from the specified channel (non-blocking). + */ +STD_tenuResult HAL_COM_enuReadBuffer(u8 u8Channel, u8 *pu8Data, u16 u16MaxLength, u16 *pu16Read); + +/** + * @brief Check if the specified channel has RX data available. + */ +STD_tBool HAL_COM_bIsRxDataAvailable(u8 u8Channel); + +#endif /* HAL_COM_H */ \ No newline at end of file diff --git a/prg/HAL_COM_prg.c b/prg/HAL_COM_prg.c new file mode 100644 index 0000000..271abd7 --- /dev/null +++ b/prg/HAL_COM_prg.c @@ -0,0 +1,106 @@ +/****************************************************************************** + * File: HAL_COM_prg.c + * Component: HAL_COM + * Description: Program (implementation) file for the HAL_COM abstraction. + * Dispatches send operations to the MCU-level driver wired to + * each channel via function pointers in HAL_COM_astrChannelConfig. + * + * The dispatch is a single indirect call — no if/else chains, + * no transport-specific code. Adding a new transport (SPI, I2C, + * etc.) requires zero changes here — only a new config entry. + * + * Layer: HAL + *****************************************************************************/ + +#include "HAL_COM.h" +#include "HAL_COM_priv.h" +#include "HAL_COM_cfg.h" + +/* ========================================================================= */ +/* INIT */ +/* ========================================================================= */ + +STD_tenuResult HAL_COM_enuInit(void) +{ + STD_tenuResult enuResultLoc = STD_OK; + + /* HAL_COM has no internal state to set up yet. The underlying MCU + * drivers are already initialized by SYS_ECU before this function + * is called. When internal queuing or channel-level state is added, + * initialize it here. */ + + return enuResultLoc; +} + +/* ========================================================================= */ +/* SEND BYTE */ +/* ========================================================================= */ + +STD_tenuResult HAL_COM_enuSendByte(u8 u8Channel, u8 u8Byte) +{ + STD_tenuResult enuResultLoc = STD_OK; + const HAL_COM_tstrChannelConfig *pstrCfgLoc = &HAL_COM_astrChannelConfig[u8Channel]; + + /* Dispatch through the function pointer configured for this channel. + * The driver's instance index is passed through transparently — the + * caller never sees it. */ + enuResultLoc = pstrCfgLoc->pfSendByte(pstrCfgLoc->u8Instance, u8Byte); + + return enuResultLoc; +} + +/* ========================================================================= */ +/* SEND BUFFER */ +/* ========================================================================= */ + +STD_tenuResult HAL_COM_enuSendBuffer(u8 u8Channel, const u8 *pu8Data, u16 u16Length) +{ + STD_tenuResult enuResultLoc = STD_OK; + const HAL_COM_tstrChannelConfig *pstrCfgLoc = &HAL_COM_astrChannelConfig[u8Channel]; + + /* Dispatch through the function pointer configured for this channel. + * Null-pointer validation is handled inside the MCU driver, so we + * don't duplicate the check here. */ + enuResultLoc = pstrCfgLoc->pfSendBuffer(pstrCfgLoc->u8Instance, pu8Data, u16Length); + + return enuResultLoc; +} + +/* ========================================================================= */ +/* RECEIVE BYTE (BLOCKING) */ +/* ========================================================================= */ + +STD_tenuResult HAL_COM_enuReadByte(u8 u8Channel, u8 *pu8Byte) +{ + STD_tenuResult enuResultLoc = STD_OK; + const HAL_COM_tstrChannelConfig *pstrCfgLoc = &HAL_COM_astrChannelConfig[u8Channel]; + + enuResultLoc = pstrCfgLoc->pfReadByte(pstrCfgLoc->u8Instance, pu8Byte); + + return enuResultLoc; +} + +/* ========================================================================= */ +/* READ BUFFER (NON-BLOCKING) */ +/* ========================================================================= */ + +STD_tenuResult HAL_COM_enuReadBuffer(u8 u8Channel, u8 *pu8Data, u16 u16MaxLength, u16 *pu16Read) +{ + STD_tenuResult enuResultLoc = STD_OK; + const HAL_COM_tstrChannelConfig *pstrCfgLoc = &HAL_COM_astrChannelConfig[u8Channel]; + + enuResultLoc = pstrCfgLoc->pfReadBuffer(pstrCfgLoc->u8Instance, pu8Data, u16MaxLength, pu16Read); + + return enuResultLoc; +} + +/* ========================================================================= */ +/* RX DATA AVAILABLE CHECK */ +/* ========================================================================= */ + +STD_tBool HAL_COM_bIsRxDataAvailable(u8 u8Channel) +{ + const HAL_COM_tstrChannelConfig *pstrCfgLoc = &HAL_COM_astrChannelConfig[u8Channel]; + + return pstrCfgLoc->pfIsRxDataAvailable(pstrCfgLoc->u8Instance); +} diff --git a/prg/HAL_COM_priv.h b/prg/HAL_COM_priv.h new file mode 100644 index 0000000..f6f4fce --- /dev/null +++ b/prg/HAL_COM_priv.h @@ -0,0 +1,32 @@ +/****************************************************************************** + * File: HAL_COM_priv.h + * Component: HAL_COM + * Description: Private header for the HAL_COM abstraction. + * Contains the extern declaration of the channel config array + * (only accessed internally by _prg.c) and any other private + * definitions. + * + * Layer: HAL - internal use only + *****************************************************************************/ + +#ifndef HAL_COM_PRIV_H +#define HAL_COM_PRIV_H + +#include "HAL_COM.h" +#include "HAL_COM_cfg.h" + +/* ------------------------------------------------------------------------ */ +/* CONFIG ARRAY (EXTERN) */ +/* ------------------------------------------------------------------------ */ + +/** + * @brief Channel configuration array indexed by HAL_COM_tenuChannel. + * + * Defined in HAL_COM_cfg.c. Each entry holds function pointers to an + * MCU-level driver's send functions + the instance index to pass through. + * Only HAL_COM_prg.c accesses this — no external component should read + * the raw config. + */ +extern const HAL_COM_tstrChannelConfig HAL_COM_astrChannelConfig[HAL_COM_NUM_CHANNELS]; + +#endif /* HAL_COM_PRIV_H */ \ No newline at end of file