You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
270 lines
5.2 KiB
C
270 lines
5.2 KiB
C
/*
|
|
* serial_port_win32.c
|
|
*
|
|
* Copyright 2013-2021 Michael Zillgith
|
|
*
|
|
* This file is part of Platform Abstraction Layer (libpal)
|
|
* for libiec61850, libmms, and lib60870.
|
|
*/
|
|
|
|
#include <stdint.h>
|
|
#include <stdio.h>
|
|
|
|
#include <windows.h>
|
|
|
|
#include "lib_memory.h"
|
|
|
|
#include "hal_serial.h"
|
|
#include "hal_time.h"
|
|
|
|
struct sSerialPort {
|
|
char interfaceName[100];
|
|
HANDLE comPort;
|
|
int baudRate;
|
|
uint8_t dataBits;
|
|
char parity;
|
|
uint8_t stopBits;
|
|
uint64_t lastSentTime;
|
|
int timeout;
|
|
SerialPortError lastError;
|
|
};
|
|
|
|
SerialPort
|
|
SerialPort_create(const char* interfaceName, int baudRate, uint8_t dataBits, char parity, uint8_t stopBits)
|
|
{
|
|
SerialPort self = (SerialPort)GLOBAL_MALLOC(sizeof(struct sSerialPort));
|
|
|
|
if (self != NULL) {
|
|
self->comPort = NULL;
|
|
self->baudRate = baudRate;
|
|
self->dataBits = dataBits;
|
|
self->stopBits = stopBits;
|
|
self->parity = parity;
|
|
self->lastSentTime = 0;
|
|
self->timeout = 100; /* 100 ms */
|
|
strncpy(self->interfaceName, interfaceName, 100);
|
|
self->lastError = SERIAL_PORT_ERROR_NONE;
|
|
}
|
|
|
|
return self;
|
|
}
|
|
|
|
void
|
|
SerialPort_destroy(SerialPort self)
|
|
{
|
|
if (self != NULL) {
|
|
|
|
if (self->comPort != INVALID_HANDLE_VALUE)
|
|
SerialPort_close(self);
|
|
|
|
GLOBAL_FREEMEM(self);
|
|
}
|
|
}
|
|
|
|
bool
|
|
SerialPort_open(SerialPort self)
|
|
{
|
|
self->comPort = CreateFile(self->interfaceName, GENERIC_READ | GENERIC_WRITE,
|
|
0, NULL, OPEN_EXISTING, 0, NULL);
|
|
|
|
|
|
if (self->comPort == INVALID_HANDLE_VALUE) {
|
|
self->lastError = SERIAL_PORT_ERROR_OPEN_FAILED;
|
|
return false;
|
|
}
|
|
|
|
DCB _serialParams = { 0 };
|
|
_serialParams.DCBlength = sizeof(DCB);
|
|
|
|
LPDCB serialParams = &_serialParams;
|
|
|
|
BOOL status = GetCommState(self->comPort, serialParams);
|
|
|
|
if (status == false) {
|
|
self->lastError = SERIAL_PORT_ERROR_UNKNOWN;
|
|
goto exit_error;
|
|
}
|
|
|
|
/* set baud rate */
|
|
switch (self->baudRate) {
|
|
case 110:
|
|
serialParams->BaudRate = CBR_110;
|
|
break;
|
|
case 300:
|
|
serialParams->BaudRate = CBR_300;
|
|
break;
|
|
case 600:
|
|
serialParams->BaudRate = CBR_600;
|
|
break;
|
|
case 1200:
|
|
serialParams->BaudRate = CBR_1200;
|
|
break;
|
|
case 2400:
|
|
serialParams->BaudRate = CBR_2400;
|
|
break;
|
|
case 4800:
|
|
serialParams->BaudRate = CBR_4800;
|
|
break;
|
|
case 9600:
|
|
serialParams->BaudRate = CBR_9600;
|
|
break;
|
|
case 19200:
|
|
serialParams->BaudRate = CBR_19200;
|
|
break;
|
|
case 38400:
|
|
serialParams->BaudRate = CBR_38400;
|
|
break;
|
|
case 57600:
|
|
serialParams->BaudRate = CBR_57600;
|
|
break;
|
|
case 115200:
|
|
serialParams->BaudRate = CBR_115200;
|
|
break;
|
|
default:
|
|
serialParams->BaudRate = CBR_9600;
|
|
self->lastError = SERIAL_PORT_ERROR_INVALID_BAUDRATE;
|
|
}
|
|
|
|
/* Set data bits (5/6/7/8) */
|
|
serialParams->ByteSize = self->dataBits;
|
|
|
|
/* Set stop bits (1/2) */
|
|
if (self->stopBits == 1)
|
|
serialParams->StopBits = ONESTOPBIT;
|
|
else /* 2 */
|
|
serialParams->StopBits = TWOSTOPBITS;
|
|
|
|
if (self->parity == 'N')
|
|
serialParams->Parity = NOPARITY;
|
|
else if (self->parity == 'E')
|
|
serialParams->Parity = EVENPARITY;
|
|
else /* 'O' */
|
|
serialParams->Parity = ODDPARITY;
|
|
|
|
status = SetCommState(self->comPort, serialParams);
|
|
|
|
if (status == false) {
|
|
self->lastError = SERIAL_PORT_ERROR_INVALID_ARGUMENT;
|
|
goto exit_error;
|
|
}
|
|
|
|
COMMTIMEOUTS timeouts = { 0 };
|
|
|
|
timeouts.ReadIntervalTimeout = 100;
|
|
timeouts.ReadTotalTimeoutConstant = 50;
|
|
timeouts.ReadTotalTimeoutMultiplier = 10;
|
|
timeouts.WriteTotalTimeoutConstant = 100;
|
|
timeouts.WriteTotalTimeoutMultiplier = 10;
|
|
|
|
status = SetCommTimeouts(self->comPort, &timeouts);
|
|
|
|
if (status == false) {
|
|
self->lastError = SERIAL_PORT_ERROR_UNKNOWN;
|
|
goto exit_error;
|
|
}
|
|
|
|
status = SetCommMask(self->comPort, EV_RXCHAR);
|
|
|
|
if (status == false) {
|
|
printf("SetCommMask failed!\n");
|
|
self->lastError = SERIAL_PORT_ERROR_UNKNOWN;
|
|
goto exit_error;
|
|
}
|
|
|
|
self->lastError = SERIAL_PORT_ERROR_NONE;
|
|
|
|
return true;
|
|
|
|
exit_error:
|
|
|
|
if (self->comPort != INVALID_HANDLE_VALUE) {
|
|
CloseHandle(self->comPort);
|
|
self->comPort = INVALID_HANDLE_VALUE;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
|
|
void
|
|
SerialPort_close(SerialPort self)
|
|
{
|
|
if (self->comPort != INVALID_HANDLE_VALUE) {
|
|
CloseHandle(self->comPort);
|
|
self->comPort = INVALID_HANDLE_VALUE;
|
|
}
|
|
}
|
|
|
|
int
|
|
SerialPort_getBaudRate(SerialPort self)
|
|
{
|
|
return self->baudRate;
|
|
}
|
|
|
|
void
|
|
SerialPort_discardInBuffer(SerialPort self)
|
|
{
|
|
PurgeComm(self->comPort, PURGE_RXCLEAR | PURGE_TXCLEAR);
|
|
}
|
|
|
|
void
|
|
SerialPort_setTimeout(SerialPort self, int timeout)
|
|
{
|
|
self->timeout = timeout;
|
|
}
|
|
|
|
SerialPortError
|
|
SerialPort_getLastError(SerialPort self)
|
|
{
|
|
return self->lastError;
|
|
}
|
|
|
|
int
|
|
SerialPort_readByte(SerialPort self)
|
|
{
|
|
uint8_t buf[1];
|
|
|
|
DWORD bytesRead = 0;
|
|
|
|
BOOL status = ReadFile(self->comPort, buf, 1, &bytesRead, NULL);
|
|
|
|
if (status == false) {
|
|
self->lastError = SERIAL_PORT_ERROR_UNKNOWN;
|
|
return -1;
|
|
}
|
|
|
|
self->lastError = SERIAL_PORT_ERROR_NONE;
|
|
|
|
if (bytesRead == 0)
|
|
return -1;
|
|
else
|
|
return (int) buf[0];
|
|
}
|
|
|
|
int
|
|
SerialPort_write(SerialPort self, uint8_t* buffer, int startPos, int bufSize)
|
|
{
|
|
//TODO assure minimum line idle time
|
|
|
|
self->lastError = SERIAL_PORT_ERROR_NONE;
|
|
|
|
DWORD numberOfBytesWritten;
|
|
|
|
BOOL status = WriteFile(self->comPort, buffer + startPos, bufSize, &numberOfBytesWritten, NULL);
|
|
|
|
if (status == false) {
|
|
self->lastError = SERIAL_PORT_ERROR_UNKNOWN;
|
|
return -1;
|
|
}
|
|
|
|
status = FlushFileBuffers(self->comPort);
|
|
|
|
if (status == false) {
|
|
printf("FlushFileBuffers failed!\n");
|
|
}
|
|
|
|
self->lastSentTime = Hal_getTimeInMs();
|
|
|
|
return (int) numberOfBytesWritten;
|
|
}
|