Пример #1
0
        /// <summary>
        /// Transmit an infrared command.
        /// </summary>
        /// <param name="port">Port to transmit on.</param>
        /// <param name="data">Data to transmit.</param>
        /// <returns><c>true</c> if successful, otherwise <c>false</c>.</returns>
        public bool Transmit(string port, byte[] data)
        {
            BlasterPort blasterPort = BlasterPort.Both;

            try
            {
                blasterPort = (BlasterPort)Enum.Parse(typeof(BlasterPort), port, true);
            }
            catch
            {
#if TRACE
                Trace.WriteLine(String.Format("Invalid Blaster Port ({0}), using default ({1})", port, blasterPort));
#endif
            }

            IrCode code = IrCode.FromByteArray(data);

            if (code == null)
            {
                throw new ArgumentException("Invalid IR Command data", "data");
            }

            _driver.Send(code, (int)blasterPort);

            return(true);
        }
Пример #2
0
        /// <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)
        {
            DebugWriteLine("DataPacket()");

            if (code.TimingData.Length == 0)
            {
                return(null);
            }

            // Construct data bytes into "packet" ...
            List <byte> 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);

                DebugWrite("{0}{1}, ", pulse ? '+' : '-', duration * TimingResolution);

                while (duration > 0x7F)
                {
                    packet.Add((byte)(pulse ? 0xFF : 0x7F));

                    duration -= 0x7F;
                }

                packet.Add((byte)(pulse ? 0x80 | duration : duration));
            }

            DebugWriteNewLine();

            // Insert byte count markers into packet data bytes ...
            int subpackets = (int)Math.Ceiling(packet.Count / (double)4);

            byte[] output = new byte[packet.Count + subpackets + 1];

            int outputPos = 0;

            for (int packetPos = 0; packetPos < packet.Count;)
            {
                byte copyCount = (byte)(packet.Count - packetPos < 4 ? packet.Count - packetPos : 0x04);

                output[outputPos++] = (byte)(0x80 | copyCount);

                for (int index = 0; index < copyCount; index++)
                {
                    output[outputPos++] = packet[packetPos++];
                }
            }

            output[outputPos] = 0x80;

            return(output);
        }
Пример #3
0
        /// <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)
        {
            DebugWriteLine("Learn()");

            learned       = null;
            _learningCode = new IrCode();

            SetInputPort(InputPort.Learning);

            int learnStartTick = Environment.TickCount;

            _readThreadMode = ReadThreadMode.Learning;

            // Wait for the learning to finish ...
            while (_readThreadMode == ReadThreadMode.Learning && Environment.TickCount < learnStartTick + learnTimeout)
            {
                Thread.Sleep(PacketTimeout);
            }

            DebugWriteLine("End Learn");

            ReadThreadMode modeWas = _readThreadMode;

            _readThreadMode = ReadThreadMode.Receiving;
            SetInputPort(InputPort.Receive);

            LearnStatus status = LearnStatus.Failure;

            switch (modeWas)
            {
            case ReadThreadMode.Learning:
                status = LearnStatus.Timeout;
                break;

            case ReadThreadMode.LearningFailed:
                status = LearnStatus.Failure;
                break;

            case ReadThreadMode.LearningDone:
                DebugDump(_learningCode.TimingData);
                if (_learningCode.FinalizeData())
                {
                    learned = _learningCode;
                    status  = LearnStatus.Success;
                }
                break;
            }

            _learningCode = null;
            return(status);
        }
Пример #4
0
        /*
         * public static ushort[] ConvertIrCodeToPronto(IrCode irCode)
         * {
         * CodeType codeType;
         * Int64 value;
         *
         * if (Decode(irCode, out codeType, out value))
         *  return EncodePronto(codeType, 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)
        {
            List <ushort> prontoData = new List <ushort>();

            double   carrier;
            ushort   prontoCarrier;
            CodeType codeType;

            int irCodeCarrier = IrCode.CarrierFrequencyDefault;

            switch (irCode.Carrier)
            {
            case IrCode.CarrierFrequencyDCMode:
                codeType      = CodeType.RawUnmodulated;
                irCodeCarrier = IrCode.CarrierFrequencyDefault;
                break;

            case IrCode.CarrierFrequencyUnknown:
                codeType      = CodeType.RawOscillated;
                irCodeCarrier = IrCode.CarrierFrequencyDefault;
                break;

            default:
                codeType      = CodeType.RawOscillated;
                irCodeCarrier = irCode.Carrier;
                break;
            }

            prontoCarrier = ConvertToProntoCarrier(irCodeCarrier);
            carrier       = prontoCarrier * ProntoClock;

            for (int index = 0; index < irCode.TimingData.Length; index++)
            {
                int duration = Math.Abs(irCode.TimingData[index]);
                prontoData.Add((ushort)Math.Round(duration / carrier));
            }

            if (prontoData.Count % 2 != 0)
            {
                prontoData.Add(SignalFree);
            }

            ushort burstPairs = (ushort)(prontoData.Count / 2);

            prontoData.Insert(0, (ushort)codeType); // 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());
        }
Пример #5
0
        /// <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++;
                }
            }
        }
Пример #6
0
        /// <summary>
        /// Creates an IrCode object from Pronto format file bytes.
        /// </summary>
        /// <param name="data">IR file bytes.</param>
        /// <returns>New IrCode object.</returns>
        private static IrCode FromProntoData(byte[] data)
        {
            string code = Encoding.ASCII.GetString(data);

            string[] stringData = code.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);

            ushort[] prontoData = new ushort[stringData.Length];
            for (int i = 0; i < stringData.Length; i++)
            {
                prontoData[i] = ushort.Parse(stringData[i], NumberStyles.HexNumber);
            }

            IrCode newCode = Pronto.ConvertProntoDataToIrCode(prontoData);

            if (newCode != null)
            {
                newCode.FinalizeData();
            }
            // Seems some old files have excessively long delays in them .. this might fix that problem ...

            return(newCode);
        }
Пример #7
0
        /// <summary>
        /// Creates an IrCode object from old IR file bytes.
        /// </summary>
        /// <param name="data">IR file bytes.</param>
        /// <returns>New IrCode object.</returns>
        private static IrCode FromOldData(byte[] data)
        {
            List <int> timingData = new List <int>();

            int len = 0;

            for (int index = 0; index < data.Length; index++)
            {
                byte curByte = data[index];

                if ((curByte & 0x80) != 0)
                {
                    len += (curByte & 0x7F);
                }
                else
                {
                    len -= curByte;
                }

                if ((curByte & 0x7F) != 0x7F)
                {
                    timingData.Add(len * 50);
                    len = 0;
                }
            }

            if (len != 0)
            {
                timingData.Add(len * 50);
            }

            IrCode newCode = new IrCode(timingData.ToArray());

            newCode.FinalizeData();
            // Seems some old files have excessively long delays in them .. this might fix that problem ...

            return(newCode);
        }
Пример #8
0
        /// <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)
        {
            DebugWrite("Send(): ");
            DebugDump(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);
        }
Пример #9
0
        /// <summary>
        /// Device read thread method.
        /// </summary>
        private void ReadThread()
        {
            byte[] packetBytes;

            WaitHandle waitHandle     = new ManualResetEvent(false);
            SafeHandle safeWaitHandle = waitHandle.SafeWaitHandle;

            WaitHandle[] waitHandles = new WaitHandle[] { waitHandle, _stopReadThread };

            IntPtr deviceBufferPtr = IntPtr.Zero;

            bool success = false;

            safeWaitHandle.DangerousAddRef(ref success);
            if (!success)
            {
                throw new InvalidOperationException("Failed to initialize safe wait handle");
            }

            try
            {
                IntPtr dangerousWaitHandle = safeWaitHandle.DangerousGetHandle();

                DeviceIoOverlapped overlapped = new DeviceIoOverlapped();
                overlapped.ClearAndSetEvent(dangerousWaitHandle);

                deviceBufferPtr = Marshal.AllocHGlobal(DeviceBufferSize);

                while (_readThreadMode != ReadThreadMode.Stop)
                {
                    int  lastError;
                    int  bytesRead;
                    bool readDevice = ReadFile(_readHandle, deviceBufferPtr, DeviceBufferSize, out bytesRead,
                                               overlapped.Overlapped);
                    lastError = Marshal.GetLastWin32Error();

                    if (!readDevice)
                    {
                        if (lastError != ErrorSuccess && lastError != ErrorIoPending)
                        {
                            throw new Win32Exception(lastError);
                        }

                        while (true)
                        {
                            int 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));
                        }

                        bool 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);

                    DebugWrite("Received bytes ({0}): ", bytesRead);
                    DebugDump(packetBytes);

                    int[] timingData = null;

                    if (_decodeCarry != 0 || packetBytes[0] >= 0x81 && packetBytes[0] <= 0x9E)
                    {
                        timingData = GetTimingDataFromPacket(packetBytes);
                    }
                    else
                    {
                        double firmware = 0.0;

                        int 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));
                                DebugWriteLine("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));
                                DebugWriteLine("Firmware: {0}", firmware);
                            }

                            if (packetBytes.Length > indexOfFF + 1)
                            {
                                indexOfFF = Array.IndexOf(packetBytes, (byte)0xFF, indexOfFF + 1);
                            }
                            else
                            {
                                break;
                            }
                        }
                    }

                    switch (_readThreadMode)
                    {
                    case ReadThreadMode.Receiving:
                    {
                        IrDecoder.DecodeIR(timingData, _remoteCallback, _keyboardCallback, _mouseCallback);
                        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
                        int 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;
                    }
                    }
                }
            }
            catch (ThreadInterruptedException ex)
            {
                DebugWriteLine(ex.Message);

                if (_readHandle != null)
                {
                    CancelIo(_readHandle);
                }
            }
            catch (Exception ex)
            {
                DebugWriteLine(ex.ToString());

                if (_readHandle != null)
                {
                    CancelIo(_readHandle);
                }
            }
            finally
            {
                if (deviceBufferPtr != IntPtr.Zero)
                {
                    Marshal.FreeHGlobal(deviceBufferPtr);
                }

                safeWaitHandle.DangerousRelease();
                waitHandle.Close();
            }

            DebugWriteLine("Read Thread Ended");
        }
Пример #10
0
 /// <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);
Пример #11
0
    /// <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)
    {
      DebugWrite("Send(): ");
      DebugDump(code.TimingData);

      byte[] data = DataPacket(code);

      int 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);
    }
Пример #12
0
    /// <summary>
    /// Creates an IrCode object from old IR file bytes.
    /// </summary>
    /// <param name="data">IR file bytes.</param>
    /// <returns>New IrCode object.</returns>
    private static IrCode FromOldData(byte[] data)
    {
      List<int> timingData = new List<int>();

      int len = 0;

      for (int index = 0; index < data.Length; index++)
      {
        byte curByte = data[index];

        if ((curByte & 0x80) != 0)
          len += (curByte & 0x7F);
        else
          len -= curByte;

        if ((curByte & 0x7F) != 0x7F)
        {
          timingData.Add(len * 50);
          len = 0;
        }
      }

      if (len != 0)
        timingData.Add(len * 50);

      IrCode newCode = new IrCode(timingData.ToArray());
      newCode.FinalizeData();
      // Seems some old files have excessively long delays in them .. this might fix that problem ...

      return newCode;
    }
    /// <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)
    {
      DebugWrite("Send(): ");
      DebugDump(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>
    /// 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++;
        }
      }
    }
Пример #15
0
    /*
    public static ushort[] ConvertIrCodeToPronto(IrCode irCode)
    {
      CodeType codeType;
      Int64 value;

      if (Decode(irCode, out codeType, out value))
        return EncodePronto(codeType, 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)
    {
      List<ushort> prontoData = new List<ushort>();

      double carrier;
      ushort prontoCarrier;
      CodeType codeType;

      int irCodeCarrier = IrCode.CarrierFrequencyDefault;

      switch (irCode.Carrier)
      {
        case IrCode.CarrierFrequencyDCMode:
          codeType = CodeType.RawUnmodulated;
          irCodeCarrier = IrCode.CarrierFrequencyDefault;
          break;

        case IrCode.CarrierFrequencyUnknown:
          codeType = CodeType.RawOscillated;
          irCodeCarrier = IrCode.CarrierFrequencyDefault;
          break;

        default:
          codeType = CodeType.RawOscillated;
          irCodeCarrier = irCode.Carrier;
          break;
      }

      prontoCarrier = ConvertToProntoCarrier(irCodeCarrier);
      carrier = prontoCarrier * ProntoClock;

      for (int index = 0; index < irCode.TimingData.Length; index++)
      {
        int duration = Math.Abs(irCode.TimingData[index]);
        prontoData.Add((ushort) Math.Round(duration / carrier));
      }

      if (prontoData.Count % 2 != 0)
        prontoData.Add(SignalFree);

      ushort burstPairs = (ushort) (prontoData.Count / 2);

      prontoData.Insert(0, (ushort) codeType); // 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();
    }
Пример #16
0
 /// <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);
Пример #17
0
 /// <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);
    /// <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)
    {
      DebugWriteLine("DataPacket()");

      if (code.TimingData.Length == 0)
        return null;

      // Construct data bytes into "packet" ...
      List<byte> 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);

        DebugWrite("{0}{1}, ", pulse ? '+' : '-', duration * TimingResolution);

        while (duration > 0x7F)
        {
          packet.Add((byte) (pulse ? 0xFF : 0x7F));

          duration -= 0x7F;
        }

        packet.Add((byte) (pulse ? 0x80 | duration : duration));
      }

      DebugWriteNewLine();

      // Insert byte count markers into packet data bytes ...
      int subpackets = (int) Math.Ceiling(packet.Count / (double) 4);

      byte[] output = new byte[packet.Count + subpackets + 1];

      int outputPos = 0;

      for (int packetPos = 0; packetPos < packet.Count;)
      {
        byte copyCount = (byte) (packet.Count - packetPos < 4 ? packet.Count - packetPos : 0x04);

        output[outputPos++] = (byte) (0x80 | copyCount);

        for (int index = 0; index < copyCount; index++)
          output[outputPos++] = packet[packetPos++];
      }

      output[outputPos] = 0x80;

      return output;
    }
Пример #19
0
    /// <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)
    {
      DebugWriteLine("Learn()");

      RestartReadThread(ReadThreadMode.Learning);

      learned = null;
      _learningCode = new IrCode();

      int learnStartTick = Environment.TickCount;

      // Wait for the learning to finish ...
      while (_readThreadMode == ReadThreadMode.Learning && Environment.TickCount < learnStartTick + learnTimeout)
        Thread.Sleep(PacketTimeout);

      DebugWriteLine("End Learn");

      ReadThreadMode modeWas = _readThreadMode;

      RestartReadThread(ReadThreadMode.Receiving);

      LearnStatus status = LearnStatus.Failure;

      switch (modeWas)
      {
        case ReadThreadMode.Learning:
          status = LearnStatus.Timeout;
          break;

        case ReadThreadMode.LearningFailed:
          status = LearnStatus.Failure;
          break;

        case ReadThreadMode.LearningDone:
          DebugDump(_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;
      WaitHandle[] waitHandles = new WaitHandle[] {waitHandle, _stopReadThread};

      IntPtr deviceBufferPtr = IntPtr.Zero;

      bool success = false;
      safeWaitHandle.DangerousAddRef(ref success);
      if (!success)
        throw new InvalidOperationException("Failed to initialize safe wait handle");

      try
      {
        IntPtr dangerousWaitHandle = safeWaitHandle.DangerousGetHandle();

        DeviceIoOverlapped overlapped = new DeviceIoOverlapped();
        overlapped.ClearAndSetEvent(dangerousWaitHandle);

        deviceBufferPtr = Marshal.AllocHGlobal(DeviceBufferSize);

        while (_readThreadMode != ReadThreadMode.Stop)
        {
          int lastError;
          int bytesRead;
          bool readDevice = ReadFile(_readHandle, deviceBufferPtr, DeviceBufferSize, out bytesRead,
                                     overlapped.Overlapped);
          lastError = Marshal.GetLastWin32Error();

          if (!readDevice)
          {
            if (lastError != ErrorSuccess && lastError != ErrorIoPending)
              throw new Win32Exception(lastError);

            while (true)
            {
              int 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));
            }

            bool 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);

          DebugWrite("Received bytes ({0}): ", bytesRead);
          DebugDump(packetBytes);

          int[] timingData = null;

          if (_decodeCarry != 0 || packetBytes[0] >= 0x81 && packetBytes[0] <= 0x9E)
          {
            timingData = GetTimingDataFromPacket(packetBytes);
          }
          else
          {
            double firmware = 0.0;

            int 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));
                DebugWriteLine("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));
                DebugWriteLine("Firmware: {0}", firmware);
              }

              if (packetBytes.Length > indexOfFF + 1)
                indexOfFF = Array.IndexOf(packetBytes, (byte) 0xFF, indexOfFF + 1);
              else
                break;
            }
          }

          switch (_readThreadMode)
          {
            case ReadThreadMode.Receiving:
              {
                IrDecoder.DecodeIR(timingData, _remoteCallback, _keyboardCallback, _mouseCallback);
                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
                int 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;
              }
          }
        }
      }
      catch (ThreadInterruptedException ex)
      {
        DebugWriteLine(ex.Message);

        if (_readHandle != null)
          CancelIo(_readHandle);
      }
      catch (Exception ex)
      {
        DebugWriteLine(ex.ToString());

        if (_readHandle != null)
          CancelIo(_readHandle);
      }
      finally
      {
        if (deviceBufferPtr != IntPtr.Zero)
          Marshal.FreeHGlobal(deviceBufferPtr);

        safeWaitHandle.DangerousRelease();
        waitHandle.Close();
      }

      DebugWriteLine("Read Thread Ended");
    }
Пример #21
0
    /// <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)
    {
      DebugWriteLine("DataPacket()");

      if (code.TimingData.Length == 0)
        return null;

      byte[] data = new byte[code.TimingData.Length * 4];

      int dataIndex = 0;
      for (int timeIndex = 0; timeIndex < code.TimingData.Length; timeIndex++)
      {
        uint time = (uint)(50 * (int)Math.Round((double)code.TimingData[timeIndex] / 50));

        for (int timeShift = 0; timeShift < 4; timeShift++)
        {
          data[dataIndex++] = (byte)(time & 0xFF);
          time >>= 8;
        }
      }

      return data;
    }
Пример #22
0
 /// <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);