
!BBCTape - technical details.

The protocol
============

  The transfer protocol is fairly simple. The Beeb sends "SB" and waits for
"sb" to come back, as a handshake. If it gets anything else it just tries
again. The Arc then sends a command: either &C0 (stop), &30 (read file
name), &0C (load file) or &3 (load using BGET). Stop is unused at the moment
(you can just hit <escape> on the Beeb keyboard). The codes are chosen to
have the maximum difference in bit patterns. If the command is recognised
the Beeb sends &FF; if not it sends 0, which the Arc announces as a protocol
error. For <read file name> the Beeb expects a <cr>-terminated name, < 11
characters long, and then goes back to the handshake phase (but will flag
anything except a load command as an error). If not sent a file name it just
uses a <cr>, which loads the next file on the tape.

  The reason for the OSBGET load option is that initially I couldn't get
OSFILE to work; this turned out to be because my copy of the Advanced User
Guide (page 335) says that OSFILE is at &FFCE, whereas it should say &FFDD.
Having written the code I decided I might as well leave it in, although I
don't know of any case where it would make a difference (it does help a bit
in debugging to have two different versions). It would help if you wanted,
say, to use sideways RAM to let you load files longer than 27.5 K. It does
essentially the same as the OSFILE load, except that it counts the bytes as
it reads them rather than taking the file length from the OSFILE parameter
block. However the file is loaded, the load/execution addresses and file
name are read from the block header stored at &3B2-&3D0 (see AUG p. 279).

  The file length is then output, low byte first; this is only used as a
check for load errors.  The file is output in 256-byte blocks. Each block
starts with &FF, followed by the block length, which is sent three times to
guard against corruption. The block itself is then sent, followed by a
two-byte cyclic redundancy check (CRC). This is supposedly the same as the
one used by the cassette filing system, as given in the AUG on p. 348. I've
never actually seen any errors, so I don't know how good it is. The Arc has
an ARM-code version of this, as the Basic version took over 2 seconds, which
was almost as long as it took to transmit the block! The ARM version takes
about 5 ms, which shows that Basic isn't always the best solution. If the
CRC matches, the Arc sends back &FF and the next block is sent; if the Arc
replies with 0 the block is re-sent. Finally, a 0 byte marks the end-of-file
(instead of the &FF block-start code).

  The Beeb then sends the load and execution addresses, followed by the file
name terminated by a <cr>. It then goes back to the handshake phase to wait
for a new command.

The Arc program
===============

I initially wrote the Arc end as a normal Basic program. Turning it into a
multi-tasking Wimp application was harder than I expected. The normal
program knew where it was in the protocol by its position in the code, but
you can't do that with a Wimp program. It's therefore implemented as a state
machine, with a state transition whenever a phase of the protocol is
completed. To some extent any Wimp program will be like that, as you have to
remember what you were doing for any process which persists over a call to
Wimp_Poll. However, this application has a particularly large number of
distinct states, as the whole thing is driven by the asynchronous arrival of
bytes in the serial buffer, so you can't just sit in a loop waiting for data
to arrive. I think the program is fairly robust against errors, and you can
always use <Reset> to put the state machine back to its initial state, but
making changes is not trivial!

  I'm afraid the program isn't too well commented; this is partly laziness,
partly to avoid making it any larger, partly because the structure and
long variable names make it fairly self-commenting, and partly because the
nature of the program makes explanations rather complicated. Changes to
the protocols tend to have ramifications all over the place, so if you
change anything make sure you know what you're doing!

  The loaded file is stored in a permanently reserved block 32K long. As
Beeb files can't be very long this seemed simpler than any form of dynamic
memory management, and it makes in-memory transfer extremely simple to
implement.

  One general point; note that if a DataLoad goes unacknowledged, the
program deletes the actual file it saved, not <Wimp$Scrap> as it says
in the PRM; I think this is safer.

Type-guessing
=============

The type-guessing algorithm is rather trivial, and would be easy to improve
(I'm sure I've seen an algorithm in a magazine, but I can't find it). The
only thing it should get consistently right is a Basic file, which is taken
to have an execution address between &8000 and &BFFF amd a load address in
RAM.

  The relevant routine is PROCguess_type; it currently just looks at the
load and execution addresses, stored in load% and exec%, but you could also
look at the file itself, stored from file_block% to file_ptr%-1, and the
original file name, stored in (surprise, surprise) original_file_name$.

The Beeb program
================

  The Beeb end of the link is a machine-code program which lives in pages
&B, &C and the start of &D, so you lose function keys, user-defined
characters and the NMI code (see below for use with discs). The source code
is stored in readable form in BBCLoad, and BBCLoadBT is a version with line
numbers (obtained by putting it through a Basic to Text converter twice) and
which has been CR<>LFed in !Edit. Note that the first three and last three
lines should not have line numbers. The first few lines give the addresses
of data areas used by the program. It normally loads files to &E00 to give
the maximum possible space, but can load to any page boundary.

Disc systems
============

This program should be able to copy from tape on a Beeb with disc drives, as
it selects *TAPE and does PAGE=&E00 at the beginning, which should leave it
looking like a tape-based system. Loading files from disc is a bit more
problematic; it would be better done with a dedicated program, but it's
probably possible with this program. The main problem is that the code
occupies part of page &D, which is used by the disc system. There is a
version of the loader in the !BBCTape directory called BBCLDisc (with a
downloadable version BBCLDiscBT) which will probably work, although I
obviously can't test it. It has had the OSBGET option removed (it just uses
the OSFILE load), and fits in pages &B and &C with zero bytes to spare! The
load/execution addresses and file name aren't returned, as I don't know
where they're stored in a disc system. In any case, you can't use a null
file name with a disc, so if you don't give one you'll get an error. This
also means that the autoload option won't work.

Other computers
===============

It should be fairly easy to produce a loader program for another computer,
as the protocol doesn't need any knowledge of the filing system apart from
the file name (the load/exec addresses are transmitted, but not used). Of
course, that would only let you transfer programs to the Arc, unless you
implemented the inverse protocol in the Arc program. I didn't see much point
in doing this for the Beeb; the loader program only just fits, and Basic and
text files are fairly easy to transfer anyway - just do *FX 2,1 on the Beeb,
and on the Arc type "Filer_OpenDir serial:" at the command line. This opens
a filer window for the serial port, and files dragged into it will be typed
into Basic or your favorite wordprocessor. Would that it were that easy in
the other direction! Another possibility would be to use the Beeb as a very
slow tape streamer for hard disc backup, but that would be a completely
different program (and would you trust it?).
