-
Notifications
You must be signed in to change notification settings - Fork 75
/
ScannerViewController.swift
211 lines (156 loc) · 6.7 KB
/
ScannerViewController.swift
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
//
// ScannerViewController.swift
// HM10 Serial
//
// Created by Alex on 10-08-15.
// Copyright (c) 2015 Balancing Rock. All rights reserved.
//
import UIKit
import CoreBluetooth
final class ScannerViewController: UIViewController, UITableViewDataSource, UITableViewDelegate, BluetoothSerialDelegate {
//MARK: IBOutlets
@IBOutlet weak var tryAgainButton: UIBarButtonItem!
@IBOutlet weak var tableView: UITableView!
//MARK: Variables
/// The peripherals that have been discovered (no duplicates and sorted by asc RSSI)
var peripherals: [(peripheral: CBPeripheral, RSSI: Float)] = []
/// The peripheral the user has selected
var selectedPeripheral: CBPeripheral?
/// Progress hud shown
var progressHUD: MBProgressHUD?
//MARK: Functions
override func viewDidLoad() {
super.viewDidLoad()
// tryAgainButton is only enabled when we've stopped scanning
tryAgainButton.isEnabled = false
// remove extra seperator insets (looks better imho)
tableView.tableFooterView = UIView(frame: CGRect.zero)
// tell the delegate to notificate US instead of the previous view if something happens
serial.delegate = self
if serial.centralManager.state != .poweredOn {
title = "Bluetooth not turned on"
return
}
// start scanning and schedule the time out
serial.startScan()
Timer.scheduledTimer(timeInterval: 10, target: self, selector: #selector(ScannerViewController.scanTimeOut), userInfo: nil, repeats: false)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
/// Should be called 10s after we've begun scanning
@objc func scanTimeOut() {
// timeout has occurred, stop scanning and give the user the option to try again
serial.stopScan()
tryAgainButton.isEnabled = true
title = "Done scanning"
}
/// Should be called 10s after we've begun connecting
@objc func connectTimeOut() {
// don't if we've already connected
if let _ = serial.connectedPeripheral {
return
}
if let hud = progressHUD {
hud.hide(false)
}
if let _ = selectedPeripheral {
serial.disconnect()
selectedPeripheral = nil
}
let hud = MBProgressHUD.showAdded(to: view, animated: true)
hud?.mode = MBProgressHUDMode.text
hud?.labelText = "Failed to connect"
hud?.hide(true, afterDelay: 2)
}
//MARK: UITableViewDataSource
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return peripherals.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
// return a cell with the peripheral name as text in the label
let cell = tableView.dequeueReusableCell(withIdentifier: "cell")!
let label = cell.viewWithTag(1) as! UILabel
label.text = peripherals[(indexPath as NSIndexPath).row].peripheral.name
return cell
}
//MARK: UITableViewDelegate
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: true)
// the user has selected a peripheral, so stop scanning and proceed to the next view
serial.stopScan()
selectedPeripheral = peripherals[(indexPath as NSIndexPath).row].peripheral
serial.connectToPeripheral(selectedPeripheral!)
progressHUD = MBProgressHUD.showAdded(to: view, animated: true)
progressHUD!.labelText = "Connecting"
// TODO: Timer doesn't use connecting ID
Timer.scheduledTimer(timeInterval: 10, target: self, selector: #selector(ScannerViewController.connectTimeOut), userInfo: nil, repeats: false)
}
//MARK: BluetoothSerialDelegate
func serialDidDiscoverPeripheral(_ peripheral: CBPeripheral, RSSI: NSNumber?) {
// check whether it is a duplicate
for exisiting in peripherals {
if exisiting.peripheral.identifier == peripheral.identifier { return }
}
// add to the array, next sort & reload
let theRSSI = RSSI?.floatValue ?? 0.0
peripherals.append((peripheral: peripheral, RSSI: theRSSI))
peripherals.sort { $0.RSSI < $1.RSSI }
tableView.reloadData()
}
func serialDidFailToConnect(_ peripheral: CBPeripheral, error: NSError?) {
if let hud = progressHUD {
hud.hide(false)
}
tryAgainButton.isEnabled = true
let hud = MBProgressHUD.showAdded(to: view, animated: true)
hud?.mode = MBProgressHUDMode.text
hud?.labelText = "Failed to connect"
hud?.hide(true, afterDelay: 1.0)
}
func serialDidDisconnect(_ peripheral: CBPeripheral, error: NSError?) {
if let hud = progressHUD {
hud.hide(false)
}
tryAgainButton.isEnabled = true
let hud = MBProgressHUD.showAdded(to: view, animated: true)
hud?.mode = MBProgressHUDMode.text
hud?.labelText = "Failed to connect"
hud?.hide(true, afterDelay: 1.0)
}
func serialIsReady(_ peripheral: CBPeripheral) {
if let hud = progressHUD {
hud.hide(false)
}
NotificationCenter.default.post(name: Notification.Name(rawValue: "reloadStartViewController"), object: self)
dismiss(animated: true, completion: nil)
}
func serialDidChangeState() {
if let hud = progressHUD {
hud.hide(false)
}
if serial.centralManager.state != .poweredOn {
NotificationCenter.default.post(name: Notification.Name(rawValue: "reloadStartViewController"), object: self)
dismiss(animated: true, completion: nil)
}
}
//MARK: IBActions
@IBAction func cancel(_ sender: AnyObject) {
// go back
serial.stopScan()
dismiss(animated: true, completion: nil)
}
@IBAction func tryAgain(_ sender: AnyObject) {
// empty array an start again
peripherals = []
tableView.reloadData()
tryAgainButton.isEnabled = false
title = "Scanning ..."
serial.startScan()
Timer.scheduledTimer(timeInterval: 10, target: self, selector: #selector(ScannerViewController.scanTimeOut), userInfo: nil, repeats: false)
}
}