diff options
Diffstat (limited to 'src/error.rs')
| -rw-r--r-- | src/error.rs | 247 |
1 files changed, 247 insertions, 0 deletions
diff --git a/src/error.rs b/src/error.rs new file mode 100644 index 0000000..f101a61 --- /dev/null +++ b/src/error.rs @@ -0,0 +1,247 @@ +//! Error types for the geek-szitman-supercamera crate + +use thiserror::Error; + +/// Result type for the crate +pub type Result<T> = std::result::Result<T, Error>; + +/// Main error type for the crate +#[derive(Error, Debug)] +pub enum Error { + /// USB communication errors + #[error("USB error: {0}")] + Usb(#[from] UsbError), + + /// Video backend errors + #[error("Video backend error: {0}")] + Video(#[from] VideoError), + + /// Protocol errors + #[error("Protocol error: {0}")] + Protocol(#[from] ProtocolError), + + /// JPEG processing errors + #[error("JPEG error: {0}")] + Jpeg(#[from] JpegError), + + /// System errors + #[error("System error: {0}")] + System(#[from] SystemError), + + /// Generic error wrapper + #[error("Generic error: {0}")] + Generic(String), +} + +/// USB-specific errors +#[derive(Error, Debug)] +pub enum UsbError { + /// Device not found + #[error("USB device not found")] + DeviceNotFound, + + /// Device disconnected + #[error("USB device disconnected")] + DeviceDisconnected, + + /// Permission denied + #[error("USB permission denied")] + PermissionDenied, + + /// Interface claim failed + #[error("Failed to claim USB interface: {0}")] + InterfaceClaimFailed(String), + + /// Bulk transfer failed + #[error("USB bulk transfer failed: {0}")] + BulkTransferFailed(String), + + /// Timeout error + #[error("USB operation timed out")] + Timeout, + + /// Generic USB error + #[error("USB error: {0}")] + Generic(String), +} + +impl UsbError { + /// Check if this error indicates device disconnection + pub fn is_device_disconnected(&self) -> bool { + matches!(self, Self::DeviceDisconnected) + } +} + +/// Video backend errors +#[derive(Error, Debug)] +pub enum VideoError { + /// PipeWire errors + #[error("PipeWire error: {0}")] + PipeWire(String), + + /// V4L2 errors (for future use) + #[error("V4L2 error: {0}")] + V4L2(String), + + /// Stdout errors + #[error("Stdout error: {0}")] + Stdout(String), + + /// Format not supported + #[error("Video format not supported: {0}")] + FormatNotSupported(String), + + /// Device initialization failed + #[error("Video device initialization failed: {0}")] + InitializationFailed(String), + + /// Frame push failed + #[error("Failed to push frame: {0}")] + FramePushFailed(String), + + /// Device not ready + #[error("Device not ready")] + DeviceNotReady, +} + +/// Protocol errors +#[derive(Error, Debug)] +pub enum ProtocolError { + /// Invalid frame format + #[error("Invalid frame format: {0}")] + InvalidFrameFormat(String), + + /// Frame too small + #[error( + "Frame too small: expected at least {} bytes, got {}", + expected, + actual + )] + FrameTooSmall { expected: usize, actual: usize }, + + /// Invalid magic number + #[error( + "Invalid magic number: expected 0x{:04X}, got 0x{:04X}", + expected, + actual + )] + InvalidMagic { expected: u16, actual: u16 }, + + /// Unknown camera ID + #[error("Unknown camera ID: {0}")] + UnknownCameraId(u8), + + /// Frame length mismatch + #[error("Frame length mismatch: expected {}, got {}", expected, actual)] + FrameLengthMismatch { expected: usize, actual: usize }, + + /// Protocol parsing error + #[error("Protocol parsing error: {0}")] + ParsingError(String), +} + +/// JPEG processing errors +#[derive(Error, Debug)] +pub enum JpegError { + /// Invalid JPEG header + #[error("Invalid JPEG header")] + InvalidHeader, + + /// Unsupported JPEG format + #[error("Unsupported JPEG format: {0}")] + UnsupportedFormat(String), + + /// JPEG parsing failed + #[error("JPEG parsing failed: {0}")] + ParsingFailed(String), + + /// Image dimensions not found + #[error("Could not determine image dimensions")] + DimensionsNotFound, +} + +/// System errors +#[derive(Error, Debug)] +pub enum SystemError { + /// File operation failed + #[error("File operation failed: {0}")] + FileError(String), + + /// Permission denied + #[error("Permission denied: {0}")] + PermissionDenied(String), + + /// Resource not available + #[error("Resource not available: {0}")] + ResourceNotAvailable(String), + + /// Signal handling error + #[error("Signal handling error: {0}")] + SignalError(String), +} + +impl From<std::io::Error> for Error { + fn from(err: std::io::Error) -> Self { + match err.kind() { + std::io::ErrorKind::NotFound => Error::Usb(UsbError::DeviceNotFound), + std::io::ErrorKind::PermissionDenied => Error::Usb(UsbError::PermissionDenied), + std::io::ErrorKind::TimedOut => Error::Usb(UsbError::Timeout), + _ => Error::System(SystemError::FileError(err.to_string())), + } + } +} + +impl From<rusb::Error> for Error { + fn from(err: rusb::Error) -> Self { + match err { + rusb::Error::NoDevice => Error::Usb(UsbError::DeviceDisconnected), + rusb::Error::Access => Error::Usb(UsbError::PermissionDenied), + rusb::Error::Timeout => Error::Usb(UsbError::Timeout), + rusb::Error::NotFound => Error::Usb(UsbError::DeviceNotFound), + _ => Error::Usb(UsbError::Generic(err.to_string())), + } + } +} + +impl From<String> for Error { + fn from(err: String) -> Self { + Error::Generic(err) + } +} + +impl From<&str> for Error { + fn from(err: &str) -> Self { + Error::Generic(err.to_string()) + } +} + +impl From<crate::usb::UsbTransferError> for Error { + fn from(err: crate::usb::UsbTransferError) -> Self { + Error::Usb(UsbError::Generic(err.to_string())) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_usb_error_is_device_disconnected() { + let err = UsbError::DeviceDisconnected; + assert!(err.is_device_disconnected()); + + let err = UsbError::DeviceNotFound; + assert!(!err.is_device_disconnected()); + } + + #[test] + fn test_error_conversion() { + let io_err = std::io::Error::new(std::io::ErrorKind::NotFound, "not found"); + let err: Error = io_err.into(); + assert!(matches!(err, Error::Usb(UsbError::DeviceNotFound))); + + let usb_err = rusb::Error::NoDevice; + let err: Error = usb_err.into(); + assert!(matches!(err, Error::Usb(UsbError::DeviceDisconnected))); + } +} |
