1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
use std::borrow::Cow;
use std::collections::HashSet;
use std::ffi::CStr;

use ::port::{PortType};

/// Describes the abilities of a device.
///
/// ## Example
///
/// An `Abilities` object can be used to retrieve information about a camera's driver:
///
/// ```no_run
/// let mut context = gphoto::Context::new().unwrap();
/// let mut camera = gphoto::Camera::autodetect(&mut context).unwrap();
/// let abilities = camera.abilities();
///
/// println!("      device type = {:?}", abilities.device_type());
/// println!("            model = {:?}", abilities.model());
/// println!("    driver status = {:?}", abilities.driver_status());
/// println!("       port types = {:?}", abilities.port_types());
/// println!("           speeds = {:?}", abilities.speeds());
/// println!("camera operations = {:?}", abilities.camera_operations());
/// println!("  file operations = {:?}", abilities.file_operations());
/// println!("folder operations = {:?}", abilities.folder_operations());
/// println!("       USB vendor = {:?}", abilities.usb_vendor());
/// println!("      USB product = {:?}", abilities.usb_product());
/// println!("        USB class = {:?}", abilities.usb_class());
/// println!("     USB subclass = {:?}", abilities.usb_subclass());
/// println!("     USB protocol = {:?}", abilities.usb_protocol());
/// ```
///
/// The above example may print something like the following:
///
/// ```text
///       device type = Camera
///             model = "Nikon DSC D750"
///     driver status = Production
///        port types = {USB}
///            speeds = []
/// camera operations = {CaptureImage, TriggerCapture, Config, CapturePreview}
///   file operations = {Delete, Preview}
/// folder operations = {MakeDirectory, RemoveDirectory, PutFile}
///        USB vendor = 1200
///       USB product = 1079
///         USB class = 0
///      USB subclass = 0
///      USB protocol = 0
/// ```
pub struct Abilities {
    inner: ::gphoto2::CameraAbilities
}

impl Abilities {
    /// Returns the type of the device.
    pub fn device_type(&self) -> DeviceType {
        match self.inner.device_type {
            ::gphoto2::GP_DEVICE_STILL_CAMERA => DeviceType::Camera,
            ::gphoto2::GP_DEVICE_AUDIO_PLAYER => DeviceType::Audio,
        }
    }

    /// Returns the name of the camera's model.
    pub fn model(&self) -> Cow<str> {
        unsafe {
            String::from_utf8_lossy(CStr::from_ptr(self.inner.model.as_ptr()).to_bytes())
        }
    }

    /// Returns the driver's stability status.
    pub fn driver_status(&self) -> DriverStatus {
        match self.inner.status {
            ::gphoto2::GP_DRIVER_STATUS_PRODUCTION   => DriverStatus::Production,
            ::gphoto2::GP_DRIVER_STATUS_TESTING      => DriverStatus::Testing,
            ::gphoto2::GP_DRIVER_STATUS_EXPERIMENTAL => DriverStatus::Experimental,
            ::gphoto2::GP_DRIVER_STATUS_DEPRECATED   => DriverStatus::Deprecated,
        }
    }

    /// Returns the supported port types.
    pub fn port_types(&self) -> HashSet<PortType> {
        let mut port_types = HashSet::<PortType>::new();

        if self.inner.port & ::gphoto2::GP_PORT_SERIAL != 0 {
            port_types.insert(PortType::Serial);
        }

        if self.inner.port & ::gphoto2::GP_PORT_USB != 0 {
            port_types.insert(PortType::USB);
        }

        if self.inner.port & ::gphoto2::GP_PORT_DISK != 0 {
            port_types.insert(PortType::Disk);
        }

        if self.inner.port & ::gphoto2::GP_PORT_PTPIP != 0 {
            port_types.insert(PortType::PTPIP);
        }

        if self.inner.port & ::gphoto2::GP_PORT_USB_DISK_DIRECT != 0 {
            port_types.insert(PortType::Direct);
        }

        if self.inner.port & ::gphoto2::GP_PORT_USB_SCSI != 0 {
            port_types.insert(PortType::SCSI);
        }

        port_types
    }

    /// Returns the supported serial port speeds.
    pub fn speeds(&self) -> Vec<usize> {
        self.inner.speed.iter().take_while(|&n| *n != 0).map(|&n| n as usize).collect()
    }

    /// Returns the camera operations supported by the device.
    pub fn camera_operations(&self) -> HashSet<CameraOperation> {
        let mut operations = HashSet::<CameraOperation>::new();

        if self.inner.operations & ::gphoto2::GP_OPERATION_CONFIG != 0 {
            operations.insert(CameraOperation::Config);
        }

        if self.inner.operations & ::gphoto2::GP_OPERATION_CAPTURE_IMAGE != 0 {
            operations.insert(CameraOperation::CaptureImage);
        }

        if self.inner.operations & ::gphoto2::GP_OPERATION_CAPTURE_VIDEO != 0 {
            operations.insert(CameraOperation::CaptureVideo);
        }

        if self.inner.operations & ::gphoto2::GP_OPERATION_CAPTURE_AUDIO != 0 {
            operations.insert(CameraOperation::CaptureAudio);
        }

        if self.inner.operations & ::gphoto2::GP_OPERATION_CAPTURE_PREVIEW != 0 {
            operations.insert(CameraOperation::CapturePreview);
        }

        if self.inner.operations & ::gphoto2::GP_OPERATION_TRIGGER_CAPTURE != 0 {
            operations.insert(CameraOperation::TriggerCapture);
        }

        operations
    }

    /// Returns the file operations supported by the device.
    pub fn file_operations(&self) -> HashSet<FileOperation> {
        let mut operations = HashSet::<FileOperation>::new();

        if self.inner.file_operations & ::gphoto2::GP_FILE_OPERATION_DELETE != 0 {
            operations.insert(FileOperation::Delete);
        }

        if self.inner.file_operations & ::gphoto2::GP_FILE_OPERATION_PREVIEW != 0 {
            operations.insert(FileOperation::Preview);
        }

        if self.inner.file_operations & ::gphoto2::GP_FILE_OPERATION_RAW != 0 {
            operations.insert(FileOperation::Raw);
        }

        if self.inner.file_operations & ::gphoto2::GP_FILE_OPERATION_AUDIO != 0 {
            operations.insert(FileOperation::Audio);
        }

        if self.inner.file_operations & ::gphoto2::GP_FILE_OPERATION_EXIF != 0 {
            operations.insert(FileOperation::EXIF);
        }

        operations
    }

    /// Returns the folder operations supported by the device.
    pub fn folder_operations(&self) -> HashSet<FolderOperation> {
        let mut operations = HashSet::<FolderOperation>::new();

        if self.inner.folder_operations & ::gphoto2::GP_FOLDER_OPERATION_DELETE_ALL != 0 {
            operations.insert(FolderOperation::DeleteAll);
        }

        if self.inner.folder_operations & ::gphoto2::GP_FOLDER_OPERATION_PUT_FILE != 0 {
            operations.insert(FolderOperation::PutFile);
        }

        if self.inner.folder_operations & ::gphoto2::GP_FOLDER_OPERATION_MAKE_DIR != 0 {
            operations.insert(FolderOperation::MakeDirectory);
        }

        if self.inner.folder_operations & ::gphoto2::GP_FOLDER_OPERATION_REMOVE_DIR != 0 {
            operations.insert(FolderOperation::RemoveDirectory);
        }

        operations
    }

    /// USB vendor ID.
    pub fn usb_vendor(&self) -> u16 {
        self.inner.usb_vendor as u16
    }

    /// USB product ID.
    pub fn usb_product(&self) -> u16 {
        self.inner.usb_product as u16
    }

    /// USB device class.
    pub fn usb_class(&self) -> u8 {
        self.inner.usb_class as u8
    }

    /// USB device subclass.
    pub fn usb_subclass(&self) -> u8 {
        self.inner.usb_subclass as u8
    }

    /// USB device protocol.
    pub fn usb_protocol(&self) -> u8 {
        self.inner.usb_protocol as u8
    }
}

/// Types of devices.
#[derive(Debug,PartialEq,Eq,Clone,Copy,Hash)]
pub enum DeviceType {
    /// Still camera.
    Camera,

    /// Audio player.
    Audio,
}

/// Stability of camera driver.
#[derive(Debug,PartialEq,Eq,Clone,Copy,Hash)]
pub enum DriverStatus {
    /// Driver is production ready.
    Production,

    /// Driver is beta quality.
    Testing,

    /// Driver is alpha quality and might not even work.
    Experimental,

    /// Driver is no longer recommended and will be removed.
    Deprecated,
}

/// Operations that can be performed on a device.
#[derive(Debug,PartialEq,Eq,Clone,Copy,Hash)]
pub enum CameraOperation {
    /// Camera can be configured.
    Config,

    /// Camera can capture images.
    CaptureImage,

    /// Camera can capture video.
    CaptureVideo,

    /// Camera can capture audio.
    CaptureAudio,

    /// Camera can capture image previews.
    CapturePreview,

    /// Camera can trigger capture and wait for events.
    TriggerCapture,
}


/// Operations that can be performed on files on a device's storage.
#[derive(Debug,PartialEq,Eq,Clone,Copy,Hash)]
pub enum FileOperation {
    /// Files can be deleted.
    Delete,

    /// Viewfinder content can be previewed.
    Preview,

    /// Raw file data can be retrieved.
    Raw,

    /// Audio data can be retrieved.
    Audio,

    /// EXIF data can be retrieved.
    EXIF,
}

/// Operations that can be performed on folders on a device's storage.
#[derive(Debug,PartialEq,Eq,Clone,Copy,Hash)]
pub enum FolderOperation {
    /// Deleting all files on the device is supported.
    DeleteAll,

    /// Uploading files to the device is supported.
    PutFile,

    /// Making new directories on the device is supported.
    MakeDirectory,

    /// Removing directories from the device is supported.
    RemoveDirectory,
}


#[doc(hidden)]
pub fn from_libgphoto2(abilities: ::gphoto2::CameraAbilities) -> Abilities {
    Abilities { inner: abilities }
}