// // 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 () @end @implementation CommunicationProtocol + (id)sharedProtocol { static CommunicationProtocol *shared = nil; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ shared = [[self alloc] init]; }); return shared; } -(void) readMessageAvailableMobile { [[EMConnectionManager sharedManager] readResource:@"messageAvailableMobile" onSuccess:^(id readValue) { [self setMessageAvailableMobile:[readValue intValue]]; if([self messageAvailableMobile]) { NSLog(@"[CommunicationProtocol.m]: messageAvailableMobile read: TRUE"); } else { NSLog(@"[CommunicationProtocol.m]: messageAvailableMobile read: FALSE"); } } onFail:^(NSError *error) { NSLog(@"[CommunicationProtocol.m]: %@",error); }]; } -(void) readMessageAvailableDevice { [[EMConnectionManager sharedManager] readResource:@"messageAvailableDevice" onSuccess:^(id readValue) { [self setMessageAvailableDevice:[readValue intValue]]; if([self messageAvailableDevice]) { NSLog(@"[CommunicationProtocol.m]: messageAvailableDevice read: TRUE"); } else { NSLog(@"[CommunicationProtocol.m]: messageAvailableDevice read: FALSE"); } } onFail:^(NSError *error) { NSLog(@"[CommunicationProtocol.m]: %@",error); }]; } -(Boolean) waitForMessageAvailableMobile: (Boolean) status { uint8_t retries = 0; [self readMessageAvailableMobile]; while([self messageAvailableMobile] != status) { [NSThread sleepForTimeInterval:5]; [self readMessageAvailableMobile]; if([self messageAvailableMobile] != status) { if(retries++ == MAX_RETRIES) { NSLog(@"[CommunicationProtocol.m]: Timeout while waiting for answer"); return FALSE; } } } return TRUE; } -(Boolean) waitForMessageAvailableDevice: (Boolean) status { uint8_t retries = 0; [self readMessageAvailableDevice]; while([self messageAvailableDevice] != status) { [NSThread sleepForTimeInterval:5]; [self readMessageAvailableDevice]; if([self messageAvailableDevice] != status) { if(retries++ == MAX_RETRIES) { NSLog(@"[CommunicationProtocol.m]: Timeout while waiting for answer"); return FALSE; } } } return TRUE; } -(NSString*) readMessage { __block uint8_t numPackets = 1, numBytes; //HACK! __block NSMutableString *message = [[NSMutableString alloc] init]; [message setString:@""]; //if([self waitForMessageAvailableDevice:TRUE]) if(1) //HACK! { [[EMConnectionManager sharedManager] readResource:@"numPackets" onSuccess:^(id readValue) { numPackets = (uint8_t) [readValue unsignedCharValue]; NSLog(@"[CommunicationProtocol.m]: numPackets read: %d",numPackets); } onFail:^(NSError *error) { NSLog(@"[CommunicationProtocol.m]: %@",error); numPackets = 0; }]; if(numPackets) { for(int i = 0; i < numPackets; i++) { //if([self waitForMessageAvailableDevice:TRUE]) if(1)//HACK! { [[EMConnectionManager sharedManager] readResource:@"numBytes" onSuccess:^(id readValue) { numBytes = (uint8_t) [readValue unsignedCharValue]; NSLog(@"[CommunicationProtocol.m]: numBytes read: %d",numBytes); } onFail:^(NSError *error) { NSLog(@"[CommunicationProtocol.m]: %@",error); numBytes = 0; }]; if(numBytes) { [[EMConnectionManager sharedManager] readResource:@"data" onSuccess:^(id readValue) { [message appendString: readValue]; [message setString: [message substringToIndex:numBytes]]; NSLog(@"[CommunicationProtocol.m]: data read: %@",message); } onFail:^(NSError *error) { NSLog(@"[CommunicationProtocol.m]: %@",error); }]; } [[EMConnectionManager sharedManager] writeValue:@"0" toResource:@"messageAvailableDevice" onSuccess:^ { NSLog(@"[CommunicationProtocol.m]: messageAvailableDevice set to FALSE"); NSLog(@"[CommunicationProtocol.m]: packet read"); } onFail:^(NSError *error) { NSLog(@"[CommunicationProtocol.m]: %@",error); } ]; } else { NSLog(@"[CommunicationProtocol.m]: Error, resetting message"); [message setString:@""]; } } } } NSLog(@"[CommunicationProtocol.m]: Message received: %@",message); return message; } -(Boolean) writeMessage: (NSString*) message { unsigned long remainingBytes = [message length]; uint8_t numBytes, current_index = 0; __block Boolean status = TRUE; //HACK __block Boolean blockCompleted = TRUE; //HACK! [[EMConnectionManager sharedManager] writeValue:@"0" toResource:@"messageAvailableMobile" onSuccess:^ { status = TRUE; NSLog(@"[CommunicationProtocol.m]: messageAvailableMobile set to FALSE"); blockCompleted = TRUE; } onFail:^(NSError *error) { NSLog(@"[CommunicationProtocol.m]: %@",error); status = FALSE; blockCompleted = TRUE; }]; while(blockCompleted != TRUE) { [NSThread sleepForTimeInterval:1]; } NSLog(@"[CommunicationProtocol.m]: messageAvailableMobile write block completed"); blockCompleted = FALSE; [[EMConnectionManager sharedManager] writeValue:[NSNumber numberWithUnsignedChar:(unsigned char)([message length]/MAX_STRING_LENGTH)+1] toResource:@"numPackets" onSuccess:^ { status = TRUE; NSLog(@"[CommunicationProtocol.m]: numPackets set to %d",([message length]/MAX_STRING_LENGTH) + 1); } onFail:^(NSError *error) { NSLog(@"[CommunicationProtocol.m]: %@",error); status = FALSE; } ]; NSLog(@"[CommunicationProtocol.m]: status is: %d",status); if(status != FALSE) { NSLog(@"[CommunicationProtocol.m]: Carrying on after numPackets..."); while(remainingBytes) { if(![self waitForMessageAvailableMobile:FALSE]) { status = FALSE; break; } NSLog(@"[CommunicationProtocol.m]: Device is ready for next packet"); if(remainingBytes > MAX_STRING_LENGTH) { numBytes = MAX_STRING_LENGTH; remainingBytes -= MAX_STRING_LENGTH; } else { numBytes = remainingBytes; remainingBytes = 0; } [[EMConnectionManager sharedManager] writeValue:[NSNumber numberWithUnsignedChar:(unsigned char)numBytes] toResource:@"numBytes" onSuccess:^ { NSLog(@"[CommunicationProtocol.m]: numBytes set to %d", numBytes); status = TRUE; } onFail:^(NSError *error) { NSLog(@"[CommunicationProtocol.m]: %@",error); status = FALSE; } ]; if(status != FALSE) { NSLog(@"[CommunicationProtocol.m]: Carrying on after numBytes..."); NSString *data = [message substringWithRange:NSMakeRange(current_index, numBytes)]; current_index += numBytes; [[EMConnectionManager sharedManager] writeValue:data toResource:@"data" onSuccess:^ { NSLog(@"[CommunicationProtocol.m]: data set to: %@",data); status = TRUE; } onFail:^(NSError *error) { NSLog(@"[CommunicationProtocol.m]: %@",error); status = FALSE; } ]; if(status != FALSE) { NSLog(@"[CommunicationProtocol.m]: Carrying on after data..."); [[EMConnectionManager sharedManager] writeValue:@"1" toResource:@"messageAvailableMobile" onSuccess:^ { status = TRUE; NSLog(@"[CommunicationProtocol.m]: messageAvailableMobile set to TRUE"); NSLog(@"[CommunicationProtocol.m]: Packet written"); } onFail:^(NSError *error) { NSLog(@"[CommunicationProtocol.m]: %@",error); status = FALSE; } ]; NSLog(@"[CommunicationProtocol.m]: Carrying on after messageAvailableMobile..."); } } } } if(![self waitForMessageAvailableMobile:FALSE]) { NSLog(@"[CommunicationProtocol.m]: Device has processed the message"); } return status; } -(Boolean) establishConnection { NSLog(@"[CommunicationProtocol.m]: Establishing connection..."); if([self writeMessage:@"Hello"]) { NSLog(@"[CommunicationProtocol.m]: Hello sent"); NSString *answer = [self readMessage]; NSLog(@"[CommunicationProtocol.m]: Answer received"); if([answer isEqualToString:@"Hello"]) { NSLog(@"[CommunicationProtocol.m]: Connection established"); return TRUE; } } NSLog(@"[CommunicationProtocol.m]: Error while establishing connection"); return TRUE; //HACK! } -(Boolean) updateTime: (NSDateComponents*) date { if(date == nil) { NSCalendar *calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar]; NSCalendarUnit units = NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit | NSHourCalendarUnit | NSMinuteCalendarUnit | NSSecondCalendarUnit; date = [calendar components:units fromDate:[NSDate date]]; } NSMutableString *command = [NSMutableString stringWithFormat: @"A5"]; NSInteger year = [date year]; year = year - (year/100)*100; [command appendString:[NSString stringWithFormat:@"%02d",year]]; [command appendString:[NSString stringWithFormat:@"%02d%02d%02d%02d%02d",[date month],[date day],[date hour],[date minute],[date second]]]; [self writeMessage:command]; NSString *answer = [self readMessage]; if([answer isEqualToString:@"P51"]) { return TRUE; } return FALSE; } -(Boolean) 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]; NSString *answer = [self readMessage]; if([answer isEqualToString:@"P61"]) { return TRUE; } return FALSE; } -(Boolean) 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]; NSString *answer = [self readMessage]; if([answer isEqualToString:@"P71"]) { return TRUE; } return FALSE; } @end