winserial.cxx
上传用户:hzhsqp
上传日期:2007-01-06
资源大小:1600k
文件大小:12k
源码类别:

IP电话/视频会议

开发平台:

Visual C++

  1. /*
  2.  * winserial.cxx
  3.  *
  4.  * Miscellaneous implementation of classes for Win32
  5.  *
  6.  * Portable Windows Library
  7.  *
  8.  * Copyright (c) 1993-1998 Equivalence Pty. Ltd.
  9.  *
  10.  * The contents of this file are subject to the Mozilla Public License
  11.  * Version 1.0 (the "License"); you may not use this file except in
  12.  * compliance with the License. You may obtain a copy of the License at
  13.  * http://www.mozilla.org/MPL/
  14.  *
  15.  * Software distributed under the License is distributed on an "AS IS"
  16.  * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
  17.  * the License for the specific language governing rights and limitations
  18.  * under the License.
  19.  *
  20.  * The Original Code is Portable Windows Library.
  21.  *
  22.  * The Initial Developer of the Original Code is Equivalence Pty. Ltd.
  23.  *
  24.  * Portions are Copyright (C) 1993 Free Software Foundation, Inc.
  25.  * All Rights Reserved.
  26.  *
  27.  * Contributor(s): ______________________________________.
  28.  *
  29.  * $Log: winserial.cxx,v $
  30.  * Revision 1.3  2000/03/20 17:55:05  robertj
  31.  * Fixed prolem with XON/XOFF under NT, thanks Damien Slee.
  32.  *
  33.  * Revision 1.2  1998/11/30 12:32:47  robertj
  34.  * Added missing copyright header.
  35.  *
  36.  */
  37. #include <ptlib.h>
  38. #include <ptlib/serchan.h>
  39. #define QUEUE_SIZE 2048
  40. ///////////////////////////////////////////////////////////////////////////////
  41. // PSerialChannel
  42. void PSerialChannel::Construct()
  43. {
  44.   commsResource = INVALID_HANDLE_VALUE;
  45.   char str[50];
  46.   strcpy(str, "com1");
  47.   GetProfileString("ports", str, "9600,n,8,1,x", &str[5], sizeof(str)-6);
  48.   str[4] = ':';
  49.   memset(&deviceControlBlock, 0, sizeof(deviceControlBlock));
  50.   deviceControlBlock.DCBlength = sizeof(deviceControlBlock);
  51.   BuildCommDCB(str, &deviceControlBlock);
  52.   // These values are not set by BuildCommDCB
  53.   deviceControlBlock.XoffChar = 19;
  54.   deviceControlBlock.XonChar = 17;
  55.   deviceControlBlock.XoffLim = (QUEUE_SIZE * 7)/8;  // upper limit before XOFF is sent to stop reception
  56.   deviceControlBlock.XonLim = (QUEUE_SIZE * 3)/4;   // lower limit before XON is sent to re-enabled reception
  57. }
  58. PString PSerialChannel::GetName() const
  59. {
  60.   return portName;
  61. }
  62. BOOL PSerialChannel::Read(void * buf, PINDEX len)
  63. {
  64.   lastReadCount = 0;
  65.   if (!IsOpen()) {
  66.     osError = EBADF;
  67.     lastError = NotOpen;
  68.     return FALSE;
  69.   }
  70.   COMMTIMEOUTS cto;
  71.   PAssertOS(GetCommTimeouts(commsResource, &cto));
  72.   cto.ReadIntervalTimeout = 0;
  73.   cto.ReadTotalTimeoutMultiplier = 0;
  74.   cto.ReadTotalTimeoutConstant = 0;
  75.   cto.ReadIntervalTimeout = MAXDWORD; // Immediate timeout
  76.   PAssertOS(SetCommTimeouts(commsResource, &cto));
  77.   DWORD eventMask;
  78.   PAssertOS(GetCommMask(commsResource, &eventMask));
  79.   if (eventMask != (EV_RXCHAR|EV_TXEMPTY))
  80.     PAssertOS(SetCommMask(commsResource, EV_RXCHAR|EV_TXEMPTY));
  81.   PWin32Overlapped overlap;
  82.   DWORD timeToGo = readTimeout.GetInterval();
  83.   DWORD bytesToGo = len;
  84.   char * bufferPtr = (char *)buf;
  85.   for (;;) {
  86.     DWORD readCount = 0;
  87.     if (!ReadFile(commsResource, bufferPtr, bytesToGo, &readCount, &overlap)) {
  88.       if (GetLastError() != ERROR_IO_PENDING)
  89.         return ConvertOSError(-2);
  90.       if (!GetOverlappedResult(commsResource, &overlap, &readCount, FALSE))
  91.         return ConvertOSError(-2);
  92.     }
  93.     bytesToGo -= readCount;
  94.     bufferPtr += readCount;
  95.     lastReadCount += readCount;
  96.     if (lastReadCount >= len || timeToGo == 0)
  97.       return lastReadCount > 0;
  98.     if (!WaitCommEvent(commsResource, &eventMask, &overlap)) {
  99.       if (GetLastError() != ERROR_IO_PENDING)
  100.         return ConvertOSError(-2);
  101.       if (WaitForSingleObject(overlap.hEvent, timeToGo) == WAIT_FAILED)
  102.         return ConvertOSError(-2);
  103.     }
  104.   }
  105. }
  106. BOOL PSerialChannel::Write(const void * buf, PINDEX len)
  107. {
  108.   lastWriteCount = 0;
  109.   if (!IsOpen()) {
  110.     osError = EBADF;
  111.     lastError = NotOpen;
  112.     return FALSE;
  113.   }
  114.   COMMTIMEOUTS cto;
  115.   PAssertOS(GetCommTimeouts(commsResource, &cto));
  116.   cto.WriteTotalTimeoutMultiplier = 0;
  117.   if (writeTimeout == PMaxTimeInterval)
  118.     cto.WriteTotalTimeoutConstant = 0;
  119.   else if (writeTimeout <= PTimeInterval(0))
  120.     cto.WriteTotalTimeoutConstant = 1;
  121.   else
  122.     cto.WriteTotalTimeoutConstant = writeTimeout.GetInterval();
  123.   PAssertOS(SetCommTimeouts(commsResource, &cto));
  124.   PWin32Overlapped overlap;
  125.   memset(&overlap, 0, sizeof(overlap));
  126.   overlap.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
  127.   if (WriteFile(commsResource, buf, len, (LPDWORD)&lastWriteCount, &overlap)) {
  128.     CloseHandle(overlap.hEvent);
  129.     return lastWriteCount == len;
  130.   }
  131.   if (GetLastError() == ERROR_IO_PENDING)
  132.     if (GetOverlappedResult(commsResource,
  133.                                    &overlap, (LPDWORD)&lastWriteCount, TRUE)) {
  134.       CloseHandle(overlap.hEvent);
  135.       return lastWriteCount == len;
  136.     }
  137.   ConvertOSError(-2);
  138.   CloseHandle(overlap.hEvent);
  139.   return FALSE;
  140. }
  141. BOOL PSerialChannel::Close()
  142. {
  143.   if (!IsOpen()) {
  144.     osError = EBADF;
  145.     lastError = NotOpen;
  146.     return FALSE;
  147.   }
  148.   CloseHandle(commsResource);
  149.   commsResource = INVALID_HANDLE_VALUE;
  150.   os_handle = -1;
  151.   return ConvertOSError(-2);
  152. }
  153. BOOL PSerialChannel::SetCommsParam(DWORD speed, BYTE data, Parity parity,
  154.                      BYTE stop, FlowControl inputFlow, FlowControl outputFlow)
  155. {
  156.   if (speed > 0)
  157.     deviceControlBlock.BaudRate = speed;
  158.   if (data > 0)
  159.     deviceControlBlock.ByteSize = data;
  160.   switch (parity) {
  161.     case NoParity :
  162.       deviceControlBlock.Parity = NOPARITY;
  163.       break;
  164.     case OddParity :
  165.       deviceControlBlock.Parity = ODDPARITY;
  166.       break;
  167.     case EvenParity :
  168.       deviceControlBlock.Parity = EVENPARITY;
  169.       break;
  170.     case MarkParity :
  171.       deviceControlBlock.Parity = MARKPARITY;
  172.       break;
  173.     case SpaceParity :
  174.       deviceControlBlock.Parity = SPACEPARITY;
  175.       break;
  176.   }
  177.   switch (stop) {
  178.     case 1 :
  179.       deviceControlBlock.StopBits = ONESTOPBIT;
  180.       break;
  181.     case 2 :
  182.       deviceControlBlock.StopBits = TWOSTOPBITS;
  183.       break;
  184.   }
  185.   switch (inputFlow) {
  186.     case NoFlowControl :
  187.       deviceControlBlock.fRtsControl = RTS_CONTROL_DISABLE;
  188.       deviceControlBlock.fInX = FALSE;
  189.       break;
  190.     case XonXoff :
  191.       deviceControlBlock.fRtsControl = RTS_CONTROL_DISABLE;
  192.       deviceControlBlock.fInX = TRUE;
  193.       break;
  194.     case RtsCts :
  195.       deviceControlBlock.fRtsControl = RTS_CONTROL_HANDSHAKE;
  196.       deviceControlBlock.fInX = FALSE;
  197.       break;
  198.   }
  199.   switch (outputFlow) {
  200.     case NoFlowControl :
  201.       deviceControlBlock.fOutxCtsFlow = FALSE;
  202.       deviceControlBlock.fOutxDsrFlow = FALSE;
  203.       deviceControlBlock.fOutX = FALSE;
  204.       break;
  205.     case XonXoff :
  206.       deviceControlBlock.fOutxCtsFlow = FALSE;
  207.       deviceControlBlock.fOutxDsrFlow = FALSE;
  208.       deviceControlBlock.fOutX = TRUE;
  209.       break;
  210.     case RtsCts :
  211.       deviceControlBlock.fOutxCtsFlow = TRUE;
  212.       deviceControlBlock.fOutxDsrFlow = FALSE;
  213.       deviceControlBlock.fOutX = FALSE;
  214.       break;
  215.   }
  216.   if (IsOpen())
  217.    return ConvertOSError(SetCommState(commsResource,
  218.                                                 &deviceControlBlock) ? 0 : -2);
  219.   osError = EBADF;
  220.   lastError = NotOpen;
  221.   return FALSE;
  222. }
  223. BOOL PSerialChannel::Open(const PString & port, DWORD speed, BYTE data,
  224.                Parity parity, BYTE stop, FlowControl inputFlow, FlowControl outputFlow)
  225. {
  226.   Close();
  227.   portName = port;
  228.   if (portName.Find(PDIR_SEPARATOR) == P_MAX_INDEX)
  229.     portName = "\\.\" + port;
  230.   commsResource = CreateFile(portName,
  231.                              GENERIC_READ|GENERIC_WRITE,
  232.                              0,
  233.                              NULL,
  234.                              OPEN_EXISTING,
  235.                              FILE_FLAG_OVERLAPPED,
  236.                              NULL);
  237.   if (commsResource == INVALID_HANDLE_VALUE)
  238.     return ConvertOSError(-2);
  239.   os_handle = 0;
  240.   SetupComm(commsResource, QUEUE_SIZE, QUEUE_SIZE);
  241.   if (SetCommsParam(speed, data, parity, stop, inputFlow, outputFlow))
  242.     return TRUE;
  243.   ConvertOSError(-2);
  244.   CloseHandle(commsResource);
  245.   os_handle = -1;
  246.   return FALSE;
  247. }
  248. BOOL PSerialChannel::SetSpeed(DWORD speed)
  249. {
  250.   return SetCommsParam(speed,
  251.                   0, DefaultParity, 0, DefaultFlowControl, DefaultFlowControl);
  252. }
  253. DWORD PSerialChannel::GetSpeed() const
  254. {
  255.   return deviceControlBlock.BaudRate;
  256. }
  257. BOOL PSerialChannel::SetDataBits(BYTE data)
  258. {
  259.   return SetCommsParam(0,
  260.                data, DefaultParity, 0, DefaultFlowControl, DefaultFlowControl);
  261. }
  262. BYTE PSerialChannel::GetDataBits() const
  263. {
  264.   return deviceControlBlock.ByteSize;
  265. }
  266. BOOL PSerialChannel::SetParity(Parity parity)
  267. {
  268.   return SetCommsParam(0,0,parity,0,DefaultFlowControl,DefaultFlowControl);
  269. }
  270. PSerialChannel::Parity PSerialChannel::GetParity() const
  271. {
  272.   switch (deviceControlBlock.Parity) {
  273.     case ODDPARITY :
  274.       return OddParity;
  275.     case EVENPARITY :
  276.       return EvenParity;
  277.     case MARKPARITY :
  278.       return MarkParity;
  279.     case SPACEPARITY :
  280.       return SpaceParity;
  281.   }
  282.   return NoParity;
  283. }
  284. BOOL PSerialChannel::SetStopBits(BYTE stop)
  285. {
  286.   return SetCommsParam(0,
  287.                0, DefaultParity, stop, DefaultFlowControl, DefaultFlowControl);
  288. }
  289. BYTE PSerialChannel::GetStopBits() const
  290. {
  291.   return (BYTE)(deviceControlBlock.StopBits == ONESTOPBIT ? 1 : 2);
  292. }
  293. BOOL PSerialChannel::SetInputFlowControl(FlowControl flowControl)
  294. {
  295.   return SetCommsParam(0,0,DefaultParity,0,flowControl,DefaultFlowControl);
  296. }
  297. PSerialChannel::FlowControl PSerialChannel::GetInputFlowControl() const
  298. {
  299.   if (deviceControlBlock.fRtsControl == RTS_CONTROL_HANDSHAKE)
  300.     return RtsCts;
  301.   if (deviceControlBlock.fInX != 0)
  302.     return XonXoff;
  303.   return NoFlowControl;
  304. }
  305. BOOL PSerialChannel::SetOutputFlowControl(FlowControl flowControl)
  306. {
  307.   return SetCommsParam(0,0,DefaultParity,0,DefaultFlowControl,flowControl);
  308. }
  309. PSerialChannel::FlowControl PSerialChannel::GetOutputFlowControl() const
  310. {
  311.   if (deviceControlBlock.fOutxCtsFlow != 0)
  312.     return RtsCts;
  313.   if (deviceControlBlock.fOutX != 0)
  314.     return XonXoff;
  315.   return NoFlowControl;
  316. }
  317. void PSerialChannel::SetDTR(BOOL state)
  318. {
  319.   if (IsOpen())
  320.     PAssertOS(EscapeCommFunction(commsResource, state ? SETDTR : CLRDTR));
  321.   else {
  322.     osError = EBADF;
  323.     lastError = NotOpen;
  324.   }
  325. }
  326. void PSerialChannel::SetRTS(BOOL state)
  327. {
  328.   if (IsOpen())
  329.     PAssertOS(EscapeCommFunction(commsResource, state ? SETRTS : CLRRTS));
  330.   else {
  331.     osError = EBADF;
  332.     lastError = NotOpen;
  333.   }
  334. }
  335. void PSerialChannel::SetBreak(BOOL state)
  336. {
  337.   if (IsOpen())
  338.     if (state)
  339.       PAssertOS(SetCommBreak(commsResource));
  340.     else
  341.       PAssertOS(ClearCommBreak(commsResource));
  342.   else {
  343.     osError = EBADF;
  344.     lastError = NotOpen;
  345.   }
  346. }
  347. BOOL PSerialChannel::GetCTS()
  348. {
  349.   if (!IsOpen()) {
  350.     osError = EBADF;
  351.     lastError = NotOpen;
  352.     return FALSE;
  353.   }
  354.   DWORD stat;
  355.   PAssertOS(GetCommModemStatus(commsResource, &stat));
  356.   return (stat&MS_CTS_ON) != 0;
  357. }
  358. BOOL PSerialChannel::GetDSR()
  359. {
  360.   if (!IsOpen()) {
  361.     osError = EBADF;
  362.     lastError = NotOpen;
  363.     return FALSE;
  364.   }
  365.   DWORD stat;
  366.   PAssertOS(GetCommModemStatus(commsResource, &stat));
  367.   return (stat&MS_DSR_ON) != 0;
  368. }
  369. BOOL PSerialChannel::GetDCD()
  370. {
  371.   if (!IsOpen()) {
  372.     osError = EBADF;
  373.     lastError = NotOpen;
  374.     return FALSE;
  375.   }
  376.   DWORD stat;
  377.   PAssertOS(GetCommModemStatus(commsResource, &stat));
  378.   return (stat&MS_RLSD_ON) != 0;
  379. }
  380. BOOL PSerialChannel::GetRing()
  381. {
  382.   if (!IsOpen()) {
  383.     osError = EBADF;
  384.     lastError = NotOpen;
  385.     return FALSE;
  386.   }
  387.   DWORD stat;
  388.   PAssertOS(GetCommModemStatus(commsResource, &stat));
  389.   return (stat&MS_RING_ON) != 0;
  390. }
  391. PStringList PSerialChannel::GetPortNames()
  392. {
  393.   PStringList ports;
  394.   for (char p = 1; p <= 9; p++)
  395.     ports.AppendString(psprintf("\\.\COM%u", p));
  396.   return ports;
  397. }