1 /*
2 * Copyright (c) 2022 FuZhou Lockzhiner Electronic Co., Ltd. All rights reserved.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "ndef.h"
17 #include <string.h>
18 #include "nfcForum.h"
19 #include "rtdTypes.h"
20 #include "NT3H.h"
21
22 typedef uint8_t (*composeRtdPtr)(const NDEFDataStr *ndef, NDEFRecordStr *ndefRecord, uint8_t *I2CMsg);
23 static composeRtdPtr composeRtd[] = {composeRtdText, composeRtdUri};
24
firstRecord(UncompletePageStr * page,const NDEFDataStr * data,RecordPosEnu rtdPosition)25 static int16_t firstRecord(UncompletePageStr *page, const NDEFDataStr *data, RecordPosEnu rtdPosition)
26 {
27 NDEFRecordStr record;
28 NDEFHeaderStr header;
29 uint8_t typeFunct = 0;
30
31 switch (data->rtdType) {
32 case RTD_TEXT:
33 typeFunct = TYPE_FUNCT_TEXT;
34 break;
35
36 case RTD_URI:
37 typeFunct = TYPE_FUNCT_URI;
38 break;
39
40 default:
41 return TYPE_FUNCT_INVALID;
42 break;
43 }
44
45 // clear all buffers
46 memset(&record, 0, sizeof(NDEFRecordStr));
47 memset(nfcPageBuffer, 0, NFC_PAGE_SIZE);
48
49 // this is the first record
50 header.startByte = NDEF_START_BYTE;
51 composeNDEFMBME(true, true, &record);
52
53 // prepare the NDEF Header and payload
54 uint8_t recordLength = composeRtd[typeFunct](data, &record, &nfcPageBuffer[sizeof(NDEFHeaderStr)]);
55 header.payloadLength = data->rtdPayloadlength + recordLength;
56
57 // write first record
58 memcpy(nfcPageBuffer, &header, sizeof(NDEFHeaderStr));
59
60 return sizeof(NDEFHeaderStr) + recordLength;
61 }
62
63
addRecord(UncompletePageStr * pageToUse,const NDEFDataStr * data,RecordPosEnu rtdPosition)64 static int16_t addRecord(UncompletePageStr *pageToUse, const NDEFDataStr *data, RecordPosEnu rtdPosition)
65 {
66 NDEFRecordStr record;
67 NDEFHeaderStr header = {0};
68 uint8_t newRecordPtr, mbMe;
69 bool ret = true;
70 uint8_t tmpBuffer[NFC_PAGE_SIZE];
71
72 uint8_t typeFunct = 0;
73
74 switch (data->rtdType) {
75 case RTD_TEXT:
76 typeFunct = 0;
77 break;
78
79 case RTD_URI:
80 typeFunct = 1;
81 break;
82
83 default:
84 return -1;
85 break;
86 }
87
88 // first Change the Header of the first Record
89 NT3HReadHeaderNfc(&newRecordPtr, &mbMe);
90 record.header = mbMe;
91 composeNDEFMBME(true, false, &record); // this is the first record
92 mbMe = record.header;
93
94 memset(&record, 0, sizeof(NDEFRecordStr));
95 memset(tmpBuffer, 0, NFC_PAGE_SIZE);
96
97 // prepare second record
98 uint8_t recordLength = composeRtd[typeFunct](data, &record, tmpBuffer);
99
100 if (rtdPosition == NDEFMiddlePos) {
101 // this is a record in the middle adjust it on the buffet
102 composeNDEFMBME(false, false, &record);
103 } else if (rtdPosition == NDEFLastPos) {
104 // this is the last record adjust it on the buffet
105 composeNDEFMBME(false, true, &record);
106 }
107
108 tmpBuffer[0] = record.header;
109
110 header.payloadLength += data->rtdPayloadlength + recordLength;
111
112 // save the new value of length on the first page
113 NT3HWriteHeaderNfc((newRecordPtr + header.payloadLength), mbMe);
114
115 // use the last valid page and start to add the new record
116 NT3HReadUserData(pageToUse->page);
117 if (pageToUse->usedBytes + recordLength < NFC_PAGE_SIZE) {
118 memcpy(&nfcPageBuffer[pageToUse->usedBytes], tmpBuffer, recordLength);
119 return recordLength + pageToUse->usedBytes;
120 } else {
121 uint8_t byteToCopy = NFC_PAGE_SIZE - pageToUse->usedBytes;
122 memcpy(&nfcPageBuffer[pageToUse->usedBytes], tmpBuffer, byteToCopy);
123 NT3HWriteUserData(pageToUse->page, nfcPageBuffer);
124 // update the info with the new page
125 pageToUse->page++;
126 pageToUse->usedBytes = recordLength - byteToCopy;
127 // copy the remain part in the pageBuffer because this is what the caller expect
128 memcpy(nfcPageBuffer, &tmpBuffer[byteToCopy], pageToUse->usedBytes);
129 return pageToUse->usedBytes;
130 }
131 }
132
writeUserPayload(int16_t payloadPtr,const NDEFDataStr * data,UncompletePageStr * addPage)133 static bool writeUserPayload(int16_t payloadPtr, const NDEFDataStr *data, UncompletePageStr *addPage)
134 {
135 uint8_t addedPayload;
136 bool ret = false;
137
138 uint8_t finish = payloadPtr + data->rtdPayloadlength;
139 bool endRecord = false;
140 uint8_t copyByte = 0;
141
142 // if the header is less then the NFC_PAGE_SIZE, fill it with the payload
143 if (NFC_PAGE_SIZE > payloadPtr) {
144 if (data->rtdPayloadlength > NFC_PAGE_SIZE - payloadPtr) {
145 copyByte = NFC_PAGE_SIZE - payloadPtr;
146 } else {
147 copyByte = data->rtdPayloadlength;
148 }
149 }
150
151 // Copy the payload
152 memcpy(&nfcPageBuffer[payloadPtr], data->rtdPayload, copyByte);
153 addedPayload = copyByte;
154
155 // if it is sufficient one send add the NDEF_END_BYTE
156 if ((addedPayload >= data->rtdPayloadlength) && ((payloadPtr + copyByte) < NFC_PAGE_SIZE)) {
157 nfcPageBuffer[(payloadPtr + copyByte)] = NDEF_END_BYTE;
158 endRecord = true;
159 }
160
161 ret = NT3HWriteUserData(addPage->page, nfcPageBuffer);
162
163 while (!endRecord) {
164 addPage->page++; // move to a new register
165 memset(nfcPageBuffer, 0, NFC_PAGE_SIZE);
166
167 // special case just the NDEF_END_BYTE remain out
168 if (addedPayload == data->rtdPayloadlength) {
169 nfcPageBuffer[0] = NDEF_END_BYTE;
170 ret = NT3HWriteUserData(addPage->page, nfcPageBuffer);
171 endRecord = true;
172 if (ret == false) {
173 errNo = NT3HERROR_WRITE_NDEF_TEXT;
174 }
175 return ret;
176 }
177
178 if (addedPayload < data->rtdPayloadlength) {
179 // add the NDEF_END_BYTE if there is enough space
180 if ((data->rtdPayloadlength - addedPayload) < NFC_PAGE_SIZE) {
181 memcpy(nfcPageBuffer, &data->rtdPayload[addedPayload], (data->rtdPayloadlength - addedPayload));
182 nfcPageBuffer[(data->rtdPayloadlength - addedPayload)] = NDEF_END_BYTE;
183 } else {
184 memcpy(nfcPageBuffer, &data->rtdPayload[addedPayload], NFC_PAGE_SIZE);
185 }
186
187 addedPayload += NFC_PAGE_SIZE;
188 ret = NT3HWriteUserData(addPage->page, nfcPageBuffer);
189 if (ret == false) {
190 errNo = NT3HERROR_WRITE_NDEF_TEXT;
191 return ret;
192 }
193 } else {
194 endRecord = true;
195 }
196 }
197
198 return ret;
199 }
200
201 typedef int16_t (*addFunct_T) (UncompletePageStr *page, const NDEFDataStr *data, RecordPosEnu rtdPosition);
202 static addFunct_T addFunct[] = {firstRecord, addRecord, addRecord};
203
NT3HwriteRecord(const NDEFDataStr * data)204 bool NT3HwriteRecord(const NDEFDataStr *data)
205 {
206 uint8_t recordLength = 0, mbMe;
207 UncompletePageStr addPage;
208 addPage.page = 0;
209
210 // calculate the last used page
211 if (data->ndefPosition != NDEFFirstPos) {
212 NT3HReadHeaderNfc(&recordLength, &mbMe);
213 addPage.page = (recordLength + sizeof(NDEFHeaderStr) + 1) / NFC_PAGE_SIZE;
214
215 // remove the NDEF_END_BYTE byte because it will overwrite by the new Record
216 addPage.usedBytes = (recordLength + sizeof(NDEFHeaderStr) + 1) % NFC_PAGE_SIZE - 1;
217 }
218
219 // call the appropriate function and consider the pointer
220 // within the NFC_PAGE_SIZE that need to be used
221 int16_t payloadPtr = addFunct[data->ndefPosition](&addPage, data, data->ndefPosition);
222 if (payloadPtr == -1) {
223 errNo = NT3HERROR_TYPE_NOT_SUPPORTED;
224 return false;
225 }
226
227 return writeUserPayload(payloadPtr, data, &addPage);
228 }
229
230