(此仓库现已存档,因为我不再维护它。您可以考虑使用 mredig
对此库的分支 https://github.com/mredig/SwiftSerial)
一个用于在 Linux 和 Mac 上读写串口的 Swift 库。此库已在 macOS Mojave、Linux Mint 18(基于 Ubuntu 16.04)以及 Ubuntu 16.04 上的 Raspberry Pi 3 和 Raspian Buster 上的 Raspberry Pi 4 上测试通过。其他使用 Ubuntu 的平台,如 Beaglebone,也可能适用。
这个库是我之前已弃用的库 SwiftLinuxSerial 的改进版本,之前的库 Swift 风格较弱,且仅支持 Linux。这个库很大程度上要感谢 Jay Jun。他的原始拉取请求可以在这里找到。
我做了一个关于此库及其示例 SwiftSerialIM 的演讲。点击以下链接查看幻灯片和视频。
您应该安装 Xcode 8 或更高版本,并 साथ में 命令行工具。
您可能需要启用 USB 和/或 串口授权。
要使用 Xcode 开发应用程序,请在 Xcode 中启用 App Sandbox 功能,并在硬件下选择 USB。(Mac 应用程序是沙盒化的,您需要 USB 授权。)
对于串口授权,没有复选框。因此,需要将 com.apple.security.device.serial
手动添加到 Xcode 项目中的 "YourApp.entitlements" 文件中。感谢 @doHernandezM 在 此问题 中提出的。
因系统而异...
要快速开始,您可以查看我的示例项目,点击这里。
为了正确运行此示例,您需要以环回方式连接一个(USB/UART)串口。基本上,您将串口的 TX 和 RX 引脚短接。此库目前仅支持 Mac 上的 /dev/cu.*
变体。阅读 API 用法部分的开头以了解更多详情。
git clone https://github.com/yeokm1/SwiftSerial.git
cd SwiftSerial/Examples/SwiftSerialExample/
swift build
#For Linux: You need root to access the serial port. Replace /dev/ttyUSB0 with the name of your serial port under test
sudo ./.build/debug/SwiftSerialExample /dev/ttyUSB0
#For Mac: Root is not required
./.build/debug/SwiftSerialExample /dev/cu.usbserial
#If all goes well you should see a series of messages informing you that data transmitted has been received properly.
示例 1 的变体,但专门测试二进制数据的传输,确保 0x0D
位不会转换为另一个字符。
git clone https://github.com/yeokm1/SwiftSerial.git
cd SwiftSerial/Examples/SwiftSerialBinary/
swift build
#For Linux: You need root to access the serial port. Replace /dev/ttyUSB0 with the name of your serial port under test
sudo ./.build/debug/SwiftSerialBinary /dev/ttyUSB0
#For Mac: Root is not required
./.build/debug/SwiftSerialBinary /dev/cu.usbserial
#If all goes well you should see a series of messages informing you that data transmitted has been received properly.
为了正确运行此示例,您需要 2 台通过 零调制解调器电缆 或 2 个 USB-串口适配器连接的机器,并将 TX-RX 引脚相互连接。在两台机器上运行我的程序副本。
git clone https://github.com/yeokm1/SwiftSerial.git
cd SwiftSerial/Examples/SwiftSerialIM/
swift build
#For Linux: You need root to access the serial port. Replace /dev/ttyUSB0 with the name of your serial port under test
sudo ./.build/debug/SwiftSerialIM /dev/ttyUSB0
#For Mac: Root is not required
./.build/debug/SwiftSerialIM /dev/cu.usbserial
现在两台机器的人可以互相“聊天”了。
通过编辑 Package.swift
文件,将 SwiftSerial 添加为项目的依赖项。
let package = Package(
name: "NameOfMyProject",
dependencies: [
.package(url: "https://github.com/yeokm1/SwiftSerial.git", from: "0.1.2"),
...
]
...
)
确保在使用我的 API 的源文件中 import SwiftSerial
。
然后运行 swift build
来下载依赖项并编译您的项目。您的可执行文件将在 ./.build/debug/
目录中找到。
let serialPort: SerialPort = SerialPort(path: portName)
提供您希望打开的端口名,例如 /dev/ttyUSB0
或 /dev/cu.usbserial
。
对于 Mac,此库目前仅适用于 /dev/cu.*
端口,而不是 /dev/tty.*
。我已在串口上启用阻塞以防止高 CPU 使用率,这将阻止 /dev/tty.*
工作。阅读 这里 了解两者之间的区别。如果出现问题,请打开一个 issue 描述您的情况,让我来调查。
func openPort()
func openPort(toReceive receive: Bool, andTransmit transmit: Bool)
不带任何参数打开端口将默认设置为接收和发送。您仍然可以选择仅接收、仅发送或两者都选。如果您将两个参数都设置为 false,则会抛出 PortError.mustReceiveOrTransmit
。也可能抛出 PortError.failedToOpen
和 PortError.invalidPath
。
serialPort.setSettings(receiveRate: .baud9600, transmitRate: .baud9600, minimumBytesToRead: 1)
端口设置调用可以像上面一样简单。对于波特率,即使您只打算使用一个传输方向,也要同时提供发送和接收的波特率。例如,如果您在打开端口时指定了 andTransmit : false
,则 transmitRate 将被忽略。
minimumBytesToRead
决定了系统必须等待接收多少个字符,然后才会从 read() 函数返回。如果不确定,只需设置为 1 即可。
此函数已定义了默认设置,如函数定义中所示。
func setSettings(receiveRate: BaudRate,
transmitRate: BaudRate,
minimumBytesToRead: Int,
timeout: Int = 0, /* 0 means wait indefinitely */
parityType: ParityType = .none,
sendTwoStopBits: Bool = false, /* 1 stop bit is the default */
dataBitsSize: DataBitsSize = .bits8,
useHardwareFlowControl: Bool = false,
useSoftwareFlowControl: Bool = false,
processOutput: Bool = false)
如果默认设置不适合您,只需传入额外的参数来覆盖它们。
您可以使用几个函数来读取数据。这里的所有函数都是阻塞的,直到收到预期的字节数或满足某个条件。所有函数都可能抛出 PortError.mustBeOpen
。
func readString(ofLength length: Int) throws -> String
如果您发送的是文本数据,这是最容易使用的。只需提供您期望读取的字节数。结果将以典型的 Swift String 形式返回。此函数内部调用 readData()
。
func readData(ofLength length: Int) throws -> Data
如果您打算接收二进制数据,则使用此函数。此函数内部调用 readBytes()
。
func readBytes(into buffer: UnsafeMutablePointer<UInt8>, size: Int) throws -> Int
如果您打算直接使用不安全指针,这就是适合您的函数!将返回读取的字节数。请注意,您负责在传递到此函数之前分配指针,并在完成后释放指针。
func readLine() throws -> String
逐字节读取,直到遇到换行符 \n
。将返回包含到目前为止结果的字符串,但不包含换行符。此函数内部调用 readUntilChar()
。可能抛出 PortError.stringsMustBeUTF8
。
func readUntilChar(_ terminator: CChar) throws -> String
持续读取,直到遇到指定的 CChar。返回到目前为止读取的字符串,但不包含该值。
func readByte() throws -> UInt8
仅读取一个字节。如果在打开端口时将 minimumBytesToRead
设置为 1
,则此函数效果最佳。此函数内部调用 readBytes()
。
func readChar() throws -> UnicodeScalar
仅读取一个字符。如果在打开端口时将 minimumBytesToRead
设置为 1
,则此函数效果最佳。此函数内部调用 readByte()
。
您可以使用几个函数来写入数据。这里的所有函数都是阻塞的,直到所有数据都已写入。所有函数都可能抛出 PortError.mustBeOpen
。
func writeString(_ string: String) throws -> Int
最直接的函数,输入 String 然后发送!将返回实际写入的字节数。内部调用 writeData()
。
func writeData(_ data: Data) throws -> Int
输入二进制数据,然后发送!将返回实际写入的字节数。内部调用 writeBytes()
。
func writeBytes(from buffer: UnsafeMutablePointer<UInt8>, size: Int) throws -> Int
适用于那些想要使用不安全指针的人的函数。您必须指定要写入的字节数。将返回实际写入的字节数。
func writeChar(_ character: UnicodeScalar) throws -> Int{
仅写入一个字符。如果成功,将返回 1
。此函数内部调用 writeString()
。欢迎提出更好的实现方式的 pull request。
只需在完成使用后执行 serialPort.closePort()
即可关闭端口。
如果没有我所依赖的优秀参考代码,就无法编写此库。