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
#![allow(clippy::manual_strip)]

use std::{any::Any, collections::HashMap, io, ptr::NonNull};

use bitflags::bitflags;
use libcamera_sys::*;

use crate::{control::ControlList, framebuffer::AsFrameBuffer, stream::Stream};

/// Status of [Request]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum RequestStatus {
    /// Request is ready to be executed by [ActiveCamera::queue_request()](crate::camera::ActiveCamera::queue_request)
    Pending,
    /// Request was executed successfully
    Complete,
    /// Request was cancelled, most likely due to call to [ActiveCamera::stop()](crate::camera::ActiveCamera::stop)
    Cancelled,
}

impl TryFrom<libcamera_request_status_t> for RequestStatus {
    type Error = String;

    fn try_from(value: libcamera_request_status_t) -> Result<Self, Self::Error> {
        match value {
            libcamera_request_status::LIBCAMERA_REQUEST_STATUS_PENDING => Ok(Self::Pending),
            libcamera_request_status::LIBCAMERA_REQUEST_STATUS_COMPLETE => Ok(Self::Complete),
            libcamera_request_status::LIBCAMERA_REQUEST_STATUS_CANCELLED => Ok(Self::Cancelled),
            _ => Err(format!("Unknown libcamera_request_status: {}", value)),
        }
    }
}

bitflags! {
    /// Flags to control the behaviour of [Request::reuse()].
    pub struct ReuseFlag: u32 {
        /// Reuse the buffers that were previously added by [Request::add_buffer()].
        const REUSE_BUFFERS = 1 << 0;
    }
}

/// A camera capture request.
///
/// Capture requests are created by [ActiveCamera::create_request()](crate::camera::ActiveCamera::create_request)
/// and scheduled for execution by [ActiveCamera::queue_request()](crate::camera::ActiveCamera::queue_request).
/// Completed requests are returned by request completed callback (see
/// [ActiveCamera::on_request_completed()](crate::camera::ActiveCamera::on_request_completed)) and can (should) be
/// reused by calling [ActiveCamera::queue_request()](crate::camera::ActiveCamera::queue_request) again.
pub struct Request {
    pub(crate) ptr: NonNull<libcamera_request_t>,
    buffers: HashMap<Stream, Box<dyn Any + 'static>>,
}

impl Request {
    pub(crate) unsafe fn from_ptr(ptr: NonNull<libcamera_request_t>) -> Self {
        Self {
            ptr,
            buffers: Default::default(),
        }
    }

    /// Returns an immutable reference of request controls.
    ///
    /// See [controls](crate::controls) for available items.
    pub fn controls(&self) -> &ControlList {
        unsafe { ControlList::from_ptr(NonNull::new(libcamera_request_controls(self.ptr.as_ptr())).unwrap()) }
    }

    /// Returns a mutable reference of request controls.
    ///
    /// See [controls](crate::controls) for available items.
    pub fn controls_mut(&mut self) -> &mut ControlList {
        unsafe { ControlList::from_ptr(NonNull::new(libcamera_request_controls(self.ptr.as_ptr())).unwrap()) }
    }

    /// Returns request metadata, which contains information relevant to the request execution (i.e. capture timestamp).
    ///
    /// See [controls](crate::controls) for available items.
    pub fn metadata(&self) -> &ControlList {
        unsafe { ControlList::from_ptr(NonNull::new(libcamera_request_metadata(self.ptr.as_ptr())).unwrap()) }
    }

    /// Attaches framebuffer to the request.
    ///
    /// Buffers can only be attached once. To access framebuffer after executing request use [Self::buffer()] or
    /// [Self::buffer_mut()].
    pub fn add_buffer<T: AsFrameBuffer + Any>(&mut self, stream: &Stream, buffer: T) -> io::Result<()> {
        let ret =
            unsafe { libcamera_request_add_buffer(self.ptr.as_ptr(), stream.ptr.as_ptr(), buffer.ptr().as_ptr()) };
        if ret < 0 {
            Err(io::Error::from_raw_os_error(ret))
        } else {
            self.buffers.insert(*stream, Box::new(buffer));
            Ok(())
        }
    }

    /// Returns a reference to the buffer that was attached with [Self::add_buffer()].
    ///
    /// `T` must be equal to the type used in [Self::add_buffer()], otherwise this will return None.
    pub fn buffer<T: 'static>(&self, stream: &Stream) -> Option<&T> {
        self.buffers.get(stream).and_then(|b| b.downcast_ref())
    }

    /// Returns a mutable reference to the buffer that was attached with [Self::add_buffer()].
    ///
    /// `T` must be equal to the type used in [Self::add_buffer()], otherwise this will return None.
    pub fn buffer_mut<T: 'static>(&mut self, stream: &Stream) -> Option<&mut T> {
        self.buffers.get_mut(stream).and_then(|b| b.downcast_mut())
    }

    /// Returns auto-incrementing sequence number of the capture
    pub fn sequence(&self) -> u32 {
        unsafe { libcamera_request_sequence(self.ptr.as_ptr()) }
    }

    /// Returns request identifier that was provided in
    /// [ActiveCamera::create_request()](crate::camera::ActiveCamera::create_request).
    ///
    /// Returns zero if cookie was not provided.
    pub fn cookie(&self) -> u64 {
        unsafe { libcamera_request_cookie(self.ptr.as_ptr()) }
    }

    /// Capture request status
    pub fn status(&self) -> RequestStatus {
        RequestStatus::try_from(unsafe { libcamera_request_status(self.ptr.as_ptr()) }).unwrap()
    }

    /// Reset the request for reuse.
    ///
    /// Reset the status and controls associated with the request, to allow it to be reused and requeued without
    /// destruction. This function shall be called prior to queueing the request to the camera, in lieu of
    /// constructing a new request. The application can reuse the buffers that were previously added to the request
    /// via [Self::add_buffer()] by setting flags to [ReuseFlag::REUSE_BUFFERS].
    pub fn reuse(&mut self, flags: ReuseFlag) {
        unsafe { libcamera_request_reuse(self.ptr.as_ptr(), flags.bits()) }
    }
}

impl core::fmt::Debug for Request {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        f.debug_struct("Request")
            .field("seq", &self.sequence())
            .field("status", &self.status())
            .field("cookie", &self.cookie())
            .finish()
    }
}

impl Drop for Request {
    fn drop(&mut self) {
        unsafe { libcamera_request_destroy(self.ptr.as_ptr()) }
    }
}

unsafe impl Send for Request {}