diff options
| author | iximeow <me@iximeow.net> | 2019-07-23 21:43:31 -0700 | 
|---|---|---|
| committer | iximeow <me@iximeow.net> | 2019-07-23 21:43:31 -0700 | 
| commit | 1af8e5a324fe55aaaac978c78c7b3cf4408496e9 (patch) | |
| tree | c9fb56526ce5a8621122d6404b43d6968788323e /src/qhyccd | |
| parent | 12ade9b864d56edc4cf3132e3de5dd2faa38f93e (diff) | |
adjust qhy support to work properly in single-frame mode, fix channel ordering issue
Diffstat (limited to 'src/qhyccd')
| -rw-r--r-- | src/qhyccd/QHYCCDCam.rs | 3 | ||||
| -rw-r--r-- | src/qhyccd/mod.rs | 200 | 
2 files changed, 173 insertions, 30 deletions
| diff --git a/src/qhyccd/QHYCCDCam.rs b/src/qhyccd/QHYCCDCam.rs index 960993e..b5911c1 100644 --- a/src/qhyccd/QHYCCDCam.rs +++ b/src/qhyccd/QHYCCDCam.rs @@ -1,7 +1,7 @@  use std::os;  #[repr(u32)] -#[derive(Copy, Clone, Debug)] +#[derive(Copy, Clone, Debug, PartialEq)]  pub enum QHYResult {      QHYCCD_SUCCESS = 0,      QHYCCD_READ_DIRECTLY = 0x2001, @@ -118,6 +118,7 @@ extern "C" {          bpp: *mut os::raw::c_int) -> os::raw::c_int;      pub fn CancelQHYCCDExposingAndReadout(handle: *mut os::raw::c_void) -> os::raw::c_int;      pub fn ControlQHYCCDTemp(handle: *mut os::raw::c_void, target: os::raw::c_double) -> os::raw::c_int; +    pub fn SetQHYCCDLogLevel(log_level: os::raw::c_char);      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; diff --git a/src/qhyccd/mod.rs b/src/qhyccd/mod.rs index 2de1b52..b50ba3a 100644 --- a/src/qhyccd/mod.rs +++ b/src/qhyccd/mod.rs @@ -14,8 +14,14 @@ use std::path::Path;  use png::HasParameters; +unsafe impl Send for Camera { }  #[derive(Debug)]  pub struct Camera { +    imagew: u32, +    imageh: u32, +    bpp: u8, +    channels: u8, +    bin: u8,      handle: *mut os::raw::c_void  } @@ -39,6 +45,21 @@ fn check(result: os::raw::c_int) -> Result<()> {  static mut INITIALIZED: bool = false; +fn fix_channels(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]; +        dataslice[i * 6 + 1] = dataslice[i * 6 + 4]; +        dataslice[i * 6] = dataslice[i * 6 + 5]; +        dataslice[i * 6 + 4] = b_high; +        dataslice[i * 6 + 5] = b_low; + +        let g_low = dataslice[i * 6 + 2]; +        dataslice[i * 6 + 2] = dataslice[i * 6 + 3]; +        dataslice[i * 6 + 3] = g_low; +    } +} +  pub fn acquire(camera_idx: i32) -> Result<Camera> {      unsafe {          if !INITIALIZED { @@ -62,16 +83,24 @@ pub fn acquire(camera_idx: i32) -> Result<Camera> {              println!("Failed to open the device");              return Err(CameraError::QHYError);          } -        check(QHYCCDCam::SetQHYCCDStreamMode(handle, 1))?; // 0 means single frame mode... +        check(QHYCCDCam::SetQHYCCDStreamMode(handle, 0))?; // 0 means single frame mode...          check(QHYCCDCam::InitQHYCCD(handle))?;          check(QHYCCDCam::CancelQHYCCDExposingAndReadout(handle))?;          Ok(Camera { +            imagew: 0, +            imageh: 0, +            bpp: 16, +            bin: 1, +            channels: 3,              handle: handle          })      }  }  impl Camera { +    pub fn image_buf_size(&self) -> usize { +        (self.imagew as usize) * (self.imageh as usize) * (self.bpp as usize / 8) * (self.channels as usize) +    }      pub fn set_exposure_ms(&self, ms: u32) -> Result<()> {          self.set_param(Control::Exposure, (ms as f64) * 1000.0)      } @@ -135,32 +164,42 @@ impl Camera {          check(QHYCCDCam::CloseQHYCCD(self.handle))          }      } -    pub fn set_defaults(&self) -> Result<()> { +    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, 20.0)?; -                self.set_param(Control::CONTROL_WBG, 20.0)?; -                self.set_param(Control::CONTROL_WBB, 20.0)?; +                self.set_param(Control::CONTROL_WBR, 1000.0)?; +                self.set_param(Control::CONTROL_WBG, 1000.0)?; +                self.set_param(Control::CONTROL_WBB, 1000.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))?; +        self.set_roi(0, 0, imagew, imageh)?; +        self.set_bin_mode(1)?;          if self.has_param(Control::TransferBit) {              check(QHYCCDCam::SetQHYCCDBitsMode(self.handle, 16))?; +            self.bpp = 16;          }          Ok(())          }      } -    pub fn set_bin_mode(&self, bin: u8) -> Result<()> { +    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; +        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); } @@ -169,7 +208,9 @@ impl Camera {              _ => { return Err(CameraError::InvalidControl); }          }          unsafe { -        check(QHYCCDCam::SetQHYCCDBinMode(self.handle, bin as i32, bin as i32)) +            check(QHYCCDCam::SetQHYCCDBinMode(self.handle, bin as i32, bin as i32))?; +            self.bin = bin; +            Ok(())          }      } @@ -197,6 +238,74 @@ impl Camera {          Ok(())      } +    pub fn take_image_live(&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 mut bufsize: usize = self.image_buf_size(); +        println!("Ok, we'll need {} bytes...", bufsize); + +        let data_layout = Layout::from_size_align(bufsize as usize, 8).unwrap(); +        let data = alloc(data_layout); + +        check(QHYCCDCam::BeginQHYCCDLive(self.handle))?; + +        loop { +//            println!("Getting data..."); + +            let mut imagew: i32 = self.imagew as i32; +            let mut imageh: i32 = self.imageh as i32; +            let mut bpp: i32 = self.bpp as i32; +            let mut channels: i32 = self.channels as i32; + +//            println!("w {} h {} bpp {} channels {}", imagew, imageh, bpp, channels); +            match check(QHYCCDCam::GetQHYCCDLiveFrame(self.handle, &mut imagew, &mut imageh, &mut bpp, &mut channels, data)) { +                Ok(()) => { +                    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); +                    let file = File::create(dest).unwrap(); +                    let ref mut w = BufWriter::new(file); +                    let mut encoder = png::Encoder::new(w, imagew as u32, imageh as u32); +                    encoder.set(png::ColorType::RGB).set(png::BitDepth::Eight); +                    // crazy theory, endianness might be wrong... +                    // so flip the bytes first + +                    let mut writer = encoder.write_header().unwrap(); + +                    writer.write_image_data(dataslice).unwrap(); + +                    println!("NEXT!"); + +                    QHYResult::QHYCCD_SUCCESS +                }, +                Err(CameraError::QHYError) => { +//                    println!("Error in live capture: {:?}. sleeping..", CameraError::QHYError); +                    println!("Still waiting..."); +                    std::thread::sleep(std::time::Duration::from_millis(100)); +                    QHYResult::QHYCCD_ERROR +                } +                Err(_) => { unreachable!(); } +            }; +        } + +        dealloc(data as *mut u8, data_layout); +        Ok(()) +        } +    } +      pub fn take_image(&self, path: &str) -> Result<()> {          unsafe {          let exposure_duration = self.get_param(Control::Exposure); @@ -210,7 +319,10 @@ impl Camera {              },              QHYResult::QHYCCD_READ_DIRECTLY => {                  println!("Exp complete, example sleeps so i'll sleep too"); -                std::thread::sleep(std::time::Duration::from_millis(1000)); +//                std::thread::sleep(std::time::Duration::from_millis(1000)); +            }, +            QHYResult::QHYCCD_DELAY_200MS => { +                println!("Sleeping 200ms...");              },              a @ _ =>{                  println!("exp err: {:?}", a); @@ -218,8 +330,35 @@ impl Camera {              }          } -        let bufsize = QHYCCDCam::GetQHYCCDMemLength(self.handle); +        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))?; +        let mut channels: i32 = 3; + +        let mut bufsize = self.image_buf_size();          println!("Ok, we'll need {} bytes...", bufsize); +        println!("but you claim to want {} bytes...", QHYCCDCam::GetQHYCCDMemLength(self.handle)); +        /* +        if self.bin != 1 { +            println!("Correcting for binning..."); +            bufsize /= self.bin as i32; +            bufsize /= self.bin as i32; +            println!("you're getting {} bytes!", bufsize); +        } +        */          let data_layout = Layout::from_size_align(bufsize as usize, 8).unwrap();          let data = alloc(data_layout); @@ -227,15 +366,16 @@ impl Camera {          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));              counter -= 500;          } -        let mut castediw = 0i32; -        let mut castedih = 0i32; -        let mut castedbpp = 0i32; -        let mut channels = 0; +        let mut castediw = self.imagew as i32; +        let mut castedih = self.imageh as i32; +        let mut castedbpp = self.bpp as i32; +        let mut channels = self.channels as i32;          println!("Getting data...");          check(QHYCCDCam::GetQHYCCDSingleFrame(self.handle, &mut castediw, &mut castedih, &mut castedbpp, &mut channels, data))?;          println!("Ok, guess we got it?"); @@ -257,21 +397,23 @@ impl Camera {                      bufsize as usize                  )              }; -        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]; -            dataslice[i * 6 + 1] = dataslice[i * 6 + 4]; -            dataslice[i * 6] = dataslice[i * 6 + 5]; -            dataslice[i * 6 + 4] = b_high; -            dataslice[i * 6 + 5] = b_low; - -            let g_low = dataslice[i * 6 + 2]; -            dataslice[i * 6 + 2] = dataslice[i * 6 + 3]; -            dataslice[i * 6 + 3] = g_low; -        } -        println!("the amount of data mod 6: {}", dataslice.len() % 6); + +        fix_channels(dataslice); +          let mut writer = encoder.write_header().unwrap(); -        writer.write_image_data(dataslice).unwrap(); + +        if self.bin != 1 { +            let scale = self.bin as usize * self.bin as usize; +            let mut cherrypicked = vec![0; bufsize as usize / scale]; +            for i in 0..cherrypicked.len() / 6 { +                for j in 0..6 { +                    cherrypicked[i * 6 + j] = dataslice[i * 6 * scale + j]; +                } +            } +            writer.write_image_data(&cherrypicked).unwrap(); +        } else { +            writer.write_image_data(dataslice).unwrap(); +        }          dealloc(data as *mut u8, data_layout);          Ok(())      } | 
