This write-up describes how to use the software provided in this
release (version 0.1) of the IRG (Infrared Gateway) for the Atari
8-bit computers.  Most of this was originally submitted to the
_Atari_Classics_ magazine as an article, but has not been published.

Enjoy!
David Deaven -- deaven@iastate.edu

---- Files included in this distribution ------------------------

  README, README.HARDWARE -- instructions
  hardware.ps, pulses.ps -- PostScript pictures to go with the
  				instructions.
  irgscan.bas -- listed Atari BASIC program (ASCII, not binary)
  irgscan.m65 -- Assembler program source for the code that is
  			used in irgscan.bas
  irg.h irg.m65 irg.obj -- IRG driver software for CC65
  irgdemo.c irgdemo.com -- CC65 example of using the IRG driver
  irgdemo.rc -- init file read by irgdemo.com (see section IV).

-----------------------------------------------------------------

0. Installation and running the programs

   a) Build the IRG circuit and plug it into your Atari, in joystick
      port 1.  See README.HARDWARE for instructions.

   b) Copy IRGSCAN.BAS, IRGDEMO.COM, and IRGDEMO.RC onto a disk, place
      it in the default drive ("D:"), usually drive 1, and run
      IRGDEMO.COM.  It will load definitions from IRGDEMO.RC and begin
      reporting any IR control codes received on the IRG.  You might
      want to write down the codes for your particular remotes, to
      include in the initialization file.

   c) If no codes are received by IRGDEMO.COM, chances are your remote
      uses a different standard than Mitsubishi, Sony, and Sharp
      remotes do.  In this case, run IRGSCAN.BAS (requires the BASIC
      cartridge) and try scanning some codes in to verify that the IRG
      is working.  You can adjust the parameters in IRGDEMO.C once you
      determine what the form of your remote's signal is.

-----------------------------------------------------------------
The Infrared gateway (IRG) for the Atari 8-bit computers.
David Deaven -- deaven@iastate.edu

     Have you ever wondered how TV and VCR remote controls work? Have
you ever dreamed of accessing your Atari Classic by remote control? If
so this project will be right up your alley -- I'll show you how about
ten dollars worth of electronic parts from your local Radio Shack can
enable your Atari to receive infrared (IR) signals from most TV, VCR,
and stereo remotes, and send IR signals to most any IR
remote-controlled appliance.  The parts fit in a small box I call an
IRG (InfraRed Gateway) which connects to a joystick port on your Atari
400/800/1200/XL/XE.

     The file README.HARDWARE describes how to build the IRG, and this 
file describes how to control it with some simple machine language
subroutines called from BASIC or CC65.

I. IR protocols

     First let's briefly consider how an IR remote works. In the nose
of each of your remotes, there's a bank of infrared LEDs that transmit
either IR modulated at 40kHz, or nothing, these two possibilities
representing logic level 1 or 0. Your TV or VCR listens for a 40kHz IR
signal and demodulates it into a serial pulse stream.  (This is
illustrated in the attached PostScript figure "pulses.ps".)
When the proper stream is sent, the TV or VCR executes a remote
function. 

     The key point is that the 40kHz IR signal is either present (logic
level 1) or not (logic level 0), so the IR link is like a single
(one-way) TTL data line. The protocol each manufacturer uses to send
information is up to them, but there are some common standards. Most
IR remotes transmit packets of roughly 30 bits using a form of
pulse-code modulation (PCM). Within one packet
information specifying manufacturer and appliance type is usually
given, so that different manufacturer's remotes don't interfere with
one another. Some remotes send several different packets even when
only one button is being pushed in order to distinguish between a
button being held down and one that is being pressed repeatedly.
Usually a single packet is enough to execute a function, but at least
one of my appliances will only respond to a correct sequence of
multiple packets.

II. Some simple software

     Once you've got the IRG hooked up, you are ready to play with it.
To do that, you'll need a bit of machine code to send and receive IR
signals. The program IRGSCAN.BAS listed with this file is a
self-contained example program which contains a short machine language
routine that simply digitizes input from the IRG at precisely timed
intervals adjustable from 64 to 1339 clock cycles (36 to 748
microseconds). The assembly code contained in IRGSCAN.BAS is also
provided (IRGSCAN.M65) so you can get some idea of how it works.
Once the IR data is digitized IRGSCAN.BAS can also send it back out
over the IRG.

     Let's take a closer look at how the machine code IRGSCAN.M65
works. One problem I had to solve was that the pulse width of 500
microseconds used in the IR standard corresponds to only 895
microprocessor cycles.  A packet 30 bits long, or 60 pulse widths
long, lasts about 1/30 sec, during which time the Atari's 6502 would
normally process two vertical blank interrupts, and two screenfuls of
DMA cycles would also be stolen from the 6502 by ANTIC.  This
introduces significant uncertainties into the timing loops I wanted to
use in my code, so my solution was to simply turn off DMA and IRQ/NMI
interrupts, avoiding vertical blanks, keyboard interrupts, and ANTIC
cycle-stealing entirely at the cost of losing the display during IR
transmission and reception. I experimented with other approaches based
on keeping track of interrupt service routine delays, for example by
reading ANTIC's vertical line counter (VCOUNT), but I had little
success.  The DMA cycles stolen by ANTIC are highly dependent on the
display mode, and I wanted this code to work with any display.  In my
applications, the Atari running the IRG isn't even hooked up to a
monitor, so this is no big deal.  (Even with a display, you
still have a usable picture, since the screen is stable as long
as there are no IR transmissions going on.)

     IRGSCAN.M65 gets loaded into memory at page six. When this routine
is called from BASIC with 4 arguments, it scans the IRG and stores
bits collected at precise time intervals into a buffer region. You can
set the sampling time interval by changing the variable SAMPLE in
IRGSCAN.BAS, which is a single byte. Values of 0 through 255 produce
digitization time intervals of 64+5*SAMPLE clock cycles. When called
with 3 arguments the routine sends the buffer out over the IRG. Each
of the eight bits in the buffer bytes are used, in order from MSB to
LSB. This allows ANTIC to display the buffer directly on the screen in
a two color graphics mode, assuming screen memory is used for the
buffer area. IRGSCAN.BAS does this with the high-resolution graphics
mode's (BASIC mode 8) display memory for the buffer. You can scan a
remote using IRGSCAN.BAS to see what kind of signals it generates, and
play back the sequence to mimic the effects of the remote control.
Try changing the timing parameter SAMPLE to see a higher or lower
resolution version of the IR signal.

     At this point, you can adjust the center frequency of the 555
timer in your IRG to precisely 40kHz, if you haven't already done so.
Just scan, say, a TV function like "mute"
into memory using IRGSCAN.BAS, then point the IRG at the TV, and play
the signal repeatedly. Adjust the trimmer until the TV responds. (The
"mute" function is convenient since you won't have to look at the TV
to see when it's responding.) My IRG had quite a broad range of
acceptable trimmer settings -- it doesn't have to be perfect.

     With some more programming effort, IRGSCAN.BAS could be
modified so as to serve as a "universal remote," with a library of
digitized functions. Unfortunately, IRGSCAN.BAS provides no easy way
to *recognize* incoming bit patterns. That problem can be solved with 
just a little bit more effort.

III. The IRG driver software

     Let's look at a schematic for a more sophisticated receiving
algorithm.  The IRG driver, which is provided here in versions
suitable for both BASIC and CC65, installs a vertical blank 
interrupt (VBI) routine that constantly (well, every 1/60 second) checks
for IRG activity. When IR input is detected, the driver takes over 
and scans the IRG, decoding the IR bit pattern on the fly.
This allows a BASIC or C program to recognize a particular IR
signal, and it solves another problem with digitizing: excessive
memory usage. You can see from running IRGSCAN.BAS that an IR packet
contains only a few bytes of data, yet IRGSCAN.BAS uses a hundred
bytes or so of storage to keep it in digitized form. The IRG driver
works with IR signal codes in a packed form, requiring only a few bytes per
packet.

     The driver uses a few parameters to describe how the incoming
signal should be digitized.  These are set by calling the
initialization routine:

  void IRGinit(int sample, int ton, int toff, int repeat,
     int tonmin, int toffmax, int qtime, int totime)

Here "sample" controls the sampling rate, or timebase of the digitizer
and sending code, using the same delay subroutine IRGSCAN.BAS uses.
"ton" ("toff") is the on (off) time for an ideal "1" ("0") pulse.
"repeat" is the number of times to repeat the send operation of a
single code.  Most equipment works better when the control codes are
repeated several times.
"tonmin" is the minimum values for valid "1" pulses.
"toffmax" is the maximum off time for a "0" pulse -- longer than this
means end of packet.  "qtime" is the required "quiet time" of IRG
inactivity before starting to receive a packet.  "totime" is the
timeout time -- the driver times out if spurious pulses are followed
by inactivity of this duration.  Good values for these parameters are

  sample = 2, ton = 20, toff = 20, repeat = 3,
  tonmin = 10, toffmax = 30, qtime = 100, totime = 25.

     Once installed, the driver can send and receive packets via the
routines

  int IRGread(char *buffer, int size) = # bytes returned
  int IRGwrite(char *buffer) = 0, or 1 if IRG is active

where "size" is the maximum buffer size, and all strings are null
terminated.  The receive code has a built-in buffer, so it won't drop
packets if you don't read them right away.  (The size of this buffer is
set inside the driver source code, so you can change it there.)
You can look at the driver code ("irg.m65") to see more of the
implementation details.

IV. Demo program

     I have provided a simple example program "irgdemo.c" which can be
used as a translator between different sets of IR codes.  For example,
it can read remote codes from your VCR remote and map those functions
onto your TV by transmitting new codes to the TV when the proper VCR
codes are received.  The demo program reads an init file containing
two types of information.  First, lines like

  def vcr_chup ab6edf

means that the IR code "ab6edf" corresponds to the named tag
"vcr_chup" (VCR channel up).  After all of the IR packets are defined
in this manner, lines like 

  map vcr_volup tv_volup end

specify that if the IRG detects the "vcr_volup" packet, it should send
the "tv_volup" packet.  More than one packet may be output by the IRG,
for example

  map vcr_qv vcr_n2 vcr_n1 vcr_enter end

maps the "vcr_qv" packet (this is an unused button on my remote) into
the three-packet sequence that changes the channel to channel 21.

     One last feature is that while the demo program is running, if a
keyboard key is pressed it will simulate reception of the packet ffXX
where XX = the internal Atari code for that key.  So

  def key_space ff21

defines the "packet" corresponding to pressing the space key.
Included with this release is a sample irgdemo.rc file that contains
some definitions for a Mitsubishi VCR.

V. Applications and ideas

     I originally built my gateway in order to understand how IR
remotes operate, and because I was interested in controlling home
appliances and security systems by IR remote.  The Atari was a perfect
match because it's so easy to connect to the outside world. But, the
applications go further than this.  I use my IRG as a "universal"
remote interface to my TV, VCRs, and cable box. My Hi-fi VCR has a
complicated remote control with many more functions on it than I use,
such as control over a TV I don't own. An Atari/IRG translates the
codes from my VCR remote to control my TV, backup VCR and cable
descrambler. Now I have one remote, without losing the VCR's special
features such as jog/shuttle control.  The universal remotes sold
commercially don't have the mechanical hardware required to emulate
these functions.

     Other applications of an Atari/IRG also spring to mind:

1) Your VCR could be programmed to record at a given time by an
Atari/IRG which deciphers those VCR+ numbers found in the TV guides.
Especially since the VCR+ algorithm has been programmed on the Atari.
I am currently working on adding VCR+ capability to the IRG code.

2) Your VCR can be programmed to record a scrambled cable channel, the
Atari/IRG handles switching the cable box to the correct channel at
the correct time, and starting/stopping the VCR.

3) The Atari/IRG could be interfaced to an audio/video switch box that
controls what input your TV gets.  Besides having TV tuner, VCR 1, VCR
2, Atari 2600, Atari 7800, NES, etc., choices, one screen could be the
Atari/IRG display, with visible menu selections (all accessed via IR
remote) for time-programmed functions.

4) An Atari/IRG programmed to act as a "recording studio" controls a
CD player, stereo, and Hi-fi VCR and allows you to select a list of
songs to put on one tape. (Thanks to Chris Chiesa for suggesting this
one.)

5) An Atari/IRG with computer-readable TV program information
downloaded into it from a subscription computer service like Prodigy
or Compuserve could directly select TV programs, performing your local
cable channel conversion invisibly.

     I hope you enjoy building and using the IRG.  Please drop me a line
(preferably by e-mail) if you find any unusual applications of the
IRG. I'm always interested in what people are doing with the Atari
8-bit machines!

David Deaven deaven@iastate.edu
