/************************************************************************************//** * \file port\win32\xcptransport.c * \brief XCP transport layer interface source file. * \ingroup SerialBoot * \internal *---------------------------------------------------------------------------------------- * C O P Y R I G H T *---------------------------------------------------------------------------------------- * Copyright (c) 2014 by Feaser http://www.feaser.com All rights reserved * *---------------------------------------------------------------------------------------- * L I C E N S E *---------------------------------------------------------------------------------------- * This file is part of OpenBLT. OpenBLT is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any later * version. * * OpenBLT is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR * PURPOSE. See the GNU General Public License for more details. * * You have received a copy of the GNU General Public License along with OpenBLT. It * should be located in ".\Doc\license.html". If not, contact Feaser to obtain a copy. * * \endinternal ****************************************************************************************/ /**************************************************************************************** * Include files ****************************************************************************************/ #include /* assertion module */ #include /* C types */ #include /* for WIN32 library */ #include /* string library */ #include "xcpmaster.h" /* XCP master protocol module */ #include "timeutil.h" /* time utility module */ /**************************************************************************************** * Macro definitions ****************************************************************************************/ #define UART_TX_BUFFER_SIZE (1024) /**< transmission buffer size */ #define UART_RX_BUFFER_SIZE (1024) /**< reception buffer size */ /** \brief maximum number of bytes in a transmit/receive XCP packet in UART. */ #define XCP_MASTER_UART_MAX_DATA ((XCP_MASTER_TX_MAX_DATA>XCP_MASTER_RX_MAX_DATA) ? \ (XCP_MASTER_TX_MAX_DATA+1) : (XCP_MASTER_RX_MAX_DATA+1)) /** \brief The smallest time in millisecond that the UART is configured for. */ #define UART_RX_TIMEOUT_MIN_MS (5) /**************************************************************************************** * Local data declarations ****************************************************************************************/ static tXcpTransportResponsePacket responsePacket; static HANDLE hUart = INVALID_HANDLE_VALUE; /************************************************************************************//** ** \brief Initializes the communication interface used by this transport layer. ** \param device Serial communication device name. For example "COM4". ** \param baudrate Communication speed in bits/sec. ** \return SB_TRUE if successful, SB_FALSE otherwise. ** ****************************************************************************************/ sb_uint8 XcpTransportInit(sb_char *device, sb_uint32 baudrate) { COMMTIMEOUTS timeouts = { 0 }; DCB dcbSerialParams = { 0 }; char portStr[64] = "\\\\.\\\0"; /* construct the COM port name as a string */ strcat_s(portStr, 59, device); /* obtain access to the COM port */ hUart = CreateFile(portStr, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); /* validate COM port handle */ if (hUart == INVALID_HANDLE_VALUE) { return SB_FALSE; } /* get current COM port configuration */ dcbSerialParams.DCBlength = sizeof(dcbSerialParams); if (!GetCommState(hUart, &dcbSerialParams)) { XcpTransportClose(); return SB_FALSE; } /* configure the baudrate and 8,n,1 */ dcbSerialParams.BaudRate = baudrate; dcbSerialParams.ByteSize = 8; dcbSerialParams.StopBits = ONESTOPBIT; dcbSerialParams.Parity = NOPARITY; if (!SetCommState(hUart, &dcbSerialParams)) { XcpTransportClose(); return SB_FALSE; } /* set communication timeout parameters */ timeouts.ReadIntervalTimeout = UART_RX_TIMEOUT_MIN_MS; timeouts.ReadTotalTimeoutConstant = UART_RX_TIMEOUT_MIN_MS; timeouts.ReadTotalTimeoutMultiplier = 1; timeouts.WriteTotalTimeoutConstant = UART_RX_TIMEOUT_MIN_MS; timeouts.WriteTotalTimeoutMultiplier = 1; if (!SetCommTimeouts(hUart, &timeouts)) { XcpTransportClose(); return SB_FALSE; } /* set transmit and receive buffer sizes */ if(!SetupComm(hUart, UART_RX_BUFFER_SIZE, UART_TX_BUFFER_SIZE)) { XcpTransportClose(); return SB_FALSE; } /* empty the transmit and receive buffers */ if (!FlushFileBuffers(hUart)) { XcpTransportClose(); return SB_FALSE; } /* successfully connected to the serial device */ return SB_TRUE; } /*** end of XcpTransportInit ***/ /************************************************************************************//** ** \brief Transmits an XCP packet on the transport layer and attemps to receive the ** response within the given timeout. The data in the response packet is ** stored in an internal data buffer that can be obtained through function ** XcpTransportReadResponsePacket(). ** \return SB_TRUE is the response packet was successfully received and stored, ** SB_FALSE otherwise. ** ****************************************************************************************/ sb_uint8 XcpTransportSendPacket(sb_uint8 *data, sb_uint8 len, sb_uint16 timeOutMs) { sb_uint32 dwWritten = 0; sb_uint32 dwRead = 0; sb_uint32 dwToRead; sb_uint16 cnt; static sb_uint8 xcpUartBuffer[XCP_MASTER_UART_MAX_DATA]; /* static to lower stack load */ sb_uint16 xcpUartLen; sb_uint8 *uartReadDataPtr; sb_uint32 timeoutTime; /* ------------------------ XCP packet transmission -------------------------------- */ /* prepare the XCP packet for transmission on UART. this is basically the same as the * xcp packet data but just the length of the packet is added to the first byte. */ xcpUartLen = len+1; xcpUartBuffer[0] = len; for (cnt=0; cnt 0) { dwRead = 0; if (ReadFile(hUart, uartReadDataPtr, dwToRead, &dwRead, NULL)) { /* update the bytes that were already read */ uartReadDataPtr += dwRead; dwToRead -= dwRead; } /* check for timeout if not yet done */ if ( (dwToRead > 0) && (TimeUtilGetSystemTimeMs() >= timeoutTime) ) { /* timeout occurred */ return SB_FALSE; } } /* read the rest of the packet */ dwToRead = responsePacket.len; uartReadDataPtr = &responsePacket.data[0]; while(dwToRead > 0) { dwRead = 0; if (ReadFile(hUart, uartReadDataPtr, dwToRead, &dwRead, NULL)) { /* update the bytes that were already read */ uartReadDataPtr += dwRead; dwToRead -= dwRead; } /* check for timeout if not yet done */ if ( (dwToRead > 0) && (TimeUtilGetSystemTimeMs() >= timeoutTime) ) { /* timeout occurred */ return SB_FALSE; } } /* still here so the complete packet was received */ return SB_TRUE; } /*** end of XcpMasterTpSendPacket ***/ /************************************************************************************//** ** \brief Reads the data from the response packet. Make sure to not call this ** function while XcpTransportSendPacket() is active, because the data won't be ** valid then. ** \return Pointer to the response packet data. ** ****************************************************************************************/ tXcpTransportResponsePacket *XcpTransportReadResponsePacket(void) { return &responsePacket; } /*** end of XcpTransportReadResponsePacket ***/ /************************************************************************************//** ** \brief Closes the communication channel. ** \return none. ** ****************************************************************************************/ void XcpTransportClose(void) { /* close the COM port handle if valid */ if (hUart != INVALID_HANDLE_VALUE) { CloseHandle(hUart); } /* set handles to invalid */ hUart = INVALID_HANDLE_VALUE; } /*** end of XcpTransportClose ***/ /*********************************** end of xcptransport.c *****************************/