Expand description
§xum1541
This crate provides a Rust interface for communicating with Commodore disk drives via the XUM1541
USB adapter (also known as the ZoomFloppy). It enables modern computers to interact with vintage
Commodore hardware through a clean, safe, and idiomatic Rust API.
§Overview
The xum1541 crate is structured around two main components:
- A high-level
Businterface for IEC/IEEE-488 bus operations - A lower-level
Deviceinterface for direct USB communication
§Key Features
- Safe Rust interface for XUM1541 USB adapter communication
- Support for both IEC and IEEE-488 protocols
- Comprehensive error handling
- Built-in device discovery and initialization
- Automatic USB resource management
- Support for multiple XUM1541 devices through serial number selection
- Configurable USB timeouts and debug logging
§Architecture
§Bus Layer
The Bus struct is the primary interface most users should interact with. It provides:
- High-level IEC/IEEE-488 bus operations (talk, listen, open, close)
- Data transfer primitives (read, write)
- Bus state management
- Pattern-based reading capabilities
- Safe state transitions between bus modes
The Bus layer enforces correct protocol usage by tracking the current bus state and validating operations against that state.
§Device Layer
The Device struct provides low-level USB communication with the XUM1541 hardware:
- Direct USB control transfers
- Bulk data transfers
- Device initialization and configuration
- Firmware version verification
- Device capability detection
- Debug information access (for firmware version 8+)
§Getting Started
The recommended way to create a new xum1541 interface is using
BusBuilder.
use xum1541::BusBuilder;
let mut bus = BusBuilder::new()
.build()
.unwrap();
bus.initialize().unwrap();§Error Handling
The library uses a custom Error type that covers:
- Device access errors (not found, firmware version mismatch, serial number mismatch)
- Communication failures (USB errors, timeouts)
- Protocol violations (invalid state transitions)
- Resource exhaustion (buffer overflows)
- Invalid parameters (zero-length transfers, invalid patterns)
§Key Types
§DeviceChannel
Represents a combination of device number and channel (secondary address) on the Commodore bus.
§BusMode
Tracks the current state of the bus:
- Idle
- Talking (a specific device talking using a specific channel)
- Listening (a specific device listening using a specific channel)
§DeviceInfo
Contains information about the XUM1541 device:
- Firmware version
- Hardware capabilities
- Device status
- Debug information (firmware v8+)
§Advanced Usage
§Custom USB Context
For applications needing fine-grained control over USB behavior:
use rusb::{Context, UsbContext};
use xum1541::BusBuilder;
let mut context = Context::new().unwrap();
context.set_log_level(rusb::LogLevel::Debug);
let bus = BusBuilder::new()
.context(context)
.build()
.unwrap();§Reading with Patterns
The library provides sophisticated pattern-based reading capabilities:
// Read until specific byte pattern, including the pattern itself
let mut buffer = vec![0u8; 256];
// Will read until 0x0D is found, and include the 0x0D in the buffer
let bytes_read = bus.read_until(&mut buffer, &[0x0D])?;
// Read until multiple byte pattern
let mut buffer = vec![0u8; 256];
// Will read until the sequence 0x31, 0x32 is found, including both bytes
let bytes_read = bus.read_until(&mut buffer, &[0x31, 0x32])?;
// Read until any byte from set is found (inclusive)
let mut buffer = vec![0u8; 256];
// Will read until either 0x0D or 0x20 is found, including the matching byte
let bytes_read = bus.read_until_any(&mut buffer, &[0x0D, 0x20])?;§Examples
See
examples/readme.rs- A very simple app which queries a drive’s status. This is also included below.examples/basic.rs- A more complex example which enables logging (run withRUST_LOG=infofor example) queries the device’s capabilities and drive status.
use xum1541::{BusBuilder, DeviceChannel, Error};
fn main() -> Result<(), Error> {
// Connect to the XUM1541 device
let mut bus = BusBuilder::new().build()?;
// Initialize the bus
bus.initialize()?;
// Reset the IEC
bus.reset()?;
// Instuct device 8 to talk using channel 15
bus.talk(DeviceChannel::new(8, 15)?)?;
// Read up to 256 bytes of data from the drive
let mut data = vec![0u8; 256];
bus.read(&mut data)?;
// Print it out (this should be the drive status)
println!(
"Retrieved data from drive: {}",
std::str::from_utf8(&data).unwrap()
);
// Tell the drive to stop talking
bus.untalk()?;
// No need to close the XUM1541 device, it will be closed when bus goes
// out of scope
Ok(())
}§Thread Safety
The library is not inherently thread-safe but can be accessed from multiple threads, and from futures/async code, with some considerations:
- Wrap the
Businstance in a mutex - Consider how to allocate/deallocate channels for device communication
- Be aware of USB timeout implications in threaded contexts
§Logging
The library uses the log crate for diagnostic output:
- Error: Critical failures requiring immediate attention
- Warn: Potential issues or deprecated usage
- Info: Important state changes
- Debug: Detailed operation information
- Trace: Function entry/exit and protocol-level details
To enable logging, use env_logger::init and set the RUST_LOG environment variable:
§Technical Details
§USB Protocol
- Vendor ID: 0x16D0
- Product ID: 0x0504
- Interface: Bulk transfers
- Endpoints: IN and OUT for data/status
- Control transfers for device management
§XUM1541 Firmware Compatibility
- Minimum supported firmware: Version 7
- Enhanced debugging: Version 8+
§Contributing
When extending the library:
- Maintain the state machine model for bus operations
- Follow the error handling patterns
- Add appropriate logging at each level
- Document public interfaces thoroughly
- Add tests for new functionality
§License
This library is licensed under the GNU General Public License Version 3 (GPLv3).
§Acknowledgments
- Original OpenCBM project and xum1541 plugin developers.
OpenCbmis licensed under the GPLv2 ZoomFloppyhardware developers
Re-exports§
pub use crate::error::Communication as CommunicationError;pub use crate::error::DeviceAccess as DeviceAccessError;pub use crate::error::Error;pub use crate::error::Internal as InternalError;pub use crate::constants::Ioctl;pub use crate::constants::DEVICE_MAX_NUM;pub use crate::constants::DEVICE_MIN_NUM;pub use crate::constants::DRIVE_MAX_CHANNEL;pub use crate::constants::DRIVE_MIN_CHANNEL;pub use crate::bus::DEFAULT_TIMEOUT as BUS_DEFAULT_TIMEOUT;pub use crate::bus::Bus;pub use crate::bus::BusBuilder;pub use crate::bus::BusRecoveryType;pub use crate::device::remoteusb::RemoteUsbDevice;pub use crate::device::remoteusb::RemoteUsbDeviceConfig;pub use crate::device::remoteusb::RemoteUsbInfo;pub use crate::device::remoteusb::UsbDeviceServer;pub use crate::device::usb::UsbDevice;pub use crate::device::usb::UsbDeviceConfig;pub use crate::device::usb::UsbInfo;pub use crate::device::Config;pub use crate::device::Device;pub use crate::device::DeviceConfig;pub use crate::device::DeviceDebugInfo;pub use crate::device::DeviceInfo;pub use crate::device::DeviceType;pub use crate::device::SpecificDeviceInfo;
Modules§
- bus
Busis the main interface for accessing Commodore disk drives and the IEC/IEEE-488 bus via the XUM1541. Its use it preferred over direct use of [Device].- constants
- Constants used in the XUM1541 implementation
- device
- The
Devicemodule provides the low-level interface to the XUM1541 USB adapter. Prefercrate::Busfor most use cases. - error
- Error objects for the xum1541 crate
Structs§
- Device
Channel - Struct holding device and channel numbers. Used by
crate::Busfunctions which require the device and channel to be specified.