Unix pages
Home -> UNIX software -> JOYCE -> LocoLink

LocoLink

LocoLink is a cable and software used to connect a PCW to a PC, so that documents can be transferred from the PCW (most likely with 3" drives) to the PC (with 5.25" or 3.5" drives).

Hardware

The physical cable has an edge connector at one end, to plug into the PCW's expansion port, and a DB-25 connector at the other to plug into the PC's parallel port. All you need to do is connect the computers together, run the transfer software and the files you require are pushed or pulled across.

At the PCW end, the LocoLink appears at I/O port 0FEh:

BitWhen readWhen written
0Data 0BUSY
1Data 1ACK

At the PC end, the LocoLink appears as a parallel printer; the value written by the PC is latched when the STROBE line is raised and then lowered.

In practice, the values sent from the PCW to the PC are inverted: when the PCW writes 1, the value on the wire is 0 and vice versa. When the PC reads the BUSY signal, it is then inverted again by the PC's chipset. So what you see is something like this:

On the PCWOn the wire On the PC
PCW writesBit 1Bit 0 BUSY~ACK ~BUSY~ACKPC reads
000 11 01040h
101 01 110C0h
210 10 00000h
311 00 10080h

LocoLink on other systems

Official LocoLink software only exists for the PC (under PCDOS and Win16) and the PCW. However, with suitable software any system that provides a Centronics port and allows the BUSY and ACK lines to be read would be able to act as the 'PC' end of a LocoLink conversation.

If, instead of the LocoLink cable, you connect two PCs together with a LapLink cable, then one of the PCs could act as the 'PCW' end of a LocoLink conversation. Because of the wiring of the LapLink cable, this would be done by writing to data bits 3 and 4 to set ACK and BUSY at the other end, and reading ERROR and SELECT IN to receive the values written by the other end.

Software

The supplied software had four major versions:

LocoLink 1.x

Supplied with LocoScript PC version 1.x. In this version, a server (LLPC.EXE) is run on the PC, and a client (LLPCW.COM) on the PCW.

This version of the software was reviewed in the April 1991 issue of 8000 Plus, on page 12. As the review points out, the transfer is a one-way process; files can be sent from the PCW to the PC, but not brought back in the other direction.

As well as the LocoLink cable, this version also allows the transfer to be made using a serial port, if the PCW has one fitted.

[Screenshot of LocoLink 1.4 running under emulation

LocoLink 2.x

An add-on for LocoScript PC 1.5 and later versions. In this version, the server (LLINK202.EMS) runs on the PCW, and the client is integrated into LocoScript PC. The PCW appears as another drive (usually with the letter Z:) within the Disc Management screen of the PC. Files can be copied both ways, or even edited 'live'.

Locomotive's Script newsletter describes this version here.

[Screenshot of LocoScript PC showing PCW as drive Z:] [Screenshot of PCW LocoLink 2.02 running under emulation]

LocoLink 3.x / LocoLink for Windows

A standalone file converter program for Windows 3.x. Again, the server runs on the PCW. This time the client is a Windows program that can copy files from the PCW to the PC, and optionally convert them from LocoScript format into wordprocessor formats better known on the PC, such as Word, WordPerfect, WordStar or Ami Pro. The PCW appears as one or more extra drives inside the file selector.

Once more, files could only be transferred from the PCW to the PC, not in the opposite direction.

[Screenshot of LocoLink for Windows showing PCW in drive chooser

LocoLink 16

For the PcW16. The client is built into the PcW16's system software (Rosanne). The server (which runs on an older PCW) LocoLink 3.x, the same program as used by LocoLink for Windows.

Within Rosanne, if an active LocoLink connection is detected, the "Import" file selector displays "LocoLink A/B" buttons allowing the user to read files from either drive on the PCW. There is no facility to export from the PcW16 to the other PCW, though the Rosanne API does allow files to be written so it would be possible to write a Rosanne program to do this.

[Screenshot of Rosanne file chooser showing LocoLink options

[Screenshot of LocoLink 3.00 serving files to a PcW16

Third-party software

Three Inch Software produced a program, PCW Link, which allowed the LocoLink cable to be used to connect between two PCWs provided that one of them was a 9512 or 9512+. The "PC" end of the cable would be plugged into the parallel port on the 9512/9512+, the "PCW" end into the other computer. A 9512 / 9512+ was required because the parallel port interfaces on other PCWs don't provide the necessary access to the ACK signal.

Unlike LocoLink proper, which shares individual files, this software shared drives at a sector level. The drives of the server PCW would appear to the client as K: and L:.

Since this sofware was not written by Locomotive and I don't have a copy to study, I don't know whether it used the same wire protocol as LocoLink proper.

A review and screenshots can be found in PCW Plus, issue 68.

When a LocoLink interface is connected to the PCW9512 parallel port, the following values are read from bits 7 and 6 of the parallel port status register:

PCW writes9512 reads
00C0h
1080h
2040h
3000h

Emulating LocoLink

JOYCE can emulate the PCW end of a LocoLink connection. Instead of a LocoLink interface, it would use a LapLink cable to connect the parallel port of the PC running JOYCE to the parallel port of the PC running LocoScript PC / LocoLink for Windows.

Similarly, ANNE can emulate the "PC" end of a LocoLink connection, accessing a real LocoLink cable through the host PC's parallel port.

JOYCE can also emulate LocoLink without a physical cable, sending its data through a TCP/IP port. Using LocoLink 3.00, this would allow a LocoLink connection to be emulated between instances of JOYCE and ANNE running on the same computer.

Wishlist

I'm looking out for a copy of PCW Link (published by Three Inch Software).

In addition, I would be interested to see versions of LocoLink for the PCW other than 1.03, 1.04, 2.02 or 3.00.

Wire Protocol

It's simplest to consider the number written by either end of the link as a number, 0 to 3. When writing from PC to PCW, that's simple: the PC writes n to the parallel port, and the PCW reads n from port 0FEh. Going the other way, the PCW writes n but the value the PC reads has the two bits swapped and the low bit inverted:

PCW writesPC reads
0040h
10C0h
2000h
3080h

In this document, I'll use the values seen and written by the PCW throughout.

Link idle

When the link initially starts, the server sends 2 and the client sends 3. This corresponds to the server listening for the first packet, and the client being ready to transmit.

Sending a packet

In order to send a packet, the transmitting computer checks that the other end is sending the value 2. It may also be 3; if so, send 3 and wait for it to change to 2.

Then:

The procedure to send each byte is:

Receiving a packet

Receiving is obviously the same protocol, seen from the other end:

The procedure to receive each byte is:

Serial Port

When LocoLink 1 is transmitting over a serial port, it transmits packets in the same form (type, payload length, payload, checksum) at 9600 baud with one stop bit.

Packet types

The first packet is sent by the client, and identifies which version of the protocol they are using. If the server recognises the packet, it will send a suitable response and the link is established.

LocoLink 1.x

SenderTypePayload lengthPayload
Client07h02h43h31h
Server55h01h07h

LocoLink 2.x

SenderTypePayload lengthPayload
Client0Bh02h-20h41h31h Client program name (optional)
Server0C3h01h-1Fh0Bh Server program name (optional)

LocoLink 3.x (for Windows / LocoLink 16)

SenderTypePayload lengthPayload
Client5Ah02h-20h46h31h Client program name (optional)
Server18h01h-1Fh5Ah Server program name (optional)

Once the connection is established, the packet types sent depend on which version of the protocol is in use.

LocoLink 1.x

The client may send the following packet types to the server:

14h
Hangup: The client disconnects from the server.
21h
Check space for file. Packet contains a 32-bit little-endian file length, followed by ASCIIZ pathname.
2Eh
Create file. Packet contains a 32-bit little-endian file length, followed by ASCIIZ pathname.
3Bh
Append bytes to the currently open file. Packet contains the bytes to append.
48h
Close currently open file. Packet contains the CRC16 of the file as a little-endian word.
6Fh
Create a directory. Packet contains ASCIIZ path name.
7Ch
Check if file / directory exists. First byte of packet payload is the search type (0 for directory, 1 for file) and the remainder is the ASCIIZ pathname.

The server may send the following packet types to the client:

55h
Result. Payload is 2 bytes. The first is the type of the packet being replied to, and the second is an error flag (0 for success, other value for failure).
62h
Unknown packet type received. No payload.

LocoLink 2.x

The client may send the following packet types to the server:

22h
Hangup: The client disconnects from the server.
39h
Make a DOS call. The payload is 1-15 bytes:
ByteMeaning
0Function (AH)
1Subfunction (AL)
2-3BX
4-5CX
6-7DX

In theory, longer versions of this packet containing SI, DI and BP could also be transmitted. Note that the packet may be shorter than you'd expect. For example, MS-DOS function 0Eh takes a drive number in DL. But since LocoLink 2.x only supports one drive, it does not need the drive number and so the transmitted packet only contains one byte of payload, the function number.

The packet for function 4Fh (find next file) comes in two forms: a 'short' one with a single byte of payload:

ByteMeaning
0Function (AH)

... and a 'long' one with 15 bytes:

ByteMeaning
0Function (AH)
1-16Bytes 0x07-0x14 of the result from FindFirst
95h
Requested data. Sent by the client following receipt of a type 7Eh packet (see below).
0C3h
Acknowledge data result or echo request.

The server may send the following packet types to the client:

50h
Success. Payload length is 0-8 bytes, giving the register values of AX, BX, CX, DX as little-endian words.
67h
Error. Payload length is a little-endian word, giving the DOS error number (cf INT 21h function 59h)
7Eh

Request data. Used where the corresponding DOS function passes data using a memory buffer. For example, when calling DOS function 3Ch (create file) you pass DX as the pointer to the filename. In LocoLink, the server sends a packet requesting the ASCIIZ data at DX, which the client then provides.

The packet has two bytes payload: the first gives the data source, the second the maximum length. The data source IDs are:

11h
Fixed length, buffer at DX
36h
Fixed length, buffer at DTA
5Bh
Fixed length, buffer at SI
80h
ASCIIZ, buffer at DX
0A5h
ASCIIZ, buffer at SI
0CAh
ASCIIZ, buffer at DI
0EFh
Fixed length, buffer follows last data copied

The last option is used when multiple transfers are necessary for the requested amount of data. For example, attempting to write 300 bytes to a file will cause two requests to be sent: the first of type 11h (data at DX), the second of type 0EFh (continue following last address).

0ACh

Return data to the client. The first byte of the payload is the location code (as above, but only codes 11h, 36h, 5Bh and 0EFh are supported) and the remainder of the packet contains the data to return. The client will acknowledge with a packet of type 0C3h containing a payload of 0ACh.

0DAh
Keep-alive. There is no payload. The client will acknowledge with a packet of type 0C3h containing a single data byte, 0DAh. This is used to stop the client disconnecting with a timeout while the server is awaiting user intervention (for example, if there is a data error reading a disc).

DOS function calls supported by LocoLink PCW 2.x are:

Function numberMeaningParametersAdditional transfersResults if successful
0DhLog out drivesnonenonenone
0EhSelect drivenonenoneAL=1 (one drive)
10hClose disc labelnonenonenone
11hGet disc labelnoneServer returns disc label as a DOS extended FCBnone
13hDelete disc labelnonenonenone
16hCreate disc labelnoneClient sends disc label as a DOS extended FCBnone
17hRename disc labelnoneClient sends a DOS extended FCB. Behaves exactly as function 16h except that the second filename (at FCB+11h) rather than the first (at FCB+1) is used.none
36hGet free spacenonenoneAX = sectors per cluster
BX = free clusters
CX = bytes per sector
DX = total clusters
39hCreate directorynoneClient sends ASCIIZ pathnameAlways fails (CP/M can't create more user areas)
3AhRemove directorynoneClient sends ASCIIZ pathnameAlways fails (CP/M can't remove user areas)
3BhSet current directorynoneClient sends ASCIIZ pathnamenone
3ChCreate fileCX=attributesClient sends ASCIIZ pathnameAX=handle
3DhOpen fileAL=modeClient sends ASCIIZ pathnameAX=handle
3EhClose fileBX=handlenonenone
3FhRead fileBX=handle, CX=countServer sends data readAX=count of bytes read
40hWrite fileBX=handle, CX=countClient sends data to writeAX=count of bytes written
41hErase filenoneClient sends ASCIIZ pathnamenone
42hSet file pointerAL=whence, BX=handle, CXDX=offsetnoneDXAX = new file position
43hGet file attributesAL=0Client sends ASCIIZ pathnameCX=attributes
43hSet file attributesAL=1, CX=attributesClient sends ASCIIZ pathnamenone
44hGet device informationAL=0, BX=0, CX=0NoneDX=device flags
47hGet current directorynoneServer returns current directorynone
4EhFind first fileAL=search attributeClient sends search path. If successful server returns find file data.none
4FhFind next file nonenoneFind file data (bytes 0x14 onward)
Bytes 0x07-0x14 of last find file data
56hRename filenoneClient sends old, then new pathnamenone
57hGet timestampAL=0, BX=file handlenoneCX=time, DX=date
57hSet timestampAL=0, BX=file handle, CX=time, DX=datenonenone
5BhCreate file (if it doesn't exist)CX=attributesClient sends ASCIIZ pathnameAX=handle

Notes

  1. The LocoLink 2.x server assumes all pathnames are absolute and in upper case. The 'current directory' set by function 3Bh is returned by function 47h, but does not appear to affect the directory used by other functions.
  2. For some reason, function 4Fh does not do a separate transfer to return its results, unlike function 4Eh. Instead, the final result packet contains one word (AX) followed by bytes 0x14 onward of the find file data.
  3. The server does not support CP/M exact file lengths. If a file of (say) 600 bytes is written, this will be rounded up to a CP/M file of 640 bytes, with the last record padded with zero bytes.
  4. In general, this protocol is vulnerable to Heartbleed-style attacks on the client by a buggy or malicious server. The server can respond to any call with packets of type 7Eh (request data) or 0ACh (return data), causing arbitrary ranges of the client's memory to be uploaded or overwritten. Even returning more bytes than the client was expecting can lead to buffer overflows.

LocoLink 3.x (for Windows / LocoLink 16)

The client may send the following packet types to the server:

05h
Echo request. Contains 0-32 bytes of payload, which will be returned in an Acknowledge packet.
18h
Acknowledge data result or echo request.
6Dh
Hangup: The client disconnects from the server.
80h
Make a DOS call. The payload is 1-17 bytes:
ByteMeaning
0Function (AH)
1Subfunction (AL)
2-3BX
4-5CX
6-7DX

In theory, longer versions of this packet containing SI, DI and BP could also be transmitted. As with LocoLink 2.x, the packet may be shorter than you'd expect since irrelevant registers are not included.

The packet for function 4Fh (find next file) comes in two forms: a 'short' one with a single byte of payload:

ByteMeaning
0Function (AH)

... and a 'long' one with 17 bytes:

ByteMeaning
0Function (AH)
1-16Bytes 0x06-0x15 of the result from FindFirst

This is because LocoLink for Windows performs depth-first searches of subdirectories. When it encounters a subdirectory, it begins a new FindFirst operation to list the files in that subdirectory; once the files have been enumerated, it then uses the 'long' version of the FindNext call to resume its search of the parent directory at the point it left off. Thus the server must be prepared to handle multiple concurrent searches, and store enough state in bytes 0x06-0x11 of the FindFirst result structure to identify which one is being requested.

0CCh
Requested data. Sent by the client following receipt of a type 0B9h packet (see below).

The server may send the following packet types to the client:

18h
Acknowledge an echo request.
2Bh
Keep-alive. The client will acknowledge with a packet of type 18h containing a single payload byte: 2Bh.
93h
Success. Payload length is 0-8 bytes, giving the register values of AX, BX, CX, DX as little-endian words.
0A6h
Error. Payload length is a little-endian word, giving the DOS error number (cf INT 21h function 59h)
0B9h

Request data.

The packet has two bytes payload: the first gives the data source, the second the maximum length. The data sources used are the same as in LocoLink v2.x:

11h
Fixed length, buffer at DX
36h
Fixed length, buffer at DTA
5Bh
Fixed length, buffer at SI
80h
ASCIIZ, buffer at DX
0A5h
ASCIIZ, buffer at SI
0CAh
ASCIIZ, buffer at DI
0EFh
Fixed length, buffer follows last data copied
0DFh

Return data to the client. The first byte of the payload is the location code (as above, but only codes 11h, 36h, 5Bh and 0EFh are supported) and the remainder of the packet contains the data to return. The client will acknowledge with a packet of type 018h containing a payload of 0EFh.

The LocoLink 3.x server supports the same range of function calls as LocoLink 2.x, though the parameters used differ in various ways. However the known clients (LocoLink for Windows and LocoLink 16) only call a subset of them (listed below). For example, LocoLink 3.x provides functions to get and set the disk label, just like LocoLink 2.x. However LocoLink for Windows and LocoLink 16 never call them, and perhaps in consequence they don't appear to be fully debugged.

Calls made by LocoLink for Windows and LocoLink 16 are:

Function numberMeaningParametersAdditional transfersResults if successful
0DhReset driveAL=mode (0 for CP/M, 0FFh for LocoScript) DL=drivenone
0EhSelect driveDL=drivenoneAL=drive count
3ChCreate fileCX=attributesClient sends ASCIIZ pathnameAX=handle
3DhOpen fileAL=modeClient sends ASCIIZ pathnameAX=handle
3EhClose fileBX=handlenonenone
3FhRead fileBX=handle, CX=countServer sends data readAX=count of bytes read
40hWrite file (LocoLink 16 only)BX=handle, CX=countClient sends data to writeAX=count of bytes written
4EhFind first fileAL=search attributeClient sends search path. If successful server returns find file data.none
4FhFind next file nonenoneFind file data (bytes 0x13 onward)
Bytes 0x06-0x15 of last find file data

Other calls handled by the LocoLink 3 server include:

Function numberMeaningParametersAdditional transfersResults if successful
10hClose disc labelnonenonenone
11hGet disc labelnoneServer requests first 7 bytes of extended FCB. It should return disc label as a DOS extended FCB.
Bug (observed in LocoLink 3.00): The server should request eight bytes, not seven, since it subsequently attempts to parse the eighth byte as a drive number, 1=>A: 2=>B: etc. This means the function always returns error 0x15, drive not ready.
none
13hDelete disc labelnoneServer requests first 7 bytes of extended FCB.
Bug: As for function 11h, this should request 8 bytes.
none
16hCreate disc labelnoneClient sends disc label as a DOS extended FCB.
Bug: Like the other label functions, always fails with error 0x15.
none
17hRename disc labelnoneClient sends a DOS extended FCB with the new name populated.
Bug: Like the other label functions, always fails with error 0x15.
none
36hGet free spacenonenoneAX = sectors per cluster
BX = free clusters
CX = bytes per sector
DX = total clusters
39hCreate directorynoneClient sends ASCIIZ pathnameAlways fails (CP/M can't create more user areas)
3AhRemove directorynoneClient sends ASCIIZ pathnameAlways fails (CP/M can't remove user areas)
3BhSet current directorynoneClient sends ASCIIZ pathnamenone
41hErase filenoneClient sends ASCIIZ pathnamenone
42hSet file pointerAL=whence, BX=handle, CXDX=offsetnoneDXAX = new file position
43hGet file attributesAL=0Client sends ASCIIZ pathnameCX=attributes
43hSet file attributesAL=1, CX=attributesClient sends ASCIIZ pathnamenone
44hGet device informationAL=0, BX=0, CX=0NoneDX=device flags
47hGet current directorynoneServer returns current directorynone
56hRename filenoneClient sends old, then new pathnamenone
57hGet timestampAL=0, BX=file handlenoneCX=time, DX=date
57hSet timestampAL=0, BX=file handle, CX=time, DX=datenonenone
5BhCreate file (if it doesn't exist)CX=attributesClient sends ASCIIZ pathnameAX=handle
68hFlush fileBX=file handlenonenone

Notes

  1. Unlike in LocoLink 2.x, function 11h (get disk label) takes a search FCB specifying the drive (though due to bugs this doesn't actually work).
  2. As with LocoLink 2.x, the 'current directory' set by function 3Bh is returned by function 47h, but does not appear to affect the directory used by other functions.
  3. Likewise, function 4Fh returns its result in the final result packet rather than as a separate transfer.

John Elliott 2024-03-02