void SendNxtMessagesThread(ThreadContext ctx) { System.Threading.Thread.CurrentThread.Name = "Connection.SendNxtMessagesThread"; WaitHandle[] waitHandles = new WaitHandle[2]; waitHandles[0] = this.MessageToSendSemaphore; waitHandles[1] = ctx.StopEvent; // // We throttle the sends a little bit in order to avoid overwhelming a samantha. // Without this throttle, QueryAvailableNXTData has been observed to overwhelm the // samantha at times and to drop messages and / or replies (not sure which). // // However (heuristic): we only throttle sends when we've got a bit of queue backed up // int msThrottle = (this.msgReplyTargets.Count > 3) ? 3 : 0; int msPrev = 0; // while (!ctx.StopRequest) { int iWait = WaitHandle.WaitAny(waitHandles); // switch (iWait) { case 0: // MessageToSendSemaphore { NxtMessage msg = null; lock (this.nxtMessagesToSend) { msg = this.nxtMessagesToSend[0]; this.nxtMessagesToSend.RemoveAt(0); } // int msNow = System.Environment.TickCount; int dms = msPrev + msThrottle - msNow; if (dms > 0) { System.Threading.Thread.Sleep(dms); msNow = System.Environment.TickCount; } // this.Send(msg); msPrev = msNow; break; } case 1: // StopEvent break; // end switch } } }
void PostTelemetryRecordsThread(ThreadContext ctx) // Forward incoming telemetry records on to Microsoft Excel { System.Threading.Thread.CurrentThread.Name = "Connection.PostTelemetryRecordsThread"; bool fDone = false; // WaitHandle[] waitHandles = new WaitHandle[2]; waitHandles[0] = this.TelemetryRecordAvailableEvent; waitHandles[1] = ctx.StopEvent; // for (; !ctx.StopRequest && !fDone ;) { int iWait = WaitHandle.WaitAny(waitHandles); switch (iWait) { case 0: // TelemetryRecordAvailableEvent { // There's one or more records there to read. // Read all that we can. for (;!fDone;) { TelemetryRecord telemetryRecord = null; lock (this.TelemetryRecords) { if (0 == this.TelemetryRecords.Count) break; telemetryRecord = this.TelemetryRecords[0]; this.TelemetryRecords.RemoveAt(0); } telemetryRecord.Parse(); // if (telemetryRecord.fEndOfRecordSet) { // If DATUM_TYPE.EOF has been transmitted then subsequent // telemetry records received will go to a new spreadsheet // Program.TheForm.DisconnectTelemetryDestination(); } else if (telemetryRecord.data.Count == 0) { // Empty records don't do anything } else { // Non-emptry records are posted to the appropriate worksheet // TelemetryFTCUI.ShowWaitCursorWhile(() => { Program.TheForm.OpenTelemetryDestinationIfNecessary(); }); telemetryRecord.PostToSheet(); } } break; } case 1: // StopEvent break; // end switch } } }
public virtual void Close() { if (null != this.sendNxtMessagesThread) this.sendNxtMessagesThread.Stop(); if (null != this.postTelemetryMessagesThread) this.postTelemetryMessagesThread.Stop(); this.sendNxtMessagesThread = null; this.postTelemetryMessagesThread = null; }
public virtual bool Open(bool fTraceFailure=true) { if (null == this.sendNxtMessagesThread) { this.sendNxtMessagesThread = new ThreadContext((ctx) => SendNxtMessagesThread((ThreadContext)ctx)); this.sendNxtMessagesThread.Start(); } // if (null == this.postTelemetryMessagesThread) { this.postTelemetryMessagesThread = new ThreadContext((ctx) => PostTelemetryRecordsThread((ThreadContext)ctx)); this.postTelemetryMessagesThread.Start(); } // return true; }
//-------------------------------------------------------------------------- // Data reception //-------------------------------------------------------------------------- unsafe void ReadThread(ThreadContext ctx) { System.Threading.Thread.CurrentThread.Name = "BluetoothConnection.ReadThread"; EventWaitHandle asyncReadCompleteEvent = new EventWaitHandle(false, System.Threading.EventResetMode.ManualReset); NativeOverlapped* pNativeOverlapped = null; byte[] rgbBuffer = new byte[64]; try { WaitHandle[] waitHandles = new WaitHandle[2]; waitHandles[0] = asyncReadCompleteEvent; waitHandles[1] = ctx.StopEvent; // while (!ctx.StopRequest) { // Issue an async read // asyncReadCompleteEvent.Reset(); Overlapped overlapped = new Overlapped(0, 0, asyncReadCompleteEvent.SafeWaitHandle.DangerousGetHandle(), null); pNativeOverlapped = overlapped.Pack(null, rgbBuffer); int cbRead = 0; bool fSuccess = ReadFile(this.hSerialPort, rgbBuffer, rgbBuffer.Length, out cbRead, new IntPtr(pNativeOverlapped)); readThreadRunning.Set(); if (!fSuccess) { int err = Marshal.GetLastWin32Error(); if (err != ERROR_IO_PENDING) ThrowWin32Error(err); } // Wait until either the async read completes or we're asked to stop int iWait = WaitHandle.WaitAny(waitHandles); // Process according to which event fired switch (iWait) { case 0: // Async read completed { ThrowIfFail(GetOverlappedResult(this.hSerialPort, new IntPtr(pNativeOverlapped), ref cbRead, System.Convert.ToByte(true))); // Program.Trace("async read complete: 0x{0:08X} 0x{1:08X} cb={2}", new IntPtr(pNativeOverlapped), this.hSerialPort, cbRead); // Record the new data and process any packets that are now complete this.RecordIncomingData(rgbBuffer, cbRead); ProcessPacketIfPossible(); System.Threading.Overlapped.Free(pNativeOverlapped); pNativeOverlapped = null; } break; case 1: // StopEvent break; // end switch } } } finally { CancelIo(this.hSerialPort); asyncReadCompleteEvent.Close(); if (pNativeOverlapped != null) { System.Threading.Overlapped.Free(pNativeOverlapped); pNativeOverlapped = null; } } }
//-------------------------------------------------------------------------- // Data Reception //-------------------------------------------------------------------------- // http://www.beefycode.com/post/Using-Overlapped-IO-from-Managed-Code.aspx #pragma warning disable 0618 // warning CS0618: 'System.Threading.WaitHandle.Handle' is obsolete: 'Use the SafeWaitHandle property instead.' unsafe void ReadThread(ThreadContext ctx) { System.Threading.Thread.CurrentThread.Name = "USBConnection.ReadThread"; EventWaitHandle asyncReadCompleteEvent = new EventWaitHandle(false, System.Threading.EventResetMode.ManualReset); NativeOverlapped* pNativeOverlapped = null; byte[] rgbBuffer = new byte[64]; try { WaitHandle[] waitHandles = new WaitHandle[2]; waitHandles[0] = asyncReadCompleteEvent; waitHandles[1] = ctx.StopEvent; // // If we get unexpected errors, we stop reading; likely these are caused by a device // in the process of disconnecting. // bool fStop = false; // while (!fStop && !ctx.StopRequest) { // Issue an async read // asyncReadCompleteEvent.Reset(); Overlapped overlapped = new Overlapped(0, 0, asyncReadCompleteEvent.Handle, null); pNativeOverlapped = overlapped.Pack(null, rgbBuffer); int cbRead = 0; // Program.Trace("issuing async read: 0x{0:08X} 0x{1:08X}", new IntPtr(pNativeOverlappedWrite), this.hWinUSB); bool fSuccess = WinUsb_ReadPipe( this.hWinUSB, bulkInPipe, rgbBuffer, rgbBuffer.Length, out cbRead, new IntPtr(pNativeOverlapped)); this.readThreadRunning.Set(); if (!fSuccess) { int err = Marshal.GetLastWin32Error(); if (err != ERROR_IO_PENDING) { Program.Trace("USB Read: WinUsb_ReadPipe=={0}", err); fStop = true; continue; } } // Wait until either the async read completes or we're asked to stop int iWait = WaitHandle.WaitAny(waitHandles); // Process according to which event fired switch (iWait) { case 0: // Async read completed { // Program.Trace("async read complete: 0x{0:08X} 0x{1:08X}", new IntPtr(pNativeOverlappedWrite), this.hWinUSB); if (WinUsb_GetOverlappedResult(this.hWinUSB, new IntPtr(pNativeOverlapped), ref cbRead, System.Convert.ToByte(true))) { ProcessIncomingPacket(rgbBuffer, cbRead); } else { int err = Marshal.GetLastWin32Error(); Program.Trace("USB Read: WinUsb_GetOverlappedResult=={0}", err); fStop = true; } // System.Threading.Overlapped.Free(pNativeOverlapped); pNativeOverlapped = null; } break; case 1: // StopEvent // Program.Trace("async read stop requested"); break; // end switch } } } finally { // Program.Trace("async cleanup: 0x{0:08X} 0x{1:08X}", new IntPtr(pNativeOverlappedWrite), this.hWinUSB); WinUsb_AbortPipe(this.hWinUSB, bulkInPipe); asyncReadCompleteEvent.Close(); if (pNativeOverlapped != null) { System.Threading.Overlapped.Free(pNativeOverlapped); pNativeOverlapped = null; } } }
void ReadThread(ThreadContext ctx) { System.Threading.Thread.CurrentThread.Name = "IPConnection.ReadThread"; EventWaitHandle asyncReadCompleteEvent = new EventWaitHandle(false, System.Threading.EventResetMode.ManualReset); SocketAsyncEventArgs socketAsyncEventArgs = new SignallingSocketEventArgs(asyncReadCompleteEvent); byte[] rgbBuffer = new byte[64]; socketAsyncEventArgs.SetBuffer(rgbBuffer, 0, rgbBuffer.Length); try { WaitHandle[] waitHandles = new WaitHandle[2]; waitHandles[0] = asyncReadCompleteEvent; waitHandles[1] = ctx.StopEvent; bool fStop = false; while (!fStop && !ctx.StopRequest) { // Issue an async read // asyncReadCompleteEvent.Reset(); bool fAsync = true; this.SocketMonitorLock(() => { fAsync = this.socket.ReceiveAsync(socketAsyncEventArgs); }); if (!fAsync) { // IO operation completed synchronously asyncReadCompleteEvent.Set(); } this.readThreadRunning.Set(); // Wait until either the async read completes or we're asked to stop int iWait = WaitHandle.WaitAny(waitHandles); // Process according to which event fired switch (iWait) { case 0: // Async read completed { if (socketAsyncEventArgs.BytesTransferred > 0) { if (socketAsyncEventArgs.SocketError == SocketError.Success) { // Program.Trace("IP Read: incoming packet"); ProcessIncomingPacket(rgbBuffer, socketAsyncEventArgs.BytesTransferred); } else { Program.Trace("IP Read: unexpected async result: cb={0} err={1}", socketAsyncEventArgs.BytesTransferred, socketAsyncEventArgs.SocketError); fStop = true; } } else { // Program.Trace("IP Read: read completed with zero bytes"); } } break; case 1: // StopEvent // Program.Trace("async read stop requested"); break; // end switch } } } finally { } }