ADTPro-Wide Protocol

The ADTPro-Wide protocol is an evolution of the 1-byte command protocol that the original DOS-based ADT used and ADTPro v1 extended. The first problem the ADTDPro-Wide protocol was designed to solve is that there was no enveloping of commands, and just a little enveloping of payloads in the v1 protocol. If the client and server got out of sync, it was common for the server to go back to its command loop, and then receive a stream of seemingly random data from the client as it attempted to re-send a non-acknolwedged disk block. The server interpreted that block of data as a stream of commands, sometimes with undesired consequences.

A second design goal was to offer larger packet sizes than the original 256-byte checksummed chunks. ADTPro-wide can now have packet sizes that are checksummed, and limited only by the buffer size of the client. This offers dramatic performance improvements as it can greatly reduce the amount of protocol "chatter" between client and server. There is of course a practical limit of buffer size with Ethernet, bounded by the UDP frame size since there is only a thin layer of support above the physical media layer.

ADTPro-Wide servers can remain compatible with Version 1 clients, which would be necessary at least for the first transaction to create an ADTPro-Wide client disk! Speediboot and SOS bootstrapping operations from an ADTPro-Wide server will automatically create ADTPro-Wide clients.

ADTPro Functions

CD - Change working directory

Directory - View contents of current working directory

Get - Initiate disk image download from host

Put - Initiate disk image upload to host (always overwrite)

Batch - Initiate batch upload (unique suffix added to specified filename prefix)

Nibble - Initiate nibble disk upload to host (always overwrite)

Multiple - Initiate multiple nibble batch upload (unique suffix added to specified filename prefix)

Bootstrapping Functions

Speediboot - Initiate Speediboot ProDOS/ADTPro bootstrap

SOS - Initiate SOS/ADTPro bootstrap

VSDrive - Initiate Speediboot ProDOS/VSDrive/BASIC bootstrap

Packet Formats

CD ('A'+'C' / $C1+$C3) - Change working directory

Directory ('A'+'D' / $C1+$C4) - View contents of current working directory

Size ('A'+'Z' / $C1+$DA) - Query file size

Get ('A'+'G' / $C1+$C7) - Initiate disk image download from host

Put ('A'+'P' / $C1+$D0) - Initiate disk image upload to host (always overwrite)

Batch ('A'+'B' / $C1+$C2) - Initiate batch disk image upload to host (unique suffix added to specified filename prefix)

Nibble ('A'+'N' / $C1+$CD) - Initiate nibble disk image upload to host

Multiple ('A'+'M' / $C1+$CC) - Initiate batch nibble disk image upload to host (unique suffix added to specified filename prefix)

Send Image Data ('A'+'S' / $C1+$D3) - RLE compressed data for image transfer (page-aligned)

Acknowledgement ('A'+'K' / $C1+$CB) - Acknowledgement - one of ACK, NAK, CAN

Summary ('A'+'Y' / $C1+$D9) - Final acknowledgement/summary of results

Return to Home State('A'+'X' / $C1+$D8) - Sender is in home state; partner should return there as well

Send File ('A'+'F' / $C1+$C6) - Send bootstrapping file

Virtual Drive Server Functions

Read Block ('E'+$01) - ProDOS device driver compatible read block request

Write Block ('E'+$02/$04) - ProDOS device driver compatible write block request

Read Block with timestamp update ('E'+$03/$05) - ProDOS device driver compatible read block request with timestamp update

ADTPro Function Flows

Change Directory

Client sends Change Working Directory Packet ('A'+'C' / $C1+$C3)

Host sends:

One byte:
  $00 = ok
  $06 = Unable to change directory

Directory

Apple sends: Directory Packet

Host sends Send Image Data Packet ('A'+'S' / $C1+$D3)

Packet contains 1K of screen-formatted data of directory contents; null-terminated

  Final byte:
    $00 = last screen
    $01 = another screen is available

Get (Receive) disk (Host -> Client)

Client sends Query File Size Packet ('A'+'Z' / $C1+$DA)

Host sends:

Two bytes: file size in blocks (LSB, MSB)
One byte:
  $00 = File exists (and file size is valid)
  $02 = File does not exist
  $04 = File exists, not recognized as a valid disk image

Client sends Image Get Packet ('A'+'G' / $C1+$C7)

Host sends:

One byte:
  $00 = Ok
  $02 = File not found (client aborts)

(loop for as much data is required)

Client sends Acknowledgement Packet ('A'+'K' / $C1+$CB) with payload according to results:

One byte:
  $06 = ACK (Ready for first packet/client understood the packet, CRC is correct;
            send next one) -or-
  $15 = NAK (Resend this same packet again: block number tells what client 
            is still waiting to get a good packet for)
Two bytes: beginning block number being acknowledged (also means ready to start
           with block zero) (LSB, MSB)

Host sends Send Image Data Packet ('A'+'S' / $C1+$D3)

(loop end)

Client sends Summary ('A'+'Y' / $C1+$D9) packet

Put (Send) disk (from client to host)

Client sends Query File Size Packet ('A'+'Z' / $C1+$DA)

Host sends:

Two bytes: file size in blocks (LSB, MSB)
One byte:
  $00 = File exists (and file size is valid)
  $02 = File does not exist
  $04 = File exists, not recognized as a valid disk image

Client sends Image Put Packet ('A'+'P' / $C1+$D0)

Host sends:

One byte:
  $00 = Ok
  $02 = Unable to write (client aborts)

(loop for as much data is required)

Client sends Send Image Data Packet ('A'+'S' / $C1+$D3)

Host sends:

One byte:
  $06 = ACK (Host understood the packet, CRC is correct; send next one)
            (Also: this is a duplicate packet, already received; acknowledge
            so the client sends the next one)
  $15 = NAK (Resend the same packet again)

(end loop)

Client sends Summary ('A'+'Y' / $C1+$D9) packet

Batch send (unique suffix added to specified filename prefix)

Client sends Batch Send Packet ('A'+'B' / $C1+$C2)

Host sends:

  One byte:
  $00 = Ok
  $02 = Unable to write (client aborts)

(loop for as much data is required)

Client sends Send Image Data Packet ('A'+'S' / $C1+$D3)

Host sends:

One byte:
  $06 = ACK (Host understood the packet, CRC is correct; send next one)
            (Also: this is a duplicate packet, already received; acknowledge
            so the client sends the next one)
  $15 = NAK (Resend the same packet again)

(end loop)

Client sends Summary ('A'+'Y' / $C1+$D9) packet

Send Nibble Disk

Client sends Query File Size Packet ('A'+'Z' / $C1+$DA)

Host sends:

Two bytes: file size in blocks (LSB, MSB)
One byte:
  $00 = File exists (and file size is valid)
  $02 = File does not exist
  $04 = File exists, not recognized as a valid disk image

Client sends Nibble Send Packet ('A'+'N' / $C1+$CD)

Host sends:

One byte:
  $00 = Ok
  $02 = Unable to write (client aborts)

(loop for 35 tracks)

(loop for as much data is required within a track)

Client sends Send Image Data Packet ('A'+'S' / $C1+$D3)

Host sends:

One byte:
  $06 = ACK (Host understood the packet, CRC is correct; send next one)
            (Also: this is a duplicate packet, already received; acknowledge
            so the client sends the next one)
  $15 = NAK (Resend the same packet again)

(end data loop)

Host sends:

One byte:
    $06 = ACK analysis was successful; please proceed with the next track
    $15 = NAK analysis failed; abort the operation
    $18 = CAN analysis failed, but please continue with next track
    $05 = ENQ analysis was inconclusive; please re-read the same track and send the newly read data

(end track loop)

Client sends Summary ('A'+'Y' / $C1+$D9) packet

Multiple nibble send (unique suffix added to specified filename prefix)

Client sends Multiple Nibble Send Packet ('A'+'M' / $C1+$CC)

Host sends:

  One byte:
  $00 = Ok
  $02 = Unable to write (client aborts)

(loop for 35 tracks)

(loop for as much data is required within a track)

Client sends Send Image Data Packet ('A'+'S' / $C1+$D3)

Host sends:

One byte:
  $06 = ACK (Host understood the packet, CRC is correct; send next one)
            (Also: this is a duplicate packet, already received; acknowledge
            so the client sends the next one)
  $15 = NAK (Resend the same packet again)

(end data loop)

Host sends:

One byte:
    $06 = ACK analysis was successful; please proceed with the next track
    $15 = NAK analysis failed; abort the operation
    $18 = CAN analysis failed, but please continue with next track
    $05 = ENQ analysis was inconclusive; please re-read the same track and send the newly read data

(end track loop)

Client sends Summary ('A'+'Y' / $C1+$D9) packet

Bootstrapping Command Flows

Initiate Speediboot ProDOS/ADTPro Bootstrap

Client sends Send File ('A'+'F' / $C1+$C6) packet with '2' payload

Host sends:

  One byte: 'P' ($50)
  Two bytes: image size in bytes (LSB, MSB)
  Continuous byte stream of ProDOS image - grub starts execution at $2000, returns to grub at $7000

Client sends Send File ('A'+'F' / $C1+$C6) packet with '6' payload

Host sends:

 One byte: "A" ($41)
  Two bytes: image size in bytes (LSB, MSB)
  Continuous byte stream of ADTPro program file image - grub starts execution at $2000

Initiate SOS/ADTPro bootstrap

Client sends Send File ('A'+'F' / $C1+$C6) packet with '3' payload

Host sends:

Continuous byte stream of $56 pages ($5600 bytes) of SOS kernel file image

Client sends Send File ('A'+'F' / $C1+$C6) packet with '4' payload

Host sends:

One byte: 'S' ($53)
Two bytes: image size in bytes (LSB, MSB)
Continuous byte stream of serial ADTPro SOS program file image

Client sends Send File ('A'+'F' / $C1+$C6) packet with '5' payload

Host sends:

  Two bytes: image size in bytes (LSB, MSB)
  Continuous byte stream of SOS driver file image

Initiate Speediboot ProDOS/VSDrive/BASIC bootstrap

Client sends Send File ('A'+'F' / $C1+$C6) packet with '7' payload

Host sends:

One byte: 'V' ($56)
Two bytes: image size in bytes (LSB, MSB)
Continuous byte stream of VSDrive program file image - grub starts execution at $2000, returns to grub at $7000

Client sends Send File ('A'+'F' / $C1+$C6) packet with '8' payload

Host sends:

One byte: 'B' ($42)
Two bytes: image size in bytes (LSB, MSB)
Continuous byte stream of BASIC file image - grub starts execution at $2000

ADTPro-Wide Protocol Packet Formats

Change Directory Packet - Command

Envelope:
  One byte: 'A' ($C1)
  Two bytes: payload length (file name + null, not including check byte)
  One byte: 'C' ($C3)
  One byte: EOR of prior four bytes
Payload:
  Byte stream: file name, null terminated
Check byte:
  One byte: EOR of the payload

Directory Packet - Command

Envelope:
  One byte: 'A' ($C1)
  Two bytes: payload length ($0001)
  One byte: 'D' ($C4)
  One byte: EOR of the first four bytes ($04)
Payload:
  One byte: 1k "page" to send
Check byte:
  One byte: EOR of the payload (will be same as the payload byte)

Query File Size Packet - Command

Envelope:
  One byte: 'A' ($C1)
  Two bytes: payload length (file name + null, not including check byte)
  One byte: 'Z' ($DA)
  One byte: EOR of prior four bytes
Payload:
  Byte stream: file name, null terminated
Check byte:
  One byte: EOR of the payload

Image Get Packet - Command

Envelope:
  One byte: 'A' ($C1)
  Two bytes: payload length (file name + null, not including check byte)
  One byte: 'G' ($C7)
  One byte: EOR of prior four bytes
Payload:
  Byte stream: file name (null terminated)
  One byte: number of blocks to send per packet
Check byte:
  One byte: EOR of the payload

Image Put Packet - Command

Envelope:
  One byte: 'A' ($C1)
  Two bytes: payload length (file name + null + 2-byte block size, not including check byte)
  One byte: 'P' ($D0)
  One byte: EOR of prior four bytes
Payload:
  Byte stream: file name (null terminated)
  Two bytes: file size in blocks (LSB, MSB)
Check byte:
  One byte: EOR of the payload

Batch Put Packet - Command

Envelope:
  One byte: 'A' ($C1)
  Two bytes: payload length (file name + null + 2-byte block size, not including check byte)
  One byte: 'B' ($C2)
  One byte: EOR of prior four bytes
Payload:
  Byte stream: file name (null terminated)
  Two bytes: file size in blocks (LSB, MSB)
Check byte:
  One byte: EOR of the payload

Multiple Nibble Put Packet - Command

Envelope:
  One byte: 'A' ($C1)
  Two bytes: payload length (file name + null + 2-byte block size, not including check byte)
  One byte: 'M' ($CC)
  One byte: EOR of prior four bytes
Payload:
  Byte stream: file name (null terminated)
  Two bytes: file size in blocks (LSB, MSB)
Check byte:
  One byte: EOR of the payload

Send Image Data Packet - Response

Envelope:
  One byte: 'A' ($C1)
  Two bytes: payload length in bytes after RLE decompression, not including block number or CRC (LSB, MSB)
  One byte: 'S' ($D3)
  One byte: EOR of prior four bytes
Payload: 
  Two bytes: starting block number (LSB, MSB)
  Page-based data, RLE encoded
Checksum:
  Two bytes: CRC of all page-based data (LSB, MSB)

Acknowledgement Packet - Response

Envelope:
  One byte: 'A' ($C1)
  Two bytes: payload length (LSB, MSB)
  One byte: 'K' ($CB)
  One byte: EOR of prior four bytes
Payload:
  One byte: acknowledgement type - ACK ($06), NAK ($15), or CAN ($18)
  Optional additional payload of length (minus one) of bytes
Check byte:
  One byte: EOR of the payload, including acknowledgement byte

Summary Packet - Response

Envelope:
  One byte: 'A' ($C1)
  Two bytes: payload length ($01, $00)
  One byte: 'Y' ($D9)
  One byte: EOR of prior four bytes ($19)
Payload:
  One byte: number of errors encountered
Check byte:
  One byte: EOR of the payload (will be same as the payload byte)

Home - Command/Response

Envelope:
  One byte: 'A' ($C1)
  Two bytes: payload length ($0000)
  One byte: 'X' ($D8)
  One byte: EOR of prior four bytes ($19)

Send File - Command

Envelope:
  One byte: 'A' ($C1)
  Two bytes: payload length ($01, $00)
  One byte: 'F' ($C6)
  One byte: EOR of prior four bytes ($06)
Payload:
  One byte: file to request - one of the following:
     $B2/'2' = ProDOS
     $B3/'3' = SOS Kernel
     $B4/'4' = SOS Interpreter (Serial ADTPro on SOS)
     $B5/'5' = SOS Driver
     $B6/'6' = Serial ADTPro on ProDOS
     $B7/'7' = VSDrive on ProDOS
     $B8/'8' = Applesoft BASIC for ProDOS
Check byte:
  One byte: EOR of the payload (will be same as the payload byte)

Vitual Drive Command Flows

Read Block

The Apple sends: byte stream:
  One byte: 'E' ($C5)
  One byte: $01
  Two bytes: requested block number (LSB, MSB)
  One byte: EOR of the first four bytes

Host sends: byte stream:
  One byte: 'E' ($C5)
  One byte: $01
  Two bytes: requested block number (LSB, MSB)
  One byte: EOR of the first four bytes
  Requested block data (512 bytes)
  One byte: EOR of all bytes in block

Read3 - Block read with date/time update

The Apple sends: byte stream:
  One byte: 'E' ($C5)
  One byte: $03 (for drive 1) or $05 (for drive 2)
  Two bytes: requested block number (LSB, MSB)
  One byte: EOR of the first four bytes

Host sends: byte stream:
  One byte: 'E' ($C5)
  One byte: $03 (for drive 1) or $05 (for drive 2)
  Two bytes: requested block number (LSB, MSB)
  Four bytes: ProDOS date and timestamp data (ultimately destined for $BF90 to $BF93)
  One byte: EOR of the first eight bytes
  512 bytes: requested block data
  One byte: EOR of all bytes in block

Write Block

The Apple sends: byte stream:
  One byte: 'E' ($C5)
  One byte: $02 (for drive 1) or $04 (for drive 2)
  Two bytes: requested block number (LSB, MSB)
  One byte: EOR of the first four bytes
  512 bytes: requested block data
  One byte: EOR of all bytes in block

Host sends: byte stream:
  One byte: 'E' ($C5)
  One byte: $02 (for drive 1) or $04 (for drive 2)
  Two bytes: requested block number (LSB, MSB)
  One byte: EOR of the first four bytes