diff options
| author | iximeow <me@iximeow.net> | 2019-03-14 23:04:31 -0700 | 
|---|---|---|
| committer | iximeow <me@iximeow.net> | 2019-03-14 23:04:31 -0700 | 
| commit | 7ab1ab5f8d923eceda77e0913900a5abec4b4c15 (patch) | |
| tree | 245c31266a0a3306e8611b4e33f164004f746811 /src | |
| parent | ba471ad83a65c42a4fc92ca49c7ecddf40514653 (diff) | |
add qhy control software
Diffstat (limited to 'src')
| -rw-r--r-- | src/main.rs | 21 | ||||
| -rw-r--r-- | src/qhyccd/QHYCCDCam.rs | 128 | ||||
| -rw-r--r-- | src/qhyccd/mod.rs | 301 | 
3 files changed, 449 insertions, 1 deletions
| diff --git a/src/main.rs b/src/main.rs index a9a664b..3640f34 100644 --- a/src/main.rs +++ b/src/main.rs @@ -5,7 +5,7 @@  #![allow(dead_code)]  #![feature(alloc_layout_extra)]  mod asicam; - +mod qhyccd;  use crate::asicam::ASICamera2::{ControlType, ImageType};  use crate::asicam::Camera; @@ -15,7 +15,26 @@ fn main() {  }  fn operate_qhy() { +    use crate::qhyccd::Control;      println!("Operating on qhy camera ... or i'll die trying"); +    let mut camera = qhyccd::acquire(0).unwrap(); +    camera.set_exposure_ms(40000).unwrap(); +    camera.set_param(Control::Gain, 64.0).unwrap(); +    camera.set_param(Control::Offset, 00.0).unwrap(); +    camera.set_param(Control::USBTraffic, 250.0).unwrap(); +    camera.set_target_temp(0.0).unwrap(); +    camera.set_param(Control::Cooler, 0.0).unwrap(); +    println!("Binning modes:"); +    println!("1x1: {}", camera.has_param(Control::Bin1x1Mode)); +    println!("2x2: {}", camera.has_param(Control::Bin2x2Mode)); +    println!("3x3: {}", camera.has_param(Control::Bin3x3Mode)); +    println!("4x4: {}", camera.has_param(Control::Bin4x4Mode)); +//    camera.set_param(Control::Speed, 1.0).unwrap(); +    println!("current temp: {}", camera.get_param(Control::CurTemp)); +    camera.set_defaults().unwrap(); +//    camera.set_bin_mode(2).unwrap(); +    camera.take_image("../../asdf.png"); +    camera.release().unwrap();  }  fn operate_asi() { diff --git a/src/qhyccd/QHYCCDCam.rs b/src/qhyccd/QHYCCDCam.rs new file mode 100644 index 0000000..6194835 --- /dev/null +++ b/src/qhyccd/QHYCCDCam.rs @@ -0,0 +1,128 @@ +use std::os; + +#[repr(u32)] +#[derive(Copy, Clone, Debug)] +pub enum QHYResult { +    QHYCCD_SUCCESS = 0, +    QHYCCD_READ_DIRECTLY = 0x2001, +    QHYCCD_DELAY_200MS = 0x2000, +    QHYCCD_ERROR = 0xffffffff +} + +impl From<u32> for QHYResult { +    fn from(u: u32) -> QHYResult { +        match u { +            0 => QHYResult::QHYCCD_SUCCESS, +            0x2000 => QHYResult::QHYCCD_READ_DIRECTLY, +            0x2001 => QHYResult::QHYCCD_DELAY_200MS, +            0xffffffff => QHYResult::QHYCCD_ERROR, +            _ => { +                panic!("Unexpected result code from qhy sdk: {:08x}", u); +            } +        } +    } +} + +#[repr(u32)] +#[derive(Copy, Clone, Debug)] +pub enum Control { +    Brightness = 0, // !< image brightness +    Contrast = 1,       //1 image contrast  +    CONTROL_WBR = 2,            //2 red of white balance  +    CONTROL_WBB = 3,            //3 blue of white balance +    CONTROL_WBG = 4,            //4 the green of white balance  +    Gamma = 5,          //5 screen gamma  +    Gain = 6,           //6 camera gain  +    Offset = 7,         //7 camera offset  +    Exposure = 8,       //8 expose time (us) +    Speed = 9,          //9 transfer speed  +    TransferBit = 10,    //10 image depth bits  +    Channels = 11,       //11 image channels  +    USBTraffic = 12,     //12 hblank  +    RowNoiseRe = 13,     //13 row denoise  +    CurTemp = 14,        //14 current cmos or ccd temprature  +    CurPWM = 15,         //15 current cool pwm  +    ManulPwm = 16,       //16 set the cool pwm  +    CFWPort = 17,        //17 control camera color filter wheel port  +    Cooler = 18,         //18 check if camera has cooler +    St4port = 19,        //19 check if camera has st4port +    Color = 20,              //20    +    Bin1x1Mode = 21,         //21 check if camera has bin1x1 mode  +    Bin2x2Mode = 22,         //22 check if camera has bin2x2 mode  +    Bin3x3Mode = 23,         //23 check if camera has bin3x3 mode  +    Bin4x4Mode = 24,         //24 check if camera has bin4x4 mode  +    CAM_MECHANICALSHUTTER = 25,                  //25 mechanical shutter   +    CAM_TRIGER_INTERFACE = 26,                   //26 triger   +    CAM_TECOVERPROTECT_INTERFACE = 27,           //27 tec overprotect +    CAM_SINGNALCLAMP_INTERFACE = 28,             //28 singnal clamp  +    CAM_FINETONE_INTERFACE = 29,                 //29 fine tone  +    CAM_SHUTTERMOTORHEATING_INTERFACE = 30,      //30 shutter motor heating  +    CAM_CALIBRATEFPN_INTERFACE = 31,             //31 calibrated frame  +    CAM_CHIPTEMPERATURESENSOR_INTERFACE = 32,    //32 chip temperaure sensor +    CAM_USBREADOUTSLOWEST_INTERFACE = 33,        //33 usb readout slowest  +    CAM_8BITS = 34,                              //34 8bit depth  +    CAM_16BITS = 35,                             //35 16bit depth +    CAM_GPS = 36,                                //36 check if camera has gps  +    CAM_IGNOREOVERSCAN_INTERFACE = 37,           //37 ignore overscan area  +    QHYCCD_3A_AUTOBALANCE = 38,                 //38 +    QHYCCD_3A_AUTOEXPOSURE = 39,                    //39 +    QHYCCD_3A_AUTOFOCUS = 40,                   //40 +    CONTROL_AMPV = 41,                           //41 ccd or cmos ampv +    CONTROL_VCAM = 42,                           //42 Virtual Camera on off  +    CAM_VIEW_MODE = 43,                         //43 +    CONTROL_CFWSLOTSNUM = 44,                   //44 check CFW slots number +    IS_EXPOSING_DONE = 45,                      //45 +    ScreenStretchB = 46,                            //46 +    ScreenStretchW = 47,                            //47 +    CONTROL_DDR = 48,                           //47 +    CAM_LIGHT_PERFORMANCE_MODE = 49,                //49 +    CAM_QHY5II_GUIDE_MODE = 50,                 //50 +    DDR_BUFFER_CAPACITY = 51,                   //51 +    DDR_BUFFER_READ_THRESHOLD = 52,             //52 +    DefaultOffset = 53,                         //53 +    OutputDataActualBits = 54,                  //54 +    OutputDataAlignment = 55                        //55 +} + +#[repr(u32)] +#[derive(Copy, Clone, Debug)] +pub enum Bayer +{ +    GB = 1, +    GR = 2, +    BG = 3, +    RG = 4 +} + + +extern "C" { +    pub fn ScanQHYCCD() -> os::raw::c_int; +    pub fn InitQHYCCDResource() -> os::raw::c_int; +    pub fn GetQHYCCDId(id: os::raw::c_int, id: *mut os::raw::c_char) -> os::raw::c_int; +    pub fn GetQHYCCDModel(id: *mut os::raw::c_char, model: *mut os::raw::c_char) -> os::raw::c_int; +    pub fn OpenQHYCCD(id: *mut os::raw::c_char) -> *mut os::raw::c_void; +    pub fn SetQHYCCDStreamMode(handle: *mut os::raw::c_void, mode: os::raw::c_char) -> os::raw::c_int; +    pub fn SetQHYCCDResolution(handle: *mut os::raw::c_void, x: os::raw::c_uint, y: os::raw::c_uint, xsize: os::raw::c_uint, ysize: os::raw::c_uint) -> os::raw::c_int; +    pub fn InitQHYCCD(id: *mut os::raw::c_void) -> os::raw::c_int; +    pub fn IsQHYCCDControlAvailable(handle: *mut os::raw::c_void, control: os::raw::c_int) -> os::raw::c_int; +    pub fn SetQHYCCDParam(handle: *mut os::raw::c_void, control: os::raw::c_int, value: os::raw::c_double) -> os::raw::c_int; +    pub fn GetQHYCCDParam(handle: *mut os::raw::c_void, control: os::raw::c_int) -> os::raw::c_double; +    pub fn GetQHYCCDEffectiveArea(handle: *mut os::raw::c_void, startx: *mut os::raw::c_int, starty: *mut os::raw::c_int, sizex: *mut os::raw::c_int, sizey: *mut os::raw::c_int) -> os::raw::c_int; +    pub fn GetQHYCCDOverScanArea(handle: *mut os::raw::c_void, startx: *mut os::raw::c_int, starty: *mut os::raw::c_int, sizex: *mut os::raw::c_int, sizey: *mut os::raw::c_int) -> os::raw::c_int; +    pub fn GetQHYCCDChipInfo( +        handle: *mut os::raw::c_void, +        chipw: *mut os::raw::c_double, chiph: *mut os::raw::c_double, +        imagew: *mut os::raw::c_int, imageh: *mut os::raw::c_int, +        pixelw: *mut os::raw::c_double, pixelh: *mut os::raw::c_double, +        bpp: *mut os::raw::c_int) -> os::raw::c_int; +    pub fn ControlQHYCCDTemp(handle: *mut os::raw::c_void, target: os::raw::c_double) -> os::raw::c_int; +    pub fn SetQHYCCDDebayerOnOff(handle: *mut os::raw::c_void, onoff: os::raw::c_int) -> os::raw::c_int; +    pub fn SetQHYCCDBinMode(handle: *mut os::raw::c_void, wbin: os::raw::c_int, hbin: os::raw::c_int) -> os::raw::c_int; +    pub fn SetQHYCCDBitsMode(handle: *mut os::raw::c_void, bits: os::raw::c_int) -> os::raw::c_int; +    pub fn ExpQHYCCDSingleFrame(handle: *mut os::raw::c_void) -> os::raw::c_int; +    pub fn GetQHYCCDExposureRemaining(handle: *mut os::raw::c_void) -> os::raw::c_uint; +    pub fn GetQHYCCDMemLength(handle: *mut os::raw::c_void) -> os::raw::c_int; +    pub fn GetQHYCCDSingleFrame(handle: *mut os::raw::c_void, w: *mut os::raw::c_int, h: *mut os::raw::c_int, bpp: *mut os::raw::c_int, channels: *mut os::raw::c_int, data: *mut os::raw::c_uchar) -> os::raw::c_int; +    pub fn CloseQHYCCD(handle: *mut os::raw::c_void) -> os::raw::c_int; +    pub fn ReleaseQHYCCDResource() -> os::raw::c_int; +} 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 +        )) +        } +    } +} | 
