From bf25311591fbcdc95347f24f8dabff7ba0112385 Mon Sep 17 00:00:00 2001 From: Yuri Date: Tue, 27 Jun 2017 23:26:14 +0300 Subject: [PATCH 01/36] read bytes until stop bytes --- Sources/SwiftSerial.swift | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/Sources/SwiftSerial.swift b/Sources/SwiftSerial.swift index d1a96f2..78370a8 100644 --- a/Sources/SwiftSerial.swift +++ b/Sources/SwiftSerial.swift @@ -478,6 +478,37 @@ extension SerialPort { } } } + + public func readUntilBytes(stopBytes: [UInt8], maxBytes: Int) throws -> [UInt8] { + let buffer = UnsafeMutablePointer.allocate(capacity: 1) + var data = [UInt8]() + defer { + buffer.deallocate(capacity: 1) + } + + while true { + let byteRead = UInt8(try readBytes(into: buffer, size: 1)) + + if byteRead > 0 { + data.append(byteRead) + if data.count >= stopBytes.count { + for index in (0..= maxBytes { + return data + } + } + } + } } From 188f4f596c9e8d486e02c4eb145bbd5db41ff7c0 Mon Sep 17 00:00:00 2001 From: Yuri Date: Tue, 27 Jun 2017 23:33:41 +0300 Subject: [PATCH 02/36] read bytes until stop bytes --- Sources/SwiftSerial.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sources/SwiftSerial.swift b/Sources/SwiftSerial.swift index 78370a8..d5eeaab 100644 --- a/Sources/SwiftSerial.swift +++ b/Sources/SwiftSerial.swift @@ -490,7 +490,7 @@ extension SerialPort { let byteRead = UInt8(try readBytes(into: buffer, size: 1)) if byteRead > 0 { - data.append(byteRead) + data.append(buffer[0]) if data.count >= stopBytes.count { for index in (0.. Date: Tue, 27 Jun 2017 23:38:36 +0300 Subject: [PATCH 03/36] read bytes until bytes --- Sources/SwiftSerial.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sources/SwiftSerial.swift b/Sources/SwiftSerial.swift index d5eeaab..9d2ad4b 100644 --- a/Sources/SwiftSerial.swift +++ b/Sources/SwiftSerial.swift @@ -494,7 +494,7 @@ extension SerialPort { if data.count >= stopBytes.count { for index in (0.. Date: Tue, 27 Jun 2017 23:39:53 +0300 Subject: [PATCH 04/36] read bytes until bytes --- Sources/SwiftSerial.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sources/SwiftSerial.swift b/Sources/SwiftSerial.swift index 9d2ad4b..79a624e 100644 --- a/Sources/SwiftSerial.swift +++ b/Sources/SwiftSerial.swift @@ -494,7 +494,7 @@ extension SerialPort { if data.count >= stopBytes.count { for index in (0.. Date: Wed, 28 Jun 2017 21:36:08 +0300 Subject: [PATCH 05/36] Update README.md new function description add --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index 9197c04..9539b25 100644 --- a/README.md +++ b/README.md @@ -201,6 +201,10 @@ func readChar() throws -> UnicodeScalar ``` Read only one character. This works best if `minimumBytesToRead` has been set to `1` when opening the port. This function internally calls `readBytes()`. +```swift +func readUntilBytes(stopBytes: [UInt8], maxBytes: Int) throws -> [UInt8] +``` +Read bytes until stop bytes found or maxBytes count was recieved ### Writing data to the port There are several functions you can use to write data. All functions here are blocking till all the data has been written. All functions can throw `PortError.mustBeOpen`. From 6033963184b4903919b810ece893db2f55347bbe Mon Sep 17 00:00:00 2001 From: Yuri Date: Fri, 30 Jun 2017 23:55:25 +0300 Subject: [PATCH 06/36] bug fixes --- Sources/SwiftSerial.swift | 518 +++++++++++++++++++------------------- 1 file changed, 266 insertions(+), 252 deletions(-) diff --git a/Sources/SwiftSerial.swift b/Sources/SwiftSerial.swift index 5d91bea..1f14c6d 100644 --- a/Sources/SwiftSerial.swift +++ b/Sources/SwiftSerial.swift @@ -1,168 +1,168 @@ import Foundation #if os(Linux) -public enum BaudRate { - case baud0 - case baud50 - case baud75 - case baud110 - case baud134 - case baud150 - case baud200 - case baud300 - case baud600 - case baud1200 - case baud1800 - case baud2400 - case baud4800 - case baud9600 - case baud19200 - case baud38400 - case baud57600 - case baud115200 - case baud230400 - case baud460800 - case baud500000 - case baud576000 - case baud921600 - case baud1000000 - case baud1152000 - case baud1500000 - case baud2000000 - case baud2500000 - case baud3500000 - case baud4000000 - - var speedValue: speed_t { - switch self { - case .baud0: - return speed_t(B0) - case .baud50: - return speed_t(B50) - case .baud75: - return speed_t(B75) - case .baud110: - return speed_t(B110) - case .baud134: - return speed_t(B134) - case .baud150: - return speed_t(B150) - case .baud200: - return speed_t(B200) - case .baud300: - return speed_t(B300) - case .baud600: - return speed_t(B600) - case .baud1200: - return speed_t(B1200) - case .baud1800: - return speed_t(B1800) - case .baud2400: - return speed_t(B2400) - case .baud4800: - return speed_t(B4800) - case .baud9600: - return speed_t(B9600) - case .baud19200: - return speed_t(B19200) - case .baud38400: - return speed_t(B38400) - case .baud57600: - return speed_t(B57600) - case .baud115200: - return speed_t(B115200) - case .baud230400: - return speed_t(B230400) - case .baud460800: - return speed_t(B460800) - case .baud500000: - return speed_t(B500000) - case .baud576000: - return speed_t(B576000) - case .baud921600: - return speed_t(B921600) - case .baud1000000: - return speed_t(B1000000) - case .baud1152000: - return speed_t(B1152000) - case .baud1500000: - return speed_t(B1500000) - case .baud2000000: - return speed_t(B2000000) - case .baud2500000: - return speed_t(B2500000) - case .baud3500000: - return speed_t(B3500000) - case .baud4000000: - return speed_t(B4000000) + public enum BaudRate { + case baud0 + case baud50 + case baud75 + case baud110 + case baud134 + case baud150 + case baud200 + case baud300 + case baud600 + case baud1200 + case baud1800 + case baud2400 + case baud4800 + case baud9600 + case baud19200 + case baud38400 + case baud57600 + case baud115200 + case baud230400 + case baud460800 + case baud500000 + case baud576000 + case baud921600 + case baud1000000 + case baud1152000 + case baud1500000 + case baud2000000 + case baud2500000 + case baud3500000 + case baud4000000 + + var speedValue: speed_t { + switch self { + case .baud0: + return speed_t(B0) + case .baud50: + return speed_t(B50) + case .baud75: + return speed_t(B75) + case .baud110: + return speed_t(B110) + case .baud134: + return speed_t(B134) + case .baud150: + return speed_t(B150) + case .baud200: + return speed_t(B200) + case .baud300: + return speed_t(B300) + case .baud600: + return speed_t(B600) + case .baud1200: + return speed_t(B1200) + case .baud1800: + return speed_t(B1800) + case .baud2400: + return speed_t(B2400) + case .baud4800: + return speed_t(B4800) + case .baud9600: + return speed_t(B9600) + case .baud19200: + return speed_t(B19200) + case .baud38400: + return speed_t(B38400) + case .baud57600: + return speed_t(B57600) + case .baud115200: + return speed_t(B115200) + case .baud230400: + return speed_t(B230400) + case .baud460800: + return speed_t(B460800) + case .baud500000: + return speed_t(B500000) + case .baud576000: + return speed_t(B576000) + case .baud921600: + return speed_t(B921600) + case .baud1000000: + return speed_t(B1000000) + case .baud1152000: + return speed_t(B1152000) + case .baud1500000: + return speed_t(B1500000) + case .baud2000000: + return speed_t(B2000000) + case .baud2500000: + return speed_t(B2500000) + case .baud3500000: + return speed_t(B3500000) + case .baud4000000: + return speed_t(B4000000) + } } } -} #elseif os(OSX) -public enum BaudRate { - case baud0 - case baud50 - case baud75 - case baud110 - case baud134 - case baud150 - case baud200 - case baud300 - case baud600 - case baud1200 - case baud1800 - case baud2400 - case baud4800 - case baud9600 - case baud19200 - case baud38400 - case baud57600 - case baud115200 - case baud230400 - - var speedValue: speed_t { - switch self { - case .baud0: - return speed_t(B0) - case .baud50: - return speed_t(B50) - case .baud75: - return speed_t(B75) - case .baud110: - return speed_t(B110) - case .baud134: - return speed_t(B134) - case .baud150: - return speed_t(B150) - case .baud200: - return speed_t(B200) - case .baud300: - return speed_t(B300) - case .baud600: - return speed_t(B600) - case .baud1200: - return speed_t(B1200) - case .baud1800: - return speed_t(B1800) - case .baud2400: - return speed_t(B2400) - case .baud4800: - return speed_t(B4800) - case .baud9600: - return speed_t(B9600) - case .baud19200: - return speed_t(B19200) - case .baud38400: - return speed_t(B38400) - case .baud57600: - return speed_t(B57600) - case .baud115200: - return speed_t(B115200) - case .baud230400: - return speed_t(B230400) + public enum BaudRate { + case baud0 + case baud50 + case baud75 + case baud110 + case baud134 + case baud150 + case baud200 + case baud300 + case baud600 + case baud1200 + case baud1800 + case baud2400 + case baud4800 + case baud9600 + case baud19200 + case baud38400 + case baud57600 + case baud115200 + case baud230400 + + var speedValue: speed_t { + switch self { + case .baud0: + return speed_t(B0) + case .baud50: + return speed_t(B50) + case .baud75: + return speed_t(B75) + case .baud110: + return speed_t(B110) + case .baud134: + return speed_t(B134) + case .baud150: + return speed_t(B150) + case .baud200: + return speed_t(B200) + case .baud300: + return speed_t(B300) + case .baud600: + return speed_t(B600) + case .baud1200: + return speed_t(B1200) + case .baud1800: + return speed_t(B1800) + case .baud2400: + return speed_t(B2400) + case .baud4800: + return speed_t(B4800) + case .baud9600: + return speed_t(B9600) + case .baud19200: + return speed_t(B19200) + case .baud38400: + return speed_t(B38400) + case .baud57600: + return speed_t(B57600) + case .baud115200: + return speed_t(B115200) + case .baud230400: + return speed_t(B230400) + } } } -} #endif public enum DataBitsSize { @@ -170,7 +170,7 @@ public enum DataBitsSize { case bits6 case bits7 case bits8 - + var flagValue: tcflag_t { switch self { case .bits5: @@ -183,14 +183,14 @@ public enum DataBitsSize { return tcflag_t(CS8) } } - + } public enum ParityType { case none case even case odd - + var parityValue: tcflag_t { switch self { case .none: @@ -212,29 +212,29 @@ public enum PortError: Int32, Error { } public class SerialPort { - + var path: String var fileDescriptor: Int32? - + public init(path: String) { self.path = path } - + public func openPort() throws { try openPort(toReceive: true, andTransmit: true) } - + public func openPort(toReceive receive: Bool, andTransmit transmit: Bool) throws { guard !path.isEmpty else { throw PortError.invalidPath } - + guard receive || transmit else { throw PortError.mustReceiveOrTransmit } - + var readWriteParam : Int32 - + if receive && transmit { readWriteParam = O_RDWR } else if receive { @@ -244,76 +244,76 @@ public class SerialPort { } else { fatalError() } - - #if os(Linux) - fileDescriptor = open(path, readWriteParam | O_NOCTTY) - #elseif os(OSX) - fileDescriptor = open(path, readWriteParam | O_NOCTTY | O_EXLOCK) - #endif - + + #if os(Linux) + fileDescriptor = open(path, readWriteParam | O_NOCTTY) + #elseif os(OSX) + fileDescriptor = open(path, readWriteParam | O_NOCTTY | O_EXLOCK) + #endif + // Throw error if open() failed if fileDescriptor == PortError.failedToOpen.rawValue { throw PortError.failedToOpen } } - + public 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) { + parityType: ParityType = .none, + sendTwoStopBits: Bool = false, /* 1 stop bit is the default */ + dataBitsSize: DataBitsSize = .bits8, + useHardwareFlowControl: Bool = false, + useSoftwareFlowControl: Bool = false, + processOutput: Bool = false) { guard let fileDescriptor = fileDescriptor else { return } - - + + // Set up the control structure var settings = termios() - + // Get options structure for the port tcgetattr(fileDescriptor, &settings) - + // Set baud rates cfsetispeed(&settings, receiveRate.speedValue) cfsetospeed(&settings, transmitRate.speedValue) - + // Enable parity (even/odd) if needed settings.c_cflag |= parityType.parityValue - + // Set stop bit flag if sendTwoStopBits { settings.c_cflag |= tcflag_t(CSTOPB) } else { settings.c_cflag &= ~tcflag_t(CSTOPB) } - + // Set data bits size flag settings.c_cflag &= ~tcflag_t(CSIZE) settings.c_cflag |= dataBitsSize.flagValue - + // Set hardware flow control flag - #if os(Linux) - if useHardwareFlowControl { - settings.c_cflag |= tcflag_t(CRTSCTS) - } else { - settings.c_cflag &= ~tcflag_t(CRTSCTS) - } - #elseif os(OSX) - if useHardwareFlowControl { - settings.c_cflag |= tcflag_t(CRTS_IFLOW) - settings.c_cflag |= tcflag_t(CCTS_OFLOW) - } else { - settings.c_cflag &= ~tcflag_t(CRTS_IFLOW) - settings.c_cflag &= ~tcflag_t(CCTS_OFLOW) - } - #endif - + #if os(Linux) + if useHardwareFlowControl { + settings.c_cflag |= tcflag_t(CRTSCTS) + } else { + settings.c_cflag &= ~tcflag_t(CRTSCTS) + } + #elseif os(OSX) + if useHardwareFlowControl { + settings.c_cflag |= tcflag_t(CRTS_IFLOW) + settings.c_cflag |= tcflag_t(CCTS_OFLOW) + } else { + settings.c_cflag &= ~tcflag_t(CRTS_IFLOW) + settings.c_cflag &= ~tcflag_t(CCTS_OFLOW) + } + #endif + // Set software flow control flags let softwareFlowControlFlags = tcflag_t(IXON | IXOFF | IXANY) if useSoftwareFlowControl { @@ -321,39 +321,39 @@ public class SerialPort { } else { settings.c_iflag &= ~softwareFlowControlFlags } - + // Turn on the receiver of the serial port, and ignore modem control lines settings.c_cflag |= tcflag_t(CREAD | CLOCAL) - + // Turn off canonical mode settings.c_lflag &= ~tcflag_t(ICANON | ECHO | ECHOE | ISIG) - + // Set output processing flag if processOutput { settings.c_oflag |= tcflag_t(OPOST) } else { settings.c_oflag &= ~tcflag_t(OPOST) } - + //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) - 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 - #elseif os(OSX) - typealias specialCharactersTuple = (VEOF: cc_t, VEOL: cc_t, VEOL2: cc_t, VERASE: cc_t, VWERASE: cc_t, VKILL: cc_t, VREPRINT: cc_t, spare1: cc_t, VINTR: cc_t, VQUIT: cc_t, VSUSP: cc_t, VDSUSP: cc_t, VSTART: cc_t, VSTOP: cc_t, VLNEXT: cc_t, VDISCARD: cc_t, VMIN: cc_t, VTIME: cc_t, VSTATUS: cc_t, spare: 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) // NCCS = 20 - #endif - + #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) + 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 + #elseif os(OSX) + typealias specialCharactersTuple = (VEOF: cc_t, VEOL: cc_t, VEOL2: cc_t, VERASE: cc_t, VWERASE: cc_t, VKILL: cc_t, VREPRINT: cc_t, spare1: cc_t, VINTR: cc_t, VQUIT: cc_t, VSUSP: cc_t, VDSUSP: cc_t, VSTART: cc_t, VSTOP: cc_t, VLNEXT: cc_t, VDISCARD: cc_t, VMIN: cc_t, VTIME: cc_t, VSTATUS: cc_t, spare: 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) // NCCS = 20 + #endif + specialCharacters.VMIN = cc_t(minimumBytesToRead) specialCharacters.VTIME = cc_t(timeout) settings.c_cc = specialCharacters - + // Commit settings tcsetattr(fileDescriptor, TCSANOW, &settings) } - + public func closePort() { if let fileDescriptor = fileDescriptor { close(fileDescriptor) @@ -365,43 +365,43 @@ public class SerialPort { // MARK: Receiving extension SerialPort { - + public func readBytes(into buffer: UnsafeMutablePointer, size: Int) throws -> Int { guard let fileDescriptor = fileDescriptor else { throw PortError.mustBeOpen } - + let bytesRead = read(fileDescriptor, buffer, size) return bytesRead } - + public func readData(ofLength length: Int) throws -> Data { let buffer = UnsafeMutablePointer.allocate(capacity: length) defer { buffer.deallocate(capacity: length) } - + let bytesRead = try readBytes(into: buffer, size: length) - + 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 } - + public func readString(ofLength length: Int) throws -> String { var remainingBytesToRead = length var result = "" - + while remainingBytesToRead > 0 { let data = try readData(ofLength: remainingBytesToRead) - + if let string = String(data: data, encoding: String.Encoding.utf8) { result += string remainingBytesToRead -= data.count @@ -409,20 +409,20 @@ extension SerialPort { return result } } - + return result } - + public func readUntilChar(_ terminator: CChar) throws -> String { var data = Data() let buffer = UnsafeMutablePointer.allocate(capacity: 1) defer { buffer.deallocate(capacity: 1) } - + while true { let bytesRead = try readBytes(into: buffer, size: 1) - + if bytesRead > 0 { let character = CChar(buffer[0]) @@ -433,19 +433,37 @@ extension SerialPort { } } } - + if let string = String(data: data, encoding: String.Encoding.utf8) { return string } else { throw PortError.stringsMustBeUTF8 } } - + public func readLine() throws -> String { let newlineChar = CChar(10) // Newline/Line feed character `\n` is 10 return try readUntilChar(newlineChar) } - + + public func readChar() throws -> UnicodeScalar { + let buffer = UnsafeMutablePointer.allocate(capacity: 1) + + defer { + buffer.deallocate(capacity: 1) + } + + while true { + let bytesRead = try readBytes(into: buffer, size: 1) + + if bytesRead > 0 { + let character = UnicodeScalar(buffer[0]) + return character + } + } + + } + public func readByte() throws -> UInt8 { let buffer = UnsafeMutablePointer.allocate(capacity: 1) @@ -460,6 +478,7 @@ extension SerialPort { return buffer[0] } } + } public func readUntilBytes(stopBytes: [UInt8], maxBytes: Int) throws -> [UInt8] { @@ -469,6 +488,8 @@ extension SerialPort { buffer.deallocate(capacity: 1) } + var isStopFound = 0 + while true { let byteRead = UInt8(try readBytes(into: buffer, size: 1)) @@ -476,7 +497,6 @@ extension SerialPort { data.append(buffer[0]) if data.count >= stopBytes.count { for index in (0.. UnicodeScalar { - let byteRead = readByte() - let character = UnicodeScalar(buffer[0]) - return character - } - + } // MARK: Transmitting extension SerialPort { - + public func writeBytes(from buffer: UnsafeMutablePointer, size: Int) throws -> Int { guard let fileDescriptor = fileDescriptor else { throw PortError.mustBeOpen } - + let bytesWritten = write(fileDescriptor, buffer, size) return bytesWritten } - + public func writeData(_ data: Data) throws -> Int { let size = data.count let buffer = UnsafeMutablePointer.allocate(capacity: size) defer { buffer.deallocate(capacity: size) } - + data.copyBytes(to: buffer, count: size) - + let bytesWritten = try writeBytes(from: buffer, size: size) return bytesWritten } - + public func writeString(_ string: String) throws -> Int { guard let data = string.data(using: String.Encoding.utf8) else { throw PortError.stringsMustBeUTF8 } - + return try writeData(data) } - + public func writeChar(_ character: UnicodeScalar) throws -> Int{ let stringEquiv = String(character) let bytesWritten = try writeString(stringEquiv) From e1f0278443237fd4351b5a8811d787409e9a7998 Mon Sep 17 00:00:00 2001 From: Yuri Date: Mon, 3 Jul 2017 00:33:26 +0300 Subject: [PATCH 07/36] bug fixes --- Sources/SwiftSerial.swift | 1091 ++++++++++++++++++------------------- 1 file changed, 534 insertions(+), 557 deletions(-) diff --git a/Sources/SwiftSerial.swift b/Sources/SwiftSerial.swift index 1f14c6d..ce7e04e 100644 --- a/Sources/SwiftSerial.swift +++ b/Sources/SwiftSerial.swift @@ -1,557 +1,534 @@ -import Foundation - -#if os(Linux) - public enum BaudRate { - case baud0 - case baud50 - case baud75 - case baud110 - case baud134 - case baud150 - case baud200 - case baud300 - case baud600 - case baud1200 - case baud1800 - case baud2400 - case baud4800 - case baud9600 - case baud19200 - case baud38400 - case baud57600 - case baud115200 - case baud230400 - case baud460800 - case baud500000 - case baud576000 - case baud921600 - case baud1000000 - case baud1152000 - case baud1500000 - case baud2000000 - case baud2500000 - case baud3500000 - case baud4000000 - - var speedValue: speed_t { - switch self { - case .baud0: - return speed_t(B0) - case .baud50: - return speed_t(B50) - case .baud75: - return speed_t(B75) - case .baud110: - return speed_t(B110) - case .baud134: - return speed_t(B134) - case .baud150: - return speed_t(B150) - case .baud200: - return speed_t(B200) - case .baud300: - return speed_t(B300) - case .baud600: - return speed_t(B600) - case .baud1200: - return speed_t(B1200) - case .baud1800: - return speed_t(B1800) - case .baud2400: - return speed_t(B2400) - case .baud4800: - return speed_t(B4800) - case .baud9600: - return speed_t(B9600) - case .baud19200: - return speed_t(B19200) - case .baud38400: - return speed_t(B38400) - case .baud57600: - return speed_t(B57600) - case .baud115200: - return speed_t(B115200) - case .baud230400: - return speed_t(B230400) - case .baud460800: - return speed_t(B460800) - case .baud500000: - return speed_t(B500000) - case .baud576000: - return speed_t(B576000) - case .baud921600: - return speed_t(B921600) - case .baud1000000: - return speed_t(B1000000) - case .baud1152000: - return speed_t(B1152000) - case .baud1500000: - return speed_t(B1500000) - case .baud2000000: - return speed_t(B2000000) - case .baud2500000: - return speed_t(B2500000) - case .baud3500000: - return speed_t(B3500000) - case .baud4000000: - return speed_t(B4000000) - } - } - } -#elseif os(OSX) - public enum BaudRate { - case baud0 - case baud50 - case baud75 - case baud110 - case baud134 - case baud150 - case baud200 - case baud300 - case baud600 - case baud1200 - case baud1800 - case baud2400 - case baud4800 - case baud9600 - case baud19200 - case baud38400 - case baud57600 - case baud115200 - case baud230400 - - var speedValue: speed_t { - switch self { - case .baud0: - return speed_t(B0) - case .baud50: - return speed_t(B50) - case .baud75: - return speed_t(B75) - case .baud110: - return speed_t(B110) - case .baud134: - return speed_t(B134) - case .baud150: - return speed_t(B150) - case .baud200: - return speed_t(B200) - case .baud300: - return speed_t(B300) - case .baud600: - return speed_t(B600) - case .baud1200: - return speed_t(B1200) - case .baud1800: - return speed_t(B1800) - case .baud2400: - return speed_t(B2400) - case .baud4800: - return speed_t(B4800) - case .baud9600: - return speed_t(B9600) - case .baud19200: - return speed_t(B19200) - case .baud38400: - return speed_t(B38400) - case .baud57600: - return speed_t(B57600) - case .baud115200: - return speed_t(B115200) - case .baud230400: - return speed_t(B230400) - } - } - } -#endif - -public enum DataBitsSize { - case bits5 - case bits6 - case bits7 - case bits8 - - var flagValue: tcflag_t { - switch self { - case .bits5: - return tcflag_t(CS5) - case .bits6: - return tcflag_t(CS6) - case .bits7: - return tcflag_t(CS7) - case .bits8: - 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 { - case failedToOpen = -1 // refer to open() - case invalidPath - case mustReceiveOrTransmit - case mustBeOpen - case stringsMustBeUTF8 -} - -public class SerialPort { - - var path: String - var fileDescriptor: Int32? - - public init(path: String) { - self.path = path - } - - public func openPort() throws { - try openPort(toReceive: true, andTransmit: true) - } - - public func openPort(toReceive receive: Bool, andTransmit transmit: Bool) throws { - guard !path.isEmpty else { - throw PortError.invalidPath - } - - guard receive || transmit else { - throw PortError.mustReceiveOrTransmit - } - - var readWriteParam : Int32 - - if receive && transmit { - readWriteParam = O_RDWR - } else if receive { - readWriteParam = O_RDONLY - } else if transmit { - readWriteParam = O_WRONLY - } else { - fatalError() - } - - #if os(Linux) - fileDescriptor = open(path, readWriteParam | O_NOCTTY) - #elseif os(OSX) - fileDescriptor = open(path, readWriteParam | O_NOCTTY | O_EXLOCK) - #endif - - // Throw error if open() failed - if fileDescriptor == PortError.failedToOpen.rawValue { - throw PortError.failedToOpen - } - } - - public 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) { - - guard let fileDescriptor = fileDescriptor else { - return - } - - - // Set up the control structure - var settings = termios() - - // Get options structure for the port - tcgetattr(fileDescriptor, &settings) - - // Set baud rates - cfsetispeed(&settings, receiveRate.speedValue) - cfsetospeed(&settings, transmitRate.speedValue) - - // Enable parity (even/odd) if needed - settings.c_cflag |= parityType.parityValue - - // Set stop bit flag - if sendTwoStopBits { - settings.c_cflag |= tcflag_t(CSTOPB) - } else { - settings.c_cflag &= ~tcflag_t(CSTOPB) - } - - // Set data bits size flag - settings.c_cflag &= ~tcflag_t(CSIZE) - settings.c_cflag |= dataBitsSize.flagValue - - // Set hardware flow control flag - #if os(Linux) - if useHardwareFlowControl { - settings.c_cflag |= tcflag_t(CRTSCTS) - } else { - settings.c_cflag &= ~tcflag_t(CRTSCTS) - } - #elseif os(OSX) - if useHardwareFlowControl { - settings.c_cflag |= tcflag_t(CRTS_IFLOW) - settings.c_cflag |= tcflag_t(CCTS_OFLOW) - } else { - settings.c_cflag &= ~tcflag_t(CRTS_IFLOW) - settings.c_cflag &= ~tcflag_t(CCTS_OFLOW) - } - #endif - - // Set software flow control flags - let softwareFlowControlFlags = tcflag_t(IXON | IXOFF | IXANY) - if useSoftwareFlowControl { - settings.c_iflag |= softwareFlowControlFlags - } else { - settings.c_iflag &= ~softwareFlowControlFlags - } - - // Turn on the receiver of the serial port, and ignore modem control lines - settings.c_cflag |= tcflag_t(CREAD | CLOCAL) - - // Turn off canonical mode - settings.c_lflag &= ~tcflag_t(ICANON | ECHO | ECHOE | ISIG) - - // Set output processing flag - if processOutput { - settings.c_oflag |= tcflag_t(OPOST) - } else { - settings.c_oflag &= ~tcflag_t(OPOST) - } - - //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) - 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 - #elseif os(OSX) - typealias specialCharactersTuple = (VEOF: cc_t, VEOL: cc_t, VEOL2: cc_t, VERASE: cc_t, VWERASE: cc_t, VKILL: cc_t, VREPRINT: cc_t, spare1: cc_t, VINTR: cc_t, VQUIT: cc_t, VSUSP: cc_t, VDSUSP: cc_t, VSTART: cc_t, VSTOP: cc_t, VLNEXT: cc_t, VDISCARD: cc_t, VMIN: cc_t, VTIME: cc_t, VSTATUS: cc_t, spare: 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) // NCCS = 20 - #endif - - specialCharacters.VMIN = cc_t(minimumBytesToRead) - specialCharacters.VTIME = cc_t(timeout) - settings.c_cc = specialCharacters - - // Commit settings - tcsetattr(fileDescriptor, TCSANOW, &settings) - } - - public func closePort() { - if let fileDescriptor = fileDescriptor { - close(fileDescriptor) - } - fileDescriptor = nil - } -} - -// MARK: Receiving - -extension SerialPort { - - public func readBytes(into buffer: UnsafeMutablePointer, size: Int) throws -> Int { - guard let fileDescriptor = fileDescriptor else { - throw PortError.mustBeOpen - } - - let bytesRead = read(fileDescriptor, buffer, size) - return bytesRead - } - - public func readData(ofLength length: Int) throws -> Data { - let buffer = UnsafeMutablePointer.allocate(capacity: length) - defer { - buffer.deallocate(capacity: length) - } - - let bytesRead = try readBytes(into: buffer, size: length) - - 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 - } - - public func readString(ofLength length: Int) throws -> String { - var remainingBytesToRead = length - var result = "" - - while remainingBytesToRead > 0 { - let data = try readData(ofLength: remainingBytesToRead) - - if let string = String(data: data, encoding: String.Encoding.utf8) { - result += string - remainingBytesToRead -= data.count - } else { - return result - } - } - - return result - } - - public func readUntilChar(_ terminator: CChar) throws -> String { - var data = Data() - let buffer = UnsafeMutablePointer.allocate(capacity: 1) - defer { - buffer.deallocate(capacity: 1) - } - - while true { - let bytesRead = try readBytes(into: buffer, size: 1) - - if bytesRead > 0 { - let character = CChar(buffer[0]) - - if character == terminator { - break - } else { - data.append(buffer, count: 1) - } - } - } - - if let string = String(data: data, encoding: String.Encoding.utf8) { - return string - } else { - throw PortError.stringsMustBeUTF8 - } - } - - public func readLine() throws -> String { - let newlineChar = CChar(10) // Newline/Line feed character `\n` is 10 - return try readUntilChar(newlineChar) - } - - public func readChar() throws -> UnicodeScalar { - let buffer = UnsafeMutablePointer.allocate(capacity: 1) - - defer { - buffer.deallocate(capacity: 1) - } - - while true { - let bytesRead = try readBytes(into: buffer, size: 1) - - if bytesRead > 0 { - let character = UnicodeScalar(buffer[0]) - return character - } - } - - } - - public func readByte() throws -> UInt8 { - let buffer = UnsafeMutablePointer.allocate(capacity: 1) - - defer { - buffer.deallocate(capacity: 1) - } - - while true { - let bytesRead = try readBytes(into: buffer, size: 1) - - if bytesRead > 0 { - return buffer[0] - } - } - - } - - public func readUntilBytes(stopBytes: [UInt8], maxBytes: Int) throws -> [UInt8] { - let buffer = UnsafeMutablePointer.allocate(capacity: 1) - var data = [UInt8]() - defer { - buffer.deallocate(capacity: 1) - } - - var isStopFound = 0 - - while true { - let byteRead = UInt8(try readBytes(into: buffer, size: 1)) - - if byteRead > 0 { - data.append(buffer[0]) - if data.count >= stopBytes.count { - for index in (0..= maxBytes { - return data - } - } - } - } - -} - -// MARK: Transmitting - -extension SerialPort { - - public func writeBytes(from buffer: UnsafeMutablePointer, size: Int) throws -> Int { - guard let fileDescriptor = fileDescriptor else { - throw PortError.mustBeOpen - } - - let bytesWritten = write(fileDescriptor, buffer, size) - return bytesWritten - } - - public func writeData(_ data: Data) throws -> Int { - let size = data.count - let buffer = UnsafeMutablePointer.allocate(capacity: size) - defer { - buffer.deallocate(capacity: size) - } - - data.copyBytes(to: buffer, count: size) - - let bytesWritten = try writeBytes(from: buffer, size: size) - return bytesWritten - } - - public func writeString(_ string: String) throws -> Int { - guard let data = string.data(using: String.Encoding.utf8) else { - throw PortError.stringsMustBeUTF8 - } - - return try writeData(data) - } - - public func writeChar(_ character: UnicodeScalar) throws -> Int{ - let stringEquiv = String(character) - let bytesWritten = try writeString(stringEquiv) - return bytesWritten - } -} +import Foundation + +#if os(Linux) +public enum BaudRate { + case baud0 + case baud50 + case baud75 + case baud110 + case baud134 + case baud150 + case baud200 + case baud300 + case baud600 + case baud1200 + case baud1800 + case baud2400 + case baud4800 + case baud9600 + case baud19200 + case baud38400 + case baud57600 + case baud115200 + case baud230400 + case baud460800 + case baud500000 + case baud576000 + case baud921600 + case baud1000000 + case baud1152000 + case baud1500000 + case baud2000000 + case baud2500000 + case baud3500000 + case baud4000000 + + var speedValue: speed_t { + switch self { + case .baud0: + return speed_t(B0) + case .baud50: + return speed_t(B50) + case .baud75: + return speed_t(B75) + case .baud110: + return speed_t(B110) + case .baud134: + return speed_t(B134) + case .baud150: + return speed_t(B150) + case .baud200: + return speed_t(B200) + case .baud300: + return speed_t(B300) + case .baud600: + return speed_t(B600) + case .baud1200: + return speed_t(B1200) + case .baud1800: + return speed_t(B1800) + case .baud2400: + return speed_t(B2400) + case .baud4800: + return speed_t(B4800) + case .baud9600: + return speed_t(B9600) + case .baud19200: + return speed_t(B19200) + case .baud38400: + return speed_t(B38400) + case .baud57600: + return speed_t(B57600) + case .baud115200: + return speed_t(B115200) + case .baud230400: + return speed_t(B230400) + case .baud460800: + return speed_t(B460800) + case .baud500000: + return speed_t(B500000) + case .baud576000: + return speed_t(B576000) + case .baud921600: + return speed_t(B921600) + case .baud1000000: + return speed_t(B1000000) + case .baud1152000: + return speed_t(B1152000) + case .baud1500000: + return speed_t(B1500000) + case .baud2000000: + return speed_t(B2000000) + case .baud2500000: + return speed_t(B2500000) + case .baud3500000: + return speed_t(B3500000) + case .baud4000000: + return speed_t(B4000000) + } + } +} +#elseif os(OSX) +public enum BaudRate { + case baud0 + case baud50 + case baud75 + case baud110 + case baud134 + case baud150 + case baud200 + case baud300 + case baud600 + case baud1200 + case baud1800 + case baud2400 + case baud4800 + case baud9600 + case baud19200 + case baud38400 + case baud57600 + case baud115200 + case baud230400 + + var speedValue: speed_t { + switch self { + case .baud0: + return speed_t(B0) + case .baud50: + return speed_t(B50) + case .baud75: + return speed_t(B75) + case .baud110: + return speed_t(B110) + case .baud134: + return speed_t(B134) + case .baud150: + return speed_t(B150) + case .baud200: + return speed_t(B200) + case .baud300: + return speed_t(B300) + case .baud600: + return speed_t(B600) + case .baud1200: + return speed_t(B1200) + case .baud1800: + return speed_t(B1800) + case .baud2400: + return speed_t(B2400) + case .baud4800: + return speed_t(B4800) + case .baud9600: + return speed_t(B9600) + case .baud19200: + return speed_t(B19200) + case .baud38400: + return speed_t(B38400) + case .baud57600: + return speed_t(B57600) + case .baud115200: + return speed_t(B115200) + case .baud230400: + return speed_t(B230400) + } + } +} +#endif + +public enum DataBitsSize { + case bits5 + case bits6 + case bits7 + case bits8 + + var flagValue: tcflag_t { + switch self { + case .bits5: + return tcflag_t(CS5) + case .bits6: + return tcflag_t(CS6) + case .bits7: + return tcflag_t(CS7) + case .bits8: + 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 { + case failedToOpen = -1 // refer to open() + case invalidPath + case mustReceiveOrTransmit + case mustBeOpen + case stringsMustBeUTF8 +} + +public class SerialPort { + + var path: String + var fileDescriptor: Int32? + + public init(path: String) { + self.path = path + } + + public func openPort() throws { + try openPort(toReceive: true, andTransmit: true) + } + + public func openPort(toReceive receive: Bool, andTransmit transmit: Bool) throws { + guard !path.isEmpty else { + throw PortError.invalidPath + } + + guard receive || transmit else { + throw PortError.mustReceiveOrTransmit + } + + var readWriteParam : Int32 + + if receive && transmit { + readWriteParam = O_RDWR + } else if receive { + readWriteParam = O_RDONLY + } else if transmit { + readWriteParam = O_WRONLY + } else { + fatalError() + } + + #if os(Linux) + fileDescriptor = open(path, readWriteParam | O_NOCTTY) + #elseif os(OSX) + fileDescriptor = open(path, readWriteParam | O_NOCTTY | O_EXLOCK) + #endif + + // Throw error if open() failed + if fileDescriptor == PortError.failedToOpen.rawValue { + throw PortError.failedToOpen + } + } + + public 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) { + + guard let fileDescriptor = fileDescriptor else { + return + } + + + // Set up the control structure + var settings = termios() + + // Get options structure for the port + tcgetattr(fileDescriptor, &settings) + + // Set baud rates + cfsetispeed(&settings, receiveRate.speedValue) + cfsetospeed(&settings, transmitRate.speedValue) + + // Enable parity (even/odd) if needed + settings.c_cflag |= parityType.parityValue + + // Set stop bit flag + if sendTwoStopBits { + settings.c_cflag |= tcflag_t(CSTOPB) + } else { + settings.c_cflag &= ~tcflag_t(CSTOPB) + } + + // Set data bits size flag + settings.c_cflag &= ~tcflag_t(CSIZE) + settings.c_cflag |= dataBitsSize.flagValue + + // Set hardware flow control flag + #if os(Linux) + if useHardwareFlowControl { + settings.c_cflag |= tcflag_t(CRTSCTS) + } else { + settings.c_cflag &= ~tcflag_t(CRTSCTS) + } + #elseif os(OSX) + if useHardwareFlowControl { + settings.c_cflag |= tcflag_t(CRTS_IFLOW) + settings.c_cflag |= tcflag_t(CCTS_OFLOW) + } else { + settings.c_cflag &= ~tcflag_t(CRTS_IFLOW) + settings.c_cflag &= ~tcflag_t(CCTS_OFLOW) + } + #endif + + // Set software flow control flags + let softwareFlowControlFlags = tcflag_t(IXON | IXOFF | IXANY) + if useSoftwareFlowControl { + settings.c_iflag |= softwareFlowControlFlags + } else { + settings.c_iflag &= ~softwareFlowControlFlags + } + + // Turn on the receiver of the serial port, and ignore modem control lines + settings.c_cflag |= tcflag_t(CREAD | CLOCAL) + + // Turn off canonical mode + settings.c_lflag &= ~tcflag_t(ICANON | ECHO | ECHOE | ISIG) + + // Set output processing flag + if processOutput { + settings.c_oflag |= tcflag_t(OPOST) + } else { + settings.c_oflag &= ~tcflag_t(OPOST) + } + + //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) + 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 + #elseif os(OSX) + typealias specialCharactersTuple = (VEOF: cc_t, VEOL: cc_t, VEOL2: cc_t, VERASE: cc_t, VWERASE: cc_t, VKILL: cc_t, VREPRINT: cc_t, spare1: cc_t, VINTR: cc_t, VQUIT: cc_t, VSUSP: cc_t, VDSUSP: cc_t, VSTART: cc_t, VSTOP: cc_t, VLNEXT: cc_t, VDISCARD: cc_t, VMIN: cc_t, VTIME: cc_t, VSTATUS: cc_t, spare: 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) // NCCS = 20 + #endif + + specialCharacters.VMIN = cc_t(minimumBytesToRead) + specialCharacters.VTIME = cc_t(timeout) + settings.c_cc = specialCharacters + + // Commit settings + tcsetattr(fileDescriptor, TCSANOW, &settings) + } + + public func closePort() { + if let fileDescriptor = fileDescriptor { + close(fileDescriptor) + } + fileDescriptor = nil + } +} + +// MARK: Receiving + +extension SerialPort { + + public func readBytes(into buffer: UnsafeMutablePointer, size: Int) throws -> Int { + guard let fileDescriptor = fileDescriptor else { + throw PortError.mustBeOpen + } + + let bytesRead = read(fileDescriptor, buffer, size) + return bytesRead + } + + public func readData(ofLength length: Int) throws -> Data { + let buffer = UnsafeMutablePointer.allocate(capacity: length) + defer { + buffer.deallocate(capacity: length) + } + + let bytesRead = try readBytes(into: buffer, size: length) + + 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 + } + + public func readString(ofLength length: Int) throws -> String { + var remainingBytesToRead = length + var result = "" + + while remainingBytesToRead > 0 { + let data = try readData(ofLength: remainingBytesToRead) + + if let string = String(data: data, encoding: String.Encoding.utf8) { + result += string + remainingBytesToRead -= data.count + } else { + return result + } + } + + return result + } + + public func readUntilChar(_ terminator: CChar) throws -> String { + var data = Data() + let buffer = UnsafeMutablePointer.allocate(capacity: 1) + defer { + buffer.deallocate(capacity: 1) + } + + while true { + let bytesRead = try readBytes(into: buffer, size: 1) + + if bytesRead > 0 { + let character = CChar(buffer[0]) + + if character == terminator { + break + } else { + data.append(buffer, count: 1) + } + } + } + + if let string = String(data: data, encoding: String.Encoding.utf8) { + return string + } else { + throw PortError.stringsMustBeUTF8 + } + } + + public func readLine() throws -> String { + let newlineChar = CChar(10) // Newline/Line feed character `\n` is 10 + return try readUntilChar(newlineChar) + } + + public func readByte() throws -> UInt8 { + let buffer = UnsafeMutablePointer.allocate(capacity: 1) + + defer { + buffer.deallocate(capacity: 1) + } + + while true { + let bytesRead = try readBytes(into: buffer, size: 1) + + if bytesRead > 0 { + return buffer[0] + } + } + } + + public func readChar() throws -> UnicodeScalar { + let byteRead = readByte() + let character = UnicodeScalar(byteRead) + return character + } + + public func readUntilBytes(stopBytes: [UInt8], maxBytes: Int) throws -> [UInt8] { + var data = [UInt8]() + var isStopFound = 0 + while true { + let byteRead = try readByte() + data.append(byteRead) + if data.count >= stopBytes.count { + for index in (0..= maxBytes { + return data + } + } + } + +} + +// MARK: Transmitting + +extension SerialPort { + + public func writeBytes(from buffer: UnsafeMutablePointer, size: Int) throws -> Int { + guard let fileDescriptor = fileDescriptor else { + throw PortError.mustBeOpen + } + + let bytesWritten = write(fileDescriptor, buffer, size) + return bytesWritten + } + + public func writeData(_ data: Data) throws -> Int { + let size = data.count + let buffer = UnsafeMutablePointer.allocate(capacity: size) + defer { + buffer.deallocate(capacity: size) + } + + data.copyBytes(to: buffer, count: size) + + let bytesWritten = try writeBytes(from: buffer, size: size) + return bytesWritten + } + + public func writeString(_ string: String) throws -> Int { + guard let data = string.data(using: String.Encoding.utf8) else { + throw PortError.stringsMustBeUTF8 + } + + return try writeData(data) + } + + public func writeChar(_ character: UnicodeScalar) throws -> Int{ + let stringEquiv = String(character) + let bytesWritten = try writeString(stringEquiv) + return bytesWritten + } +} From 9ef73fd61075ea8d8b4688eec4ec6e024297e091 Mon Sep 17 00:00:00 2001 From: Yuri Date: Mon, 3 Jul 2017 00:39:46 +0300 Subject: [PATCH 08/36] bug fixes --- Sources/SwiftSerial.swift | 499 +++++++++++++++++++------------------- 1 file changed, 251 insertions(+), 248 deletions(-) diff --git a/Sources/SwiftSerial.swift b/Sources/SwiftSerial.swift index ce7e04e..419ac1b 100644 --- a/Sources/SwiftSerial.swift +++ b/Sources/SwiftSerial.swift @@ -1,168 +1,168 @@ import Foundation #if os(Linux) -public enum BaudRate { - case baud0 - case baud50 - case baud75 - case baud110 - case baud134 - case baud150 - case baud200 - case baud300 - case baud600 - case baud1200 - case baud1800 - case baud2400 - case baud4800 - case baud9600 - case baud19200 - case baud38400 - case baud57600 - case baud115200 - case baud230400 - case baud460800 - case baud500000 - case baud576000 - case baud921600 - case baud1000000 - case baud1152000 - case baud1500000 - case baud2000000 - case baud2500000 - case baud3500000 - case baud4000000 - - var speedValue: speed_t { - switch self { - case .baud0: - return speed_t(B0) - case .baud50: - return speed_t(B50) - case .baud75: - return speed_t(B75) - case .baud110: - return speed_t(B110) - case .baud134: - return speed_t(B134) - case .baud150: - return speed_t(B150) - case .baud200: - return speed_t(B200) - case .baud300: - return speed_t(B300) - case .baud600: - return speed_t(B600) - case .baud1200: - return speed_t(B1200) - case .baud1800: - return speed_t(B1800) - case .baud2400: - return speed_t(B2400) - case .baud4800: - return speed_t(B4800) - case .baud9600: - return speed_t(B9600) - case .baud19200: - return speed_t(B19200) - case .baud38400: - return speed_t(B38400) - case .baud57600: - return speed_t(B57600) - case .baud115200: - return speed_t(B115200) - case .baud230400: - return speed_t(B230400) - case .baud460800: - return speed_t(B460800) - case .baud500000: - return speed_t(B500000) - case .baud576000: - return speed_t(B576000) - case .baud921600: - return speed_t(B921600) - case .baud1000000: - return speed_t(B1000000) - case .baud1152000: - return speed_t(B1152000) - case .baud1500000: - return speed_t(B1500000) - case .baud2000000: - return speed_t(B2000000) - case .baud2500000: - return speed_t(B2500000) - case .baud3500000: - return speed_t(B3500000) - case .baud4000000: - return speed_t(B4000000) + public enum BaudRate { + case baud0 + case baud50 + case baud75 + case baud110 + case baud134 + case baud150 + case baud200 + case baud300 + case baud600 + case baud1200 + case baud1800 + case baud2400 + case baud4800 + case baud9600 + case baud19200 + case baud38400 + case baud57600 + case baud115200 + case baud230400 + case baud460800 + case baud500000 + case baud576000 + case baud921600 + case baud1000000 + case baud1152000 + case baud1500000 + case baud2000000 + case baud2500000 + case baud3500000 + case baud4000000 + + var speedValue: speed_t { + switch self { + case .baud0: + return speed_t(B0) + case .baud50: + return speed_t(B50) + case .baud75: + return speed_t(B75) + case .baud110: + return speed_t(B110) + case .baud134: + return speed_t(B134) + case .baud150: + return speed_t(B150) + case .baud200: + return speed_t(B200) + case .baud300: + return speed_t(B300) + case .baud600: + return speed_t(B600) + case .baud1200: + return speed_t(B1200) + case .baud1800: + return speed_t(B1800) + case .baud2400: + return speed_t(B2400) + case .baud4800: + return speed_t(B4800) + case .baud9600: + return speed_t(B9600) + case .baud19200: + return speed_t(B19200) + case .baud38400: + return speed_t(B38400) + case .baud57600: + return speed_t(B57600) + case .baud115200: + return speed_t(B115200) + case .baud230400: + return speed_t(B230400) + case .baud460800: + return speed_t(B460800) + case .baud500000: + return speed_t(B500000) + case .baud576000: + return speed_t(B576000) + case .baud921600: + return speed_t(B921600) + case .baud1000000: + return speed_t(B1000000) + case .baud1152000: + return speed_t(B1152000) + case .baud1500000: + return speed_t(B1500000) + case .baud2000000: + return speed_t(B2000000) + case .baud2500000: + return speed_t(B2500000) + case .baud3500000: + return speed_t(B3500000) + case .baud4000000: + return speed_t(B4000000) + } } } -} #elseif os(OSX) -public enum BaudRate { - case baud0 - case baud50 - case baud75 - case baud110 - case baud134 - case baud150 - case baud200 - case baud300 - case baud600 - case baud1200 - case baud1800 - case baud2400 - case baud4800 - case baud9600 - case baud19200 - case baud38400 - case baud57600 - case baud115200 - case baud230400 - - var speedValue: speed_t { - switch self { - case .baud0: - return speed_t(B0) - case .baud50: - return speed_t(B50) - case .baud75: - return speed_t(B75) - case .baud110: - return speed_t(B110) - case .baud134: - return speed_t(B134) - case .baud150: - return speed_t(B150) - case .baud200: - return speed_t(B200) - case .baud300: - return speed_t(B300) - case .baud600: - return speed_t(B600) - case .baud1200: - return speed_t(B1200) - case .baud1800: - return speed_t(B1800) - case .baud2400: - return speed_t(B2400) - case .baud4800: - return speed_t(B4800) - case .baud9600: - return speed_t(B9600) - case .baud19200: - return speed_t(B19200) - case .baud38400: - return speed_t(B38400) - case .baud57600: - return speed_t(B57600) - case .baud115200: - return speed_t(B115200) - case .baud230400: - return speed_t(B230400) + public enum BaudRate { + case baud0 + case baud50 + case baud75 + case baud110 + case baud134 + case baud150 + case baud200 + case baud300 + case baud600 + case baud1200 + case baud1800 + case baud2400 + case baud4800 + case baud9600 + case baud19200 + case baud38400 + case baud57600 + case baud115200 + case baud230400 + + var speedValue: speed_t { + switch self { + case .baud0: + return speed_t(B0) + case .baud50: + return speed_t(B50) + case .baud75: + return speed_t(B75) + case .baud110: + return speed_t(B110) + case .baud134: + return speed_t(B134) + case .baud150: + return speed_t(B150) + case .baud200: + return speed_t(B200) + case .baud300: + return speed_t(B300) + case .baud600: + return speed_t(B600) + case .baud1200: + return speed_t(B1200) + case .baud1800: + return speed_t(B1800) + case .baud2400: + return speed_t(B2400) + case .baud4800: + return speed_t(B4800) + case .baud9600: + return speed_t(B9600) + case .baud19200: + return speed_t(B19200) + case .baud38400: + return speed_t(B38400) + case .baud57600: + return speed_t(B57600) + case .baud115200: + return speed_t(B115200) + case .baud230400: + return speed_t(B230400) + } } } -} #endif public enum DataBitsSize { @@ -170,7 +170,7 @@ public enum DataBitsSize { case bits6 case bits7 case bits8 - + var flagValue: tcflag_t { switch self { case .bits5: @@ -183,14 +183,14 @@ public enum DataBitsSize { return tcflag_t(CS8) } } - + } public enum ParityType { case none case even case odd - + var parityValue: tcflag_t { switch self { case .none: @@ -212,29 +212,29 @@ public enum PortError: Int32, Error { } public class SerialPort { - + var path: String var fileDescriptor: Int32? - + public init(path: String) { self.path = path } - + public func openPort() throws { try openPort(toReceive: true, andTransmit: true) } - + public func openPort(toReceive receive: Bool, andTransmit transmit: Bool) throws { guard !path.isEmpty else { throw PortError.invalidPath } - + guard receive || transmit else { throw PortError.mustReceiveOrTransmit } - + var readWriteParam : Int32 - + if receive && transmit { readWriteParam = O_RDWR } else if receive { @@ -244,76 +244,76 @@ public class SerialPort { } else { fatalError() } - - #if os(Linux) - fileDescriptor = open(path, readWriteParam | O_NOCTTY) - #elseif os(OSX) - fileDescriptor = open(path, readWriteParam | O_NOCTTY | O_EXLOCK) - #endif - + + #if os(Linux) + fileDescriptor = open(path, readWriteParam | O_NOCTTY) + #elseif os(OSX) + fileDescriptor = open(path, readWriteParam | O_NOCTTY | O_EXLOCK) + #endif + // Throw error if open() failed if fileDescriptor == PortError.failedToOpen.rawValue { throw PortError.failedToOpen } } - + public 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) { + parityType: ParityType = .none, + sendTwoStopBits: Bool = false, /* 1 stop bit is the default */ + dataBitsSize: DataBitsSize = .bits8, + useHardwareFlowControl: Bool = false, + useSoftwareFlowControl: Bool = false, + processOutput: Bool = false) { guard let fileDescriptor = fileDescriptor else { return } - - + + // Set up the control structure var settings = termios() - + // Get options structure for the port tcgetattr(fileDescriptor, &settings) - + // Set baud rates cfsetispeed(&settings, receiveRate.speedValue) cfsetospeed(&settings, transmitRate.speedValue) - + // Enable parity (even/odd) if needed settings.c_cflag |= parityType.parityValue - + // Set stop bit flag if sendTwoStopBits { settings.c_cflag |= tcflag_t(CSTOPB) } else { settings.c_cflag &= ~tcflag_t(CSTOPB) } - + // Set data bits size flag settings.c_cflag &= ~tcflag_t(CSIZE) settings.c_cflag |= dataBitsSize.flagValue - + // Set hardware flow control flag - #if os(Linux) - if useHardwareFlowControl { - settings.c_cflag |= tcflag_t(CRTSCTS) - } else { - settings.c_cflag &= ~tcflag_t(CRTSCTS) - } - #elseif os(OSX) - if useHardwareFlowControl { - settings.c_cflag |= tcflag_t(CRTS_IFLOW) - settings.c_cflag |= tcflag_t(CCTS_OFLOW) - } else { - settings.c_cflag &= ~tcflag_t(CRTS_IFLOW) - settings.c_cflag &= ~tcflag_t(CCTS_OFLOW) - } - #endif - + #if os(Linux) + if useHardwareFlowControl { + settings.c_cflag |= tcflag_t(CRTSCTS) + } else { + settings.c_cflag &= ~tcflag_t(CRTSCTS) + } + #elseif os(OSX) + if useHardwareFlowControl { + settings.c_cflag |= tcflag_t(CRTS_IFLOW) + settings.c_cflag |= tcflag_t(CCTS_OFLOW) + } else { + settings.c_cflag &= ~tcflag_t(CRTS_IFLOW) + settings.c_cflag &= ~tcflag_t(CCTS_OFLOW) + } + #endif + // Set software flow control flags let softwareFlowControlFlags = tcflag_t(IXON | IXOFF | IXANY) if useSoftwareFlowControl { @@ -321,39 +321,39 @@ public class SerialPort { } else { settings.c_iflag &= ~softwareFlowControlFlags } - + // Turn on the receiver of the serial port, and ignore modem control lines settings.c_cflag |= tcflag_t(CREAD | CLOCAL) - + // Turn off canonical mode settings.c_lflag &= ~tcflag_t(ICANON | ECHO | ECHOE | ISIG) - + // Set output processing flag if processOutput { settings.c_oflag |= tcflag_t(OPOST) } else { settings.c_oflag &= ~tcflag_t(OPOST) } - + //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) - 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 - #elseif os(OSX) - typealias specialCharactersTuple = (VEOF: cc_t, VEOL: cc_t, VEOL2: cc_t, VERASE: cc_t, VWERASE: cc_t, VKILL: cc_t, VREPRINT: cc_t, spare1: cc_t, VINTR: cc_t, VQUIT: cc_t, VSUSP: cc_t, VDSUSP: cc_t, VSTART: cc_t, VSTOP: cc_t, VLNEXT: cc_t, VDISCARD: cc_t, VMIN: cc_t, VTIME: cc_t, VSTATUS: cc_t, spare: 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) // NCCS = 20 - #endif - + #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) + 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 + #elseif os(OSX) + typealias specialCharactersTuple = (VEOF: cc_t, VEOL: cc_t, VEOL2: cc_t, VERASE: cc_t, VWERASE: cc_t, VKILL: cc_t, VREPRINT: cc_t, spare1: cc_t, VINTR: cc_t, VQUIT: cc_t, VSUSP: cc_t, VDSUSP: cc_t, VSTART: cc_t, VSTOP: cc_t, VLNEXT: cc_t, VDISCARD: cc_t, VMIN: cc_t, VTIME: cc_t, VSTATUS: cc_t, spare: 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) // NCCS = 20 + #endif + specialCharacters.VMIN = cc_t(minimumBytesToRead) specialCharacters.VTIME = cc_t(timeout) settings.c_cc = specialCharacters - + // Commit settings tcsetattr(fileDescriptor, TCSANOW, &settings) } - + public func closePort() { if let fileDescriptor = fileDescriptor { close(fileDescriptor) @@ -365,43 +365,43 @@ public class SerialPort { // MARK: Receiving extension SerialPort { - + public func readBytes(into buffer: UnsafeMutablePointer, size: Int) throws -> Int { guard let fileDescriptor = fileDescriptor else { throw PortError.mustBeOpen } - + let bytesRead = read(fileDescriptor, buffer, size) return bytesRead } - + public func readData(ofLength length: Int) throws -> Data { let buffer = UnsafeMutablePointer.allocate(capacity: length) defer { buffer.deallocate(capacity: length) } - + let bytesRead = try readBytes(into: buffer, size: length) - + 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 } - + public func readString(ofLength length: Int) throws -> String { var remainingBytesToRead = length var result = "" - + while remainingBytesToRead > 0 { let data = try readData(ofLength: remainingBytesToRead) - + if let string = String(data: data, encoding: String.Encoding.utf8) { result += string remainingBytesToRead -= data.count @@ -409,20 +409,20 @@ extension SerialPort { return result } } - + return result } - + public func readUntilChar(_ terminator: CChar) throws -> String { var data = Data() let buffer = UnsafeMutablePointer.allocate(capacity: 1) defer { buffer.deallocate(capacity: 1) } - + while true { let bytesRead = try readBytes(into: buffer, size: 1) - + if bytesRead > 0 { let character = CChar(buffer[0]) @@ -433,19 +433,19 @@ extension SerialPort { } } } - + if let string = String(data: data, encoding: String.Encoding.utf8) { return string } else { throw PortError.stringsMustBeUTF8 } } - + public func readLine() throws -> String { let newlineChar = CChar(10) // Newline/Line feed character `\n` is 10 return try readUntilChar(newlineChar) } - + public func readByte() throws -> UInt8 { let buffer = UnsafeMutablePointer.allocate(capacity: 1) @@ -461,15 +461,18 @@ extension SerialPort { } } } - + public func readChar() throws -> UnicodeScalar { - let byteRead = readByte() + let byteRead = try readByte() let character = UnicodeScalar(byteRead) - return character + return character } public func readUntilBytes(stopBytes: [UInt8], maxBytes: Int) throws -> [UInt8] { var data = [UInt8]() + defer { + data = nil + } var isStopFound = 0 while true { let byteRead = try readByte() @@ -489,43 +492,43 @@ extension SerialPort { } } } - + } // MARK: Transmitting extension SerialPort { - + public func writeBytes(from buffer: UnsafeMutablePointer, size: Int) throws -> Int { guard let fileDescriptor = fileDescriptor else { throw PortError.mustBeOpen } - + let bytesWritten = write(fileDescriptor, buffer, size) return bytesWritten } - + public func writeData(_ data: Data) throws -> Int { let size = data.count let buffer = UnsafeMutablePointer.allocate(capacity: size) defer { buffer.deallocate(capacity: size) } - + data.copyBytes(to: buffer, count: size) - + let bytesWritten = try writeBytes(from: buffer, size: size) return bytesWritten } - + public func writeString(_ string: String) throws -> Int { guard let data = string.data(using: String.Encoding.utf8) else { throw PortError.stringsMustBeUTF8 } - + return try writeData(data) } - + public func writeChar(_ character: UnicodeScalar) throws -> Int{ let stringEquiv = String(character) let bytesWritten = try writeString(stringEquiv) From e24d39286e4d6506640e46d684957a147eec13a8 Mon Sep 17 00:00:00 2001 From: Yuri Date: Mon, 3 Jul 2017 00:42:53 +0300 Subject: [PATCH 09/36] bug fix --- Sources/SwiftSerial.swift | 3 --- 1 file changed, 3 deletions(-) diff --git a/Sources/SwiftSerial.swift b/Sources/SwiftSerial.swift index 419ac1b..e6a6373 100644 --- a/Sources/SwiftSerial.swift +++ b/Sources/SwiftSerial.swift @@ -470,9 +470,6 @@ extension SerialPort { public func readUntilBytes(stopBytes: [UInt8], maxBytes: Int) throws -> [UInt8] { var data = [UInt8]() - defer { - data = nil - } var isStopFound = 0 while true { let byteRead = try readByte() From e29bb1bddf2faf827e672ca906c1d0efcbb74a85 Mon Sep 17 00:00:00 2001 From: Yuri Date: Mon, 3 Jul 2017 21:31:55 +0300 Subject: [PATCH 10/36] read 0x0D value bug fix --- Sources/SwiftSerial.swift | 31 +++++++++++++++++++++++++------ 1 file changed, 25 insertions(+), 6 deletions(-) diff --git a/Sources/SwiftSerial.swift b/Sources/SwiftSerial.swift index e6a6373..d8a377f 100644 --- a/Sources/SwiftSerial.swift +++ b/Sources/SwiftSerial.swift @@ -348,6 +348,11 @@ public class SerialPort { specialCharacters.VMIN = cc_t(minimumBytesToRead) specialCharacters.VTIME = cc_t(timeout) + + //if not set we reciving 0x0A where must be 0x0D value + settings.c_iflag &= ~UInt(INLCR) + settings.c_iflag &= ~UInt(ICRNL) + settings.c_cc = specialCharacters // Commit settings @@ -446,7 +451,7 @@ extension SerialPort { return try readUntilChar(newlineChar) } - public func readByte() throws -> UInt8 { + public func readChar() throws -> UnicodeScalar { let buffer = UnsafeMutablePointer.allocate(capacity: 1) defer { @@ -457,15 +462,28 @@ extension SerialPort { let bytesRead = try readBytes(into: buffer, size: 1) if bytesRead > 0 { - return buffer[0] + let character = UnicodeScalar(buffer[0]) + return character } } + } - public func readChar() throws -> UnicodeScalar { - let byteRead = try readByte() - let character = UnicodeScalar(byteRead) - return character + public func readByte() throws -> UInt8 { + let buffer = UnsafeMutablePointer.allocate(capacity: 1) + + defer { + buffer.deallocate(capacity: 1) + } + + while true { + let bytesRead = try readBytes(into: buffer, size: 1) + + if bytesRead > 0 { + return buffer[0] + } + } + } public func readUntilBytes(stopBytes: [UInt8], maxBytes: Int) throws -> [UInt8] { @@ -480,6 +498,7 @@ extension SerialPort { isStopFound = isStopFound + 1 } if isStopFound == stopBytes.count { + return data } } From 675c169cc11c8634d7acb79c846fd099bbdea884 Mon Sep 17 00:00:00 2001 From: Yuri Date: Mon, 3 Jul 2017 21:40:36 +0300 Subject: [PATCH 11/36] build bug fix --- Sources/SwiftSerial.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Sources/SwiftSerial.swift b/Sources/SwiftSerial.swift index d8a377f..2a290b0 100644 --- a/Sources/SwiftSerial.swift +++ b/Sources/SwiftSerial.swift @@ -350,8 +350,8 @@ public class SerialPort { specialCharacters.VTIME = cc_t(timeout) //if not set we reciving 0x0A where must be 0x0D value - settings.c_iflag &= ~UInt(INLCR) - settings.c_iflag &= ~UInt(ICRNL) + settings.c_iflag &= ~tcflag_t(INLCR) + settings.c_iflag &= ~tcflag_t(ICRNL) settings.c_cc = specialCharacters From b8bab273f62851201c5ff67b42cca90a2d749491 Mon Sep 17 00:00:00 2001 From: Yuri Date: Mon, 3 Jul 2017 22:58:05 +0300 Subject: [PATCH 12/36] bug fixes --- Sources/SwiftSerial.swift | 598 ++++++-------------------------------- 1 file changed, 81 insertions(+), 517 deletions(-) diff --git a/Sources/SwiftSerial.swift b/Sources/SwiftSerial.swift index 2a290b0..897c240 100644 --- a/Sources/SwiftSerial.swift +++ b/Sources/SwiftSerial.swift @@ -1,553 +1,117 @@ +// +// ARTemperatureMonitor.swift +// hexapod +// +// Created by Yuri on 01.07.17. +// +// + import Foundation +import Dispatch +import SwiftSerial -#if os(Linux) - public enum BaudRate { - case baud0 - case baud50 - case baud75 - case baud110 - case baud134 - case baud150 - case baud200 - case baud300 - case baud600 - case baud1200 - case baud1800 - case baud2400 - case baud4800 - case baud9600 - case baud19200 - case baud38400 - case baud57600 - case baud115200 - case baud230400 - case baud460800 - case baud500000 - case baud576000 - case baud921600 - case baud1000000 - case baud1152000 - case baud1500000 - case baud2000000 - case baud2500000 - case baud3500000 - case baud4000000 - - var speedValue: speed_t { - switch self { - case .baud0: - return speed_t(B0) - case .baud50: - return speed_t(B50) - case .baud75: - return speed_t(B75) - case .baud110: - return speed_t(B110) - case .baud134: - return speed_t(B134) - case .baud150: - return speed_t(B150) - case .baud200: - return speed_t(B200) - case .baud300: - return speed_t(B300) - case .baud600: - return speed_t(B600) - case .baud1200: - return speed_t(B1200) - case .baud1800: - return speed_t(B1800) - case .baud2400: - return speed_t(B2400) - case .baud4800: - return speed_t(B4800) - case .baud9600: - return speed_t(B9600) - case .baud19200: - return speed_t(B19200) - case .baud38400: - return speed_t(B38400) - case .baud57600: - return speed_t(B57600) - case .baud115200: - return speed_t(B115200) - case .baud230400: - return speed_t(B230400) - case .baud460800: - return speed_t(B460800) - case .baud500000: - return speed_t(B500000) - case .baud576000: - return speed_t(B576000) - case .baud921600: - return speed_t(B921600) - case .baud1000000: - return speed_t(B1000000) - case .baud1152000: - return speed_t(B1152000) - case .baud1500000: - return speed_t(B1500000) - case .baud2000000: - return speed_t(B2000000) - case .baud2500000: - return speed_t(B2500000) - case .baud3500000: - return speed_t(B3500000) - case .baud4000000: - return speed_t(B4000000) - } - } - } -#elseif os(OSX) - public enum BaudRate { - case baud0 - case baud50 - case baud75 - case baud110 - case baud134 - case baud150 - case baud200 - case baud300 - case baud600 - case baud1200 - case baud1800 - case baud2400 - case baud4800 - case baud9600 - case baud19200 - case baud38400 - case baud57600 - case baud115200 - case baud230400 - - var speedValue: speed_t { - switch self { - case .baud0: - return speed_t(B0) - case .baud50: - return speed_t(B50) - case .baud75: - return speed_t(B75) - case .baud110: - return speed_t(B110) - case .baud134: - return speed_t(B134) - case .baud150: - return speed_t(B150) - case .baud200: - return speed_t(B200) - case .baud300: - return speed_t(B300) - case .baud600: - return speed_t(B600) - case .baud1200: - return speed_t(B1200) - case .baud1800: - return speed_t(B1800) - case .baud2400: - return speed_t(B2400) - case .baud4800: - return speed_t(B4800) - case .baud9600: - return speed_t(B9600) - case .baud19200: - return speed_t(B19200) - case .baud38400: - return speed_t(B38400) - case .baud57600: - return speed_t(B57600) - case .baud115200: - return speed_t(B115200) - case .baud230400: - return speed_t(B230400) - } - } - } -#endif -public enum DataBitsSize { - case bits5 - case bits6 - case bits7 - case bits8 - - var flagValue: tcflag_t { - switch self { - case .bits5: - return tcflag_t(CS5) - case .bits6: - return tcflag_t(CS6) - case .bits7: - return tcflag_t(CS7) - case .bits8: - return tcflag_t(CS8) - } - } - -} +//port temp_monitor -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 { - case failedToOpen = -1 // refer to open() - case invalidPath - case mustReceiveOrTransmit - case mustBeOpen - case stringsMustBeUTF8 -} - -public class SerialPort { - - var path: String - var fileDescriptor: Int32? - - public init(path: String) { - self.path = path - } - - public func openPort() throws { - try openPort(toReceive: true, andTransmit: true) - } - - public func openPort(toReceive receive: Bool, andTransmit transmit: Bool) throws { - guard !path.isEmpty else { - throw PortError.invalidPath - } - - guard receive || transmit else { - throw PortError.mustReceiveOrTransmit - } - - var readWriteParam : Int32 - - if receive && transmit { - readWriteParam = O_RDWR - } else if receive { - readWriteParam = O_RDONLY - } else if transmit { - readWriteParam = O_WRONLY +class ARTemperatureMonitor { + private var serialPort: SerialPort! + private var portName = "" + private var thread:Thread? + var isRuningLoop = false + var maxBufferSize = 1024 //1K input UART buffer for parcing incomming data + var packetSize = 32 //29 bytes gyro packet size + + var serialQueue: DispatchQueue! + + func isRuning() -> Bool { + if (thread != nil) { + return (thread?.isExecuting)! } else { - fatalError() - } - - #if os(Linux) - fileDescriptor = open(path, readWriteParam | O_NOCTTY) - #elseif os(OSX) - fileDescriptor = open(path, readWriteParam | O_NOCTTY | O_EXLOCK) - #endif - - // Throw error if open() failed - if fileDescriptor == PortError.failedToOpen.rawValue { - throw PortError.failedToOpen + return false } } - public 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) { - - guard let fileDescriptor = fileDescriptor else { - return - } - - - // Set up the control structure - var settings = termios() - - // Get options structure for the port - tcgetattr(fileDescriptor, &settings) - - // Set baud rates - cfsetispeed(&settings, receiveRate.speedValue) - cfsetospeed(&settings, transmitRate.speedValue) - - // Enable parity (even/odd) if needed - settings.c_cflag |= parityType.parityValue - - // Set stop bit flag - if sendTwoStopBits { - settings.c_cflag |= tcflag_t(CSTOPB) - } else { - settings.c_cflag &= ~tcflag_t(CSTOPB) - } - - // Set data bits size flag - settings.c_cflag &= ~tcflag_t(CSIZE) - settings.c_cflag |= dataBitsSize.flagValue - - // Set hardware flow control flag - #if os(Linux) - if useHardwareFlowControl { - settings.c_cflag |= tcflag_t(CRTSCTS) - } else { - settings.c_cflag &= ~tcflag_t(CRTSCTS) - } - #elseif os(OSX) - if useHardwareFlowControl { - settings.c_cflag |= tcflag_t(CRTS_IFLOW) - settings.c_cflag |= tcflag_t(CCTS_OFLOW) - } else { - settings.c_cflag &= ~tcflag_t(CRTS_IFLOW) - settings.c_cflag &= ~tcflag_t(CCTS_OFLOW) - } - #endif - - // Set software flow control flags - let softwareFlowControlFlags = tcflag_t(IXON | IXOFF | IXANY) - if useSoftwareFlowControl { - settings.c_iflag |= softwareFlowControlFlags - } else { - settings.c_iflag &= ~softwareFlowControlFlags - } - - // Turn on the receiver of the serial port, and ignore modem control lines - settings.c_cflag |= tcflag_t(CREAD | CLOCAL) - - // Turn off canonical mode - settings.c_lflag &= ~tcflag_t(ICANON | ECHO | ECHOE | ISIG) - - // Set output processing flag - if processOutput { - settings.c_oflag |= tcflag_t(OPOST) - } else { - settings.c_oflag &= ~tcflag_t(OPOST) - } - - //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) - 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 - #elseif os(OSX) - typealias specialCharactersTuple = (VEOF: cc_t, VEOL: cc_t, VEOL2: cc_t, VERASE: cc_t, VWERASE: cc_t, VKILL: cc_t, VREPRINT: cc_t, spare1: cc_t, VINTR: cc_t, VQUIT: cc_t, VSUSP: cc_t, VDSUSP: cc_t, VSTART: cc_t, VSTOP: cc_t, VLNEXT: cc_t, VDISCARD: cc_t, VMIN: cc_t, VTIME: cc_t, VSTATUS: cc_t, spare: 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) // NCCS = 20 - #endif - - specialCharacters.VMIN = cc_t(minimumBytesToRead) - specialCharacters.VTIME = cc_t(timeout) - - //if not set we reciving 0x0A where must be 0x0D value - settings.c_iflag &= ~tcflag_t(INLCR) - settings.c_iflag &= ~tcflag_t(ICRNL) - - settings.c_cc = specialCharacters - - // Commit settings - tcsetattr(fileDescriptor, TCSANOW, &settings) + init(portName:String = "temp_monitor") { + self.portName = portName + serialPort = SerialPort(path: portName) } - public func closePort() { - if let fileDescriptor = fileDescriptor { - close(fileDescriptor) - } - fileDescriptor = nil - } -} - -// MARK: Receiving - -extension SerialPort { - public func readBytes(into buffer: UnsafeMutablePointer, size: Int) throws -> Int { - guard let fileDescriptor = fileDescriptor else { - throw PortError.mustBeOpen - } - - let bytesRead = read(fileDescriptor, buffer, size) - return bytesRead - } - public func readData(ofLength length: Int) throws -> Data { - let buffer = UnsafeMutablePointer.allocate(capacity: length) - defer { - buffer.deallocate(capacity: length) - } - - let bytesRead = try readBytes(into: buffer, size: length) + func start() { - 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) + if thread != nil { + return } - return data - } - - public func readString(ofLength length: Int) throws -> String { - var remainingBytesToRead = length - var result = "" + isRuningLoop = true - while remainingBytesToRead > 0 { - let data = try readData(ofLength: remainingBytesToRead) + do { + + // print("Attempting to open port: \(portName)") + try serialPort.openPort() + print("Serial port \(portName) opened successfully.") - if let string = String(data: data, encoding: String.Encoding.utf8) { - result += string - remainingBytesToRead -= data.count - } else { - return result + serialPort.setSettings(receiveRate: .baud115200, + transmitRate: .baud115200, + minimumBytesToRead: 1) + + serialQueue = DispatchQueue(label: self.portName) + serialQueue.async { + self.backgroundRead() } + + } catch PortError.failedToOpen { + print("Serial port \(portName) failed to open. You might need root permissions.") + } catch { + print("Error: \(error)") } - - return result } - public func readUntilChar(_ terminator: CChar) throws -> String { - var data = Data() - let buffer = UnsafeMutablePointer.allocate(capacity: 1) - defer { - buffer.deallocate(capacity: 1) - } - - while true { - let bytesRead = try readBytes(into: buffer, size: 1) - - if bytesRead > 0 { - let character = CChar(buffer[0]) + func backgroundRead() { + do{ + let readData = try serialPort.readUntilBytes(stopBytes: [58,58,58,13,10], maxBytes: 64) + if readData.count >= 23 { + //decoding recieved data + var CRC: UInt32 = 0; + for i in 0...16 { + CRC = CRC + UInt32(readData[i]) + } + + CRC = CRC & 0xFF + + // print("\(readData)") + + let sensorNumber:UInt8 = readData[0] + let sensorAddress:String = "\(String(format:"%2X", readData[1])) \(String(format:"%2X", readData[2])) \(String(format:"%2X", readData[3])) \(String(format:"%2X", readData[4])) \(String(format:"%2X", readData[5])) \(String(format:"%2X", readData[6])) \(String(format:"%2X", readData[7])) \(String(format:"%2X", readData[8]))" + let temperature: Int32 = Int32(readData[9]) | Int32(readData[10]) << 8 | Int32(readData[11]) << 16 | Int32(readData[12]) << 24 + + let timer: UInt32 = UInt32(readData[13]) | UInt32(readData[14]) << 8 | UInt32(readData[15]) << 16 | UInt32(readData[16]) << 24 + + let crc_pack = UInt32(readData[17]) - if character == terminator { - break + if CRC == crc_pack { + print("\(portName) packet end found CRC=\(CRC)==\(crc_pack)) OK \(sensorNumber) \(sensorAddress) \(temperature) \(timer)") } else { - data.append(buffer, count: 1) + print("\(portName) packet end found CRC=\(CRC)==\(crc_pack)) FAIL \(sensorNumber) \(sensorAddress) \(temperature) \(timer)") + // print("\(portName) packet end found CRC=\(CRC)!=\(crc_pack)) FAIL") } } - } - - if let string = String(data: data, encoding: String.Encoding.utf8) { - return string - } else { - throw PortError.stringsMustBeUTF8 - } - } - - public func readLine() throws -> String { - let newlineChar = CChar(10) // Newline/Line feed character `\n` is 10 - return try readUntilChar(newlineChar) - } - - public func readChar() throws -> UnicodeScalar { - let buffer = UnsafeMutablePointer.allocate(capacity: 1) - - defer { - buffer.deallocate(capacity: 1) - } - - while true { - let bytesRead = try readBytes(into: buffer, size: 1) - if bytesRead > 0 { - let character = UnicodeScalar(buffer[0]) - return character - } - } - - } - - public func readByte() throws -> UInt8 { - let buffer = UnsafeMutablePointer.allocate(capacity: 1) - - defer { - buffer.deallocate(capacity: 1) - } - - while true { - let bytesRead = try readBytes(into: buffer, size: 1) - if bytesRead > 0 { - return buffer[0] - } + } catch { + print("Error: \(error)") } - } - - public func readUntilBytes(stopBytes: [UInt8], maxBytes: Int) throws -> [UInt8] { - var data = [UInt8]() - var isStopFound = 0 - while true { - let byteRead = try readByte() - data.append(byteRead) - if data.count >= stopBytes.count { - for index in (0..= maxBytes { - return data - } - } - } - -} - -// MARK: Transmitting - -extension SerialPort { - - public func writeBytes(from buffer: UnsafeMutablePointer, size: Int) throws -> Int { - guard let fileDescriptor = fileDescriptor else { - throw PortError.mustBeOpen + serialQueue.async { + self.backgroundRead() } - - let bytesWritten = write(fileDescriptor, buffer, size) - return bytesWritten } - public func writeData(_ data: Data) throws -> Int { - let size = data.count - let buffer = UnsafeMutablePointer.allocate(capacity: size) - defer { - buffer.deallocate(capacity: size) - } - - data.copyBytes(to: buffer, count: size) - - let bytesWritten = try writeBytes(from: buffer, size: size) - return bytesWritten + func stop() { + isRuningLoop = false + print("Stoping thread \(self.portName)...") } - public func writeString(_ string: String) throws -> Int { - guard let data = string.data(using: String.Encoding.utf8) else { - throw PortError.stringsMustBeUTF8 - } - - return try writeData(data) - } - public func writeChar(_ character: UnicodeScalar) throws -> Int{ - let stringEquiv = String(character) - let bytesWritten = try writeString(stringEquiv) - return bytesWritten - } } From af6779d07fd13bd7f477dcea08d8cd440f10dc76 Mon Sep 17 00:00:00 2001 From: Yuri Date: Mon, 3 Jul 2017 23:46:06 +0300 Subject: [PATCH 13/36] Revert "bug fixes" This reverts commit b8bab273f62851201c5ff67b42cca90a2d749491. --- Sources/SwiftSerial.swift | 598 ++++++++++++++++++++++++++++++++------ 1 file changed, 517 insertions(+), 81 deletions(-) diff --git a/Sources/SwiftSerial.swift b/Sources/SwiftSerial.swift index 897c240..2a290b0 100644 --- a/Sources/SwiftSerial.swift +++ b/Sources/SwiftSerial.swift @@ -1,117 +1,553 @@ -// -// ARTemperatureMonitor.swift -// hexapod -// -// Created by Yuri on 01.07.17. -// -// - import Foundation -import Dispatch -import SwiftSerial +#if os(Linux) + public enum BaudRate { + case baud0 + case baud50 + case baud75 + case baud110 + case baud134 + case baud150 + case baud200 + case baud300 + case baud600 + case baud1200 + case baud1800 + case baud2400 + case baud4800 + case baud9600 + case baud19200 + case baud38400 + case baud57600 + case baud115200 + case baud230400 + case baud460800 + case baud500000 + case baud576000 + case baud921600 + case baud1000000 + case baud1152000 + case baud1500000 + case baud2000000 + case baud2500000 + case baud3500000 + case baud4000000 + + var speedValue: speed_t { + switch self { + case .baud0: + return speed_t(B0) + case .baud50: + return speed_t(B50) + case .baud75: + return speed_t(B75) + case .baud110: + return speed_t(B110) + case .baud134: + return speed_t(B134) + case .baud150: + return speed_t(B150) + case .baud200: + return speed_t(B200) + case .baud300: + return speed_t(B300) + case .baud600: + return speed_t(B600) + case .baud1200: + return speed_t(B1200) + case .baud1800: + return speed_t(B1800) + case .baud2400: + return speed_t(B2400) + case .baud4800: + return speed_t(B4800) + case .baud9600: + return speed_t(B9600) + case .baud19200: + return speed_t(B19200) + case .baud38400: + return speed_t(B38400) + case .baud57600: + return speed_t(B57600) + case .baud115200: + return speed_t(B115200) + case .baud230400: + return speed_t(B230400) + case .baud460800: + return speed_t(B460800) + case .baud500000: + return speed_t(B500000) + case .baud576000: + return speed_t(B576000) + case .baud921600: + return speed_t(B921600) + case .baud1000000: + return speed_t(B1000000) + case .baud1152000: + return speed_t(B1152000) + case .baud1500000: + return speed_t(B1500000) + case .baud2000000: + return speed_t(B2000000) + case .baud2500000: + return speed_t(B2500000) + case .baud3500000: + return speed_t(B3500000) + case .baud4000000: + return speed_t(B4000000) + } + } + } +#elseif os(OSX) + public enum BaudRate { + case baud0 + case baud50 + case baud75 + case baud110 + case baud134 + case baud150 + case baud200 + case baud300 + case baud600 + case baud1200 + case baud1800 + case baud2400 + case baud4800 + case baud9600 + case baud19200 + case baud38400 + case baud57600 + case baud115200 + case baud230400 + + var speedValue: speed_t { + switch self { + case .baud0: + return speed_t(B0) + case .baud50: + return speed_t(B50) + case .baud75: + return speed_t(B75) + case .baud110: + return speed_t(B110) + case .baud134: + return speed_t(B134) + case .baud150: + return speed_t(B150) + case .baud200: + return speed_t(B200) + case .baud300: + return speed_t(B300) + case .baud600: + return speed_t(B600) + case .baud1200: + return speed_t(B1200) + case .baud1800: + return speed_t(B1800) + case .baud2400: + return speed_t(B2400) + case .baud4800: + return speed_t(B4800) + case .baud9600: + return speed_t(B9600) + case .baud19200: + return speed_t(B19200) + case .baud38400: + return speed_t(B38400) + case .baud57600: + return speed_t(B57600) + case .baud115200: + return speed_t(B115200) + case .baud230400: + return speed_t(B230400) + } + } + } +#endif -//port temp_monitor +public enum DataBitsSize { + case bits5 + case bits6 + case bits7 + case bits8 + + var flagValue: tcflag_t { + switch self { + case .bits5: + return tcflag_t(CS5) + case .bits6: + return tcflag_t(CS6) + case .bits7: + return tcflag_t(CS7) + case .bits8: + return tcflag_t(CS8) + } + } + +} -class ARTemperatureMonitor { - private var serialPort: SerialPort! - private var portName = "" - private var thread:Thread? - var isRuningLoop = false - var maxBufferSize = 1024 //1K input UART buffer for parcing incomming data - var packetSize = 32 //29 bytes gyro packet size - - var serialQueue: DispatchQueue! - - func isRuning() -> Bool { - if (thread != nil) { - return (thread?.isExecuting)! - } else { - return false +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 { + case failedToOpen = -1 // refer to open() + case invalidPath + case mustReceiveOrTransmit + case mustBeOpen + case stringsMustBeUTF8 +} + +public class SerialPort { + + var path: String + var fileDescriptor: Int32? - init(portName:String = "temp_monitor") { - self.portName = portName - serialPort = SerialPort(path: portName) + public init(path: String) { + self.path = path } + public func openPort() throws { + try openPort(toReceive: true, andTransmit: true) + } + public func openPort(toReceive receive: Bool, andTransmit transmit: Bool) throws { + guard !path.isEmpty else { + throw PortError.invalidPath + } + + guard receive || transmit else { + throw PortError.mustReceiveOrTransmit + } + + var readWriteParam : Int32 + + if receive && transmit { + readWriteParam = O_RDWR + } else if receive { + readWriteParam = O_RDONLY + } else if transmit { + readWriteParam = O_WRONLY + } else { + fatalError() + } + + #if os(Linux) + fileDescriptor = open(path, readWriteParam | O_NOCTTY) + #elseif os(OSX) + fileDescriptor = open(path, readWriteParam | O_NOCTTY | O_EXLOCK) + #endif + + // Throw error if open() failed + if fileDescriptor == PortError.failedToOpen.rawValue { + throw PortError.failedToOpen + } + } - func start() { + public 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) { - if thread != nil { + guard let fileDescriptor = fileDescriptor else { return } - isRuningLoop = true - do { - - // print("Attempting to open port: \(portName)") - try serialPort.openPort() - print("Serial port \(portName) opened successfully.") - - serialPort.setSettings(receiveRate: .baud115200, - transmitRate: .baud115200, - minimumBytesToRead: 1) - - serialQueue = DispatchQueue(label: self.portName) - serialQueue.async { - self.backgroundRead() + // Set up the control structure + var settings = termios() + + // Get options structure for the port + tcgetattr(fileDescriptor, &settings) + + // Set baud rates + cfsetispeed(&settings, receiveRate.speedValue) + cfsetospeed(&settings, transmitRate.speedValue) + + // Enable parity (even/odd) if needed + settings.c_cflag |= parityType.parityValue + + // Set stop bit flag + if sendTwoStopBits { + settings.c_cflag |= tcflag_t(CSTOPB) + } else { + settings.c_cflag &= ~tcflag_t(CSTOPB) + } + + // Set data bits size flag + settings.c_cflag &= ~tcflag_t(CSIZE) + settings.c_cflag |= dataBitsSize.flagValue + + // Set hardware flow control flag + #if os(Linux) + if useHardwareFlowControl { + settings.c_cflag |= tcflag_t(CRTSCTS) + } else { + settings.c_cflag &= ~tcflag_t(CRTSCTS) } + #elseif os(OSX) + if useHardwareFlowControl { + settings.c_cflag |= tcflag_t(CRTS_IFLOW) + settings.c_cflag |= tcflag_t(CCTS_OFLOW) + } else { + settings.c_cflag &= ~tcflag_t(CRTS_IFLOW) + settings.c_cflag &= ~tcflag_t(CCTS_OFLOW) + } + #endif + + // Set software flow control flags + let softwareFlowControlFlags = tcflag_t(IXON | IXOFF | IXANY) + if useSoftwareFlowControl { + settings.c_iflag |= softwareFlowControlFlags + } else { + settings.c_iflag &= ~softwareFlowControlFlags + } + + // Turn on the receiver of the serial port, and ignore modem control lines + settings.c_cflag |= tcflag_t(CREAD | CLOCAL) + + // Turn off canonical mode + settings.c_lflag &= ~tcflag_t(ICANON | ECHO | ECHOE | ISIG) + + // Set output processing flag + if processOutput { + settings.c_oflag |= tcflag_t(OPOST) + } else { + settings.c_oflag &= ~tcflag_t(OPOST) + } + + //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) + 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 + #elseif os(OSX) + typealias specialCharactersTuple = (VEOF: cc_t, VEOL: cc_t, VEOL2: cc_t, VERASE: cc_t, VWERASE: cc_t, VKILL: cc_t, VREPRINT: cc_t, spare1: cc_t, VINTR: cc_t, VQUIT: cc_t, VSUSP: cc_t, VDSUSP: cc_t, VSTART: cc_t, VSTOP: cc_t, VLNEXT: cc_t, VDISCARD: cc_t, VMIN: cc_t, VTIME: cc_t, VSTATUS: cc_t, spare: 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) // NCCS = 20 + #endif + + specialCharacters.VMIN = cc_t(minimumBytesToRead) + specialCharacters.VTIME = cc_t(timeout) + + //if not set we reciving 0x0A where must be 0x0D value + settings.c_iflag &= ~tcflag_t(INLCR) + settings.c_iflag &= ~tcflag_t(ICRNL) + + settings.c_cc = specialCharacters + + // Commit settings + tcsetattr(fileDescriptor, TCSANOW, &settings) + } + + public func closePort() { + if let fileDescriptor = fileDescriptor { + close(fileDescriptor) + } + fileDescriptor = nil + } +} + +// MARK: Receiving + +extension SerialPort { + + public func readBytes(into buffer: UnsafeMutablePointer, size: Int) throws -> Int { + guard let fileDescriptor = fileDescriptor else { + throw PortError.mustBeOpen + } + + let bytesRead = read(fileDescriptor, buffer, size) + return bytesRead + } + + public func readData(ofLength length: Int) throws -> Data { + let buffer = UnsafeMutablePointer.allocate(capacity: length) + defer { + buffer.deallocate(capacity: length) + } + + let bytesRead = try readBytes(into: buffer, size: length) + + 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 + } + + public func readString(ofLength length: Int) throws -> String { + var remainingBytesToRead = length + var result = "" + + while remainingBytesToRead > 0 { + let data = try readData(ofLength: remainingBytesToRead) - } catch PortError.failedToOpen { - print("Serial port \(portName) failed to open. You might need root permissions.") - } catch { - print("Error: \(error)") + if let string = String(data: data, encoding: String.Encoding.utf8) { + result += string + remainingBytesToRead -= data.count + } else { + return result + } } + + return result } - func backgroundRead() { - do{ - let readData = try serialPort.readUntilBytes(stopBytes: [58,58,58,13,10], maxBytes: 64) - if readData.count >= 23 { - //decoding recieved data - var CRC: UInt32 = 0; - for i in 0...16 { - CRC = CRC + UInt32(readData[i]) - } - - CRC = CRC & 0xFF - - // print("\(readData)") - - let sensorNumber:UInt8 = readData[0] - let sensorAddress:String = "\(String(format:"%2X", readData[1])) \(String(format:"%2X", readData[2])) \(String(format:"%2X", readData[3])) \(String(format:"%2X", readData[4])) \(String(format:"%2X", readData[5])) \(String(format:"%2X", readData[6])) \(String(format:"%2X", readData[7])) \(String(format:"%2X", readData[8]))" - let temperature: Int32 = Int32(readData[9]) | Int32(readData[10]) << 8 | Int32(readData[11]) << 16 | Int32(readData[12]) << 24 - - let timer: UInt32 = UInt32(readData[13]) | UInt32(readData[14]) << 8 | UInt32(readData[15]) << 16 | UInt32(readData[16]) << 24 - - let crc_pack = UInt32(readData[17]) + public func readUntilChar(_ terminator: CChar) throws -> String { + var data = Data() + let buffer = UnsafeMutablePointer.allocate(capacity: 1) + defer { + buffer.deallocate(capacity: 1) + } + + while true { + let bytesRead = try readBytes(into: buffer, size: 1) + + if bytesRead > 0 { + let character = CChar(buffer[0]) - if CRC == crc_pack { - print("\(portName) packet end found CRC=\(CRC)==\(crc_pack)) OK \(sensorNumber) \(sensorAddress) \(temperature) \(timer)") + if character == terminator { + break } else { - print("\(portName) packet end found CRC=\(CRC)==\(crc_pack)) FAIL \(sensorNumber) \(sensorAddress) \(temperature) \(timer)") - // print("\(portName) packet end found CRC=\(CRC)!=\(crc_pack)) FAIL") + data.append(buffer, count: 1) } } + } + + if let string = String(data: data, encoding: String.Encoding.utf8) { + return string + } else { + throw PortError.stringsMustBeUTF8 + } + } + + public func readLine() throws -> String { + let newlineChar = CChar(10) // Newline/Line feed character `\n` is 10 + return try readUntilChar(newlineChar) + } + + public func readChar() throws -> UnicodeScalar { + let buffer = UnsafeMutablePointer.allocate(capacity: 1) + + defer { + buffer.deallocate(capacity: 1) + } + + while true { + let bytesRead = try readBytes(into: buffer, size: 1) + if bytesRead > 0 { + let character = UnicodeScalar(buffer[0]) + return character + } + } + + } + + public func readByte() throws -> UInt8 { + let buffer = UnsafeMutablePointer.allocate(capacity: 1) + + defer { + buffer.deallocate(capacity: 1) + } + + while true { + let bytesRead = try readBytes(into: buffer, size: 1) - } catch { - print("Error: \(error)") + if bytesRead > 0 { + return buffer[0] + } } - serialQueue.async { - self.backgroundRead() + } + + public func readUntilBytes(stopBytes: [UInt8], maxBytes: Int) throws -> [UInt8] { + var data = [UInt8]() + var isStopFound = 0 + while true { + let byteRead = try readByte() + data.append(byteRead) + if data.count >= stopBytes.count { + for index in (0..= maxBytes { + return data + } + } + } + +} + +// MARK: Transmitting + +extension SerialPort { + + public func writeBytes(from buffer: UnsafeMutablePointer, size: Int) throws -> Int { + guard let fileDescriptor = fileDescriptor else { + throw PortError.mustBeOpen } + + let bytesWritten = write(fileDescriptor, buffer, size) + return bytesWritten } - func stop() { - isRuningLoop = false - print("Stoping thread \(self.portName)...") + public func writeData(_ data: Data) throws -> Int { + let size = data.count + let buffer = UnsafeMutablePointer.allocate(capacity: size) + defer { + buffer.deallocate(capacity: size) + } + + data.copyBytes(to: buffer, count: size) + + let bytesWritten = try writeBytes(from: buffer, size: size) + return bytesWritten } + public func writeString(_ string: String) throws -> Int { + guard let data = string.data(using: String.Encoding.utf8) else { + throw PortError.stringsMustBeUTF8 + } + + return try writeData(data) + } + public func writeChar(_ character: UnicodeScalar) throws -> Int{ + let stringEquiv = String(character) + let bytesWritten = try writeString(stringEquiv) + return bytesWritten + } } From 1d83a8a66112435196de40a1e9ac203026d11a1b Mon Sep 17 00:00:00 2001 From: Yuri Date: Mon, 3 Jul 2017 23:48:35 +0300 Subject: [PATCH 14/36] bug fix --- Sources/SwiftSerial.swift | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/Sources/SwiftSerial.swift b/Sources/SwiftSerial.swift index 2a290b0..8e249cd 100644 --- a/Sources/SwiftSerial.swift +++ b/Sources/SwiftSerial.swift @@ -490,25 +490,28 @@ extension SerialPort { var data = [UInt8]() var isStopFound = 0 while true { + isStopFound = 0 let byteRead = try readByte() data.append(byteRead) + if data.count >= stopBytes.count { - for index in (0..= maxBytes { return data } } } - } // MARK: Transmitting From 015ef386256f2acb814449f2d9e1383b2cc6e863 Mon Sep 17 00:00:00 2001 From: Yuri Date: Mon, 3 Jul 2017 23:59:07 +0300 Subject: [PATCH 15/36] bug fix --- Sources/SwiftSerial.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sources/SwiftSerial.swift b/Sources/SwiftSerial.swift index 8e249cd..fb47522 100644 --- a/Sources/SwiftSerial.swift +++ b/Sources/SwiftSerial.swift @@ -497,7 +497,7 @@ extension SerialPort { if data.count >= stopBytes.count { if byteRead == stopBytes[stopBytes.count - 1] { for index in (0.. Date: Sat, 8 Jul 2017 10:07:20 +0300 Subject: [PATCH 16/36] add write byte, write byte array functions --- Sources/SwiftSerial.swift | 1136 +++++++++++++++++++------------------ 1 file changed, 580 insertions(+), 556 deletions(-) diff --git a/Sources/SwiftSerial.swift b/Sources/SwiftSerial.swift index fb47522..b3cf6fc 100644 --- a/Sources/SwiftSerial.swift +++ b/Sources/SwiftSerial.swift @@ -1,556 +1,580 @@ -import Foundation - -#if os(Linux) - public enum BaudRate { - case baud0 - case baud50 - case baud75 - case baud110 - case baud134 - case baud150 - case baud200 - case baud300 - case baud600 - case baud1200 - case baud1800 - case baud2400 - case baud4800 - case baud9600 - case baud19200 - case baud38400 - case baud57600 - case baud115200 - case baud230400 - case baud460800 - case baud500000 - case baud576000 - case baud921600 - case baud1000000 - case baud1152000 - case baud1500000 - case baud2000000 - case baud2500000 - case baud3500000 - case baud4000000 - - var speedValue: speed_t { - switch self { - case .baud0: - return speed_t(B0) - case .baud50: - return speed_t(B50) - case .baud75: - return speed_t(B75) - case .baud110: - return speed_t(B110) - case .baud134: - return speed_t(B134) - case .baud150: - return speed_t(B150) - case .baud200: - return speed_t(B200) - case .baud300: - return speed_t(B300) - case .baud600: - return speed_t(B600) - case .baud1200: - return speed_t(B1200) - case .baud1800: - return speed_t(B1800) - case .baud2400: - return speed_t(B2400) - case .baud4800: - return speed_t(B4800) - case .baud9600: - return speed_t(B9600) - case .baud19200: - return speed_t(B19200) - case .baud38400: - return speed_t(B38400) - case .baud57600: - return speed_t(B57600) - case .baud115200: - return speed_t(B115200) - case .baud230400: - return speed_t(B230400) - case .baud460800: - return speed_t(B460800) - case .baud500000: - return speed_t(B500000) - case .baud576000: - return speed_t(B576000) - case .baud921600: - return speed_t(B921600) - case .baud1000000: - return speed_t(B1000000) - case .baud1152000: - return speed_t(B1152000) - case .baud1500000: - return speed_t(B1500000) - case .baud2000000: - return speed_t(B2000000) - case .baud2500000: - return speed_t(B2500000) - case .baud3500000: - return speed_t(B3500000) - case .baud4000000: - return speed_t(B4000000) - } - } - } -#elseif os(OSX) - public enum BaudRate { - case baud0 - case baud50 - case baud75 - case baud110 - case baud134 - case baud150 - case baud200 - case baud300 - case baud600 - case baud1200 - case baud1800 - case baud2400 - case baud4800 - case baud9600 - case baud19200 - case baud38400 - case baud57600 - case baud115200 - case baud230400 - - var speedValue: speed_t { - switch self { - case .baud0: - return speed_t(B0) - case .baud50: - return speed_t(B50) - case .baud75: - return speed_t(B75) - case .baud110: - return speed_t(B110) - case .baud134: - return speed_t(B134) - case .baud150: - return speed_t(B150) - case .baud200: - return speed_t(B200) - case .baud300: - return speed_t(B300) - case .baud600: - return speed_t(B600) - case .baud1200: - return speed_t(B1200) - case .baud1800: - return speed_t(B1800) - case .baud2400: - return speed_t(B2400) - case .baud4800: - return speed_t(B4800) - case .baud9600: - return speed_t(B9600) - case .baud19200: - return speed_t(B19200) - case .baud38400: - return speed_t(B38400) - case .baud57600: - return speed_t(B57600) - case .baud115200: - return speed_t(B115200) - case .baud230400: - return speed_t(B230400) - } - } - } -#endif - -public enum DataBitsSize { - case bits5 - case bits6 - case bits7 - case bits8 - - var flagValue: tcflag_t { - switch self { - case .bits5: - return tcflag_t(CS5) - case .bits6: - return tcflag_t(CS6) - case .bits7: - return tcflag_t(CS7) - case .bits8: - 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 { - case failedToOpen = -1 // refer to open() - case invalidPath - case mustReceiveOrTransmit - case mustBeOpen - case stringsMustBeUTF8 -} - -public class SerialPort { - - var path: String - var fileDescriptor: Int32? - - public init(path: String) { - self.path = path - } - - public func openPort() throws { - try openPort(toReceive: true, andTransmit: true) - } - - public func openPort(toReceive receive: Bool, andTransmit transmit: Bool) throws { - guard !path.isEmpty else { - throw PortError.invalidPath - } - - guard receive || transmit else { - throw PortError.mustReceiveOrTransmit - } - - var readWriteParam : Int32 - - if receive && transmit { - readWriteParam = O_RDWR - } else if receive { - readWriteParam = O_RDONLY - } else if transmit { - readWriteParam = O_WRONLY - } else { - fatalError() - } - - #if os(Linux) - fileDescriptor = open(path, readWriteParam | O_NOCTTY) - #elseif os(OSX) - fileDescriptor = open(path, readWriteParam | O_NOCTTY | O_EXLOCK) - #endif - - // Throw error if open() failed - if fileDescriptor == PortError.failedToOpen.rawValue { - throw PortError.failedToOpen - } - } - - public 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) { - - guard let fileDescriptor = fileDescriptor else { - return - } - - - // Set up the control structure - var settings = termios() - - // Get options structure for the port - tcgetattr(fileDescriptor, &settings) - - // Set baud rates - cfsetispeed(&settings, receiveRate.speedValue) - cfsetospeed(&settings, transmitRate.speedValue) - - // Enable parity (even/odd) if needed - settings.c_cflag |= parityType.parityValue - - // Set stop bit flag - if sendTwoStopBits { - settings.c_cflag |= tcflag_t(CSTOPB) - } else { - settings.c_cflag &= ~tcflag_t(CSTOPB) - } - - // Set data bits size flag - settings.c_cflag &= ~tcflag_t(CSIZE) - settings.c_cflag |= dataBitsSize.flagValue - - // Set hardware flow control flag - #if os(Linux) - if useHardwareFlowControl { - settings.c_cflag |= tcflag_t(CRTSCTS) - } else { - settings.c_cflag &= ~tcflag_t(CRTSCTS) - } - #elseif os(OSX) - if useHardwareFlowControl { - settings.c_cflag |= tcflag_t(CRTS_IFLOW) - settings.c_cflag |= tcflag_t(CCTS_OFLOW) - } else { - settings.c_cflag &= ~tcflag_t(CRTS_IFLOW) - settings.c_cflag &= ~tcflag_t(CCTS_OFLOW) - } - #endif - - // Set software flow control flags - let softwareFlowControlFlags = tcflag_t(IXON | IXOFF | IXANY) - if useSoftwareFlowControl { - settings.c_iflag |= softwareFlowControlFlags - } else { - settings.c_iflag &= ~softwareFlowControlFlags - } - - // Turn on the receiver of the serial port, and ignore modem control lines - settings.c_cflag |= tcflag_t(CREAD | CLOCAL) - - // Turn off canonical mode - settings.c_lflag &= ~tcflag_t(ICANON | ECHO | ECHOE | ISIG) - - // Set output processing flag - if processOutput { - settings.c_oflag |= tcflag_t(OPOST) - } else { - settings.c_oflag &= ~tcflag_t(OPOST) - } - - //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) - 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 - #elseif os(OSX) - typealias specialCharactersTuple = (VEOF: cc_t, VEOL: cc_t, VEOL2: cc_t, VERASE: cc_t, VWERASE: cc_t, VKILL: cc_t, VREPRINT: cc_t, spare1: cc_t, VINTR: cc_t, VQUIT: cc_t, VSUSP: cc_t, VDSUSP: cc_t, VSTART: cc_t, VSTOP: cc_t, VLNEXT: cc_t, VDISCARD: cc_t, VMIN: cc_t, VTIME: cc_t, VSTATUS: cc_t, spare: 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) // NCCS = 20 - #endif - - specialCharacters.VMIN = cc_t(minimumBytesToRead) - specialCharacters.VTIME = cc_t(timeout) - - //if not set we reciving 0x0A where must be 0x0D value - settings.c_iflag &= ~tcflag_t(INLCR) - settings.c_iflag &= ~tcflag_t(ICRNL) - - settings.c_cc = specialCharacters - - // Commit settings - tcsetattr(fileDescriptor, TCSANOW, &settings) - } - - public func closePort() { - if let fileDescriptor = fileDescriptor { - close(fileDescriptor) - } - fileDescriptor = nil - } -} - -// MARK: Receiving - -extension SerialPort { - - public func readBytes(into buffer: UnsafeMutablePointer, size: Int) throws -> Int { - guard let fileDescriptor = fileDescriptor else { - throw PortError.mustBeOpen - } - - let bytesRead = read(fileDescriptor, buffer, size) - return bytesRead - } - - public func readData(ofLength length: Int) throws -> Data { - let buffer = UnsafeMutablePointer.allocate(capacity: length) - defer { - buffer.deallocate(capacity: length) - } - - let bytesRead = try readBytes(into: buffer, size: length) - - 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 - } - - public func readString(ofLength length: Int) throws -> String { - var remainingBytesToRead = length - var result = "" - - while remainingBytesToRead > 0 { - let data = try readData(ofLength: remainingBytesToRead) - - if let string = String(data: data, encoding: String.Encoding.utf8) { - result += string - remainingBytesToRead -= data.count - } else { - return result - } - } - - return result - } - - public func readUntilChar(_ terminator: CChar) throws -> String { - var data = Data() - let buffer = UnsafeMutablePointer.allocate(capacity: 1) - defer { - buffer.deallocate(capacity: 1) - } - - while true { - let bytesRead = try readBytes(into: buffer, size: 1) - - if bytesRead > 0 { - let character = CChar(buffer[0]) - - if character == terminator { - break - } else { - data.append(buffer, count: 1) - } - } - } - - if let string = String(data: data, encoding: String.Encoding.utf8) { - return string - } else { - throw PortError.stringsMustBeUTF8 - } - } - - public func readLine() throws -> String { - let newlineChar = CChar(10) // Newline/Line feed character `\n` is 10 - return try readUntilChar(newlineChar) - } - - public func readChar() throws -> UnicodeScalar { - let buffer = UnsafeMutablePointer.allocate(capacity: 1) - - defer { - buffer.deallocate(capacity: 1) - } - - while true { - let bytesRead = try readBytes(into: buffer, size: 1) - - if bytesRead > 0 { - let character = UnicodeScalar(buffer[0]) - return character - } - } - - } - - public func readByte() throws -> UInt8 { - let buffer = UnsafeMutablePointer.allocate(capacity: 1) - - defer { - buffer.deallocate(capacity: 1) - } - - while true { - let bytesRead = try readBytes(into: buffer, size: 1) - - if bytesRead > 0 { - return buffer[0] - } - } - - } - - public func readUntilBytes(stopBytes: [UInt8], maxBytes: Int) throws -> [UInt8] { - var data = [UInt8]() - var isStopFound = 0 - while true { - isStopFound = 0 - let byteRead = try readByte() - data.append(byteRead) - - if data.count >= stopBytes.count { - if byteRead == stopBytes[stopBytes.count - 1] { - for index in (0..= maxBytes { - return data - } - } - } -} - -// MARK: Transmitting - -extension SerialPort { - - public func writeBytes(from buffer: UnsafeMutablePointer, size: Int) throws -> Int { - guard let fileDescriptor = fileDescriptor else { - throw PortError.mustBeOpen - } - - let bytesWritten = write(fileDescriptor, buffer, size) - return bytesWritten - } - - public func writeData(_ data: Data) throws -> Int { - let size = data.count - let buffer = UnsafeMutablePointer.allocate(capacity: size) - defer { - buffer.deallocate(capacity: size) - } - - data.copyBytes(to: buffer, count: size) - - let bytesWritten = try writeBytes(from: buffer, size: size) - return bytesWritten - } - - public func writeString(_ string: String) throws -> Int { - guard let data = string.data(using: String.Encoding.utf8) else { - throw PortError.stringsMustBeUTF8 - } - - return try writeData(data) - } - - public func writeChar(_ character: UnicodeScalar) throws -> Int{ - let stringEquiv = String(character) - let bytesWritten = try writeString(stringEquiv) - return bytesWritten - } -} +import Foundation + +#if os(Linux) +public enum BaudRate { + case baud0 + case baud50 + case baud75 + case baud110 + case baud134 + case baud150 + case baud200 + case baud300 + case baud600 + case baud1200 + case baud1800 + case baud2400 + case baud4800 + case baud9600 + case baud19200 + case baud38400 + case baud57600 + case baud115200 + case baud230400 + case baud460800 + case baud500000 + case baud576000 + case baud921600 + case baud1000000 + case baud1152000 + case baud1500000 + case baud2000000 + case baud2500000 + case baud3500000 + case baud4000000 + + var speedValue: speed_t { + switch self { + case .baud0: + return speed_t(B0) + case .baud50: + return speed_t(B50) + case .baud75: + return speed_t(B75) + case .baud110: + return speed_t(B110) + case .baud134: + return speed_t(B134) + case .baud150: + return speed_t(B150) + case .baud200: + return speed_t(B200) + case .baud300: + return speed_t(B300) + case .baud600: + return speed_t(B600) + case .baud1200: + return speed_t(B1200) + case .baud1800: + return speed_t(B1800) + case .baud2400: + return speed_t(B2400) + case .baud4800: + return speed_t(B4800) + case .baud9600: + return speed_t(B9600) + case .baud19200: + return speed_t(B19200) + case .baud38400: + return speed_t(B38400) + case .baud57600: + return speed_t(B57600) + case .baud115200: + return speed_t(B115200) + case .baud230400: + return speed_t(B230400) + case .baud460800: + return speed_t(B460800) + case .baud500000: + return speed_t(B500000) + case .baud576000: + return speed_t(B576000) + case .baud921600: + return speed_t(B921600) + case .baud1000000: + return speed_t(B1000000) + case .baud1152000: + return speed_t(B1152000) + case .baud1500000: + return speed_t(B1500000) + case .baud2000000: + return speed_t(B2000000) + case .baud2500000: + return speed_t(B2500000) + case .baud3500000: + return speed_t(B3500000) + case .baud4000000: + return speed_t(B4000000) + } + } +} +#elseif os(OSX) +public enum BaudRate { + case baud0 + case baud50 + case baud75 + case baud110 + case baud134 + case baud150 + case baud200 + case baud300 + case baud600 + case baud1200 + case baud1800 + case baud2400 + case baud4800 + case baud9600 + case baud19200 + case baud38400 + case baud57600 + case baud115200 + case baud230400 + + var speedValue: speed_t { + switch self { + case .baud0: + return speed_t(B0) + case .baud50: + return speed_t(B50) + case .baud75: + return speed_t(B75) + case .baud110: + return speed_t(B110) + case .baud134: + return speed_t(B134) + case .baud150: + return speed_t(B150) + case .baud200: + return speed_t(B200) + case .baud300: + return speed_t(B300) + case .baud600: + return speed_t(B600) + case .baud1200: + return speed_t(B1200) + case .baud1800: + return speed_t(B1800) + case .baud2400: + return speed_t(B2400) + case .baud4800: + return speed_t(B4800) + case .baud9600: + return speed_t(B9600) + case .baud19200: + return speed_t(B19200) + case .baud38400: + return speed_t(B38400) + case .baud57600: + return speed_t(B57600) + case .baud115200: + return speed_t(B115200) + case .baud230400: + return speed_t(B230400) + } + } +} +#endif + +public enum DataBitsSize { + case bits5 + case bits6 + case bits7 + case bits8 + + var flagValue: tcflag_t { + switch self { + case .bits5: + return tcflag_t(CS5) + case .bits6: + return tcflag_t(CS6) + case .bits7: + return tcflag_t(CS7) + case .bits8: + 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 { + case failedToOpen = -1 // refer to open() + case invalidPath + case mustReceiveOrTransmit + case mustBeOpen + case stringsMustBeUTF8 +} + +public class SerialPort { + + var path: String + var fileDescriptor: Int32? + + public init(path: String) { + self.path = path + } + + public func openPort() throws { + try openPort(toReceive: true, andTransmit: true) + } + + public func openPort(toReceive receive: Bool, andTransmit transmit: Bool) throws { + guard !path.isEmpty else { + throw PortError.invalidPath + } + + guard receive || transmit else { + throw PortError.mustReceiveOrTransmit + } + + var readWriteParam : Int32 + + if receive && transmit { + readWriteParam = O_RDWR + } else if receive { + readWriteParam = O_RDONLY + } else if transmit { + readWriteParam = O_WRONLY + } else { + fatalError() + } + + #if os(Linux) + fileDescriptor = open(path, readWriteParam | O_NOCTTY) + #elseif os(OSX) + fileDescriptor = open(path, readWriteParam | O_NOCTTY | O_EXLOCK) + #endif + + // Throw error if open() failed + if fileDescriptor == PortError.failedToOpen.rawValue { + throw PortError.failedToOpen + } + } + + public 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) { + + guard let fileDescriptor = fileDescriptor else { + return + } + + + // Set up the control structure + var settings = termios() + + // Get options structure for the port + tcgetattr(fileDescriptor, &settings) + + // Set baud rates + cfsetispeed(&settings, receiveRate.speedValue) + cfsetospeed(&settings, transmitRate.speedValue) + + // Enable parity (even/odd) if needed + settings.c_cflag |= parityType.parityValue + + // Set stop bit flag + if sendTwoStopBits { + settings.c_cflag |= tcflag_t(CSTOPB) + } else { + settings.c_cflag &= ~tcflag_t(CSTOPB) + } + + // Set data bits size flag + settings.c_cflag &= ~tcflag_t(CSIZE) + settings.c_cflag |= dataBitsSize.flagValue + + // Set hardware flow control flag + #if os(Linux) + if useHardwareFlowControl { + settings.c_cflag |= tcflag_t(CRTSCTS) + } else { + settings.c_cflag &= ~tcflag_t(CRTSCTS) + } + #elseif os(OSX) + if useHardwareFlowControl { + settings.c_cflag |= tcflag_t(CRTS_IFLOW) + settings.c_cflag |= tcflag_t(CCTS_OFLOW) + } else { + settings.c_cflag &= ~tcflag_t(CRTS_IFLOW) + settings.c_cflag &= ~tcflag_t(CCTS_OFLOW) + } + #endif + + // Set software flow control flags + let softwareFlowControlFlags = tcflag_t(IXON | IXOFF | IXANY) + if useSoftwareFlowControl { + settings.c_iflag |= softwareFlowControlFlags + } else { + settings.c_iflag &= ~softwareFlowControlFlags + } + + // Turn on the receiver of the serial port, and ignore modem control lines + settings.c_cflag |= tcflag_t(CREAD | CLOCAL) + + // Turn off canonical mode + settings.c_lflag &= ~tcflag_t(ICANON | ECHO | ECHOE | ISIG) + + // Set output processing flag + if processOutput { + settings.c_oflag |= tcflag_t(OPOST) + } else { + settings.c_oflag &= ~tcflag_t(OPOST) + } + + //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) + 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 + #elseif os(OSX) + typealias specialCharactersTuple = (VEOF: cc_t, VEOL: cc_t, VEOL2: cc_t, VERASE: cc_t, VWERASE: cc_t, VKILL: cc_t, VREPRINT: cc_t, spare1: cc_t, VINTR: cc_t, VQUIT: cc_t, VSUSP: cc_t, VDSUSP: cc_t, VSTART: cc_t, VSTOP: cc_t, VLNEXT: cc_t, VDISCARD: cc_t, VMIN: cc_t, VTIME: cc_t, VSTATUS: cc_t, spare: 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) // NCCS = 20 + #endif + + specialCharacters.VMIN = cc_t(minimumBytesToRead) + specialCharacters.VTIME = cc_t(timeout) + + //if not set we reciving 0x0A where must be 0x0D value + settings.c_iflag &= ~tcflag_t(INLCR) + settings.c_iflag &= ~tcflag_t(ICRNL) + + settings.c_cc = specialCharacters + + // Commit settings + tcsetattr(fileDescriptor, TCSANOW, &settings) + } + + public func closePort() { + if let fileDescriptor = fileDescriptor { + close(fileDescriptor) + } + fileDescriptor = nil + } +} + +// MARK: Receiving + +extension SerialPort { + + public func readBytes(into buffer: UnsafeMutablePointer, size: Int) throws -> Int { + guard let fileDescriptor = fileDescriptor else { + throw PortError.mustBeOpen + } + + let bytesRead = read(fileDescriptor, buffer, size) + return bytesRead + } + + public func readData(ofLength length: Int) throws -> Data { + let buffer = UnsafeMutablePointer.allocate(capacity: length) + defer { + buffer.deallocate(capacity: length) + } + + let bytesRead = try readBytes(into: buffer, size: length) + + 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 + } + + public func readString(ofLength length: Int) throws -> String { + var remainingBytesToRead = length + var result = "" + + while remainingBytesToRead > 0 { + let data = try readData(ofLength: remainingBytesToRead) + + if let string = String(data: data, encoding: String.Encoding.utf8) { + result += string + remainingBytesToRead -= data.count + } else { + return result + } + } + + return result + } + + public func readUntilChar(_ terminator: CChar) throws -> String { + var data = Data() + let buffer = UnsafeMutablePointer.allocate(capacity: 1) + defer { + buffer.deallocate(capacity: 1) + } + + while true { + let bytesRead = try readBytes(into: buffer, size: 1) + + if bytesRead > 0 { + let character = CChar(buffer[0]) + + if character == terminator { + break + } else { + data.append(buffer, count: 1) + } + } + } + + if let string = String(data: data, encoding: String.Encoding.utf8) { + return string + } else { + throw PortError.stringsMustBeUTF8 + } + } + + public func readLine() throws -> String { + let newlineChar = CChar(10) // Newline/Line feed character `\n` is 10 + return try readUntilChar(newlineChar) + } + + public func readChar() throws -> UnicodeScalar { + let buffer = UnsafeMutablePointer.allocate(capacity: 1) + + defer { + buffer.deallocate(capacity: 1) + } + + while true { + let bytesRead = try readBytes(into: buffer, size: 1) + + if bytesRead > 0 { + let character = UnicodeScalar(buffer[0]) + return character + } + } + + } + + public func readByte() throws -> UInt8 { + let buffer = UnsafeMutablePointer.allocate(capacity: 1) + + defer { + buffer.deallocate(capacity: 1) + } + + while true { + let bytesRead = try readBytes(into: buffer, size: 1) + + if bytesRead > 0 { + return buffer[0] + } + } + + } + + public func readUntilBytes(stopBytes: [UInt8], maxBytes: Int) throws -> [UInt8] { + var data = [UInt8]() + var isStopFound = 0 + while true { + isStopFound = 0 + let byteRead = try readByte() + data.append(byteRead) + + if data.count >= stopBytes.count { + if byteRead == stopBytes[stopBytes.count - 1] { + for index in (0..= maxBytes { + return data + } + } + } +} + +// MARK: Transmitting + +extension SerialPort { + + public func writeBytes(from buffer: UnsafeMutablePointer, size: Int) throws -> Int { + guard let fileDescriptor = fileDescriptor else { + throw PortError.mustBeOpen + } + + let bytesWritten = write(fileDescriptor, buffer, size) + return bytesWritten + } + + public func writeData(_ data: Data) throws -> Int { + let size = data.count + let buffer = UnsafeMutablePointer.allocate(capacity: size) + defer { + buffer.deallocate(capacity: size) + } + + data.copyBytes(to: buffer, count: size) + + let bytesWritten = try writeBytes(from: buffer, size: size) + return bytesWritten + } + + public func writeString(_ string: String) throws -> Int { + guard let data = string.data(using: String.Encoding.utf8) else { + throw PortError.stringsMustBeUTF8 + } + + return try writeData(data) + } + + public func writeChar(_ character: UnicodeScalar) throws -> Int{ + let stringEquiv = String(character) + let bytesWritten = try writeString(stringEquiv) + return bytesWritten + } + + public func writeByte(byte: UInt8) throws -> Int { + let buffer = UnsafeMutablePointer.allocate(capacity: 1) + + defer { + buffer.deallocate(capacity: 1) + } + buffer[0] = byte + let bytesWritten = write(fileDescriptor!, buffer, 1) + return bytesWritten + } + + public func writeByteArray(into bytes: [UInt8]) throws -> Int { + let buffer = UnsafeMutablePointer.allocate(capacity: bytes.count) + + defer { + buffer.deallocate(capacity: bytes.count) + } + for i in 0...bytes.count - 1 { + buffer[i] = bytes[i] + } + let bytesWritten = write(fileDescriptor!, buffer, bytes.count) + return bytesWritten + } +} From a6b8d9bf7b7c77e0b1658791e85ecbe901b98a37 Mon Sep 17 00:00:00 2001 From: Yuri Date: Sat, 8 Jul 2017 20:26:26 +0300 Subject: [PATCH 17/36] new speed value add --- Sources/SwiftSerial.swift | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Sources/SwiftSerial.swift b/Sources/SwiftSerial.swift index b3cf6fc..5983d88 100644 --- a/Sources/SwiftSerial.swift +++ b/Sources/SwiftSerial.swift @@ -21,6 +21,7 @@ public enum BaudRate { case baud57600 case baud115200 case baud230400 + case baud250000 case baud460800 case baud500000 case baud576000 @@ -73,6 +74,8 @@ public enum BaudRate { return speed_t(B115200) case .baud230400: return speed_t(B230400) + case .baud250000: + return speed_t(B250000) case .baud460800: return speed_t(B460800) case .baud500000: @@ -119,6 +122,7 @@ public enum BaudRate { case baud57600 case baud115200 case baud230400 + case baud250000 var speedValue: speed_t { switch self { @@ -160,6 +164,8 @@ public enum BaudRate { return speed_t(B115200) case .baud230400: return speed_t(B230400) + case .baud250000: + return speed_t(B250000) } } } From bf380e00257bc7ad4fbcd352745b6557e9d110bb Mon Sep 17 00:00:00 2001 From: Yuri Date: Sat, 8 Jul 2017 20:28:52 +0300 Subject: [PATCH 18/36] bug fix --- Sources/SwiftSerial.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Sources/SwiftSerial.swift b/Sources/SwiftSerial.swift index 5983d88..cc2cb34 100644 --- a/Sources/SwiftSerial.swift +++ b/Sources/SwiftSerial.swift @@ -75,7 +75,7 @@ public enum BaudRate { case .baud230400: return speed_t(B230400) case .baud250000: - return speed_t(B250000) + return speed_t(250000) case .baud460800: return speed_t(B460800) case .baud500000: @@ -165,7 +165,7 @@ public enum BaudRate { case .baud230400: return speed_t(B230400) case .baud250000: - return speed_t(B250000) + return speed_t(250000) } } } From 73ecf6a674d0cfd1b3450dab0dae799b4a812899 Mon Sep 17 00:00:00 2001 From: Yuri Date: Sat, 8 Jul 2017 20:53:59 +0300 Subject: [PATCH 19/36] read data from start to stop Byte --- Sources/SwiftSerial.swift | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/Sources/SwiftSerial.swift b/Sources/SwiftSerial.swift index cc2cb34..2dcf0b2 100644 --- a/Sources/SwiftSerial.swift +++ b/Sources/SwiftSerial.swift @@ -518,6 +518,34 @@ extension SerialPort { } } } + + public func readBytes(startByte: UInt8, stopByte: UInt8, packetLength: Int, maxBytes: Int) throws -> [UInt8] { + var data: Array = [UInt8]() + let buffer = UnsafeMutablePointer.allocate(capacity: 1) + defer { + buffer.deallocate(capacity: maxBytes) + } + while true { + let bytesRead = try readBytes(into: buffer, size: 1) + + if bytesRead > 0 { + if buffer[0] == stopByte { + data.append(buffer[0]) + if data.count >= packetLength { + if data[data.count - packetLength - 1] == startByte { + let data_result: Array = Array(data[(data.count - packetLength - 1) ... data.count]) + return data_result + } + } + } else { + data.append(buffer[0]) + } + } + if data.count >= maxBytes { + return data + } + } + } } // MARK: Transmitting From 2a4507d21fc314566c96e51d8c0d824ff6390e55 Mon Sep 17 00:00:00 2001 From: Yuri Date: Sat, 8 Jul 2017 21:52:12 +0300 Subject: [PATCH 20/36] variable port speed add --- Sources/SwiftSerial.swift | 112 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 106 insertions(+), 6 deletions(-) diff --git a/Sources/SwiftSerial.swift b/Sources/SwiftSerial.swift index 2dcf0b2..d0ac3ba 100644 --- a/Sources/SwiftSerial.swift +++ b/Sources/SwiftSerial.swift @@ -21,7 +21,6 @@ public enum BaudRate { case baud57600 case baud115200 case baud230400 - case baud250000 case baud460800 case baud500000 case baud576000 @@ -74,8 +73,6 @@ public enum BaudRate { return speed_t(B115200) case .baud230400: return speed_t(B230400) - case .baud250000: - return speed_t(250000) case .baud460800: return speed_t(B460800) case .baud500000: @@ -122,7 +119,6 @@ public enum BaudRate { case baud57600 case baud115200 case baud230400 - case baud250000 var speedValue: speed_t { switch self { @@ -164,8 +160,6 @@ public enum BaudRate { return speed_t(B115200) case .baud230400: return speed_t(B230400) - case .baud250000: - return speed_t(250000) } } } @@ -364,6 +358,112 @@ public class SerialPort { // Commit settings tcsetattr(fileDescriptor, TCSANOW, &settings) } + + + public func setSettings(customReceiveRate: UInt, + customTransmitRate: UInt, + 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) { + + guard let fileDescriptor = fileDescriptor else { + return + } + + + // Set up the control structure + var settings = termios() + + // Get options structure for the port + tcgetattr(fileDescriptor, &settings) + + // Set baud rates + + settings.c_cflag &= ~UInt(0010017) //Remove current BAUD rate CBAUD = 0010017 + settings.c_cflag |= UInt(0010000) //Allow custom BAUD rate using int input BOTHER = 0010000 + settings.c_ispeed = customReceiveRate //Set the input BAUD rate + settings.c_ospeed = customTransmitRate //Set the output BAUD rate + + // Enable parity (even/odd) if needed + settings.c_cflag |= parityType.parityValue + + // Set stop bit flag + if sendTwoStopBits { + settings.c_cflag |= tcflag_t(CSTOPB) + } else { + settings.c_cflag &= ~tcflag_t(CSTOPB) + } + + // Set data bits size flag + settings.c_cflag &= ~tcflag_t(CSIZE) + settings.c_cflag |= dataBitsSize.flagValue + + // Set hardware flow control flag + #if os(Linux) + if useHardwareFlowControl { + settings.c_cflag |= tcflag_t(CRTSCTS) + } else { + settings.c_cflag &= ~tcflag_t(CRTSCTS) + } + #elseif os(OSX) + if useHardwareFlowControl { + settings.c_cflag |= tcflag_t(CRTS_IFLOW) + settings.c_cflag |= tcflag_t(CCTS_OFLOW) + } else { + settings.c_cflag &= ~tcflag_t(CRTS_IFLOW) + settings.c_cflag &= ~tcflag_t(CCTS_OFLOW) + } + #endif + + // Set software flow control flags + let softwareFlowControlFlags = tcflag_t(IXON | IXOFF | IXANY) + if useSoftwareFlowControl { + settings.c_iflag |= softwareFlowControlFlags + } else { + settings.c_iflag &= ~softwareFlowControlFlags + } + + // Turn on the receiver of the serial port, and ignore modem control lines + settings.c_cflag |= tcflag_t(CREAD | CLOCAL) + + // Turn off canonical mode + settings.c_lflag &= ~tcflag_t(ICANON | ECHO | ECHOE | ISIG) + + // Set output processing flag + if processOutput { + settings.c_oflag |= tcflag_t(OPOST) + } else { + settings.c_oflag &= ~tcflag_t(OPOST) + } + + //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) + 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 + #elseif os(OSX) + typealias specialCharactersTuple = (VEOF: cc_t, VEOL: cc_t, VEOL2: cc_t, VERASE: cc_t, VWERASE: cc_t, VKILL: cc_t, VREPRINT: cc_t, spare1: cc_t, VINTR: cc_t, VQUIT: cc_t, VSUSP: cc_t, VDSUSP: cc_t, VSTART: cc_t, VSTOP: cc_t, VLNEXT: cc_t, VDISCARD: cc_t, VMIN: cc_t, VTIME: cc_t, VSTATUS: cc_t, spare: 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) // NCCS = 20 + #endif + + specialCharacters.VMIN = cc_t(minimumBytesToRead) + specialCharacters.VTIME = cc_t(timeout) + + //if not set we reciving 0x0A where must be 0x0D value + settings.c_iflag &= ~tcflag_t(INLCR) + settings.c_iflag &= ~tcflag_t(ICRNL) + + settings.c_cc = specialCharacters + + // Commit settings + tcsetattr(fileDescriptor, TCSANOW, &settings) + } public func closePort() { if let fileDescriptor = fileDescriptor { From b1208091db72d7b868ad970ca0b882a103c28739 Mon Sep 17 00:00:00 2001 From: Yuri Date: Sat, 8 Jul 2017 21:54:45 +0300 Subject: [PATCH 21/36] bug fix --- Sources/SwiftSerial.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Sources/SwiftSerial.swift b/Sources/SwiftSerial.swift index d0ac3ba..9edc2a2 100644 --- a/Sources/SwiftSerial.swift +++ b/Sources/SwiftSerial.swift @@ -384,8 +384,8 @@ public class SerialPort { // Set baud rates - settings.c_cflag &= ~UInt(0010017) //Remove current BAUD rate CBAUD = 0010017 - settings.c_cflag |= UInt(0010000) //Allow custom BAUD rate using int input BOTHER = 0010000 + settings.c_cflag &= ~tcflag_t(0010017) //Remove current BAUD rate CBAUD = 0010017 + settings.c_cflag |= tcflag_t(0010000) //Allow custom BAUD rate using int input BOTHER = 0010000 settings.c_ispeed = customReceiveRate //Set the input BAUD rate settings.c_ospeed = customTransmitRate //Set the output BAUD rate From 2e4d8f20487397e09276e0872aa9d8988a438a9b Mon Sep 17 00:00:00 2001 From: Yuri Date: Sat, 8 Jul 2017 21:56:08 +0300 Subject: [PATCH 22/36] bug fix --- Sources/SwiftSerial.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Sources/SwiftSerial.swift b/Sources/SwiftSerial.swift index 9edc2a2..4af1d90 100644 --- a/Sources/SwiftSerial.swift +++ b/Sources/SwiftSerial.swift @@ -360,8 +360,8 @@ public class SerialPort { } - public func setSettings(customReceiveRate: UInt, - customTransmitRate: UInt, + public func setSettings(customReceiveRate: UInt32, + customTransmitRate: UInt32, minimumBytesToRead: Int, timeout: Int = 0, /* 0 means wait indefinitely */ parityType: ParityType = .none, From 4b1c09bf2ec04ac3fb0d891cb8480fdb32701f65 Mon Sep 17 00:00:00 2001 From: Yuri Date: Sat, 8 Jul 2017 22:22:19 +0300 Subject: [PATCH 23/36] bug fix --- Sources/SwiftSerial.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Sources/SwiftSerial.swift b/Sources/SwiftSerial.swift index 4af1d90..9867ff3 100644 --- a/Sources/SwiftSerial.swift +++ b/Sources/SwiftSerial.swift @@ -386,8 +386,8 @@ public class SerialPort { settings.c_cflag &= ~tcflag_t(0010017) //Remove current BAUD rate CBAUD = 0010017 settings.c_cflag |= tcflag_t(0010000) //Allow custom BAUD rate using int input BOTHER = 0010000 - settings.c_ispeed = customReceiveRate //Set the input BAUD rate - settings.c_ospeed = customTransmitRate //Set the output BAUD rate + settings.c_ispeed = speed_t(customReceiveRate) //Set the input BAUD rate + settings.c_ospeed = speed_t(customTransmitRate) //Set the output BAUD rate // Enable parity (even/odd) if needed settings.c_cflag |= parityType.parityValue From 433ad0cdadacae228ee128b9045be7e50904926f Mon Sep 17 00:00:00 2001 From: Yuri Date: Sun, 9 Jul 2017 10:26:23 +0300 Subject: [PATCH 24/36] bugfix --- Sources/SwiftSerial.swift | 29 +++++++++++++++++++---------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/Sources/SwiftSerial.swift b/Sources/SwiftSerial.swift index 9867ff3..53e036b 100644 --- a/Sources/SwiftSerial.swift +++ b/Sources/SwiftSerial.swift @@ -360,8 +360,7 @@ public class SerialPort { } - public func setSettings(customReceiveRate: UInt32, - customTransmitRate: UInt32, + public func setSettings(customBaud: UInt32, minimumBytesToRead: Int, timeout: Int = 0, /* 0 means wait indefinitely */ parityType: ParityType = .none, @@ -382,13 +381,6 @@ public class SerialPort { // Get options structure for the port tcgetattr(fileDescriptor, &settings) - // Set baud rates - - settings.c_cflag &= ~tcflag_t(0010017) //Remove current BAUD rate CBAUD = 0010017 - settings.c_cflag |= tcflag_t(0010000) //Allow custom BAUD rate using int input BOTHER = 0010000 - settings.c_ispeed = speed_t(customReceiveRate) //Set the input BAUD rate - settings.c_ospeed = speed_t(customTransmitRate) //Set the output BAUD rate - // Enable parity (even/odd) if needed settings.c_cflag |= parityType.parityValue @@ -403,6 +395,13 @@ public class SerialPort { settings.c_cflag &= ~tcflag_t(CSIZE) settings.c_cflag |= dataBitsSize.flagValue + + // Set baud rate + // Set baud rates + cfsetispeed(&settings, speed_t(customBaud)) + cfsetospeed(&settings, speed_t(customBaud)) + + // Set hardware flow control flag #if os(Linux) if useHardwareFlowControl { @@ -462,7 +461,17 @@ public class SerialPort { settings.c_cc = specialCharacters // Commit settings - tcsetattr(fileDescriptor, TCSANOW, &settings) + var result = tcsetattr(fileDescriptor, TCSANOW, &settings) + + if result != 0 { + var baudRate = Int(customBaud) + result = ioctl(fileDescriptor, 0x80045402, &baudRate) + if result != 0 { + print("set customBaud fail \(result)") + } + } + + } public func closePort() { From 40cebeaafe282d21d71f2f47f2300d1a3db988fe Mon Sep 17 00:00:00 2001 From: Yuri Date: Sun, 9 Jul 2017 10:34:31 +0300 Subject: [PATCH 25/36] debug --- Sources/SwiftSerial.swift | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Sources/SwiftSerial.swift b/Sources/SwiftSerial.swift index 53e036b..5de9399 100644 --- a/Sources/SwiftSerial.swift +++ b/Sources/SwiftSerial.swift @@ -629,6 +629,7 @@ extension SerialPort { } public func readBytes(startByte: UInt8, stopByte: UInt8, packetLength: Int, maxBytes: Int) throws -> [UInt8] { + var data: Array = [UInt8]() let buffer = UnsafeMutablePointer.allocate(capacity: 1) defer { @@ -638,6 +639,8 @@ extension SerialPort { let bytesRead = try readBytes(into: buffer, size: 1) if bytesRead > 0 { + print("read \(bytesRead)") + if buffer[0] == stopByte { data.append(buffer[0]) if data.count >= packetLength { From c5c7be8746a7664f558aa3dc383691a1c2993af0 Mon Sep 17 00:00:00 2001 From: Yuri Date: Sun, 9 Jul 2017 12:03:58 +0300 Subject: [PATCH 26/36] bugfix --- Sources/SwiftSerial.swift | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/Sources/SwiftSerial.swift b/Sources/SwiftSerial.swift index 5de9399..c464a93 100644 --- a/Sources/SwiftSerial.swift +++ b/Sources/SwiftSerial.swift @@ -119,6 +119,7 @@ public enum BaudRate { case baud57600 case baud115200 case baud230400 + case baud250000 var speedValue: speed_t { switch self { @@ -160,6 +161,8 @@ public enum BaudRate { return speed_t(B115200) case .baud230400: return speed_t(B230400) + case .baud250000: + return speed_t(250000) } } } @@ -463,12 +466,10 @@ public class SerialPort { // Commit settings var result = tcsetattr(fileDescriptor, TCSANOW, &settings) + var baudRate = Int(customBaud) + result = ioctl(fileDescriptor, 0x80045402, &baudRate) if result != 0 { - var baudRate = Int(customBaud) - result = ioctl(fileDescriptor, 0x80045402, &baudRate) - if result != 0 { - print("set customBaud fail \(result)") - } + print("set customBaud fail \(result)") } From 44e11a259c2fe3625a912e851f7250780ef76dba Mon Sep 17 00:00:00 2001 From: Yuri Date: Tue, 11 Jul 2017 23:29:23 +0300 Subject: [PATCH 27/36] bugfix --- Sources/SwiftSerial.swift | 114 +------------------------------------- 1 file changed, 1 insertion(+), 113 deletions(-) diff --git a/Sources/SwiftSerial.swift b/Sources/SwiftSerial.swift index c464a93..8a43a24 100644 --- a/Sources/SwiftSerial.swift +++ b/Sources/SwiftSerial.swift @@ -362,118 +362,6 @@ public class SerialPort { tcsetattr(fileDescriptor, TCSANOW, &settings) } - - public func setSettings(customBaud: UInt32, - 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) { - - guard let fileDescriptor = fileDescriptor else { - return - } - - - // Set up the control structure - var settings = termios() - - // Get options structure for the port - tcgetattr(fileDescriptor, &settings) - - // Enable parity (even/odd) if needed - settings.c_cflag |= parityType.parityValue - - // Set stop bit flag - if sendTwoStopBits { - settings.c_cflag |= tcflag_t(CSTOPB) - } else { - settings.c_cflag &= ~tcflag_t(CSTOPB) - } - - // Set data bits size flag - settings.c_cflag &= ~tcflag_t(CSIZE) - settings.c_cflag |= dataBitsSize.flagValue - - - // Set baud rate - // Set baud rates - cfsetispeed(&settings, speed_t(customBaud)) - cfsetospeed(&settings, speed_t(customBaud)) - - - // Set hardware flow control flag - #if os(Linux) - if useHardwareFlowControl { - settings.c_cflag |= tcflag_t(CRTSCTS) - } else { - settings.c_cflag &= ~tcflag_t(CRTSCTS) - } - #elseif os(OSX) - if useHardwareFlowControl { - settings.c_cflag |= tcflag_t(CRTS_IFLOW) - settings.c_cflag |= tcflag_t(CCTS_OFLOW) - } else { - settings.c_cflag &= ~tcflag_t(CRTS_IFLOW) - settings.c_cflag &= ~tcflag_t(CCTS_OFLOW) - } - #endif - - // Set software flow control flags - let softwareFlowControlFlags = tcflag_t(IXON | IXOFF | IXANY) - if useSoftwareFlowControl { - settings.c_iflag |= softwareFlowControlFlags - } else { - settings.c_iflag &= ~softwareFlowControlFlags - } - - // Turn on the receiver of the serial port, and ignore modem control lines - settings.c_cflag |= tcflag_t(CREAD | CLOCAL) - - // Turn off canonical mode - settings.c_lflag &= ~tcflag_t(ICANON | ECHO | ECHOE | ISIG) - - // Set output processing flag - if processOutput { - settings.c_oflag |= tcflag_t(OPOST) - } else { - settings.c_oflag &= ~tcflag_t(OPOST) - } - - //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) - 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 - #elseif os(OSX) - typealias specialCharactersTuple = (VEOF: cc_t, VEOL: cc_t, VEOL2: cc_t, VERASE: cc_t, VWERASE: cc_t, VKILL: cc_t, VREPRINT: cc_t, spare1: cc_t, VINTR: cc_t, VQUIT: cc_t, VSUSP: cc_t, VDSUSP: cc_t, VSTART: cc_t, VSTOP: cc_t, VLNEXT: cc_t, VDISCARD: cc_t, VMIN: cc_t, VTIME: cc_t, VSTATUS: cc_t, spare: 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) // NCCS = 20 - #endif - - specialCharacters.VMIN = cc_t(minimumBytesToRead) - specialCharacters.VTIME = cc_t(timeout) - - //if not set we reciving 0x0A where must be 0x0D value - settings.c_iflag &= ~tcflag_t(INLCR) - settings.c_iflag &= ~tcflag_t(ICRNL) - - settings.c_cc = specialCharacters - - // Commit settings - var result = tcsetattr(fileDescriptor, TCSANOW, &settings) - - var baudRate = Int(customBaud) - result = ioctl(fileDescriptor, 0x80045402, &baudRate) - if result != 0 { - print("set customBaud fail \(result)") - } - - - } public func closePort() { if let fileDescriptor = fileDescriptor { @@ -646,7 +534,7 @@ extension SerialPort { data.append(buffer[0]) if data.count >= packetLength { if data[data.count - packetLength - 1] == startByte { - let data_result: Array = Array(data[(data.count - packetLength - 1) ... data.count]) + let data_result: Array = Array(data[(data.count - packetLength - 1) ... data.count - 1]) return data_result } } From c6d38061e32908bfd9178e87b058e0a552a9fd71 Mon Sep 17 00:00:00 2001 From: Yuri Date: Thu, 13 Jul 2017 22:34:10 +0300 Subject: [PATCH 28/36] debug --- Sources/SwiftSerial.swift | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/Sources/SwiftSerial.swift b/Sources/SwiftSerial.swift index 2dcf0b2..4138e9b 100644 --- a/Sources/SwiftSerial.swift +++ b/Sources/SwiftSerial.swift @@ -529,16 +529,17 @@ extension SerialPort { let bytesRead = try readBytes(into: buffer, size: 1) if bytesRead > 0 { + + data.append(buffer[0]) + if buffer[0] == stopByte { - data.append(buffer[0]) if data.count >= packetLength { + print("data.count - packetLength - 1 = \(data.count - packetLength - 1)") if data[data.count - packetLength - 1] == startByte { let data_result: Array = Array(data[(data.count - packetLength - 1) ... data.count]) return data_result } } - } else { - data.append(buffer[0]) } } if data.count >= maxBytes { From 39ffa6ec9740d49bcc4b4265200992da33e4ec82 Mon Sep 17 00:00:00 2001 From: Yuri Date: Thu, 13 Jul 2017 23:03:42 +0300 Subject: [PATCH 29/36] bugfix --- Sources/SwiftSerial.swift | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Sources/SwiftSerial.swift b/Sources/SwiftSerial.swift index 8a43a24..0eb587d 100644 --- a/Sources/SwiftSerial.swift +++ b/Sources/SwiftSerial.swift @@ -161,8 +161,6 @@ public enum BaudRate { return speed_t(B115200) case .baud230400: return speed_t(B230400) - case .baud250000: - return speed_t(250000) } } } @@ -533,6 +531,7 @@ extension SerialPort { if buffer[0] == stopByte { data.append(buffer[0]) if data.count >= packetLength { + print("data.count - packetLength - 1 = \(data.count - packetLength - 1) data.count:\(data.count)") if data[data.count - packetLength - 1] == startByte { let data_result: Array = Array(data[(data.count - packetLength - 1) ... data.count - 1]) return data_result From 41545b8af3c8d544fc825e2155afe2f216facfc2 Mon Sep 17 00:00:00 2001 From: Yuri Date: Thu, 13 Jul 2017 23:05:11 +0300 Subject: [PATCH 30/36] bugfix --- Sources/SwiftSerial.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Sources/SwiftSerial.swift b/Sources/SwiftSerial.swift index 0eb587d..c53bdcb 100644 --- a/Sources/SwiftSerial.swift +++ b/Sources/SwiftSerial.swift @@ -531,8 +531,8 @@ extension SerialPort { if buffer[0] == stopByte { data.append(buffer[0]) if data.count >= packetLength { - print("data.count - packetLength - 1 = \(data.count - packetLength - 1) data.count:\(data.count)") - if data[data.count - packetLength - 1] == startByte { + print("data.count - packetLength = \(data.count - packetLength - 1) | data.count:\(data.count)") + if data[data.count - packetLength] == startByte { let data_result: Array = Array(data[(data.count - packetLength - 1) ... data.count - 1]) return data_result } From 733f263c19bcc8cc16226cb2bed98d6c70cf2aa8 Mon Sep 17 00:00:00 2001 From: Yuri Date: Thu, 13 Jul 2017 23:07:12 +0300 Subject: [PATCH 31/36] fix --- Sources/SwiftSerial.swift | 1 + 1 file changed, 1 insertion(+) diff --git a/Sources/SwiftSerial.swift b/Sources/SwiftSerial.swift index c53bdcb..4cd68d8 100644 --- a/Sources/SwiftSerial.swift +++ b/Sources/SwiftSerial.swift @@ -533,6 +533,7 @@ extension SerialPort { if data.count >= packetLength { print("data.count - packetLength = \(data.count - packetLength - 1) | data.count:\(data.count)") if data[data.count - packetLength] == startByte { + print("package found: \(data)") let data_result: Array = Array(data[(data.count - packetLength - 1) ... data.count - 1]) return data_result } From 414e030db82cd2076882b767bd12e273cda130e0 Mon Sep 17 00:00:00 2001 From: Yuri Date: Thu, 13 Jul 2017 23:09:16 +0300 Subject: [PATCH 32/36] fix --- Sources/SwiftSerial.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Sources/SwiftSerial.swift b/Sources/SwiftSerial.swift index 4cd68d8..eba3507 100644 --- a/Sources/SwiftSerial.swift +++ b/Sources/SwiftSerial.swift @@ -518,12 +518,12 @@ extension SerialPort { public func readBytes(startByte: UInt8, stopByte: UInt8, packetLength: Int, maxBytes: Int) throws -> [UInt8] { var data: Array = [UInt8]() - let buffer = UnsafeMutablePointer.allocate(capacity: 1) + let buffer = UnsafeMutablePointer.allocate(capacity: packetLength+packetLength+packetLength) defer { buffer.deallocate(capacity: maxBytes) } while true { - let bytesRead = try readBytes(into: buffer, size: 1) + let bytesRead = try readBytes(into: buffer, size: packetLength) if bytesRead > 0 { print("read \(bytesRead)") From 2679706e1277bd21b7f5478fb0836c0494cb12a2 Mon Sep 17 00:00:00 2001 From: Yuri Date: Thu, 13 Jul 2017 23:18:11 +0300 Subject: [PATCH 33/36] fix --- Sources/SwiftSerial.swift | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/Sources/SwiftSerial.swift b/Sources/SwiftSerial.swift index eba3507..e87fad1 100644 --- a/Sources/SwiftSerial.swift +++ b/Sources/SwiftSerial.swift @@ -527,20 +527,18 @@ extension SerialPort { if bytesRead > 0 { print("read \(bytesRead)") - - if buffer[0] == stopByte { - data.append(buffer[0]) - if data.count >= packetLength { - print("data.count - packetLength = \(data.count - packetLength - 1) | data.count:\(data.count)") - if data[data.count - packetLength] == startByte { - print("package found: \(data)") - let data_result: Array = Array(data[(data.count - packetLength - 1) ... data.count - 1]) - return data_result + for i in 0 ... bytesRead { + data.append(buffer[i]) + if buffer[i] == stopByte { + if data.count >= packetLength { + print("data.count - packetLength = \(data.count - packetLength - 1) | data.count:\(data.count)") + if data[data.count - packetLength] == startByte { + print("package found: \(data)") + let data_result: Array = Array(data[(data.count - packetLength - 1) ... data.count - 1]) + return data_result + } } } - } else { - data.append(buffer[0]) - } } if data.count >= maxBytes { return data From 7c7d9b08b33e12f597574f9b8fc7b4a8646a99f5 Mon Sep 17 00:00:00 2001 From: Yuri Date: Thu, 13 Jul 2017 23:19:11 +0300 Subject: [PATCH 34/36] fix --- Sources/SwiftSerial.swift | 1 + 1 file changed, 1 insertion(+) diff --git a/Sources/SwiftSerial.swift b/Sources/SwiftSerial.swift index e87fad1..22c1b6c 100644 --- a/Sources/SwiftSerial.swift +++ b/Sources/SwiftSerial.swift @@ -539,6 +539,7 @@ extension SerialPort { } } } + } } if data.count >= maxBytes { return data From fe8e37d5c0364d807476a4856601529075f1040f Mon Sep 17 00:00:00 2001 From: Yuri Date: Thu, 13 Jul 2017 23:22:29 +0300 Subject: [PATCH 35/36] fix --- Sources/SwiftSerial.swift | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Sources/SwiftSerial.swift b/Sources/SwiftSerial.swift index 22c1b6c..fffd17c 100644 --- a/Sources/SwiftSerial.swift +++ b/Sources/SwiftSerial.swift @@ -161,6 +161,7 @@ public enum BaudRate { return speed_t(B115200) case .baud230400: return speed_t(B230400) + default: return speed_t(B9600) } } } @@ -527,7 +528,7 @@ extension SerialPort { if bytesRead > 0 { print("read \(bytesRead)") - for i in 0 ... bytesRead { + for i in 0 ... bytesRead - 1 { data.append(buffer[i]) if buffer[i] == stopByte { if data.count >= packetLength { From e09e214d8ee8a7cd8d24e17dd33c041295e684b7 Mon Sep 17 00:00:00 2001 From: Yuri Date: Thu, 13 Jul 2017 23:30:20 +0300 Subject: [PATCH 36/36] fix --- Sources/SwiftSerial.swift | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Sources/SwiftSerial.swift b/Sources/SwiftSerial.swift index fffd17c..16b7eb2 100644 --- a/Sources/SwiftSerial.swift +++ b/Sources/SwiftSerial.swift @@ -517,18 +517,18 @@ extension SerialPort { } public func readBytes(startByte: UInt8, stopByte: UInt8, packetLength: Int, maxBytes: Int) throws -> [UInt8] { - + print("readBytes startByte:\(startByte) stopByte:\(stopByte) packetLength: \(packetLength) maxBytes:\(maxBytes)") var data: Array = [UInt8]() - let buffer = UnsafeMutablePointer.allocate(capacity: packetLength+packetLength+packetLength) + let buffer = UnsafeMutablePointer.allocate(capacity: maxBytes) defer { buffer.deallocate(capacity: maxBytes) } while true { - let bytesRead = try readBytes(into: buffer, size: packetLength) + let bytesRead = try readBytes(into: buffer, size: maxBytes) if bytesRead > 0 { print("read \(bytesRead)") - for i in 0 ... bytesRead - 1 { + for i in 0 ... (bytesRead - 1) { data.append(buffer[i]) if buffer[i] == stopByte { if data.count >= packetLength {