--- /dev/null
+;######################################################################
+; seriallib.inc - SERIAL LIBRARY - DECLARATIONS AND DOCUMENTATION
+;
+;============================================================
+; GENERAL INFORMATION
+
+; Purpose:
+; --------
+;
+; This library allows the PIC to communicate with the host via the
+; PIC's UART, configured for RS232 at 9600 8N1. It implements
+; unidirectional flow control: the host may ask the PIC not to
+; transmit, but not vice versa.
+
+; Naming scheme:
+; --------------
+;
+; serial_... are for use by the rest of the program and
+; are the entrypoints which enable use of the serial port
+; serialu_... must be defined in the rest of the program
+; with the functionality and behaviour described.
+
+; At all times following serial_init, the serial hardware in the PIC is
+; completely reserved to the routines defined in seriallib.asm. Nothing
+; else is allowed to read or modify the PIC UART state.
+
+; Use of PORTB, RBIF etc.:
+; ------------------------
+;
+; The seriallib makes use of the PORTB `interrupt on change' feature,
+; and expects at all times after serial_init to have exclusive use of
+; that feature, including the RBIF flag. Only seriallib is allowed to
+; make reads of PORTB directly; the main program must call
+; serial_portb_read instead. The main program may freely write to
+; LATB.
+;
+; If any of RB5, RB6 or RB7 is an output which would be electrically
+; floating if left in tristate (Z state by the PIC) then before
+; calling serial_init the main program must have configured the
+; appropriate TRISB bit(s) as outputs - presumably, after having
+; configured the corresponding LATB bit(s). This will avoid excessive
+; interrupts resulting from floating values.
+;
+; Registers and calling conventions:
+; ----------------------------------
+;
+; Unless otherwise stated, all routines accept any value in, and may
+; trash, W and the flags. All other registers and locations not
+; specifically mentioned here will be preserved by the
+; serial_... routines (and are therefore reserved for the rest of the
+; program). In all cases, routines are called with CALL or RCALL or
+; the equivalent, and routines are allowed to have subroutines (ie, to
+; use the call/return address stack).
+
+; serial_... routines except serial_interrupt will never _directly_ call
+; any serialu_... routine; when we say `causes' this means that the
+; relevant serialu_... routine will be called at some later point from
+; serial_interrupt. serialu_... routines are allowed to call appropriate
+; serial_... routines (except serial_interrupt) directly if the context
+; and Tx State allows.
+
+; All routines except serial_init and serial_write_please
+; must be called only:
+; * During a low-priority interrupt;
+; * From the main loop with low-priority interrupts disabled; or
+; * From within an serialu_... routine (which are always called
+; from within serial_interrupt).
+; This is to avoid having one serial_... routine running in an interrupt
+; which interrupted the middle of another serial_... routine.
+
+; Some time between calling serial_init and waiting for the first event,
+; the main program should of course enable interrupts.
+
+;============================================================
+; COMMON ROUTINES and RECEPTION
+
+;--------------------
+ extern serial_init
+;
+; Initialises the serial port and library state appropriately. Must
+; be called exactly once, which must be before any other
+; serial_... function.
+;
+; At call On return
+; serial controller any for use by seriallib
+; PORTB any for use by seriallib
+; serial interrupt config any enabled, low priority
+; Port B interrupt-on-change any enabled, low priority
+; TRISB<5:7> any outputs configured unchanged
+; TRISB<4> any configured for input
+; TRISB<0:2> any unchanged
+; LATB any outputs configured unchanged, use freely
+; global interrupt enable disabled unchanged
+; Tx State Not-in-use Must-Notify
+;
+; Note that as soon as the interrupts are enabled, the serial port
+; will generate an interrupt, so that we go from Tx State Must-Notify
+; to Idle via call to serialu_writeable. (See the Transmission
+; section below.)
+
+;--------------------
+ extern serial_portb_read
+; At call On return
+; W any value from PORTB
+;
+; Provided to allow the main program to read any bits in PORTB which
+; it is using as inputs. See the notes above about PORTB.
+
+;--------------------
+ extern serial_interrupt
+;
+; Must be called by the main program's low priority interrupt handler.
+; The main program's interrupt handler is responsible for saving W and
+; the flags register and other interrupt-related administrivia. If
+; there is a serial interrupt, this routine will service it, taking any
+; necessary action including calling appropriate serialu_... routines,
+; and clear the interrupt flag[*].
+;
+; At call On return
+; Tx State any except Not-in-use may change
+; serial interrupt state any cleared[*]
+;
+; [*] The interrupt event on entry, if any, will be dealt with. If
+; interrupt processing takes a long time, another interrupt will occur
+; and this may result in the serial interrupt flag being set on return
+; from serial_inerrupt.
+
+;--------------------
+ extern serialu_receive
+;
+; Called to notify the main program that a byte has been recieved from
+; the host. The byte value is supplied. There is no way for the PIC
+; to signal flow control to the host, to stop the host from sending
+; data. It is up to the main program to do _something_ with the
+; received data (or to panic or to discard it).
+;
+; Beforehand At call
+; W data byte from host
+
+;======================================================================
+; TRANSMISSION
+;
+; States:
+; [Not-in-use]
+; |
+; |init
+; V
+; ,------------->+<-------------.
+; | | |
+; | [Must-Notify] |
+; | | |
+; | write_ready| |
+; | | |
+; | V |
+; | [Idle] |
+; | | `-----------'
+; | write_byte| write_please
+; | |
+; | V
+; | [Busy]<----------.
+; | | `-----------'
+; `--------------' write_please
+
+; The seriallib will handle the host's requests for flow control.
+
+;--------------------
+ extern serialu_write_ready
+;
+; Called to notify the main program that the serial port is now ready
+; to transmit a byte. The main program should call serial_write_byte,
+; or serial_write_please, either immediately or at some later point.
+;
+; Beforehand At call
+; Tx State Must-Notify Idle
+
+;--------------------
+ extern serial_write_byte
+;
+; Provides a byte to be written to the serial port.
+;
+; At call On return
+; Tx State Idle Busy
+; W byte for host any
+
+;--------------------
+ extern serial_write_please
+;
+; Asks to be re-notified if the serial port is ready for transmission.
+; This will regenerate the call to serialu_write_ready if applicable.
+;
+; At call On return
+; Tx State Idle Must-Notify
+; Tx State Busy Busy
+;
+; serialu_write_ready will *not* be called directly from
+; serial_write_please, but only from serial_interrupt (as discussed
+; above).
+;
+; Exceptionally, serial_write_please is fully reentrant. It need not
+; be called from interrupt context and need not be called with
+; interrupts disabled. It is permissible for serial_write_please to
+; be interrupted by an invocation of serial_interrupt or vice versa.
+;
+; For example, if the main program has a buffer of characters for
+; transmission, serialu_write_ready would call serial_write_byte if
+; the buffer had something in it. If it didn't then it would simply
+; return. When something is put in the buffer, the main program would
+; call serial_write_please unconditionally, which would ensure that
+; serialu_write_ready will be called soon.
+
+;======================================================================