⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 winserial.cxx

📁 pwlib源码库
💻 CXX
字号:
/* * winserial.cxx * * Miscellaneous implementation of classes for Win32 * * Portable Windows Library * * Copyright (c) 1993-1998 Equivalence Pty. Ltd. * * The contents of this file are subject to the Mozilla Public License * Version 1.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.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See * the License for the specific language governing rights and limitations * under the License. * * The Original Code is Portable Windows Library. * * The Initial Developer of the Original Code is Equivalence Pty. Ltd. * * Portions are Copyright (C) 1993 Free Software Foundation, Inc. * All Rights Reserved. * * Contributor(s): ______________________________________. * * $Log: winserial.cxx,v $ * Revision 1.7  2005/01/12 03:24:08  csoutheren * More cleanup of event handling * * Revision 1.6  2005/01/11 12:46:37  csoutheren * Removed handle leak on serial port caused by memset * Thanks to Dmitry Samokhin * * Revision 1.5  2004/12/27 22:38:27  csoutheren * Fixed problems with accessing serial port under Windows * * Revision 1.4  2001/09/10 02:51:23  robertj * Major change to fix problem with error codes being corrupted in a *   PChannel when have simultaneous reads and writes in threads. * * Revision 1.3  2000/03/20 17:55:05  robertj * Fixed prolem with XON/XOFF under NT, thanks Damien Slee. * * Revision 1.2  1998/11/30 12:32:47  robertj * Added missing copyright header. * */#include <ptlib.h>#include <ptlib/serchan.h>#define QUEUE_SIZE 2048///////////////////////////////////////////////////////////////////////////////// PSerialChannelvoid PSerialChannel::Construct(){  commsResource = INVALID_HANDLE_VALUE;  char str[50];  strcpy(str, "com1");  GetProfileString("ports", str, "9600,n,8,1,x", &str[5], sizeof(str)-6);  str[4] = ':';  memset(&deviceControlBlock, 0, sizeof(deviceControlBlock));  deviceControlBlock.DCBlength = sizeof(deviceControlBlock);  BuildCommDCB(str, &deviceControlBlock);  // These values are not set by BuildCommDCB  deviceControlBlock.XoffChar = 19;  deviceControlBlock.XonChar = 17;  deviceControlBlock.XoffLim = (QUEUE_SIZE * 7)/8;  // upper limit before XOFF is sent to stop reception  deviceControlBlock.XonLim = (QUEUE_SIZE * 3)/4;   // lower limit before XON is sent to re-enabled reception}PString PSerialChannel::GetName() const{  return portName;}BOOL PSerialChannel::Read(void * buf, PINDEX len){  lastReadCount = 0;  if (!IsOpen())    return SetErrorValues(NotOpen, EBADF, LastReadError);  COMMTIMEOUTS cto;  PAssertOS(GetCommTimeouts(commsResource, &cto));  cto.ReadIntervalTimeout = 0;  cto.ReadTotalTimeoutMultiplier = 0;  cto.ReadTotalTimeoutConstant = 0;  cto.ReadIntervalTimeout = MAXDWORD; // Immediate timeout  PAssertOS(SetCommTimeouts(commsResource, &cto));  DWORD eventMask;  PAssertOS(GetCommMask(commsResource, &eventMask));  if (eventMask != (EV_RXCHAR|EV_TXEMPTY))    PAssertOS(SetCommMask(commsResource, EV_RXCHAR|EV_TXEMPTY));  DWORD timeToGo = readTimeout.GetInterval();  DWORD bytesToGo = len;  char * bufferPtr = (char *)buf;  for (;;) {    PWin32Overlapped overlap;    DWORD readCount = 0;    if (!ReadFile(commsResource, bufferPtr, bytesToGo, &readCount, &overlap)) {      if (::GetLastError() != ERROR_IO_PENDING)        return ConvertOSError(-2, LastReadError);      if (!::GetOverlappedResult(commsResource, &overlap, &readCount, FALSE))        return ConvertOSError(-2, LastReadError);    }    bytesToGo -= readCount;    bufferPtr += readCount;    lastReadCount += readCount;    if (lastReadCount >= len || timeToGo == 0)      return lastReadCount > 0;    if (!::WaitCommEvent(commsResource, &eventMask, &overlap)) {      if (::GetLastError()!= ERROR_IO_PENDING)        return ConvertOSError(-2, LastReadError);      DWORD err = ::WaitForSingleObject(overlap.hEvent, timeToGo);      if (err == WAIT_TIMEOUT) {        SetErrorValues(Timeout, EAGAIN, LastReadError);        ::CancelIo(commsResource);        return lastReadCount > 0;      }      else if (err == WAIT_FAILED)        return ConvertOSError(-2, LastReadError);    }  }}BOOL PSerialChannel::Write(const void * buf, PINDEX len){  lastWriteCount = 0;  if (!IsOpen())    return SetErrorValues(NotOpen, EBADF, LastWriteError);  COMMTIMEOUTS cto;  PAssertOS(GetCommTimeouts(commsResource, &cto));  cto.WriteTotalTimeoutMultiplier = 0;  if (writeTimeout == PMaxTimeInterval)    cto.WriteTotalTimeoutConstant = 0;  else if (writeTimeout <= PTimeInterval(0))    cto.WriteTotalTimeoutConstant = 1;  else    cto.WriteTotalTimeoutConstant = writeTimeout.GetInterval();  PAssertOS(SetCommTimeouts(commsResource, &cto));  PWin32Overlapped overlap;  if (WriteFile(commsResource, buf, len, (LPDWORD)&lastWriteCount, &overlap))     return lastWriteCount == len;  if (GetLastError() == ERROR_IO_PENDING)    if (GetOverlappedResult(commsResource, &overlap, (LPDWORD)&lastWriteCount, TRUE)) {      return lastWriteCount == len;    }  ConvertOSError(-2, LastWriteError);  return FALSE;}BOOL PSerialChannel::Close(){  if (!IsOpen())    return SetErrorValues(NotOpen, EBADF);  CloseHandle(commsResource);  commsResource = INVALID_HANDLE_VALUE;  os_handle = -1;  return ConvertOSError(-2);}BOOL PSerialChannel::SetCommsParam(DWORD speed, BYTE data, Parity parity,                     BYTE stop, FlowControl inputFlow, FlowControl outputFlow){  if (speed > 0)    deviceControlBlock.BaudRate = speed;  if (data > 0)    deviceControlBlock.ByteSize = data;  switch (parity) {    case NoParity :      deviceControlBlock.Parity = NOPARITY;      break;    case OddParity :      deviceControlBlock.Parity = ODDPARITY;      break;    case EvenParity :      deviceControlBlock.Parity = EVENPARITY;      break;    case MarkParity :      deviceControlBlock.Parity = MARKPARITY;      break;    case SpaceParity :      deviceControlBlock.Parity = SPACEPARITY;      break;  }  switch (stop) {    case 1 :      deviceControlBlock.StopBits = ONESTOPBIT;      break;    case 2 :      deviceControlBlock.StopBits = TWOSTOPBITS;      break;  }  switch (inputFlow) {    case NoFlowControl :      deviceControlBlock.fRtsControl = RTS_CONTROL_DISABLE;      deviceControlBlock.fInX = FALSE;      break;    case XonXoff :      deviceControlBlock.fRtsControl = RTS_CONTROL_DISABLE;      deviceControlBlock.fInX = TRUE;      break;    case RtsCts :      deviceControlBlock.fRtsControl = RTS_CONTROL_HANDSHAKE;      deviceControlBlock.fInX = FALSE;      break;  }  switch (outputFlow) {    case NoFlowControl :      deviceControlBlock.fOutxCtsFlow = FALSE;      deviceControlBlock.fOutxDsrFlow = FALSE;      deviceControlBlock.fOutX = FALSE;      break;    case XonXoff :      deviceControlBlock.fOutxCtsFlow = FALSE;      deviceControlBlock.fOutxDsrFlow = FALSE;      deviceControlBlock.fOutX = TRUE;      break;    case RtsCts :      deviceControlBlock.fOutxCtsFlow = TRUE;      deviceControlBlock.fOutxDsrFlow = FALSE;      deviceControlBlock.fOutX = FALSE;      break;  }  if (!IsOpen())    return SetErrorValues(NotOpen, EBADF);  return ConvertOSError(SetCommState(commsResource, &deviceControlBlock) ? 0 : -2);}BOOL PSerialChannel::Open(const PString & port, DWORD speed, BYTE data,               Parity parity, BYTE stop, FlowControl inputFlow, FlowControl outputFlow){  Close();  portName = port;  if (portName.Find(PDIR_SEPARATOR) == P_MAX_INDEX)    portName = "\\\\.\\" + port;  commsResource = CreateFile(portName,                             GENERIC_READ|GENERIC_WRITE,                             0,                             NULL,                             OPEN_EXISTING,                             FILE_FLAG_OVERLAPPED,                             NULL);  if (commsResource == INVALID_HANDLE_VALUE)    return ConvertOSError(-2);  os_handle = 0;  SetupComm(commsResource, QUEUE_SIZE, QUEUE_SIZE);  if (SetCommsParam(speed, data, parity, stop, inputFlow, outputFlow))    return TRUE;  ConvertOSError(-2);  CloseHandle(commsResource);  os_handle = -1;  return FALSE;}BOOL PSerialChannel::SetSpeed(DWORD speed){  return SetCommsParam(speed,                  0, DefaultParity, 0, DefaultFlowControl, DefaultFlowControl);}DWORD PSerialChannel::GetSpeed() const{  return deviceControlBlock.BaudRate;}BOOL PSerialChannel::SetDataBits(BYTE data){  return SetCommsParam(0,               data, DefaultParity, 0, DefaultFlowControl, DefaultFlowControl);}BYTE PSerialChannel::GetDataBits() const{  return deviceControlBlock.ByteSize;}BOOL PSerialChannel::SetParity(Parity parity){  return SetCommsParam(0,0,parity,0,DefaultFlowControl,DefaultFlowControl);}PSerialChannel::Parity PSerialChannel::GetParity() const{  switch (deviceControlBlock.Parity) {    case ODDPARITY :      return OddParity;    case EVENPARITY :      return EvenParity;    case MARKPARITY :      return MarkParity;    case SPACEPARITY :      return SpaceParity;  }  return NoParity;}BOOL PSerialChannel::SetStopBits(BYTE stop){  return SetCommsParam(0,               0, DefaultParity, stop, DefaultFlowControl, DefaultFlowControl);}BYTE PSerialChannel::GetStopBits() const{  return (BYTE)(deviceControlBlock.StopBits == ONESTOPBIT ? 1 : 2);}BOOL PSerialChannel::SetInputFlowControl(FlowControl flowControl){  return SetCommsParam(0,0,DefaultParity,0,flowControl,DefaultFlowControl);}PSerialChannel::FlowControl PSerialChannel::GetInputFlowControl() const{  if (deviceControlBlock.fRtsControl == RTS_CONTROL_HANDSHAKE)    return RtsCts;  if (deviceControlBlock.fInX != 0)    return XonXoff;  return NoFlowControl;}BOOL PSerialChannel::SetOutputFlowControl(FlowControl flowControl){  return SetCommsParam(0,0,DefaultParity,0,DefaultFlowControl,flowControl);}PSerialChannel::FlowControl PSerialChannel::GetOutputFlowControl() const{  if (deviceControlBlock.fOutxCtsFlow != 0)    return RtsCts;  if (deviceControlBlock.fOutX != 0)    return XonXoff;  return NoFlowControl;}void PSerialChannel::SetDTR(BOOL state){  if (IsOpen())    PAssertOS(EscapeCommFunction(commsResource, state ? SETDTR : CLRDTR));  else    SetErrorValues(NotOpen, EBADF);}void PSerialChannel::SetRTS(BOOL state){  if (IsOpen())    PAssertOS(EscapeCommFunction(commsResource, state ? SETRTS : CLRRTS));  else    SetErrorValues(NotOpen, EBADF);}void PSerialChannel::SetBreak(BOOL state){  if (IsOpen())    if (state)      PAssertOS(SetCommBreak(commsResource));    else      PAssertOS(ClearCommBreak(commsResource));  else    SetErrorValues(NotOpen, EBADF);}BOOL PSerialChannel::GetCTS(){  if (!IsOpen())    return SetErrorValues(NotOpen, EBADF);  DWORD stat;  PAssertOS(GetCommModemStatus(commsResource, &stat));  return (stat&MS_CTS_ON) != 0;}BOOL PSerialChannel::GetDSR(){  if (!IsOpen())    return SetErrorValues(NotOpen, EBADF);  DWORD stat;  PAssertOS(GetCommModemStatus(commsResource, &stat));  return (stat&MS_DSR_ON) != 0;}BOOL PSerialChannel::GetDCD(){  if (!IsOpen())    return SetErrorValues(NotOpen, EBADF);  DWORD stat;  PAssertOS(GetCommModemStatus(commsResource, &stat));  return (stat&MS_RLSD_ON) != 0;}BOOL PSerialChannel::GetRing(){  if (!IsOpen())    return SetErrorValues(NotOpen, EBADF);  DWORD stat;  PAssertOS(GetCommModemStatus(commsResource, &stat));  return (stat&MS_RING_ON) != 0;}PStringList PSerialChannel::GetPortNames(){  PStringList ports;  for (char p = 1; p <= 9; p++)    ports.AppendString(psprintf("\\\\.\\COM%u", p));  return ports;}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -