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 #define LOG_TAG "StEse-SpiLayerDriver"
20 #include "SpiLayerDriver.h"
21 #include <errno.h>
22 #include <string.h>
23 #include <sys/time.h>
24 #include "android_logmsg.h"
25 #include "utils-lib/Utils.h"
26 
27 int spiDeviceId;
28 int currentMode;
29 struct timeval lastRxTxTime;
30 #define LINUX_DBGBUFFER_SIZE 300
31 
32 /*******************************************************************************
33 **
34 ** Function         SpiLayerDriver_open
35 **
36 ** Description      Open the spi device driver.
37 **
38 ** Parameters       spiDevPath - Spi device path.
39 **
40 ** Returns          the file descriptor if everything is ok, -1 otherwise.
41 **
42 *******************************************************************************/
SpiLayerDriver_open(char * spiDevPath)43 int SpiLayerDriver_open(char* spiDevPath) {
44   char* spiDeviceName = spiDevPath;
45   STLOG_HAL_D("%s : Enter ", __func__);
46   // Open the master spi device and save the spi device identifier
47   spiDeviceId = open(spiDeviceName, O_RDWR | O_NOCTTY);
48   STLOG_HAL_V(" spiDeviceId: %d", spiDeviceId);
49   if (spiDeviceId < 0) {
50     return -1;
51   }
52   currentMode = MODE_RX;
53   gettimeofday(&lastRxTxTime, 0);
54 
55   return spiDeviceId;
56 }
57 
58 /*******************************************************************************
59 **
60 ** Function         SpiLayerDriver_close
61 **
62 ** Description      Close the spi device driver.
63 **
64 ** Parameters       none
65 **
66 ** Returns          void
67 **
68 *******************************************************************************/
SpiLayerDriver_close()69 void SpiLayerDriver_close() {
70   if (spiDeviceId > 0) {
71     close(spiDeviceId);
72   }
73 }
74 
75 /*******************************************************************************
76 **
77 ** Function         SpiLayerDriver_read
78 **
79 ** Description      Reads bytesToRead bytes from the SPI interface.
80 **
81 ** Parameters       rxBuffer    - Buffer to store recieved datas.
82 **                  bytesToRead - Expected number of bytes to be read.
83 **
84 ** Returns          The amount of bytes read from the slave, -1 if something
85 **                  failed.
86 **
87 *******************************************************************************/
SpiLayerDriver_read(uint8_t * rxBuffer,unsigned int bytesToRead)88 int SpiLayerDriver_read(uint8_t* rxBuffer, unsigned int bytesToRead) {
89   int retries = 0;
90   int rc = -1;
91 
92   if (currentMode != MODE_RX) {
93     currentMode = MODE_RX;
94     STLOG_HAL_V(" Last TX: %ld,%ld", lastRxTxTime.tv_sec, lastRxTxTime.tv_usec);
95     struct timeval currentTime;
96     gettimeofday(&currentTime, 0);
97     STLOG_HAL_V("     Now: %ld,%ld", currentTime.tv_sec, currentTime.tv_usec);
98     int elapsedTime = Utils_getElapsedTimeInMs(lastRxTxTime, currentTime);
99     if (elapsedTime < MIN_TIME_BETWEEN_MODE_SWITCH) {
100       int waitTime = MIN_TIME_BETWEEN_MODE_SWITCH - elapsedTime;
101       STLOG_HAL_V("Waiting %d ms to switch from TX to RX", waitTime);
102       usleep(waitTime * 1000);
103     }
104     gettimeofday(&currentTime, 0);
105     STLOG_HAL_V("Start RX: %ld,%ld", currentTime.tv_sec, currentTime.tv_usec);
106   }
107 
108   while (retries < 3) {
109     rc = read(spiDeviceId, rxBuffer, bytesToRead);
110 
111     if (rc < 0) {
112       int e = errno;
113 
114       /* unexpected result */
115       char msg[LINUX_DBGBUFFER_SIZE];
116       strerror_r(e, msg, LINUX_DBGBUFFER_SIZE);
117       STLOG_HAL_E("##  SpiRead returns %d errno %d (%s)", rc, e, msg);
118       /* delays are different and increasing for the three retries. */
119       static const uint8_t delayTab[] = {2, 3, 5};
120       int delay = delayTab[retries];
121 
122       retries++;
123       usleep(delay * 1000);
124       STLOG_HAL_W("##  SpiRead retry %d/3 in %d milliseconds.", retries, delay);
125     } else if (rc > 0) {
126       gettimeofday(&lastRxTxTime, 0);
127       return rc;
128     } else {
129       STLOG_HAL_W("read on spi failed, retrying\n");
130       usleep(4000);
131       retries++;
132     }
133   }
134   gettimeofday(&lastRxTxTime, 0);
135 
136   if (bytesToRead == 1 && rxBuffer[0] != 0 && rxBuffer[0] != 0x12 &&
137       rxBuffer[0] != 0x25) {
138     STLOG_HAL_D("Unexpected byte read from SPI: 0x%02X", rxBuffer[0]);
139   }
140   return rc;
141 }
142 
143 /*******************************************************************************
144 **
145 ** Function         SpiLayerDriver_write
146 **
147 ** Description      Write txBufferLength bytes to the SPI interface.
148 **
149 ** Parameters       txBuffer       - Buffer to transmit.
150 **                  txBufferLength - Number of bytes to be written.
151 **
152 ** Returns          The amount of bytes written to the slave, -1 if something
153 **                  failed.
154 **
155 *******************************************************************************/
SpiLayerDriver_write(uint8_t * txBuffer,unsigned int txBufferLength)156 int SpiLayerDriver_write(uint8_t* txBuffer, unsigned int txBufferLength) {
157   int retries = 0;
158   int rc = 0;
159 
160   if (currentMode != MODE_TX) {
161     currentMode = MODE_TX;
162     STLOG_HAL_V(" Last RX: %ld,%ld", lastRxTxTime.tv_sec, lastRxTxTime.tv_usec);
163     struct timeval currentTime;
164     gettimeofday(&currentTime, 0);
165     STLOG_HAL_V("     Now: %ld,%ld", currentTime.tv_sec, currentTime.tv_usec);
166     int elapsedTime = Utils_getElapsedTimeInMs(lastRxTxTime, currentTime);
167     if (elapsedTime < MIN_TIME_BETWEEN_MODE_SWITCH) {
168       int waitTime = MIN_TIME_BETWEEN_MODE_SWITCH - elapsedTime;
169       STLOG_HAL_V("Waiting %d ms to switch from RX to TX", waitTime);
170       usleep(waitTime * 1000);
171     }
172     gettimeofday(&currentTime, 0);
173     STLOG_HAL_V("Start TX: %ld,%ld", currentTime.tv_sec, currentTime.tv_usec);
174   }
175 
176   DispHal("Tx", txBuffer, txBufferLength);
177 
178   while (retries < 3) {
179     rc = write(spiDeviceId, txBuffer, txBufferLength);
180 
181     if (rc < 0) {
182       int e = errno;
183 
184       /* unexpected result */
185       char msg[LINUX_DBGBUFFER_SIZE];
186       strerror_r(e, msg, LINUX_DBGBUFFER_SIZE);
187       STLOG_HAL_E("##  Spiwrite returns %d errno %d (%s)", rc, e, msg);
188       /* delays are different and increasing for the three retries. */
189       static const uint8_t delayTab[] = {2, 3, 5};
190       int delay = delayTab[retries];
191 
192       retries++;
193       usleep(delay * 1000);
194       STLOG_HAL_W("##  SpiWrite retry %d/3 in %d milliseconds.", retries,
195                   delay);
196 
197     } else if (rc > 0) {
198       gettimeofday(&lastRxTxTime, 0);
199       return rc;
200     } else {
201       STLOG_HAL_W("write on spi failed, retrying\n");
202       usleep(4000);
203       retries++;
204     }
205   }
206 
207   gettimeofday(&lastRxTxTime, 0);
208   return rc;
209 }
210 
211 /*******************************************************************************
212 **
213 ** Function         SpiLayerDriver_reset
214 **
215 ** Description      Send a Reset pulse to the eSE.
216 **
217 ** Parameters       none
218 **
219 ** Returns          O if success, -1 otherwise
220 **
221 *******************************************************************************/
SpiLayerDriver_reset()222 int SpiLayerDriver_reset() {
223   int rc = ioctl(spiDeviceId, ST54J_SE_PULSE_RESET, NULL);
224   if (rc < 0) {
225     char msg[LINUX_DBGBUFFER_SIZE];
226 
227     strerror_r(errno, msg, LINUX_DBGBUFFER_SIZE);
228     STLOG_HAL_E("! Se reset!!, errno is '%s'", msg);
229   }
230   return rc;
231 }
232