SwiftSerial.swift 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526
  1. import Foundation
  2. #if os(Linux)
  3. public enum BaudRate {
  4. case baud0
  5. case baud50
  6. case baud75
  7. case baud110
  8. case baud134
  9. case baud150
  10. case baud200
  11. case baud300
  12. case baud600
  13. case baud1200
  14. case baud1800
  15. case baud2400
  16. case baud4800
  17. case baud9600
  18. case baud19200
  19. case baud38400
  20. case baud57600
  21. case baud115200
  22. case baud230400
  23. case baud460800
  24. case baud500000
  25. case baud576000
  26. case baud921600
  27. case baud1000000
  28. case baud1152000
  29. case baud1500000
  30. case baud2000000
  31. case baud2500000
  32. case baud3500000
  33. case baud4000000
  34. var speedValue: speed_t {
  35. switch self {
  36. case .baud0:
  37. return speed_t(B0)
  38. case .baud50:
  39. return speed_t(B50)
  40. case .baud75:
  41. return speed_t(B75)
  42. case .baud110:
  43. return speed_t(B110)
  44. case .baud134:
  45. return speed_t(B134)
  46. case .baud150:
  47. return speed_t(B150)
  48. case .baud200:
  49. return speed_t(B200)
  50. case .baud300:
  51. return speed_t(B300)
  52. case .baud600:
  53. return speed_t(B600)
  54. case .baud1200:
  55. return speed_t(B1200)
  56. case .baud1800:
  57. return speed_t(B1800)
  58. case .baud2400:
  59. return speed_t(B2400)
  60. case .baud4800:
  61. return speed_t(B4800)
  62. case .baud9600:
  63. return speed_t(B9600)
  64. case .baud19200:
  65. return speed_t(B19200)
  66. case .baud38400:
  67. return speed_t(B38400)
  68. case .baud57600:
  69. return speed_t(B57600)
  70. case .baud115200:
  71. return speed_t(B115200)
  72. case .baud230400:
  73. return speed_t(B230400)
  74. case .baud460800:
  75. return speed_t(B460800)
  76. case .baud500000:
  77. return speed_t(B500000)
  78. case .baud576000:
  79. return speed_t(B576000)
  80. case .baud921600:
  81. return speed_t(B921600)
  82. case .baud1000000:
  83. return speed_t(B1000000)
  84. case .baud1152000:
  85. return speed_t(B1152000)
  86. case .baud1500000:
  87. return speed_t(B1500000)
  88. case .baud2000000:
  89. return speed_t(B2000000)
  90. case .baud2500000:
  91. return speed_t(B2500000)
  92. case .baud3500000:
  93. return speed_t(B3500000)
  94. case .baud4000000:
  95. return speed_t(B4000000)
  96. }
  97. }
  98. }
  99. #elseif os(OSX)
  100. public enum BaudRate {
  101. case baud0
  102. case baud50
  103. case baud75
  104. case baud110
  105. case baud134
  106. case baud150
  107. case baud200
  108. case baud300
  109. case baud600
  110. case baud1200
  111. case baud1800
  112. case baud2400
  113. case baud4800
  114. case baud9600
  115. case baud19200
  116. case baud38400
  117. case baud57600
  118. case baud115200
  119. case baud230400
  120. var speedValue: speed_t {
  121. switch self {
  122. case .baud0:
  123. return speed_t(B0)
  124. case .baud50:
  125. return speed_t(B50)
  126. case .baud75:
  127. return speed_t(B75)
  128. case .baud110:
  129. return speed_t(B110)
  130. case .baud134:
  131. return speed_t(B134)
  132. case .baud150:
  133. return speed_t(B150)
  134. case .baud200:
  135. return speed_t(B200)
  136. case .baud300:
  137. return speed_t(B300)
  138. case .baud600:
  139. return speed_t(B600)
  140. case .baud1200:
  141. return speed_t(B1200)
  142. case .baud1800:
  143. return speed_t(B1800)
  144. case .baud2400:
  145. return speed_t(B2400)
  146. case .baud4800:
  147. return speed_t(B4800)
  148. case .baud9600:
  149. return speed_t(B9600)
  150. case .baud19200:
  151. return speed_t(B19200)
  152. case .baud38400:
  153. return speed_t(B38400)
  154. case .baud57600:
  155. return speed_t(B57600)
  156. case .baud115200:
  157. return speed_t(B115200)
  158. case .baud230400:
  159. return speed_t(B230400)
  160. }
  161. }
  162. }
  163. #endif
  164. public enum DataBitsSize {
  165. case bits5
  166. case bits6
  167. case bits7
  168. case bits8
  169. var flagValue: tcflag_t {
  170. switch self {
  171. case .bits5:
  172. return tcflag_t(CS5)
  173. case .bits6:
  174. return tcflag_t(CS6)
  175. case .bits7:
  176. return tcflag_t(CS7)
  177. case .bits8:
  178. return tcflag_t(CS8)
  179. }
  180. }
  181. }
  182. public enum ParityType {
  183. case none
  184. case even
  185. case odd
  186. var parityValue: tcflag_t {
  187. switch self {
  188. case .none:
  189. return 0
  190. case .even:
  191. return tcflag_t(PARENB)
  192. case .odd:
  193. return tcflag_t(PARENB | PARODD)
  194. }
  195. }
  196. }
  197. public enum PortError: Int32, Error {
  198. case failedToOpen = -1 // refer to open()
  199. case invalidPath
  200. case mustReceiveOrTransmit
  201. case mustBeOpen
  202. case stringsMustBeUTF8
  203. case unableToConvertByteToCharacter
  204. case deviceNotConnected
  205. }
  206. public class SerialPort {
  207. var path: String
  208. var fileDescriptor: Int32?
  209. public init(path: String) {
  210. self.path = path
  211. }
  212. public func openPort() throws {
  213. try openPort(toReceive: true, andTransmit: true)
  214. }
  215. public func openPort(toReceive receive: Bool, andTransmit transmit: Bool) throws {
  216. guard !path.isEmpty else {
  217. throw PortError.invalidPath
  218. }
  219. guard receive || transmit else {
  220. throw PortError.mustReceiveOrTransmit
  221. }
  222. var readWriteParam : Int32
  223. if receive && transmit {
  224. readWriteParam = O_RDWR
  225. } else if receive {
  226. readWriteParam = O_RDONLY
  227. } else if transmit {
  228. readWriteParam = O_WRONLY
  229. } else {
  230. fatalError()
  231. }
  232. #if os(Linux)
  233. fileDescriptor = open(path, readWriteParam | O_NOCTTY)
  234. #elseif os(OSX)
  235. fileDescriptor = open(path, readWriteParam | O_NOCTTY | O_EXLOCK)
  236. #endif
  237. // Throw error if open() failed
  238. if fileDescriptor == PortError.failedToOpen.rawValue {
  239. throw PortError.failedToOpen
  240. }
  241. }
  242. public func setSettings(receiveRate: BaudRate,
  243. transmitRate: BaudRate,
  244. minimumBytesToRead: Int,
  245. timeout: Int = 0, /* 0 means wait indefinitely */
  246. parityType: ParityType = .none,
  247. sendTwoStopBits: Bool = false, /* 1 stop bit is the default */
  248. dataBitsSize: DataBitsSize = .bits8,
  249. useHardwareFlowControl: Bool = false,
  250. useSoftwareFlowControl: Bool = false,
  251. processOutput: Bool = false) {
  252. guard let fileDescriptor = fileDescriptor else {
  253. return
  254. }
  255. // Set up the control structure
  256. var settings = termios()
  257. // Get options structure for the port
  258. tcgetattr(fileDescriptor, &settings)
  259. // Set baud rates
  260. cfsetispeed(&settings, receiveRate.speedValue)
  261. cfsetospeed(&settings, transmitRate.speedValue)
  262. // Enable parity (even/odd) if needed
  263. settings.c_cflag |= parityType.parityValue
  264. // Set stop bit flag
  265. if sendTwoStopBits {
  266. settings.c_cflag |= tcflag_t(CSTOPB)
  267. } else {
  268. settings.c_cflag &= ~tcflag_t(CSTOPB)
  269. }
  270. // Set data bits size flag
  271. settings.c_cflag &= ~tcflag_t(CSIZE)
  272. settings.c_cflag |= dataBitsSize.flagValue
  273. //Disable input mapping of CR to NL, mapping of NL into CR, and ignoring CR
  274. settings.c_iflag &= ~tcflag_t(ICRNL | INLCR | IGNCR)
  275. // Set hardware flow control flag
  276. #if os(Linux)
  277. if useHardwareFlowControl {
  278. settings.c_cflag |= tcflag_t(CRTSCTS)
  279. } else {
  280. settings.c_cflag &= ~tcflag_t(CRTSCTS)
  281. }
  282. #elseif os(OSX)
  283. if useHardwareFlowControl {
  284. settings.c_cflag |= tcflag_t(CRTS_IFLOW)
  285. settings.c_cflag |= tcflag_t(CCTS_OFLOW)
  286. } else {
  287. settings.c_cflag &= ~tcflag_t(CRTS_IFLOW)
  288. settings.c_cflag &= ~tcflag_t(CCTS_OFLOW)
  289. }
  290. #endif
  291. // Set software flow control flags
  292. let softwareFlowControlFlags = tcflag_t(IXON | IXOFF | IXANY)
  293. if useSoftwareFlowControl {
  294. settings.c_iflag |= softwareFlowControlFlags
  295. } else {
  296. settings.c_iflag &= ~softwareFlowControlFlags
  297. }
  298. // Turn on the receiver of the serial port, and ignore modem control lines
  299. settings.c_cflag |= tcflag_t(CREAD | CLOCAL)
  300. // Turn off canonical mode
  301. settings.c_lflag &= ~tcflag_t(ICANON | ECHO | ECHOE | ISIG)
  302. // Set output processing flag
  303. if processOutput {
  304. settings.c_oflag |= tcflag_t(OPOST)
  305. } else {
  306. settings.c_oflag &= ~tcflag_t(OPOST)
  307. }
  308. //Special characters
  309. //We do this as c_cc is a C-fixed array which is imported as a tuple in Swift.
  310. //To avoid hardcoding the VMIN or VTIME value to access the tuple value, we use the typealias instead
  311. #if os(Linux)
  312. 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)
  313. 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
  314. #elseif os(OSX)
  315. 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)
  316. 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
  317. #endif
  318. specialCharacters.VMIN = cc_t(minimumBytesToRead)
  319. specialCharacters.VTIME = cc_t(timeout)
  320. settings.c_cc = specialCharacters
  321. // Commit settings
  322. tcsetattr(fileDescriptor, TCSANOW, &settings)
  323. }
  324. public func closePort() {
  325. if let fileDescriptor = fileDescriptor {
  326. close(fileDescriptor)
  327. }
  328. fileDescriptor = nil
  329. }
  330. }
  331. // MARK: Receiving
  332. extension SerialPort {
  333. public func readBytes(into buffer: UnsafeMutablePointer<UInt8>, size: Int) throws -> Int {
  334. guard let fileDescriptor = fileDescriptor else {
  335. throw PortError.mustBeOpen
  336. }
  337. var s: stat = stat()
  338. fstat(fileDescriptor, &s)
  339. if s.st_nlink != 1 {
  340. throw PortError.deviceNotConnected
  341. }
  342. let bytesRead = read(fileDescriptor, buffer, size)
  343. return bytesRead
  344. }
  345. public func readData(ofLength length: Int) throws -> Data {
  346. let buffer = UnsafeMutablePointer<UInt8>.allocate(capacity: length)
  347. defer {
  348. buffer.deallocate()
  349. }
  350. let bytesRead = try readBytes(into: buffer, size: length)
  351. var data : Data
  352. if bytesRead > 0 {
  353. data = Data(bytes: buffer, count: bytesRead)
  354. } else {
  355. //This is to avoid the case where bytesRead can be negative causing problems allocating the Data buffer
  356. data = Data(bytes: buffer, count: 0)
  357. }
  358. return data
  359. }
  360. public func readString(ofLength length: Int) throws -> String {
  361. var remainingBytesToRead = length
  362. var result = ""
  363. while remainingBytesToRead > 0 {
  364. let data = try readData(ofLength: remainingBytesToRead)
  365. if let string = String(data: data, encoding: String.Encoding.utf8) {
  366. result += string
  367. remainingBytesToRead -= data.count
  368. } else {
  369. return result
  370. }
  371. }
  372. return result
  373. }
  374. public func readUntilChar(_ terminator: CChar) throws -> String {
  375. var data = Data()
  376. let buffer = UnsafeMutablePointer<UInt8>.allocate(capacity: 1)
  377. defer {
  378. buffer.deallocate()
  379. }
  380. while true {
  381. let bytesRead = try readBytes(into: buffer, size: 1)
  382. if bytesRead > 0 {
  383. if ( buffer[0] > 127) {
  384. throw PortError.unableToConvertByteToCharacter
  385. }
  386. let character = CChar(buffer[0])
  387. if character == terminator {
  388. break
  389. } else {
  390. data.append(buffer, count: 1)
  391. }
  392. }
  393. }
  394. if let string = String(data: data, encoding: String.Encoding.utf8) {
  395. return string
  396. } else {
  397. throw PortError.stringsMustBeUTF8
  398. }
  399. }
  400. public func readLine() throws -> String {
  401. let newlineChar = CChar(10) // Newline/Line feed character `\n` is 10
  402. return try readUntilChar(newlineChar)
  403. }
  404. public func readByte() throws -> UInt8 {
  405. let buffer = UnsafeMutablePointer<UInt8>.allocate(capacity: 1)
  406. defer {
  407. buffer.deallocate()
  408. }
  409. while true {
  410. let bytesRead = try readBytes(into: buffer, size: 1)
  411. if bytesRead > 0 {
  412. return buffer[0]
  413. }
  414. }
  415. }
  416. public func readChar() throws -> UnicodeScalar {
  417. let byteRead = try readByte()
  418. let character = UnicodeScalar(byteRead)
  419. return character
  420. }
  421. }
  422. // MARK: Transmitting
  423. extension SerialPort {
  424. public func writeBytes(from buffer: UnsafeMutablePointer<UInt8>, size: Int) throws -> Int {
  425. guard let fileDescriptor = fileDescriptor else {
  426. throw PortError.mustBeOpen
  427. }
  428. let bytesWritten = write(fileDescriptor, buffer, size)
  429. return bytesWritten
  430. }
  431. public func writeData(_ data: Data) throws -> Int {
  432. let size = data.count
  433. let buffer = UnsafeMutablePointer<UInt8>.allocate(capacity: size)
  434. defer {
  435. buffer.deallocate()
  436. }
  437. data.copyBytes(to: buffer, count: size)
  438. let bytesWritten = try writeBytes(from: buffer, size: size)
  439. return bytesWritten
  440. }
  441. public func writeString(_ string: String) throws -> Int {
  442. guard let data = string.data(using: String.Encoding.utf8) else {
  443. throw PortError.stringsMustBeUTF8
  444. }
  445. return try writeData(data)
  446. }
  447. public func writeChar(_ character: UnicodeScalar) throws -> Int{
  448. let stringEquiv = String(character)
  449. let bytesWritten = try writeString(stringEquiv)
  450. return bytesWritten
  451. }
  452. }