The Museum of HP Calculators

HP Articles Forum

[Return to the Index ]
[ Previous | Next ]


IR Printer information

Posted by Steve (Australia) on 31 July 2000, 11:00 a.m.

Maybe someone else will find this of interest. I know I was looking for this for a long time.

Most of the correct stuff :-) comes from the HP Journal article October 1997 pp16-20. The rest is based on my observations in writing code to decode the output from my HP41 IR Printer interface.

Basics

The carrier frequency is 32.768Khz. (for the HP-18C)

The carrier has an even mark and space of approximately 15.26uS

The carrier is modulated by a square wave with a fixed mark, but variable space. Thus the information is carried by the gaps between pulses, not the pulses themselves!

Data Encoding

The data is encoded bit by bit. Bit times are fixed (28 pulses of the carrier, or approx 854.5uS). This bit time is broken into two halves.

* A 1 bit is defined as a burst in the first half of the bit time, and no pulse in the second half
* A 0 bit is defined as a burst in the second half, but not in the first half.
* A start bit is defined as a burst at the begining of three successive half bit times (an otherwise illegal combination)

Note that this makes a start bit 50% longer than a normal bit.

An Example

If I were drawing things, it would look like this:

(this is a start bit followed by a 1 and a 0.) Note that you don't start counting until you see the first rising edge. To make things easier, I only show 4 pulses per 1/4 bit time, rather than the 6 to 8 that you may see in practice.

Also note that while HP talks of 1/2 bit times, you can usefully think in terms of 1/4 bit times with the even 1/4's ALWAYS in a space, and the mark only ever occuring in one of the odd 1/4's.

___||||____||||____||||____||||________________________||||____

To break that up:

___
is some amount of space between characters

||||____||||____||||____
is three half bit times with pulses in their first half. (and is thus a start bit)

||||____________
is two half bit times with pulses in the first half bit time (a 1)

________||||____
is two half bit times with pulses in the second half bit time (a 0)

Data is sent in frames. Each frame consists of a start bit, 4 ECC bits, and 8 data bits.

If you look at the output of one of these IR devices on a storage scope, or via some other method, you'll notice immediatly that the frames stand out like islands of data in the sea of noise. As you look closer you'll see the groups of pulses and the spacing between them. You'll notice the three different size gaps. These are 1 unit, 3 units, and 5 units. Coding these gaps is actually one way of coding the data.

A Table to Cheat By :-)

Here is a table that some of my software uses to decode these gaps. Note that it was devises BEFORE I knew anything about how te data was decoded.

const
  FrameChars : Array[0..255] of string[14] = (
    '11222222222222', //    0
    '11221232222221', //    1
    '11213132222213', //    2
    '11212322222212', //    3
    '11212322222132', //    4
    '11213132222131', //    5
    '11221232222123', //    6
    '11222222222122', //    7
    '11132132221322', //    8
    '11131322221321', //    9
    '11123222221313', //    10
    '11122232221312', //    11
    '11122232221232', //    12
    '11123222221231', //    13
    '11131322221223', //    14
    '11132132221222', //    15
    '11131322213222', //    16
    '11132132213221', //    17
    '11122232213213', //    18
    '11123222213212', //    19
    '11123222213132', //    20
    '11122232213131', //    21
    '11132132213123', //    22
    '11131322213122', //    23
    '11221232212322', //    24
    '11222222212321', //    25
    '11212322212313', //    26
    '11213132212312', //    27
    '11213132212232', //    28
    '11212322212231', //    29
    '11222222212223', //    30
    '11221232212222', //    31
    '11123222132222', //    32
    '11122232132221', //    33
    '11132132132213', //    34
    '11131322132212', //    35
    '11131322132132', //    36
    '11132132132131', //    37
    '11122232132123', //    38
    '11123222132122', //    39
    '11213132131322', //    40
    '11212322131321', //    41
    '11222222131313', //    42
    '11221232131312', //    43
    '11221232131232', //    44
    '11222222131231', //    45
    '11212322131223', //    46
    '11213132131222', //    47
    '11212322123222', //    48
    '11213132123221', //    49
    '11221232123213', //    50
    '11222222123212', //    51
    '11222222123132', //    52
    '11221232123131', //    53
    '11213132123123', //    54
    '11212322123122', //    55
    '11122232122322', //    56
    '11123222122321', //    57
    '11131322122313', //    58
    '11132132122312', //    59
    '11132132122232', //    60
    '11131322122231', //    61
    '11123222122223', //    62
    '11122232122222', //    63
    '11122321322222', //    64
    '11123131322221', //    65
    '11131231322213', //    66
    '11132221322212', //    67
    '11132221322132', //    68
    '11131231322131', //    69
    '11123131322123', //    70
    '11122321322122', //    71
    '11212231321322', //    72
    '11213221321321', //    73
    '11221321321313', //    74
    '11222131321312', //    75
    '11222131321232', //    76
    '11221321321231', //    77
    '11213221321223', //    78
    '11212231321222', //    79
    '11213221313222', //    80
    '11212231313221', //    81
    '11222131313213', //    82
    '11221321313212', //    83
    '11221321313132', //    84
    '11222131313131', //    85
    '11212231313123', //    86
    '11213221313122', //    87
    '11123131312322', //    88
    '11122321312321', //    89
    '11132221312313', //    90
    '11131231312312', //    91
    '11131231312232', //    92
    '11132221312231', //    93
    '11122321312223', //    94
    '11123131312222', //    95
    '11221321232222', //    96
    '11222131232221', //    97
    '11212231232213', //    98
    '11213221232212', //    99
    '11213221232132', //    100
    '11212231232131', //    101
    '11222131232123', //    102
    '11221321232122', //    103
    '11131231231322', //    104
    '11132221231321', //    105
    '11122321231313', //    106
    '11123131231312', //    107
    '11123131231232', //    108
    '11122321231231', //    109
    '11132221231223', //    110
    '11131231231222', //    111
    '11132221223222', //    112
    '11131231223221', //    113
    '11123131223213', //    114
    '11122321223212', //    115
    '11122321223132', //    116
    '11123131223131', //    117
    '11131231223123', //    118
    '11132221223122', //    119
    '11222131222322', //    120
    '11221321222321', //    121
    '11213221222313', //    122
    '11212231222312', //    123
    '11212231222232', //    124
    '11213221222231', //    125
    '11221321222223', //    126
    '11222131222222', //    127
    '11212223222222', //    128
    '11213213222221',
    '11221313222213',
    '11222123222212',
    '11222123222132',
    '11221313222131',
    '11213213222123',
    '11212223222122',
    '11122313221322',
    '11123123221321',
    '11131223221313',
    '11132213221312',
    '11132213221232',
    '11131223221231',
    '11123123221223',
    '11122313221222',
    '11123123213222',
    '11122313213221',
    '11132213213213',
    '11131223213212',
    '11131223213132',
    '11132213213131',
    '11122313213123',
    '11123123213122',
    '11213213212322',
    '11212223212321',
    '11222123212313',
    '11221313212312',
    '11221313212232',
    '11222123212231',
    '11212223212223',
    '11213213212222',
    '11131223132222',
    '11132213132221',
    '11122313132213',
    '11123123132212',
    '11123123132132',
    '11122313132131',
    '11132213132123',
    '11131223132122',
    '11221313131322',
    '11222123131321',
    '11212223131313',
    '11213213131312',
    '11213213131232',
    '11212223131231',
    '11222123131223',
    '11221313131222',
    '11222123123222',
    '11221313123221',
    '11213213123213',
    '11212223123212',
    '11212223123132',
    '11213213123131',
    '11221313123123',
    '11222123123122',
    '11132213122322',
    '11131223122321',
    '11123123122313',
    '11122313122312',
    '11122313122232',
    '11123123122231',
    '11131223122223',
    '11132213122222', //   191
    '11132122322222', //   192
    '11131312322221',
    '11123212322213',
    '11122222322212',
    '11122222322132',
    '11123212322131',
    '11131312322123',
    '11132122322122',
    '11222212321322',
    '11221222321321',
    '11213122321313',
    '11212312321312',
    '11212312321232',
    '11213122321231',
    '11221222321223',
    '11222212321222',
    '11221222313222',
    '11222212313221',
    '11212312313213', //   210
    '11213122313212',
    '11213122313132',
    '11212312313131',
    '11222212313123',
    '11221222313122',
    '11131312312322',
    '11132122312321',
    '11122222312313',
    '11123212312312',
    '11123212312232', //   220
    '11122222312231',
    '11132122312223',
    '11131312312222',
    '11213122232222',
    '11212312232221',
    '11222212232213',
    '11221222232212',
    '11221222232132',
    '11222212232131',
    '11212312232123', //   230
    '11213122232122',
    '11123212231322',
    '11122222231321',
    '11132122231313',
    '11131312231312',
    '11131312231232',
    '11132122231231',
    '11122222231223',
    '11123212231222',
    '11122222223222', //   240
    '11123212223221',
    '11131312223213',
    '11132122223212',
    '11132122223132',
    '11131312223131',
    '11123212223123',
    '11122222223122',
    '11212312222322',
    '11213122222321',
    '11221222222313', //   250
    '11222212222312',
    '11222212222232',
    '11221222222231',
    '11213122222223',
    '11212312222222' ) ; //  255

This table encodes the GAPS between modulation pulses for each character. 1 indicates a short gap, 2 the middle size gap, and 3 the long gap. Knowing that the pulses fit around each gap, that the gaps are in the proportion 1:3:5, and that you should send 7 carrier pulses at 32767Hz, this is probably enough info.

How To Cheat

So, character A is 65 and is '11123131322221'

You would send:

|_|_|_|___|_____|_|_____|_|_____|___|___|___|___|_|

Where each | is 7 carrier pulses, and each _ is a gap of equivalent size.

If you're further interested...

|_|_|_|___|_____|_|_____|_|_____|___|___|___|___|_|
SSSSSS111111110000111100001111000000000000000000001111
And yes the 1's do extend out beyond the end! This is becasue the last set of pulses occur in the first quarter of the last bit time (first half of the first half of the last bit time!!!). So even though we're encoding information in the gaps, the last gap does not need to be terminated.

SSSSSS = start bit
1111 = 1 bit
0000 = 0 bit

So it was S110101000001

1101 is the ECC 01000001 is the code for A in ASCII MSB first

Calculating the ECC

How do we get the ECC? well it's like this...

The 4 bits (call them H1, H2, H3, and H4) are calculated individually

Firstly for each bit you apply a mask (AND) to the data

the masks are:

H1 01111000
H2 11100110
H3 11010101
H4 10001011

So for the code 01000001 the resulting data for these is

H1 01000000
H2 01000000
H3 01000001
H4 00000001

Then you calculate the EVEN parity bit required for these (i.e. the bit required so that there are an EVEN number of bits. Since H1, H2, and H4 have an odd number of bits, the parity bit for these would be 1, bit for H3 it is 0.

Then you string them together (the parity bits) this gives you:

1101 which is what we found above!

These parity bits can be used to detect and correct up to two missed bits (though how you do that is well beyond what I'm prepared to go into!)

But, my software DOES decode these without resorting to calculating the ECC bits (although I may add that some time)

But you're trying to SEND this data right? So the lookup table I've given you should be all you need, unless you want to do all the hard work yourself :-)

P.S. (Timing made easy)

An easy way to play with this is to capture it with your sound card... (Oh damn, I've let out my secret). It has the advantage of handling all the timing for you, so software speed is no longer an issue. This is especially important when using an operating system that multi-tasks.

P.P.S. (Missing bits on received data)

This table indicates what you should do when you receive a bit (i.e. a rising edge) after x timer ticks (a timer tick is 1/32768 sec)

Ticks      Bit      Comment

0 - 2 Ignore (too short)

3 - 7 X 2 pulses in the same bit time (treat as a missed bit)

8 - 12 1

13 - 17 0

18 - 23 X 1 Missed bit followed by a 1

23 - 28 X 0 Missed bit followed by a 0

28 - 34 X X 1 2 mised bits then a 1

33 - 39 X X 0 2 missed bits then a 0

You can use the ECC to determine what the bits are, as long as you know which are missing (which you probably will).

What I do is to decode the gaps, then use some heuristics to determine what the gap is likely to be, then do pattern matching to determine which is the most likely. This is probably too code intensive for a PIC, bit the calculation of bits using the ECC should be OK.

P.P.P.S. (Printer Buffer Management)

Because the IR interface is one-way, there is no way to detect that the buffer is full. Thus the sender needs to send data in such a way that the buffer never overflows.

With new batteries, the IR printer can print about 2 lines per second. When the batteries are almost exhauseted, this drops as far as 1 second per line.

The buffer in the printer can contain 200 characters.

The HP way is to have a rather simple algorithm that assumes each line has 25 bytes. Thus it assumes the buffer will hold 8 lines. The calculator simply keeps track of how many lines have been sent, and how long it has been since the last line was sent. Before a line is sent, the calculator determines how much time has elapsed since the last line was sent, and decrements the assumed number of lines in the buffer by the appropriate amount. If the number is less than 8, it allows a line to be printed, otherwise it waits.

P.P.P.P.S. (Error Correction)

I know I promised I wouldn't go into this, but I lied! (but I won't go into this in great detail)

If you have missing bits (up to two of them) in the data area of the frame, the ECC can be used to determine what they are.

For each bit in he data, there are 2 (or 3) parity bits that have been calculated using this bit. If there is only a single missing bit, then any of these can be used to determine what the missing bit is.

For example, suppose the bits received have been:

11010100x001

The X represents a missing bit. From looking at the masks for the ECC bits, we see that H1 and H4 have been calculated using this bit.

so

    0100x001  (data)
AND 01111000  (H1 mask)
------------
    0100x000  with EVEN parity of 1  (from first bit of 1101)

If we add all the 1s up (in the result and the parity) we have 2 which is even, therefore the missing bit must be a 0

Lets assume a more difficult case:

11010x00x001

There are 2 missing bits, but you can see that only the first missing bit is in H3, and only the second is in H4, so we can calculate them individually:

    0x00x001  (data)
AND 11010101  (H3 mask)
------------
    0x000001  with EVEN parity of 0  (from first bit of 1101)

Note that we only get an x in the result if the mask has a 1 in that position.

The 1s have to add up to an even number (always) and in this case there's an odd number, so this missing bit is a 1.

The other missing bit is calculated in a similar manner.

Missing bits can also happen in the ECC area too. If that's the only place they are, then there's really nothing to worry about. If there's one in this area, and one in the data area, then the remaining ECC bits will provide enough information to correct the single bit in the data area.

All of this is based on the fact that we can determine that a bit is actually missing. This is a fair assumption, because the bits are far more likely to be missed than mistakenly detected as a 1 rather than a 0 (or vice versa). However it can happen.

Assume you get this:

Note that you can easily correct for 2 missing bits, and sometimes 3. But it's not always this easy...

110101001001

This all seems OK, but what happens if we recalculate the ECC?

H1 calculates as 0
H2 calculates as 1
H3 calculates as 0
H4 calculates as 0

So we got an ECC of 1101 but calculated 0100.

What we do is XOR the receved and calculated ECC

    1101  (received)
XOR 0100  (calculated}
    1001

Now we AND the masks of H1 and H4 to find out what bit is incorrect

    01111000  (H1)
AND 10001011  (H4}
    00001000

And this tells us which bit has been flipped.

But this is really a special case. Consider this bit pattern

110101100001

H1 calculates as 0
H2 calculates as 0
H3 calculates as 0
H4 calculates as 1

So we got an ECC of 1101 but calculated 0001.

So we do is XOR the receved and calculated ECC

    1101  (received)
XOR 0001  (calculated}
    1100

Now we AND the masks of H1 and H2 to find out what bit is incorrect

    01111000  (H1)
AND 11100110  (H2}
    01100000

Oh dear!!!!! 2 bits!!! Well not really. To fully determine the bit we need to also OR together the other masks

    11010101  (H3)
OR  10001011  (H4}
    11011111

Then invert this

    00100000

then AND this with the result above:

    01100000  (H1 AND H2)
AND 00100000  (NOT (H3 OR H4)}
    00100000

Which singles out the bit. What we've done is to find out what is common in the masks of the ECC that were calculated in error and removed ALL the bits of the ECC that calculated correctly. Note that this also applies to the missing bit problem too, but if you didn't read this far, you're not really serious :-)

All a bit anal really :-) But useful if you're trying to recover data out of noise.

You may ask, what happens if a bit in the ECC is flipped? The answer is that only a single ECC bit will calculate in error, and this means that either multiple bits in the data are in error, or that the ECC was corrupt.

Password:

[ Return to the Message Index ]

Go back to the main exhibit hall