static unsigned getUCSChar(const std::string& unicode4HexChar) { return (HexToDecimal(unicode4HexChar[0]) << 12) | (HexToDecimal(unicode4HexChar[1]) << 8) | (HexToDecimal(unicode4HexChar[2]) << 4) | (HexToDecimal(unicode4HexChar[3])); }
/******************************************************************************* * Function Name: Ancs_UpdateOutputInformation() ******************************************************************************** * Summary: * This function prints data onto the UART terminal. * * Parameters: * None * * Return: * None * * Theory: * The function prints the number of Missed calls, Voicemails and Emails on the * screen. The same line on the terminal is updated with new data if no other * notification came up. * *******************************************************************************/ static void Ancs_UpdateOutputInformation(void) { /* Update the same line if no new notification since. */ if(printStatus == PRINT_SAME_LINE) { /* Go back to the same line */ UART_UartPutChar(13); } else { UART_UartPutString("\n\r"); } printStatus = PRINT_SAME_LINE; UART_UartPutString("Missed calls: "); UART_UartPutChar(HexToDecimal(missedCallCount, 1)); UART_UartPutChar(HexToDecimal(missedCallCount, 0)); UART_UartPutString(" Voicemails: "); UART_UartPutChar(HexToDecimal(voiceMailCount, 1)); UART_UartPutChar(HexToDecimal(voiceMailCount, 0)); UART_UartPutString(" Emails: "); UART_UartPutChar(HexToDecimal(emailCount, 1)); UART_UartPutChar(HexToDecimal(emailCount, 0)); }
/** * Parses an input Intel HEX formatted stream one character at a time, loading * the data contents into the device's internal FLASH memory. * * \param[in] ReadCharacter Next input ASCII byte of data to parse */ static void ParseIntelHEXByte(const char ReadCharacter) { /* Reset the line parser while waiting for a new line to start */ if ((HEXParser.ParserState == HEX_PARSE_STATE_WAIT_LINE) || (ReadCharacter == ':')) { HEXParser.Checksum = 0; HEXParser.CurrAddress = HEXParser.CurrBaseAddress; HEXParser.ReadMSB = false; /* ASCII ':' indicates the start of a new HEX record */ if (ReadCharacter == ':') HEXParser.ParserState = HEX_PARSE_STATE_BYTE_COUNT; return; } /* Only allow ASCII HEX encoded digits, ignore all other characters */ int8_t ReadCharacterDec = HexToDecimal(ReadCharacter); if (ReadCharacterDec < 0) return; /* Read and convert the next nibble of data from the current character */ HEXParser.Data = (HEXParser.Data << 4) | ReadCharacterDec; HEXParser.ReadMSB = !HEXParser.ReadMSB; /* Only process further when a full byte (two nibbles) have been read */ if (HEXParser.ReadMSB) return; /* Intel HEX checksum is for all fields except starting character and the * checksum itself */ if (HEXParser.ParserState != HEX_PARSE_STATE_CHECKSUM) HEXParser.Checksum += HEXParser.Data; switch (HEXParser.ParserState) { case HEX_PARSE_STATE_BYTE_COUNT: HEXParser.DataRem = HEXParser.Data; HEXParser.ParserState = HEX_PARSE_STATE_ADDRESS_HIGH; break; case HEX_PARSE_STATE_ADDRESS_HIGH: HEXParser.CurrAddress += ((uint16_t)HEXParser.Data << 8); HEXParser.ParserState = HEX_PARSE_STATE_ADDRESS_LOW; break; case HEX_PARSE_STATE_ADDRESS_LOW: HEXParser.CurrAddress += HEXParser.Data; HEXParser.ParserState = HEX_PARSE_STATE_RECORD_TYPE; break; case HEX_PARSE_STATE_RECORD_TYPE: HEXParser.RecordType = HEXParser.Data; HEXParser.ParserState = (HEXParser.DataRem ? HEX_PARSE_STATE_READ_DATA : HEX_PARSE_STATE_CHECKSUM); break; case HEX_PARSE_STATE_READ_DATA: /* Track the number of read data bytes in the record */ HEXParser.DataRem--; /* Protect the bootloader against being written to */ if (HEXParser.CurrAddress >= BOOT_START_ADDR) { HEXParser.ParserState = HEX_PARSE_STATE_WAIT_LINE; PageDirty = false; return; } /* Wait for a machine word (two bytes) of data to be read */ if (HEXParser.DataRem & 0x01) { HEXParser.PrevData = HEXParser.Data; break; } /* Convert the last two received data bytes into a 16-bit word */ uint16_t NewDataWord = ((uint16_t)HEXParser.Data << 8) | HEXParser.PrevData; switch (HEXParser.RecordType) { case HEX_RECORD_TYPE_Data: /* If we are writing to a new page, we need to erase it first */ if (!(PageDirty)) { boot_page_erase(HEXParser.PageStartAddress); boot_spm_busy_wait(); PageDirty = true; } /* Fill the FLASH memory buffer with the new word of data */ boot_page_fill(HEXParser.CurrAddress, NewDataWord); HEXParser.CurrAddress += 2; /* Flush the FLASH page to physical memory if we are crossing a page boundary */ FlushPageIfRequired(); break; case HEX_RECORD_TYPE_ExtendedSegmentAddress: /* Extended address data - store the upper 12-bits of the new address */ HEXParser.CurrBaseAddress = ((uint32_t)NewDataWord << 4); break; case HEX_RECORD_TYPE_ExtendedLinearAddress: /* Extended address data - store the upper 16-bits of the new address */ HEXParser.CurrBaseAddress = ((uint32_t)NewDataWord << 16); break; } if (!HEXParser.DataRem) HEXParser.ParserState = HEX_PARSE_STATE_CHECKSUM; break; case HEX_PARSE_STATE_CHECKSUM: /* Verify checksum of the completed record */ if (HEXParser.Data != ((~HEXParser.Checksum + 1) & 0xFF)) break; /* Flush the FLASH page to physical memory if we are crossing a page boundary */ FlushPageIfRequired(); /* If end of the HEX file reached, the bootloader should exit at next opportunity */ if (HEXParser.RecordType == HEX_RECORD_TYPE_EndOfFile) RunBootloader = false; break; default: HEXParser.ParserState = HEX_PARSE_STATE_WAIT_LINE; break; } }
/******************************************************************************* * Function Name: StackEventHandler() ******************************************************************************** * Summary: * Event handler for the BLE events processing. * * Parameters: * uint32 eventCode: The event to be processed * void * eventParam: Pointer to hold the additional information associated * with an event * * Return: * None * * Theory: * The function is responsible for handling the events generated by the stack. * It first starts advertisement once the stack is initialized. * Upon advertisement timeout or disconnect events, this function sets a flag * to indicate to the main() function that it should enter Hibernate mode. * * Once the device is connected, this function initiates an authentication * request. It displays a 6-digit passkey on the UART output on a PC and asks * the user to enter this key on the iOS device (NP) side. * Once the authentication is complete, the function starts the discovery * procedure to know whether ANCS service is supported by the peer device. * * When the automated service discovery is complete, the function starts a manual * discovery procedure for the ANCS service (since the BLE component does not * handle discovery of custom services yet - that will be added as part of * Creator 3.2). * * When the automated service discovery is complete and the ANCS service is not * found, the function subscribes to the Service Changed characteristic * indication to know if and when the iOS device adds ANCS support later. * * Once the ANCS service is found and a new GATT Notification comes for any of * the ANCS characteristic, it calls the corresponding function in ANCS.c. * *******************************************************************************/ void StackEventHandler(uint32 eventCode, void * eventParam) { CYBLE_GATTC_HANDLE_VALUE_NTF_PARAM_T * handleValueNotification; switch(eventCode) { case CYBLE_EVT_STACK_ON: /* Minor change in ADV packet for service solicitation */ cyBle_discoveryData.advData[10] = 0x15; /* Start advertisement after stack is initialized */ UART_UartPutString("\n\rAdvertising."); CyBle_GappStartAdvertisement(CYBLE_ADVERTISING_FAST); break; case CYBLE_EVT_GAPP_ADVERTISEMENT_START_STOP: if(authState != AUTHENTICATION_BONDING_REMOVE_WAITING_EVENT) { if(CyBle_GetState() == CYBLE_STATE_DISCONNECTED) { UART_UartPutString("\n\rAdvertisement timed out. "); UART_UartPutString("Going to Hibernate mode."); /* Enter hibernate mode upon advertisement timeout */ enterHibernateFlag = true; } } else { UART_UartPutString("\n\rAdvertisement stopped. "); authState = AUTHENTICATION_BONDING_REMOVE_GO_AHEAD; } break; case CYBLE_EVT_GAP_DEVICE_DISCONNECTED: /* Enter Hibernate mode upon disconnect * Previous state is erased. */ if(authState != AUTHENTICATION_BONDING_REMOVE_WAITING_EVENT) { UART_UartPutString("\n\rDisconnected. Going to Hibernate mode."); enterHibernateFlag = true; } else { UART_UartPutString("\n\rDisconnected. "); authState = AUTHENTICATION_BONDING_REMOVE_GO_AHEAD; } Ancs_Reset(); break; case CYBLE_EVT_GAP_DEVICE_CONNECTED: UART_UartPutString("\n\rConnected to a peer device."); /* Send authentication request upon connection */ CyBle_GapAuthReq(cyBle_connHandle.bdHandle, &cyBle_authInfo); break; case CYBLE_EVT_GAP_PASSKEY_DISPLAY_REQUEST: UART_UartPutString("\n\rEnter this passkey in your iPhone: "); UART_UartPutChar(HexToDecimal(*(uint32 *)eventParam, 5)); UART_UartPutChar(HexToDecimal(*(uint32 *)eventParam, 4)); UART_UartPutChar(HexToDecimal(*(uint32 *)eventParam, 3)); UART_UartPutChar(HexToDecimal(*(uint32 *)eventParam, 2)); UART_UartPutChar(HexToDecimal(*(uint32 *)eventParam, 1)); UART_UartPutChar(HexToDecimal(*(uint32 *)eventParam, 0)); break; case CYBLE_EVT_GAP_AUTH_COMPLETE: /* Authentication complete; initiate service discovery procedure */ UART_UartPutString("\n\rAuthentication complete. "); authState = AUTHENTICATION_COMPLETE_BONDING_REQD; CyBle_GattcStartDiscovery(cyBle_connHandle); break; case CYBLE_EVT_GAP_AUTH_FAILED: /* Authentication failed; enter Hibernate mode */ UART_UartPutString("\n\rAuthentication failed. Going to Hibernate mode."); enterHibernateFlag = true; /* Update authentication state so that bond information could be * removed later. */ authState = AUTHENTICATION_BONDING_COMPLETE; break; case CYBLE_EVT_GATTC_INDICATION: /* Server's services changed; restart service discovery */ UART_UartPutString("\n\rService changed indication. Redo service discovery."); Ancs_Reset(); CyBle_GattcStartDiscovery(cyBle_connHandle); break; case CYBLE_EVT_GATTC_DISCOVERY_COMPLETE: /* Automatic discovery does not cover discovery of service snd * characteristics with custom 128-bit UUIDs. This has to be done * manually. The Read by Group response for Service discovery covers * the ANCS custom service. For the ANCS service characteristics, the * Read by Type Request has to be sent by the application. */ if(ANCS_DISC_SERVICE_DISCOVERED == ancsDiscoveryStatus) { CyBle_GattcDiscoverAllCharacteristics(cyBle_connHandle, ancsServiceRange); } else if(ANCS_DISC_NONE_DISCOVERED == ancsDiscoveryStatus) { UART_UartPutString("\n\rANCS service not found. "); /* Service discovery procedure complete; subscribe to the GATT * Service changed indication by writing 0x02 to its CCCD. */ if((serviceChangedCccdWriteStatus == SERVICE_CHANGED_CCCD_WRITE_REQ_NOT_SENT) && (cyBle_gattc.serviceChanged.valueHandle != CYBLE_GATT_INVALID_ATTR_HANDLE_VALUE)) { serviceChangedCccdPacket.value = cccdIndFlagSetStruct; serviceChangedCccdPacket.attrHandle = cyBle_gattc.cccdHandle; CyBle_GattcWriteCharacteristicDescriptors(cyBle_connHandle, &serviceChangedCccdPacket); } /* Internal state machine tracking the CCCD status */ serviceChangedCccdWriteStatus = SERVICE_CHANGED_CCCD_WRITE_REQ_SENT; } else { /* Other conditions need not be handled; they are handled * in the event handler in ANCS.c. */ } break; case CYBLE_EVT_GATTC_READ_BY_GROUP_TYPE_RSP: case CYBLE_EVT_GATTC_READ_BY_TYPE_RSP: case CYBLE_EVT_GATTC_FIND_INFO_RSP: case CYBLE_EVT_GATTC_WRITE_RSP: case CYBLE_EVT_GATTC_ERROR_RSP: /* See if the events are for ANCS */ Ancs_EventHandler(eventCode, eventParam); break; case CYBLE_EVT_GATTC_HANDLE_VALUE_NTF: /* See if the notification packet is for any ANCS characteristic */ handleValueNotification = (CYBLE_GATTC_HANDLE_VALUE_NTF_PARAM_T *)eventParam; if(handleValueNotification->handleValPair.attrHandle == ancsNotifSourceCharHandle) { /* Notification source characteristic has a new notification */ Ancs_HandleNotifications(handleValueNotification->handleValPair.value.val); } else if(handleValueNotification->handleValPair.attrHandle == ancsDataSourceCharHandle) { /* Data source characteristic has a new notification */ Ancs_HandleData(handleValueNotification->handleValPair.value.val); } else { /* Some other characteristic notification; ignore */ } break; default: break; } }