Browse Source

Fix example and speedup performance

pull/94/head
Andrea Ciliberti 2 years ago
parent
commit
326cfde36f
  1. 37
      ctru-rs/examples/camera-image.rs
  2. 6
      ctru-rs/src/error.rs
  3. 33
      ctru-rs/src/services/cam.rs

37
ctru-rs/examples/camera-image.rs

@ -9,9 +9,9 @@ const WIDTH: usize = 400; @@ -9,9 +9,9 @@ const WIDTH: usize = 400;
const HEIGHT: usize = 240;
// The screen size is the width and height multiplied by 2 (RGB565 store pixels in 2 bytes)
// const BUF_SIZE: usize = WIDTH * HEIGHT * 2;
const BUF_SIZE: usize = WIDTH * HEIGHT * 2;
const WAIT_TIMEOUT: Duration = Duration::from_micros(300);
const WAIT_TIMEOUT: Duration = Duration::from_millis(300);
fn main() {
ctru::use_panic_handler();
@ -56,7 +56,7 @@ fn main() { @@ -56,7 +56,7 @@ fn main() {
.expect("Failed to disable trimming");
}
let mut buf;
let mut buf = vec![0; BUF_SIZE];
println!("\nPress R to take a new picture");
println!("Press Start to exit to Homebrew Launcher");
@ -74,8 +74,9 @@ fn main() { @@ -74,8 +74,9 @@ fn main() {
let camera = &mut cam.outer_right_cam;
buf = camera
camera
.take_picture(
&mut buf,
WIDTH.try_into().unwrap(),
HEIGHT.try_into().unwrap(),
WAIT_TIMEOUT,
@ -85,15 +86,12 @@ fn main() { @@ -85,15 +86,12 @@ fn main() {
cam.play_shutter_sound(CamShutterSoundType::NORMAL)
.expect("Failed to play shutter sound");
let img = rotate_image(&buf, WIDTH, HEIGHT);
unsafe {
gfx.top_screen
.borrow_mut()
.get_raw_framebuffer()
.ptr
.copy_from(img.as_ptr(), img.len());
}
rotate_image_to_screen(
&buf,
gfx.top_screen.borrow_mut().get_raw_framebuffer().ptr,
WIDTH,
HEIGHT,
);
gfx.flush_buffers();
gfx.swap_buffers();
@ -104,9 +102,8 @@ fn main() { @@ -104,9 +102,8 @@ fn main() {
// The 3DS' screens are 2 vertical LCD panels rotated by 90 degrees.
// As such, we'll need to write a "vertical" image to the framebuffer to have it displayed properly.
// This functions handles the rotation of an horizontal image to a vertical one.
fn rotate_image(img: &[u8], width: usize, height: usize) -> Vec<u8> {
let mut res = vec![0u8; img.len()];
// This functions rotates an horizontal image by 90 degrees to the right.
fn rotate_image_to_screen(src: &[u8], framebuf: *mut u8, width: usize, height: usize) {
for j in 0..height {
for i in 0..width {
// Y-coordinate of where to draw in the frame buffer
@ -121,9 +118,11 @@ fn rotate_image(img: &[u8], width: usize, height: usize) -> Vec<u8> { @@ -121,9 +118,11 @@ fn rotate_image(img: &[u8], width: usize, height: usize) -> Vec<u8> {
// Initial index of where to draw in the frame buffer based on y and x coordinates
let draw_index = (draw_x * height + draw_y) * 2; // This 2 stands for the number of bytes per pixel (16 bits)
res[draw_index] = img[read_index];
res[draw_index + 1] = img[read_index + 1];
unsafe {
let pixel_pointer = framebuf.offset(draw_index as isize);
*pixel_pointer = src[read_index];
*pixel_pointer.offset(1) = src[read_index + 1];
}
}
}
res
}

6
ctru-rs/src/error.rs

@ -21,7 +21,11 @@ impl Try for ResultCode { @@ -21,7 +21,11 @@ impl Try for ResultCode {
}
fn branch(self) -> ControlFlow<Self::Residual, Self::Output> {
if self.0 < 0 {
// Wait timeouts aren't counted as "failures" in libctru, but an unfinished task means unsafety for us.
// Luckily all summary cases are for system failures (except RS_SUCCESS).
// I don't know if there are any cases in libctru where a Result holds a "failing" summary but a "success" code, so we'll just check for both.
if ctru_sys::R_FAILED(self.0) || ctru_sys::R_SUMMARY(self.0) != ctru_sys::RS_SUCCESS as i32
{
ControlFlow::Break(self.into())
} else {
ControlFlow::Continue(())

33
ctru-rs/src/services/cam.rs

@ -704,12 +704,16 @@ pub trait Camera { @@ -704,12 +704,16 @@ pub trait Camera {
}
}
/// Requests the camera to take a picture and returns a vector containing the image bytes.
/// Requests the camera to take a picture and write it in a buffer.
///
/// # Errors
///
/// This will error if the camera is busy or if the timeout duration is reached.
///
/// # Panics
///
/// This function will panic if `buffer.len() < (width * height * 2)`.
///
/// # Arguments
///
/// * `width` - Width of the desired image
@ -717,10 +721,11 @@ pub trait Camera { @@ -717,10 +721,11 @@ pub trait Camera {
/// * `timeout` - Duration to wait for the image
fn take_picture(
&mut self,
buffer: &mut [u8],
width: u16,
height: u16,
timeout: Duration,
) -> crate::Result<Vec<u8>> {
) -> crate::Result<()> {
let transfer_unit = unsafe {
let mut buf_size = 0;
ResultCode(ctru_sys::CAMU_GetMaxBytes(
@ -731,10 +736,6 @@ pub trait Camera { @@ -731,10 +736,6 @@ pub trait Camera {
Ok::<u32, i32>(buf_size)
}?;
let screen_size = u32::from(width) * u32::from(height) * 2;
let mut buf = vec![0u8; usize::try_from(screen_size).unwrap()];
unsafe {
ResultCode(ctru_sys::CAMU_SetTransferBytes(
self.port_as_raw(),
@ -744,6 +745,11 @@ pub trait Camera { @@ -744,6 +745,11 @@ pub trait Camera {
))?;
};
let screen_size = u32::from(width) * u32::from(height) * 2;
if buffer.len() < screen_size as usize {
panic!("Provided buffer's length is shorter than the desired width and height matrix.")
}
unsafe {
ResultCode(ctru_sys::CAMU_Activate(self.camera_as_raw()))?;
ResultCode(ctru_sys::CAMU_ClearBuffer(self.port_as_raw()))?;
@ -754,7 +760,7 @@ pub trait Camera { @@ -754,7 +760,7 @@ pub trait Camera {
let mut completion_handle: Handle = 0;
ResultCode(ctru_sys::CAMU_SetReceiving(
&mut completion_handle,
buf.as_mut_ptr() as *mut ::libc::c_void,
buffer.as_mut_ptr() as *mut ::libc::c_void,
self.port_as_raw(),
screen_size,
transfer_unit.try_into().unwrap(),
@ -763,16 +769,21 @@ pub trait Camera { @@ -763,16 +769,21 @@ pub trait Camera {
}?;
unsafe {
ResultCode(ctru_sys::svcWaitSynchronization(
// Panicking without closing an SVC handle causes an ARM exception, we have to handle it carefully (TODO: SVC module)
let wait_result = ResultCode(ctru_sys::svcWaitSynchronization(
receive_event,
timeout.as_nanos().try_into().unwrap(),
))?;
));
// We close everything first, then we check for possible errors
ResultCode(ctru_sys::svcCloseHandle(receive_event));
ResultCode(ctru_sys::CAMU_StopCapture(self.port_as_raw()))?;
ResultCode(ctru_sys::svcCloseHandle(receive_event))?;
ResultCode(ctru_sys::CAMU_Activate(ctru_sys::SELECT_NONE))?;
wait_result?;
};
Ok(buf)
Ok(())
}
}

Loading…
Cancel
Save