| /****************************************************************************** |
| * |
| * Copyright (C) 2018 ST Microelectronics S.A. |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at: |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| * |
| * |
| ******************************************************************************/ |
| #define LOG_TAG "StEse-SpiLayerDriver" |
| #include "SpiLayerDriver.h" |
| #include <errno.h> |
| #include <string.h> |
| #include <sys/time.h> |
| #include "android_logmsg.h" |
| #include "utils-lib/Utils.h" |
| |
| int spiDeviceId; |
| int currentMode; |
| struct timeval lastRxTxTime; |
| #define LINUX_DBGBUFFER_SIZE 300 |
| |
| /******************************************************************************* |
| ** |
| ** Function SpiLayerDriver_open |
| ** |
| ** Description Open the spi device driver. |
| ** |
| ** Parameters spiDevPath - Spi device path. |
| ** |
| ** Returns the file descriptor if everything is ok, -1 otherwise. |
| ** |
| *******************************************************************************/ |
| int SpiLayerDriver_open(char* spiDevPath) { |
| char* spiDeviceName = spiDevPath; |
| STLOG_HAL_D("%s : Enter ", __func__); |
| // Open the master spi device and save the spi device identifier |
| spiDeviceId = open(spiDeviceName, O_RDWR | O_NOCTTY); |
| STLOG_HAL_V(" spiDeviceId: %d", spiDeviceId); |
| if (spiDeviceId < 0) { |
| return -1; |
| } |
| currentMode = MODE_RX; |
| gettimeofday(&lastRxTxTime, 0); |
| |
| return spiDeviceId; |
| } |
| |
| /******************************************************************************* |
| ** |
| ** Function SpiLayerDriver_close |
| ** |
| ** Description Close the spi device driver. |
| ** |
| ** Parameters none |
| ** |
| ** Returns void |
| ** |
| *******************************************************************************/ |
| void SpiLayerDriver_close() { |
| if (spiDeviceId > 0) { |
| close(spiDeviceId); |
| } |
| } |
| |
| /******************************************************************************* |
| ** |
| ** Function SpiLayerDriver_read |
| ** |
| ** Description Reads bytesToRead bytes from the SPI interface. |
| ** |
| ** Parameters rxBuffer - Buffer to store recieved datas. |
| ** bytesToRead - Expected number of bytes to be read. |
| ** |
| ** Returns The amount of bytes read from the slave, -1 if something |
| ** failed. |
| ** |
| *******************************************************************************/ |
| int SpiLayerDriver_read(uint8_t* rxBuffer, unsigned int bytesToRead) { |
| int retries = 0; |
| int rc = -1; |
| |
| if (currentMode != MODE_RX) { |
| currentMode = MODE_RX; |
| STLOG_HAL_V(" Last TX: %ld,%ld", lastRxTxTime.tv_sec, lastRxTxTime.tv_usec); |
| struct timeval currentTime; |
| gettimeofday(¤tTime, 0); |
| STLOG_HAL_V(" Now: %ld,%ld", currentTime.tv_sec, currentTime.tv_usec); |
| int elapsedTime = Utils_getElapsedTimeInMs(lastRxTxTime, currentTime); |
| if (elapsedTime < MIN_TIME_BETWEEN_MODE_SWITCH) { |
| int waitTime = MIN_TIME_BETWEEN_MODE_SWITCH - elapsedTime; |
| STLOG_HAL_V("Waiting %d ms to switch from TX to RX", waitTime); |
| usleep(waitTime * 1000); |
| } |
| gettimeofday(¤tTime, 0); |
| STLOG_HAL_V("Start RX: %ld,%ld", currentTime.tv_sec, currentTime.tv_usec); |
| } |
| |
| while (retries < 3) { |
| rc = read(spiDeviceId, rxBuffer, bytesToRead); |
| |
| if (rc < 0) { |
| int e = errno; |
| |
| /* unexpected result */ |
| char msg[LINUX_DBGBUFFER_SIZE]; |
| strerror_r(e, msg, LINUX_DBGBUFFER_SIZE); |
| STLOG_HAL_E("## SpiRead returns %d errno %d (%s)", rc, e, msg); |
| /* delays are different and increasing for the three retries. */ |
| static const uint8_t delayTab[] = {2, 3, 5}; |
| int delay = delayTab[retries]; |
| |
| retries++; |
| usleep(delay * 1000); |
| STLOG_HAL_W("## SpiRead retry %d/3 in %d milliseconds.", retries, delay); |
| } else if (rc > 0) { |
| gettimeofday(&lastRxTxTime, 0); |
| return rc; |
| } else { |
| STLOG_HAL_W("read on spi failed, retrying\n"); |
| usleep(4000); |
| retries++; |
| } |
| } |
| gettimeofday(&lastRxTxTime, 0); |
| |
| if (bytesToRead == 1 && rxBuffer[0] != 0 && rxBuffer[0] != 0x12 && |
| rxBuffer[0] != 0x25) { |
| STLOG_HAL_D("Unexpected byte read from SPI: 0x%02X", rxBuffer[0]); |
| } |
| return rc; |
| } |
| |
| /******************************************************************************* |
| ** |
| ** Function SpiLayerDriver_write |
| ** |
| ** Description Write txBufferLength bytes to the SPI interface. |
| ** |
| ** Parameters txBuffer - Buffer to transmit. |
| ** txBufferLength - Number of bytes to be written. |
| ** |
| ** Returns The amount of bytes written to the slave, -1 if something |
| ** failed. |
| ** |
| *******************************************************************************/ |
| int SpiLayerDriver_write(uint8_t* txBuffer, unsigned int txBufferLength) { |
| int retries = 0; |
| int rc = 0; |
| |
| if (currentMode != MODE_TX) { |
| currentMode = MODE_TX; |
| STLOG_HAL_V(" Last RX: %ld,%ld", lastRxTxTime.tv_sec, lastRxTxTime.tv_usec); |
| struct timeval currentTime; |
| gettimeofday(¤tTime, 0); |
| STLOG_HAL_V(" Now: %ld,%ld", currentTime.tv_sec, currentTime.tv_usec); |
| int elapsedTime = Utils_getElapsedTimeInMs(lastRxTxTime, currentTime); |
| if (elapsedTime < MIN_TIME_BETWEEN_MODE_SWITCH) { |
| int waitTime = MIN_TIME_BETWEEN_MODE_SWITCH - elapsedTime; |
| STLOG_HAL_V("Waiting %d ms to switch from RX to TX", waitTime); |
| usleep(waitTime * 1000); |
| } |
| gettimeofday(¤tTime, 0); |
| STLOG_HAL_V("Start TX: %ld,%ld", currentTime.tv_sec, currentTime.tv_usec); |
| } |
| |
| DispHal("Tx", txBuffer, txBufferLength); |
| |
| while (retries < 3) { |
| rc = write(spiDeviceId, txBuffer, txBufferLength); |
| |
| if (rc < 0) { |
| int e = errno; |
| |
| /* unexpected result */ |
| char msg[LINUX_DBGBUFFER_SIZE]; |
| strerror_r(e, msg, LINUX_DBGBUFFER_SIZE); |
| STLOG_HAL_E("## Spiwrite returns %d errno %d (%s)", rc, e, msg); |
| /* delays are different and increasing for the three retries. */ |
| static const uint8_t delayTab[] = {2, 3, 5}; |
| int delay = delayTab[retries]; |
| |
| retries++; |
| usleep(delay * 1000); |
| STLOG_HAL_W("## SpiWrite retry %d/3 in %d milliseconds.", retries, |
| delay); |
| |
| } else if (rc > 0) { |
| gettimeofday(&lastRxTxTime, 0); |
| return rc; |
| } else { |
| STLOG_HAL_W("write on spi failed, retrying\n"); |
| usleep(4000); |
| retries++; |
| } |
| } |
| |
| gettimeofday(&lastRxTxTime, 0); |
| return rc; |
| } |
| |
| /******************************************************************************* |
| ** |
| ** Function SpiLayerDriver_reset |
| ** |
| ** Description Send a Reset pulse to the eSE. |
| ** |
| ** Parameters none |
| ** |
| ** Returns O if success, -1 otherwise |
| ** |
| *******************************************************************************/ |
| int SpiLayerDriver_reset() { |
| int rc = ioctl(spiDeviceId, ST54J_SE_PULSE_RESET, NULL); |
| if (rc < 0) { |
| char msg[LINUX_DBGBUFFER_SIZE]; |
| |
| strerror_r(errno, msg, LINUX_DBGBUFFER_SIZE); |
| STLOG_HAL_E("! Se reset!!, errno is '%s'", msg); |
| } |
| return rc; |
| } |