diff options
author | Andy Wortman <ixineeringeverywhere@gmail.com> | 2019-07-27 20:07:05 -0700 |
---|---|---|
committer | Andy Wortman <ixineeringeverywhere@gmail.com> | 2019-07-27 20:07:05 -0700 |
commit | 144854e4b1a7ac38c5ddd2b0d45c495f491aa5dc (patch) | |
tree | 55306a36cfe8fef91a38496510acf34a771e582e | |
parent | 0d887779b8dee042999d04a29d4a095a3df93a6c (diff) |
significant rewrite for threaded qhy operation
-rw-r--r-- | .gitignore | 1 | ||||
-rw-r--r-- | Cargo.toml | 2 | ||||
-rw-r--r-- | src/main.rs | 172 | ||||
-rw-r--r-- | src/qhyccd/QHYCCDCam.rs | 70 | ||||
-rw-r--r-- | src/qhyccd/mod.rs | 388 |
5 files changed, 576 insertions, 57 deletions
@@ -1,2 +1,3 @@ /target **/*.rs.bk +/sdks @@ -7,3 +7,5 @@ build = "build.rs" [dependencies] "png" = "0.13.2" +"crossbeam" = "0.7.2" +"crossbeam-channel" = "0.3.9" diff --git a/src/main.rs b/src/main.rs index 7275c96..dc70da6 100644 --- a/src/main.rs +++ b/src/main.rs @@ -7,20 +7,181 @@ mod asicam; mod qhyccd; +#[macro_use] +extern crate crossbeam_channel; + +use crossbeam_channel::{Sender, Receiver}; +use crossbeam_channel::unbounded; + +use std::time::Duration; + use crate::asicam::ASICamera2::{ControlType, ImageType}; use crate::asicam::Camera; +use crate::qhyccd::QHYResponse; +use crate::qhyccd::QHYMessage; + +use std::path::Path; +use std::fs::File; +use std::io::BufWriter; + +use png::HasParameters; + +fn record_image(data: &[u8], dimensions: Dimensions, target: &'static str, image_id: u32) { + let path_string = format!("{}_{}.png", target, image_id); + println!("writing {}..", path_string); + let dest = Path::new(&path_string); + let file = File::create(dest).unwrap(); + let ref mut w = BufWriter::new(file); + let mut encoder = png::Encoder::new(w, dimensions.width, dimensions.height); + let color_type = if dimensions.channels == 3 { + png::ColorType::RGB + } else if dimensions.channels == 1 { + png::ColorType::Grayscale + } else { panic!("Unsupported channel count: {}", dimensions.channels); }; + + let bitness = if dimensions.bpp == 8 { + png::BitDepth::Eight + } else if dimensions.bpp == 16 { + png::BitDepth::Sixteen + } else { + panic!("Unknwon bitness: {}", dimensions.bpp); + }; + encoder.set(color_type).set(bitness); + let mut writer = encoder.write_header().unwrap(); + writer.write_image_data(data).unwrap(); + println!("image written!"); +} + fn main() { let test = true; -// println!("Doing qhy..."); -// operate_qhy(test); - println!("Doing asi..."); - operate_asi(test); + println!("Doing qhy..."); + let (image_writer, image_reader) = unbounded(); + let (frame_sender, free_frames) = unbounded(); + + std::thread::spawn(move || { + loop { + select! { + recv(image_reader) -> msg => { + match msg { + Ok(ImageInfo { mut data, dimensions, target, image_id }) => { + qhyccd::fix_channels_and_endianness(data.as_mut_slice()); + record_image(data.as_slice(), dimensions, target, image_id); + println!("pretend i wrote image {}_{}", target, image_id); + frame_sender.send(data).unwrap(); + } + Err(RecvError) => { + // something in the application has crashed. time 2 die + return; + } + } + } + } + } + }); + + operate_qhy("dark_gain_4000", None, free_frames, image_writer); +// println!("Doing asi..."); +// operate_asi(test); +} + +#[derive(Debug, Copy, Clone)] +struct Dimensions { + width: u32, + height: u32, + bpp: u8, + channels: u8, } -fn operate_qhy(test: bool) { +impl Dimensions { + pub fn new(width: u32, height: u32, bpp: u8, channels: u8) -> Self { + Dimensions { width, height, bpp, channels } + } +} + +struct ImageInfo { + data: Vec<u8>, + dimensions: Dimensions, + target: &'static str, + image_id: u32 +} + +enum ImageWriter { + FrameReady(Vec<u8>, Dimensions, &'static str, u32) +} + +fn operate_qhy(target: &'static str, count: Option<u32>, mut free_frames: Receiver<Vec<u8>>, mut image_writer: Sender<ImageInfo>) { use crate::qhyccd::Control; println!("Operating on qhy camera ... or i'll die trying"); + let (mut camera_rx, mut camera_tx) = qhyccd::connect(0).unwrap(); + + let mut image_id = 0u32; + let mut settings_copy = qhyccd::Settings::default(); + + camera_tx.send(QHYMessage::SetControl(Control::Exposure, 20000000.0)).unwrap(); + camera_tx.send(QHYMessage::SetControl(Control::Gain, 4000.0)).unwrap(); + camera_tx.send(QHYMessage::SetControl(Control::Offset, 00.0)).unwrap(); + camera_tx.send(QHYMessage::SetControl(Control::Cooler, 27.0)).unwrap(); + camera_tx.send(QHYMessage::SetControl(Control::USBTraffic, 60.0)).unwrap(); + camera_tx.send(QHYMessage::SetControl(Control::Color, 0.0)).unwrap(); // disable color +// camera.set_roi(0, 0, 1920 * 2, 1080 * 2).unwrap(); +// println!("Gain: {:?}", camera.get_param_limits(Control::ManulPwm)); +// println!("cur pwm ???: {}", camera.get_param(Control::CurPWM)); + camera_tx.send(QHYMessage::BeginCapture).unwrap(); + + loop { + select! { + recv(free_frames) -> msg => { + match msg { + Ok(buffer) => { + camera_tx.send(QHYMessage::FrameAvailable(buffer)).unwrap(); + }, + Err(RecvError) => { + // disconnected. nothing we can do but to.. + return; + } + } + }, + recv(camera_rx) -> msg => { + match msg { + Ok(QHYResponse::CurrentControlValue(control, value)) => { + println!("Control {:?} value: {}", control, value); + } + Ok(QHYResponse::InitializationError) => { + println!("Failed to initialize camera, exiting..."); + return; + } + Ok(QHYResponse::Shutdown) => { + return; + } + Ok(QHYResponse::UpdatedSettings(settings)) => { + settings_copy = settings; + } + Ok(QHYResponse::Data(data, dimensions)) => { + image_writer.send(ImageInfo { data, dimensions, target, image_id: image_id }).unwrap(); + // images.log(target, image_id, settings_copy); + image_id += 1; + if Some(image_id) == count { + camera_tx.send(QHYMessage::Shutdown); + } + } + Ok(QHYResponse::DroppedFrame) => { + println!("Dropped frame..."); + } + Err(RecvError) => { + // camera is closed. hopefully it just shut down? but maybe crashed!! + return; + } + } + } + default(Duration::from_millis(2000)) => { + camera_tx.send( + QHYMessage::QueryControl(Control::CurTemp) + ); + } + } + } + /* let t = std::thread::spawn(move || { let mut camera = qhyccd::acquire(0).unwrap(); camera.set_defaults().unwrap(); @@ -52,6 +213,7 @@ fn operate_qhy(test: bool) { camera.release().unwrap(); }); t.join(); + */ } fn operate_asi(test: bool) { diff --git a/src/qhyccd/QHYCCDCam.rs b/src/qhyccd/QHYCCDCam.rs index c0a0775..2f6b4fb 100644 --- a/src/qhyccd/QHYCCDCam.rs +++ b/src/qhyccd/QHYCCDCam.rs @@ -24,7 +24,7 @@ impl From<u32> for QHYResult { } #[repr(u32)] -#[derive(Copy, Clone, Debug)] +#[derive(Copy, Clone, Debug, PartialEq, Eq)] pub enum Control { Brightness = 0, // !< image brightness Contrast = 1, //1 image contrast @@ -84,6 +84,74 @@ pub enum Control { OutputDataAlignment = 55 //55 } +impl Control { + pub fn requires_reset(&self) -> bool { + match self { + Control::Brightness + | Control::Contrast + | Control::CONTROL_WBR + | Control::CONTROL_WBB + | Control::CONTROL_WBG + | Control::Gamma + | Control::Gain + | Control::Offset + | Control::Exposure + | Control::Speed + | Control::TransferBit + | Control::Channels + | Control::Bin1x1Mode + | Control::Bin2x2Mode + | Control::Bin3x3Mode + | Control::Bin4x4Mode + | Control::USBTraffic => { + true + } + | Control::CurTemp + | Control::CurPWM + | Control::ManulPwm + | Control::CFWPort + | Control::Cooler + | Control::St4port + | Control::Color + | Control::CAM_MECHANICALSHUTTER + | Control::CAM_TRIGER_INTERFACE + | Control::CAM_TECOVERPROTECT_INTERFACE + | Control::CAM_SINGNALCLAMP_INTERFACE + | Control::CAM_FINETONE_INTERFACE + | Control::CAM_SHUTTERMOTORHEATING_INTERFACE + | Control::CAM_CALIBRATEFPN_INTERFACE + | Control::CAM_CHIPTEMPERATURESENSOR_INTERFACE + | Control::CAM_USBREADOUTSLOWEST_INTERFACE + | Control::CAM_8BITS + | Control::CAM_16BITS + | Control::CAM_GPS + | Control::CAM_IGNOREOVERSCAN_INTERFACE + | Control::QHYCCD_3A_AUTOBALANCE + | Control::QHYCCD_3A_AUTOEXPOSURE + | Control::QHYCCD_3A_AUTOFOCUS + | Control::CONTROL_AMPV + | Control::CONTROL_VCAM + | Control::CAM_VIEW_MODE + | Control::CONTROL_CFWSLOTSNUM + | Control::IS_EXPOSING_DONE + | Control::ScreenStretchB + | Control::ScreenStretchW + | Control::CONTROL_DDR + | Control::CAM_LIGHT_PERFORMANCE_MODE + | Control::CAM_QHY5II_GUIDE_MODE + | Control::DDR_BUFFER_CAPACITY + | Control::DDR_BUFFER_READ_THRESHOLD + | Control::DefaultOffset + | Control::OutputDataActualBits + | Control::OutputDataAlignment => { + false + } + _ => { false } + } + } +} + + #[repr(u32)] #[derive(Copy, Clone, Debug)] pub enum Bayer diff --git a/src/qhyccd/mod.rs b/src/qhyccd/mod.rs index b50ba3a..12630d6 100644 --- a/src/qhyccd/mod.rs +++ b/src/qhyccd/mod.rs @@ -12,17 +12,83 @@ use std::fs::File; use std::io::BufWriter; use std::path::Path; +use std::time::Duration; +use crossbeam_channel::unbounded; +use crossbeam_channel::{Sender, Receiver, TryRecvError}; +use crossbeam_channel::select; + use png::HasParameters; -unsafe impl Send for Camera { } +use crate::Dimensions; + +// unsafe impl Send for Camera { } #[derive(Debug)] pub struct Camera { - imagew: u32, - imageh: u32, + buffer: Vec<Vec<u8>>, + frame_size: usize, + handle: *mut os::raw::c_void, + settings: Settings, +} + +#[derive(Debug, Default, Copy, Clone)] +pub struct Settings { + exposure: u64, + brightness: u32, + contrast: u32, + control_wbr: u32, + control_wbb: u32, + control_wbg: u32, + gamma: u32, + gain: u32, + offset: u32, + speed: u32, + transfer_bit: u32, + usb_traffic: u32, + row_noise_re: bool, + cur_temp: f64, + cur_pwm: f64, + manual_pwm: f64, + cfw_port: f64, + cooler: bool, + st4_port: bool, + color: bool, + bin: u8, bpp: u8, channels: u8, - bin: u8, - handle: *mut os::raw::c_void + // width, height + image_roi: (u32, u32), + image_xy: (u32, u32), +} + +impl Settings { + pub fn frame_size(&self) -> usize { + let pixels = (self.image_roi.0 as usize) * (self.image_roi.1 as usize); + let bytes_per_pixel = (self.bpp as usize / 8) * (self.channels as usize); + pixels * bytes_per_pixel + } + + pub fn update_param(&mut self, control: Control, value: f64) { + match control { + Control::Brightness => { self.brightness = value as u32; } + Control::Contrast => { self.contrast = value as u32; } + Control::CONTROL_WBR => { self.control_wbr = value as u32; } + Control::CONTROL_WBB => { self.control_wbb = value as u32; } + Control::CONTROL_WBG => { self.control_wbg = value as u32; } + Control::Gamma => { self.gamma = value as u32; } + Control::Gain => { self.gain = value as u32; } + Control::Offset => { self.offset = value as u32; } + Control::Exposure => { self.exposure = value as u64; } + Control::TransferBit => { self.transfer_bit = value as u32; } + Control::Channels => { self.channels = value as u8; } + Control::USBTraffic => { self.usb_traffic = value as u32; } + Control::RowNoiseRe => { self.row_noise_re = value as u32 == 1; } + Control::CurTemp => { self.cur_temp = value; } + Control::CurPWM => { self.cur_pwm = value; } + Control::ManulPwm => { self.manual_pwm = value; } + Control::Cooler => { self.cooler = value as u32 == 1; } + _ => { } + } + } } #[derive(Debug, Copy, Clone)] @@ -45,7 +111,7 @@ fn check(result: os::raw::c_int) -> Result<()> { static mut INITIALIZED: bool = false; -fn fix_channels(dataslice: &mut [u8]) { +pub fn fix_channels_and_endianness(dataslice: &mut [u8]) { for i in 0..(dataslice.len() / 6) { let (b_low, b_high) = (dataslice[i * 6], dataslice[i * 6 + 1]); let tmp2 = dataslice[i * 6 + 1]; @@ -60,7 +126,139 @@ fn fix_channels(dataslice: &mut [u8]) { } } -pub fn acquire(camera_idx: i32) -> Result<Camera> { +pub fn fix_endianness(dataslice: &mut [u8]) { + for i in 0..(dataslice.len() / 2) { + let (low, high) = (dataslice[i * 2], dataslice[i * 2 + 1]); + dataslice[i * 2 + 0] = high; + dataslice[i * 2 + 1] = low; + } +} + + +pub fn connect(camera_idx: i32) -> Result<(Receiver<QHYResponse>, Sender<QHYMessage>)> { + let (response_sender, response_receiver) = unbounded(); + let (message_sender, message_receiver) = unbounded(); + + std::thread::spawn(move || { + let mut camera = match acquire(camera_idx) { + Ok(camera) => camera, + Err(e) => { + response_sender.send(QHYResponse::InitializationError).unwrap(); + return; + }, + }; + + camera.set_defaults().unwrap(); + + // sleep for 2ms between waiting for messages and reading frames. This introduces an + // artificial cap of 500fps, but I don't own a camera that can hit that. + let SLEEP_TIME = 2u64; + let mut exposing = false; + let mut counter = 0u64; + + loop { + match message_receiver.try_recv() { + Ok(QHYMessage::Shutdown) => { + println!("Got shutdown request, closing camera..."); + return; + } + Ok(QHYMessage::FrameAvailable(data)) => { + if data.len() == camera.settings.frame_size() { + camera.buffer.push(data); + } else { + // otherwise the writer finished handling a frame from an old size, + // and the array is incorrectly sized for current settings. + // so drop the buffer and free that memory. + drop(data); + } + } + Ok(QHYMessage::BeginCapture) => { + counter = camera.settings.exposure; + println!("Beginning capture"); + camera.begin_exposure().expect("can begin exposures"); + exposing = true; + } + Ok(QHYMessage::StopCapture) => { + counter = 0; + camera.cancel_exposure().expect("can cancel exposures"); + exposing = false; + } + Ok(QHYMessage::SetControl(control, value)) => { + if control == Control::Color { + // overload Control::Color to signal if we want to switch to + // debayer-disabled "mono" + let mono_mode = value == 0.0; + camera.set_color_mode(mono_mode); + // yes, this requires reset. + counter = 0; + camera.cancel_exposure().expect("can cancel exposures"); + exposing = false; + } else { + if control.requires_reset() { + counter = 0; + camera.cancel_exposure().expect("can cancel exposures"); + exposing = false; + } + camera.set_control(control, value).expect("can set camera controls"); + } + response_sender.send(QHYResponse::UpdatedSettings(camera.settings.clone())).expect("can send responses to main thread"); + } + Ok(QHYMessage::QueryControl(control)) => { + let value = camera.get_control(control); + camera.settings.update_param(control, value); + response_sender.send(QHYResponse::CurrentControlValue(control, value)).expect("can send control value"); + } + Err(TryRecvError::Empty) => { + // this is fine. nothing new to do. + }, + Err(TryRecvError::Disconnected) => { + // uh oh. main thread crashed? all we can do is exit. + return; + } + } + + if counter == 0 && exposing { + if let Some(data) = camera.get_frame() { + let (data, width, height, bpp, channels) = camera.read_frame(data).expect("can read frames from camera"); + counter = camera.settings.exposure; + camera.begin_exposure().expect("can begin exposures"); + response_sender.send(QHYResponse::Data(data, Dimensions::new(width, height, bpp, channels))).unwrap(); + } else { + // no frame ready in the buffer! we can't actually read the image... + counter = camera.settings.exposure; + camera.begin_exposure().expect("can begin exposures"); + response_sender.send(QHYResponse::DroppedFrame).unwrap(); + } + } + + counter = counter.saturating_sub(SLEEP_TIME * 1000); + std::thread::sleep(Duration::from_millis(SLEEP_TIME)); + } + + }); + + Ok((response_receiver, message_sender)) +} + +pub enum QHYResponse { + InitializationError, + Data(Vec<u8>, Dimensions), + DroppedFrame, + Shutdown, + UpdatedSettings(Settings), + CurrentControlValue(Control, f64), +} + +pub enum QHYMessage { + FrameAvailable(Vec<u8>), + BeginCapture, + StopCapture, + QueryControl(Control), + SetControl(Control, f64), + Shutdown, +} + +fn acquire(camera_idx: i32) -> Result<Camera> { unsafe { if !INITIALIZED { println!("Initializing QHYCCDResource"); @@ -87,29 +285,35 @@ pub fn acquire(camera_idx: i32) -> Result<Camera> { check(QHYCCDCam::InitQHYCCD(handle))?; check(QHYCCDCam::CancelQHYCCDExposingAndReadout(handle))?; Ok(Camera { - imagew: 0, - imageh: 0, - bpp: 16, - bin: 1, - channels: 3, - handle: handle + buffer: vec![], + frame_size: 0, + handle: handle, + settings: Settings::default() }) } } impl Camera { + pub fn get_frame(&mut self) -> Option<Vec<u8>> { + if self.frame_size != self.image_buf_size() { + // something has happened that requires a new buffer + self.resize_buffer(); + } + + self.buffer.pop() + } pub fn image_buf_size(&self) -> usize { - (self.imagew as usize) * (self.imageh as usize) * (self.bpp as usize / 8) * (self.channels as usize) + self.settings.frame_size() } - pub fn set_exposure_ms(&self, ms: u32) -> Result<()> { - self.set_param(Control::Exposure, (ms as f64) * 1000.0) + pub fn set_exposure_ms(&mut self, ms: u32) -> Result<()> { + self.set_control(Control::Exposure, (ms as f64) * 1000.0) } pub fn set_target_temp(&self, temp: f64) -> Result<()> { unsafe { check(QHYCCDCam::ControlQHYCCDTemp(self.handle, temp)) } } - pub fn has_param(&self, control: Control) -> bool { + pub fn has_control(&self, control: Control) -> bool { unsafe { match QHYResult::from(QHYCCDCam::IsQHYCCDControlAvailable(self.handle, control as i32) as u32) { QHYResult::QHYCCD_ERROR => { @@ -124,19 +328,21 @@ impl Camera { } } } - pub fn set_param(&self, control: Control, value: f64) -> Result<()> { + pub fn set_control(&mut self, control: Control, value: f64) -> Result<()> { unsafe { - if self.has_param(control) { - check(QHYCCDCam::SetQHYCCDParam(self.handle, control as i32, value)) + if self.has_control(control) { + check(QHYCCDCam::SetQHYCCDParam(self.handle, control as i32, value))?; + self.settings.update_param(control, value); + Ok(()) } else { println!("Cannot set control: {:?}", control); Ok(()) } } } - pub fn get_param_limits(&self, control: Control) -> Result<(f64, f64, f64)> { + pub fn get_control_limits(&self, control: Control) -> Result<(f64, f64, f64)> { unsafe { - if self.has_param(control) { + if self.has_control(control) { let mut min = 0f64; let mut max = 0f64; let mut step = 0f64; @@ -154,7 +360,7 @@ impl Camera { } } - pub fn get_param(&self, control: Control) -> f64 { + pub fn get_control(&self, control: Control) -> f64 { unsafe { QHYCCDCam::GetQHYCCDParam(self.handle, control as i32) } @@ -164,16 +370,34 @@ impl Camera { check(QHYCCDCam::CloseQHYCCD(self.handle)) } } + pub fn set_color_mode(&mut self, mono: bool) -> Result<()> { + // TODO: handle mono cameras correctly + if mono { + unsafe { + check(QHYCCDCam::SetQHYCCDDebayerOnOff(self.handle, 0))?; + } + self.set_control(Control::CONTROL_WBR, 1000.0)?; + self.set_control(Control::CONTROL_WBG, 1000.0)?; + self.set_control(Control::CONTROL_WBB, 1000.0)?; + self.settings.channels = 1; + } else { + unsafe { + check(QHYCCDCam::SetQHYCCDDebayerOnOff(self.handle, 1))?; + } + self.set_control(Control::CONTROL_WBR, 1000.0)?; + self.set_control(Control::CONTROL_WBG, 1000.0)?; + self.set_control(Control::CONTROL_WBB, 1000.0)?; + self.settings.channels = 3; + } + Ok(()) + } pub fn set_defaults(&mut self) -> Result<()> { unsafe { println!("Hey wait gotta get dimensions first"); let ((chipw, chiph), (imagew, imageh), (pixelw, pixelh), bpp) = self.get_dimensions()?; match QHYCCDCam::IsQHYCCDControlAvailable(self.handle, Control::Color as i32) { 1 | 2 | 3 | 4 => { - check(QHYCCDCam::SetQHYCCDDebayerOnOff(self.handle, 1))?; - self.set_param(Control::CONTROL_WBR, 1000.0)?; - self.set_param(Control::CONTROL_WBG, 1000.0)?; - self.set_param(Control::CONTROL_WBB, 1000.0)?; + self.set_color_mode(false)?; }, a @ _ => { println!("unexpected response when querying color setting: {}", a); @@ -182,34 +406,35 @@ impl Camera { } self.set_roi(0, 0, imagew, imageh)?; self.set_bin_mode(1)?; - if self.has_param(Control::TransferBit) { + if self.has_control(Control::TransferBit) { check(QHYCCDCam::SetQHYCCDBitsMode(self.handle, 16))?; - self.bpp = 16; + self.settings.bpp = 16; } + println!("roi set to {} x {} ???", imagew, imageh); Ok(()) } } pub fn set_roi(&mut self, x: u32, y: u32, w: u32, h: u32) -> Result<()> { unsafe { - check(QHYCCDCam::SetQHYCCDResolution(self.handle, x, y, w, h)); - self.imageh = h; - self.imagew = w; + check(QHYCCDCam::SetQHYCCDResolution(self.handle, x, y, w, h))?; + self.settings.image_roi = (w, h); + self.settings.image_xy = (x, y); Ok(()) } } pub fn set_bin_mode(&mut self, bin: u8) -> Result<()> { match bin { - 1 => if !self.has_param(Control::Bin1x1Mode) { return Err(CameraError::InvalidControl); } - 2 => if !self.has_param(Control::Bin2x2Mode) { return Err(CameraError::InvalidControl); } - 3 => if !self.has_param(Control::Bin3x3Mode) { return Err(CameraError::InvalidControl); } - 4 => if !self.has_param(Control::Bin4x4Mode) { return Err(CameraError::InvalidControl); } + 1 => if !self.has_control(Control::Bin1x1Mode) { return Err(CameraError::InvalidControl); } + 2 => if !self.has_control(Control::Bin2x2Mode) { return Err(CameraError::InvalidControl); } + 3 => if !self.has_control(Control::Bin3x3Mode) { return Err(CameraError::InvalidControl); } + 4 => if !self.has_control(Control::Bin4x4Mode) { return Err(CameraError::InvalidControl); } _ => { return Err(CameraError::InvalidControl); } } unsafe { check(QHYCCDCam::SetQHYCCDBinMode(self.handle, bin as i32, bin as i32))?; - self.bin = bin; + self.settings.bin = bin; Ok(()) } } @@ -238,9 +463,65 @@ impl Camera { Ok(()) } + pub fn cancel_exposure(&self) -> Result<()> { + unsafe { + check(QHYCCDCam::CancelQHYCCDExposingAndReadout(self.handle)) + } + } + + pub fn begin_exposure(&self) -> Result<()> { + let result = unsafe { QHYCCDCam::ExpQHYCCDSingleFrame(self.handle) }; + match QHYCCDCam::QHYResult::from(result as u32) { + QHYResult::QHYCCD_SUCCESS => { +// println!("Didn't expect this result..."); + Ok(()) + }, + QHYResult::QHYCCD_READ_DIRECTLY => { +// println!("Exp complete, example sleeps so i'll sleep too"); + Ok(()) + }, + QHYResult::QHYCCD_DELAY_200MS => { + println!("Sleeping 200ms... but not actually, bout to have a bug :):)))"); + Ok(()) + }, + a @ _ =>{ + println!("exp err: {:?}", a); + return Err(CameraError::QHYError); + } + } + } + + fn resize_buffer(&mut self) { + println!("Resizing buffer to 3x{}", self.settings.frame_size()); + self.frame_size = self.settings.frame_size(); + self.buffer = vec![ + vec![0u8; self.frame_size], + vec![0u8; self.frame_size], + vec![0u8; self.frame_size], + ]; + } + + pub fn read_frame(&self, mut buf: Vec<u8>) -> Result<(Vec<u8>, u32, u32, u8, u8)> { + let mut castediw = 0i32; + let mut castedih = 0i32; + let mut castedbpp = 0i32; + let mut channels = 0i32; + println!("Getting data..."); + unsafe { + use std::time::{SystemTime, UNIX_EPOCH}; + let start = SystemTime::now().duration_since(UNIX_EPOCH).unwrap(); + let start = start.as_secs() * 1000 + (start.subsec_nanos() as u64) / 1000000; + check(QHYCCDCam::GetQHYCCDSingleFrame(self.handle, &mut castediw, &mut castedih, &mut castedbpp, &mut channels, buf.as_mut_ptr()))?; + let end = SystemTime::now().duration_since(UNIX_EPOCH).unwrap(); + let end = end.as_secs() * 1000 + (end.subsec_nanos() as u64) / 1000000; + println!("camera record time: {}ms", end - start); + } + Ok((buf, castediw as u32, castedih as u32, castedbpp as u8, channels as u8)) + } + /* pub fn take_image_live(&self, path: &str) -> Result<()> { unsafe { - let exposure_duration = self.get_param(Control::Exposure); + let exposure_duration = self.get_control(Control::Exposure); let exposure_ms = exposure_duration / 1000.0; println!("Exposure duration: {}", exposure_ms); @@ -260,19 +541,19 @@ impl Camera { let mut bpp: i32 = self.bpp as i32; let mut channels: i32 = self.channels as i32; + let frame = match frame_rx.recv() { + Ok(frame) => frame, + Err(signal) => { + return Err(CollectionError::BufferClosed); + } + }; // println!("w {} h {} bpp {} channels {}", imagew, imageh, bpp, channels); - match check(QHYCCDCam::GetQHYCCDLiveFrame(self.handle, &mut imagew, &mut imageh, &mut bpp, &mut channels, data)) { + match check(QHYCCDCam::GetQHYCCDLiveFrame(self.handle, &mut imagew, &mut imageh, &mut bpp, &mut channels, data.as_mut_ptr())) { Ok(()) => { + processor.send(Ok(frame)) + } println!("Ok, guess we got it?"); - let mut dataslice: &mut [u8] = - unsafe { - std::slice::from_raw_parts_mut( - data, - bufsize as usize - ) - }; - //fix_channels(dataslice); let dest = Path::new(path); @@ -303,12 +584,16 @@ impl Camera { dealloc(data as *mut u8, data_layout); Ok(()) + + pub fn begin_exposure(&self) -> Result<()> { + + } } } pub fn take_image(&self, path: &str) -> Result<()> { unsafe { - let exposure_duration = self.get_param(Control::Exposure); + let exposure_duration = self.get_control(Control::Exposure); let exposure_ms = exposure_duration / 1000.0; println!("Exposure duration: {}", exposure_ms); let result = QHYCCDCam::ExpQHYCCDSingleFrame(self.handle); @@ -362,13 +647,13 @@ impl Camera { let data_layout = Layout::from_size_align(bufsize as usize, 8).unwrap(); let data = alloc(data_layout); - let mut counter: i64 = (self.get_param(Control::Exposure) as u64 / 1000) as i64; + let mut counter: i64 = (self.get_control(Control::Exposure) as u64 / 1000) as i64; while counter > 0 { println!("I think there's about {}ms remaining", counter); println!("You think there's about {}ms remaining", self.get_exposure_remaining()); std::thread::sleep(std::time::Duration::from_millis(500)); - println!("Camera temp is currently: {}", self.get_param(Control::CurTemp)); + println!("Camera temp is currently: {}", self.get_control(Control::CurTemp)); counter -= 500; } @@ -390,7 +675,7 @@ impl Camera { encoder.set(png::ColorType::RGB).set(png::BitDepth::Sixteen); // crazy theory, endianness might be wrong... // so flip the bytes first - let mut dataslice: &mut [u8] = + let dataslice: &mut [u8] = unsafe { std::slice::from_raw_parts_mut( data, @@ -418,6 +703,7 @@ impl Camera { Ok(()) } } +*/ pub fn get_overscan_area(&self) -> Result<(u32, u32, u32, u32)> { unsafe { let mut startX: i32 = 0; |