// // CommunicationProtocol.m // DUREX Vendor Control // // Created by Imanol Barba on 5/23/14. // Copyright (c) 2014 Emmoco. All rights reserved. // #import "CommunicationProtocol.h" @interface CommunicationProtocol () @property Boolean messageAvailableMobile; @property Boolean messageAvailableDevice; @property NSMutableString *message; @property NSUInteger currentIndex; @property NSUInteger remainingBytes; @property NSInteger numPackets; @end @implementation CommunicationProtocol + (id)sharedProtocol { static CommunicationProtocol *shared = nil; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ shared = [[self alloc] init]; [shared setMessageAvailableDevice:FALSE]; [shared setMessageAvailableMobile:FALSE]; }); return shared; } -(void) readMessage { [self setMessage:[NSMutableString stringWithFormat:@""]]; self.numPackets = -1; [self waitForMessage: 0]; } - (void) readNextFragment { __block NSUInteger numBytes; [[EMConnectionManager sharedManager] readResource:@"numBytes" onSuccess:^(id readValue) { numBytes = [readValue unsignedCharValue]; NSLog(@"[CommunicationProtocol.m]: numBytes read: %d",numBytes); [[EMConnectionManager sharedManager] readResource:@"data" onSuccess:^(id readValue) { NSString *readData = [readValue substringToIndex:numBytes]; if([readValue length] < numBytes) { NSLog(@"[CommunicationProtocol.m]: WARNING: Device issued wrong numBytes, possible truncated message."); } [self.message appendString:readData]; NSLog(@"[CommunicationProtocol.m]: data read: %@",readData); [[EMConnectionManager sharedManager] writeValue:@"0" toResource:@"messageAvailableDevice" onSuccess:^ { NSLog(@"[CommunicationProtocol.m]: messageAvailableDevice set to FALSE"); NSLog(@"[CommunicationProtocol.m]: packet read"); self.numPackets--; if(self.numPackets) { [self waitForMessage: 0]; } else { [[self delegate] processMessage:self didFinishEnteringItem:self.message]; } }onFail:^(NSError *error) { NSLog(@"[CommunicationProtocol.m]: On setMessageAvailableDevice to FALSE: %@",error); [[self delegate] reportProtocolError:self didFinishEnteringItem:[NSString stringWithFormat:@"%@: %@",NSLocalizedString(@"Error occurred while reading answer from device",nil),[error localizedDescription]]]; }]; }onFail:^(NSError *error) { NSLog(@"[CommunicationProtocol.m]: On readData: %@",error); [[self delegate] reportProtocolError:self didFinishEnteringItem:[NSString stringWithFormat:@"%@: %@",NSLocalizedString(@"Error occurred while reading answer from device",nil),[error localizedDescription]]]; }]; }onFail:^(NSError *error) { NSLog(@"[CommunicationProtocol.m]: On readNumBytes: %@",error); [[self delegate] reportProtocolError:self didFinishEnteringItem:[NSString stringWithFormat:@"%@: %@",NSLocalizedString(@"Error occurred while reading answer from device",nil),[error localizedDescription]]]; }]; } - (void) readNumPackets { [[EMConnectionManager sharedManager] readResource:@"numPackets" onSuccess:^(id readValue) { self.numPackets = [readValue unsignedCharValue]; NSLog(@"[CommunicationProtocol.m]: numPackets read: %d",self.numPackets); [self readNextFragment]; }onFail:^(NSError *error) { NSLog(@"[CommunicationProtocol.m]: On readNumPackets: %@",error); [[self delegate] reportProtocolError:self didFinishEnteringItem:[NSString stringWithFormat:@"%@: %@",NSLocalizedString(@"Error occurred while reading answer from device",nil),[error localizedDescription]]]; }]; } - (void) waitForMessage: (uint8_t) retries { if(retries == MAX_RETRIES) { NSLog(@"[CommunicationProtocol.m]: Device not ready."); NSLog(@"[CommunicationProtocol.m]: Timeout while expecting message"); } else { NSLog(@"[CommunicationProtocol.m]: Reading messageAvailable from device"); [[EMConnectionManager sharedManager] readResource:@"messageAvailableDevice" onSuccess:^(id readValue) { [self setMessageAvailableDevice:[readValue intValue]]; if(![self messageAvailableDevice]) { NSLog(@"[CommunicationProtocol.m]: Device not ready. Retrying..."); [NSThread sleepForTimeInterval:SLEEP_TIME]; [self waitForMessage:retries + 1]; } else { if(self.numPackets == -1) { [self readNumPackets]; } else { [self readNextFragment]; } } }onFail:^(NSError *error) { NSLog(@"[CommunicationProtocol.m]: On waitForMessage: %@",error); [[self delegate] reportProtocolError:self didFinishEnteringItem:[NSString stringWithFormat:@"%@: %@",NSLocalizedString(@"Error occurred while reading answer from device",nil),[error localizedDescription]]]; }]; } } -(void) writeMessage: (NSString*) message { NSLog(@"[CommunicationProtocol.m]: Sending message: %@",message); [self setMessage:[NSMutableString stringWithString:message]]; [self setRemainingBytes:[message length]]; [self setCurrentIndex:0]; [[EMConnectionManager sharedManager] writeValue:[NSNumber numberWithUnsignedChar:(unsigned char)([message length]/MAX_STRING_LENGTH)+1] toResource:@"numPackets" onSuccess:^ { NSLog(@"[CommunicationProtocol.m]: numPackets set to %u",([message length]/MAX_STRING_LENGTH) + 1); [self sendNextFragment]; }onFail:^(NSError *error) { NSLog(@"[CommunicationProtocol.m]: On setNumPackets: %@",error); [[self delegate] reportProtocolError:self didFinishEnteringItem:[NSString stringWithFormat:@"%@: %@",NSLocalizedString(@"Error occurred while sending command to device",nil),[error localizedDescription]]]; }]; } - (void) sendNextFragment { if(self.remainingBytes) { NSLog(@"[CommunicationProtocol.m]: Sending next fragment"); NSUInteger numBytes; if(self.remainingBytes > MAX_STRING_LENGTH) { numBytes = MAX_STRING_LENGTH; self.remainingBytes -= MAX_STRING_LENGTH; } else { numBytes = self.remainingBytes; self.remainingBytes = 0; } [[EMConnectionManager sharedManager] writeValue:[NSNumber numberWithUnsignedChar:(unsigned char)numBytes] toResource:@"numBytes" onSuccess:^ { NSLog(@"[CommunicationProtocol.m]: numBytes set to %d", numBytes); NSString *data = [self.message substringWithRange:NSMakeRange(self.currentIndex, numBytes)]; self.currentIndex += numBytes; [[EMConnectionManager sharedManager] writeValue:data toResource:@"data" onSuccess:^ { NSLog(@"[CommunicationProtocol.m]: data set to: %@",data); [[EMConnectionManager sharedManager] writeValue:@"1" toResource:@"messageAvailableMobile" onSuccess:^ { NSLog(@"[CommunicationProtocol.m]: messageAvailableMobile set to TRUE"); NSLog(@"[CommunicationProtocol.m]: Packet written"); [self readACK: 0]; }onFail:^(NSError *error) { NSLog(@"[CommunicationProtocol.m]: On setMessageAvailable to TRUE: %@",error); [[self delegate] reportProtocolError:self didFinishEnteringItem:[NSString stringWithFormat:@"%@: %@",NSLocalizedString(@"Error occurred while sending command to device",nil),[error localizedDescription]]]; }]; }onFail:^(NSError *error) { NSLog(@"[CommunicationProtocol.m]: On setData: %@",error); [[self delegate] reportProtocolError:self didFinishEnteringItem:[NSString stringWithFormat:@"%@: %@",NSLocalizedString(@"Error occurred while sending command to device",nil),[error localizedDescription]]]; }]; }onFail:^(NSError *error) { NSLog(@"[CommunicationProtocol.m]: On setNumBytes: %@",error); [[self delegate] reportProtocolError:self didFinishEnteringItem:[NSString stringWithFormat:@"%@: %@",NSLocalizedString(@"Error occurred while sending command to device",nil),[error localizedDescription]]]; }]; } else { NSLog(@"[CommunicationProtocol.m]: Finished sending message"); [self readMessage]; } } - (void) readACK: (uint8_t) retries { if(retries == MAX_RETRIES) { NSLog(@"[CommunicationProtocol.m]: Device not ready."); NSLog(@"[CommunicationProtocol.m]: Timeout while expecting ACK"); } else { NSLog(@"[CommunicationProtocol.m]: Reading ACK from device"); [[EMConnectionManager sharedManager] readResource:@"messageAvailableMobile" onSuccess:^(id readValue) { [self setMessageAvailableMobile:[readValue intValue]]; if([self messageAvailableMobile]) { NSLog(@"[CommunicationProtocol.m]: Device not ready. Retrying..."); [NSThread sleepForTimeInterval:SLEEP_TIME]; [self readACK:retries + 1]; } else { [self sendNextFragment]; } }onFail:^(NSError *error) { NSLog(@"[CommunicationProtocol.m]: On readACK: %@",error); [[self delegate] reportProtocolError:self didFinishEnteringItem:[NSString stringWithFormat:@"%@: %@",NSLocalizedString(@"Error occurred while sending command to device",nil),[error localizedDescription]]]; }]; } } -(void) establishConnection { NSLog(@"[CommunicationProtocol.m]: Establishing connection..."); [self writeMessage:@"Hello"]; NSLog(@"[CommunicationProtocol.m]: Hello sent"); } -(void) disconnect { NSLog(@"[CommunicationProtocol.m]: Terminating connection..."); [self writeMessage:@"Bye"]; NSLog(@"[CommunicationProtocol.m]: Bye sent"); } -(void) updateTime: (NSDateComponents*) date { NSMutableString *command = [NSMutableString stringWithFormat: @"A5"]; NSInteger year = [date year]; year = year - (year/100)*100; [command appendString:[NSString stringWithFormat:@"%02ld%02ld%02ld%02ld%02ld%02ld",(long)year,(long)[date month],(long)[date day],(long)[date hour],(long)[date minute],(long)[date second]]]; [self writeMessage:command]; } -(void) updatePrice: (uint8_t) channel : (uint8_t) product : (uint8_t) eur : (uint8_t) cents { NSMutableString *command = [NSMutableString stringWithFormat: @"A6%01d%01d%02d%02d",channel,product,eur,cents]; [self writeMessage:command]; } -(void) updateProductName: (uint8_t) channel : (uint8_t) product : (NSString*) name { if([name length] > MAX_PRODUCT_NAME_LENGTH) { name = [name substringToIndex:MAX_PRODUCT_NAME_LENGTH-1]; } NSMutableString *command = [NSMutableString stringWithFormat: @"A7%01d%01d%@",channel,product,name]; [self writeMessage:command]; } -(void) readSensorData { NSString *command = @"A4"; [self writeMessage:command]; } -(void) readSalesLog : (NSDateComponents*) start : (NSDateComponents*) end { NSMutableString *startDate = [NSMutableString stringWithString:@""]; NSMutableString *endDate = [NSMutableString stringWithString:@""]; NSMutableString *command = [NSMutableString stringWithString:@"A2"]; if(start == nil) { [startDate setString:@""]; } else { NSInteger year = [start year]; year = year - (year/100)*100; [startDate appendString:[NSString stringWithFormat:@"%02ld%02ld%02ld%02ld%02ld",(long)year,(long)[start month],(long)[start day],(long)[start hour],(long)[start minute]]]; } if(end == nil) { [endDate setString:@""]; } else { NSInteger year = [end year]; year = year - (year/100)*100; [endDate appendString:[NSString stringWithFormat:@"%02ld%02ld%02ld%02ld%02ld",(long)year,(long)[end month],(long)[end day],(long)[end hour],(long)[end minute]]]; } [command appendString:startDate]; [command appendString:@"-"]; [command appendString:endDate]; [self writeMessage:command]; } -(void) readIncidentLog:(NSDateComponents *)start :(NSDateComponents *)end { NSMutableString *startDate = [NSMutableString stringWithString:@""]; NSMutableString *endDate = [NSMutableString stringWithString:@""]; NSMutableString *command = [NSMutableString stringWithString:@"A3"]; if(start == nil) { [startDate setString:@""]; } else { NSInteger year = [start year]; year = year - (year/100)*100; [startDate appendString:[NSString stringWithFormat:@"%02ld%02ld%02ld%02ld%02ld",(long)year,(long)[start month],(long)[start day],(long)[start hour],(long)[start minute]]]; } if(end == nil) { [endDate setString:@""]; } else { NSInteger year = [end year]; year = year - (year/100)*100; [endDate appendString:[NSString stringWithFormat:@"%02ld%02ld%02ld%02ld%02ld",(long)year,(long)[end month],(long)[end day],(long)[end hour],(long)[end minute]]]; } [command appendString:startDate]; [command appendString:@"-"]; [command appendString:endDate]; [self writeMessage:command]; } @end