TubeHost for Linux

discuss PC<>Acorn file transfer issues & the use of FDC, XFER, Omniflop/disk etc.
User avatar
sweh
Posts: 1847
Joined: Sat Mar 10, 2012 12:05 pm
Location: New York, New York
Contact:

TubeHost for Linux

Postby sweh » Sat Feb 16, 2013 4:25 pm

Thanks due to JGH for his help and, of course, in writing the HostFS code in the first place! If you want the code, follow the link to http://sweh.spuddy.org/Beeb/TubeHost/

Code: Select all

The latest version of this code is always at
  http://sweh.spuddy.org/Beeb/TubeHost/

This is a Unix TubeHost filesystem written in perl based around JGH's
HostFS concept

  http://mdfs.net/Software/Tube/Serial/
  http://mdfs.net/Software/Tube/Serial/HostFS.txt

In this model, the HostFS ROM makes "Tube" like communication but using
the RS423 serial port instead.  Since RS423 is a single channel in each
directions, commands are embedded in the datastream.  Essentially the
HostFS passes standard BBC calls (eg OSBGET, OSARGS, OSFSC) and data
structures across the channel, and all the complicated processing is
performed on the remote server (aka TubeHost or Host, for short).

Now this design (whilst slightly idiosyncratic - eg in how file data is
transferred) is very clever and flexible.  Ultimately it's up to the Host
as to how to present a filesystem.  *COMMANDS are also interpreted by
the Host.  In JGH's reference code he has a BASIC TubeHost server (and a
precompiled Windows .exe from it).  This has an ADFS look and feel; it's
a hierarchical filesystem, with *DIR enter subdirectories, and "." as the
directory separator and so on.  His code translates Host<->Beeb filenames
and presents them in a form native to the Beeb.

I took a more DFS-like approach, taking ideas from MMB structures.  In
my system we have a single level tree (eg $HOME/Beeb_Disks).  Each Unix
subdirectory becomes an available disk which can be "inserted" into a
drive (using the *DIN) command.  There are 10 drives available (0->9).

If the Unix directory is numbered then we assign this disk to a slot of
that number; any unnumbered directories are assigned sequential numbers

So, for example, on Unix:
    % ls Beeb_Disks
    0.Mr_Ee  1.test1  10.test10  TAPES

We would see this on the Beeb:
    >*DCAT
   
    Disks available:
         0: 0.Mr_Ee
         1: 1.test1
        10: 10.test10
        11: TAPES

"TAPES" was assigned "11" because it was the next free slot.

The rationale behind this structure was to make SSDs easier to handle.
Using MMB_utils ( http://sweh.spuddy.org/Beeb/mmb_utils.html ) we could
extract the contents of an SSD into a directory and now it shows up on
the Beeb exactly as it should.

    % cd Beeb_Disks
    % beeb getfile ~/Cylon_Attack.ssd Cylon_Attack
    Saving $.Ca as Ca
    Saving $.Cylon as Cylon
    Saving $.!BOOT as !BOOT
    % ls Cylon_Attack
    !BOOT  !BOOT.inf  Ca  Ca.inf  Cylon  Cylon.inf

And now:
    >*DCAT
    Disks available:
         0: 0.Mr_Ee
         1: 1.test1
        10: 10.test10
        11: Cylon_Attack
        12: TAPES
    >*DIN 5 Cylon_Attack
    >REM could also have done *DIN 5 11 'cos the assigned number was 11
    >*I. :5.*.*
    $.Cylon     L  FF1900 FF8023 00237E
    $.Ca        L  001100 00257D 004900
    $.!BOOT        000000 000000 000025
    >*DRIVE 5
    >*TYPE !BOOT
    10CLOSE#0
    20*FX21
    30CHAIN"CYLON"
    RUN
    >

We can see the load/exec/locked attributes have been mainted, due to the
INF files (which should be bbcim compatible).

When TubeHost starts up, any disks with numbers 0->9 are pre-loaded into
slots 0->9.  You can see the current disks loaded:
    >*HSTATUS D
    Disk 0: 0.Mr_Ee
    Disk 1: 1.test1
    Disk 2:
    Disk 3:
    Disk 4:
    Disk 5: Cylon_Attack
    Disk 6:
    Disk 7:
    Disk 8:
    Disk 9:

    Current drive: 5
    Current directory: $ (:5:$)
    Current library: :0.$


Functions handled
=================

  0x0C => 'OSARGS',
    Y=0, A=0 return current filesystem in A  (Also handled in HOSTFS ROM)
    Y=0, A=1 return rest of command line   (Handled in HOSTFS ROM)
    Y=0, A=255 sync all open files
   Y!=0, A=0 Get PTR#
   Y!=0, A=1 Set PTR#
   Y!=0, A=2 Read length (EXT#)
   Y!=0, A=3 Set length (EXT#)   [ see note ]
   Y!=0, A=255 Sync this file

  0x0E => 'OSBGET',
    Y=filehandle, read byte from file into A, C set if EOF before read occured

  0x10 => 'OSBPUT',
    Y=filehandle, write byte from A into file

  0x12 => 'OSFIND',
    A=0, close file Y
    A=40, openin
    A=80, openout
    A=C0, openup

  0x14 => 'OSFILE',
    00 SAVE
    01 rewrite load/exec/attr
    02 rewrite load
    03 rewrite exec
    04 rewrite attr
    05 read catalog entry
    06 Delete
    07 Create empty file of defined size
    FF LOAD

  0x16 => 'OSGBPB',
    A=1 write bytes to new ptr
    A=2 write bytes to current ptr
    A=3 get bytes from new ptr
    A=4 get bytes from current ptr
    A=5 Read disks title, boot opts
    A=6 read directory name
    A=7 read library name
    A=8 read files from directory

  0x18 => 'OSFSC',
    00 *OPT  [ see note ]
    01 CheckEOF
    02 */
    03 *command
    04 *RUN
    05 *CAT
    06 New filesystem  (handled by HOSTFS ROM)
    07 Handles (handled by HOSTFS ROM?  Done here as 0x80-0x9F just in case)
    08 *command alert  (dropped by HOSTFS ROM)
    09 *EX
    0A *INFO
    0B *RUN for library  [ see note ]

COMMENTS
=========
OSARGS Y!=0, A=3 Set length (EXT#) - Neither B nor Master support this;
  the code is there but I dunno if it'll work

OSFILE 07 Create empty file of defined size - appears to work.

OSFSC
  00 *OPT - "*OPT 5" sets debug level on host.
            "*OPT 6" sets speed delays (see below)
            No other *OPT value does anything
  0B *RUN for library - not sure how to verify this one works!

OSGBPB
  A=5 Read disks title, boot opts - disk name truncated to 12 chars if
       necessary
  A=8 read files from directory - This appears to work.  Note that Unix
    filenames may be long and BBC programs may expect 7 or 10 character
    limits; not a bug in TubeHost but in Beeb programs

A full Tube Host should also handle other types of calls (eg OSRDCHIO).
These are not handled by this program; we are a pure filesystem server
and not a generic Host application.  Calls *NOT* handled:
   0x00 => 'OSRDCHIO',
   0x02 => 'OSCLI',
   0x04 => 'OSBYTELO',
   0x06 => 'OSBYTEHI',
   0x08 => 'OSWORD',
   0x0A => 'OSWORD0',

*COMMANDS
=========
can be prefixed with a ! if a ROM or OS commands conflicts
  *HSTATUS [DF]
     Displays status of Host, including what disks are in what slots,
     current directory/library status, and what files are currently open.
     "D" limits to disks/directories; "F" limits to open files
 
  *DCAT
     Shows what disks (Unix subdirectories) are available
   
  *DCREATE diskname
     Creates a new Unix subdirectory
   
  *DIN drive disk
     Inserts "disk" into drive
   
  *DOUT drive
     Ejects "disk" from drive
   
  *DRIVE drive
  *DIR dir
     As per DFS
   
  *HRESET
     Causes TubeHost to re-exec itself, which effectively resets it
     to startup mode (default disks, default directories, no open files etc)
   
  *INFO filespec
  *DELETE file
  *RENAME file1 file2
  *ACCESS file [L]
     As per DFS

  *DMP file
     Test emulation of *DUMP performed on Host side
   
  *FOO count
     Debug command; sends "count" number of X's to the screen

Running
=======

This is pure perl code.  To talk to a serial port you need the
Device::SerialPort module.  I'm not sure if I'm making any hard assumptions
around Unix/Linux so this may work on other platforms.

./TubeHost [-s|-u] device [speed]

   "-s" ==> serial device (default)
   "-u" ==> Unix domain socket
   device ==> filename to connect to
   speed ==> Baud rate (only for serial; 9600 default).

"Unix domain socket" is for VirtualBox users and BeebEm.  It's possible
to configure VirtualBox so the client OS (Windows, for example) has its
serial port mapped to a Unix domain socket.  Then BeebEm can connect its
serial port to the client OS serial port.  In this way TubeHost can talk
to HostFS inside BeebEm inside Virtualbox.  It's how I did my debugging!

*OPT6
=====
Now HostFS and TubeHost is totally reliant on a clean serial channel.
I've found, in testing, that sending data too quickly can cause
characters to be lost, and thus corruption.  I've seen this with both
real serial ports and the VirtualBox emulated serial port.  It's unclear
if the issue is in HostFS or in my serial cable and the Linux/Virtualbox
serial emulation.  To work around this the serial send routines
have delays built into them; after "A" characters have been sent, delay
for "B" microseconds.  The default is "A=1,B=1", which causes a 1ms
delay after each character sent.  Throughput on a 9600 baud connection
works out around 720cps.  Not as fast as floppy, but a lot faster than
tape :-)

These values can be tuned with "*OPT6".  Convert AB into hex; &AB (or
A*16+B) and pass to *OPT6.  So the default is, effectively, *OPT6 17.
If you are finding communication issues you can use *OPT6 and "*FOO"
to help tune these timings.  Once you have good values then you can, of
course, hard code them into the script.
Rgds
Stephen

User avatar
jgharston
Posts: 2759
Joined: Thu Sep 24, 2009 11:22 am
Location: Whitby/Sheffield

Re: TubeHost for Linux

Postby jgharston » Sun Feb 17, 2013 1:41 pm

sweh wrote:In JGH's reference code he has a BASIC TubeHost server (and a precompiled Windows .exe from it). This has an ADFS look and feel; it's a hierarchical filesystem, with *DIR enter subdirectories, and "." as the directory separator and so on.
Note, to make the above comment more explicit, TubeHost does not present an ADFS-like filing system, Windows presents an ADFS-like filing system, all that TubeHost does is export whatever filing system it happens to be sitting on. TubeHost running on RISC OS with ImageDFS as the selected filing system exports a DFS-like filing system (ie, ImageDFS).

Code: Select all

$ bbcbasic
PDP11 BBC BASIC IV Version 0.25
(C) Copyright J.G.Harston 1989,2005-2015
>_

User avatar
sweh
Posts: 1847
Joined: Sat Mar 10, 2012 12:05 pm
Location: New York, New York
Contact:

Re: TubeHost for Linux

Postby sweh » Sun Feb 17, 2013 2:01 pm

jgharston wrote:
sweh wrote:In JGH's reference code he has a BASIC TubeHost server (and a precompiled Windows .exe from it). This has an ADFS look and feel; it's a hierarchical filesystem, with *DIR enter subdirectories, and "." as the directory separator and so on.
Note, to make the above comment more explicit, TubeHost does not present an ADFS-like filing system, Windows presents an ADFS-like filing system, all that TubeHost does is export whatever filing system it happens to be sitting on. TubeHost running on RISC OS with ImageDFS as the selected filing system exports a DFS-like filing system (ie, ImageDFS).

Yes and no :-) You provide a "*CDIR" command; you trap "^" to mean ".."; you convert the directory separator from a \ to a . on output and back again on input; and so on. Your TubeHost does more than just export the underlying filesystem; it "Acornifies" it. Which is a good thing :-)

I chose a different path; rather than expose and mangle the underlying OS, my TubeHost tries for a DFS look'n'feel. This is only possible because of how much control the TubeHost code has over the presentation layer.
Rgds
Stephen

User avatar
BigEd
Posts: 1496
Joined: Sun Jan 24, 2010 10:24 am
Location: West
Contact:

Re: TubeHost for Linux

Postby BigEd » Tue Feb 26, 2013 6:47 pm

Great work Stephen! I wanted something like this... was thinking of hooking up my STM32F4-based emulator "a6502" as a copro.
Cheers
Ed

Edit: I needed to

Code: Select all

sudo apt-get install libdevice-serialport-perl

User avatar
sweh
Posts: 1847
Joined: Sat Mar 10, 2012 12:05 pm
Location: New York, New York
Contact:

Re: TubeHost for Linux

Postby sweh » Sun Sep 22, 2013 8:38 pm

Just in case anyone else is using this code, there have been a few minor updates

Code: Select all

# v0.01 - 2013/02/16 - first release
# v0.02 - 2013/02/16 - mess around with Device::SerialPort
#                      to avoid need for delays
# v0.03 - 2013/04/06 - Minor tweaks to handle UPURS
# v0.04 - 2013/04/07 - *OPT4 handling; shift-break handling
# v0.05 - 2013/04/20 - Hide *OPT4 value from most routines.  Fix OSFILE getattr
#                      to also return length properly!
# v0.06 - 2013/09/07 - *HSTATUS and *DCREATE were sending an additional <00>
#                      which was confusing the client no end!
# v0.07 - 2013/09/15 - add a pseudo "L" drive for _Library mapping; always
#                      search this if command not found in $dir or $lib
#                      Add *IAM and *VERSION
# v0.08 - 2013/09/22 - add *DBOOT - it cheats and sends back a binary
#                      that does a *FX 255 7 and then calls (&FFFC)
#                      Allow disk names with a number prefix to be called
#                      without the number


The _Library mapping might be of interest. From the README

Code: Select all

There is an invisible drive L which is mapped to the _Library directory on the
host.  This will be searched for bad commands if the normal search mechanism
fails.  You can save executables here.
eg
   10FOR A=0 TO 3 STEP 3
   20P%=&900
   30[OPT A
   40LDX #0
   50.LP
   60LDA MSG,X
   70BEQ FIN
   80JSR &FFEE
   90INX
  100BNE LP
  110.FIN
  120RTS
  130.MSG
  140EQUS "HELLO"
  150EQUB 13
  160EQUB 10
  170BRK
  180]
  190NEXT
  200OSCLI "SAVE :L.GRONK 900 "+STR$~P%

Now "*GRONK" will print "HELLO".  This allows you to build out a library
of commands that will always be present.  (You can, of course, use *DIN to
change where the L drive points).
Rgds
Stephen


Return to “software & utilities for the pc, mac or unix”

Who is online

Users browsing this forum: No registered users and 1 guest