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