-
Notifications
You must be signed in to change notification settings - Fork 1
DriveWire Specification
The Host shall be defined as a modern personal computer or hand-held device with sufficient mass storage and a communications interface such as an RS-232 serial port that can be reliably driven at the desired (or in some cases, required) rate.
The Guest shall be defined as any computer equipped with a communications interface compatible with the Host.
The physical cable connecting the Guest to the Host shall be dictated by the communications interface.
The communication protocol shall follow the RS-232 standard of 8-N-1 (1 start bit, 8 data bits, and 1 stop bit). Communication bit rates shall be determined by the capabilities of the Guest and Host.
The transaction is the basis for exchanging information between Guest and Host. All transactions consist of one or more packets of information, and are generally initiated by the Guest.
Some transactions are uni-directional: from the Guest to the Host. Other transactions are bi-directional. In a bi-directional transaction, both the Guest and the Host shall send their respective responses within 250 milliseconds (1/4 of a second) of receiving the last packet from its peer, or else each shall presume a timeout condition and abort the transaction.
This is a uni-directional transaction, and is performed by the Guest as a notification to the Host when the Guest is powered on or reset. The following packet is sent to the Host:
Byte | Value |
---|---|
0 | OP_RESET1 ($FF) or OP_RESET2 ($FE) or OP_RESET3 ($F8) |
Upon receipt of the packet, the Host shall: 1. Reset any statistical values related to read/write and sector transfer throughput for ALL drives. 2. Flush all caches connected to the virtual drives.
This is a uni-directional transaction that the Guest may send to indicate that a DW driver has initialized.
It currently does not cause any action on the Host. See OP_DWINIT for the DW4 extended form, which is preferable.
Byte | Value |
---|---|
0 | OP_INIT ($49) |
This is a uni-directional transaction that the Guest may send to indicate that a DW driver has terminated.
It currently does not cause any action on the Host.
Byte | Value |
---|---|
0 | OP_TERM ($54) |
This bi-directional transaction allows the Guest to inform the Host of it's driver version or capabilities, and the Host to respond with it's own version/capabilities. The exact meanings of the version byte are not yet defined. The only current use of this operation is by the OS-9 driver. It performs this operation when initialized to determine whether it should load the DW4 specific extensions (virtual channel poller, etc). The DW3 Host will not respond to DWINIT, whereas the DW4 Host will. Any response is currently interpreted by the driver to indicate that the DW4 extensions should be loaded.
Guest sends:
Byte | Value |
---|---|
0 | OP_DWINIT ($5A) |
1 | Driver version/capabilities byte |
Host response:
Byte | Value |
---|---|
0 | Host version/capabilities byte |
This bi-directional transaction allows the Guest to request time and date information from the Host:
Byte | Value |
---|---|
0 | OP_TIME ($23) |
Host response:
Byte | Value |
---|---|
0 | Current year minus 1900 (0-255) |
1 | Month (1-12) |
2 | Day (1-31) |
3 | Hour (0-23) |
4 | Minute (0-59) |
5 | Second (0-59) |
This is a uni-directional transaction that can be ignored by the Host.
Byte | Value |
---|---|
0 | OP_NOP ($00) |
This bi-directional transaction is initiated by the Guest to request one 256 byte sector of data from the Host. When the Guest desires to request a sector, it will send the following Read Request packet:
Byte | Value |
---|---|
0 | OP_READ ($52) |
1 | Drive number (0-255) |
2 | Bits 23-16 of 24-bit Logical Sector Number (LSN) |
3 | Bits 15-8 of LSN |
4 | Bits 7-0 of LSN |
The drive number represents the disk image where the desired sector is located.
Upon receipt of the packet, the Host shall consult the appropriate disk image for the provided LSN and read that 256 byte sector. If an error occurs and the Host cannot read the specified sector, it shall return the following Read Failure packet:
Byte | Value |
---|---|
0 | Error code (any value other than 0) |
If no error occurred on reading the sector from the Host file system, the Host shall return the following packet:
Byte | Value |
---|---|
0 | Error code of 0 (success) |
1 - 2 | 16-bit checksum |
3 - 258 | 256 bytes of valid sector data |
Upon receipt of the Read Success, the Guest shall:
1. Compute the 16 bit checksum on the 256 bytes of sector data received from the Host. 2. Compare the checksum it calculated against the checksum provided by the Host. If the checksums match, then the sector transfer is deemed a success and the transmission is terminated.
In the event that the Guest receives a Checksum Mismatch packet during the Read Transaction, the Guest MAY send the following packet to the Host:
Byte | Value |
---|---|
0 | OP_REREAD ($72) |
1 | Drive number |
2 | Bits 23-16 of of 24-bit Logical Sector Number (LSN |
3 | Bits 15-8 of LSN |
4 | Bits 7-0 of LSN |
Upon receiving this packet, the Host will attempt a retransmission of the requested sector. At any time, the Guest may suspend the re-reading of a sector if errors continue to accumulate, and the Host will return to monitoring for additional commands.
This bi-directional transaction allows the Guest to send one 256 byte sector of data to the Host in order for it to be written to a specific virtual drive.
Byte | Value |
---|---|
0 | OP_WRITE ($57) |
1 | Drive number (0-255) |
2 | Bits 23-16 of of 24-bit Logical Sector Number (LSN |
3 | Bits 15-8 of LSN |
4 | Bits 7-0 of LSN |
5-260 | 256 bytes of sector data to write |
261 | Bits 15-8 of checksum (computed by Guest) |
262 | Bits 7-0 of checksum (computed by Guest) |
The Host shall implement a timeout of 250 milliseconds (1/4 second), in the event that the Guest stops sending data. This allows the Host to recover from the Write Transaction state and return to processing other packets. Once the Host receives this packet, it shall:
1. Compute the 16 bit checksum over the 256 byte sector it received 2. Compare the checksum that it computed against the checksum provided by the Guest
Once the checksums have been compared, the Host shall acknowledge the transmission as follows:
Byte | Value |
---|---|
0 | 0 (checksum OK) or 243 (CRC error) or some other error |
The Guest, upon receipt of the packet, will do one the following:
1. If the error code received is 0 ($00), the Guest will assume the transfer of the sector was a success and terminate the transmission. 2. If the error code received is 243 (E$CRC), the Guest MAY send the following packet:
This bi-directional transaction is initiated by the Guest to request one 256 byte sector of data from the Host. When the Guest desires to request a sector, it will send the following Read Extended Request packet:
Byte | Value |
---|---|
0 | OP_READEX ($D2) |
1 | Drive number (0-255) |
2 | Bits 23-16 of of 24-bit Logical Sector Number (LSN) |
3 | Bits 15-8 of LSN |
4 | Bits 7-0 of LSN |
The drive number is a value between 0-255, and represents the disk image where the desired sector is located.
Upon receipt of the packet, the Host shall consult the appropriate disk image for the provided LSN and read that 256 byte sector. If an error occurs and the Host cannot read the specified sector, it shall return the Read Failure packet:
Byte | Value |
---|---|
0-255 | 0 (256 bytes of 0) |
If no error occurred on reading the sector from the Host file system, the Host shall return the following packet:
Byte | Value |
---|---|
0-255 | 256 bytes of valid sector data |
Upon receipt of either the Read Success or the Read Failure packet, the Guest shall:
1. Compute the 16 bit checksum on the 256 bytes of sector data received from the Host.
2. Send the computed checksum to the Host as follows:
Byte | Value |
---|---|
0 | Bits 15-8 of the checksum (computed by Guest) |
1 | Bits 7-0 of the checksum (computed by Guest) |
Upon receipt of the checksum packet, the Host shall take one of two actions:
Action 1 – No Error Condition : If the server acquired the requested sector without error, then it shall compute the 16 bit checksum on the 256 bytes of sector data sent to the Guest and compare its calculated checksum against that of the Guest.
If the compare yields a match occurs, then Host shall send the following packet to the Guest:
Byte | Value |
---|---|
0 | Error code (0 = no error) |
If the compare does not yield a match, then Host shall send the following packet to the Guest:
Byte | Value |
---|---|
0 | Error code (243 = checksum mismatch) |
Once either of these packets is received by the Guest, the Read transaction is considered terminated. Action 2 – Error Condition : If the Host was unable to acquire the requested sector due to an error, then the Host shall return an appropriate read error code:
Byte | Value |
---|---|
0 | Error code (1-242 or 244-255) |
Once the Read Error packet is received by the Guest, the Read transaction is considered terminated. See Appendix A for a list of supported error codes, and Appendix B for the checksum algorithm used by the Guest to generate the checksums.
In the event that the Guest receives a Checksum Mismatch packet during the Read Transaction, the Guest MAY send the following packet to the Host:
Byte | Value |
---|---|
0 | OP_REREADEX ($F2) |
1 | Drive number (0-255) |
2 | Bits 23-16 of 24-bit Logical Sector Number (LSN) |
3 | Bits 15-8 of LSN |
4 | Bits 7-0 of LSN |
Upon receiving this packet, the Host will attempt a retransmission of the requested sector. The ReReadEx transaction is identical to the ReadEx transaction in every way other than its op code (aaw?) At any time, the Guest may suspend the re-reading of a sector if errors continue to accumulate, and the server will return to monitoring for additional commands.
Byte | Value |
---|---|
0 | OP_REWRITE ($77) |
1 | Drive number (0-255) |
2 | Bits 23-16 of 24-bit Logical Sector Number (LSN) |
3 | Bits 15-8 of LSN |
4 | Bits 7-0 of LSN |
5-260 | 256 bytes of sector data to write |
261 | Bits 15-8 of checksum (computed by Guest) |
262 | Bits 7-0 of checksum (computed by Guest) |
The ReWrite operation is identical to the Write operation except in opcode (aaw?).
This uni-directional transaction is for informational purposes only and may not be supported in all client environments. Its inclusion into the protocol specification is mainly for the benefit of DriveWire-enabled OS-9 drivers that execute on the Guest.
In such a driver, all GetStats/SetStats are passed to the Host via the OP_GETSTAT or OP_SETSTAT code, followed by a byte representing the GetStat/ SetStat code. The Host may wish to log this information, but does not act upon the packet itself.
Byte | Value |
---|---|
0 | OP_GETSTAT ($47) or OP_SETSTAT ($53) |
1 | Drive Number (0-255) |
2 | GetStat or SetStat code |
DriveWire 3 introduced a special set of transactions to allow printing to the Host that it is connected to. The Host shall maintain a printer buffer where data bytes are added until a flush command is sent.
Upon receiving the flush command, the Host shall output the buffer in the format and location specified by the user. DW4 extensions to the printing system allow multiple types of output and arbitrary processing commands to be executed by the server upon a flush.
Using this uni-directional transaction, the Guest notifies the Host that it has a single byte of data to add to the print queue.
Byte | Value |
---|---|
0 | OP_PRINT ($50) |
1 | Byte of data to add to the queue |
Upon receiving this packet, the Host shall add the passed byte to its internal print buffer.
Using this uni-directional transaction, the Guest notifies the Host that it has completed sending printer data and that the Host should send its print buffer to the printer.
Byte | Value |
---|---|
0 | OP_PRINTFLUSH ($46) |
DW4 adds 30 virtual channels (15 in versions prior to 4.2) which can be used to provide high level bidirectional communications between server and Guest. Unlike the low level DW operations, communications using these virtual channels can be initiated by either side and packets need not be of a known size. These channels are multiplexed over the the single physical serial connection, but act as separate serial connections in most ways and are independent of one another. They are designed to be presented as serial devices by the Guest operating system, and currently the OS-9 driver does exactly this: they are devices /N0 through /N14, with a special pseudo device '/N' that simply returns the first unused channel. TODO: /Z window descriptor overview, /TERM and /MIDI variations Each channel communicates with it's own virtual modem on the server side, which provides access to the new high level API commands. Much like a regular modem, these virtual modems have command states and 'online' or pass through states. When a port is opened, it's virtual modem will be in the command state. The following low level operations are used to implement these virtual channels. For documentation of the API calls available via the virtual modems, see XXXX:
Using this uni-directional transaction, the Guest notifies the Host that a particular channel should be initialized. It is equivalent to SERSETSTAT with status code SS.Open, and one of the two must be sent prior to any other operations on a given virtual channel.
Note that DW4 server versions prior to 4.0.5 do not support SERINIT and SERTERM properly (they are NOPs in earlier versions). Use SERSETSTAT instead.
Byte | Value |
---|---|
0 | OP_SERINIT ($45) |
1 | Channel number to initialize (0-14 for virtual serial channels, or 128-142 for virtual window channels)* |
* 0-14 only in versions prior to 4.2
Note: This operation as current implemented is known as OP_SERREAD, and is a fully compatible subset of the proposed OP_POLL operation.
This bi-directional operation is sent by the Guest to determine if incoming data is waiting for any of the virtual channels. The server will queue a practically unlimited amount of incoming data, but it is recommended to issue this command and respond to it's results as often as possible, while keeping the effect on overall system performance in mind, especially when in a multitasking environment.
For instance, the current OS-9 driver may issue this command as frequently as every 50ms when interactive data (user typing) is detected on a virtual channel and no other use of the serial line is seen. The driver dynamically adjusts this rate to as slow as every 700ms when all channels are idle. When bulk data (file transfer, etc) is detected on a channel, the rate is adjusted so as to keep the local per channel buffer full (polling more often would simply waste cycles, less often would mean the local buffer may starve).
The server attempts to do load balancing between the channels in situations where multiple channels have data waiting by manipulating the SERREAD response. Channels with interactive data are given priority over channels with bulk data waiting. Each SERREAD that results in a channel being ignored causes that channel's wait counter to increment, and the channel with the highest wait counter is usually given preference in the SERREAD response. This prevents a single channel from monopolizing the serial line and attempts to ensure interactive traffic remains responsive even while other channels are transferring bulk data.
For simple single tasking applications where you wish to perform a single high level operation (such as the 'dw' word as implemented in cocoboot) it is often acceptable to simply loop sending SERREAD and interpreting its response as quickly as possible until the high level operation is complete.
Since this operation may happen very often (much more often than any other operation in a normal OS-9 system), every effort has been made to make the response from the server small and easy for the Guest side driver to interpret quickly. We want to stay out of the way of other operations as much as possible, so quick processing is critical. The response is fairly complex as it packs a lot of information into a couple bytes, but the most common patterns are easy to detect.
Sent by the Guest:
Byte | Value |
---|---|
0 | OP_SERREAD ($43) |
Host response:
Byte | Value |
---|---|
0 | Response byte 1 |
1 | Response byte 2 |
Response byte 1 contains 3 pieces of information:
Byte 1 Bits | Description |
---|---|
7-6 | Response mode. 0b00=VSerial mode, 0b10=VWindow mode |
5 | Come again. 1 indicates that the server wishes Guest to send another SERREAD/POLL immediately if possible. **Currently always 0. ** |
4-0 | Option bits. Mode-dependent. Currently always defined in the SERREAD format, see next table |
Option bits in SERREAD mode (Used by both VSerial and VWindow modes):
Bits | Description |
---|---|
4 | Single/Multi byte response toggle (determines contents of response byte 2) |
3 - 0 | Virtual Channel indicator (relative channel number + 1) |
Since currently we only implement the SERREAD mode and do not yet use the Come Again bit, the value of response byte 1 can be used to indicate the contents of byte 2 according to the following table.
Byte 1 value | Meaning |
---|---|
0 | There is no data or status waiting for any channel, ignore byte 2, end of operation. |
1 to 15 | Byte 2 contains a single byte of data for VSerial channel (byte 1 - 1). Guest must add byte 2 to the input queue for channel (byte 1 - 1) and may consider this channel to be in interactive mode. |
16 | Byte 2 contains a VSerial status byte, see explanation below |
17 - 31 | Byte 2 contains the number of bytes waiting for VSerial channel (byte 1 - 1 - 16). |
128 | There is no data or status waiting for any channel, ignore byte 2, end of operation. |
129 to 143 | Byte 2 contains a single byte of data for VWindow channel (byte 1 - 1 - 128). Guest must add byte 2 to the input queue for channel (byte 1 - 1 - 128) and may consider this channel to be in interactive mode. |
144 | Byte 2 contains a VWindow status byte, see explanation below |
145 - 161 | Byte 2 contains the number of bytes waiting for VWindow channel (byte 1 - 1 - 16 - 128). Host is recommending that Guest sends an OP_SERREADM to retrieve these bytes. Guest may consider this channel to be in bulk transfer mode. |
If byte 1 is 16 or 144, then byte 2 is a status byte and can be interpreted as follows:
Operation | Bits 7-4 | Bits 3-0 Channel Closed | 0000 | Channel number, or 15 (1111) for all channels Reboot Request | 1111 | 1111
The OP_POLL/SERREAD response is a bit complex, but implementing a routine to handle the current SERREAD-only implementation is not:
if $byte1 == 0 then exit
else if $byte1
Using this bi-directional transaction, the Guest requests a variable number of input bytes for a specific virtual channel.
Guest sends:
Byte | Value |
---|---|
0 | OP_SERREADM ($63) |
1 | Channel number (0-14) or (128-142) |
2 | Number of bytes requested (0-255) |
Host responds:
Byte | Value |
---|---|
0-255 | Variable; input bytes from requested channel's queue |
Note that requesting more bytes than are present will result in a server error, and it will simply not respond for the timeout period, causing read error on the Guest side. So, don't ask for more bytes than a SERREAD has told you exist in the queue, it will only bring sadness.
This uni-directional transaction instructs the server to add a byte to the specified channel's output queue.
Note that the FASTWRITE operations are preferred in nearly every situation.
Byte | Value |
---|---|
0 | OP_SERWRITE ($C3) |
1 | Channel number (0-14) or (128-142) |
2 | Data byte |
This uni-directional transaction instructs the server to add a byte to the specified channel's output queue. The op code itself indicates the channel number, saving 33% of the overhead needed for a SERWRITE. We still waste 50% of the potential bandwidth, but FASTWRITE is fast enough to allow realtime MIDI playback on a Guest 3 (which requires 32kbps effective throughput).
Byte | Value |
---|---|
0 | OP_FASTWRITE ($80) + vserial channel number (0-14) |
or 0 | OP_FASTWRITE ($80) + vwindow channel number (128-142) - 128 + 32??? see aaw |
1 | Data byte |
Not implemented in current OS-9 driver. Available in version 4.0.5 of the DW4 server.
SERWRITEM allows the Guest to send multiple bytes of output data to a specific virtual channel.
Byte | Value |
---|---|
0 | OP_SERWRITEM ($64) |
1 | Channel number |
2 | Number of data bytes following |
3-258 | Data bytes |
Much like the OP_GETSTAT transaction, this uni-directional operation is sent when a getstat call is made on a particular channel. Currently for logging purposes only.
Byte | Value |
---|---|
0 | OP_SERGETSTAT ($44) |
1 | Virtual channel number (0-14) or (128-142) |
2 | Getstat code |
This uni-directional transaction is sent by the Guest when a setstat operation is performed on a virtual channel. There are 3 setstat codes that are interpretted by the server, and one that causes additional data to be read.
Byte | Value |
---|---|
0 | OP_SERSETSTAT ($C4) |
1 | Virtual channel number (0-14) or (128-142) |
2 | setstat code |
3 - 28 | If byte 2 == $28 (SS.ComSt), 26 bytes containing the new device descriptor. Any other value in byte 2 means byte 2 is the end of the transaction. |
If byte 2 is SS.ComSt (value $28), then the Guest sends a total of 29 bytes. In all other cases, the Guest sends a total of 3 bytes.
If byte 2 is SS.Open (value $29), then the channel is initialized and considered ready for I/O by the server. Please note: A SERINIT or SERSETSTAT with SS.Open must be sent prior to using any virtual channel!
If byte 2 is SS.Close (value $2A), the channel is considered closed by the server. Any attached TCP sessions are terminated, any listening sockets controlled by this channel are terminated, etc.
This uni-directional operation is used to indicate that a particular channel should be closed, and any associated links be terminated. It is equivalent to SERSETSTAT with status code SS.Close.
Note that DW4 server versions prior to 4.0.5 do not support SERINIT and SERTERM properly (they are NOPs in earlier versions). Use SERSETSTAT instead.
Byte | Value |
---|---|
0 | OP_SERTERM ($C5) |
1 | Virtual channel number (0-14) or (128-142) |
Named Objects are an extension found in DW4 server versions 4.0.4 and higher. They are currently only used by GuestBoot but are available for any project that needs this type of thing. If you need a way to refer to specific entities that exist in permanent storage but don't want to implement a file system, named objects might be just the thing.
Basically, a named object is just a collection of bytes known by a particular name (a string of up to 255 bytes in length). Operations are provided for mounting and creating these objects by their name, and little else. The simplest example would be that the string itself is a file name on the server, but that is not a requirement of the protocol. The server sends back one of two results in response to any named object operation:
0, meaning it was unable to mount or create the requested object. or a value from 1 to 255, which means the requested object is now mounted in the corresponding drive.
Mount fails if the object doesn't exist, whereas Create fails if it does exist. Create also fails if the desired object cannot be created, and both fail if the object ultimately cannot be mounted in a drive. This may be due to things unrelated to the object itself, perhaps there are no free drives, etc. The only result is 0 = sorry, didn't work.
If a named object is already mounted, the server may return the drive number already containing the object rather than remounting it.
DW4 provides mechanisms for associating specific names with arbitrary paths, which may be any path that is valid to a dw disk insert command, including local paths and a wide variety of URLs. You may also specify a local directory to be used as the source for named objects (specific mappings override matches in the named object directory).
Any mount resulting from a named object call is guaranteed valid only until the next named object call is made. This is an important control for some corner cases that can happen because we are in effect promising access to a specific named object, not just to a drive number. If we can't talk to that named object, we must at least ensure the I/O fails and doesn't get sent to some other object. So for the duration of this "lease" the server ensures all i/o to that drive # happens on that specific named object, and each named object call releases the previous lease and obtains a new one.
Byte | Value |
---|---|
0 | OP_NAMEOBJ_MOUNT ($01) |
1 | Length of name |
2-258 | Name |
Byte | Value |
---|---|
0 | OP_NAMEOBJ_CREATE ($02) |
1 | Length of name |
2-258 | Name |
Note that WireBug is not yet implemented. Looking for a cool project??
DriveWire 3 introduced a special set of transactions to facilitate remote debugging between a Guest and the Host that it is connected to. This feature, known as WireBug, allows the transfer of register information and memory from the Guest to the Host. Once the Guest has entered WireBug mode, it can receive messages initiated by the server.
Because of the nature of the protocol and to increase accuracy and efficiency, WireBug uses a fixed packet size of 24 bytes and reserves the last byte as an 8- bit checksum byte.
Using this uni-directional transaction, the Guest notifies the Host that it has entered WireBug remote debugging mode.
Byte | Value |
---|---|
0 | OP_WIREBUG_MODE ($42) |
1 | Guest Type ($02 = Guest 2, $03 = Guest 3) |
2 | CPU Type ($08 = 6809, $03 = 6309) |
3-23 | Reserved for future definition |
Once the Guest has sent this packet, it shall go into WireBug Mode where it will wait for commands from the Host.
Along with notifying the Host that the Guest is in WireBug mode, the packet also communicates the Guest and processor type. The Host should use this information as a cue to what type of processor is in the Guest, and adjust accordingly.
Host Initiated
Using this bi-directional transaction, the Host requests the contents of the registers from the Guest.
Byte | Value |
---|---|
0 | OP_WIREBUG_READREGS ($52) |
1-22 | 0 |
23 | Checksum |
Upon receipt of the packet, the Guest shall compute the checksum of bytes 0-22 and compare its computed value against byte 23. If a checksum match does not occur, then the Guest shall disregard the packet and send the following response packet:
Byte | Value |
---|---|
0 | Error code (243 = checksum mismatch) |
Upon receipt of this packet, the Host may elect to restart the transaction.
If a checksum match occurs, the Guest shall respond with the following packet:
Byte | Value |
---|---|
0 | OP_WIREBUG_READREGS ($52) |
1 | Value of DP register |
2 | Value of CC register |
3 | Value of A register |
4 | Value of B register |
5 | Value of E register |
6 | Value of F register |
7 | Value of X register (hi) |
8 | Value of X register (lo) |
9 | Value of Y register (hi) |
10 | Value of Y register (lo) |
11 | Value of U register (hi) |
12 | Value of U register (lo) |
13 | Value of MD register |
14 | Value of V register (hi) |
15 | Value of V register (lo) |
16 | Value of SP register (hi) |
17 | Value of SP register (lo) |
18 | Value of PC register (hi) |
19 | Value of PC register (lo) |
20-22 | Not yet defined |
23 | Checksum |
Upon receipt of the packet, the Host shall compute the checksum of bytes 0-22 and compare its computed value against byte 23. If a match occurs, the Host shall accept the packet’s payload. If a match does not occur, then the Host may elect to restart the transaction.
Host Initiated
Using this bi-directional transaction, the Host requests that the contents of the packet passed to the Guest be written to its registers.
The following packet shall be sent to the Guest:
Byte | Value |
---|---|
0 | OP_WIREBUG_WRITEREGS ($72) |
1 | Value of DP register |
2 | Value of CC register |
3 | Value of A register |
4 | Value of B register |
5 | Value of E register |
6 | Value of F register |
7 | Value of X register (hi) |
8 | Value of X register (lo) |
9 | Value of Y register (hi) |
10 | Value of Y register (lo) |
11 | Value of U register (hi) |
12 | Value of U register (lo) |
13 | Value of MD register |
14 | Value of V register (hi) |
15 | Value of V register (lo) |
16 | Value of SP register (hi) |
17 | Value of SP register (lo) |
18 | Value of PC register (hi) |
19 | Value of PC register (lo) |
20-22 | Not yet defined |
23 | Checksum |
Upon receipt of the packet, the Guest shall compute the checksum of bytes 0-22 and compare its computed value against byte 23. If a match occurs, the Guest shall accept the packet’s payload, update its registers and send the following response packet:
Byte | Value |
---|---|
0 | Error code (0 = no error) |
If a checksum match does not occur, then the Guest shall disregard the packet and send the following response packet:
Byte | Value |
---|---|
0 | Error code (243 = checksum mismatch) |
Upon receipt of this packet, the Host may elect to restart the transaction.
Host Initiated
This bi-directional transaction is sent from the Host to the Guest. The Host uses this transaction to obtain memory values from the Guest.
The following packet is sent from the Host:
Byte | Value |
---|---|
0 | OP_WIREBUG_READMEM ($4D) |
1 | Hi-byte of starting memory location |
2 | Lo-byte of starting memory location |
3 | Count (0) |
4-22 | Don't Care |
23 | Checksum |
Upon receipt of the packet, the Guest shall compute the checksum of bytes 0-22 and compare its computed value against byte 23. If a checksum match does not occur, then the Guest shall disregard the packet and send the following response packet:
Byte | Value |
---|---|
0 | Error code (243 = checksum mismatch) |
Upon receipt of the Checksum Mismatch Packet, the Host may elect to restart the transaction.
If a match occurs, the Guest shall validate the memory request. If byte 3 (count) is not between 1 and 22, then the Guest shall send the following response packet:
Byte | Value |
---|---|
0 | Error code (16 = illegal number) |
If the byte count is between 1 and 22, then the Guest shall accept the packet’s payload and send the following response packet:
Byte | Value |
---|---|
0 | OP_WIREBUG_READMEM ($4D) |
1..n | Memory contents from start to end |
n+1..22 | Don't care |
23 | Checksum |
Upon receipt of the packet, the Host shall compute the checksum of bytes 0 to 22 and compare its computed value against byte 23. If a match occurs, the Host shall accept the packet’s payload. If a match does not occur, then the Host may elect to restart the transaction.
Host Initiated
This bi-directional transaction is sent from the Host to the Guest. The Host uses this transaction to modify the contents of the Guest’s memory.
The following packet is sent from the Host:
Byte | Value |
---|---|
0 | OP_WIREBUG_WRITEMEM ($6D) |
1 | Hi-byte of starting memory location |
2 | Lo-byte of starting memory location |
3 | Count (n bytes where 0 |
4-22 | Bytes to be modified |
23 | Checksum |
Upon receipt of the packet, the Guest shall compute the checksum of bytes 0-22 and compare its computed value against byte 23. If a checksum match does not occur, then the Guest shall disregard the packet and send the following response packet:
Byte | Value |
---|---|
0 | Error code (243 = checksum mismatch) |
If a match occurs, the Guest shall validate the memory request. If byte 3 (count) is not between 1 and 19, then the Guest shall send the following response packet:
Byte | Value |
---|---|
0 | Error code (16 = illegal number) |
If the byte count is between 1 and 19, then the Guest shall accept the packet’s payload, update its memory with the contents from the Host, and send the following response packet:
Byte | Value |
---|---|
0 | Error code (0 = no error) |
Host Initiated
This uni-directional transaction is sent from the Host to the Guest. The Host uses this transaction to notify the Guest that it should continue executing normally.
The following packet is sent from the Host:
Byte | Value |
---|---|
0 | OP_WIREBUG_GO ($47) |
1 - 23 | Don't care |
Upon receiving this packet, the Guest shall exit WireBug Mode and commence execution. The Host shall commence responding to Guest-initiated DriveWire transactions.
With the introduction of virtual channels, DriveWire 4 brings a second type of communication between the Guest and server. This is accomplished by sending commands over one of the virtual channels to its dedicated virtual modem. Several command sets are available, each dedicated to a certain type of task.
Unlike the low level API, commands and responses using the high level APIs do not necessarily have fixed sizes, nor are they required to complete within a specific time window. These constraints are met by the underlying operations that implement the virtual channel, freeing the programmer or user from worrying about such details. The virtual channels can be used very much like a regular serial port connected to a regular modem, in fact there is a Hayes compatible command set for using the virtual channel exactly like a modem with regular telecom software.
The virtual modem implements a complete Hayes compatible command set. This allows practically any existing telecommunications software to become "internet capable" (Terminal emulators, BBSes, and UUCP have all been used successfully). Simply use an IP address or hostname and port in the place of a phone number, i.e. ATDT127.0.0.1:6800 or ATDmybbs.somewhere.net:4000. Echo, command result format and other Hayes parameters work exactly as they would with a standard Hayes modem.
When a Hayes command is sent over the virtual channel, the virtual modem interprets it and either responds with a standard Hayes type response (exact format determined by current modem settings, i.e. OK/ERROR or numeric results) or goes into "online mode" just as a regular modem would do in response to ATD commands. There currently is no 'escape sequence' such as +++ to exit 'online mode'. Instead, the modem will return to command mode when the TCP/IP connection is closed.
ATA
A/
ATD
ATE
ATH
ATI
ATO
ATQ
ATSxx=xx
ATSxx?
ATV
ATZ
AT&F
AT&V
(they have no meaning in our implementation)
ATB
ATL
ATM
ATN
ATX
(all 256 can be set and queried, but these are actually used by the emulation)
S0, S1, S2, S3, S4, S5, S12
The various 'dw' commands allow you to control and configure every aspect of the server. These commands can be sent to the server in a number of ways, including the dw command utility in OS-9 and the DriveWire User Interface graphical tool.
When the virtual modem receives a dw command, it passes that command to the instance handler responsible for this Guest. The handler returns a result that consists of a status byte, a status message, and possibly a result message which may be quite large.
The virtual modem returns a status line containing the status value as ascii text, a space, and the status text. It is expected that this line will be interpreted by the calling code but it may be shown to the user, especially for error responses. A status value of 0 indicates that the command was successful. The status text in a non 0 result may contain information that is useful to the user, for instance explaining why a command is not valid or suggesting a syntax correction.
If the status code is 0, one or more lines of text may follow the status line. Generally these are intended to be shown verbatim to the user (or written to standard output for use in a piped command).
When the status line and any additional response lines have been transmitted the server will close the channel. To send an additional dw command you must open a new channel. By closing the channel at the end out output we cause OS-9 to return an EOF condition to the calling program. This makes determining the end of output very simple and allows piping the result text into a local file easily. Since some dw commands return entire files themselves, this mechanism is a critical part of making file transfer over the dw channels simple.
Non OS-9 implementations may wish to use an EOF mechanism if such a thing is available, or may simply want to do an input loop using SERREAD and SERREADM until a SERREAD indicating that the channel has been closed is received.
For a complete list of result codes, see Appendix D.
An example 'dw' command exchange:
-
virtual device /N is requested open by the 'dw' utility using an OS-9 syscall.
-
the /N pseudo device returns real device /N2, calls SERSETSTAT SS.Open on /N2, and returns a file handle to the 'dw' utility.
-
the dw utility writes the string:
dw disk show\n
-
on the server, the virtual modem detects a dw command and passes it to the proto handler for the connected instance
-
the proto handler returns a result to the virtual modem containing a status byte of 0, status text of "OK" and result text with current disk drive details.
-
the virtual modem writes:
0 OK\n Current DriveWire disks:\n \n X0 E:/cocodisks/named/snd\n X255 E:/cocodisks/named/GuestBoot.isave\n
-
the dw utility reads this data from the /N2 device. because the status line begins with '0 ' it knows the command succeeded, and so it simply loops writing the additional lines to the screen.
-
the virtual modem closes the channel when it detects all lines have been read.
-
the dw utility gets an EOF condition and exits.
All commands may be abbreviated to their shortest unique form. For help on any dw command, enter the portion you know followed by ?.
Examples:
dw disk ? : show help for 'dw disk'
dw d sh : abbreviated form of 'dw disk show'
The dw config commands allow you to view, edit, and save the running instance configuration. Note that these commands all apply only to instance specific settings. Host wide settings cannot be changed from within a particular instance, however they can be viewed using the dw server show config command.
Usage: dw config save
Requests that the server write the current running configuration to the configuration file on disk. Note that this command is typically not necessary as the server runs in 'autosave' mode by default (this mode is required if you will be using the GUI client).
Usage: dw config set item [value]
Sets or clears a particular configuration item.
Examples:
dw config set HDBDOSMode true : Set the item 'HDBDOSMode' to equal 'true'
dw config set TelnetBannerFile : Remove/clear the item 'TelnetBannerFile'
Usage: dw config show [item]
Displays the current value of specified item, or lists entire configuration if item is not specified.
Usage: dw disk [command]
The dw disk commands allow you to manage the DriveWire virtual drives.
Usage: dw disk show [#]
Show current disk details
The dw disk show command is a useful tool for quickly determining the status of the virtual disk drives that DW4 provides. It can be abbreviated as "dw d sh".
Examples:
dw disk sh : show overview of the currently loaded drives
dw disk sh 0 : show details about disk in drive 0
Usage: dw disk eject [# | al\l]
Eject disk from drive #
This command lets you eject disk images from the virtual drives. The special word 'all' may be used in place of a drive number to eject all disks.
Examples:
dw disk eject 1 : eject disk from virtual drive 1
dw disk eject all : unload all virtual drives
Usage: dw disk insert [# path]
Load disk into drive #
The disk insert command is used to load a disk image into a virtual drive. The path argument can be either a local file path or a URI. See the wiki information on paths for more details.
Examples:
dw disk in 0 c:\cocodisks\mydisk.dsk : load disk into drive 0
Usage: dw disk reload [# | all]
Reload disk in drive #
This command tells the server to reload a buffer from it's current source path. This will overwrite any unsaved changes in the buffer.
Example:
dw d reload 5 : reload disk image for drive 5
Usage: dw disk write [# [path]]
Write disk image
The dw disk write command can do different operations depending on the arguments you provide. In the simplest form, with only a drive number specified, it will write a drive's current buffer contents back to the source path. You can specify a different path if you'd like to write the buffer to somewhere else. This will create the destination if it does not exist, or overwrite the destination if it does. The dw disk write command is especially handy for writing disk images that originally were loaded from read only sources to alternate, writable locations.
Examples:
dw disk write 9 : write buffer for drive 9 to the source path
dw d w 9 /home/coco/backup1.dsk : write drive 9 buffer to an alternate path
Usage: dw disk create [# [path]]
Create new disk image
This command will create a new disk image. If given, a 0 byte file will be created at the specified path and mounted in the specified drive. If no path is specified the image will be held in memory only (but can be written to disk at any time using the dw disk write command).
Examples:
dw disk create 3 : create new image for drive 3 in memory
dw d c 0 c:\coco\newdisk.dsk : create new .dsk in drive 0
Usage: dw disk set [# param [val]]
Set disk parameters
The disk set command allows you to set or unset a variety of parameters that control the operation of a virtual disk drive. For information on the various parameters available, see the relevant wiki topic.
Examples:
dw disk set 1 writeprotect true : Enable an option for drive 1
dw d set 1 sizelimit : Unset a parameter on drive 1.
Usage: dw disk dos [command]
The various dw disk dos commands allow manipulation of DECB formatted disk image contents.
Usage: dw disk dos add [# path]
Add specified file to the DECB disk image in drive #.
Usage: dw disk dos dir [#]
Show directory of the DECB disk image in drive #.
Usage: dw disk dos format [#]
Format the image in drive # with a DECB filesystem.
Usage: dw disk dos list [# filename]
Lists contents of specified filename from DECB image in specified drive #.
Usage: dw log show [#]
Show the specified number of lines from the server log (defaults to 20 if not specified).
Usage: dw midi output #
Set midi output to device # (as enumerated by dw midi status).
Usage: dw midi status
Show current MIDI status
Show current network connections.
The networking API provides high level TCP/IP session establishment. There is some redundancy with the Hayes AT command set, but it is hoped that the networking API maybe someday be used to interface with a variety of devices in addition to DriveWire, where the AT command set would not make sense.
Currently the commands are limited to TCP connection management, but it is expected that they will be expanded to provide UDP, ICMP and other additional functionality at some point.
Usage: tcp connect [host] [port]
Attempts to establish connection to specified host:port. Returns standard DW response line (i.e. 0 OK\n or XXX Error message\n). If response is OK then channel is now connected and all future read/write is done to the new tcp connection. If the connection is closed by the remote end, the channel will be closed, and vice versa.
Usage: tcp listen [port] [zero or more flags]
Instructs server to begin listening on the specified TCP port. Returns a standard DW response line. If the socket is successfully opened for listening the result will be 0, and in the future if a client connects, that connection will be announced on this channel in the form:
con# local_port host_address\n
The con# is a unique identifier for this connection, and is typically passed to a forked process so it may be specified in a tcp join command. Note that the local port number is included in the connection announcement. This is because it is legal (and normal) to send several 'tcp listen' commands on a single channel. By reading the local port in the connection announcement, your server process knows which port has a new connection and can spawn the correct handling code.
Usage: tcp join [con#]
Connects this channel to the specified connection. A standard DW response line is returned. If the status code is 0, this channel is now connected and all future read/write will occur on the joined TCP connection.
Usage: tcp kill [con#]
Closes the specified connection. May be used by a listening process in place of a join if the connection is not desired, or may be used at any time to severe a connection already in progress.
These commands are fairly equivalent to the 'dw' commands, but return machine readable output and provide certain functionality only applicable to the DW user interface. If you are writing software that controls the DW server, you may find these commands are better suited than the user oriented 'dw' versions.
The error codes used by the Host to indicate an error condition mirror the same codes used in OS-9. Here is a list of codes that should be used and the conditions that will trigger them: • $F3 – CRC Error (if the Host’s computed checksum doesn’t match a write request from the Guest) • $F4 – Read Error (if the Host encounters an error when reading a sector from a virtual drive) • $F5 – Write Error (if the Host encounters an error when writing a sector) • $F6 - Not Ready Error (if the a command requests accesses a non- existent virtual drive)
Even though DriveWire has been shown to provide very stable and reliable communications between Guest and Host, a checksum algorithm has been employed to bring an added level of data integrity. This checksum algorithm (new in DW3) is simpler and significantly better at tracking bit errors than the CRC algorithm employed in DriveWire Version 1, which used a fast but weak CRC method. Designers of DriveWire Host software should implement the following checksum algorithm (presented in C source code) for computing a checksum for all sectors read and written to/from the Guest.
int calChecksum(unsigned char *ptr, int count)
{
short Checksum = 0;
while(--count)
{
Checksum += *(ptr++);
}
return (Checksum);
}
Note that WireBug uses an 8-bit rather than a 16-bit checksum.
Op Code | Value | ASCII | In DW Version | Notes |
---|---|---|---|---|
OP_NOP | 0 (0x00) | DW 3 | ||
OP_NAMEOBJ_MOUNT | 1 (0x01) | DW 4.0.3 | ||
OP_NAMEOBJ_CREATE | 2 (0x02) | DW 4.0.3 | ||
Reserved for future named obj use | 3-15 (0x03 - 0x0F) | N/A | ||
OP_TIME | 35 (0x23) | # | DW 3 | |
OP_AARON | 65 (0x41) | A | N/A | |
OP_WIREBUG_MODE | 66 (0x42) | B | N/A | |
OP_SERREAD | 67 (0x43) | C | DW 4.0.0 | |
OP_SERGETSTAT | 68 (0x44) | D | DW 4.0.0 | |
OP_SERINIT | 69 (0x45) | E | DW 4.0.5 | |
OP_PRINTFLUSH | 70 (0x46) | F | DW 3 | |
OP_GETSTAT | 71 (0x47) | G | DW 3 | |
OP_INIT | 73 (0x49) | I | DW 3 | |
OP_PRINT | 80 (0x50) | P | DW 3 | |
OP_READ | 82 (0x52) | R | DW 3 | |
OP_SETSTAT | 83 (0x53) | S | DW 3 | |
OP_TERM | 84 (0x54) | T | DW 3 | |
OP_WRITE | 87 (0x57) | W | DW 3 | |
OP_DWINIT | 90 (0x5A) | Z | DW 4.0.0 | |
OP_SERREADM | 99 (0x63) | c | DW 4.0.0 | |
OP_SERWRITEM | 100 (0x64) | d | DW 4.0.0 | |
OP_REREAD | 114 (0x72) | r | DW 3 | |
OP_REWRITE | 119 (0x77) | w | DW 3 | |
OP_FASTWRITE_BASE | 128 (0x80) | DW 4.0.0 | ||
OP_FASTWRITE_P1 | 129 (0x81) | DW 4.0.0 | ||
OP_FASTWRITE_P2 | 130 (0x82) | DW 4.0.0 | ||
OP_FASTWRITE_P3 | 131 (0x83) | DW 4.0.0 | ||
OP_FASTWRITE_P4 | 132 (0x84) | DW 4.0.0 | ||
OP_FASTWRITE_P5 | 133 (0x85) | DW 4.0.0 | ||
OP_FASTWRITE_P6 | 134 (0x86) | DW 4.0.0 | ||
OP_FASTWRITE_P7 | 135 (0x87) | DW 4.0.0 | ||
OP_FASTWRITE_P8 | 136 (0x88) | DW 4.0.0 | ||
OP_FASTWRITE_P9 | 137 (0x89) | DW 4.0.0 | ||
OP_FASTWRITE_P10 | 138 (0x8A) | DW 4.0.0 | ||
OP_FASTWRITE_P11 | 139 (0x8B) | DW 4.0.0 | ||
OP_FASTWRITE_P12 | 140 (0x8C) | DW 4.0.0 | ||
OP_FASTWRITE_P13 | 141 (0x8D) | DW 4.0.0 | ||
OP_FASTWRITE_P14 | 142 (0x8E) | DW 4.0.0 | ||
OP_FASTWRITE_P15 | 143 (0x8F) | DW 4.0.0 | ||
Reserved for future vserial use | 144-159 (0x90 - 0x9F) | N/A | ||
OP_SERWRITE | 195 (0xC3) | C+128 | DW 4.0.0 | |
OP_SERSETSTAT | 196 (0xC4) | D+128 | DW 4.0.0 | |
OP_SERTERM | 197 (0xC5) | E+128 | DW 4.0.5 | |
OP_READEX | 210 (0xD2) | R+128 | DW 3 | |
OP_RFM | 214 (0xD6) | V+128 | N/A | |
OP_230K230K | 230 (0xE6) | DW 4.0.0 | For 230k mode | |
OP_REREADEX | 242 (0xF2) | r+128 | DW 3 | |
OP_RESET3 | 248 (0xF8) | DW 4.0.0 | ||
OP_230K115K | 253 (0xFD) | DW 4.0.0 | For 230k mode, detects bps switch | |
OP_RESET2 | 254 (0xFE) | DW 3 | ||
OP_RESET1 | 255 (0xFF) | DW 3 |
Result Code | Description |
---|---|
0 | RC_SUCCESS |
10 (0xA) | RC_SYNTAX_ERROR |
100 (0x64) | RC_DRIVE_ERROR |
101 (0x65) | RC_INVALID_DRIVE |
102 (0x66) | RC_DRIVE_NOT_LOADED |
103 (0x67) | RC_DRIVE_ALREADY_LOADED |
104 (0x68) | RC_IMAGE_FORMAT_EXCEPTION |
110 (0x6E) | RC_NO_SUCH_DISKSET |
111 (0x6F) | RC_INVALID_DISK_DEF |
120 (0x78) | RC_NET_ERROR |
121 (0x79) | RC_NET_IO_ERROR |
122 (0x7A) | RC_NET_UNKNOWN_HOST |
123 (0x7B) | RC_NET_INVALID_CONNECTION |
140 (0x8C) | RC_INVALID_PORT |
141 (0x8D) | RC_INVALID_HANDLER |
142 (0x8E) | RC_CONFIG_KEY_NOT_SET |
150 (0x96) | RC_MIDI_ERROR |
151 (0x97) | RC_MIDI_UNAVAILABLE |
152 (0x98) | RC_MIDI_INVALID_DEVICE |
153 (0x99) | RC_MIDI_INVALID_DATA |
154 (0x9A) | RC_MIDI_SOUNDBANK_FAILED |
155 (0x9B) | RC_MIDI_SOUNDBANK_NOT_SUPPORTED |
156 (0x9C) | RC_MIDI_INVALID_PROFILE |
200 (0xC8) | RC_SERVER_ERROR |
201 (0xC9) | RC_SERVER_FILESYSTEM_EXCEPTION |
202 (0xCA) | RC_SERVER_IO_EXCEPTION |
203 (0xCB) | RC_SERVER_FILE_NOT_FOUND |
204 (0xCC) | RC_SERVER_NOT_IMPLEMENTED |
205 (0xCD) | RC_SERVER_NOT_READY |
206 (0xCE) | RC_INSTANCE_NOT_READY |
220 (0xDC) | RC_UI_ERROR |
221 (0xDD) | RC_UI_MALFORMED_REQUEST |
222 (0xDE) | RC_UI_MALFORMED_RESPONSE |
230 (0xE6) | RC_HELP_TOPIC_NOT_FOUND |
255 (0xFF) | RC_FAIL |