void HandleI2CWrite(void) { CYBLE_GATTC_WRITE_CMD_REQ_T I2CDataWriteCmd; /* Check if the peripheral is connected before trying to write*/ if(CyBle_GetState() == CYBLE_STATE_CONNECTED) { /* update the attribute handle to be written */ I2CDataWriteCmd.attrHandle = I2CWriteDataCharHandle; I2CDataWriteCmd.value.len = byteCnt; I2CDataWriteCmd.value.val = wrBuf; do { apiResult = CyBle_GattcWriteWithoutResponse(cyBle_connHandle, &I2CDataWriteCmd); CyBle_ProcessEvents(); } while((CYBLE_ERROR_OK != apiResult) && (CYBLE_STATE_CONNECTED == cyBle_state)); } }
/****************************************************************************** * Function Name: CyBle_IascSetCharacteristicValue ***************************************************************************//** * * Sets a Alert Level characteristic value of the service, which is identified * by charIndex. * * \param connHandle: The connection handle. * \param charIndex: The index of the Alert Level service characteristic. * \param attrSize: The size of the Alert Level characteristic value attribute. * \param attrValue: The pointer to the Alert Level characteristic value data that * should be sent to the server device. * * \return * Return value is of type CYBLE_API_RESULT_T. * * CYBLE_ERROR_OK - The request was sent successfully * * CYBLE_ERROR_INVALID_PARAMETER - Validation of the input parameters failed * * CYBLE_ERROR_MEMORY_ALLOCATION_FAILED - Memory allocation failed * * CYBLE_ERROR_INVALID_STATE - Connection with the server is not established * * CYBLE_ERROR_INVALID_OPERATION - Operation is invalid for this * characteristic * * \events * In case of successful execution (return value = CYBLE_ERROR_OK) * the next events can appear: \n * If the IAS service-specific callback is registered * (with CyBle_IasRegisterAttrCallback): * * CYBLE_EVT_IASC_WRITE_CHAR_RESPONSE - in case if the requested attribute is * successfully wrote on the peer device, * the details (char index, etc.) are * provided with event parameter structure * of type CYBLE_IAS_CHAR_VALUE_T. * . * Otherwise (if the IAS service-specific callback is not registered): * * CYBLE_EVT_GATTC_WRITE_RSP - in case if the requested attribute is * successfully wrote on the peer device. * * CYBLE_EVT_GATTC_ERROR_RSP - in case if there some trouble with the * requested attribute on the peer device, * the details are provided with event parameters * structure (CYBLE_GATTC_ERR_RSP_PARAM_T). * ******************************************************************************/ CYBLE_API_RESULT_T CyBle_IascSetCharacteristicValue(CYBLE_CONN_HANDLE_T connHandle, CYBLE_IAS_CHAR_INDEX_T charIndex, uint8 attrSize, uint8 *attrValue) { CYBLE_GATTC_WRITE_CMD_REQ_T wrCmdReq; CYBLE_API_RESULT_T apiResult = CYBLE_ERROR_INVALID_PARAMETER; if(CyBle_GetClientState() != CYBLE_CLIENT_STATE_DISCOVERED) { apiResult = CYBLE_ERROR_INVALID_STATE; } else if((NULL != attrValue) && (CYBLE_IAS_ALERT_LEVEL == charIndex) && (CYBLE_IAS_ALERT_LEVEL_SIZE == attrSize) && (*attrValue <= CYBLE_HIGH_ALERT) && (CYBLE_GATT_INVALID_ATTR_HANDLE_VALUE != cyBle_iasc.alertLevelChar.valueHandle)) { /* Fill all fields of write command request structure ... */ wrCmdReq.value.val = attrValue; wrCmdReq.value.len = attrSize; wrCmdReq.attrHandle = cyBle_iasc.alertLevelChar.valueHandle; /* Send request to write Alert Level characteristic value */ apiResult = CyBle_GattcWriteWithoutResponse(connHandle, &wrCmdReq); } else { /* apiResult equals CYBLE_ERROR_INVALID_PARAMETER */ } /* Return status */ return(apiResult); }
int main() { hkj_timer t; const uint16 myCharHandle = 0x0E; uint8 writeData = 0; CYBLE_GATT_VALUE_T writeValue = \ { &writeData, sizeof(writeData), sizeof(writeData) }; CYBLE_GATTC_WRITE_REQ_T writeReqParam = \ { .value = writeValue, .attrHandle = myCharHandle }; CYBLE_STACK_LIB_VERSION_T stackVersion; CyGlobalIntEnable; UART_Start(); hkj_debug_init(); CyBle_GetStackLibraryVersion(&stackVersion); debug_print("Latency Central Stack: %u.%u.%u.%u\r\n", \ stackVersion.majorVersion, stackVersion.minorVersion, \ stackVersion.patch, stackVersion.buildNumber); CyBle_Start(BleEventHandler); hkj_timer_ms_init(&t); while(1) { CyBle_ProcessEvents(); if (connHandle.bdHandle != 0) { if (hkj_timer_ms_get_delta(&t) > 500) { WRITE_CMD_PIN_Write(1); CyBle_GattcWriteWithoutResponse(connHandle, &writeReqParam); hkj_timer_ms_reset_delta(&t); CyDelay(2); WRITE_CMD_PIN_Write(0); } } hkj_ble_events_log_debug_print(); } }
int main() { CyGlobalIntEnable; CyBle_Start(BleEventHandler); while(connHandle.bdHandle == 0) /* Wait for connection to GATT server */ CyBle_ProcessEvents(); CyBle_GattcStartDiscovery(connHandle); /* Attempt discovery of configured services */ while(ledStateHandle == 0) /* Wait for discovery */ CyBle_ProcessEvents(); writeData = 0x01; /* Turn on LED on Minimal_Peripheral dongle */ writeValue.val = &writeData; writeValue.len = sizeof(writeData); writeValue.actualLen = sizeof(writeData); writeReqParam.value = writeValue; writeReqParam.attrHandle = ledStateHandle; /* Use discovered handle */ CyBle_GattcWriteWithoutResponse(connHandle, &writeReqParam); /* Write to server */ CyBle_ProcessEvents(); return 0; }
/******************************************************************************* * Function Name: HandleUartTxTraffic ******************************************************************************** * * Summary: * This function takes data from UART RX buffer and pushes it to the server * as Write Without Response command. * * Parameters: * None. * * Return: * None. * *******************************************************************************/ void HandleUartTxTraffic(void) { uint8 index; uint8 uartTxData[MAX_MTU_SIZE - 3]; uint16 uartTxDataLength; static uint16 uartIdleCount = UART_IDLE_TIMEOUT; CYBLE_API_RESULT_T bleApiResult; CYBLE_GATTC_WRITE_CMD_REQ_T uartTxDataWriteCmd; uartTxDataLength = UART_SpiUartGetRxBufferSize(); #ifdef FLOW_CONTROL if(uartTxDataLength >= (UART_UART_RX_BUFFER_SIZE - (UART_UART_RX_BUFFER_SIZE/2))) { DisableUartRxInt(); } else { EnableUartRxInt(); } #endif if((uartTxDataLength != 0)) { if(uartTxDataLength >= (mtuSize - 3)) { uartIdleCount = UART_IDLE_TIMEOUT; uartTxDataLength = mtuSize - 3; } else { if(--uartIdleCount == 0) { /*uartTxDataLength remains unchanged */; } else { uartTxDataLength = 0; } } if(0 != uartTxDataLength) { uartIdleCount = UART_IDLE_TIMEOUT; for(index = 0; index < uartTxDataLength; index++) { uartTxData[index] = (uint8) UART_UartGetByte(); } uartTxDataWriteCmd.attrHandle = rxCharHandle; uartTxDataWriteCmd.value.len = uartTxDataLength; uartTxDataWriteCmd.value.val = uartTxData; #ifdef FLOW_CONTROL DisableUartRxInt(); #endif do { bleApiResult = CyBle_GattcWriteWithoutResponse(cyBle_connHandle, &uartTxDataWriteCmd); CyBle_ProcessEvents(); } while((CYBLE_ERROR_OK != bleApiResult) && (CYBLE_STATE_CONNECTED == cyBle_state)); } } }
/******************************************************************************* * Function Name: GenericEventHandler ******************************************************************************** * Summary: * Event handler function for the BLE stack. All the events by BLE stack * are received by application through this function. For this, CyBle_ProcessEvents() * should be called continuously in main loop. * * Parameters: * event: event value * eventParame: pointer to the location where relevant event data is stored * * Return: * void * *******************************************************************************/ void GenericEventHandler(uint32 event, void * eventParam) { /* Local variables and data structures*/ CYBLE_GATTS_WRITE_REQ_PARAM_T writeReqData; CYBLE_GATTC_WRITE_REQ_T writeADVcounterdata; CYBLE_GAPC_ADV_REPORT_T scan_report; CYBLE_GATTS_WRITE_CMD_REQ_PARAM_T writeCmdData; CYBLE_API_RESULT_T apiResult; CYBLE_GATTC_WRITE_REQ_T writeRGBdata; switch(event) { case CYBLE_EVT_STACK_ON: #ifdef DEBUG_ENABLED UART_UartPutString("CYBLE_EVT_STACK_ON "); UART_UartPutCRLF(' '); #endif /* At the start of the BLE stack, start advertisement */ CyBle_GappStartAdvertisement(CYBLE_ADVERTISING_FAST); break; case CYBLE_EVT_GAPP_ADVERTISEMENT_START_STOP: /* This event is received at every start or stop of peripheral advertisement*/ #ifdef DEBUG_ENABLED UART_UartPutString("CYBLE_EVT_GAPP_ADVERTISEMENT_START_STOP "); SendBLEStatetoUART(CyBle_GetState()); UART_UartPutCRLF(' '); #endif if((CYBLE_STATE_DISCONNECTED == CyBle_GetState()) && (switch_Role == FALSE)) { /* If the current state of the BLE is Disconnected, then restart advertisement. * Note that the advertisement should only be restarted if the switch flag is not * TRUE. If switch role flag is TRUE, then there is no need to start advertisement * as the GAP role has to be switched*/ CyBle_GappStartAdvertisement(CYBLE_ADVERTISING_FAST); if(apiResult == CYBLE_ERROR_OK) { #ifdef DEBUG_ENABLED UART_UartPutString("Restart Advertisement "); SendBLEStatetoUART(CyBle_GetState()); UART_UartPutCRLF(' '); #endif } } break; case CYBLE_EVT_GAPC_SCAN_START_STOP: /* This event is received at every start or stop of central scanning*/ #ifdef DEBUG_ENABLED UART_UartPutString("CYBLE_EVT_GAPC_SCAN_START_STOP "); SendBLEStatetoUART(CyBle_GetState()); UART_UartPutCRLF(' '); #endif break; case CYBLE_EVT_GATT_CONNECT_IND: /* This event is received at GATT connection with a device. This event * is received for both Client or Server role */ #ifdef DEBUG_ENABLED UART_UartPutString("CYBLE_EVT_GATT_CONNECT_IND "); UART_UartPutCRLF(' '); #endif break; case CYBLE_EVT_GATT_DISCONNECT_IND: /* This event is received at GATT disconnection with a device. This event * is received for both Client or Server role */ #ifdef DEBUG_ENABLED UART_UartPutString("CYBLE_EVT_GATT_DISCONNECT_IND "); UART_UartPutCRLF(' '); #endif break; case CYBLE_EVT_GATTS_WRITE_REQ: /* This event is received at when Server receives a Write request from * connected Client device */ /* Save the associated event parameter in local variable */ writeReqData = *(CYBLE_GATTS_WRITE_REQ_PARAM_T*)eventParam; if(writeReqData.handleValPair.attrHandle == CYBLE_RGB_LED_CONTROL_CHAR_HANDLE) { /* If the Write request is on RGB LED Control Characteristic, then Client is * trying to set a new color to the device. */ if(writeReqData.handleValPair.value.len == RGB_LED_DATA_LEN) { #ifdef DEBUG_ENABLED UART_UartPutString("RGB CYBLE_EVT_GATTS_WRITE_REQ "); UART_UartPutCRLF(' '); #endif /* Extract the four bytes containing the color value and store it */ RGBData[RGB_RED_INDEX] = writeReqData.handleValPair.value.val[0]; RGBData[RGB_GREEN_INDEX] = writeReqData.handleValPair.value.val[1]; RGBData[RGB_BLUE_INDEX] = writeReqData.handleValPair.value.val[2]; RGBData[RGB_INTENSITY_INDEX] = writeReqData.handleValPair.value.val[3]; /* Modify RGB Color my configuring the PrISM components with new density * value*/ UpdateRGBled(RGBData, RGB_LED_DATA_LEN); /* Update the RGB LED Control characteristic in GATT DB to allow * Client to read the latest RGB LED color value set */ CyBle_GattsWriteAttributeValue(&writeReqData.handleValPair,0,&cyBle_connHandle,CYBLE_GATT_DB_LOCALLY_INITIATED); #ifdef ENABLE_ADV_DATA_COUNTER /* Increment the ADV data counter so that scanning Central device knows * if this device has updated RGB LED data or not */ dataADVCounter++; #endif #ifdef DEBUG_ENABLED UART_UartPutString("incremented dataADVCounter value in CYBLE_EVT_GATTS_WRITE_REQ= "); PrintNum(dataADVCounter); UART_UartPutCRLF(' '); #endif /* After receiveing the color value, set the switch role flag to allow the system * to switch role to Central role */ switch_Role = TRUE; #ifdef DEBUG_ENABLED UART_UartPutString("switchRole to Central"); UART_UartPutCRLF(' '); #endif } else { /* Send the error code for invalid attribute length packet */ SendErrorCode(CYBLE_GATT_WRITE_REQ, writeReqData.handleValPair.attrHandle, ERR_INVALID_ATT_LEN); return; } } /* As part of every write request, the server needs to send a write response. Note * that this will be sent only if all the application layer conditions are met on a * write request. Else, an appropriate error code is sent. */ CyBle_GattsWriteRsp(cyBle_connHandle); break; case CYBLE_EVT_GATTS_WRITE_CMD_REQ: /* This event is generated whenever a Client device sends a Write Command (Write * without response) to a connected Server. Save the associated event parameter in * local variable. */ writeCmdData = *(CYBLE_GATTS_WRITE_CMD_REQ_PARAM_T*)eventParam; /* Check if the Write command is for ADV Data counter characteristic */ if(writeCmdData.handleValPair.attrHandle == CYBLE_RGB_DATA_COUNT_CHAR_HANDLE) { /* If the data sent is of one byte, then proceed. */ if(writeCmdData.handleValPair.value.len == 1) { /* Extract and save the set ADV data counter value */ dataADVCounter = *(writeCmdData.handleValPair.value.val); /* This increment is done to balance the ++ done as part of CYBLE_EVT_GATTS_WRITE_REQ */ dataADVCounter--; /* Update the ADV data counter characteristic in GATT DB to allow * Client to read the latest ADV data counter value */ CyBle_GattsWriteAttributeValue(&writeCmdData.handleValPair, 0, &cyBle_connHandle, CYBLE_GATT_DB_LOCALLY_INITIATED); #ifdef DEBUG_ENABLED UART_UartPutString("dataADVCounter from CYBLE_EVT_GATTS_WRITE_CMD_REQ = "); PrintNum(dataADVCounter); UART_UartPutCRLF(' '); #endif } /* if(writeCmdData.handleValPair.value.len == 1) */ } break; case CYBLE_EVT_GAPC_SCAN_PROGRESS_RESULT: /* This event is generated whenever there is a peripheral device found by * while scanning */ if(CYBLE_STATE_CONNECTED != CyBle_GetState()) { /* If we are not connected to any peripheral device, then save the new device * information so to add it to our list */ scan_report = *(CYBLE_GAPC_ADV_REPORT_T*)eventParam; #ifdef DEBUG_ENABLED UART_UartPutString("CYBLE_EVT_GAPC_SCAN_PROGRESS_RESULT "); UART_UartPutCRLF(' '); #endif #ifdef ENABLE_ADV_DATA_COUNTER /* If ADV DATA COUNTER is enabled, then the central device would check * if the counter in ADV packet of peripheral is less than its own counter * or not. If yes, then it will consider the peripheral as a potential * device to connect to.*/ if(scan_report.eventType == CYBLE_GAPC_CONN_UNDIRECTED_ADV) { /* If the scan report received is of advertising nature and the data * length is as expected... */ if(scan_report.dataLen == new_advData.advDataLen) { /* If the second last value of the advertising data matches the custom * marker, then the peripheral is a node of the network */ if(scan_report.data[scan_report.dataLen-2] == CUSTOM_ADV_DATA_MARKER) { /* If the ADV counter data in Advertising data is less than that of * the value in this scanning device, then the node is a potential node * whose color has to be updated. */ if((scan_report.data[scan_report.dataLen-1] < dataADVCounter) || ((scan_report.data[scan_report.dataLen-1] == 255) && (dataADVCounter == 0))) { /* Potential node found*/ potential_node_found = TRUE; /* Save the advertising peripheral address and type*/ memcpy(potential_node_bdAddr, scan_report.peerBdAddr, 6); potential_node_bdAddrType = scan_report.peerAddrType; #ifdef DEBUG_ENABLED UART_UartPutString("potential_node_found "); UART_UartPutCRLF(' '); #endif } else { /* If the ADV data counter is equal or more than the data counter * in this scanning device, then the node has latest RGB LED data * and does not need to be connected to. Reset the potential node * address */ potential_node_found = FALSE; potential_node_bdAddrType = 0; potential_node_bdAddr[0] = 0x00; potential_node_bdAddr[1] = 0x00; potential_node_bdAddr[2] = 0x00; potential_node_bdAddr[3] = 0x00; potential_node_bdAddr[4] = 0x00; potential_node_bdAddr[5] = 0x00; } } } } #endif /* If the received scan data is part of scan response from a peripheral... */ if(scan_report.eventType == CYBLE_GAPC_SCAN_RSP) { /* If the data lenght of the scan reponse packet is equal to expected * scan response data lenght...*/ if(scan_report.dataLen == SCAN_TAG_DATA_LEN) { #ifdef ENABLE_ADV_DATA_COUNTER /* If a potential node had been found earlier as part of received * advertising data, then compare the address of stored potential * node and received address of the scan response */ if(potential_node_found) { /* Compare the two addresses and type */ if((!memcmp(scan_report.peerBdAddr, potential_node_bdAddr, 6)) && (potential_node_bdAddrType == scan_report.peerAddrType)) { #endif /* If the scan report data matches the expected data (scan_tag), * then it is our desired node */ if(!memcmp(scan_report.data, scan_tag, scan_report.dataLen)) { #ifdef DEBUG_ENABLED UART_UartPutString("Titan Found "); UART_UartPutCRLF(' '); #endif /* Stop existing scan */ CyBle_GapcStopScan(); #ifdef DEBUG_ENABLED UART_UartPutString("Stop Scan called "); UART_UartPutCRLF(' '); #endif /* Save the peripheral BD address and type*/ peripAddr.type = scan_report.peerAddrType; peripAddr.bdAddr[0] = scan_report.peerBdAddr[0]; peripAddr.bdAddr[1] = scan_report.peerBdAddr[1]; peripAddr.bdAddr[2] = scan_report.peerBdAddr[2]; peripAddr.bdAddr[3] = scan_report.peerBdAddr[3]; peripAddr.bdAddr[4] = scan_report.peerBdAddr[4]; peripAddr.bdAddr[5] = scan_report.peerBdAddr[5]; /* Set the flag to allow application to connect to the * peripheral found */ clientConnectToDevice = TRUE; #ifdef ENABLE_ADV_DATA_COUNTER /* Reset the potential node flag*/ potential_node_found = FALSE; #endif } #ifdef ENABLE_ADV_DATA_COUNTER } } #endif } } } break; case CYBLE_EVT_GAP_DEVICE_CONNECTED: /* This event is received whenever the device connect on GAP layer */ if(ble_gap_state == BLE_CENTRAL) { #ifdef ENABLE_CENTRAL_DISCOVERY /* The Device is connected now. Start Attributes discovery process.*/ CyBle_GattcStartDiscovery(cyBle_connHandle); #ifdef DEBUG_ENABLED UART_UartPutString("CYBLE_EVT_GAP_DEVICE_CONNECTED "); SendBLEStatetoUART(CyBle_GetState()); UART_UartPutCRLF(' '); #endif #else /* If this system is currently acting in Central role and has connected * to a peripheral device, then write directly the ADV counter data and * RGB LED control data using attribute handles */ /* Set the device connected flag */ deviceConnected = TRUE; #ifdef DEBUG_ENABLED UART_UartPutString("Directly write RGB using Attr handle "); SendBLEStatetoUART(CyBle_GetState()); UART_UartPutCRLF(' '); #endif /* Write the Data Counter value */ writeADVcounterdata.attrHandle = CYBLE_RGB_DATA_COUNT_CHAR_HANDLE; writeADVcounterdata.value.val = &dataADVCounter; writeADVcounterdata.value.len = 1; CyBle_GattcWriteWithoutResponse(cyBle_connHandle, &writeADVcounterdata); /* Write the RGB LED Value */ writeRGBdata.attrHandle = CYBLE_RGB_LED_CONTROL_CHAR_HANDLE; writeRGBdata.value.val = RGBData; writeRGBdata.value.len = RGB_LED_DATA_LEN; CyBle_GattcWriteCharacteristicValue(cyBle_connHandle, &writeRGBdata); #endif } break; case CYBLE_EVT_GATTC_DISCOVERY_COMPLETE: /* This event is generated whenever the discovery procedure is complete*/ #ifdef ENABLE_CENTRAL_DISCOVERY deviceConnected = TRUE; #ifdef DEBUG_ENABLED UART_UartPutString("CYBLE_EVT_GATTC_DISCOVERY_COMPLETE "); SendBLEStatetoUART(CyBle_GetState()); UART_UartPutCRLF(' '); #endif /* Write the Data Counter value */ writeADVcounterdata.attrHandle = CYBLE_RGB_DATA_COUNT_CHAR_HANDLE; writeADVcounterdata.value.val = &dataADVCounter; writeADVcounterdata.value.len = 1; CyBle_GattcWriteWithoutResponse(cyBle_connHandle, &writeADVcounterdata); /* Write the RGB LED Value */ writeRGBdata.attrHandle = CYBLE_RGB_LED_CONTROL_CHAR_HANDLE; writeRGBdata.value.val = RGBData; writeRGBdata.value.len = RGB_LED_DATA_LEN; CyBle_GattcWriteCharacteristicValue(cyBle_connHandle, &writeRGBdata); #endif break; case CYBLE_EVT_GATTC_WRITE_RSP: /* This event is generated when the Client device receives a response * as part of the Write request sent earlier. This indicates that * the RGB LED data was written successfully */ #ifdef DEBUG_ENABLED UART_UartPutString("CYBLE_EVT_GATTC_WRITE_RSP "); SendBLEStatetoUART(CyBle_GetState()); UART_UartPutCRLF(' '); #endif /* Disconnect the existing connection and restart scanning */ if((cyBle_connHandle.bdHandle != 0)) { CyBle_GapDisconnect(cyBle_connHandle.bdHandle); restartScanning = TRUE; #ifdef DEBUG_ENABLED UART_UartPutString("Disconnect from CYBLE_EVT_GATTC_WRITE_RSP "); SendBLEStatetoUART(CyBle_GetState()); UART_UartPutCRLF(' '); #endif } break; case CYBLE_EVT_GAP_DEVICE_DISCONNECTED: /* This event is generated when the device disconnects from an * existing connection */ deviceConnected = FALSE; #ifdef DEBUG_ENABLED UART_UartPutString("CYBLE_EVT_GAP_DEVICE_DISCONNECTED "); SendBLEStatetoUART(CyBle_GetState()); UART_UartPutCRLF(' '); #endif if((ble_gap_state == BLE_PERIPHERAL) && (switch_Role != TRUE)) { /* If the current role of this system was Peripheral and the role * is not to be switched, then restart advertisement */ if(CYBLE_STATE_DISCONNECTED == CyBle_GetState()) { CyBle_GappStartAdvertisement(CYBLE_ADVERTISING_FAST); #ifdef DEBUG_ENABLED UART_UartPutString("Restart Advertisement "); SendBLEStatetoUART(CyBle_GetState()); UART_UartPutCRLF(' '); #endif } } else if((ble_gap_state == BLE_CENTRAL) && (switch_Role != TRUE)) { /* If the current role of this system was Central and the role * is not to be switched, then restart scanning */ if(CYBLE_STATE_DISCONNECTED == CyBle_GetState()) { CyBle_GapcStartScan(CYBLE_SCANNING_FAST); #ifdef DEBUG_ENABLED UART_UartPutString("Restart Scanning "); SendBLEStatetoUART(CyBle_GetState()); UART_UartPutCRLF(' '); #endif } } break; default: eventParam = eventParam; break; } }