commit | author | age
|
e0a3ca
|
1 |
|
SP |
2 |
/** NimBLE_Server Demo: |
|
3 |
* |
|
4 |
* Demonstrates many of the available features of the NimBLE client library. |
|
5 |
* |
|
6 |
* Created: on March 24 2020 |
|
7 |
* Author: H2zero |
|
8 |
* |
|
9 |
*/ |
|
10 |
|
|
11 |
#include <NimBLEDevice.h> |
|
12 |
|
|
13 |
void scanEndedCB(NimBLEScanResults results); |
|
14 |
|
|
15 |
static NimBLEAdvertisedDevice* advDevice=nullptr; |
|
16 |
|
|
17 |
static bool doConnect = false; |
|
18 |
static uint32_t scanTime = 0; /** 0 = scan forever */ |
|
19 |
static NimBLEClient* BTClient=nullptr; |
|
20 |
NimBLERemoteCharacteristic* BTChr = nullptr; |
|
21 |
|
|
22 |
/** Define a class to handle the callbacks when advertisments are received */ |
|
23 |
class AdvertisedDeviceCallbacks: public NimBLEAdvertisedDeviceCallbacks { |
|
24 |
|
|
25 |
void onResult(NimBLEAdvertisedDevice* advertisedDevice) { |
|
26 |
// Serial.print("Advertised Device found: "); |
|
27 |
// Serial.println(advertisedDevice->toString().c_str()); |
|
28 |
if(advertisedDevice->isAdvertisingService(NimBLEUUID("DEAD"))) |
|
29 |
{ |
|
30 |
// Serial.println("Found Our Service"); |
|
31 |
/** stop scan before connecting */ |
|
32 |
NimBLEDevice::getScan()->stop(); |
|
33 |
/** Save the device reference in a global for the client to use*/ |
|
34 |
advDevice = advertisedDevice; |
|
35 |
/** Ready to connect now */ |
|
36 |
doConnect = true; |
|
37 |
} |
|
38 |
}; |
|
39 |
}; |
|
40 |
|
|
41 |
|
|
42 |
|
|
43 |
|
|
44 |
/** Callback to process the results of the last scan or restart it */ |
|
45 |
void scanEndedCB(NimBLEScanResults results){ |
|
46 |
// Serial.println("Scan Ended"); |
|
47 |
} |
|
48 |
|
|
49 |
|
|
50 |
/** Handles the provisioning of clients and connects / interfaces with the server */ |
|
51 |
bool connectToServer() { |
|
52 |
NimBLEClient* pClient = nullptr; |
|
53 |
|
|
54 |
/** Check if we have a client we should reuse first **/ |
|
55 |
if(NimBLEDevice::getClientListSize()) { |
|
56 |
/** Special case when we already know this device, we send false as the |
|
57 |
* second argument in connect() to prevent refreshing the service database. |
|
58 |
* This saves considerable time and power. |
|
59 |
*/ |
|
60 |
pClient = NimBLEDevice::getClientByPeerAddress(advDevice->getAddress()); |
|
61 |
if(pClient){ |
|
62 |
if(!pClient->connect(advDevice, false)) { |
|
63 |
// Serial.println("Reconnect failed"); |
|
64 |
return false; |
|
65 |
} |
|
66 |
// Serial.println("Reconnected client"); |
|
67 |
} |
|
68 |
/** We don't already have a client that knows this device, |
|
69 |
* we will check for a client that is disconnected that we can use. |
|
70 |
*/ |
|
71 |
else { |
|
72 |
pClient = NimBLEDevice::getDisconnectedClient(); |
|
73 |
} |
|
74 |
} |
|
75 |
|
|
76 |
/** No client to reuse? Create a new one. */ |
|
77 |
if(!pClient) { |
|
78 |
if(NimBLEDevice::getClientListSize() >= NIMBLE_MAX_CONNECTIONS) { |
|
79 |
// Serial.println("Max clients reached - no more connections available"); |
|
80 |
return false; |
|
81 |
} |
|
82 |
|
|
83 |
pClient = NimBLEDevice::createClient(); |
|
84 |
|
|
85 |
// Serial.println("New client created"); |
|
86 |
|
|
87 |
// pClient->setClientCallbacks(&clientCB, false); |
|
88 |
/** Set initial connection parameters: These settings are 15ms interval, 0 latency, 120ms timout. |
|
89 |
* These settings are safe for 3 clients to connect reliably, can go faster if you have less |
|
90 |
* connections. Timeout should be a multiple of the interval, minimum is 100ms. |
|
91 |
* Min interval: 12 * 1.25ms = 15, Max interval: 12 * 1.25ms = 15, 0 latency, 51 * 10ms = 510ms timeout |
|
92 |
*/ |
|
93 |
pClient->setConnectionParams(12,12,0,51); |
|
94 |
/** Set how long we are willing to wait for the connection to complete (seconds), default is 30. */ |
|
95 |
pClient->setConnectTimeout(5); |
|
96 |
|
|
97 |
|
|
98 |
if (!pClient->connect(advDevice)) { |
|
99 |
/** Created a client but failed to connect, don't need to keep it as it has no data */ |
|
100 |
NimBLEDevice::deleteClient(pClient); |
|
101 |
// Serial.println("Failed to connect, deleted client"); |
|
102 |
return false; |
|
103 |
} |
|
104 |
} |
|
105 |
|
|
106 |
if(!pClient->isConnected()) { |
|
107 |
if (!pClient->connect(advDevice)) { |
|
108 |
// Serial.println("Failed to connect"); |
|
109 |
return false; |
|
110 |
} |
|
111 |
} |
|
112 |
|
|
113 |
// Serial.print("Connected to: "); |
|
114 |
// Serial.println(pClient->getPeerAddress().toString().c_str()); |
|
115 |
// Serial.print("RSSI: "); |
|
116 |
// Serial.println(pClient->getRssi()); |
|
117 |
|
|
118 |
/** Now we can read/write/subscribe the charateristics of the services we are interested in */ |
|
119 |
NimBLERemoteService* pSvc = nullptr; |
|
120 |
NimBLERemoteCharacteristic* pChr = nullptr; |
|
121 |
NimBLERemoteDescriptor* pDsc = nullptr; |
|
122 |
BTClient = NimBLEDevice::getClientByPeerAddress(advDevice->getAddress()); |
|
123 |
pSvc = pClient->getService("DEAD"); |
|
124 |
if(pSvc) { /** make sure it's not null */ |
|
125 |
pChr = pSvc->getCharacteristic("BEEF"); |
|
126 |
BTChr = pSvc->getCharacteristic("BEEF"); |
|
127 |
if(pChr) { /** make sure it's not null */ |
|
128 |
if(pChr->canRead()) { |
|
129 |
// Serial.print(pChr->getUUID().toString().c_str()); |
|
130 |
// Serial.print(" Value: "); |
|
131 |
// Serial.println(pChr->readValue().c_str()); |
|
132 |
} |
|
133 |
|
|
134 |
} |
|
135 |
|
|
136 |
} else { |
|
137 |
// Serial.println("DEAD service not found."); |
|
138 |
} |
|
139 |
|
|
140 |
|
|
141 |
// Serial.println("Done with this device!"); |
|
142 |
return true; |
|
143 |
} |
|
144 |
|
|
145 |
void setup (){ |
|
146 |
Serial.begin(115200); |
|
147 |
// Serial.println("Starting NimBLE Client"); |
|
148 |
/** Initialize NimBLE, no device name spcified as we are not advertising */ |
|
149 |
NimBLEDevice::init(""); |
|
150 |
|
|
151 |
/** Set the IO capabilities of the device, each option will trigger a different pairing method. |
|
152 |
* BLE_HS_IO_KEYBOARD_ONLY - Passkey pairing |
|
153 |
* BLE_HS_IO_DISPLAY_YESNO - Numeric comparison pairing |
|
154 |
* BLE_HS_IO_NO_INPUT_OUTPUT - DEFAULT setting - just works pairing |
|
155 |
*/ |
|
156 |
//NimBLEDevice::setSecurityIOCap(BLE_HS_IO_KEYBOARD_ONLY); // use passkey |
|
157 |
//NimBLEDevice::setSecurityIOCap(BLE_HS_IO_DISPLAY_YESNO); //use numeric comparison |
|
158 |
|
|
159 |
/** 2 different ways to set security - both calls achieve the same result. |
|
160 |
* no bonding, no man in the middle protection, secure connections. |
|
161 |
* |
|
162 |
* These are the default values, only shown here for demonstration. |
|
163 |
*/ |
|
164 |
//NimBLEDevice::setSecurityAuth(false, false, true); |
|
165 |
NimBLEDevice::setSecurityAuth(/*BLE_SM_PAIR_AUTHREQ_BOND | BLE_SM_PAIR_AUTHREQ_MITM |*/ BLE_SM_PAIR_AUTHREQ_SC); |
|
166 |
|
|
167 |
/** Optional: set the transmit power, default is 3db */ |
|
168 |
NimBLEDevice::setPower(ESP_PWR_LVL_P9); /** +9db */ |
|
169 |
|
|
170 |
/** Optional: set any devices you don't want to get advertisments from */ |
|
171 |
// NimBLEDevice::addIgnored(NimBLEAddress ("aa:bb:cc:dd:ee:ff")); |
|
172 |
|
|
173 |
/** create new scan */ |
|
174 |
NimBLEScan* pScan = NimBLEDevice::getScan(); |
|
175 |
|
|
176 |
/** create a callback that gets called when advertisers are found */ |
|
177 |
pScan->setAdvertisedDeviceCallbacks(new AdvertisedDeviceCallbacks()); |
|
178 |
|
|
179 |
/** Set scan interval (how often) and window (how long) in milliseconds */ |
|
180 |
pScan->setInterval(45); |
|
181 |
pScan->setWindow(15); |
|
182 |
|
|
183 |
/** Active scan will gather scan response data from advertisers |
|
184 |
* but will use more energy from both devices |
|
185 |
*/ |
|
186 |
pScan->setActiveScan(true); |
|
187 |
/** Start scanning for advertisers for the scan time specified (in seconds) 0 = forever |
|
188 |
* Optional callback for when scanning stops. |
|
189 |
*/ |
|
190 |
pScan->start(scanTime, scanEndedCB); |
|
191 |
|
|
192 |
} |
|
193 |
|
|
194 |
|
|
195 |
void loop (){ |
|
196 |
/** Loop here until we find a device we want to connect to */ |
|
197 |
while(!doConnect){ |
|
198 |
if(BTClient){ |
|
199 |
Serial.print(millis()); |
|
200 |
Serial.print(": "); |
|
201 |
Serial.println( (int)(BTChr->readValue().data()[0])); |
|
202 |
} |
|
203 |
//Serial.println(millis()); |
|
204 |
delay(10); |
|
205 |
} |
|
206 |
|
|
207 |
doConnect = false; |
|
208 |
connectToServer(); |
|
209 |
|
|
210 |
// NimBLEDevice::getScan()->start(scanTime,scanEndedCB); |
|
211 |
} |