1 /*
2 * Copyright 2024 NXP
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "ReaderPollConfigParser.h"
18
19 #include <phNfcNciConstants.h>
20
21 using namespace std;
22
23 /*****************************************************************************
24 *
25 * Function getWellKnownModEventData
26 *
27 * Description Frames Well known type reader poll info notification
28 *
29 * Parameters event - Event type A, B & F
30 * timeStamp - time stamp of the event
31 * gain - RSSI value
32 *
33 * Returns Returns Well known type reader poll info notification
34 *
35 ****************************************************************************/
getWellKnownModEventData(uint8_t event,vector<uint8_t> timeStamp,uint8_t gain,vector<uint8_t> data=vector<uint8_t> ())36 vector<uint8_t> ReaderPollConfigParser::getWellKnownModEventData(
37 uint8_t event, vector<uint8_t> timeStamp, uint8_t gain,
38 vector<uint8_t> data = vector<uint8_t>()) {
39 vector<uint8_t> eventData;
40 eventData.push_back(event);
41 eventData.push_back(SHORT_FLAG); // Always short frame
42 eventData.push_back(timeStamp.size() + GAIN_FIELD_LENGTH + data.size());
43 eventData.insert(std::end(eventData), std::begin(timeStamp),
44 std::end(timeStamp));
45 eventData.push_back(gain);
46 eventData.insert(std::end(eventData), std::begin(data), std::end(data));
47 return eventData;
48 }
49
50 /*****************************************************************************
51 *
52 * Function getUnknownEvent
53 *
54 * Description Frames Unknown event type reader poll info notification
55 *
56 * Parameters data - Data bytes of Unknown event
57 * timeStamp - time stamp of the event
58 * gain - RSSI value
59 *
60 * Returns Returns Unknown type reader poll info notification
61 *
62 ***************************************************************************/
getUnknownEvent(vector<uint8_t> data,vector<uint8_t> timeStamp,uint8_t gain)63 vector<uint8_t> ReaderPollConfigParser::getUnknownEvent(
64 vector<uint8_t> data, vector<uint8_t> timeStamp, uint8_t gain) {
65 uint8_t eventLength = timeStamp.size() + GAIN_FIELD_LENGTH + (int)data.size();
66 vector<uint8_t> eventData;
67 eventData.push_back(TYPE_UNKNOWN);
68 eventData.push_back(SHORT_FLAG); // Always short frame
69 eventData.push_back(eventLength);
70 eventData.insert(std::end(eventData), std::begin(timeStamp),
71 std::end(timeStamp));
72 eventData.push_back(gain);
73 eventData.insert(std::end(eventData), std::begin(data), std::end(data));
74 return eventData;
75 }
76
77 /*****************************************************************************
78 *
79 * Function getRFEventData
80 *
81 * Description Frames Well known type reader poll info notification
82 *
83 * Parameters timeStamp - time stamp of the event
84 * gain - RSSI value
85 * rfState - 0x00 for RF OFF, 0x01 for RF ON
86 *
87 * Returns Returns RF State reader poll info notification
88 *
89 ****************************************************************************/
getRFEventData(vector<uint8_t> timeStamp,uint8_t gain,bool rfState)90 vector<uint8_t> ReaderPollConfigParser::getRFEventData(
91 vector<uint8_t> timeStamp, uint8_t gain, bool rfState) {
92 uint8_t eventLength =
93 timeStamp.size() + GAIN_FIELD_LENGTH + RF_STATE_FIELD_LENGTH;
94 vector<uint8_t> eventData;
95 eventData.push_back(TYPE_RF_FLAG);
96 eventData.push_back(SHORT_FLAG); // Always short frame
97 eventData.push_back(eventLength);
98 eventData.insert(std::end(eventData), std::begin(timeStamp),
99 std::end(timeStamp));
100 eventData.push_back(gain);
101 eventData.push_back((uint8_t)(rfState ? 0x01 : 0x00));
102 return eventData;
103 }
104
105 /*****************************************************************************
106 *
107 * Function parseCmaEvent
108 *
109 * Description This function parses the unknown frames
110 *
111 * Parameters p_event - Data bytes of type Unknown event
112 *
113 * Returns Filters Type-B/Type-F data frames
114 * and converts other frame to unknown frame
115 *
116 ***************************************************************************/
parseCmaEvent(vector<uint8_t> p_event)117 vector<uint8_t> ReaderPollConfigParser::parseCmaEvent(vector<uint8_t> p_event) {
118 vector<uint8_t> event_data = vector<uint8_t>();
119 if (lastKnownModEvent == EVENT_MOD_B && p_event.size() > 0 &&
120 p_event[0] == TYPE_B_APF) { // Type B Apf value is 0x05
121 if (this->notificationType != TYPE_ONLY_MOD_EVENTS) {
122 event_data =
123 getWellKnownModEventData(TYPE_MOD_B, std::move(unknownEventTimeStamp),
124 lastKnownGain, std::move(p_event));
125 }
126 } else if (lastKnownModEvent == EVENT_MOD_F &&
127 p_event[0] == TYPE_F_CMD_LENGH && p_event[2] == TYPE_F_ID &&
128 p_event[3] == TYPE_F_ID) {
129 if (this->notificationType != TYPE_ONLY_MOD_EVENTS) {
130 event_data =
131 getWellKnownModEventData(TYPE_MOD_F, std::move(unknownEventTimeStamp),
132 lastKnownGain, std::move(p_event));
133 }
134 } else {
135 bool invalidData = std::all_of(p_event.begin(), p_event.end(),
136 [](int i) { return i == 0; });
137 if (!invalidData) {
138 event_data = getUnknownEvent(
139 std::move(p_event), std::move(unknownEventTimeStamp), lastKnownGain);
140 }
141 }
142 return event_data;
143 }
144
145 /*****************************************************************************
146 *
147 * Function getTimestampInMicroSeconds
148 *
149 * Description Function to convert Timestamp in microseconds and gives it
150 * in Big endian format
151 *
152 * Parameters rawFrame
153 *
154 * Returns vector<uint8_t>
155 *
156 ****************************************************************************/
getTimestampInMicroSeconds(vector<uint8_t> rawFrame)157 vector<uint8_t> ReaderPollConfigParser::getTimestampInMicroSeconds(
158 vector<uint8_t> rawFrame) {
159 if (rawFrame.size() < 4) {
160 return vector<uint8_t>{0x00, 0x00, 0x00, 0x00};
161 }
162 uint32_t timeStampInMicroSeconds =
163 ((rawFrame.at(1) << 8) + rawFrame.at(0)) * 1000 +
164 ((rawFrame.at(3) << 8) + rawFrame.at(2));
165
166 vector<uint8_t> timeStamp;
167 timeStamp.push_back((timeStampInMicroSeconds >> 24) & 0xFF);
168 timeStamp.push_back((timeStampInMicroSeconds >> 16) & 0xFF);
169 timeStamp.push_back((timeStampInMicroSeconds >> 8) & 0xFF);
170 timeStamp.push_back((timeStampInMicroSeconds) & 0xFF);
171
172 return timeStamp;
173 }
174
175 /*****************************************************************************
176 *
177 * Function getEvent
178 *
179 * Description It identifies the type of event and gets the reader poll
180 * info
181 * notification
182 *
183 * Parameters p_event - Vector Lx Notification
184 * cmaEventType - CMA event type
185 *
186 * Returns This function return reader poll info notification
187 *
188 ****************************************************************************/
getEvent(vector<uint8_t> p_event,uint8_t cmaEventType)189 vector<uint8_t> ReaderPollConfigParser::getEvent(vector<uint8_t> p_event,
190 uint8_t cmaEventType) {
191 vector<uint8_t> event_data;
192 if ((cmaEventType == L2_EVT_TAG &&
193 (int)p_event.size() < MIN_LEN_NON_CMA_EVT) ||
194 (cmaEventType == CMA_EVT_TAG && (int)p_event.size() < MIN_LEN_CMA_EVT) ||
195 (cmaEventType == CMA_EVT_EXTRA_DATA_TAG &&
196 (int)p_event.size() < MIN_LEN_CMA_EXTRA_DATA_EVT)) {
197 return event_data;
198 }
199
200 if (cmaEventType == L2_EVT_TAG) {
201 // Timestamp should be in Big Endian format
202
203 vector<uint8_t> timestamp = getTimestampInMicroSeconds(p_event);
204
205 lastKnownGain = p_event[INDEX_OF_L2_EVT_GAIN];
206 switch (p_event[INDEX_OF_L2_EVT_TYPE] & LX_TYPE_MASK) {
207 // Trigger Type
208 case L2_EVENT_TRIGGER_TYPE:
209 // Modulation detected
210 switch ((p_event[INDEX_OF_L2_EVT_TYPE] & LX_EVENT_MASK) >> 4) {
211 case EVENT_MOD_A:
212 lastKnownModEvent = EVENT_MOD_A;
213 if (this->notificationType != TYPE_ONLY_CMA_EVENTS) {
214 event_data = getWellKnownModEventData(
215 TYPE_MOD_A, std::move(timestamp), lastKnownGain);
216 }
217 break;
218
219 case EVENT_MOD_B:
220 lastKnownModEvent = EVENT_MOD_B;
221 if (this->notificationType != TYPE_ONLY_CMA_EVENTS) {
222 event_data = getWellKnownModEventData(
223 TYPE_MOD_B, std::move(timestamp), lastKnownGain);
224 }
225 break;
226
227 case EVENT_MOD_F:
228 lastKnownModEvent = EVENT_MOD_F;
229 if (this->notificationType != TYPE_ONLY_CMA_EVENTS) {
230 event_data = getWellKnownModEventData(
231 TYPE_MOD_F, std::move(timestamp), lastKnownGain);
232 }
233 break;
234
235 default:
236 break;
237 }
238 break;
239
240 case EVENT_RF_ON:
241 // External RF Field is ON
242 event_data = getRFEventData(std::move(timestamp), lastKnownGain, true);
243 break;
244
245 case EVENT_RF_OFF:
246 event_data = getRFEventData(std::move(timestamp), lastKnownGain, false);
247 break;
248
249 default:
250 break;
251 }
252
253 } else if (cmaEventType == CMA_EVT_TAG) {
254 // Timestamp should be in Big Endian format
255 vector<uint8_t> timestamp = getTimestampInMicroSeconds(p_event);
256 switch (p_event[INDEX_OF_CMA_EVT_TYPE]) {
257 // Trigger Type
258 case CMA_EVENT_TRIGGER_TYPE:
259 switch (p_event[INDEX_OF_CMA_EVT_DATA]) {
260 case REQ_A:
261 if (this->notificationType != TYPE_ONLY_MOD_EVENTS) {
262 event_data = getWellKnownModEventData(
263 TYPE_MOD_A, std::move(timestamp), lastKnownGain, {REQ_A});
264 }
265 break;
266
267 case WUP_A:
268 if (this->notificationType != TYPE_ONLY_MOD_EVENTS) {
269 event_data = getWellKnownModEventData(
270 TYPE_MOD_A, std::move(timestamp), lastKnownGain, {WUP_A});
271 }
272 break;
273 default:
274 break;
275 }
276 break;
277 case CMA_DATA_TRIGGER_TYPE: {
278 readExtraBytesForUnknownEvent = true;
279 extraByteLength = p_event[INDEX_OF_CMA_EVT_DATA];
280 unknownEventTimeStamp = timestamp;
281 break;
282 }
283 default:
284 break;
285 }
286 } else if (cmaEventType == CMA_EVT_EXTRA_DATA_TAG &&
287 readExtraBytesForUnknownEvent) {
288 extraBytes.insert(std::end(extraBytes), std::begin(p_event),
289 std::end(p_event));
290
291 // If the required bytes received from Extra Data frames, process the
292 // unknown event and reset the extra data bytes
293 if (extraBytes.size() >= extraByteLength) {
294 event_data = parseCmaEvent(std::move(extraBytes));
295 resetExtraBytesInfo();
296 }
297 }
298
299 return event_data;
300 }
301
302 /*****************************************************************************
303 *
304 * Function notifyPollingLoopInfoEvent
305 *
306 * Description It sends polling info notification to upper layer
307 *
308 * Parameters p_data - Polling loop info notification
309 *
310 * Returns void
311 *
312 ****************************************************************************/
notifyPollingLoopInfoEvent(vector<uint8_t> p_data)313 void ReaderPollConfigParser::notifyPollingLoopInfoEvent(
314 vector<uint8_t> p_data) {
315 if (this->callback == NULL) return;
316
317 vector<uint8_t> readerPollInfoNotifications;
318 readerPollInfoNotifications.push_back(NCI_PROP_NTF_GID);
319 readerPollInfoNotifications.push_back(NCI_PROP_NTF_ANDROID_OID);
320 readerPollInfoNotifications.push_back((int)p_data.size() + 1);
321 readerPollInfoNotifications.push_back(OBSERVE_MODE_OP_CODE);
322 readerPollInfoNotifications.insert(std::end(readerPollInfoNotifications),
323 std::begin(p_data), std::end(p_data));
324 this->callback((int)readerPollInfoNotifications.size(),
325 readerPollInfoNotifications.data());
326 }
327
328 /*****************************************************************************
329 *
330 * Function parseAndSendReaderPollInfo
331 *
332 * Description Function to parse Lx Notification & Send Reader Poll info
333 * notification
334 *
335 * Parameters p_ntf - Lx Notification
336 * p_len - Notification length
337 *
338 * Returns This function return true in case of success
339 * In case of failure returns false.
340 *
341 ****************************************************************************/
parseAndSendReaderPollInfo(uint8_t * p_ntf,uint16_t p_len)342 bool ReaderPollConfigParser::parseAndSendReaderPollInfo(uint8_t* p_ntf,
343 uint16_t p_len) {
344 if (!p_ntf || (p_ntf && !isLxNotification(p_ntf, p_len))) {
345 return false;
346 }
347 vector<uint8_t> lxNotification = vector<uint8_t>(p_ntf, p_ntf + p_len);
348 uint16_t idx = NCI_MESSAGE_OFFSET;
349
350 vector<uint8_t> readerPollInfoNotifications;
351 while (idx < p_len) {
352 uint8_t entryTag = ((lxNotification[idx] & LX_TAG_MASK) >> 4);
353 uint8_t entryLength = (lxNotification[idx] & LX_LENGTH_MASK);
354
355 idx++;
356 if ((entryTag == L2_EVT_TAG || entryTag == CMA_EVT_TAG ||
357 entryTag == CMA_EVT_EXTRA_DATA_TAG) &&
358 lxNotification.size() >= (idx + entryLength)) {
359 /*
360 Reset the extra data bytes, If it receives other events while reading
361 for unknown event chained frames
362 */
363 if (readExtraBytesForUnknownEvent &&
364 (entryTag == L2_EVT_TAG || entryTag == CMA_EVT_TAG)) {
365 resetExtraBytesInfo();
366 }
367 vector<uint8_t> readerPollInfo =
368 getEvent(vector<uint8_t>(lxNotification.begin() + idx,
369 lxNotification.begin() + idx + entryLength),
370 entryTag);
371
372 if ((int)(readerPollInfoNotifications.size() + readerPollInfo.size()) >=
373 0xFF) {
374 notifyPollingLoopInfoEvent(std::move(readerPollInfoNotifications));
375 readerPollInfoNotifications.clear();
376 }
377 readerPollInfoNotifications.insert(std::end(readerPollInfoNotifications),
378 std::begin(readerPollInfo),
379 std::end(readerPollInfo));
380 }
381
382 idx += entryLength;
383 }
384
385 if (readerPollInfoNotifications.size() <= 0 ||
386 readerPollInfoNotifications.size() >= 0xFF) {
387 return false;
388 }
389
390 notifyPollingLoopInfoEvent(std::move(readerPollInfoNotifications));
391
392 return true;
393 }
394
395 /*****************************************************************************
396 *
397 * Function parseAndSendReaderPollInfo
398 *
399 * Description Function to check it is Lx Notification or not
400 *
401 * Parameters p_ntf - Lx Notification
402 * p_len - Notification length
403 *
404 * Returns This function return true if it is Lx otherwise false
405 *
406 ****************************************************************************/
isLxNotification(uint8_t * p_ntf,uint16_t p_len)407 bool ReaderPollConfigParser::isLxNotification(uint8_t* p_ntf, uint16_t p_len) {
408 return (p_ntf && p_len >= 2 && p_ntf[NCI_GID_INDEX] == NCI_PROP_NTF_GID &&
409 p_ntf[NCI_OID_INDEX] == NCI_PROP_LX_NTF_OID);
410 }
411
412 /*****************************************************************************
413 *
414 * Function setReaderPollCallBack
415 *
416 * Description Function to set the callback, It will be used to notify
417 * each reader polling data notifications
418 *
419 * Parameters callback - nfc data callback object
420 *
421 * Returns void
422 *
423 ****************************************************************************/
setReaderPollCallBack(reader_poll_info_callback_t * callback)424 void ReaderPollConfigParser::setReaderPollCallBack(
425 reader_poll_info_callback_t* callback) {
426 this->callback = callback;
427 }
428
429 /*****************************************************************************
430 *
431 * Function resetExtraBytesInfo
432 *
433 * Description Function to reset the extra bytes info of UnknownEvent
434 *
435 * Parameters None
436 *
437 * Returns void
438 *
439 ****************************************************************************/
resetExtraBytesInfo()440 void ReaderPollConfigParser::resetExtraBytesInfo() {
441 readExtraBytesForUnknownEvent = false;
442 extraByteLength = 0;
443 extraBytes = vector<uint8_t>();
444 unknownEventTimeStamp = vector<uint8_t>();
445 }
446
447 /*****************************************************************************
448 *
449 * Function setNotificationType
450 *
451 * Description Function to select the Notification type for Observe mode
452 * By default all type of notification enabled if not set
453 *
454 * Parameters None
455 *
456 * Returns void
457 *
458 ****************************************************************************/
setNotificationType(uint8_t notificationType)459 void ReaderPollConfigParser::setNotificationType(uint8_t notificationType) {
460 this->notificationType = notificationType;
461 }
462