Exemple #1
0
        /// <summary>
        /// Opens the com port and configures it with the required settings
        /// </summary>
        /// <returns>false if the port could not be opened</returns>
        public bool Open()
        {
            Win32Com.DCB PortDCB = new Win32Com.DCB();
            Win32Com.COMMTIMEOUTS CommTimeouts = new Win32Com.COMMTIMEOUTS();
            CommBaseSettings cs;
            Win32Com.OVERLAPPED wo = new Win32Com.OVERLAPPED();
            Win32Com.COMMPROP cp;

            if (online) return false;
            cs = CommSettings();

            hPort = Win32Com.CreateFile(cs.port, Win32Com.GENERIC_READ | Win32Com.GENERIC_WRITE, 0, IntPtr.Zero,
                Win32Com.OPEN_EXISTING, Win32Com.FILE_FLAG_OVERLAPPED, IntPtr.Zero);
            if (hPort == (IntPtr)Win32Com.INVALID_HANDLE_VALUE)
            {
                if (Marshal.GetLastWin32Error() == Win32Com.ERROR_ACCESS_DENIED)
                {
                    return false;
                }
                else
                {
                    //JH 1.3: Try alternative name form if main one fails:
                    hPort = Win32Com.CreateFile(AltName(cs.port), Win32Com.GENERIC_READ | Win32Com.GENERIC_WRITE, 0, IntPtr.Zero,
                        Win32Com.OPEN_EXISTING, Win32Com.FILE_FLAG_OVERLAPPED, IntPtr.Zero);
                    if (hPort == (IntPtr)Win32Com.INVALID_HANDLE_VALUE)
                    {
                        if (Marshal.GetLastWin32Error() == Win32Com.ERROR_ACCESS_DENIED)
                        {
                            return false;
                        }
                        else
                        {
                            throw new CommPortException("Port Open Failure");
                        }
                    }
                }
            }

            online = true;

            //JH1.1: Changed from 0 to "magic number" to give instant return on ReadFile:
            CommTimeouts.ReadIntervalTimeout = Win32Com.MAXDWORD;
            CommTimeouts.ReadTotalTimeoutConstant = 0;
            CommTimeouts.ReadTotalTimeoutMultiplier = 0;

            //JH1.2: 0 does not seem to mean infinite on non-NT platforms, so default it to 10
            //seconds per byte which should be enough for anyone.
            if (cs.sendTimeoutMultiplier == 0)
            {
                if (System.Environment.OSVersion.Platform == System.PlatformID.Win32NT)
                {
                    CommTimeouts.WriteTotalTimeoutMultiplier = 0;
                }
                else
                {
                    CommTimeouts.WriteTotalTimeoutMultiplier = 10000;
                }
            }
            else
            {
                CommTimeouts.WriteTotalTimeoutMultiplier = cs.sendTimeoutMultiplier;
            }
            CommTimeouts.WriteTotalTimeoutConstant = cs.sendTimeoutConstant;

            PortDCB.init(((cs.parity == Parity.odd) || (cs.parity == Parity.even)), cs.txFlowCTS, cs.txFlowDSR,
                (int)cs.useDTR, cs.rxGateDSR, !cs.txWhenRxXoff, cs.txFlowX, cs.rxFlowX, (int)cs.useRTS);
            PortDCB.BaudRate = cs.baudRate;
            PortDCB.ByteSize = (byte)cs.dataBits;
            PortDCB.Parity = (byte)cs.parity;
            PortDCB.StopBits = (byte)cs.stopBits;
            PortDCB.XoffChar = (byte)cs.XoffChar;
            PortDCB.XonChar = (byte)cs.XonChar;
            if ((cs.rxQueue != 0) || (cs.txQueue != 0))
                if (!Win32Com.SetupComm(hPort, (uint)cs.rxQueue, (uint)cs.txQueue)) ThrowException("Bad queue settings");

            //JH 1.2: Defaulting mechanism for handshake thresholds - prevents problems of setting specific
            //defaults which may violate the size of the actually granted queue. If the user specifically sets
            //these values, it's their problem!
            if ((cs.rxLowWater == 0) || (cs.rxHighWater == 0))
            {
                if (!Win32Com.GetCommProperties(hPort, out cp))	cp.dwCurrentRxQueue = 0;
                if (cp.dwCurrentRxQueue > 0)
                {
                    //If we can determine the queue size, default to 1/10th, 8/10ths, 1/10th.
                    //Note that HighWater is measured from top of queue.
                    PortDCB.XoffLim = PortDCB.XonLim = (short)((int)cp.dwCurrentRxQueue / 10);
                }
                else
                {
                    //If we do not know the queue size, set very low defaults for safety.
                    PortDCB.XoffLim = PortDCB.XonLim = 8;
                }
            }
            else
            {
                PortDCB.XoffLim = (short)cs.rxHighWater;
                PortDCB.XonLim = (short)cs.rxLowWater;
            }

            if (!Win32Com.SetCommState(hPort, ref PortDCB)) ThrowException("Bad com settings");
            if (!Win32Com.SetCommTimeouts(hPort, ref CommTimeouts)) ThrowException("Bad timeout settings");

            stateBRK = 0;
            if (cs.useDTR == HSOutput.none) stateDTR = 0;
            if (cs.useDTR == HSOutput.online) stateDTR = 1;
            if (cs.useRTS == HSOutput.none) stateRTS = 0;
            if (cs.useRTS == HSOutput.online) stateRTS = 1;

            checkSends = cs.checkAllSends;
            wo.Offset = 0;
            wo.OffsetHigh = 0;
            if (checkSends)
                wo.hEvent = writeEvent.Handle;
            else
                wo.hEvent = IntPtr.Zero;

            ptrUWO = Marshal.AllocHGlobal(Marshal.SizeOf(wo));

            Marshal.StructureToPtr(wo, ptrUWO, true);
            writeCount = 0;
            //JH1.3:
            empty[0] = true;
            dataQueued = false;

            rxException = null;
            rxExceptionReported = false;
            rxThread = new Thread(new ThreadStart(this.ReceiveThread));
            rxThread.Name = "CommBaseRx";
            rxThread.Priority = ThreadPriority.AboveNormal;
            rxThread.Start();

            //JH1.2: More robust thread start-up wait.
            startEvent.WaitOne(500, false);

            auto = false;
            if (AfterOpen())
            {
                auto = cs.autoReopen;
                return true;
            }
            else
            {
                Close();
                return false;
            }
        }
Exemple #2
0
        private void ReceiveThread()
        {
            byte[] buf = new Byte[1];
            uint gotbytes;
            bool starting;

            starting = true;
            AutoResetEvent sg = new AutoResetEvent(false);
            Win32Com.OVERLAPPED ov = new Win32Com.OVERLAPPED();

            IntPtr unmanagedOv;
            IntPtr uMask;
            uint eventMask = 0;
            unmanagedOv = Marshal.AllocHGlobal(Marshal.SizeOf(ov));
            uMask = Marshal.AllocHGlobal(Marshal.SizeOf(eventMask));

            ov.Offset = 0; ov.OffsetHigh = 0;
            ov.hEvent = sg.Handle;
            Marshal.StructureToPtr(ov, unmanagedOv, true);

            try
            {
                while(true)
                {
                    if (!Win32Com.SetCommMask(hPort, Win32Com.EV_RXCHAR | Win32Com.EV_TXEMPTY | Win32Com.EV_CTS | Win32Com.EV_DSR
                        | Win32Com.EV_BREAK | Win32Com.EV_RLSD | Win32Com.EV_RING | Win32Com.EV_ERR))
                    {
                        throw new CommPortException("IO Error [001]");
                    }
                    Marshal.WriteInt32(uMask, 0);
                    //JH 1.2: Tells the main thread that this thread is ready for action.
                    if (starting) {startEvent.Set(); starting = false;}
                    if (!Win32Com.WaitCommEvent(hPort, uMask, unmanagedOv))
                    {
                        if (Marshal.GetLastWin32Error() == Win32Com.ERROR_IO_PENDING)
                        {
                            sg.WaitOne();
                        }
                        else
                        {
                            throw new CommPortException("IO Error [002]");
                        }
                    }
                    eventMask = (uint)Marshal.ReadInt32(uMask);
                    if ((eventMask & Win32Com.EV_ERR) != 0)
                    {
                        UInt32 errs;
                        if (Win32Com.ClearCommError(hPort, out errs, IntPtr.Zero))
                        {
                            //JH 1.2: BREAK condition has an error flag and and an event flag. Not sure if both
                            //are always raised, so if CE_BREAK is only error flag ignore it and set the EV_BREAK
                            //flag for normal handling. Also made more robust by handling case were no recognised
                            //error was present in the flags. (Thanks to Fred Pittroff for finding this problem!)
                            int ec = 0;
                            StringBuilder s = new StringBuilder("UART Error: ", 40);
                            if ((errs & Win32Com.CE_FRAME) != 0) {s = s.Append("Framing,"); ec++;}
                            if ((errs & Win32Com.CE_IOE) != 0) {s = s.Append("IO,"); ec++;}
                            if ((errs & Win32Com.CE_OVERRUN) != 0) {s = s.Append("Overrun,"); ec++;}
                            if ((errs & Win32Com.CE_RXOVER) != 0) {s = s.Append("Receive Cverflow,"); ec++;}
                            if ((errs & Win32Com.CE_RXPARITY) != 0) {s = s.Append("Parity,"); ec++;}
                            if ((errs & Win32Com.CE_TXFULL) != 0) {s = s.Append("Transmit Overflow,"); ec++;}
                            if (ec > 0)
                            {
                                s.Length = s.Length - 1;
                                throw new CommPortException(s.ToString());
                            }
                            else
                            {
                                if (errs == Win32Com.CE_BREAK)
                                {
                                    eventMask |= Win32Com.EV_BREAK;
                                }
                                else
                                {
                                    throw new CommPortException("IO Error [003]");
                                }
                            }
                        }
                        else
                        {
                            throw new CommPortException("IO Error [003]");
                        }
                    }
                    if ((eventMask & Win32Com.EV_RXCHAR) != 0)
                    {
                        do
                        {
                            gotbytes = 0;
                            if (!Win32Com.ReadFile(hPort, buf, 1, out gotbytes, unmanagedOv))
                            {
                                //JH 1.1: Removed ERROR_IO_PENDING handling as comm timeouts have now
                                //been set so ReadFile returns immediately. This avoids use of CancelIo
                                //which was causing loss of data. Thanks to Daniel Moth for suggesting this
                                //might be a problem, and to many others for reporting that it was!

                                int x = Marshal.GetLastWin32Error();

                                throw new CommPortException("IO Error [004]");
                            }
                            if (gotbytes == 1) OnRxChar(buf[0]);
                        } while (gotbytes > 0);
                    }
                    if ((eventMask & Win32Com.EV_TXEMPTY) != 0)
                    {
                        //JH1.3:
                        lock(empty) empty[0] = true;
                        OnTxDone();
                    }
                    if ((eventMask & Win32Com.EV_BREAK) != 0) OnBreak();

                    uint i = 0;
                    if ((eventMask & Win32Com.EV_CTS) != 0) i |= Win32Com.MS_CTS_ON;
                    if ((eventMask & Win32Com.EV_DSR) != 0) i |= Win32Com.MS_DSR_ON;
                    if ((eventMask & Win32Com.EV_RLSD) != 0) i |= Win32Com.MS_RLSD_ON;
                    if ((eventMask & Win32Com.EV_RING) != 0) i |= Win32Com.MS_RING_ON;
                    if (i != 0)
                    {
                        uint f;
                        if (!Win32Com.GetCommModemStatus(hPort, out f)) throw new CommPortException("IO Error [005]");
                        OnStatusChange(new ModemStatus(i), new ModemStatus(f));
                    }
                }
            }
            catch (Exception e)
            {
                //JH 1.3: Added for shutdown robustness (Thanks to Fred Pittroff, Mark Behner and Kevin Williamson!), .
                Win32Com.CancelIo(hPort);
                if (uMask != IntPtr.Zero) Marshal.FreeHGlobal(uMask);
                if (unmanagedOv != IntPtr.Zero) Marshal.FreeHGlobal(unmanagedOv);

                if (!(e is ThreadAbortException))
                {
                    rxException = e;
                    OnRxException(e);
                }
            }
        }
Exemple #3
0
        /// <summary>
        /// 向端口写入指定的数据
        /// </summary>
        /// <param name="Data">指定的数据</param>
        /// <returns></returns>
        public bool WriteData(byte[] Data)
        {
            //for (int i = 0; i < Data.Length; i++)
            //    Output(BasePort, Data[i]); 这里原来也想用inpout32实现,但是从字节到int转换比较麻烦,试了几次没达到效果
            //return true;

            if (_iHandle != -1)
            {
                Win32Com.OVERLAPPED x = new Win32Com.OVERLAPPED();
                int i = 0;
                Win32Com.WriteFile(_iHandle, Data, Data.Length, ref i, ref x);
                return true;
            }
            else
            {
                //不能连接到打印机;
                return false;
            }
        }