/*
 * Copyright 2018-2024 NXP
 * All rights reserved.
 *
 *
 * SPDX-License-Identifier: BSD-3-Clause
 */

#ifndef __SERIAL_MANAGER_H__
#define __SERIAL_MANAGER_H__

#include "fsl_common.h"

/*!
 * @addtogroup serialmanager
 * @{
 */

/*******************************************************************************
 * Definitions
 ******************************************************************************/
/*! @brief Enable or disable serial manager non-blocking mode (1 - enable, 0 - disable) */
#ifdef DEBUG_CONSOLE_TRANSFER_NON_BLOCKING
#if (defined(SERIAL_MANAGER_NON_BLOCKING_MODE) && (SERIAL_MANAGER_NON_BLOCKING_MODE == 0U))
#error When SERIAL_MANAGER_NON_BLOCKING_MODE=0, DEBUG_CONSOLE_TRANSFER_NON_BLOCKING can not be set.
#else
#define SERIAL_MANAGER_NON_BLOCKING_MODE (1U)
#endif
#else
#ifndef SERIAL_MANAGER_NON_BLOCKING_MODE
#define SERIAL_MANAGER_NON_BLOCKING_MODE (0U)
#endif
#endif

/*! @brief Enable or ring buffer flow control (1 - enable, 0 - disable) */
#ifndef SERIAL_MANAGER_RING_BUFFER_FLOWCONTROL
#define SERIAL_MANAGER_RING_BUFFER_FLOWCONTROL (0U)
#endif

/*! @brief Enable or disable uart port (1 - enable, 0 - disable) */
#ifndef SERIAL_PORT_TYPE_UART
#define SERIAL_PORT_TYPE_UART (0U)
#endif

/*! @brief Enable or disable uart dma port (1 - enable, 0 - disable) */
#ifndef SERIAL_PORT_TYPE_UART_DMA
#define SERIAL_PORT_TYPE_UART_DMA (0U)
#endif
/*! @brief Enable or disable USB CDC port (1 - enable, 0 - disable) */
#ifndef SERIAL_PORT_TYPE_USBCDC
#define SERIAL_PORT_TYPE_USBCDC (0U)
#endif

/*! @brief Enable or disable SWO port (1 - enable, 0 - disable) */
#ifndef SERIAL_PORT_TYPE_SWO
#define SERIAL_PORT_TYPE_SWO (0U)
#endif

/*! @brief Enable or disable USB CDC virtual port (1 - enable, 0 - disable) */
#ifndef SERIAL_PORT_TYPE_VIRTUAL
#define SERIAL_PORT_TYPE_VIRTUAL (0U)
#endif

/*! @brief Enable or disable rPMSG port (1 - enable, 0 - disable) */
#ifndef SERIAL_PORT_TYPE_RPMSG
#define SERIAL_PORT_TYPE_RPMSG (0U)
#endif

/*! @brief Enable or disable SPI Master port (1 - enable, 0 - disable) */
#ifndef SERIAL_PORT_TYPE_SPI_MASTER
#define SERIAL_PORT_TYPE_SPI_MASTER (0U)
#endif

/*! @brief Enable or disable SPI Slave port (1 - enable, 0 - disable) */
#ifndef SERIAL_PORT_TYPE_SPI_SLAVE
#define SERIAL_PORT_TYPE_SPI_SLAVE (0U)
#endif

/*! @brief Enable or disable BLE WU port (1 - enable, 0 - disable) */
#ifndef SERIAL_PORT_TYPE_BLE_WU
#define SERIAL_PORT_TYPE_BLE_WU (0U)
#endif

#if (defined(SERIAL_PORT_TYPE_SPI_SLAVE) && (SERIAL_PORT_TYPE_SPI_SLAVE == 1U))
#if (defined(SERIAL_MANAGER_NON_BLOCKING_MODE) && (SERIAL_MANAGER_NON_BLOCKING_MODE == 0U))
#warning When SERIAL_PORT_TYPE_SPI_SLAVE=1, SERIAL_MANAGER_NON_BLOCKING_MODE should be set.
#undef SERIAL_MANAGER_NON_BLOCKING_MODE
#define SERIAL_MANAGER_NON_BLOCKING_MODE (1U)
#endif
#endif

/*! @brief Set the default delay time in ms used by SerialManager_WriteTimeDelay(). */
#ifndef SERIAL_MANAGER_WRITE_TIME_DELAY_DEFAULT_VALUE
#define SERIAL_MANAGER_WRITE_TIME_DELAY_DEFAULT_VALUE (1U)
#endif

/*! @brief Set the default delay time in ms used by SerialManager_ReadTimeDelay(). */
#ifndef SERIAL_MANAGER_READ_TIME_DELAY_DEFAULT_VALUE
#define SERIAL_MANAGER_READ_TIME_DELAY_DEFAULT_VALUE (1U)
#endif

/*! @brief Enable or disable SerialManager_Task() handle RX data available notify */
#ifndef SERIAL_MANAGER_TASK_HANDLE_RX_AVAILABLE_NOTIFY
#define SERIAL_MANAGER_TASK_HANDLE_RX_AVAILABLE_NOTIFY (0U)
#endif
#if (defined(SERIAL_MANAGER_TASK_HANDLE_RX_AVAILABLE_NOTIFY) && (SERIAL_MANAGER_TASK_HANDLE_RX_AVAILABLE_NOTIFY > 0U))
#ifndef OSA_USED
#error When SERIAL_MANAGER_TASK_HANDLE_RX_AVAILABLE_NOTIFY=1, OSA_USED must be set.
#endif
#endif

/*! @brief Set serial manager write handle size */
#if (defined(SERIAL_MANAGER_NON_BLOCKING_MODE) && (SERIAL_MANAGER_NON_BLOCKING_MODE > 0U))
#define SERIAL_MANAGER_WRITE_HANDLE_SIZE       (44U)
#define SERIAL_MANAGER_READ_HANDLE_SIZE        (44U)
#define SERIAL_MANAGER_WRITE_BLOCK_HANDLE_SIZE (4U)
#define SERIAL_MANAGER_READ_BLOCK_HANDLE_SIZE  (4U)
#else
#define SERIAL_MANAGER_WRITE_HANDLE_SIZE       (4U)
#define SERIAL_MANAGER_READ_HANDLE_SIZE        (4U)
#define SERIAL_MANAGER_WRITE_BLOCK_HANDLE_SIZE (4U)
#define SERIAL_MANAGER_READ_BLOCK_HANDLE_SIZE  (4U)
#endif

#if (defined(SERIAL_PORT_TYPE_UART) && (SERIAL_PORT_TYPE_UART > 0U))
#include "fsl_component_serial_port_uart.h"
#endif

#if (defined(SERIAL_PORT_TYPE_UART_DMA) && (SERIAL_PORT_TYPE_UART_DMA > 0U))
#include "fsl_component_serial_port_uart.h"
#endif
#if (defined(SERIAL_PORT_TYPE_RPMSG) && (SERIAL_PORT_TYPE_RPMSG > 0U))
#include "fsl_component_serial_port_rpmsg.h"
#endif

#if (defined(SERIAL_PORT_TYPE_USBCDC) && (SERIAL_PORT_TYPE_USBCDC > 0U))

#if !(defined(SERIAL_MANAGER_NON_BLOCKING_MODE) && (SERIAL_MANAGER_NON_BLOCKING_MODE > 0U))
#error The serial manager blocking mode cannot be supported for USB CDC.
#endif

#include "fsl_component_serial_port_usb.h"
#endif

#if (defined(SERIAL_PORT_TYPE_SWO) && (SERIAL_PORT_TYPE_SWO > 0U))
#include "fsl_component_serial_port_swo.h"
#endif

#if (defined(SERIAL_PORT_TYPE_SPI_MASTER) && (SERIAL_PORT_TYPE_SPI_MASTER > 0U))
#include "fsl_component_serial_port_spi.h"
#endif
#if (defined(SERIAL_PORT_TYPE_SPI_SLAVE) && (SERIAL_PORT_TYPE_SPI_SLAVE > 0U))
#include "fsl_component_serial_port_spi.h"
#endif
#if (defined(SERIAL_PORT_TYPE_VIRTUAL) && (SERIAL_PORT_TYPE_VIRTUAL > 0U))

#if !(defined(SERIAL_MANAGER_NON_BLOCKING_MODE) && (SERIAL_MANAGER_NON_BLOCKING_MODE > 0U))
#error The serial manager blocking mode cannot be supported for USB CDC.
#endif

#include "fsl_component_serial_port_virtual.h"
#endif
#if (defined(SERIAL_PORT_TYPE_BLE_WU) && (SERIAL_PORT_TYPE_BLE_WU > 0U))

#if !(defined(SERIAL_MANAGER_NON_BLOCKING_MODE) && (SERIAL_MANAGER_NON_BLOCKING_MODE > 0U))
#error The serial manager blocking mode cannot be supported for BLE WU.
#endif /* SERIAL_MANAGER_NON_BLOCKING_MODE */

#include "fsl_component_serial_port_ble_wu.h"
#endif /* SERIAL_PORT_TYPE_BLE_WU */

#define SERIAL_MANAGER_HANDLE_SIZE_TEMP 0U
#if (defined(SERIAL_PORT_TYPE_UART) && (SERIAL_PORT_TYPE_UART > 0U))

#if (SERIAL_PORT_UART_HANDLE_SIZE > SERIAL_MANAGER_HANDLE_SIZE_TEMP)
#undef SERIAL_MANAGER_HANDLE_SIZE_TEMP
#define SERIAL_MANAGER_HANDLE_SIZE_TEMP SERIAL_PORT_UART_HANDLE_SIZE
#endif
#endif

#if (defined(SERIAL_PORT_TYPE_UART_DMA) && (SERIAL_PORT_TYPE_UART_DMA > 0U))
#if (SERIAL_PORT_UART_DMA_HANDLE_SIZE > SERIAL_MANAGER_HANDLE_SIZE_TEMP)
#undef SERIAL_MANAGER_HANDLE_SIZE_TEMP
#define SERIAL_MANAGER_HANDLE_SIZE_TEMP SERIAL_PORT_UART_DMA_HANDLE_SIZE
#endif
#endif

#if (defined(SERIAL_PORT_TYPE_USBCDC) && (SERIAL_PORT_TYPE_USBCDC > 0U))

#if (SERIAL_PORT_USB_CDC_HANDLE_SIZE > SERIAL_MANAGER_HANDLE_SIZE_TEMP)
#undef SERIAL_MANAGER_HANDLE_SIZE_TEMP
#define SERIAL_MANAGER_HANDLE_SIZE_TEMP SERIAL_PORT_USB_CDC_HANDLE_SIZE
#endif

#endif

#if (defined(SERIAL_PORT_TYPE_SWO) && (SERIAL_PORT_TYPE_SWO > 0U))

#if (SERIAL_PORT_SWO_HANDLE_SIZE > SERIAL_MANAGER_HANDLE_SIZE_TEMP)
#undef SERIAL_MANAGER_HANDLE_SIZE_TEMP
#define SERIAL_MANAGER_HANDLE_SIZE_TEMP SERIAL_PORT_SWO_HANDLE_SIZE
#endif

#endif

#if (defined(SERIAL_PORT_TYPE_SPI_MASTER) && (SERIAL_PORT_TYPE_SPI_MASTER > 0U))
#if (SERIAL_PORT_SPI_MASTER_HANDLE_SIZE > SERIAL_MANAGER_HANDLE_SIZE_TEMP)
#undef SERIAL_MANAGER_HANDLE_SIZE_TEMP
#define SERIAL_MANAGER_HANDLE_SIZE_TEMP SERIAL_PORT_SPI_MASTER_HANDLE_SIZE
#endif
#endif

#if (defined(SERIAL_PORT_TYPE_SPI_SLAVE) && (SERIAL_PORT_TYPE_SPI_SLAVE > 0U))
#if (SERIAL_PORT_SPI_SLAVE_HANDLE_SIZE > SERIAL_MANAGER_HANDLE_SIZE_TEMP)
#undef SERIAL_MANAGER_HANDLE_SIZE_TEMP
#define SERIAL_MANAGER_HANDLE_SIZE_TEMP SERIAL_PORT_SPI_SLAVE_HANDLE_SIZE
#endif
#endif

#if (defined(SERIAL_PORT_TYPE_VIRTUAL) && (SERIAL_PORT_TYPE_VIRTUAL > 0U))

#if (SERIAL_PORT_VIRTUAL_HANDLE_SIZE > SERIAL_MANAGER_HANDLE_SIZE_TEMP)
#undef SERIAL_MANAGER_HANDLE_SIZE_TEMP
#define SERIAL_MANAGER_HANDLE_SIZE_TEMP SERIAL_PORT_VIRTUAL_HANDLE_SIZE
#endif

#endif

#if (defined(SERIAL_PORT_TYPE_RPMSG) && (SERIAL_PORT_TYPE_RPMSG > 0U))

#if (SERIAL_PORT_RPMSG_HANDLE_SIZE > SERIAL_MANAGER_HANDLE_SIZE_TEMP)
#undef SERIAL_MANAGER_HANDLE_SIZE_TEMP
#define SERIAL_MANAGER_HANDLE_SIZE_TEMP SERIAL_PORT_RPMSG_HANDLE_SIZE

#endif

#endif

#if (defined(SERIAL_PORT_TYPE_BLE_WU) && (SERIAL_PORT_TYPE_BLE_WU > 0U))

#if (SERIAL_PORT_BLE_WU_HANDLE_SIZE > SERIAL_MANAGER_HANDLE_SIZE_TEMP)
#undef SERIAL_MANAGER_HANDLE_SIZE_TEMP
#define SERIAL_MANAGER_HANDLE_SIZE_TEMP SERIAL_PORT_BLE_WU_HANDLE_SIZE
#endif

#endif

/*! @brief SERIAL_PORT_UART_HANDLE_SIZE/SERIAL_PORT_USB_CDC_HANDLE_SIZE + serial manager dedicated size */
#if ((defined(SERIAL_MANAGER_HANDLE_SIZE_TEMP) && (SERIAL_MANAGER_HANDLE_SIZE_TEMP > 0U)))
#else
#error SERIAL_PORT_TYPE_UART, SERIAL_PORT_TYPE_USBCDC, SERIAL_PORT_TYPE_SWO, SERIAL_PORT_TYPE_VIRTUAL, and SERIAL_PORT_TYPE_BLE_WU should not be cleared at same time.
#endif

/*! @brief Macro to determine whether use common task. */
#ifndef SERIAL_MANAGER_USE_COMMON_TASK
#define SERIAL_MANAGER_USE_COMMON_TASK (0U)
#endif

#if defined(OSA_USED)
#if (defined(SERIAL_MANAGER_USE_COMMON_TASK) && (SERIAL_MANAGER_USE_COMMON_TASK > 0U))
#include "fsl_component_common_task.h"
#endif
/*! @brief Enable or disable SerialManager_Task() handle TX to prevent recursive calling */
#ifndef SERIAL_MANAGER_TASK_HANDLE_TX
#define SERIAL_MANAGER_TASK_HANDLE_TX (1U)
#endif
#endif

#if (defined(SERIAL_MANAGER_TASK_HANDLE_TX) && (SERIAL_MANAGER_TASK_HANDLE_TX > 0U))
#ifndef OSA_USED
#error When SERIAL_MANAGER_TASK_HANDLE_TX=1, OSA_USED must be set.
#endif
#endif

#if (defined(SERIAL_MANAGER_NON_BLOCKING_MODE) && (SERIAL_MANAGER_NON_BLOCKING_MODE > 0U))
#if (defined(OSA_USED) && !(defined(SERIAL_MANAGER_USE_COMMON_TASK) && (SERIAL_MANAGER_USE_COMMON_TASK > 0U)))
#include "fsl_os_abstraction.h"
#endif
#endif

/*! @brief Definition of serial manager handle size. */
#if (defined(SERIAL_MANAGER_NON_BLOCKING_MODE) && (SERIAL_MANAGER_NON_BLOCKING_MODE > 0U))
#if (defined(OSA_USED) && !(defined(SERIAL_MANAGER_USE_COMMON_TASK) && (SERIAL_MANAGER_USE_COMMON_TASK > 0U)))
#define SERIAL_MANAGER_HANDLE_SIZE \
    (SERIAL_MANAGER_HANDLE_SIZE_TEMP + 124U + OSA_TASK_HANDLE_SIZE + OSA_EVENT_HANDLE_SIZE)
#else  /*defined(OSA_USED)*/
#define SERIAL_MANAGER_HANDLE_SIZE (SERIAL_MANAGER_HANDLE_SIZE_TEMP + 124U)
#endif /*defined(OSA_USED)*/
#define SERIAL_MANAGER_BLOCK_HANDLE_SIZE (SERIAL_MANAGER_HANDLE_SIZE_TEMP + 16U)
#else
#define SERIAL_MANAGER_HANDLE_SIZE       (SERIAL_MANAGER_HANDLE_SIZE_TEMP + 12U)
#define SERIAL_MANAGER_BLOCK_HANDLE_SIZE (SERIAL_MANAGER_HANDLE_SIZE_TEMP + 12U)
#endif

/*!
 * @brief Defines the serial manager handle
 *
 * This macro is used to define a 4 byte aligned serial manager handle.
 * Then use "(serial_handle_t)name" to get the serial manager handle.
 *
 * The macro should be global and could be optional. You could also define serial manager handle by yourself.
 *
 * This is an example,
 * @code
 * SERIAL_MANAGER_HANDLE_DEFINE(serialManagerHandle);
 * @endcode
 *
 * @param name The name string of the serial manager handle.
 */
#define SERIAL_MANAGER_HANDLE_DEFINE(name) \
    uint32_t name[((SERIAL_MANAGER_HANDLE_SIZE + sizeof(uint32_t) - 1U) / sizeof(uint32_t))]
#define SERIAL_MANAGER_BLOCK_HANDLE_DEFINE(name) \
    uint32_t name[((SERIAL_MANAGER_BLOCK_HANDLE_SIZE + sizeof(uint32_t) - 1U) / sizeof(uint32_t))]
/*!
 * @brief Defines the serial manager write handle
 *
 * This macro is used to define a 4 byte aligned serial manager write handle.
 * Then use "(serial_write_handle_t)name" to get the serial manager write handle.
 *
 * The macro should be global and could be optional. You could also define serial manager write handle by yourself.
 *
 * This is an example,
 * @code
 * SERIAL_MANAGER_WRITE_HANDLE_DEFINE(serialManagerwriteHandle);
 * @endcode
 *
 * @param name The name string of the serial manager write handle.
 */
#define SERIAL_MANAGER_WRITE_HANDLE_DEFINE(name) \
    uint32_t name[((SERIAL_MANAGER_WRITE_HANDLE_SIZE + sizeof(uint32_t) - 1U) / sizeof(uint32_t))]
#define SERIAL_MANAGER_WRITE_BLOCK_HANDLE_DEFINE(name) \
    uint32_t name[((SERIAL_MANAGER_WRITE_BLOCK_HANDLE_SIZE + sizeof(uint32_t) - 1U) / sizeof(uint32_t))]
/*!
 * @brief Defines the serial manager read handle
 *
 * This macro is used to define a 4 byte aligned serial manager read handle.
 * Then use "(serial_read_handle_t)name" to get the serial manager read handle.
 *
 * The macro should be global and could be optional. You could also define serial manager read handle by yourself.
 *
 * This is an example,
 * @code
 * SERIAL_MANAGER_READ_HANDLE_DEFINE(serialManagerReadHandle);
 * @endcode
 *
 * @param name The name string of the serial manager read handle.
 */
#define SERIAL_MANAGER_READ_HANDLE_DEFINE(name) \
    uint32_t name[((SERIAL_MANAGER_READ_HANDLE_SIZE + sizeof(uint32_t) - 1U) / sizeof(uint32_t))]
#define SERIAL_MANAGER_READ_BLOCK_HANDLE_DEFINE(name) \
    uint32_t name[((SERIAL_MANAGER_READ_BLOCK_HANDLE_SIZE + sizeof(uint32_t) - 1U) / sizeof(uint32_t))]

/*! @brief Macro to set serial manager task priority. */
#ifndef SERIAL_MANAGER_TASK_PRIORITY
#define SERIAL_MANAGER_TASK_PRIORITY (2U)
#endif

/*! @brief Macro to set serial manager task stack size. */
#ifndef SERIAL_MANAGER_TASK_STACK_SIZE
#define SERIAL_MANAGER_TASK_STACK_SIZE (1000U)
#endif

/*! @brief The handle of the serial manager module */
typedef void *serial_handle_t;

/*! @brief The write handle of the serial manager module */
typedef void *serial_write_handle_t;

/*! @brief The read handle of the serial manager module */
typedef void *serial_read_handle_t;

#ifndef _SERIAL_PORT_T_
#define _SERIAL_PORT_T_
/*! @brief serial port type*/
typedef enum _serial_port_type
{
    kSerialPort_None = 0U, /*!< Serial port is none */
    kSerialPort_Uart = 1U, /*!< Serial port UART */
    kSerialPort_UsbCdc,    /*!< Serial port USB CDC */
    kSerialPort_Swo,       /*!< Serial port SWO */
    kSerialPort_Virtual,   /*!< Serial port Virtual */
    kSerialPort_Rpmsg,     /*!< Serial port RPMSG */
    kSerialPort_UartDma,   /*!< Serial port UART DMA*/
    kSerialPort_SpiMaster, /*!< Serial port SPIMASTER*/
    kSerialPort_SpiSlave,  /*!< Serial port SPISLAVE*/
    kSerialPort_BleWu,     /*!< Serial port BLE WU */
} serial_port_type_t;
#endif

/*! @brief serial manager type*/
typedef enum _serial_manager_type
{
    kSerialManager_NonBlocking = 0x0U,    /*!< None blocking handle*/
    kSerialManager_Blocking    = 0x8F41U, /*!< Blocking handle*/
} serial_manager_type_t;
/*! @brief serial manager config structure*/
typedef struct _serial_manager_config
{
#if (defined(SERIAL_MANAGER_NON_BLOCKING_MODE) && (SERIAL_MANAGER_NON_BLOCKING_MODE > 0U))
    uint8_t *ringBuffer;             /*!< Ring buffer address, it is used to buffer data received by the hardware.
                                          Besides, the memory space cannot be free during the lifetime of the serial
                                          manager module. */
    uint32_t ringBufferSize;         /*!< The size of the ring buffer */
#if (defined(OSA_USED) && !(defined(SERIAL_MANAGER_USE_COMMON_TASK) && (SERIAL_MANAGER_USE_COMMON_TASK > 0U)))
    osa_task_def_t *serialTaskConfig;  /*!< Serial manager task configuration, can be defined the serial manager 
                                            task configuration for this instance, if serialTaskConfig is NULL, will use the 
                                            default serial manager configure provided by serial manger module.*/
#endif
#endif
    serial_port_type_t type;         /*!< Serial port type */
    serial_manager_type_t blockType; /*!< Serial manager port type */
    void *portConfig;                /*!< Serial port configuration */
} serial_manager_config_t;

/*! @brief serial manager error code*/
typedef enum _serial_manager_status
{
    kStatus_SerialManager_Success = kStatus_Success,                            /*!< Success */
    kStatus_SerialManager_Error   = MAKE_STATUS(kStatusGroup_SERIALMANAGER, 1), /*!< Failed */
    kStatus_SerialManager_Busy    = MAKE_STATUS(kStatusGroup_SERIALMANAGER, 2), /*!< Busy */
    kStatus_SerialManager_Notify  = MAKE_STATUS(kStatusGroup_SERIALMANAGER, 3), /*!< Ring buffer is not empty */
    kStatus_SerialManager_Canceled =
        MAKE_STATUS(kStatusGroup_SERIALMANAGER, 4), /*!< the non-blocking request is canceled */
    kStatus_SerialManager_HandleConflict = MAKE_STATUS(kStatusGroup_SERIALMANAGER, 5), /*!< The handle is opened */
    kStatus_SerialManager_RingBufferOverflow =
        MAKE_STATUS(kStatusGroup_SERIALMANAGER, 6), /*!< The ring buffer is overflowed */
    kStatus_SerialManager_NotConnected = MAKE_STATUS(kStatusGroup_SERIALMANAGER, 7), /*!< The host is not connected */
} serial_manager_status_t;

/*! @brief Callback message structure */
typedef struct _serial_manager_callback_message
{
    uint8_t *buffer; /*!< Transferred buffer */
    uint32_t length; /*!< Transferred data length */
} serial_manager_callback_message_t;

/*! @brief serial manager callback function */
typedef void (*serial_manager_callback_t)(void *callbackParam,
                                          serial_manager_callback_message_t *message,
                                          serial_manager_status_t status);

/*! @brief serial manager Lowpower Critical callback function */
typedef int32_t (*serial_manager_lowpower_critical_callback_t)(int32_t power_mode);
typedef struct _serial_manager_lowpower_critical_CBs_t
{
    serial_manager_lowpower_critical_callback_t serialEnterLowpowerCriticalFunc;
    serial_manager_lowpower_critical_callback_t serialExitLowpowerCriticalFunc;
} serial_manager_lowpower_critical_CBs_t;
/*******************************************************************************
 * API
 ******************************************************************************/

#if defined(__cplusplus)
extern "C" {
#endif /* _cplusplus */

/*!
 * @brief Initializes a serial manager module with the serial manager handle and the user configuration structure.
 *
 * This function configures the Serial Manager module with user-defined settings.
 * The user can configure the configuration structure.
 * The parameter serialHandle is a pointer to point to a memory space of size #SERIAL_MANAGER_HANDLE_SIZE
 * allocated by the caller.
 * The Serial Manager module supports three types of serial port, UART (includes UART, USART, LPSCI, LPUART, etc), USB
 * CDC and swo.
 * Please refer to #serial_port_type_t for serial port setting.
 * These three types can be set by using #serial_manager_config_t.
 *
 * Example below shows how to use this API to configure the Serial Manager.
 * For UART,
 *  @code
 *   #define SERIAL_MANAGER_RING_BUFFER_SIZE (256U)
 *   static SERIAL_MANAGER_HANDLE_DEFINE(s_serialHandle);
 *   static uint8_t s_ringBuffer[SERIAL_MANAGER_RING_BUFFER_SIZE];
 *
 *   serial_manager_config_t config;
 *   serial_port_uart_config_t uartConfig;
 *   config.type = kSerialPort_Uart;
 *   config.ringBuffer = &s_ringBuffer[0];
 *   config.ringBufferSize = SERIAL_MANAGER_RING_BUFFER_SIZE;
 *   uartConfig.instance = 0;
 *   uartConfig.clockRate = 24000000;
 *   uartConfig.baudRate = 115200;
 *   uartConfig.parityMode = kSerialManager_UartParityDisabled;
 *   uartConfig.stopBitCount = kSerialManager_UartOneStopBit;
 *   uartConfig.enableRx = 1;
 *   uartConfig.enableTx = 1;
 *   uartConfig.enableRxRTS = 0;
 *   uartConfig.enableTxCTS = 0;
 *   config.portConfig = &uartConfig;
 *   SerialManager_Init((serial_handle_t)s_serialHandle, &config);
 *  @endcode
 * For USB CDC,
 *  @code
 *   #define SERIAL_MANAGER_RING_BUFFER_SIZE (256U)
 *   static SERIAL_MANAGER_HANDLE_DEFINE(s_serialHandle);
 *   static uint8_t s_ringBuffer[SERIAL_MANAGER_RING_BUFFER_SIZE];
 *
 *   serial_manager_config_t config;
 *   serial_port_usb_cdc_config_t usbCdcConfig;
 *   config.type = kSerialPort_UsbCdc;
 *   config.ringBuffer = &s_ringBuffer[0];
 *   config.ringBufferSize = SERIAL_MANAGER_RING_BUFFER_SIZE;
 *   usbCdcConfig.controllerIndex = kSerialManager_UsbControllerKhci0;
 *   config.portConfig = &usbCdcConfig;
 *   SerialManager_Init((serial_handle_t)s_serialHandle, &config);
 *  @endcode
 *
 * Example below shows how to use this API to configure the Serial Manager task configuration.
 * For example if user need do specfical configuration(s_os_thread_def_serialmanager)for the
 * serial mananger task,
 *  @code
 *   #define SERIAL_MANAGER_RING_BUFFER_SIZE (256U)
 *   static SERIAL_MANAGER_HANDLE_DEFINE(s_serialHandle);
 *   static uint8_t s_ringBuffer[SERIAL_MANAGER_RING_BUFFER_SIZE];
 *   const osa_task_def_t s_os_thread_def_serialmanager = {
 *       .tpriority = 4,
 *       .instances = 1,
 *       .stacksize = 2048,
 *   };
 *   serial_manager_config_t config;
 *   serial_port_uart_config_t uartConfig;
 *   config.type = kSerialPort_Uart;
 *   config.ringBuffer = &s_ringBuffer[0];
 *   config.ringBufferSize = SERIAL_MANAGER_RING_BUFFER_SIZE;
 *   config.serialTaskConfig = (osa_task_def_t *)&s_os_thread_def_serialmanager,
 *   uartConfig.instance = 0;
 *   uartConfig.clockRate = 24000000;
 *   uartConfig.baudRate = 115200;
 *   uartConfig.parityMode = kSerialManager_UartParityDisabled;
 *   uartConfig.stopBitCount = kSerialManager_UartOneStopBit;
 *   uartConfig.enableRx = 1;
 *   uartConfig.enableTx = 1;
 *   uartConfig.enableRxRTS = 0;
 *   uartConfig.enableTxCTS = 0;
 *   config.portConfig = &uartConfig;
 *   SerialManager_Init((serial_handle_t)s_serialHandle, &config);
 *  @endcode
 * @param serialHandle Pointer to point to a memory space of size #SERIAL_MANAGER_HANDLE_SIZE allocated by the caller.
 * The handle should be 4 byte aligned, because unaligned access doesn't be supported on some devices.
 * You can define the handle in the following two ways:
 * #SERIAL_MANAGER_HANDLE_DEFINE(serialHandle);
 * or
 * uint32_t serialHandle[((SERIAL_MANAGER_HANDLE_SIZE + sizeof(uint32_t) - 1U) / sizeof(uint32_t))];
 * @param serialConfig Pointer to user-defined configuration structure.
 * @retval kStatus_SerialManager_Error An error occurred.
 * @retval kStatus_SerialManager_Success The Serial Manager module initialization succeed.
 */
serial_manager_status_t SerialManager_Init(serial_handle_t serialHandle, const serial_manager_config_t *serialConfig);

/*!
 * @brief De-initializes the serial manager module instance.
 *
 * This function de-initializes the serial manager module instance. If the opened writing or
 * reading handle is not closed, the function will return kStatus_SerialManager_Busy.
 *
 * @param serialHandle The serial manager module handle pointer.
 * @retval kStatus_SerialManager_Success The serial manager de-initialization succeed.
 * @retval kStatus_SerialManager_Busy Opened reading or writing handle is not closed.
 */
serial_manager_status_t SerialManager_Deinit(serial_handle_t serialHandle);

/*!
 * @brief Opens a writing handle for the serial manager module.
 *
 * This function Opens a writing handle for the serial manager module. If the serial manager needs to
 * be used in different tasks, the task should open a dedicated write handle for itself by calling
 * #SerialManager_OpenWriteHandle. Since there can only one buffer for transmission for the writing
 * handle at the same time, multiple writing handles need to be opened when the multiple transmission
 * is needed for a task.
 *
 * @param serialHandle The serial manager module handle pointer.
 * The handle should be 4 byte aligned, because unaligned access doesn't be supported on some devices.
 * @param writeHandle The serial manager module writing handle pointer.
 * The handle should be 4 byte aligned, because unaligned access doesn't be supported on some devices.
 * You can define the handle in the following two ways:
 * #SERIAL_MANAGER_WRITE_HANDLE_DEFINE(writeHandle);
 * or
 * uint32_t writeHandle[((SERIAL_MANAGER_WRITE_HANDLE_SIZE + sizeof(uint32_t) - 1U) / sizeof(uint32_t))];
 * @retval kStatus_SerialManager_Error An error occurred.
 * @retval kStatus_SerialManager_HandleConflict The writing handle was opened.
 * @retval kStatus_SerialManager_Success The writing handle is opened.
 *
 * Example below shows how to use this API to write data.
 * For task 1,
 *  @code
 *   static SERIAL_MANAGER_WRITE_HANDLE_DEFINE(s_serialWriteHandle1);
 *   static uint8_t s_nonBlockingWelcome1[] = "This is non-blocking writing log for task1!\r\n";
 *   SerialManager_OpenWriteHandle((serial_handle_t)serialHandle, (serial_write_handle_t)s_serialWriteHandle1);
 *   SerialManager_InstallTxCallback((serial_write_handle_t)s_serialWriteHandle1,
 *                                    Task1_SerialManagerTxCallback,
 *                                    s_serialWriteHandle1);
 *   SerialManager_WriteNonBlocking((serial_write_handle_t)s_serialWriteHandle1,
 *                                   s_nonBlockingWelcome1,
 *                                   sizeof(s_nonBlockingWelcome1) - 1U);
 *  @endcode
 * For task 2,
 *  @code
 *   static SERIAL_MANAGER_WRITE_HANDLE_DEFINE(s_serialWriteHandle2);
 *   static uint8_t s_nonBlockingWelcome2[] = "This is non-blocking writing log for task2!\r\n";
 *   SerialManager_OpenWriteHandle((serial_handle_t)serialHandle, (serial_write_handle_t)s_serialWriteHandle2);
 *   SerialManager_InstallTxCallback((serial_write_handle_t)s_serialWriteHandle2,
 *                                    Task2_SerialManagerTxCallback,
 *                                    s_serialWriteHandle2);
 *   SerialManager_WriteNonBlocking((serial_write_handle_t)s_serialWriteHandle2,
 *                                   s_nonBlockingWelcome2,
 *                                   sizeof(s_nonBlockingWelcome2) - 1U);
 *  @endcode
 */
serial_manager_status_t SerialManager_OpenWriteHandle(serial_handle_t serialHandle, serial_write_handle_t writeHandle);

/*!
 * @brief Closes a writing handle for the serial manager module.
 *
 * This function Closes a writing handle for the serial manager module.
 *
 * @param writeHandle The serial manager module writing handle pointer.
 * @retval kStatus_SerialManager_Success The writing handle is closed.
 */
serial_manager_status_t SerialManager_CloseWriteHandle(serial_write_handle_t writeHandle);

/*!
 * @brief Opens a reading handle for the serial manager module.
 *
 * This function Opens a reading handle for the serial manager module. The reading handle can not be
 * opened multiple at the same time. The error code kStatus_SerialManager_Busy would be returned when
 * the previous reading handle is not closed. And there can only be one buffer for receiving for the
 * reading handle at the same time.
 *
 * @param serialHandle The serial manager module handle pointer.
 * The handle should be 4 byte aligned, because unaligned access doesn't be supported on some devices.
 * @param readHandle The serial manager module reading handle pointer.
 * The handle should be 4 byte aligned, because unaligned access doesn't be supported on some devices.
 * You can define the handle in the following two ways:
 * #SERIAL_MANAGER_READ_HANDLE_DEFINE(readHandle);
 * or
 * uint32_t readHandle[((SERIAL_MANAGER_READ_HANDLE_SIZE + sizeof(uint32_t) - 1U) / sizeof(uint32_t))];
 * @retval kStatus_SerialManager_Error An error occurred.
 * @retval kStatus_SerialManager_Success The reading handle is opened.
 * @retval kStatus_SerialManager_Busy Previous reading handle is not closed.
 *
 * Example below shows how to use this API to read data.
 *  @code
 *   static SERIAL_MANAGER_READ_HANDLE_DEFINE(s_serialReadHandle);
 *   SerialManager_OpenReadHandle((serial_handle_t)serialHandle, (serial_read_handle_t)s_serialReadHandle);
 *   static uint8_t s_nonBlockingBuffer[64];
 *   SerialManager_InstallRxCallback((serial_read_handle_t)s_serialReadHandle,
 *                                    APP_SerialManagerRxCallback,
 *                                    s_serialReadHandle);
 *   SerialManager_ReadNonBlocking((serial_read_handle_t)s_serialReadHandle,
 *                                  s_nonBlockingBuffer,
 *                                  sizeof(s_nonBlockingBuffer));
 *  @endcode
 */
serial_manager_status_t SerialManager_OpenReadHandle(serial_handle_t serialHandle, serial_read_handle_t readHandle);

/*!
 * @brief Closes a reading for the serial manager module.
 *
 * This function Closes a reading for the serial manager module.
 *
 * @param readHandle The serial manager module reading handle pointer.
 * @retval kStatus_SerialManager_Success The reading handle is closed.
 */
serial_manager_status_t SerialManager_CloseReadHandle(serial_read_handle_t readHandle);

/*!
 * @brief Transmits data with the blocking mode.
 *
 * This is a blocking function, which polls the sending queue, waits for the sending queue to be empty.
 * This function sends data using an interrupt method. The interrupt of the hardware could not be disabled.
 * And There can only one buffer for transmission for the writing handle at the same time.
 *
 * @note The function #SerialManager_WriteBlocking and the function SerialManager_WriteNonBlocking
 * cannot be used at the same time.
 * And, the function SerialManager_CancelWriting cannot be used to abort the transmission of this function.
 *
 * @param writeHandle The serial manager module handle pointer.
 * @param buffer Start address of the data to write.
 * @param length Length of the data to write.
 * @retval kStatus_SerialManager_Success Successfully sent all data.
 * @retval kStatus_SerialManager_Busy Previous transmission still not finished; data not all sent yet.
 * @retval kStatus_SerialManager_Error An error occurred.
 */
serial_manager_status_t SerialManager_WriteBlocking(serial_write_handle_t writeHandle,
                                                    uint8_t *buffer,
                                                    uint32_t length);

/*!
 * @brief Reads data with the blocking mode.
 *
 * This is a blocking function, which polls the receiving buffer, waits for the receiving buffer to be full.
 * This function receives data using an interrupt method. The interrupt of the hardware could not be disabled.
 * And There can only one buffer for receiving for the reading handle at the same time.
 *
 * @note The function #SerialManager_ReadBlocking and the function SerialManager_ReadNonBlocking
 * cannot be used at the same time.
 * And, the function SerialManager_CancelReading cannot be used to abort the transmission of this function.
 *
 * @param readHandle The serial manager module handle pointer.
 * @param buffer Start address of the data to store the received data.
 * @param length The length of the data to be received.
 * @retval kStatus_SerialManager_Success Successfully received all data.
 * @retval kStatus_SerialManager_Busy Previous transmission still not finished; data not all received yet.
 * @retval kStatus_SerialManager_Error An error occurred.
 */
serial_manager_status_t SerialManager_ReadBlocking(serial_read_handle_t readHandle, uint8_t *buffer, uint32_t length);

#if (defined(SERIAL_MANAGER_NON_BLOCKING_MODE) && (SERIAL_MANAGER_NON_BLOCKING_MODE > 0U))
/*!
 * @brief Transmits data with the non-blocking mode.
 *
 * This is a non-blocking function, which returns directly without waiting for all data to be sent.
 * When all data is sent, the module notifies the upper layer through a TX callback function and passes
 * the status parameter @ref kStatus_SerialManager_Success.
 * This function sends data using an interrupt method. The interrupt of the hardware could not be disabled.
 * And There can only one buffer for transmission for the writing handle at the same time.
 *
 * @note The function #SerialManager_WriteBlocking and the function #SerialManager_WriteNonBlocking
 * cannot be used at the same time. And, the TX callback is mandatory before the function could be used.
 *
 * @param writeHandle The serial manager module handle pointer.
 * @param buffer Start address of the data to write.
 * @param length Length of the data to write.
 * @retval kStatus_SerialManager_Success Successfully sent all data.
 * @retval kStatus_SerialManager_Busy Previous transmission still not finished; data not all sent yet.
 * @retval kStatus_SerialManager_Error An error occurred.
 */
serial_manager_status_t SerialManager_WriteNonBlocking(serial_write_handle_t writeHandle,
                                                       uint8_t *buffer,
                                                       uint32_t length);

/*!
 * @brief Reads data with the non-blocking mode.
 *
 * This is a non-blocking function, which returns directly without waiting for all data to be received.
 * When all data is received, the module driver notifies the upper layer
 * through a RX callback function and passes the status parameter @ref kStatus_SerialManager_Success.
 * This function receives data using an interrupt method. The interrupt of the hardware could not be disabled.
 * And There can only one buffer for receiving for the reading handle at the same time.
 *
 * @note The function #SerialManager_ReadBlocking and the function #SerialManager_ReadNonBlocking
 * cannot be used at the same time. And, the RX callback is mandatory before the function could be used.
 *
 * @param readHandle The serial manager module handle pointer.
 * @param buffer Start address of the data to store the received data.
 * @param length The length of the data to be received.
 * @retval kStatus_SerialManager_Success Successfully received all data.
 * @retval kStatus_SerialManager_Busy Previous transmission still not finished; data not all received yet.
 * @retval kStatus_SerialManager_Error An error occurred.
 */
serial_manager_status_t SerialManager_ReadNonBlocking(serial_read_handle_t readHandle,
                                                      uint8_t *buffer,
                                                      uint32_t length);

/*!
 * @brief Tries to read data.
 *
 * The function tries to read data from internal ring buffer. If the ring buffer is not empty, the data will be
 * copied from ring buffer to up layer buffer. The copied length is the minimum of the ring buffer and up layer length.
 * After the data is copied, the actual data length is passed by the parameter length.
 * And There can only one buffer for receiving for the reading handle at the same time.
 *
 * @param readHandle The serial manager module handle pointer.
 * @param buffer Start address of the data to store the received data.
 * @param length The length of the data to be received.
 * @param receivedLength Length received from the ring buffer directly.
 * @retval kStatus_SerialManager_Success Successfully received all data.
 * @retval kStatus_SerialManager_Busy Previous transmission still not finished; data not all received yet.
 * @retval kStatus_SerialManager_Error An error occurred.
 */
serial_manager_status_t SerialManager_TryRead(serial_read_handle_t readHandle,
                                              uint8_t *buffer,
                                              uint32_t length,
                                              uint32_t *receivedLength);

/*!
 * @brief Cancels unfinished send transmission.
 *
 * The function cancels unfinished send transmission. When the transfer is canceled, the module notifies the upper layer
 * through a TX callback function and passes the status parameter @ref kStatus_SerialManager_Canceled.
 *
 * @note The function #SerialManager_CancelWriting cannot be used to abort the transmission of
 * the function #SerialManager_WriteBlocking.
 *
 * @param writeHandle The serial manager module handle pointer.
 * @retval kStatus_SerialManager_Success Get successfully abort the sending.
 * @retval kStatus_SerialManager_Error An error occurred.
 */
serial_manager_status_t SerialManager_CancelWriting(serial_write_handle_t writeHandle);

/*!
 * @brief Cancels unfinished receive transmission.
 *
 * The function cancels unfinished receive transmission. When the transfer is canceled, the module notifies the upper
 * layer
 * through a RX callback function and passes the status parameter @ref kStatus_SerialManager_Canceled.
 *
 * @note The function #SerialManager_CancelReading cannot be used to abort the transmission of
 * the function #SerialManager_ReadBlocking.
 *
 * @param readHandle The serial manager module handle pointer.
 * @retval kStatus_SerialManager_Success Get successfully abort the receiving.
 * @retval kStatus_SerialManager_Error An error occurred.
 */
serial_manager_status_t SerialManager_CancelReading(serial_read_handle_t readHandle);

/*!
 * @brief Installs a TX callback and callback parameter.
 *
 * This function is used to install the TX callback and callback parameter for the serial manager module.
 * When any status of TX transmission changed, the driver will notify the upper layer by the installed callback
 * function. And the status is also passed as status parameter when the callback is called.
 *
 * @param writeHandle The serial manager module handle pointer.
 * @param callback The callback function.
 * @param callbackParam The parameter of the callback function.
 * @retval kStatus_SerialManager_Success Successfully install the callback.
 */
serial_manager_status_t SerialManager_InstallTxCallback(serial_write_handle_t writeHandle,
                                                        serial_manager_callback_t callback,
                                                        void *callbackParam);

/*!
 * @brief Installs a RX callback and callback parameter.
 *
 * This function is used to install the RX callback and callback parameter for the serial manager module.
 * When any status of RX transmission changed, the driver will notify the upper layer by the installed callback
 * function. And the status is also passed as status parameter when the callback is called.
 *
 * @param readHandle The serial manager module handle pointer.
 * @param callback The callback function.
 * @param callbackParam The parameter of the callback function.
 * @retval kStatus_SerialManager_Success Successfully install the callback.
 */
serial_manager_status_t SerialManager_InstallRxCallback(serial_read_handle_t readHandle,
                                                        serial_manager_callback_t callback,
                                                        void *callbackParam);

/*!
 * @brief Check if need polling ISR.
 *
 * This function is used to check if need polling ISR.
 *
 * @retval TRUE if need polling.
 */
static inline bool SerialManager_needPollingIsr(void)
{
#if (defined(__DSC__) && defined(__CW__))
    return !(isIRQAllowed());
#elif defined(CPSR_M_Msk)
    return (0x13 == (__get_CPSR() & CPSR_M_Msk));
#elif defined(DAIF_I_BIT)
    return (__get_DAIF() & DAIF_I_BIT);
#elif defined(__XCC__)
    return (xthal_get_interrupt() & xthal_get_intenable());
#else
    return (0U != __get_IPSR());
#endif
}
#endif

/*!
 * @brief Prepares to enter low power consumption.
 *
 * This function is used to prepare to enter low power consumption.
 *
 * @param serialHandle The serial manager module handle pointer.
 * @retval kStatus_SerialManager_Success Successful operation.
 */
serial_manager_status_t SerialManager_EnterLowpower(serial_handle_t serialHandle);

/*!
 * @brief Restores from low power consumption.
 *
 * This function is used to restore from low power consumption.
 *
 * @param serialHandle The serial manager module handle pointer.
 * @retval kStatus_SerialManager_Success Successful operation.
 */
serial_manager_status_t SerialManager_ExitLowpower(serial_handle_t serialHandle);

/*!
 * @brief This function performs initialization of the callbacks structure used to disable lowpower
 *          when serial manager is active.
 *
 *
 * @param  pfCallback Pointer to the function structure used to allow/disable lowpower.
 *
 */
void SerialManager_SetLowpowerCriticalCb(const serial_manager_lowpower_critical_CBs_t *pfCallback);

#if defined(__cplusplus)
}
#endif
/*! @} */
#endif /* __SERIAL_MANAGER_H__ */
