/************************************************************************************//** * \file port/windows/serialport.c * \brief Serial port source file. * \ingroup Session * \internal *---------------------------------------------------------------------------------------- * C O P Y R I G H T *---------------------------------------------------------------------------------------- * Copyright (c) 2017 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 /* for assertions */ #include /* for standard integer types */ #include /* for NULL declaration */ #include /* for boolean type */ #include /* for windows library */ #include "serialport.h" /* serial port module */ /**************************************************************************************** * Macro definitions ****************************************************************************************/ #define UART_TX_BUFFER_SIZE (1024u) /**< transmission buffer size */ #define UART_RX_BUFFER_SIZE (1024u) /**< reception buffer size */ /**************************************************************************************** * Local data declarations ****************************************************************************************/ /** \brief Serial port handle. */ static HANDLE hUart; /**************************************************************************************** * Function prototypes ****************************************************************************************/ static uint32_t SerialConvertBaudrate(tSerialPortBaudrate baudrate); /************************************************************************************//** ** \brief Initializes the serial port module. ** ****************************************************************************************/ void SerialPortInit(void) { /* Invalidate the port handle. */ hUart = INVALID_HANDLE_VALUE; } /*** end of SerialPortInit ***/ /************************************************************************************//** ** \brief Terminates the serial port module. ** ****************************************************************************************/ void SerialPortTerminate(void) { /* Make sure the serial port is closed. */ SerialPortClose(); } /*** end of SerialPortTerminate ***/ /************************************************************************************//** ** \brief Opens the connection with the serial port configured as 8,N,1 and no flow ** control. ** \param portname The name of the serial port to open, i.e. COM4. ** \param baudrate The desired communication speed. ** \return True if successful, false otherwise. ** ****************************************************************************************/ bool SerialPortOpen(char const * portname, tSerialPortBaudrate baudrate) { bool result = false; COMMTIMEOUTS timeouts = { 0 }; DCB dcbSerialParams = { 0 }; char portStr[64] = "\\\\.\\"; /* Check parameters. */ assert(portname != NULL); /* Only continue if parameters are valid. */ if (portname != NULL) { /* Assume the result to be okay from here on and only set it to error when a problem * was detected. */ result = true; /* Construct the COM port name as a string. */ strcat(portStr, portname); /* 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) { result = false; } /* Get current COM port configuration. */ if (result) { dcbSerialParams.DCBlength = sizeof(dcbSerialParams); if (!GetCommState(hUart, &dcbSerialParams)) { (void)CloseHandle(hUart); result = false; } } /* Configure the baudrate and 8,n,1. */ if (result) { dcbSerialParams.BaudRate = SerialConvertBaudrate(baudrate); dcbSerialParams.ByteSize = 8; dcbSerialParams.StopBits = ONESTOPBIT; dcbSerialParams.Parity = NOPARITY; dcbSerialParams.fOutX = FALSE; dcbSerialParams.fInX = FALSE; dcbSerialParams.fRtsControl = RTS_CONTROL_DISABLE; dcbSerialParams.fDtrControl = DTR_CONTROL_ENABLE; if (!SetCommState(hUart, &dcbSerialParams)) { (void)CloseHandle(hUart); result =false; } } /* Set communication timeout parameters. */ if (result) { timeouts.ReadIntervalTimeout = 0; timeouts.ReadTotalTimeoutConstant = 0; timeouts.ReadTotalTimeoutMultiplier = 100; timeouts.WriteTotalTimeoutConstant = 0; timeouts.WriteTotalTimeoutMultiplier = 100; if (!SetCommTimeouts(hUart, &timeouts)) { (void)CloseHandle(hUart); result = false; } } /* Set transmit and receive buffer sizes. */ if (result) { if (!SetupComm(hUart, UART_RX_BUFFER_SIZE, UART_TX_BUFFER_SIZE)) { (void)CloseHandle(hUart); result = false; } } /* Empty the transmit and receive buffers. */ if (result) { if (!FlushFileBuffers(hUart)) { (void)CloseHandle(hUart); result = false; } } } /* Give the result back to the caller. */ return result; } /*** end of SerialPortOpen ***/ /************************************************************************************//** ** \brief Closes the connection with the serial port. ** ****************************************************************************************/ void SerialPortClose(void) { /* Close the COM port handle if valid. */ if (hUart != INVALID_HANDLE_VALUE) { (void)CloseHandle(hUart); } /* Set handles to invalid. */ hUart = INVALID_HANDLE_VALUE; } /*** end of SerialPortClose ***/ /************************************************************************************//** ** \brief Writes data to the serial port. ** \param data Pointer to byte array with data to write. ** \param length Number of bytes to write. ** \return True if successful, false otherwise. ** ****************************************************************************************/ bool SerialPortWrite(uint8_t const * data, uint32_t length) { bool result = false; DWORD dwWritten = 0; /* Check parameters. */ assert(data != NULL); assert(length > 0); /* Only continue with valid parameters. */ if ( (data != NULL) && (length > 0) ) { /* Submit the data for transmission with the serial port. */ if (WriteFile(hUart, data, length, &dwWritten, NULL)) { /* Double check that all bytes were actually transmitted. */ if (dwWritten == length) { result = true; } } } /* Give the result back to the caller. */ return result; } /*** end of SerialPortWrite ***/ /************************************************************************************//** ** \brief Reads data from the serial port in a blocking manner. ** \param data Pointer to byte array to store read data. ** \param length Number of bytes to read. ** \return True if successful, false otherwise. ** ****************************************************************************************/ bool SerialPortRead(uint8_t * data, uint32_t length) { bool result = false; DWORD dwRead = 0; /* Check parameters. */ assert(data != NULL); assert(length > 0); /* Only continue with valid parameters. */ if ( (data != NULL) && (length > 0) ) { /* Attempt to read data from the serial port. */ if (ReadFile(hUart, data, length, &dwRead, NULL)) { /* Double check that all bytes were actually read. */ if (dwRead == length) { result = true; } } } /* Give the result back to the caller. */ return result; } /*** end of SerialPortRead ***/ /************************************************************************************//** ** \brief Opens the connection with the serial port configured as 8,N,1 and no flow ** control. ** \param baudrate The desired communication speed. ** \return True if successful, false otherwise. ** ****************************************************************************************/ static uint32_t SerialConvertBaudrate(tSerialPortBaudrate baudrate) { uint32_t result; switch (baudrate) { case SERIALPORT_BR9600: result = CBR_9600; break; case SERIALPORT_BR19200: result = CBR_19200; break; case SERIALPORT_BR38400: result = CBR_38400; break; case SERIALPORT_BR57600: result = CBR_57600; break; case SERIALPORT_BR115200: result = CBR_115200; break; default: result = CBR_9600; break; } return result; } /*** end of SerialConvertBaudrate ***/ /*********************************** end of serialport.c *******************************/