USB IR Toy: Sampling mode

From DP

Jump to: navigation , search



USB IR Toy firmware v04+ has an infrared sampling mode that was added for a USB IR Toy WinLIRC plugin. This mode times the duration of infrared pulses and sends the measurements to the computer. This is far superior to the old IRIO mode.

Enter IR sample mode

The IR Toy appears as a serial port. Open it at any speed, 8/N/1.

First send 0x00 (raw byte value 0) to reset from any other mode. It might be good to send it 5 times to be sure it's out of SUMP mode too.

Next, send 's' or 'S' to enter IR sample mode. The IR Toy will respond with the protocol version (currently S01).

Now the bytes start flowing on any IR activity.

Timing information format

IRsample mode will spit out timing measurements for any IR activity it detects. 0xffff is sent after there hasn't been any activity for 1.7seconds.

The protocol is very simple. It might need to be updated in the future (see potential issues).

pulse1-high8 pulse1-low8 blank1-high8 blank1-low8 ... blankn-high8 blankn-low8

The first IR pulse starts a timer that measures length of the pulse. The length is returned as a 16bit count, high byte first. Multiply the raw 16bit timer value by 21.3333us to determine the actual length in microseconds.

The IR Toy continues to spit out measurements of each pulse and the blank space between. Sampling stops when there is no IR change for a full (0xffff) period of 1.7seconds. This will hopefully end during a blank period, but could be a pulse period if an IR jammer were in use. After a full period of no change the IR Toy 'sleeps' and won't send any more data until the beginning of the next IR pulse.

Calculate the duration in microseconds (us)

To get the actual width of each pulse or space:

  • Combine the high and low byte
  • Multiply by 21.3333us

Here's an example:


  • 002b (first pulse duration) = 43 = 43 * 21.3333us = 917.3319us
  • 0028 (first blank duration) = 40 = 40 * 21.3333us = 853.332us
  • 002a (second pulse duration) = 42 = 42 * 21.3333us = 895.9986us
  • ... 0xff 0xff = final blank space of 1.7seconds, end of data sequence

The measurements are all pretty close to the 889us bit period of an RC5 remote. We could probably improve accuracy by increasing the resolution of the timer measuring the pulse period to 10us or less. We won't worry about this unless there are problems with the current scheme, but it could easily be made adjustable.

Error codes

If the IR Toy can't keep up with the IR data, or the USB connection gets congested, it returns 0xff six times. After the error code it resets and waits for the next infrared pulse before sampling again.

Potential issues

Which byte is which? Tracking the byte stream.

There's no easy way to sync to the byte stream unless you track it from the start or wait for the first 0xff 0xff terminator. This probably isn't a huge deal in practice, just reset (0x00, 'S') and track the data from the beginning.

Alternatively, we could update the protocol to use a bit of the high byte to flag pulse and blank periods. The issue of determining which bytes in the stream are the high and low 8bits remains.

How to detect end of data? The long IR Toy timeout.

The IR Toy will send the 0xff 0xff terminator flag after no pin change is detected for one timer period, but that is nearly two seconds. A program will be really unresponsive if it depends on the terminator sequence to start processing the data.

Another issue is that the IR Toy doesn't care if the timeout happens during a pulse or blank period, and it has no ability to let us know a pulse is longer than 1.7seconds. A continuous IR pulse, like an IR jammer, would really mess up the bytestream. We made the IR Toy somewhat robust against this situation by syncing only to the start of an IR pulse.


By default the IR sample mode just sits and spits out infrared signal timing data according to the protocol described above. There are also commands that can be used to transmit data, or configure various aspects of the mode.

0x00 Reset (returns to remote decoder mode)
0x03 Transmit (FW v07+)
0x04 Frequency report (reserved for future hardware)
0x05 Setup sample timer (FW v07+)
0x06 Setup frequency modulation timer (FW v07+)
0x10 LED mute on (FW v07+)
0x11 LED mute off (FW v07+)
0x12 LED on (FW v07+)
0x13 LED off (FW v07+)
0x23 Settings descriptor report (FW v20+)
0x24 Enable transmit byte count report (FW v20+)
0x25 Enable transmit notify on complete (FW v20+)
0x26 Enable transmit handshake (FW v20+)
0x30 IO write
0x31 IO direction
0x32 IO read
0x40 UART setup
0x41 UART close
0x42 UART write

Commands available from raw sampling mode.

Reset (0x00)

Returns to IRman compatible decoder mode.

All IR Sample mode settings are cleared on exit.
LED settings are cleared on exit and do not apply outside IR sample mode.

SUMP RUN and ID (0x01, 0x02)

Reserved if IR sample ever becomes the default mode and needs to support these SUMP commands.

Transmit (0x03)

Updated for firmware v20+. Since firmware v20 the IR Toy uses a USB double buffer to ensure glitch-less transmissions. The new mode is backwards compatible with old firmware, but we highly recommend you enable transmit handshake (0x26), return transmit count (0x24), and notify on complete (0x25).

0x03 pulse1-high8 pulse1-low8 blank1-high8 blank1-low8 ... blankn-high8 (0xff) blankn-low8 (0xff)
  1. Send 0x03 to enter transmit mode
  2. Optional: If transmit handshake (0x26) is enabled the IR Toy will respond with the number of bytes free in the buffer, currently 62bytes
  3. Send timing data in the same format as the IR Toy output. If handshake is enabled (0x26), send the number of bytes requested by the IR Toy (62), and wait for the next handshake
  4. Transmit ends with an interval of 0xffff (same as receive protocol)
  5. Optional: If transmit handshake (0x26) is enabled the IR Toy will -again- respond with the number of bytes free in the buffer even though all packets have been sent. This is because the IR TOY does not know that it is receiving the last packet until it processes it and this is done AFTER the transmit handshake was sent. If transmit handshake (0x26) is enabled you must collect this token before trying to get the return transmit count (0x24) AND/OR notify on complete (0x25) if either or both are enabled. See EXAMPLE 2 below (which was previously correct.) [JTR Item added 1st May 2013]
  6. Optional: If return transmit count (0x24) is enabled, the IR Toy will report the number of bytes transmitted in the format t|high-8bits|low-8bits. This should match the number of bytes sent
  7. Optional: If notify on complete (0x25) is enabled, the IR Toy will respond with result code. 'C' is successful transmission, 'F' indicates a buffer underrun

Buffer underrun errors happen when the IR Toy does not get a new packet of data before the previous transmission data ran out. Best practice is:

  • Use handshake option. It will report each time the IR Toy has an empty buffer ready for new data
  • Respond to the handshake quickly. You must get the handshake and send the next data packet before the last packet finishes transmitting


  • After transmit ends, you must send 0x03 again prior to the next transmission.
  • Indicator LED is on during transmit
  • The transmitting infrared LED activates the IR Toy receiver, but receive is not active while transmitting. There is a minimum 426uS delay after transmitting ends before receive resumes. This delay this gives the receiver time to recover, and prevents self-inflicted data packets.

Example 1

00 2C 00 27 00 2A 00 27 00 2B 00 27
00 2A 00 27 00 2C 00 27 00 2A 00 27
00 54 00 51 00 2C 00 27 00 54 00 51
00 54 00 51 00 2A FF FF

This example is PLAY on an RC5 remote control. Handshake (0x26), return transmit count (0x24), and notify on complete (0x25) are disabled in this example.

0x03 tells the IR toy to expect a packet to transmit. The data follows, ending with 0xff 0xff. The data packet, including 0xff 0xff at the end, was copied verbatim from the receive mode.

Example 2

In firmware v20+ the IR Toy has a new double-buffered USB interface that ensures glitch-less transmitting. We highly recommend that you enable all three new transmit mode features.

  • Send 0x24, 0x25, and 0x26 once after entering IR Sample mode to enable the new features.
Example transmit sequence
Computer IR Toy Description
0x24 0x25 0x26 Enable advanced TX features (no reply)
0x03 Start transmit
0x3E Handshake: ready for 62 byte packet
0xXX...0xNN Send up to 62 bytes
0x3E Handshake: ready for 62 more bytes
0xXX...0xFF 0xFF Send up to 62 bytes, 0xFF 0xFF ends transmit
0x3E One more handshake: ready for 62 more bytes
t 0x00 0x64 Transmit byte count: 100 bytes processed
C Notify on complete: C for success, F for buffer underrun error

Frequency report (0x04)

This command is for v2 hardware only.

This command gives information on the raw, modulated infrared signal. This can be used to find the frequency of the remote control signal.

The count is only accurate if the remote control is held within a centimeter of the detector.

t1-high8 t1-low8 t2-high8 t2-low8 t3-high8 t3-low8 count-high8 count-low8

Send 0x04 to get the raw frequency data for the previous infrared signal.

  1. t1 H/L - start timer at second rising edge of signal
  2. t2 H/L - timer at third rising edge
  3. t3 H/L - timer at fourth rising edge
  4. count H/L - total count of infrared modulated signal light pulses since last 0xffff

The measurements are taken from the beginning of the IR signal.

The measurement is not reacquired until the beginning of the next signal after the 0xffff terminator.

  1. 0x00f4 - start timer
  2. 0x0243 - timer 1
  3. 0x0391 - timer 2
  4. 0x01b3 - total count of infrared modulated light pulses

This is an example of a reply to the 0x04 command.

  • PIC timer Period 1 count = 0x0243-0x00f4=0x14F (334)
  • PIC timer Period 2 count = 0x0391-0x0243=0x14E (333)
  • Total infrared pulse count = 0x01b3 = 435

The timer counts are taken on the second, third, and fourth rising edge of the raw infrared signal. Subtract 2 from 3, and 3 from 4 to determine the period of the modulated IR light.

The total count is the total number of pulses. The maximum is 0xffff, and the counter will roll over to 0 after a long enough IR pulse.

(1/12000000)* PIC timer count =
(1/12000000)*334 =

The PIC has a 12MHz internal clock signal, so the actual period is 0.0000278333s. The measurement is within +0.20% of the actual 0.0000277778s 36KHz period.

Setup sample timer (0x05)

0x05 prescaler value

The sample timer is 21.3333us by default. It can be shorter by modifying the prescaler for the timer.

Setting Prescale value Sample timer
111 (0x07) 1:256 21.3333uS
110 (0x06) 1:128 10.6666uS
101 (0x05) 1:64
100 (0x04) 1:32
011 (0x03) 1:16
010 (0x02) 1:8
001 (0x01) 1:4
000 (0x00) 1:2

Setup transmit modulation (0x06)

0x06 PR2 value duty cycle (or 0x00 don't care)

Configures the modulation frequency of the IR transmitter.

IR sample mode starts with a default 36kHz infrared transmit modulation frequency. The rate can be changed with the setup modulation command, followed by a byte that sets the pulse-width modulator match value (PR2), and a don't care byte.

  1. First, calculate the timer PR2 value that gives the closest frequency. The best online tool we've found is this PWM Calculator.
  2. Setup the PR2 calculator with the USB IR Toy constants (the clock (fosc) is 48Mhz, duty cycle is always 50%, the prescaler is fixed at 4x). Enter your desired frequency in Hz (eg 38400), and click calculate.
  3. Choose the closest frequency from the table with a 4x prescaler. The values won't match exactly, but IR receivers usually work over a range of modulations, from roughly 30kHz to 40kHz.
  4. The USB IR Toy currently uses a fixed 4x prescaler, so choose a value with a 4x timer2 prescaler. The prescaler could be made adjustable in a future firmware if more flexibility is needed.

Send the IR Toy PR2. For 38.4kHz the PR2 value is 0b01001101, or 77 (0x4D). The complete command to send to the IR Toy is 0x06 0x4d 0x00:

  • 0x06 is the setup TX command
  • 0x4d is the PR2 value from the table
  • 0x00 is a don't care byte (doesn't matter)

New settings take effect immediately. See also the PR2 example for IRIO mode.

Duty cycle adjustment

V09 has experimental support for duty cycle adjustment.

  • The don't care byte of the transmit modulation sets the duty cycle IF IT IS NOT equal to 0x00
  • If the don't care byte is 0x00, the default 50% duty cycle will be used
  • The PIC has a 10bit duty cycle register. At default settings there is 10bits of resolution, but higher frequencies will give lower resolutions. Be careful you don't set the duty cycle to 100% and over power the LED.
  • The don't care byte is used as the middle 8bits of the 10bit duty cycle register. With the fixed 4x prescaler, this should almost always ensure that the duty cycle is 50% OR LESS. LEDs have higher pulse current ratings than continuous current rating, if the duty cycle is set to more than 50% the LED specifications might be violated.

LED mute on/off (0x10/0x11)

Enables/disables the LED in IR sample mode. The LED will not blink during receive or transmit when LED mute is set to ON (0x10). LED settings do not apply outside IR sample mode, and are cleared when changing between modes.

mute/on&off truth table
state Mute ON/OFF LED
transmit/receive OFF N/A illuminated
transmit/receive ON N/A dark
transmit/receive OFF ON illuminated until end of RX/TX
idle OFF OFF dark until next RX/TX
idle ON N/A dark
idle OFF ON illuminated until next RX/TX

LED on/off (0x12/0x13)

Turn the IR Toy LED on/off. Send LED ON (0x12) to illuminate the indicator LED on the IR Toy. The LED will turn on and stay on until the next receive or transmit activity.

Respects the LED mute setting, if LED mute is enabled the LED will not turn on when the 0x12 LED ON command is sent. LED settings do not apply outside IR sample mode, and are cleared when changing between modes.

See the truth table above for a detailed look at the interaction of the ON/OFF and mute commands.

Get settings descriptor (0x23)

Firmware v20+. Returns 8 bytes that describe the current IR Toy settings:

Descriptor fields
Bytes Description
1 PR2 value (PWM)
1 Duty cycle
1 PWM prescaler, 2 extra bits of duty cycle
1 Transmit timer prescaler
4 Clock frequency in Hz (eg 48,000,000Hz)

Enable transmit byte count (0x24)

Firmware v20+. Send this command to enable transmit byte count reporting.

If enabled, the IR Toy returns the number of bytes transmitted at the end of a 0x03 command. The format is tXY, where XY is the 16bit count of bytes transmitted:

  • 't' is the character t
  • X is the high 8bits of byte count
  • Y is the low 8bits of byte count

Compare this count to the bytes sent to confirm transmit.

Enable transmit notify on complete (0x25)

Firmware v20+. Send this command to enable success/fail notification in transmit mode.

If enabled, the IR Toy returns a success or error code at the end of a 0x03 transmit command.

Notify on complete codes
Code Discription
C Success, no errors, complete
F Buffer underrun during transmit

Enable transmit handshake (0x26)

Firmware v20+. Send this command to enable handshakes during a 0x03 transmit command.

If enabled, the IR Toy will request data packets during a transmit command. Each request is the number of bytes free in the USB buffer, currently always 62. The software interfacing the IR Toy should wait for each request before sending the data. See the 0x03 transmit mode example above.

IO write (0x30)

Sets the IO pins to ground (0) or +5volt (1).


V1 hardware: bits 7 and 6 of byte 1 control the UART pins (RX=bit7, TX=bit6)

IO direction (0x31)

Sets the IO pins to input (1) or output (0).


V1 hardware: bits 7 and 6 of byte 1 control the UART pins (RX=bit7, TX=bit6)

IO read (0x32)

Read the IO pins, returns 1 byte.

V1 hardware: bits 7 and 6 of byte 1 show the status of the UART pins (RX=bit7, TX=bit6)

UART setup (0x40)

Setup the UART to send serial data. Uses the current virtual serial port settings.

UART close (0x41)

Close the UART.

UART write (0x42)

Send a byte to the serial UART.

0x42data to write

Send the UART write command, followed by one byte to transmit from the serial UART.

Deprecated commands

These commands were unused and removed.

Little endian byte format (0x20)

high 8 bitslow 8 bits

Default byte format. 16bit RX/TX values are handled high 8 bits first byte, low 8 bits second byte. Removed in firmware v20.

Big endian byte format (0x21)

low 8 bitshigh 8 bits

Reverse the RX/TX byte order. 16bit RX/TX values are handled low 8 bits first byte, high 8 bits second byte. Removed in firmware v20.

Liyin no terminator mode (0x22)

This command disables the 0xff 0xff terminator at the end of receives. Removed in firmware v20.


Taking it further

  • Version info command
  • Self test command
  • Make sampling mode the default mode

See the USB IR Toy WinLirc how to.