| /****************************************************************************** |
| * |
| * 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. |
| * |
| * |
| ******************************************************************************/ |
| #ifndef _T1PROTOCOL_H_ |
| #define _T1PROTOCOL_H_ |
| |
| #include <stdbool.h> |
| #include <stdint.h> |
| #include <stdlib.h> |
| #include "SpiLayerInterface.h" |
| #include "StEseApi.h" |
| #include "utils-lib/Tpdu.h" |
| |
| // Recovery states |
| #define RECOVERY_STATUS_OK 0 |
| #define RECOVERY_STATUS_RESEND_1 1 |
| #define RECOVERY_STATUS_RESEND_2 2 |
| #define RECOVERY_STATUS_RESYNC_1 3 |
| #define RECOVERY_STATUS_RESYNC_2 4 |
| #define RECOVERY_STATUS_RESYNC_3 5 |
| #define RECOVERY_STATUS_WARM_RESET 6 |
| #define RECOVERY_STATUS_KO 7 |
| |
| // Apdu modes |
| #define APDU_PART_IS_LAST true |
| #define APDU_PART_IS_NOT_LAST false |
| |
| // SBlock types |
| #define SBLOCK_WTX_REQUEST_MASK 0b11000011 |
| #define SBLOCK_WTX_RESPONSE_MASK 0b11100011 |
| #define SBLOCK_IFS_REQUEST_MASK 0b11000001 |
| #define SBLOCK_IFS_RESPONSE_MASK 0b11100001 |
| #define SBLOCK_ABORT_REQUEST_MASK 0b11000010 |
| #define SBLOCK_ABORT_RESPONSE_MASK 0b11100010 |
| #define SBLOCK_RESYNCH_REQUEST_MASK 0b11000000 |
| #define SBLOCK_RESYNCH_RESPONSE_MASK 0b11100000 |
| #define SBLOCK_SWRESET_REQUEST_MASK 0b11001111 |
| #define SBLOCK_SWRESET_RESPONSE_MASK 0b11101111 |
| |
| // IBlock parameters |
| #define IBLOCK_M_BIT_MASK 0b00100000 |
| #define IBLOCK_NS_BIT_MASK 0b01000000 |
| |
| #define DEFAULT_NBWT 1 |
| |
| // Global variables |
| // uint8_t SEQ_NUM_MASTER; |
| // uint8_t SEQ_NUM_SLAVE; |
| // bool firstTransmission; |
| // uint8_t recoveryStatus; |
| // bool aborted; |
| // uint8_t IFSD; |
| |
| typedef enum { |
| Idle = 0, |
| I_block, |
| R_ACK, |
| R_CRC_Error, |
| R_Other_Error, |
| S_Resync_REQ, |
| S_Resync_RES, |
| S_IFS_REQ, |
| S_IFS_RES, |
| S_WTX_RES, |
| S_SWReset_REQ |
| } T1TProtocol_TransceiveState; |
| /** |
| * Form a valid pcb according to the Tpdu type, subtype, master sequence number, |
| * slave sequence number and isLast. |
| * |
| * @param type The Tpdu type (IBlock, RBlock or SBlock). |
| * @param subtype The different subtype options when using RBlock. Error free, |
| * checksum error or other errors. |
| * @param numSeqMaster Master sequence number. |
| * @param numseqSlave Slave sequence number. |
| * @param isLast Indicate if there are more tpdus to send within the same APDU. |
| * |
| * @return pcb The value of the pcb computed. |
| */ |
| uint8_t T1protocol_getValidPcb(TpduType type, RBlockType subtype, |
| uint8_t numSeqMaster, uint8_t numseqSlave, |
| bool isLast); |
| |
| /** |
| * Check if the checksum of a given tpdu is well formed. |
| * |
| * @param tpdu Tpdu to check. |
| * |
| * @return 0 If checksum is ok, -1 otherwise. |
| */ |
| int T1protocol_checkResponseTpduChecksum(Tpdu *tpdu); |
| |
| /** |
| * Check if the pcb of a given tpdu is valid. |
| * |
| * @param tpdu Tpdu to check. |
| * |
| * @return 0 If checksum is ok, -1 otherwise. |
| */ |
| int T1protocol_checkResponsePcbConsistency(Tpdu *tpdu); |
| |
| /** |
| * Check if the length field of a given tpdu is valid. |
| * |
| * @param tpdu Tpdu to check. |
| * |
| * @return 0 If checksum is ok, -1 otherwise. |
| */ |
| int T1protocol_checkResponseLenConsistency(Tpdu *tpdu); |
| |
| /** |
| * Check if the sequence number of a given tpdu is valid. |
| * |
| * @param tpdu Tpdu to check. |
| * |
| * @return 0 If checksum is ok, -1 otherwise. |
| */ |
| int T1protocol_checkResponseSeqNumberConsistency(Tpdu *tpdu); |
| |
| /** |
| * Check if an SBlock response was received after having transmitted a SBlock |
| * request. |
| * |
| * @param lastCmdTpduSent Last Tpdu sent. |
| * @param lastRespTpduReceived Response received. |
| * |
| * @return 0 If checksum is ok, -1 otherwise. |
| */ |
| int T1protocol_checkSBlockResponseConsistency(Tpdu *lastCmdTpduSent, |
| Tpdu *lastRespTpduReceived); |
| |
| /** |
| * Check if the response TPDU is consistent (check the checksum, check if the |
| * pcb is valid and the expected one and check the len consistency). |
| * |
| * @param lastCmdTpduSent Last Tpdu sent, could be different than the |
| * originalCmdTpdu if there was retransmissions request or SBlocks. |
| * @param lastRespTpduReceived Last response received from the slave. |
| * |
| * @return 0 If consistency is ok, -1 otherwise. |
| */ |
| int T1protocol_checkTpduConsistency(Tpdu *lastCmdTpduSent, |
| Tpdu *lastRespTpduReceived); |
| |
| /** |
| * Set the sequence numbers to it's initial values. |
| */ |
| void T1protocol_resetSequenceNumbers(); |
| |
| /** |
| * Update the master sequence number. Increase the value, taking into account is |
| * module 2 type. |
| */ |
| void T1protocol_updateMasterSequenceNumber(); |
| |
| /** |
| * Update the slave sequence number. Increase the value, taking into account is |
| * module 2 type. |
| */ |
| void T1protocol_updateSlaveSequenceNumber(); |
| |
| /** |
| * Process the last IBlock received from the slave. |
| * |
| * @param originalCmdTpdu Original Tpdu sent. |
| * @param lastRespTpduReceived Last response received from the slave. |
| * |
| * @return 0 If all went is ok, -1 otherwise. |
| */ |
| int T1protocol_processIBlock(Tpdu* originalCmdTpdu, Tpdu* lastRespTpduReceived); |
| |
| /** |
| * Process the last RBlock received from the slave. |
| * |
| * @param originalCmdTpdu Original Tpdu sent. |
| * @param lastRespTpduReceived Last response received from the slave. |
| * |
| */ |
| void T1protocol_processRBlock(Tpdu *originalCmdTpdu, |
| Tpdu *lastRespTpduReceived); |
| |
| /** |
| * Process the last RBlock received from the slave. |
| * |
| * @param rack if 1, send a ack frame, nack otherwise. |
| * @param lastRespTpduReceived Last response received from the slave. |
| * |
| * @return -1 if the retransmission needed fails, 0 if no more retransmission |
| * were needed and 1 if extra retransmission success. |
| */ |
| int T1protocol_sendRBlock(int rack, Tpdu *lastRespTpduReceived); |
| |
| /** |
| * Form a SBlock response according to a given SBlock Request. |
| * |
| * @param responseTpdu A valid SBlock response according to the SBlock request |
| * in the requestTpdu param. |
| * @param requestTpdu The Sblock request received from the eSE to process. |
| * |
| * @return 0 If all went is ok, -1 otherwise. |
| */ |
| int T1protocol_formSblockResponse(Tpdu *responseTpdu, Tpdu *requestTpdu); |
| |
| /** |
| * Process the last SBlock received from the slave. |
| * |
| * @param originalCmdTpdu Original Tpdu sent. |
| * @param lastCmdTpduSent Last Tpdu sent, could be different than the |
| * originalCmdTpdu if there was retransmissions request or SBlocks. |
| * @param lastRespTpduReceived Last response received from the slave. |
| * |
| * @return -1 if the extra retransmission needed fails or 1 if extra |
| * retransmission success. |
| */ |
| int T1protocol_processSBlock(Tpdu *originalCmdTpdu, Tpdu *lastCmdTpduSent, |
| Tpdu *lastRespTpduReceived); |
| |
| /** |
| * Check if the sequence number of the response TPDU is the expected one. |
| * |
| * @param originalTpdu The original tpdu sent. |
| * @param respTpdu The last response received from the slave. |
| * |
| * @return true If sequence number is ok, false otherwise. |
| */ |
| bool T1protocol_isSequenceNumberOk(Tpdu *originalTpdu, Tpdu *respTpdu); |
| |
| /** |
| * Updates the recovery state to the following step. |
| */ |
| void T1protocol_updateRecoveryStatus(); |
| |
| /** |
| * Copy the data in the response Tpdu into the respApduBuffer. |
| * |
| * @param respTpdu Response tpdu where the data is stored. |
| * @param respApduBuffer Apdu buffer where to store the data received in the |
| * response Tpdu. |
| * |
| * @return The amount of data bytes saved into the apdu buffer. |
| */ |
| uint8_t T1protocol_setRespApduData(Tpdu *respTpdu, uint8_t *respApduBuffer); |
| |
| /** |
| * If the eSE send a S(WTX request), acknowledge it by sending |
| * a S(WTX response) |
| * |
| * @param lastRespTpduReceived Last response received from the slave. |
| * |
| * @return bytesRead if data was read, 0 if timeout expired with |
| * no response, -1 otherwise |
| */ |
| int T1protocol_doWTXResponse(Tpdu *lastRespTpduReceived); |
| |
| /** |
| * The first thing to do in the recovery mechanism is to ask for a |
| * retransmission. |
| * |
| * @param lastCmdTpduSent Last Tpdu sent, could be different than the |
| * originalCmdTpdu if there was retransmissions request or SBlocks. |
| * @param lastRespTpduReceived Last response received from the slave. |
| * @param bytesRead If a retransmission occurs, this field contains the amout of |
| * bytes read from the slave in the new transaction. |
| * |
| * @return 0 if everything went fine, -1 if something failed. |
| */ |
| int T1protocol_doResendRequest(Tpdu *lastCmdTpduSent, |
| Tpdu *lastRespTpduReceived, int *bytesRead); |
| |
| /** |
| * The second thing to do in the recovery mechanism if the resend fails |
| * is to perform a Resync. |
| * |
| * @param lastCmdTpduSent Last Tpdu sent, could be different than the |
| * originalCmdTpdu if there was retransmissions request or SBlocks. |
| * @param lastRespTpduReceived Last response received from the slave. |
| * @param bytesRead If a retransmission occurs, this field contains the amout of |
| * bytes read from the slave in the new transaction. |
| * |
| * @return 0 if everything went fine, -1 if something failed. |
| */ |
| int T1protocol_doResyncRequest(Tpdu *lastRespTpduReceived); |
| |
| /** |
| * Implements the recovery mechanism when a non-consistent TPDU has been |
| * received or no response has been received before the timeout. |
| * |
| * @param lastCmdTpduSent Last Tpdu sent, could be different than the |
| * originalCmdTpdu if there was retransmissions request or SBlocks. |
| * @param lastRespTpduReceived Last response received from the slave. |
| * @param bytesRead If a retransmission occurs, this field contains the amout of |
| * bytes read from the slave in the new transaction. |
| * |
| * @return 0 if everything went fine, |
| * -1 if something failed, or |
| * RC_WARM_RESET_REQUIERD if a warm reset needs to be performed. |
| * TODO: If a warm reset needs to be performed, the service will die |
| * and the user will need do the reset manually, as Power Manager is not |
| * yet implemented. |
| */ |
| int T1protocol_doRecovery(); |
| |
| /** |
| * Send a soft reset (S-Block) |
| * |
| * @param lastRespTpduReceived Last response received from the slave. |
| * |
| * @return 0 if everything went fine, -1 if an error occurred. |
| */ |
| int T1protocol_doSoftReset(Tpdu *lastRespTpduReceived); |
| |
| /** |
| * Send IFS request(S-Block) |
| * |
| * @param None. |
| * |
| * @return 0 if everything went fine, -1 if an error occurred. |
| */ |
| int T1protocol_doRequestIFS(); |
| |
| /** |
| * Handles any TPDU response iteratively. |
| * |
| * @param originalCmdTpdu Original Tpdu sent. |
| * @param lastCmdTpduSent Last Tpdu sent, could be different than the |
| * originalCmdTpdu if there was retransmissions request or SBlocks. |
| * @param lastRespTpduReceived Last response received from the slave. |
| * @param bytesRead If a retransmission occurs, this field contains the amout of |
| * bytes read from the slave in the new transaction. |
| * |
| * @return 0 if everything went fine, -1 if an error occurred. |
| */ |
| int T1protocol_handleTpduResponse(Tpdu *originalCmdTpdu, Tpdu *lastCmdTpduSent, |
| Tpdu *lastRespTpduReceived, int *bytesRead); |
| |
| /** |
| * Form a valid Tpdu to send according to the if we need to send |
| * an IBlock or a RBlock (for chained response from the slave). |
| * |
| * @param cmdApduPart Data to sent within an IBlock. |
| * @param cmdLength Amount of data to sent. |
| * @param isLast Flag indicating if there are more data to send. |
| * @param cmdTpdu Resulting Tpdu. |
| * |
| * @return 0 if everything went fine, -1 if something failed. |
| */ |
| int T1protocol_formCommandTpduToSend(uint8_t *cmdApduPart, uint8_t cmdLength, |
| bool isLast, Tpdu *cmdTpdu); |
| |
| /** |
| * Initializes the T1 Protocol. |
| * |
| * @return 0 if initialization was ok, -1 otherwise. |
| */ |
| int T1protocol_init(SpiDriver_config_t *tSpiDriver); |
| |
| /** |
| * This method is used to send and/or receive an APDU part. There are 3 ways of |
| * calling it: |
| * 1. transcieveApduPart(&cmdApduPart, cmdLength, APDU_PART_IS_NOT_LAST, null, |
| * null): will send an APDU part and expect no response. |
| * 2. transcieveApduPart(&cmdApduPart, cmdLength, APDU_PART_IS_LAST, |
| * &respApduPart, &respLength): will send an APDU part and get a response |
| * part. |
| * 3. transcieveApduPart(null, null, null, &respApduPart, &respLength): sends no |
| * APDU part and gets a response part. |
| * |
| * It will for and send the required TPDU, receive the response and handle it. |
| * |
| * @param cmdApduPart The cmdApdu part that shall be sent (or null). |
| * @param cmdLength The length of the cmdApduPart to be sent (or null). |
| * @param isLast Either APDU_PART_IS_NOT_LAST or APDU_PART_IS_LAST (or null). |
| * @param pRsp Structure to the response buffer and length. |
| * (or null). |
| * |
| * @return If no response is expected: |
| * - 0 if everything was ok |
| * - -1 if an error occurred |
| * If response is expected: |
| * - 0 if it is the last response part |
| * - 1 if there are more response parts |
| * - -1 if an error occurred. |
| */ |
| int T1protocol_transcieveApduPart(uint8_t *cmdApduPart, uint8_t cmdLength, |
| bool isLast, StEse_data *pRsp); |
| |
| #endif /* _T1PROTOCOL_H_ */ |