summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authoriximeow <me@iximeow.net>2019-07-23 21:43:31 -0700
committeriximeow <me@iximeow.net>2019-07-23 21:43:31 -0700
commit1af8e5a324fe55aaaac978c78c7b3cf4408496e9 (patch)
treec9fb56526ce5a8621122d6404b43d6968788323e
parent12ade9b864d56edc4cf3132e3de5dd2faa38f93e (diff)
adjust qhy support to work properly in single-frame mode, fix channel ordering issue
-rw-r--r--src/qhyccd/QHYCCDCam.rs3
-rw-r--r--src/qhyccd/mod.rs200
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(())
}