Skip to content

Commit 1b7a21d

Browse files
committed
Add ANCS example
1 parent d161f35 commit 1b7a21d

1 file changed

Lines changed: 211 additions & 0 deletions

File tree

examples/ANCS/ANCS.ino

Lines changed: 211 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,211 @@
1+
// Original: https://github.com/mathcampbell/ANCS
2+
#include <Arduino.h>
3+
#include "NimBLEDevice.h"
4+
5+
static NimBLEUUID ancsServiceUUID("7905F431-B5CE-4E99-A40F-4B1E122D00D0");
6+
static NimBLEUUID notificationSourceCharacteristicUUID("9FBF120D-6301-42D9-8C58-25E699A21DBD");
7+
static NimBLEUUID controlPointCharacteristicUUID("69D1D8F3-45E1-49A8-9821-9BBDFDAAD9D9");
8+
static NimBLEUUID dataSourceCharacteristicUUID("22EAC6E9-24D6-4BB5-BE44-B36ACE7C7BFB");
9+
10+
static NimBLEClient* pClient;
11+
12+
uint8_t latestMessageID[4];
13+
boolean pendingNotification = false;
14+
boolean incomingCall = false;
15+
uint8_t acceptCall = 0;
16+
17+
static void dataSourceNotifyCallback(NimBLERemoteCharacteristic* pDataSourceCharacteristic,
18+
uint8_t* pData,
19+
size_t length,
20+
bool isNotify) {
21+
// Serial.print("Notify callback for characteristic ");
22+
// Serial.print(pDataSourceCharacteristic->getUUID().toString().c_str());
23+
// Serial.print(" of data length ");
24+
// Serial.println(length);
25+
for (int i = 0; i < length; i++) {
26+
if (i > 7) {
27+
Serial.write(pData[i]);
28+
} else {
29+
Serial.print(pData[i], HEX);
30+
Serial.print(" ");
31+
}
32+
}
33+
Serial.println();
34+
}
35+
36+
static void NotificationSourceNotifyCallback(NimBLERemoteCharacteristic* pNotificationSourceCharacteristic,
37+
uint8_t* pData,
38+
size_t length,
39+
bool isNotify) {
40+
if (pData[0] == 0) {
41+
Serial.println("New notification!");
42+
latestMessageID[0] = pData[4];
43+
latestMessageID[1] = pData[5];
44+
latestMessageID[2] = pData[6];
45+
latestMessageID[3] = pData[7];
46+
47+
switch (pData[2]) {
48+
case 0:
49+
Serial.println("Category: Other");
50+
break;
51+
case 1:
52+
incomingCall = true;
53+
Serial.println("Category: Incoming call");
54+
break;
55+
case 2:
56+
Serial.println("Category: Missed call");
57+
break;
58+
case 3:
59+
Serial.println("Category: Voicemail");
60+
break;
61+
case 4:
62+
Serial.println("Category: Social");
63+
break;
64+
case 5:
65+
Serial.println("Category: Schedule");
66+
break;
67+
case 6:
68+
Serial.println("Category: Email");
69+
break;
70+
case 7:
71+
Serial.println("Category: News");
72+
break;
73+
case 8:
74+
Serial.println("Category: Health");
75+
break;
76+
case 9:
77+
Serial.println("Category: Business");
78+
break;
79+
case 10:
80+
Serial.println("Category: Location");
81+
break;
82+
case 11:
83+
Serial.println("Category: Entertainment");
84+
break;
85+
default:
86+
break;
87+
}
88+
} else if (pData[0] == 1) {
89+
Serial.println("Notification Modified!");
90+
if (pData[2] == 1) {
91+
Serial.println("Call Changed!");
92+
}
93+
} else if (pData[0] == 2) {
94+
Serial.println("Notification Removed!");
95+
if (pData[2] == 1) {
96+
Serial.println("Call Gone!");
97+
}
98+
}
99+
pendingNotification = true;
100+
}
101+
102+
class ServerCallbacks : public NimBLEServerCallbacks {
103+
void onConnect(NimBLEServer* pServer, NimBLEConnInfo& connInfo) {
104+
Serial.printf("Client connected: %s\n", connInfo.getAddress().toString().c_str());
105+
pClient = pServer->getClient(connInfo);
106+
Serial.println("Client connected!");
107+
}
108+
109+
void onDisconnect(NimBLEServer* pServer, NimBLEConnInfo& connInfo, int reason) {
110+
Serial.printf("Client disconnected: %s, reason: %d\n", connInfo.getAddress().toString().c_str(), reason);
111+
}
112+
} serverCallbacks;
113+
114+
void setup() {
115+
Serial.begin(115200);
116+
117+
NimBLEDevice::init("ANCS");
118+
NimBLEDevice::setSecurityAuth(true, true, true);
119+
NimBLEDevice::setSecurityIOCap(BLE_HS_IO_DISPLAY_YESNO);
120+
NimBLEDevice::setPower(9);
121+
122+
NimBLEServer* pServer = NimBLEDevice::createServer();
123+
pServer->setCallbacks(&serverCallbacks);
124+
pServer->advertiseOnDisconnect(true);
125+
126+
NimBLEAdvertising* pAdvertising = pServer->getAdvertising();
127+
NimBLEAdvertisementData advData{};
128+
advData.setFlags(0x06);
129+
advData.addServiceUUID(ancsServiceUUID);
130+
pAdvertising->setAdvertisementData(advData);
131+
pAdvertising->start();
132+
133+
Serial.println("Advertising started!");
134+
}
135+
136+
void loop() {
137+
if (pClient != nullptr && pClient->isConnected()) {
138+
auto pAncsService = pClient->getService(ancsServiceUUID);
139+
if (pAncsService == nullptr) {
140+
Serial.printf("Failed to find our service UUID: %s\n", ancsServiceUUID.toString().c_str());
141+
return;
142+
}
143+
// Obtain a reference to the characteristic in the service of the remote BLE server.
144+
auto pNotificationSourceCharacteristic = pAncsService->getCharacteristic(notificationSourceCharacteristicUUID);
145+
if (pNotificationSourceCharacteristic == nullptr) {
146+
Serial.printf("Failed to find our characteristic UUID: %s\n",
147+
notificationSourceCharacteristicUUID.toString().c_str());
148+
return;
149+
}
150+
// Obtain a reference to the characteristic in the service of the remote BLE server.
151+
auto pControlPointCharacteristic = pAncsService->getCharacteristic(controlPointCharacteristicUUID);
152+
if (pControlPointCharacteristic == nullptr) {
153+
Serial.printf("Failed to find our characteristic UUID: %s\n",
154+
controlPointCharacteristicUUID.toString().c_str());
155+
return;
156+
}
157+
// Obtain a reference to the characteristic in the service of the remote BLE server.
158+
auto pDataSourceCharacteristic = pAncsService->getCharacteristic(dataSourceCharacteristicUUID);
159+
if (pDataSourceCharacteristic == nullptr) {
160+
Serial.printf("Failed to find our characteristic UUID: %s\n", dataSourceCharacteristicUUID.toString().c_str());
161+
return;
162+
}
163+
pDataSourceCharacteristic->subscribe(true, dataSourceNotifyCallback);
164+
pNotificationSourceCharacteristic->subscribe(true, NotificationSourceNotifyCallback);
165+
166+
while (1) {
167+
if (pendingNotification || incomingCall) {
168+
// CommandID: CommandIDGetNotificationAttributes
169+
// 32bit uid
170+
// AttributeID
171+
Serial.println("Requesting details...");
172+
uint8_t val[8] =
173+
{0x0, latestMessageID[0], latestMessageID[1], latestMessageID[2], latestMessageID[3], 0x0, 0x0, 0x10};
174+
pControlPointCharacteristic->writeValue(val, 6, true); // Identifier
175+
val[5] = 0x1;
176+
pControlPointCharacteristic->writeValue(val, 8, true); // Title
177+
val[5] = 0x3;
178+
pControlPointCharacteristic->writeValue(val, 8, true); // Message
179+
val[5] = 0x5;
180+
pControlPointCharacteristic->writeValue(val, 6, true); // Date
181+
182+
while (incomingCall) {
183+
if (Serial.available() > 0) {
184+
acceptCall = Serial.read();
185+
Serial.println((char)acceptCall);
186+
}
187+
188+
if (acceptCall == 49) { // call accepted , get number 1 from serial
189+
const uint8_t vResponse[] =
190+
{0x02, latestMessageID[0], latestMessageID[1], latestMessageID[2], latestMessageID[3], 0x00};
191+
pControlPointCharacteristic->writeValue((uint8_t*)vResponse, 6, true);
192+
193+
acceptCall = 0;
194+
// incomingCall = false;
195+
} else if (acceptCall == 48) { // call rejected , get number 0 from serial
196+
const uint8_t vResponse[] =
197+
{0x02, latestMessageID[0], latestMessageID[1], latestMessageID[2], latestMessageID[3], 0x01};
198+
pControlPointCharacteristic->writeValue((uint8_t*)vResponse, 6, true);
199+
200+
acceptCall = 0;
201+
incomingCall = false;
202+
}
203+
}
204+
205+
pendingNotification = false;
206+
}
207+
delay(1);
208+
}
209+
}
210+
delay(1);
211+
}

0 commit comments

Comments
 (0)