📄 portserial.c
字号:
/* * FreeModbus Libary: Win32 Port * Copyright (C) 2006 Christian Walter <wolti@sil.at> * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * File: $Id: portserial.c,v 1.6 2006/07/21 10:59:14 wolti Exp $ */#include <windows.h>#include "port.h"/* ----------------------- Modbus includes ----------------------------------*/#include "mb.h"#include "mbport.h"#include "mbconfig.h"/* ----------------------- Defines -----------------------------------------*/#if MB_ASCII_ENABLED == 1#define BUF_SIZE 513 /* must hold a complete ASCII frame. */#else#define BUF_SIZE 256 /* must hold a complete RTU frame. */#endif/* ----------------------- Static variables ---------------------------------*/static HANDLE g_hSerial;static BOOL bRxEnabled;static BOOL bTxEnabled;static UCHAR ucBuffer[BUF_SIZE];static INT uiRxBufferPos;static INT uiTxBufferPos;/* ----------------------- Function prototypes ------------------------------*/LPTSTR Error2String( DWORD dwError );/* ----------------------- Begin implementation -----------------------------*/voidvMBPortSerialEnable( BOOL bEnableRx, BOOL bEnableTx ){ /* it is not allowed that both receiver and transmitter are enabled. */ assert( !bEnableRx || !bEnableTx ); if( bEnableRx ) { PurgeComm( g_hSerial, PURGE_RXCLEAR ); uiRxBufferPos = 0; bRxEnabled = TRUE; } else { bRxEnabled = FALSE; } if( bEnableTx ) { bTxEnabled = TRUE; uiTxBufferPos = 0; } else { bTxEnabled = FALSE; }}BOOLxMBPortSerialInit( UCHAR ucPort, ULONG ulBaudRate, UCHAR ucDataBits, eMBParity eParity ){ TCHAR szDevice[8]; BOOL bStatus = TRUE; DCB dcb; memset( &dcb, 0, sizeof( dcb ) ); dcb.DCBlength = sizeof( dcb ); dcb.BaudRate = ulBaudRate; _stprintf_s( szDevice, 8, _T( "COM%d" ), ucPort ); switch ( eParity ) { case MB_PAR_NONE: dcb.Parity = NOPARITY; dcb.fParity = 0; break; case MB_PAR_EVEN: dcb.Parity = EVENPARITY; dcb.fParity = 1; break; case MB_PAR_ODD: dcb.Parity = ODDPARITY; dcb.fParity = 1; break; default: bStatus = FALSE; } switch ( ucDataBits ) { case 8: dcb.ByteSize = 8; break; case 7: dcb.ByteSize = 7; break; default: bStatus = FALSE; } if( bStatus ) { /* we don't use XON/XOFF flow control. */ dcb.fInX = dcb.fOutX = FALSE; /* we don't need hardware handshake. */ dcb.fOutxCtsFlow = dcb.fOutxCtsFlow = FALSE; dcb.fRtsControl = RTS_CONTROL_ENABLE; dcb.fDtrControl = DTR_CONTROL_ENABLE; /* misc parameters */ dcb.fErrorChar = FALSE; dcb.fBinary = TRUE; dcb.fNull = FALSE; dcb.fAbortOnError = FALSE; dcb.wReserved = 0; dcb.XonLim = 2; dcb.XoffLim = 4; dcb.XonChar = 0x13; dcb.XoffChar = 0x19; dcb.EvtChar = 0; /* Open the serial device. */ g_hSerial = CreateFile( szDevice, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL ); if( g_hSerial == INVALID_HANDLE_VALUE ) { vMBPortLog( MB_LOG_ERROR, _T( "SER-INIT" ), _T( "Can't open serial port %s: %s" ), szDevice, Error2String( GetLastError( ) ) ); bStatus = FALSE; } else if( !SetCommState( g_hSerial, &dcb ) ) { vMBPortLog( MB_LOG_ERROR, _T( "SER-INIT" ), _T( "Can't set settings for serial device %s: %s" ), szDevice, Error2String( GetLastError( ) ) ); bStatus = FALSE; } else if( !SetCommMask( g_hSerial, 0 ) ) { vMBPortLog( MB_LOG_ERROR, _T( "SER-INIT" ), _T( "Can't set communication event mask for serial device %s: %s" ), szDevice, Error2String( GetLastError( ) ) ); bStatus = FALSE; } else { vMBPortSerialEnable( FALSE, FALSE ); bStatus = TRUE; } } return bStatus;}BOOLxMBPortSerialSetTimeout( DWORD dwTimeoutMs ){ BOOL bStatus; COMMTIMEOUTS cto; /* usTimeOut is the inter character timeout used to detect the end * of frame. The total timeout is set to 50ms to make sure we * can exit the blocking read. */ cto.ReadIntervalTimeout = dwTimeoutMs; cto.ReadTotalTimeoutConstant = 50; cto.ReadTotalTimeoutMultiplier = 0; cto.WriteTotalTimeoutConstant = 0; cto.WriteTotalTimeoutMultiplier = 0; if( !SetCommTimeouts( g_hSerial, &cto ) ) { vMBPortLog( MB_LOG_ERROR, _T( "SER-INIT" ), _T( "Can't set timeouts for serial device: %s" ), Error2String( GetLastError( ) ) ); bStatus = FALSE; } else { bStatus = TRUE; } return bStatus;}voidvMBPortClose ( void ){ ( void )CloseHandle( g_hSerial );}BOOLxMBPortSerialPoll( ){ BOOL bStatus = TRUE; DWORD dwBytesRead; DWORD dwBytesWritten; DWORD i; while( bRxEnabled ) { /* buffer wrap around. */ if( uiRxBufferPos >= BUF_SIZE ) uiRxBufferPos = 0; if( ReadFile( g_hSerial, &ucBuffer[uiRxBufferPos], BUF_SIZE - uiRxBufferPos, &dwBytesRead, NULL ) ) { if( dwBytesRead == 0 ) { /* timeout with no bytes. */ break; } else if( dwBytesRead > 0 ) { vMBPortLog( MB_LOG_DEBUG, _T( "SER-POLL" ), _T( "detected end of frame (t3.5 expired.)\r\n" ) ); for( i = 0; i < dwBytesRead; i++ ) { /* Call the modbus stack and let him fill the buffers. */ ( void )pxMBFrameCBByteReceived( ); } } } else { vMBPortLog( MB_LOG_ERROR, _T( "SER-POLL" ), _T( "I/O error on serial device: %s" ), Error2String( GetLastError ( ) ) ); bStatus = FALSE; } } if( bTxEnabled ) { while( bTxEnabled ) { ( void )pxMBFrameCBTransmitterEmpty( ); /* Call the modbus stack to let him fill the buffer. */ } dwBytesWritten = 0; if( !WriteFile ( g_hSerial, &ucBuffer[0], uiTxBufferPos, &dwBytesWritten, NULL ) || ( dwBytesWritten != uiTxBufferPos ) ) { vMBPortLog( MB_LOG_ERROR, _T( "SER-POLL" ), _T( "I/O error on serial device: %s" ), Error2String( GetLastError ( ) ) ); bStatus = FALSE; } } return bStatus;}BOOLxMBPortSerialPutByte( CHAR ucByte ){ assert( uiTxBufferPos < BUF_SIZE ); ucBuffer[uiTxBufferPos] = ucByte; uiTxBufferPos++; return TRUE;}BOOLxMBPortSerialGetByte( CHAR * pucByte ){ assert( uiRxBufferPos < BUF_SIZE ); *pucByte = ucBuffer[uiRxBufferPos]; uiRxBufferPos++; return TRUE;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -