/* * 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 "GlucoseModel.h" #import "CBMoralManager.h" #import "Constants.h" /*! * @class GlucoseModel * * @discussion Class to handle the glucose service related operations * */ @interface GlucoseModel () @end @implementation GlucoseModel { void(^cbCharacteristicHandler)(BOOL success, NSError *error); void(^cbcharacteristicDiscoverHandler)(BOOL success, NSError *error); CBCharacteristic *glucoseMeasurementChar; } /*! * @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; if (glucoseMeasurementChar) { [Utilities logDataWithService:[ResourceHandler getServiceNameForUUID:GLUCOSE_SERVICE_UUID] characteristic:[ResourceHandler getCharacteristicNameForUUID:GLUCOSE_MEASUREMENT_CHARACTERISTIC_UUID] descriptor:nil operation:START_NOTIFY]; [[[CBMoralManager sharedManager] myPeripheral] setNotifyValue:YES forCharacteristic:glucoseMeasurementChar]; } } /*! * @method stopUpdate * * @discussion Stop notifications or indications for the value of a specified characteristic. */ -(void) stopUpdate { if (glucoseMeasurementChar) { if (glucoseMeasurementChar.isNotifying) { [Utilities logDataWithService:[ResourceHandler getServiceNameForUUID:GLUCOSE_SERVICE_UUID] characteristic:[ResourceHandler getCharacteristicNameForUUID:GLUCOSE_MEASUREMENT_CHARACTERISTIC_UUID] descriptor:nil operation:STOP_NOTIFY]; [[[CBMoralManager sharedManager] myPeripheral] setNotifyValue:NO forCharacteristic:glucoseMeasurementChar]; } } } #pragma mark - CBCharacteristicManager delegate /*! * @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:GLUCOSE_SERVICE_UUID]) { for (CBCharacteristic *aChar in service.characteristics) { // Check for the required characteristic if ([aChar.UUID isEqual:GLUCOSE_MEASUREMENT_CHARACTERISTIC_UUID]) { glucoseMeasurementChar = aChar; cbcharacteristicDiscoverHandler(YES,nil); } } } else { cbcharacteristicDiscoverHandler(NO,error); } } /*! * @method peripheral: didUpdateValueForCharacteristic: error: * * @discussion Method invoked when the characteristic value changes * */ -(void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error { if ([characteristic.UUID isEqual:GLUCOSE_MEASUREMENT_CHARACTERISTIC_UUID]) { if (error == nil) { [self getGlucoseData:characteristic]; cbCharacteristicHandler(YES,nil); } else { cbCharacteristicHandler(NO,error); } } } /*! * @method getGlucoseData: * * @discussion Instance method to parse the data received from the peripheral */ -(void) getGlucoseData:(CBCharacteristic *)characteristic { NSData *charData = [characteristic value]; uint8_t *dataPointer = (uint8_t *)[charData bytes]; uint8_t flags = dataPointer[0]; if (flags & 0x01) { // Time stamp data is present dataPointer+=2; uint16_t timeStamp = (uint16_t)CFSwapInt16LittleToHost(*((uint16_t *) dataPointer)); dataPointer+=2; NSLog(@"timestamp = %hu",timeStamp); } // Checking whether Glucose concentration,type or sample location present else if (flags & 0x02) { // Checking Glucose concentration unit uint16_t concentrationValue; if (!(flags & 0x04)) { // Unit is kg/L _concentrationUnitString = @"kg/L"; concentrationValue = (uint16_t )CFSwapInt16LittleToHost(*((uint16_t *) dataPointer)); dataPointer +=4; } else { // Unit is mol/L _concentrationUnitString = @"mol/L"; dataPointer +=2; concentrationValue = (uint16_t )CFSwapInt16LittleToHost(*((uint16_t *) dataPointer)); dataPointer +=2; } _glucoseConcentrationValue = concentrationValue; // Get type uint8_t tempValue = *(uint8_t *)dataPointer; uint8_t typeValue = (tempValue >> 4) & 0x0F; _type = [self getTypeNameForValue:typeValue]; // Get sample location uint8_t locationValue = tempValue & 0x0F; _sampleLocation = [self getSampleLocationForValue:locationValue]; // Get date dataPointer = (uint8_t *)[charData bytes]; dataPointer+=3; uint16_t year = CFSwapInt16LittleToHost(*(uint16_t*)dataPointer); dataPointer += 2; uint8_t month = *(uint8_t*)dataPointer; dataPointer++; uint8_t day = *(uint8_t*)dataPointer; dataPointer++; uint8_t hour = *(uint8_t*)dataPointer; dataPointer++; uint8_t min = *(uint8_t*)dataPointer; dataPointer++; uint8_t sec = *(uint8_t*)dataPointer; dataPointer++; 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]; /*EEE for day, yyyy for Year, dd for date, MM for month*/ [dateFormat setDateFormat:@"yyyy MMM dd"]; NSString* dateFormattedString = [dateFormat stringFromDate:date]; [dateFormat setDateFormat:@"hh:mm:ss"]; NSString* timeFormattedString = [dateFormat stringFromDate:date]; if( dateFormattedString && timeFormattedString ) { _timeString = [NSString stringWithFormat:@"%@ %@", dateFormattedString, timeFormattedString]; NSLog(@"time string = %@",_timeString); } } [Utilities logDataWithService:[ResourceHandler getServiceNameForUUID:GLUCOSE_SERVICE_UUID] characteristic:[ResourceHandler getCharacteristicNameForUUID:GLUCOSE_MEASUREMENT_CHARACTERISTIC_UUID] descriptor:nil operation:[NSString stringWithFormat:@"%@%@ %@",NOTIFY_RESPONSE,DATA_SEPERATOR,[Utilities convertDataToLoggerFormat:charData]]]; } /*! * @method getTypeNameForValue: * * @discussion Instance method to get the Type Name */ -(NSString *) getTypeNameForValue:(uint8_t)value { NSString *typeName = nil; switch (value) { case 0x00: typeName = @"Reserved for future use"; break; case 0x01: typeName = @"Capillary Whole blood"; break; case 0x02: typeName = @"Capillary Plasma"; break; case 0x03: typeName = @"Venous Whole blood"; break; case 0x04: typeName = @"Venous Plasma"; break; case 0x05: typeName = @"Arterial Whole blood"; break; case 0x06: typeName = @"Arterial Plasma"; break; case 0x07: typeName = @"Undetermined Whole blood"; break; case 0x08: typeName = @"Undetermined Plasma"; break; case 0x09: typeName = @"Interstitial Fluid (ISF)"; break; case 0x0A: typeName = @"Control Solution"; break; default: typeName = @"Reserved for future use"; break; } return typeName; } /*! * @method getSampleLocationForValue: * * @discussion Instance method to get the sample location */ -(NSString *) getSampleLocationForValue:(uint8_t)value { NSString *locationName = nil; switch (value) { case 0x00: locationName = @"Reserved for future use"; break; case 0x01: locationName = @"Finger"; break; case 0x02: locationName = @"Alternate Site Test (AST)"; break; case 0x03: locationName = @"Earlobe"; break; case 0x04: locationName = @"Control solution"; break; case 0x0F: locationName = @"Sample Location value not available"; break; default: locationName = @" Reserved for future use "; break; } return locationName; } @end