读取串口iOS

11

我有以下代码用于在iOS 10.3.3越狱的iPhone 6S上读写串口(我使用h3lix进行越狱):

Serial.h:

//
//  Serial.h
//  iOUSB
//
//  Created by Brandon on 2018-05-21.
//  Copyright © 2018 XIO. All rights reserved.
//

#if !defined(__cplusplus)  //-fmodules -fcxx-modules
@import Foundation;
#else
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wauto-import"
#import <Foundation/Foundation.h>
#pragma clang diagnostic pop
#endif

#define BAUD_RATE 9600

@interface Serial : NSObject
+ (instancetype)shared;
- (bool)setup:(NSString *)filePath;
- (bool)disconnect;
- (size_t)available;
- (size_t)read:(uint8_t *)bytes length:(int32_t)length;
- (size_t)write:(uint8_t *)bytes length:(int32_t)length;
- (void)flushInputStream;
- (void)flushOutputStream;
- (void)flush;
- (NSString *)lastError;
- (void)eraseLastError;
@end

Serial.mm:

//
//  Serial.mm
//  iOUSB
//
//  Created by Brandon on 2018-05-21.
//  Copyright © 2018 XIO. All rights reserved.
//

#import "Serial.h"
#include <fstream>
#include <iostream>
#include <sys/fcntl.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <termios.h>
#include <unistd.h>

#define DEFAULT_BAUD_RATE 9600

@interface Serial()
@property (nonatomic, assign) int file_descriptor;
@property (nonatomic, strong) NSString *lastError;
@end

@implementation Serial
+ (instancetype)shared {
    static Serial *instance;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        instance = [[Serial alloc] init];
    });
    return instance;
}

- (instancetype)init {
    if ((self = [super init])) {
        self.file_descriptor = -1;
        self.lastError = nil;
    }
    return self;
}

- (void)dealloc {
    [self disconnect];
}

- (bool)setup:(NSString *)filePath {
    if (self.file_descriptor != -1)
    {
        return true;
    }

    self.file_descriptor = open(filePath.UTF8String, O_RDWR | O_NOCTTY | O_NDELAY | O_NONBLOCK);
    if (self.file_descriptor == -1)
    {
        const char* error = strerror(errno);
        self.lastError = [[NSString alloc] initWithUTF8String:error];
        perror(error);
        return false;
    }

    struct termios options;
    struct termios oldoptions;
    tcgetattr(self.file_descriptor, &oldoptions);
    options = oldoptions;

    #if !defined(_POSIX_C_SOURCE) || defined(_DARWIN_C_SOURCE)
    int baud_rates[] = {B0, B50, B75, B110, B134, B150, B200, B300, B1200, B1800, B2400, B4800, B9600, B19200, B38400, B7200, B14400, B28800, B57600, B76800, B115200, B230400
    };
    #else
    int baud_rates[] = {B0, B50, B75, B110, B134, B150, B200, B300, B1200, B1800, B2400, B4800, B9600, B19200, B38400};
    #endif

    auto it = std::find(std::begin(baud_rates), std::end(baud_rates), BAUD_RATE);
    if (it != std::end(baud_rates))
    {
        cfsetispeed(&options, *it);
        cfsetospeed(&options, *it);
        std::cout<<"BAUD_RATE Set Successfully!\n";
    }
    else
    {
        cfsetispeed(&options, DEFAULT_BAUD_RATE);
        cfsetospeed(&options, DEFAULT_BAUD_RATE);
        std::cerr<<"Invalid BAUD_RATE.. Setting to default: "<<DEFAULT_BAUD_RATE<<"\n";
    }

    options.c_cflag |= (CLOCAL | CREAD);
    options.c_cflag |= CS8;
    options.c_cflag &= ~PARENB;
    options.c_cflag &= ~CSTOPB;
    options.c_cflag &= ~CSIZE;
    tcsetattr(self.file_descriptor, TCSANOW, &options);
    return true;
}

- (bool)disconnect {
    if (self.file_descriptor != -1)
    {
        close(self.file_descriptor);
        self.file_descriptor = -1;
        self.lastError = nil;
    }

    return self.file_descriptor == -1;
}

- (size_t)available {
    if (self.file_descriptor == -1)
    {
        return -1;
    }

    int available = -1;
    ioctl(self.file_descriptor, FIONREAD, &available);
    return available;
}

- (size_t)read:(uint8_t *)bytes length:(int32_t)length {
    if (self.file_descriptor == -1)
    {
        return -1;
    }

    ssize_t bytesRead = read(self.file_descriptor, bytes, length);
    if (bytesRead < 0)
    {
        const char* error = strerror(errno);
        self.lastError = [[NSString alloc] initWithUTF8String:error];
        perror(error);
    }
    return bytesRead;
}

- (size_t)write:(uint8_t *)bytes length:(int32_t)length {
    if (self.file_descriptor == -1)
    {
        return -1;
    }

    ssize_t bytesWritten = write(self.file_descriptor, bytes, length);
    if (bytesWritten <= 0)
    {
        const char* error = strerror(errno);
        self.lastError = [[NSString alloc] initWithUTF8String:error];
        perror(error);
    }
    return bytesWritten;
}

- (void)flushInputStream {
    if (self.file_descriptor == -1)
    {
        return;
    }

    tcflush(self.file_descriptor, TCIFLUSH);
}

- (void)flushOutputStream {
    if (self.file_descriptor == -1)
    {
        return;
    }

    tcflush(self.file_descriptor, TCOFLUSH);
}

- (void)flush {
    if (self.file_descriptor == -1)
    {
        return;
    }

    tcflush(self.file_descriptor, TCIOFLUSH);
}

- (NSString *)lastError {
    return _lastError ?: @"";
}

- (void)eraseLastError {
    _lastError = nil;
}
@end

我购买了OTG适配器:"Lightning to USB 3 Camera Adapter",如此展示:https://www.apple.com/ca/shop/product/MK0W2AM/A/lightning-to-usb-3-camera-adapter

我已经插上了设备,但是它显示为不支持的设备,这没关系,因为它没有MFI认证。

然而,当我尝试打开/dev/tty.iap时,我一直收到错误:资源繁忙

我可以打开/dev/tty.wlan,只有一些端口会给我带来麻烦,例如iap

我做错了什么以至于无法读取tty.iap?我尝试将应用程序移动到/Applications中并作为root运行,从/var/containers/Bundle/Applications中尝试chown root:wheel应用程序并将应用程序chmod 0777。但是我仍然遇到资源繁忙的问题。

我在网上看到说,你没有root权限就会出现这个错误。

我该如何以root身份运行我的应用程序? 我该怎么解决才能读取闪电接口?

我尝试了https://dev59.com/IHDYa4cB1Zd3GeqPE9uf#15970080但是它似乎不起作用。无论我尝试多少次,应用程序都会启动然后立即关闭。


你插上了 USB 转 RS232 适配器吗?(你说你插上了“设备”,但我不知道你是指 Lightning/USB-3 适配器还是 USB/RS232 适配器。) - Bryan Scott
1个回答

4

默认情况下,串口被用作带外管理接口(如果网络连接断开,允许您通过串行连接连接到系统)。

在您可以将串口重新用于其他任何目的之前,您需要禁用此功能。

如何禁用此功能的具体方法因操作系统版本而异。


对于您的情况,基于串口的终端支持是通过StartupItem(https://developer.apple.com/library/content/documentation/MacOSX/Conceptual/BPSystemStartup/Chapters/StartupItems.html)进行控制的。了解这一点后,您应该找到文件/System/Library/StartupItems/SerialTerminalSupport。查找ENABLE SERIALTERMINAL并将其更改为$FALSE。 - Tiago Martins Peres

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接