diff options
Diffstat (limited to 'src/qhyccd/mod.rs')
-rw-r--r-- | src/qhyccd/mod.rs | 301 |
1 files changed, 301 insertions, 0 deletions
diff --git a/src/qhyccd/mod.rs b/src/qhyccd/mod.rs new file mode 100644 index 0000000..192b943 --- /dev/null +++ b/src/qhyccd/mod.rs @@ -0,0 +1,301 @@ +pub mod QHYCCDCam; + +pub use self::QHYCCDCam::Control; + +use self::QHYCCDCam::*; + +use std::alloc::{alloc, dealloc, Layout}; +use std::collections::HashMap; +use std::ffi::CStr; +use std::os; +use std::fs::File; +use std::io::BufWriter; +use std::path::Path; + +use png::HasParameters; + +#[derive(Debug)] +pub struct Camera { + handle: *mut os::raw::c_void +} + +#[derive(Debug, Copy, Clone)] +pub enum CameraError { + QHYError, // unspecified error from the qhy sdk + InvalidControl +} + +type Result<T> = std::result::Result<T, CameraError>; + +fn check(result: os::raw::c_int) -> Result<()> { + match QHYResult::from(result as u32) { + QHYResult::QHYCCD_SUCCESS => Ok(()), + QHYResult::QHYCCD_ERROR => Err(CameraError::QHYError), + a @ _ => { + panic!("Unexpected result code from qhy sdk: {:?}", a); + } + } +} + +static mut INITIALIZED: bool = false; + +pub fn acquire(camera_idx: i32) -> Result<Camera> { + unsafe { + if !INITIALIZED { + println!("Initializing QHYCCDResource"); + check(QHYCCDCam::InitQHYCCDResource())?; + INITIALIZED = true; + } + let cameracount = QHYCCDCam::ScanQHYCCD(); + println!("Detected {} cameras", cameracount); + if camera_idx >= cameracount { + panic!("Camera id is invalid (detected {} cameras)", cameracount); + } + + let mut id_space: [os::raw::c_char; 32] = [0; 32]; + check(QHYCCDCam::GetQHYCCDId(camera_idx, id_space.as_mut_ptr()))?; + println!("Got camera id: {:?}", id_space); + println!("One sec, trying again..."); + println!("How's this: {}", CStr::from_ptr(id_space.as_ptr()).to_str().unwrap()); + let handle: *mut os::raw::c_void = QHYCCDCam::OpenQHYCCD(id_space.as_mut_ptr()); + if handle == std::ptr::null_mut() { + println!("Failed to open the device"); + return Err(CameraError::QHYError); + } + check(QHYCCDCam::SetQHYCCDStreamMode(handle, 0))?; // 0 means single frame mode... + check(QHYCCDCam::InitQHYCCD(handle))?; + Ok(Camera { + handle: handle + }) + } +} + +impl Camera { + pub fn set_exposure_ms(&self, ms: u32) -> Result<()> { + self.set_param(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 { + unsafe { + match QHYResult::from(QHYCCDCam::IsQHYCCDControlAvailable(self.handle, control as i32) as u32) { + QHYResult::QHYCCD_ERROR => { + false + }, + QHYResult::QHYCCD_SUCCESS => { + true + } + a @ _ => { + panic!("Unexpected response when querying if control '{:?}' is available: {:?}", control, a); + } + } + } + } + pub fn set_param(&self, control: Control, value: f64) -> Result<()> { + unsafe { + if self.has_param(control) { + check(QHYCCDCam::SetQHYCCDParam(self.handle, control as i32, value)) + } else { + println!("Cannot set control: {:?}", control); + Ok(()) + } + } + } + pub fn get_param(&self, control: Control) -> f64 { + unsafe { + QHYCCDCam::GetQHYCCDParam(self.handle, control as i32) + } + } + pub fn release(self) -> Result<()> { + unsafe { + check(QHYCCDCam::CloseQHYCCD(self.handle)) + } + } + pub fn set_defaults(&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, 20.0)?; + self.set_param(Control::CONTROL_WBG, 20.0)?; + self.set_param(Control::CONTROL_WBB, 20.0)?; + }, + a @ _ => { + println!("unexpected response when querying color setting: {}", a); + return Err(CameraError::QHYError) + } + } + check(QHYCCDCam::SetQHYCCDResolution(self.handle, 0, 0, imagew, imageh))?; + check(QHYCCDCam::SetQHYCCDBinMode(self.handle, 1, 1))?; + if self.has_param(Control::TransferBit) { + check(QHYCCDCam::SetQHYCCDBitsMode(self.handle, 16))?; + } + Ok(()) + } + } + + pub fn set_bin_mode(&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); } + _ => { return Err(CameraError::InvalidControl); } + } + unsafe { + check(QHYCCDCam::SetQHYCCDBinMode(self.handle, bin as i32, bin as i32)) + } + } + + pub fn get_exposure_remaining(&self) -> u32 { + unsafe { + QHYCCDCam::GetQHYCCDExposureRemaining(self.handle) + } + } + + pub fn display_camera_dimensions(&self) -> Result<()> { + let (overscan_start_X, overscan_start_Y, overscan_size_X, overscan_size_Y) = self.get_overscan_area()?; + println!("Overscan area:"); + println!(" startX x startY : {:05} x {:05}", overscan_start_X, overscan_start_Y); + println!(" sizeX x sizeY : {:05} x {:05}", overscan_size_X, overscan_size_Y); + let (effective_start_X, effective_start_Y, effective_size_X, effective_size_Y) = self.get_effective_area()?; + println!("Effective area:"); + println!(" startX x startY : {:05} x {:05}", effective_start_X, effective_start_Y); + println!(" sizeX x sizeY : {:05} x {:05}", effective_size_X, effective_size_Y); + let ((chipw, chiph), (imagew, imageh), (pixelw, pixelh), bpp) = self.get_dimensions()?; + println!("Chip dimensions:"); + println!("Chip size (w/h): {:05} x {:05} [mm]", chipw, chiph); + println!("Pixel size (w/h): {:05} x {:05} [um]", pixelw, pixelh); + println!("Image size (w/h): {:05} x {:05} [pixels]", imagew, imageh); + println!(" bpp: {}", bpp); + Ok(()) + } + + pub fn take_image(&self, path: &str) -> Result<()> { + unsafe { + let exposure_duration = self.get_param(Control::Exposure); + let exposure_ms = exposure_duration / 1000.0; + println!("Exposure duration: {}", exposure_ms); + let result = QHYCCDCam::ExpQHYCCDSingleFrame(self.handle); + match QHYCCDCam::QHYResult::from(result as u32) { + QHYResult::QHYCCD_SUCCESS => { + println!("Didn't expect this result..."); + std::thread::sleep(std::time::Duration::from_millis(1000)); + }, + QHYResult::QHYCCD_READ_DIRECTLY => { + println!("Exp complete, example sleeps so i'll sleep too"); + std::thread::sleep(std::time::Duration::from_millis(1000)); + }, + a @ _ =>{ + println!("exp err: {:?}", a); + return Err(CameraError::QHYError); + } + } + + let bufsize = QHYCCDCam::GetQHYCCDMemLength(self.handle); + println!("Ok, we'll need {} bytes...", bufsize); + 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; + + while counter > 0 { + println!("I think there's about {}ms remaining", counter); + std::thread::sleep(std::time::Duration::from_millis(500)); + println!("Camera temp is currently: {}", self.get_param(Control::CurTemp)); + counter -= 500; + } + + let mut castediw = 0i32; + let mut castedih = 0i32; + let mut castedbpp = 0i32; + let mut channels = 0; + println!("Getting data..."); + check(QHYCCDCam::GetQHYCCDSingleFrame(self.handle, &mut castediw, &mut castedih, &mut castedbpp, &mut channels, data))?; + println!("Ok, guess we got it?"); + println!("image: {} x {}", castediw, castedih); + println!("bpp: {}", castedbpp); + println!("channels: {}", channels); + + let dest = Path::new(path); + let file = File::create(dest).unwrap(); + let ref mut w = BufWriter::new(file); + let mut encoder = png::Encoder::new(w, castediw as u32, castedih as u32); + encoder.set(png::ColorType::RGB).set(png::BitDepth::Sixteen); + let mut writer = encoder.write_header().unwrap(); + writer.write_image_data( + unsafe { + std::slice::from_raw_parts( + data, + bufsize as usize + ) + } + ).unwrap(); + dealloc(data as *mut u8, data_layout); + Ok(()) + } + } + pub fn get_overscan_area(&self) -> Result<(u32, u32, u32, u32)> { + unsafe { + let mut startX: i32 = 0; + let mut startY: i32 = 0; + let mut sizeX: i32 = 0; + let mut sizeY: i32 = 0; + check(QHYCCDCam::GetQHYCCDOverScanArea( + self.handle, + &mut startX as *mut os::raw::c_int, + &mut startY as *mut os::raw::c_int, + &mut sizeX as *mut os::raw::c_int, + &mut sizeY as *mut os::raw::c_int + ))?; + Ok((startX as u32, startY as u32, sizeX as u32, sizeY as u32)) + } + } + pub fn get_effective_area(&self) -> Result<(u32, u32, u32, u32)> { + unsafe { + let mut startX: i32 = 0; + let mut startY: i32 = 0; + let mut sizeX: i32 = 0; + let mut sizeY: i32 = 0; + check(QHYCCDCam::GetQHYCCDEffectiveArea( + self.handle, + &mut startX as *mut os::raw::c_int, + &mut startY as *mut os::raw::c_int, + &mut sizeX as *mut os::raw::c_int, + &mut sizeY as *mut os::raw::c_int + ))?; + Ok((startX as u32, startY as u32, sizeX as u32, sizeY as u32)) + } + } + pub fn get_dimensions(&self) -> Result<((f64, f64), (u32, u32), (f64, f64), u32)> { + unsafe { + let mut chipw: f64 = 0.0; + let mut chiph: f64 = 0.0; + let mut imagew: i32 = 0; + let mut imageh: i32 = 0; + let mut pixelw: f64 = 0.0; + let mut pixelh: f64 = 0.0; + let mut bpp: i32 = 0; + check(QHYCCDCam::GetQHYCCDChipInfo( + self.handle, + &mut chipw as *mut os::raw::c_double, + &mut chiph as *mut os::raw::c_double, + &mut imagew as *mut os::raw::c_int, + &mut imageh as *mut os::raw::c_int, + &mut pixelw as *mut os::raw::c_double, + &mut pixelh as *mut os::raw::c_double, + &mut bpp as *mut os::raw::c_int))?; + Ok(( + (chipw, chiph), + (imagew as u32, imageh as u32), + (pixelw, pixelh), + bpp as u32 + )) + } + } +} |