/// <summary> /// Synchronously write a packet of bytes to the device. /// </summary> /// <param name="data">Packet to write to device.</param> private void WriteSync(byte[] data) { Log.Trace("WriteSync({0}): ", data.Length); Log.WriteArray(LogLevel.Trace, data); if (!_deviceAvailable) throw new InvalidOperationException("Device not available"); WaitHandle waitHandle = new ManualResetEvent(false); SafeHandle safeWaitHandle = waitHandle.SafeWaitHandle; var waitHandles = new WaitHandle[] { waitHandle }; try { int lastError; var success = false; safeWaitHandle.DangerousAddRef(ref success); if (!success) throw new InvalidOperationException("Failed to initialize safe wait handle"); var overlapped = new DeviceIoOverlapped(); overlapped.ClearAndSetEvent(safeWaitHandle.DangerousGetHandle()); int bytesWritten; var writeDevice = WriteFile(_writeHandle, data, data.Length, out bytesWritten, overlapped.Overlapped); lastError = Marshal.GetLastWin32Error(); if (writeDevice) return; if (lastError != ErrorSuccess && lastError != ErrorIoPending) throw new Win32Exception(lastError); var handle = WaitHandle.WaitAny(waitHandles, WriteSyncTimeout, false); if (handle == ErrorWaitTimeout) throw new TimeoutException("Timeout trying to write data to device"); if (handle != 0) throw new InvalidOperationException(String.Format("Invalid wait handle return: {0}", handle)); var getOverlapped = GetOverlappedResult(_writeHandle, overlapped.Overlapped, out bytesWritten, true); lastError = Marshal.GetLastWin32Error(); if (!getOverlapped && lastError != ErrorSuccess) throw new Win32Exception(lastError); Thread.Sleep(PacketTimeout); } catch { if (_writeHandle != null) CancelIo(_writeHandle); throw; } finally { safeWaitHandle.DangerousRelease(); waitHandle.Close(); } }
/// <summary> /// Device read thread method. /// </summary> private void ReadThread() { byte[] packetBytes; WaitHandle waitHandle = new ManualResetEvent(false); SafeHandle safeWaitHandle = waitHandle.SafeWaitHandle; var waitHandles = new WaitHandle[] { waitHandle, _stopReadThread }; var deviceBufferPtr = IntPtr.Zero; var success = false; safeWaitHandle.DangerousAddRef(ref success); if (!success) throw new InvalidOperationException("Failed to initialize safe wait handle"); try { var dangerousWaitHandle = safeWaitHandle.DangerousGetHandle(); var overlapped = new DeviceIoOverlapped(); overlapped.ClearAndSetEvent(dangerousWaitHandle); deviceBufferPtr = Marshal.AllocHGlobal(DeviceBufferSize); while (_readThreadMode != ReadThreadMode.Stop) { int lastError; int bytesRead; var readDevice = ReadFile(_readHandle, deviceBufferPtr, DeviceBufferSize, out bytesRead, overlapped.Overlapped); lastError = Marshal.GetLastWin32Error(); switch (_readThreadMode) { case ReadThreadMode.Receiving: FireStateChanged(new StateChangedEventArgs(RunningState.Started, ReceivingState.Receiving)); break; case ReadThreadMode.Learning: FireStateChanged(new StateChangedEventArgs(RunningState.Started, ReceivingState.Learning)); break; } if (!readDevice) { if (lastError != ErrorSuccess && lastError != ErrorIoPending) throw new Win32Exception(lastError); while (true) { var handle = WaitHandle.WaitAny(waitHandles, 2*PacketTimeout, false); if (handle == ErrorWaitTimeout) continue; if (handle == 0) break; if (handle == 1) throw new ThreadInterruptedException("Read thread stopping by request"); throw new InvalidOperationException(String.Format("Invalid wait handle return: {0}", handle)); } var getOverlapped = GetOverlappedResult(_readHandle, overlapped.Overlapped, out bytesRead, true); lastError = Marshal.GetLastWin32Error(); if (!getOverlapped && lastError != ErrorSuccess) throw new Win32Exception(lastError); } if (bytesRead == 0) continue; packetBytes = new byte[bytesRead]; Marshal.Copy(deviceBufferPtr, packetBytes, 0, bytesRead); Log.Trace("Received bytes ({0}): ", bytesRead); Log.WriteArray(LogLevel.Trace, packetBytes); int[] timingData = null; if (_decodeCarry != 0 || packetBytes[0] >= 0x81 && packetBytes[0] <= 0x9E) { timingData = GetTimingDataFromPacket(packetBytes); } else { double firmware = 0.0; var indexOfFF = Array.IndexOf(packetBytes, (byte) 0xFF); while (indexOfFF != -1) { if (packetBytes.Length > indexOfFF + 2 && packetBytes[indexOfFF + 1] == 0x0B) // FF 0B XY - Firmware X.Y00 { byte b1 = packetBytes[indexOfFF + 2]; firmware += (b1 >> 4) + (0.1*(b1 & 0x0F)); Log.Debug("Firmware: {0}", firmware); } if (packetBytes.Length > indexOfFF + 2 && packetBytes[indexOfFF + 1] == 0x1B) // FF 1B XY - Firmware 0.0XY { byte b1 = packetBytes[indexOfFF + 2]; firmware += (0.01*(b1 >> 4)) + (0.001*(b1 & 0x0F)); Log.Debug("Firmware: {0}", firmware); } if (packetBytes.Length > indexOfFF + 1) indexOfFF = Array.IndexOf(packetBytes, (byte) 0xFF, indexOfFF + 1); else break; } } switch (_readThreadMode) { case ReadThreadMode.Receiving: { var code = new IRCode(timingData); code.FinalizeData(); FireCodeReceived(new CodeReceivedEventArgs(code)); break; } case ReadThreadMode.Learning: { if (timingData == null) { if (_learningCode.TimingData.Length > 0) { _learningCode = null; _readThreadMode = ReadThreadMode.LearningFailed; } break; } if (_learningCode == null) throw new InvalidOperationException( "Learning not initialised correctly, _learningCode object is null"); _learningCode.AddTimingData(timingData); // Example: 9F 01 02 9F 15 00 BE 80 var indexOf9F = Array.IndexOf(packetBytes, (byte) 0x9F); while (indexOf9F != -1) { if (packetBytes.Length > indexOf9F + 3 && packetBytes[indexOf9F + 1] == 0x15) // 9F 15 XX XX { byte b1 = packetBytes[indexOf9F + 2]; byte b2 = packetBytes[indexOf9F + 3]; int onTime, onCount; GetIrCodeLengths(_learningCode, out onTime, out onCount); double carrierCount = (b1*256) + b2; if (carrierCount/onCount < 2.0) { _learningCode.Carrier = IRCode.CarrierFrequencyDCMode; } else { double carrier = 1000000*carrierCount/onTime; // TODO: Double-Check this calculation. if (carrier > 32000) { _learningCode.Carrier = (int) (carrier + 0.05*carrier - 0.666667); // was: _learningCode.Carrier = (int) (carrier + 0.05*carrier - 32000/48000); } else { _learningCode.Carrier = (int) carrier; } } _readThreadMode = ReadThreadMode.LearningDone; break; } if (packetBytes.Length > indexOf9F + 1) { indexOf9F = Array.IndexOf(packetBytes, (byte) 0x9F, indexOf9F + 1); } else { _readThreadMode = ReadThreadMode.LearningFailed; break; } } break; } } } FireStateChanged(new StateChangedEventArgs(RunningState.Stopping)); } catch (ThreadInterruptedException ex) { Log.Info(ex); if (_readHandle != null) CancelIo(_readHandle); } catch (Exception ex) { Log.Warn(ex); if (_readHandle != null) CancelIo(_readHandle); } finally { if (deviceBufferPtr != IntPtr.Zero) Marshal.FreeHGlobal(deviceBufferPtr); safeWaitHandle.DangerousRelease(); waitHandle.Close(); } Log.Debug("Read Thread Ended"); FireStateChanged(new StateChangedEventArgs(RunningState.Stopped)); }
private void IoControl(IoCtrl ioControlCode, IntPtr inBuffer, int inBufferSize, IntPtr outBuffer, int outBufferSize, out int bytesReturned) { if (!_deviceAvailable) throw new InvalidOperationException("Device not available"); using (WaitHandle waitHandle = new ManualResetEvent(false)) { SafeHandle safeWaitHandle = waitHandle.SafeWaitHandle; var success = false; safeWaitHandle.DangerousAddRef(ref success); if (!success) throw new InvalidOperationException("Failed to initialize safe wait handle"); try { var dangerousWaitHandle = safeWaitHandle.DangerousGetHandle(); var overlapped = new DeviceIoOverlapped(); overlapped.ClearAndSetEvent(dangerousWaitHandle); var deviceIoControl = DeviceIoControl(_eHomeHandle, ioControlCode, inBuffer, inBufferSize, outBuffer, outBufferSize, out bytesReturned, overlapped.Overlapped); var lastError = Marshal.GetLastWin32Error(); if (deviceIoControl) return; // Now also handles Operation Aborted and Bad Command errors. switch (lastError) { case ErrorIoPending: waitHandle.WaitOne(); var getOverlapped = GetOverlappedResult(_eHomeHandle, overlapped.Overlapped, out bytesReturned, false); lastError = Marshal.GetLastWin32Error(); if (!getOverlapped) { if (lastError == ErrorBadCommand) goto case ErrorBadCommand; if (lastError == ErrorOperationAborted) goto case ErrorOperationAborted; throw new Win32Exception(lastError); } break; case ErrorBadCommand: if (Thread.CurrentThread == _readThread) //Cause receive restart _deviceReceiveStarted = false; break; case ErrorOperationAborted: if (Thread.CurrentThread != _readThread) throw new Win32Exception(lastError); //Cause receive restart _deviceReceiveStarted = false; break; default: throw new Win32Exception(lastError); } } catch { Log.Warn("IoControl: something went bad with StructToPtr or the other way around"); if (_eHomeHandle != null) CancelIo(_eHomeHandle); throw; } finally { safeWaitHandle.DangerousRelease(); } } }