2

Mac Mini のデスクトップからプロジェクターを制御するアプリケーションを作成しています。Xcode と termios.h を使用してシリアル ポートと通信する Objective-C でアプリケーションを作成しています。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

プログラムを実行するとハングするので、どこが間違っているのか疑問に思っていました。

4

1 に答える 1

1

特にMacOSX Lionで、ProlificのUSB-シリアルアダプタドライバに深刻な問題が発生しました。この代替ドライバーを試すことができます。これは、 osx-pl2303オープンソースドライバーコードに基づいています。

個人的には、別のUSB-シリアルアダプタを入手することをお勧めします。私はKeyspanのUSA-19HSアダプターが好きで、Mac OS Xのどのバージョンでもドライバーに問題があったことはありません。FTDIについても良いことを聞いたことがありますが、そのチップセットに基づくアダプターの個人的な経験はありません。

この問題の詳細については、以前の質問を参照してください。

于 2012-02-07T18:39:33.480 に答える