Hexiwear library for communicating with the on-board KW40Z BLE device. KW40Z handles also the touch buttons.
Dependents: Hexi_BLE_Example_Modified Hexi_BLE_Example_ModifiedPOTATO
Fork of Hexi_KW40Z by
Hexi_KW40Z.cpp
- Committer:
- khuang
- Date:
- 2016-09-20
- Revision:
- 5:8c7c1cc024ed
- Parent:
- 3:9e92f113c671
- Child:
- 6:23323e8aeda4
File content as of revision 5:8c7c1cc024ed:
/** BLE KW40Z Driver for Hexiwear * This file contains BLE and Touch Buttons driver functionality for Hexiwear * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright notice, this list * of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, this * list of conditions and the following disclaimer in the documentation and/or * other materials provided with the distribution. * * Neither the name of NXP, nor the names of its * contributors may be used to endorse or promote products derived from this * software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * visit: http://www.mikroe.com and http://www.nxp.com * * get support at: http://www.mikroe.com/forum and https://community.nxp.com * * Project HEXIWEAR, 2015 */ #include "Hexi_KW40Z.h" #if defined (LIB_DEBUG) RawSerial pc(USBTX, USBRX); // tx, rx #endif KW40Z::KW40Z(PinName txPin,PinName rxPin) : device(txPin, rxPin), mainThread(&KW40Z::mainStarter, this, osPriorityNormal,1024), rxThread(&KW40Z::rxStarter, this, osPriorityNormal,1024) { #if defined (LIB_DEBUG) pc.baud(115200); pc.printf("Initializing\r\n"); #endif device.baud(230400); device.format(8, Serial::None, 2); rxBuff = (uint8_t*)&hostInterface_rxPacket; /* initialize callbacks */ buttonUpCb = NULL; buttonDownCb = NULL; buttonLeftCb = NULL; buttonRightCb = NULL; buttonSlideCb = NULL; alertCb = NULL; passkeyCb = NULL; notificationsCb = NULL; kw40_version.ver_patchNumber = 0; kw40_version.ver_minorNumber = 0; kw40_version.ver_majorNumber = 0; activeTsiGroup = 0; advertisementMode = 0; linkState = 0; bondPassKey = 0; /* intialization finalized, signal to start the threads */ mainThread.signal_set(START_THREAD); rxThread.signal_set(START_THREAD); } KW40Z::~KW40Z(void) { } void KW40Z::attach_buttonUp(button_t btnFct) { buttonUpCb = btnFct; } void KW40Z::attach_buttonDown(button_t btnFct) { buttonDownCb = btnFct; } void KW40Z::attach_buttonLeft(button_t btnFct) { buttonLeftCb = btnFct; } void KW40Z::attach_buttonRight(button_t btnFct) { buttonRightCb = btnFct; } void KW40Z::attach_buttonSlide(button_t btnFct) { buttonSlideCb = btnFct; } void KW40Z::attach_alert(alert_t alertFct) { alertCb = alertFct; } void KW40Z::attach_passkey(passkey_t passkeyFct){ passkeyCb = passkeyFct; } void KW40Z::attach_notifications(notifications_t notFct) { notificationsCb = notFct; } void KW40Z::rxStarter(void const *p) { KW40Z *instance = (KW40Z*)p; instance->rxTask(); } void KW40Z::mainStarter(void const *p) { KW40Z *instance = (KW40Z*)p; instance->mainTask(); } void KW40Z::mainTask(void) { mainThread.signal_wait(START_THREAD); #if defined (LIB_DEBUG) pc.printf("MainTask Stared\r\n"); #endif SendGetActiveTsiGroup(); SendGetAdvertisementMode(); SendGetLinkState(); SendGetVersion(); while(1) { osEvent evt = queue.get(); if (evt.status == osEventMessage) { hostInterface_packet_t *rxPacket = (hostInterface_packet_t*)evt.value.p; ProcessReceivedPacket(rxPacket); mpool.free(rxPacket); } } } void KW40Z::rxTask(void) { rxThread.signal_wait(START_THREAD); #if defined (LIB_DEBUG) pc.printf("RxTask Stared\r\n"); #endif while(1) { if(device.readable()) { *rxBuff++ = device.getc(); ProcessBuffer(); /* check for buffer overflow */ if(rxBuff >= ((uint8_t*)&hostInterface_rxPacket + sizeof(hostInterface_rxPacket))) { rxBuff = (uint8_t*)&hostInterface_rxPacket; } } } } #if defined (LIB_DEBUG) void KW40Z::DebugPrintTxPacket(hostInterface_packet_t * txPacket) { char * txBuff = (char *)txPacket; uint8_t length = txPacket->length + gHostInterface_headerSize + 1; pc.printf("Tx: "); for(uint8_t i = 0; i < length; i++) { pc.printf("%02X ",*txBuff); txBuff++; } pc.printf("\r\n"); } void KW40Z::DebugPrintRxPacket() { pc.printf("RX: "); for(uint8_t * i = (uint8_t*)&hostInterface_rxPacket; i<rxBuff; i++) { pc.printf("%02X ",*i); } pc.printf("\r\n"); } #endif void KW40Z::SendPacket(hostInterface_packet_t * txPacket, bool confirmRequested) { uint8_t retries = 0; confirmReceived = false; do { char * txBuff = (char *)txPacket; uint8_t length = txPacket->length + gHostInterface_headerSize + 1; if(confirmRequested == true) { txPacket->start2 |= 0x01; } for(uint8_t i = 0; i < length; i++) { device.putc(*txBuff); txBuff++; } #if defined (LIB_DEBUG) DebugPrintTxPacket(txPacket); #endif retries++; #if defined (gHostInterface_RxConfirmationEnable) if((confirmRequested == true) && (confirmReceived == false)) { Thread::wait(gHostInterface_retransmitTimeout); } #endif } while((confirmRequested == true) && (confirmReceived == false) && (retries < gHostInterface_retransmitCount)); } void KW40Z::ProcessBuffer() { /* check if header has been received */ if(rxBuff > ((uint8_t*)&hostInterface_rxPacket + gHostInterface_headerSize)) { /* check packet header */ if((gHostInterface_startByte1 != hostInterface_rxPacket.start1)|| (gHostInterface_startByte2 != (hostInterface_rxPacket.start2 & 0xFE))|| (hostInterface_rxPacket.length > gHostInterface_dataSize)) { #if defined (LIB_DEBUG) DebugPrintRxPacket(); pc.printf("check header failed\r\n"); #endif SearchStartByte(); } else { /* check data length */ if(rxBuff > ((uint8_t*)&hostInterface_rxPacket + gHostInterface_headerSize + hostInterface_rxPacket.length)) { /* check trailer byte */ if(gHostInterface_trailerByte != hostInterface_rxPacket.data[hostInterface_rxPacket.length]) { #if defined (LIB_DEBUG) DebugPrintRxPacket(); pc.printf("trailer byte failed\r\n"); #endif SearchStartByte(); } else { #if defined (gHostInterface_RxConfirmationEnable) if(hostInterface_rxPacket.type == packetType_OK) { confirmReceived = true; } #endif /* send message to main task */ hostInterface_packet_t *rxPacket = mpool.alloc(); memcpy(rxPacket, &hostInterface_rxPacket, sizeof(hostInterface_packet_t)); queue.put(rxPacket); #if defined (LIB_DEBUG) DebugPrintRxPacket(); #endif /* reset buffer position */ rxBuff = (uint8_t*)&hostInterface_rxPacket; } } } } } void KW40Z::SearchStartByte() { bool found = false; uint8_t * rdIdx = (uint8_t*)&hostInterface_rxPacket + 1; while(rdIdx < rxBuff) { if(*rdIdx == gHostInterface_startByte1) { uint32_t len = rxBuff - rdIdx; memcpy(&hostInterface_rxPacket,rdIdx,len); rxBuff -= len; found = true; #if defined (LIB_DEBUG) pc.printf("moving "); #endif break; } rdIdx++; } if(!found) { /* reset buffer position */ rxBuff = (uint8_t*)&hostInterface_rxPacket; } #if defined (LIB_DEBUG) pc.printf("search done\r\n"); DebugPrintRxPacket(); #endif } void KW40Z::ProcessReceivedPacket(hostInterface_packet_t * rxPacket) { #if defined (LIB_DEBUG) pc.printf("packet found %d\r\n", rxPacket->type); #endif #ifdef gHostInterface_TxConfirmationEnable // acknowledge the packet reception if ( 1 == ( rxPacket->start2 & 0x01 ) ) { SendPacketOK(); } #endif switch(rxPacket->type) { /* button presses */ case packetType_pressUp: if(buttonUpCb != NULL) buttonUpCb(); break; case packetType_pressDown: if(buttonDownCb != NULL) buttonDownCb(); break; case packetType_pressLeft: if(buttonLeftCb != NULL) buttonLeftCb(); break; case packetType_pressRight: if(buttonRightCb != NULL) buttonRightCb(); break; case packetType_slide: if(buttonSlideCb != NULL) buttonSlideCb(); break; /* Alert Service */ case packetType_alertIn: if(alertCb != NULL) alertCb(&rxPacket->data[0], rxPacket->length); break; /* Passkey for pairing received */ case packetType_passDisplay: if(passkeyCb != NULL) { memcpy((uint8_t *)&bondPassKey,&rxPacket->data[0], 3); passkeyCb(); } break; /* OTAP messages */ case packetType_otapCompleted: case packetType_otapFailed: break; /* TSI Status */ case packetType_buttonsGroupSendActive: activeTsiGroup = rxPacket->data[0]; break; /* Advertisement Mode Info */ case packetType_advModeSend: advertisementMode = rxPacket->data[0]; break; /* Link State */ case packetType_linkStateSend: linkState = rxPacket->data[0]; break; /* ANCS Service Notification Received */ case packetType_notification: if(notificationsCb != NULL) notificationsCb(rxPacket->data[0], rxPacket->data[1]); break; /* Build version */ case packetType_buildVersion: kw40_version.ver_patchNumber = rxPacket->data[2]; kw40_version.ver_minorNumber = rxPacket->data[1]; kw40_version.ver_majorNumber = rxPacket->data[0]; break; case packetType_OK: /* do nothing, the flag is set in the RxTask */ break; default: break; } } void KW40Z::SendBatteryLevel(uint8_t percentage) { hostInterface_packet_t txPacket = {0}; txPacket.start1 = gHostInterface_startByte1; txPacket.start2 = gHostInterface_startByte2; txPacket.type = packetType_batteryLevel; txPacket.length = 1; txPacket.data[0] = percentage; txPacket.data[1] = gHostInterface_trailerByte; SendPacket(&txPacket, true); } void KW40Z::SendAccel(uint8_t x, uint8_t y, uint8_t z) { hostInterface_packet_t txPacket = {0}; txPacket.start1 = gHostInterface_startByte1; txPacket.start2 = gHostInterface_startByte2; txPacket.type = packetType_accel; txPacket.length = 3; txPacket.data[0] = x; txPacket.data[1] = y; txPacket.data[2] = z; txPacket.data[3] = gHostInterface_trailerByte; SendPacket(&txPacket, true); } void KW40Z::SendGyro(uint8_t x, uint8_t y, uint8_t z) { hostInterface_packet_t txPacket = {0}; txPacket.start1 = gHostInterface_startByte1; txPacket.start2 = gHostInterface_startByte2; txPacket.type = packetType_gyro; txPacket.length = 3; txPacket.data[0] = x; txPacket.data[1] = y; txPacket.data[2] = z; txPacket.data[3] = gHostInterface_trailerByte; SendPacket(&txPacket, true); } void KW40Z::SendMag(uint8_t x, uint8_t y, uint8_t z) { hostInterface_packet_t txPacket = {0}; txPacket.start1 = gHostInterface_startByte1; txPacket.start2 = gHostInterface_startByte2; txPacket.type = packetType_magnet; txPacket.length = 3; txPacket.data[0] = x; txPacket.data[1] = y; txPacket.data[2] = z; txPacket.data[3] = gHostInterface_trailerByte; SendPacket(&txPacket, true); } void KW40Z::SendAmbientLight(uint8_t percentage) { hostInterface_packet_t txPacket = {0}; txPacket.start1 = gHostInterface_startByte1; txPacket.start2 = gHostInterface_startByte2; txPacket.type = packetType_ambiLight; txPacket.length = 1; txPacket.data[0] = percentage; txPacket.data[1] = gHostInterface_trailerByte; SendPacket(&txPacket, true); } void KW40Z::SendTemperature(uint16_t celsius) { hostInterface_packet_t txPacket = {0}; txPacket.start1 = gHostInterface_startByte1; txPacket.start2 = gHostInterface_startByte2; txPacket.type = packetType_temperature; txPacket.length = 2; memcpy(&txPacket.data[0],(uint8_t*)&celsius,txPacket.length); txPacket.data[2] = gHostInterface_trailerByte; SendPacket(&txPacket, true); } void KW40Z::SendHumidity(uint16_t percentage) { hostInterface_packet_t txPacket = {0}; txPacket.start1 = gHostInterface_startByte1; txPacket.start2 = gHostInterface_startByte2; txPacket.type = packetType_humidity; txPacket.length = 2; memcpy(&txPacket.data[0],(uint8_t*)&percentage,txPacket.length); txPacket.data[2] = gHostInterface_trailerByte; SendPacket(&txPacket, true); } void KW40Z::SendPressure(uint16_t pascal) { hostInterface_packet_t txPacket = {0}; txPacket.start1 = gHostInterface_startByte1; txPacket.start2 = gHostInterface_startByte2; txPacket.type = packetType_pressure; txPacket.length = 2; memcpy(&txPacket.data[0],(uint8_t*)&pascal,txPacket.length); txPacket.data[2] = gHostInterface_trailerByte; SendPacket(&txPacket, true); } void KW40Z::SendHeartRate(uint8_t rate) { hostInterface_packet_t txPacket = {0}; txPacket.start1 = gHostInterface_startByte1; txPacket.start2 = gHostInterface_startByte2; txPacket.type = packetType_steps; txPacket.length = 1; txPacket.data[0] = rate; txPacket.data[1] = gHostInterface_trailerByte; SendPacket(&txPacket, true); } void KW40Z::SendSteps(uint16_t steps) { hostInterface_packet_t txPacket = {0}; txPacket.start1 = gHostInterface_startByte1; txPacket.start2 = gHostInterface_startByte2; txPacket.type = packetType_steps; txPacket.length = 2; memcpy(&txPacket.data[0],(uint8_t*)&steps,txPacket.length); txPacket.data[2] = gHostInterface_trailerByte; SendPacket(&txPacket, true); } void KW40Z::SendCalories(uint16_t calories) { hostInterface_packet_t txPacket = {0}; txPacket.start1 = gHostInterface_startByte1; txPacket.start2 = gHostInterface_startByte2; txPacket.type = packetType_calories; txPacket.length = 2; memcpy(&txPacket.data[0],(uint8_t*)&calories,txPacket.length); txPacket.data[2] = gHostInterface_trailerByte; SendPacket(&txPacket, true); } void KW40Z::SendAlert(uint8_t *pData, uint8_t length) { hostInterface_packet_t txPacket = {0}; txPacket.start1 = gHostInterface_startByte1; txPacket.start2 = gHostInterface_startByte2; txPacket.type = packetType_alertOut; txPacket.length = length; memcpy(&txPacket.data[0],pData,length); txPacket.data[length] = gHostInterface_trailerByte; SendPacket(&txPacket, true); } void KW40Z::ToggleTsiGroup(void) { hostInterface_packet_t txPacket = {0}; txPacket.start1 = gHostInterface_startByte1; txPacket.start2 = gHostInterface_startByte2; txPacket.type = packetType_buttonsGroupToggleActive; txPacket.length = 0; txPacket.data[0] = gHostInterface_trailerByte; SendPacket(&txPacket, true); } void KW40Z::ToggleAdvertisementMode(void) { hostInterface_packet_t txPacket = {0}; txPacket.start1 = gHostInterface_startByte1; txPacket.start2 = gHostInterface_startByte2; txPacket.type = packetType_advModeToggle; txPacket.length = 0; txPacket.data[0] = gHostInterface_trailerByte; SendPacket(&txPacket, true); } void KW40Z::SendSetApplicationMode(gui_current_app_t mode) { hostInterface_packet_t txPacket = {0}; txPacket.start1 = gHostInterface_startByte1; txPacket.start2 = gHostInterface_startByte2; txPacket.type = packetType_appMode; txPacket.length = 1; txPacket.data[0] = (uint8_t)mode; txPacket.data[1] = gHostInterface_trailerByte; SendPacket(&txPacket, true); } void KW40Z::SendGetActiveTsiGroup(void) { hostInterface_packet_t txPacket = {0}; txPacket.start1 = gHostInterface_startByte1; txPacket.start2 = gHostInterface_startByte2; txPacket.type = packetType_buttonsGroupGetActive; txPacket.length = 0; txPacket.data[0] = gHostInterface_trailerByte; SendPacket(&txPacket, false); } void KW40Z::SendGetAdvertisementMode(void) { hostInterface_packet_t txPacket = {0}; txPacket.start1 = gHostInterface_startByte1; txPacket.start2 = gHostInterface_startByte2; txPacket.type = packetType_advModeGet; txPacket.length = 0; txPacket.data[0] = gHostInterface_trailerByte; SendPacket(&txPacket, false); } void KW40Z::SendGetLinkState(void) { hostInterface_packet_t txPacket = {0}; txPacket.start1 = gHostInterface_startByte1; txPacket.start2 = gHostInterface_startByte2; txPacket.type = packetType_linkStateGet; txPacket.length = 0; txPacket.data[0] = gHostInterface_trailerByte; SendPacket(&txPacket, false); } void KW40Z::SendGetVersion(void) { hostInterface_packet_t txPacket = {0}; txPacket.start1 = gHostInterface_startByte1; txPacket.start2 = gHostInterface_startByte2; txPacket.type = packetType_buildVersion; txPacket.length = 3; txPacket.data[0] = HEXIWEAR_VERSION_MAJOR; txPacket.data[1] = HEXIWEAR_VERSION_MINOR; txPacket.data[2] = HEXIWEAR_VERSION_PATCH; txPacket.data[3] = gHostInterface_trailerByte; SendPacket(&txPacket, false); } void KW40Z::SendPacketOK(void) { hostInterface_packet_t txPacket = {0}; txPacket.start1 = gHostInterface_startByte1; txPacket.start2 = gHostInterface_startByte2; txPacket.type = packetType_OK; txPacket.length = 0; txPacket.data[0] = gHostInterface_trailerByte; SendPacket(&txPacket, false); } uint8_t KW40Z::GetAdvertisementMode(void) { return advertisementMode; } uint32_t KW40Z::GetPassKey(void) { return bondPassKey; } uint8_t KW40Z::GetLinkState(void) { return linkState; } hexiwear_version_t KW40Z::GetVersion(void) { return kw40_version; } uint8_t KW40Z::GetTsiGroup(void) { return activeTsiGroup; }