diff --git a/AOloopControl_n1.c b/AOloopControl_n1.c new file mode 100644 index 0000000..0e11742 --- /dev/null +++ b/AOloopControl_n1.c @@ -0,0 +1,7474 @@ +/** + * @file AOloopControl.c + * @brief Adaptive Optics Control loop engine + * + * AO engine uses stream data structure + * + * @author O. Guyon + * @date 25 Aug 2017 + * + * + * @bug No known bugs. + * + * @see http://oguyon.github.io/AdaptiveOpticsControl/src/AOloopControl/doc/AOloopControl.html + * + * + * + * @defgroup AOloopControl_streams Image streams + * @defgroup AOloopControl_AOLOOPCONTROL_CONF AOloopControl main data structure + * + */ + + + +#define _GNU_SOURCE + +// uncomment for test print statements to stdout +//#define _PRINT_TEST + + + +/* =============================================================================================== */ +/* =============================================================================================== */ +/* HEADER FILES */ +/* =============================================================================================== */ +/* =============================================================================================== */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include // needed for tid = syscall(SYS_gettid); + + + +#ifdef __MACH__ +#include +#define CLOCK_REALTIME 0 +#define CLOCK_MONOTONIC 0 +int clock_gettime(int clk_id, struct mach_timespec *t) { + mach_timebase_info_data_t timebase; + mach_timebase_info(&timebase); + uint64_t time; + time = mach_absolute_time(); + double nseconds = ((double)time * (double)timebase.numer)/((double)timebase.denom); + double seconds = ((double)time * (double)timebase.numer)/((double)timebase.denom * 1e9); + t->tv_sec = seconds; + t->tv_nsec = nseconds; + return 0; +} +#else +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +//#include +#include + + +#include +#include +#include +#include +#include + +#include + +#include "CLIcore.h" +#include "00CORE/00CORE.h" +#include "COREMOD_memory/COREMOD_memory.h" +#include "COREMOD_iofits/COREMOD_iofits.h" +#include "COREMOD_tools/COREMOD_tools.h" +#include "COREMOD_arith/COREMOD_arith.h" +#include "linopt_imtools/linopt_imtools.h" +#include "AOloopControl/AOloopControl.h" +#include "image_filter/image_filter.h" +#include "info/info.h" +#include "ZernikePolyn/ZernikePolyn.h" +#include "linopt_imtools/linopt_imtools.h" +#include "image_gen/image_gen.h" +#include "statistic/statistic.h" +#include "fft/fft.h" + + +#include "AOloopControl_IOtools/AOloopControl_IOtools.h" +#include "AOloopControl_PredictiveControl/AOloopControl_PredictiveControl.h" +#include "AOloopControl_acquireCalib/AOloopControl_acquireCalib.h" +#include "AOloopControl_computeCalib/AOloopControl_computeCalib.h" +#include "AOloopControl_perfTest/AOloopControl_perfTest.h" + + + +#ifdef HAVE_CUDA +#include "cudacomp/cudacomp.h" +#endif + +# ifdef _OPENMP +# include +#define OMP_NELEMENT_LIMIT 1000000 +# endif + + + +/* =============================================================================================== */ +/* =============================================================================================== */ +/* DEFINES, MACROS */ +/* =============================================================================================== */ +/* =============================================================================================== */ + + + + + + + +// data passed to each thread +//typedef struct +//{ +// long nelem; +// float *arrayptr; +// float *result; // where to white status +//} THDATA_IMTOTAL; + + + + + + +/* =============================================================================================== */ +/* =============================================================================================== */ +/* GLOBAL DATA DECLARATION */ +/* =============================================================================================== */ +/* =============================================================================================== */ + + + + + +/* =============================================================================================== */ +/* LOGGING ACCESS TO FUNCTIONS */ +/* =============================================================================================== */ + +// uncomment at compilation time to enable logging of function entry/exit +//#define AOLOOPCONTROL_LOGFUNC +static int AOLOOPCONTROL_logfunc_level = 0; +static int AOLOOPCONTROL_logfunc_level_max = 2; // log all levels equal or below this number +static char AOLOOPCONTROL_logfunc_fname[] = "AOloopControl.fcall.log"; +static char flogcomment[200]; + + +// GPU MultMat indexes +// +// 0: main loop CM multiplication +// +// 1: set DM modes: +// int set_DM_modes(long loop) +// +// 2: compute modes loop +// int AOloopControl_CompModes_loop(char *ID_CM_name, char *ID_WFSref_name, char *ID_WFSim_name, char *ID_WFSimtot_name, char *ID_coeff_name) +// +// 3: coefficients to DM shape [ NOTE: CRASHES IF NOT USING index 0 ] +// int AOloopControl_GPUmodecoeffs2dm_filt_loop(char *modecoeffs_name, char *DMmodes_name, int semTrigg, char *out_name, int GPUindex, long loop, int offloadMode) +// +// 4: Predictive control (in modules linARfilterPred) + + + + + + + +// TIMING +static struct timespec tnow; +static struct timespec tdiff; +static double tdiffv; + + + + + + +static int initWFSref_GPU[100] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static int initcontrMcact_GPU[100] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + +float GPU_alpha = 0.0; +float GPU_beta = 0.0; + + +static int COMPUTE_PIXELSTREAMING = 0; // multiple pixel groups +int PIXSTREAM_NBSLICES = 1; // number of image slices (= pixel groups) +int PIXSTREAM_SLICE; // slice index 0 = all pixels + + + + +// static int MATRIX_COMPUTATION_MODE = 0; +// 0: compute sequentially modes and DM commands +// 1: use combined control matrix + + + + + +/* =============================================================================================== */ +/* aoconfID are global variables for convenience */ +/* aoconfID can be used in other modules as well (with extern) */ +/* =============================================================================================== */ + + +// Hardware connections +long aoconfID_wfsim = -1; +uint8_t WFSatype; +long aoconfID_dmC = -1; +long aoconfID_dmRM = -1; + +long aoconfID_wfsdark = -1; +long aoconfID_imWFS0 = -1; +long aoconfID_imWFS0tot = -1; +long aoconfID_imWFS1 = -1; +long aoconfID_imWFS2 = -1; +static long aoconfID_wfsref0 = -1; +long aoconfID_wfsref = -1; +static long long aoconfcnt0_wfsref_current = -1; + +long aoconfID_DMmodes = -1; +static long aoconfID_dmdisp = -1; // to notify DMcomb that DM maps should be summed + + +// Control Modes +long aoconfID_cmd_modes = -1; +long aoconfID_meas_modes = -1; // measured +long aoconfID_RMS_modes = -1; +long aoconfID_AVE_modes = -1; + + + +// mode gains, multf, limit are set in 3 tiers +// global gain +// block gain +// individual gains + +// blocks +long aoconfID_gainb = -1; // block modal gains +long aoconfID_multfb = -1; // block modal gains +long aoconfID_limitb = -1; // block modal gains + +// individual modes +long aoconfID_DMmode_GAIN = -1; +long aoconfID_LIMIT_modes = -1; +long aoconfID_MULTF_modes = -1; + +long aoconfID_cmd_modesRM = -1; + +long aoconfID_wfsmask = -1; +static long aoconfID_dmmask = -1; + +static long aoconfID_respM = -1; +static long aoconfID_contrM = -1; // pixels -> modes +static long long aoconfcnt0_contrM_current = -1; +static long aoconfID_contrMc = -1; // combined control matrix: pixels -> DM actuators +static long aoconfID_meas_act = -1; +static long aoconfID_contrMcact[100] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}; + +// pixel streaming +long aoconfID_pixstream_wfspixindex; // index of WFS pixels + +long aoconfID_looptiming = -1; // control loop timing data. Pixel values correspond to time offset +// currently has 20 timing slots +// beginning of iteration is defined when entering "wait for image" +// md[0].atime.ts is absolute time at beginning of iteration +// +// pixel 0 is dt since last iteration +// +// pixel 1 is time from beginning of loop to status 01 +// pixel 2 is time from beginning of loop to status 02 +// ... +static long NBtimers = 21; + +static long aoconfIDlogdata = -1; +static long aoconfIDlog0 = -1; +static long aoconfIDlog1 = -1; + +int *WFS_active_map; // used to map WFS pixels into active array +int *DM_active_map; // used to map DM actuators into active array +static long aoconfID_meas_act_active; +static long aoconfID_imWFS2_active[100]; + + + + + + + + + + + + +float normfloorcoeff = 1.0; + + + + + +static long wfsrefcnt0 = -1; +static long contrMcactcnt0[100] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1};; + + + +// variables used by functions + + +static int GPUcntMax = 100; +static int *GPUset0; +static int *GPUset1; + + + + + + + + +/* =============================================================================================== */ +/* MAIN DATA STRUCTURES */ +/* =============================================================================================== */ + +extern DATA data; + +#define NB_AOloopcontrol 10 // max number of loops +long LOOPNUMBER = 0; // current loop index + +int AOloopcontrol_meminit = 0; +static int AOlooploadconf_init = 0; + +#define AOconfname "/tmp/AOconf.shm" +AOLOOPCONTROL_CONF *AOconf; // configuration - this can be an array + + + + + + + + + + + + + + + + + + + + + + + + + + + +// CLI commands +// +// function CLI_checkarg used to check arguments +// CLI_checkarg ( CLI argument index , type code ) +// +// type codes: +// 1: float +// 2: long +// 3: string, not existing image +// 4: existing image +// 5: string +// + + + + + + +/* =============================================================================================== */ +/* =============================================================================================== */ +/** @name AOloopControl - 1. INITIALIZATION, configurations + * Allocate memory, import/export configurations */ +/* =============================================================================================== */ +/* =============================================================================================== */ + +/** @brief CLI function for AOloopControl_loadconfigure */ +int_fast8_t AOloopControl_loadconfigure_cli() { + if(CLI_checkarg(1,2)==0) { + AOloopControl_loadconfigure(data.cmdargtoken[1].val.numl, 1, 10); + return 0; + } + else return 1; +} + + + + + +/** @brief CLI function for AOloopControl_stream3Dto2D */ +/*int_fast8_t AOloopControl_stream3Dto2D_cli() { + if(CLI_checkarg(1,4)+CLI_checkarg(2,3)+CLI_checkarg(3,2)+CLI_checkarg(4,2)==0) { + AOloopControl_stream3Dto2D(data.cmdargtoken[1].val.string, data.cmdargtoken[2].val.string, data.cmdargtoken[3].val.numl, data.cmdargtoken[4].val.numl); + return 0; + } + else return 1; +}*/ + + + + + + + + + + + +/* =============================================================================================== */ +/* =============================================================================================== */ +/** @name AOloopControl - 6. REAL TIME COMPUTING ROUTINES + * calls CPU and GPU processing */ +/* =============================================================================================== */ +/* =============================================================================================== */ + +/** @brief CLI function for AOloopControl_WFSzpupdate_loop */ +int_fast8_t AOloopControl_WFSzpupdate_loop_cli() { + if(CLI_checkarg(1,4)+CLI_checkarg(2,4)+CLI_checkarg(3,4)==0) { + AOloopControl_WFSzpupdate_loop(data.cmdargtoken[1].val.string, data.cmdargtoken[2].val.string, data.cmdargtoken[3].val.string); + return 0; + } + else return 1; +} + +/** @brief CLI function for AOloopControl_WFSzeropoint_sum_update_loop */ +int_fast8_t AOloopControl_WFSzeropoint_sum_update_loop_cli() { + if(CLI_checkarg(1,3)+CLI_checkarg(2,2)+CLI_checkarg(3,4)+CLI_checkarg(4,4)==0) { + AOloopControl_WFSzeropoint_sum_update_loop(LOOPNUMBER, data.cmdargtoken[1].val.string, data.cmdargtoken[2].val.numl, data.cmdargtoken[3].val.string, data.cmdargtoken[4].val.string); + return 0; + } + else return 1; +} + +/** @brief CLI function for AOloopControl_CompModes_loop */ +int_fast8_t AOloopControl_CompModes_loop_cli() { + if(CLI_checkarg(1,4)+CLI_checkarg(2,4)+CLI_checkarg(3,4)+CLI_checkarg(4,4)+CLI_checkarg(5,3)==0) { + AOloopControl_CompModes_loop(data.cmdargtoken[1].val.string, data.cmdargtoken[2].val.string, data.cmdargtoken[3].val.string, data.cmdargtoken[4].val.string, data.cmdargtoken[5].val.string); + return 0; + } + else return 1; +} + +/** @brief CLI function for AOloopControl_GPUmodecoeffs2dm_filt */ +int_fast8_t AOloopControl_GPUmodecoeffs2dm_filt_loop_cli() { + if(CLI_checkarg(1,4)+CLI_checkarg(2,4)+CLI_checkarg(3,2)+CLI_checkarg(4,4)+CLI_checkarg(5,2)+CLI_checkarg(6,2)+CLI_checkarg(7,2)==0) { + AOloopControl_GPUmodecoeffs2dm_filt_loop(data.cmdargtoken[1].val.string, data.cmdargtoken[2].val.string, data.cmdargtoken[3].val.numl, data.cmdargtoken[4].val.string, data.cmdargtoken[5].val.numl, data.cmdargtoken[6].val.numl, data.cmdargtoken[7].val.numl); + return 0; + } + else return 1; +} + +/** @brief CLI function for AOloopControl_computeWFSresidualimage */ +int_fast8_t AOloopControl_computeWFSresidualimage_cli() { + if(CLI_checkarg(1,2)+CLI_checkarg(2,4)==0) { + AOloopControl_computeWFSresidualimage(data.cmdargtoken[1].val.numl, data.cmdargtoken[2].val.string); + return 0; + } + else return 1; +} + +/** @brief CLI function for AOloopControl_ComputeOpenLoopModes */ +int_fast8_t AOloopControl_ComputeOpenLoopModes_cli() { + if(CLI_checkarg(1,2)==0) { + AOloopControl_ComputeOpenLoopModes(data.cmdargtoken[1].val.numl); + return 0; + } else return 1; +} + +/** @brief CLI function for AOloopControl_AutoTuneGains */ +int_fast8_t AOloopControl_AutoTuneGains_cli() { + if(CLI_checkarg(1,2)+CLI_checkarg(2,3)+CLI_checkarg(3,1)+CLI_checkarg(4,2)==0) { + AOloopControl_AutoTuneGains(data.cmdargtoken[1].val.numl, data.cmdargtoken[2].val.string, data.cmdargtoken[3].val.numf, data.cmdargtoken[4].val.numl); + return 0; + } + else return 1; +} + +/** @brief CLI function for AOloopControl_dm2dm_offload */ +int_fast8_t AOloopControl_dm2dm_offload_cli() { + if(CLI_checkarg(1,4)+CLI_checkarg(2,4)+CLI_checkarg(3,1)+CLI_checkarg(4,1)+CLI_checkarg(5,1)==0) { + AOloopControl_dm2dm_offload(data.cmdargtoken[1].val.string, data.cmdargtoken[2].val.string, data.cmdargtoken[3].val.numf, data.cmdargtoken[4].val.numf, data.cmdargtoken[5].val.numf); + return 0; + } + else return 1; +} + +/** @brief CLI function for AOloopControl_sig2Modecoeff */ +int_fast8_t AOloopControl_sig2Modecoeff_cli() { + if(CLI_checkarg(1,4)+CLI_checkarg(2,4)+CLI_checkarg(3,4)+CLI_checkarg(4,3)==0) { + AOloopControl_sig2Modecoeff(data.cmdargtoken[1].val.string, data.cmdargtoken[2].val.string, data.cmdargtoken[3].val.string, data.cmdargtoken[4].val.string); + return 0; + } else return 1; +} + + + + + + + +/* =============================================================================================== */ +/* =============================================================================================== */ +/** @name AOloopControl - 8. LOOP CONTROL INTERFACE */ +/* =============================================================================================== */ +/* =============================================================================================== */ + + +/** @brief CLI function for AOloopControl_setLoopNumber */ +int_fast8_t AOloopControl_setLoopNumber_cli() { + if(CLI_checkarg(1,2)==0) { + AOloopControl_setLoopNumber(data.cmdargtoken[1].val.numl); + return 0; + } + else return 1; +} + + + +/* =============================================================================================== */ +/** @name AOloopControl - 8.1. LOOP CONTROL INTERFACE - MAIN CONTROL : LOOP ON/OFF START/STOP/STEP/RESET */ +/* =============================================================================================== */ + + +/* =============================================================================================== */ +/** @name AOloopControl - 8.2. LOOP CONTROL INTERFACE - DATA LOGGING */ +/* =============================================================================================== */ + + +/* =============================================================================================== */ +/** @name AOloopControl - 8.3. LOOP CONTROL INTERFACE - PRIMARY DM WRITE */ +/* =============================================================================================== */ + +/* =============================================================================================== */ +/** @name AOloopControl - 8.4. LOOP CONTROL INTERFACE - INTEGRATOR AUTO TUNING */ +/* =============================================================================================== */ + + +/* =============================================================================================== */ +/** @name AOloopControl - 8.5. LOOP CONTROL INTERFACE - PREDICTIVE FILTER ON/OFF */ +/* =============================================================================================== */ + + +/* =============================================================================================== */ +/** @name AOloopControl - 8.6. LOOP CONTROL INTERFACE - TIMING PARAMETERS */ +/* =============================================================================================== */ + + + +/* =============================================================================================== */ +/** @name AOloopControl - 8.7. LOOP CONTROL INTERFACE - CONTROL LOOP PARAMETERS */ +/* =============================================================================================== */ + + + +/** @brief CLI function for AOloopControl_set_modeblock_gain */ +int_fast8_t AOloopControl_set_modeblock_gain_cli() { + if(CLI_checkarg(1,2)+CLI_checkarg(2,1)+CLI_checkarg(3,2)==0) { + AOloopControl_set_modeblock_gain(LOOPNUMBER, data.cmdargtoken[1].val.numl, data.cmdargtoken[2].val.numf, data.cmdargtoken[3].val.numl); + return 0; + } + else return 1; +} + +/** @brief CLI function for AOloopControl_loopstep */ +int_fast8_t AOloopControl_loopstep_cli() { + if(CLI_checkarg(1,2)==0) { + AOloopControl_loopstep(LOOPNUMBER, data.cmdargtoken[1].val.numl); + return 0; + } + else return 1; +} + +/** @brief CLI function for AOloopControl_set_loopfrequ */ +int_fast8_t AOloopControl_set_loopfrequ_cli() { + if(CLI_checkarg(1,1)==0) { + AOloopControl_set_loopfrequ(data.cmdargtoken[1].val.numf); + return 0; + } + else return 1; +} + +/** @brief CLI function for AOloopControl_set_hardwlatency_frame */ +int_fast8_t AOloopControl_set_hardwlatency_frame_cli() { + if(CLI_checkarg(1,1)==0) { + AOloopControl_set_hardwlatency_frame(data.cmdargtoken[1].val.numf); + return 0; + } + else return 1; +} + +/** @brief CLI function for AOloopControl_set_complatency_frame + latency for the primary DM write */ +int_fast8_t AOloopControl_set_complatency_frame_cli() { + if(CLI_checkarg(1,1)==0) { + AOloopControl_set_complatency_frame(data.cmdargtoken[1].val.numf); + return 0; + } + else return 1; +} + +/** @brief CLI function for AOloopControl_set_wfsmextrlatency_frame + delay between the time when the WFS measures and the time when commands are sent to the DM */ +int_fast8_t AOloopControl_set_wfsmextrlatency_frame_cli() { + if(CLI_checkarg(1,1)==0) { + AOloopControl_set_wfsmextrlatency_frame(data.cmdargtoken[1].val.numf); + return 0; + } + else return 1; +} + +/** @brief CLI function for AOloopControl_set_AUTOTUNE_LIMITS_delta */ +int_fast8_t AOloopControl_set_AUTOTUNE_LIMITS_delta_cli() { + if(CLI_checkarg(1,1)==0) { + AOloopControl_set_AUTOTUNE_LIMITS_delta(data.cmdargtoken[1].val.numf); + return 0; + } + else return 1; +} + +/** @brief CLI function for AOloopControl_set_AUTOTUNE_LIMITS_perc */ +int_fast8_t AOloopControl_set_AUTOTUNE_LIMITS_perc_cli() { + if(CLI_checkarg(1,1)==0) { + AOloopControl_set_AUTOTUNE_LIMITS_perc(data.cmdargtoken[1].val.numf); + return 0; + } + else return 1; +} + +/** @brief CLI function for AOloopControl_set_AUTOTUNE_LIMITS_mcoeff */ +int_fast8_t AOloopControl_set_AUTOTUNE_LIMITS_mcoeff_cli() { + if(CLI_checkarg(1,1)==0) { + AOloopControl_set_AUTOTUNE_LIMITS_mcoeff(data.cmdargtoken[1].val.numf); + return 0; + } + else return 1; +} + +/** @brief CLI function for AOloopControl_setgain */ +int_fast8_t AOloopControl_setgain_cli() { + if(CLI_checkarg(1,1)==0) { + AOloopControl_setgain(data.cmdargtoken[1].val.numf); + return 0; + } + else return 1; +} + +/** @brief CLI function for AOloopControl_setARPFgain */ +int_fast8_t AOloopControl_setARPFgain_cli() { + if(CLI_checkarg(1,1)==0) { + AOloopControl_setARPFgain(data.cmdargtoken[1].val.numf); + return 0; + } + else return 1; +} + +/** @brief CLI function for AOloopControl_setWFSnormfloor */ +int_fast8_t AOloopControl_setWFSnormfloor_cli() { + if(CLI_checkarg(1,1)==0) { + AOloopControl_setWFSnormfloor(data.cmdargtoken[1].val.numf); + return 0; + } else return 1; +} + +/** @brief CLI function for AOloopControl_setmaxlimit */ +int_fast8_t AOloopControl_setmaxlimit_cli() { + if(CLI_checkarg(1,1)==0) { + AOloopControl_setmaxlimit(data.cmdargtoken[1].val.numf); + return 0; + } + else return 1; +} + +/** @brief CLI function for AOloopControl_setmult */ +int_fast8_t AOloopControl_setmult_cli() { + if(CLI_checkarg(1,1)==0) { + AOloopControl_setmult(data.cmdargtoken[1].val.numf); + return 0; + } + else return 1; +} + +/** @brief CLI function for AOloopControl_setframesAve */ +int_fast8_t AOloopControl_setframesAve_cli() { + if(CLI_checkarg(1,2)==0) { + AOloopControl_setframesAve(data.cmdargtoken[1].val.numl); + return 0; + } + else return 1; +} + +////////////////////////////////////////// +// begin declaring fonctions for Filtering +////////////////////////////////////////// +/* +limit_total = limit_global * limit_block * limit_mode +gain_total = gain_global * gain_block * gain_mode +*/ + +/** @brief CLI function for AOloopControl_setgainrange */ +int_fast8_t AOloopControl_setgainrange_cli() { + if(CLI_checkarg(1,2)+CLI_checkarg(2,2)+CLI_checkarg(3,1)==0) { + AOloopControl_setgainrange(data.cmdargtoken[1].val.numl, data.cmdargtoken[2].val.numl, data.cmdargtoken[3].val.numf); + return 0; + } + else return 1; +} + +/** @brief CLI function for AOloopControl_setlimitrange */ +int_fast8_t AOloopControl_setlimitrange_cli() { + if(CLI_checkarg(1,2)+CLI_checkarg(2,2)+CLI_checkarg(3,1)==0) { + AOloopControl_setlimitrange(data.cmdargtoken[1].val.numl, data.cmdargtoken[2].val.numl, data.cmdargtoken[3].val.numf); + return 0; + } + else return 1; +} + +/** @brief CLI function for AOloopControl_setmultfrange */ +int_fast8_t AOloopControl_setmultfrange_cli() { + if(CLI_checkarg(1,2)+CLI_checkarg(2,2)+CLI_checkarg(3,1)==0) { + AOloopControl_setmultfrange(data.cmdargtoken[1].val.numl, data.cmdargtoken[2].val.numl, data.cmdargtoken[3].val.numf); + return 0; + } + else return 1; +} + +/** @brief CLI function for AOloopControl_setgainblock (filtering) */ +int_fast8_t AOloopControl_setgainblock_cli() { + if(CLI_checkarg(1,2)+CLI_checkarg(2,1)==0) { + AOloopControl_setgainblock(data.cmdargtoken[1].val.numl, data.cmdargtoken[2].val.numf); + return 0; + } + else return 1; +} + +/** @brief CLI function for AOloopControl_setlimitblock (filtering) */ +int_fast8_t AOloopControl_setlimitblock_cli() { + if(CLI_checkarg(1,2)+CLI_checkarg(2,1)==0) { + AOloopControl_setlimitblock(data.cmdargtoken[1].val.numl, data.cmdargtoken[2].val.numf); + return 0; + } + else return 1; +} + +/** @brief CLI function for AOloopControl_setmultfblock / coeff MULTF (filtering) */ +int_fast8_t AOloopControl_setmultfblock_cli() { + if(CLI_checkarg(1,2)+CLI_checkarg(2,1)==0) { + AOloopControl_setmultfblock(data.cmdargtoken[1].val.numl, data.cmdargtoken[2].val.numf); + return 0; + } + else return 1; +} + +/** @brief CLI function for AOloopControl_scanGainBlock (filtering) */ +int_fast8_t AOloopControl_scanGainBlock_cli() { + if(CLI_checkarg(1,2)+CLI_checkarg(2,2)+CLI_checkarg(3,1)+CLI_checkarg(4,1)+CLI_checkarg(5,2)==0) { + AOloopControl_scanGainBlock(data.cmdargtoken[1].val.numl, data.cmdargtoken[2].val.numl, data.cmdargtoken[3].val.numf, data.cmdargtoken[4].val.numf, data.cmdargtoken[5].val.numl); + return 0; + } + else return 1; +} +//////////////////////////////////////// +// end declaring fonctions for Filtering +//////////////////////////////////////// + + +/* =============================================================================================== */ +/* =============================================================================================== */ +/** @name AOloopControl - 10. FOCAL PLANE SPECKLE MODULATION / CONTROL */ +/* =============================================================================================== */ +/* =============================================================================================== */ + +/** @brief CLI function for AOloopControl_DMmodulateAB */ +int_fast8_t AOloopControl_DMmodulateAB_cli() +{ + if(CLI_checkarg(1,4)+CLI_checkarg(2,4)+CLI_checkarg(3,4)+CLI_checkarg(4,4)+CLI_checkarg(5,4)+CLI_checkarg(6,1)+CLI_checkarg(7,2)==0) { + AOloopControl_DMmodulateAB(data.cmdargtoken[1].val.string, data.cmdargtoken[2].val.string, data.cmdargtoken[3].val.string, data.cmdargtoken[4].val.string, data.cmdargtoken[5].val.string, data.cmdargtoken[6].val.numf, data.cmdargtoken[7].val.numl); + return 0; + } + else return 1; +} + + + +/* =============================================================================================== */ +/* =============================================================================================== */ +/** @name AOloopControl - 11. PROCESS LOG FILES */ +/* =============================================================================================== */ +/* =============================================================================================== */ + +/** @brief CLI function for AOloopControl_logprocess_modeval */ +int_fast8_t AOloopControl_logprocess_modeval_cli() { + if(CLI_checkarg(1,4)==0) { + AOloopControl_logprocess_modeval(data.cmdargtoken[1].val.string); + return 0; + } + else return 1; +} + + + + + + +// 1: float +// 2: long +// 3: string, not existing image +// 4: existing image +// 5: string + + + + + +// OBSOLETE ?? + + + +int_fast8_t AOloopControl_setparam_cli() +{ + if(CLI_checkarg(1,3)+CLI_checkarg(2,1)==0) + { + AOloopControl_setparam(LOOPNUMBER, data.cmdargtoken[1].val.string, data.cmdargtoken[2].val.numf); + return 0; + } + else + return 1; +} + + + + + + + + + + + +/* =============================================================================================== */ +/* =============================================================================================== */ +/* FUNCTIONS SOURCE CODE */ +/* =============================================================================================== */ +/* =============================================================================================== */ +/** @name AOloopControl functions */ + + + + + + + +/* =============================================================================================== */ +/* =============================================================================================== */ +/** @name AOloopControl - 1. INITIALIZATION, configurations */ +/* =============================================================================================== */ +/* =============================================================================================== */ + + + +int_fast8_t init_AOloopControl() +{ + FILE *fp; + +#ifdef AOLOOPCONTROL_LOGFUNC + CORE_logFunctionCall( 0, __FUNCTION__, __LINE__, ""); +#endif + + + if((fp=fopen("LOOPNUMBER","r"))!=NULL) + { + if(fscanf(fp,"%8ld", &LOOPNUMBER) != 1) + printERROR(__FILE__,__func__,__LINE__, "Cannot read LOOPNUMBER"); + + printf("LOOP NUMBER = %ld\n", LOOPNUMBER); + fclose(fp); + } + else + LOOPNUMBER = 0; + + + strcpy(data.module[data.NBmodule].name, __FILE__); + strcpy(data.module[data.NBmodule].info, "AO loop control"); + data.NBmodule++; + + + + RegisterCLIcommand("aolloadconf",__FILE__, AOloopControl_loadconfigure_cli, "load AO loop configuration", "", "AOlooploadconf 1", "int AOloopControl_loadconfigure(long loopnb, 1, 10)"); + + + + +/* =============================================================================================== */ +/* =============================================================================================== */ +/** @name AOloopControl - 2. LOW LEVEL UTILITIES & TOOLS */ +/* =============================================================================================== */ +/* =============================================================================================== */ + + +/* =============================================================================================== */ +/** @name AOloopControl - 2.1. LOW LEVEL UTILITIES & TOOLS - LOAD DATA STREAMS */ +/* =============================================================================================== */ + +/* =============================================================================================== */ +/** @name AOloopControl - 2.2. LOW LEVEL UTILITIES & TOOLS - DATA STREAMS PROCESSING */ +/* =============================================================================================== */ + +/* RegisterCLIcommand("aveACshmim", __FILE__, AOloopControl_AveStream_cli, "average and AC shared mem image", " " , "aveACshmim imin 0.01 outave outAC outRMS", "int AOloopControl_AveStream(char *IDname, double alpha, char *IDname_out_ave, char *IDname_out_AC, char *IDname_out_RMS)"); + + RegisterCLIcommand("aolstream3Dto2D", __FILE__, AOloopControl_stream3Dto2D_cli, "remaps 3D cube into 2D image", " <# cols> " , "aolstream3Dto2D in3dim out2dim 4 1", "long AOloopControl_stream3Dto2D(const char *in_name, const char *out_name, int NBcols, int insem)"); +*/ + + + + + + + + +/* =============================================================================================== */ +/* =============================================================================================== */ +/** @name AOloopControl - 6. REAL TIME COMPUTING ROUTINES */ +/* =============================================================================================== */ +/* =============================================================================================== */ + + + RegisterCLIcommand("aolrun", __FILE__, AOloopControl_run, "run AO loop", "no arg", "aolrun", "int AOloopControl_run()"); + + RegisterCLIcommand("aolzpwfsloop",__FILE__, AOloopControl_WFSzpupdate_loop_cli, "WFS zero point offset loop", " ", "aolzpwfsloop dmZP zrespM wfszp", "int AOloopControl_WFSzpupdate_loop(char *IDzpdm_name, char *IDzrespM_name, char *IDwfszp_name)"); + + RegisterCLIcommand("aolzpwfscloop", __FILE__, AOloopControl_WFSzeropoint_sum_update_loop_cli, "WFS zero point offset loop: combine multiple input channels", " ", "aolzpwfscloop wfs2zpoffset 4 wfsref0 wfsref", "int AOloopControl_WFSzeropoint_sum_update_loop(long loopnb, char *ID_WFSzp_name, int NBzp, char *IDwfsref0_name, char *IDwfsref_name)"); + + RegisterCLIcommand("aocmlrun", __FILE__, AOloopControl_CompModes_loop_cli, "run AO compute modes loop", " ", "aocmlrun CM wfsref wfsim wfsimtot aomodeval", "int AOloopControl_CompModes_loop(char *ID_CM_name, char *ID_WFSref_name, char *ID_WFSim_name, char *ID_WFSimtot, char *ID_coeff_name)"); + + RegisterCLIcommand("aolmc2dmfilt", __FILE__, AOloopControl_GPUmodecoeffs2dm_filt_loop_cli, "convert mode coefficients to DM map", " ", "aolmc2dmfilt aolmodeval DMmodesC 2 dmmapc 0.2 1 2 1", "int AOloopControl_GPUmodecoeffs2dm_filt_loop(char *modecoeffs_name, char *DMmodes_name, int semTrigg, char *out_name, int GPUindex, long loop, long offloadMode)"); + + RegisterCLIcommand("aolsig2mcoeff", __FILE__, AOloopControl_sig2Modecoeff_cli, "convert signals to mode coeffs", " ", "aolsig2mcoeff wfsdata wfsref wfsmodes outim", "long AOloopControl_sig2Modecoeff(char *WFSim_name, char *IDwfsref_name, char *WFSmodes_name, char *outname)"); + + + +/* =============================================================================================== */ +/* =============================================================================================== */ +/** @name AOloopControl - 8. LOOP CONTROL INTERFACE */ +/* =============================================================================================== */ +/* =============================================================================================== */ + + RegisterCLIcommand("aolnb", __FILE__, AOloopControl_setLoopNumber_cli, "set AO loop #", "", "AOloopnb 0", "int AOloopControl_setLoopNumber(long loop)"); + +/* =============================================================================================== */ +/** @name AOloopControl - 8.1. LOOP CONTROL INTERFACE - MAIN CONTROL : LOOP ON/OFF START/STOP/STEP/RESET */ +/* =============================================================================================== */ + + +/* =============================================================================================== */ +/** @name AOloopControl - 8.2. LOOP CONTROL INTERFACE - DATA LOGGING */ +/* =============================================================================================== */ + +/* =============================================================================================== */ +/** @name AOloopControl - 8.3. LOOP CONTROL INTERFACE - PRIMARY DM WRITE */ +/* =============================================================================================== */ + +/* =============================================================================================== */ +/** @name AOloopControl - 8.4. LOOP CONTROL INTERFACE - INTEGRATOR AUTO TUNING */ +/* =============================================================================================== */ + + +/* =============================================================================================== */ +/** @name AOloopControl - 8.5. LOOP CONTROL INTERFACE - PREDICTIVE FILTER ON/OFF */ +/* =============================================================================================== */ + +/* =============================================================================================== */ +/** @name AOloopControl - 8.6. LOOP CONTROL INTERFACE - TIMING PARAMETERS */ +/* =============================================================================================== */ + +/* =============================================================================================== */ +/** @name AOloopControl - 8.7. LOOP CONTROL INTERFACE - CONTROL LOOP PARAMETERS */ +/* =============================================================================================== */ + + RegisterCLIcommand("aolsetgain", __FILE__, AOloopControl_setgain_cli, "set gain", "", "aolsetgain 0.1", "int AOloopControl_setgain(float gain)"); + + RegisterCLIcommand("aolsetARPFgain", __FILE__, AOloopControl_setARPFgain_cli, "set auto-regressive predictive filter gain", "", "aolsetARPFgain 0.1", "int AOloopControl_setARPFgain(float gain)"); + + + + + + + + + + + RegisterCLIcommand("aolkill", __FILE__, AOloopControl_loopkill, "kill AO loop", "no arg", "aolkill", "int AOloopControl_setLoopNumber()"); + + RegisterCLIcommand("aolon", __FILE__, AOloopControl_loopon, "turn loop on", "no arg", "aolon", "int AOloopControl_loopon()"); + + RegisterCLIcommand("aoloff", __FILE__, AOloopControl_loopoff, "turn loop off", "no arg", "aoloff", "int AOloopControl_loopoff()"); + + RegisterCLIcommand("aolstep",__FILE__, AOloopControl_loopstep_cli, "turn loop on for N steps", "", "aolstep", "int AOloopControl_loopstep(long loop, long NBstep)"); + + RegisterCLIcommand("aolreset", __FILE__, AOloopControl_loopreset, "reset loop, and turn it off", "no arg", "aolreset", "int AOloopControl_loopreset()"); + + RegisterCLIcommand("aolsetmbgain",__FILE__, AOloopControl_set_modeblock_gain_cli, "set modal block gain", " ", "aolsetmbgain 2 0.2 1", "int AOloopControl_set_modeblock_gain(long loop, long blocknb, float gain, int add)"); + + RegisterCLIcommand("aolDMprimWon", __FILE__, AOloopControl_DMprimaryWrite_on, "turn DM primary write on", "no arg", "aolDMprimWon", "int AOloopControl_DMprimaryWrite_on()"); + + RegisterCLIcommand("aolDMprimWoff", __FILE__, AOloopControl_DMprimaryWrite_off, "turn DM primary write off", "no arg", "aolDMprimWoff", "int AOloopControl_DMprimaryWrite_off()"); + + RegisterCLIcommand("aolDMfiltWon", __FILE__, AOloopControl_DMfilteredWrite_on, "turn DM filtered write on", "no arg", "aolDMfiltWon", "int AOloopControl_DMfilteredWrite_on()"); + + RegisterCLIcommand("aolDMfiltWoff", __FILE__, AOloopControl_DMfilteredWrite_off, "turn DM filtered write off", "no arg", "aolDMfiltWoff", "int AOloopControl_DMfilteredWrite_off()"); + + RegisterCLIcommand("aolAUTOTUNELIMon", __FILE__, AOloopControl_AUTOTUNE_LIMITS_on, "turn auto-tuning modal limits on", "no arg", "aolAUTOTUNELIMon", "int AOloopControl_AUTOTUNE_LIMITS_on()"); + + RegisterCLIcommand("aolAUTOTUNELIMoff", __FILE__, AOloopControl_AUTOTUNE_LIMITS_off, "turn auto-tuning modal limits off", "no arg", "aolAUTOTUNELIMoff", "int AOloopControl_AUTOTUNE_LIMITS_off()"); + + RegisterCLIcommand("aolsetATlimd", __FILE__, AOloopControl_set_AUTOTUNE_LIMITS_delta_cli, "set auto-tuning modal limits delta", "", "aolsetATlimd 0.0001", "int AOloopControl_set_AUTOTUNE_LIMITS_delta(float AUTOTUNE_LIMITS_delta)"); + + RegisterCLIcommand("aolsetATlimp", __FILE__, AOloopControl_set_AUTOTUNE_LIMITS_perc_cli, "set auto-tuning modal limits percentile", "", "aolsetATlimp 1.0", "int AOloopControl_set_AUTOTUNE_LIMITS_perc(float AUTOTUNE_LIMITS_perc)"); + + RegisterCLIcommand("aolsetATlimm", __FILE__, AOloopControl_set_AUTOTUNE_LIMITS_mcoeff_cli, "set auto-tuning modal limits multiplicative coeff", "", "aolsetATlimm 1.5", "int AOloopControl_set_AUTOTUNE_LIMITS_mcoeff(float AUTOTUNE_LIMITS_mcoeff)"); + + RegisterCLIcommand("aolAUTOTUNEGAINon", __FILE__, AOloopControl_AUTOTUNE_GAINS_on, "turn auto-tuning modal gains on", "no arg", "aolAUTOTUNEGAINon", "int AOloopControl_AUTOTUNE_GAINS_on()"); + + RegisterCLIcommand("aolAUTOTUNEGAINoff", __FILE__, AOloopControl_AUTOTUNE_GAINS_off, "turn auto-tuning modal gains off", "no arg", "aolAUTOTUNEGAINoff", "int AOloopControl_AUTOTUNE_GAINS_off()"); + + RegisterCLIcommand("aolARPFon", __FILE__, AOloopControl_ARPFon, "turn auto-regressive predictive filter on", "no arg", "aolARPFon", "int AOloopControl_ARPFon()"); + + RegisterCLIcommand("aolARPFoff", __FILE__, AOloopControl_ARPFoff, "turn auto-regressive predictive filter off", "no arg", "aolARPFoff", "int AOloopControl_ARPFoff()"); + + + + +/* =============================================================================================== */ +/* =============================================================================================== */ +/** @name AOloopControl - 10. FOCAL PLANE SPECKLE MODULATION / CONTROL */ +/* =============================================================================================== */ +/* =============================================================================================== */ + + + + +/* =============================================================================================== */ +/* =============================================================================================== */ +/** @name AOloopControl - 11. PROCESS LOG FILES */ +/* =============================================================================================== */ +/* =============================================================================================== */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + RegisterCLIcommand("aolsetloopfrequ", + __FILE__, + AOloopControl_set_loopfrequ_cli, + "set loop frequency", + "", + "aolsetloopfrequ 2000", + "int AOloopControl_set_loopfrequ(float loopfrequ)"); + + + + RegisterCLIcommand("aolsethlat", __FILE__, AOloopControl_set_hardwlatency_frame_cli, "set hardware latency", "", "aolsethlat 2.7", "int AOloopControl_set_hardwlatency_frame(float hardwlatency_frame)"); + + RegisterCLIcommand("aolsetclat",__FILE__, AOloopControl_set_complatency_frame_cli,"set computation latency", "", "aolsetclat 0.6", "int AOloopControl_set_complatency_frame(float complatency_frame)"); + + RegisterCLIcommand("aolsetwlat", __FILE__, AOloopControl_set_wfsmextrlatency_frame_cli, "set WFS mode extraction latency", "", "aolsetwlat 0.8", "int AOloopControl_set_wfsmextrlatency_frame(float wfsmextrlatency_frame)"); + + RegisterCLIcommand("aolsetwfsnormf", __FILE__, AOloopControl_setWFSnormfloor_cli, "set WFS normalization floor", "", "aolsetwfsnormf 10000.0", "int AOloopControl_setWFSnormfloor(float WFSnormfloor)"); + + RegisterCLIcommand("aolsetmaxlim", __FILE__, AOloopControl_setmaxlimit_cli, "set max limit for AO mode correction", "", "aolsetmaxlim 0.01", "int AOloopControl_setmaxlimit(float maxlimit)"); + + RegisterCLIcommand("aolsetmult", __FILE__, AOloopControl_setmult_cli, "set mult coeff for AO mode correction", "", "aolsetmult 0.98", "int AOloopControl_setmult(float multcoeff)"); + + RegisterCLIcommand("aolsetnbfr",__FILE__, AOloopControl_setframesAve_cli, "set number of frames to be averaged", "", "aolsetnbfr 10", "int AOloopControl_setframesAve(long nbframes)"); + + + + + + + + + + + + + + RegisterCLIcommand("aollogprocmodeval",__FILE__, AOloopControl_logprocess_modeval_cli, "process log image modeval", "", "aollogprocmodeval imc", "int AOloopControl_logprocess_modeval(const char *IDname);"); + + + + + + + + + + + RegisterCLIcommand("aolsetgainr", __FILE__, AOloopControl_setgainrange_cli, "set modal gains from m0 to m1 included", " ", "aolsetgainr 20 30 0.2", "int AOloopControl_setgainrange(long m0, long m1, float gainval)"); + + RegisterCLIcommand("aolsetlimitr",__FILE__, AOloopControl_setlimitrange_cli, "set modal limits", " ", "aolsetlimitr 20 30 0.02", "int AOloopControl_setlimitrange(long m0, long m1, float gainval)"); + + RegisterCLIcommand("aolsetmultfr", __FILE__, AOloopControl_setmultfrange_cli, "set modal multf", " ", "aolsetmultfr 10 30 0.98", "int AOloopControl_setmultfrange(long m0, long m1, float multfval)"); + + RegisterCLIcommand("aolsetgainb", __FILE__, AOloopControl_setgainblock_cli, "set modal gains by block", " ", "aolsetgainb 2 0.2", "int AOloopControl_setgainblock(long m0, long m1, float gainval)"); + + RegisterCLIcommand("aolsetlimitb",__FILE__, AOloopControl_setlimitblock_cli, "set modal limits by block", " ", "aolsetlimitb 2 0.02", "int AOloopControl_setlimitblock(long mb, float limitval)"); + + RegisterCLIcommand("aolsetmultfb", __FILE__, AOloopControl_setmultfblock_cli, "set modal multf by block", " ", "aolsetmultfb 2 0.98", "int AOloopControl_setmultfblock(long mb, float multfval)"); + + RegisterCLIcommand("aolscangainb", __FILE__, AOloopControl_scanGainBlock_cli, "scan gain for block", " ", "aolscangainb", "int AOloopControl_scanGainBlock(long NBblock, long NBstep, float gainStart, float gainEnd, long NBgain)"); + + RegisterCLIcommand("aolmkwfsres", __FILE__, AOloopControl_computeWFSresidualimage_cli, "compute WFS residual real time", " ", "aolmkwfsres 2 coeffim", "long AOloopControl_computeWFSresidualimage(long loop, char *IDalpha_name)"); + + + + RegisterCLIcommand("aolcompolm", __FILE__, AOloopControl_ComputeOpenLoopModes_cli, "compute open loop mode values", "", "aolcompolm 2", "long AOloopControl_ComputeOpenLoopModes(long loop)"); + + RegisterCLIcommand("aolautotunegains", __FILE__, AOloopControl_AutoTuneGains_cli, "compute optimal gains", " ", "aolautotunegains 0 autogain 0.1 20000", "long AOloopControl_AutoTuneGains(long loop, const char *IDout_name, float GainCoeff, long NBsamples)"); + + RegisterCLIcommand("aoldm2dmoffload", __FILE__, AOloopControl_dm2dm_offload_cli, "slow offload from dm to dm", " ", "aoldm2dmoffload dmin dmout 0.5 -0.01 0.999", "long AOloopControl_dm2dm_offload(const char *streamin, const char *streamout, float twait, float offcoeff, float multcoeff)"); + + RegisterCLIcommand("aolautotune", __FILE__, AOloopControl_AutoTune, "auto tuning of loop parameters", "no arg", "aolautotune", "int_fast8_t AOloopControl_AutoTune()"); + + RegisterCLIcommand("aolset", __FILE__, AOloopControl_setparam_cli, "set parameter", " " , "aolset", "int AOloopControl_setparam(long loop, const char *key, double value)"); + + RegisterCLIcommand("aoldmmodAB", __FILE__, AOloopControl_DMmodulateAB_cli, "module DM with linear combination of probes A and B", " ", "aoldmmodAB probeA probeB wfsrespmat wfsref 0.1 6","int AOloopControl_DMmodulateAB(const char *IDprobeA_name, const char *IDprobeB_name, const char *IDdmstream_name, const char *IDrespmat_name, const char *IDwfsrefstream_name, double delay, long NBprobes)"); + + + + + + + + + // add atexit functions here + // atexit((void*) myfunc); + + return 0; +} + + + + + + + + + + + + + + + + + + + +/* =============================================================================================== */ +/* =============================================================================================== */ +/** @name AOloopControl - 1. INITIALIZATION, configurations */ +/* =============================================================================================== */ +/* =============================================================================================== */ + + + + +/** + * ## Purpose + * + * Read parameter value (float) + * + * ## Arguments + * + * @param[in] + * paramname CHAR* + * parameter name + * + * @param[in] + * defaultValue FLOAT + * default value if file conf/param_paramname.txt not found + * + * @param[in] + * fplog FILE* + * log file. If NULL, do not log + * + */ +float AOloopControl_readParam_float(char *paramname, float defaultValue, FILE *fplog) +{ + FILE *fp; + char fname[200]; + float value; + int wParamFile = 0; + + sprintf(fname, "./conf/param_%s.txt", paramname); + if((fp=fopen(fname, "r"))==NULL) + { + printf("WARNING: file %s missing\n", fname); + value = defaultValue; + wParamFile = 1; + } + else + { + if(fscanf(fp, "%50f", &value) != 1){ + printERROR(__FILE__,__func__,__LINE__, "Cannot read parameter for file"); + value = defaultValue; + wParamFile = 1; + } + fclose(fp); + } + + if(wParamFile == 1) // write file + { + fp = fopen(fname, "w"); + fprintf(fp, "%f", value); + fclose(fp); + } + + + if(fplog!=NULL) + fprintf(fplog, "parameter %20s = %f\n", paramname, value); + + + return value; +} + + + +/** + * ## Purpose + * + * Read parameter value (int) + * + * ## Arguments + * + * @param[in] + * paramname CHAR* + * parameter name + * + * @param[in] + * defaultValue INT + * default value if file conf/param_paramname.txt not found + * + * @param[in] + * fplog FILE* + * log file. If NULL, do not log + * + */ +int AOloopControl_readParam_int(char *paramname, int defaultValue, FILE *fplog) +{ + FILE *fp; + char fname[200]; + int value; + int wParamFile = 0; + + sprintf(fname, "./conf/param_%s.txt", paramname); + if((fp=fopen(fname, "r"))==NULL) + { + printf("WARNING: file %s missing\n", fname); + value = defaultValue; + wParamFile = 1; + } + else + { + if(fscanf(fp, "%50d", &value) != 1){ + printERROR(__FILE__,__func__,__LINE__, "Cannot read parameter for file"); + value = defaultValue; + wParamFile = 1; + } + fclose(fp); + } + + if(wParamFile == 1) // write file + { + fp = fopen(fname, "w"); + fprintf(fp, "%d", value); + fclose(fp); + } + + + if(fplog!=NULL) + fprintf(fplog, "parameter %20s = %d\n", paramname, value); + + + return value; +} + + + +/** + * ## Purpose + * + * Read parameter value (char*) + * + * ## Arguments + * + * @param[in] + * paramname CHAR* + * parameter name + * + * @param[in] + * defaultValue CHAR* + * default value if file conf/param_paramname.txt not found + * + * @param[in] + * fplog FILE* + * log file. If NULL, do not log + * + */ +char* AOloopControl_readParam_string(char *paramname, char* defaultValue, FILE *fplog) +{ + FILE *fp; + char fname[200]; + char* value = " "; + int wParamFile = 0; + + sprintf(fname, "./conf/param_%s.txt", paramname); + if((fp=fopen(fname, "r"))==NULL) + { + printf("WARNING: file %s missing\n", fname); + strcpy(value, defaultValue); + wParamFile = 1; + } + else + { + if(fscanf(fp, "%200s", value) != 1){ + printERROR(__FILE__,__func__,__LINE__, "Cannot read parameter for file"); + strcpy(value, defaultValue); + wParamFile = 1; + } + fclose(fp); + } + + if(wParamFile == 1) // write file + { + fp = fopen(fname, "w"); + fprintf(fp, "%s", value); + fclose(fp); + } + + + if(fplog!=NULL) + fprintf(fplog, "parameter %20s = %s\n", paramname, value); + + + return value; +} + + + + + + + + + + + + + + + + + + + + + +/** + * ## Purpose + * + * load / setup configuration + * + * ## Arguments + * + * @param[in] + * loop INT + * Loop number + * + * @param[in] + * mode INT + * - 1 loads from ./conf/ directory to shared memory + * - 0 simply connects to shared memory + * + * @param[in] + * level INT + * - 2 zonal only + * - 10+ load all + * + * + * + * @ingroup AOloopControl_streams + */ +int_fast8_t AOloopControl_loadconfigure(long loop, int mode, int level) +{ + FILE *fp; + char content[201]; + char name[201]; + char fname[201]; + uint32_t *sizearray; + int kw; + long k; + int r; + int sizeOK; + char command[501]; + int CreateSMim; + long ii; + long tmpl; + char testdirname[201]; + + int initwfsref; + + FILE *fplog; // human-readable log of load sequence + + +#ifdef AOLOOPCONTROL_LOGFUNC + AOLOOPCONTROL_logfunc_level = 0; + CORE_logFunctionCall( AOLOOPCONTROL_logfunc_level, AOLOOPCONTROL_logfunc_level_max, 0, __FUNCTION__, __LINE__, ""); +#endif + + + // Create logfile for this function + // + if((fplog=fopen("logdir/loadconf.log", "w"))==NULL) + { + printf("ERROR: cannot create logdir/loadconf.log\n"); + exit(0); + } + loadcreateshm_log = 1; + loadcreateshm_fplog = fplog; + + /** --- */ + /** # Details */ + + /** ## 1. Initial setup from configuration files */ + + + /** - 1.1. Initialize memory */ + fprintf(fplog, "\n\n============== 1.1. Initialize memory ===================\n\n"); + if(AOloopcontrol_meminit==0) + AOloopControl_InitializeMemory(0); + + + + + // + /** ### 1.2. Set names of key streams */ + // + // Here we define names of key streams used by loop + + fprintf(fplog, "\n\n============== 1.2. Set names of key streams ===================\n\n"); + + /** - dmC stream : DM control */ + if(sprintf(name, "aol%ld_dmC", loop)<1) + printERROR(__FILE__, __func__, __LINE__, "sprintf wrote <1 char"); + printf("DM control file name : %s\n", name); + strcpy(AOconf[loop].dmCname, name); + + /** - dmdisp stream : total DM displacement */ + // used to notify dm combine that a new displacement should be computed + if(sprintf(name, "aol%ld_dmdisp", loop) < 1) + printERROR(__FILE__, __func__, __LINE__, "sprintf wrote <1 char"); + printf("DM displacement file name : %s\n", name); + strcpy(AOconf[loop].dmdispname, name); + + /** - dmRM stream : response matrix */ + if(sprintf(name, "aol%ld_dmRM", loop) < 1) + printERROR(__FILE__, __func__, __LINE__, "sprintf wrote <1 char"); + printf("DM RM file name : %s\n", name); + strcpy(AOconf[loop].dmRMname, name); + + /** - wfsim : WFS image */ + if(sprintf(name, "aol%ld_wfsim", loop) < 1) + printERROR(__FILE__, __func__, __LINE__, "sprintf wrote <1 char"); + printf("WFS file name: %s\n", name); + strcpy(AOconf[loop].WFSname, name); + + + + // Modal control + + /** - DMmodes : control modes */ + if(sprintf(name, "aol%ld_DMmodes", loop) < 1) + printERROR(__FILE__, __func__, __LINE__, "sprintf wrote <1 char"); + printf("DMmodes file name: %s\n", name); + strcpy(AOconf[loop].DMmodesname, name); + + /** - respM : response matrix */ + if(sprintf(name, "aol%ld_respM", loop) < 1) + printERROR(__FILE__, __func__, __LINE__, "sprintf wrote <1 char"); + printf("respM file name: %s\n", name); + strcpy(AOconf[loop].respMname, name); + + /** - contrM : control matrix */ + if(sprintf(name, "aol%ld_contrM", loop) < 1) + printERROR(__FILE__, __func__, __LINE__, "sprintf wrote <1 char"); + printf("contrM file name: %s\n", name); + strcpy(AOconf[loop].contrMname, name); + + + + + + + sizearray = (uint32_t*) malloc(sizeof(uint32_t)*3); + + + /** ### 1.3. Read loop name + * + * - ./conf/conf_LOOPNAME.txt -> AOconf[loop].name + */ + fprintf(fplog, "\n\n============== 1.3. Read loop name ===================\n\n"); + + if((fp=fopen("./conf/conf_LOOPNAME.txt","r"))==NULL) + { + printf("ERROR: file ./conf/conf_LOOPNAME.txt missing\n"); + exit(0); + } + if(fscanf(fp, "%200s", content) != 1) + { + printERROR(__FILE__,__func__,__LINE__, "Cannot read parameter for file"); + exit(0); + } + + printf("loop name : %s\n", content); + fflush(stdout); + fprintf(fplog, "AOconf[%ld].name = %s\n", loop, AOconf[loop].name); + fclose(fp); + strcpy(AOconf[loop].name, content); + + + /** ### 1.4. Define WFS image normalization mode + * + * - conf/param_WFSnorm.txt -> AOconf[loop].WFSnormalize + */ + fprintf(fplog, "\n\n============== 1.4. Define WFS image normalization mode ===================\n\n"); + + AOconf[loop].WFSnormalize = AOloopControl_readParam_int("WFSnorm", 1, fplog); + + + + /** ### 1.5. Read Timing info + * + * - ./conf/param_loopfrequ.txt -> AOconf[loop].loopfrequ + * - ./conf/param_hardwlatency.txt -> AOconf[loop].hardwlatency + * - AOconf[loop].hardwlatency_frame = AOconf[loop].hardwlatency * AOconf[loop].loopfrequ + * - ./conf/param_complatency.txt -> AOconf[loop].complatency + * - AOconf[loop].complatency_frame = AOconf[loop].complatency * AOconf[loop].loopfrequ; + * - ./conf/param_wfsmextrlatency.txt -> AOconf[loop].wfsmextrlatency + */ + fprintf(fplog, "\n\n============== 1.5. Read Timing info ===================\n\n"); + + + + AOconf[loop].loopfrequ = AOloopControl_readParam_float("loopfrequ", 1000.0, fplog); + AOconf[loop].hardwlatency = AOloopControl_readParam_float("hardwlatency", 0.0, fplog); + AOconf[loop].hardwlatency_frame = AOconf[loop].hardwlatency * AOconf[loop].loopfrequ; + + AOconf[loop].complatency = AOloopControl_readParam_float("complatency", 0.0, fplog); + AOconf[loop].complatency_frame = AOconf[loop].complatency * AOconf[loop].loopfrequ; + + AOconf[loop].wfsmextrlatency = AOloopControl_readParam_float("wfsmextrlatency", 0.0, fplog); + AOconf[loop].wfsmextrlatency_frame = AOconf[loop].wfsmextrlatency * AOconf[loop].loopfrequ; + + + + /** ### 1.6. Define GPU use + * + * - ./conf/param_GPU0.txt > AOconf[loop].GPU0 (0 if missing) + * - ./conf/param_GPU1.txt > AOconf[loop].GPU1 (0 if missing) + * - ./conf/param_GPUall.txt -> AOconf[loop].GPUall + * - ./conf/param_DMprimWriteON.txt -> AOconf[loop].DMprimaryWriteON + * + */ + fprintf(fplog, "\n\n============== 1.6. Define GPU use ===================\n\n"); + + AOconf[loop].GPU0 = AOloopControl_readParam_int("GPU0", 0, fplog); + AOconf[loop].GPU1 = AOloopControl_readParam_int("GPU1", 0, fplog); + AOconf[loop].GPUall = AOloopControl_readParam_int("GPUall", 0, fplog); // Skip CPU image scaling and go straight to GPUs ? + AOconf[loop].DMprimaryWriteON = AOloopControl_readParam_int("DMprimaryWriteON", 0, fplog); // Direct DM write ? + AOconf[loop].DMfilteredWriteON = AOloopControl_readParam_int("DMfilteredWriteON", 0, fplog); // Filtered DM write ? + + + /** ### 1.7. WFS image total flux computation mode + * + * + */ + fprintf(fplog, "\n\n============== 1.7. WFS image total flux computation mode ===================\n\n"); + + // TOTAL image done in separate thread ? + AOconf[loop].AOLCOMPUTE_TOTAL_ASYNC = AOloopControl_readParam_int("COMPUTE_TOTAL_ASYNC", 1, fplog); + + + /** ### 1.8. Read CMatrix mult mode + * + * - ./conf/param_CMMMODE.txt -> CMMODE + * - 0 : WFS signal -> Mode coeffs -> DM act values (2 sequential matrix multiplications) + * - 1 : WFS signal -> DM act values (1 combined matrix multiplication) + */ + + fprintf(fplog, "\n\n============== 1.8. Read CMatrix mult mode ===================\n\n"); + + AOconf[loop].CMMODE = AOloopControl_readParam_int("CMMODE", 1, fplog); + + + + + + + + /** ### 1.9. Setup loop timing array + */ + fprintf(fplog, "\n\n============== 1.10. Setup loop timing array ===================\n\n"); + + if(sprintf(name, "aol%ld_looptiming", loop) < 1) + printERROR(__FILE__, __func__, __LINE__, "sprintf wrote <1 char"); + + aoconfID_looptiming = AOloopControl_IOtools_2Dloadcreate_shmim(name, " ", NBtimers, 1, 0.0); + + + + + + /** ## 2. Read/load shared memory arrays + * + */ + fprintf(fplog, "\n\n============== 2. Read/load shared memory arrays ===================\n\n"); + + /** + * ### 2.1. CONNECT to existing streams + * + * Note: these streams MUST exist + * + * - AOconf[loop].dmdispname : this image is read to notify when new dm displacement is ready + * - AOconf[loop].WFSname : connect to WFS camera. This is where the size of the WFS is read + */ + + fprintf(fplog, "\n\n============== 2.1. CONNECT to existing streams ===================\n\n"); + + aoconfID_dmdisp = read_sharedmem_image(AOconf[loop].dmdispname); + if(aoconfID_dmdisp==-1) + fprintf(fplog, "ERROR : cannot read shared memory stream %s\n", AOconf[loop].dmdispname); + else + fprintf(fplog, "stream %s loaded as ID = %ld\n", AOconf[loop].dmdispname, aoconfID_dmdisp); + + + aoconfID_wfsim = read_sharedmem_image(AOconf[loop].WFSname); + if(aoconfID_wfsim == -1) + fprintf(fplog, "ERROR : cannot read shared memory stream %s\n", AOconf[loop].WFSname); + else + fprintf(fplog, "stream %s loaded as ID = %ld\n", AOconf[loop].WFSname, aoconfID_wfsim); + + AOconf[loop].sizexWFS = data.image[aoconfID_wfsim].md[0].size[0]; + AOconf[loop].sizeyWFS = data.image[aoconfID_wfsim].md[0].size[1]; + AOconf[loop].sizeWFS = AOconf[loop].sizexWFS*AOconf[loop].sizeyWFS; + + fprintf(fplog, "WFS stream size = %ld x %ld\n", AOconf[loop].sizexWFS, AOconf[loop].sizeyWFS); + + + + + + /** + * + * ### 2.2. Read file to stream or connect to existing stream + * + * The AOloopControl_xDloadcreate_shmim functions are used, and follows these rules: + * + * If file already loaded, use it (we assume it's already been properly loaded) \n + * If not, attempt to read it from shared memory \n + * If not available in shared memory, create it in shared memory \n + * if "fname" exists, attempt to load it into the shared memory image + * + * Stream names are fixed: + * - aol_wfsdark + * - aol_imWFS0 + * - aol_imWFS0tot + * - aol_imWFS1 + * - aol_imWFS2 + * - aol_wfsref0 + * - aol_wfsref + */ + + + fprintf(fplog, "\n\n============== 2.2. Read file to stream or connect to existing stream ===================\n\n"); + + if(sprintf(name, "aol%ld_wfsdark", loop) < 1) + printERROR(__FILE__, __func__, __LINE__, "sprintf wrote <1 char"); + sprintf(fname, "./conf/shmim_wfsdark.fits"); + aoconfID_wfsdark = AOloopControl_IOtools_2Dloadcreate_shmim(name, fname, AOconf[loop].sizexWFS, AOconf[loop].sizeyWFS, 0.0); + + + + if(sprintf(name, "aol%ld_imWFS0", loop) < 1) + printERROR(__FILE__, __func__, __LINE__, "sprintf wrote <1 char"); + aoconfID_imWFS0 = AOloopControl_IOtools_2Dloadcreate_shmim(name, " ", AOconf[loop].sizexWFS, AOconf[loop].sizeyWFS, 0.0); + COREMOD_MEMORY_image_set_createsem(name, 10); + + if(sprintf(name, "aol%ld_imWFS0tot", loop) < 1) + printERROR(__FILE__, __func__, __LINE__, "sprintf wrote <1 char"); + aoconfID_imWFS0tot = AOloopControl_IOtools_2Dloadcreate_shmim(name, " ", 1, 1, 0.0); + COREMOD_MEMORY_image_set_createsem(name, 10); + + if(sprintf(name, "aol%ld_imWFS1", loop) < 1) + printERROR(__FILE__, __func__, __LINE__, "sprintf wrote <1 char"); + aoconfID_imWFS1 = AOloopControl_IOtools_2Dloadcreate_shmim(name, " ", AOconf[loop].sizexWFS, AOconf[loop].sizeyWFS, 0.0); + + if(sprintf(name, "aol%ld_imWFS2", loop) < 1) + printERROR(__FILE__, __func__, __LINE__, "sprintf wrote <1 char"); + aoconfID_imWFS2 = AOloopControl_IOtools_2Dloadcreate_shmim(name, " ", AOconf[loop].sizexWFS, AOconf[loop].sizeyWFS, 0.0); + + + + + + initwfsref = AOconf[loop].init_wfsref0; + + if(sprintf(name, "aol%ld_wfsref0", loop) < 1) + printERROR(__FILE__, __func__, __LINE__, "sprintf wrote <1 char"); + + if(sprintf(fname, "./conf/shmim_wfsref0.fits") < 1) + printERROR(__FILE__, __func__, __LINE__, "sprintf wrote <1 char"); + + aoconfID_wfsref0 = AOloopControl_IOtools_2Dloadcreate_shmim(name, fname, AOconf[loop].sizexWFS, AOconf[loop].sizeyWFS, 0.0); + AOconf[loop].init_wfsref0 = 1; + + if(sprintf(name, "aol%ld_wfsref", loop) < 1) + printERROR(__FILE__, __func__, __LINE__, "sprintf wrote <1 char"); + + if(sprintf(fname, "./conf/shmim_wfsref.fits") < 1) + printERROR(__FILE__, __func__, __LINE__, "sprintf wrote <1 char"); + + aoconfID_wfsref = AOloopControl_IOtools_2Dloadcreate_shmim(name, fname, AOconf[loop].sizexWFS, AOconf[loop].sizeyWFS, 0.0); + + if(initwfsref==0) + { + char name1[200]; + + if(sprintf(name1, "aol%ld_wfsref0", loop) < 1) + printERROR(__FILE__, __func__, __LINE__, "sprintf wrote <1 char"); + + copy_image_ID(name1, name, 1); + } + + + + + /** ### 2.3. Connect to DM + * + * - AOconf[loop].dmCname : DM control channel + * + * Here the DM size is read -> Oconf[loop].sizexDM, AOconf[loop].sizeyDM + */ + + + AOconf[loop].DMMODE = AOloopControl_readParam_int("DMMODE", 0, fplog); // zonal DM by default + + aoconfID_dmC = image_ID(AOconf[loop].dmCname); + if(aoconfID_dmC==-1) + { + printf("connect to %s\n", AOconf[loop].dmCname); + aoconfID_dmC = read_sharedmem_image(AOconf[loop].dmCname); + if(aoconfID_dmC==-1) + { + printf("ERROR: cannot connect to shared memory %s\n", AOconf[loop].dmCname); + exit(0); + } + } + AOconf[loop].sizexDM = data.image[aoconfID_dmC].md[0].size[0]; + AOconf[loop].sizeyDM = data.image[aoconfID_dmC].md[0].size[1]; + AOconf[loop].sizeDM = AOconf[loop].sizexDM*AOconf[loop].sizeyDM; + + fprintf(fplog, "Connected to DM %s, size = %ld x %ld\n", AOconf[loop].dmCname, AOconf[loop].sizexDM, AOconf[loop].sizeyDM); + + + + + + /** + * - AOconf[loop].dmRMname : DM response matrix channel + * + */ + aoconfID_dmRM = image_ID(AOconf[loop].dmRMname); + if(aoconfID_dmRM==-1) + { + printf("connect to %s\n", AOconf[loop].dmRMname); + aoconfID_dmRM = read_sharedmem_image(AOconf[loop].dmRMname); + if(aoconfID_dmRM==-1) + { + printf("ERROR: cannot connect to shared memory %s\n", AOconf[loop].dmRMname); + exit(0); + } + } + fprintf(fplog, "stream %s loaded as ID = %ld\n", AOconf[loop].dmRMname, aoconfID_dmRM); + + + + + /// Connect to DM modes shared mem + aoconfID_DMmodes = image_ID(AOconf[loop].DMmodesname); + if(aoconfID_DMmodes==-1) + { + printf("connect to %s\n", AOconf[loop].DMmodesname); + aoconfID_DMmodes = read_sharedmem_image(AOconf[loop].DMmodesname); + if(aoconfID_DMmodes==-1) + { + printf("ERROR: cannot connect to shared memory %s\n", AOconf[loop].DMmodesname); + exit(0); + } + } + fprintf(fplog, "stream %s loaded as ID = %ld\n", AOconf[loop].DMmodesname, aoconfID_DMmodes); + AOconf[loop].NBDMmodes = data.image[aoconfID_DMmodes].md[0].size[2]; + printf("NBmodes = %ld\n", AOconf[loop].NBDMmodes); + + + + + + /** + * ## 3. Load DM modes (if level >= 10) + * + * + * */ + + fprintf(fplog, "\n\n============== 3. Load DM modes (if level >= 10) ===================\n\n"); + + + + if(level>=10) // Load DM modes (will exit if not successful) + { + /** + * Load AOconf[loop].DMmodesname \n + * if already exists in local memory, trust it and adopt it \n + * if not, load from ./conf/shmim_DMmodes.fits \n + * + */ + + aoconfID_DMmodes = image_ID(AOconf[loop].DMmodesname); + + + + if(aoconfID_DMmodes == -1) // If not, check file + { + long ID1tmp, ID2tmp; + int vOK; + + + + if(sprintf(fname, "./conf/shmim_DMmodes.fits") < 1) + printERROR(__FILE__, __func__, __LINE__, "sprintf wrote <1 char"); + + printf("Checking file \"%s\"\n", fname); + + // GET SIZE FROM FILE + ID1tmp = load_fits(fname, "tmp3Dim", 1); + if(ID1tmp==-1) + { + printf("WARNING: no file \"%s\" -> loading zonal modes\n", fname); + + if(sprintf(fname, "./conf/shmim_DMmodes_zonal.fits") <1) + printERROR(__FILE__, __func__, __LINE__, "sprintf wrote <1 char"); + + ID1tmp = load_fits(fname, "tmp3Dim", 1); + if(ID1tmp==-1) + { + printf("ERROR: cannot read zonal modes \"%s\"\n", fname); + exit(0); + } + } + + + // check size + if(data.image[ID1tmp].md[0].naxis != 3) + { + printf("ERROR: File \"%s\" is not a 3D image (cube)\n", fname); + exit(0); + } + if(data.image[ID1tmp].md[0].size[0] != AOconf[loop].sizexDM) + { + printf("ERROR: File \"%s\" has wrong x size: should be %ld, is %ld\n", fname, AOconf[loop].sizexDM, (long) data.image[ID1tmp].md[0].size[0]); + exit(0); + } + if(data.image[ID1tmp].md[0].size[1] != AOconf[loop].sizeyDM) + { + printf("ERROR: File \"%s\" has wrong y size: should be %ld, is %ld\n", fname, AOconf[loop].sizeyDM, (long) data.image[ID1tmp].md[0].size[1]); + exit(0); + } + AOconf[loop].NBDMmodes = data.image[ID1tmp].md[0].size[2]; + + printf("NUMBER OF MODES = %ld\n", AOconf[loop].NBDMmodes); + + // try to read it from shared memory + ID2tmp = read_sharedmem_image(AOconf[loop].DMmodesname); + vOK = 0; + if(ID2tmp != -1) // if shared memory exists, check its size + { + vOK = 1; + if(data.image[ID2tmp].md[0].naxis != 3) + { + printf("ERROR: Shared memory File %s is not a 3D image (cube)\n", AOconf[loop].DMmodesname); + vOK = 0; + } + if(data.image[ID2tmp].md[0].size[0] != AOconf[loop].sizexDM) + { + printf("ERROR: Shared memory File %s has wrong x size: should be %ld, is %ld\n", AOconf[loop].DMmodesname, AOconf[loop].sizexDM, (long) data.image[ID2tmp].md[0].size[0]); + vOK = 0; + } + if(data.image[ID2tmp].md[0].size[1] != AOconf[loop].sizeyDM) + { + printf("ERROR: Shared memory File %s has wrong y size: should be %ld, is %ld\n", AOconf[loop].DMmodesname, AOconf[loop].sizeyDM, (long) data.image[ID2tmp].md[0].size[1]); + vOK = 0; + } + if(data.image[ID2tmp].md[0].size[2] != AOconf[loop].NBDMmodes) + { + printf("ERROR: Shared memory File %s has wrong y size: should be %ld, is %ld\n", AOconf[loop].DMmodesname, AOconf[loop].NBDMmodes, (long) data.image[ID2tmp].md[0].size[2]); + vOK = 0; + } + + if(vOK==1) // if size is OK, adopt it + aoconfID_DMmodes = ID2tmp; + else // if not, erase shared memory + { + printf("SHARED MEM IMAGE HAS WRONG SIZE -> erasing it\n"); + delete_image_ID(AOconf[loop].DMmodesname); + } + } + + + if(vOK==0) // create shared memory + { + + sizearray[0] = AOconf[loop].sizexDM; + sizearray[1] = AOconf[loop].sizeyDM; + sizearray[2] = AOconf[loop].NBDMmodes; + printf("Creating %s [%ld x %ld x %ld]\n", AOconf[loop].DMmodesname, (long) sizearray[0], (long) sizearray[1], (long) sizearray[2]); + fflush(stdout); + aoconfID_DMmodes = create_image_ID(AOconf[loop].DMmodesname, 3, sizearray, _DATATYPE_FLOAT, 1, 0); + } + + // put modes into shared memory + + switch (data.image[ID1tmp].md[0].atype) { + case _DATATYPE_FLOAT : + memcpy(data.image[aoconfID_DMmodes].array.F, data.image[ID1tmp].array.F, sizeof(float)*AOconf[loop].sizexDM*AOconf[loop].sizeyDM*AOconf[loop].NBDMmodes); + break; + case _DATATYPE_DOUBLE : + for(ii=0; ii=10) + { + long ID; + + // Load/create modal command vector memory + if(sprintf(name, "aol%ld_DMmode_cmd", loop) < 1) + printERROR(__FILE__, __func__, __LINE__, "sprintf wrote <1 char"); + aoconfID_cmd_modes = AOloopControl_IOtools_2Dloadcreate_shmim(name, "", AOconf[loop].NBDMmodes, 1, 0.0); + + + if(sprintf(name, "aol%ld_DMmode_meas", loop) < 1) + printERROR(__FILE__, __func__, __LINE__, "sprintf wrote <1 char"); + aoconfID_meas_modes = AOloopControl_IOtools_2Dloadcreate_shmim(name, "", AOconf[loop].NBDMmodes, 1, 0.0); + + if(sprintf(name, "aol%ld_DMmode_AVE", loop) < 1) + printERROR(__FILE__, __func__, __LINE__, "sprintf wrote <1 char"); + aoconfID_AVE_modes = AOloopControl_IOtools_2Dloadcreate_shmim(name, "", AOconf[loop].NBDMmodes, 1, 0.0); + + if(sprintf(name, "aol%ld_DMmode_RMS", loop) < 1) + printERROR(__FILE__, __func__, __LINE__, "sprintf wrote <1 char"); + aoconfID_RMS_modes = AOloopControl_IOtools_2Dloadcreate_shmim(name, "", AOconf[loop].NBDMmodes, 1, 0.0); + + if(sprintf(name, "aol%ld_DMmode_GAIN", loop) < 1) + printERROR(__FILE__, __func__, __LINE__, "sprintf wrote <1 char"); + aoconfID_DMmode_GAIN = AOloopControl_IOtools_2Dloadcreate_shmim(name, "", AOconf[loop].NBDMmodes, 1, 1.0); + + if(sprintf(name, "aol%ld_DMmode_LIMIT", loop) < 1) + printERROR(__FILE__, __func__, __LINE__, "sprintf wrote <1 char"); + aoconfID_LIMIT_modes = AOloopControl_IOtools_2Dloadcreate_shmim(name, "", AOconf[loop].NBDMmodes, 1, 1.0); + + if(sprintf(name, "aol%ld_DMmode_MULTF", loop) < 1) + printERROR(__FILE__, __func__, __LINE__, "sprintf wrote <1 char"); + aoconfID_MULTF_modes = AOloopControl_IOtools_2Dloadcreate_shmim(name, "", AOconf[loop].NBDMmodes, 1, 1.0); + + + if(sprintf(name, "aol%ld_wfsmask", loop) < 1) + printERROR(__FILE__, __func__, __LINE__, "sprintf wrote <1 char"); + sprintf(fname, "conf/%s.fits", name); + aoconfID_wfsmask = AOloopControl_IOtools_2Dloadcreate_shmim(name, fname, AOconf[loop].sizexWFS, AOconf[loop].sizeyWFS, 1.0); + AOconf[loop].activeWFScnt = 0; + for(ii=0; ii0.5) + AOconf[loop].activeWFScnt++; + + if(sprintf(name, "aol%ld_dmmask", loop) < 1) + printERROR(__FILE__, __func__, __LINE__, "sprintf wrote <1 char"); + if(sprintf(fname, "conf/%s.fits", name) < 1) + printERROR(__FILE__, __func__, __LINE__, "sprintf wrote <1 char"); + aoconfID_dmmask = AOloopControl_IOtools_2Dloadcreate_shmim(name, fname, AOconf[loop].sizexDM, AOconf[loop].sizeyDM, 1.0); + AOconf[loop].activeDMcnt = 0; + for(ii=0; ii0.5) + AOconf[loop].activeDMcnt++; + + printf(" AOconf[loop].activeWFScnt = %ld\n", AOconf[loop].activeWFScnt ); + printf(" AOconf[loop].activeDMcnt = %ld\n", AOconf[loop].activeDMcnt ); + + + AOconf[loop].init_RM = 0; + if(sprintf(fname, "conf/shmim_respM.fits") < 1) + printERROR(__FILE__, __func__, __LINE__, "sprintf wrote <1 char"); + + aoconfID_respM = AOloopControl_IOtools_3Dloadcreate_shmim(AOconf[loop].respMname, fname, AOconf[loop].sizexWFS, AOconf[loop].sizeyWFS, AOconf[loop].NBDMmodes, 0.0); + AOconf[loop].init_RM = 1; + + + + AOconf[loop].init_CM = 0; + if(sprintf(fname, "conf/shmim_contrM.fits") < 1) + printERROR(__FILE__, __func__, __LINE__, "sprintf wrote <1 char"); + + aoconfID_contrM = AOloopControl_IOtools_3Dloadcreate_shmim(AOconf[loop].contrMname, fname, AOconf[loop].sizexWFS, AOconf[loop].sizeyWFS, AOconf[loop].NBDMmodes, 0.0); + AOconf[loop].init_CM = 1; + + if((fp=fopen("conf/param_NBmodeblocks.txt", "r"))==NULL) + { + printf("Cannot open conf/param_NBmodeblocks.txt.... assuming 1 block\n"); + AOconf[loop].DMmodesNBblock = 1; + } + else + { + if(fscanf(fp, "%50ld", &tmpl) == 1) + AOconf[loop].DMmodesNBblock = tmpl; + else + { + printf("Cannot read conf/param_NBmodeblocks.txt.... assuming 1 block\n"); + AOconf[loop].DMmodesNBblock = 1; + } + fclose(fp); + } + + + + if(sprintf(name, "aol%ld_contrMc", loop) < 1) + printERROR(__FILE__, __func__, __LINE__, "sprintf wrote <1 char"); + if(sprintf(fname, "conf/shmim_contrMc.fits") < 1) + printERROR(__FILE__, __func__, __LINE__, "sprintf wrote <1 char"); + aoconfID_contrMc = AOloopControl_IOtools_3Dloadcreate_shmim(name, fname, AOconf[loop].sizexWFS, AOconf[loop].sizeyWFS, AOconf[loop].sizeDM, 0.0); + + if(sprintf(name, "aol%ld_contrMcact", loop) < 1) + printERROR(__FILE__, __func__, __LINE__, "sprintf wrote <1 char"); + if(sprintf(fname, "conf/shmim_contrMcact_00.fits") < 1) + printERROR(__FILE__, __func__, __LINE__, "sprintf wrote <1 char"); + aoconfID_contrMcact[0] = AOloopControl_IOtools_2Dloadcreate_shmim(name, fname, AOconf[loop].activeWFScnt, AOconf[loop].activeDMcnt, 0.0); + + + + + if(sprintf(name, "aol%ld_gainb", loop) < 1) + printERROR(__FILE__, __func__, __LINE__, "sprintf wrote <1 char"); + if(sprintf(fname, "conf/shmim_gainb.fits") < 1) + printERROR(__FILE__, __func__, __LINE__, "sprintf wrote <1 char"); + + aoconfID_gainb = AOloopControl_IOtools_2Dloadcreate_shmim(name, fname, AOconf[loop].DMmodesNBblock, 1, 0.0); + + if(sprintf(name, "aol%ld_multfb", loop) < 1) + printERROR(__FILE__, __func__, __LINE__, "sprintf wrote <1 char"); + if(sprintf(fname, "conf/shmim_multfb.fits") < 1) + printERROR(__FILE__, __func__, __LINE__, "sprintf wrote <1 char"); + aoconfID_multfb = AOloopControl_IOtools_2Dloadcreate_shmim(name, fname, AOconf[loop].DMmodesNBblock, 1, 0.0); + + if(sprintf(name, "aol%ld_limitb", loop) < 1) + printERROR(__FILE__, __func__, __LINE__, "sprintf wrote <1 char"); + if(sprintf(fname, "conf/shmim_limitb.fits") < 1) + printERROR(__FILE__, __func__, __LINE__, "sprintf wrote <1 char"); + aoconfID_limitb = AOloopControl_IOtools_2Dloadcreate_shmim(name, fname, AOconf[loop].DMmodesNBblock, 1, 0.0); + + +#ifdef _PRINT_TEST + printf("TEST - INITIALIZE contrMc, contrMcact\n"); + fflush(stdout); +#endif + + + uint_fast16_t kk; + int mstart = 0; + + for(kk=0; kk creating file\n", AOconfname); + create = 1; + } + else + { + fstat(SM_fd, &file_stat); + printf("File %s size: %zd\n", AOconfname, file_stat.st_size); + if(file_stat.st_size!=sizeof(AOLOOPCONTROL_CONF)*NB_AOloopcontrol) + { + printf("File \"%s\" size is wrong -> recreating file\n", AOconfname); + create = 1; + close(SM_fd); + } + } + + if(create==1) + { + int result; + + SM_fd = open(AOconfname, O_RDWR | O_CREAT | O_TRUNC, (mode_t)0600); + + if (SM_fd == -1) { + perror("Error opening file for writing"); + exit(0); + } + + result = lseek(SM_fd, sizeof(AOLOOPCONTROL_CONF)*NB_AOloopcontrol-1, SEEK_SET); + if (result == -1) { + close(SM_fd); + perror("Error calling lseek() to 'stretch' the file"); + exit(0); + } + + result = write(SM_fd, "", 1); + if (result != 1) { + close(SM_fd); + perror("Error writing last byte of the file"); + exit(0); + } + } + + + + + AOconf = (AOLOOPCONTROL_CONF*) mmap(0, sizeof(AOLOOPCONTROL_CONF)*NB_AOloopcontrol, PROT_READ | PROT_WRITE, MAP_SHARED, SM_fd, 0); + if (AOconf == MAP_FAILED) { + close(SM_fd); + perror("Error mmapping the file"); + exit(0); + } + + + + + if((mode==0)||(create==1)) + { + char cntname[200]; + + AOconf[loop].on = 0; + AOconf[loop].DMprimaryWriteON = 0; + AOconf[loop].DMfilteredWriteON = 0; + AOconf[loop].AUTOTUNE_LIMITS_ON = 0; + AOconf[loop].AUTOTUNE_GAINS_ON = 0; + AOconf[loop].ARPFon = 0; + AOconf[loop].cnt = 0; + AOconf[loop].cntmax = 0; + AOconf[loop].init_CMc = 0; + + if(sprintf(cntname, "aol%ld_logdata", loop) < 1) // contains loop count (cnt0) and loop gain + printERROR(__FILE__, __func__, __LINE__, "sprintf wrote <1 char"); + + if((aoconfIDlogdata = image_ID(cntname))==-1) + { + uint32_t *sizearray; + sizearray = (uint32_t*) malloc(sizeof(uint32_t)*2); + sizearray[0] = 1; + sizearray[1] = 1; + aoconfIDlogdata = create_image_ID(cntname, 2, sizearray, _DATATYPE_FLOAT, 1, 0); + free(sizearray); + } + } + + + if(create==1) + { + for(loop=0; loop 1) // drive semaphore #1 to zero + while(sem_trywait(data.image[IDzpdm].semptr[1])==0) {} + else + { + printf("ERROR: semaphore #1 missing from image %s\n", IDzpdm_name); + exit(0); + } + + while(data.signal_USR1==0) + { + memset(data.image[IDtmp].array.F, '\0', sizeof(float)*wfsxysize); + + while(zpcnt0 == data.image[IDzpdm].md[0].cnt0) + usleep(10); + + zpcnt0 = data.image[IDzpdm].md[0].cnt0; + + // TO BE DONE + // sem_wait(data.image[IDzpdm].semptr[1]); + + + printf("WFS zero point offset update # %8ld (%s -> %s) ", zpcnt, data.image[IDzpdm].name, data.image[IDwfszp].name); + fflush(stdout); + + + clock_gettime(CLOCK_REALTIME, &t1); + +# ifdef _OPENMP + #pragma omp parallel for private(elem) +# endif + for(act=0; act sum all channels to update WFS zero point +// runs in separate process from RT computation +// +// +// +int_fast8_t AOloopControl_WFSzeropoint_sum_update_loop(long loopnb, const char *ID_WFSzp_name, int NBzp, const char *IDwfsref0_name, const char *IDwfsref_name) +{ + long wfsxsize, wfsysize, wfsxysize; + long IDwfsref, IDwfsref0; + long *IDwfszparray; + long cntsumold; + int RT_priority = 95; //any number from 0-99 + struct sched_param schedpar; + long nsecwait = 10000; // 10 us + struct timespec semwaitts; + long ch; + long IDtmp; + long ii; + char name[200]; + int semval; + + + + schedpar.sched_priority = RT_priority; +#ifndef __MACH__ + if(seteuid(euid_called) != 0) //This goes up to maximum privileges + printERROR(__FILE__, __func__, __LINE__, "seteuid() returns non-zero value"); + + sched_setscheduler(0, SCHED_FIFO, &schedpar); //other option is SCHED_RR, might be faster + + if(seteuid(euid_real) != 0) //Go back to normal privileges + printERROR(__FILE__, __func__, __LINE__, "seteuid() returns non-zero value"); +#endif + + IDwfsref = image_ID(IDwfsref_name); + wfsxsize = data.image[IDwfsref].md[0].size[0]; + wfsysize = data.image[IDwfsref].md[0].size[1]; + wfsxysize = wfsxsize*wfsysize; + IDtmp = create_2Dimage_ID("wfsrefoffset", wfsxsize, wfsysize); + IDwfsref0 = image_ID(IDwfsref0_name); + + if(data.image[IDwfsref].md[0].sem > 1) // drive semaphore #1 to zero + while(sem_trywait(data.image[IDwfsref].semptr[1])==0) {} + else + { + printf("ERROR: semaphore #1 missing from image %s\n", IDwfsref_name); + exit(0); + } + + IDwfszparray = (long*) malloc(sizeof(long)*NBzp); + // create / read the zero point WFS channels + for(ch=0; ch= 1000000000) + semwaitts.tv_sec = semwaitts.tv_sec + 1; + + sem_timedwait(data.image[IDwfsref].semptr[1], &semwaitts); + + long cntsum = 0; + for(ch=0; ch PIXSTREAM_NBSLICES) + PIXSTREAM_NBSLICES = data.image[aoconfID_pixstream_wfspixindex].array.UI16[ii]; + PIXSTREAM_NBSLICES++; + printf("PIXEL STREAMING: %d image slices\n", PIXSTREAM_NBSLICES); + } + + + + printf("============ FORCE pixel streaming = 0\n"); + fflush(stdout); + COMPUTE_PIXELSTREAMING = 0; // TEST + + + printf("GPU0 = %d\n", AOconf[loop].GPU0); + if(AOconf[loop].GPU0>1) + { + uint8_t k; + for(k=0; k1) + { + uint8_t k; + for(k=0; k mode coeffs -> DM act + { +#ifdef _PRINT_TEST + printf("TEST - DMprimaryWriteON = %d\n", AOconf[loop].DMprimaryWriteON); + fflush(stdout); +#endif + + if(AOconf[loop].DMprimaryWriteON==1) // if Writing to DM + { +#ifdef _PRINT_TEST + printf("TEST - gain = %f\n", AOconf[loop].gain); + fflush(stdout); +#endif + + if(fabs(AOconf[loop].gain)>1.0e-6) + set_DM_modes(loop); + } + + } + else // 1 step: WFS -> DM act + { + if(AOconf[loop].DMprimaryWriteON==1) // if Writing to DM + { + data.image[aoconfID_dmC].md[0].write = 1; + + for(ii=0; ii replacing by 0\n", ii); + data.image[aoconfID_meas_act].array.F[ii] = 0.0; + } + } + + + + + AOconf[loop].status = 13; // enforce limits + clock_gettime(CLOCK_REALTIME, &tnow); + tdiff = info_time_diff(data.image[aoconfID_looptiming].md[0].atime.ts, tnow); + tdiffv = 1.0*tdiff.tv_sec + 1.0e-9*tdiff.tv_nsec; + data.image[aoconfID_looptiming].array.F[13] = tdiffv; + + + for(ii=0; ii AOconf[loop].maxlimit) + data.image[aoconfID_dmC].array.F[ii] = AOconf[loop].maxlimit; + if(data.image[aoconfID_dmC].array.F[ii] < -AOconf[loop].maxlimit) + data.image[aoconfID_dmC].array.F[ii] = -AOconf[loop].maxlimit; + } + + + AOconf[loop].status = 14; // write to DM + clock_gettime(CLOCK_REALTIME, &tnow); + tdiff = info_time_diff(data.image[aoconfID_looptiming].md[0].atime.ts, tnow); + tdiffv = 1.0*tdiff.tv_sec + 1.0e-9*tdiff.tv_nsec; + data.image[aoconfID_looptiming].array.F[14] = tdiffv; + + + + int semnb; + for(semnb=0; semnb 1) + { + sem_getvalue(data.image[aoconfID_dmdisp].semptr[0], &semval); + if(semval 0) + { + sem_getvalue(data.image[aoconfID_dmC].semptr[0], &semval); + if(semval 1) + { + sem_getvalue(data.image[aoconfID_dmdisp].semptr[1], &semval); + if(semval %d\n", slice, PIXSTREAM_SLICE); + // fflush(stdout); + + AOconf[loop].status = 4; // 4: REMOVING REF + clock_gettime(CLOCK_REALTIME, &tnow); + tdiff = info_time_diff(data.image[aoconfID_looptiming].md[0].atime.ts, tnow); + tdiffv = 1.0*tdiff.tv_sec + 1.0e-9*tdiff.tv_nsec; + data.image[aoconfID_looptiming].array.F[4] = tdiffv; + + + if(AOconf[loop].GPUall==0) + { + data.image[aoconfID_imWFS2].md[0].write = 1; + for(ii=0; ii MODE VALUES + clock_gettime(CLOCK_REALTIME, &tnow); + tdiff = info_time_diff(data.image[aoconfID_looptiming].md[0].atime.ts, tnow); + tdiffv = 1.0*tdiff.tv_sec + 1.0e-9*tdiff.tv_nsec; + data.image[aoconfID_looptiming].array.F[5] = tdiffv; + + + if(AOconf[loop].initmapping == 0) // compute combined control matrix or matrices + { + printf("COMPUTING MAPPING ARRAYS .... \n"); + fflush(stdout); + + clock_gettime(CLOCK_REALTIME, &t1); + + // + // There is one mapping array per WFS slice + // WFS slice 0 = all active pixels + // + WFS_active_map = (int*) malloc(sizeof(int)*AOconf[loop].sizeWFS*PIXSTREAM_NBSLICES); + if(aoconfID_wfsmask != -1) + { + for(slice=0; slice0.1) + { + if(slice==0) + { + WFS_active_map[slice*AOconf[loop].sizeWFS+ii1] = ii; + ii1++; + } + else if (data.image[aoconfID_pixstream_wfspixindex].array.UI16[ii]==slice+1) + { + WFS_active_map[slice*AOconf[loop].sizeWFS+ii1] = ii; + ii1++; + } + } + AOconf[loop].sizeWFS_active[slice] = ii1; + + char imname[200]; + if(sprintf(imname, "aol%ld_imWFS2active_%02d", LOOPNUMBER, slice) < 1) + printERROR(__FILE__, __func__, __LINE__, "sprintf wrote <1 char"); + + uint32_t *sizearray; + sizearray = (uint32_t*) malloc(sizeof(uint32_t)*2); + sizearray[0] = AOconf[loop].sizeWFS_active[slice]; + sizearray[1] = 1; + aoconfID_imWFS2_active[slice] = create_image_ID(imname, 2, sizearray, _DATATYPE_FLOAT, 1, 0); + free(sizearray); + //aoconfID_imWFS2_active[slice] = create_2Dimage_ID(imname, AOconf[loop].sizeWFS_active[slice], 1); + } + } + else + { + printf("ERROR: aoconfID_wfsmask = -1\n"); + fflush(stdout); + exit(0); + } + + + + // create DM active map + DM_active_map = (int*) malloc(sizeof(int)*AOconf[loop].sizeDM); + if(aoconfID_dmmask != -1) + { + long ii1 = 0; + for(ii=0; ii0.5) + { + DM_active_map[ii1] = ii; + ii1++; + } + AOconf[loop].sizeDM_active = ii1; + } + + + + uint32_t *sizearray; + sizearray = (uint32_t*) malloc(sizeof(uint32_t)*2); + sizearray[0] = AOconf[loop].sizeDM_active; + sizearray[1] = 1; + + char imname[200]; + if(sprintf(imname, "aol%ld_meas_act_active", LOOPNUMBER) < 1) + printERROR(__FILE__, __func__, __LINE__, "sprintf wrote <1 char"); + + aoconfID_meas_act_active = create_image_ID(imname, 2, sizearray, _DATATYPE_FLOAT, 1, 0); + free(sizearray); + + + + if(aoconfID_meas_act==-1) + { + sizearray = (uint32_t*) malloc(sizeof(uint32_t)*2); + sizearray[0] = AOconf[loop].sizexDM; + sizearray[1] = AOconf[loop].sizeyDM; + + if(sprintf(imname, "aol%ld_meas_act", LOOPNUMBER) < 1) + printERROR(__FILE__, __func__, __LINE__, "sprintf wrote <1 char"); + + aoconfID_meas_act = create_image_ID(imname, 2, sizearray, _DATATYPE_FLOAT, 1, 0); + COREMOD_MEMORY_image_set_createsem(imname, 10); + free(sizearray); + } + + clock_gettime(CLOCK_REALTIME, &t2); + tdiff = info_time_diff(t1, t2); + tdiffv = 1.0*tdiff.tv_sec + 1.0e-9*tdiff.tv_nsec; + printf("\n"); + printf("TIME TO COMPUTE MAPPING ARRAYS = %f sec\n", tdiffv); + AOconf[loop].initmapping = 1; + } + + + + + if(AOconf[loop].GPU0 == 0) // run in CPU + { + if(AOconf[loop].CMMODE==0) // goes explicitely through modes, slower but required for access to mode values + { +#ifdef _PRINT_TEST + printf("TEST - CM mult: GPU=0, CMMODE=0 - %s x %s -> %s\n", data.image[aoconfID_contrM].md[0].name, data.image[aoconfID_imWFS2].md[0].name, data.image[aoconfID_meas_modes].md[0].name); + fflush(stdout); +#endif + + data.image[aoconfID_meas_modes].md[0].write = 1; + ControlMatrixMultiply( data.image[aoconfID_contrM].array.F, data.image[aoconfID_imWFS2].array.F, AOconf[loop].NBDMmodes, AOconf[loop].sizeWFS, data.image[aoconfID_meas_modes].array.F); + COREMOD_MEMORY_image_set_sempost_byID(aoconfID_meas_modes, -1); + data.image[aoconfID_meas_modes].md[0].cnt0 ++; + data.image[aoconfID_meas_modes].md[0].write = 0; + } + else // (*) + { +#ifdef _PRINT_TEST + printf("TEST - CM mult: GPU=0, CMMODE=1 - using matrix %s\n", data.image[aoconfID_contrMc].md[0].name); + fflush(stdout); +#endif + + data.image[aoconfID_meas_modes].md[0].write = 1; + ControlMatrixMultiply( data.image[aoconfID_contrMc].array.F, data.image[aoconfID_imWFS2].array.F, AOconf[loop].sizeDM, AOconf[loop].sizeWFS, data.image[aoconfID_meas_act].array.F); + data.image[aoconfID_meas_modes].md[0].cnt0 ++; + COREMOD_MEMORY_image_set_sempost_byID(aoconfID_meas_modes, -1); + data.image[aoconfID_meas_modes].md[0].cnt0 ++; + data.image[aoconfID_meas_modes].md[0].write = 0; + } + } + else + { +#ifdef HAVE_CUDA + if(AOconf[loop].CMMODE==0) // goes explicitely through modes, slower but required for access to mode values + { +#ifdef _PRINT_TEST + printf("TEST - CM mult: GPU=1, CMMODE=0 - using matrix %s GPU alpha beta = %f %f\n", data.image[aoconfID_contrM].md[0].name, GPU_alpha, GPU_beta); + fflush(stdout); +#endif + + initWFSref_GPU[PIXSTREAM_SLICE] = 1; // default: do not re-compute reference output + + if(AOconf[loop].GPUall == 1) + { + // TEST IF contrM or wfsref have changed + if((data.image[aoconfID_wfsref].md[0].cnt0 != aoconfcnt0_wfsref_current) || (data.image[aoconfID_contrM].md[0].cnt0 != aoconfcnt0_contrM_current)) + { + printf("NEW wfsref [%10ld] or contrM [%10ld]\n", data.image[aoconfID_wfsref].md[0].cnt0, data.image[aoconfID_contrM].md[0].cnt0); + aoconfcnt0_wfsref_current = data.image[aoconfID_wfsref].md[0].cnt0; + aoconfcnt0_contrM_current = data.image[aoconfID_contrM].md[0].cnt0; + initWFSref_GPU[PIXSTREAM_SLICE] = 0; + } + + + if(initWFSref_GPU[PIXSTREAM_SLICE]==0) // initialize WFS reference + { +#ifdef _PRINT_TEST + printf("\nINITIALIZE WFS REFERENCE: COPY NEW REF (WFSREF) TO imWFS0\n"); //TEST + fflush(stdout); +#endif + + data.image[aoconfID_imWFS0].md[0].write = 1; + // TBD: replace by memcpy + for(wfselem=0; wfselem actuators linear transformation + { +#ifdef _PRINT_TEST + printf("TEST - CM mult: GPU=1, CMMODE=1\n"); + fflush(stdout); +#endif + + // depreciated: use all pixels +/* if(1==0) + { + GPU_loop_MultMat_setup(0, data.image[aoconfID_contrMc].name, data.image[aoconfID_imWFS2].name, data.image[aoconfID_meas_act].name, AOconf[loop].GPU0, GPUset0, 0, AOconf[loop].GPUusesem, 1, loop); + AOconf[loop].status = 6; + clock_gettime(CLOCK_REALTIME, &tnow); + tdiff = info_time_diff(data.image[aoconfID_looptiming].md[0].atime.ts, tnow); + tdiffv = 1.0*tdiff.tv_sec + 1.0e-9*tdiff.tv_nsec; + data.image[aoconfID_looptiming].array.F[6] = tdiffv; + + GPU_loop_MultMat_execute(0, &AOconf[loop].status, &AOconf[loop].GPUstatus[0], 1.0, 0.0, 1); + } + else // only use active pixels and actuators (**) + {*/ + + // re-map input vector into imWFS2_active + + if(AOconf[loop].GPUall == 1) // (**) + { +#ifdef _PRINT_TEST + printf("TEST - CM mult: GPU=1, CMMODE=1, GPUall = 1\n"); + fflush(stdout); +#endif + + data.image[aoconfID_imWFS2_active[PIXSTREAM_SLICE]].md[0].write = 1; + for(wfselem_active=0; wfselem_active RECOMPUTE REFERENCE x MATRIX\n", data.image[aoconfID_contrMcact[PIXSTREAM_SLICE]].md[0].name); + fflush(stdout); + + initWFSref_GPU[PIXSTREAM_SLICE] = 0; + contrMcactcnt0[PIXSTREAM_SLICE] = data.image[aoconfID_contrMcact[PIXSTREAM_SLICE]].md[0].cnt0; + } + + if(data.image[aoconfID_wfsref].md[0].cnt0 != wfsrefcnt0) // (*) + { + printf("NEW REFERENCE WFS DETECTED (%s) [ %ld %ld ]\n", data.image[aoconfID_wfsref].md[0].name, data.image[aoconfID_wfsref].md[0].cnt0, wfsrefcnt0); + fflush(stdout); + + initWFSref_GPU[PIXSTREAM_SLICE] = 0; + wfsrefcnt0 = data.image[aoconfID_wfsref].md[0].cnt0; + } + if(initWFSref_GPU[PIXSTREAM_SLICE]==0) // initialize WFS reference + { + printf("\nINITIALIZE WFS REFERENCE: COPY NEW REF (WFSREF) TO imWFS2_active\n"); //TEST + fflush(stdout); + data.image[aoconfID_imWFS2_active[PIXSTREAM_SLICE]].md[0].write = 1; + for(wfselem_active=0; wfselem_active limitval) + data.image[aoconfID_cmd_modes].array.F[k] = limitval; + + + // apply mult factor + + data.image[aoconfID_cmd_modes].array.F[k] *= AOconf[loop].mult * data.image[aoconfID_multfb].array.F[AOconf[loop].modeBlockIndex[k]] * data.image[aoconfID_MULTF_modes].array.F[k]; + + + + // update total gain + // data.image[aoconfID_DMmode_GAIN].array.F[k+AOconf[loop].NBDMmodes] = AOconf[loop].gain * data.image[aoconfID_DMmode_GAIN].array.F[k]; + } + + + data.image[aoconfID_cmd_modes].md[0].cnt0 ++; + } + + return(0); +} + + + + + + + + + + + + +int_fast8_t AOloopControl_CompModes_loop(const char *ID_CM_name, const char *ID_WFSref_name, const char *ID_WFSim_name, const char *ID_WFSimtot_name, const char *ID_coeff_name) +{ +#ifdef HAVE_CUDA + + int *GPUsetM; + long ID_CM; + long ID_WFSref; + long ID_coeff; + long GPUcnt; + int k; + int_fast8_t GPUstatus[100]; + int_fast8_t status; + long NBmodes; + uint32_t *sizearray; + + long ID_WFSim; + long ID_WFSim_n; + long wfsxsize, wfsysize; + int m; + long IDcoeff0; + + long ID_WFSimtot; + double totfluxave; + long ID_coefft; + + double alpha = 0.1; + + + GPUcnt = 2; + + GPUsetM = (int*) malloc(sizeof(int)*GPUcnt); + for(k=0; k using index = 0 +// +// if offloadMode = 1, apply correction to aol#_dmC +// +int_fast8_t AOloopControl_GPUmodecoeffs2dm_filt_loop(const char *modecoeffs_name, const char *DMmodes_name, int semTrigg, const char *out_name, int GPUindex, long loop, int offloadMode) +{ +#ifdef HAVE_CUDA + long IDmodecoeffs; + int GPUcnt, k; + int *GPUsetM; + int_fast8_t GPUstatus[100]; + int_fast8_t status; + float alpha = 1.0; + float beta = 0.0; + int initWFSref = 0; + int orientation = 1; + int use_sem = 1; + long IDout; + int write_timing = 0; + long NBmodes, m; + + float x, x2, x4, x8; + float gamma; + + uint32_t *sizearray; + char imnamecorr[200]; + long IDmodesC; + + long IDc; + long dmxsize, dmysize; + long ii; + + + int RT_priority = 80; //any number from 0-99 + struct sched_param schedpar; + + + + schedpar.sched_priority = RT_priority; +#ifndef __MACH__ + sched_setscheduler(0, SCHED_FIFO, &schedpar); +#endif + + + // read AO loop gain, mult + if(AOloopcontrol_meminit==0) + AOloopControl_InitializeMemory(1); + + + GPUcnt = 1; + GPUsetM = (int*) malloc(sizeof(int)*GPUcnt); + for(k=0; k out + + data.image[IDout].md[0].write = 1; + for(ii=0; ii found %2ld modes\n", n); + blockNBmodes[blk] = n; + + for(i=0; i modelimit[m]) + data.image[aoconfID_LIMIT_modes].array.F[m] *= (1.0 + AOconf[loop].AUTOTUNE_LIMITS_delta); + else + data.image[aoconfID_LIMIT_modes].array.F[m] *= (1.0 - AOconf[loop].AUTOTUNE_LIMITS_delta*0.01*AOconf[loop].AUTOTUNE_LIMITS_perc); + + limitblockarray[block] += data.image[aoconfID_LIMIT_modes].array.F[m]; + } + COREMOD_MEMORY_image_set_sempost_byID(aoconfID_LIMIT_modes, -1); + data.image[aoconfID_LIMIT_modes].md[0].cnt0++; + data.image[aoconfID_LIMIT_modes].md[0].write = 0; + + // update block limits to drive average limit coefficients to 1 + data.image[IDatlimbcoeff].md[0].write = 1; + for(block=0; block 1.0+AOconf[loop].AUTOTUNE_LIMITS_delta ) + coeff = 1.0+AOconf[loop].AUTOTUNE_LIMITS_delta; + data.image[aoconfID_limitb].array.F[block] = data.image[aoconfID_limitb].array.F[block] * coeff; + } + COREMOD_MEMORY_image_set_sempost_byID(IDatlimbcoeff, -1); + data.image[IDatlimbcoeff].md[0].cnt0++; + data.image[IDatlimbcoeff].md[0].write = 0; + + + COREMOD_MEMORY_image_set_sempost_byID(aoconfID_limitb, -1); + data.image[aoconfID_limitb].md[0].cnt0++; + data.image[aoconfID_limitb].md[0].write = 0; + + } + + if(AOconf[loop].AUTOTUNE_GAINS_ON==1) + { + // CONNECT to auto gain input + if(IDautogain == -1) + { + if(sprintf(imname, "aol%ld_autogain", loop) < 1) + printERROR(__FILE__, __func__, __LINE__, "sprintf wrote <1 char"); + + IDautogain = read_sharedmem_image(imname); + } + + if(IDautogain != -1) + { + if(data.image[IDautogain].md[0].cnt0 != autogainCnt) + { + float maxGainVal = 0.0; + float globalgain = 0.0; + char command[500]; + + // New gains available - updating + printf("[%ld %s] Updated autogain [%12ld %12ld] -> applying gains\n", IDautogain, data.image[IDautogain].md[0].name, (long) autogainCnt, (long) data.image[IDautogain].md[0].cnt0); + fflush(stdout); + + // Set global gain to highest gain + for(m=0;m maxGainVal) + maxGainVal = data.image[IDautogain].array.F[m]; + } + globalgain = maxGainVal; + printf(" Setting global gain = %f\n", maxGainVal); + AOconf[loop].gain = maxGainVal; + + sprintf(command, "echo \"%6.4f\" > conf/param_loopgain.txt", AOconf[loop].gain); + system(command); + + + + // Set block gain to max gain within block, scaled to global gain + for(block=0; block maxGainVal) + maxGainVal = data.image[IDautogain].array.F[m]; + + printf("Set block %2ld gain to %f\n", block, maxGainVal/globalgain); + + data.image[aoconfID_gainb].array.F[block] = maxGainVal/AOconf[loop].gain; + + + sprintf(command, "echo \"%6.4f\" > conf/param_gainb%02ld.txt", data.image[aoconfID_gainb].array.F[block], block); + system(command); + } + + // Set individual gain + for(m=0;m %12f %12f\n", m, AOconf[loop].gain, data.image[aoconfID_gainb].array.F[modeblock[m]], data.image[aoconfID_DMmode_GAIN].array.F[m], AOconf[loop].gain*data.image[aoconfID_gainb].array.F[modeblock[m]]*data.image[aoconfID_DMmode_GAIN].array.F[m], data.image[IDautogain].array.F[m]); + } + + + + autogainCnt = data.image[IDautogain].md[0].cnt0; + } + + } + + + +/* float alphagain = 0.1; + + // if update available + + data.image[aoconfID_GAIN_modes].md[0].write = 1; + data.image[aoconfID_gaiinb].md[0].write = 1; + + // Adjust gain for EACH mode + + for(m=0; m 1.0+AOconf[loop].AUTOTUNE_LIMITS_delta ) + coeff = 1.0+AOconf[loop].AUTOTUNE_LIMITS_delta; + data.image[aoconfID_limitb].array.F[block] = data.image[aoconfID_limitb].array.F[block] * coeff; + } + COREMOD_MEMORY_image_set_sempost_byID(IDatlimbcoeff, -1); + data.image[IDatlimbcoeff].md[0].cnt0++; + data.image[IDatlimbcoeff].md[0].write = 0; + + + COREMOD_MEMORY_image_set_sempost_byID(aoconfID_limitb, -1); + data.image[aoconfID_limitb].md[0].cnt0++; + data.image[aoconfID_limitb].md[0].write = 0; + */ + } + + + + if(FILTERMODE == 1) + { + for(m=0; m modelimit[m]) + { + blockavelimFrac[block] += 1.0; + data.image[IDmodevalDMnowfilt].array.F[m] = modelimit[m]; + } + if(data.image[IDmodevalDMnowfilt].array.F[m] < -modelimit[m]) + { + blockavelimFrac[block] += 1.0; + data.image[IDmodevalDMnowfilt].array.F[m] = -modelimit[m]; + } + } + } + + + + COREMOD_MEMORY_image_set_sempost_byID(IDmodevalDMnow, -1); + data.image[IDmodevalDMnow].md[0].cnt1 = modevalDMindex; + data.image[IDmodevalDMnow].md[0].cnt0++; + data.image[IDmodevalDMnow].md[0].write = 0; + + if(AOconf[loop].DMfilteredWriteON==1) + COREMOD_MEMORY_image_set_sempost_byID(IDmodevalDMnowfilt, -1); + else + { + // DM write triggered by sem 2 + // posting all sems except 2 to block DM write + COREMOD_MEMORY_image_set_sempost_excl_byID(IDmodevalDMnowfilt, 2); + } + data.image[IDmodevalDMnowfilt].md[0].cnt1 = modevalDMindex; + data.image[IDmodevalDMnowfilt].md[0].cnt0++; + data.image[IDmodevalDMnowfilt].md[0].write = 0; + + // IF MODAL DM, AND FILTERED DM WRITE IS ON, SEND TO DM + if((AOconf[loop].DMfilteredWriteON==1) && (AOconf[loop].DMMODE==1)) + { + data.image[aoconfID_dmC].md[0].write = 1; + memcpy(data.image[aoconfID_dmC].array.F, data.image[IDmodevalDMnowfilt].array.F, sizeof(float)*NBmodes); + COREMOD_MEMORY_image_set_sempost_byID(aoconfID_dmC, -1); + data.image[aoconfID_dmC].md[0].cnt1++; + data.image[aoconfID_dmC].md[0].cnt0++; + data.image[aoconfID_dmC].md[0].write = 0; + } + + + AOconf[loop].statusM = 6; + + // + // update current location of dm correction circular buffer + // + data.image[IDmodevalDM_C].md[0].write = 1; + for(m=0; mcntstart) + { + ave0[m] += data.image[IDmodevalOL].array.F[m]; + sig0[m] += data.image[IDmodevalOL].array.F[m]*data.image[IDmodevalOL].array.F[m]; + sig1[m] += diff1*diff1; + sig2[m] += diff2*diff2; + sig3[m] += diff3*diff3; + sig4[m] += diff4*diff4; + } + } + + if(TESTMODE==1) + fprintf(fptest, "%5lld %+12.10f %+12.10f %+12.10f %+12.10f %+12.10f\n", cnt, data.image[IDmodeval].array.F[TEST_m], data.image[IDmodevalOL].array.F[TEST_m], data.image[IDmodeval_dm].array.F[TEST_m], data.image[IDmodeval_dm_now].array.F[TEST_m], data.image[IDmodeval_dm_now_filt].array.F[TEST_m]); + + cnt++; + } + if(TESTMODE==1) + fclose(fptest); + + + + GainCoeff1 = 1.0/(iter+1); + if(GainCoeff1 < AOconf[loop].AUTOTUNEGAINS_updateGainCoeff) + GainCoeff1 = AOconf[loop].AUTOTUNEGAINS_updateGainCoeff; + + + data.image[IDout].md[0].write = 1; + for(m=0; m %8.6f\n", iter, AOconf[loop].AUTOTUNEGAINS_NBsamples, AOconf[loop].AUTOTUNEGAINS_updateGainCoeff, GainCoeff1); + + iter++; + + } + + free(gainval_array); + free(gainval1_array); + free(gainval2_array); + free(errarray); + + free(array_mvalOL1); + free(array_mvalOL2); + free(array_mvalOL3); + free(array_mvalOL4); + free(ave0); + free(sig0); + free(sig1); + free(sig2); + free(sig3); + free(sig4); + free(array_sig1); + free(array_sig2); + free(array_sig3); + free(array_sig4); + free(array_sig); + free(array_asq); + + free(modegain); + free(modemult); + free(NOISEfactor); + + free(stdev); + + return(0); +} + + + + + + + + + + +long AOloopControl_dm2dm_offload(const char *streamin, const char *streamout, float twait, float offcoeff, float multcoeff) +{ + long IDin, IDout; + long cnt = 0; + long xsize, ysize, xysize; + long ii; + //long IDtmp; + + + IDin = image_ID(streamin); + IDout = image_ID(streamout); + + xsize = data.image[IDin].md[0].size[0]; + ysize = data.image[IDin].md[0].size[1]; + xysize = xsize*ysize; + + while(1) + { + printf("%8ld : offloading %s -> %s\n", cnt, streamin, streamout); + + data.image[IDout].md[0].write = 1; + for(ii=0; ii-1)) + data.image[aoconfID_gainb].array.F[blocknb] = gain; + + + if(add==1) + { + long IDcontrMc0; // local storage + long IDcontrMcact0; // local storage + + + IDcontrMc0 = image_ID("contrMc0"); + if(IDcontrMc0==-1) + IDcontrMc0 = create_3Dimage_ID("contrMc0", AOconf[loop].sizexWFS, AOconf[loop].sizeyWFS, AOconf[loop].sizexDM*AOconf[loop].sizeyDM); + + + IDcontrMcact0 = image_ID("contrMcact0"); + if(IDcontrMcact0==-1) + IDcontrMcact0 = create_2Dimage_ID("contrMcact0", AOconf[loop].activeWFScnt, AOconf[loop].activeDMcnt); + + //arith_image_zero("contrM0"); + arith_image_zero("contrMc0"); + arith_image_zero("contrMcact0"); + + + for(kk=0; kkeps) + { + long ii; + + ID = image_ID(name2); +# ifdef _OPENMP + #pragma omp parallel for +# endif + for(ii=0; ii%f (%ld septs)\n", NBblock, NBstep, gainStart, gainEnd, NBgain); + + for(kg=0; kgtm_year, 1+uttime->tm_mon, uttime->tm_mday, uttime->tm_hour, uttime->tm_min, uttime->tm_sec) < 1) + printERROR(__FILE__, __func__, __LINE__, "sprintf wrote <1 char"); + + if((fp=fopen(flogname,"w"))==NULL) + { + printf("ERROR: cannot create file \"%s\"\n", flogname); + exit(0); + } + fclose(fp); + + + dmframesize = sizeof(float)*dmsize; + wfsframesize = sizeof(float)*wfssize; + + list_image_ID(); + + + + if (sigaction(SIGINT, &data.sigact, NULL) == -1) { + perror("sigaction"); + exit(EXIT_FAILURE); + } + if (sigaction(SIGTERM, &data.sigact, NULL) == -1) { + perror("sigaction"); + exit(EXIT_FAILURE); + } + if (sigaction(SIGBUS, &data.sigact, NULL) == -1) { + perror("sigaction"); + exit(EXIT_FAILURE); + } + /* if (sigaction(SIGSEGV, &data.sigact, NULL) == -1) { + perror("sigaction"); + exit(EXIT_FAILURE); + }*/ + if (sigaction(SIGABRT, &data.sigact, NULL) == -1) { + perror("sigaction"); + exit(EXIT_FAILURE); + } + if (sigaction(SIGHUP, &data.sigact, NULL) == -1) { + perror("sigaction"); + exit(EXIT_FAILURE); + } + if (sigaction(SIGPIPE, &data.sigact, NULL) == -1) { + perror("sigaction"); + exit(EXIT_FAILURE); + } + + + + k = 0; + loopOK = 1; + + while(loopOK == 1) + { + printf("Applying probe # %d %ld %ld\n", k, IDdmstream, IDwfsrefstream); + fflush(stdout); + + // apply probe + char *ptr0; + ptr0 = (char*) data.image[IDdmC].array.F; + ptr0 += k*dmframesize; + data.image[IDdmstream].md[0].write = 1; + memcpy(data.image[IDdmstream].array.F, (void*) ptr0, dmframesize); + sem_getvalue(data.image[IDdmstream].semptr[0], &semval); + if(semvaltm_hour, uttime->tm_min, uttime->tm_sec, thetime->tv_nsec) < 1) + printERROR(__FILE__, __func__, __LINE__, "sprintf wrote <1 char"); + + printf("time = %s\n", timestr); + if((fp = fopen(flogname, "a"))==NULL) + { + printf("ERROR: cannot open file \"%s\"\n", flogname); + exit(0); + } + fprintf(fp, "%s %2d %10f %10f\n", timestr, k, coeffA[k], coeffB[k]); + fclose(fp); + + usleep((long) (1.0e6*delay)); + k++; + if(k==NBprobes) + k = 0; + + if((data.signal_INT == 1)||(data.signal_TERM == 1)||(data.signal_ABRT==1)||(data.signal_BUS==1)||(data.signal_SEGV==1)||(data.signal_HUP==1)||(data.signal_PIPE==1)) + loopOK = 0; + } + + data.image[IDdmstream].md[0].write = 1; + for(ii=0; iiAOconf[LOOPNUMBER].NBDMmodes) + kmax = AOconf[LOOPNUMBER].NBDMmodes-1; + + for(k=m0; kAOconf[LOOPNUMBER].NBDMmodes) + kmax = AOconf[LOOPNUMBER].NBDMmodes-1; + + for(k=m0; kAOconf[LOOPNUMBER].NBDMmodes) + kmax = AOconf[LOOPNUMBER].NBDMmodes-1; + + for(k=m0; k +#include +#include +#include +#include +#include +#include +#include +#include +#include // needed for tid = syscall(SYS_gettid); + + + +#ifdef __MACH__ +#include +#define CLOCK_REALTIME 0 +#define CLOCK_MONOTONIC 0 +int clock_gettime(int clk_id, struct mach_timespec *t) { + mach_timebase_info_data_t timebase; + mach_timebase_info(&timebase); + uint64_t time; + time = mach_absolute_time(); + double nseconds = ((double)time * (double)timebase.numer)/((double)timebase.denom); + double seconds = ((double)time * (double)timebase.numer)/((double)timebase.denom * 1e9); + t->tv_sec = seconds; + t->tv_nsec = nseconds; + return 0; +} +#else +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +//#include +#include + + +#include +#include +#include +#include +#include + +#include + +#include "CLIcore.h" +#include "00CORE/00CORE.h" +#include "COREMOD_memory/COREMOD_memory.h" +#include "COREMOD_iofits/COREMOD_iofits.h" +#include "COREMOD_tools/COREMOD_tools.h" +#include "COREMOD_arith/COREMOD_arith.h" +#include "linopt_imtools/linopt_imtools.h" +#include "AOloopControl/AOloopControl.h" +#include "image_filter/image_filter.h" +#include "info/info.h" +#include "ZernikePolyn/ZernikePolyn.h" +#include "linopt_imtools/linopt_imtools.h" +#include "image_gen/image_gen.h" +#include "statistic/statistic.h" +#include "fft/fft.h" + + +#include "AOloopControl_IOtools/AOloopControl_IOtools.h" +#include "AOloopControl_PredictiveControl/AOloopControl_PredictiveControl.h" +#include "AOloopControl_acquireCalib/AOloopControl_acquireCalib.h" +#include "AOloopControl_computeCalib/AOloopControl_computeCalib.h" +#include "AOloopControl_perfTest/AOloopControl_perfTest.h" + + + +#ifdef HAVE_CUDA +#include "cudacomp/cudacomp.h" +#endif + +# ifdef _OPENMP +# include +#define OMP_NELEMENT_LIMIT 1000000 +# endif + + + +/* =============================================================================================== */ +/* =============================================================================================== */ +/* DEFINES, MACROS */ +/* =============================================================================================== */ +/* =============================================================================================== */ + + + + + + + +// data passed to each thread +//typedef struct +//{ +// long nelem; +// float *arrayptr; +// float *result; // where to white status +//} THDATA_IMTOTAL; + + + + + + +/* =============================================================================================== */ +/* =============================================================================================== */ +/* GLOBAL DATA DECLARATION */ +/* =============================================================================================== */ +/* =============================================================================================== */ + + + + + +/* =============================================================================================== */ +/* LOGGING ACCESS TO FUNCTIONS */ +/* =============================================================================================== */ + +// uncomment at compilation time to enable logging of function entry/exit +//#define AOLOOPCONTROL_LOGFUNC +static int AOLOOPCONTROL_logfunc_level = 0; +static int AOLOOPCONTROL_logfunc_level_max = 2; // log all levels equal or below this number +static char AOLOOPCONTROL_logfunc_fname[] = "AOloopControl.fcall.log"; +static char flogcomment[200]; + + +// GPU MultMat indexes +// +// 0: main loop CM multiplication +// +// 1: set DM modes: +// int set_DM_modes(long loop) +// +// 2: compute modes loop +// int AOloopControl_CompModes_loop(char *ID_CM_name, char *ID_WFSref_name, char *ID_WFSim_name, char *ID_WFSimtot_name, char *ID_coeff_name) +// +// 3: coefficients to DM shape [ NOTE: CRASHES IF NOT USING index 0 ] +// int AOloopControl_GPUmodecoeffs2dm_filt_loop(char *modecoeffs_name, char *DMmodes_name, int semTrigg, char *out_name, int GPUindex, long loop, int offloadMode) +// +// 4: Predictive control (in modules linARfilterPred) + + + + + + + +// TIMING +static struct timespec tnow; +static struct timespec tdiff; +static double tdiffv; + + + + + + +static int initWFSref_GPU[100] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static int initcontrMcact_GPU[100] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + +float GPU_alpha = 0.0; +float GPU_beta = 0.0; + + +static int COMPUTE_PIXELSTREAMING = 0; // multiple pixel groups +int PIXSTREAM_NBSLICES = 1; // number of image slices (= pixel groups) +int PIXSTREAM_SLICE; // slice index 0 = all pixels + + + + +// static int MATRIX_COMPUTATION_MODE = 0; +// 0: compute sequentially modes and DM commands +// 1: use combined control matrix + + + + + +/* =============================================================================================== */ +/* aoconfID are global variables for convenience */ +/* aoconfID can be used in other modules as well (with extern) */ +/* =============================================================================================== */ + + +// Hardware connections +long aoconfID_wfsim = -1; +uint8_t WFSatype; +long aoconfID_dmC = -1; +long aoconfID_dmRM = -1; + +long aoconfID_wfsdark = -1; +long aoconfID_imWFS0 = -1; +long aoconfID_imWFS0tot = -1; +long aoconfID_imWFS1 = -1; +long aoconfID_imWFS2 = -1; +static long aoconfID_wfsref0 = -1; +long aoconfID_wfsref = -1; +static long long aoconfcnt0_wfsref_current = -1; + +long aoconfID_DMmodes = -1; +static long aoconfID_dmdisp = -1; // to notify DMcomb that DM maps should be summed + + +// Control Modes +long aoconfID_cmd_modes = -1; +long aoconfID_meas_modes = -1; // measured +long aoconfID_RMS_modes = -1; +long aoconfID_AVE_modes = -1; + + + +// mode gains, multf, limit are set in 3 tiers +// global gain +// block gain +// individual gains + +// blocks +long aoconfID_gainb = -1; // block modal gains +long aoconfID_multfb = -1; // block modal gains +long aoconfID_limitb = -1; // block modal gains + +// individual modes +long aoconfID_DMmode_GAIN = -1; +long aoconfID_LIMIT_modes = -1; +long aoconfID_MULTF_modes = -1; + +long aoconfID_cmd_modesRM = -1; + +long aoconfID_wfsmask = -1; +static long aoconfID_dmmask = -1; + +static long aoconfID_respM = -1; +static long aoconfID_contrM = -1; // pixels -> modes +static long long aoconfcnt0_contrM_current = -1; +static long aoconfID_contrMc = -1; // combined control matrix: pixels -> DM actuators +static long aoconfID_meas_act = -1; +static long aoconfID_contrMcact[100] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}; + +// pixel streaming +long aoconfID_pixstream_wfspixindex; // index of WFS pixels + +long aoconfID_looptiming = -1; // control loop timing data. Pixel values correspond to time offset +// currently has 20 timing slots +// beginning of iteration is defined when entering "wait for image" +// md[0].atime.ts is absolute time at beginning of iteration +// +// pixel 0 is dt since last iteration +// +// pixel 1 is time from beginning of loop to status 01 +// pixel 2 is time from beginning of loop to status 02 +// ... +static long NBtimers = 21; + +static long aoconfIDlogdata = -1; +static long aoconfIDlog0 = -1; +static long aoconfIDlog1 = -1; + +int *WFS_active_map; // used to map WFS pixels into active array +int *DM_active_map; // used to map DM actuators into active array +static long aoconfID_meas_act_active; +static long aoconfID_imWFS2_active[100]; + + + + + + + + + + + + +float normfloorcoeff = 1.0; + + + + + +static long wfsrefcnt0 = -1; +static long contrMcactcnt0[100] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1};; + + + +// variables used by functions + + +static int GPUcntMax = 100; +static int *GPUset0; +static int *GPUset1; + + + + + + + + +/* =============================================================================================== */ +/* MAIN DATA STRUCTURES */ +/* =============================================================================================== */ + +extern DATA data; + +#define NB_AOloopcontrol 10 // max number of loops +long LOOPNUMBER = 0; // current loop index + +int AOloopcontrol_meminit = 0; +static int AOlooploadconf_init = 0; + +#define AOconfname "/tmp/AOconf.shm" +AOLOOPCONTROL_CONF *AOconf; // configuration - this can be an array + + + + + + + + + + + + + + + + + + + + + + + + + + + +// CLI commands +// +// function CLI_checkarg used to check arguments +// CLI_checkarg ( CLI argument index , type code ) +// +// type codes: +// 1: float +// 2: long +// 3: string, not existing image +// 4: existing image +// 5: string +// + + + + + + +/* =============================================================================================== */ +/* =============================================================================================== */ +/** @name AOloopControl - 1. INITIALIZATION, configurations + * Allocate memory, import/export configurations */ +/* =============================================================================================== */ +/* =============================================================================================== */ + +/** @brief CLI function for AOloopControl_loadconfigure */ +int_fast8_t AOloopControl_loadconfigure_cli() { + if(CLI_checkarg(1,2)==0) { + AOloopControl_loadconfigure(data.cmdargtoken[1].val.numl, 1, 10); + return 0; + } + else return 1; +} + + + + + +/** @brief CLI function for AOloopControl_stream3Dto2D */ +/*int_fast8_t AOloopControl_stream3Dto2D_cli() { + if(CLI_checkarg(1,4)+CLI_checkarg(2,3)+CLI_checkarg(3,2)+CLI_checkarg(4,2)==0) { + AOloopControl_stream3Dto2D(data.cmdargtoken[1].val.string, data.cmdargtoken[2].val.string, data.cmdargtoken[3].val.numl, data.cmdargtoken[4].val.numl); + return 0; + } + else return 1; +}*/ + + + + + + + + + + + +/* =============================================================================================== */ +/* =============================================================================================== */ +/** @name AOloopControl - 6. REAL TIME COMPUTING ROUTINES + * calls CPU and GPU processing */ +/* =============================================================================================== */ +/* =============================================================================================== */ + +/** @brief CLI function for AOloopControl_WFSzpupdate_loop */ +int_fast8_t AOloopControl_WFSzpupdate_loop_cli() { + if(CLI_checkarg(1,4)+CLI_checkarg(2,4)+CLI_checkarg(3,4)==0) { + AOloopControl_WFSzpupdate_loop(data.cmdargtoken[1].val.string, data.cmdargtoken[2].val.string, data.cmdargtoken[3].val.string); + return 0; + } + else return 1; +} + +/// tout juste ajouté pour le test, à enlever +/** @brief CLI function for AOloopControl_WFSzpupdate_loop */ +int_fast8_t AOloopControl_WFSzpupdateloop_cli() { + if(CLI_checkarg(1,4)+CLI_checkarg(2,4)+CLI_checkarg(3,4)==0) { + AOloopControl_WFSzpupdate_loop(data.cmdargtoken[1].val.string, data.cmdargtoken[2].val.string, data.cmdargtoken[3].val.string); + return 0; + } + else return 1; +} + + + +/** @brief CLI function for AOloopControl_WFSzeropoint_sum_update_loop */ +int_fast8_t AOloopControl_WFSzeropoint_sum_update_loop_cli() { + if(CLI_checkarg(1,3)+CLI_checkarg(2,2)+CLI_checkarg(3,4)+CLI_checkarg(4,4)==0) { + AOloopControl_WFSzeropoint_sum_update_loop(LOOPNUMBER, data.cmdargtoken[1].val.string, data.cmdargtoken[2].val.numl, data.cmdargtoken[3].val.string, data.cmdargtoken[4].val.string); + return 0; + } + else return 1; +} + +/** @brief CLI function for AOloopControl_CompModes_loop */ +int_fast8_t AOloopControl_CompModes_loop_cli() { + if(CLI_checkarg(1,4)+CLI_checkarg(2,4)+CLI_checkarg(3,4)+CLI_checkarg(4,4)+CLI_checkarg(5,3)==0) { + AOloopControl_CompModes_loop(data.cmdargtoken[1].val.string, data.cmdargtoken[2].val.string, data.cmdargtoken[3].val.string, data.cmdargtoken[4].val.string, data.cmdargtoken[5].val.string); + return 0; + } + else return 1; +} + +/** @brief CLI function for AOloopControl_GPUmodecoeffs2dm_filt */ +int_fast8_t AOloopControl_GPUmodecoeffs2dm_filt_loop_cli() { + if(CLI_checkarg(1,4)+CLI_checkarg(2,4)+CLI_checkarg(3,2)+CLI_checkarg(4,4)+CLI_checkarg(5,2)+CLI_checkarg(6,2)+CLI_checkarg(7,2)==0) { + AOloopControl_GPUmodecoeffs2dm_filt_loop(data.cmdargtoken[1].val.string, data.cmdargtoken[2].val.string, data.cmdargtoken[3].val.numl, data.cmdargtoken[4].val.string, data.cmdargtoken[5].val.numl, data.cmdargtoken[6].val.numl, data.cmdargtoken[7].val.numl); + return 0; + } + else return 1; +} + +/** @brief CLI function for AOloopControl_computeWFSresidualimage */ +int_fast8_t AOloopControl_computeWFSresidualimage_cli() { + if(CLI_checkarg(1,2)+CLI_checkarg(2,4)==0) { + AOloopControl_computeWFSresidualimage(data.cmdargtoken[1].val.numl, data.cmdargtoken[2].val.string); + return 0; + } + else return 1; +} + +/** @brief CLI function for AOloopControl_ComputeOpenLoopModes */ +int_fast8_t AOloopControl_ComputeOpenLoopModes_cli() { + if(CLI_checkarg(1,2)==0) { + AOloopControl_ComputeOpenLoopModes(data.cmdargtoken[1].val.numl); + return 0; + } else return 1; +} + +/** @brief CLI function for AOloopControl_AutoTuneGains */ +int_fast8_t AOloopControl_AutoTuneGains_cli() { + if(CLI_checkarg(1,2)+CLI_checkarg(2,3)+CLI_checkarg(3,1)+CLI_checkarg(4,2)==0) { + AOloopControl_AutoTuneGains(data.cmdargtoken[1].val.numl, data.cmdargtoken[2].val.string, data.cmdargtoken[3].val.numf, data.cmdargtoken[4].val.numl); + return 0; + } + else return 1; +} + +/** @brief CLI function for AOloopControl_dm2dm_offload */ +int_fast8_t AOloopControl_dm2dm_offload_cli() { + if(CLI_checkarg(1,4)+CLI_checkarg(2,4)+CLI_checkarg(3,1)+CLI_checkarg(4,1)+CLI_checkarg(5,1)==0) { + AOloopControl_dm2dm_offload(data.cmdargtoken[1].val.string, data.cmdargtoken[2].val.string, data.cmdargtoken[3].val.numf, data.cmdargtoken[4].val.numf, data.cmdargtoken[5].val.numf); + return 0; + } + else return 1; +} + +/** @brief CLI function for AOloopControl_sig2Modecoeff */ +int_fast8_t AOloopControl_sig2Modecoeff_cli() { + if(CLI_checkarg(1,4)+CLI_checkarg(2,4)+CLI_checkarg(3,4)+CLI_checkarg(4,3)==0) { + AOloopControl_sig2Modecoeff(data.cmdargtoken[1].val.string, data.cmdargtoken[2].val.string, data.cmdargtoken[3].val.string, data.cmdargtoken[4].val.string); + return 0; + } else return 1; +} + + + + + + + +/* =============================================================================================== */ +/* =============================================================================================== */ +/** @name AOloopControl - 8. LOOP CONTROL INTERFACE */ +/* =============================================================================================== */ +/* =============================================================================================== */ + + +/** @brief CLI function for AOloopControl_setLoopNumber */ +int_fast8_t AOloopControl_setLoopNumber_cli() { + if(CLI_checkarg(1,2)==0) { + AOloopControl_setLoopNumber(data.cmdargtoken[1].val.numl); + return 0; + } + else return 1; +} + + + +/* =============================================================================================== */ +/** @name AOloopControl - 8.1. LOOP CONTROL INTERFACE - MAIN CONTROL : LOOP ON/OFF START/STOP/STEP/RESET */ +/* =============================================================================================== */ + + +/* =============================================================================================== */ +/** @name AOloopControl - 8.2. LOOP CONTROL INTERFACE - DATA LOGGING */ +/* =============================================================================================== */ + + +/* =============================================================================================== */ +/** @name AOloopControl - 8.3. LOOP CONTROL INTERFACE - PRIMARY DM WRITE */ +/* =============================================================================================== */ + +/* =============================================================================================== */ +/** @name AOloopControl - 8.4. LOOP CONTROL INTERFACE - INTEGRATOR AUTO TUNING */ +/* =============================================================================================== */ + + +/* =============================================================================================== */ +/** @name AOloopControl - 8.5. LOOP CONTROL INTERFACE - PREDICTIVE FILTER ON/OFF */ +/* =============================================================================================== */ + + +/* =============================================================================================== */ +/** @name AOloopControl - 8.6. LOOP CONTROL INTERFACE - TIMING PARAMETERS */ +/* =============================================================================================== */ + + + +/* =============================================================================================== */ +/** @name AOloopControl - 8.7. LOOP CONTROL INTERFACE - CONTROL LOOP PARAMETERS */ +/* =============================================================================================== */ + + + +/** @brief CLI function for AOloopControl_set_modeblock_gain */ +int_fast8_t AOloopControl_set_modeblock_gain_cli() { + if(CLI_checkarg(1,2)+CLI_checkarg(2,1)+CLI_checkarg(3,2)==0) { + AOloopControl_set_modeblock_gain(LOOPNUMBER, data.cmdargtoken[1].val.numl, data.cmdargtoken[2].val.numf, data.cmdargtoken[3].val.numl); + return 0; + } + else return 1; +} + +/** @brief CLI function for AOloopControl_loopstep */ +int_fast8_t AOloopControl_loopstep_cli() { + if(CLI_checkarg(1,2)==0) { + AOloopControl_loopstep(LOOPNUMBER, data.cmdargtoken[1].val.numl); + return 0; + } + else return 1; +} + +/** @brief CLI function for AOloopControl_set_loopfrequ */ +int_fast8_t AOloopControl_set_loopfrequ_cli() { + if(CLI_checkarg(1,1)==0) { + AOloopControl_set_loopfrequ(data.cmdargtoken[1].val.numf); + return 0; + } + else return 1; +} + +/** @brief CLI function for AOloopControl_set_hardwlatency_frame */ +int_fast8_t AOloopControl_set_hardwlatency_frame_cli() { + if(CLI_checkarg(1,1)==0) { + AOloopControl_set_hardwlatency_frame(data.cmdargtoken[1].val.numf); + return 0; + } + else return 1; +} + +/** @brief CLI function for AOloopControl_set_complatency_frame + latency for the primary DM write */ +int_fast8_t AOloopControl_set_complatency_frame_cli() { + if(CLI_checkarg(1,1)==0) { + AOloopControl_set_complatency_frame(data.cmdargtoken[1].val.numf); + return 0; + } + else return 1; +} + +/** @brief CLI function for AOloopControl_set_wfsmextrlatency_frame + delay between the time when the WFS measures and the time when commands are sent to the DM */ +int_fast8_t AOloopControl_set_wfsmextrlatency_frame_cli() { + if(CLI_checkarg(1,1)==0) { + AOloopControl_set_wfsmextrlatency_frame(data.cmdargtoken[1].val.numf); + return 0; + } + else return 1; +} + +/** @brief CLI function for AOloopControl_set_AUTOTUNE_LIMITS_delta */ +int_fast8_t AOloopControl_set_AUTOTUNE_LIMITS_delta_cli() { + if(CLI_checkarg(1,1)==0) { + AOloopControl_set_AUTOTUNE_LIMITS_delta(data.cmdargtoken[1].val.numf); + return 0; + } + else return 1; +} + +/** @brief CLI function for AOloopControl_set_AUTOTUNE_LIMITS_perc */ +int_fast8_t AOloopControl_set_AUTOTUNE_LIMITS_perc_cli() { + if(CLI_checkarg(1,1)==0) { + AOloopControl_set_AUTOTUNE_LIMITS_perc(data.cmdargtoken[1].val.numf); + return 0; + } + else return 1; +} + +/** @brief CLI function for AOloopControl_set_AUTOTUNE_LIMITS_mcoeff */ +int_fast8_t AOloopControl_set_AUTOTUNE_LIMITS_mcoeff_cli() { + if(CLI_checkarg(1,1)==0) { + AOloopControl_set_AUTOTUNE_LIMITS_mcoeff(data.cmdargtoken[1].val.numf); + return 0; + } + else return 1; +} + +/** @brief CLI function for AOloopControl_setgain */ +int_fast8_t AOloopControl_setgain_cli() { + if(CLI_checkarg(1,1)==0) { + AOloopControl_setgain(data.cmdargtoken[1].val.numf); + return 0; + } + else return 1; +} + +/** @brief CLI function for AOloopControl_setARPFgain */ +int_fast8_t AOloopControl_setARPFgain_cli() { + if(CLI_checkarg(1,1)==0) { + AOloopControl_setARPFgain(data.cmdargtoken[1].val.numf); + return 0; + } + else return 1; +} + +/** @brief CLI function for AOloopControl_setWFSnormfloor */ +int_fast8_t AOloopControl_setWFSnormfloor_cli() { + if(CLI_checkarg(1,1)==0) { + AOloopControl_setWFSnormfloor(data.cmdargtoken[1].val.numf); + return 0; + } else return 1; +} + +/** @brief CLI function for AOloopControl_setmaxlimit */ +int_fast8_t AOloopControl_setmaxlimit_cli() { + if(CLI_checkarg(1,1)==0) { + AOloopControl_setmaxlimit(data.cmdargtoken[1].val.numf); + return 0; + } + else return 1; +} + +/** @brief CLI function for AOloopControl_setmult */ +int_fast8_t AOloopControl_setmult_cli() { + if(CLI_checkarg(1,1)==0) { + AOloopControl_setmult(data.cmdargtoken[1].val.numf); + return 0; + } + else return 1; +} + +/** @brief CLI function for AOloopControl_setframesAve */ +int_fast8_t AOloopControl_setframesAve_cli() { + if(CLI_checkarg(1,2)==0) { + AOloopControl_setframesAve(data.cmdargtoken[1].val.numl); + return 0; + } + else return 1; +} + +////////////////////////////////////////// +// begin declaring fonctions for Filtering +////////////////////////////////////////// +/* +limit_total = limit_global * limit_block * limit_mode +gain_total = gain_global * gain_block * gain_mode +*/ + +/** @brief CLI function for AOloopControl_setgainrange */ +int_fast8_t AOloopControl_setgainrange_cli() { + if(CLI_checkarg(1,2)+CLI_checkarg(2,2)+CLI_checkarg(3,1)==0) { + AOloopControl_setgainrange(data.cmdargtoken[1].val.numl, data.cmdargtoken[2].val.numl, data.cmdargtoken[3].val.numf); + return 0; + } + else return 1; +} + +/** @brief CLI function for AOloopControl_setlimitrange */ +int_fast8_t AOloopControl_setlimitrange_cli() { + if(CLI_checkarg(1,2)+CLI_checkarg(2,2)+CLI_checkarg(3,1)==0) { + AOloopControl_setlimitrange(data.cmdargtoken[1].val.numl, data.cmdargtoken[2].val.numl, data.cmdargtoken[3].val.numf); + return 0; + } + else return 1; +} + +/** @brief CLI function for AOloopControl_setmultfrange */ +int_fast8_t AOloopControl_setmultfrange_cli() { + if(CLI_checkarg(1,2)+CLI_checkarg(2,2)+CLI_checkarg(3,1)==0) { + AOloopControl_setmultfrange(data.cmdargtoken[1].val.numl, data.cmdargtoken[2].val.numl, data.cmdargtoken[3].val.numf); + return 0; + } + else return 1; +} + +/** @brief CLI function for AOloopControl_setgainblock (filtering) */ +int_fast8_t AOloopControl_setgainblock_cli() { + if(CLI_checkarg(1,2)+CLI_checkarg(2,1)==0) { + AOloopControl_setgainblock(data.cmdargtoken[1].val.numl, data.cmdargtoken[2].val.numf); + return 0; + } + else return 1; +} + +/** @brief CLI function for AOloopControl_setlimitblock (filtering) */ +int_fast8_t AOloopControl_setlimitblock_cli() { + if(CLI_checkarg(1,2)+CLI_checkarg(2,1)==0) { + AOloopControl_setlimitblock(data.cmdargtoken[1].val.numl, data.cmdargtoken[2].val.numf); + return 0; + } + else return 1; +} + +/** @brief CLI function for AOloopControl_setmultfblock / coeff MULTF (filtering) */ +int_fast8_t AOloopControl_setmultfblock_cli() { + if(CLI_checkarg(1,2)+CLI_checkarg(2,1)==0) { + AOloopControl_setmultfblock(data.cmdargtoken[1].val.numl, data.cmdargtoken[2].val.numf); + return 0; + } + else return 1; +} + +/** @brief CLI function for AOloopControl_scanGainBlock (filtering) */ +int_fast8_t AOloopControl_scanGainBlock_cli() { + if(CLI_checkarg(1,2)+CLI_checkarg(2,2)+CLI_checkarg(3,1)+CLI_checkarg(4,1)+CLI_checkarg(5,2)==0) { + AOloopControl_scanGainBlock(data.cmdargtoken[1].val.numl, data.cmdargtoken[2].val.numl, data.cmdargtoken[3].val.numf, data.cmdargtoken[4].val.numf, data.cmdargtoken[5].val.numl); + return 0; + } + else return 1; +} +//////////////////////////////////////// +// end declaring fonctions for Filtering +//////////////////////////////////////// + + +/* =============================================================================================== */ +/* =============================================================================================== */ +/** @name AOloopControl - 10. FOCAL PLANE SPECKLE MODULATION / CONTROL */ +/* =============================================================================================== */ +/* =============================================================================================== */ + +/** @brief CLI function for AOloopControl_DMmodulateAB */ +int_fast8_t AOloopControl_DMmodulateAB_cli() +{ + if(CLI_checkarg(1,4)+CLI_checkarg(2,4)+CLI_checkarg(3,4)+CLI_checkarg(4,4)+CLI_checkarg(5,4)+CLI_checkarg(6,1)+CLI_checkarg(7,2)==0) { + AOloopControl_DMmodulateAB(data.cmdargtoken[1].val.string, data.cmdargtoken[2].val.string, data.cmdargtoken[3].val.string, data.cmdargtoken[4].val.string, data.cmdargtoken[5].val.string, data.cmdargtoken[6].val.numf, data.cmdargtoken[7].val.numl); + return 0; + } + else return 1; +} + + + +/* =============================================================================================== */ +/* =============================================================================================== */ +/** @name AOloopControl - 11. PROCESS LOG FILES */ +/* =============================================================================================== */ +/* =============================================================================================== */ + +/** @brief CLI function for AOloopControl_logprocess_modeval */ +int_fast8_t AOloopControl_logprocess_modeval_cli() { + if(CLI_checkarg(1,4)==0) { + AOloopControl_logprocess_modeval(data.cmdargtoken[1].val.string); + return 0; + } + else return 1; +} + + + + + + +// 1: float +// 2: long +// 3: string, not existing image +// 4: existing image +// 5: string + + + + + +// OBSOLETE ?? + + +// set command line interface , parameters +int_fast8_t AOloopControl_setparam_cli() +{ + if(CLI_checkarg(1,3)+CLI_checkarg(2,1)==0) + { + AOloopControl_setparam(LOOPNUMBER, data.cmdargtoken[1].val.string, data.cmdargtoken[2].val.numf); + return 0; + } + else + return 1; +} + + + + + + + + + + + +/* =============================================================================================== */ +/* =============================================================================================== */ +/* FUNCTIONS SOURCE CODE */ +/* =============================================================================================== */ +/* =============================================================================================== */ +/** @name AOloopControl functions */ + + + + + + + +/* =============================================================================================== */ +/* =============================================================================================== */ +/** @name AOloopControl - 1. INITIALIZATION, configurations */ +/* =============================================================================================== */ +/* =============================================================================================== */ + + + +int_fast8_t init_AOloopControl() +{ + FILE *fp; + +#ifdef AOLOOPCONTROL_LOGFUNC + CORE_logFunctionCall( 0, __FUNCTION__, __LINE__, ""); +#endif + + + if((fp=fopen("LOOPNUMBER","r"))!=NULL) + { + if(fscanf(fp,"%8ld", &LOOPNUMBER) != 1) + printERROR(__FILE__,__func__,__LINE__, "Cannot read LOOPNUMBER"); + + printf("LOOP NUMBER = %ld\n", LOOPNUMBER); + fclose(fp); + } + else + LOOPNUMBER = 0; + + + strcpy(data.module[data.NBmodule].name, __FILE__); + strcpy(data.module[data.NBmodule].info, "AO loop control"); + data.NBmodule++; + + + + RegisterCLIcommand("aolloadconf",__FILE__, AOloopControl_loadconfigure_cli, "load AO loop configuration", "", "AOlooploadconf 1", "int AOloopControl_loadconfigure(long loopnb, 1, 10)"); + + + + +/* =============================================================================================== */ +/* =============================================================================================== */ +/** @name AOloopControl - 2. LOW LEVEL UTILITIES & TOOLS */ +/* =============================================================================================== */ +/* =============================================================================================== */ + + +/* =============================================================================================== */ +/** @name AOloopControl - 2.1. LOW LEVEL UTILITIES & TOOLS - LOAD DATA STREAMS */ +/* =============================================================================================== */ + +/* =============================================================================================== */ +/** @name AOloopControl - 2.2. LOW LEVEL UTILITIES & TOOLS - DATA STREAMS PROCESSING */ +/* =============================================================================================== */ + +/* RegisterCLIcommand("aveACshmim", __FILE__, AOloopControl_AveStream_cli, "average and AC shared mem image", " " , "aveACshmim imin 0.01 outave outAC outRMS", "int AOloopControl_AveStream(char *IDname, double alpha, char *IDname_out_ave, char *IDname_out_AC, char *IDname_out_RMS)"); + + RegisterCLIcommand("aolstream3Dto2D", __FILE__, AOloopControl_stream3Dto2D_cli, "remaps 3D cube into 2D image", " <# cols> " , "aolstream3Dto2D in3dim out2dim 4 1", "long AOloopControl_stream3Dto2D(const char *in_name, const char *out_name, int NBcols, int insem)"); +*/ + + + + + + + + +/* =============================================================================================== */ +/* =============================================================================================== */ +/** @name AOloopControl - 6. REAL TIME COMPUTING ROUTINES */ +/* =============================================================================================== */ +/* =============================================================================================== */ + + + RegisterCLIcommand("aolrun", __FILE__, AOloopControl_run, "run AO loop", "no arg", "aolrun", "int AOloopControl_run()"); + + RegisterCLIcommand("aolzpwfsloop",__FILE__, AOloopControl_WFSzpupdate_loop_cli, "WFS zero point offset loop", " ", "aolzpwfsloop dmZP zrespM wfszp", "int AOloopControl_WFSzpupdate_loop(char *IDzpdm_name, char *IDzrespM_name, char *IDwfszp_name)"); + + RegisterCLIcommand("aolzpwfscloop", __FILE__, AOloopControl_WFSzeropoint_sum_update_loop_cli, "WFS zero point offset loop: combine multiple input channels", " ", "aolzpwfscloop wfs2zpoffset 4 wfsref0 wfsref", "int AOloopControl_WFSzeropoint_sum_update_loop(long loopnb, char *ID_WFSzp_name, int NBzp, char *IDwfsref0_name, char *IDwfsref_name)"); + + RegisterCLIcommand("aocmlrun", __FILE__, AOloopControl_CompModes_loop_cli, "run AO compute modes loop", " ", "aocmlrun CM wfsref wfsim wfsimtot aomodeval", "int AOloopControl_CompModes_loop(char *ID_CM_name, char *ID_WFSref_name, char *ID_WFSim_name, char *ID_WFSimtot, char *ID_coeff_name)"); + + RegisterCLIcommand("aolmc2dmfilt", __FILE__, AOloopControl_GPUmodecoeffs2dm_filt_loop_cli, "convert mode coefficients to DM map", " ", "aolmc2dmfilt aolmodeval DMmodesC 2 dmmapc 0.2 1 2 1", "int AOloopControl_GPUmodecoeffs2dm_filt_loop(char *modecoeffs_name, char *DMmodes_name, int semTrigg, char *out_name, int GPUindex, long loop, long offloadMode)"); + + RegisterCLIcommand("aolsig2mcoeff", __FILE__, AOloopControl_sig2Modecoeff_cli, "convert signals to mode coeffs", " ", "aolsig2mcoeff wfsdata wfsref wfsmodes outim", "long AOloopControl_sig2Modecoeff(char *WFSim_name, char *IDwfsref_name, char *WFSmodes_name, char *outname)"); + + + +/* =============================================================================================== */ +/* =============================================================================================== */ +/** @name AOloopControl - 8. LOOP CONTROL INTERFACE */ +/* =============================================================================================== */ +/* =============================================================================================== */ + + RegisterCLIcommand("aolnb", __FILE__, AOloopControl_setLoopNumber_cli, "set AO loop #", "", "AOloopnb 0", "int AOloopControl_setLoopNumber(long loop)"); + +/* =============================================================================================== */ +/** @name AOloopControl - 8.1. LOOP CONTROL INTERFACE - MAIN CONTROL : LOOP ON/OFF START/STOP/STEP/RESET */ +/* =============================================================================================== */ + + +/* =============================================================================================== */ +/** @name AOloopControl - 8.2. LOOP CONTROL INTERFACE - DATA LOGGING */ +/* =============================================================================================== */ + +/* =============================================================================================== */ +/** @name AOloopControl - 8.3. LOOP CONTROL INTERFACE - PRIMARY DM WRITE */ +/* =============================================================================================== */ + +/* =============================================================================================== */ +/** @name AOloopControl - 8.4. LOOP CONTROL INTERFACE - INTEGRATOR AUTO TUNING */ +/* =============================================================================================== */ + + +/* =============================================================================================== */ +/** @name AOloopControl - 8.5. LOOP CONTROL INTERFACE - PREDICTIVE FILTER ON/OFF */ +/* =============================================================================================== */ + +/* =============================================================================================== */ +/** @name AOloopControl - 8.6. LOOP CONTROL INTERFACE - TIMING PARAMETERS */ +/* =============================================================================================== */ + +/* =============================================================================================== */ +/** @name AOloopControl - 8.7. LOOP CONTROL INTERFACE - CONTROL LOOP PARAMETERS */ +/* =============================================================================================== */ + + RegisterCLIcommand("aolsetgain", __FILE__, AOloopControl_setgain_cli, "set gain", "", "aolsetgain 0.1", "int AOloopControl_setgain(float gain)"); + + RegisterCLIcommand("aolsetARPFgain", __FILE__, AOloopControl_setARPFgain_cli, "set auto-regressive predictive filter gain", "", "aolsetARPFgain 0.1", "int AOloopControl_setARPFgain(float gain)"); + + + + + + + + + + + RegisterCLIcommand("aolkill", __FILE__, AOloopControl_loopkill, "kill AO loop", "no arg", "aolkill", "int AOloopControl_setLoopNumber()"); + + RegisterCLIcommand("aolon", __FILE__, AOloopControl_loopon, "turn loop on", "no arg", "aolon", "int AOloopControl_loopon()"); + + RegisterCLIcommand("aoloff", __FILE__, AOloopControl_loopoff, "turn loop off", "no arg", "aoloff", "int AOloopControl_loopoff()"); + + RegisterCLIcommand("aolstep",__FILE__, AOloopControl_loopstep_cli, "turn loop on for N steps", "", "aolstep", "int AOloopControl_loopstep(long loop, long NBstep)"); + + RegisterCLIcommand("aolreset", __FILE__, AOloopControl_loopreset, "reset loop, and turn it off", "no arg", "aolreset", "int AOloopControl_loopreset()"); + + RegisterCLIcommand("aolsetmbgain",__FILE__, AOloopControl_set_modeblock_gain_cli, "set modal block gain", " ", "aolsetmbgain 2 0.2 1", "int AOloopControl_set_modeblock_gain(long loop, long blocknb, float gain, int add)"); + + RegisterCLIcommand("aolDMprimWon", __FILE__, AOloopControl_DMprimaryWrite_on, "turn DM primary write on", "no arg", "aolDMprimWon", "int AOloopControl_DMprimaryWrite_on()"); + + RegisterCLIcommand("aolDMprimWoff", __FILE__, AOloopControl_DMprimaryWrite_off, "turn DM primary write off", "no arg", "aolDMprimWoff", "int AOloopControl_DMprimaryWrite_off()"); + + RegisterCLIcommand("aolDMfiltWon", __FILE__, AOloopControl_DMfilteredWrite_on, "turn DM filtered write on", "no arg", "aolDMfiltWon", "int AOloopControl_DMfilteredWrite_on()"); + + RegisterCLIcommand("aolDMfiltWoff", __FILE__, AOloopControl_DMfilteredWrite_off, "turn DM filtered write off", "no arg", "aolDMfiltWoff", "int AOloopControl_DMfilteredWrite_off()"); + + RegisterCLIcommand("aolAUTOTUNELIMon", __FILE__, AOloopControl_AUTOTUNE_LIMITS_on, "turn auto-tuning modal limits on", "no arg", "aolAUTOTUNELIMon", "int AOloopControl_AUTOTUNE_LIMITS_on()"); + + RegisterCLIcommand("aolAUTOTUNELIMoff", __FILE__, AOloopControl_AUTOTUNE_LIMITS_off, "turn auto-tuning modal limits off", "no arg", "aolAUTOTUNELIMoff", "int AOloopControl_AUTOTUNE_LIMITS_off()"); + + RegisterCLIcommand("aolsetATlimd", __FILE__, AOloopControl_set_AUTOTUNE_LIMITS_delta_cli, "set auto-tuning modal limits delta", "", "aolsetATlimd 0.0001", "int AOloopControl_set_AUTOTUNE_LIMITS_delta(float AUTOTUNE_LIMITS_delta)"); + + RegisterCLIcommand("aolsetATlimp", __FILE__, AOloopControl_set_AUTOTUNE_LIMITS_perc_cli, "set auto-tuning modal limits percentile", "", "aolsetATlimp 1.0", "int AOloopControl_set_AUTOTUNE_LIMITS_perc(float AUTOTUNE_LIMITS_perc)"); + + RegisterCLIcommand("aolsetATlimm", __FILE__, AOloopControl_set_AUTOTUNE_LIMITS_mcoeff_cli, "set auto-tuning modal limits multiplicative coeff", "", "aolsetATlimm 1.5", "int AOloopControl_set_AUTOTUNE_LIMITS_mcoeff(float AUTOTUNE_LIMITS_mcoeff)"); + + RegisterCLIcommand("aolAUTOTUNEGAINon", __FILE__, AOloopControl_AUTOTUNE_GAINS_on, "turn auto-tuning modal gains on", "no arg", "aolAUTOTUNEGAINon", "int AOloopControl_AUTOTUNE_GAINS_on()"); + + RegisterCLIcommand("aolAUTOTUNEGAINoff", __FILE__, AOloopControl_AUTOTUNE_GAINS_off, "turn auto-tuning modal gains off", "no arg", "aolAUTOTUNEGAINoff", "int AOloopControl_AUTOTUNE_GAINS_off()"); + + RegisterCLIcommand("aolARPFon", __FILE__, AOloopControl_ARPFon, "turn auto-regressive predictive filter on", "no arg", "aolARPFon", "int AOloopControl_ARPFon()"); + + RegisterCLIcommand("aolARPFoff", __FILE__, AOloopControl_ARPFoff, "turn auto-regressive predictive filter off", "no arg", "aolARPFoff", "int AOloopControl_ARPFoff()"); + + + + +/* =============================================================================================== */ +/* =============================================================================================== */ +/** @name AOloopControl - 10. FOCAL PLANE SPECKLE MODULATION / CONTROL */ +/* =============================================================================================== */ +/* =============================================================================================== */ + + + + +/* =============================================================================================== */ +/* =============================================================================================== */ +/** @name AOloopControl - 11. PROCESS LOG FILES */ +/* =============================================================================================== */ +/* =============================================================================================== */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + RegisterCLIcommand("aolsetloopfrequ", + __FILE__, + AOloopControl_set_loopfrequ_cli, + "set loop frequency", + "", + "aolsetloopfrequ 2000", + "int AOloopControl_set_loopfrequ(float loopfrequ)"); + + + + RegisterCLIcommand("aolsethlat", __FILE__, AOloopControl_set_hardwlatency_frame_cli, "set hardware latency", "", "aolsethlat 2.7", "int AOloopControl_set_hardwlatency_frame(float hardwlatency_frame)"); + + RegisterCLIcommand("aolsetclat",__FILE__, AOloopControl_set_complatency_frame_cli,"set computation latency", "", "aolsetclat 0.6", "int AOloopControl_set_complatency_frame(float complatency_frame)"); + + RegisterCLIcommand("aolsetwlat", __FILE__, AOloopControl_set_wfsmextrlatency_frame_cli, "set WFS mode extraction latency", "", "aolsetwlat 0.8", "int AOloopControl_set_wfsmextrlatency_frame(float wfsmextrlatency_frame)"); + + RegisterCLIcommand("aolsetwfsnormf", __FILE__, AOloopControl_setWFSnormfloor_cli, "set WFS normalization floor", "", "aolsetwfsnormf 10000.0", "int AOloopControl_setWFSnormfloor(float WFSnormfloor)"); + + RegisterCLIcommand("aolsetmaxlim", __FILE__, AOloopControl_setmaxlimit_cli, "set max limit for AO mode correction", "", "aolsetmaxlim 0.01", "int AOloopControl_setmaxlimit(float maxlimit)"); + + RegisterCLIcommand("aolsetmult", __FILE__, AOloopControl_setmult_cli, "set mult coeff for AO mode correction", "", "aolsetmult 0.98", "int AOloopControl_setmult(float multcoeff)"); + + RegisterCLIcommand("aolsetnbfr",__FILE__, AOloopControl_setframesAve_cli, "set number of frames to be averaged", "", "aolsetnbfr 10", "int AOloopControl_setframesAve(long nbframes)"); + + + + + + + + + + + + + + RegisterCLIcommand("aollogprocmodeval",__FILE__, AOloopControl_logprocess_modeval_cli, "process log image modeval", "", "aollogprocmodeval imc", "int AOloopControl_logprocess_modeval(const char *IDname);"); + + + + + + + + + + + RegisterCLIcommand("aolsetgainr", __FILE__, AOloopControl_setgainrange_cli, "set modal gains from m0 to m1 included", " ", "aolsetgainr 20 30 0.2", "int AOloopControl_setgainrange(long m0, long m1, float gainval)"); + + RegisterCLIcommand("aolsetlimitr",__FILE__, AOloopControl_setlimitrange_cli, "set modal limits", " ", "aolsetlimitr 20 30 0.02", "int AOloopControl_setlimitrange(long m0, long m1, float gainval)"); + + RegisterCLIcommand("aolsetmultfr", __FILE__, AOloopControl_setmultfrange_cli, "set modal multf", " ", "aolsetmultfr 10 30 0.98", "int AOloopControl_setmultfrange(long m0, long m1, float multfval)"); + + RegisterCLIcommand("aolsetgainb", __FILE__, AOloopControl_setgainblock_cli, "set modal gains by block", " ", "aolsetgainb 2 0.2", "int AOloopControl_setgainblock(long m0, long m1, float gainval)"); + + RegisterCLIcommand("aolsetlimitb",__FILE__, AOloopControl_setlimitblock_cli, "set modal limits by block", " ", "aolsetlimitb 2 0.02", "int AOloopControl_setlimitblock(long mb, float limitval)"); + + RegisterCLIcommand("aolsetmultfb", __FILE__, AOloopControl_setmultfblock_cli, "set modal multf by block", " ", "aolsetmultfb 2 0.98", "int AOloopControl_setmultfblock(long mb, float multfval)"); + + RegisterCLIcommand("aolscangainb", __FILE__, AOloopControl_scanGainBlock_cli, "scan gain for block", " ", "aolscangainb", "int AOloopControl_scanGainBlock(long NBblock, long NBstep, float gainStart, float gainEnd, long NBgain)"); + + RegisterCLIcommand("aolmkwfsres", __FILE__, AOloopControl_computeWFSresidualimage_cli, "compute WFS residual real time", " ", "aolmkwfsres 2 coeffim", "long AOloopControl_computeWFSresidualimage(long loop, char *IDalpha_name)"); + + + + RegisterCLIcommand("aolcompolm", __FILE__, AOloopControl_ComputeOpenLoopModes_cli, "compute open loop mode values", "", "aolcompolm 2", "long AOloopControl_ComputeOpenLoopModes(long loop)"); + + RegisterCLIcommand("aolautotunegains", __FILE__, AOloopControl_AutoTuneGains_cli, "compute optimal gains", " ", "aolautotunegains 0 autogain 0.1 20000", "long AOloopControl_AutoTuneGains(long loop, const char *IDout_name, float GainCoeff, long NBsamples)"); + + RegisterCLIcommand("aoldm2dmoffload", __FILE__, AOloopControl_dm2dm_offload_cli, "slow offload from dm to dm", " ", "aoldm2dmoffload dmin dmout 0.5 -0.01 0.999", "long AOloopControl_dm2dm_offload(const char *streamin, const char *streamout, float twait, float offcoeff, float multcoeff)"); + + RegisterCLIcommand("aolautotune", __FILE__, AOloopControl_AutoTune, "auto tuning of loop parameters", "no arg", "aolautotune", "int_fast8_t AOloopControl_AutoTune()"); + + RegisterCLIcommand("aolset", __FILE__, AOloopControl_setparam_cli, "set parameter", " " , "aolset", "int AOloopControl_setparam(long loop, const char *key, double value)"); + + RegisterCLIcommand("aoldmmodAB", __FILE__, AOloopControl_DMmodulateAB_cli, "module DM with linear combination of probes A and B", " ", "aoldmmodAB probeA probeB wfsrespmat wfsref 0.1 6","int AOloopControl_DMmodulateAB(const char *IDprobeA_name, const char *IDprobeB_name, const char *IDdmstream_name, const char *IDrespmat_name, const char *IDwfsrefstream_name, double delay, long NBprobes)"); + + + + + + + + + // add atexit functions here + // atexit((void*) myfunc); + + return 0; +} + + + + + + + + + + + + + + + + + + + +/* =============================================================================================== */ +/* =============================================================================================== */ +/** @name AOloopControl - 1. INITIALIZATION, configurations */ +/* =============================================================================================== */ +/* =============================================================================================== */ + + + + +/** + * ## Purpose + * + * Read parameter value (float) + * + * ## Arguments + * + * @param[in] + * paramname CHAR* + * parameter name + * + * @param[in] + * defaultValue FLOAT + * default value if file conf/param_paramname.txt not found + * + * @param[in] + * fplog FILE* + * log file. If NULL, do not log + * + */ +float AOloopControl_readParam_float(char *paramname, float defaultValue, FILE *fplog) +{ + FILE *fp; + char fname[200]; + float value; + int wParamFile = 0; + + sprintf(fname, "./conf/param_%s.txt", paramname); + if((fp=fopen(fname, "r"))==NULL) + { + printf("WARNING: file %s missing\n", fname); + value = defaultValue; + wParamFile = 1; + } + else + { + if(fscanf(fp, "%50f", &value) != 1){ + printERROR(__FILE__,__func__,__LINE__, "Cannot read parameter for file"); + value = defaultValue; + wParamFile = 1; + } + fclose(fp); + } + + if(wParamFile == 1) // write file + { + fp = fopen(fname, "w"); + fprintf(fp, "%f", value); + fclose(fp); + } + + + if(fplog!=NULL) + fprintf(fplog, "parameter %20s = %f\n", paramname, value); + + + return value; +} + + + +/** + * ## Purpose + * + * Read parameter value (int) + * + * ## Arguments + * + * @param[in] + * paramname CHAR* + * parameter name + * + * @param[in] + * defaultValue INT + * default value if file conf/param_paramname.txt not found + * + * @param[in] + * fplog FILE* + * log file. If NULL, do not log + * + */ +int AOloopControl_readParam_int(char *paramname, int defaultValue, FILE *fplog) +{ + FILE *fp; + char fname[200]; + int value; + int wParamFile = 0; + + sprintf(fname, "./conf/param_%s.txt", paramname); + if((fp=fopen(fname, "r"))==NULL) + { + printf("WARNING: file %s missing\n", fname); + value = defaultValue; + wParamFile = 1; + } + else + { + if(fscanf(fp, "%50d", &value) != 1){ + printERROR(__FILE__,__func__,__LINE__, "Cannot read parameter for file"); + value = defaultValue; + wParamFile = 1; + } + fclose(fp); + } + + if(wParamFile == 1) // write file + { + fp = fopen(fname, "w"); + fprintf(fp, "%d", value); + fclose(fp); + } + + + if(fplog!=NULL) + fprintf(fplog, "parameter %20s = %d\n", paramname, value); + + + return value; +} + + + +/** + * ## Purpose + * + * Read parameter value (char*) + * + * ## Arguments + * + * @param[in] + * paramname CHAR* + * parameter name + * + * @param[in] + * defaultValue CHAR* + * default value if file conf/param_paramname.txt not found + * + * @param[in] + * fplog FILE* + * log file. If NULL, do not log + * + */ +char* AOloopControl_readParam_string(char *paramname, char* defaultValue, FILE *fplog) +{ + FILE *fp; + char fname[200]; + char* value = " "; + int wParamFile = 0; + + sprintf(fname, "./conf/param_%s.txt", paramname); + if((fp=fopen(fname, "r"))==NULL) + { + printf("WARNING: file %s missing\n", fname); + strcpy(value, defaultValue); + wParamFile = 1; + } + else + { + if(fscanf(fp, "%200s", value) != 1){ + printERROR(__FILE__,__func__,__LINE__, "Cannot read parameter for file"); + strcpy(value, defaultValue); + wParamFile = 1; + } + fclose(fp); + } + + if(wParamFile == 1) // write file + { + fp = fopen(fname, "w"); + fprintf(fp, "%s", value); + fclose(fp); + } + + + if(fplog!=NULL) + fprintf(fplog, "parameter %20s = %s\n", paramname, value); + + + return value; +} + + + + + + + + + + + + + + + + + + + + + +/** + * ## Purpose + * + * load / setup configuration + * + * ## Arguments + * + * @param[in] + * loop INT + * Loop number + * + * @param[in] + * mode INT + * - 1 loads from ./conf/ directory to shared memory + * - 0 simply connects to shared memory + * + * @param[in] + * level INT + * - 2 zonal only + * - 10+ load all + * + * + * + * @ingroup AOloopControl_streams + */ +int_fast8_t AOloopControl_loadconfigure(long loop, int mode, int level) +{ + FILE *fp; + char content[201]; + char name[201]; + char fname[201]; + uint32_t *sizearray; + int kw; + long k; + int r; + int sizeOK; + char command[501]; + int CreateSMim; + long ii; + long tmpl; + char testdirname[201]; + + int initwfsref; + + FILE *fplog; // human-readable log of load sequence + + +#ifdef AOLOOPCONTROL_LOGFUNC + AOLOOPCONTROL_logfunc_level = 0; + CORE_logFunctionCall( AOLOOPCONTROL_logfunc_level, AOLOOPCONTROL_logfunc_level_max, 0, __FUNCTION__, __LINE__, ""); +#endif + + + // Create logfile for this function + // + if((fplog=fopen("logdir/loadconf.log", "w"))==NULL) + { + printf("ERROR: cannot create logdir/loadconf.log\n"); + exit(0); + } + loadcreateshm_log = 1; + loadcreateshm_fplog = fplog; + + /** --- */ + /** # Details */ + + /** ## 1. Initial setup from configuration files */ + + + /** - 1.1. Initialize memory */ + fprintf(fplog, "\n\n============== 1.1. Initialize memory ===================\n\n"); + if(AOloopcontrol_meminit==0) + AOloopControl_InitializeMemory(0); + + + + + // + /** ### 1.2. Set names of key streams */ + // + // Here we define names of key streams used by loop + + fprintf(fplog, "\n\n============== 1.2. Set names of key streams ===================\n\n"); + + /** - dmC stream : DM control */ + if(sprintf(name, "aol%ld_dmC", loop)<1) + printERROR(__FILE__, __func__, __LINE__, "sprintf wrote <1 char"); + printf("DM control file name : %s\n", name); + strcpy(AOconf[loop].dmCname, name); + + /** - dmdisp stream : total DM displacement */ + // used to notify dm combine that a new displacement should be computed + if(sprintf(name, "aol%ld_dmdisp", loop) < 1) + printERROR(__FILE__, __func__, __LINE__, "sprintf wrote <1 char"); + printf("DM displacement file name : %s\n", name); + strcpy(AOconf[loop].dmdispname, name); + + /** - dmRM stream : response matrix */ + if(sprintf(name, "aol%ld_dmRM", loop) < 1) + printERROR(__FILE__, __func__, __LINE__, "sprintf wrote <1 char"); + printf("DM RM file name : %s\n", name); + strcpy(AOconf[loop].dmRMname, name); + + /** - wfsim : WFS image */ + if(sprintf(name, "aol%ld_wfsim", loop) < 1) + printERROR(__FILE__, __func__, __LINE__, "sprintf wrote <1 char"); + printf("WFS file name: %s\n", name); + strcpy(AOconf[loop].WFSname, name); + + + + // Modal control + + /** - DMmodes : control modes */ + if(sprintf(name, "aol%ld_DMmodes", loop) < 1) + printERROR(__FILE__, __func__, __LINE__, "sprintf wrote <1 char"); + printf("DMmodes file name: %s\n", name); + strcpy(AOconf[loop].DMmodesname, name); + + /** - respM : response matrix */ + if(sprintf(name, "aol%ld_respM", loop) < 1) + printERROR(__FILE__, __func__, __LINE__, "sprintf wrote <1 char"); + printf("respM file name: %s\n", name); + strcpy(AOconf[loop].respMname, name); + + /** - contrM : control matrix */ + if(sprintf(name, "aol%ld_contrM", loop) < 1) + printERROR(__FILE__, __func__, __LINE__, "sprintf wrote <1 char"); + printf("contrM file name: %s\n", name); + strcpy(AOconf[loop].contrMname, name); + + + + + + + sizearray = (uint32_t*) malloc(sizeof(uint32_t)*3); + + + /** ### 1.3. Read loop name + * + * - ./conf/conf_LOOPNAME.txt -> AOconf[loop].name + */ + fprintf(fplog, "\n\n============== 1.3. Read loop name ===================\n\n"); + + if((fp=fopen("./conf/conf_LOOPNAME.txt","r"))==NULL) + { + printf("ERROR: file ./conf/conf_LOOPNAME.txt missing\n"); + exit(0); + } + if(fscanf(fp, "%200s", content) != 1) + { + printERROR(__FILE__,__func__,__LINE__, "Cannot read parameter for file"); + exit(0); + } + + printf("loop name : %s\n", content); + fflush(stdout); + fprintf(fplog, "AOconf[%ld].name = %s\n", loop, AOconf[loop].name); + fclose(fp); + strcpy(AOconf[loop].name, content); + + + /** ### 1.4. Define WFS image normalization mode + * + * - conf/param_WFSnorm.txt -> AOconf[loop].WFSnormalize + */ + fprintf(fplog, "\n\n============== 1.4. Define WFS image normalization mode ===================\n\n"); + + AOconf[loop].WFSnormalize = AOloopControl_readParam_int("WFSnorm", 1, fplog); + + + + /** ### 1.5. Read Timing info + * + * - ./conf/param_loopfrequ.txt -> AOconf[loop].loopfrequ + * - ./conf/param_hardwlatency.txt -> AOconf[loop].hardwlatency + * - AOconf[loop].hardwlatency_frame = AOconf[loop].hardwlatency * AOconf[loop].loopfrequ + * - ./conf/param_complatency.txt -> AOconf[loop].complatency + * - AOconf[loop].complatency_frame = AOconf[loop].complatency * AOconf[loop].loopfrequ; + * - ./conf/param_wfsmextrlatency.txt -> AOconf[loop].wfsmextrlatency + */ + fprintf(fplog, "\n\n============== 1.5. Read Timing info ===================\n\n"); + + + + AOconf[loop].loopfrequ = AOloopControl_readParam_float("loopfrequ", 1000.0, fplog); + AOconf[loop].hardwlatency = AOloopControl_readParam_float("hardwlatency", 0.0, fplog); + AOconf[loop].hardwlatency_frame = AOconf[loop].hardwlatency * AOconf[loop].loopfrequ; + + AOconf[loop].complatency = AOloopControl_readParam_float("complatency", 0.0, fplog); + AOconf[loop].complatency_frame = AOconf[loop].complatency * AOconf[loop].loopfrequ; + + AOconf[loop].wfsmextrlatency = AOloopControl_readParam_float("wfsmextrlatency", 0.0, fplog); + AOconf[loop].wfsmextrlatency_frame = AOconf[loop].wfsmextrlatency * AOconf[loop].loopfrequ; + + + + /** ### 1.6. Define GPU use + * + * - ./conf/param_GPU0.txt > AOconf[loop].GPU0 (0 if missing) + * - ./conf/param_GPU1.txt > AOconf[loop].GPU1 (0 if missing) + * - ./conf/param_GPUall.txt -> AOconf[loop].GPUall + * - ./conf/param_DMprimWriteON.txt -> AOconf[loop].DMprimaryWriteON + * + */ + fprintf(fplog, "\n\n============== 1.6. Define GPU use ===================\n\n"); + + AOconf[loop].GPU0 = AOloopControl_readParam_int("GPU0", 0, fplog); + AOconf[loop].GPU1 = AOloopControl_readParam_int("GPU1", 0, fplog); + AOconf[loop].GPUall = AOloopControl_readParam_int("GPUall", 0, fplog); // Skip CPU image scaling and go straight to GPUs ? + AOconf[loop].DMprimaryWriteON = AOloopControl_readParam_int("DMprimaryWriteON", 0, fplog); // Direct DM write ? + AOconf[loop].DMfilteredWriteON = AOloopControl_readParam_int("DMfilteredWriteON", 0, fplog); // Filtered DM write ? + + + /** ### 1.7. WFS image total flux computation mode + * + * + */ + fprintf(fplog, "\n\n============== 1.7. WFS image total flux computation mode ===================\n\n"); + + // TOTAL image done in separate thread ? + AOconf[loop].AOLCOMPUTE_TOTAL_ASYNC = AOloopControl_readParam_int("COMPUTE_TOTAL_ASYNC", 1, fplog); + + + /** ### 1.8. Read CMatrix mult mode + * + * - ./conf/param_CMMMODE.txt -> CMMODE + * - 0 : WFS signal -> Mode coeffs -> DM act values (2 sequential matrix multiplications) + * - 1 : WFS signal -> DM act values (1 combined matrix multiplication) + */ + + fprintf(fplog, "\n\n============== 1.8. Read CMatrix mult mode ===================\n\n"); + + AOconf[loop].CMMODE = AOloopControl_readParam_int("CMMODE", 1, fplog); + + + + + + + + /** ### 1.9. Setup loop timing array + */ + fprintf(fplog, "\n\n============== 1.10. Setup loop timing array ===================\n\n"); + + if(sprintf(name, "aol%ld_looptiming", loop) < 1) + printERROR(__FILE__, __func__, __LINE__, "sprintf wrote <1 char"); + + aoconfID_looptiming = AOloopControl_IOtools_2Dloadcreate_shmim(name, " ", NBtimers, 1, 0.0); + + + + + + /** ## 2. Read/load shared memory arrays + * + */ + fprintf(fplog, "\n\n============== 2. Read/load shared memory arrays ===================\n\n"); + + /** + * ### 2.1. CONNECT to existing streams + * + * Note: these streams MUST exist + * + * - AOconf[loop].dmdispname : this image is read to notify when new dm displacement is ready + * - AOconf[loop].WFSname : connect to WFS camera. This is where the size of the WFS is read + */ + + fprintf(fplog, "\n\n============== 2.1. CONNECT to existing streams ===================\n\n"); + + aoconfID_dmdisp = read_sharedmem_image(AOconf[loop].dmdispname); + if(aoconfID_dmdisp==-1) + fprintf(fplog, "ERROR : cannot read shared memory stream %s\n", AOconf[loop].dmdispname); + else + fprintf(fplog, "stream %s loaded as ID = %ld\n", AOconf[loop].dmdispname, aoconfID_dmdisp); + + + aoconfID_wfsim = read_sharedmem_image(AOconf[loop].WFSname); + if(aoconfID_wfsim == -1) + fprintf(fplog, "ERROR : cannot read shared memory stream %s\n", AOconf[loop].WFSname); + else + fprintf(fplog, "stream %s loaded as ID = %ld\n", AOconf[loop].WFSname, aoconfID_wfsim); + + AOconf[loop].sizexWFS = data.image[aoconfID_wfsim].md[0].size[0]; + AOconf[loop].sizeyWFS = data.image[aoconfID_wfsim].md[0].size[1]; + AOconf[loop].sizeWFS = AOconf[loop].sizexWFS*AOconf[loop].sizeyWFS; + + fprintf(fplog, "WFS stream size = %ld x %ld\n", AOconf[loop].sizexWFS, AOconf[loop].sizeyWFS); + + + + + + /** + * + * ### 2.2. Read file to stream or connect to existing stream + * + * The AOloopControl_xDloadcreate_shmim functions are used, and follows these rules: + * + * If file already loaded, use it (we assume it's already been properly loaded) \n + * If not, attempt to read it from shared memory \n + * If not available in shared memory, create it in shared memory \n + * if "fname" exists, attempt to load it into the shared memory image + * + * Stream names are fixed: + * - aol_wfsdark + * - aol_imWFS0 + * - aol_imWFS0tot + * - aol_imWFS1 + * - aol_imWFS2 + * - aol_wfsref0 + * - aol_wfsref + */ + + + fprintf(fplog, "\n\n============== 2.2. Read file to stream or connect to existing stream ===================\n\n"); + + if(sprintf(name, "aol%ld_wfsdark", loop) < 1) + printERROR(__FILE__, __func__, __LINE__, "sprintf wrote <1 char"); + sprintf(fname, "./conf/shmim_wfsdark.fits"); + aoconfID_wfsdark = AOloopControl_IOtools_2Dloadcreate_shmim(name, fname, AOconf[loop].sizexWFS, AOconf[loop].sizeyWFS, 0.0); + + + + if(sprintf(name, "aol%ld_imWFS0", loop) < 1) + printERROR(__FILE__, __func__, __LINE__, "sprintf wrote <1 char"); + aoconfID_imWFS0 = AOloopControl_IOtools_2Dloadcreate_shmim(name, " ", AOconf[loop].sizexWFS, AOconf[loop].sizeyWFS, 0.0); + COREMOD_MEMORY_image_set_createsem(name, 10); + + if(sprintf(name, "aol%ld_imWFS0tot", loop) < 1) + printERROR(__FILE__, __func__, __LINE__, "sprintf wrote <1 char"); + aoconfID_imWFS0tot = AOloopControl_IOtools_2Dloadcreate_shmim(name, " ", 1, 1, 0.0); + COREMOD_MEMORY_image_set_createsem(name, 10); + + if(sprintf(name, "aol%ld_imWFS1", loop) < 1) + printERROR(__FILE__, __func__, __LINE__, "sprintf wrote <1 char"); + aoconfID_imWFS1 = AOloopControl_IOtools_2Dloadcreate_shmim(name, " ", AOconf[loop].sizexWFS, AOconf[loop].sizeyWFS, 0.0); + + if(sprintf(name, "aol%ld_imWFS2", loop) < 1) + printERROR(__FILE__, __func__, __LINE__, "sprintf wrote <1 char"); + aoconfID_imWFS2 = AOloopControl_IOtools_2Dloadcreate_shmim(name, " ", AOconf[loop].sizexWFS, AOconf[loop].sizeyWFS, 0.0); + + + + + + initwfsref = AOconf[loop].init_wfsref0; + + if(sprintf(name, "aol%ld_wfsref0", loop) < 1) + printERROR(__FILE__, __func__, __LINE__, "sprintf wrote <1 char"); + + if(sprintf(fname, "./conf/shmim_wfsref0.fits") < 1) + printERROR(__FILE__, __func__, __LINE__, "sprintf wrote <1 char"); + + aoconfID_wfsref0 = AOloopControl_IOtools_2Dloadcreate_shmim(name, fname, AOconf[loop].sizexWFS, AOconf[loop].sizeyWFS, 0.0); + AOconf[loop].init_wfsref0 = 1; + + if(sprintf(name, "aol%ld_wfsref", loop) < 1) + printERROR(__FILE__, __func__, __LINE__, "sprintf wrote <1 char"); + + if(sprintf(fname, "./conf/shmim_wfsref.fits") < 1) + printERROR(__FILE__, __func__, __LINE__, "sprintf wrote <1 char"); + + aoconfID_wfsref = AOloopControl_IOtools_2Dloadcreate_shmim(name, fname, AOconf[loop].sizexWFS, AOconf[loop].sizeyWFS, 0.0); + + if(initwfsref==0) + { + char name1[200]; + + if(sprintf(name1, "aol%ld_wfsref0", loop) < 1) + printERROR(__FILE__, __func__, __LINE__, "sprintf wrote <1 char"); + + copy_image_ID(name1, name, 1); + } + + + + + /** ### 2.3. Connect to DM + * + * - AOconf[loop].dmCname : DM control channel + * + * Here the DM size is read -> Oconf[loop].sizexDM, AOconf[loop].sizeyDM + */ + + + AOconf[loop].DMMODE = AOloopControl_readParam_int("DMMODE", 0, fplog); // zonal DM by default + + aoconfID_dmC = image_ID(AOconf[loop].dmCname); + if(aoconfID_dmC==-1) + { + printf("connect to %s\n", AOconf[loop].dmCname); + aoconfID_dmC = read_sharedmem_image(AOconf[loop].dmCname); + if(aoconfID_dmC==-1) + { + printf("ERROR: cannot connect to shared memory %s\n", AOconf[loop].dmCname); + exit(0); + } + } + AOconf[loop].sizexDM = data.image[aoconfID_dmC].md[0].size[0]; + AOconf[loop].sizeyDM = data.image[aoconfID_dmC].md[0].size[1]; + AOconf[loop].sizeDM = AOconf[loop].sizexDM*AOconf[loop].sizeyDM; + + fprintf(fplog, "Connected to DM %s, size = %ld x %ld\n", AOconf[loop].dmCname, AOconf[loop].sizexDM, AOconf[loop].sizeyDM); + + + + + + /** + * - AOconf[loop].dmRMname : DM response matrix channel + * + */ + aoconfID_dmRM = image_ID(AOconf[loop].dmRMname); + if(aoconfID_dmRM==-1) + { + printf("connect to %s\n", AOconf[loop].dmRMname); + aoconfID_dmRM = read_sharedmem_image(AOconf[loop].dmRMname); + if(aoconfID_dmRM==-1) + { + printf("ERROR: cannot connect to shared memory %s\n", AOconf[loop].dmRMname); + exit(0); + } + } + fprintf(fplog, "stream %s loaded as ID = %ld\n", AOconf[loop].dmRMname, aoconfID_dmRM); + + + + + /// Connect to DM modes shared mem + aoconfID_DMmodes = image_ID(AOconf[loop].DMmodesname); + if(aoconfID_DMmodes==-1) + { + printf("connect to %s\n", AOconf[loop].DMmodesname); + aoconfID_DMmodes = read_sharedmem_image(AOconf[loop].DMmodesname); + if(aoconfID_DMmodes==-1) + { + printf("ERROR: cannot connect to shared memory %s\n", AOconf[loop].DMmodesname); + exit(0); + } + } + fprintf(fplog, "stream %s loaded as ID = %ld\n", AOconf[loop].DMmodesname, aoconfID_DMmodes); + AOconf[loop].NBDMmodes = data.image[aoconfID_DMmodes].md[0].size[2]; + printf("NBmodes = %ld\n", AOconf[loop].NBDMmodes); + + + + + + /** + * ## 3. Load DM modes (if level >= 10) + * + * + * */ + + fprintf(fplog, "\n\n============== 3. Load DM modes (if level >= 10) ===================\n\n"); + + + + if(level>=10) // Load DM modes (will exit if not successful) + { + /** + * Load AOconf[loop].DMmodesname \n + * if already exists in local memory, trust it and adopt it \n + * if not, load from ./conf/shmim_DMmodes.fits \n + * + */ + + aoconfID_DMmodes = image_ID(AOconf[loop].DMmodesname); + + + + if(aoconfID_DMmodes == -1) // If not, check file + { + long ID1tmp, ID2tmp; + int vOK; + + + + if(sprintf(fname, "./conf/shmim_DMmodes.fits") < 1) + printERROR(__FILE__, __func__, __LINE__, "sprintf wrote <1 char"); + + printf("Checking file \"%s\"\n", fname); + + // GET SIZE FROM FILE + ID1tmp = load_fits(fname, "tmp3Dim", 1); + if(ID1tmp==-1) + { + printf("WARNING: no file \"%s\" -> loading zonal modes\n", fname); + + if(sprintf(fname, "./conf/shmim_DMmodes_zonal.fits") <1) + printERROR(__FILE__, __func__, __LINE__, "sprintf wrote <1 char"); + + ID1tmp = load_fits(fname, "tmp3Dim", 1); + if(ID1tmp==-1) + { + printf("ERROR: cannot read zonal modes \"%s\"\n", fname); + exit(0); + } + } + + + // check size + if(data.image[ID1tmp].md[0].naxis != 3) + { + printf("ERROR: File \"%s\" is not a 3D image (cube)\n", fname); + exit(0); + } + if(data.image[ID1tmp].md[0].size[0] != AOconf[loop].sizexDM) + { + printf("ERROR: File \"%s\" has wrong x size: should be %ld, is %ld\n", fname, AOconf[loop].sizexDM, (long) data.image[ID1tmp].md[0].size[0]); + exit(0); + } + if(data.image[ID1tmp].md[0].size[1] != AOconf[loop].sizeyDM) + { + printf("ERROR: File \"%s\" has wrong y size: should be %ld, is %ld\n", fname, AOconf[loop].sizeyDM, (long) data.image[ID1tmp].md[0].size[1]); + exit(0); + } + AOconf[loop].NBDMmodes = data.image[ID1tmp].md[0].size[2]; + + printf("NUMBER OF MODES = %ld\n", AOconf[loop].NBDMmodes); + + // try to read it from shared memory + ID2tmp = read_sharedmem_image(AOconf[loop].DMmodesname); + vOK = 0; + if(ID2tmp != -1) // if shared memory exists, check its size + { + vOK = 1; + if(data.image[ID2tmp].md[0].naxis != 3) + { + printf("ERROR: Shared memory File %s is not a 3D image (cube)\n", AOconf[loop].DMmodesname); + vOK = 0; + } + if(data.image[ID2tmp].md[0].size[0] != AOconf[loop].sizexDM) + { + printf("ERROR: Shared memory File %s has wrong x size: should be %ld, is %ld\n", AOconf[loop].DMmodesname, AOconf[loop].sizexDM, (long) data.image[ID2tmp].md[0].size[0]); + vOK = 0; + } + if(data.image[ID2tmp].md[0].size[1] != AOconf[loop].sizeyDM) + { + printf("ERROR: Shared memory File %s has wrong y size: should be %ld, is %ld\n", AOconf[loop].DMmodesname, AOconf[loop].sizeyDM, (long) data.image[ID2tmp].md[0].size[1]); + vOK = 0; + } + if(data.image[ID2tmp].md[0].size[2] != AOconf[loop].NBDMmodes) + { + printf("ERROR: Shared memory File %s has wrong y size: should be %ld, is %ld\n", AOconf[loop].DMmodesname, AOconf[loop].NBDMmodes, (long) data.image[ID2tmp].md[0].size[2]); + vOK = 0; + } + + if(vOK==1) // if size is OK, adopt it + aoconfID_DMmodes = ID2tmp; + else // if not, erase shared memory + { + printf("SHARED MEM IMAGE HAS WRONG SIZE -> erasing it\n"); + delete_image_ID(AOconf[loop].DMmodesname); + } + } + + + if(vOK==0) // create shared memory + { + + sizearray[0] = AOconf[loop].sizexDM; + sizearray[1] = AOconf[loop].sizeyDM; + sizearray[2] = AOconf[loop].NBDMmodes; + printf("Creating %s [%ld x %ld x %ld]\n", AOconf[loop].DMmodesname, (long) sizearray[0], (long) sizearray[1], (long) sizearray[2]); + fflush(stdout); + aoconfID_DMmodes = create_image_ID(AOconf[loop].DMmodesname, 3, sizearray, _DATATYPE_FLOAT, 1, 0); + } + + // put modes into shared memory + + switch (data.image[ID1tmp].md[0].atype) { + case _DATATYPE_FLOAT : + memcpy(data.image[aoconfID_DMmodes].array.F, data.image[ID1tmp].array.F, sizeof(float)*AOconf[loop].sizexDM*AOconf[loop].sizeyDM*AOconf[loop].NBDMmodes); + break; + case _DATATYPE_DOUBLE : + for(ii=0; ii=10) + { + long ID; + + // Load/create modal command vector memory + if(sprintf(name, "aol%ld_DMmode_cmd", loop) < 1) + printERROR(__FILE__, __func__, __LINE__, "sprintf wrote <1 char"); + aoconfID_cmd_modes = AOloopControl_IOtools_2Dloadcreate_shmim(name, "", AOconf[loop].NBDMmodes, 1, 0.0); + + + if(sprintf(name, "aol%ld_DMmode_meas", loop) < 1) + printERROR(__FILE__, __func__, __LINE__, "sprintf wrote <1 char"); + aoconfID_meas_modes = AOloopControl_IOtools_2Dloadcreate_shmim(name, "", AOconf[loop].NBDMmodes, 1, 0.0); + + if(sprintf(name, "aol%ld_DMmode_AVE", loop) < 1) + printERROR(__FILE__, __func__, __LINE__, "sprintf wrote <1 char"); + aoconfID_AVE_modes = AOloopControl_IOtools_2Dloadcreate_shmim(name, "", AOconf[loop].NBDMmodes, 1, 0.0); + + if(sprintf(name, "aol%ld_DMmode_RMS", loop) < 1) + printERROR(__FILE__, __func__, __LINE__, "sprintf wrote <1 char"); + aoconfID_RMS_modes = AOloopControl_IOtools_2Dloadcreate_shmim(name, "", AOconf[loop].NBDMmodes, 1, 0.0); + + if(sprintf(name, "aol%ld_DMmode_GAIN", loop) < 1) + printERROR(__FILE__, __func__, __LINE__, "sprintf wrote <1 char"); + aoconfID_DMmode_GAIN = AOloopControl_IOtools_2Dloadcreate_shmim(name, "", AOconf[loop].NBDMmodes, 1, 1.0); + + if(sprintf(name, "aol%ld_DMmode_LIMIT", loop) < 1) + printERROR(__FILE__, __func__, __LINE__, "sprintf wrote <1 char"); + aoconfID_LIMIT_modes = AOloopControl_IOtools_2Dloadcreate_shmim(name, "", AOconf[loop].NBDMmodes, 1, 1.0); + + if(sprintf(name, "aol%ld_DMmode_MULTF", loop) < 1) + printERROR(__FILE__, __func__, __LINE__, "sprintf wrote <1 char"); + aoconfID_MULTF_modes = AOloopControl_IOtools_2Dloadcreate_shmim(name, "", AOconf[loop].NBDMmodes, 1, 1.0); + + + if(sprintf(name, "aol%ld_wfsmask", loop) < 1) + printERROR(__FILE__, __func__, __LINE__, "sprintf wrote <1 char"); + sprintf(fname, "conf/%s.fits", name); + aoconfID_wfsmask = AOloopControl_IOtools_2Dloadcreate_shmim(name, fname, AOconf[loop].sizexWFS, AOconf[loop].sizeyWFS, 1.0); + AOconf[loop].activeWFScnt = 0; + for(ii=0; ii0.5) + AOconf[loop].activeWFScnt++; + + if(sprintf(name, "aol%ld_dmmask", loop) < 1) + printERROR(__FILE__, __func__, __LINE__, "sprintf wrote <1 char"); + if(sprintf(fname, "conf/%s.fits", name) < 1) + printERROR(__FILE__, __func__, __LINE__, "sprintf wrote <1 char"); + aoconfID_dmmask = AOloopControl_IOtools_2Dloadcreate_shmim(name, fname, AOconf[loop].sizexDM, AOconf[loop].sizeyDM, 1.0); + AOconf[loop].activeDMcnt = 0; + for(ii=0; ii0.5) + AOconf[loop].activeDMcnt++; + + printf(" AOconf[loop].activeWFScnt = %ld\n", AOconf[loop].activeWFScnt ); + printf(" AOconf[loop].activeDMcnt = %ld\n", AOconf[loop].activeDMcnt ); + + + AOconf[loop].init_RM = 0; + if(sprintf(fname, "conf/shmim_respM.fits") < 1) + printERROR(__FILE__, __func__, __LINE__, "sprintf wrote <1 char"); + + aoconfID_respM = AOloopControl_IOtools_3Dloadcreate_shmim(AOconf[loop].respMname, fname, AOconf[loop].sizexWFS, AOconf[loop].sizeyWFS, AOconf[loop].NBDMmodes, 0.0); + AOconf[loop].init_RM = 1; + + + + AOconf[loop].init_CM = 0; + if(sprintf(fname, "conf/shmim_contrM.fits") < 1) + printERROR(__FILE__, __func__, __LINE__, "sprintf wrote <1 char"); + + aoconfID_contrM = AOloopControl_IOtools_3Dloadcreate_shmim(AOconf[loop].contrMname, fname, AOconf[loop].sizexWFS, AOconf[loop].sizeyWFS, AOconf[loop].NBDMmodes, 0.0); + AOconf[loop].init_CM = 1; + + if((fp=fopen("conf/param_NBmodeblocks.txt", "r"))==NULL) + { + printf("Cannot open conf/param_NBmodeblocks.txt.... assuming 1 block\n"); + AOconf[loop].DMmodesNBblock = 1; + } + else + { + if(fscanf(fp, "%50ld", &tmpl) == 1) + AOconf[loop].DMmodesNBblock = tmpl; + else + { + printf("Cannot read conf/param_NBmodeblocks.txt.... assuming 1 block\n"); + AOconf[loop].DMmodesNBblock = 1; + } + fclose(fp); + } + + + + if(sprintf(name, "aol%ld_contrMc", loop) < 1) + printERROR(__FILE__, __func__, __LINE__, "sprintf wrote <1 char"); + if(sprintf(fname, "conf/shmim_contrMc.fits") < 1) + printERROR(__FILE__, __func__, __LINE__, "sprintf wrote <1 char"); + aoconfID_contrMc = AOloopControl_IOtools_3Dloadcreate_shmim(name, fname, AOconf[loop].sizexWFS, AOconf[loop].sizeyWFS, AOconf[loop].sizeDM, 0.0); + + if(sprintf(name, "aol%ld_contrMcact", loop) < 1) + printERROR(__FILE__, __func__, __LINE__, "sprintf wrote <1 char"); + if(sprintf(fname, "conf/shmim_contrMcact_00.fits") < 1) + printERROR(__FILE__, __func__, __LINE__, "sprintf wrote <1 char"); + aoconfID_contrMcact[0] = AOloopControl_IOtools_2Dloadcreate_shmim(name, fname, AOconf[loop].activeWFScnt, AOconf[loop].activeDMcnt, 0.0); + + + + + if(sprintf(name, "aol%ld_gainb", loop) < 1) + printERROR(__FILE__, __func__, __LINE__, "sprintf wrote <1 char"); + if(sprintf(fname, "conf/shmim_gainb.fits") < 1) + printERROR(__FILE__, __func__, __LINE__, "sprintf wrote <1 char"); + + aoconfID_gainb = AOloopControl_IOtools_2Dloadcreate_shmim(name, fname, AOconf[loop].DMmodesNBblock, 1, 0.0); + + if(sprintf(name, "aol%ld_multfb", loop) < 1) + printERROR(__FILE__, __func__, __LINE__, "sprintf wrote <1 char"); + if(sprintf(fname, "conf/shmim_multfb.fits") < 1) + printERROR(__FILE__, __func__, __LINE__, "sprintf wrote <1 char"); + aoconfID_multfb = AOloopControl_IOtools_2Dloadcreate_shmim(name, fname, AOconf[loop].DMmodesNBblock, 1, 0.0); + + if(sprintf(name, "aol%ld_limitb", loop) < 1) + printERROR(__FILE__, __func__, __LINE__, "sprintf wrote <1 char"); + if(sprintf(fname, "conf/shmim_limitb.fits") < 1) + printERROR(__FILE__, __func__, __LINE__, "sprintf wrote <1 char"); + aoconfID_limitb = AOloopControl_IOtools_2Dloadcreate_shmim(name, fname, AOconf[loop].DMmodesNBblock, 1, 0.0); + + +#ifdef _PRINT_TEST + printf("TEST - INITIALIZE contrMc, contrMcact\n"); + fflush(stdout); +#endif + + + uint_fast16_t kk; + int mstart = 0; + + for(kk=0; kk creating file\n", AOconfname); + create = 1; + } + else + { + fstat(SM_fd, &file_stat); + printf("File %s size: %zd\n", AOconfname, file_stat.st_size); + if(file_stat.st_size!=sizeof(AOLOOPCONTROL_CONF)*NB_AOloopcontrol) + { + printf("File \"%s\" size is wrong -> recreating file\n", AOconfname); + create = 1; + close(SM_fd); + } + } + + if(create==1) + { + int result; + + SM_fd = open(AOconfname, O_RDWR | O_CREAT | O_TRUNC, (mode_t)0600); + + if (SM_fd == -1) { + perror("Error opening file for writing"); + exit(0); + } + + result = lseek(SM_fd, sizeof(AOLOOPCONTROL_CONF)*NB_AOloopcontrol-1, SEEK_SET); + if (result == -1) { + close(SM_fd); + perror("Error calling lseek() to 'stretch' the file"); + exit(0); + } + + result = write(SM_fd, "", 1); + if (result != 1) { + close(SM_fd); + perror("Error writing last byte of the file"); + exit(0); + } + } + + + + + AOconf = (AOLOOPCONTROL_CONF*) mmap(0, sizeof(AOLOOPCONTROL_CONF)*NB_AOloopcontrol, PROT_READ | PROT_WRITE, MAP_SHARED, SM_fd, 0); + if (AOconf == MAP_FAILED) { + close(SM_fd); + perror("Error mmapping the file"); + exit(0); + } + + + + + if((mode==0)||(create==1)) + { + char cntname[200]; + + AOconf[loop].on = 0; + AOconf[loop].DMprimaryWriteON = 0; + AOconf[loop].DMfilteredWriteON = 0; + AOconf[loop].AUTOTUNE_LIMITS_ON = 0; + AOconf[loop].AUTOTUNE_GAINS_ON = 0; + AOconf[loop].ARPFon = 0; + AOconf[loop].cnt = 0; + AOconf[loop].cntmax = 0; + AOconf[loop].init_CMc = 0; + + if(sprintf(cntname, "aol%ld_logdata", loop) < 1) // contains loop count (cnt0) and loop gain + printERROR(__FILE__, __func__, __LINE__, "sprintf wrote <1 char"); + + if((aoconfIDlogdata = image_ID(cntname))==-1) + { + uint32_t *sizearray; + sizearray = (uint32_t*) malloc(sizeof(uint32_t)*2); + sizearray[0] = 1; + sizearray[1] = 1; + aoconfIDlogdata = create_image_ID(cntname, 2, sizearray, _DATATYPE_FLOAT, 1, 0); + free(sizearray); + } + } + + + if(create==1) + { + for(loop=0; loop 1) // drive semaphore #1 to zero + while(sem_trywait(data.image[IDzpdm].semptr[1])==0) {} + else + { + printf("ERROR: semaphore #1 missing from image %s\n", IDzpdm_name); + exit(0); + } + + while(data.signal_USR1==0) + { + memset(data.image[IDtmp].array.F, '\0', sizeof(float)*wfsxysize); + + while(zpcnt0 == data.image[IDzpdm].md[0].cnt0) + usleep(10); + + zpcnt0 = data.image[IDzpdm].md[0].cnt0; + + // TO BE DONE + // sem_wait(data.image[IDzpdm].semptr[1]); + + + printf("WFS zero point offset update # %8ld (%s -> %s) ", zpcnt, data.image[IDzpdm].name, data.image[IDwfszp].name); + fflush(stdout); + + + clock_gettime(CLOCK_REALTIME, &t1); + +# ifdef _OPENMP + #pragma omp parallel for private(elem) +# endif + for(act=0; act sum all channels to update WFS zero point +// runs in separate process from RT computation +// +// +// +int_fast8_t AOloopControl_WFSzeropoint_sum_update_loop(long loopnb, const char *ID_WFSzp_name, int NBzp, const char *IDwfsref0_name, const char *IDwfsref_name) +{ + long wfsxsize, wfsysize, wfsxysize; + long IDwfsref, IDwfsref0; + long *IDwfszparray; + long cntsumold; + int RT_priority = 95; //any number from 0-99 + struct sched_param schedpar; + long nsecwait = 10000; // 10 us + struct timespec semwaitts; + long ch; + long IDtmp; + long ii; + char name[200]; + int semval; + + + + schedpar.sched_priority = RT_priority; +#ifndef __MACH__ + if(seteuid(euid_called) != 0) //This goes up to maximum privileges + printERROR(__FILE__, __func__, __LINE__, "seteuid() returns non-zero value"); + + sched_setscheduler(0, SCHED_FIFO, &schedpar); //other option is SCHED_RR, might be faster + + if(seteuid(euid_real) != 0) //Go back to normal privileges + printERROR(__FILE__, __func__, __LINE__, "seteuid() returns non-zero value"); +#endif + + IDwfsref = image_ID(IDwfsref_name); + wfsxsize = data.image[IDwfsref].md[0].size[0]; + wfsysize = data.image[IDwfsref].md[0].size[1]; + wfsxysize = wfsxsize*wfsysize; + IDtmp = create_2Dimage_ID("wfsrefoffset", wfsxsize, wfsysize); + IDwfsref0 = image_ID(IDwfsref0_name); + + if(data.image[IDwfsref].md[0].sem > 1) // drive semaphore #1 to zero + while(sem_trywait(data.image[IDwfsref].semptr[1])==0) {} + else + { + printf("ERROR: semaphore #1 missing from image %s\n", IDwfsref_name); + exit(0); + } + + IDwfszparray = (long*) malloc(sizeof(long)*NBzp); + // create / read the zero point WFS channels + for(ch=0; ch= 1000000000) + semwaitts.tv_sec = semwaitts.tv_sec + 1; + + sem_timedwait(data.image[IDwfsref].semptr[1], &semwaitts); + + long cntsum = 0; + for(ch=0; ch PIXSTREAM_NBSLICES) + PIXSTREAM_NBSLICES = data.image[aoconfID_pixstream_wfspixindex].array.UI16[ii]; + PIXSTREAM_NBSLICES++; + printf("PIXEL STREAMING: %d image slices\n", PIXSTREAM_NBSLICES); + } + + + + printf("============ FORCE pixel streaming = 0\n"); + fflush(stdout); + COMPUTE_PIXELSTREAMING = 0; // TEST + + + printf("GPU0 = %d\n", AOconf[loop].GPU0); + if(AOconf[loop].GPU0>1) + { + uint8_t k; + for(k=0; k1) + { + uint8_t k; + for(k=0; k mode coeffs -> DM act + { +#ifdef _PRINT_TEST + printf("TEST - DMprimaryWriteON = %d\n", AOconf[loop].DMprimaryWriteON); + fflush(stdout); +#endif + + if(AOconf[loop].DMprimaryWriteON==1) // if Writing to DM + { +#ifdef _PRINT_TEST + printf("TEST - gain = %f\n", AOconf[loop].gain); + fflush(stdout); +#endif + + if(fabs(AOconf[loop].gain)>1.0e-6) + set_DM_modes(loop); + } + + } + else // 1 step: WFS -> DM act + { + if(AOconf[loop].DMprimaryWriteON==1) // if Writing to DM + { + data.image[aoconfID_dmC].md[0].write = 1; + + for(ii=0; ii replacing by 0\n", ii); + data.image[aoconfID_meas_act].array.F[ii] = 0.0; + } + } + + + + + AOconf[loop].status = 13; // enforce limits + clock_gettime(CLOCK_REALTIME, &tnow); + tdiff = info_time_diff(data.image[aoconfID_looptiming].md[0].atime.ts, tnow); + tdiffv = 1.0*tdiff.tv_sec + 1.0e-9*tdiff.tv_nsec; + data.image[aoconfID_looptiming].array.F[13] = tdiffv; + + + for(ii=0; ii AOconf[loop].maxlimit) + data.image[aoconfID_dmC].array.F[ii] = AOconf[loop].maxlimit; + if(data.image[aoconfID_dmC].array.F[ii] < -AOconf[loop].maxlimit) + data.image[aoconfID_dmC].array.F[ii] = -AOconf[loop].maxlimit; + } + + + AOconf[loop].status = 14; // write to DM + clock_gettime(CLOCK_REALTIME, &tnow); + tdiff = info_time_diff(data.image[aoconfID_looptiming].md[0].atime.ts, tnow); + tdiffv = 1.0*tdiff.tv_sec + 1.0e-9*tdiff.tv_nsec; + data.image[aoconfID_looptiming].array.F[14] = tdiffv; + + + + int semnb; + for(semnb=0; semnb 1) + { + sem_getvalue(data.image[aoconfID_dmdisp].semptr[0], &semval); + if(semval 0) + { + sem_getvalue(data.image[aoconfID_dmC].semptr[0], &semval); + if(semval 1) + { + sem_getvalue(data.image[aoconfID_dmdisp].semptr[1], &semval); + if(semval %d\n", slice, PIXSTREAM_SLICE); + // fflush(stdout); + + AOconf[loop].status = 4; // 4: REMOVING REF + clock_gettime(CLOCK_REALTIME, &tnow); + tdiff = info_time_diff(data.image[aoconfID_looptiming].md[0].atime.ts, tnow); + tdiffv = 1.0*tdiff.tv_sec + 1.0e-9*tdiff.tv_nsec; + data.image[aoconfID_looptiming].array.F[4] = tdiffv; + + + if(AOconf[loop].GPUall==0) + { + data.image[aoconfID_imWFS2].md[0].write = 1; + for(ii=0; ii MODE VALUES + clock_gettime(CLOCK_REALTIME, &tnow); + tdiff = info_time_diff(data.image[aoconfID_looptiming].md[0].atime.ts, tnow); + tdiffv = 1.0*tdiff.tv_sec + 1.0e-9*tdiff.tv_nsec; + data.image[aoconfID_looptiming].array.F[5] = tdiffv; + + + if(AOconf[loop].initmapping == 0) // compute combined control matrix or matrices + { + printf("COMPUTING MAPPING ARRAYS .... \n"); + fflush(stdout); + + clock_gettime(CLOCK_REALTIME, &t1); + + // + // There is one mapping array per WFS slice + // WFS slice 0 = all active pixels + // + WFS_active_map = (int*) malloc(sizeof(int)*AOconf[loop].sizeWFS*PIXSTREAM_NBSLICES); + if(aoconfID_wfsmask != -1) + { + for(slice=0; slice0.1) + { + if(slice==0) + { + WFS_active_map[slice*AOconf[loop].sizeWFS+ii1] = ii; + ii1++; + } + else if (data.image[aoconfID_pixstream_wfspixindex].array.UI16[ii]==slice+1) + { + WFS_active_map[slice*AOconf[loop].sizeWFS+ii1] = ii; + ii1++; + } + } + AOconf[loop].sizeWFS_active[slice] = ii1; + + char imname[200]; + if(sprintf(imname, "aol%ld_imWFS2active_%02d", LOOPNUMBER, slice) < 1) + printERROR(__FILE__, __func__, __LINE__, "sprintf wrote <1 char"); + + uint32_t *sizearray; + sizearray = (uint32_t*) malloc(sizeof(uint32_t)*2); + sizearray[0] = AOconf[loop].sizeWFS_active[slice]; + sizearray[1] = 1; + aoconfID_imWFS2_active[slice] = create_image_ID(imname, 2, sizearray, _DATATYPE_FLOAT, 1, 0); + free(sizearray); + //aoconfID_imWFS2_active[slice] = create_2Dimage_ID(imname, AOconf[loop].sizeWFS_active[slice], 1); + } + } + else + { + printf("ERROR: aoconfID_wfsmask = -1\n"); + fflush(stdout); + exit(0); + } + + + + // create DM active map + DM_active_map = (int*) malloc(sizeof(int)*AOconf[loop].sizeDM); + if(aoconfID_dmmask != -1) + { + long ii1 = 0; + for(ii=0; ii0.5) + { + DM_active_map[ii1] = ii; + ii1++; + } + AOconf[loop].sizeDM_active = ii1; + } + + + + uint32_t *sizearray; + sizearray = (uint32_t*) malloc(sizeof(uint32_t)*2); + sizearray[0] = AOconf[loop].sizeDM_active; + sizearray[1] = 1; + + char imname[200]; + if(sprintf(imname, "aol%ld_meas_act_active", LOOPNUMBER) < 1) + printERROR(__FILE__, __func__, __LINE__, "sprintf wrote <1 char"); + + aoconfID_meas_act_active = create_image_ID(imname, 2, sizearray, _DATATYPE_FLOAT, 1, 0); + free(sizearray); + + + + if(aoconfID_meas_act==-1) + { + sizearray = (uint32_t*) malloc(sizeof(uint32_t)*2); + sizearray[0] = AOconf[loop].sizexDM; + sizearray[1] = AOconf[loop].sizeyDM; + + if(sprintf(imname, "aol%ld_meas_act", LOOPNUMBER) < 1) + printERROR(__FILE__, __func__, __LINE__, "sprintf wrote <1 char"); + + aoconfID_meas_act = create_image_ID(imname, 2, sizearray, _DATATYPE_FLOAT, 1, 0); + COREMOD_MEMORY_image_set_createsem(imname, 10); + free(sizearray); + } + + clock_gettime(CLOCK_REALTIME, &t2); + tdiff = info_time_diff(t1, t2); + tdiffv = 1.0*tdiff.tv_sec + 1.0e-9*tdiff.tv_nsec; + printf("\n"); + printf("TIME TO COMPUTE MAPPING ARRAYS = %f sec\n", tdiffv); + AOconf[loop].initmapping = 1; + } + + + + + if(AOconf[loop].GPU0 == 0) // run in CPU + { + if(AOconf[loop].CMMODE==0) // goes explicitely through modes, slower but required for access to mode values + { +#ifdef _PRINT_TEST + printf("TEST - CM mult: GPU=0, CMMODE=0 - %s x %s -> %s\n", data.image[aoconfID_contrM].md[0].name, data.image[aoconfID_imWFS2].md[0].name, data.image[aoconfID_meas_modes].md[0].name); + fflush(stdout); +#endif + + data.image[aoconfID_meas_modes].md[0].write = 1; + ControlMatrixMultiply( data.image[aoconfID_contrM].array.F, data.image[aoconfID_imWFS2].array.F, AOconf[loop].NBDMmodes, AOconf[loop].sizeWFS, data.image[aoconfID_meas_modes].array.F); + COREMOD_MEMORY_image_set_sempost_byID(aoconfID_meas_modes, -1); + data.image[aoconfID_meas_modes].md[0].cnt0 ++; + data.image[aoconfID_meas_modes].md[0].write = 0; + } + else // (*) + { +#ifdef _PRINT_TEST + printf("TEST - CM mult: GPU=0, CMMODE=1 - using matrix %s\n", data.image[aoconfID_contrMc].md[0].name); + fflush(stdout); +#endif + + data.image[aoconfID_meas_modes].md[0].write = 1; + ControlMatrixMultiply( data.image[aoconfID_contrMc].array.F, data.image[aoconfID_imWFS2].array.F, AOconf[loop].sizeDM, AOconf[loop].sizeWFS, data.image[aoconfID_meas_act].array.F); + data.image[aoconfID_meas_modes].md[0].cnt0 ++; + COREMOD_MEMORY_image_set_sempost_byID(aoconfID_meas_modes, -1); + data.image[aoconfID_meas_modes].md[0].cnt0 ++; + data.image[aoconfID_meas_modes].md[0].write = 0; + } + } + else + { +#ifdef HAVE_CUDA + if(AOconf[loop].CMMODE==0) // goes explicitely through modes, slower but required for access to mode values + { +#ifdef _PRINT_TEST + printf("TEST - CM mult: GPU=1, CMMODE=0 - using matrix %s GPU alpha beta = %f %f\n", data.image[aoconfID_contrM].md[0].name, GPU_alpha, GPU_beta); + fflush(stdout); +#endif + + initWFSref_GPU[PIXSTREAM_SLICE] = 1; // default: do not re-compute reference output + + if(AOconf[loop].GPUall == 1) + { + // TEST IF contrM or wfsref have changed + if((data.image[aoconfID_wfsref].md[0].cnt0 != aoconfcnt0_wfsref_current) || (data.image[aoconfID_contrM].md[0].cnt0 != aoconfcnt0_contrM_current)) + { + printf("NEW wfsref [%10ld] or contrM [%10ld]\n", data.image[aoconfID_wfsref].md[0].cnt0, data.image[aoconfID_contrM].md[0].cnt0); + aoconfcnt0_wfsref_current = data.image[aoconfID_wfsref].md[0].cnt0; + aoconfcnt0_contrM_current = data.image[aoconfID_contrM].md[0].cnt0; + initWFSref_GPU[PIXSTREAM_SLICE] = 0; + } + + + if(initWFSref_GPU[PIXSTREAM_SLICE]==0) // initialize WFS reference + { +#ifdef _PRINT_TEST + printf("\nINITIALIZE WFS REFERENCE: COPY NEW REF (WFSREF) TO imWFS0\n"); //TEST + fflush(stdout); +#endif + + data.image[aoconfID_imWFS0].md[0].write = 1; + // TBD: replace by memcpy + for(wfselem=0; wfselem actuators linear transformation + { +#ifdef _PRINT_TEST + printf("TEST - CM mult: GPU=1, CMMODE=1\n"); + fflush(stdout); +#endif + + // depreciated: use all pixels +/* if(1==0) + { + GPU_loop_MultMat_setup(0, data.image[aoconfID_contrMc].name, data.image[aoconfID_imWFS2].name, data.image[aoconfID_meas_act].name, AOconf[loop].GPU0, GPUset0, 0, AOconf[loop].GPUusesem, 1, loop); + AOconf[loop].status = 6; + clock_gettime(CLOCK_REALTIME, &tnow); + tdiff = info_time_diff(data.image[aoconfID_looptiming].md[0].atime.ts, tnow); + tdiffv = 1.0*tdiff.tv_sec + 1.0e-9*tdiff.tv_nsec; + data.image[aoconfID_looptiming].array.F[6] = tdiffv; + + GPU_loop_MultMat_execute(0, &AOconf[loop].status, &AOconf[loop].GPUstatus[0], 1.0, 0.0, 1); + } + else // only use active pixels and actuators (**) + {*/ + + // re-map input vector into imWFS2_active + + if(AOconf[loop].GPUall == 1) // (**) + { +#ifdef _PRINT_TEST + printf("TEST - CM mult: GPU=1, CMMODE=1, GPUall = 1\n"); + fflush(stdout); +#endif + + data.image[aoconfID_imWFS2_active[PIXSTREAM_SLICE]].md[0].write = 1; + for(wfselem_active=0; wfselem_active RECOMPUTE REFERENCE x MATRIX\n", data.image[aoconfID_contrMcact[PIXSTREAM_SLICE]].md[0].name); + fflush(stdout); + + initWFSref_GPU[PIXSTREAM_SLICE] = 0; + contrMcactcnt0[PIXSTREAM_SLICE] = data.image[aoconfID_contrMcact[PIXSTREAM_SLICE]].md[0].cnt0; + } + + if(data.image[aoconfID_wfsref].md[0].cnt0 != wfsrefcnt0) // (*) + { + printf("NEW REFERENCE WFS DETECTED (%s) [ %ld %ld ]\n", data.image[aoconfID_wfsref].md[0].name, data.image[aoconfID_wfsref].md[0].cnt0, wfsrefcnt0); + fflush(stdout); + + initWFSref_GPU[PIXSTREAM_SLICE] = 0; + wfsrefcnt0 = data.image[aoconfID_wfsref].md[0].cnt0; + } + if(initWFSref_GPU[PIXSTREAM_SLICE]==0) // initialize WFS reference + { + printf("\nINITIALIZE WFS REFERENCE: COPY NEW REF (WFSREF) TO imWFS2_active\n"); //TEST + fflush(stdout); + data.image[aoconfID_imWFS2_active[PIXSTREAM_SLICE]].md[0].write = 1; + for(wfselem_active=0; wfselem_active limitval) + data.image[aoconfID_cmd_modes].array.F[k] = limitval; + + + // apply mult factor + + data.image[aoconfID_cmd_modes].array.F[k] *= AOconf[loop].mult * data.image[aoconfID_multfb].array.F[AOconf[loop].modeBlockIndex[k]] * data.image[aoconfID_MULTF_modes].array.F[k]; + + + + // update total gain + // data.image[aoconfID_DMmode_GAIN].array.F[k+AOconf[loop].NBDMmodes] = AOconf[loop].gain * data.image[aoconfID_DMmode_GAIN].array.F[k]; + } + + + data.image[aoconfID_cmd_modes].md[0].cnt0 ++; + } + + return(0); +} + + + + + + + + + + + + +int_fast8_t AOloopControl_CompModes_loop(const char *ID_CM_name, const char *ID_WFSref_name, const char *ID_WFSim_name, const char *ID_WFSimtot_name, const char *ID_coeff_name) +{ +#ifdef HAVE_CUDA + + int *GPUsetM; + long ID_CM; + long ID_WFSref; + long ID_coeff; + long GPUcnt; + int k; + int_fast8_t GPUstatus[100]; + int_fast8_t status; + long NBmodes; + uint32_t *sizearray; + + long ID_WFSim; + long ID_WFSim_n; + long wfsxsize, wfsysize; + int m; + long IDcoeff0; + + long ID_WFSimtot; + double totfluxave; + long ID_coefft; + + double alpha = 0.1; + + + GPUcnt = 2; + + GPUsetM = (int*) malloc(sizeof(int)*GPUcnt); + for(k=0; k using index = 0 +// +// if offloadMode = 1, apply correction to aol#_dmC +// +int_fast8_t AOloopControl_GPUmodecoeffs2dm_filt_loop(const char *modecoeffs_name, const char *DMmodes_name, int semTrigg, const char *out_name, int GPUindex, long loop, int offloadMode) +{ +#ifdef HAVE_CUDA + long IDmodecoeffs; + int GPUcnt, k; + int *GPUsetM; + int_fast8_t GPUstatus[100]; + int_fast8_t status; + float alpha = 1.0; + float beta = 0.0; + int initWFSref = 0; + int orientation = 1; + int use_sem = 1; + long IDout; + int write_timing = 0; + long NBmodes, m; + + float x, x2, x4, x8; + float gamma; + + uint32_t *sizearray; + char imnamecorr[200]; + long IDmodesC; + + long IDc; + long dmxsize, dmysize; + long ii; + + + int RT_priority = 80; //any number from 0-99 + struct sched_param schedpar; + + + + schedpar.sched_priority = RT_priority; +#ifndef __MACH__ + sched_setscheduler(0, SCHED_FIFO, &schedpar); +#endif + + + // read AO loop gain, mult + if(AOloopcontrol_meminit==0) + AOloopControl_InitializeMemory(1); + + + GPUcnt = 1; + GPUsetM = (int*) malloc(sizeof(int)*GPUcnt); + for(k=0; k out + + data.image[IDout].md[0].write = 1; + for(ii=0; ii found %2ld modes\n", n); + blockNBmodes[blk] = n; + + for(i=0; i modelimit[m]) + data.image[aoconfID_LIMIT_modes].array.F[m] *= (1.0 + AOconf[loop].AUTOTUNE_LIMITS_delta); + else + data.image[aoconfID_LIMIT_modes].array.F[m] *= (1.0 - AOconf[loop].AUTOTUNE_LIMITS_delta*0.01*AOconf[loop].AUTOTUNE_LIMITS_perc); + + limitblockarray[block] += data.image[aoconfID_LIMIT_modes].array.F[m]; + } + COREMOD_MEMORY_image_set_sempost_byID(aoconfID_LIMIT_modes, -1); + data.image[aoconfID_LIMIT_modes].md[0].cnt0++; + data.image[aoconfID_LIMIT_modes].md[0].write = 0; + + // update block limits to drive average limit coefficients to 1 + data.image[IDatlimbcoeff].md[0].write = 1; + for(block=0; block 1.0+AOconf[loop].AUTOTUNE_LIMITS_delta ) + coeff = 1.0+AOconf[loop].AUTOTUNE_LIMITS_delta; + data.image[aoconfID_limitb].array.F[block] = data.image[aoconfID_limitb].array.F[block] * coeff; + } + COREMOD_MEMORY_image_set_sempost_byID(IDatlimbcoeff, -1); + data.image[IDatlimbcoeff].md[0].cnt0++; + data.image[IDatlimbcoeff].md[0].write = 0; + + + COREMOD_MEMORY_image_set_sempost_byID(aoconfID_limitb, -1); + data.image[aoconfID_limitb].md[0].cnt0++; + data.image[aoconfID_limitb].md[0].write = 0; + + } + + if(AOconf[loop].AUTOTUNE_GAINS_ON==1) + { + // CONNECT to auto gain input + if(IDautogain == -1) + { + if(sprintf(imname, "aol%ld_autogain", loop) < 1) + printERROR(__FILE__, __func__, __LINE__, "sprintf wrote <1 char"); + + IDautogain = read_sharedmem_image(imname); + } + + if(IDautogain != -1) + { + if(data.image[IDautogain].md[0].cnt0 != autogainCnt) + { + float maxGainVal = 0.0; + float globalgain = 0.0; + char command[500]; + + // New gains available - updating + printf("[%ld %s] Updated autogain [%12ld %12ld] -> applying gains\n", IDautogain, data.image[IDautogain].md[0].name, (long) autogainCnt, (long) data.image[IDautogain].md[0].cnt0); + fflush(stdout); + + // Set global gain to highest gain + for(m=0;m maxGainVal) + maxGainVal = data.image[IDautogain].array.F[m]; + } + globalgain = maxGainVal; + printf(" Setting global gain = %f\n", maxGainVal); + AOconf[loop].gain = maxGainVal; + + sprintf(command, "echo \"%6.4f\" > conf/param_loopgain.txt", AOconf[loop].gain); + system(command); + + + + // Set block gain to max gain within block, scaled to global gain + for(block=0; block maxGainVal) + maxGainVal = data.image[IDautogain].array.F[m]; + + printf("Set block %2ld gain to %f\n", block, maxGainVal/globalgain); + + data.image[aoconfID_gainb].array.F[block] = maxGainVal/AOconf[loop].gain; + + + sprintf(command, "echo \"%6.4f\" > conf/param_gainb%02ld.txt", data.image[aoconfID_gainb].array.F[block], block); + system(command); + } + + // Set individual gain + for(m=0;m %12f %12f\n", m, AOconf[loop].gain, data.image[aoconfID_gainb].array.F[modeblock[m]], data.image[aoconfID_DMmode_GAIN].array.F[m], AOconf[loop].gain*data.image[aoconfID_gainb].array.F[modeblock[m]]*data.image[aoconfID_DMmode_GAIN].array.F[m], data.image[IDautogain].array.F[m]); + } + + + + autogainCnt = data.image[IDautogain].md[0].cnt0; + } + + } + + + +/* float alphagain = 0.1; + + // if update available + + data.image[aoconfID_GAIN_modes].md[0].write = 1; + data.image[aoconfID_gaiinb].md[0].write = 1; + + // Adjust gain for EACH mode + + for(m=0; m 1.0+AOconf[loop].AUTOTUNE_LIMITS_delta ) + coeff = 1.0+AOconf[loop].AUTOTUNE_LIMITS_delta; + data.image[aoconfID_limitb].array.F[block] = data.image[aoconfID_limitb].array.F[block] * coeff; + } + COREMOD_MEMORY_image_set_sempost_byID(IDatlimbcoeff, -1); + data.image[IDatlimbcoeff].md[0].cnt0++; + data.image[IDatlimbcoeff].md[0].write = 0; + + + COREMOD_MEMORY_image_set_sempost_byID(aoconfID_limitb, -1); + data.image[aoconfID_limitb].md[0].cnt0++; + data.image[aoconfID_limitb].md[0].write = 0; + */ + } + + + + if(FILTERMODE == 1) + { + for(m=0; m modelimit[m]) + { + blockavelimFrac[block] += 1.0; + data.image[IDmodevalDMnowfilt].array.F[m] = modelimit[m]; + } + if(data.image[IDmodevalDMnowfilt].array.F[m] < -modelimit[m]) + { + blockavelimFrac[block] += 1.0; + data.image[IDmodevalDMnowfilt].array.F[m] = -modelimit[m]; + } + } + } + + + + COREMOD_MEMORY_image_set_sempost_byID(IDmodevalDMnow, -1); + data.image[IDmodevalDMnow].md[0].cnt1 = modevalDMindex; + data.image[IDmodevalDMnow].md[0].cnt0++; + data.image[IDmodevalDMnow].md[0].write = 0; + + if(AOconf[loop].DMfilteredWriteON==1) + COREMOD_MEMORY_image_set_sempost_byID(IDmodevalDMnowfilt, -1); + else + { + // DM write triggered by sem 2 + // posting all sems except 2 to block DM write + COREMOD_MEMORY_image_set_sempost_excl_byID(IDmodevalDMnowfilt, 2); + } + data.image[IDmodevalDMnowfilt].md[0].cnt1 = modevalDMindex; + data.image[IDmodevalDMnowfilt].md[0].cnt0++; + data.image[IDmodevalDMnowfilt].md[0].write = 0; + + // IF MODAL DM, AND FILTERED DM WRITE IS ON, SEND TO DM + if((AOconf[loop].DMfilteredWriteON==1) && (AOconf[loop].DMMODE==1)) + { + data.image[aoconfID_dmC].md[0].write = 1; + memcpy(data.image[aoconfID_dmC].array.F, data.image[IDmodevalDMnowfilt].array.F, sizeof(float)*NBmodes); + COREMOD_MEMORY_image_set_sempost_byID(aoconfID_dmC, -1); + data.image[aoconfID_dmC].md[0].cnt1++; + data.image[aoconfID_dmC].md[0].cnt0++; + data.image[aoconfID_dmC].md[0].write = 0; + } + + + AOconf[loop].statusM = 6; + + // + // update current location of dm correction circular buffer + // + data.image[IDmodevalDM_C].md[0].write = 1; + for(m=0; mcntstart) + { + ave0[m] += data.image[IDmodevalOL].array.F[m]; + sig0[m] += data.image[IDmodevalOL].array.F[m]*data.image[IDmodevalOL].array.F[m]; + sig1[m] += diff1*diff1; + sig2[m] += diff2*diff2; + sig3[m] += diff3*diff3; + sig4[m] += diff4*diff4; + } + } + + if(TESTMODE==1) + fprintf(fptest, "%5lld %+12.10f %+12.10f %+12.10f %+12.10f %+12.10f\n", cnt, data.image[IDmodeval].array.F[TEST_m], data.image[IDmodevalOL].array.F[TEST_m], data.image[IDmodeval_dm].array.F[TEST_m], data.image[IDmodeval_dm_now].array.F[TEST_m], data.image[IDmodeval_dm_now_filt].array.F[TEST_m]); + + cnt++; + } + if(TESTMODE==1) + fclose(fptest); + + + + GainCoeff1 = 1.0/(iter+1); + if(GainCoeff1 < AOconf[loop].AUTOTUNEGAINS_updateGainCoeff) + GainCoeff1 = AOconf[loop].AUTOTUNEGAINS_updateGainCoeff; + + + data.image[IDout].md[0].write = 1; + for(m=0; m %8.6f\n", iter, AOconf[loop].AUTOTUNEGAINS_NBsamples, AOconf[loop].AUTOTUNEGAINS_updateGainCoeff, GainCoeff1); + + iter++; + + } + + free(gainval_array); + free(gainval1_array); + free(gainval2_array); + free(errarray); + + free(array_mvalOL1); + free(array_mvalOL2); + free(array_mvalOL3); + free(array_mvalOL4); + free(ave0); + free(sig0); + free(sig1); + free(sig2); + free(sig3); + free(sig4); + free(array_sig1); + free(array_sig2); + free(array_sig3); + free(array_sig4); + free(array_sig); + free(array_asq); + + free(modegain); + free(modemult); + free(NOISEfactor); + + free(stdev); + + return(0); +} + + + + + + + + + + +long AOloopControl_dm2dm_offload(const char *streamin, const char *streamout, float twait, float offcoeff, float multcoeff) +{ + long IDin, IDout; + long cnt = 0; + long xsize, ysize, xysize; + long ii; + //long IDtmp; + + + IDin = image_ID(streamin); + IDout = image_ID(streamout); + + xsize = data.image[IDin].md[0].size[0]; + ysize = data.image[IDin].md[0].size[1]; + xysize = xsize*ysize; + + while(1) + { + printf("%8ld : offloading %s -> %s\n", cnt, streamin, streamout); + + data.image[IDout].md[0].write = 1; + for(ii=0; ii-1)) + data.image[aoconfID_gainb].array.F[blocknb] = gain; + + + if(add==1) + { + long IDcontrMc0; // local storage + long IDcontrMcact0; // local storage + + + IDcontrMc0 = image_ID("contrMc0"); + if(IDcontrMc0==-1) + IDcontrMc0 = create_3Dimage_ID("contrMc0", AOconf[loop].sizexWFS, AOconf[loop].sizeyWFS, AOconf[loop].sizexDM*AOconf[loop].sizeyDM); + + + IDcontrMcact0 = image_ID("contrMcact0"); + if(IDcontrMcact0==-1) + IDcontrMcact0 = create_2Dimage_ID("contrMcact0", AOconf[loop].activeWFScnt, AOconf[loop].activeDMcnt); + + //arith_image_zero("contrM0"); + arith_image_zero("contrMc0"); + arith_image_zero("contrMcact0"); + + + for(kk=0; kkeps) + { + long ii; + + ID = image_ID(name2); +# ifdef _OPENMP + #pragma omp parallel for +# endif + for(ii=0; ii%f (%ld septs)\n", NBblock, NBstep, gainStart, gainEnd, NBgain); + + for(kg=0; kgtm_year, 1+uttime->tm_mon, uttime->tm_mday, uttime->tm_hour, uttime->tm_min, uttime->tm_sec) < 1) + printERROR(__FILE__, __func__, __LINE__, "sprintf wrote <1 char"); + + if((fp=fopen(flogname,"w"))==NULL) + { + printf("ERROR: cannot create file \"%s\"\n", flogname); + exit(0); + } + fclose(fp); + + + dmframesize = sizeof(float)*dmsize; + wfsframesize = sizeof(float)*wfssize; + + list_image_ID(); + + + + if (sigaction(SIGINT, &data.sigact, NULL) == -1) { + perror("sigaction"); + exit(EXIT_FAILURE); + } + if (sigaction(SIGTERM, &data.sigact, NULL) == -1) { + perror("sigaction"); + exit(EXIT_FAILURE); + } + if (sigaction(SIGBUS, &data.sigact, NULL) == -1) { + perror("sigaction"); + exit(EXIT_FAILURE); + } + /* if (sigaction(SIGSEGV, &data.sigact, NULL) == -1) { + perror("sigaction"); + exit(EXIT_FAILURE); + }*/ + if (sigaction(SIGABRT, &data.sigact, NULL) == -1) { + perror("sigaction"); + exit(EXIT_FAILURE); + } + if (sigaction(SIGHUP, &data.sigact, NULL) == -1) { + perror("sigaction"); + exit(EXIT_FAILURE); + } + if (sigaction(SIGPIPE, &data.sigact, NULL) == -1) { + perror("sigaction"); + exit(EXIT_FAILURE); + } + + + + k = 0; + loopOK = 1; + + while(loopOK == 1) + { + printf("Applying probe # %d %ld %ld\n", k, IDdmstream, IDwfsrefstream); + fflush(stdout); + + // apply probe + char *ptr0; + ptr0 = (char*) data.image[IDdmC].array.F; + ptr0 += k*dmframesize; + data.image[IDdmstream].md[0].write = 1; + memcpy(data.image[IDdmstream].array.F, (void*) ptr0, dmframesize); + sem_getvalue(data.image[IDdmstream].semptr[0], &semval); + if(semvaltm_hour, uttime->tm_min, uttime->tm_sec, thetime->tv_nsec) < 1) + printERROR(__FILE__, __func__, __LINE__, "sprintf wrote <1 char"); + + printf("time = %s\n", timestr); + if((fp = fopen(flogname, "a"))==NULL) + { + printf("ERROR: cannot open file \"%s\"\n", flogname); + exit(0); + } + fprintf(fp, "%s %2d %10f %10f\n", timestr, k, coeffA[k], coeffB[k]); + fclose(fp); + + usleep((long) (1.0e6*delay)); + k++; + if(k==NBprobes) + k = 0; + + if((data.signal_INT == 1)||(data.signal_TERM == 1)||(data.signal_ABRT==1)||(data.signal_BUS==1)||(data.signal_SEGV==1)||(data.signal_HUP==1)||(data.signal_PIPE==1)) + loopOK = 0; + } + + data.image[IDdmstream].md[0].write = 1; + for(ii=0; iiAOconf[LOOPNUMBER].NBDMmodes) + kmax = AOconf[LOOPNUMBER].NBDMmodes-1; + + for(k=m0; kAOconf[LOOPNUMBER].NBDMmodes) + kmax = AOconf[LOOPNUMBER].NBDMmodes-1; + + for(k=m0; kAOconf[LOOPNUMBER].NBDMmodes) + kmax = AOconf[LOOPNUMBER].NBDMmodes-1; + + for(k=m0; k