9 Commits
0.0.1 ... 0.0.2

Author SHA1 Message Date
Yeo Kheng Meng
860221c029 adjust code to read until new character is encountered. Example code now tests for this. 2016-10-25 23:57:25 +08:00
Yeo Kheng Meng
55fa2ee514 comment explanation for the type alias 2016-10-25 23:21:54 +08:00
Yeo Kheng Meng
58c6521bbf Correct issue where sometimes the bytesRead can be -1 especially when read() is called for the first time 2016-10-25 23:17:24 +08:00
Yeo Kheng Meng
f6730aae6f remove print top 2016-10-25 22:56:22 +08:00
Yeo Kheng Meng
4183f388a6 open port params separate for mac 2016-10-25 22:47:02 +08:00
Yeo Kheng Meng
d69f2a8f04 ability to choose parity even or odd if enabled 2016-10-25 22:23:11 +08:00
Yeo Kheng Meng
9c121788a6 adjust bug in param name 2016-10-25 21:56:08 +08:00
Yeo Kheng Meng
f206aa706c newer gitignore 2016-10-25 21:47:55 +08:00
Yeo Kheng Meng
1492511477 updated swift serial example to use proper library name 2016-10-25 21:45:49 +08:00
3 changed files with 97 additions and 21 deletions

View File

@@ -1,10 +1,14 @@
import Foundation import Foundation
import SwiftLinuxSerial import SwiftSerial
print("You should do a loopback i.e short the TX and RX pins of the target serial port before testing.") print("You should do a loopback i.e short the TX and RX pins of the target serial port before testing.")
let testString: String = "The quick brown fox jumps over the lazy dog 01234567890." let testString: String = "The quick brown fox jumps over the lazy dog 01234567890."
let numberOfMultiNewLineTest : Int = 5
let test3Strings: String = testString + "\n" + testString + "\n" + testString + "\n"
let arguments = CommandLine.arguments let arguments = CommandLine.arguments
guard arguments.count >= 2 else { guard arguments.count >= 2 else {
print("Need serial port name, e.g. /dev/ttyUSB0 as the first argument.") print("Need serial port name, e.g. /dev/ttyUSB0 as the first argument.")
@@ -12,9 +16,11 @@ guard arguments.count >= 2 else {
} }
let portName = arguments[1] let portName = arguments[1]
let serialPort: SerialPort = SerialPort(name: portName) let serialPort: SerialPort = SerialPort(path: portName)
do { do {
print("Attempting to open port: \(portName)")
try serialPort.openPort() try serialPort.openPort()
print("Serial port \(portName) opened successfully.") print("Serial port \(portName) opened successfully.")
defer { defer {
@@ -41,6 +47,36 @@ do {
print("<\(stringReceived)>") print("<\(stringReceived)>")
} }
print("Now testing reading/writing of \(numberOfMultiNewLineTest) lines")
var multiLineString: String = ""
for i in 1...numberOfMultiNewLineTest {
multiLineString += testString + "\n"
}
print("Now writing multiLineString")
var _ = try serialPort.writeString(multiLineString)
for i in 1...numberOfMultiNewLineTest {
let stringReceived = try serialPort.readLine()
if testString == stringReceived {
print("Received string \(i) is the same as transmitted section. Moving on...")
} else {
print("Uh oh! Received string \(i) is not the same as what was transmitted. This was what we received,")
print("<\(stringReceived)>")
break
}
}
print("We successfully received back \(numberOfMultiNewLineTest) lines")
} catch PortError.failedToOpen { } catch PortError.failedToOpen {
print("Serial port \(portName) failed to open. You might need root permissions.") print("Serial port \(portName) failed to open. You might need root permissions.")
} catch { } catch {

View File

@@ -183,6 +183,24 @@ public enum DataBitsSize {
return tcflag_t(CS8) return tcflag_t(CS8)
} }
} }
}
public enum ParityType {
case none
case even
case odd
var parityValue: tcflag_t {
switch self {
case .none:
return 0
case .even:
return tcflag_t(PARENB)
case .odd:
return tcflag_t(PARENB | PARODD)
}
}
} }
public enum PortError: Int32, Error { public enum PortError: Int32, Error {
@@ -215,16 +233,24 @@ public class SerialPort {
throw PortError.mustReceiveOrTransmit throw PortError.mustReceiveOrTransmit
} }
var readWriteParam : Int32
if receive && transmit { if receive && transmit {
fileDescriptor = open(path, O_RDWR | O_NOCTTY) readWriteParam = O_RDWR
} else if receive { } else if receive {
fileDescriptor = open(path, O_RDONLY | O_NOCTTY) readWriteParam = O_RDONLY
} else if transmit { } else if transmit {
fileDescriptor = open(path, O_WRONLY | O_NOCTTY) readWriteParam = O_WRONLY
} else { } else {
fatalError() fatalError()
} }
#if os(Linux)
fileDescriptor = open(path, readWriteParam | O_NOCTTY)
#elseif os(OSX)
fileDescriptor = open(path, readWriteParam | O_NOCTTY | O_EXLOCK | O_NONBLOCK)
#endif
// Throw error if open() failed // Throw error if open() failed
if fileDescriptor == PortError.failedToOpen.rawValue { if fileDescriptor == PortError.failedToOpen.rawValue {
throw PortError.failedToOpen throw PortError.failedToOpen
@@ -235,16 +261,18 @@ public class SerialPort {
transmitRate: BaudRate, transmitRate: BaudRate,
minimumBytesToRead: Int, minimumBytesToRead: Int,
timeout: Int = 0, /* 0 means wait indefinitely */ timeout: Int = 0, /* 0 means wait indefinitely */
enableParity: Bool = false, parityType: ParityType = .none,
sendTwoStopBits: Bool = false, /* 1 stop bit is the default */ sendTwoStopBits: Bool = false, /* 1 stop bit is the default */
dataBitsSize: DataBitsSize = .bits8, dataBitsSize: DataBitsSize = .bits8,
useHardwareFlowControl: Bool = false, useHardwareFlowControl: Bool = false,
useSoftwareFlowControl: Bool = false, useSoftwareFlowControl: Bool = false,
processOutput: Bool = false) { processOutput: Bool = false) {
guard let fileDescriptor = fileDescriptor else { guard let fileDescriptor = fileDescriptor else {
return return
} }
// Set up the control structure // Set up the control structure
var settings = termios() var settings = termios()
@@ -255,12 +283,8 @@ public class SerialPort {
cfsetispeed(&settings, receiveRate.speedValue) cfsetispeed(&settings, receiveRate.speedValue)
cfsetospeed(&settings, transmitRate.speedValue) cfsetospeed(&settings, transmitRate.speedValue)
// Set parity enable flag // Enable parity (even/odd) if needed
if enableParity { settings.c_cflag |= parityType.parityValue
settings.c_cflag |= ~tcflag_t(PARENB)
} else {
settings.c_cflag &= ~tcflag_t(PARENB)
}
// Set stop bit flag // Set stop bit flag
if sendTwoStopBits { if sendTwoStopBits {
@@ -312,6 +336,8 @@ public class SerialPort {
} }
// Special characters // Special characters
//We do this as c_cc is a C-fixed array which is imported as a tuple in Swift.
//To avoid hardcoding the VMIN or VTIME value to access the tuple value, we use the typealias instead
#if os(Linux) #if os(Linux)
typealias specialCharactersTuple = (VINTR: cc_t, VQUIT: cc_t, VERASE: cc_t, VKILL: cc_t, VEOF: cc_t, VTIME: cc_t, VMIN: cc_t, VSWTC: cc_t, VSTART: cc_t, VSTOP: cc_t, VSUSP: cc_t, VEOL: cc_t, VREPRINT: cc_t, VDISCARD: cc_t, VWERASE: cc_t, VLNEXT: cc_t, VEOL2: cc_t, spare1: cc_t, spare2: cc_t, spare3: cc_t, spare4: cc_t, spare5: cc_t, spare6: cc_t, spare7: cc_t, spare8: cc_t, spare9: cc_t, spare10: cc_t, spare11: cc_t, spare12: cc_t, spare13: cc_t, spare14: cc_t, spare15: cc_t) typealias specialCharactersTuple = (VINTR: cc_t, VQUIT: cc_t, VERASE: cc_t, VKILL: cc_t, VEOF: cc_t, VTIME: cc_t, VMIN: cc_t, VSWTC: cc_t, VSTART: cc_t, VSTOP: cc_t, VSUSP: cc_t, VEOL: cc_t, VREPRINT: cc_t, VDISCARD: cc_t, VWERASE: cc_t, VLNEXT: cc_t, VEOL2: cc_t, spare1: cc_t, spare2: cc_t, spare3: cc_t, spare4: cc_t, spare5: cc_t, spare6: cc_t, spare7: cc_t, spare8: cc_t, spare9: cc_t, spare10: cc_t, spare11: cc_t, spare12: cc_t, spare13: cc_t, spare14: cc_t, spare15: cc_t)
var specialCharacters: specialCharactersTuple = (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) // NCCS = 32 var specialCharacters: specialCharactersTuple = (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) // NCCS = 32
@@ -356,7 +382,16 @@ extension SerialPort {
} }
let bytesRead = try readBytes(into: buffer, size: length) let bytesRead = try readBytes(into: buffer, size: length)
let data = Data(bytes: buffer, count: bytesRead)
var data : Data
if bytesRead > 0 {
data = Data(bytes: buffer, count: bytesRead)
} else {
//This is to avoid the case where bytesRead can be negative causing problems allocating the Data buffer
data = Data(bytes: buffer, count: 0)
}
return data return data
} }
@@ -366,6 +401,7 @@ extension SerialPort {
while remainingBytesToRead > 0 { while remainingBytesToRead > 0 {
let data = try readData(ofLength: remainingBytesToRead) let data = try readData(ofLength: remainingBytesToRead)
if let string = String(data: data, encoding: String.Encoding.utf8) { if let string = String(data: data, encoding: String.Encoding.utf8) {
result += string result += string
remainingBytesToRead -= data.count remainingBytesToRead -= data.count
@@ -384,13 +420,17 @@ extension SerialPort {
buffer.deallocate(capacity: 1) buffer.deallocate(capacity: 1)
} }
// Read byte by byte while true {
while try readBytes(into: buffer, size: 1) > 0 { let bytesRead = try readBytes(into: buffer, size: 1)
if bytesRead > 0 {
let character = CChar(buffer[0]) let character = CChar(buffer[0])
if character != terminator {
data.append(buffer, count: 1) if character == terminator {
} else {
break break
} else {
data.append(buffer, count: 1)
}
} }
} }