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