public static Code FromIRCode(int index, IRCode irCode) { var prontoCode = irCode.ToProntoString(); return new Code { Index = index, ProntoCode = prontoCode, ProntoFormat = IRFormat.FromProntoWord(prontoCode.Substring(0, 4)).Format.ToString() }; }
/// <summary> /// Converts an IrCode into raw data for the device. /// </summary> /// <param name="code">IrCode to convert.</param> /// <returns>Raw device data.</returns> private static byte[] DataPacket(IRCode code) { Log.Trace("DataPacket()"); if (code.TimingData.Length == 0) return null; // Construct data bytes into "packet" ... var packet = new List<byte>(); for (int index = 0; index < code.TimingData.Length; index++) { double time = code.TimingData[index]; byte duration = (byte)Math.Abs(Math.Round(time / TimingResolution)); bool pulse = (time > 0); Log.Trace("{0}{1}", pulse ? '+' : '-', duration * TimingResolution); while (duration > 0x7F) { packet.Add((byte)(pulse ? 0xFF : 0x7F)); duration -= 0x7F; } packet.Add((byte)(pulse ? 0x80 | duration : duration)); } // Insert byte count markers into packet data bytes ... var subpackets = (int)Math.Ceiling(packet.Count / (double)4); var output = new byte[packet.Count + subpackets + 1]; var outputPos = 0; for (int packetPos = 0; packetPos < packet.Count; ) { var copyCount = (byte)(packet.Count - packetPos < 4 ? packet.Count - packetPos : 0x04); output[outputPos++] = (byte)(0x80 | copyCount); for (var index = 0; index < copyCount; index++) output[outputPos++] = packet[packetPos++]; } output[outputPos] = 0x80; return output; }
/// <summary> /// Send an IR Command. /// </summary> /// <param name="code">IR Command data to send.</param> /// <param name="port">IR port to send to.</param> public override void Send(IRCode code, int port) { Log.Trace("Send()"); Log.WriteArray(LogLevel.Trace, code.TimingData); // Reset device (hopefully this will stop the blaster from stalling) //WriteSync(ResetPacket); SetOutputPort(port); SetCarrierFrequency(code.Carrier); // Send packet byte[] data = DataPacket(code); // If the code would go longer than the allowable limit, truncate the code if (data.Length > 341) // 340 minus the overhead of 1 byte in 4 for header is 255 bytes of actual time code data, add one for a terminator byte { Array.Resize(ref data, 341); // Shrink the array to fit data[340] = 0x80; // Set the terminator byte } WriteSync(data); }
/// <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; }
/* public static ushort[] ConvertIrCodeToPronto(IrCode irCode) { CodeFormat codeFormat; Int64 value; if (Decode(irCode, out codeFormat, out value)) return EncodePronto(codeFormat, value); else return null; } */ /// <summary> /// Converts the ir code into Pronto raw format. /// </summary> /// <param name="irCode">The ir code to convert.</param> /// <returns>Pronto data (raw format).</returns> public static ushort[] ConvertIrCodeToProntoRaw(IRCode irCode) { CodeFormat codeFormat; var irCodeCarrier = IRCode.CarrierFrequencyDefault; switch (irCode.Carrier) { case IRCode.CarrierFrequencyDCMode: codeFormat = CodeFormat.RawUnmodulated; irCodeCarrier = IRCode.CarrierFrequencyDefault; break; case IRCode.CarrierFrequencyUnknown: codeFormat = CodeFormat.RawOscillated; irCodeCarrier = IRCode.CarrierFrequencyDefault; break; default: codeFormat = CodeFormat.RawOscillated; irCodeCarrier = irCode.Carrier; break; } var prontoCarrier = ConvertToProntoCarrier(irCodeCarrier); var carrier = prontoCarrier * ProntoClock; var prontoData = irCode.TimingData.Select(Math.Abs) .Select(duration => (ushort) Math.Round(duration/carrier)) .ToList(); if (prontoData.Count % 2 != 0) prontoData.Add(SignalFree); var burstPairs = (ushort)(prontoData.Count / 2); prontoData.Insert(0, (ushort)codeFormat); // Pronto Code Type prontoData.Insert(1, prontoCarrier); // IR Frequency prontoData.Insert(2, burstPairs); // First Burst Pairs prontoData.Insert(3, 0x0000); // Repeat Burst Pairs return prontoData.ToArray(); }
/// <summary> /// Send an IR Command. /// </summary> /// <param name="code">IR Command data to send.</param> /// <param name="port">IR port to send to.</param> public abstract void Send(IRCode code, int port);
internal void OnDeserializedMethod(StreamingContext context) { IRCode = new IRCode(data, bitCount); }
public MayhemIRCode(IRCode code) { SetIRCode(code); }
void ir_Learn(object sender, IRLearnEventArgs e) { codeLearnTextBox.Text = "0x" + e.LearnedCode.Code.ToString(); bitLengthLearnTextBox.Text = e.LearnedCode.CodeInfo.BitCount.ToString(); lengthLearnTextBox.Text = e.LearnedCode.CodeInfo.Length.ToString() + " Length"; encodingTextBox.Text = e.LearnedCode.CodeInfo.Encoding.ToString(); gapTextBox.Text = e.LearnedCode.CodeInfo.Gap.ToString(); if (e.LearnedCode.CodeInfo.Trail != 0) trailTextBox.Text = e.LearnedCode.CodeInfo.Trail.ToString(); else trailTextBox.Text = "None"; oneTextBox.Text = e.LearnedCode.CodeInfo.One[0].ToString() + ", " + e.LearnedCode.CodeInfo.One[1].ToString(); zeroTextBox.Text = e.LearnedCode.CodeInfo.Zero[0].ToString() + ", " + e.LearnedCode.CodeInfo.Zero[1].ToString(); if (e.LearnedCode.CodeInfo.Header != null) { StringBuilder sb = new StringBuilder(e.LearnedCode.CodeInfo.Header.Length * 2); foreach (int i in e.LearnedCode.CodeInfo.Header) { sb.Append(i.ToString()); sb.Append(", "); } headerTextBox.Text = sb.ToString(); } else headerTextBox.Text = "No Header"; if (e.LearnedCode.CodeInfo.ToggleMask != null) { toggleTextBox.Text = "0x" + e.LearnedCode.CodeInfo.ToggleMask.ToString(); } else toggleTextBox.Text = "No Toggle Mask"; if (e.LearnedCode.CodeInfo.Repeat != null) { StringBuilder sb = new StringBuilder(e.LearnedCode.CodeInfo.Repeat.Length * 2); foreach (int i in e.LearnedCode.CodeInfo.Repeat) { sb.Append(i.ToString()); sb.Append(", "); } repeatTextBox.Text = sb.ToString(); } else repeatTextBox.Text = "No Repeat Code"; lastLearnedCode = e.LearnedCode.Code; lastLearnedCodeInfo = e.LearnedCode.CodeInfo; retransmitButton.Enabled = true; }
/// <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)); }
/// <summary> /// Converts an IrCode into raw data for the device. /// </summary> /// <param name="code">IrCode to convert.</param> /// <returns>Raw device data.</returns> internal static byte[] DataPacket(IRCode code) { Log.Trace("DataPacket()"); if (code.TimingData.Length == 0) return null; var data = new byte[code.TimingData.Length*4]; var dataIndex = 0; foreach (var timing in code.TimingData) { var time = (uint) (50*(int) Math.Round((double) timing/50)); for (var timeShift = 0; timeShift < 4; timeShift++) { data[dataIndex++] = (byte) (time & 0xFF); time >>= 8; } } return data; }
/// <summary> /// Send an IR Command. /// </summary> /// <param name="code">IR Command data to send.</param> /// <param name="port">IR port to send to.</param> public override void Send(IRCode code, int port) { Log.Trace("Send()"); Log.WriteArray(LogLevel.Trace, code.TimingData); var data = DataPacket(code); var portMask = 0; // Hardware ports map to bits in mask with Port 1 at left, ascending to right switch ((BlasterPort) port) { case BlasterPort.Both: portMask = _txPortMask; break; case BlasterPort.Port_1: portMask = GetHighBit(_txPortMask, _numTxPorts); break; case BlasterPort.Port_2: portMask = GetHighBit(_txPortMask, _numTxPorts - 1); break; } TransmitIR(data, code.Carrier, portMask); }
void ir_Learn(object sender, IRLearnEventArgs e) { codeLearnTextBox.Text = "0x" + e.LearnedCode.Code.ToString(); bitLengthLearnTextBox.Text = e.LearnedCode.CodeInfo.BitCount.ToString(); lengthLearnTextBox.Text = e.LearnedCode.CodeInfo.Length.ToString() + " Length"; encodingTextBox.Text = e.LearnedCode.CodeInfo.Encoding.ToString(); gapTextBox.Text = e.LearnedCode.CodeInfo.Gap.ToString(); if (e.LearnedCode.CodeInfo.Trail != 0) { trailTextBox.Text = e.LearnedCode.CodeInfo.Trail.ToString(); } else { trailTextBox.Text = "None"; } oneTextBox.Text = e.LearnedCode.CodeInfo.One[0].ToString() + ", " + e.LearnedCode.CodeInfo.One[1].ToString(); zeroTextBox.Text = e.LearnedCode.CodeInfo.Zero[0].ToString() + ", " + e.LearnedCode.CodeInfo.Zero[1].ToString(); if (e.LearnedCode.CodeInfo.Header != null) { StringBuilder sb = new StringBuilder(e.LearnedCode.CodeInfo.Header.Length * 2); foreach (int i in e.LearnedCode.CodeInfo.Header) { sb.Append(i.ToString()); sb.Append(", "); } headerTextBox.Text = sb.ToString(); } else { headerTextBox.Text = "No Header"; } if (e.LearnedCode.CodeInfo.ToggleMask != null) { toggleTextBox.Text = "0x" + e.LearnedCode.CodeInfo.ToggleMask.ToString(); } else { toggleTextBox.Text = "No Toggle Mask"; } if (e.LearnedCode.CodeInfo.Repeat != null) { StringBuilder sb = new StringBuilder(e.LearnedCode.CodeInfo.Repeat.Length * 2); foreach (int i in e.LearnedCode.CodeInfo.Repeat) { sb.Append(i.ToString()); sb.Append(", "); } repeatTextBox.Text = sb.ToString(); } else { repeatTextBox.Text = "No Repeat Code"; } lastLearnedCode = e.LearnedCode.Code; lastLearnedCodeInfo = e.LearnedCode.CodeInfo; retransmitButton.Enabled = true; }
public CodeReceivedEventArgs(IRCode code) { Code = code; }
/// <summary> /// Determines the pulse count and total time of the supplied IrCode. /// This is used to determine the carrier frequency. /// </summary> /// <param name="code">The IrCode to analyse.</param> /// <param name="pulseTime">The total ammount of pulse time.</param> /// <param name="pulseCount">The total count of pulses.</param> private static void GetIrCodeLengths(IRCode code, out int pulseTime, out int pulseCount) { pulseTime = 0; pulseCount = 0; foreach (int time in code.TimingData) { if (time > 0) { pulseTime += time; pulseCount++; } } }
/// <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)); }
internal LearnResult(LearnStatus status, IRCode code) { Status = status; Code = code; }
private void SetIRCode(IRCode code) { irCode = code; bitCount = code.BitCount; data = code.Data; }
public LearnStatus Learn(out IRCode code) { Log.Trace("Learn()"); LearnStatus status; lock (_learnLock) { status = _driver.Learn(_learnTimeout, out code); } return status; }
public bool Transmit(string port, IRCode code) { Log.Trace("Transmit()"); var blasterPort = BlasterPort.Both; try { blasterPort = (BlasterPort) Enum.Parse(typeof (BlasterPort), port, true); } catch (Exception) { Log.Warn("Invalid Blaster Port ({0}), using default {1}", port, blasterPort); } if(code == null) throw new ArgumentException("Invalid IR Command data", "code"); _driver.Send(code, (int)blasterPort); return true; }
/// <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 abstract LearnStatus Learn(int learnTimeout, out IRCode learned);