1 /******************************************************************************
2  *
3  *  Copyright (C) 2018 ST Microelectronics S.A.
4  *
5  *  Licensed under the Apache License, Version 2.0 (the "License");
6  *  you may not use this file except in compliance with the License.
7  *  You may obtain a copy of the License at:
8  *
9  *  http://www.apache.org/licenses/LICENSE-2.0
10  *
11  *  Unless required by applicable law or agreed to in writing, software
12  *  distributed under the License is distributed on an "AS IS" BASIS,
13  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  *  See the License for the specific language governing permissions and
15  *  limitations under the License.
16  *
17  *
18  ******************************************************************************/
19 
20 #define LOG_TAG "StEse-SpiLayerComm"
21 #include "SpiLayerComm.h"
22 #include <errno.h>
23 #include <stdbool.h>
24 #include <string.h>
25 #include <sys/stat.h>
26 #include <sys/time.h>
27 #include <time.h>
28 #include "SpiLayerDriver.h"
29 #include "android_logmsg.h"
30 #include "utils-lib/Atp.h"
31 #include "utils-lib/Tpdu.h"
32 #include "utils-lib/Utils.h"
33 
34 int pollInterval;
35 
36 /*******************************************************************************
37 **
38 ** Function         SpiLayerComm_waitForAtpLength
39 **
40 ** Description      Starts the polling mechanism to read the length of the ATP.
41 **
42 ** Parameters       none.
43 **
44 ** Returns          0 if everything is ok, -1 otherwise.
45 **
46 *******************************************************************************/
47 
SpiLayerComm_waitForAtpLength()48 int SpiLayerComm_waitForAtpLength() {
49   STLOG_HAL_D("%s : Enter ", __func__);
50   uint8_t spiLecture;
51   struct timeval startTime;
52   struct timeval currentTime;
53   unsigned int elapsedTimeInMs = 0;
54 
55   // Wait PWT before to try to read the ATP length
56   gettimeofday(&startTime, 0);
57 
58   while (elapsedTimeInMs < DEFAULT_PWT) {
59     gettimeofday(&currentTime, 0);
60     elapsedTimeInMs = Utils_getElapsedTimeInMs(startTime, currentTime);
61   }
62 
63   // Try to read the ATP length
64   if (SpiLayerDriver_read(&spiLecture, 1) == -1) {
65     STLOG_HAL_E("Error reading the ATP length");
66     return -1;
67   }
68 
69   // Check if ATP length read is OK
70   if ((spiLecture == 0x00) || (spiLecture == 0xFF)) {
71     STLOG_HAL_E("Invalid ATP length read");
72     return -1;
73   }
74 
75   ATP.len = spiLecture;
76 
77   return 0;
78 }
79 
80 /*******************************************************************************
81 **
82 ** Function         SpiLayerComm_readAtp
83 **
84 ** Description      Reads the ATP and stores it in the ATP parameter.
85 **
86 ** Parameters       none.
87 **
88 ** Returns          0 if everything is ok, -1 otherwise.
89 **
90 *******************************************************************************/
91 
SpiLayerComm_readAtp()92 int SpiLayerComm_readAtp() {
93   uint8_t i;
94   STLOG_HAL_D("%s : Enter ", __func__);
95   // Read the ATP length
96   if (SpiLayerDriver_reset() != -1) {
97     if (SpiLayerComm_waitForAtpLength() != 0) {
98       return -1;
99     }
100   } else {
101     return -1;
102   }
103 
104   // Read the rest of the ATP (ATP.len is already set).
105   int atpArrayLength = ATP.len + LEN_LENGTH_IN_ATP;
106   uint8_t atpArray[atpArrayLength];
107 
108   if (SpiLayerDriver_read(atpArray, ATP.len) != ATP.len) {
109     STLOG_HAL_E("Error reading the rest of the ATP");
110     return -1;
111   }
112 
113   // Put the ATP length at the beginning of the atpArray
114   for (i = ATP.len; i > 0; i--) {
115     atpArray[i] = atpArray[i - 1];
116   }
117   atpArray[LEN_OFFSET_IN_ATP] = ATP.len;
118 
119   DispHal("Rx", atpArray, ATP.len);
120 
121   // Set-up the ATP into the corresponding struct
122   if (Atp_setAtp(atpArray) != 0) {
123     STLOG_HAL_E("Error setting ATP");
124     return -1;
125   }
126 
127   return 0;
128 }
129 
130 /*******************************************************************************
131 **
132 ** Function         SpiLayerComm_readAtpFromFile
133 **
134 ** Description      Reads the ATP previously stored in a file.
135 **
136 ** Parameters       none.
137 **
138 ** Returns          void.
139 **
140 *******************************************************************************/
SpiLayerComm_readAtpFromFile()141 void SpiLayerComm_readAtpFromFile() {
142   STLOG_HAL_D("%s : Enter ", __func__);
143 
144   FILE* atp_file = fopen(ATP_FILE_PATH, "rb");
145   if (atp_file) {
146     struct stat st;
147 
148     if (stat(ATP_FILE_PATH, &st) < 0) {
149       STLOG_HAL_E("Error reading ATP file.");
150     }
151 
152     uint8_t atpArray[st.st_size];
153     fread(atpArray, st.st_size, 1, atp_file);
154     // Check if error occurs
155     if (ferror(atp_file)) {
156       STLOG_HAL_E("An error occurred.");
157     }
158 
159     // Set-up the ATP into the corresponding struct
160     Atp_setAtp(atpArray);
161   }
162 }
163 
164 /*******************************************************************************
165 **
166 ** Function         SpiLayerComm_writeTpdu
167 **
168 ** Description      Writes the specified TPDU to the SPI interface.
169 **
170 ** Parameters       cmdTpdu The TPDU to be written.
171 **
172 ** Returns          The number of bytes written if everything went well, -1 if
173 **                  an error occurred.
174 **
175 *******************************************************************************/
176 
SpiLayerComm_writeTpdu(Tpdu * cmdTpdu)177 int SpiLayerComm_writeTpdu(Tpdu* cmdTpdu) {
178   int txBufferLength;
179   uint8_t txBuffer[TPDU_MAX_LENGTH];
180   STLOG_HAL_D("%s : Enter ", __func__);
181   // Build the tx buffer to allocate the array of bytes to be sent
182   switch (ATP.checksumType) {
183     case LRC:
184       txBufferLength = TPDU_PROLOGUE_LENGTH + cmdTpdu->len + TPDU_LRC_LENGTH;
185       break;
186     case CRC:
187       txBufferLength = TPDU_PROLOGUE_LENGTH + cmdTpdu->len + TPDU_CRC_LENGTH;
188       break;
189   }
190 
191   // Copy the array of bytes to be sent from the cmdTpdu struct
192   Tpdu_toByteArray(cmdTpdu, txBuffer);
193 
194   // Send the txBuffer through SPI
195   if (SpiLayerDriver_write(txBuffer, txBufferLength) != txBufferLength) {
196     STLOG_HAL_E("Error writing a TPDU through the spi");
197     return -1;
198   }
199 
200   return txBufferLength;
201 }
202 
203 /*******************************************************************************
204 **
205 ** Function         SpiLayerComm_waitForResponse
206 **
207 ** Description      Waits for a TPDU response to be available on the
208 **                  SPI interface.
209 **
210 ** Parameters       respTpdu The buffer where to store the TDPU.
211 **                  nBwt The maximum number of BWT to wait for the response.
212 **
213 ** Returns          0 if the response is available and the header could be read
214 **                  -2 if no response received before the timeout
215 **                  -1 otherwise.
216 **
217 *******************************************************************************/
SpiLayerComm_waitForResponse(Tpdu * respTpdu,int nBwt)218 int SpiLayerComm_waitForResponse(Tpdu* respTpdu, int nBwt) {
219   uint8_t pollingRxByte;
220   struct timeval startTime;
221   struct timeval currentTime;
222 
223   STLOG_HAL_D("Waiting for TPDU response (nBwt = %d).", nBwt);
224 
225   // Initialize the timeout mechanism if the BWT is under a given threshold.
226   bool isTimeoutRequired = false;
227   unsigned int maxWaitingTime = 0;
228   if (ATP.bwt < BWT_THRESHOlD) {
229     // Enable and init the timeout mechanism
230     isTimeoutRequired = true;
231     maxWaitingTime = ATP.bwt * nBwt;
232     STLOG_HAL_D("Maximum waiting time = %d", maxWaitingTime);
233     gettimeofday(&startTime, 0);
234   }
235 
236   // Start the polling mechanism
237   while (true) {
238     // Wait between each polling sequence
239     usleep(1000);
240     // Read the slave response by sending three null bytes
241     if (SpiLayerDriver_read(&pollingRxByte, 1) != 1) {
242       STLOG_HAL_E("Error reading a valid NAD from the slave.");
243       return -1;
244     }
245 
246     // Look for a start of valid frame
247     if (pollingRxByte == NAD_SLAVE_TO_HOST) {
248       STLOG_HAL_V("Start of valid frame detected");
249       break;
250     }
251 
252     // Check the timeout status (if required)
253     if (isTimeoutRequired) {
254       gettimeofday(&currentTime, 0);
255       unsigned int elapsedTimeInMs =
256           Utils_getElapsedTimeInMs(startTime, currentTime);
257       if (elapsedTimeInMs > maxWaitingTime) {
258         STLOG_HAL_D("BWT timed out after %d ms before receiving a valid NAD",
259                     elapsedTimeInMs);
260         return -2;
261       }
262     }
263   }
264 
265   // If the start of frame has been received continue reading the pending part
266   // of the epilogue (PCB and LEN).
267   uint8_t buffer[2];
268   if (SpiLayerDriver_read(buffer, 2) != 2) {
269     return -1;
270   }
271 
272   // Save the prologue read into the tpduRx
273   respTpdu->nad = pollingRxByte;
274   respTpdu->pcb = buffer[0];
275   respTpdu->len = (uint8_t)buffer[1];
276 
277   return 0;
278 }
279 
280 /*******************************************************************************
281 **
282 ** Function         SpiLayerComm_readTpdu
283 **
284 ** Description      Reads the pending bytes of the response
285 **                  (data information and crc fields).
286 **
287 ** Parameters       respTpdu The buffer where to store the response.
288 **
289 ** Returns          0 if everything went well, -1 otherwise.
290 **
291 *******************************************************************************/
292 
SpiLayerComm_readTpdu(Tpdu * respTpdu)293 int SpiLayerComm_readTpdu(Tpdu* respTpdu) {
294   int pendingBytes;
295   unsigned int i;
296   // Set the number of bytes to be read.
297   switch (ATP.checksumType) {
298     case LRC:
299       pendingBytes = respTpdu->len + TPDU_LRC_LENGTH;
300       break;
301     case CRC:
302       pendingBytes = respTpdu->len + TPDU_CRC_LENGTH;
303       break;
304   }
305 
306   // Read and store them in a buffer.
307   uint8_t rxBuffer[pendingBytes];
308   int bytesRead;
309 
310   bytesRead = SpiLayerDriver_read(rxBuffer, pendingBytes);
311 
312   // Check if the amount of bytesRead matches with the expected
313   if (bytesRead != pendingBytes) {
314     STLOG_HAL_E("Tpdu bytes read does not match the expected %d %d", bytesRead,
315                 pendingBytes);
316     return -1;
317   }
318 
319   // Save data values in respTpdu
320   for (i = 0; i < respTpdu->len; i++) {
321     respTpdu->data[i] = rxBuffer[i];
322   }
323 
324   // Copy checksum read to its struct's position
325   switch (ATP.checksumType) {
326     case LRC:
327       respTpdu->checksum = Tpdu_getChecksumValue(rxBuffer, respTpdu->len, LRC);
328       break;
329     case CRC:
330       respTpdu->checksum = Tpdu_getChecksumValue(rxBuffer, respTpdu->len, CRC);
331       break;
332   }
333   // Return the struct length
334   // NAD + PCB + LEN + bytesRead (DATA + CHECKSUM).
335   STLOG_HAL_V("%s : bytesRead = %d", __func__, bytesRead);
336   return 3 + bytesRead;
337 }
338