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         getEvent
108  *
109  * Description      It identifies the type of event and gets the reader poll
110  *                  info
111  *                  notification
112  *
113  * Parameters       p_event - Vector Lx Notification
114  *                  isCmaEvent - true if it CMA event otherwise false
115  *
116  * Returns          This function return reader poll info notification
117  *
118  ****************************************************************************/
getEvent(vector<uint8_t> p_event,bool isCmaEvent)119 vector<uint8_t> ReaderPollConfigParser::getEvent(vector<uint8_t> p_event,
120                                                  bool isCmaEvent) {
121   vector<uint8_t> event_data;
122   if ((!isCmaEvent && (int)p_event.size() < MIN_LEN_NON_CMA_EVT) ||
123       (isCmaEvent && (int)p_event.size() < MIN_LEN_CMA_EVT)) {
124     return event_data;
125   }
126 
127   // Timestamp should be in Big Endian format
128   int idx = 3;
129   vector<uint8_t> timestamp;
130   timestamp.push_back(p_event[idx--]);
131   timestamp.push_back(p_event[idx--]);
132   timestamp.push_back(p_event[idx--]);
133   timestamp.push_back(p_event[idx]);
134   if (!isCmaEvent) {
135     lastKnownGain = p_event[INDEX_OF_L2_EVT_GAIN];
136     switch (p_event[INDEX_OF_L2_EVT_TYPE] & LX_TYPE_MASK) {
137       // Trigger Type
138       case L2_EVENT_TRIGGER_TYPE:
139         // Modulation detected
140         switch ((p_event[INDEX_OF_L2_EVT_TYPE] & LX_EVENT_MASK) >> 4) {
141           case EVENT_MOD_A:
142             lastKnownModEvent = EVENT_MOD_A;
143             event_data = getWellKnownModEventData(
144                 TYPE_MOD_A, std::move(timestamp), lastKnownGain);
145             break;
146 
147           case EVENT_MOD_B:
148             lastKnownModEvent = EVENT_MOD_B;
149             event_data = getWellKnownModEventData(
150                 TYPE_MOD_B, std::move(timestamp), lastKnownGain);
151             break;
152 
153           case EVENT_MOD_F:
154             lastKnownModEvent = EVENT_MOD_F;
155             event_data = getWellKnownModEventData(
156                 TYPE_MOD_F, std::move(timestamp), lastKnownGain);
157             break;
158 
159           default:
160             event_data = getUnknownEvent(
161                 vector<uint8_t>(p_event.begin() + INDEX_OF_L2_EVT_TYPE,
162                                 p_event.end()),
163                 std::move(timestamp), lastKnownGain);
164         }
165         break;
166 
167       case EVENT_RF_ON:
168         // External RF Field is ON
169         event_data = getRFEventData(std::move(timestamp), lastKnownGain, true);
170         break;
171 
172       case EVENT_RF_OFF:
173         event_data = getRFEventData(std::move(timestamp), lastKnownGain, false);
174         break;
175 
176       default:
177         event_data = getUnknownEvent(
178             vector<uint8_t>(p_event.begin() + INDEX_OF_L2_EVT_TYPE,
179                             p_event.end()),
180             std::move(timestamp), lastKnownGain);
181         break;
182     }
183 
184   } else {
185     switch (p_event[INDEX_OF_CMA_EVT_TYPE]) {
186       // Trigger Type
187       case CMA_EVENT_TRIGGER_TYPE:
188         switch (p_event[INDEX_OF_CMA_EVT_DATA]) {
189           case REQ_A:
190             event_data = getWellKnownModEventData(
191                 TYPE_MOD_A, std::move(timestamp), lastKnownGain, {REQ_A});
192             break;
193 
194           case WUP_A:
195             event_data = getWellKnownModEventData(
196                 TYPE_MOD_A, std::move(timestamp), lastKnownGain, {WUP_A});
197             break;
198           default:
199             event_data = getUnknownEvent(
200                 vector<uint8_t>(p_event.begin() + INDEX_OF_CMA_EVT_DATA,
201                                 p_event.end()),
202                 std::move(timestamp), lastKnownGain);
203         }
204         break;
205       case CMA_DATA_TRIGGER_TYPE: {
206         uint8_t entryLength = p_event[INDEX_OF_CMA_EVT_DATA];
207         if (p_event.size() >= INDEX_OF_CMA_EVT_DATA + entryLength) {
208           vector<uint8_t> payloadData = vector<uint8_t>(
209               p_event.begin() + INDEX_OF_CMA_DATA, p_event.end());
210 
211           if (lastKnownModEvent == EVENT_MOD_B &&
212               payloadData[0] == TYPE_B_APF) {  // Type B Apf value is 0x05
213             event_data =
214                 getWellKnownModEventData(TYPE_MOD_B, std::move(timestamp),
215                                          lastKnownGain, std::move(payloadData));
216             break;
217           } else if (lastKnownModEvent == EVENT_MOD_F &&
218                      payloadData[0] == TYPE_F_CMD_LENGH &&
219                      payloadData[2] == TYPE_F_ID &&
220                      payloadData[3] == TYPE_F_ID) {
221             event_data =
222                 getWellKnownModEventData(TYPE_MOD_F, std::move(timestamp),
223                                          lastKnownGain, std::move(payloadData));
224             break;
225           } else {
226             event_data = getUnknownEvent(std::move(payloadData),
227                                          std::move(timestamp), lastKnownGain);
228             break;
229           }
230         }
231         [[fallthrough]];
232       }
233       default:
234         vector<uint8_t> payloadData = vector<uint8_t>(
235             p_event.begin() + INDEX_OF_CMA_EVT_TYPE, p_event.end());
236         event_data = getUnknownEvent(std::move(payloadData),
237                                      std::move(timestamp), lastKnownGain);
238     }
239   }
240 
241   return event_data;
242 }
243 
244 /*****************************************************************************
245  *
246  * Function         notifyPollingLoopInfoEvent
247  *
248  * Description      It sends polling info notification to upper layer
249  *
250  * Parameters       p_data - Polling loop info notification
251  *
252  * Returns          void
253  *
254  ****************************************************************************/
notifyPollingLoopInfoEvent(vector<uint8_t> p_data)255 void ReaderPollConfigParser::notifyPollingLoopInfoEvent(
256     vector<uint8_t> p_data) {
257   if (this->callback == NULL) return;
258 
259   vector<uint8_t> readerPollInfoNotifications;
260   readerPollInfoNotifications.push_back(NCI_PROP_NTF_GID);
261   readerPollInfoNotifications.push_back(NCI_PROP_NTF_ANDROID_OID);
262   readerPollInfoNotifications.push_back((int)p_data.size() + 1);
263   readerPollInfoNotifications.push_back(OBSERVE_MODE_OP_CODE);
264   readerPollInfoNotifications.insert(std::end(readerPollInfoNotifications),
265                                      std::begin(p_data), std::end(p_data));
266   this->callback((int)readerPollInfoNotifications.size(),
267                  readerPollInfoNotifications.data());
268 }
269 
270 /*****************************************************************************
271  *
272  * Function         parseAndSendReaderPollInfo
273  *
274  * Description      Function to parse Lx Notification & Send Reader Poll info
275  *                  notification
276  *
277  * Parameters       p_ntf - Lx Notification
278  *                  p_len - Notification length
279  *
280  * Returns          This function return true in case of success
281  *                  In case of failure returns false.
282  *
283  ****************************************************************************/
parseAndSendReaderPollInfo(uint8_t * p_ntf,uint16_t p_len)284 bool ReaderPollConfigParser::parseAndSendReaderPollInfo(uint8_t* p_ntf,
285                                                         uint16_t p_len) {
286   if (!p_ntf || (p_ntf && !isLxNotification(p_ntf, p_len))) {
287     return false;
288   }
289   vector<uint8_t> lxNotification = vector<uint8_t>(p_ntf, p_ntf + p_len);
290   uint16_t idx = NCI_MESSAGE_OFFSET;
291 
292   vector<uint8_t> readerPollInfoNotifications;
293   while (idx < p_len) {
294     uint8_t entryTag = ((lxNotification[idx] & LX_TAG_MASK) >> 4);
295     uint8_t entryLength = (lxNotification[idx] & LX_LENGTH_MASK);
296 
297     idx++;
298     if ((entryTag == L2_EVT_TAG || entryTag == CMA_EVT_TAG) &&
299         lxNotification.size() >= (idx + entryLength)) {
300       vector<uint8_t> readerPollInfo =
301           getEvent(vector<uint8_t>(lxNotification.begin() + idx,
302                                    lxNotification.begin() + idx + entryLength),
303                    entryTag == CMA_EVT_TAG);
304       if ((int)(readerPollInfoNotifications.size() + readerPollInfo.size()) >=
305           0xFF) {
306         notifyPollingLoopInfoEvent(std::move(readerPollInfoNotifications));
307         readerPollInfoNotifications.clear();
308       }
309       readerPollInfoNotifications.insert(std::end(readerPollInfoNotifications),
310                                          std::begin(readerPollInfo),
311                                          std::end(readerPollInfo));
312     }
313 
314     idx += entryLength;
315   }
316 
317   if (readerPollInfoNotifications.size() <= 0 ||
318       readerPollInfoNotifications.size() >= 0xFF) {
319     return false;
320   }
321 
322   notifyPollingLoopInfoEvent(std::move(readerPollInfoNotifications));
323 
324   return true;
325 }
326 
327 /*****************************************************************************
328  *
329  * Function         parseAndSendReaderPollInfo
330  *
331  * Description      Function to check it is Lx Notification or not
332  *
333  * Parameters       p_ntf - Lx Notification
334  *                  p_len - Notification length
335  *
336  * Returns          This function return true if it is Lx otherwise false
337  *
338  ****************************************************************************/
isLxNotification(uint8_t * p_ntf,uint16_t p_len)339 bool ReaderPollConfigParser::isLxNotification(uint8_t* p_ntf, uint16_t p_len) {
340   return (p_ntf && p_len >= 2 && p_ntf[NCI_GID_INDEX] == NCI_PROP_NTF_GID &&
341           p_ntf[NCI_OID_INDEX] == NCI_PROP_LX_NTF_OID);
342 }
343 
344 /*****************************************************************************
345  *
346  * Function         setReaderPollCallBack
347  *
348  * Description      Function to set the callback, It will be used to notify
349  *                  each reader polling data notifications
350  *
351  * Parameters       callback - nfc data callback object
352  *
353  * Returns          void
354  *
355  ****************************************************************************/
setReaderPollCallBack(reader_poll_info_callback_t * callback)356 void ReaderPollConfigParser::setReaderPollCallBack(
357     reader_poll_info_callback_t* callback) {
358   this->callback = callback;
359 }
360