/* * Copyright Cypress Semiconductor Corporation, 2014-2015 All rights reserved. * * This software, associated documentation and materials ("Software") is * owned by Cypress Semiconductor Corporation ("Cypress") and is * protected by and subject to worldwide patent protection (UnitedStates and foreign), United States copyright laws and international * treaty provisions. Therefore, unless otherwise specified in a separate license agreement between you and Cypress, this Software * must be treated like any other copyrighted material. Reproduction, * modification, translation, compilation, or representation of this * Software in any other form (e.g., paper, magnetic, optical, silicon) * is prohibited without Cypress's express written permission. * * Disclaimer: THIS SOFTWARE IS PROVIDED AS-IS, WITH NO WARRANTY OF ANY * KIND, EXPRESS OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, * NONINFRINGEMENT, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE. Cypress reserves the right to make changes * to the Software without notice. Cypress does not assume any liability * arising out of the application or use of Software or any product or * circuit described in the Software. Cypress does not authorize its * products for use as critical components in any products where a * malfunction or failure may reasonably be expected to result in * significant injury or death ("High Risk Product"). By including * Cypress's product in a High Risk Product, the manufacturer of such * system or application assumes all risk of such use and in doing so * indemnifies Cypress against all liability. * * Use of this Software may be limited by and subject to the applicable * Cypress software license agreement. * * */ #import "ThermometerModel.h" #import "CBMoralManager.h" /*! * @class ThermometerModel * * @discussion Class to handle the thermometer service related operations * */ @interface ThermometerModel () { void (^cbCharacteristicHandler)(BOOL success, NSError *error); void (^cbCharacteristicDiscoverHandler)(BOOL success, NSError *error); CBCharacteristic *RSCCharacter; } @end @implementation ThermometerModel @synthesize tempStringValue; @synthesize mesurementType; @synthesize timeStampString; @synthesize tempType; - (instancetype)init { self = [super init]; return self; } /*! * @method startDiscoverChar: * * @discussion Discovers the specified characteristics of a service.. */ -(void)startDiscoverChar:(void (^) (BOOL success, NSError *error))handler { cbCharacteristicDiscoverHandler = handler; [[CBMoralManager sharedManager] setCbCharacteristicDelegate:self]; [[[CBMoralManager sharedManager] myPeripheral] discoverCharacteristics:nil forService:[[CBMoralManager sharedManager] myService]]; } /*! * @method updateCharacteristicWithHandler: * * @discussion Sets notifications or indications for the value of a specified characteristic. */ -(void)updateCharacteristicWithHandler:(void (^) (BOOL success, NSError *error))handler { cbCharacteristicHandler = handler; } /*! * @method stopUpdate * * @discussion Stop notifications or indications for the value of a specified characteristic. */ -(void)stopUpdate { cbCharacteristicHandler = nil; if ([[[CBMoralManager sharedManager] myService].UUID isEqual:THM_SERVICE_UUID]) { for (CBCharacteristic *aChar in [[CBMoralManager sharedManager] myService].characteristics) { if ([aChar.UUID isEqual:THM_TEMPERATURE_MEASUREMENT_CHARACTERISTIC_UUID]){ if (aChar.isNotifying) { [[[CBMoralManager sharedManager] myPeripheral] setNotifyValue:NO forCharacteristic:aChar]; [Utilities logDataWithService:[ResourceHandler getServiceNameForUUID:THM_SERVICE_UUID] characteristic:[ResourceHandler getCharacteristicNameForUUID:THM_TEMPERATURE_MEASUREMENT_CHARACTERISTIC_UUID] descriptor:nil operation:STOP_INDICATE]; } cbCharacteristicDiscoverHandler(YES,nil); } } } } #pragma mark - CBCharecteristicManger /*! * @method peripheral: didDiscoverCharacteristicsForService: error: * * @discussion Method invoked when characteristics are discovered for a service * */ -(void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error { if ([service.UUID isEqual:THM_SERVICE_UUID]){ for (CBCharacteristic *aChar in service.characteristics){ if ([aChar.UUID isEqual:THM_TEMPERATURE_MEASUREMENT_CHARACTERISTIC_UUID]){ [[[CBMoralManager sharedManager] myPeripheral] setNotifyValue:YES forCharacteristic:aChar]; [Utilities logDataWithService:[ResourceHandler getServiceNameForUUID:THM_SERVICE_UUID] characteristic:[ResourceHandler getCharacteristicNameForUUID:THM_TEMPERATURE_MEASUREMENT_CHARACTERISTIC_UUID] descriptor:nil operation:START_INDICATE]; cbCharacteristicDiscoverHandler(YES,nil); } else if([aChar.UUID isEqual:THM_TEMPERATURE_TYPE_CHARACTERISTIC_UUID]) { [[[CBMoralManager sharedManager] myPeripheral] readValueForCharacteristic:aChar]; [Utilities logDataWithService:[ResourceHandler getServiceNameForUUID:THM_SERVICE_UUID] characteristic:[ResourceHandler getCharacteristicNameForUUID:THM_TEMPERATURE_TYPE_CHARACTERISTIC_UUID] descriptor:nil operation:READ_REQUEST]; } } } else { cbCharacteristicDiscoverHandler(NO,nil); } } /*! * @method peripheral: didUpdateValueForCharacteristic: error: * * @discussion Method invoked when the characteristic value changes * */ -(void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error { if(error == nil) { if ([characteristic.UUID isEqual:THM_TEMPERATURE_MEASUREMENT_CHARACTERISTIC_UUID] && characteristic.value) { [self getTHMtemp:characteristic]; } else if ([characteristic.UUID isEqual:THM_TEMPERATURE_TYPE_CHARACTERISTIC_UUID] && characteristic.value) { [self getTempType:characteristic]; } cbCharacteristicHandler(YES,nil); } else { cbCharacteristicHandler(NO,error); } } /*! * @method getTHMtemp: * * @discussion Instance method to get the temperature value * */ -(void)getTHMtemp:(CBCharacteristic *)characteristic { // Convert the contents of the characteristic value to a data-object // NSData *data = [characteristic value]; // Get the byte sequence of the data-object // const uint8_t *reportData = [data bytes]; // Initialise the offset variable // NSUInteger offset = 1; // Initialise the bpm variable // if ((reportData[0] & 0x01) == 0) { [self calculateTemperaturefromCharacteristic:characteristic]; offset = offset + 4; // Plus 4 byte // self.mesurementType = @"°C"; } else { [self calculateTemperaturefromCharacteristic:characteristic]; offset = offset + 4; // Plus 4 bytes // self.mesurementType = @"°F"; } /* timestamp */ if( (reportData[0] & 0x02) ) { uint16_t year = CFSwapInt16LittleToHost(*(uint16_t*)offset); offset += 2; uint8_t month = *(uint8_t*)offset; offset++; uint8_t day = *(uint8_t*)offset; offset++; uint8_t hour = *(uint8_t*)offset; offset++; uint8_t min = *(uint8_t*)offset; offset++; uint8_t sec = *(uint8_t*)offset; offset++; NSString * dateString = [NSString stringWithFormat:@"%d %d %d %d %d %d", year, month, day, hour, min, sec]; NSDateFormatter *dateFormat = [[NSDateFormatter alloc] init]; [dateFormat setDateFormat: @"yyyy MM dd HH mm ss"]; NSDate* date = [dateFormat dateFromString:dateString]; [dateFormat setDateFormat:@"EEE MMM dd, yyyy"]; NSString* dateFormattedString = [dateFormat stringFromDate:date]; [dateFormat setDateFormat:@"h:mm a"]; NSString* timeFormattedString = [dateFormat stringFromDate:date]; if( dateFormattedString && timeFormattedString ) { self.timeStampString = [NSString stringWithFormat:@"%@ at %@", dateFormattedString, timeFormattedString]; } } [Utilities logDataWithService:[ResourceHandler getServiceNameForUUID:characteristic.service.UUID] characteristic:[ResourceHandler getCharacteristicNameForUUID:characteristic.UUID] descriptor:nil operation:[NSString stringWithFormat:@"%@%@ %@",NOTIFY_RESPONSE,DATA_SEPERATOR,[Utilities convertDataToLoggerFormat:data]]]; } /*! * @method calculateTemperaturefromCharacteristic * * @discussion Method to calculate the temperature * */ -(void) calculateTemperaturefromCharacteristic:(CBCharacteristic *)characteristic { // Convert the contents of the characteristic value to a data-object // NSData *data = [characteristic value]; // Get the byte sequence of the data-object // const uint8_t *reportData = [data bytes]; unsigned char *commandPacket = (unsigned char *)malloc(4 * sizeof(unsigned char)); reportData++; int32_t tempData ; if (reportData[2] != 0xff) { commandPacket[0] = reportData[0]; commandPacket[1] = reportData[1]; commandPacket[2] = reportData[2]; commandPacket[3] = 0x00; } else { commandPacket[0] = ~ (reportData[0] - 1); commandPacket[1] = ~reportData[1]; commandPacket[2] = ~reportData[2]; commandPacket[3] = 0x00; } NSData *testData = [NSData dataWithBytes:commandPacket length:4]; const uint8_t *re = [testData bytes]; tempData = (int32_t)CFSwapInt32LittleToHost(*(uint32_t*)re); int8_t exponent = (int8_t)(tempData >> 24); int32_t mantissa = (int32_t)(tempData & 0x00FFFFFF); if( tempData == 0x007FFFFF ) { NSLog(@"Invalid temperature value received"); return; } float tempValue = (float)(mantissa*pow(10, exponent)); if (reportData[2] == 0xff) { tempValue = tempValue * -1; } self.tempStringValue = [NSString stringWithFormat:@"%.1f",(float) tempValue]; free(commandPacket); } /*! * @method isTempTypeValid: * * @discussion Instance method to check temperature type exist or not * */ -(BOOL)isTempTypeValid:(CBCharacteristic *)characteristic { NSData * updatedValue = characteristic.value; uint8_t* dataPointer = (uint8_t*)[updatedValue bytes]; uint8_t flags = dataPointer[0]; if( flags & 0x04 ) { return true; } return false; } /*! * @method getTempType: * * @discussion Instance method to get the Temperature Type characteristic is an enumeration that indicates where the temperature was measured * */ -(void)getTempType:(CBCharacteristic *)characteristic { /* temperature type */ NSData * updatedValue = characteristic.value; uint8_t* dataPointer = (uint8_t*)[updatedValue bytes]; uint8_t type = *(uint8_t*)dataPointer; NSString* location = nil; switch (type) { case 0x01: location = @"Armpit"; break; case 0x02: location = @"Body (general)"; break; case 0x03: location = @"Ear"; break; case 0x04: location = @"Finger"; break; case 0x05: location = @"Gastro-intenstinal Tract"; break; case 0x06: location = @"Mouth"; break; case 0x07: location = @"Rectum"; break; case 0x08: location = @"Toe"; break; case 0x09: location = @"Tympanum - ear drum"; break; default: break; } if (location) { self.tempType = [NSString stringWithFormat:@"%@", location]; } [Utilities logDataWithService:[ResourceHandler getServiceNameForUUID:characteristic.service.UUID] characteristic:[ResourceHandler getCharacteristicNameForUUID:characteristic.UUID] descriptor:nil operation:[NSString stringWithFormat:@"%@%@ %@",READ_RESPONSE,DATA_SEPERATOR,[Utilities convertDataToLoggerFormat:updatedValue]]]; } @end