Mark Drobnak
2 years ago
committed by
GitHub
3 changed files with 1083 additions and 0 deletions
@ -0,0 +1,138 @@ |
|||||||
|
use ctru::console::Console; |
||||||
|
use ctru::gfx::{Screen, Side}; |
||||||
|
use ctru::services::cam::{Cam, CamOutputFormat, CamShutterSoundType, CamSize, Camera}; |
||||||
|
use ctru::services::hid::KeyPad; |
||||||
|
use ctru::services::{Apt, Hid}; |
||||||
|
use ctru::Gfx; |
||||||
|
use std::time::Duration; |
||||||
|
|
||||||
|
const WIDTH: usize = 400; |
||||||
|
const HEIGHT: usize = 240; |
||||||
|
|
||||||
|
// The screen size is the width and height multiplied by 2 and
|
||||||
|
// then multiplied by 2 again for 3D images
|
||||||
|
const BUF_SIZE: usize = WIDTH * HEIGHT * 2 * 2; |
||||||
|
|
||||||
|
const WAIT_TIMEOUT: Duration = Duration::from_micros(300); |
||||||
|
|
||||||
|
fn main() { |
||||||
|
ctru::init(); |
||||||
|
|
||||||
|
let apt = Apt::init().expect("Failed to initialize Apt service."); |
||||||
|
let hid = Hid::init().expect("Failed to initialize Hid service."); |
||||||
|
let gfx = Gfx::init().expect("Failed to initialize GFX service."); |
||||||
|
|
||||||
|
gfx.top_screen.borrow_mut().set_double_buffering(true); |
||||||
|
gfx.bottom_screen.borrow_mut().set_double_buffering(false); |
||||||
|
|
||||||
|
let _console = Console::init(gfx.bottom_screen.borrow_mut()); |
||||||
|
|
||||||
|
let mut keys_down; |
||||||
|
|
||||||
|
println!("Initializing camera"); |
||||||
|
|
||||||
|
let mut cam = Cam::init().expect("Failed to initialize CAM service."); |
||||||
|
|
||||||
|
{ |
||||||
|
let camera = &mut cam.outer_right_cam; |
||||||
|
|
||||||
|
camera |
||||||
|
.set_view_size(CamSize::CTR_TOP_LCD) |
||||||
|
.expect("Failed to set camera size"); |
||||||
|
camera |
||||||
|
.set_output_format(CamOutputFormat::RGB_565) |
||||||
|
.expect("Failed to set camera output format"); |
||||||
|
camera |
||||||
|
.set_noise_filter(true) |
||||||
|
.expect("Failed to enable noise filter"); |
||||||
|
camera |
||||||
|
.set_auto_exposure(true) |
||||||
|
.expect("Failed to enable auto exposure"); |
||||||
|
camera |
||||||
|
.set_auto_white_balance(true) |
||||||
|
.expect("Failed to enable auto white balance"); |
||||||
|
camera |
||||||
|
.set_trimming(false) |
||||||
|
.expect("Failed to disable trimming"); |
||||||
|
} |
||||||
|
let mut buf = vec![0u8; BUF_SIZE]; |
||||||
|
|
||||||
|
println!("\nPress R to take a new picture"); |
||||||
|
println!("Press Start to exit to Homebrew Launcher"); |
||||||
|
|
||||||
|
while apt.main_loop() { |
||||||
|
hid.scan_input(); |
||||||
|
keys_down = hid.keys_down(); |
||||||
|
|
||||||
|
if keys_down.contains(KeyPad::KEY_START) { |
||||||
|
break; |
||||||
|
} |
||||||
|
|
||||||
|
if keys_down.contains(KeyPad::KEY_R) { |
||||||
|
println!("Capturing new image"); |
||||||
|
cam.play_shutter_sound(CamShutterSoundType::NORMAL) |
||||||
|
.expect("Failed to play shutter sound"); |
||||||
|
|
||||||
|
let camera = &mut cam.outer_right_cam; |
||||||
|
|
||||||
|
buf = camera |
||||||
|
.take_picture( |
||||||
|
WIDTH.try_into().unwrap(), |
||||||
|
HEIGHT.try_into().unwrap(), |
||||||
|
WAIT_TIMEOUT, |
||||||
|
) |
||||||
|
.expect("Failed to take picture"); |
||||||
|
} |
||||||
|
|
||||||
|
let img = convert_image_to_rgb8(&buf, 0, 0, WIDTH as usize, HEIGHT as usize); |
||||||
|
|
||||||
|
unsafe { |
||||||
|
gfx.top_screen |
||||||
|
.borrow_mut() |
||||||
|
.get_raw_framebuffer(Side::Left) |
||||||
|
.ptr |
||||||
|
.copy_from(img.as_ptr(), img.len()); |
||||||
|
} |
||||||
|
|
||||||
|
gfx.flush_buffers(); |
||||||
|
gfx.swap_buffers(); |
||||||
|
gfx.wait_for_vblank(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// The available camera output formats are both using u16 values.
|
||||||
|
// To write to the frame buffer with the default RGB8 format,
|
||||||
|
// the values must be converted.
|
||||||
|
//
|
||||||
|
// Alternatively, the frame buffer format could be set to RGB565 as well
|
||||||
|
// but the image would need to be rotated 90 degrees.
|
||||||
|
fn convert_image_to_rgb8(img: &[u8], x: usize, y: usize, width: usize, height: usize) -> Vec<u8> { |
||||||
|
let mut rgb8 = vec![0u8; img.len()]; |
||||||
|
for j in 0..height { |
||||||
|
for i in 0..width { |
||||||
|
// Y-coordinate of where to draw in the frame buffer
|
||||||
|
let draw_y = y + height - j; |
||||||
|
// X-coordinate of where to draw in the frame buffer
|
||||||
|
let draw_x = x + i; |
||||||
|
// Initial index of where to draw in the frame buffer based on y and x coordinates
|
||||||
|
let draw_index = (draw_y + draw_x * height) * 3; |
||||||
|
|
||||||
|
// Index of the pixel to draw within the image buffer
|
||||||
|
let index = (j * width + i) * 2; |
||||||
|
// Pixels in the image are 2 bytes because of the RGB565 format.
|
||||||
|
let pixel = u16::from_ne_bytes(img[index..index + 2].try_into().unwrap()); |
||||||
|
// b value from the pixel
|
||||||
|
let b = (((pixel >> 11) & 0x1F) << 3) as u8; |
||||||
|
// g value from the pixel
|
||||||
|
let g = (((pixel >> 5) & 0x3F) << 2) as u8; |
||||||
|
// r value from the pixel
|
||||||
|
let r = ((pixel & 0x1F) << 3) as u8; |
||||||
|
|
||||||
|
// set the r, g, and b values to the calculated index within the frame buffer
|
||||||
|
rgb8[draw_index] = r; |
||||||
|
rgb8[draw_index + 1] = g; |
||||||
|
rgb8[draw_index + 2] = b; |
||||||
|
} |
||||||
|
} |
||||||
|
rgb8 |
||||||
|
} |
@ -0,0 +1,944 @@ |
|||||||
|
//! CAM service
|
||||||
|
//!
|
||||||
|
//! The CAM service provides access to the cameras. Cameras can return 2D images
|
||||||
|
//! in the form of byte vectors which can be used for display or other usages.
|
||||||
|
|
||||||
|
use crate::services::gspgpu::FramebufferFormat; |
||||||
|
use bitflags::bitflags; |
||||||
|
use ctru_sys::Handle; |
||||||
|
use std::time::Duration; |
||||||
|
|
||||||
|
/// A reference-counted handle to the CAM service and the usable cameras.
|
||||||
|
/// The service is closed when all instances of this struct fall out of scope.
|
||||||
|
///
|
||||||
|
/// This service requires no special permissions to use.
|
||||||
|
#[non_exhaustive] |
||||||
|
pub struct Cam { |
||||||
|
pub inner_cam: InwardCam, |
||||||
|
pub outer_right_cam: OutwardRightCam, |
||||||
|
pub outer_left_cam: OutwardLeftCam, |
||||||
|
pub both_outer_cams: BothOutwardCam, |
||||||
|
} |
||||||
|
|
||||||
|
bitflags! { |
||||||
|
/// A set of flags to be passed to [Camera::flip_image]
|
||||||
|
#[derive(Default)] |
||||||
|
pub struct CamFlip: u32 { |
||||||
|
const NONE = ctru_sys::FLIP_NONE; |
||||||
|
const HORIZONTAL = ctru_sys::FLIP_HORIZONTAL; |
||||||
|
const VERTICAL = ctru_sys::FLIP_VERTICAL; |
||||||
|
const REVERSE = ctru_sys::FLIP_REVERSE; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
bitflags! { |
||||||
|
/// A set of flags to be passed to [Camera::set_view_size]
|
||||||
|
#[derive(Default)] |
||||||
|
pub struct CamSize: u32 { |
||||||
|
const VGA = ctru_sys::SIZE_VGA; |
||||||
|
const QVGA = ctru_sys::SIZE_QVGA; |
||||||
|
const QQVGA = ctru_sys::SIZE_QQVGA; |
||||||
|
const CIF = ctru_sys::SIZE_CIF; |
||||||
|
const QCIF = ctru_sys::SIZE_QCIF; |
||||||
|
const DS_LCD = ctru_sys::SIZE_DS_LCD; |
||||||
|
const DS_LCD_X4 = ctru_sys::SIZE_DS_LCDx4; |
||||||
|
const CTR_TOP_LCD = ctru_sys::SIZE_CTR_TOP_LCD; |
||||||
|
const CTR_BOTTOM_LCD = ctru_sys::SIZE_CTR_BOTTOM_LCD; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
bitflags! { |
||||||
|
/// A set of flags to be passed to [Camera::set_frame_rate]
|
||||||
|
#[derive(Default)] |
||||||
|
pub struct CamFrameRate: u32 { |
||||||
|
const RATE_15 = ctru_sys::FRAME_RATE_15; |
||||||
|
const RATE_15_TO_5 = ctru_sys::FRAME_RATE_15_TO_5; |
||||||
|
const RATE_15_TO_2 = ctru_sys::FRAME_RATE_15_TO_2; |
||||||
|
const RATE_10 = ctru_sys::FRAME_RATE_10; |
||||||
|
const RATE_8_5 = ctru_sys::FRAME_RATE_8_5; |
||||||
|
const RATE_5 = ctru_sys::FRAME_RATE_5; |
||||||
|
const RATE_20 = ctru_sys::FRAME_RATE_20; |
||||||
|
const RATE_20_TO_5 = ctru_sys::FRAME_RATE_20_TO_5; |
||||||
|
const RATE_30 = ctru_sys::FRAME_RATE_30; |
||||||
|
const RATE_30_TO_5 = ctru_sys::FRAME_RATE_30_TO_5; |
||||||
|
const RATE_15_TO_10 = ctru_sys::FRAME_RATE_15_TO_10; |
||||||
|
const RATE_20_TO_10 = ctru_sys::FRAME_RATE_20_TO_10; |
||||||
|
const RATE_30_TO_10 = ctru_sys::FRAME_RATE_30_TO_10; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
bitflags! { |
||||||
|
/// A set of flags to be passed to [Camera::set_white_balance] or
|
||||||
|
/// [Camera::set_white_balance_without_base_up]
|
||||||
|
#[derive(Default)] |
||||||
|
pub struct CamWhiteBalance: u32 { |
||||||
|
const AUTO = ctru_sys::WHITE_BALANCE_AUTO; |
||||||
|
const BALANCE_3200K = ctru_sys::WHITE_BALANCE_3200K; |
||||||
|
const BALANCE_4150K = ctru_sys::WHITE_BALANCE_4150K; |
||||||
|
const BALANCE_5200K = ctru_sys::WHITE_BALANCE_5200K; |
||||||
|
const BALANCE_6000K = ctru_sys::WHITE_BALANCE_6000K; |
||||||
|
const BALANCE_7000K = ctru_sys::WHITE_BALANCE_7000K; |
||||||
|
|
||||||
|
const NORMAL = ctru_sys::WHITE_BALANCE_NORMAL; |
||||||
|
const TUNGSTEN = ctru_sys::WHITE_BALANCE_TUNGSTEN; |
||||||
|
const WHITE_FLUORESCENT_LIGHT = ctru_sys::WHITE_BALANCE_WHITE_FLUORESCENT_LIGHT; |
||||||
|
const DAYLIGHT = ctru_sys::WHITE_BALANCE_DAYLIGHT; |
||||||
|
const CLOUDY = ctru_sys::WHITE_BALANCE_CLOUDY; |
||||||
|
const HORIZON = ctru_sys::WHITE_BALANCE_HORIZON; |
||||||
|
const SHADE = ctru_sys::WHITE_BALANCE_SHADE; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
bitflags! { |
||||||
|
/// A set of flags to be passed to [Camera::set_photo_mode]
|
||||||
|
#[derive(Default)] |
||||||
|
pub struct CamPhotoMode: u32 { |
||||||
|
const NORMAL = ctru_sys::PHOTO_MODE_NORMAL; |
||||||
|
const PORTRAIT = ctru_sys::PHOTO_MODE_PORTRAIT; |
||||||
|
const LANDSCAPE = ctru_sys::PHOTO_MODE_LANDSCAPE; |
||||||
|
const NIGHTVIEW = ctru_sys::PHOTO_MODE_NIGHTVIEW; |
||||||
|
const LETTER = ctru_sys::PHOTO_MODE_LETTER; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
bitflags! { |
||||||
|
/// A set of flags to be passed to [Camera::set_effect]
|
||||||
|
#[derive(Default)] |
||||||
|
pub struct CamEffect: u32 { |
||||||
|
const NONE = ctru_sys::EFFECT_NONE; |
||||||
|
const MONO = ctru_sys::EFFECT_MONO; |
||||||
|
const SEPIA = ctru_sys::EFFECT_SEPIA; |
||||||
|
const NEGATIVE = ctru_sys::EFFECT_NEGATIVE; |
||||||
|
const NEGAFILM = ctru_sys::EFFECT_NEGAFILM; |
||||||
|
const SEPIA01 = ctru_sys::EFFECT_SEPIA01; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
bitflags! { |
||||||
|
/// A set of flags to be passed to [Camera::set_contrast]
|
||||||
|
#[derive(Default)] |
||||||
|
pub struct CamContrast: u32 { |
||||||
|
const PATTERN_01 = ctru_sys::CONTRAST_PATTERN_01; |
||||||
|
const PATTERN_02 = ctru_sys::CONTRAST_PATTERN_02; |
||||||
|
const PATTERN_03 = ctru_sys::CONTRAST_PATTERN_03; |
||||||
|
const PATTERN_04 = ctru_sys::CONTRAST_PATTERN_04; |
||||||
|
const PATTERN_05 = ctru_sys::CONTRAST_PATTERN_05; |
||||||
|
const PATTERN_06 = ctru_sys::CONTRAST_PATTERN_06; |
||||||
|
const PATTERN_07 = ctru_sys::CONTRAST_PATTERN_07; |
||||||
|
const PATTERN_08 = ctru_sys::CONTRAST_PATTERN_08; |
||||||
|
const PATTERN_09 = ctru_sys::CONTRAST_PATTERN_09; |
||||||
|
const PATTERN_10 = ctru_sys::CONTRAST_PATTERN_10; |
||||||
|
const PATTERN_11 = ctru_sys::CONTRAST_PATTERN_11; |
||||||
|
|
||||||
|
const LOW = ctru_sys::CONTRAST_LOW; |
||||||
|
const NORMAL = ctru_sys::CONTRAST_NORMAL; |
||||||
|
const HIGH = ctru_sys::CONTRAST_HIGH; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
bitflags! { |
||||||
|
/// A set of flags to be passed to [Camera::set_lens_correction]
|
||||||
|
#[derive(Default)] |
||||||
|
pub struct CamLensCorrection: u32 { |
||||||
|
const OFF = ctru_sys::LENS_CORRECTION_OFF; |
||||||
|
const ON_70 = ctru_sys::LENS_CORRECTION_ON_70; |
||||||
|
const ON_90 = ctru_sys::LENS_CORRECTION_ON_90; |
||||||
|
|
||||||
|
const DARK = ctru_sys::LENS_CORRECTION_DARK; |
||||||
|
const NORMAL = ctru_sys::LENS_CORRECTION_NORMAL; |
||||||
|
const BRIGHT = ctru_sys::LENS_CORRECTION_BRIGHT; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
bitflags! { |
||||||
|
/// A set of flags to be passed to [Camera::set_output_format]
|
||||||
|
#[derive(Default)] |
||||||
|
pub struct CamOutputFormat: u32 { |
||||||
|
const YUV_422 = ctru_sys::OUTPUT_YUV_422; |
||||||
|
const RGB_565 = ctru_sys::OUTPUT_RGB_565; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
impl TryFrom<FramebufferFormat> for CamOutputFormat { |
||||||
|
type Error = (); |
||||||
|
|
||||||
|
fn try_from(value: FramebufferFormat) -> Result<Self, Self::Error> { |
||||||
|
match value { |
||||||
|
FramebufferFormat::Rgb565 => Ok(CamOutputFormat::RGB_565), |
||||||
|
_ => Err(()), |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
impl TryFrom<CamOutputFormat> for FramebufferFormat { |
||||||
|
type Error = (); |
||||||
|
|
||||||
|
fn try_from(value: CamOutputFormat) -> Result<Self, Self::Error> { |
||||||
|
match value { |
||||||
|
CamOutputFormat::RGB_565 => Ok(FramebufferFormat::Rgb565), |
||||||
|
_ => Err(()), |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
bitflags! { |
||||||
|
/// A set of flags to be passed to [Cam::play_shutter_sound]
|
||||||
|
#[derive(Default)] |
||||||
|
pub struct CamShutterSoundType: u32 { |
||||||
|
const NORMAL = ctru_sys::SHUTTER_SOUND_TYPE_NORMAL; |
||||||
|
const MOVIE = ctru_sys::SHUTTER_SOUND_TYPE_MOVIE; |
||||||
|
const MOVIE_END = ctru_sys::SHUTTER_SOUND_TYPE_MOVIE_END; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/// Struct containing coordinates passed to [Camera::set_trimming_params].
|
||||||
|
pub struct CamTrimmingParams { |
||||||
|
x_start: i16, |
||||||
|
y_start: i16, |
||||||
|
x_end: i16, |
||||||
|
y_end: i16, |
||||||
|
} |
||||||
|
|
||||||
|
impl CamTrimmingParams { |
||||||
|
/// Creates a new [CamTrimmingParams] and guarantees the start coordinates are less than or
|
||||||
|
/// equal to the end coordinates.
|
||||||
|
///
|
||||||
|
/// `x_start <= x_end && y_start <= y_end`
|
||||||
|
pub fn new(x_start: i16, y_start: i16, x_end: i16, y_end: i16) -> CamTrimmingParams { |
||||||
|
assert!(x_start <= x_end && y_start <= y_end); |
||||||
|
Self { |
||||||
|
x_start, |
||||||
|
y_start, |
||||||
|
x_end, |
||||||
|
y_end, |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/// Represents data used by the camera to calibrate image quality
|
||||||
|
#[derive(Default)] |
||||||
|
pub struct ImageQualityCalibrationData(pub ctru_sys::CAMU_ImageQualityCalibrationData); |
||||||
|
|
||||||
|
/// Represents data used by the camera to calibrate image quality when using both outward cameras
|
||||||
|
#[derive(Default)] |
||||||
|
pub struct StereoCameraCalibrationData(pub ctru_sys::CAMU_StereoCameraCalibrationData); |
||||||
|
|
||||||
|
/// Represents the camera on the inside of the 3DS
|
||||||
|
#[non_exhaustive] |
||||||
|
pub struct InwardCam; |
||||||
|
|
||||||
|
impl Camera for InwardCam { |
||||||
|
fn camera_as_raw(&self) -> ctru_sys::u32_ { |
||||||
|
ctru_sys::SELECT_IN1 |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/// Represents the the outer right camera when the 3DS is open and the dual cameras are pointed
|
||||||
|
/// away from the user
|
||||||
|
#[non_exhaustive] |
||||||
|
pub struct OutwardRightCam; |
||||||
|
|
||||||
|
impl Camera for OutwardRightCam { |
||||||
|
fn camera_as_raw(&self) -> ctru_sys::u32_ { |
||||||
|
ctru_sys::SELECT_OUT1 |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/// Represents the the outer left camera when the 3DS is open and the dual cameras are pointed
|
||||||
|
/// away from the user
|
||||||
|
#[non_exhaustive] |
||||||
|
pub struct OutwardLeftCam; |
||||||
|
|
||||||
|
impl Camera for OutwardLeftCam { |
||||||
|
fn camera_as_raw(&self) -> ctru_sys::u32_ { |
||||||
|
ctru_sys::SELECT_OUT2 |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/// Represents the both outer cameras combined
|
||||||
|
#[non_exhaustive] |
||||||
|
pub struct BothOutwardCam; |
||||||
|
|
||||||
|
impl BothOutwardCam { |
||||||
|
/// Sets whether to enable or disable synchronization
|
||||||
|
/// of brightness for both left and right cameras
|
||||||
|
pub fn set_brightness_synchronization( |
||||||
|
&mut self, |
||||||
|
brightness_synchronization: bool, |
||||||
|
) -> crate::Result<()> { |
||||||
|
unsafe { |
||||||
|
let r = ctru_sys::CAMU_SetBrightnessSynchronization(brightness_synchronization); |
||||||
|
if r < 0 { |
||||||
|
Err(r.into()) |
||||||
|
} else { |
||||||
|
Ok(()) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
fn synchronize_vsync_timing(&self) -> crate::Result<()> { |
||||||
|
unsafe { |
||||||
|
let r = |
||||||
|
ctru_sys::CAMU_SynchronizeVsyncTiming(ctru_sys::SELECT_OUT1, ctru_sys::SELECT_OUT2); |
||||||
|
if r < 0 { |
||||||
|
Err(r.into()) |
||||||
|
} else { |
||||||
|
Ok(()) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
impl Camera for BothOutwardCam { |
||||||
|
fn camera_as_raw(&self) -> ctru_sys::u32_ { |
||||||
|
ctru_sys::SELECT_OUT1_OUT2 |
||||||
|
} |
||||||
|
|
||||||
|
fn port_as_raw(&self) -> ctru_sys::u32_ { |
||||||
|
ctru_sys::PORT_BOTH |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/// Represents a camera and its functionality
|
||||||
|
pub trait Camera { |
||||||
|
/// Returns the raw value of the selected camera
|
||||||
|
fn camera_as_raw(&self) -> ctru_sys::u32_; |
||||||
|
|
||||||
|
/// Returns the raw port of the selected camera
|
||||||
|
fn port_as_raw(&self) -> ctru_sys::u32_ { |
||||||
|
ctru_sys::PORT_CAM1 |
||||||
|
} |
||||||
|
|
||||||
|
/// Returns true if the camera is busy (receiving data)
|
||||||
|
fn is_busy(&self) -> crate::Result<bool> { |
||||||
|
unsafe { |
||||||
|
let mut is_busy = false; |
||||||
|
let r = ctru_sys::CAMU_IsBusy(&mut is_busy, self.port_as_raw()); |
||||||
|
if r < 0 { |
||||||
|
Err(r.into()) |
||||||
|
} else { |
||||||
|
Ok(is_busy) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/// Returns the maximum amount of transfer bytes based on the view size, trimming, and other
|
||||||
|
/// modifications set to the camera
|
||||||
|
fn get_transfer_bytes(&self) -> crate::Result<u32> { |
||||||
|
unsafe { |
||||||
|
let mut transfer_bytes = 0; |
||||||
|
let r = ctru_sys::CAMU_GetTransferBytes(&mut transfer_bytes, self.port_as_raw()); |
||||||
|
if r < 0 { |
||||||
|
Err(r.into()) |
||||||
|
} else { |
||||||
|
Ok(transfer_bytes) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/// Sets whether or not the camera should trim the image based on parameters set by
|
||||||
|
/// [Camera::set_trimming_params]
|
||||||
|
fn set_trimming(&mut self, enabled: bool) -> crate::Result<()> { |
||||||
|
unsafe { |
||||||
|
let r = ctru_sys::CAMU_SetTrimming(self.port_as_raw(), enabled); |
||||||
|
if r < 0 { |
||||||
|
Err(r.into()) |
||||||
|
} else { |
||||||
|
Ok(()) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/// Returns whether or not trimming is currently enabled for the camera
|
||||||
|
fn is_trimming_enabled(&self) -> crate::Result<bool> { |
||||||
|
unsafe { |
||||||
|
let mut trimming = false; |
||||||
|
let r = ctru_sys::CAMU_IsTrimming(&mut trimming, self.port_as_raw()); |
||||||
|
if r < 0 { |
||||||
|
Err(r.into()) |
||||||
|
} else { |
||||||
|
Ok(trimming) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/// Sets trimming parameters based on coordinates specified inside a [CamTrimmingParams]
|
||||||
|
fn set_trimming_params(&mut self, params: CamTrimmingParams) -> crate::Result<()> { |
||||||
|
unsafe { |
||||||
|
let r = ctru_sys::CAMU_SetTrimmingParams( |
||||||
|
self.port_as_raw(), |
||||||
|
params.x_start, |
||||||
|
params.y_start, |
||||||
|
params.x_end, |
||||||
|
params.y_end, |
||||||
|
); |
||||||
|
if r < 0 { |
||||||
|
Err(r.into()) |
||||||
|
} else { |
||||||
|
Ok(()) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/// Returns the set [CamTrimmingParams] from the camera
|
||||||
|
fn get_trimming_params(&self) -> crate::Result<CamTrimmingParams> { |
||||||
|
unsafe { |
||||||
|
let mut x_start = 0; |
||||||
|
let mut y_start = 0; |
||||||
|
let mut x_end = 0; |
||||||
|
let mut y_end = 0; |
||||||
|
let r = ctru_sys::CAMU_GetTrimmingParams( |
||||||
|
&mut x_start, |
||||||
|
&mut y_start, |
||||||
|
&mut x_end, |
||||||
|
&mut y_end, |
||||||
|
self.port_as_raw(), |
||||||
|
); |
||||||
|
if r < 0 { |
||||||
|
Err(r.into()) |
||||||
|
} else { |
||||||
|
Ok(CamTrimmingParams { |
||||||
|
x_start, |
||||||
|
y_start, |
||||||
|
x_end, |
||||||
|
y_end, |
||||||
|
}) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/// Sets the trimming parameters revolving around the center of the image.
|
||||||
|
/// The new width will be `trim_width / 2` to the left and right of the center.
|
||||||
|
/// The new height will be `trim_height / 2` above and below the center.
|
||||||
|
fn set_trimming_params_center( |
||||||
|
&self, |
||||||
|
trim_width: i16, |
||||||
|
trim_height: i16, |
||||||
|
cam_width: i16, |
||||||
|
cam_height: i16, |
||||||
|
) -> crate::Result<()> { |
||||||
|
unsafe { |
||||||
|
let r = ctru_sys::CAMU_SetTrimmingParamsCenter( |
||||||
|
self.port_as_raw(), |
||||||
|
trim_width, |
||||||
|
trim_height, |
||||||
|
cam_width, |
||||||
|
cam_height, |
||||||
|
); |
||||||
|
if r < 0 { |
||||||
|
Err(r.into()) |
||||||
|
} else { |
||||||
|
Ok(()) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/// Sets the exposure level of the camera
|
||||||
|
fn set_exposure(&mut self, exposure: i8) -> crate::Result<()> { |
||||||
|
unsafe { |
||||||
|
let r = ctru_sys::CAMU_SetExposure(self.camera_as_raw(), exposure); |
||||||
|
if r < 0 { |
||||||
|
Err(r.into()) |
||||||
|
} else { |
||||||
|
Ok(()) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/// Sets the white balance mod of the camera based on the passed [CamWhiteBalance] argument
|
||||||
|
fn set_white_balance(&mut self, white_balance: CamWhiteBalance) -> crate::Result<()> { |
||||||
|
unsafe { |
||||||
|
let r = ctru_sys::CAMU_SetWhiteBalance(self.camera_as_raw(), white_balance.bits()); |
||||||
|
if r < 0 { |
||||||
|
Err(r.into()) |
||||||
|
} else { |
||||||
|
Ok(()) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/// Sets the white balance mode of the camera based on the passed [CamWhiteBalance] argument
|
||||||
|
// TODO: Explain base up
|
||||||
|
fn set_white_balance_without_base_up( |
||||||
|
&mut self, |
||||||
|
white_balance: CamWhiteBalance, |
||||||
|
) -> crate::Result<()> { |
||||||
|
unsafe { |
||||||
|
let r = ctru_sys::CAMU_SetWhiteBalanceWithoutBaseUp( |
||||||
|
self.camera_as_raw(), |
||||||
|
white_balance.bits(), |
||||||
|
); |
||||||
|
if r < 0 { |
||||||
|
Err(r.into()) |
||||||
|
} else { |
||||||
|
Ok(()) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/// Sets the sharpness of the camera
|
||||||
|
fn set_sharpness(&mut self, sharpness: i8) -> crate::Result<()> { |
||||||
|
unsafe { |
||||||
|
let r = ctru_sys::CAMU_SetSharpness(self.camera_as_raw(), sharpness); |
||||||
|
if r < 0 { |
||||||
|
Err(r.into()) |
||||||
|
} else { |
||||||
|
Ok(()) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/// Sets whether auto exposure is enabled or disabled for the camera
|
||||||
|
fn set_auto_exposure(&mut self, enabled: bool) -> crate::Result<()> { |
||||||
|
unsafe { |
||||||
|
let r = ctru_sys::CAMU_SetAutoExposure(self.camera_as_raw(), enabled); |
||||||
|
if r < 0 { |
||||||
|
Err(r.into()) |
||||||
|
} else { |
||||||
|
Ok(()) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/// Returns true if auto exposure is enabled for the camera
|
||||||
|
fn is_auto_exposure_enabled(&self) -> crate::Result<bool> { |
||||||
|
unsafe { |
||||||
|
let mut enabled = false; |
||||||
|
let r = ctru_sys::CAMU_IsAutoExposure(&mut enabled, self.camera_as_raw()); |
||||||
|
if r < 0 { |
||||||
|
Err(r.into()) |
||||||
|
} else { |
||||||
|
Ok(enabled) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/// Sets whether auto white balance is enabled or disabled for the camera
|
||||||
|
fn set_auto_white_balance(&mut self, enabled: bool) -> crate::Result<()> { |
||||||
|
unsafe { |
||||||
|
let r = ctru_sys::CAMU_SetAutoWhiteBalance(self.camera_as_raw(), enabled); |
||||||
|
if r < 0 { |
||||||
|
Err(r.into()) |
||||||
|
} else { |
||||||
|
Ok(()) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/// Returns true if auto white balance is enabled for the camera
|
||||||
|
fn is_auto_white_balance_enabled(&self) -> crate::Result<bool> { |
||||||
|
unsafe { |
||||||
|
let mut enabled = false; |
||||||
|
let r = ctru_sys::CAMU_IsAutoWhiteBalance(&mut enabled, self.camera_as_raw()); |
||||||
|
if r < 0 { |
||||||
|
Err(r.into()) |
||||||
|
} else { |
||||||
|
Ok(enabled) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/// Sets the flip direction of the camera's image based on the passed [CamFlip] argument
|
||||||
|
fn flip_image(&mut self, flip: CamFlip) -> crate::Result<()> { |
||||||
|
unsafe { |
||||||
|
let r = |
||||||
|
ctru_sys::CAMU_FlipImage(self.camera_as_raw(), flip.bits(), ctru_sys::CONTEXT_A); |
||||||
|
if r < 0 { |
||||||
|
Err(r.into()) |
||||||
|
} else { |
||||||
|
Ok(()) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/// Sets the image resolution of the camera in detail
|
||||||
|
///
|
||||||
|
/// # Errors
|
||||||
|
///
|
||||||
|
/// This function will error if the coordinates of the first crop point are greater than the
|
||||||
|
/// coordinates of the second crop point.
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
/// * `width` - Width of the image
|
||||||
|
/// * `height` - height of the image
|
||||||
|
/// * `crop_0` - The first crop point in which the image will be trimmed
|
||||||
|
/// * `crop_0` - The second crop point in which the image will be trimmed
|
||||||
|
fn set_detail_size( |
||||||
|
&mut self, |
||||||
|
width: i16, |
||||||
|
height: i16, |
||||||
|
crop_0: (i16, i16), |
||||||
|
crop_1: (i16, i16), |
||||||
|
) -> crate::Result<()> { |
||||||
|
unsafe { |
||||||
|
let r = ctru_sys::CAMU_SetDetailSize( |
||||||
|
self.camera_as_raw(), |
||||||
|
width, |
||||||
|
height, |
||||||
|
crop_0.0, |
||||||
|
crop_0.1, |
||||||
|
crop_1.0, |
||||||
|
crop_1.1, |
||||||
|
ctru_sys::CONTEXT_A, |
||||||
|
); |
||||||
|
if r < 0 { |
||||||
|
Err(r.into()) |
||||||
|
} else { |
||||||
|
Ok(()) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/// Sets the view size of the camera based on the passed [CamSize] argument.
|
||||||
|
fn set_view_size(&mut self, size: CamSize) -> crate::Result<()> { |
||||||
|
unsafe { |
||||||
|
let r = ctru_sys::CAMU_SetSize(self.camera_as_raw(), size.bits(), ctru_sys::CONTEXT_A); |
||||||
|
if r < 0 { |
||||||
|
Err(r.into()) |
||||||
|
} else { |
||||||
|
Ok(()) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/// Sets the frame rate of the camera based on the passed [CamFrameRate] argument.
|
||||||
|
fn set_frame_rate(&mut self, frame_rate: CamFrameRate) -> crate::Result<()> { |
||||||
|
unsafe { |
||||||
|
let r = ctru_sys::CAMU_SetFrameRate(self.camera_as_raw(), frame_rate.bits()); |
||||||
|
if r < 0 { |
||||||
|
Err(r.into()) |
||||||
|
} else { |
||||||
|
Ok(()) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/// Sets the photo mode of the camera based on the passed [CamPhotoMode] argument.
|
||||||
|
fn set_photo_mode(&mut self, photo_mode: CamPhotoMode) -> crate::Result<()> { |
||||||
|
unsafe { |
||||||
|
let r = ctru_sys::CAMU_SetPhotoMode(self.camera_as_raw(), photo_mode.bits()); |
||||||
|
if r < 0 { |
||||||
|
Err(r.into()) |
||||||
|
} else { |
||||||
|
Ok(()) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/// Sets the effect of the camera based on the passed [CamEffect] argument.
|
||||||
|
///
|
||||||
|
/// Multiple effects can be set at once by combining the bitflags of [CamEffect]
|
||||||
|
fn set_effect(&mut self, effect: CamEffect) -> crate::Result<()> { |
||||||
|
unsafe { |
||||||
|
let r = |
||||||
|
ctru_sys::CAMU_SetEffect(self.camera_as_raw(), effect.bits(), ctru_sys::CONTEXT_A); |
||||||
|
if r < 0 { |
||||||
|
Err(r.into()) |
||||||
|
} else { |
||||||
|
Ok(()) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/// Sets the contrast of the camera based on the passed [CamContrast] argument.
|
||||||
|
fn set_contrast(&mut self, contrast: CamContrast) -> crate::Result<()> { |
||||||
|
unsafe { |
||||||
|
let r = ctru_sys::CAMU_SetContrast(self.camera_as_raw(), contrast.bits()); |
||||||
|
if r < 0 { |
||||||
|
Err(r.into()) |
||||||
|
} else { |
||||||
|
Ok(()) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/// Sets the lens correction of the camera based on the passed [CamLensCorrection] argument.
|
||||||
|
fn set_lens_correction(&mut self, lens_correction: CamLensCorrection) -> crate::Result<()> { |
||||||
|
unsafe { |
||||||
|
let r = ctru_sys::CAMU_SetLensCorrection(self.camera_as_raw(), lens_correction.bits()); |
||||||
|
if r < 0 { |
||||||
|
Err(r.into()) |
||||||
|
} else { |
||||||
|
Ok(()) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/// Sets the output format of the camera based on the passed [CamOutputFormat] argument.
|
||||||
|
fn set_output_format(&mut self, format: CamOutputFormat) -> crate::Result<()> { |
||||||
|
unsafe { |
||||||
|
let r = ctru_sys::CAMU_SetOutputFormat( |
||||||
|
self.camera_as_raw(), |
||||||
|
format.bits(), |
||||||
|
ctru_sys::CONTEXT_A, |
||||||
|
); |
||||||
|
if r < 0 { |
||||||
|
Err(r.into()) |
||||||
|
} else { |
||||||
|
Ok(()) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/// Sets the region in which auto exposure should be based on.
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
///
|
||||||
|
/// * `x` - Starting x coordinate of the window
|
||||||
|
/// * `y` - Starting y coordinate of the window
|
||||||
|
/// * `width` - Width of the window
|
||||||
|
/// * `height` - Height of the window
|
||||||
|
fn set_auto_exposure_window( |
||||||
|
&mut self, |
||||||
|
x: i16, |
||||||
|
y: i16, |
||||||
|
width: i16, |
||||||
|
height: i16, |
||||||
|
) -> crate::Result<()> { |
||||||
|
unsafe { |
||||||
|
let r = ctru_sys::CAMU_SetAutoExposureWindow(self.camera_as_raw(), x, y, width, height); |
||||||
|
if r < 0 { |
||||||
|
Err(r.into()) |
||||||
|
} else { |
||||||
|
Ok(()) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/// Sets the region in which auto white balance should be based on.
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
///
|
||||||
|
/// * `x` - Starting x coordinate of the window
|
||||||
|
/// * `y` - Starting y coordinate of the window
|
||||||
|
/// * `width` - Width of the window
|
||||||
|
/// * `height` - Height of the window
|
||||||
|
fn set_auto_white_balance_window( |
||||||
|
&mut self, |
||||||
|
x: i16, |
||||||
|
y: i16, |
||||||
|
width: i16, |
||||||
|
height: i16, |
||||||
|
) -> crate::Result<()> { |
||||||
|
unsafe { |
||||||
|
let r = |
||||||
|
ctru_sys::CAMU_SetAutoWhiteBalanceWindow(self.camera_as_raw(), x, y, width, height); |
||||||
|
if r < 0 { |
||||||
|
Err(r.into()) |
||||||
|
} else { |
||||||
|
Ok(()) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/// Sets whether the noise filter should be enabled or disabled for the camera
|
||||||
|
fn set_noise_filter(&mut self, enabled: bool) -> crate::Result<()> { |
||||||
|
unsafe { |
||||||
|
let r = ctru_sys::CAMU_SetNoiseFilter(self.camera_as_raw(), enabled); |
||||||
|
if r < 0 { |
||||||
|
Err(r.into()) |
||||||
|
} else { |
||||||
|
Ok(()) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/// Sets the image quality calibration data for the camera based on the passed in
|
||||||
|
/// [ImageQualityCalibrationData] argument
|
||||||
|
fn set_image_quality_calibration_data( |
||||||
|
&mut self, |
||||||
|
data: ImageQualityCalibrationData, |
||||||
|
) -> crate::Result<()> { |
||||||
|
unsafe { |
||||||
|
let r = ctru_sys::CAMU_SetImageQualityCalibrationData(data.0); |
||||||
|
if r < 0 { |
||||||
|
Err(r.into()) |
||||||
|
} else { |
||||||
|
Ok(()) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/// Returns the current [ImageQualityCalibrationData] for the camera
|
||||||
|
fn get_image_quality_calibration_data(&self) -> crate::Result<ImageQualityCalibrationData> { |
||||||
|
unsafe { |
||||||
|
let mut data = ImageQualityCalibrationData::default(); |
||||||
|
let r = ctru_sys::CAMU_GetImageQualityCalibrationData(&mut data.0); |
||||||
|
if r < 0 { |
||||||
|
Err(r.into()) |
||||||
|
} else { |
||||||
|
Ok(data) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/// Sets the camera as the current sleep camera
|
||||||
|
// TODO: Explain sleep camera
|
||||||
|
fn set_sleep_camera(&mut self) -> crate::Result<()> { |
||||||
|
unsafe { |
||||||
|
let r = ctru_sys::CAMU_SetSleepCamera(self.camera_as_raw()); |
||||||
|
if r < 0 { |
||||||
|
Err(r.into()) |
||||||
|
} else { |
||||||
|
Ok(()) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/// Requests the camera to take a picture and returns a vector containing the image bytes.
|
||||||
|
///
|
||||||
|
/// # Errors
|
||||||
|
///
|
||||||
|
/// This will error if the camera is busy or if the timeout duration is reached.
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
///
|
||||||
|
/// * `width` - Width of the desired image
|
||||||
|
/// * `height` - Height of the desired image
|
||||||
|
/// * `timeout` - Duration to wait for the image
|
||||||
|
fn take_picture( |
||||||
|
&mut self, |
||||||
|
width: u16, |
||||||
|
height: u16, |
||||||
|
timeout: Duration, |
||||||
|
) -> crate::Result<Vec<u8>> { |
||||||
|
let transfer_unit = unsafe { |
||||||
|
let mut buf_size = 0; |
||||||
|
let r = ctru_sys::CAMU_GetMaxBytes(&mut buf_size, width as i16, height as i16); |
||||||
|
if r < 0 { |
||||||
|
Err(crate::Error::from(r)) |
||||||
|
} else { |
||||||
|
Ok(buf_size) |
||||||
|
} |
||||||
|
}?; |
||||||
|
|
||||||
|
let screen_size = u32::from(width) * u32::from(width) * 2; |
||||||
|
|
||||||
|
let mut buf = vec![0u8; usize::try_from(screen_size).unwrap()]; |
||||||
|
|
||||||
|
unsafe { |
||||||
|
let r = ctru_sys::CAMU_SetTransferBytes( |
||||||
|
self.port_as_raw(), |
||||||
|
transfer_unit, |
||||||
|
width as i16, |
||||||
|
height as i16, |
||||||
|
); |
||||||
|
if r < 0 { |
||||||
|
return Err(r.into()); |
||||||
|
} |
||||||
|
}; |
||||||
|
|
||||||
|
unsafe { |
||||||
|
let r = ctru_sys::CAMU_Activate(self.camera_as_raw()); |
||||||
|
if r < 0 { |
||||||
|
return Err(r.into()); |
||||||
|
} |
||||||
|
}; |
||||||
|
|
||||||
|
unsafe { |
||||||
|
let r = ctru_sys::CAMU_ClearBuffer(self.port_as_raw()); |
||||||
|
if r < 0 { |
||||||
|
return Err(r.into()); |
||||||
|
} |
||||||
|
}; |
||||||
|
|
||||||
|
unsafe { |
||||||
|
let r = ctru_sys::CAMU_StartCapture(self.port_as_raw()); |
||||||
|
if r < 0 { |
||||||
|
return Err(r.into()); |
||||||
|
} |
||||||
|
}; |
||||||
|
|
||||||
|
let receive_event = unsafe { |
||||||
|
let mut completion_handle: Handle = 0; |
||||||
|
let r = ctru_sys::CAMU_SetReceiving( |
||||||
|
&mut completion_handle, |
||||||
|
buf.as_mut_ptr() as *mut ::libc::c_void, |
||||||
|
self.port_as_raw(), |
||||||
|
screen_size, |
||||||
|
transfer_unit.try_into().unwrap(), |
||||||
|
); |
||||||
|
if r < 0 { |
||||||
|
Err(crate::Error::from(r)) |
||||||
|
} else { |
||||||
|
Ok(completion_handle) |
||||||
|
} |
||||||
|
}?; |
||||||
|
|
||||||
|
unsafe { |
||||||
|
let r = ctru_sys::svcWaitSynchronization( |
||||||
|
receive_event, |
||||||
|
timeout.as_nanos().try_into().unwrap(), |
||||||
|
); |
||||||
|
if r < 0 { |
||||||
|
return Err(r.into()); |
||||||
|
} |
||||||
|
}; |
||||||
|
|
||||||
|
unsafe { |
||||||
|
let r = ctru_sys::CAMU_StopCapture(self.port_as_raw()); |
||||||
|
if r < 0 { |
||||||
|
return Err(r.into()); |
||||||
|
} |
||||||
|
}; |
||||||
|
|
||||||
|
unsafe { |
||||||
|
let r = ctru_sys::svcCloseHandle(receive_event); |
||||||
|
if r < 0 { |
||||||
|
return Err(r.into()); |
||||||
|
} |
||||||
|
}; |
||||||
|
|
||||||
|
unsafe { |
||||||
|
let r = ctru_sys::CAMU_Activate(ctru_sys::SELECT_NONE); |
||||||
|
if r < 0 { |
||||||
|
return Err(r.into()); |
||||||
|
} |
||||||
|
}; |
||||||
|
|
||||||
|
Ok(buf) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
impl Cam { |
||||||
|
/// Initializes the CAM service.
|
||||||
|
///
|
||||||
|
/// # Errors
|
||||||
|
///
|
||||||
|
/// This function will return an error if the service was unable to be initialized.
|
||||||
|
/// Since this service requires no special or elevated permissions, errors are
|
||||||
|
/// rare in practice.
|
||||||
|
pub fn init() -> crate::Result<Cam> { |
||||||
|
unsafe { |
||||||
|
let r = ctru_sys::camInit(); |
||||||
|
if r < 0 { |
||||||
|
Err(r.into()) |
||||||
|
} else { |
||||||
|
Ok(Cam { |
||||||
|
inner_cam: InwardCam, |
||||||
|
outer_right_cam: OutwardRightCam, |
||||||
|
outer_left_cam: OutwardLeftCam, |
||||||
|
both_outer_cams: BothOutwardCam, |
||||||
|
}) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/// Plays the specified sound based on the [CamShutterSoundType] argument
|
||||||
|
pub fn play_shutter_sound(&self, sound: CamShutterSoundType) -> crate::Result<()> { |
||||||
|
unsafe { |
||||||
|
let r = ctru_sys::CAMU_PlayShutterSound(sound.bits()); |
||||||
|
if r < 0 { |
||||||
|
Err(r.into()) |
||||||
|
} else { |
||||||
|
Ok(()) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
impl Drop for Cam { |
||||||
|
fn drop(&mut self) { |
||||||
|
unsafe { ctru_sys::camExit() }; |
||||||
|
} |
||||||
|
} |
Loading…
Reference in new issue