/***************************************************************************//** * \file transport_ble.c * \version 3.0 * * This file provides the source code of the DFU communication APIs * for the BLE Component. * ******************************************************************************** * \copyright * Copyright 2016-2018, Cypress Semiconductor Corporation. All rights reserved. * You may use this file only in accordance with the license, terms, conditions, * disclaimers, and limitations in the end user license agreement accompanying * the software package with which this file was provided. *******************************************************************************/ #include "transport_ble.h" #if defined(CY_PSOC_CREATOR_USED) #include "BLE.h" #else #include "cy_flash.h" #include "ble/cy_ble_gap.h" #include "ble/cy_ble_stack.h" #endif /* defined(CY_PSOC_CREATOR_USED) */ #include "ble/cy_ble_stack_host_error.h" #include "ble/cy_ble_event_handler.h" #include "ble/cy_ble_bts.h" #if CY_BLE_HOST_CORE static uint16_t cyBle_btsDataPacketIndex = 0u; static uint8_t cyBle_cmdReceivedFlag = 0u; static uint16_t cyBle_cmdLength = 0u; static uint8_t *cyBle_btsBuffPtr; static uint16_t cyBle_btsDataPacketSize = 0u; static uint8_t cyBle_btsDataBuffer[CY_FLASH_SIZEOF_ROW + CYBLE_BTS_COMMAND_CONTROL_BYTES_NUM]; /* Connection Handle */ cy_stc_ble_conn_handle_t appConnHandle; /******************************************************************************* * Function Name: CyBLE_CyBtldrCommStart ****************************************************************************//** * * Initializes DFU state for BLE communication. * *******************************************************************************/ void CyBLE_CyBtldrCommStart(void) { #if defined(CY_PSOC_CREATOR_USED) /* Start BLE and register the callback function */ (void)Cy_BLE_Start(&AppCallBack); /* Registers a callback function for DFU */ (void)Cy_BLE_BTS_RegisterAttrCallback(&DFUCallBack); #endif /* defined(CY_PSOC_CREATOR_USED) */ cyBle_btsDataPacketIndex = 0u; } /******************************************************************************* * Function Name: CyBLE_CyBtldrCommStop ****************************************************************************//** * * Disconnects from the peer device and stops BLE component. * ******************************************************************************/ void CyBLE_CyBtldrCommStop(void) { cy_stc_ble_gap_disconnect_info_t disconnectInfoParam = { .bdHandle = appConnHandle.bdHandle, .reason = CY_BLE_HCI_ERROR_OTHER_END_TERMINATED_USER }; /* Initiate disconnection from the peer device*/ if(Cy_BLE_GAP_Disconnect(&disconnectInfoParam) == CY_BLE_SUCCESS) { /* Wait for disconnection event */ while(Cy_BLE_GetConnectionState(appConnHandle) == CY_BLE_CONN_STATE_CONNECTED) { /* Process BLE events */ Cy_BLE_ProcessEvents(); } } /* Stop BLE component. Ignores an error code because current function returns nothing */ (void) Cy_BLE_Disable(); } /******************************************************************************* * Function Name: CyBtldrCommReset ****************************************************************************//** * * Resets DFU state for BLE communication. * *******************************************************************************/ void CyBLE_CyBtldrCommReset(void) { cyBle_btsDataPacketIndex = 0u; } /******************************************************************************* * Function Name: CyBLE_CyBtldrCommWrite ****************************************************************************//** * * Requests that the provided size (number of bytes) should be written from the * input data buffer to the host device. This function in turn invokes the * CyBle_GattsNotification() API to sent the data. If a notification is * accepted, the function returns CYRET_SUCCESS. The timeOut parameter is ignored * in this case. * * \param data The pointer to the buffer containing data to be written. * \param size The number of bytes from the data buffer to write. * \param count The pointer to where the BLE component will write the number * of written bytes, generally the same as the size. * \param timeOut Ignored. Used for consistency. * * \return * The return value is of type \ref cy_en_dfu_status_t: * - CY_DFU_SUCCESS - Indicates if a notification is successful. * - CY_DFU_ERROR_UNKNOWN - Failed to send notification to the host. * *******************************************************************************/ cy_en_dfu_status_t CyBLE_CyBtldrCommWrite(const uint8_t pData[], uint32_t size, uint32_t *count, uint32_t timeout) { cy_en_dfu_status_t status = CY_DFU_ERROR_UNKNOWN; if (timeout == 0u) { /* empty */ } if(Cy_BLE_BTSS_SendNotification(appConnHandle, CY_BLE_BTS_BT_SERVICE, size, (const uint8 *)pData) == CY_BLE_SUCCESS) { *count = size; status = CY_DFU_SUCCESS; } else { *count = 0u; } return (status); } /******************************************************************************* * Function Name: CyBLE_CyBtldrCommRead ****************************************************************************//** * * Requests that the provided size (number of bytes) is read from the host device * and stored in the provided data buffer. Once the read is done, the "count" is * endorsed with the number of bytes written. The timeOut parameter is used to * provide an upper bound on the time that the function is allowed to operate. If * the read completes early, it should return success code as soon as possible. * If the read was not successful before the allocated time has expired, it * should return an error. * * \param data The pointer to the buffer to store data from the host controller. * \param size The number of bytes to read into the data buffer. * \param count The pointer to where the BLE component will write the number of * read bytes. * \param timeout The amount of time (in milliseconds) for which the * BLE component should wait before indicating communication * time out. * * \return * The return value is of type \ref cy_en_dfu_status_t: * - CY_DFU_SUCCESS - A command was successfully read. * - CY_DFU_ERROR_DATA - The size of the command exceeds the buffer. * - CY_DFU_ERROR_TIMEOUT - The host controller did not respond during specified time out. * \sideeffect * \ref CyBle_ProcessEvents() is called as a part of this function. * *******************************************************************************/ cy_en_dfu_status_t CyBLE_CyBtldrCommRead(uint8_t pData[], uint32_t size, uint32_t *count, uint32_t timeout) { cy_en_dfu_status_t status = CY_DFU_ERROR_UNKNOWN; if ((pData != NULL) && (size > 0u)) { status = CY_DFU_ERROR_TIMEOUT; while(timeout != 0u) { /* Process BLE events */ Cy_BLE_ProcessEvents(); if(cyBle_cmdReceivedFlag == 1u) { /* Clear command receive flag */ cyBle_cmdReceivedFlag = 0u; if(cyBle_cmdLength < size) { (void) memcpy((void *) pData, (const void *) cyBle_btsBuffPtr, (uint32_t)cyBle_cmdLength); /* Return actual received command length */ *count = cyBle_cmdLength; status = CY_DFU_SUCCESS; } else { pData = NULL; *count = 0u; status = CY_DFU_ERROR_DATA; } break; } /* Wait 1 ms and update timeout counter */ Cy_SysLib_Delay(1u); --timeout; } /* Process BLE events */ Cy_BLE_ProcessEvents(); } return (status); } /******************************************************************************* * Function Name: DFUCallBack ****************************************************************************//** * * Handles the events from the BLE stack for the DFU Service. * * \param eventCode Event code * \param eventParam Event parameters * *******************************************************************************/ void DFUCallBack(uint32 event, void* eventParam) { /* To remove incorrect compiler warning */ (void)eventParam; switch ((cy_en_ble_evt_t)event) { case CY_BLE_EVT_BTSS_NOTIFICATION_ENABLED: break; case CY_BLE_EVT_BTSS_NOTIFICATION_DISABLED: break; case CY_BLE_EVT_BTSS_EXEC_WRITE_REQ: /* Check the execWriteFlag before execute or cancel write long operation */ if(((cy_stc_ble_gatts_exec_write_req_t *)eventParam)->execWriteFlag == CY_BLE_GATT_EXECUTE_WRITE_EXEC_FLAG) { cyBle_btsBuffPtr = ((cy_stc_ble_gatts_exec_write_req_t *)eventParam)->baseAddr[0u].handleValuePair.value.val; /* Extract length of command data and add control bytes to data * length to get command length. */ cyBle_cmdLength = (((uint16)(((uint16) cyBle_btsBuffPtr[CYBLE_BTS_COMMAND_DATA_LEN_OFFSET + 1u]) << 8u)) | (uint16) cyBle_btsBuffPtr[CYBLE_BTS_COMMAND_DATA_LEN_OFFSET]) + CYBLE_BTS_COMMAND_CONTROL_BYTES_NUM; if(cyBle_cmdLength > CYBLE_BTS_COMMAND_MAX_LENGTH) { cyBle_cmdLength = CYBLE_BTS_COMMAND_MAX_LENGTH; } /* Set flag for DFU to know that command is received from host */ cyBle_cmdReceivedFlag = 1u; } break; case CY_BLE_EVT_BTSS_PREP_WRITE_REQ: if(((cy_stc_ble_gatts_prep_write_req_param_t *)eventParam)->currentPrepWriteReqCount == 1u) { /* Send Prepare Write Response which identifies acknowledgement for * long characteristic value write. */ cyBle_cmdLength = 0u; } break; case CY_BLE_EVT_BTSS_WRITE_CMD_REQ: { uint8 *localDataBuffer = ((cy_stc_ble_bts_char_value_t *)eventParam)->value->val; /* This is the beginning of the packet, let's read the size now */ if(cyBle_btsDataPacketIndex == 0u) { cyBle_btsDataPacketSize = (((uint16)(((uint16) localDataBuffer[CYBLE_BTS_COMMAND_DATA_LEN_OFFSET + 1u]) << 8u)) | (uint16) localDataBuffer[CYBLE_BTS_COMMAND_DATA_LEN_OFFSET]) + CYBLE_BTS_COMMAND_CONTROL_BYTES_NUM; } (void) memcpy(&cyBle_btsDataBuffer[cyBle_btsDataPacketIndex], localDataBuffer, (uint32_t) ((cy_stc_ble_bts_char_value_t *)eventParam)->value->len); cyBle_btsDataPacketIndex += ((cy_stc_ble_bts_char_value_t *)eventParam)->value->len; if(cyBle_btsDataPacketIndex == cyBle_btsDataPacketSize) { cyBle_btsBuffPtr = &cyBle_btsDataBuffer[0]; cyBle_cmdLength = cyBle_btsDataPacketSize; cyBle_cmdReceivedFlag = 1u; cyBle_btsDataPacketIndex = 0u; } break; } case CY_BLE_EVT_BTSS_WRITE_REQ: cyBle_btsBuffPtr = CY_BLE_GATT_DB_ATTR_GET_ATTR_GEN_PTR(cy_ble_btsConfigPtr->btss->btServiceInfo[0u].btServiceCharHandle); /* Extract length of command data and add control bytes to data * length to get command length. */ cyBle_cmdLength = (((uint16)(((uint16) cyBle_btsBuffPtr[CYBLE_BTS_COMMAND_DATA_LEN_OFFSET + 1u]) << 8u)) | (uint16) cyBle_btsBuffPtr[CYBLE_BTS_COMMAND_DATA_LEN_OFFSET]) + CYBLE_BTS_COMMAND_CONTROL_BYTES_NUM; /* Set flag for DFU to know that command is received from host */ cyBle_cmdReceivedFlag = 1u; break; default: break; } } #endif /* CY_BLE_HOST_CORE */ /* [] END OF FILE */