Commit | Line | Data |
---|---|---|
d42e7319 JB |
1 | /* |
2 | * Copyright (C) 2012 Jolla Ltd. | |
3 | * Contact: Aaron McCarthy <aaron.mccarthy@jollamobile.com> | |
4 | * | |
5 | * Licensed under the Apache License, Version 2.0 (the "License"); | |
6 | * you may not use this file except in compliance with the License. | |
7 | * You may obtain a copy of the License at | |
8 | * | |
9 | * http://www.apache.org/licenses/LICENSE-2.0 | |
10 | * | |
11 | * Unless required by applicable law or agreed to in writing, software | |
12 | * distributed under the License is distributed on an "AS IS" BASIS, | |
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
14 | * See the License for the specific language governing permissions and | |
15 | * limitations under the License. | |
16 | * | |
17 | */ | |
18 | ||
19 | #include <assert.h> | |
20 | #include <stdio.h> | |
21 | #include <pthread.h> | |
22 | #include <stdlib.h> | |
23 | #include <getopt.h> | |
24 | ||
25 | #include <hardware/hardware.h> | |
26 | #include <hardware/nfc.h> | |
27 | #include <libnfc-nxp/phLibNfc.h> | |
28 | #include <libnfc-nxp/phDal4Nfc_messageQueueLib.h> | |
29 | ||
30 | static int messageThreadRunning = 0; | |
31 | static int numberOfDiscoveredTargets = 0; | |
32 | static phLibNfc_RemoteDevList_t *discoveredTargets = 0; | |
33 | static NFCSTATUS targetStatus = 0xFFFF; | |
34 | static phLibNfc_sRemoteDevInformation_t *connectedRemoteDevInfo = 0; | |
35 | static phLibNfc_ChkNdef_Info_t ndefInfo; | |
36 | static pthread_mutex_t mut = PTHREAD_MUTEX_INITIALIZER; | |
37 | static pthread_cond_t cond = PTHREAD_COND_INITIALIZER; | |
38 | ||
39 | static void *messageThreadFunc(void *arg) | |
40 | { | |
41 | int *clientId = (int *)arg; | |
42 | messageThreadRunning = 1; | |
43 | while (messageThreadRunning) { | |
44 | phDal4Nfc_Message_Wrapper_t message; | |
45 | int ret = phDal4Nfc_msgrcv(*clientId, &message, | |
46 | sizeof(phLibNfc_Message_t), 0, 0); | |
47 | if (ret == -1) { | |
48 | fprintf(stderr, "Failed to receive message from NFC stack.\n"); | |
49 | continue; | |
50 | } | |
51 | ||
52 | switch (message.msg.eMsgType) { | |
53 | case PH_LIBNFC_DEFERREDCALL_MSG: { | |
54 | phLibNfc_DeferredCall_t *msg = (phLibNfc_DeferredCall_t *)message.msg.pMsgData; | |
55 | if (msg->pCallback) | |
56 | msg->pCallback(msg->pParameter); | |
57 | break; | |
58 | } | |
59 | default: | |
60 | fprintf(stderr, "Unknown message type %d.", message.msg.eMsgType); | |
61 | } | |
62 | ||
63 | pthread_cond_signal(&cond); | |
64 | } | |
65 | ||
66 | return 0; | |
67 | } | |
68 | ||
69 | static pthread_t createMessageThread(void *arg) | |
70 | { | |
71 | pthread_t thread_id; | |
72 | int error = pthread_create(&thread_id, NULL, messageThreadFunc, arg); | |
73 | if (error != 0) | |
74 | return 0; | |
75 | ||
76 | return thread_id; | |
77 | } | |
78 | ||
79 | static void terminateMessageThread(int clientId) | |
80 | { | |
81 | messageThreadRunning = 0; | |
82 | ||
83 | phDal4Nfc_Message_Wrapper_t message; | |
84 | phLibNfc_DeferredCall_t *msg; | |
85 | ||
86 | msg = (phLibNfc_DeferredCall_t *)malloc(sizeof(phLibNfc_DeferredCall_t)); | |
87 | msg->pCallback = 0; | |
88 | msg->pParameter = 0; | |
89 | message.msg.eMsgType = PH_LIBNFC_DEFERREDCALL_MSG; | |
90 | message.msg.pMsgData = msg; | |
91 | message.msg.Size = sizeof(phLibNfc_DeferredCall_t); | |
92 | ||
93 | phDal4Nfc_msgsnd(clientId, &message, sizeof(phLibNfc_Message_t), 0); | |
94 | } | |
95 | ||
96 | void initializeCallback(void *pContext, NFCSTATUS status) | |
97 | { | |
98 | NFCSTATUS *callbackStatus = (NFCSTATUS *)pContext; | |
99 | *callbackStatus = status; | |
100 | } | |
101 | ||
102 | void discoveryNotificationCallback(void *pContext, phLibNfc_RemoteDevList_t *psRemoteDevList, | |
103 | uint8_t uNofRemoteDev, NFCSTATUS status) | |
104 | { | |
105 | if (status == NFCSTATUS_DESELECTED) { | |
106 | fprintf(stderr, "Target deselected\n"); | |
107 | } else { | |
108 | fprintf(stderr, "Discovered %d targets\n", uNofRemoteDev); | |
109 | ||
110 | uint8_t i; | |
111 | for (i = 0; i < uNofRemoteDev; ++i) { | |
112 | fprintf(stderr, "Target[%d]\n\tType: %d\n\tSession: %d\n", i, | |
113 | psRemoteDevList[i].psRemoteDevInfo->RemDevType, | |
114 | psRemoteDevList[i].psRemoteDevInfo->SessionOpened); | |
115 | } | |
116 | numberOfDiscoveredTargets = uNofRemoteDev; | |
117 | discoveredTargets = psRemoteDevList; | |
118 | targetStatus = status; | |
119 | } | |
120 | } | |
121 | ||
122 | void discoveryCallback(void *pContext, NFCSTATUS status) | |
123 | { | |
124 | fprintf(stderr, "discoveryCallback %d\n", status); | |
125 | } | |
126 | ||
127 | void remoteDevConnectCallback(void *pContext, phLibNfc_Handle hRemoteDev, | |
128 | phLibNfc_sRemoteDevInformation_t *psRemoteDevInfo, NFCSTATUS status) | |
129 | { | |
130 | targetStatus = status; | |
131 | connectedRemoteDevInfo = psRemoteDevInfo; | |
132 | } | |
133 | ||
134 | void remoteDevNdefReadCheckCallback(void *pContext, phLibNfc_ChkNdef_Info_t Ndef_Info, | |
135 | NFCSTATUS status) | |
136 | { | |
137 | ndefInfo = Ndef_Info; | |
138 | targetStatus = status; | |
139 | } | |
140 | ||
141 | void remoteDevNdefReadCallback(void *pContext, NFCSTATUS status) | |
142 | { | |
143 | targetStatus = status; | |
144 | } | |
145 | ||
146 | void testNfc(int readNdefMessages) | |
147 | { | |
148 | printf("Starting test_nfc.\n"); | |
149 | ||
150 | const hw_module_t *hwModule = 0; | |
151 | nfc_pn544_device_t *nfcDevice = 0; | |
152 | ||
153 | printf("Finding NFC hardware module.\n"); | |
154 | hw_get_module(NFC_HARDWARE_MODULE_ID, &hwModule); | |
155 | assert(hwModule != NULL); | |
156 | ||
157 | printf("Opening NFC device.\n"); | |
158 | assert(nfc_pn544_open(hwModule, &nfcDevice) == 0); | |
159 | assert(nfcDevice != 0); | |
160 | ||
161 | assert(nfcDevice->num_eeprom_settings != 0); | |
162 | assert(nfcDevice->eeprom_settings); | |
163 | ||
164 | printf("Configuring NFC driver.\n"); | |
165 | phLibNfc_sConfig_t driverConfig; | |
166 | driverConfig.nClientId = phDal4Nfc_msgget(0, 0600); | |
167 | assert(driverConfig.nClientId); | |
168 | ||
169 | void *hwRef; | |
170 | NFCSTATUS status = phLibNfc_Mgt_ConfigureDriver(&driverConfig, &hwRef); | |
171 | assert(hwRef); | |
172 | assert(status == NFCSTATUS_SUCCESS); | |
173 | ||
174 | pthread_t messageThread = createMessageThread(&driverConfig.nClientId); | |
175 | ||
176 | printf("Initializing NFC stack.\n"); | |
177 | NFCSTATUS callbackStatus = 0xFFFF; | |
178 | status = phLibNfc_Mgt_Initialize(hwRef, initializeCallback, &callbackStatus); | |
179 | assert(status == NFCSTATUS_PENDING); | |
180 | ||
181 | pthread_mutex_lock(&mut); | |
182 | while (callbackStatus == 0xFFFF) | |
183 | pthread_cond_wait(&cond, &mut); | |
184 | pthread_mutex_unlock(&mut); | |
185 | ||
186 | assert(callbackStatus == NFCSTATUS_SUCCESS); | |
187 | ||
188 | printf("Getting NFC stack capabilities.\n"); | |
189 | phLibNfc_StackCapabilities_t capabilities; | |
190 | status = phLibNfc_Mgt_GetstackCapabilities(&capabilities, &callbackStatus); | |
191 | assert(status == NFCSTATUS_SUCCESS); | |
192 | ||
193 | printf("NFC capabilities:\n" | |
194 | "\tHAL version: %u\n" | |
195 | "\tFW version: %u\n" | |
196 | "\tHW version: %u\n" | |
197 | "\tModel: %u\n" | |
198 | "\tHCI version: %u\n" | |
199 | "\tVendor: %s\n" | |
200 | "\tFull version: %u %u\n" | |
201 | "\tFW Update: %u\n", | |
202 | capabilities.psDevCapabilities.hal_version, capabilities.psDevCapabilities.fw_version, | |
203 | capabilities.psDevCapabilities.hw_version, capabilities.psDevCapabilities.model_id, | |
204 | capabilities.psDevCapabilities.hci_version, | |
205 | capabilities.psDevCapabilities.vendor_name, | |
206 | capabilities.psDevCapabilities.full_version[NXP_FULL_VERSION_LEN-1], | |
207 | capabilities.psDevCapabilities.full_version[NXP_FULL_VERSION_LEN-2], | |
208 | capabilities.psDevCapabilities.firmware_update_info); | |
209 | ||
210 | if (readNdefMessages) { | |
211 | /* Start tag discovery */ | |
212 | phLibNfc_Registry_Info_t registryInfo; | |
213 | ||
214 | registryInfo.MifareUL = 1; | |
215 | registryInfo.MifareStd = 1; | |
216 | registryInfo.ISO14443_4A = 1; | |
217 | registryInfo.ISO14443_4B = 1; | |
218 | registryInfo.Jewel = 1; | |
219 | registryInfo.Felica = 1; | |
220 | registryInfo.NFC = 1; | |
221 | registryInfo.ISO15693 = 1; | |
222 | ||
223 | int context; | |
224 | status = phLibNfc_RemoteDev_NtfRegister(®istryInfo, discoveryNotificationCallback, &context); | |
225 | assert(status == NFCSTATUS_SUCCESS); | |
226 | ||
227 | phLibNfc_sADD_Cfg_t discoveryConfig; | |
228 | discoveryConfig.NfcIP_Mode = phNfc_eP2P_ALL; | |
229 | discoveryConfig.NfcIP_Target_Mode = 0x0E; | |
230 | discoveryConfig.Duration = 300000; | |
231 | discoveryConfig.NfcIP_Tgt_Disable = 0; | |
232 | discoveryConfig.PollDevInfo.PollCfgInfo.EnableIso14443A = 1; | |
233 | discoveryConfig.PollDevInfo.PollCfgInfo.EnableIso14443B = 1; | |
234 | discoveryConfig.PollDevInfo.PollCfgInfo.EnableFelica212 = 1; | |
235 | discoveryConfig.PollDevInfo.PollCfgInfo.EnableFelica424 = 1; | |
236 | discoveryConfig.PollDevInfo.PollCfgInfo.EnableIso15693 = 1; | |
237 | discoveryConfig.PollDevInfo.PollCfgInfo.EnableNfcActive = 1; | |
238 | discoveryConfig.PollDevInfo.PollCfgInfo.DisableCardEmulation = 1; | |
239 | ||
240 | targetStatus = 0xFFFF; | |
241 | status = phLibNfc_Mgt_ConfigureDiscovery(NFC_DISCOVERY_CONFIG, discoveryConfig, | |
242 | discoveryCallback, &context); | |
243 | ||
244 | for (;;) { | |
245 | pthread_mutex_lock(&mut); | |
246 | while (targetStatus == 0xFFFF) | |
247 | pthread_cond_wait(&cond, &mut); | |
248 | pthread_mutex_unlock(&mut); | |
249 | ||
250 | fprintf(stderr, "Discovered %d targets\n", numberOfDiscoveredTargets); | |
251 | if (numberOfDiscoveredTargets > 0) { | |
252 | targetStatus = 0xFFFF; | |
253 | status = phLibNfc_RemoteDev_Connect(discoveredTargets[0].hTargetDev, | |
254 | remoteDevConnectCallback, &context); | |
255 | if (status == NFCSTATUS_PENDING) { | |
256 | pthread_mutex_lock(&mut); | |
257 | while (targetStatus == 0xFFFF) | |
258 | pthread_cond_wait(&cond, &mut); | |
259 | pthread_mutex_unlock(&mut); | |
260 | ||
261 | if (targetStatus == NFCSTATUS_SUCCESS) { | |
262 | targetStatus = 0xFFFF; | |
263 | status = phLibNfc_Ndef_CheckNdef(discoveredTargets[0].hTargetDev, | |
264 | remoteDevNdefReadCheckCallback, &context); | |
265 | ||
266 | pthread_mutex_lock(&mut); | |
267 | while (targetStatus == 0xFFFF) | |
268 | pthread_cond_wait(&cond, &mut); | |
269 | pthread_mutex_unlock(&mut); | |
270 | ||
271 | if (targetStatus == NFCSTATUS_SUCCESS && | |
272 | (ndefInfo.NdefCardState == PHLIBNFC_NDEF_CARD_READ_WRITE || | |
273 | ndefInfo.NdefCardState == PHLIBNFC_NDEF_CARD_READ_ONLY)) { | |
274 | phLibNfc_Data_t ndefBuffer; | |
275 | ndefBuffer.length = ndefInfo.MaxNdefMsgLength; | |
276 | ndefBuffer.buffer = malloc(ndefBuffer.length); | |
277 | ||
278 | targetStatus = 0xFFFF; | |
279 | status = phLibNfc_Ndef_Read(discoveredTargets[0].hTargetDev, &ndefBuffer, | |
280 | phLibNfc_Ndef_EBegin, remoteDevNdefReadCallback, &context); | |
281 | ||
282 | pthread_mutex_lock(&mut); | |
283 | while (targetStatus == 0xFFFF) | |
284 | pthread_cond_wait(&cond, &mut); | |
285 | pthread_mutex_unlock(&mut); | |
286 | ||
287 | if (targetStatus == NFCSTATUS_SUCCESS) { | |
288 | int i; | |
289 | fprintf(stderr, "NDEF: "); | |
290 | for (i = 0; i < ndefBuffer.length; ++i) | |
291 | fprintf(stderr, "%02x", ndefBuffer.buffer[i]); | |
292 | fprintf(stderr, "\n"); | |
293 | } | |
294 | ||
295 | free(ndefBuffer.buffer); | |
296 | } | |
297 | } | |
298 | } | |
299 | } | |
300 | ||
301 | if (status == NFCSTATUS_FAILED) { | |
302 | fprintf(stderr, "Failed to connect to remote device\n"); | |
303 | break; | |
304 | } | |
305 | ||
306 | targetStatus = 0xFFFF; | |
307 | status = phLibNfc_Mgt_ConfigureDiscovery(NFC_DISCOVERY_RESUME, discoveryConfig, | |
308 | discoveryCallback, &context); | |
309 | assert(status == NFCSTATUS_SUCCESS || status == NFCSTATUS_PENDING); | |
310 | } | |
311 | } | |
312 | ||
313 | printf("Deinitializing NFC stack.\n"); | |
314 | callbackStatus = 0xFFFF; | |
315 | status = phLibNfc_Mgt_DeInitialize(hwRef, initializeCallback, &callbackStatus); | |
316 | assert(status == NFCSTATUS_PENDING); | |
317 | ||
318 | pthread_mutex_lock(&mut); | |
319 | while (callbackStatus == 0xFFFF) | |
320 | pthread_cond_wait(&cond, &mut); | |
321 | pthread_mutex_unlock(&mut); | |
322 | ||
323 | assert(callbackStatus == NFCSTATUS_SUCCESS); | |
324 | ||
325 | terminateMessageThread(driverConfig.nClientId); | |
326 | pthread_join(messageThread, NULL); | |
327 | ||
328 | printf("Unconfiguring NFC driver.\n"); | |
329 | status = phLibNfc_Mgt_UnConfigureDriver(hwRef); | |
330 | assert(status == NFCSTATUS_SUCCESS); | |
331 | ||
332 | int result = phDal4Nfc_msgctl(driverConfig.nClientId, 0, 0); | |
333 | assert(result == 0); | |
334 | ||
335 | printf("Closing NFC device.\n"); | |
336 | nfc_pn544_close(nfcDevice); | |
337 | } | |
338 | ||
339 | int main(int argc, char **argv) | |
340 | { | |
341 | int opt; | |
342 | int readNdefMessages = 0; | |
343 | int restartOnFailure = 0; | |
344 | ||
345 | while ((opt = getopt(argc, argv, "nrh")) != -1) { | |
346 | switch (opt) { | |
347 | case 'n': | |
348 | readNdefMessages = 1; | |
349 | fprintf(stdout, "Reading NDEF messages from targets\n"); | |
350 | break; | |
351 | case 'r': | |
352 | restartOnFailure = 1; | |
353 | readNdefMessages = 1; | |
354 | fprintf(stdout, "Restarting on NDEF read failure, implies -n\n"); | |
355 | break; | |
356 | case 'h': | |
357 | default: | |
358 | fprintf(stderr, "\n Usage: %s \n" | |
359 | "\t-n Read NDEF message from targets,\n" | |
360 | "\t-r Restart on NDEF read failure.\n", argv[0]); | |
361 | return 1; | |
362 | } | |
363 | } | |
364 | ||
365 | do { | |
366 | testNfc(readNdefMessages); | |
367 | } while (restartOnFailure && readNdefMessages); | |
368 | ||
369 | return 0; | |
370 | } |