diff --git a/awg-cxx/build.rs b/awg-cxx/build.rs index 29aff690a6bcd9ccc96d7c971a080ccb33e22446..bb443af11a54b7185c741ebb52d09d46b7c81425 100644 --- a/awg-cxx/build.rs +++ b/awg-cxx/build.rs @@ -6,21 +6,21 @@ fn main() { println!("cargo:rustc-link-search=/usr/lib64"); println!("cargo:rustc-link-lib=spcm_linux"); - println!("cargo:rustc-link-search=/opt/pylon/lib"); - println!("cargo:rustc-link-lib=pylonbase"); - println!("cargo:rustc-link-lib=pylonutility"); - println!("cargo:rustc-link-lib=GenApi_gcc_v3_1_Basler_pylon"); - println!("cargo:rustc-link-lib=GCBase_gcc_v3_1_Basler_pylon"); + // println!("cargo:rustc-link-search=/opt/pylon/lib"); + // println!("cargo:rustc-link-lib=pylonbase"); + // println!("cargo:rustc-link-lib=pylonutility"); + // println!("cargo:rustc-link-lib=GenApi_gcc_v3_1_Basler_pylon"); + // println!("cargo:rustc-link-lib=GCBase_gcc_v3_1_Basler_pylon"); cxx_build::bridge("lib/awg_ffi.rs") .cpp(true) .warnings(false) .flag("-std=c++14") .include("include") - .include("awg-control/Cpp/lib") + .include("awg-control/Cpp/lib/devices") .include("awg-control/Cpp/lib/devices/driver_header") - .include("/opt/pylon/include") - .include("/usr/include/opencv4") + // .include("/opt/pylon/include") + // .include("/usr/include/opencv4") .file("awg-control/Cpp/lib/devices/AWG.cpp") .file("lib/awg.cc") .compile("awg-cxx"); diff --git a/awg-cxx/include/awg.h b/awg-cxx/include/awg.h index 7df74a27dc52e038b04c7ccedd20b11a4c7133e5..8b033b11d484eeab1694b20ef4a87f9a5ebed879 100644 --- a/awg-cxx/include/awg.h +++ b/awg-cxx/include/awg.h @@ -3,9 +3,9 @@ #include <vector> #include "rust/cxx.h" #include "awg-cxx/awg-control/Cpp/lib/devices/AWG.h" -#include "awg-cxx/awg-control/Cpp/lib/devices/basler.h" -#include "awg-cxx/awg-control/Cpp/lib/waveform.h" -#include "awg-cxx/awg-control/Cpp/lib/uniformization.h" +// #include "awg-cxx/awg-control/Cpp/lib/devices/basler.h" +// #include "awg-cxx/awg-control/Cpp/lib/waveform.h" +// #include "awg-cxx/awg-control/Cpp/lib/uniformization.h" // class PageAlignedMem { // public: @@ -39,41 +39,41 @@ private: AWG awg; }; -class BaslerBox { -public: - BaslerBox(int); - ~BaslerBox(); +// class BaslerBox { +// public: +// BaslerBox(int); +// ~BaslerBox(); - BaslerCam &get_cam(); -private: - BaslerCam cam; -}; +// BaslerCam &get_cam(); +// private: +// BaslerCam cam; +// }; -class UniformizationParams { -public: - UniformizationParams( - std::string source, - double polarizability, - double mean_depth, - double step_size, - double error_threshold, - int max_iters, - int num_imaging_avg, - int num_tweezer - ); - ~UniformizationParams(); - - Uniformization::Params to_raw(); -private: - std::string source; - double polarizability; - double mean_depth; - double step_size; - double error_threshold; - int max_iters; - int num_imaging_avg; - int num_tweezers; -}; +// class UniformizationParams { +// public: +// UniformizationParams( +// std::string source, +// double polarizability, +// double mean_depth, +// double step_size, +// double error_threshold, +// int max_iters, +// int num_imaging_avg, +// int num_tweezer +// ); +// ~UniformizationParams(); + +// Uniformization::Params to_raw(); +// private: +// std::string source; +// double polarizability; +// double mean_depth; +// double step_size; +// double error_threshold; +// int max_iters; +// int num_imaging_avg; +// int num_tweezers; +// }; std::unique_ptr<AWGBox> new_awg(int idx); @@ -150,17 +150,17 @@ int64_t awg_get_clock_out_freq(AWGBox &awg); // void arraywaveform_set_freq_resolution(ArrayWaveform &waveform, ulong resolution); // ulong arraywaveform_get_freq_resolution(ArrayWaveform &waveform); -void arraywaveform_set_freq_tones_spaced(ArrayWaveform &waveform, int center, int spacing, int num_tones); -void arraywaveform_set_freq_tones(ArrayWaveform &waveform, const std::vector<int> &tones); -rust::Vec<int> arraywaveform_get_freq_tones(ArrayWaveform &waveform); -void arraywaveform_set_phases(ArrayWaveform &waveform, const std::vector<double> &phases); -rust::Vec<double> arraywaveform_get_phases(ArrayWaveform &waveform); -void arraywaveform_set_amplitudes(ArrayWaveform &waveform, const std::vector<double>& amplitudes); -rust::Vec<double> arraywaveform_get_amplitudes(ArrayWaveform &waveform); -void arraywaveform_set_default_params(ArrayWaveform &waveform); -void arraywaveform_save_params(ArrayWaveform &waveform, const std::string &filename); -void arraywaveform_load_params(ArrayWaveform &waveform, const std::string &filename); -void arraywaveform_print_params(ArrayWaveform &waveform); +// void arraywaveform_set_freq_tones_spaced(ArrayWaveform &waveform, int center, int spacing, int num_tones); +// void arraywaveform_set_freq_tones(ArrayWaveform &waveform, const std::vector<int> &tones); +// rust::Vec<int> arraywaveform_get_freq_tones(ArrayWaveform &waveform); +// void arraywaveform_set_phases(ArrayWaveform &waveform, const std::vector<double> &phases); +// rust::Vec<double> arraywaveform_get_phases(ArrayWaveform &waveform); +// void arraywaveform_set_amplitudes(ArrayWaveform &waveform, const std::vector<double>& amplitudes); +// rust::Vec<double> arraywaveform_get_amplitudes(ArrayWaveform &waveform); +// void arraywaveform_set_default_params(ArrayWaveform &waveform); +// void arraywaveform_save_params(ArrayWaveform &waveform, const std::string &filename); +// void arraywaveform_load_params(ArrayWaveform &waveform, const std::string &filename); +// void arraywaveform_print_params(ArrayWaveform &waveform); // ulong arraywaveform_get_min_sample_len(ArrayWaveform &waveform, ulong sampling_rate, ulong frequency_resolution); // ulong arraywaveform_get_sample_len(ArrayWaveform &waveform, double tau, ulong sampling_rate, ulong frequency_resolution); @@ -168,38 +168,38 @@ void arraywaveform_print_params(ArrayWaveform &waveform); // std::unique_ptr<WaveformData> arraywaveform_get_static_waveform(ArrayWaveform &waveform); // std::unique_ptr<WaveformData> arraywaveform_get_trick_waveform(ArrayWaveform &waveform, const std::vector<int> &site_index, double df, double tau_move, double tau_stay); -void arraywaveform_save_waveform(ArrayWaveform &waveform, const std::string &filename); +// void arraywaveform_save_waveform(ArrayWaveform &waveform, const std::string &filename); -std::unique_ptr<PageAlignedMem> waveformdata_get_mem(WaveformData &data); -int64_t waveformdata_get_datalen(WaveformData &data); +// std::unique_ptr<PageAlignedMem> waveformdata_get_mem(WaveformData &data); +// int64_t waveformdata_get_datalen(WaveformData &data); /******************************************************************************/ -std::unique_ptr<BaslerBox> new_basler(int index); - -void basler_print_device_info(BaslerBox &basler); -void basler_set_exposure(BaslerBox &basler, double exposure_time); -double basler_get_exposure(BaslerBox &basler); -void basler_set_frame_rate(BaslerBox &basler, uint frame_rate); -void basler_set_frame_rate_max(BaslerBox &basler); -void basler_set_gain(BaslerBox &basler, double gain); -double basler_get_gain(BaslerBox &basler); -void basler_set_roi(BaslerBox &basler, uint offset_x, uint offset_y, uint width, uint height); -uint basler_get_offset_x(BaslerBox &basler); -uint basler_get_offset_y(BaslerBox &basler); -uint basler_get_width(BaslerBox &basler); -uint basler_get_height(BaslerBox &basler); -void basler_set_acquisition_mode(BaslerBox &basler, const std::string &mode); -void basler_print_available_acquisition_modes(BaslerBox &basler); - -void basler_start_grabbing(BaslerBox &basler); -void basler_stop_grabbing(BaslerBox &basler); -bool basler_is_grabbing(BaslerBox &basler); -rust::Vec<uint8_t> basler_get_image(BaslerBox &basler); +// std::unique_ptr<BaslerBox> new_basler(int index); + +// void basler_print_device_info(BaslerBox &basler); +// void basler_set_exposure(BaslerBox &basler, double exposure_time); +// double basler_get_exposure(BaslerBox &basler); +// void basler_set_frame_rate(BaslerBox &basler, uint frame_rate); +// void basler_set_frame_rate_max(BaslerBox &basler); +// void basler_set_gain(BaslerBox &basler, double gain); +// double basler_get_gain(BaslerBox &basler); +// void basler_set_roi(BaslerBox &basler, uint offset_x, uint offset_y, uint width, uint height); +// uint basler_get_offset_x(BaslerBox &basler); +// uint basler_get_offset_y(BaslerBox &basler); +// uint basler_get_width(BaslerBox &basler); +// uint basler_get_height(BaslerBox &basler); +// void basler_set_acquisition_mode(BaslerBox &basler, const std::string &mode); +// void basler_print_available_acquisition_modes(BaslerBox &basler); + +// void basler_start_grabbing(BaslerBox &basler); +// void basler_stop_grabbing(BaslerBox &basler); +// bool basler_is_grabbing(BaslerBox &basler); +// rust::Vec<uint8_t> basler_get_image(BaslerBox &basler); /******************************************************************************/ -std::unique_ptr<UniformizationParams> new_uniformizationparams(const std::string &source, double polarizability, double mean_depth, double step_size, double error_threshold, int max_iters, int num_imaging_avg, int num_tweezers); +// std::unique_ptr<UniformizationParams> new_uniformizationparams(const std::string &source, double polarizability, double mean_depth, double step_size, double error_threshold, int max_iters, int num_imaging_avg, int num_tweezers); -void run_uniformization(AWGBox &awg, BaslerBox &basler, ArrayWaveform &waveform, const UniformizationParams ¶ms); +// void run_uniformization(AWGBox &awg, BaslerBox &basler, ArrayWaveform &waveform, const UniformizationParams ¶ms); diff --git a/awg-cxx/lib/awg.cc b/awg-cxx/lib/awg.cc index d806aa33f267ed85779e7effe95374320283353b..9088e17078928bc2efbe1b42110e0c769497927e 100644 --- a/awg-cxx/lib/awg.cc +++ b/awg-cxx/lib/awg.cc @@ -1,5 +1,5 @@ #include "awg-cxx/awg-control/Cpp/lib/devices/AWG.h" -#include "awg-cxx/awg-control/Cpp/lib/devices/basler.h" +// #include "awg-cxx/awg-control/Cpp/lib/devices/basler.h" #include "awg-cxx/include/awg.h" #include "rust/cxx.h" @@ -215,6 +215,7 @@ AWGBox::AWGBox(int idx) { } AWGBox::~AWGBox() { + this->awg.cardStop(); this->awg.close(); } @@ -562,10 +563,10 @@ int64_t awg_get_clock_out_freq(AWGBox &awg) { // waveform.setFreqTone(tones); // } -rust::Vec<int> arraywaveform_get_freq_tones(ArrayWaveform &waveform) { - std::vector<int> tones = waveform.getFreqTone(); - return conv_to_int_vec(tones); -} +// rust::Vec<int> arraywaveform_get_freq_tones(ArrayWaveform &waveform) { +// std::vector<int> tones = waveform.getFreqTone(); +// return conv_to_int_vec(tones); +// } // void arraywaveform_set_phases( // ArrayWaveform &waveform, @@ -574,10 +575,10 @@ rust::Vec<int> arraywaveform_get_freq_tones(ArrayWaveform &waveform) { // waveform.setPhase(phases); // } -rust::Vec<double> arraywaveform_get_phases(ArrayWaveform &waveform) { - std::vector<double> phases = waveform.getPhase(); - return conv_to_f64_vec(phases); -} +// rust::Vec<double> arraywaveform_get_phases(ArrayWaveform &waveform) { +// std::vector<double> phases = waveform.getPhase(); +// return conv_to_f64_vec(phases); +// } // void arraywaveform_set_amplitudes( // ArrayWaveform &waveform, @@ -586,10 +587,10 @@ rust::Vec<double> arraywaveform_get_phases(ArrayWaveform &waveform) { // waveform.setAmplitude(amplitudes); // } -rust::Vec<double> arraywaveform_get_amplitudes(ArrayWaveform &waveform) { - std::vector<double> amplitudes = waveform.getAmplitude(); - return conv_to_f64_vec(amplitudes); -} +// rust::Vec<double> arraywaveform_get_amplitudes(ArrayWaveform &waveform) { +// std::vector<double> amplitudes = waveform.getAmplitude(); +// return conv_to_f64_vec(amplitudes); +// } // void arraywaveform_set_default_params(ArrayWaveform &waveform) { // waveform.setDefaultParam(); @@ -630,36 +631,36 @@ rust::Vec<double> arraywaveform_get_amplitudes(ArrayWaveform &waveform) { // return waveform.getSampleLen(tau, sampling_rate, frequency_resolution); // } -std::unique_ptr<WaveformData> arraywaveform_get_static_waveform( - ArrayWaveform &waveform -) { - std::pair<void *, int64_t> memsize = waveform.getStaticWaveform(); - std::unique_ptr<WaveformData> - data_ptr_unique(new WaveformData(memsize.first, memsize.second)); - // auto [mem, datalen] = waveform.getStaticWaveform(); - // std::unique_ptr<WaveformData> - // data_ptr_unique(new WaveformData(mem, datalen)); - return data_ptr_unique; -} - -std::unique_ptr<WaveformData> arraywaveform_get_trick_waveform( - ArrayWaveform &waveform, - const std::vector<int> &site_index, - double df, - double tau_move, - double tau_stay -) { - std::set<int> sites = int_vector_to_int_set(site_index); - std::pair<void *, int64_t> memsize - = waveform.getTrickWaveform(sites, df, tau_move, tau_stay); - std::unique_ptr<WaveformData> - data_ptr_unique(new WaveformData(memsize.first, memsize.second)); - // auto [mem, datalen] - // = waveform.getTrickWaveform(sites, df, tau_move, tau_stay); - // std::unique_ptr<WaveformData> - // data_ptr_unique(new WaveformData(mem, datalen)); - return data_ptr_unique; -} +// std::unique_ptr<WaveformData> arraywaveform_get_static_waveform( +// ArrayWaveform &waveform +// ) { +// std::pair<void *, int64_t> memsize = waveform.getStaticWaveform(); +// std::unique_ptr<WaveformData> +// data_ptr_unique(new WaveformData(memsize.first, memsize.second)); +// // auto [mem, datalen] = waveform.getStaticWaveform(); +// // std::unique_ptr<WaveformData> +// // data_ptr_unique(new WaveformData(mem, datalen)); +// return data_ptr_unique; +// } + +// std::unique_ptr<WaveformData> arraywaveform_get_trick_waveform( +// ArrayWaveform &waveform, +// const std::vector<int> &site_index, +// double df, +// double tau_move, +// double tau_stay +// ) { +// std::set<int> sites = int_vector_to_int_set(site_index); +// std::pair<void *, int64_t> memsize +// = waveform.getTrickWaveform(sites, df, tau_move, tau_stay); +// std::unique_ptr<WaveformData> +// data_ptr_unique(new WaveformData(memsize.first, memsize.second)); +// // auto [mem, datalen] +// // = waveform.getTrickWaveform(sites, df, tau_move, tau_stay); +// // std::unique_ptr<WaveformData> +// // data_ptr_unique(new WaveformData(mem, datalen)); +// return data_ptr_unique; +// } // void arraywaveform_save_waveform( // ArrayWaveform &waveform, @@ -676,176 +677,176 @@ std::unique_ptr<WaveformData> arraywaveform_get_trick_waveform( // return mem_ptr_unique; // } -int64_t waveformdata_get_datalen(WaveformData &data) { - return data.get_datalen(); -} +// int64_t waveformdata_get_datalen(WaveformData &data) { +// return data.get_datalen(); +// } /******************************************************************************/ -BaslerBox::BaslerBox(int index) { - this->cam.open(index); -} +// BaslerBox::BaslerBox(int index) { +// this->cam.open(index); +// } -BaslerBox::~BaslerBox() { } +// BaslerBox::~BaslerBox() { } -BaslerCam &BaslerBox::get_cam() { - return this->cam; -} +// BaslerCam &BaslerBox::get_cam() { +// return this->cam; +// } -std::unique_ptr<BaslerBox> new_basler(int index) { - std::unique_ptr<BaslerBox> - basler_ptr_unique(new BaslerBox(index)); - return basler_ptr_unique; -} +// std::unique_ptr<BaslerBox> new_basler(int index) { +// std::unique_ptr<BaslerBox> +// basler_ptr_unique(new BaslerBox(index)); +// return basler_ptr_unique; +// } -void basler_print_device_info(BaslerBox &basler) { - basler.get_cam().printDeviceInfo(); -} +// void basler_print_device_info(BaslerBox &basler) { +// basler.get_cam().printDeviceInfo(); +// } -void basler_set_exposure(BaslerBox &basler, double exposure_time) { - basler.get_cam().setExposure(exposure_time); -} +// void basler_set_exposure(BaslerBox &basler, double exposure_time) { +// basler.get_cam().setExposure(exposure_time); +// } -double basler_get_exposure(BaslerBox &basler) { - return basler.get_cam().getExposure(); -} +// double basler_get_exposure(BaslerBox &basler) { +// return basler.get_cam().getExposure(); +// } -void basler_set_frame_rate(BaslerBox &basler, uint frame_rate) { - basler.get_cam().setFrameRate(frame_rate); -} +// void basler_set_frame_rate(BaslerBox &basler, uint frame_rate) { +// basler.get_cam().setFrameRate(frame_rate); +// } -void basler_set_frame_rate_max(BaslerBox &basler) { - basler.get_cam().setFrameRateMax(); -} +// void basler_set_frame_rate_max(BaslerBox &basler) { +// basler.get_cam().setFrameRateMax(); +// } -void basler_set_gain(BaslerBox &basler, double gain) { - basler.get_cam().setGain(gain); -} +// void basler_set_gain(BaslerBox &basler, double gain) { +// basler.get_cam().setGain(gain); +// } -double basler_get_gain(BaslerBox &basler) { - return basler.get_cam().getGain(); -} +// double basler_get_gain(BaslerBox &basler) { +// return basler.get_cam().getGain(); +// } -void basler_set_roi(BaslerBox &basler, uint offset_x, uint offset_y, uint width, uint height) { - basler.get_cam().setROI(offset_x, offset_y, width, height); -} +// void basler_set_roi(BaslerBox &basler, uint offset_x, uint offset_y, uint width, uint height) { +// basler.get_cam().setROI(offset_x, offset_y, width, height); +// } -uint basler_get_offset_x(BaslerBox &basler) { - return basler.get_cam().getOffsetX(); -} +// uint basler_get_offset_x(BaslerBox &basler) { +// return basler.get_cam().getOffsetX(); +// } -uint basler_get_offset_y(BaslerBox &basler) { - return basler.get_cam().getOffsetY(); -} +// uint basler_get_offset_y(BaslerBox &basler) { +// return basler.get_cam().getOffsetY(); +// } -uint basler_get_width(BaslerBox &basler) { - return basler.get_cam().getWidth(); -} +// uint basler_get_width(BaslerBox &basler) { +// return basler.get_cam().getWidth(); +// } -uint basler_get_height(BaslerBox &basler) { - return basler.get_cam().getHeight(); -} +// uint basler_get_height(BaslerBox &basler) { +// return basler.get_cam().getHeight(); +// } -void basler_set_acquisition_mode(BaslerBox &basler, const std::string &mode) { - basler.get_cam().setAcquisitionMode(mode); -} +// void basler_set_acquisition_mode(BaslerBox &basler, const std::string &mode) { +// basler.get_cam().setAcquisitionMode(mode); +// } -void basler_print_available_acquisition_modes(BaslerBox &basler) { - basler.get_cam().printAvailAcqModes(); -} +// void basler_print_available_acquisition_modes(BaslerBox &basler) { +// basler.get_cam().printAvailAcqModes(); +// } -void basler_start_grabbing(BaslerBox &basler) { - basler.get_cam().startGrabbing(); -} +// void basler_start_grabbing(BaslerBox &basler) { +// basler.get_cam().startGrabbing(); +// } -void basler_stop_grabbing(BaslerBox &basler) { - basler.get_cam().stopGrabbing(); -} +// void basler_stop_grabbing(BaslerBox &basler) { +// basler.get_cam().stopGrabbing(); +// } -bool basler_is_grabbing(BaslerBox &basler) { - return basler.get_cam().isGrabbing(); -} +// bool basler_is_grabbing(BaslerBox &basler) { +// return basler.get_cam().isGrabbing(); +// } -rust::Vec<uint8_t> basler_get_image(BaslerBox &basler) { - std::vector<uint8_t> image = basler.get_cam().getImage(); - return to_u8_vec(image); -} +// rust::Vec<uint8_t> basler_get_image(BaslerBox &basler) { +// std::vector<uint8_t> image = basler.get_cam().getImage(); +// return to_u8_vec(image); +// } -/******************************************************************************/ +// /******************************************************************************/ -UniformizationParams::UniformizationParams( - std::string source, - double polarizability, - double mean_depth, - double step_size, - double error_threshold, - int max_iters, - int num_imaging_avg, - int num_tweezers -) { - this->source = source; - this->polarizability = polarizability; - this->mean_depth = mean_depth; - this->step_size = step_size; - this->error_threshold = error_threshold; - this->max_iters = max_iters; - this->num_imaging_avg = num_imaging_avg; - this->num_tweezers = num_tweezers; -} - -UniformizationParams::~UniformizationParams() { } - -Uniformization::Params UniformizationParams::to_raw() { - Uniformization::Params params; - params.probeScanPath = this->source; - params.polarizability = this->polarizability; - params.meanDepth = this->mean_depth; - params.stepSize = this->step_size; - params.errorThreshold = this->error_threshold; - params.maxLoop = this->max_iters; - params.numImgingAvg = this->num_imaging_avg; - params.numTweezer = this->num_tweezers; - return params; -} - -std::unique_ptr<UniformizationParams> new_uniformizationparams( - const std::string &source, - double polarizability, - double mean_depth, - double step_size, - double error_threshold, - int max_iters, - int num_imaging_avg, - int num_tweezers -) { - std::unique_ptr<UniformizationParams> - params_ptr_unique( - new UniformizationParams( - source, - polarizability, - mean_depth, - step_size, - error_threshold, - max_iters, - num_imaging_avg, - num_tweezers - ) - ); - return params_ptr_unique; -} +// UniformizationParams::UniformizationParams( +// std::string source, +// double polarizability, +// double mean_depth, +// double step_size, +// double error_threshold, +// int max_iters, +// int num_imaging_avg, +// int num_tweezers +// ) { +// this->source = source; +// this->polarizability = polarizability; +// this->mean_depth = mean_depth; +// this->step_size = step_size; +// this->error_threshold = error_threshold; +// this->max_iters = max_iters; +// this->num_imaging_avg = num_imaging_avg; +// this->num_tweezers = num_tweezers; +// } -void run_uniformization( - AWGBox &awg, - BaslerBox &basler, - ArrayWaveform &waveform, - UniformizationParams ¶ms -) { - const Uniformization::Params raw_params = params.to_raw(); - Uniformization::run( - awg.get_awg(), - basler.get_cam(), - waveform, - raw_params - ); -} +// UniformizationParams::~UniformizationParams() { } + +// Uniformization::Params UniformizationParams::to_raw() { +// Uniformization::Params params; +// params.probeScanPath = this->source; +// params.polarizability = this->polarizability; +// params.meanDepth = this->mean_depth; +// params.stepSize = this->step_size; +// params.errorThreshold = this->error_threshold; +// params.maxLoop = this->max_iters; +// params.numImgingAvg = this->num_imaging_avg; +// params.numTweezer = this->num_tweezers; +// return params; +// } + +// std::unique_ptr<UniformizationParams> new_uniformizationparams( +// const std::string &source, +// double polarizability, +// double mean_depth, +// double step_size, +// double error_threshold, +// int max_iters, +// int num_imaging_avg, +// int num_tweezers +// ) { +// std::unique_ptr<UniformizationParams> +// params_ptr_unique( +// new UniformizationParams( +// source, +// polarizability, +// mean_depth, +// step_size, +// error_threshold, +// max_iters, +// num_imaging_avg, +// num_tweezers +// ) +// ); +// return params_ptr_unique; +// } + +// void run_uniformization( +// AWGBox &awg, +// BaslerBox &basler, +// ArrayWaveform &waveform, +// UniformizationParams ¶ms +// ) { +// const Uniformization::Params raw_params = params.to_raw(); +// Uniformization::run( +// awg.get_awg(), +// basler.get_cam(), +// waveform, +// raw_params +// ); +// } diff --git a/awg-cxx/lib/awg.rs b/awg-cxx/lib/awg.rs index a5d1a7296d3fe9ec85db4f9088101d55e5a04721..09c698fe3818dc4fdb79e04d4eedb2ada5486313 100644 --- a/awg-cxx/lib/awg.rs +++ b/awg-cxx/lib/awg.rs @@ -7,23 +7,24 @@ use std::{ collections::HashSet, ffi::{ OsStr, OsString }, - f64::consts::TAU, - fmt, - fs, - io::{ Read, Write }, - path::{ Path, PathBuf }, + // f64::consts::TAU, + // fmt, + // fs, + // io::{ Read, Write }, + // path::{ Path, PathBuf }, + path::{ Path }, pin::Pin, }; use cxx::{ let_cxx_string, CxxVector, UniquePtr, kind::Trivial }; use thiserror::Error; use crate::{ awg_ffi::ffi, - basler::Basler, + // basler::Basler, config::{ TriggerConfig, ChannelConfig, - SequenceStepConfig, - SequenceKind, + SequenceSegmentsConfig, + // SequenceKind, Config, ConfigError, }, @@ -43,9 +44,6 @@ pub enum AWGError { // #[error("bad waveform filename '{0:?}': must end in '.csv'")] // WaveformCSV(OsString), - #[error("bad waveform data filename '{0:?}': must end in '.txt'")] - WaveformTXT(OsString), - // #[error("uninitialized waveform parameters")] // WaveformUninit, @@ -82,38 +80,38 @@ pub enum AWGError { // #[error("invalid amplitude setting: number of amplitudes must match frequency tone and phase settings")] // NumAmplitudes, - #[error("invalid amplitude {0}: must be [0, 2^15 - 1]")] - InvalidAmplitude(f64), + // #[error("invalid waveform amplitude {0}: must be 0..2^15-1")] + // InvalidAmplitude(f64), - #[error("uniformization error: {0}")] - UniformizationError(String), + // #[error("uniformization error: {0}")] + // UniformizationError(String), - #[error("uninitialized uniformization parameters")] - UniformizationUninit, + // #[error("uninitialized uniformization parameters")] + // UniformizationUninit, - #[error("invalid uniformization waveform source '{0}': file does not exist")] - InvalidUniformizationSource(String), + // #[error("invalid uniformization waveform source '{0}': file does not exist")] + // InvalidUniformizationSource(String), - #[error("invalid polarizability {0}: setting only makes sense for negative values")] - InvalidPolarizability(f64), + // #[error("invalid polarizability {0}: setting only makes sense for negative values")] + // InvalidPolarizability(f64), - #[error("invalid mean depth {0}: setting only makes sense for positive values")] - InvalidMeanDepth(f64), + // #[error("invalid mean depth {0}: setting only makes sense for positive values")] + // InvalidMeanDepth(f64), - #[error("invalid step size {0}: setting only makes sense for positive values")] - InvalidStepSize(f64), + // #[error("invalid step size {0}: setting only makes sense for positive values")] + // InvalidStepSize(f64), - #[error("invalid error threshold {0}: setting only makes sense for positive values")] - InvalidErrorThreshold(f64), + // #[error("invalid error threshold {0}: setting only makes sense for positive values")] + // InvalidErrorThreshold(f64), - #[error("invalid max iters {0}: must be at least 1")] - InvalidMaxIters(usize), + // #[error("invalid max iters {0}: must be at least 1")] + // InvalidMaxIters(usize), - #[error("invalid imaging average {0}: must be at least 1")] - InvalidNumImagingAvg(usize), + // #[error("invalid imaging average {0}: must be at least 1")] + // InvalidNumImagingAvg(usize), - #[error("invalid tweezer array size {0}: must be at least 1")] - InvalidNumTweezers(usize), + // #[error("invalid tweezer array size {0}: must be at least 1")] + // InvalidNumTweezers(usize), #[error("config error: {0}")] ConfigError(#[from] ConfigError), @@ -125,13 +123,13 @@ impl AWGError { Self::DeviceError(except.what().to_string()) } - fn as_waveform_err(except: cxx::Exception) -> Self { - Self::WaveformError(except.what().to_string()) - } + // fn as_waveform_err(except: cxx::Exception) -> Self { + // Self::WaveformError(except.what().to_string()) + // } - fn as_uniformization_err(except: cxx::Exception) -> Self { - Self::UniformizationError(except.what().to_string()) - } + // fn as_uniformization_err(except: cxx::Exception) -> Self { + // Self::UniformizationError(except.what().to_string()) + // } } fn collect_cxx_vector<'a, I, T>(vals: I) -> UniquePtr<CxxVector<T>> @@ -157,58 +155,58 @@ macro_rules! impl_debug_boring { /// Represents a thin wrapper around a (thin wrapper around a) raw C++ `void*` /// pointing to a page-aligned slice of memory. -pub struct PageAlignedMem<'a> { - ptr: UniquePtr<ffi::PageAlignedMem>, - wf_ref: &'a ArrayWaveform, -} +// pub struct PageAlignedMem<'a> { +// ptr: UniquePtr<ffi::PageAlignedMem>, +// wf_ref: &'a ArrayWaveform, +// } -impl<'a> std::fmt::Debug for PageAlignedMem<'a> { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "PageAlignedMem") - } -} +// impl<'a> std::fmt::Debug for PageAlignedMem<'a> { +// fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { +// write!(f, "PageAlignedMem") +// } +// } -impl<'a> PageAlignedMem<'a> { - fn pinned(&mut self) -> Pin<&mut ffi::PageAlignedMem> { self.ptr.pin_mut() } -} +// impl<'a> PageAlignedMem<'a> { +// fn pinned(&mut self) -> Pin<&mut ffi::PageAlignedMem> { self.ptr.pin_mut() } +// } /// Thin wrapper around a raw C++ `void*` pointing to a waveform array stored at /// a page-aligned slice of memory, along with the array's length. -pub struct WaveformDataPtr<'a> { - ptr: UniquePtr<ffi::WaveformData>, - wf_ref: &'a ArrayWaveform, -} - -impl<'a> std::fmt::Debug for WaveformDataPtr<'a> { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "WaveformDataPtr") - } -} - -impl<'a> TryFrom<WaveformDataPtr<'a>> for (PageAlignedMem<'a>, u64) { - type Error = AWGError; - - fn try_from(wf_data_ptr: WaveformDataPtr<'a>) -> AWGResult<Self> { - wf_data_ptr.into_memsize() - } -} - -impl<'a> WaveformDataPtr<'a> { - fn pinned(&mut self) -> Pin<&mut ffi::WaveformData> { self.ptr.pin_mut() } - - fn into_memsize(self) -> AWGResult<(PageAlignedMem<'a>, u64)> { - unsafe { - let Self { mut ptr, wf_ref } = self; - ffi::waveformdata_get_mem(ptr.pin_mut()) - .map(|ptr| PageAlignedMem { ptr, wf_ref }) - .map_err(AWGError::as_waveform_err) - .and_then(|buf| { - ffi::waveformdata_get_datalen(ptr.pin_mut()) - .map(|len| (buf, len as u64)) - .map_err(AWGError::as_waveform_err) - }) - } - } +// pub struct WaveformDataPtr<'a> { +// ptr: UniquePtr<ffi::WaveformData>, +// wf_ref: &'a ArrayWaveform, +// } + +// impl<'a> std::fmt::Debug for WaveformDataPtr<'a> { +// fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { +// write!(f, "WaveformDataPtr") +// } +// } + +// impl<'a> TryFrom<WaveformDataPtr<'a>> for (PageAlignedMem<'a>, u64) { +// type Error = AWGError; + +// fn try_from(wf_data_ptr: WaveformDataPtr<'a>) -> AWGResult<Self> { +// wf_data_ptr.into_memsize() +// } +// } + +// impl<'a> WaveformDataPtr<'a> { +// fn pinned(&mut self) -> Pin<&mut ffi::WaveformData> { self.ptr.pin_mut() } + +// fn into_memsize(self) -> AWGResult<(PageAlignedMem<'a>, u64)> { +// unsafe { +// let Self { mut ptr, wf_ref } = self; +// ffi::waveformdata_get_mem(ptr.pin_mut()) +// .map(|ptr| PageAlignedMem { ptr, wf_ref }) +// .map_err(AWGError::as_waveform_err) +// .and_then(|buf| { +// ffi::waveformdata_get_datalen(ptr.pin_mut()) +// .map(|len| (buf, len as u64)) +// .map_err(AWGError::as_waveform_err) +// }) +// } +// } // pub fn get_mem(&mut self) -> AWGResult<PageAlignedMem> { // unsafe { @@ -225,7 +223,7 @@ impl<'a> WaveformDataPtr<'a> { // .map_err(|err| AWGError::WaveformError(err.to_string())) // } // } -} +// } macro_rules! cpp_enum { ( @@ -490,24 +488,6 @@ cpp_enum!( } ); -/// AWG card index. -#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] -pub enum AWGIndex { - Zero = 0, - One = 1, -} - -impl TryFrom<i32> for AWGIndex { - type Error = AWGError; - - fn try_from(i: i32) -> AWGResult<Self> { - match i { - 0 => Ok(Self::Zero), - 1 => Ok(Self::One), - x => Err(AWGError::InvalidCardIndex(x)), - } - } -} /// AWG channel pair for use in [`AWG::set_channel_diff_mode`]. #[derive(Copy, Clone, Debug, PartialEq, Eq)] @@ -573,7 +553,7 @@ impl_debug_boring!(AWG); impl AWG { /// Open a new connection to the AWG by index. - pub fn connect(idx: AWGIndex) -> AWGResult<Self> { + pub fn connect(idx: usize) -> AWGResult<Self> { unsafe { ffi::new_awg(idx as i32) .map(|awg| Self { awg }) @@ -596,11 +576,10 @@ impl AWG { } /// Get the AWG card index. - pub fn get_card_idx(&mut self) -> AWGResult<AWGIndex> { + pub fn get_card_idx(&mut self) -> AWGResult<i32> { unsafe { ffi::awg_get_card_idx(self.pinned()) .map_err(AWGError::as_device_err) - .and_then(|idx| idx.try_into()) } } @@ -997,7 +976,7 @@ impl AWG { } /// Initialize sequence replay mode. - pub fn init_replay_mode_seq(&mut self, n_segments: usize) + pub fn init_replay_mode_seq(&mut self, n_segments: u32) -> AWGResult<&mut Self> { unsafe { @@ -1032,70 +1011,90 @@ impl AWG { } /// Write buffered data into a memory segment in sequence replay mode. - pub fn write_seq_mode_segment<'a, P>( + // pub fn write_seq_mode_segment<'a, P>( + // &mut self, + // segment: i32, + // data_buffer: P, + // ) -> AWGResult<&mut Self> + // where P: TryInto<(PageAlignedMem<'a>, u64), Error = AWGError> + // { + // let (mut p_data_buffer, size) = data_buffer.try_into()?; + // unsafe { + // ffi::awg_write_seq_mode_segment( + // self.pinned(), + // segment, + // p_data_buffer.pinned(), + // size as i32, + // ) + // .map_err(AWGError::as_device_err)?; + // Ok(self) + // } + // } + + pub fn write_seq_mode_segment<P>( &mut self, segment: i32, - data_buffer: P, + filename: P, ) -> AWGResult<&mut Self> - where P: TryInto<(PageAlignedMem<'a>, u64), Error = AWGError> + where P: AsRef<Path> { - let (mut p_data_buffer, size) = data_buffer.try_into()?; unsafe { - ffi::awg_write_seq_mode_segment( - self.pinned(), - segment, - p_data_buffer.pinned(), - size as i32, - ) - .map_err(AWGError::as_device_err)?; + let path_osstr: &OsStr = filename.as_ref().as_os_str(); + let path_str: &str + = path_osstr.to_str() + .ok_or(AWGError::PathError(path_osstr.to_os_string()))?; + let_cxx_string!(fname = path_str); + ffi::awg_write_seq_mode_segment(self.pinned(), segment, &fname) + .map_err(AWGError::as_device_err)?; Ok(self) } + } /// Prepare the board for data transfer. - pub fn prep_data_transfer<'a, P>( - &mut self, - data_buffer: P, - buf_type: BufferType, - dir: TransferDir, - notify_size: u32, - board_mem_offs: u64, - ) -> AWGResult<&mut Self> - where P: TryInto<(PageAlignedMem<'a>, u64), Error = AWGError> - { - let (mut p_data_buffer, buffer_len) = data_buffer.try_into()?; - unsafe { - ffi::awg_prep_data_transfer( - self.pinned(), - p_data_buffer.pinned(), - buffer_len, - buf_type as i32, - dir as i32, - notify_size, - board_mem_offs, - ) - .map_err(AWGError::as_device_err)?; - Ok(self) - } - } + // pub fn prep_data_transfer<'a, P>( + // &mut self, + // data_buffer: P, + // buf_type: BufferType, + // dir: TransferDir, + // notify_size: u32, + // board_mem_offs: u64, + // ) -> AWGResult<&mut Self> + // where P: TryInto<(PageAlignedMem<'a>, u64), Error = AWGError> + // { + // let (mut p_data_buffer, buffer_len) = data_buffer.try_into()?; + // unsafe { + // ffi::awg_prep_data_transfer( + // self.pinned(), + // p_data_buffer.pinned(), + // buffer_len, + // buf_type as i32, + // dir as i32, + // notify_size, + // board_mem_offs, + // ) + // .map_err(AWGError::as_device_err)?; + // Ok(self) + // } + // } - /// Start a data transfer. - pub fn start_data_transfer(&mut self) -> AWGResult<&mut Self> { - unsafe { - ffi::awg_start_data_transfer(self.pinned()) - .map_err(AWGError::as_device_err)?; - Ok(self) - } - } + // /// Start a data transfer. + // pub fn start_data_transfer(&mut self) -> AWGResult<&mut Self> { + // unsafe { + // ffi::awg_start_data_transfer(self.pinned()) + // .map_err(AWGError::as_device_err)?; + // Ok(self) + // } + // } - /// Stop the current data transfer. - pub fn stop_data_transfer(&mut self) -> AWGResult<&mut Self> { - unsafe { - ffi::awg_stop_data_transfer(self.pinned()) - .map_err(AWGError::as_device_err)?; - Ok(self) - } - } + // /// Stop the current data transfer. + // pub fn stop_data_transfer(&mut self) -> AWGResult<&mut Self> { + // unsafe { + // ffi::awg_stop_data_transfer(self.pinned()) + // .map_err(AWGError::as_device_err)?; + // Ok(self) + // } + // } /// Set the clock mode. pub fn set_clock_mode(&mut self, mode: ClockMode) -> AWGResult<&mut Self> { @@ -1146,129 +1145,129 @@ impl AWG { pub fn set_trigger_config(&mut self, config: &TriggerConfig) -> AWGResult<&mut Self> { - // validate before actually setting anything - config.check()?; + // config validation should have already been done at this point // channel termination impedance for both channels self.set_trig_term(config.termination)?; // ext0 settings self.set_trig_mode(TriggerChannel::Ext0, config.ext0.mode)?; self.set_trig_level(TriggerChannel::Ext0, config.ext0.level)?; self.set_trig_rearm_level(TriggerChannel::Ext0, config.ext0.rearm_level)?; + self.set_trig_coupling(TriggerChannel::Ext0, config.ext0.coupling)?; // ext1 settings self.set_trig_mode(TriggerChannel::Ext1, config.ext1.mode)?; self.set_trig_level(TriggerChannel::Ext1, config.ext1.level)?; self.set_trig_rearm_level(TriggerChannel::Ext1, config.ext1.rearm_level)?; + self.set_trig_coupling(TriggerChannel::Ext1, config.ext1.coupling)?; // masks + // self.set_trig_mask_and(&config.masks_and)?; self.set_trig_mask_or(&config.masks_or)?; - self.set_trig_mask_and(&config.masks_and)?; Ok(self) } - pub fn set_channels_config(&mut self, channels: &[ChannelConfig]) + pub fn set_channels_config(&mut self, channels: &ChannelConfig) -> AWGResult<&mut Self> { - // validate before actually setting anything - Config::check_channels(channels)?; - // reset all channels - self.set_active_channels([])?; + // config validation should have already been done at this point + let enabled_channels: Vec<usize> + = channels.enabled_channels + .iter() + .enumerate() + .filter_map(|(index, &b)| (b).then_some(index)) + .collect::<Vec<_>>(); // set channel states and params - channels.iter() - .map(|ch| { - self.set_channel( - ch.channel as i32, - ch.amplitude as i32, - ch.stop_level, - ch.enabled, - ) - .map(|_| ()) - }) - .collect::<AWGResult<Vec<()>>>()?; + let enabled_channels_i32: Vec<i32> + = enabled_channels.iter().map(|&ch| ch as i32).collect(); + self.set_active_channels(&enabled_channels_i32)?; + for ch in enabled_channels { + self.set_channel_amp(ch as i32, channels.amplitudes[ch])?; + self.set_channel_stop_level(ch as i32, channels.stop_levels[ch])?; + self.set_channel_output(ch as i32, true)?; + } Ok(self) } pub fn load_sequence_loop_config( &mut self, - sequence_loop: &[SequenceStepConfig], - sampling_rate: Option<u64>, - frequency_resolution: Option<u64>, + sequence_loop: &[SequenceSegmentsConfig], ) -> AWGResult<&mut Self> { - // validate before actually setting anything - if sequence_loop.is_empty() { - eprintln!( - "AWG::load_sequence_loop_config: \ - called on an empty sequence loop" - ); - return Ok(self); - } - Config::check_sequence_steps(sequence_loop)?; + // validition should have already been done at this point // load waveform param data - let waveform_steps: Vec<(WaveformParams, &SequenceStepConfig)> - = sequence_loop.iter() - .map(|step| WaveformParams::load(&step.source).map(|wf| (wf, step))) - .collect::<AWGResult<Vec<_>>>()?; - let sampling_rate - = sampling_rate.unwrap_or_else(|| { - waveform_steps.iter() - .map(|(wf, _)| wf.get_sampling_rate().unwrap()) - .max() - .unwrap() - }); - let frequency_resolution - = frequency_resolution.unwrap_or_else(|| { - waveform_steps.iter() - .map(|(wf, _)| wf.get_frequency_resolution().unwrap()) - .max() - .unwrap() - }); - let n_segments: usize - = 2.0_f64.powi( - (waveform_steps.len() as f64).log2().ceil() as i32 - ) as usize; - - // generate and write waveforms - let waveform_steps: Vec<(ArrayWaveform, &SequenceStepConfig)> - = waveform_steps.into_iter() - .map(|(mut wf_params, step)| { - wf_params.set_sampling_rate(sampling_rate); - wf_params.set_frequency_resolution(frequency_resolution); - wf_params.to_waveform() - .map(|wf| (wf, step)) - }) - .collect::<AWGResult<Vec<_>>>()?; - self.init_replay_mode_seq(n_segments)?; - self.set_sample_rate(sampling_rate as i64)?; - let mut wf_data_ptr: WaveformDataPtr; - for (k, (mut wf, step_conf)) in waveform_steps.into_iter().enumerate() { - wf_data_ptr - = match step_conf.kind { - SequenceKind::Static => wf.get_static_waveform(), - SequenceKind::Trick => todo!(), - }?; - // let (mut mem, size) = wf_data_ptr.into_memsize()?; - self.write_seq_mode_segment(k as i32, wf_data_ptr)?; - // self.write_seq_mode_segment(k as i32, &mut mem, size as i32)?; + // let waveform_steps: Vec<(WaveformParams, &SequenceStepConfig)> + // = sequence_loop.iter() + // .map(|step| WaveformParams::load(&step.source).map(|wf| (wf, step))) + // .collect::<AWGResult<Vec<_>>>()?; + // let sampling_rate + // = sampling_rate.unwrap_or_else(|| { + // waveform_steps.iter() + // .map(|(wf, _)| wf.get_sampling_rate().unwrap()) + // .max() + // .unwrap() + // }); + // let frequency_resolution + // = frequency_resolution.unwrap_or_else(|| { + // waveform_steps.iter() + // .map(|(wf, _)| wf.get_frequency_resolution().unwrap()) + // .max() + // .unwrap() + // }); + // let n_segments: usize + // = 2.0_f64.powi( + // (waveform_steps.len() as f64).log2().ceil() as i32 + // ) as usize; + + // // generate and write waveforms + // let waveform_steps: Vec<(ArrayWaveform, &SequenceStepConfig)> + // = waveform_steps.into_iter() + // .map(|(mut wf_params, step)| { + // wf_params.set_sampling_rate(sampling_rate); + // wf_params.set_frequency_resolution(frequency_resolution); + // wf_params.to_waveform() + // .map(|wf| (wf, step)) + // }) + // .collect::<AWGResult<Vec<_>>>()?; + // self.init_replay_mode_seq(n_segments)?; + // self.set_sample_rate(sampling_rate as i64)?; + // let mut wf_data_ptr: WaveformDataPtr; + // for (k, (mut wf, step_conf)) in waveform_steps.into_iter().enumerate() { + // wf_data_ptr + // = match step_conf.kind { + // SequenceKind::Static => wf.get_static_waveform(), + // SequenceKind::Trick => todo!(), + // }?; + // // let (mut mem, size) = wf_data_ptr.into_memsize()?; + // self.write_seq_mode_segment(k as i32, wf_data_ptr)?; + // // self.write_seq_mode_segment(k as i32, &mut mem, size as i32)?; + // self.set_seq_mode_step( + // k as u64, + // k as u64, + // step_conf.next_step as u64, + // step_conf.n_loop as u64, + // step_conf.condition, + // )?; + // } + for (seg_index, seg_config) in sequence_loop.iter().enumerate() { + self.write_seq_mode_segment(seg_index as i32, &seg_config.source)?; self.set_seq_mode_step( - k as u64, - k as u64, - step_conf.next_step as u64, - step_conf.n_loop as u64, - step_conf.condition, + seg_config.step as u64, + seg_index as u64, + seg_config.next_step as u64, + seg_config.n_loop as u64, + seg_config.loop_condition, )?; } Ok(self) } pub fn set_config(&mut self, config: &Config) -> AWGResult<&mut Self> { + config.check()?; + self.reset()?; self.set_sample_rate(config.sampling_rate as i64)?; self.set_trigger_config(&config.trigger)?; + self.init_replay_mode_seq(config.num_segments)?; + self.load_sequence_loop_config(&config.sequence_segments)?; self.set_channels_config(&config.active_channels)?; - self.load_sequence_loop_config( - &config.sequence_steps, - Some(config.sampling_rate), - Some(config.frequency_resolution), - )?; Ok(self) } @@ -1291,1041 +1290,1039 @@ impl AWG { // } } -/// Safe interface to waveform parameter configuration. -/// -/// All parameters must be initialized before an [`ArrayWaveform`] can be -/// generated: -/// - [`tones`][Self::set_tones]: Frequency tones in hertz -/// - [`phases`][Self::set_phases]: Initial phases for each tone in radians -/// - [`amplitudes`][Self::set_amplitudes]: Amplitudes for each tone -/// - [`sampling_rate`][Self::set_sampling_rate]: Sampling rate in hertz -/// - [`frequency_resolution`][Self::set_frequency_resolution]: Frequency -/// -/// resolution in hertz -#[derive(Clone, Debug)] -pub struct WaveformParams { - tones: Option<Vec<i32>>, - phases: Option<Vec<f64>>, - amplitudes: Option<Vec<f64>>, - sampling_rate: Option<u64>, - frequency_resolution: Option<u64>, -} - -impl Default for WaveformParams { - fn default() -> Self { Self::new() } -} - -impl WaveformParams { - /// Create a new, uninitialized set of waveform parameters. - pub fn new() -> Self { - Self { - tones: None, - phases: None, - amplitudes: None, - sampling_rate: None, - frequency_resolution: None, - } - } - - /// Return `true` if all parameters have been initialized. - pub fn is_init(&self) -> bool { - self.has_tones() - && self.has_phases() - && self.has_amplitudes() - && self.has_sampling_rate() - && self.has_frequency_resolution() - } - - /// Write current parameter settings to a file. - /// - /// The file is formatted as a CSV file: - /// ```text - /// sampling_rate - /// frequency_resolution - /// tones[0],tones[1],... - /// phases[0],phases[1],... - /// amplitudes[0],amplitudes[1],... - /// ``` - /// - /// The given file name must have a `.csv` extension. - pub fn save<P>(&self, outfile: P) -> AWGResult<&Self> - where P: AsRef<Path> - { - self.is_init().then_some(()) - .ok_or(AWGError::WaveformUninit)?; - let outfile = outfile.as_ref(); - outfile.extension().and_then(|ext| (ext == "csv").then_some(())) - .ok_or(AWGError::WaveformCSV(outfile.as_os_str().to_os_string()))?; - let mut out - = fs::OpenOptions::new() - .write(true) - .create(true) - .truncate(true) - .open(outfile) - .map_err(|err| AWGError::WaveformWriteError(err.to_string()))?; - writeln!(&mut out, "{}", self.sampling_rate.unwrap()) - .map_err(|err| AWGError::WaveformWriteError(err.to_string()))?; - writeln!(&mut out, "{}", self.frequency_resolution.unwrap()) - .map_err(|err| AWGError::WaveformWriteError(err.to_string()))?; - writeln!(&mut out, "{}", - self.tones.as_ref().unwrap().iter() - .map(|f| f.to_string()) - .collect::<Vec<String>>() - .join(",") - ) - .map_err(|err| AWGError::WaveformWriteError(err.to_string()))?; - writeln!(&mut out, "{}", - self.phases.as_ref().unwrap().iter() - .map(|ph| ph.to_string()) - .collect::<Vec<String>>() - .join(",") - ) - .map_err(|err| AWGError::WaveformWriteError(err.to_string()))?; - writeln!(&mut out, "{}", - self.amplitudes.as_ref().unwrap().iter() - .map(|a| a.to_string()) - .collect::<Vec<String>>() - .join(",") - ) - .map_err(|err| AWGError::WaveformWriteError(err.to_string()))?; - Ok(self) - } - - /// Load parameter settings from a file. - /// - /// The file is expected as a CSV file: - /// ```text - /// sampling_rate - /// frequency_resolution - /// tones[0],tones[1],... - /// phases[0],phases[1],... - /// amplitudes[0],amplitudes[1],... - /// ``` - /// - /// The given file name must have a `.csv` extension. - pub fn load<P>(infile: P) -> AWGResult<Self> - where P: AsRef<Path> - { - let infile = infile.as_ref(); - infile.extension().and_then(|ext| (ext == "csv").then_some(())) - .ok_or(AWGError::WaveformCSV(infile.as_os_str().to_os_string()))?; - let mut buf = String::new(); - fs::OpenOptions::new() - .read(true) - .open(infile) - .map_err(|err| AWGError::WaveformParseError(err.to_string()))? - .read_to_string(&mut buf) - .map_err(|err| AWGError::WaveformParseError(err.to_string()))?; - let mut lines = buf.split('\n'); - let sampling_rate: u64 - = lines.next() - .ok_or(AWGError::WaveformParseError( - "missing sampling rate".to_string() - ))? - .parse::<u64>() - .map_err(|err| AWGError::WaveformParseError(err.to_string()))?; - let frequency_resolution: u64 - = lines.next() - .ok_or(AWGError::WaveformParseError( - "missing frequency resolution".to_string() - ))? - .parse::<u64>() - .map_err(|err| AWGError::WaveformParseError(err.to_string()))?; - let tones: Vec<i32> - = lines.next() - .ok_or(AWGError::WaveformParseError( - "missing frequency tones".to_string() - ))? - .split(',') - .map(|f| { - f.parse::<i32>() - .map_err(|err| AWGError::WaveformParseError(err.to_string())) - }) - .collect::<AWGResult<Vec<i32>>>()?; - let phases: Vec<f64> - = lines.next() - .ok_or(AWGError::WaveformParseError( - "missing phases".to_string() - ))? - .split(',') - .map(|ph| { - ph.parse::<f64>() - .map_err(|err| AWGError::WaveformParseError(err.to_string())) - }) - .collect::<AWGResult<Vec<f64>>>()?; - let amplitudes: Vec<f64> - = lines.next() - .ok_or(AWGError::WaveformParseError( - "missing amplitudes".to_string() - ))? - .split(',') - .map(|a| { - a.parse::<f64>() - .map_err(|err| AWGError::WaveformParseError(err.to_string())) - }) - .collect::<AWGResult<Vec<f64>>>()?; - let data = Self { - tones: Some(tones), - phases: Some(phases), - amplitudes: Some(amplitudes), - sampling_rate: Some(sampling_rate), - frequency_resolution: Some(frequency_resolution), - }; - Ok(data) - } - - /// Return `true` if frequency tones have been initialized. - pub fn has_tones(&self) -> bool { self.tones.is_some() } - - /// Get the frequency tones in hertz, if initialized. - pub fn get_tones(&self) -> Option<&Vec<i32>> { - self.tones.as_ref() - } - - /// Set the frequency tones in hertz. - pub fn set_tones<'a, I>(&mut self, tones: I) -> AWGResult<&mut Self> - where I: IntoIterator<Item = &'a i32> - { - let tones: Vec<i32> = tones.into_iter().copied().collect(); - if let Some(phases) = &self.phases { - (tones.len() == phases.len()).then_some(()) - .ok_or(AWGError::NumTones)?; - } - if let Some(amplitudes) = &self.amplitudes { - (tones.len() == amplitudes.len()).then_some(()) - .ok_or(AWGError::NumTones)?; - } - self.tones = Some(tones); - Ok(self) - } - - /// Set the frequency tones using a center frequency and a uniform spacing, - /// both in hertz. - pub fn set_tones_spaced(&mut self, center: i32, spacing: i32, num: usize) - -> AWGResult<&mut Self> - { - if let Some(phases) = &self.phases { - (num == phases.len()).then_some(()) - .ok_or(AWGError::NumTones)?; - } - if let Some(amplitudes) = &self.amplitudes { - (num == amplitudes.len()).then_some(()) - .ok_or(AWGError::NumTones)?; - } - let f0: i32 = center - spacing * num as i32 / 2; - let tones: Vec<i32> - = (0..num as i32).map(|k| f0 + spacing * k).collect(); - self.tones = Some(tones); - Ok(self) - } - - /// Return `true` if initial phases have been initialized. - pub fn has_phases(&self) -> bool { self.phases.is_some() } - - /// Get the initial phases of each tone in radians. - pub fn get_phases(&self) -> Option<&Vec<f64>> { - self.phases.as_ref() - } - - /// Set the initial phases of each tone in radians. - pub fn set_phases<'a, I>(&mut self, phases: I) -> AWGResult<&mut Self> - where I: IntoIterator<Item = &'a f64> - { - let phases: Vec<f64> - = phases.into_iter().copied().map(|ph| ph % TAU).collect(); - if let Some(tones) = &self.tones { - (phases.len() == tones.len()).then_some(()) - .ok_or(AWGError::NumPhases)?; - } - if let Some(amplitudes) = &self.amplitudes { - (phases.len() == amplitudes.len()).then_some(()) - .ok_or(AWGError::NumPhases)?; - } - self.phases = Some(phases); - Ok(self) - } - - /// Return `true` if amplitudes have been initialized. - pub fn has_amplitudes(&self) -> bool { self.amplitudes.is_some() } - - /// Get the amplitudes of each tone. - pub fn get_amplitudes(&self) -> Option<&Vec<f64>> { - self.amplitudes.as_ref() - } - - /// Set the amplitudes of each tone. - /// - /// Each amplitude must lie in the range `[0, 2^15 - 1)`. - pub fn set_amplitudes<'a, I>(&mut self, amplitudes: I) - -> AWGResult<&mut Self> - where I: IntoIterator<Item = &'a f64> - { - let amplitudes: Vec<f64> - = amplitudes.into_iter().copied() - .map(|a| { - (0.0..32767.0).contains(&a) - .then_some(a) - .ok_or(AWGError::InvalidAmplitude(a)) - }) - .collect::<AWGResult<Vec<f64>>>()?; - if let Some(tones) = &self.tones { - (amplitudes.len() == tones.len()).then_some(()) - .ok_or(AWGError::NumAmplitudes)?; - } - if let Some(phases) = &self.phases { - (amplitudes.len() == phases.len()).then_some(()) - .ok_or(AWGError::NumAmplitudes)?; - } - self.amplitudes = Some(amplitudes); - Ok(self) - } - - /// Return `true` if the sampling rate has been initialized. - pub fn has_sampling_rate(&self) -> bool { - self.sampling_rate.is_some() - } - - /// Get the sampling rate in hertz. - pub fn get_sampling_rate(&self) -> Option<u64> { - self.sampling_rate - } - - /// Set the sampling rate in hertz. - pub fn set_sampling_rate(&mut self, sampling_rate: u64) -> &mut Self { - self.sampling_rate = Some(sampling_rate); - self - } - - /// Return `true` if the frequency resolution has been initialized. - pub fn has_frequency_resolution(&self) -> bool { - self.frequency_resolution.is_some() - } - - /// Get the frequency resolution in hertz. - pub fn get_frequency_resolution(&self) -> Option<u64> { - self.frequency_resolution - } - - /// Set the frequency resolution in hertz. - pub fn set_frequency_resolution(&mut self, resolution: u64) -> &mut Self { - self.frequency_resolution = Some(resolution); - self - } - - /// Generate an [`ArrayWaveform`] from the current set of parameters if all - /// have been initialized. - pub fn to_waveform(&self) -> AWGResult<ArrayWaveform> { - self.is_init().then_some(()) - .ok_or(AWGError::WaveformUninit)?; - let mut waveform = ArrayWaveform::new_uninit(); - waveform - .set_freq_tones(self.tones.as_ref().unwrap())? - .set_phases(self.phases.as_ref().unwrap())? - .set_amplitudes(self.amplitudes.as_ref().unwrap())? - .set_sampling_rate(self.sampling_rate.unwrap())? - .set_freq_resolution(self.frequency_resolution.unwrap())?; - Ok(waveform) - } -} - -impl TryFrom<&WaveformParams> for ArrayWaveform { - type Error = AWGError; - - fn try_from(params: &WaveformParams) -> AWGResult<Self> { - params.to_waveform() - } -} - -impl TryFrom<WaveformParams> for ArrayWaveform { - type Error = AWGError; - - fn try_from(params: WaveformParams) -> AWGResult<Self> { - params.to_waveform() - } -} - -impl fmt::Display for WaveformParams { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - writeln!(f, "WaveformParams {{")?; - - write!(f, " tones: [")?; - if let Some(tones) = &self.tones { - let n = tones.len(); - for (k, tone) in tones.iter().enumerate() { - tone.fmt(f)?; - if k < n - 1 { write!(f, ", ")?; } - } - } else { - write!(f, "<uninit>")?; - } - writeln!(f, "],")?; - - write!(f, " phases: [")?; - if let Some(phases) = &self.phases { - let n = phases.len(); - for (k, phase) in phases.iter().enumerate() { - phase.fmt(f)?; - if k < n - 1 { write!(f, ", ")?; } - } - } else { - write!(f, "<uninit>")?; - } - writeln!(f, "],")?; - - write!(f, " amplitudes: [")?; - if let Some(amplitudes) = &self.amplitudes { - let n = amplitudes.len(); - for (k, amplitude) in amplitudes.iter().enumerate() { - amplitude.fmt(f)?; - if k < n - 1 { write!(f, ", ")?; } - } - } else { - write!(f, "<uninit>")?; - } - writeln!(f, "],")?; - - write!(f, " sampling_rate: ")?; - if let Some(sampling_rate) = self.sampling_rate { - sampling_rate.fmt(f)?; - } else { - write!(f, "<uninit>")?; - } - writeln!(f, ",")?; - - write!(f, " frequency_resolution: ")?; - if let Some(frequency_resolution) = self.frequency_resolution { - frequency_resolution.fmt(f)?; - } else { - write!(f, "<uninit>")?; - } - writeln!(f, ",")?; - - write!(f, "}}")?; - Ok(()) - } -} - -/// Data type for array waveform generation. -pub struct ArrayWaveform { - data: UniquePtr<ffi::ArrayWaveform>, -} - -impl_debug_boring!(ArrayWaveform); - -impl Default for ArrayWaveform { - fn default() -> Self { Self::new_uninit() } -} - -impl ArrayWaveform { - fn pinned(&mut self) -> Pin<&mut ffi::ArrayWaveform> { self.data.pin_mut() } - - /// Create a new, uninitialized waveform. - /// - /// # Safety - /// After this constructor is called, all private member variables are set - /// to 0 or `nullptr` values. It is the programmer's responsibility to - /// ensure that all properties and memory addresses are properly - /// initialized. - fn new_uninit() -> Self { - unsafe { - Self { data: ffi::new_arraywaveform().unwrap() } - } - } - - /// Get a pointer to the associated data buffer. - pub fn get_data_buffer(&mut self) -> AWGResult<PageAlignedMem> { - unsafe { - ffi::arraywaveform_get_data_buffer(self.pinned()) - .map(|ptr| PageAlignedMem { ptr, wf_ref: self }) - .map_err(AWGError::as_waveform_err) - } - } - - /// Get the number of samples in the current waveform. - pub fn get_data_len(&mut self) -> AWGResult<u64> { - unsafe { - ffi::arraywaveform_get_data_len(self.pinned()) - .map(|len| len as u64) - .map_err(AWGError::as_waveform_err) - } - } - - /// Set the sampling rate in hertz. - fn set_sampling_rate(&mut self, rate: u64) -> AWGResult<&mut Self> { - unsafe { - ffi::arraywaveform_set_sampling_rate(self.pinned(), rate) - .map_err(AWGError::as_waveform_err)?; - Ok(self) - } - } - - /// Get the sampling rate in hertz. - pub fn get_sampling_rate(&mut self) -> AWGResult<u64> { - unsafe { - ffi::arraywaveform_get_sampling_rate(self.pinned()) - .map_err(AWGError::as_waveform_err) - } - } - - /// Set the frequency resolution in hertz. - fn set_freq_resolution(&mut self, resolution: u64) - -> AWGResult<&mut Self> - { - unsafe { - ffi::arraywaveform_set_freq_resolution(self.pinned(), resolution) - .map_err(AWGError::as_waveform_err)?; - Ok(self) - } - } - - /// Get the frequency resolution in hertz. - pub fn get_freq_resolution(&mut self) -> AWGResult<u64> { - unsafe { - ffi::arraywaveform_get_freq_resolution(self.pinned()) - .map_err(AWGError::as_waveform_err) - } - } - - /// Set the constituent tones using a fixed center frequency and uniform - /// spacing in hertz. - fn set_freq_tones_spaced( - &mut self, - center: i32, - spacing: i32, - num_tones: u16, - ) -> AWGResult<&mut Self> - { - unsafe { - ffi::arraywaveform_set_freq_tones_spaced( - self.pinned(), center, spacing, num_tones.into()) - .map_err(AWGError::as_waveform_err)?; - Ok(self) - } - } - - /// Set the constituent tones to arbitrary values in hertz. - fn set_freq_tones<'a, I>(&mut self, tones: I) -> AWGResult<&mut Self> - where I: IntoIterator<Item = &'a i32> - { - unsafe { - let tones_cxx: UniquePtr<CxxVector<i32>> - = collect_cxx_vector(tones); - ffi::arraywaveform_set_freq_tones( - self.pinned(), tones_cxx.as_ref().unwrap()) - .map_err(AWGError::as_waveform_err)?; - Ok(self) - } - } - - /// Get a list of contituent tones. - pub fn get_freq_tones(&mut self) -> AWGResult<Vec<i32>> { - unsafe { - ffi::arraywaveform_get_freq_tones(self.pinned()) - .map_err(AWGError::as_waveform_err) - } - } - - /// Set the initial phases in radians of all tones. - fn set_phases<'a, I>(&mut self, phases: I) -> AWGResult<&mut Self> - where I: IntoIterator<Item = &'a f64> - { - unsafe { - let phases_cxx: UniquePtr<CxxVector<f64>> - = collect_cxx_vector(phases); - ffi::arraywaveform_set_phases( - self.pinned(), phases_cxx.as_ref().unwrap()) - .map_err(AWGError::as_waveform_err)?; - Ok(self) - } - } - - /// Get a list of initial phases in radians for each tone. - pub fn get_phases(&mut self) -> AWGResult<Vec<f64>> { - unsafe { - ffi::arraywaveform_get_phases(self.pinned()) - .map_err(AWGError::as_waveform_err) - } - } - - /// Set the amplitudes of all tones. - /// - /// Each amplitude must be in the range `[0, 2^15 - 1)` - fn set_amplitudes<'a, I>(&mut self, amplitudes: I) - -> AWGResult<&mut Self> - where I: IntoIterator<Item = &'a f64> - { - unsafe { - let amplitudes: Vec<f64> - = amplitudes.into_iter().copied() - .map(|a| { - (0.0..32767.0).contains(&a) - .then_some(a) - .ok_or(AWGError::InvalidAmplitude(a)) - }) - .collect::<AWGResult<Vec<f64>>>()?; - let amplitudes_cxx: UniquePtr<CxxVector<f64>> - = collect_cxx_vector(&litudes); - ffi::arraywaveform_set_amplitudes( - self.pinned(), amplitudes_cxx.as_ref().unwrap()) - .map_err(AWGError::as_waveform_err)?; - Ok(self) - } - } - - /// Get a list of amplitudes for each tone. - pub fn get_amplitudes(&mut self) -> AWGResult<Vec<f64>> { - unsafe { - ffi::arraywaveform_get_amplitudes(self.pinned()) - .map_err(AWGError::as_waveform_err) - } - } - - /// Set phases to 0 and amplitudes to 2000. - fn set_default_params(&mut self) -> AWGResult<&mut Self> { - unsafe { - ffi::arraywaveform_set_default_params(self.pinned()) - .map_err(AWGError::as_waveform_err)?; - Ok(self) - } - } - - /// Save the current waveform parameters to a file in CSV format. - fn save_params<P>(&mut self, filename: P) -> AWGResult<&mut Self> - where P: AsRef<Path> - { - unsafe { - let path_osstr: &OsStr = filename.as_ref().as_os_str(); - let path_str: &str - = path_osstr.to_str() - .ok_or(AWGError::PathError(path_osstr.to_os_string()))?; - path_str.ends_with(".csv").then_some(()) - .ok_or(AWGError::WaveformCSV(path_osstr.to_os_string()))?; - let_cxx_string!(fname = path_str); - ffi::arraywaveform_save_params(self.pinned(), &fname) - .map_err(AWGError::as_waveform_err)?; - Ok(self) - } - } - - /// Load waveform parameters from a file. - /// - /// The file must be in CSV format. - fn load_params<P>(&mut self, filename: P) -> AWGResult<&mut Self> - where P: AsRef<Path> - { - unsafe { - let path_osstr: &OsStr = filename.as_ref().as_os_str(); - let path_str: &str - = path_osstr.to_str() - .ok_or(AWGError::PathError(path_osstr.to_os_string()))?; - path_str.ends_with(".csv").then_some(()) - .ok_or(AWGError::WaveformCSV(path_osstr.to_os_string()))?; - let_cxx_string!(fname = path_str); - ffi::arraywaveform_load_params(self.pinned(), &fname) - .map_err(AWGError::as_waveform_err)?; - Ok(self) - } - } - - /// Print the current waveform parameters. - pub fn print_params(&mut self) -> AWGResult<&mut Self> { - unsafe { - ffi::arraywaveform_print_params(self.pinned()) - .map_err(AWGError::as_waveform_err)?; - Ok(self) - } - } - - /// Get the minimum data length that fulfills rounding constraints for the - /// given sampling rate and frequency resolution (in hertz). - pub fn get_min_sample_len( - &mut self, - sampling_rate: u64, - frequency_resolution: u64, - ) -> AWGResult<u64> - { - unsafe { - ffi::arraywaveform_get_min_sample_len( - self.pinned(), sampling_rate, frequency_resolution) - .map_err(AWGError::as_waveform_err) - } - } - - /// Get a data array length close to the specified runtime tau (in seconds) - /// that also fulfills rounding constraints for the given sampling rate and - /// frequency resolution (in hertz). - pub fn get_sample_len( - &mut self, - tau: f64, - sampling_rate: u64, - frequency_resolution: u64, - ) -> AWGResult<u64> - { - unsafe { - ffi::arraywaveform_get_sample_len( - self.pinned(), tau, sampling_rate, frequency_resolution) - .map_err(AWGError::as_waveform_err) - } - } - - /// Generate a static frequency waveform from the current set of parameters. - /// - /// The returned [`WaveformDataPtr`] is passed a reference to `self` upon - /// creation for safety. - pub fn get_static_waveform(&mut self) -> AWGResult<WaveformDataPtr> { - unsafe { - ffi::arraywaveform_get_static_waveform(self.pinned()) - .map(|ptr| WaveformDataPtr { ptr, wf_ref: &*self }) - .map_err(AWGError::as_waveform_err) - } - } - - /// Generate a tricky-trick waveform from the current set of parameters. - /// - /// - `sites`: Iterable of array site indices for which the tricky-trick - /// will be performed - /// - `df`: Frequency to move by in hertz - /// - `tau_move`: Moving time in seconds - /// - `tau_stay`: Wait time in seconds - /// - /// The returned [`WaveformDataPtr`] is passed a reference to `self` upon - /// creation for safety. - pub fn get_trick_waveform<'a, I>( - &mut self, - sites: I, - df: f64, - tau_move: f64, - tau_stay: f64, - ) -> AWGResult<WaveformDataPtr> - where I: IntoIterator<Item = &'a i32> - { - unsafe { - let sites_cxx: UniquePtr<CxxVector<i32>> - = collect_cxx_vector(sites); - ffi::arraywaveform_get_trick_waveform( - self.pinned(), - sites_cxx.as_ref().unwrap(), - df, - tau_move, - tau_stay, - ) - .map(|ptr| WaveformDataPtr { ptr, wf_ref: &*self }) - .map_err(AWGError::as_waveform_err) - } - } - - /// Save the generated waveform to a CSV-formatted file. - pub fn save_waveform<P>(&mut self, filename: P) -> AWGResult<&mut Self> - where P: AsRef<Path> - { - unsafe { - let path_osstr: &OsStr = filename.as_ref().as_os_str(); - let path_str: &str - = path_osstr.to_str() - .ok_or(AWGError::PathError(path_osstr.to_os_string()))?; - path_str.ends_with(".csv").then_some(()) - .ok_or(AWGError::WaveformCSV(path_osstr.to_os_string()))?; - let_cxx_string!(fname = path_str); - ffi::arraywaveform_save_waveform(self.pinned(), &fname) - .map_err(AWGError::as_waveform_err)?; - Ok(self) - } - } -} - -/// Parameters to the tweezer uniformization routine. -/// -/// All parameters must be initialized before they can be passed to -/// [`run_uniformization`]: -/// - [`source`][Self::set_source] source waveform file -/// - [`polarizability`][Self::set_polarizability] expected atomic -/// polarizability of the 3P1 ∣F = 3/2, mF = -3/2⟩ state in kHz/μK -/// - [`mean_depth`][Self::set_mean_depth] target mean tweezer depth in -/// μK -/// - [`step_size`][Self::set_step_size] step size to use for the optimization -/// algorithm -/// - [`error_threshold`][Self::set_error_threshold] threshold for termination -/// to use in the optimization algorithm -/// - [`max_iters`][Self::set_max_iters] maximum number of iterations to use in -/// the optimization algorithm -/// - [`num_imaging_avg`][Self::set_num_imaging_avg] number of Basler images to -/// average for tweezer power measurements -/// - [`num_tweezers`][Self::set_num_tweezers] tweezer array size -#[derive(Clone, Debug)] -pub struct UniformizationParams { - source: Option<PathBuf>, - polarizability: Option<f64>, - mean_depth: Option<f64>, - step_size: Option<f64>, - error_threshold: Option<f64>, - max_iters: Option<usize>, - num_imaging_avg: Option<usize>, - num_tweezers: Option<usize>, -} - -impl Default for UniformizationParams { - fn default() -> Self { Self::new() } -} - -impl UniformizationParams { - /// Create a new, uninitialized uniformization config. - pub fn new() -> Self { - Self { - source: None, - polarizability: None, - mean_depth: None, - step_size: None, - error_threshold: None, - max_iters: None, - num_imaging_avg: None, - num_tweezers: None, - } - } - - #[allow(clippy::too_many_arguments)] - pub fn new_all<P>( - source: P, - polarizability: f64, - mean_depth: f64, - step_size: f64, - error_threshold: f64, - max_iters: usize, - num_imaging_avg: usize, - num_tweezers: usize, - ) -> Self - where P: AsRef<Path> - { - Self { - source: Some(source.as_ref().to_path_buf()), - polarizability: Some(polarizability), - mean_depth: Some(mean_depth), - step_size: Some(step_size), - error_threshold: Some(error_threshold), - max_iters: Some(max_iters), - num_imaging_avg: Some(num_imaging_avg), - num_tweezers: Some(num_tweezers), - } - } - - /// Return `true` if all parameters have been initialized. - pub fn is_init(&self) -> bool { - self.has_source() - && self.has_polarizability() - && self.has_mean_depth() - && self.has_step_size() - && self.has_error_threshold() - && self.has_max_iters() - && self.has_num_imaging_avg() - && self.has_num_tweezers() - } - - /// Return `true` if the source waveform file has been set. - pub fn has_source(&self) -> bool { self.source.is_some() } - - /// Get the source waveform file. - pub fn get_source(&self) -> Option<&PathBuf> { - self.source.as_ref() - } - - /// Set the source waveform file. - pub fn set_source<P>(&mut self, source: P) -> AWGResult<&mut Self> - where P: AsRef<Path> - { - let source = source.as_ref().to_path_buf(); - let source_string = source.display().to_string(); - source.exists().then_some(()) - .ok_or(AWGError::InvalidUniformizationSource(source_string))?; - self.source = Some(source); - Ok(self) - } - - /// Return `true` if the polarizability has been set. - pub fn has_polarizability(&self) -> bool { self.polarizability.is_some() } - - /// Get the polarizability in kHz/μK. - pub fn get_polarizability(&self) -> Option<f64> { self.polarizability } - - /// Set the polarizability in kHz/μK. - pub fn set_polarizability(&mut self, polarizability: f64) - -> AWGResult<&mut Self> - { - (polarizability < 0.0).then_some(()) - .ok_or(AWGError::InvalidPolarizability(polarizability))?; - self.polarizability = Some(polarizability); - Ok(self) - } - - /// Return `true` if the mean tweezer depth has been set. - pub fn has_mean_depth(&self) -> bool { self.mean_depth.is_some() } - - /// Get the mean tweezer depth in μK. - pub fn get_mean_depth(&self) -> Option<f64> { self.mean_depth } - - pub fn set_mean_depth(&mut self, mean_depth: f64) -> AWGResult<&mut Self> { - (mean_depth > 0.0).then_some(()) - .ok_or(AWGError::InvalidMeanDepth(mean_depth))?; - self.mean_depth = Some(mean_depth); - Ok(self) - } - - /// Return `true` if the step size has been set. - pub fn has_step_size(&self) -> bool { self.step_size.is_some() } - - /// Get the step size. - pub fn get_step_size(&self) -> Option<f64> { self.step_size } - - /// Set the step size. - pub fn set_step_size(&mut self, step_size: f64) -> AWGResult<&mut Self> { - (step_size > 0.0).then_some(()) - .ok_or(AWGError::InvalidStepSize(step_size))?; - self.step_size = Some(step_size); - Ok(self) - } - - /// Return `true` if the error threshold has been set. - pub fn has_error_threshold(&self) -> bool { self.error_threshold.is_some() } - - /// Get the error threshold. - pub fn get_error_threshold(&self) -> Option<f64> { self.error_threshold } - - pub fn set_error_threshold(&mut self, error_threshold: f64) - -> AWGResult<&mut Self> - { - (error_threshold > 0.0).then_some(()) - .ok_or(AWGError::InvalidErrorThreshold(error_threshold))?; - self.error_threshold = Some(error_threshold); - Ok(self) - } - - /// Return `true` if the maximum iterations has been set. - pub fn has_max_iters(&self) -> bool { self.max_iters.is_some() } - - /// Get the max iters. - pub fn get_max_iters(&self) -> Option<usize> { self.max_iters } - - /// Set the max iters. - pub fn set_max_iters(&mut self, max_iters: usize) -> AWGResult<&mut Self> { - (max_iters > 0).then_some(()) - .ok_or(AWGError::InvalidMaxIters(max_iters))?; - self.max_iters = Some(max_iters); - Ok(self) - } - - /// Return `true` if the number of tweezer images to average has been set. - pub fn has_num_imaging_avg(&self) -> bool { self.num_imaging_avg.is_some() } - - /// Get the number of images to average over. - pub fn get_num_imaging_avg(&self) -> Option<usize> { self.num_imaging_avg } - - /// Set the number of images to average over. - pub fn set_num_imaging_avg(&mut self, num_imaging_avg: usize) - -> AWGResult<&mut Self> - { - (num_imaging_avg > 0).then_some(()) - .ok_or(AWGError::InvalidNumImagingAvg(num_imaging_avg))?; - self.num_imaging_avg = Some(num_imaging_avg); - Ok(self) - } - - pub fn has_num_tweezers(&self) -> bool { self.num_tweezers.is_some() } - - /// Get the number of tweezers. - pub fn get_num_tweezers(&self) -> Option<usize> { self.num_tweezers } - - /// Set the number of tweezers. - pub fn set_num_tweezers(&mut self, num_tweezers: usize) - -> AWGResult<&mut Self> - { - (num_tweezers > 0).then_some(()) - .ok_or(AWGError::InvalidNumTweezers(num_tweezers))?; - self.num_tweezers = Some(num_tweezers); - Ok(self) - } - - /// Convert to the corresponding C++ data type. - fn to_ffi_type(&self) -> AWGResult<UniquePtr<ffi::UniformizationParams>> { - self.check()?; - let source_osstr: &OsStr = self.source.as_ref().unwrap().as_os_str(); - let source_str: &str - = source_osstr.to_str() - .ok_or(AWGError::PathError(source_osstr.to_os_string()))?; - let_cxx_string!(source = source_str); - unsafe { - let ffi_params: UniquePtr<ffi::UniformizationParams> - = ffi::new_uniformizationparams( - &source, - self.polarizability.unwrap(), - self.mean_depth.unwrap(), - self.step_size.unwrap(), - self.error_threshold.unwrap(), - self.max_iters.unwrap() as i32, - self.num_imaging_avg.unwrap() as i32, - self.num_tweezers.unwrap() as i32, - ) - .map_err(AWGError::as_uniformization_err)?; - Ok(ffi_params) - } - } - - /// Check that all necessary conditions are satisfied. - pub fn check(&self) -> AWGResult<()> { - self.is_init().then_some(()) - .ok_or(AWGError::UniformizationUninit)?; - if let Some(source) = self.source.as_ref() { - let source_string = source.display().to_string(); - source.exists().then_some(()) - .ok_or(AWGError::InvalidUniformizationSource(source_string))?; - } - if let Some(polarizability) = self.polarizability { - (polarizability < 0.0).then_some(()) - .ok_or(AWGError::InvalidPolarizability(polarizability))?; - } - if let Some(mean_depth) = self.mean_depth { - (mean_depth > 0.0).then_some(()) - .ok_or(AWGError::InvalidMeanDepth(mean_depth))?; - } - if let Some(step_size) = self.step_size { - (step_size > 0.0).then_some(()) - .ok_or(AWGError::InvalidStepSize(step_size))?; - } - if let Some(error_threshold) = self.error_threshold { - (error_threshold > 0.0).then_some(()) - .ok_or(AWGError::InvalidErrorThreshold(error_threshold))?; - } - if let Some(max_iters) = self.max_iters { - (max_iters > 0).then_some(()) - .ok_or(AWGError::InvalidMaxIters(max_iters))?; - } - if let Some(num_imaging_avg) = self.num_imaging_avg { - (num_imaging_avg > 0).then_some(()) - .ok_or(AWGError::InvalidNumImagingAvg(num_imaging_avg))?; - } - if let Some(num_tweezers) = self.num_tweezers { - (num_tweezers > 0).then_some(()) - .ok_or(AWGError::InvalidNumTweezers(num_tweezers))?; - } - Ok(()) - } -} - -pub fn run_uniformization<A, B>( - mut awg: A, - mut basler: B, - waveform: &mut ArrayWaveform, - params: &UniformizationParams, -) -> AWGResult<()> -where - A: std::ops::DerefMut<Target = AWG>, - B: std::ops::DerefMut<Target = Basler>, -{ - unsafe { - ffi::run_uniformization( - awg.deref_mut().pinned(), - basler.deref_mut().pinned(), - waveform.pinned(), - params.to_ffi_type()?.as_ref().unwrap(), - ) - .map_err(AWGError::as_uniformization_err) - } -} - +// Safe interface to waveform parameter configuration. +// +// All parameters must be initialized before an [`ArrayWaveform`] can be +// generated: +// - [`tones`][Self::set_tones]: Frequency tones in hertz +// - [`phases`][Self::set_phases]: Initial phases for each tone in radians +// - [`amplitudes`][Self::set_amplitudes]: Amplitudes for each tone +// - [`sampling_rate`][Self::set_sampling_rate]: Sampling rate in hertz +// - [`frequency_resolution`][Self::set_frequency_resolution]: Frequency resolution in hertz + +// #[derive(Clone, Debug)] +// pub struct WaveformParams { +// tones: Option<Vec<i32>>, +// phases: Option<Vec<f64>>, +// amplitudes: Option<Vec<f64>>, +// sampling_rate: Option<u64>, +// frequency_resolution: Option<u64>, +// } + +// impl Default for WaveformParams { +// fn default() -> Self { Self::new() } +// } + +// impl WaveformParams { +// /// Create a new, uninitialized set of waveform parameters. +// pub fn new() -> Self { +// Self { +// tones: None, +// phases: None, +// amplitudes: None, +// sampling_rate: None, +// frequency_resolution: None, +// } +// } + +// /// Return `true` if all parameters have been initialized. +// pub fn is_init(&self) -> bool { +// self.has_tones() +// && self.has_phases() +// && self.has_amplitudes() +// && self.has_sampling_rate() +// && self.has_frequency_resolution() +// } + +// /// Write current parameter settings to a file. +// /// +// /// The file is formatted as a CSV file: +// /// ```text +// /// sampling_rate +// /// frequency_resolution +// /// tones[0],tones[1],... +// /// phases[0],phases[1],... +// /// amplitudes[0],amplitudes[1],... +// /// ``` +// /// +// /// The given file name must have a `.csv` extension. +// pub fn save<P>(&self, outfile: P) -> AWGResult<&Self> +// where P: AsRef<Path> +// { +// self.is_init().then_some(()) +// .ok_or(AWGError::WaveformUninit)?; +// let outfile = outfile.as_ref(); +// outfile.extension().and_then(|ext| (ext == "csv").then_some(())) +// .ok_or(AWGError::WaveformCSV(outfile.as_os_str().to_os_string()))?; +// let mut out +// = fs::OpenOptions::new() +// .write(true) +// .create(true) +// .truncate(true) +// .open(outfile) +// .map_err(|err| AWGError::WaveformWriteError(err.to_string()))?; +// writeln!(&mut out, "{}", self.sampling_rate.unwrap()) +// .map_err(|err| AWGError::WaveformWriteError(err.to_string()))?; +// writeln!(&mut out, "{}", self.frequency_resolution.unwrap()) +// .map_err(|err| AWGError::WaveformWriteError(err.to_string()))?; +// writeln!(&mut out, "{}", +// self.tones.as_ref().unwrap().iter() +// .map(|f| f.to_string()) +// .collect::<Vec<String>>() +// .join(",") +// ) +// .map_err(|err| AWGError::WaveformWriteError(err.to_string()))?; +// writeln!(&mut out, "{}", +// self.phases.as_ref().unwrap().iter() +// .map(|ph| ph.to_string()) +// .collect::<Vec<String>>() +// .join(",") +// ) +// .map_err(|err| AWGError::WaveformWriteError(err.to_string()))?; +// writeln!(&mut out, "{}", +// self.amplitudes.as_ref().unwrap().iter() +// .map(|a| a.to_string()) +// .collect::<Vec<String>>() +// .join(",") +// ) +// .map_err(|err| AWGError::WaveformWriteError(err.to_string()))?; +// Ok(self) +// } + +// /// Load parameter settings from a file. +// /// +// /// The file is expected as a CSV file: +// /// ```text +// /// sampling_rate +// /// frequency_resolution +// /// tones[0],tones[1],... +// /// phases[0],phases[1],... +// /// amplitudes[0],amplitudes[1],... +// /// ``` +// /// +// /// The given file name must have a `.csv` extension. +// pub fn load<P>(infile: P) -> AWGResult<Self> +// where P: AsRef<Path> +// { +// let infile = infile.as_ref(); +// infile.extension().and_then(|ext| (ext == "csv").then_some(())) +// .ok_or(AWGError::WaveformCSV(infile.as_os_str().to_os_string()))?; +// let mut buf = String::new(); +// fs::OpenOptions::new() +// .read(true) +// .open(infile) +// .map_err(|err| AWGError::WaveformParseError(err.to_string()))? +// .read_to_string(&mut buf) +// .map_err(|err| AWGError::WaveformParseError(err.to_string()))?; +// let mut lines = buf.split('\n'); +// let sampling_rate: u64 +// = lines.next() +// .ok_or(AWGError::WaveformParseError( +// "missing sampling rate".to_string() +// ))? +// .parse::<u64>() +// .map_err(|err| AWGError::WaveformParseError(err.to_string()))?; +// let frequency_resolution: u64 +// = lines.next() +// .ok_or(AWGError::WaveformParseError( +// "missing frequency resolution".to_string() +// ))? +// .parse::<u64>() +// .map_err(|err| AWGError::WaveformParseError(err.to_string()))?; +// let tones: Vec<i32> +// = lines.next() +// .ok_or(AWGError::WaveformParseError( +// "missing frequency tones".to_string() +// ))? +// .split(',') +// .map(|f| { +// f.parse::<i32>() +// .map_err(|err| AWGError::WaveformParseError(err.to_string())) +// }) +// .collect::<AWGResult<Vec<i32>>>()?; +// let phases: Vec<f64> +// = lines.next() +// .ok_or(AWGError::WaveformParseError( +// "missing phases".to_string() +// ))? +// .split(',') +// .map(|ph| { +// ph.parse::<f64>() +// .map_err(|err| AWGError::WaveformParseError(err.to_string())) +// }) +// .collect::<AWGResult<Vec<f64>>>()?; +// let amplitudes: Vec<f64> +// = lines.next() +// .ok_or(AWGError::WaveformParseError( +// "missing amplitudes".to_string() +// ))? +// .split(',') +// .map(|a| { +// a.parse::<f64>() +// .map_err(|err| AWGError::WaveformParseError(err.to_string())) +// }) +// .collect::<AWGResult<Vec<f64>>>()?; +// let data = Self { +// tones: Some(tones), +// phases: Some(phases), +// amplitudes: Some(amplitudes), +// sampling_rate: Some(sampling_rate), +// frequency_resolution: Some(frequency_resolution), +// }; +// Ok(data) +// } + +// /// Return `true` if frequency tones have been initialized. +// pub fn has_tones(&self) -> bool { self.tones.is_some() } + +// /// Get the frequency tones in hertz, if initialized. +// pub fn get_tones(&self) -> Option<&Vec<i32>> { +// self.tones.as_ref() +// } + +// /// Set the frequency tones in hertz. +// pub fn set_tones<'a, I>(&mut self, tones: I) -> AWGResult<&mut Self> +// where I: IntoIterator<Item = &'a i32> +// { +// let tones: Vec<i32> = tones.into_iter().copied().collect(); +// if let Some(phases) = &self.phases { +// (tones.len() == phases.len()).then_some(()) +// .ok_or(AWGError::NumTones)?; +// } +// if let Some(amplitudes) = &self.amplitudes { +// (tones.len() == amplitudes.len()).then_some(()) +// .ok_or(AWGError::NumTones)?; +// } +// self.tones = Some(tones); +// Ok(self) +// } + +// /// Set the frequency tones using a center frequency and a uniform spacing, +// /// both in hertz. +// pub fn set_tones_spaced(&mut self, center: i32, spacing: i32, num: usize) +// -> AWGResult<&mut Self> +// { +// if let Some(phases) = &self.phases { +// (num == phases.len()).then_some(()) +// .ok_or(AWGError::NumTones)?; +// } +// if let Some(amplitudes) = &self.amplitudes { +// (num == amplitudes.len()).then_some(()) +// .ok_or(AWGError::NumTones)?; +// } +// let f0: i32 = center - spacing * num as i32 / 2; +// let tones: Vec<i32> +// = (0..num as i32).map(|k| f0 + spacing * k).collect(); +// self.tones = Some(tones); +// Ok(self) +// } + +// /// Return `true` if initial phases have been initialized. +// pub fn has_phases(&self) -> bool { self.phases.is_some() } + +// /// Get the initial phases of each tone in radians. +// pub fn get_phases(&self) -> Option<&Vec<f64>> { +// self.phases.as_ref() +// } + +// /// Set the initial phases of each tone in radians. +// pub fn set_phases<'a, I>(&mut self, phases: I) -> AWGResult<&mut Self> +// where I: IntoIterator<Item = &'a f64> +// { +// let phases: Vec<f64> +// = phases.into_iter().copied().map(|ph| ph % TAU).collect(); +// if let Some(tones) = &self.tones { +// (phases.len() == tones.len()).then_some(()) +// .ok_or(AWGError::NumPhases)?; +// } +// if let Some(amplitudes) = &self.amplitudes { +// (phases.len() == amplitudes.len()).then_some(()) +// .ok_or(AWGError::NumPhases)?; +// } +// self.phases = Some(phases); +// Ok(self) +// } + +// /// Return `true` if amplitudes have been initialized. +// pub fn has_amplitudes(&self) -> bool { self.amplitudes.is_some() } + +// /// Get the amplitudes of each tone. +// pub fn get_amplitudes(&self) -> Option<&Vec<f64>> { +// self.amplitudes.as_ref() +// } + +// /// Set the amplitudes of each tone. +// /// +// /// Each amplitude must lie in the range `[0, 2^15 - 1)`. +// pub fn set_amplitudes<'a, I>(&mut self, amplitudes: I) +// -> AWGResult<&mut Self> +// where I: IntoIterator<Item = &'a f64> +// { +// let amplitudes: Vec<f64> +// = amplitudes.into_iter().copied() +// .map(|a| { +// (0.0..32767.0).contains(&a) +// .then_some(a) +// .ok_or(AWGError::InvalidAmplitude(a)) +// }) +// .collect::<AWGResult<Vec<f64>>>()?; +// if let Some(tones) = &self.tones { +// (amplitudes.len() == tones.len()).then_some(()) +// .ok_or(AWGError::NumAmplitudes)?; +// } +// if let Some(phases) = &self.phases { +// (amplitudes.len() == phases.len()).then_some(()) +// .ok_or(AWGError::NumAmplitudes)?; +// } +// self.amplitudes = Some(amplitudes); +// Ok(self) +// } + +// /// Return `true` if the sampling rate has been initialized. +// pub fn has_sampling_rate(&self) -> bool { +// self.sampling_rate.is_some() +// } + +// /// Get the sampling rate in hertz. +// pub fn get_sampling_rate(&self) -> Option<u64> { +// self.sampling_rate +// } + +// /// Set the sampling rate in hertz. +// pub fn set_sampling_rate(&mut self, sampling_rate: u64) -> &mut Self { +// self.sampling_rate = Some(sampling_rate); +// self +// } + +// /// Return `true` if the frequency resolution has been initialized. +// pub fn has_frequency_resolution(&self) -> bool { +// self.frequency_resolution.is_some() +// } + +// /// Get the frequency resolution in hertz. +// pub fn get_frequency_resolution(&self) -> Option<u64> { +// self.frequency_resolution +// } + +// /// Set the frequency resolution in hertz. +// pub fn set_frequency_resolution(&mut self, resolution: u64) -> &mut Self { +// self.frequency_resolution = Some(resolution); +// self +// } + +// /// Generate an [`ArrayWaveform`] from the current set of parameters if all +// /// have been initialized. +// pub fn to_waveform(&self) -> AWGResult<ArrayWaveform> { +// self.is_init().then_some(()) +// .ok_or(AWGError::WaveformUninit)?; +// let mut waveform = ArrayWaveform::new_uninit(); +// waveform +// .set_freq_tones(self.tones.as_ref().unwrap())? +// .set_phases(self.phases.as_ref().unwrap())? +// .set_amplitudes(self.amplitudes.as_ref().unwrap())? +// .set_sampling_rate(self.sampling_rate.unwrap())? +// .set_freq_resolution(self.frequency_resolution.unwrap())?; +// Ok(waveform) +// } +// } + +// impl TryFrom<&WaveformParams> for ArrayWaveform { +// type Error = AWGError; + +// fn try_from(params: &WaveformParams) -> AWGResult<Self> { +// params.to_waveform() +// } +// } + +// impl TryFrom<WaveformParams> for ArrayWaveform { +// type Error = AWGError; + +// fn try_from(params: WaveformParams) -> AWGResult<Self> { +// params.to_waveform() +// } +// } + +// impl fmt::Display for WaveformParams { +// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { +// writeln!(f, "WaveformParams {{")?; + +// write!(f, " tones: [")?; +// if let Some(tones) = &self.tones { +// let n = tones.len(); +// for (k, tone) in tones.iter().enumerate() { +// tone.fmt(f)?; +// if k < n - 1 { write!(f, ", ")?; } +// } +// } else { +// write!(f, "<uninit>")?; +// } +// writeln!(f, "],")?; + +// write!(f, " phases: [")?; +// if let Some(phases) = &self.phases { +// let n = phases.len(); +// for (k, phase) in phases.iter().enumerate() { +// phase.fmt(f)?; +// if k < n - 1 { write!(f, ", ")?; } +// } +// } else { +// write!(f, "<uninit>")?; +// } +// writeln!(f, "],")?; + +// write!(f, " amplitudes: [")?; +// if let Some(amplitudes) = &self.amplitudes { +// let n = amplitudes.len(); +// for (k, amplitude) in amplitudes.iter().enumerate() { +// amplitude.fmt(f)?; +// if k < n - 1 { write!(f, ", ")?; } +// } +// } else { +// write!(f, "<uninit>")?; +// } +// writeln!(f, "],")?; + +// write!(f, " sampling_rate: ")?; +// if let Some(sampling_rate) = self.sampling_rate { +// sampling_rate.fmt(f)?; +// } else { +// write!(f, "<uninit>")?; +// } +// writeln!(f, ",")?; + +// write!(f, " frequency_resolution: ")?; +// if let Some(frequency_resolution) = self.frequency_resolution { +// frequency_resolution.fmt(f)?; +// } else { +// write!(f, "<uninit>")?; +// } +// writeln!(f, ",")?; + +// write!(f, "}}")?; +// Ok(()) +// } +// } + +// /// Data type for array waveform generation. +// pub struct ArrayWaveform { +// data: UniquePtr<ffi::ArrayWaveform>, +// } + +// impl_debug_boring!(ArrayWaveform); + +// impl Default for ArrayWaveform { +// fn default() -> Self { Self::new_uninit() } +// } + +// impl ArrayWaveform { +// fn pinned(&mut self) -> Pin<&mut ffi::ArrayWaveform> { self.data.pin_mut() } + +// /// Create a new, uninitialized waveform. +// /// +// /// # Safety +// /// After this constructor is called, all private member variables are set +// /// to 0 or `nullptr` values. It is the programmer's responsibility to +// /// ensure that all properties and memory addresses are properly +// /// initialized. +// fn new_uninit() -> Self { +// unsafe { +// Self { data: ffi::new_arraywaveform().unwrap() } +// } +// } + +// /// Get a pointer to the associated data buffer. +// pub fn get_data_buffer(&mut self) -> AWGResult<PageAlignedMem> { +// unsafe { +// ffi::arraywaveform_get_data_buffer(self.pinned()) +// .map(|ptr| PageAlignedMem { ptr, wf_ref: self }) +// .map_err(AWGError::as_waveform_err) +// } +// } + +// /// Get the number of samples in the current waveform. +// pub fn get_data_len(&mut self) -> AWGResult<u64> { +// unsafe { +// ffi::arraywaveform_get_data_len(self.pinned()) +// .map(|len| len as u64) +// .map_err(AWGError::as_waveform_err) +// } +// } + +// /// Set the sampling rate in hertz. +// fn set_sampling_rate(&mut self, rate: u64) -> AWGResult<&mut Self> { +// unsafe { +// ffi::arraywaveform_set_sampling_rate(self.pinned(), rate) +// .map_err(AWGError::as_waveform_err)?; +// Ok(self) +// } +// } + +// /// Get the sampling rate in hertz. +// pub fn get_sampling_rate(&mut self) -> AWGResult<u64> { +// unsafe { +// ffi::arraywaveform_get_sampling_rate(self.pinned()) +// .map_err(AWGError::as_waveform_err) +// } +// } + +// /// Set the frequency resolution in hertz. +// fn set_freq_resolution(&mut self, resolution: u64) +// -> AWGResult<&mut Self> +// { +// unsafe { +// ffi::arraywaveform_set_freq_resolution(self.pinned(), resolution) +// .map_err(AWGError::as_waveform_err)?; +// Ok(self) +// } +// } + +// /// Get the frequency resolution in hertz. +// pub fn get_freq_resolution(&mut self) -> AWGResult<u64> { +// unsafe { +// ffi::arraywaveform_get_freq_resolution(self.pinned()) +// .map_err(AWGError::as_waveform_err) +// } +// } + +// /// Set the constituent tones using a fixed center frequency and uniform +// /// spacing in hertz. +// fn set_freq_tones_spaced( +// &mut self, +// center: i32, +// spacing: i32, +// num_tones: u16, +// ) -> AWGResult<&mut Self> +// { +// unsafe { +// ffi::arraywaveform_set_freq_tones_spaced( +// self.pinned(), center, spacing, num_tones.into()) +// .map_err(AWGError::as_waveform_err)?; +// Ok(self) +// } +// } + +// /// Set the constituent tones to arbitrary values in hertz. +// fn set_freq_tones<'a, I>(&mut self, tones: I) -> AWGResult<&mut Self> +// where I: IntoIterator<Item = &'a i32> +// { +// unsafe { +// let tones_cxx: UniquePtr<CxxVector<i32>> +// = collect_cxx_vector(tones); +// ffi::arraywaveform_set_freq_tones( +// self.pinned(), tones_cxx.as_ref().unwrap()) +// .map_err(AWGError::as_waveform_err)?; +// Ok(self) +// } +// } + +// /// Get a list of contituent tones. +// pub fn get_freq_tones(&mut self) -> AWGResult<Vec<i32>> { +// unsafe { +// ffi::arraywaveform_get_freq_tones(self.pinned()) +// .map_err(AWGError::as_waveform_err) +// } +// } + +// /// Set the initial phases in radians of all tones. +// fn set_phases<'a, I>(&mut self, phases: I) -> AWGResult<&mut Self> +// where I: IntoIterator<Item = &'a f64> +// { +// unsafe { +// let phases_cxx: UniquePtr<CxxVector<f64>> +// = collect_cxx_vector(phases); +// ffi::arraywaveform_set_phases( +// self.pinned(), phases_cxx.as_ref().unwrap()) +// .map_err(AWGError::as_waveform_err)?; +// Ok(self) +// } +// } + +// /// Get a list of initial phases in radians for each tone. +// pub fn get_phases(&mut self) -> AWGResult<Vec<f64>> { +// unsafe { +// ffi::arraywaveform_get_phases(self.pinned()) +// .map_err(AWGError::as_waveform_err) +// } +// } + +// /// Set the amplitudes of all tones. +// /// +// /// Each amplitude must be in the range `[0, 2^15 - 1)` +// fn set_amplitudes<'a, I>(&mut self, amplitudes: I) +// -> AWGResult<&mut Self> +// where I: IntoIterator<Item = &'a f64> +// { +// unsafe { +// let amplitudes: Vec<f64> +// = amplitudes.into_iter().copied() +// .map(|a| { +// (0.0..32767.0).contains(&a) +// .then_some(a) +// .ok_or(AWGError::InvalidAmplitude(a)) +// }) +// .collect::<AWGResult<Vec<f64>>>()?; +// let amplitudes_cxx: UniquePtr<CxxVector<f64>> +// = collect_cxx_vector(&litudes); +// ffi::arraywaveform_set_amplitudes( +// self.pinned(), amplitudes_cxx.as_ref().unwrap()) +// .map_err(AWGError::as_waveform_err)?; +// Ok(self) +// } +// } + +// /// Get a list of amplitudes for each tone. +// pub fn get_amplitudes(&mut self) -> AWGResult<Vec<f64>> { +// unsafe { +// ffi::arraywaveform_get_amplitudes(self.pinned()) +// .map_err(AWGError::as_waveform_err) +// } +// } + +// /// Set phases to 0 and amplitudes to 2000. +// fn set_default_params(&mut self) -> AWGResult<&mut Self> { +// unsafe { +// ffi::arraywaveform_set_default_params(self.pinned()) +// .map_err(AWGError::as_waveform_err)?; +// Ok(self) +// } +// } + +// /// Save the current waveform parameters to a file in CSV format. +// fn save_params<P>(&mut self, filename: P) -> AWGResult<&mut Self> +// where P: AsRef<Path> +// { +// unsafe { +// let path_osstr: &OsStr = filename.as_ref().as_os_str(); +// let path_str: &str +// = path_osstr.to_str() +// .ok_or(AWGError::PathError(path_osstr.to_os_string()))?; +// path_str.ends_with(".csv").then_some(()) +// .ok_or(AWGError::WaveformCSV(path_osstr.to_os_string()))?; +// let_cxx_string!(fname = path_str); +// ffi::arraywaveform_save_params(self.pinned(), &fname) +// .map_err(AWGError::as_waveform_err)?; +// Ok(self) +// } +// } + +// /// Load waveform parameters from a file. +// /// +// /// The file must be in CSV format. +// fn load_params<P>(&mut self, filename: P) -> AWGResult<&mut Self> +// where P: AsRef<Path> +// { +// unsafe { +// let path_osstr: &OsStr = filename.as_ref().as_os_str(); +// let path_str: &str +// = path_osstr.to_str() +// .ok_or(AWGError::PathError(path_osstr.to_os_string()))?; +// path_str.ends_with(".csv").then_some(()) +// .ok_or(AWGError::WaveformCSV(path_osstr.to_os_string()))?; +// let_cxx_string!(fname = path_str); +// ffi::arraywaveform_load_params(self.pinned(), &fname) +// .map_err(AWGError::as_waveform_err)?; +// Ok(self) +// } +// } + +// /// Print the current waveform parameters. +// pub fn print_params(&mut self) -> AWGResult<&mut Self> { +// unsafe { +// ffi::arraywaveform_print_params(self.pinned()) +// .map_err(AWGError::as_waveform_err)?; +// Ok(self) +// } +// } + +// /// Get the minimum data length that fulfills rounding constraints for the +// /// given sampling rate and frequency resolution (in hertz). +// pub fn get_min_sample_len( +// &mut self, +// sampling_rate: u64, +// frequency_resolution: u64, +// ) -> AWGResult<u64> +// { +// unsafe { +// ffi::arraywaveform_get_min_sample_len( +// self.pinned(), sampling_rate, frequency_resolution) +// .map_err(AWGError::as_waveform_err) +// } +// } + +// /// Get a data array length close to the specified runtime tau (in seconds) +// /// that also fulfills rounding constraints for the given sampling rate and +// /// frequency resolution (in hertz). +// pub fn get_sample_len( +// &mut self, +// tau: f64, +// sampling_rate: u64, +// frequency_resolution: u64, +// ) -> AWGResult<u64> +// { +// unsafe { +// ffi::arraywaveform_get_sample_len( +// self.pinned(), tau, sampling_rate, frequency_resolution) +// .map_err(AWGError::as_waveform_err) +// } +// } + +// /// Generate a static frequency waveform from the current set of parameters. +// /// +// /// The returned [`WaveformDataPtr`] is passed a reference to `self` upon +// /// creation for safety. +// pub fn get_static_waveform(&mut self) -> AWGResult<WaveformDataPtr> { +// unsafe { +// ffi::arraywaveform_get_static_waveform(self.pinned()) +// .map(|ptr| WaveformDataPtr { ptr, wf_ref: &*self }) +// .map_err(AWGError::as_waveform_err) +// } +// } + +// /// Generate a tricky-trick waveform from the current set of parameters. +// /// +// /// - `sites`: Iterable of array site indices for which the tricky-trick +// /// will be performed +// /// - `df`: Frequency to move by in hertz +// /// - `tau_move`: Moving time in seconds +// /// - `tau_stay`: Wait time in seconds +// /// +// /// The returned [`WaveformDataPtr`] is passed a reference to `self` upon +// /// creation for safety. +// pub fn get_trick_waveform<'a, I>( +// &mut self, +// sites: I, +// df: f64, +// tau_move: f64, +// tau_stay: f64, +// ) -> AWGResult<WaveformDataPtr> +// where I: IntoIterator<Item = &'a i32> +// { +// unsafe { +// let sites_cxx: UniquePtr<CxxVector<i32>> +// = collect_cxx_vector(sites); +// ffi::arraywaveform_get_trick_waveform( +// self.pinned(), +// sites_cxx.as_ref().unwrap(), +// df, +// tau_move, +// tau_stay, +// ) +// .map(|ptr| WaveformDataPtr { ptr, wf_ref: &*self }) +// .map_err(AWGError::as_waveform_err) +// } +// } + +// /// Save the generated waveform to a CSV-formatted file. +// pub fn save_waveform<P>(&mut self, filename: P) -> AWGResult<&mut Self> +// where P: AsRef<Path> +// { +// unsafe { +// let path_osstr: &OsStr = filename.as_ref().as_os_str(); +// let path_str: &str +// = path_osstr.to_str() +// .ok_or(AWGError::PathError(path_osstr.to_os_string()))?; +// path_str.ends_with(".csv").then_some(()) +// .ok_or(AWGError::WaveformCSV(path_osstr.to_os_string()))?; +// let_cxx_string!(fname = path_str); +// ffi::arraywaveform_save_waveform(self.pinned(), &fname) +// .map_err(AWGError::as_waveform_err)?; +// Ok(self) +// } +// } +// } + +// /// Parameters to the tweezer uniformization routine. +// /// +// /// All parameters must be initialized before they can be passed to +// /// [`run_uniformization`]: +// /// - [`source`][Self::set_source] source waveform file +// /// - [`polarizability`][Self::set_polarizability] expected atomic +// /// polarizability of the 3P1 ∣F = 3/2, mF = -3/2⟩ state in kHz/μK +// /// - [`mean_depth`][Self::set_mean_depth] target mean tweezer depth in +// /// μK +// /// - [`step_size`][Self::set_step_size] step size to use for the optimization +// /// algorithm +// /// - [`error_threshold`][Self::set_error_threshold] threshold for termination +// /// to use in the optimization algorithm +// /// - [`max_iters`][Self::set_max_iters] maximum number of iterations to use in +// /// the optimization algorithm +// /// - [`num_imaging_avg`][Self::set_num_imaging_avg] number of Basler images to +// /// average for tweezer power measurements +// /// - [`num_tweezers`][Self::set_num_tweezers] tweezer array size +// #[derive(Clone, Debug)] +// pub struct UniformizationParams { +// source: Option<PathBuf>, +// polarizability: Option<f64>, +// mean_depth: Option<f64>, +// step_size: Option<f64>, +// error_threshold: Option<f64>, +// max_iters: Option<usize>, +// num_imaging_avg: Option<usize>, +// num_tweezers: Option<usize>, +// } + +// impl Default for UniformizationParams { +// fn default() -> Self { Self::new() } +// } + +// impl UniformizationParams { +// /// Create a new, uninitialized uniformization config. +// pub fn new() -> Self { +// Self { +// source: None, +// polarizability: None, +// mean_depth: None, +// step_size: None, +// error_threshold: None, +// max_iters: None, +// num_imaging_avg: None, +// num_tweezers: None, +// } +// } + +// #[allow(clippy::too_many_arguments)] +// pub fn new_all<P>( +// source: P, +// polarizability: f64, +// mean_depth: f64, +// step_size: f64, +// error_threshold: f64, +// max_iters: usize, +// num_imaging_avg: usize, +// num_tweezers: usize, +// ) -> Self +// where P: AsRef<Path> +// { +// Self { +// source: Some(source.as_ref().to_path_buf()), +// polarizability: Some(polarizability), +// mean_depth: Some(mean_depth), +// step_size: Some(step_size), +// error_threshold: Some(error_threshold), +// max_iters: Some(max_iters), +// num_imaging_avg: Some(num_imaging_avg), +// num_tweezers: Some(num_tweezers), +// } +// } + +// /// Return `true` if all parameters have been initialized. +// pub fn is_init(&self) -> bool { +// self.has_source() +// && self.has_polarizability() +// && self.has_mean_depth() +// && self.has_step_size() +// && self.has_error_threshold() +// && self.has_max_iters() +// && self.has_num_imaging_avg() +// && self.has_num_tweezers() +// } + +// /// Return `true` if the source waveform file has been set. +// pub fn has_source(&self) -> bool { self.source.is_some() } + +// /// Get the source waveform file. +// pub fn get_source(&self) -> Option<&PathBuf> { +// self.source.as_ref() +// } + +// /// Set the source waveform file. +// pub fn set_source<P>(&mut self, source: P) -> AWGResult<&mut Self> +// where P: AsRef<Path> +// { +// let source = source.as_ref().to_path_buf(); +// let source_string = source.display().to_string(); +// source.exists().then_some(()) +// .ok_or(AWGError::InvalidUniformizationSource(source_string))?; +// self.source = Some(source); +// Ok(self) +// } + +// /// Return `true` if the polarizability has been set. +// pub fn has_polarizability(&self) -> bool { self.polarizability.is_some() } + +// /// Get the polarizability in kHz/μK. +// pub fn get_polarizability(&self) -> Option<f64> { self.polarizability } + +// /// Set the polarizability in kHz/μK. +// pub fn set_polarizability(&mut self, polarizability: f64) +// -> AWGResult<&mut Self> +// { +// (polarizability < 0.0).then_some(()) +// .ok_or(AWGError::InvalidPolarizability(polarizability))?; +// self.polarizability = Some(polarizability); +// Ok(self) +// } + +// /// Return `true` if the mean tweezer depth has been set. +// pub fn has_mean_depth(&self) -> bool { self.mean_depth.is_some() } + +// /// Get the mean tweezer depth in μK. +// pub fn get_mean_depth(&self) -> Option<f64> { self.mean_depth } + +// pub fn set_mean_depth(&mut self, mean_depth: f64) -> AWGResult<&mut Self> { +// (mean_depth > 0.0).then_some(()) +// .ok_or(AWGError::InvalidMeanDepth(mean_depth))?; +// self.mean_depth = Some(mean_depth); +// Ok(self) +// } + +// /// Return `true` if the step size has been set. +// pub fn has_step_size(&self) -> bool { self.step_size.is_some() } + +// /// Get the step size. +// pub fn get_step_size(&self) -> Option<f64> { self.step_size } + +// /// Set the step size. +// pub fn set_step_size(&mut self, step_size: f64) -> AWGResult<&mut Self> { +// (step_size > 0.0).then_some(()) +// .ok_or(AWGError::InvalidStepSize(step_size))?; +// self.step_size = Some(step_size); +// Ok(self) +// } + +// /// Return `true` if the error threshold has been set. +// pub fn has_error_threshold(&self) -> bool { self.error_threshold.is_some() } + +// /// Get the error threshold. +// pub fn get_error_threshold(&self) -> Option<f64> { self.error_threshold } + +// pub fn set_error_threshold(&mut self, error_threshold: f64) +// -> AWGResult<&mut Self> +// { +// (error_threshold > 0.0).then_some(()) +// .ok_or(AWGError::InvalidErrorThreshold(error_threshold))?; +// self.error_threshold = Some(error_threshold); +// Ok(self) +// } + +// /// Return `true` if the maximum iterations has been set. +// pub fn has_max_iters(&self) -> bool { self.max_iters.is_some() } + +// /// Get the max iters. +// pub fn get_max_iters(&self) -> Option<usize> { self.max_iters } + +// /// Set the max iters. +// pub fn set_max_iters(&mut self, max_iters: usize) -> AWGResult<&mut Self> { +// (max_iters > 0).then_some(()) +// .ok_or(AWGError::InvalidMaxIters(max_iters))?; +// self.max_iters = Some(max_iters); +// Ok(self) +// } + +// /// Return `true` if the number of tweezer images to average has been set. +// pub fn has_num_imaging_avg(&self) -> bool { self.num_imaging_avg.is_some() } + +// /// Get the number of images to average over. +// pub fn get_num_imaging_avg(&self) -> Option<usize> { self.num_imaging_avg } + +// /// Set the number of images to average over. +// pub fn set_num_imaging_avg(&mut self, num_imaging_avg: usize) +// -> AWGResult<&mut Self> +// { +// (num_imaging_avg > 0).then_some(()) +// .ok_or(AWGError::InvalidNumImagingAvg(num_imaging_avg))?; +// self.num_imaging_avg = Some(num_imaging_avg); +// Ok(self) +// } + +// pub fn has_num_tweezers(&self) -> bool { self.num_tweezers.is_some() } + +// /// Get the number of tweezers. +// pub fn get_num_tweezers(&self) -> Option<usize> { self.num_tweezers } + +// /// Set the number of tweezers. +// pub fn set_num_tweezers(&mut self, num_tweezers: usize) +// -> AWGResult<&mut Self> +// { +// (num_tweezers > 0).then_some(()) +// .ok_or(AWGError::InvalidNumTweezers(num_tweezers))?; +// self.num_tweezers = Some(num_tweezers); +// Ok(self) +// } + +// /// Convert to the corresponding C++ data type. +// fn to_ffi_type(&self) -> AWGResult<UniquePtr<ffi::UniformizationParams>> { +// self.check()?; +// let source_osstr: &OsStr = self.source.as_ref().unwrap().as_os_str(); +// let source_str: &str +// = source_osstr.to_str() +// .ok_or(AWGError::PathError(source_osstr.to_os_string()))?; +// let_cxx_string!(source = source_str); +// unsafe { +// let ffi_params: UniquePtr<ffi::UniformizationParams> +// = ffi::new_uniformizationparams( +// &source, +// self.polarizability.unwrap(), +// self.mean_depth.unwrap(), +// self.step_size.unwrap(), +// self.error_threshold.unwrap(), +// self.max_iters.unwrap() as i32, +// self.num_imaging_avg.unwrap() as i32, +// self.num_tweezers.unwrap() as i32, +// ) +// .map_err(AWGError::as_uniformization_err)?; +// Ok(ffi_params) +// } +// } + +// /// Check that all necessary conditions are satisfied. +// pub fn check(&self) -> AWGResult<()> { +// self.is_init().then_some(()) +// .ok_or(AWGError::UniformizationUninit)?; +// if let Some(source) = self.source.as_ref() { +// let source_string = source.display().to_string(); +// source.exists().then_some(()) +// .ok_or(AWGError::InvalidUniformizationSource(source_string))?; +// } +// if let Some(polarizability) = self.polarizability { +// (polarizability < 0.0).then_some(()) +// .ok_or(AWGError::InvalidPolarizability(polarizability))?; +// } +// if let Some(mean_depth) = self.mean_depth { +// (mean_depth > 0.0).then_some(()) +// .ok_or(AWGError::InvalidMeanDepth(mean_depth))?; +// } +// if let Some(step_size) = self.step_size { +// (step_size > 0.0).then_some(()) +// .ok_or(AWGError::InvalidStepSize(step_size))?; +// } +// if let Some(error_threshold) = self.error_threshold { +// (error_threshold > 0.0).then_some(()) +// .ok_or(AWGError::InvalidErrorThreshold(error_threshold))?; +// } +// if let Some(max_iters) = self.max_iters { +// (max_iters > 0).then_some(()) +// .ok_or(AWGError::InvalidMaxIters(max_iters))?; +// } +// if let Some(num_imaging_avg) = self.num_imaging_avg { +// (num_imaging_avg > 0).then_some(()) +// .ok_or(AWGError::InvalidNumImagingAvg(num_imaging_avg))?; +// } +// if let Some(num_tweezers) = self.num_tweezers { +// (num_tweezers > 0).then_some(()) +// .ok_or(AWGError::InvalidNumTweezers(num_tweezers))?; +// } +// Ok(()) +// } +// } + +// pub fn run_uniformization<A, B>( +// mut awg: A, +// mut basler: B, +// waveform: &mut ArrayWaveform, +// params: &UniformizationParams, +// ) -> AWGResult<()> +// where +// A: std::ops::DerefMut<Target = AWG>, +// B: std::ops::DerefMut<Target = Basler>, +// { +// unsafe { +// ffi::run_uniformization( +// awg.deref_mut().pinned(), +// basler.deref_mut().pinned(), +// waveform.pinned(), +// params.to_ffi_type()?.as_ref().unwrap(), +// ) +// .map_err(AWGError::as_uniformization_err) +// } +// } diff --git a/awg-cxx/lib/awg_ffi.rs b/awg-cxx/lib/awg_ffi.rs index 53bb031cfb35660eb975ad4b814b0b37bd0d4dbc..90d0de484999d52177a292c612caded9236da0e2 100644 --- a/awg-cxx/lib/awg_ffi.rs +++ b/awg-cxx/lib/awg_ffi.rs @@ -3,8 +3,8 @@ pub(crate) mod ffi { unsafe extern "C++" { include!("awg-cxx/awg-control/Cpp/lib/devices/AWG.h"); - include!("awg-cxx/awg-control/Cpp/lib/devices/basler.h"); - include!("awg-cxx/awg-control/Cpp/lib/waveform.h"); + // include!("awg-cxx/awg-control/Cpp/lib/devices/basler.h"); + // include!("awg-cxx/awg-control/Cpp/lib/waveform.h"); include!("awg-cxx/include/awg.h"); } @@ -77,75 +77,75 @@ pub(crate) mod ffi { /**********************************************************************/ - type ArrayWaveform; - type WaveformData; + // type ArrayWaveform; + // type WaveformData; - unsafe fn new_arraywaveform() -> Result<UniquePtr<ArrayWaveform>>; + // unsafe fn new_arraywaveform() -> Result<UniquePtr<ArrayWaveform>>; - unsafe fn arraywaveform_get_data_buffer(waveform: Pin<&mut ArrayWaveform>) -> Result<UniquePtr<PageAlignedMem>>; - unsafe fn arraywaveform_get_data_len(waveform: Pin<&mut ArrayWaveform>) -> Result<i64>; + // unsafe fn arraywaveform_get_data_buffer(waveform: Pin<&mut ArrayWaveform>) -> Result<UniquePtr<PageAlignedMem>>; + // unsafe fn arraywaveform_get_data_len(waveform: Pin<&mut ArrayWaveform>) -> Result<i64>; - unsafe fn arraywaveform_set_sampling_rate(waveform: Pin<&mut ArrayWaveform>, rate: u64) -> Result<()>; - unsafe fn arraywaveform_get_sampling_rate(waveform: Pin<&mut ArrayWaveform>) -> Result<u64>; - unsafe fn arraywaveform_set_freq_resolution(waveform: Pin<&mut ArrayWaveform>, resolution: u64) -> Result<()>; - unsafe fn arraywaveform_get_freq_resolution(waveform: Pin<&mut ArrayWaveform>) -> Result<u64>; + // unsafe fn arraywaveform_set_sampling_rate(waveform: Pin<&mut ArrayWaveform>, rate: u64) -> Result<()>; + // unsafe fn arraywaveform_get_sampling_rate(waveform: Pin<&mut ArrayWaveform>) -> Result<u64>; + // unsafe fn arraywaveform_set_freq_resolution(waveform: Pin<&mut ArrayWaveform>, resolution: u64) -> Result<()>; + // unsafe fn arraywaveform_get_freq_resolution(waveform: Pin<&mut ArrayWaveform>) -> Result<u64>; - unsafe fn arraywaveform_set_freq_tones_spaced(waveform: Pin<&mut ArrayWaveform>, center: i32, spacing: i32, num_tones: i32) -> Result<()>; - unsafe fn arraywaveform_set_freq_tones(waveform: Pin<&mut ArrayWaveform>, tones: &CxxVector<i32>) -> Result<()>; - unsafe fn arraywaveform_get_freq_tones(waveform: Pin<&mut ArrayWaveform>) -> Result<Vec<i32>>; - unsafe fn arraywaveform_set_phases(waveform: Pin<&mut ArrayWaveform>, phases: &CxxVector<f64>) -> Result<()>; - unsafe fn arraywaveform_get_phases(waveform: Pin<&mut ArrayWaveform>) -> Result<Vec<f64>>; - unsafe fn arraywaveform_set_amplitudes(waveform: Pin<&mut ArrayWaveform>, amplitudes: &CxxVector<f64>) -> Result<()>; - unsafe fn arraywaveform_get_amplitudes(waveform: Pin<&mut ArrayWaveform>) -> Result<Vec<f64>>; - unsafe fn arraywaveform_set_default_params(waveform: Pin<&mut ArrayWaveform>) -> Result<()>; - unsafe fn arraywaveform_save_params(waveform: Pin<&mut ArrayWaveform>, filename: &CxxString) -> Result<()>; - unsafe fn arraywaveform_load_params(waveform: Pin<&mut ArrayWaveform>, filename: &CxxString) -> Result<()>; - unsafe fn arraywaveform_print_params(waveform: Pin<&mut ArrayWaveform>) -> Result<()>; + // unsafe fn arraywaveform_set_freq_tones_spaced(waveform: Pin<&mut ArrayWaveform>, center: i32, spacing: i32, num_tones: i32) -> Result<()>; + // unsafe fn arraywaveform_set_freq_tones(waveform: Pin<&mut ArrayWaveform>, tones: &CxxVector<i32>) -> Result<()>; + // unsafe fn arraywaveform_get_freq_tones(waveform: Pin<&mut ArrayWaveform>) -> Result<Vec<i32>>; + // unsafe fn arraywaveform_set_phases(waveform: Pin<&mut ArrayWaveform>, phases: &CxxVector<f64>) -> Result<()>; + // unsafe fn arraywaveform_get_phases(waveform: Pin<&mut ArrayWaveform>) -> Result<Vec<f64>>; + // unsafe fn arraywaveform_set_amplitudes(waveform: Pin<&mut ArrayWaveform>, amplitudes: &CxxVector<f64>) -> Result<()>; + // unsafe fn arraywaveform_get_amplitudes(waveform: Pin<&mut ArrayWaveform>) -> Result<Vec<f64>>; + // unsafe fn arraywaveform_set_default_params(waveform: Pin<&mut ArrayWaveform>) -> Result<()>; + // unsafe fn arraywaveform_save_params(waveform: Pin<&mut ArrayWaveform>, filename: &CxxString) -> Result<()>; + // unsafe fn arraywaveform_load_params(waveform: Pin<&mut ArrayWaveform>, filename: &CxxString) -> Result<()>; + // unsafe fn arraywaveform_print_params(waveform: Pin<&mut ArrayWaveform>) -> Result<()>; - unsafe fn arraywaveform_get_min_sample_len(waveform: Pin<&mut ArrayWaveform>, sampling_rate: u64, frequency_resolution: u64) -> Result<u64>; - unsafe fn arraywaveform_get_sample_len(waveform: Pin<&mut ArrayWaveform>, tau: f64, sampling_rate: u64, frequency_resolution: u64) -> Result<u64>; + // unsafe fn arraywaveform_get_min_sample_len(waveform: Pin<&mut ArrayWaveform>, sampling_rate: u64, frequency_resolution: u64) -> Result<u64>; + // unsafe fn arraywaveform_get_sample_len(waveform: Pin<&mut ArrayWaveform>, tau: f64, sampling_rate: u64, frequency_resolution: u64) -> Result<u64>; - unsafe fn arraywaveform_get_static_waveform(waveform: Pin<&mut ArrayWaveform>) -> Result<UniquePtr<WaveformData>>; - unsafe fn arraywaveform_get_trick_waveform(waveform: Pin<&mut ArrayWaveform>, site_index: &CxxVector<i32>, df: f64, tau_move: f64, tau_stay: f64) -> Result<UniquePtr<WaveformData>>; + // unsafe fn arraywaveform_get_static_waveform(waveform: Pin<&mut ArrayWaveform>) -> Result<UniquePtr<WaveformData>>; + // unsafe fn arraywaveform_get_trick_waveform(waveform: Pin<&mut ArrayWaveform>, site_index: &CxxVector<i32>, df: f64, tau_move: f64, tau_stay: f64) -> Result<UniquePtr<WaveformData>>; - unsafe fn arraywaveform_save_waveform(waveform: Pin<&mut ArrayWaveform>, filename: &CxxString) -> Result<()>; + // unsafe fn arraywaveform_save_waveform(waveform: Pin<&mut ArrayWaveform>, filename: &CxxString) -> Result<()>; - unsafe fn waveformdata_get_mem(data: Pin<&mut WaveformData>) -> Result<UniquePtr<PageAlignedMem>>; - unsafe fn waveformdata_get_datalen(data: Pin<&mut WaveformData>) -> Result<i64>; + // unsafe fn waveformdata_get_mem(data: Pin<&mut WaveformData>) -> Result<UniquePtr<PageAlignedMem>>; + // unsafe fn waveformdata_get_datalen(data: Pin<&mut WaveformData>) -> Result<i64>; - /**********************************************************************/ + // /**********************************************************************/ - type BaslerBox; - - unsafe fn new_basler(index: i32) -> Result<UniquePtr<BaslerBox>>; - - unsafe fn basler_print_device_info(basler: Pin<&mut BaslerBox>) -> Result<()>; - unsafe fn basler_set_exposure(basler: Pin<&mut BaslerBox>, exposure_time: f64) -> Result<()>; - unsafe fn basler_get_exposure(basler: Pin<&mut BaslerBox>) -> Result<f64>; - unsafe fn basler_set_frame_rate(basler: Pin<&mut BaslerBox>, frame_rate: u32) -> Result<()>; - unsafe fn basler_set_frame_rate_max(basler: Pin<&mut BaslerBox>) -> Result<()>; - unsafe fn basler_set_gain(basler: Pin<&mut BaslerBox>, gain: f64) -> Result<()>; - unsafe fn basler_get_gain(basler: Pin<&mut BaslerBox>) -> Result<f64>; - unsafe fn basler_set_roi(basler: Pin<&mut BaslerBox>, offset_x: u32, offset_y: u32, width: u32, height: u32) -> Result<()>; - unsafe fn basler_get_offset_x(basler: Pin<&mut BaslerBox>) -> Result<u32>; - unsafe fn basler_get_offset_y(basler: Pin<&mut BaslerBox>) -> Result<u32>; - unsafe fn basler_get_width(basler: Pin<&mut BaslerBox>) -> Result<u32>; - unsafe fn basler_get_height(basler: Pin<&mut BaslerBox>) -> Result<u32>; - unsafe fn basler_set_acquisition_mode(basler: Pin<&mut BaslerBox>, mode: &CxxString) -> Result<()>; - unsafe fn basler_print_available_acquisition_modes(basler: Pin<&mut BaslerBox>) -> Result<()>; - - unsafe fn basler_start_grabbing(basler: Pin<&mut BaslerBox>) -> Result<()>; - unsafe fn basler_stop_grabbing(basler: Pin<&mut BaslerBox>) -> Result<()>; - unsafe fn basler_is_grabbing(basler: Pin<&mut BaslerBox>) -> Result<bool>; - unsafe fn basler_get_image(basler: Pin<&mut BaslerBox>) -> Result<Vec<u8>>; + // type BaslerBox; - /**********************************************************************/ + // unsafe fn new_basler(index: i32) -> Result<UniquePtr<BaslerBox>>; + + // unsafe fn basler_print_device_info(basler: Pin<&mut BaslerBox>) -> Result<()>; + // unsafe fn basler_set_exposure(basler: Pin<&mut BaslerBox>, exposure_time: f64) -> Result<()>; + // unsafe fn basler_get_exposure(basler: Pin<&mut BaslerBox>) -> Result<f64>; + // unsafe fn basler_set_frame_rate(basler: Pin<&mut BaslerBox>, frame_rate: u32) -> Result<()>; + // unsafe fn basler_set_frame_rate_max(basler: Pin<&mut BaslerBox>) -> Result<()>; + // unsafe fn basler_set_gain(basler: Pin<&mut BaslerBox>, gain: f64) -> Result<()>; + // unsafe fn basler_get_gain(basler: Pin<&mut BaslerBox>) -> Result<f64>; + // unsafe fn basler_set_roi(basler: Pin<&mut BaslerBox>, offset_x: u32, offset_y: u32, width: u32, height: u32) -> Result<()>; + // unsafe fn basler_get_offset_x(basler: Pin<&mut BaslerBox>) -> Result<u32>; + // unsafe fn basler_get_offset_y(basler: Pin<&mut BaslerBox>) -> Result<u32>; + // unsafe fn basler_get_width(basler: Pin<&mut BaslerBox>) -> Result<u32>; + // unsafe fn basler_get_height(basler: Pin<&mut BaslerBox>) -> Result<u32>; + // unsafe fn basler_set_acquisition_mode(basler: Pin<&mut BaslerBox>, mode: &CxxString) -> Result<()>; + // unsafe fn basler_print_available_acquisition_modes(basler: Pin<&mut BaslerBox>) -> Result<()>; + + // unsafe fn basler_start_grabbing(basler: Pin<&mut BaslerBox>) -> Result<()>; + // unsafe fn basler_stop_grabbing(basler: Pin<&mut BaslerBox>) -> Result<()>; + // unsafe fn basler_is_grabbing(basler: Pin<&mut BaslerBox>) -> Result<bool>; + // unsafe fn basler_get_image(basler: Pin<&mut BaslerBox>) -> Result<Vec<u8>>; + + // /**********************************************************************/ - type UniformizationParams; + // type UniformizationParams; - unsafe fn new_uniformizationparams(source: &CxxString, polarizability: f64, mean_depth: f64, step_size: f64, error_threshold: f64, max_iters: i32, num_imaging_avg: i32, num_tweezers: i32) -> Result<UniquePtr<UniformizationParams>>; + // unsafe fn new_uniformizationparams(source: &CxxString, polarizability: f64, mean_depth: f64, step_size: f64, error_threshold: f64, max_iters: i32, num_imaging_avg: i32, num_tweezers: i32) -> Result<UniquePtr<UniformizationParams>>; - unsafe fn run_uniformization(awg: Pin<&mut AWGBox>, basler: Pin<&mut BaslerBox>, waveform: Pin<&mut ArrayWaveform>, params: &UniformizationParams) -> Result<()>; + // unsafe fn run_uniformization(awg: Pin<&mut AWGBox>, basler: Pin<&mut BaslerBox>, waveform: Pin<&mut ArrayWaveform>, params: &UniformizationParams) -> Result<()>; } } diff --git a/awg-cxx/lib/config.rs b/awg-cxx/lib/config.rs index 405725dd26c0d349c46cd5b6bf9359055274ad79..eacf53e240d03f98c60834b2df6f038b52591028 100644 --- a/awg-cxx/lib/config.rs +++ b/awg-cxx/lib/config.rs @@ -9,6 +9,7 @@ use crate::awg::{ TriggerMask, TriggerMode, TriggerTerm, + TriggerCoupling }; #[derive(Error, Debug)] @@ -16,15 +17,24 @@ pub enum ConfigError { #[error("invalid trigger level {0} for {1}: must be in the range -10000..+10000 mV")] InvalidTriggerLevel(i32, &'static str), - #[error("number of active channels must not be 3 and ≤ 4")] + #[error("length of enabled_channels, amplitudes, and stop_levels must be 4")] + ChannelLength, + + #[error("number of enabled channels must not be 3 and <= 4")] NumChannels, - #[error("channel {0}: amplitude must be in range 0..2^15 - 1")] + #[error("channel {0}: amplitude must be in range 80..2500 mV")] InvalidAmplitude(usize), #[error("invalid next_step index {0} at step {1}")] InvalidStepIndex(usize, usize), + #[error("number of memory segments must be power of 2, got {0}")] + InvalidNumSegments(u32), + + #[error("number of sequence segments must be less than or equal to number of memory segments, got {0}")] + InvalidNumSequenceSegments(usize), + // #[error("non-unique segment index {0} at step {1}")] // NonUniqueSegmentIndex(usize, usize), @@ -39,6 +49,7 @@ pub struct TriggerParams { pub mode: TriggerMode, pub level: i32, pub rearm_level: i32, + pub coupling: TriggerCoupling, } /// Configuration for the two `ext*` trigger channels. @@ -72,19 +83,32 @@ impl TriggerConfig { /// Output channel configuration. /// -/// Channel amplitudes must be in the range 0..2^15 - 1. -#[derive(Copy, Clone, Debug)] +/// Channel amplitudes must be in the range 80..2500 mV. +#[derive(Clone, Debug)] pub struct ChannelConfig { - pub channel: usize, - pub enabled: bool, - pub amplitude: u32, // ∊ [0, 2^15 - 1] - pub stop_level: ChannelStopLevel, + pub enabled_channels: [bool; 4], + pub amplitudes: [i32; 4], // ∊ [80, 2500] mV + pub stop_levels: Vec<ChannelStopLevel>, // must be 4 elements, use of vec here is not ideal, but okay for now } impl ChannelConfig { pub fn check(&self) -> ConfigResult<()> { - (0..32767_u32).contains(&self.amplitude).then_some(()) - .ok_or(ConfigError::InvalidAmplitude(self.channel))?; + let channels = &self.enabled_channels; + (self.stop_levels.len() == 4) + .then_some(()) + .ok_or(ConfigError::ChannelLength)?; + (channels.iter().filter(|&&c| c).count() != 3) + .then_some(()) + .ok_or(ConfigError::NumChannels)?; + self.amplitudes + .iter() + .enumerate() + .map(|(i, &)| { + (80..=2500).contains(&).then_some(()) + .ok_or(ConfigError::InvalidAmplitude(i)) + }) + .collect::<ConfigResult<Vec<_>>>()?; + Ok(()) } } @@ -98,23 +122,24 @@ pub enum SequenceKind { /// Sequence step configuration. #[derive(Clone, Debug)] -pub struct SequenceStepConfig { +pub struct SequenceSegmentsConfig { pub source: PathBuf, - pub kind: SequenceKind, - pub next_step: usize, // < number of steps + pub step: usize, // step index associated with this segment + pub next_step: usize, // next step index to jump to pub n_loop: u32, - pub condition: SeqLoopCondition, + pub loop_condition: SeqLoopCondition, } /// Overall AWG configuration. #[derive(Clone, Debug)] pub struct Config { + pub r#use: bool, // whether to use the AWG pub index: usize, pub sampling_rate: u64, // ≥ 1 - pub frequency_resolution: u64, // ≥ 1 + pub num_segments: u32, // must be a power of 2 pub trigger: TriggerConfig, - pub active_channels: Vec<ChannelConfig>, - pub sequence_steps: Vec<SequenceStepConfig>, + pub active_channels: ChannelConfig, + pub sequence_segments: Vec<SequenceSegmentsConfig>, } impl Config { @@ -124,70 +149,44 @@ impl Config { trigger.check() } - pub(crate) fn check_channels(channels: &[ChannelConfig]) + pub(crate) fn check_channels(channels: &ChannelConfig) -> ConfigResult<()> { - let n_channels = channels.len(); - (n_channels <= 4 && n_channels != 3).then_some(()) - .ok_or(ConfigError::NumChannels)?; - channels.iter() - .map(|ch| ch.check()) - .collect::<ConfigResult<Vec<()>>>()?; - Ok(()) + channels.check() } - pub(crate) fn check_sequence_steps(steps: &[SequenceStepConfig]) + pub(crate) fn check_sequence_segments(segments: &[SequenceSegmentsConfig]) -> ConfigResult<()> { - let n_steps = steps.len(); - let step_range = 0..n_steps; - // let mut segments: Vec<usize> = (0..n_steps).collect(); - steps.iter().enumerate() - .map(|(k, step)| { - Ok((k, step)) - // .and_then(|(k, step)| { - // step_range.contains(&step.segment) - // .then_some((k, step)) - // .ok_or(ConfigError::InvalidStepIndex( - // step.segment, k - // )) - // }) - // .and_then(|(k, step)| { - // segments.iter().enumerate() - // .find_map(|(i, seg)| { - // (*seg == step.segment).then_some(i) - // }) - // .map(|i| { - // segments.swap_remove(i); - // (k, step) - // }) - // .ok_or(ConfigError::NonUniqueSegmentIndex( - // step.segment, k - // )) - // }) - .and_then(|(k, step)| { - step_range.contains(&step.next_step) - .then_some((k, step)) - .ok_or(ConfigError::InvalidStepIndex( - step.next_step, k - )) - }) - .and_then(|(k, step)| { - step.source.exists().then_some((k, step)) + segments.iter().enumerate() + .map(|(k, seg)| { + Ok((k, seg)) + .and_then(|(k, seg)| { + (seg.source.exists() && seg.source.ends_with(".txt")) + .then_some((k, seg)) .ok_or(ConfigError::MissingWaveformSource( - step.source.display().to_string(), k + seg.source.display().to_string(), k )) }) }) .collect::<ConfigResult<Vec<_>>>()?; Ok(()) - } + } // - /// Verify that all data satisfies necessary constraints. + /// Verify that all data satisfies necessary constraints, commenting out since + /// this is already checked at the camera control config level. pub fn check(&self) -> ConfigResult<()> { - Self::check_trigger_params(&self.trigger)?; - Self::check_channels(&self.active_channels)?; - Self::check_sequence_steps(&self.sequence_steps)?; + // let n_segments = self.num_segments; + // (n_segments & (n_segments - 1) == 0) // this checks if n_segments is a power of 2 + // .then_some(()) + // .ok_or(ConfigError::InvalidNumSegments(n_segments))?; + // let n_seq_segments = &self.sequence_segments.len(); + // (*n_seq_segments as u32 > n_segments) + // .then_some(()) + // .ok_or(ConfigError::InvalidNumSequenceSegments(*n_seq_segments))?; + // Self::check_trigger_params(&self.trigger)?; + // Self::check_channels(&self.active_channels)?; + // Self::check_sequence_segments(&self.sequence_segments)?; Ok(()) } } diff --git a/awg-cxx/lib/lib.rs b/awg-cxx/lib/lib.rs index ad29185a7ea11d60e3ff475e8a3ffcddbdf56882..4a53e557a6d7d13e5ccd7c7b45db28b573ea017b 100644 --- a/awg-cxx/lib/lib.rs +++ b/awg-cxx/lib/lib.rs @@ -2,7 +2,7 @@ pub(crate) mod awg_ffi; pub mod awg; -pub mod basler; +// pub mod basler; pub mod config; pub mod prelude; diff --git a/awg-cxx/lib/prelude.rs b/awg-cxx/lib/prelude.rs index 4a71ddbc23178a5e36d4e17e80e62d2712e46470..291850e29facd0e2397fc9c7b028ae75f13f3ae6 100644 --- a/awg-cxx/lib/prelude.rs +++ b/awg-cxx/lib/prelude.rs @@ -1,11 +1,11 @@ pub use crate::{ awg::{ AWG, - ArrayWaveform, - PageAlignedMem, - WaveformDataPtr, - WaveformParams, - BufferType, + // ArrayWaveform, + // PageAlignedMem, + // WaveformDataPtr, + // WaveformParams, + // BufferType, ChannelPair, ChannelStopLevel, ClockMode, @@ -17,23 +17,23 @@ pub use crate::{ TriggerMask, TriggerMode, TriggerTerm, - UniformizationParams, + // UniformizationParams, AWGError, AWGResult, }, - basler::{ - Basler, - Config as BaslerConfig, - AcquisitionMode, - BaslerError, - BaslerResult, - }, + // basler::{ + // Basler, + // Config as BaslerConfig, + // AcquisitionMode, + // BaslerError, + // BaslerResult, + // }, config::{ TriggerParams, TriggerConfig, ChannelConfig, SequenceKind, - SequenceStepConfig, + SequenceSegmentsConfig, Config, ConfigError, ConfigResult, diff --git a/config.toml b/config.toml index 63f5aae3e2bf43865aa2d75ab9d81666e57fffa8..7bebff88be54bf55ef9cf6c73d40794236d6ded4 100644 --- a/config.toml +++ b/config.toml @@ -78,7 +78,7 @@ enabled = false image_dim = [3, 3] # [int, int] : [w, h] n_loop = 3 # int : images per loop mode = "bright" # str : bright, dark -box = [9, 3, 3, 3] # [int, int, int, int] : sub-ROI for photon counting +counting_box = [9, 3, 3, 3] # [int, int, int, int] : sub-ROI for photon counting threshold = 12.0 # float [processing.ff_series] @@ -86,61 +86,62 @@ enabled = false image_dim = [3, 3] # [int, int] : [w, h] n_loop = 14 # int : images per loop mode = "xor" # str : xor, xnor, alternate -box = [9, 3, 3, 3] # [int, int, int, int] : sub-ROI for photon counting +counting_box = [9, 3, 3, 3] # [int, int, int, int] : sub-ROI for photon counting threshold = 12.0 # float [awg] -index = 0 # int : 0, 1 +use = false # bool +index = 1 # int : 0, 1 sampling_rate = 614400000 # int, Hz -frequency_resolution = 1000 # int, Hz +num_segments = 2 # int : must be pow(2) +# frequency_resolution = 1000 # int, Hz [awg.trigger] masks_or = ["ext0"] # [str] : none, software, ext0, ext1 -masks_and = [] # [str] : none, software, ext0, ext1 +masks_and = ["none"] # [str] : none, ext0, ext1 termination = "fiftyohm" # str : high, fiftyohm [awg.trigger.ext0] mode = "pos" # str : none, pos, neg, both, high, low, winenter, winleave, inwin, outsidewin, pos_rearm, neg_rearm -level = 2500 # int : [-10000, +10000] mV -rearm_level = 2500 # int : [-10000, +10000] mV +level = 1000 # int : [-10000, +10000] mV +rearm_level = 1000 # int : [-10000, +10000] mV, used only in "win*, *win, *_rearm" modes +coupling = "dc" # str : dc, ac [awg.trigger.ext1] mode = "none" # str : none, pos, neg, both, high, low, winenter, winleave, inwin, outsidewin, pos_rearm, neg_rearm -level = 2500 # int : [-10000, +10000] mV -rearm_level = 2500 # int : [-10000, +10000] mV - -[[awg.active_channels]] -channel = 0 # int -enabled = true # bool -amplitude = 2500 # int : 0..2^15-1 -stop_level = "zero" # str : low, high, hold-last, zero - -[[awg.sequence_steps]] -source = "<file>" # str -kind = "static" # str : static, trick -segment = 0 # int -next_segment = 1 # int +level = 1000 # int : [-10000, +10000] mV +rearm_level = 1000 # int : [-10000, +10000] mV +coupling = "dc" # str : dc, ac + +[awg.active_channels] +enabled_channels = [true, false, false, false] # [bool, bool, bool, bool] : [ch0, ch1, ch2, ch3] +amplitudes = [2500, 2500, 2500, 2500] # [80, 2500] mV +stop_levels = ["zero", "zero", "zero", "zero"] # str : low, high, hold-last, zero + +[[awg.sequence_segments]] +source = "/home/coveylab/Documents/Control/awg-control/Python/data/wfmPython.txt" # str +step = 0 # int +next_step = 0 # int n_loop = 1 # int : ≥ 1 -condition = "ontrigger" # str : always, ontrigger, end - -[[awg.sequence_steps]] -source = "<file>" # str -kind = "static" # str : static, trick -segment = 1 # int -next_segment = 0 # int -n_loop = 1 # int -condition = "ontrigger" # str : always, ontrigger, end - -[awg.uniformization] -source = "/home/coveylab/Documents/Data/atomic_data/20231013/probe-scan_000" # str -# polarizability = -1.24e-3 # float : kHz/μK (H-polarized tweezers, measured 2023.08.08) -polarizability_kHz_uK = -5.6e-3 # float : kHz/μK (V-polarized tweezers, measured 2023.08.08) -mean_depth_uK = 575.0 # float : μK -step_size = 50.0 # float : 0..2^15 - 1 -error_threshold = 0.003 # float -max_iters = 50 # int -num_imaging_avg = 10 # int -num_tweezers = 20 # int +loop_condition = "ontrigger" # str : always, ontrigger, end + +# [[awg.sequence_segments]] +# source = "<file>" # str +# step = 1 # int +# next_step = 0 # int +# n_loop = 1 # int : ≥ 1 +# loop_condition = "ontrigger" # str : always, ontrigger, end + +# [awg.uniformization] +# source = "/home/coveylab/Documents/Data/atomic_data/20231013/probe-scan_000" # str +# # polarizability = -1.24e-3 # float : kHz/μK (H-polarized tweezers, measured 2023.08.08) +# polarizability_kHz_uK = -5.6e-3 # float : kHz/μK (V-polarized tweezers, measured 2023.08.08) +# mean_depth_uK = 575.0 # float : μK +# step_size = 50.0 # float : 0..2^15 - 1 +# error_threshold = 0.003 # float +# max_iters = 50 # int +# num_imaging_avg = 10 # int +# num_tweezers = 20 # int [timetagger] use = false # bool @@ -151,11 +152,11 @@ stop_channel = 3 # int binwidth_sec = 0.015 # float n_bins = 1 # int -[basler] -index = 0 # int -exposure_time_us = 1200.0 # float -gain = 0.0 # float -acquisition_mode = "continuous" # str : continuous, <?...> -frame_rate = 10 # int -roi = [0, 500, 0, 500] # [xmin, xmax, ymin, ymax] +# [basler] +# index = 0 # int +# exposure_time_us = 1200.0 # float +# gain = 0.0 # float +# acquisition_mode = "continuous" # str : continuous, <?...> +# frame_rate = 10 # int +# roi = [0, 500, 0, 500] # [xmin, xmax, ymin, ymax] diff --git a/librs/actions.rs b/librs/actions.rs index 3f412bbdd3d6c6ea8c8e9188b8eea3994f91bd84..9efa646c5f434a033930a616e1a23debfb365ca2 100644 --- a/librs/actions.rs +++ b/librs/actions.rs @@ -65,6 +65,9 @@ pub enum ActionError { #[error("AWG error: {0}")] AWGError(#[from] awg::AWGError), + #[error("AWG mutability lock has been violated")] + AWGMutabilityLock, + #[error("timetagger mutability lock has been violated")] TaggerMutabilityLock, @@ -109,6 +112,11 @@ pub static ACTION_REGISTRY: phf::Map<&'static str, ActionFn> "acquire" => acquire, "camera-info" => camera_info, "temperature" => temperature, + "temperature-monitor" => temperature_monitor, + "awg-run" =>awg_run, + "awg-stop" => awg_stop, + "awg-trigger" => awg_trigger, + "awg-reload-config" => awg_reload_config, // "get-capabilities" => get_capabilities, }; @@ -269,6 +277,39 @@ pub fn temperature( } } +pub fn temperature_monitor( + devices: Arc<ArcDevices>, + _config: &config::Config, + _args: &[String], +) -> ActionResult<()> +{ + struct Stop; + let cam = devices.camera(); + let (tx, rx) = unbounded::<Stop>(); + println!("Press ENTER to stop:"); + let slave = std::thread::spawn(move || -> ActionResult<()> { + let mut line: String = "".to_string(); + loop { + if rx.try_recv().is_ok() { + println!(); + break; + } + let (temperature, status): (f32, andor::TemperatureStatus) + = cam.get_temperature()?; + print_flush!("\r{}", " ".repeat(line.len())); + line = format!(" Temperature: {:+.1}C; {:?} ", temperature, status); + print_flush!("\r{}", line); + std::thread::sleep(std::time::Duration::from_millis(1000)); + } + Ok(()) + }); + + let mut line = String::new(); + std::io::stdin().read_line(&mut line)?; + tx.send(Stop).expect("termination channel closed unexpectedly"); + return jointhrough!(slave); +} + macro_rules! convert_cmap_bound { ($val:expr) => { if $val < 0.0 { @@ -392,13 +433,9 @@ pub fn acquire( = outpath.join(format!("{}_{:03}.npy", out_name, counter)); } outfile = Some(test_out.clone()); - let mut file_name = test_out.file_stem().unwrap().to_owned(); - file_name.push(format!("_tt.npy")); outfile_tt = Some( - // test_out.with_file_name( - // format!("{:?}_tt.npy", test_out.file_stem().unwrap().to_str().unwrap()) - // ) - test_out.with_file_name(file_name) + test_out.with_file_name( + format!("{:?}_tt.npy", test_out.file_stem().unwrap())) ); println!("Save data to file '{}'", outfile.as_ref().unwrap().display()); } @@ -513,6 +550,78 @@ pub fn acquire( Ok(()) } +pub fn awg_run( + devices: Arc<ArcDevices>, + _config: &config::Config, + _args: &[String], +) -> ActionResult<()> +{ + if let Some(awg_arc) = devices.awg().as_mut() { + awg_arc.lock() + .map_err(|_| ActionError::AWGMutabilityLock)? + .card_run()? + .force_trigger()? + ; + println!("AWG is running"); + } else { + println!("AWG is not connected"); + } + Ok(()) +} + +pub fn awg_stop( + devices: Arc<ArcDevices>, + _config: &config::Config, + _args: &[String], +) -> ActionResult<()> +{ + if let Some(awg_arc) = devices.awg().as_mut() { + awg_arc.lock() + .map_err(|_| ActionError::AWGMutabilityLock)? + .card_stop()?; + println!("AWG is stopped"); + } else { + println!("AWG is not connected"); + } + Ok(()) +} + +pub fn awg_trigger( + devices: Arc<ArcDevices>, + _config: &config::Config, + _args: &[String], +) -> ActionResult<()> +{ + if let Some(awg_arc) = devices.awg().as_mut() { + awg_arc.lock() + .map_err(|_| ActionError::AWGMutabilityLock)? + .force_trigger()?; + println!("AWG is triggered"); + } else { + println!("AWG is not connected"); + } + Ok(()) +} + +pub fn awg_reload_config( + devices: Arc<ArcDevices>, + config: &config::Config, + _args: &[String], +) -> ActionResult<()> +{ + if let Some(awg_arc) = devices.awg().as_mut() { + awg_arc.lock() + .map_err(|_| ActionError::AWGMutabilityLock)? + .card_stop()? + .set_config(&config.awg.clone().into())?; + println!("AWG config reloaded"); + } else { + println!("AWG is not connected"); + } + Ok(()) +} + + /// Acquisition abort signal. pub struct AbortAcquisition; diff --git a/librs/cli.rs b/librs/cli.rs index caff2b8b635bb0a34667ea7e43a19244a2b7ee99..8648e65bac6f78c8907749479f204a6c14389720 100644 --- a/librs/cli.rs +++ b/librs/cli.rs @@ -647,6 +647,31 @@ Available commands:", continue; } } + if config.awg.r#use && !devices.has_awg() { + if let Some(dev) = Arc::get_mut(&mut devices) { + let awg_index: usize = config.awg.index; + let mut awg + = continue_err!(AWG::connect(awg_index)); + awg.set_config(&config.awg.clone().into())?; + dev.use_awg(awg); + } else { + println!( + "Error: device mutability check failed. \ + This shouldn't happen!" + ); + continue; + } + } else if !config.awg.r#use && devices.has_awg() { + if let Some(dev) = Arc::get_mut(&mut devices) { + dev.remove_awg(); + } else { + println!( + "Error: device mutability check failed. \ + This shouldn't happen!" + ); + continue; + } + } let action_res = action_f( devices.clone(), diff --git a/librs/colors.rs b/librs/colors.rs index 0c940f5271da67641bf8a232b3b118bd408cdca8..207de2502c408abb5a5e2e47e54617b9859cf3c2 100644 --- a/librs/colors.rs +++ b/librs/colors.rs @@ -55,9 +55,6 @@ pub enum ColorMap { /// Linear scale from blue through gold to white. Pix(Pix), - /// Linear scale from black to 556nm (modeled as `#b6ff00`). - AtomWL(AtomWL), - /// Specify a custom colormap as a list of colors at different points with /// linear interpolation in between. LinearSegmentedColorMap(LinearSegmentedColorMap), @@ -116,11 +113,6 @@ impl ColorMap { Self::Pix(Pix::new()) } - /// Create a new [AtomWL] colormap. - pub fn new_atom_wl() -> Self { - return Self::AtomWL(AtomWL::new()); - } - /// Create a new linear segmented colormap. pub fn new_linear_segmented_colormap(colormap: LinearSegmentedColorMap) -> Self @@ -145,7 +137,6 @@ impl ColorMap { Self::Vibrant(v) => v.c(x), Self::Artsy(a) => a.c(x), Self::Pix(p) => p.c(x), - Self::AtomWL(a) => a.c(x), Self::FuncColorMap(f) => f.c(x), Self::LinearSegmentedColorMap(l) => l.c(x), } @@ -353,15 +344,6 @@ make_linsegcolormap!( } ); -make_linsegcolormap!( - "Linear scale black -> 556nm (`#b6ff00`)", - AtomWL, - colors: { - 0.000 => ( 0, 0, 0), - 1.000 => (182, 255, 0), - } -); - /// Color scale based on a provided function. #[derive(Copy, Clone, Debug)] pub struct FuncColorMap { diff --git a/librs/config.rs b/librs/config.rs index 24eb5054c59bde11cc3a99b109314442fab41bb4..bc505145afb433430b180d346c05996d2f626de3 100644 --- a/librs/config.rs +++ b/librs/config.rs @@ -322,12 +322,29 @@ impl From<AWGTriggerTerm> for awg::TriggerTerm { } } +/// awg.trigger.coupling +#[derive(Copy, Clone, Debug, PartialEq, Eq, Deserialize)] +pub enum AWGTriggerCoupling { + dc, + ac, +} + +impl From<AWGTriggerCoupling> for awg::TriggerCoupling { + fn from(coupling: AWGTriggerCoupling) -> Self { + match coupling { + AWGTriggerCoupling::dc => Self::DC, + AWGTriggerCoupling::ac => Self::AC, + } + } +} + /// `awg.trigger.ext0`, `awg.trigger.ext1` #[derive(Copy, Clone, Debug, Deserialize)] pub struct AWGTriggerParams { pub mode: AWGTriggerMode, pub level: i32, pub rearm_level: i32, + pub coupling: AWGTriggerCoupling, // } impl From<AWGTriggerParams> for awg::TriggerParams { @@ -336,6 +353,7 @@ impl From<AWGTriggerParams> for awg::TriggerParams { mode: params.mode.into(), level: params.level, rearm_level: params.rearm_level, + coupling: params.coupling.into(), } } } @@ -407,21 +425,20 @@ impl From<AWGChannelStopLevel> for awg::ChannelStopLevel { } /// `awg.active_channels[...]` -#[derive(Copy, Clone, Debug, Deserialize)] +#[derive(Clone, Debug, Deserialize)] pub struct AWGChannel { - pub channel: usize, - pub enabled: bool, - pub amplitude: u32, // ∊ [0, 2^15 - 1] - pub stop_level: AWGChannelStopLevel, + pub enabled_channels: [bool; 4], // ∈ {true, false} + pub amplitudes: [i32; 4], // ∊ [80, 2500] mV + pub stop_levels: Vec<AWGChannelStopLevel>, // must be 4 elements, use of vec here is not ideal, but okay for now } impl From<AWGChannel> for awg::ChannelConfig { fn from(channel_conf: AWGChannel) -> Self { Self { - channel: channel_conf.channel, - enabled: channel_conf.enabled, - amplitude: channel_conf.amplitude, - stop_level: channel_conf.stop_level.into(), + enabled_channels: channel_conf.enabled_channels, + amplitudes: channel_conf.amplitudes, + stop_levels: channel_conf.stop_levels.into_iter() + .map(|sl| sl.into()).collect(), } } } @@ -462,79 +479,79 @@ impl From<AWGSequenceCondition> for awg::SeqLoopCondition { /// `awg.sequence_steps[...]` #[derive(Clone, Debug, Deserialize)] -pub struct AWGSequenceStep { +pub struct AWGSequenceSegment { pub source: PathBuf, - pub kind: AWGSequenceKind, + pub step: usize, pub next_step: usize, // < number of steps pub n_loop: u32, - pub condition: AWGSequenceCondition, + pub loop_condition: AWGSequenceCondition, } -impl From<AWGSequenceStep> for awg::SequenceStepConfig { - fn from(seq_step: AWGSequenceStep) -> Self { +impl From<AWGSequenceSegment> for awg::SequenceSegmentsConfig { + fn from(seq_seg: AWGSequenceSegment) -> Self { Self { - source: seq_step.source, - kind: seq_step.kind.into(), - next_step: seq_step.next_step, - n_loop: seq_step.n_loop, - condition: seq_step.condition.into(), + source: seq_seg.source, + step: seq_seg.step, + next_step: seq_seg.next_step, + n_loop: seq_seg.n_loop, + loop_condition: seq_seg.loop_condition.into(), } } } /// `awg.uniformization` -#[derive(Clone, Debug, Deserialize)] -pub struct AWGUniformizationParams { - pub source: PathBuf, - pub polarizability_kHz_uK: f64, - pub mean_depth_uK: f64, - pub step_size: f64, - pub error_threshold: f64, - pub max_iters: usize, - pub num_imaging_avg: usize, - pub num_tweezers: usize, -} - -impl From<AWGUniformizationParams> for awg::UniformizationParams { - fn from(params: AWGUniformizationParams) -> Self { - Self::new_all( - params.source, - params.polarizability_kHz_uK, - params.mean_depth_uK, - params.step_size, - params.error_threshold, - params.max_iters, - params.num_imaging_avg, - params.num_tweezers, - ) - } -} +// #[derive(Clone, Debug, Deserialize)] +// pub struct AWGUniformizationParams { +// pub source: PathBuf, +// pub polarizability_kHz_uK: f64, +// pub mean_depth_uK: f64, +// pub step_size: f64, +// pub error_threshold: f64, +// pub max_iters: usize, +// pub num_imaging_avg: usize, +// pub num_tweezers: usize, +// } + +// impl From<AWGUniformizationParams> for awg::UniformizationParams { +// fn from(params: AWGUniformizationParams) -> Self { +// Self::new_all( +// params.source, +// params.polarizability_kHz_uK, +// params.mean_depth_uK, +// params.step_size, +// params.error_threshold, +// params.max_iters, +// params.num_imaging_avg, +// params.num_tweezers, +// ) +// } +// } /// `awg` #[derive(Clone, Debug, Deserialize)] pub struct AWG { + pub r#use: bool, pub index: usize, pub sampling_rate: u64, // ≥ 1 - pub frequency_resolution: u64, // ≥ 1 + pub num_segments: u32, pub trigger: AWGTrigger, - pub active_channels: Vec<AWGChannel>, - pub sequence_steps: Vec<AWGSequenceStep>, - pub uniformization: AWGUniformizationParams, + pub active_channels: AWGChannel, + pub sequence_segments: Vec<AWGSequenceSegment>, + // pub uniformization: AWGUniformizationParams, } impl From<AWG> for awg::Config { fn from(awg_conf: AWG) -> Self { Self { + r#use: awg_conf.r#use, index: awg_conf.index, sampling_rate: awg_conf.sampling_rate, - frequency_resolution: awg_conf.frequency_resolution, + num_segments: awg_conf.num_segments, trigger: awg_conf.trigger.into(), - active_channels: - awg_conf.active_channels.into_iter() - .map(|ch| ch.into()).collect(), - sequence_steps: - awg_conf.sequence_steps.into_iter() - .map(|step| step.into()).collect(), + active_channels: awg_conf.active_channels.into(), + sequence_segments: + awg_conf.sequence_segments.into_iter() + .map(|seg| seg.into()).collect(), } } } @@ -552,729 +569,337 @@ pub struct TimeTagger { } /// `basler.acquisition_mode` -#[derive(Copy, Clone, Debug, PartialEq, Eq, Deserialize)] -pub enum BaslerAcquisitionMode { - continuous, - // ...? -} - -impl From<BaslerAcquisitionMode> for awg::AcquisitionMode { - fn from(mode: BaslerAcquisitionMode) -> Self { - match mode { - BaslerAcquisitionMode::continuous => Self::Continuous, - } - } -} +// #[derive(Copy, Clone, Debug, PartialEq, Eq, Deserialize)] +// pub enum BaslerAcquisitionMode { +// continuous, +// // ...? +// } + +// impl From<BaslerAcquisitionMode> for awg::AcquisitionMode { +// fn from(mode: BaslerAcquisitionMode) -> Self { +// match mode { +// BaslerAcquisitionMode::continuous => Self::Continuous, +// } +// } +// } /// `basler` -#[derive(Copy, Clone, Debug, Deserialize)] -pub struct Basler { - pub index: usize, - pub exposure_time_us: f64, - pub gain: f64, - pub acquisition_mode: BaslerAcquisitionMode, - pub frame_rate: u32, - pub roi: [usize; 4], -} - -/// Shorthand for creating [`ConfigSpecItem`]s. -#[macro_export] -macro_rules! spec { - ( Bool ) => { ConfigSpecItem::Value(Verifier::TypeVer(TypeVer::Bool)) }; - ( Int ) => { ConfigSpecItem::Value(Verifier::TypeVer(TypeVer::Int)) }; - ( Float ) => { ConfigSpecItem::Value(Verifier::TypeVer(TypeVer::Float)) }; - ( Datetime ) => { ConfigSpecItem::Value(Verifier::TypeVer(TypeVer::Datetime)) }; - ( Array ) => { ConfigSpecItem::Value(Verifier::TypeVer(TypeVer::Array)) }; - ( TypedArray { [ $( $t:expr ),* $(,)? ], finite: $f:expr } ) => { - ConfigSpecItem::Value( - Verifier::TypeVer( - TypeVer::TypedArray { types: vec![$( $t ),*], finite: $f } - ) - ) - }; - ( Str ) => { ConfigSpecItem::Value(Verifier::TypeVer(TypeVer::Str)) }; - ( IntRange { ($min:expr, $max:expr) } ) => { - ConfigSpecItem::Value( - Verifier::ValueVer( - ValueVer::IntRange { - min: $min, - max: $max, - incl_start: false, - incl_end: false, - } - ) - ) - }; - ( IntRange { ($min:expr, $max:expr)= } ) => { - ConfigSpecItem::Value( - Verifier::ValueVer( - ValueVer::IntRange { - min: $min, - max: $max, - incl_start: false, - incl_end: true, - } - ) - ) - }; - ( IntRange { =($min:expr, $max:expr) } ) => { - ConfigSpecItem::Value( - Verifier::ValueVer( - ValueVer::IntRange { - min: $min, - max: $max, - incl_start: true, - incl_end: false, - } - ) - ) - }; - ( IntRange { =($min:expr, $max:expr)= } ) => { - ConfigSpecItem::Value( - Verifier::ValueVer( - ValueVer::IntRange { - min: $min, - max: $max, - incl_start: true, - incl_end: true, - } - ) - ) - }; - ( FloatRange { ($min:expr, $max:expr) } ) => { - ConfigSpecItem::Value( - Verifier::ValueVer( - ValueVer::FloatRange { - min: $min, - max: $max, - incl_start: false, - incl_end: false, - } - ) - ) - }; - ( FloatRange { ($min:expr, $max:expr)= } ) => { - ConfigSpecItem::Value( - Verifier::ValueVer( - ValueVer::FloatRange { - min: $min, - max: $max, - incl_start: false, - incl_end: true, - } - ) - ) - }; - ( FloatRange { =($min:expr, $max:expr) } ) => { - ConfigSpecItem::Value( - Verifier::ValueVer( - ValueVer::FloatRange { - min: $min, - max: $max, - incl_start: true, - incl_end: false, - } - ) - ) - }; - ( FloatRange { =($min:expr, $max:expr)= } ) => { - ConfigSpecItem::Value( - Verifier::ValueVer( - ValueVer::FloatRange { - min: $min, - max: $max, - incl_start: true, - incl_end: true, - } - ) - ) - }; - ( Table { $( $key:literal => $val:expr ),* $(,)? } ) => { - ConfigSpecItem::Table( - ConfigSpec::from_iter([ - $( - ($key.to_string(), $val) - ),* - ]) - ) - }; - ( StrCollection { $( $s:expr ),* $(,)? } ) => { - ConfigSpecItem::Value( - Verifier::ValueVer( - ValueVer::StrCollection( - HashSet::from_iter([ - $( $s.to_string() ),* - ]) - ) - ) - ) - }; -} - -/// Sugared [`std::collections::HashMap`] representing a specification for the -/// values and structure of a TOML-formatted config file. -#[derive(Clone, Debug)] -pub struct ConfigSpec { - spec: HashMap<String, ConfigSpecItem> -} - -impl AsRef<HashMap<String, ConfigSpecItem>> for ConfigSpec { - fn as_ref(&self) -> &HashMap<String, ConfigSpecItem> { &self.spec } -} - -impl From<HashMap<String, ConfigSpecItem>> for ConfigSpec { - fn from(spec: HashMap<String, ConfigSpecItem>) -> Self { Self { spec } } -} - -impl FromIterator<(String, ConfigSpecItem)> for ConfigSpec { - fn from_iter<I>(iter: I) -> Self - where I: IntoIterator<Item = (String, ConfigSpecItem)> - { - return Self { spec: iter.into_iter().collect() }; - } -} - -/// Create a [`ConfigSpec`]. -/// -/// Expects `str` literals for keys and [`ConfigSpecItem`]s for values. See also -/// [`spec`]. -#[macro_export] -macro_rules! config_spec { - ( $( $key:literal => $val:expr ),* $(,)? ) => { - ConfigSpec::from_iter([ - $( - ($key.to_string(), $val) - ),* - ]) - } -} - -impl Default for ConfigSpec { - fn default() -> Self { - return config_spec!( - "output" => spec!(Table { - "save" => spec!(Bool), - "datadir" => spec!(Str), - "dir" => spec!(Str), - "name" => spec!(Str), - "counter" => spec!(Int), - "show_frames" => spec!(Table { - "mode" => spec!(StrCollection { - "off", - "first", - "last", - "all", - }), - "color_scale" => spec!(StrCollection { - "gray", - "grayclip", - "paperscale", - "plasma", - "vibrant", - "artsy", - "pix", - "atomwl", - }), - "colorbar_limits" => spec!(TypedArray { - [TypeVer::Float, TypeVer::Float], - finite: true - }), - }), - }), - "camera" => spec!(Table { - "acquisition_mode" => spec!(StrCollection { - "single", - "accum", - "kinetic", - "fast_kinetic", - "cont", - }), - "roi" => spec!(TypedArray { - [TypeVer::Int, TypeVer::Int, TypeVer::Int, TypeVer::Int], - finite: true - }), - "bin" => spec!(TypedArray { - [TypeVer::Int, TypeVer::Int], - finite: true - }), - "exposure_time_ms" => spec!(FloatRange { =(1e-3, 1e3)= }), - "cooler" => spec!(Table { - "on" => spec!(Bool), - "fan_mode" => spec!(StrCollection { - "full", - "low", - "off", - }), - "temperature_c" => spec!(FloatRange { =(-100.0, 30.0)= }), - }), - "amp" => spec!(Table { - "em_gain" => spec!(IntRange { =(2, 300)= }), - "preamp_gain_idx" => spec!(IntRange { =(0, 1)= }), - "oamp" => spec!(IntRange { =(0, 1)= }), - }), - "shutter" => spec!(Table { - "mode" => spec!(StrCollection { - "auto", - "open", - "closed", - "fvb", - "any", - }), - "ttl_mode" => spec!(IntRange { =(0, 1)= }), - "open_time_ms" - => spec!(FloatRange { =(27.0, f64::INFINITY) }), - "close_time_ms" - => spec!(FloatRange { =(27.0, f64::INFINITY) }), - }), - "trigger" => spec!(Table { - "mode" => spec!(StrCollection { - "int", - "ext", - "ext_start", - "ext_exp", - "software", - "ext_chargeshift", - }), - }), - "read" => spec!(Table { - "mode" => spec!(StrCollection { - "fvb", - "single_track", - "multi_track", - "random_track", - "image", - }), - "hsspeed_idx" => spec!(IntRange { =(0, 3)= }), - "vsspeed_idx" => spec!(IntRange { =(0, 3)= }), - }), - "kinetic" => spec!(Table { - "buffer_size" => spec!(IntRange { =(1, i64::MAX)= }), - "cycle_time" - => spec!(FloatRange { =(0.0, f64::INFINITY) }), - "num_acc" => spec!(IntRange { =(1, i64::MAX)= }), - "cycle_time_acc" - => spec!(FloatRange { =(0.0, f64::INFINITY) }), - "num_prescan" => spec!(IntRange { =(0, i64::MAX)= }), - }), - }), - "processing" => spec!(Table { - "show" => spec!(StrCollection { - "off", - "first", - "last", - "all", - }), - "color_scale" => spec!(StrCollection { - "gray", - "grayclip", - "paperscale", - "plasma", - "vibrant", - "artsy", - "pix", - "atomwl", - }), - "colorbar_limits" => spec!(TypedArray { - [TypeVer::Float, TypeVer::Float], - finite: true - }), - "count_bias" => spec!(Float), - "qe" => spec!(FloatRange { =(0.0, 1.0)= }), - "window_avg" => spec!(Table { - "enabled" => spec!(Bool), - "image_dim" => spec!(TypedArray { - [TypeVer::Int, TypeVer::Int], - finite: true - }), - "window_size" => spec!(IntRange { =(1, i64::MAX)= }), - "rolling_avg" => spec!(Bool), - }), - "ff_prep" => spec!(Table { - "enabled" => spec!(Bool), - "image_dim" => spec!(TypedArray { - [TypeVer::Int, TypeVer::Int], - finite: true - }), - "n_loop" => spec!(IntRange { =(1, i64::MAX)= }), - "mode" => spec!(StrCollection { "bright", "dark" }), - "box" => spec!(TypedArray { - [ - TypeVer::Int, - TypeVer::Int, - TypeVer::Int, - TypeVer::Int, - ], - finite: true - }), - "threshold" => spec!(FloatRange { =(0.0, f64::INFINITY) }), - }), - "ff_series" => spec!(Table { - "enabled" => spec!(Bool), - "image_dim" => spec!(TypedArray { - [TypeVer::Int, TypeVer::Int], - finite: true - }), - "n_loop" => spec!(IntRange { =(1, i64::MAX)= }), - "mode" => spec!(StrCollection { - "xor", - "xnor", - "alternate", - }), - "box" => spec!(TypedArray { - [ - TypeVer::Int, - TypeVer::Int, - TypeVer::Int, - TypeVer::Int, - ], - finite: true - }), - "threshold" => spec!(FloatRange { =(0.0, f64::INFINITY) }), - }), - }), - "timetagger" => spec!(Table { - "use" => spec!(Bool), - "serial" => spec!(Str), - "counter_channel" => spec!(Int), - "start_channel" => spec!(Int), - "stop_channel" => spec!(Int), - "binwidth_sec" => spec!(Float), - "n_bins" => spec!(Int), - }), - ); - } -} - -impl ConfigSpec { - pub fn from_spec(spec: HashMap<String, ConfigSpecItem>) -> Self { - return Self { spec }; - } - - fn verify_ok(&self, value: Value) -> ConfigResult<Value> { - if let Value::Table(mut tab) = value { - let mut data = Table::new(); - let mut val: Value; - let mut valstr: String; - for (key, spec_item) in self.spec.iter() { - val = match (spec_item, tab.remove(key)) { - (ConfigSpecItem::Table(spec_table), Some(v)) => { - spec_table.verify_ok(v) - }, - (ConfigSpecItem::Value(verifier), Some(v)) => { - match verifier { - Verifier::TypeVer(type_ver) => { - valstr = v.to_string(); - type_ver.verify_ok_or( - v, - ConfigError::InvalidType( - key.clone(), - type_ver.to_string(), - valstr, - ) - ) - }, - Verifier::ValueVer(value_ver) => { - valstr = v.to_string(); - value_ver.verify_ok_or( - v, - ConfigError::InvalidValue( - key.clone(), - value_ver.to_string(), - valstr, - ) - ) - }, - } - }, - _ => Err(ConfigError::MissingKey(key.clone())), - }?; - data.insert(key.clone(), val); - } - return Ok(Value::Table(data)); - } else { - return Err(ConfigError::IncompatibleStructure); - } - } - - /// Return `Ok` if `table` matches the specification, `Err` otherwise. - /// - /// The keys of `table` are filtered to contain only those in the - /// specification. - pub fn verify(&self, table: Table) -> ConfigResult<Config> { - let data: Table - = self.verify_ok(Value::Table(table))? - .try_into() - .unwrap(); - return Ok(Config { data }); - } -} - -/// Sugared [`toml::Table`] holding configuration values. -#[derive(Clone, Debug)] +// #[derive(Copy, Clone, Debug, Deserialize)] +// pub struct Basler { +// pub index: usize, +// pub exposure_time_us: f64, +// pub gain: f64, +// pub acquisition_mode: BaslerAcquisitionMode, +// pub frame_rate: u32, +// pub roi: [usize; 4], +// } + +// impl From<Basler> for awg::BaslerConfig { +// fn from(config: Basler) -> Self { +// Self { +// exposure_time_us: config.exposure_time_us, +// gain: config.gain, +// acquisition_mode: config.acquisition_mode.into(), +// frame_rate: config.frame_rate, +// roi: config.roi, +// } +// } +// } + +/// Everything. +#[derive(Clone, Debug, Deserialize)] pub struct Config { - data: Table -} - -impl AsRef<Table> for Config { - fn as_ref(&self) -> &Table { &self.data } + pub output: Output, + pub camera: Camera, + pub processing: Processing, + pub awg: AWG, + pub timetagger: TimeTagger, + // pub basler: Basler, } impl Config { - /// Create a new [`Config`] with verification against [`spec`]. - pub fn new(data: Table, spec: &ConfigSpec) -> ConfigResult<Self> { - return spec.verify(data); - } - - fn table_get_path<'a, K>(table: &Table, mut keys: Peekable<K>) - -> Option<&Value> - where K: Iterator<Item = &'a str> - { - return if let Some(key) = keys.next() { - match (table.get(key), keys.peek()) { - (Some(Value::Table(tab)), Some(_)) => { - Self::table_get_path(tab, keys) - }, - (x, None) => x, - (Some(_), Some(_)) => None, - (None, _) => None, - } - } else { - unreachable!() - }; - } - - /// Access a key path in `self`, returning `Some` if the complete path - /// exists, `None` otherwise. - pub fn get_path<'a, K>(&self, keys: K) -> Option<&Value> - where K: IntoIterator<Item = &'a str> - { - return Self::table_get_path(&self.data, keys.into_iter().peekable()); - } - - /// Access a key path in `self` where the individual keys in the path are - /// separated by `'.'`. Returns `Some` if the complete path exists, `None` - /// otherwise. - pub fn get_path_s(&self, keys: &str) -> Option<&Value> { - return self.get_path(keys.split('.')); - } - - /// Access a key path in `self` and attempt to convert its type to `T`, - /// returning `Some(T)` if the complete path exists and the type is - /// convertible, `None` otherwise. - pub fn get_path_into<'a, 'de, K, T>(&self, keys: K) -> Option<T> - where - T: Deserialize<'de>, - K: IntoIterator<Item = &'a str>, - { - return match self.get_path(keys) { - Some(x) => x.clone().try_into().ok(), - None => None, - }; - } - - /// Access a key path in `self`, where individual keys in the path are - /// separated by `'.'`, and attempt to convert its type to `T`, returning - /// `Some(T)` if the complete path exists and the type is convertible, - /// `None` otherwise. - pub fn get_path_s_into<'de, T>(&self, keys: &str) -> Option<T> - where T: Deserialize<'de> - { - return match self.get_path_s(keys) { - Some(x) => x.clone().try_into().ok(), - None => None, - }; - } - - fn table_get_path_ok<'a, K>(table: &Table, mut keys: Peekable<K>) - -> ConfigResult<&Value> - where K: Iterator<Item = &'a str> - { - return if let Some(key) = keys.next() { - match (table.get(key), keys.peek()) { - (Some(Value::Table(tab)), Some(_)) => { - Self::table_get_path_ok(tab, keys) - }, - (x, None) => { - x.ok_or_else(|| ConfigError::MissingKey(key.to_string())) - }, - (Some(_), Some(k)) - => Err(ConfigError::KeyPathTooLong(k.to_string())), - (None, _) => Err(ConfigError::MissingKey(key.to_string())), - } - } else { - unreachable!() - }; - } - - /// Access a key path in `self`, returning `Ok` if the complete path - /// exists, `Err` otherwise. - pub fn get_path_ok<'a, K>(&self, keys: K) -> ConfigResult<&Value> - where K: IntoIterator<Item = &'a str> - { - return Self::table_get_path_ok(&self.data, keys.into_iter().peekable()); - } - - /// Access a key path in `self` where the individual keys in the path are - /// separated by `'.'`. Returns `Ok` if the complete path exists, `Err` - /// otherwise. - pub fn get_path_s_ok(&self, keys: &str) -> ConfigResult<&Value> { - return self.get_path_ok(keys.split('.')); - } - - /// Access a key path in `self` and attempt to convert its type to `T`, - /// returning `Ok(T)` if the complete path exists and the type is - /// convertible, `Err` otherwise. - pub fn get_path_ok_into<'a, 'de, K, T>(&self, keys: K) -> ConfigResult<T> - where - T: Deserialize<'de>, - K: IntoIterator<Item = &'a str>, - { - return self.get_path_ok(keys) - .and_then(|x| { - x.clone() - .try_into() - .map_err(|_| { - ConfigError::FailedTypeConversion(x.to_string()) - }) - }); - } - - /// Access a key path in `self`, where individual keys in the path are - /// separated by `'.'`, and attempt to convert its type to `T`, returning - /// `Ok(T)` if the complete path exists and the type is convertible, `Err` - /// otherwise. - pub fn get_path_s_ok_into<'de, T>(&self, keys: &str) -> ConfigResult<T> - where T: Deserialize<'de> - { - return self.get_path_s_ok(keys) - .and_then(|x| { - x.clone() - .try_into() - .map_err(|_| { - ConfigError::FailedTypeConversion(x.to_string()) + fn check_shutter_times(&self) -> ConfigResult<()> { + (self.camera.shutter.open_time_ms >= 27.0).then_some(()) + .ok_or(ConfigError::InvalidValue( + self.camera.shutter.open_time_ms.to_string(), + "camera.shutter.open_time_ms".to_string(), + "≥ 27.0", + ))?; + (self.camera.shutter.close_time_ms >= 27.0).then_some(()) + .ok_or(ConfigError::InvalidValue( + self.camera.shutter.close_time_ms.to_string(), + "camera.shutter.close_time_ms".to_string(), + "≥ 27.0", + ))?; + Ok(()) + } + + fn check_shift_speed(&self) -> ConfigResult<()> { + const IDX: &[usize] = &[0, 1, 2, 3]; + IDX.contains(&self.camera.read.hsspeed_idx).then_some(()) + .ok_or(ConfigError::InvalidValue( + self.camera.read.hsspeed_idx.to_string(), + "camera.read.hsspeed_idx".to_string(), + "one of {0, 1, 2, 3}", + ))?; + IDX.contains(&self.camera.read.vsspeed_idx).then_some(()) + .ok_or(ConfigError::InvalidValue( + self.camera.read.vsspeed_idx.to_string(), + "camera.read.vsspeed_idx".to_string(), + "one of {0, 1, 2, 3}", + ))?; + Ok(()) + } + + fn check_kinetic_params(&self) -> ConfigResult<()> { + (self.camera.kinetic.buffer_size >= 1).then_some(()) + .ok_or(ConfigError::InvalidValue( + self.camera.kinetic.buffer_size.to_string(), + "camera.kinetic.buffer_size".to_string(), + "≥ 1", + ))?; + (self.camera.kinetic.cycle_time >= 0.0).then_some(()) + .ok_or(ConfigError::InvalidValue( + self.camera.kinetic.cycle_time.to_string(), + "camera.kinetic.cycle_time".to_string(), + "≥ 0.0", + ))?; + (self.camera.kinetic.num_acc >= 1).then_some(()) + .ok_or(ConfigError::InvalidValue( + self.camera.kinetic.num_acc.to_string(), + "camera.kinetic.num_acc".to_string(), + "≥ 1", + ))?; + (self.camera.kinetic.cycle_time_acc >= 0.0).then_some(()) + .ok_or(ConfigError::InvalidValue( + self.camera.kinetic.cycle_time_acc.to_string(), + "camera.kinetic.cycle_time_acc".to_string(), + "≥ 0.0", + ))?; + Ok(()) + } + + fn check_roi(&self) -> ConfigResult<()> { + let xmin = self.camera.roi[0]; + let xmax = self.camera.roi[1]; + (xmin < xmax).then_some(()) + .ok_or(ConfigError::InvalidValue( + format!("{:?}", self.camera.roi), + "camera.roi".to_string(), + "xmin < xmax", + ))?; + let ymin = self.camera.roi[2]; + let ymax = self.camera.roi[3]; + (ymin < ymax).then_some(()) + .ok_or(ConfigError::InvalidValue( + format!("{:?}", self.camera.roi), + "camera.roi".to_string(), + "ymin < ymax", + ))?; + Ok(()) + } + + fn check_camera_temperature(&self) -> ConfigResult<()> { + (-100.0..30.0).contains(&self.camera.cooler.temperature_c).then_some(()) + .ok_or(ConfigError::InvalidValue( + self.camera.cooler.temperature_c.to_string(), + "camera.cooler.temperature_c".to_string(), + "in range -100..+30", + ))?; + Ok(()) + } + + fn check_camera_params(&self) -> ConfigResult<()> { + (self.camera.exposure_time_ms > 0.0).then_some(()) + .ok_or(ConfigError::InvalidValue( + self.camera.exposure_time_ms.to_string(), + "camera.exposure_time_ms".to_string(), + "> 0.0", + ))?; + Ok(()) + } + + fn check_windowavg(&self) -> ConfigResult<()> { + (self.processing.window_avg.window_size >= 1).then_some(()) + .ok_or(ConfigError::InvalidValue( + self.processing.window_avg.window_size.to_string(), + "processing.window_avg.window_size".to_string(), + "≥ 1", + ))?; + Ok(()) + } + + fn check_awg_trigger_params(&self) -> ConfigResult<()> { + let volt_range = -10000..=10000; + volt_range.contains(&self.awg.trigger.ext0.level).then_some(()) + .ok_or(ConfigError::InvalidValue( + self.awg.trigger.ext0.level.to_string(), + "awg.trigger.ext0.level".to_string(), + "in range -10000..+10000 mV", + ))?; + volt_range.contains(&self.awg.trigger.ext0.rearm_level).then_some(()) + .ok_or(ConfigError::InvalidValue( + self.awg.trigger.ext0.rearm_level.to_string(), + "awg.trigger.ext0.rearm_level".to_string(), + "in range -10000..+10000 mV", + ))?; + volt_range.contains(&self.awg.trigger.ext1.level).then_some(()) + .ok_or(ConfigError::InvalidValue( + self.awg.trigger.ext1.level.to_string(), + "awg.trigger.ext1.level".to_string(), + "in range -10000..+10000 mV", + ))?; + volt_range.contains(&self.awg.trigger.ext1.rearm_level).then_some(()) + .ok_or(ConfigError::InvalidValue( + self.awg.trigger.ext1.rearm_level.to_string(), + "awg.trigger.ext1.rearm_level".to_string(), + "in range -10000..+10000 mV", + ))?; + Ok(()) + } + + + fn check_awg_channels(&self) -> ConfigResult<()> { + (self.awg.active_channels.stop_levels.len() == 4).then_some(()) + .ok_or(ConfigError::InvalidValue( + "[{...}]".to_string(), + "awg.active_channels.stop_levels".to_string(), + "length must be 4", + ))?; + let channels = &self.awg.active_channels.enabled_channels; + (channels.iter().filter(|&&c| c).count() != 3).then_some(()) + .ok_or(ConfigError::InvalidValue( + "[{...}]".to_string(), + "awg.active_channels.enabled_channels".to_string(), + "number of enabled channels must not be 3", + ))?; + self.awg.active_channels.amplitudes.iter().enumerate() + .map(|(k, &)| { + (80..=2500).contains(&).then_some(()) + .ok_or(ConfigError::InvalidValue( + amp.to_string(), + format!("awg.active_channels.amplitudes[{}]", k), + "in range 80..2500 mV", + )) + }) + .collect::<ConfigResult<Vec<()>>>()?; + + Ok(()) + } + + fn check_awg_sequence_steps(&self) -> ConfigResult<()> { + self.awg.sequence_segments.iter().enumerate() + .map(|(k, seg)| { + Ok((k, seg)) + .and_then(|(k, seg)| { + (seg.source.exists() + && seg.source.to_str().unwrap_or("").ends_with(".txt") + ) + .then_some((k, seg)) + .ok_or(ConfigError::InvalidValue( + seg.source.to_string_lossy().to_string(), + format!("awg.sequence_segments[{}].source", k), + "file must exist and end with .txt", + )) }) - }); - } - - /// Alias for [`Self::get_path_s_ok_into`]. - pub fn a<'de, T>(&self, keys: &str) -> ConfigResult<T> - where T: Deserialize<'de> + }) + .collect::<ConfigResult<Vec<_>>>()?; + Ok(()) + } + + fn check_awg_params(&self) -> ConfigResult<()> { + let n_segs = self.awg.num_segments; + (n_segs & (n_segs - 1) == 0) // n_segs must be a power of two + .then_some(()) + .ok_or(ConfigError::InvalidValue( + n_segs.to_string(), + "awg.num_segments".to_string(), + "must be a power of two", + ))?; + + (self.awg.sampling_rate >= 1).then_some(()) + .ok_or(ConfigError::InvalidValue( + self.awg.sampling_rate.to_string(), + "awg.sampling_rate".to_string(), + "≥ 1", + ))?; + self.check_awg_trigger_params()?; + self.check_awg_channels()?; + self.check_awg_sequence_steps()?; + Ok(()) + } + + fn check_timetagger_params(&self) -> ConfigResult<()> { + (self.timetagger.binwidth_sec > 0.0).then_some(()) + .ok_or(ConfigError::InvalidValue( + self.timetagger.binwidth_sec.to_string(), + "timetagger.binwidth_sec".to_string(), + "> 0.0", + ))?; + Ok(()) + } + + // fn check_basler_params(&self) -> ConfigResult<()> { + // (self.basler.exposure_time_us > 0.0).then_some(()) + // .ok_or(ConfigError::InvalidValue( + // self.basler.exposure_time_us.to_string(), + // "basler.exposure_time_us".to_string(), + // "> 0.0", + // ))?; + // (self.basler.frame_rate > 0).then_some(()) + // .ok_or(ConfigError::InvalidValue( + // self.basler.frame_rate.to_string(), + // "basler.frame_rate".to_string(), + // "> 0", + // ))?; + // ( + // self.basler.roi[0] < self.basler.roi[1] + // && self.basler.roi[1] <= awg::Basler::SENSOR_WIDTH + // && self.basler.roi[2] < self.basler.roi[3] + // && self.basler.roi[3] <= awg::Basler::SENSOR_HEIGHT + // ).then_some(()) + // .ok_or(ConfigError::InvalidValue( + // format!("{:?}", self.basler.roi), + // "basler.roi".to_string(), + // "xmin < xmax < 3840, ymin < ymax < 2740", + // ))?; + // Ok(()) + // } + + /// Verify that all necessary conditions are satisfied. + pub fn check(&self) -> ConfigResult<()> { + self.check_shutter_times()?; + self.check_shift_speed()?; + self.check_kinetic_params()?; + self.check_roi()?; + self.check_camera_temperature()?; + self.check_camera_params()?; + self.check_windowavg()?; + self.check_awg_params()?; + self.check_timetagger_params()?; + // self.check_basler_params()?; + Ok(()) + } + + + /// Load a config from a file and verify that all necessary conditions are + /// satisfied. + pub fn load<P>(infile: P) -> ConfigResult<Self> + where P: AsRef<Path> { - return self.get_path_s_ok_into(keys); - } -} - -/// Load a [`Config`] from the given path, optionally verifying against a -/// specification. -fn load_config<P>(infile: P, verify: Option<&ConfigSpec>) - -> ConfigResult<Config> -where P: AsRef<Path> -{ - let infile_str: String = infile.as_ref().display().to_string(); - let table: Table - = fs::read_to_string(infile) - .map_err(|_| ConfigError::FileRead(infile_str.clone()))? - .parse() - .map_err(|_| ConfigError::FileParse(infile_str.clone()))?; - return if let Some(config_spec) = verify { - config_spec.verify(table) - } else { - Ok(Config { data: table }) - }; -} - -/// Load a [`Config`] from the given path, verifying aginst -/// [`ConfigSpec::default`] -pub fn load_def_config<P>(infile: P) -> ConfigResult<Config> -where P: AsRef<Path> -{ - return load_config(infile, Some(DEF_CONFIG_SPEC.deref())); -} - -#[cfg(test)] -mod test { - use super::*; - - fn create_table_good() -> Table { - return "[suptab]\nf1 = true\nf2 = \"foo\"\nf3 = [1.0, 1]" - .parse::<Table>().unwrap(); - } - - fn create_table_bad() -> Table { - return "[suptab]\nf1 = true\nf2 = \"foo\"\nf3 = [1, 1.0]" - .parse::<Table>().unwrap(); - } - - fn create_spec() -> ConfigSpec { - return config_spec!( - "suptab" => spec!(Table { - "f1" => spec!(Bool), - "f2" => spec!(StrCollection { "foo", "bar" }), - "f3" => spec!(TypedArray { - [TypeVer::Float, TypeVer::Int], - finite: true - }), - }), - ); - } - - #[test] - fn verify_config_good() -> ConfigResult<()> { - let table = create_table_good(); - let spec = create_spec(); - spec.verify(table)?; - return Ok(()); - } - - #[test] - #[should_panic] - fn verify_config_bad() -> () { - let table = create_table_bad(); - let spec = create_spec(); - spec.verify(table).expect("should fail!"); - return (); - } - - #[test] - fn key_path_access() -> ConfigResult<()> { - let table = create_table_good(); - let spec = create_spec(); - let config = spec.verify(table)?; - config.get_path_ok(["suptab", "f1"])?; - config.get_path_s_ok("suptab.f1")?; - return Ok(()); - } - - #[test] - #[should_panic] - fn key_path_access_bad() -> () { - let table = create_table_good(); - let spec = create_spec(); - let config = spec.verify(table).expect("won't fail"); - config.get_path_ok(["suptab", "f4"]).expect("should fail!"); - return (); - } - - #[test] - fn key_path_access_convert() -> ConfigResult<()> { - let table = create_table_good(); - let spec = create_spec(); - let config = spec.verify(table)?; - let f1: bool = config.get_path_ok_into(["suptab", "f1"])?; - assert_eq!(f1, true); - return Ok(()); - } - - #[test] - #[should_panic] - fn key_path_access_convert_bad() -> () { - let table = create_table_good(); - let spec = create_spec(); - let config = spec.verify(table).expect("won't fail"); - let f1: f64 = config.get_path_ok_into(["suptab", "f1"]) - .expect("should fail!"); - assert_eq!(f1, 1.0); - return () + let infile_str: String = infile.as_ref().display().to_string(); + let config_str: String + = fs::read_to_string(infile) + .map_err(|err| { + ConfigError::FileRead(infile_str.clone(), err.to_string()) + })?; + let config: Self + = toml::from_str(&config_str) + .map_err(|err| { + ConfigError::FileParse(infile_str.clone(), err.to_string()) + })?; + config.check()?; + Ok(config) } } diff --git a/src/cli.rs b/src/cli.rs index 44e682a019b6ffa24cc383e4d1dc8b5ca4206da6..50f8f8f946d063c16261b027bce2ea64da0b36d2 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -76,7 +76,16 @@ fn main() -> Result<()> { } // TODO - let awg: Option<AWG> = None; + let mut awg: Option<AWG> + = config.awg.r#use + .then(|| { + println!("Connect to AWG"); + AWG::connect(config.awg.index) + }) + .transpose()?; + if awg.is_some() { + AWG::set_config(awg.as_mut().unwrap(), &config.awg.into())?; + } let tagger: Option<TimeTaggerUltra> = config.timetagger.r#use