Почему этот последовательный код связи зависает при разговоре с адаптером USB-to-serial? - PullRequest
2 голосов
/ 07 февраля 2012

Я пишу приложение, которое должно управлять проектором с рабочего стола Mac Mini.Я пишу приложение в Objective-C, используя Xcode и termios.h для связи с последовательным портом.Я подключаюсь от адаптера USB-to-Serial и знаю, что драйверы установлены правильно, потому что я могу отправлять HEX-команды на проектор для управления его функциями.

У меня написан код, который, по моему мнению, должен открыть последовательный порт, подключиться к проектору, отправить коды и отключиться:

@implementation Projector

@synthesize helpUrl = _helpUrl;
@synthesize projectorConnected;

- (id)init {

    //[self connectProjector];

    if (TRUE == projectorConnected) {
        // Success!
    }
    else {
        // Error!
    }

    return self;
}
- (id)initWithHelpUrl:(NSString *)helpUrlString {

    [self setHelpUrl:helpUrlString];

    return [self init];
}

- (void)connectProjector {

    [self setProjectorConnected:FALSE];

    NSString *deviceNameString = @"/dev/tty.usbserial";
    speed_t baudRate = B19200;

    serialFileDescriptor = [self openSerialPort:[deviceNameString cStringUsingEncoding:NSASCIIStringEncoding] baud:baudRate];
    if (serialFileDescriptor == -1) {
        NSLog(@"Error opening serial port file!");
    }

    _fileHandle = [[NSFileHandle alloc] initWithFileDescriptor: serialFileDescriptor];

    //[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(receiveSerialMessage:) name:NSFileHandleReadCompletionNotification object:_fileHandle];
    //[_fileHandle readInBackgroundAndNotify];

    // [self closeSerialPort];

}

- (int)openSerialPort:(const char *)serialPortFile baud:(speed_t)baudRate {

    struct termios toptions;
    int fd;

    fd = open(serialPortFile, O_RDWR | O_NOCTTY | O_NDELAY);
    if (fd == -1)  {
        perror("init_serialport: Unable to open port ");
        return -1;
    }

    if (tcgetattr(fd, &gOriginalTTYAttrs) < 0) {
        perror("init_serialport: Couldn't get term attributes");
        return -1;
    }

    toptions = gOriginalTTYAttrs;

    cfsetispeed(&toptions, baudRate);
    cfsetospeed(&toptions, baudRate);

    toptions.c_cflag &= PARENB;
    toptions.c_cflag &= CSTOPB;
    toptions.c_cflag &= CSIZE;
    toptions.c_cflag |= CS8;

    toptions.c_cflag &= CRTSCTS;

    toptions.c_cflag |= CREAD | CLOCAL;  
    toptions.c_iflag &= (IXON | IXOFF | IXANY); 

    toptions.c_lflag &= (ICANON | ECHO | ECHOE | ISIG); 
    toptions.c_oflag &= OPOST; 

    // see: http://unixwiz.net/techtips/termios-vmin-vtime.html
    toptions.c_cc[VMIN]  = 0;
    toptions.c_cc[VTIME] = 20;

    if( tcsetattr(fd, TCSANOW, &toptions) < 0) {
        perror("init_serialport: Couldn't set term attributes");
        return -1;
    }

    return fd;

}

- (void)sendSerialMessage:(NSString *)message {

    NSString *deviceNameString = @"/dev/tty.usbserial";
    speed_t baudRate = B19200;

    serialFileDescriptor = [self openSerialPort:[deviceNameString cStringUsingEncoding:NSASCIIStringEncoding] baud:baudRate];
    if (serialFileDescriptor == -1) {
        NSLog(@"Error opening serial port file!");
    }

    _fileHandle = [[NSFileHandle alloc] initWithFileDescriptor: serialFileDescriptor];

    //[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(receiveSerialMessage:) name:NSFileHandleReadCompletionNotification object:_fileHandle];
    //[_fileHandle readInBackgroundAndNotify];

    // convert message string into NSData
    NSString *dataString = [message stringByReplacingOccurrencesOfString:@" " withString:@""];
    NSMutableData *dataToSend = [[NSMutableData alloc] init];
    unsigned char whole_byte;
    char byte_chars[3] = {'\0','\0','\0'};
    int i;
    for (i=0; i < 6; i++) {
        byte_chars[0] = [dataString characterAtIndex:i*2];
        byte_chars[1] = [dataString characterAtIndex:i*2+1];
        whole_byte = strtol(byte_chars, NULL, 16);
        [dataToSend appendBytes:&whole_byte length:1];
    }

    // write to the serial port file
    [_fileHandle writeData:dataToSend];

    sleep(10);

    [self closeSerialPort];
}

- (void)receiveSerialMessage:(NSNotification *)notification {
    NSData* messageData = [[notification userInfo] objectForKey:NSFileHandleNotificationDataItem];
    if ( [messageData length] == 0 ) {
        [_fileHandle readInBackgroundAndNotify];
        return;
    }

    NSString* receivedMessage = [[NSString alloc] initWithData:messageData encoding:NSASCIIStringEncoding];

    [[NSNotificationCenter defaultCenter] postNotificationName:@"serialMessageReceived" object:receivedMessage];
    [_fileHandle readInBackgroundAndNotify];

}

// Given the file descriptor for a serial device, close that device.
- (void)closeSerialPort {

    ///*
    // Block until all written output has been sent from the device.
    // Note that this call is simply passed on to the serial device driver. 
    // See tcsendbreak(3) ("man 3 tcsendbreak") for details.
    if (tcdrain(serialFileDescriptor) == -1) {
        NSLog(@"Error waiting for drain - %s(%d).", strerror(errno), errno);
    }

    // Traditionally it is good practice to reset a serial port back to
    // the state in which you found it. This is why the original termios struct
    // was saved.
    if (tcsetattr(serialFileDescriptor, TCSANOW, &gOriginalTTYAttrs) == -1) {
        NSLog(@"Error resetting tty attributes - %s(%d).\n", strerror(errno), errno);
    }
    //*/

    close(serialFileDescriptor);
    serialFileDescriptor = -1;

    _fileHandle = nil;
}

- (BOOL)powerOn {
    [self sendSerialMessage:@"02 00 00 00 00 02"];
    // TODO: change to success/failure
    return TRUE;
}

- (BOOL)powerOff {
    [self sendSerialMessage:@"02 01 00 00 00 03"];
    // TODO: change to success/failure
    return TRUE;
}

- (BOOL)blankScreen {
    [self sendSerialMessage:@"02 10 00 00 00 12"];
    // TODO: change to success/failure
    return TRUE;
}

- (BOOL)showScreen {
    [self sendSerialMessage:@"02 11 00 00 00 13"];
    // TODO: change to success/failure
    return TRUE;
}

- (BOOL)requestHelp {

    NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:_helpUrl]];

    // Perform request and get data back
    NSData *responseData = [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:nil];

    if (nil != responseData) {

        // TODO change this to check for response code is 200?
        return TRUE;

        /*
         // get String value of response
         NSString *returnString = [[NSString alloc] initWithData:responseData            encoding:NSUTF8StringEncoding];

         // DEBUG
         NSLog(@"Return string: %@", returnString);

         // TODO: better way to do this?
         NSString *successString = @"{\"status\":true}";

         if ([returnString isEqualToString:successString]) {
         // success
         NSLog(@"Success!");

         return TRUE;
         }
         else {
         NSLog(@"Error bad response");
         }
         */

    }
    else {
        NSLog(@"Error: no response");
    }

    // return faliure!
    return FALSE;

}

@end

Мне было интересно, где я иду не так, потому что когдаЯ запускаю программу, она зависает.

1 Ответ

1 голос
/ 07 февраля 2012

Я видел серьезные проблемы с драйвером адаптера USB для последовательного порта Prolific, особенно в Mac OS X Lion. Вы можете попробовать этот альтернативный драйвер Он основан на osx-pl2303 открытом коде драйвера.

Лично я бы порекомендовал приобрести другой USB-адаптер для последовательного порта. Мне нравится адаптер Keyspan USA-19HS, и у меня никогда не было проблем с их драйверами ни в одной версии Mac OS X. Я тоже слышал много хорошего о FTDI, но у меня нет личного опыта работы с адаптерами на основе этого чипсета.

См. Мой предыдущий вопрос для получения дополнительной информации об этой проблеме.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...