summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/main.rs172
-rw-r--r--src/qhyccd/QHYCCDCam.rs70
-rw-r--r--src/qhyccd/mod.rs388
3 files changed, 573 insertions, 57 deletions
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;