/// <summary> /// Learn an IR Command. /// </summary> /// <param name="learnTimeout">How long to wait before aborting learn.</param> /// <param name="learned">Newly learned IR Command.</param> /// <returns>Learn status.</returns> public override LearnStatus Learn(int learnTimeout, out IRCode learned) { Log.Trace("Learn()"); learned = null; _learningCode = new IRCode(); SetInputPort(InputPort.Learning); var learnStartTick = Environment.TickCount; _readThreadMode = ReadThreadMode.Learning; // Wait for the learning to finish ... while (_readThreadMode == ReadThreadMode.Learning && Environment.TickCount < learnStartTick + learnTimeout) Thread.Sleep(PacketTimeout); Log.Trace("End Learn"); var modeWas = _readThreadMode; _readThreadMode = ReadThreadMode.Receiving; SetInputPort(InputPort.Receive); var status = LearnStatus.Failure; switch (modeWas) { case ReadThreadMode.Learning: status = LearnStatus.Timeout; break; case ReadThreadMode.LearningFailed: status = LearnStatus.Failure; break; case ReadThreadMode.LearningDone: Log.WriteArray(LogLevel.Trace, _learningCode.TimingData); if (_learningCode.FinalizeData()) { learned = _learningCode; status = LearnStatus.Success; } break; } _learningCode = null; return status; }
/// <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)); }
/// <summary> /// Device read thread method. /// </summary> private void ReadThread() { var receiveParamsPtr = IntPtr.Zero; try { IReceiveParams receiveParams; if (_isSystem64Bit) { receiveParams = new ReceiveParams64(); } else { receiveParams = new ReceiveParams32(); } var receiveParamsSize = Marshal.SizeOf(receiveParams) + DeviceBufferSize + 8; receiveParamsPtr = Marshal.AllocHGlobal(receiveParamsSize); receiveParams.ByteCount = DeviceBufferSize; Marshal.StructureToPtr(receiveParams, receiveParamsPtr, false); while (_readThreadMode != ReadThreadMode.Stop) { // Cycle thread if device stopped reading. if (!_deviceReceiveStarted) { StartReceive(_readThreadModeNext == ReadThreadMode.Receiving ? _receivePort : _learnPort, PacketTimeout); _readThreadMode = _readThreadModeNext; _deviceReceiveStarted = true; switch (_readThreadMode) { case ReadThreadMode.Receiving: FireStateChanged(new StateChangedEventArgs(RunningState.Started, ReceivingState.Receiving)); break; case ReadThreadMode.Learning: FireStateChanged(new StateChangedEventArgs(RunningState.Started, ReceivingState.Learning)); break; } } int bytesRead; IoControl(IoCtrl.Receive, IntPtr.Zero, 0, receiveParamsPtr, receiveParamsSize, out bytesRead); if (bytesRead > Marshal.SizeOf(receiveParams)) { var dataSize = bytesRead; bytesRead -= Marshal.SizeOf(receiveParams); var packetBytes = new byte[bytesRead]; var dataBytes = new byte[dataSize]; Marshal.Copy(receiveParamsPtr, dataBytes, 0, dataSize); Array.Copy(dataBytes, dataSize - bytesRead, packetBytes, 0, bytesRead); var timingData = GetTimingDataFromPacket(packetBytes); Log.Trace("{0:yyyy-MM-dd HH:mm:ss.ffffff} - ", DateTime.Now); Log.Trace("Received timing: "); Log.WriteArray(LogLevel.Trace, timingData); if (_readThreadMode == ReadThreadMode.Learning) _learningCode.AddTimingData(timingData); else { var code = new IRCode(timingData); code.FinalizeData(); FireCodeReceived(new CodeReceivedEventArgs(code)); } } // Determine carrier frequency when learning ... Log.Trace("bytesRead: {0}, receiveParams Size: {1}", bytesRead, Marshal.SizeOf(receiveParams)); if (_readThreadMode == ReadThreadMode.Learning && bytesRead >= Marshal.SizeOf(receiveParams)) { IReceiveParams receiveParams2; if (_isSystem64Bit) { receiveParams2 = (ReceiveParams64) Marshal.PtrToStructure(receiveParamsPtr, receiveParams.GetType()); } else { receiveParams2 = (ReceiveParams32) Marshal.PtrToStructure(receiveParamsPtr, receiveParams.GetType()); } Log.Trace("DataEnd {0}", Convert.ToInt64(receiveParams2.DataEnd)); if (Convert.ToInt64(receiveParams2.DataEnd) != 0) { _learningCode.Carrier = Convert.ToInt32(receiveParams2.CarrierFrequency); _readThreadMode = ReadThreadMode.LearningDone; } } } FireStateChanged(new StateChangedEventArgs(RunningState.Stopping)); } catch (Exception ex) { Log.Warn(ex); if (_eHomeHandle != null) CancelIo(_eHomeHandle); } finally { if (receiveParamsPtr != IntPtr.Zero) Marshal.FreeHGlobal(receiveParamsPtr); try { if (_eHomeHandle != null) StopReceive(); } catch (Exception ex) { Log.Warn(ex); } } Log.Debug("Read Thread Ended"); FireStateChanged(new StateChangedEventArgs(RunningState.Stopped)); }