/********************************************************************* * @fn performPeriodicTask * * @brief Perform a periodic application task. * * @param none * * @return none */ static void performPeriodicTask( void ) { uint8 notify_interval; int32 n32; //Measurement Ready - send if Client Configuration is Configured if(temperatureMeasCharConfig == true) { //read stored interval value Thermometer_GetParameter( THERMOMETER_INTERVAL, ¬ify_interval ); n32 = ((uint32)(notify_interval)) * (1000); //if interval is zero don't send indication if( n32 != 0) { // send thermometer measurement notification thermometerMeasIndicate(); // Start interval timer osal_start_timerEx( thermometerTaskId, TH_PERIODIC_MEAS_EVT, n32 ); } } }
/********************************************************************* * @fn thermometer_HandleKeys * * @brief Handles all key events for this device. * * @param shift - true if in shift/alt. * @param keys - bit field for key events. Valid entries: * HAL_KEY_SW_2 * HAL_KEY_SW_1 * * @return none */ static void thermometer_HandleKeys( uint8 shift, uint8 keys ) { bStatus_t status; uint8 notify_interval; if ( keys & HAL_KEY_SW_1 ) { // set simulated measurement flag index thermometerFlagsIdx+=1; if (thermometerFlagsIdx == FLAGS_IDX_MAX) { thermometerFlagsIdx = 0; } } //read stored interval value Thermometer_GetParameter( THERMOMETER_INTERVAL, ¬ify_interval ); if(notify_interval == 0) { thMeasTimerRunning = FALSE; } if ( keys & HAL_KEY_SW_2 ) { // if device is not in a connection, pressing the right key should toggle // advertising on and off. If timer is running, then will adv when meas is ready if((gapProfileState != GAPROLE_CONNECTED) && (thMeasTimerRunning == FALSE)) { uint8 current_adv_enabled_status; uint8 new_adv_enabled_status; //Find the current GAP advertisement status GAPRole_GetParameter( GAPROLE_ADVERT_ENABLED, ¤t_adv_enabled_status ); if( current_adv_enabled_status == FALSE ) { new_adv_enabled_status = TRUE; } else { new_adv_enabled_status = FALSE; } //change the GAP advertisement status to opposite of current status GAPRole_SetParameter( GAPROLE_ADVERT_ENABLED, sizeof( uint8 ), &new_adv_enabled_status ); } else //timer is running, so allow simulated changes { //change temperature, remove single precision if((thermometerCelcius) < 0X000175) { thermometerCelcius +=1; } else { uint8 thInterval = 30; attHandleValueInd_t intervalIndication; thermometerCelcius = 0X000173; //Simulate interval change Thermometer_SetParameter( THERMOMETER_INTERVAL, THERMOMETER_INTERVAL_LEN, &thInterval ); if(temperatureIntervalConfig == true) { intervalIndication.value[0] = thInterval; intervalIndication.handle = THERMOMETER_INTERVAL_VALUE_POS; status = Thermometer_IntervalIndicate( gapConnHandle, &intervalIndication, thermometerTaskId ); // we can fail if there was pending meas or not connected if (status != SUCCESS) { //queue indication thermometerStoreIndications(&intervalIndication); } } } } } }
/********************************************************************* * @fn Thermometer_ProcessEvent * * @brief Thermometer Application Task event processor. This function * is called to process all events for the task. Events * include timers, messages and any other user defined events. * * @param task_id - The OSAL assigned task ID. * @param events - events to process. This is a bit map and can * contain more than one event. * * @return events not processed */ uint16 Thermometer_ProcessEvent( uint8 task_id, uint16 events ) { VOID task_id; // OSAL required parameter that isn't used in this function uint8 notify_interval; int32 n32; if ( events & SYS_EVENT_MSG ) { uint8 *pMsg; if ( (pMsg = osal_msg_receive( thermometerTaskId )) != NULL ) { thermometer_ProcessOSALMsg( (osal_event_hdr_t *)pMsg ); // Release the OSAL message VOID osal_msg_deallocate( pMsg ); } // return unprocessed events return (events ^ SYS_EVENT_MSG); } if ( events & TH_START_DEVICE_EVT ) { // Start the Device VOID GAPRole_StartDevice( &thermometer_PeripheralCBs ); // Register with bond manager after starting device VOID GAPBondMgr_Register( &thermometer_BondMgrCBs ); updateUI(); return ( events ^ TH_START_DEVICE_EVT ); } if ( events & TH_START_DISCOVERY_EVT ) { if ( timeAppPairingStarted ) { // Postpone discovery until pairing completes timeAppDiscPostponed = TRUE; } else { timeAppDiscState = timeAppDiscStart(); } timeAppDiscState = timeAppDiscStart(); return ( events ^ TH_START_DISCOVERY_EVT ); } //periodic indications - if enabled if ( events & TH_PERIODIC_MEAS_EVT ) { // Perform periodic application task performPeriodicTask(); return (events ^ TH_PERIODIC_MEAS_EVT); } //periodic notifications for IMEAS if ( events & TH_PERIODIC_IMEAS_EVT ) { // Perform periodic application task performPeriodicImeasTask(); return (events ^ TH_PERIODIC_IMEAS_EVT); } // Disconnect after sending measurement if ( events & TH_DISCONNECT_EVT ) { uint8 advEnable = FALSE; //disable advertising on disconnect GAPRole_SetParameter( GAPROLE_ADVERT_ENABLED, sizeof( uint8 ), &advEnable ); // Terminate Connection GAPRole_TerminateConnection(); return (events ^ TH_DISCONNECT_EVT); } if ( events & TH_CCC_UPDATE_EVT ) //This event is triggered when CCC is enabled if (gapProfileState == GAPROLE_CONNECTED) { temperatureMeasCharConfig = true; //if previously connected and measurements are active send stored if( connectedToLastAddress == true) { //send stored measurements thermometerSendStoredMeas(); } //Only start meas timer if it's not running if(thMeasTimerRunning == FALSE) { //read stored interval value Thermometer_GetParameter( THERMOMETER_INTERVAL, ¬ify_interval ); n32 = ((uint32)(notify_interval)) * (1000); //zero interval means should not perform meas if (n32 !=0) { // Start interval timer osal_start_timerEx( thermometerTaskId, TH_PERIODIC_MEAS_EVT, n32 ); thMeasTimerRunning = TRUE; } } return (events ^ TH_CCC_UPDATE_EVT); } return 0; }
/********************************************************************* * @fn thermometerMeasIndicate * * @brief Prepare and send a thermometer measurement indication * * @return none */ static void thermometerMeasIndicate(void) { // Thermometer measurement value stored in this structure. attHandleValueInd_t thermometerMeas; thermometerMeas.pValue = GATT_bm_alloc(gapConnHandle, ATT_HANDLE_VALUE_IND, THERMOMETER_MEAS_LEN, NULL); if (thermometerMeas.pValue != NULL) { // att value notification structure uint8 *p = thermometerMeas.pValue; // temperature uint32 temperature; //flags uint8 flags = thermometerFlags[thermometerFlagsIdx]; // flags 1 byte long *p++ = flags; if(flags & THERMOMETER_FLAGS_FARENHEIT) { temperature = (thermometerCelcius *9/5) +320; } else { temperature = thermometerCelcius; } temperature = 0xFF000000 | temperature; //osal_buffer_uint32 p = osal_buffer_uint32( p, temperature ); //timestamp if (flags & THERMOMETER_FLAGS_TIMESTAMP) { UTCTimeStruct time; // Get time structure from OSAL osal_ConvertUTCTime( &time, osal_getClock() ); *p++ = LO_UINT16(time.year); *p++ = HI_UINT16(time.year); *p++ = time.month; *p++ = time.day; *p++ = time.hour; *p++ = time.minutes; *p++ = time.seconds; } if(flags & THERMOMETER_FLAGS_TYPE) { uint8 site; Thermometer_GetParameter( THERMOMETER_TYPE, &site ); *p++ = site; } thermometerMeas.len = (uint8) (p - thermometerMeas.pValue); thermometerMeas.handle = THERMOMETER_TEMP_VALUE_POS; // Queue indication. thermometerStoreIndications( &thermometerMeas); //advertise measurement is ready thermometer_Advertise(); } }
/********************************************************************* * @fn thermometerMeasNotify * * @brief Prepare and send a thermometer measurement notification * * @return none */ static void thermometerImeasNotify(void) { if (temperatureIMeasCharConfig == true) { attHandleValueNoti_t thermometerIMeas; thermometerIMeas.pValue = GATT_bm_alloc( gapConnHandle, ATT_HANDLE_VALUE_NOTI, THERMOMETER_IMEAS_LEN, NULL ); if ( thermometerIMeas.pValue != NULL ) { // att value notification structure uint8 *p = thermometerIMeas.pValue; // temperature uint32 temperature; //flags uint8 flags = thermometerFlags[thermometerFlagsIdx]; // flags 1 byte long *p++ = flags; if(flags & THERMOMETER_FLAGS_FARENHEIT) { temperature = (thermometerCelcius *9/5) +320; } else { temperature = thermometerCelcius; } temperature = 0xFF000000 | temperature; //osal_buffer_uint32 p = osal_buffer_uint32( p, temperature ); //timestamp if (flags & THERMOMETER_FLAGS_TIMESTAMP) { UTCTimeStruct time; // Get time structure from OSAL osal_ConvertUTCTime( &time, osal_getClock() ); *p++ = LO_UINT16(time.year); *p++ = HI_UINT16(time.year); *p++ = time.month; *p++ = time.day; *p++ = time.hour; *p++ = time.minutes; *p++ = time.seconds; } if(flags & THERMOMETER_FLAGS_TYPE) { uint8 site; Thermometer_GetParameter( THERMOMETER_TYPE, &site ); *p++ = site; } thermometerIMeas.len = (uint8) (p - thermometerIMeas.pValue); if ( Thermometer_IMeasNotify( gapConnHandle, &thermometerIMeas) != SUCCESS ) { GATT_bm_free( (gattMsg_t *)&thermometerIMeas, ATT_HANDLE_VALUE_NOTI ); } } } }
/********************************************************************* * @fn Thermometer_handleKeys * * @brief Handles all key events for this device. * * @param shift - true if in shift/alt. * @param keys - bit field for key events. * * @return none */ static void Thermometer_handleKeys(uint8_t shift, uint8_t keys) { bStatus_t status; uint8_t notify_interval; if (keys & KEY_UP) { // Set simulated measurement flag index. thermometerFlagsIdx+=1; if (thermometerFlagsIdx == FLAGS_IDX_MAX) { thermometerFlagsIdx = 0; } } // Read stored interval value. Thermometer_GetParameter(THERMOMETER_INTERVAL, ¬ify_interval); if(notify_interval == 0) { thMeasTimerRunning = FALSE; } if (keys & KEY_RIGHT) { // If device is not in a connection, pressing the right key should toggle // advertising on and off. If timer is running, then will adv when meas is // ready. if((gapProfileState != GAPROLE_CONNECTED) && (thMeasTimerRunning == FALSE)) { uint8_t current_adv_enabled_status; uint8_t new_adv_enabled_status; // Find the current GAP advertisement status. GAPRole_GetParameter(GAPROLE_ADVERT_ENABLED, ¤t_adv_enabled_status); if(current_adv_enabled_status == FALSE) { new_adv_enabled_status = TRUE; } else { new_adv_enabled_status = FALSE; } // Change the GAP advertisement status to opposite of current status. GAPRole_SetParameter(GAPROLE_ADVERT_ENABLED, sizeof(uint8_t), &new_adv_enabled_status); } // Timer is running, so allow simulated changes. else { // Change temperature, remove single precision. if((thermometerCelcius) < 0x000175) { thermometerCelcius += 1; } else { uint16_t thInterval = 30; thermometerCelcius = 0x000173; // Simulate interval change. Thermometer_SetParameter(THERMOMETER_INTERVAL, THERMOMETER_INTERVAL_LEN, &thInterval); if(temperatureIntervalConfig == true) { attHandleValueInd_t intervalInd; intervalInd.pValue = GATT_bm_alloc(thermometer_connHandle, ATT_HANDLE_VALUE_IND, THERMOMETER_INTERVAL_LEN, NULL); if (intervalInd.pValue != NULL) { intervalInd.len = THERMOMETER_INTERVAL_LEN; intervalInd.pValue[0] = LO_UINT16(thInterval); intervalInd.pValue[1] = HI_UINT16(thInterval); intervalInd.handle = THERMOMETER_INTERVAL_VALUE_POS; status = Thermometer_IntervalIndicate(thermometer_connHandle, &intervalInd, ICall_getEntityId()); // We can fail if there was pending meas or not connected. if (status != SUCCESS) { // Queue indication. Thermometer_storeIndications(&intervalInd); } } } } } } }