Guest User

Untitled

a guest
Mar 20th, 2018
66
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 13.29 KB | None | 0 0
  1. //
  2. // Koshian.swift
  3. //
  4. // Created by Kazuo Tsubaki on 2018/03/09.
  5. // Copyright © 2018年 Kazuo Tsubaki. All rights reserved.
  6. //
  7.  
  8. import Foundation
  9. import CoreBluetooth
  10.  
  11. struct KoshianConstants {
  12. // Digital I/0
  13. static let HIGH = UInt8(1)
  14. static let LOW = UInt8(0)
  15.  
  16. // Pin Mode
  17. static let PinModeInput = UInt8(0)
  18. static let PinModeOutput = UInt8(1)
  19. static let PinModeNoPulls = UInt8(0)
  20. static let PinModePullup = UInt8(1)
  21.  
  22. // Digital IO Pin
  23. static let DigitalIO0 = UInt8(0)
  24. static let DigitalIO1 = UInt8(1)
  25. static let DigitalIO2 = UInt8(2)
  26. static let DigitalIO3 = UInt8(3)
  27. static let DigitalIO4 = UInt8(4)
  28. static let DigitalIO5 = UInt8(5)
  29. static let DigitalIO6 = UInt8(6)
  30. static let DigitalIO7 = UInt8(7)
  31. static let S1 = DigitalIO0
  32. static let PIO1 = DigitalIO1
  33. static let PIO2 = DigitalIO2
  34. static let PIO3 = DigitalIO3
  35. static let PIO4 = DigitalIO4
  36.  
  37. static let KoshianPoweredOn = Notification.Name("KoshianPoweredOn")
  38. static let KoshianConnected = Notification.Name("KoshianConnected")
  39. static let KoshianDisconnected = Notification.Name("KoshianDisconnected")
  40. static let KoshianConnectionTimeout = Notification.Name("KoshianConnectionTimeout")
  41. }
  42.  
  43. struct KoshianResult {
  44. static let Success = 1
  45. static let Failure = 0
  46. }
  47.  
  48. class Koshian: NSObject {
  49.  
  50. private static var _batteryServiceUUID: CBUUID!
  51. private static var _levelServiceUUID: CBUUID!
  52. private static var _powerStateUUID: CBUUID!
  53. private static var _serviceUUID: CBUUID!
  54. private static var _pioSettingUUID: CBUUID!
  55. private static var _pioPullupUUID: CBUUID!
  56. private static var _pioOutputUUID: CBUUID!
  57.  
  58. var pioSetting: UInt8 = 0
  59. var pioOutput: UInt8 = 0
  60. var pioPullup: UInt8 = 0
  61.  
  62. var peripheral: CBPeripheral!
  63. var services: [CBService] = []
  64. var characteristics = [String: [CBCharacteristic]]()
  65.  
  66. var centralManager: CBCentralManager!
  67. var localName: String!
  68. var connected: Bool = false
  69.  
  70. var connectionTimer: Timer!
  71.  
  72. // デバイス名を設定してKoshianインスタンスを生成する
  73. init(localName: String) {
  74. super.init()
  75. pioSetting = 0
  76. pioOutput = 0
  77. pioPullup = 0
  78. centralManager = CBCentralManager(delegate: self, queue: nil, options:nil)
  79. self.localName = localName
  80. }
  81.  
  82. // 切断
  83. func disconnect() {
  84. if connected {
  85. print("Disconnecting Koshian")
  86. centralManager.cancelPeripheralConnection(peripheral)
  87. }
  88. }
  89.  
  90. // 接続
  91. // 目的のデバイスを探す
  92. // 30秒間のうちに目的のデバイスが見つからない場合はタイムアウトする
  93. func connect() {
  94. if !connected {
  95. print("Scanning Koshian")
  96. connectionTimer = Timer.scheduledTimer(withTimeInterval: 30.0, repeats: false, block: { (timer) in
  97. if self.connected == false {
  98. print("Connection Timeout")
  99. NotificationCenter.default.post(name: KoshianConstants.KoshianConnectionTimeout, object: self)
  100. self.centralManager.stopScan()
  101. }
  102. })
  103. centralManager.scanForPeripherals(withServices: nil, options: nil)
  104. }
  105. }
  106.  
  107. func createUUIDFromString(_ string: String!) -> CBUUID! {
  108. if string != nil {
  109. let uuid = CBUUID(string: string)
  110. return uuid
  111. }
  112. return nil
  113. }
  114.  
  115. // from KNSKoshianPeripheralImpl.m
  116.  
  117. func batteryServiceUUID() -> CBUUID {
  118. if Koshian._batteryServiceUUID == nil {
  119. Koshian._batteryServiceUUID = createUUIDFromString("180F")
  120. }
  121. return Koshian._batteryServiceUUID
  122. }
  123.  
  124. func levelServiceUUID() -> CBUUID {
  125. if Koshian._levelServiceUUID == nil {
  126. Koshian._levelServiceUUID = createUUIDFromString("2A19")
  127. }
  128. return Koshian._levelServiceUUID
  129. }
  130.  
  131. func powerStateUUID() -> CBUUID {
  132. if Koshian._powerStateUUID == nil {
  133. Koshian._powerStateUUID = createUUIDFromString("2A1B")
  134. }
  135. return Koshian._powerStateUUID
  136. }
  137.  
  138. func serviceUUID() -> CBUUID {
  139. if Koshian._serviceUUID == nil {
  140. Koshian._serviceUUID = createUUIDFromString("229BFF00-03FB-40DA-98A7-B0DEF65C2D4B")
  141. }
  142. return Koshian._serviceUUID
  143. }
  144.  
  145. func pioSettingUUID() -> CBUUID {
  146. if Koshian._pioSettingUUID == nil {
  147. Koshian._pioSettingUUID = createUUIDFromString("229B3000-03FB-40DA-98A7-B0DEF65C2D4B")
  148. }
  149. return Koshian._pioSettingUUID
  150. }
  151.  
  152. func pioPullupUUID() -> CBUUID {
  153. if Koshian._pioPullupUUID == nil {
  154. Koshian._pioPullupUUID = createUUIDFromString("229B3001-03FB-40DA-98A7-B0DEF65C2D4B")
  155. }
  156. return Koshian._pioPullupUUID
  157. }
  158.  
  159. func pioOutputUUID() -> CBUUID {
  160. if Koshian._pioOutputUUID == nil {
  161. Koshian._pioOutputUUID = createUUIDFromString("229B3002-03FB-40DA-98A7-B0DEF65C2D4B")
  162. }
  163. return Koshian._pioOutputUUID
  164. }
  165.  
  166. // from KNSPeripheralBaseImpl.m
  167.  
  168. func writeUInt8(_ value: UInt8, toCharacteristic: CBCharacteristic) -> Void {
  169. var i = value
  170. let data = Data(buffer: UnsafeBufferPointer(start: &i, count: MemoryLayout<UInt8>.size))
  171. peripheral.writeValue(data, for:toCharacteristic, type: CBCharacteristicWriteType.withoutResponse)
  172. }
  173.  
  174. func lookupCharacteristic(serviceUUID: CBUUID, characteristicUUID: CBUUID) -> CBCharacteristic! {
  175. guard let chars = characteristics[serviceUUID.uuidString] else {
  176. return nil
  177. }
  178. for char in chars {
  179. let c = char as CBCharacteristic
  180. if c.uuid.isEqual(characteristicUUID) {
  181. return c
  182. }
  183. }
  184. return nil
  185. }
  186.  
  187. // Digital I/Oピンのモード設定
  188. func pinMode(pin: UInt8, mode: UInt8) -> Int {
  189. if pin >= KoshianConstants.DigitalIO0 && pin <= KoshianConstants.DigitalIO7 && (mode == KoshianConstants.PinModeInput || mode == KoshianConstants.PinModeOutput) {
  190. if mode == KoshianConstants.PinModeOutput {
  191. pioSetting |= 0x01 << pin
  192. } else {
  193. pioSetting &= ~(0x01 << pin) & 0xFF
  194. }
  195. let c = lookupCharacteristic(serviceUUID: serviceUUID(), characteristicUUID: pioSettingUUID())
  196. if c != nil {
  197. writeUInt8(pioSetting, toCharacteristic: c!)
  198. return KoshianResult.Success
  199. } else {
  200. return KoshianResult.Failure
  201. }
  202. }
  203. return KoshianResult.Failure
  204. }
  205.  
  206. func pinModeAll(mode: UInt8) -> Int {
  207. if mode >= 0x00 && mode <= 0xFF {
  208. pioSetting = mode
  209. let c = lookupCharacteristic(serviceUUID: serviceUUID(), characteristicUUID: pioSettingUUID())
  210. if c != nil {
  211. writeUInt8(pioSetting, toCharacteristic: c!)
  212. return KoshianResult.Success
  213. } else {
  214. return KoshianResult.Failure
  215. }
  216. }
  217. return KoshianResult.Failure
  218. }
  219.  
  220. // Digital I/Oピンのプルアップ設定
  221. func pinPullup(pin: UInt8, mode: UInt8) -> Int {
  222. if pin >= KoshianConstants.DigitalIO0 && pin <= KoshianConstants.DigitalIO7 && (mode == KoshianConstants.PinModeNoPulls || mode == KoshianConstants.PinModePullup) {
  223. if mode == KoshianConstants.PinModePullup {
  224. pioPullup |= 0x01 << pin
  225. } else {
  226. pioPullup &= ~(0x01 << pin) & 0xFF
  227. }
  228. let c = lookupCharacteristic(serviceUUID: serviceUUID(), characteristicUUID: pioPullupUUID())
  229. if c != nil {
  230. writeUInt8(pioPullup, toCharacteristic: c!)
  231. return KoshianResult.Success
  232. } else {
  233. return KoshianResult.Failure
  234. }
  235. }
  236. return KoshianResult.Failure
  237. }
  238.  
  239. func pinPullupAll(mode: UInt8) -> Int {
  240. if mode >= 0x00 && mode <= 0xFF {
  241. pioPullup = mode
  242. let c = lookupCharacteristic(serviceUUID: serviceUUID(), characteristicUUID: pioPullupUUID())
  243. if c != nil {
  244. writeUInt8(pioPullup, toCharacteristic: c!)
  245. return KoshianResult.Success
  246. } else {
  247. return KoshianResult.Failure
  248. }
  249. }
  250. return KoshianResult.Failure
  251. }
  252.  
  253. // Digital I/Oピンへの書き込み
  254. func digitalWrite(pin: UInt8, value:UInt8) -> Int {
  255. if pin >= KoshianConstants.DigitalIO0 && pin <= KoshianConstants.DigitalIO7 && (value == KoshianConstants.HIGH || value == KoshianConstants.LOW) {
  256. if value == KoshianConstants.HIGH {
  257. pioOutput |= 0x01 << pin
  258. } else {
  259. pioOutput &= ~(0x01 << pin) & 0xFF
  260. }
  261. let c = lookupCharacteristic(serviceUUID: serviceUUID(), characteristicUUID: pioOutputUUID())
  262. if c != nil {
  263. writeUInt8(pioOutput, toCharacteristic: c!)
  264. return KoshianResult.Success
  265. } else {
  266. return KoshianResult.Failure
  267. }
  268. }
  269. return KoshianResult.Failure
  270. }
  271.  
  272. func digitalWriteAll(value: UInt8) -> Int {
  273. if value >= 0x00 && value <= 0xFF {
  274. pioOutput = value
  275. let c = lookupCharacteristic(serviceUUID: serviceUUID(), characteristicUUID: pioOutputUUID())
  276. if c != nil {
  277. writeUInt8(pioOutput, toCharacteristic: c!)
  278. return KoshianResult.Success
  279. } else {
  280. return KoshianResult.Failure
  281. }
  282. }
  283. return KoshianResult.Failure
  284. }
  285. }
  286.  
  287. extension Koshian: CBCentralManagerDelegate {
  288.  
  289. // PowerOnステートになったら通知する
  290. func centralManagerDidUpdateState(_ central: CBCentralManager) {
  291. switch central.state {
  292. case .poweredOn:
  293. print("powerOn")
  294. NotificationCenter.default.post(name: KoshianConstants.KoshianPoweredOn, object: self)
  295. default:
  296. print("central.state = \(central.state)")
  297. }
  298. }
  299.  
  300. // デバイスとの通信を切断した時に呼び出される
  301. // オブジェクトの内部状態を初期値に戻す
  302. // 切断したことを通知する
  303. func centralManager(_ central: CBCentralManager, didDisconnectPeripheral peripheral: CBPeripheral, error: Error?) {
  304. print("Koshian disconnected")
  305. self.peripheral = nil
  306. self.services.removeAll()
  307. self.characteristics.removeAll()
  308. self.pioOutput = 0
  309. self.pioSetting = 0
  310. self.pioPullup = 0
  311. self.connected = false
  312. NotificationCenter.default.post(name: KoshianConstants.KoshianDisconnected, object: self)
  313. }
  314.  
  315. // デバイスとの接続に成功したらサービスを検索する
  316. func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) {
  317. print("Koshian connected")
  318. self.peripheral = peripheral
  319. self.peripheral.delegate = self
  320. self.services.removeAll()
  321. self.peripheral.discoverServices(nil)
  322. }
  323.  
  324. // 目的のデバイスが見つかったら接続する
  325. func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber) {
  326. let name = advertisementData["kCBAdvDataLocalName"] as? String
  327. if name == localName {
  328. central.stopScan()
  329. print("\(localName) found")
  330. self.peripheral = peripheral
  331. print("Connecting \(localName)")
  332. self.centralManager.connect(self.peripheral, options: nil)
  333. }
  334. }
  335.  
  336. func centralManager(_ central: CBCentralManager, didFailToConnect peripheral: CBPeripheral, error: Error?) {
  337. print("Failed to connect to Koshian")
  338. }
  339.  
  340. }
  341.  
  342. extension Koshian: CBPeripheralDelegate {
  343.  
  344. // 全てのサービスのキャラクタリスティックを検索する
  345. func peripheral(_ peripheral: CBPeripheral, didDiscoverServices error: Error?) {
  346. for service in peripheral.services! {
  347. print("Found service \(service.uuid)")
  348. services.append(service)
  349. peripheral.discoverCharacteristics(nil, for: service)
  350. }
  351. }
  352.  
  353. // 全てのサービスとそのキャラクタりスティックが見つかったら使用可能状態に遷移
  354. // 使用可能状態であることを通知
  355. private func notifyWhenReady() {
  356. for s in services {
  357. let chars = characteristics[s.uuid.uuidString]
  358. if chars?.count == 0 {
  359. return
  360. }
  361. }
  362. connected = true
  363. if connectionTimer != nil {
  364. connectionTimer.invalidate()
  365. connectionTimer = nil
  366. }
  367. NotificationCenter.default.post(name: KoshianConstants.KoshianConnected, object: self)
  368. }
  369.  
  370. func peripheral(_ peripheral: CBPeripheral, didDiscoverCharacteristicsFor service: CBService, error: Error?) {
  371. print("Found characteristic \(String(describing: service.characteristics)) for service \(String(describing: service))")
  372. characteristics[service.uuid.uuidString] = service.characteristics
  373. print("Saved characteristics \(String(describing: self.characteristics))")
  374. notifyWhenReady()
  375. }
  376.  
  377. }
Add Comment
Please, Sign In to add comment