/*
|
* 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 "BootLoaderServiceModel.h"
|
|
#import "CBMoralManager.h"
|
#import "Constants.h"
|
|
#define COMMAND_PACKET_MIN_SIZE 7
|
|
/*!
|
* @class BootLoaderServiceModel
|
*
|
* @discussion Class to handle the bootloader service related operations
|
*
|
*/
|
|
|
@interface BootLoaderServiceModel ()<cbCharacteristicManagerDelegate>
|
{
|
void (^cbCharacteristicDiscoverHandler)(BOOL success, NSError *error);
|
void (^cbCharacteristicUpdationHandler)(BOOL success,id command,NSError *error);
|
CBCharacteristic *bootLoaderCharacteristic;
|
|
NSMutableArray *commandArray;
|
NSString *checkSumType;
|
}
|
|
@end
|
|
|
|
@implementation BootLoaderServiceModel
|
|
- (instancetype)init
|
{
|
self = [super init];
|
if (self) {
|
|
commandArray = [[NSMutableArray alloc] init];
|
}
|
return self;
|
}
|
|
/*!
|
* @method setCheckSumType:
|
*
|
* @discussion Method to set the checksum calculation type
|
*
|
*/
|
-(void) setCheckSumType:(NSString *) type
|
{
|
checkSumType = type;
|
}
|
|
/*!
|
* @method discoverCharacteristicsWithCompletionHandler:
|
*
|
* @discussion Method to discover the specified characteristics of a service.
|
*
|
*/
|
-(void) discoverCharacteristicsWithCompletionHandler:(void (^) (BOOL success, NSError *error)) handler
|
{
|
cbCharacteristicDiscoverHandler = handler;
|
[[CBMoralManager sharedManager] setCbCharacteristicDelegate:self];
|
[[[CBMoralManager sharedManager] myPeripheral] discoverCharacteristics:nil forService:[[CBMoralManager sharedManager] myService]];
|
}
|
|
/*!
|
* @method updateValueForCharacteristicWithCompletionHandler:
|
*
|
* @discussion Method to set notifications or indications for the value of a specified characteristic
|
*
|
*/
|
-(void) updateValueForCharacteristicWithCompletionHandler:(void (^) (BOOL success,id command,NSError *error)) handler
|
{
|
cbCharacteristicUpdationHandler = handler;
|
|
if (bootLoaderCharacteristic != nil)
|
{
|
[Utilities logDataWithService:[ResourceHandler getServiceNameForUUID:bootLoaderCharacteristic.service.UUID] characteristic:[ResourceHandler getCharacteristicNameForUUID:bootLoaderCharacteristic.UUID] descriptor:nil operation:START_NOTIFY];
|
|
[[[CBMoralManager sharedManager] myPeripheral] setNotifyValue:YES forCharacteristic:bootLoaderCharacteristic];
|
}
|
}
|
|
/*!
|
* @method writeValueToCharacteristicWithData: bootLoaderCommandCode:
|
*
|
* @discussion Method to write data to the device
|
*
|
*/
|
|
-(void) writeValueToCharacteristicWithData:(NSData *)data bootLoaderCommandCode:(unsigned short)commandCode
|
{
|
if (data != nil && bootLoaderCharacteristic != nil)
|
{
|
if (commandCode)
|
{
|
[commandArray addObject:@(commandCode)];
|
}
|
|
[Utilities logDataWithService:[ResourceHandler getServiceNameForUUID:bootLoaderCharacteristic.service.UUID] characteristic:[ResourceHandler getCharacteristicNameForUUID:bootLoaderCharacteristic.UUID] descriptor:nil operation:[NSString stringWithFormat:@"%@%@ %@",WRITE_REQUEST,DATA_SEPERATOR,[Utilities convertDataToLoggerFormat:data]]];
|
|
[[[CBMoralManager sharedManager] myPeripheral] writeValue:data forCharacteristic:bootLoaderCharacteristic type:CBCharacteristicWriteWithResponse];
|
}
|
}
|
|
/*!
|
* @method stopUpdate
|
*
|
* @discussion Method to stop notifications or indications for the specified characteristic.
|
*
|
*/
|
-(void) stopUpdate
|
{
|
cbCharacteristicUpdationHandler = nil;
|
[commandArray removeAllObjects];
|
|
if (bootLoaderCharacteristic != nil)
|
{
|
[Utilities logDataWithService:[ResourceHandler getServiceNameForUUID:bootLoaderCharacteristic.service.UUID] characteristic:[ResourceHandler getCharacteristicNameForUUID:bootLoaderCharacteristic.UUID] descriptor:nil operation:STOP_NOTIFY];
|
|
[[[CBMoralManager sharedManager] myPeripheral] setNotifyValue:NO forCharacteristic:bootLoaderCharacteristic];
|
}
|
}
|
|
|
|
#pragma mark - CBCharacteristicManagerDelegate
|
|
|
/*!
|
* @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:CUSTOM_BOOT_LOADER_SERVICE_UUID])
|
{
|
for (CBCharacteristic *characteristic in service.characteristics)
|
{
|
if ([characteristic.UUID isEqual:BOOT_LOADER_CHARACTERISTIC_UUID])
|
{
|
bootLoaderCharacteristic = characteristic;
|
cbCharacteristicDiscoverHandler(YES,nil);
|
}
|
}
|
}
|
else
|
cbCharacteristicDiscoverHandler(NO,error);
|
}
|
|
|
/*!
|
* @method peripheral: didUpdateValueForCharacteristic: error:
|
*
|
* @discussion Method invoked when the characteristic value changes or read value
|
*
|
*/
|
|
-(void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error
|
{
|
if (error == nil)
|
{
|
if ([characteristic.UUID isEqual:BOOT_LOADER_CHARACTERISTIC_UUID])
|
{
|
uint8_t *dataPointer = (uint8_t *) [characteristic.value bytes];
|
NSString *errorCode = [NSString stringWithFormat:@"0x%2x",dataPointer[1]];
|
errorCode = [errorCode stringByReplacingOccurrencesOfString:@" " withString:@"0"];
|
|
// Checking the error code from the response
|
if ([errorCode isEqualToString:SUCCESS])
|
{
|
if ([[commandArray objectAtIndex:0] isEqual:@(ENTER_BOOTLOADER)])
|
{
|
[self getBootLoaderDataFromCharacteristic:characteristic];
|
}
|
else if ([[commandArray objectAtIndex:0] isEqual:@(GET_FLASH_SIZE)])
|
{
|
[self getFlashDataFromCharacteristic:characteristic];
|
}
|
else if ([[commandArray objectAtIndex:0] isEqual:@(SEND_DATA)])
|
{
|
_isWritePacketDataSuccess = YES;
|
}
|
else if ([[commandArray objectAtIndex:0] isEqual:@(PROGRAM_ROW)])
|
{
|
_isWriteRowDataSuccess = YES;
|
}
|
else if ([[commandArray objectAtIndex:0] isEqual:@(VERIFY_ROW)])
|
{
|
[self getRowCheckSumFromCharacteristic:characteristic];
|
}
|
else if([[commandArray objectAtIndex:0] isEqual:@(VERIFY_CHECKSUM)])
|
{
|
[self checkApplicationCheckSumFromCharacteristic:characteristic];
|
}
|
|
if (cbCharacteristicUpdationHandler != nil)
|
{
|
cbCharacteristicUpdationHandler(YES,[commandArray objectAtIndex:0],nil);
|
[commandArray removeObjectAtIndex:0];
|
}
|
|
}
|
else
|
{
|
if ([[commandArray objectAtIndex:0] isEqual:@(PROGRAM_ROW)])
|
{
|
_isWriteRowDataSuccess = NO;
|
}
|
else if ([[commandArray objectAtIndex:0] isEqual:@(SEND_DATA)])
|
{
|
_isWritePacketDataSuccess = NO;
|
}
|
if (cbCharacteristicUpdationHandler != nil)
|
{
|
cbCharacteristicUpdationHandler(YES,[commandArray objectAtIndex:0],nil);
|
[commandArray removeObjectAtIndex:0];
|
}
|
}
|
}
|
|
[Utilities logDataWithService:[ResourceHandler getServiceNameForUUID:characteristic.service.UUID] characteristic:[ResourceHandler getCharacteristicNameForUUID:characteristic.UUID] descriptor:nil operation:[NSString stringWithFormat:@"%@%@ %@",NOTIFY_RESPONSE,DATA_SEPERATOR,[Utilities convertDataToLoggerFormat:characteristic.value]]];
|
}
|
else
|
cbCharacteristicUpdationHandler(NO,0,error);
|
}
|
|
/*!
|
* @method getBootLoaderDataFromCharacteristic:
|
*
|
* @discussion Method to parse the characteristic value to get the siliconID and silicon rev string
|
*
|
*/
|
|
-(void) getBootLoaderDataFromCharacteristic:(CBCharacteristic *) characteristic
|
{
|
uint8_t *dataPointer = (uint8_t *)[characteristic.value bytes];
|
|
// Move to the position of data field
|
|
dataPointer +=4;
|
|
// Get silicon Id
|
|
NSMutableString *siliconIDString = [NSMutableString stringWithCapacity:8];
|
|
for (int i = 3; i>=0; i--)
|
{
|
[siliconIDString appendFormat:@"%02x",(unsigned int)dataPointer[i]];
|
}
|
|
_siliconIDString = siliconIDString;
|
|
// Get silicon Rev
|
NSMutableString *siliconRevString = [NSMutableString stringWithCapacity:2];
|
[siliconRevString appendFormat:@"%02x",(unsigned int)dataPointer[4]];
|
|
_siliconRevString = siliconRevString;
|
|
}
|
|
/*!
|
* @method getFlashDataFromCharacteristic:
|
*
|
* @discussion Method to parse the characteristic value to get the flash start and end row number
|
*
|
*/
|
-(void) getFlashDataFromCharacteristic:(CBCharacteristic *)charatceristic
|
{
|
uint8_t *dataPointer = (uint8_t *)[charatceristic.value bytes];
|
|
dataPointer+=4;
|
|
uint16_t firstRowNumber = CFSwapInt16LittleToHost(*(uint16_t *) dataPointer);
|
|
dataPointer += 2;
|
|
uint16_t lastRowNumber = CFSwapInt16LittleToHost(*(uint16_t *) dataPointer);
|
|
_startRowNumber = firstRowNumber;
|
_endRowNumber = lastRowNumber;
|
|
}
|
|
/*!
|
* @method getRowCheckSumFromCharacteristic:
|
*
|
* @discussion Method to parse the characteristic value to get the row checksum
|
*
|
*/
|
-(void) getRowCheckSumFromCharacteristic:(CBCharacteristic *)characteristic
|
{
|
uint8_t *dataPointer = (uint8_t *)[characteristic.value bytes];
|
|
_checkSum = dataPointer[4];
|
}
|
|
/*!
|
* @method checkApplicationCheckSumFromCharacteristic:
|
*
|
* @discussion Method to parse the characteristic value to get the application checksum
|
*
|
*/
|
-(void) checkApplicationCheckSumFromCharacteristic:(CBCharacteristic *) characteristic
|
{
|
uint8_t *dataPointer = (uint8_t *)[characteristic.value bytes];
|
|
int applicationChecksum = dataPointer[4];
|
|
if (applicationChecksum > 0)
|
{
|
_isApplicationValid = YES;
|
}
|
else
|
_isApplicationValid = NO;
|
}
|
|
|
/*!
|
* @method createCommandPacketWithCommand: dataLength: data:
|
*
|
* @discussion Method to create the command packet from the host
|
*
|
*/
|
-(NSData *) createCommandPacketWithCommand:(uint8_t)commandCode dataLength:(unsigned short)dataLength data:(NSDictionary *)packetDataDictionary
|
{
|
NSData *data = [[NSData alloc] init];
|
|
uint8_t startByte = COMMAND_START_BYTE;
|
uint8_t endbyte = COMMAND_END_BYTE;
|
int bitPosition = 0;
|
|
unsigned char *commandPacket = (unsigned char *)malloc((COMMAND_PACKET_MIN_SIZE + dataLength)* sizeof(unsigned char));
|
|
commandPacket[bitPosition++] = startByte;
|
commandPacket[bitPosition++] = commandCode;
|
commandPacket[bitPosition++] = dataLength;
|
commandPacket[bitPosition++] = dataLength >> 8;
|
|
|
|
|
// Handle command code for GET_FLASH_SIZE command
|
if (commandCode == GET_FLASH_SIZE)
|
{
|
uint8_t flashArrayID = [[packetDataDictionary objectForKey:FLASH_ARRAY_ID] integerValue];
|
commandPacket[bitPosition++] = flashArrayID;
|
}
|
|
//Handle command code for PROGRAM_ROW command
|
|
if (commandCode == PROGRAM_ROW || commandCode == VERIFY_ROW)
|
{
|
NSLog(@"program row command");
|
|
uint8_t flashArrayID = [[packetDataDictionary objectForKey:FLASH_ARRAY_ID] integerValue];
|
unsigned short flashRowNumber = [[packetDataDictionary objectForKey:FLASH_ROW_NUMBER] integerValue];
|
commandPacket[bitPosition++] = flashArrayID;
|
commandPacket[bitPosition++] = flashRowNumber;
|
commandPacket[bitPosition++] = flashRowNumber >> 8;
|
|
}
|
|
// Add the data to send to the command packet
|
if (commandCode == SEND_DATA || commandCode == PROGRAM_ROW)
|
{
|
NSArray *dataArray = [packetDataDictionary objectForKey:ROW_DATA];
|
|
for (int i =0; i<dataArray.count; i++)
|
{
|
NSString *value = dataArray[i];
|
|
unsigned int outVal;
|
NSScanner* scanner = [NSScanner scannerWithString:value];
|
[scanner scanHexInt:&outVal];
|
|
unsigned short valueToWrite = (unsigned short)outVal;
|
commandPacket[bitPosition++] = valueToWrite;
|
|
}
|
}
|
|
|
|
unsigned short checkSum = [self calculateChacksumWithCommandPacket:commandPacket withSize:(bitPosition) type:checkSumType];
|
|
|
commandPacket[bitPosition++] = checkSum;
|
commandPacket[bitPosition++] = checkSum >> 8;
|
commandPacket[bitPosition++] = endbyte;
|
|
data = [NSData dataWithBytes:commandPacket length:(bitPosition)];
|
|
free(commandPacket);
|
|
return data;
|
}
|
|
/*!
|
* @method calculateChacksumWithCommandPacket: withSize: type:
|
*
|
* @discussion Method to calculate the checksum
|
*
|
*/
|
-(unsigned short) calculateChacksumWithCommandPacket:(unsigned char [])array withSize:(int)packetSize type:(NSString *)type
|
{
|
if ([type isEqualToString:CHECK_SUM])
|
{
|
// Sum checksum
|
unsigned short sum = 0;
|
|
for (int i = 0; i<packetSize; i++)
|
{
|
sum = sum + array[i];
|
}
|
return ~sum+1;
|
}
|
else
|
{
|
// CRC 16
|
unsigned short sum = 0xffff;
|
|
unsigned short tmp;
|
int i;
|
|
if (packetSize == 0)
|
return (~sum);
|
|
do
|
{
|
for (i = 0, tmp = 0x00ff & *array++; i < 8; i++, tmp >>= 1)
|
{
|
if ((sum & 0x0001) ^ (tmp & 0x0001))
|
sum = (sum >> 1) ^ 0x8408;
|
else
|
sum >>= 1;
|
}
|
}
|
while (--packetSize);
|
|
sum = ~sum;
|
tmp = sum;
|
sum = (sum << 8) | (tmp >> 8 & 0xFF);
|
return sum;
|
}
|
}
|
|
|
|
|
@end
|