/****************************************************************************** * * 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. * * ******************************************************************************/ #include "Tpdu.h" #include "Iso13239CRC.h" /******************************************************************************* ** ** Function Tpdu_toByteArray ** ** Description Forms a byte array representing the given TPDU. ** ** Parameters structTpdu - TPDU struct to be converted to byte array. ** baTpdu - Memory position where to store the formed ** byte array. ** ** Returns length of the formed array, -1 if there is an error. ** *******************************************************************************/ uint16_t Tpdu_toByteArray(Tpdu *structTpdu, uint8_t *baTpdu) { // NAD - Copy the nad into the nad array position baTpdu[NAD_OFFSET_IN_TPDU] = structTpdu->nad; // PCB - Copy the pcb into the pcb array position baTpdu[PCB_OFFSET_IN_TPDU] = structTpdu->pcb; // Length - Copy the length into the length array position baTpdu[LEN_OFFSET_IN_TPDU] = structTpdu->len; // Data - Copy the data into the data array position uint8_t i; for (i = 0; i < structTpdu->len; i++) { baTpdu[DATA_OFFSET_IN_TPDU + i] = structTpdu->data[i]; } // Compute where the checksum shall be stored. uint16_t checksumOffsetInTpdu = DATA_OFFSET_IN_TPDU + structTpdu->len; uint16_t length; uint8_t checksum[2]; switch (ATP.checksumType) { case LRC: Tpdu_getChecksumBytes(structTpdu, checksum); baTpdu[checksumOffsetInTpdu] = checksum[0]; length = checksumOffsetInTpdu + 1; break; case CRC: default: Tpdu_getChecksumBytes(structTpdu, checksum); baTpdu[checksumOffsetInTpdu] = checksum[0]; baTpdu[checksumOffsetInTpdu + 1] = checksum[1]; length = checksumOffsetInTpdu + 2; break; } return length; } /******************************************************************************* ** ** Function Tpdu_isChecksumOk ** ** Description Checks that the checksum in the TPDU is as expected. ** ** Parameters tpdu - TPDU whose checksum needs to be checked. ** ** Returns true if checksum is ok, false otherwise. ** *******************************************************************************/ bool Tpdu_isChecksumOk(Tpdu *tpdu) { switch (ATP.checksumType) { case LRC: // TODO: implement return false; case CRC:; uint8_t buffer[TPDU_MAX_LENGTH]; Tpdu_toByteArray(tpdu, buffer); if (tpdu->checksum == computeCrc(buffer, (TPDU_PROLOGUE_LENGTH + tpdu->len))) { return true; } else { return false; } } } /******************************************************************************* ** ** Function Tpdu_formTpdu ** ** Description Forms a TPDU with the specified fields. ** ** Parameters nad - NAD byte of the TPDU. ** pcb - PCB byte of the TPDU. ** len - Length of the data ** data - data of the TPDU ** tpdu - output TPDU struct ** ** Returns 0 if everything went ok, -1 otherwise. ** *******************************************************************************/ int Tpdu_formTpdu(uint8_t nad, uint8_t pcb, uint8_t len, uint8_t *data, Tpdu *tpdu) { uint8_t i; if (len > TPDU_MAX_DATA_LENGTH) { return -1; } // NAD - Copy the incoming nad into the tpdu nad tpdu->nad = nad; // PCB - Copy the incoming pcb into the tpdu pcb tpdu->pcb = pcb; // Length - Copy the incoming len into the tpdu len tpdu->len = len; // Data - Copy the incoming data into the tpdu data // TODO: check if it will ever be overwritten for (i = 0; i < len; i++) { tpdu->data[i] = data[i]; } // tpdu->data = data; // Checksum - Calculate the checksum according to the prologue + data fields // and copy into the tpdu checksum switch (ATP.checksumType) { case LRC: // TODO: implement return -1; case CRC: // Set temporally checksum to 0 to be able to convert the tpdu struct // to an array tpdu->checksum = 0; // Create a buffer to store the tpdu to compute the CRC. uint8_t buffer[TPDU_MAX_LENGTH]; Tpdu_toByteArray(tpdu, buffer); // Calculate the crc tpdu->checksum = computeCrc(buffer, (TPDU_PROLOGUE_LENGTH + tpdu->len)); break; } return 0; } /******************************************************************************* ** ** Function Tpdu_getChecksumBytes ** ** Description Get the checksum value in the form of a byte array. ** ** Parameters tpdu - TPDU from where to get the checksum value. ** checksumBytes - mem postion whre to store the result. ** ** Returns void ** *******************************************************************************/ void Tpdu_getChecksumBytes(Tpdu *tpdu, uint8_t *checksumBytes) { switch (ATP.checksumType) { case LRC: checksumBytes[0] = (uint8_t)tpdu->checksum; break; case CRC: checksumBytes[0] = (uint8_t)tpdu->checksum; checksumBytes[1] = (uint8_t)(tpdu->checksum >> 8); break; } } /******************************************************************************* ** ** Function Tpdu_getChecksumValue ** ** Description Gets the value of the checksum stored in the array. ** ** Parameters array - array that contains the checksum. ** checksumStartPosition ** checksumType -Checksum type (LRC or CRC) ** ** Returns checksum value ** *******************************************************************************/ uint16_t Tpdu_getChecksumValue(uint8_t *array, int checksumStartPosition, ChecksumType checksumType) { switch (checksumType) { case LRC: return (uint16_t)array[checksumStartPosition]; case CRC: return (uint16_t)(array[checksumStartPosition + 1] << 8) | array[checksumStartPosition]; } } /******************************************************************************* ** ** Function Tpdu_getType ** ** Description Returns the type of the TPDU. ** ** Parameters tpdu - the tpdu the type has to be get. ** ** Returns TPDU type (I-Block, R-Block or S-Block) ** *******************************************************************************/ TpduType Tpdu_getType(Tpdu *tpdu) { if ((tpdu->pcb & 0x80) == 0x00) { return IBlock; } else if ((tpdu->pcb & 0xC0) == 0x80) { return RBlock; } else { return SBlock; } } /******************************************************************************* ** ** Function Tpdu_copy ** ** Description Copy a Tpdu Struct to an another one. ** ** Parameters dest - the destination tpdu ** src - the tpdu to be copied ** ** Returns void ** *******************************************************************************/ void Tpdu_copy(Tpdu *dest, Tpdu *src) { dest->checksum = src->checksum; dest->len = src->len; dest->nad = src->nad; dest->pcb = src->pcb; if (dest->data == NULL) { dest->data = (uint8_t *)malloc(ATP.ifsc * sizeof(uint8_t)); } if (((src->len) > 0) && ((src->len) < ATP.ifsc)) { memcpy(dest->data, src->data, src->len); } } /******************************************************************************* ** ** Function Tpdu_toHexString ** ** Description Converts the TPDU in hex string buffer. ** ** Parameters tpdu - input tpdu ** hexStringBuffer - output hex buffer ** ** ** Returns void ** *******************************************************************************/ void Tpdu_toHexString(Tpdu *tpdu, uint8_t *hexStringBuffer) { uint8_t buffer[tpdu->len + 5]; uint16_t length = Tpdu_toByteArray(tpdu, buffer); char *ptr = (char *)hexStringBuffer; int i; for (i = 0; i < length; i++) { ptr += sprintf(ptr, "%02X ", (char)buffer[i]); } }