/** * @brief Send data in interrupt mode * @param hcec: CEC handle. * Function called under interruption only, once * interruptions have been enabled by HAL_CEC_Transmit_IT() * @retval HAL status */ static HAL_StatusTypeDef CEC_Transmit_IT(CEC_HandleTypeDef *hcec) { /* if the IP is already busy or if there is a previous transmission already pending due to arbitration loss */ if ((hcec->State == HAL_CEC_STATE_BUSY_TX) || (__HAL_CEC_GET_TRANSMISSION_START_FLAG(hcec) != RESET)) { /* set state to BUSY TX, in case it wasn't set already (case * of transmission new attempt after arbitration loss) */ if (hcec->State != HAL_CEC_STATE_BUSY_TX) { hcec->State = HAL_CEC_STATE_BUSY_TX; } /* if all data have been sent */ if(hcec->TxXferCount == 0) { /* Disable Peripheral to write CEC_IER register */ __HAL_CEC_DISABLE(hcec); /* Disable the CEC Transmission Interrupts */ __HAL_CEC_DISABLE_IT(hcec, CEC_IER_TXBRIE|CEC_IER_TXENDIE); /* Disable the CEC Transmission Error Interrupts */ __HAL_CEC_DISABLE_IT(hcec, CEC_IER_TX_ALL_ERR); /* Enable the Peripheral */ __HAL_CEC_ENABLE(hcec); __HAL_CEC_CLEAR_FLAG(hcec,CEC_ISR_TXBR|CEC_ISR_TXEND); hcec->State = HAL_CEC_STATE_READY; HAL_CEC_TxCpltCallback(hcec); return HAL_OK; } else { if (hcec->TxXferCount == 1) { /* if this is the last byte transmission, set TX End of Message (TXEOM) bit */ __HAL_CEC_LAST_BYTE_TX_SET(hcec); } /* clear Tx-Byte request flag */ __HAL_CEC_CLEAR_FLAG(hcec,CEC_ISR_TXBR); hcec->Instance->TXDR = *hcec->pTxBuffPtr++; hcec->TxXferCount--; return HAL_OK; } } else { return HAL_BUSY; } }
/** * @brief Send data in interrupt mode * @param hcec: CEC handle. * Function called under interruption only, once * interruptions have been enabled by HAL_CEC_Transmit_IT() * @retval HAL status */ static HAL_StatusTypeDef CEC_Transmit_IT(CEC_HandleTypeDef *hcec) { /* if the IP is already busy or if there is a previous transmission already pending due to arbitration loss */ if((hcec->gState == HAL_CEC_STATE_BUSY_TX) || (__HAL_CEC_GET_TRANSMISSION_START_FLAG(hcec) != RESET)) { /* if all data have been sent */ if(hcec->TxXferCount == 0U) { /* Acknowledge successful completion by writing 0x00 */ MODIFY_REG(hcec->Instance->CSR, CEC_FLAG_TRANSMIT_MASK, 0x00U); hcec->gState = HAL_CEC_STATE_READY; HAL_CEC_TxCpltCallback(hcec); return HAL_OK; } else { /* Reduce the number of bytes to transfer by one */ hcec->TxXferCount--; /* Write data to TX buffer*/ hcec->Instance->TXD = *hcec->pTxBuffPtr++; /* If this is the last byte of the ongoing transmission */ if(hcec->TxXferCount == 0U) { /* Acknowledge byte request and signal end of message */ MODIFY_REG(hcec->Instance->CSR, CEC_FLAG_TRANSMIT_MASK, CEC_FLAG_TEOM); } else { /* Acknowledge byte request by writing 0x00 */ MODIFY_REG(hcec->Instance->CSR, CEC_FLAG_TRANSMIT_MASK, 0x00U); } return HAL_OK; } } else { return HAL_BUSY; } }
/** * @brief Send data in interrupt mode * @param hcec: CEC handle * @param DestinationAddress: destination logical address * @param pData: pointer to input byte data buffer * @param Size: amount of data to be sent in bytes (without counting the header). * 0 means only the header is sent (ping operation). * Maximum TX size is 15 bytes (1 opcode and up to 14 operands). * @retval HAL status */ HAL_StatusTypeDef HAL_CEC_Transmit_IT(CEC_HandleTypeDef *hcec, uint8_t DestinationAddress, uint8_t *pData, uint32_t Size) { uint8_t temp = 0; /* if the IP isn't already busy and if there is no previous transmission already pending due to arbitration lost */ if (((hcec->State == HAL_CEC_STATE_READY) || (hcec->State == HAL_CEC_STATE_STANDBY_RX)) && (__HAL_CEC_GET_TRANSMISSION_START_FLAG(hcec) == RESET)) { if((pData == NULL ) && (Size > 0)) { hcec->State = HAL_CEC_STATE_ERROR; return HAL_ERROR; } assert_param(IS_CEC_ADDRESS(DestinationAddress)); assert_param(IS_CEC_MSGSIZE(Size)); /* Process Locked */ __HAL_LOCK(hcec); hcec->pTxBuffPtr = pData; hcec->State = HAL_CEC_STATE_BUSY_TX; hcec->ErrorCode = HAL_CEC_ERROR_NONE; /* Disable Peripheral to write CEC_IER register */ __HAL_CEC_DISABLE(hcec); /* Enable the following two CEC Transmission interrupts as * well as the following CEC Transmission Errors interrupts: * Tx Byte Request IT * End of Transmission IT * Tx Missing Acknowledge IT * Tx-Error IT * Tx-Buffer Underrun IT * Tx arbitration lost */ __HAL_CEC_ENABLE_IT(hcec, CEC_IT_TXBR|CEC_IT_TXEND|CEC_IER_TX_ALL_ERR); /* Enable the Peripheral */ __HAL_CEC_ENABLE(hcec); /* initialize the number of bytes to send, * 0 means only one header is sent (ping operation) */ hcec->TxXferCount = Size; /* Process Unlocked */ __HAL_UNLOCK(hcec); /* in case of no payload (Size = 0), sender is only pinging the system; * Set TX End of Message (TXEOM) bit, must be set before writing data to TXDR */ if (Size == 0) { __HAL_CEC_LAST_BYTE_TX_SET(hcec); } /* send header block */ temp = ((uint32_t)hcec->Init.InitiatorAddress << CEC_INITIATOR_LSB_POS) | DestinationAddress; hcec->Instance->TXDR = temp; /* Set TX Start of Message (TXSOM) bit */ __HAL_CEC_FIRST_BYTE_TX_SET(hcec); return HAL_OK; } /* if the IP is already busy or if there is a previous transmission already pending due to arbitration loss */ else if ((hcec->State == HAL_CEC_STATE_BUSY_TX) || (__HAL_CEC_GET_TRANSMISSION_START_FLAG(hcec) != RESET)) { __HAL_LOCK(hcec); /* set state to BUSY TX, in case it wasn't set already (case * of transmission new attempt after arbitration loss) */ if (hcec->State != HAL_CEC_STATE_BUSY_TX) { hcec->State = HAL_CEC_STATE_BUSY_TX; } /* if all data have been sent */ if(hcec->TxXferCount == 0) { /* Disable Peripheral to write CEC_IER register */ __HAL_CEC_DISABLE(hcec); /* Disable the CEC Transmission Interrupts */ __HAL_CEC_DISABLE_IT(hcec, CEC_IT_TXBR|CEC_IT_TXEND); /* Disable the CEC Transmission Error Interrupts */ __HAL_CEC_DISABLE_IT(hcec, CEC_IER_TX_ALL_ERR); /* Enable the Peripheral */ __HAL_CEC_ENABLE(hcec); __HAL_CEC_CLEAR_FLAG(hcec, CEC_FLAG_TXBR|CEC_FLAG_TXEND); hcec->State = HAL_CEC_STATE_READY; /* Call the Process Unlocked before calling the Tx call back API to give the possibility to start again the Transmission under the Tx call back API */ __HAL_UNLOCK(hcec); HAL_CEC_TxCpltCallback(hcec); return HAL_OK; } else { if (hcec->TxXferCount == 1) { /* if this is the last byte transmission, set TX End of Message (TXEOM) bit */ __HAL_CEC_LAST_BYTE_TX_SET(hcec); } /* clear Tx-Byte request flag */ __HAL_CEC_CLEAR_FLAG(hcec, CEC_FLAG_TXBR); hcec->Instance->TXDR = *hcec->pTxBuffPtr++; hcec->TxXferCount--; /* Process Unlocked */ __HAL_UNLOCK(hcec); return HAL_OK; } } else { return HAL_BUSY; } }
/** * @brief Send data in blocking mode * @param hcec: CEC handle * @param DestinationAddress: destination logical address * @param pData: pointer to input byte data buffer * @param Size: amount of data to be sent in bytes (without counting the header). * 0 means only the header is sent (ping operation). * Maximum TX size is 15 bytes (1 opcode and up to 14 operands). * @param Timeout: Timeout duration. * @retval HAL status */ HAL_StatusTypeDef HAL_CEC_Transmit(CEC_HandleTypeDef *hcec, uint8_t DestinationAddress, uint8_t *pData, uint32_t Size, uint32_t Timeout) { uint8_t temp = 0; uint32_t tempisr = 0; uint32_t tickstart = 0; if((hcec->State == HAL_CEC_STATE_READY) && (__HAL_CEC_GET_TRANSMISSION_START_FLAG(hcec) == RESET)) { hcec->ErrorCode = HAL_CEC_ERROR_NONE; if((pData == NULL ) && (Size > 0)) { hcec->State = HAL_CEC_STATE_ERROR; return HAL_ERROR; } assert_param(IS_CEC_ADDRESS(DestinationAddress)); assert_param(IS_CEC_MSGSIZE(Size)); /* Process Locked */ __HAL_LOCK(hcec); hcec->State = HAL_CEC_STATE_BUSY_TX; hcec->TxXferCount = Size; /* case no data to be sent, sender is only pinging the system */ if (Size == 0) { /* Set TX End of Message (TXEOM) bit, must be set before writing data to TXDR */ __HAL_CEC_LAST_BYTE_TX_SET(hcec); } /* send header block */ temp = ((uint32_t)hcec->Init.InitiatorAddress << CEC_INITIATOR_LSB_POS) | DestinationAddress; hcec->Instance->TXDR = temp; /* Set TX Start of Message (TXSOM) bit */ __HAL_CEC_FIRST_BYTE_TX_SET(hcec); while (hcec->TxXferCount > 0) { hcec->TxXferCount--; tickstart = HAL_GetTick(); while(HAL_IS_BIT_CLR(hcec->Instance->ISR, CEC_FLAG_TXBR)) { if(Timeout != HAL_MAX_DELAY) { if((Timeout == 0) || ((HAL_GetTick() - tickstart) > Timeout)) { hcec->State = HAL_CEC_STATE_TIMEOUT; /* Process Unlocked */ __HAL_UNLOCK(hcec); return HAL_TIMEOUT; } } /* check whether error occurred while waiting for TXBR to be set: * has Tx underrun occurred ? * has Tx error occurred ? * has Tx Missing Acknowledge error occurred ? * has Arbitration Loss error occurred ? */ tempisr = hcec->Instance->ISR; if ((tempisr & (CEC_FLAG_TXUDR|CEC_FLAG_TXERR|CEC_FLAG_TXACKE|CEC_FLAG_ARBLST)) != 0) { /* copy ISR for error handling purposes */ hcec->ErrorCode = tempisr; /* clear all error flags by default */ __HAL_CEC_CLEAR_FLAG(hcec, (CEC_FLAG_TXUDR|CEC_FLAG_TXERR|CEC_FLAG_TXACKE|CEC_FLAG_ARBLST)); hcec->State = HAL_CEC_STATE_ERROR; __HAL_UNLOCK(hcec); return HAL_ERROR; } } /* TXBR to clear BEFORE writing TXDR register */ __HAL_CEC_CLEAR_FLAG(hcec, CEC_FLAG_TXBR); if (hcec->TxXferCount == 0) { /* if last byte transmission, set TX End of Message (TXEOM) bit */ __HAL_CEC_LAST_BYTE_TX_SET(hcec); } hcec->Instance->TXDR = *pData++; /* error check after TX byte write up */ tempisr = hcec->Instance->ISR; if ((tempisr & (CEC_FLAG_TXUDR|CEC_FLAG_TXERR|CEC_FLAG_TXACKE|CEC_FLAG_ARBLST)) != 0) { /* copy ISR for error handling purposes */ hcec->ErrorCode = tempisr; /* clear all error flags by default */ __HAL_CEC_CLEAR_FLAG(hcec, (CEC_FLAG_TXUDR|CEC_FLAG_TXERR|CEC_FLAG_TXACKE|CEC_FLAG_ARBLST)); hcec->State = HAL_CEC_STATE_ERROR; __HAL_UNLOCK(hcec); return HAL_ERROR; } } /* end while (while (hcec->TxXferCount > 0)) */ /* if no error up to this point, check that transmission is * complete, that is wait until TXEOM is reset */ tickstart = HAL_GetTick(); while (HAL_IS_BIT_SET(hcec->Instance->CR, CEC_CR_TXEOM)) { if(Timeout != HAL_MAX_DELAY) { if((Timeout == 0) || ((HAL_GetTick() - tickstart) > Timeout)) { hcec->State = HAL_CEC_STATE_ERROR; __HAL_UNLOCK(hcec); return HAL_TIMEOUT; } } } /* Final error check once all bytes have been transmitted */ tempisr = hcec->Instance->ISR; if ((tempisr & (CEC_FLAG_TXUDR|CEC_FLAG_TXERR|CEC_FLAG_TXACKE)) != 0) { /* copy ISR for error handling purposes */ hcec->ErrorCode = tempisr; /* clear all error flags by default */ __HAL_CEC_CLEAR_FLAG(hcec, (CEC_FLAG_TXUDR|CEC_FLAG_TXERR|CEC_FLAG_TXACKE)); hcec->State = HAL_CEC_STATE_ERROR; __HAL_UNLOCK(hcec); return HAL_ERROR; } hcec->State = HAL_CEC_STATE_READY; __HAL_UNLOCK(hcec); return HAL_OK; } else { return HAL_BUSY; } }
/** * @brief Send data in interrupt mode * @param hcec: CEC handle. * Function called under interruption only, once * interruptions have been enabled by HAL_CEC_Transmit_IT() * @retval HAL status */ static HAL_StatusTypeDef CEC_Transmit_IT(CEC_HandleTypeDef *hcec) { uint32_t tmp_state = 0; tmp_state = hcec->State; /* if the IP is already busy or if there is a previous transmission already pending due to arbitration loss */ if(((tmp_state == HAL_CEC_STATE_BUSY_TX) || (tmp_state == HAL_CEC_STATE_BUSY_TX_RX)) || (__HAL_CEC_GET_TRANSMISSION_START_FLAG(hcec) != RESET)) { /* if all data have been sent */ if(hcec->TxXferCount == 0) { /* Acknowledge successful completion by writing 0x00 */ MODIFY_REG(hcec->Instance->CSR, CEC_FLAG_TRANSMIT_MASK, 0x00); /* Check if a receive process is ongoing or not */ if(hcec->State == HAL_CEC_STATE_BUSY_TX_RX) { /* Interrupts are not disabled due to reception still ongoing */ hcec->State = HAL_CEC_STATE_BUSY_RX; } else { /* Disable the CEC Transmission Interrupts */ __HAL_CEC_DISABLE_IT(hcec, CEC_IT_IE); hcec->State = HAL_CEC_STATE_READY; } HAL_CEC_TxCpltCallback(hcec); return HAL_OK; } else { /* Reduce the number of bytes to transfer by one */ hcec->TxXferCount--; /* Write data to TX buffer*/ hcec->Instance->TXD = *hcec->pTxBuffPtr++; /* If this is the last byte of the ongoing transmission */ if (hcec->TxXferCount == 0) { /* Acknowledge byte request and signal end of message */ MODIFY_REG(hcec->Instance->CSR, CEC_FLAG_TRANSMIT_MASK, CEC_FLAG_TEOM); } else { /* Acknowledge byte request by writing 0x00 */ MODIFY_REG(hcec->Instance->CSR, CEC_FLAG_TRANSMIT_MASK, 0x00); } return HAL_OK; } } else { return HAL_BUSY; } }
/** * @brief Send data in interrupt mode * @param hcec: CEC handle * @param DestinationAddress: destination logical address * @param pData: pointer to input byte data buffer * @param Size: amount of data to be sent in bytes (without counting the header). * 0 means only the header is sent (ping operation). * Maximum TX size is 15 bytes (1 opcode and up to 14 operands). * @retval HAL status */ HAL_StatusTypeDef HAL_CEC_Transmit_IT(CEC_HandleTypeDef *hcec, uint8_t DestinationAddress, uint8_t *pData, uint32_t Size) { uint8_t temp = 0; uint32_t tmp_state = 0; tmp_state = hcec->State; if(((tmp_state == HAL_CEC_STATE_READY) || (tmp_state == HAL_CEC_STATE_BUSY_RX)) && (__HAL_CEC_GET_TRANSMISSION_START_FLAG(hcec) == RESET)) { /* Basic check on pData pointer */ if(((pData == NULL) && (Size > 0)) || (! IS_CEC_MSGSIZE(Size))) { return HAL_ERROR; } assert_param(IS_CEC_ADDRESS(DestinationAddress)); /* Process Locked */ __HAL_LOCK(hcec); hcec->pTxBuffPtr = pData; /* Check if a receive process is ongoing or not */ if(hcec->State == HAL_CEC_STATE_BUSY_RX) { hcec->State = HAL_CEC_STATE_BUSY_TX_RX; /* Interrupt are not enabled here because they are already enabled in the Reception process */ } else { hcec->State = HAL_CEC_STATE_BUSY_TX; /* Enable the CEC interrupt */ __HAL_CEC_ENABLE_IT(hcec, CEC_IT_IE); } hcec->ErrorCode = HAL_CEC_ERROR_NONE; /* initialize the number of bytes to send, * 0 means only one header is sent (ping operation) */ hcec->TxXferCount = Size; /* send header block */ temp = (uint8_t)((uint32_t)(hcec->Init.InitiatorAddress) << CEC_INITIATOR_LSB_POS) | DestinationAddress; hcec->Instance->TXD = temp; /* Process Unlocked */ __HAL_UNLOCK(hcec); /* case no data to be sent, sender is only pinging the system */ if (Size != 0) { /* Set TX Start of Message (TXSOM) bit */ MODIFY_REG(hcec->Instance->CSR, CEC_FLAG_TRANSMIT_MASK, CEC_FLAG_TSOM); } else { /* Send a ping command */ MODIFY_REG(hcec->Instance->CSR, CEC_FLAG_TRANSMIT_MASK, CEC_FLAG_TEOM|CEC_FLAG_TSOM); } return HAL_OK; } else { return HAL_BUSY; } }
/** * @brief Send data in blocking mode * @param hcec: CEC handle * @param DestinationAddress: destination logical address * @param pData: pointer to input byte data buffer * @param Size: amount of data to be sent in bytes (without counting the header). * 0 means only the header is sent (ping operation). * Maximum TX size is 15 bytes (1 opcode and up to 14 operands). * @param Timeout: Timeout duration. * @retval HAL status */ HAL_StatusTypeDef HAL_CEC_Transmit(CEC_HandleTypeDef *hcec, uint8_t DestinationAddress, uint8_t *pData, uint32_t Size, uint32_t Timeout) { uint8_t temp = 0; uint32_t tickstart = 0; /* If the IP is ready */ if((hcec->State == HAL_CEC_STATE_READY) && (__HAL_CEC_GET_TRANSMISSION_START_FLAG(hcec) == RESET)) { /* Basic check on pData pointer */ if(((pData == NULL) && (Size > 0)) || (! IS_CEC_MSGSIZE(Size))) { return HAL_ERROR; } assert_param(IS_CEC_ADDRESS(DestinationAddress)); /* Process Locked */ __HAL_LOCK(hcec); /* Enter the transmit mode */ hcec->State = HAL_CEC_STATE_BUSY_TX; hcec->ErrorCode = HAL_CEC_ERROR_NONE; /* Initialize the number of bytes to send, * 0 means only one header is sent (ping operation) */ hcec->TxXferCount = Size; /* Send header block */ temp = (uint8_t)((uint32_t)(hcec->Init.InitiatorAddress) << CEC_INITIATOR_LSB_POS) | DestinationAddress; hcec->Instance->TXD = temp; /* In case no data to be sent, sender is only pinging the system */ if (Size != 0) { /* Set TX Start of Message (TXSOM) bit */ hcec->Instance->CSR = CEC_FLAG_TSOM; } else { /* Send a ping command */ hcec->Instance->CSR = CEC_FLAG_TEOM|CEC_FLAG_TSOM; } /* Polling TBTRF bit with timeout handling*/ while (hcec->TxXferCount > 0) { /* Decreasing of the number of remaining data to receive */ hcec->TxXferCount--; /* Timeout handling */ tickstart = HAL_GetTick(); /* Waiting for the next data transmission */ while(HAL_IS_BIT_CLR(hcec->Instance->CSR, CEC_FLAG_TBTRF)) { /* Timeout handling */ if(Timeout != HAL_MAX_DELAY) { if((Timeout == 0) || ((HAL_GetTick()-tickstart) > Timeout)) { hcec->State = HAL_CEC_STATE_READY; /* Process Unlocked */ __HAL_UNLOCK(hcec); return HAL_TIMEOUT; } } /* Check if an error occured */ if(HAL_IS_BIT_SET(hcec->Instance->CSR, CEC_FLAG_TERR) || HAL_IS_BIT_SET(hcec->Instance->CSR, CEC_FLAG_RERR)) { /* Copy ESR for error handling purposes */ hcec->ErrorCode = READ_BIT(hcec->Instance->ESR, CEC_ESR_ALL_ERROR); /* Acknowledgement of the error */ __HAL_CEC_CLEAR_FLAG(hcec, CEC_FLAG_TERR); __HAL_CEC_CLEAR_FLAG(hcec, CEC_FLAG_RERR); hcec->State = HAL_CEC_STATE_READY; __HAL_UNLOCK(hcec); return HAL_ERROR; } } /* Write the next data to TX buffer */ hcec->Instance->TXD = *pData++; /* If this is the last byte of the ongoing transmission */ if (hcec->TxXferCount == 0) { /* Acknowledge byte request and signal end of message */ MODIFY_REG(hcec->Instance->CSR, CEC_FLAG_TRANSMIT_MASK, CEC_FLAG_TEOM); } else { /* Acknowledge byte request by writing 0x00 */ MODIFY_REG(hcec->Instance->CSR, CEC_FLAG_TRANSMIT_MASK, 0x00); } } /* Timeout handling */ tickstart = HAL_GetTick(); /* Wait for message transmission completion (TBTRF is set) */ while (HAL_IS_BIT_CLR(hcec->Instance->CSR, CEC_FLAG_TBTRF)) { /* Timeout handling */ if(Timeout != HAL_MAX_DELAY) { if((Timeout == 0) || ((HAL_GetTick()-tickstart) > Timeout)) { hcec->State = HAL_CEC_STATE_READY; __HAL_UNLOCK(hcec); return HAL_TIMEOUT; } } /* Check of error during transmission of the last byte */ if(HAL_IS_BIT_SET(hcec->Instance->CSR, CEC_FLAG_TERR) || HAL_IS_BIT_SET(hcec->Instance->CSR, CEC_FLAG_RERR)) { /* Copy ESR for error handling purposes */ hcec->ErrorCode = READ_BIT(hcec->Instance->ESR, CEC_ESR_ALL_ERROR); /* Acknowledgement of the error */ __HAL_CEC_CLEAR_FLAG(hcec, CEC_FLAG_TERR); __HAL_CEC_CLEAR_FLAG(hcec, CEC_FLAG_RERR); hcec->State = HAL_CEC_STATE_READY; __HAL_UNLOCK(hcec); return HAL_ERROR; } } /* Check of error after the last byte transmission */ if(HAL_IS_BIT_SET(hcec->Instance->CSR, CEC_FLAG_TERR) || HAL_IS_BIT_SET(hcec->Instance->CSR, CEC_FLAG_RERR)) { /* Copy ESR for error handling purposes */ hcec->ErrorCode = READ_BIT(hcec->Instance->ESR, CEC_ESR_ALL_ERROR); /* Acknowledgement of the error */ __HAL_CEC_CLEAR_FLAG(hcec, CEC_FLAG_TERR); __HAL_CEC_CLEAR_FLAG(hcec, CEC_FLAG_RERR); hcec->State = HAL_CEC_STATE_READY; __HAL_UNLOCK(hcec); return HAL_ERROR; } /* Acknowledge successful completion by writing 0x00 */ MODIFY_REG(hcec->Instance->CSR, CEC_FLAG_TRANSMIT_MASK, 0x00); hcec->State = HAL_CEC_STATE_READY; __HAL_UNLOCK(hcec); return HAL_OK; } else { return HAL_BUSY; } }