CommunicationProtocol.m 13.6 KB
//
//  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 %u",([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:@"%02ld",(long)year]];
    [command appendString:[NSString stringWithFormat:@"%02ld%02ld%02ld%02ld%02ld",(long)[date month],(long)[date day],(long)[date hour],(long)[date minute],(long)[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;
}

-(NSString*) readSensorData
{
    NSString *command = @"A4";
    [self writeMessage:command];
    //NSString *answer = [self readMessage];
    
    char command_str[65];
    command_str[0] = 'P';
    command_str[1] = '4';
    command_str[2] = 255;
    command_str[3] = 0;
    command_str[4] = 255;
    command_str[5] = 0;
    command_str[6] = 255;
    command_str[7] = 0;
    command_str[8] = '1';
    command_str[9] = '0';
    for(int i = 10; i < 10; i+=3)
    {
        command_str[i] = '0';
        command_str[i+1] = '0';
        command_str[i+2] = '0';
    }
    for(int i = 40; i < 16; i+=2)
    {
        command_str[i] = '0';
        command_str[i+1] = '0';
    }
    command_str[63] = '1';
    command_str[64] = '1';
    
    NSMutableString *answer = [[NSMutableString alloc]init];
    [answer appendString:[NSString stringWithUTF8String:command_str]];
    
    if([[answer substringToIndex:2] isEqualToString:@"P4"])
    {
        return answer;
    }
    return nil;
}

@end