/*
  ******************************************************************************
  * @file    HAL_LPUART.c
  * @version V1.0.0
  * @date    2020
  * @brief   LPUART HAL module driver.
  *          This file provides firmware functions to manage the following
  *          functionalities of the Universal Asynchronous Receiver Transmitter Peripheral (LPUART).
  *           @ Initialization and de-initialization functions
  *           @ IO operation functions
  *           @ Peripheral Control functions
  ******************************************************************************
*/
#include "ACM32Fxx_HAL.h"

/*********************************************************************************
* Function    : HAL_LPUART_IRQHander
* Description : LPUART IRQHander 
* Input       : 
* Outpu       : 
* Author      :                          Data : 2024Äê
**********************************************************************************/ 
void HAL_LPUART_IRQHander(LPUART_HandleTypeDef *hlpuart)  
{
    volatile uint32_t ie = hlpuart->Instance->IE & ((1 << LPUART_IE_RX_INDEX) | (1 << LPUART_IE_TX_EMPTY_INDEX) | (1 << LPUART_IE_TX_FINISH_INDEX));
    
    if (ie & (hlpuart->Instance->SR) & (1U << LPUART_SR_RX_INDEX))        
    {
        if(hlpuart->rx_read_index != (((hlpuart->rx_write_index) + 1)% (hlpuart->rx_buffer_size) ) )     
        {
            hlpuart->rx_buffer[hlpuart->rx_write_index] = hlpuart->Instance->RXDR;   
            hlpuart->rx_write_index = ((hlpuart->rx_write_index + 1)%(hlpuart->rx_buffer_size) );        
        }
        else
        {
            hlpuart->Instance->SR = (1U << LPUART_SR_RX_INDEX);  // buffer overflow  
            return;  
        }
    }
    
    if (ie & (hlpuart->Instance->SR) & (1U << LPUART_SR_TX_EMPTY_INDEX))
    {
        if(hlpuart->tx_size--)
        {
            hlpuart->Instance->TXDR = *hlpuart->tx_buffer++;
        }
        else
        {
            hlpuart->Instance->IE &= ~(1U << LPUART_IE_TX_EMPTY_INDEX);
            hlpuart->Instance->IE |= (1U << LPUART_IE_TX_FINISH_INDEX);
        }
    }
    else if(ie & (hlpuart->Instance->SR) & (1U << LPUART_SR_TX_FINISH_INDEX))
    {
        hlpuart->Instance->IE &= ~(1U << LPUART_IE_TX_FINISH_INDEX);
        if (hlpuart->TxCpltCallback)
        {
            hlpuart->TxCpltCallback(hlpuart);
        }
    }
        
}
/************************************************************************
 * function   : HAL_UART_Buffer_Init
 * Description: uart buffer initiation.  
 * input : 
 *         UART_HandleTypeDef *huart: pointer to uart handle structure
 * return: 0: FAIL; 1: SUCCESS 
 ************************************************************************/
HAL_StatusTypeDef HAL_LPUART_Buffer_Init(LPUART_HandleTypeDef *hlpuart) 
{
    if(0x00 == IS_LPUART_INSTANCE(hlpuart->Instance))
    {
        return HAL_ERROR;  
    }
    hlpuart->rx_read_index = 0;
    hlpuart->rx_write_index = 0;
    hlpuart->tx_busy = 0;  
    return HAL_OK;  
}

/**********************************************************************************
 * function   : HAL_LPUART_MSPInit  
 * Description: UART MCU specific initiation, such as IO share, module clock, ...  
 * input : 
 *         UART_HandleTypeDef *huart: pointer to uart handle structure
 * return: 0: FAIL; 1: SUCCESS 
 ***************************************************************************************/ 
 
__weak void HAL_LPUART_MSPInit(LPUART_HandleTypeDef *hlpuart) 
{ 
    GPIO_InitTypeDef gpio_init; 
    System_Module_Enable(EN_GPIOAB);
    System_Module_Reset(RST_LPUART); 
    gpio_init.Pin = GPIO_PIN_10|GPIO_PIN_11;
    gpio_init.Mode = GPIO_MODE_AF_PP;   
    gpio_init.Pull = GPIO_PULLUP;   
    gpio_init.Alternate = GPIO_FUNCTION_1;  
    HAL_GPIO_Init(GPIOB,&gpio_init);   
    System_Module_Enable(EN_LPUART);  
}

/*********************************************************************************
* Function    : HAL_LPUART_MspDeInit
* Description :	LPUART MSP De-Initialization 
*               This function frees the hardware resources used in this example:
*              - Disable the Peripheral's clock
*              - Revert GPIO configuration to their default state
* Input       : hcan : pointer to a CAN_HandleTypeDef structure that contains
*                      the configuration information for CAN module
* Output      : 
* Author      : CWT                         Data : 2020Äê
**********************************************************************************/
void HAL_LPUART_MspDeInit(LPUART_HandleTypeDef *hlpuart)
{  	
    HAL_GPIO_DeInit(GPIOB, GPIO_PIN_10);
    HAL_GPIO_DeInit(GPIOB, GPIO_PIN_11);
}
/**********************************************************************************
 * function   : HAL_LPUART_Set_Baud_Rate
 * Description: set uart module's baud rate. It should be set when UART is disabled. 
 * input : 
 *         UART_HandleTypeDef *huart: pointer to uart handle structure
 * return: 0: FAIL; 1: SUCCESS 
 ***************************************************************************************/ 
uint8_t HAL_LPUART_Set_Baud_Rate(LPUART_HandleTypeDef *hlpuart, uint32_t lpuart_clk, uint32_t baud_rate)
{
    uint32_t ibaud, fbaud, rxsamp;   

    if(0x00 == IS_LPUART_INSTANCE(hlpuart->Instance))   
    {
        return 0;  
    }
    ibaud = 2;
    fbaud = 0x952;   
    rxsamp = 1;    
    switch(lpuart_clk)  
    {
        case 32000:
        case 32768: 
        switch(baud_rate) 
        {
        case 9600:
        ibaud = 2;
        fbaud = 0x952; 
//         ibaud = 2;
//        fbaud = 0xA44; 
        break;

        case 4800: 
        ibaud = 5;
        fbaud = 0xefb;    
        break;

        case 2400: 
        ibaud = 12;
        fbaud = 0x6db;   
        break;

        case 1200: 
        ibaud = 26;
        fbaud = 0x492;   
        break;   
        default: 
        ibaud = 2;
        fbaud = 0x952; 
        break;  
        }
        rxsamp = ibaud >> 1;    
        break; 

   	default: 
		switch(baud_rate) 
		{
			case 115200:  
			ibaud = 16;  
			fbaud = 0x924;  
			break;
			
			case 9600:
			ibaud = 203;  
			fbaud = 0x888;  
			break;
		}
        rxsamp = ibaud >> 1;    
        break;  
    } 
    hlpuart->Instance->IBAUD = ibaud | (rxsamp << 8); 
    hlpuart->Instance->FBAUD = fbaud;  
    return 1;   
}

/************************************************************************
 * function   : HAL_LPUART_Config
 * Description: Configure UART module parameters, such as baudrate, parity, 
 *              stop bits, dataword. 
 * input : 
 *         UART_HandleTypeDef *huart: pointer to uart handle structure
 * return: 0: FAIL; 1: SUCCESS  
 ************************************************************************/
uint8_t HAL_LPUART_Config(LPUART_HandleTypeDef *hlpuart)  
{   
    volatile uint32_t temp_reg;
    if(0x00 == IS_LPUART_INSTANCE(hlpuart->Instance)) 
    {
        return 0;  
    }
    temp_reg = 1U << 7; // default value  
    temp_reg |= ((hlpuart->ConfigParam.WordLength << 4) | (hlpuart->ConfigParam.StopBits << 3));
    switch(hlpuart->ConfigParam.Parity)
    {
        case LPUART_PARITY_NONE:
        break;  // do nothing 

        case LPUART_PARITY_SELECT_ODD:
        case LPUART_PARITY_SELECT_EVEN:
        temp_reg |= (((hlpuart->ConfigParam.Parity - LPUART_PARITY_SELECT_ODD) << LPUART_EPS_INDEX) | (1 << LPUART_PEN_INDEX));    
        break;  

        case LPUART_PARITY_SELECT_ONE:
        case LPUART_PARITY_SELECT_ZERO: 
        temp_reg |= (((hlpuart->ConfigParam.Parity - LPUART_PARITY_SELECT_ONE) << LPUART_EPS_INDEX) | (1 << LPUART_SPS_INDEX) | (1 << LPUART_PEN_INDEX) );    
        break;
    }
    hlpuart->Instance->LCR = temp_reg;  
    return 1;  
}

/*********************************************************************************
* Function    : LPUART_Clock_Select
* Description : Select the LPUART clock. 
* Input       : lpuart_clk_src:Could be LPUART_CLOCK_SOURCE_RC32K        LPUART_CLOCK_SOURCE_XTAL       LPUART_CLOCK_SOURCE_PLL_DIV
* Outpu       : 
* Author      : CWT                         Data : 2020Äê
**********************************************************************************/ 
void LPUART_Clock_Select(uint8_t lpuart_clk_src)
{
    if (0 == lpuart_clk_src)
    {
        SCU->CCR2 &= (~(BIT13 | BIT14) );     // RC32K 
    }
    else if (1 == lpuart_clk_src) 
    {
        SCU->CCR2 = (SCU->CCR2 & (~(BIT13 | BIT14) )) | (BIT13);     // XTAL 
    }
    else
    {
        SCU->CCR2 = (SCU->CCR2 & (~(BIT11 | BIT12| BIT13 | BIT14) )) | (BIT11 | BIT12 | BIT14);  // pclk/32          
    }
}

/******************************************************************************
*@brief : Register a User LPUART Callback.
*@param : hlpuart: pointer to a LPUART_HandleTypeDef structure that contains
*                  the configuration information for LPUART module.
*@param : id: ID of the callback to be registered
*             This parameter can be a combination of @ref LPUART_CallbackID.
*             @arg LPUART_CALLBACKID_TXCPLT     : transfer completion callback function.
*             @arg LPUART_CALLBACKID_TXHALFCPLT : transfer half completion callback function.
*             @arg LPUART_CALLBACKID_TXERROR    : transfer error callback function.
*             @arg LPUART_CALLBACKID_RXCPLT     : receive completion callback function.
*             @arg LPUART_CALLBACKID_RXHALFCPLT : receive half completion callback function.
*             @arg LPUART_CALLBACKID_RXERROR    : receive error callback function.
*             @arg LPUART_CALLBACKID_WAKEUP     : wakeup callback function.
*@param : pCallback: pointer to the Callback function.
*@return: HAL status
******************************************************************************/
HAL_StatusTypeDef HAL_LPUART_RegisterCallback(LPUART_HandleTypeDef *hlpuart, uint32_t id, pLPUART_CallbackTypeDef pCallback)
{
    if(0x00 == IS_LPUART_INSTANCE(hlpuart->Instance)) 
    {
        return HAL_ERROR;;  
    }
    
	switch (id)
	{
		case  LPUART_CALLBACKID_TXCPLT:
			
			hlpuart->TxCpltCallback = pCallback;
			break;

		case  LPUART_CALLBACKID_TXHALFCPLT:
			
			hlpuart->TxHalfCpltCallback = pCallback;
			break;

		case  LPUART_CALLBACKID_TXERROR:
			
			hlpuart->TxErrorCallback = pCallback;
			break;

		case  LPUART_CALLBACKID_RXCPLT:
			
			hlpuart->RxCpltCallback = pCallback;
			break;

		case  LPUART_CALLBACKID_RXHALFCPLT:
			
			hlpuart->RxHalfCpltCallback = pCallback;
			break;

		case  LPUART_CALLBACKID_RXERROR:
			
			hlpuart->RxErrorCallback = pCallback;
			break;

		case  LPUART_CALLBACKID_WAKEUP:
			
			hlpuart->WakeupCallback = pCallback;
			break;

		default:
			return HAL_ERROR;
	}
	return HAL_OK;
}


/******************************************************************************
*@brief : Unregister a User LPUART Callback.
*@param : hlpuart: pointer to a LPUART_HandleTypeDef structure that contains
*                  the configuration information for LPUART module.
*@param : id: ID of the callback to be registered
*             This parameter can be a combination of @ref LPUART_CallbackID.
*             @arg LPUART_CALLBACK_ID_TX_CPLT: transfer completion callback function.
*             @arg LPUART_CALLBACK_ID_RX_CPLT: receive completion callback function.
*             @arg LPUART_CALLBACK_ID_ERROR: receive error callback function.
*             @arg LPUART_CALLBACK_ID_WAKEUP: wakeup callback function.
*             @arg LPUART_CALLBACK_ID_DMA_TX_CPLT: tx DMA transfer completion callback function.
*             @arg LPUART_CALLBACK_ID_DMA_TX_HALF_CPLT: tx DMA transfer half completion callback function.
*             @arg LPUART_CALLBACK_ID_DMA_TX_ERROR: tx DMA transfer error callback function.
*             @arg LPUART_CALLBACK_ID_DMA_RX_CPLT: rx DMA receive completion callback function.
*             @arg LPUART_CALLBACK_ID_DMA_RX_HALF_CPLT: rx DMA receive half completion callback function.
*             @arg LPUART_CALLBACK_ID_DMA_RX_ERROR: rx DMA receive error callback function.
*@return: HAL status
******************************************************************************/
HAL_StatusTypeDef HAL_LPUART_UnRegisterCallback(LPUART_HandleTypeDef *hlpuart, uint32_t id)
{
    if(0x00 == IS_LPUART_INSTANCE(hlpuart->Instance)) 
    {
        return HAL_ERROR;;  
    }
    
	switch (id)
	{
		case  LPUART_CALLBACKID_TXCPLT:
			
			hlpuart->TxCpltCallback = NULL;
			break;

		case  LPUART_CALLBACKID_TXHALFCPLT:
			
			hlpuart->TxHalfCpltCallback = NULL;
			break;

		case  LPUART_CALLBACKID_TXERROR:
			
			hlpuart->TxErrorCallback = NULL;
			break;

		case  LPUART_CALLBACKID_RXCPLT:
			
			hlpuart->RxCpltCallback = NULL;
			break;

		case  LPUART_CALLBACKID_RXHALFCPLT:
			
			hlpuart->RxHalfCpltCallback = NULL;
			break;

		case  LPUART_CALLBACKID_RXERROR:
			
			hlpuart->RxErrorCallback = NULL;
			break;

		case  LPUART_CALLBACKID_WAKEUP:
			
			hlpuart->WakeupCallback = NULL;
			break;

		default:
			return HAL_ERROR;
	}
	return HAL_OK;
}

/************************************************************************
 * function   : HAL_LPUART_Init
 * Description: uart initial with parameters. 
 * input : 
 *         UART_HandleTypeDef *huart: pointer to uart handle structure
 * return: 0: FAIL; 1: SUCCESS   
 ************************************************************************/
HAL_StatusTypeDef HAL_LPUART_Init(LPUART_HandleTypeDef *hlpuart) 
{  
    uint32_t lpuart_clock;
    if(0x00 == IS_LPUART_INSTANCE(hlpuart->Instance)) 
    {
        return HAL_ERROR;;  
    }

    HAL_LPUART_Buffer_Init(hlpuart);    
    /*reset module, configure tx and rx, enable module clock*/
    HAL_LPUART_MSPInit(hlpuart); 

    if (LPUART_CLOCK_SOURCE_RC32K == hlpuart->ConfigParam.ClockSrc)
    {
        lpuart_clock = 32000;  
        System_Module_Enable(EN_RTC); 
        System_Enable_Disable_RTC_Domain_Access(FUNC_ENABLE);
        System_Enable_RC32K(); 
        LPUART_Clock_Select(0);
    }
    else if (LPUART_CLOCK_SOURCE_XTAL == hlpuart->ConfigParam.ClockSrc)
    {
        lpuart_clock = 32768;  
        System_Module_Enable(EN_RTC); 
       System_Enable_Disable_RTC_Domain_Access(FUNC_ENABLE);
        System_Enable_XTAL();   
        LPUART_Clock_Select(1);
    }
    else
    {
        lpuart_clock = System_Get_APBClock()/32;      
        LPUART_Clock_Select(2);  
    }
    HAL_LPUART_Set_Baud_Rate(hlpuart, lpuart_clock, hlpuart->ConfigParam.BaudRate);    

    HAL_LPUART_Config(hlpuart);     

    hlpuart->Instance->SR = LPUART_SR_BITS_ALL;  

    hlpuart->Instance->CR = (1U << LPUART_CR_RXE_INDEX) | (1 << LPUART_CR_TXE_INDEX);  
    hlpuart->Instance->LCR |=((hlpuart->StopWakeup.Wakeup_Source<<5)|(hlpuart->StopWakeup.Wakeup_Check<<7)); 
    hlpuart->Instance->ADDR=(hlpuart->StopWakeup.Wakeup_Addr);

    return HAL_OK;;  
}
HAL_StatusTypeDef HAL_LPUART_DeInit(LPUART_HandleTypeDef *hlpuart)
{
    /* Check  handle */
    if(!IS_LPUART_INSTANCE(hlpuart->Instance)) return HAL_ERROR;
    HAL_LPUART_MspDeInit(hlpuart);
    /* Disable LPUART clock */
    System_Module_Disable(EN_LPUART);
    /* Return function status */
    return HAL_OK;
}
/************************************************************************
 * function   : HAL_LPUART_Wait_TX_Done
 * Description: wait uart not busy 
 * input : 
 *         UART_HandleTypeDef *huart: pointer to uart handle structure
 * return: 0: FAIL; 1: SUCCESS   
 ************************************************************************/
HAL_StatusTypeDef HAL_LPUART_Wait_TX_Done(LPUART_HandleTypeDef *hlpuart) 
{   
    while (0 == (hlpuart->Instance->SR & (1 << LPUART_SR_TX_FINISH_INDEX) ) ) {};  
    hlpuart->Instance->SR = (1 << LPUART_SR_TX_FINISH_INDEX);     
    return HAL_OK;  
}  

void HAL_LPUART_Output(LPUART_HandleTypeDef *hlpuart, unsigned char c)     
{
    while (0 == (hlpuart->Instance->SR & (1U << LPUART_SR_TX_EMPTY_INDEX)) ) {};  

    hlpuart->Instance->TXDR = c;  

    HAL_LPUART_Wait_TX_Done(hlpuart);   
}

/************************************************************************
 * function   : uart_send_bytes
 * Description: uart send bytes
 * input :
 *         UINT32 uart_index: Serial port number 
 *         UINT8* buff: out buffer
 *         UINT32 length: buffer length
 * return: none
 ************************************************************************/
void HAL_LPUART_Send_Bytes(LPUART_HandleTypeDef *hlpuart, uint8_t *buff, uint32_t length)    
{
    uint32_t i;
    for (i = 0; i < length; i++)
    {
        HAL_LPUART_Output(hlpuart, *buff++);     
    }
}



/************************************************************************
 * function   : uart_send_bytes
 * Description: uart send bytes
 * input :
 *         UINT32 uart_index: Serial port number 
 *         UINT8* buff: out buffer
 *         UINT32 length: buffer length
 * return: none
 ************************************************************************/
void HAL_LPUART_SendIT(LPUART_HandleTypeDef *hlpuart, uint8_t *buff, uint32_t length)    
{
    hlpuart->tx_buffer = buff;
    hlpuart->tx_size = length;
    hlpuart->tx_busy = true;
    hlpuart->Instance->IE = (1U << LPUART_IE_TX_EMPTY_INDEX);
}

/************************************************************************
 * function   : HAL_LPUART_Receive_Bytes_Timeout  
 * Description: uart receive bytes 
 * input : 
 *         UART_HandleTypeDef *huart: pointer to uart handle structure
 *         UINT8* buff: out buffer
 *         UINT32 length: buffer length 
 *         UINT32 ms: number of ms to delay one byte 
 * return: received bytes 
 ************************************************************************/
uint32_t HAL_LPUART_ReceiveIT_Timeout(LPUART_HandleTypeDef *hlpuart, uint8_t * rxbuff, uint32_t length, uint32_t ms)
{
    volatile uint32_t i, timeout, count;;    
    if(0x00 == IS_LPUART_INSTANCE(hlpuart->Instance)) 
    {
        return 0;  
    }

    hlpuart->Instance->IE = (1U << LPUART_IE_RX_INDEX);
    
    NVIC_ClearPendingIRQ(LPUART_IRQn);
    NVIC_EnableIRQ(LPUART_IRQn);  
    
    timeout = (System_Get_APBClock() >> 13) * ms;  
    count = timeout;  
    i = 0;
    while(i < length) 
    {
        if((hlpuart->rx_read_index) != (hlpuart->rx_write_index)) 
        {
            rxbuff[i] = hlpuart->rx_buffer[hlpuart->rx_read_index];  
            hlpuart->rx_read_index = (((hlpuart->rx_read_index) + 1)%(hlpuart->rx_buffer_size) );   
            count = timeout;   
            i++;
        }
        else
        {       
            if (0 == count)//timeout 
            {
                break;  
            }
            else
            {
                count--;  
            }
        }
    }
    return i; 
}

/************************************************************************
 * function   : HAL_LPUART_Receive_Bytes_Timeout  
 * Description: uart receive bytes 
 * input : 
 *         UART_HandleTypeDef *huart: pointer to uart handle structure
 *         UINT8* buff: out buffer
 *         UINT32 length: buffer length 
 *         UINT32 ms: number of ms to delay one byte 
 * return: received bytes 
 ************************************************************************/
uint32_t HAL_LPUART_Receive_Bytes_Timeout(LPUART_HandleTypeDef *hlpuart, uint8_t * rxbuff, uint32_t length, uint32_t ms) 
{
    volatile uint32_t i, timeout, count;;    
#if (USE_FULL_ASSERT == 1)
    if (!IS_LPUART_INSTANCE(hlpuart->Instance))    
    {
        return HAL_ERROR;
    }
#endif
    timeout = (System_Get_APBClock() >> 13) * ms;  
    count = timeout;  
    i = 0;

    while (i < length) 
    {
        if(hlpuart->Instance->SR & (1U << LPUART_SR_RX_INDEX))
        {
            *rxbuff++ = hlpuart->Instance->RXDR;
            count = timeout;
            i++;
        }
        else 
        {
            if (0 == count)//timeout 
            {
                break;  
            }
            else
            {
                count--;  
            }
        }
    }
    
    return i; 
}   

/************************************************************************
 * function   : HAL_LPUART_Receive_Bytes
 * Description: LPUART receive bytes.
 * input : 
 *         UART_HandleTypeDef *huart: pointer to uart handle structure
 *         buff:receive data buff
 *         length:length of buff
 * return:length  
 ************************************************************************/
uint32_t HAL_LPUART_Receive_Bytes(LPUART_HandleTypeDef *hlpuart, uint8_t * rxbuff, uint32_t length) 
{
    volatile uint32_t i, ie_backup;       
    if(0x00 == IS_LPUART_INSTANCE(hlpuart->Instance)) 
    {
        return 0;  
    }
    ie_backup = hlpuart->Instance->IE;   
    hlpuart->Instance->IE = 0;  
    i = 0;
    while(i < length) 
    {
        if( (hlpuart->Instance->SR) & (1U << LPUART_SR_RX_INDEX) ) 
        {
            rxbuff[i] = hlpuart->Instance->RXDR; 
            i++; 
        }
    }
    hlpuart->Instance->IE = ie_backup;    
    return length; 
}   
/************************************************************************
 * function   : HAL_LPUART_DMA_Send_Bytes
 * Description: LPUART send bytes by DMA.
 * input : 
 *         UART_HandleTypeDef *huart: pointer to uart handle structure
 *         buff:send data buff
 *         length:length of buff
 * return:none  
 ************************************************************************/
void HAL_LPUART_DMA_Send_Bytes(LPUART_HandleTypeDef *hlpuart, uint8_t *buff, uint32_t length)    
{
    hlpuart->Instance->CR |= (1U << LPUART_CR_DMA_EN_INDEX);   
    hlpuart->tx_busy = 1;   
    HAL_DMA_Start_IT(hlpuart->dma_tx_handler, (uint32_t)buff, (uint32_t)&hlpuart->Instance->TXDR, length);   
 }   

/************************************************************************
 * function   : HAL_LPUART_Clear_Wakeup_Flags
 * Description: Clear the LPUART STOP wake up flag.
 * input : 
 *         UART_HandleTypeDef *huart: pointer to uart handle structure
 *         Wakeup_Bits:LPUART wakeup flag,could be: LPUART_WAKEUP_RX_BIT    LPUART_WAKEUP_MATCH_BIT    LPUART_WAKEUP_START_BIT
 * return:none  
 ************************************************************************/

void HAL_LPUART_Clear_Wakeup_Flags(LPUART_HandleTypeDef *hlpuart, uint32_t Wakeup_Bits)  
{
    hlpuart->Instance->SR = Wakeup_Bits;   
}


