mirror of
https://github.com/slsdetectorgroup/slsDetectorPackage.git
synced 2025-04-30 18:00:05 +02:00
* dev: update 2d gain plot color map (if no x and ymin/max changes or window resizing): setFixedWidth was updating for window resize, updated virtual servers for g2 and jungfrau to keep changing gain and data for every frame. the data value (#819) * Dev/jf/fix pedestal (#821) * jf pedestal fix: touch enable bit last * dev: jf sync: stopping master gives idle (#824) * jf sync mode master could return idle when stopped and so not all modules return the same value and must check for 'stopped or idle', Also must throw if any of the module gives an error * added contains_only to sls::Result (#827) * added variadic template for checking if a result contains only specified values * fix for gcc4.8 * renamed to Result::contains_only * updated condition in Detector.cpp * stop on only the positions --------- Co-authored-by: Erik Fröjdh <erik.frojdh@gmail.com> * dev jf: change status reg bits (#829) * jf: rewrite of status reg bits, waiting state includes both wati for trigger and start frame, blocking trigger only waits if its not in waiting for trigger and run busy enabled, error state connected in firmware * dev jf: reconfigure chip when touching electron collection mode bit (#831) * jf: if bit 14 in reg 0x5d (electron mode collection bit) is changed, configure chip if v1.1 and powered on. so touch writeregister (setbit/clearbit also calls write register in the end). replace when electroncollectionmode command introduced * eiger required fw version to 32: fix for blocking trigger in quad (#834) * fix warning for prev_val (variable size array) in tests (#838) * Dev: : gui acq finished callback for different status (#850) * fix acquisition finished status to have different status for different modules, but does not have to be error. for eg. jf sync fw (2.4.1 gives idle for master and stopped for slaves when stopping acquiistion) * handling inconsistent fnums to be -1 in gui, so when one sets 0 (change of value) will also give an exception (#854) * Dev: fix py virtual test (#846) * draft to fix virtual test when it fails * catching errors in tests and removing sigchild ignore so servers (process in background) executing commands will not fail (pclose no child processes, if sigchld is ignored) fixed * uncommented python loading config * somehow killal slsReciever in second detector test fails even though no receiver running * fixing script for virtual simlator test:fixed issue with check if process running, fixed moench tests * formatting * tests for jf (#835) * execute command inside server fixed (from fix simulator tests and exec command PR) (#857) * dev: fix server logic in checking detector idle (#861) * fix buggy logic in checking detector idle and an argument check * Dev: trigger signal issues handled at acquire (#864) * if blocking and handling sync, only master gets blocking acq, slaves get non blocking as they are first and so dont get status or error caught when slaves dont get trigger (due to not connected etc) and acq returns with slaves still in waiting status. so check status of all in blocking acq * for all dets with sync, ensure atleast one master when starting acq * docs updated about sync * minor fix for test_simulator * updating docs * fixed doc * added python 3.12 to the conda build variants * documentation and examples * formatting * forward declare zmq_msg_t and moved include (#869) * forward declare zmq_msg_t and moved include * removed zmq from pkg list * removed zmq as dependency for slsdet (#870) * dev: moench: min exptime (#865) * moench: remove min clock cycles for setting exptime (had been ported from jf) * commands code generation (#871) * commands code generation (#803) * commands code generation for only frames command * fix cmake file and add Caller files * working exptime, fully extended commands file and its variants * start adding template commands * add INT_CMD_VEC_ID template * add list command, generate multiple bins, format code * reach 208 commands using the cpp macros * add tests for command parser * start adding tests for commands parser * fix typo to use commands.yaml * add more tests for command_parser * add all template functions (up to 218 commands) * finish template functions and add more CmdProxy.cpp functions (250+) * 257 commands * 300 commands the rest are very special commands * add special commands without generation * separate special functions from generated c++ file * implementing one command for put and get (buggy) * add infer action in a separate file * generate header for special commands from yaml * allow only 0 or 1 for bool inputs * group all commands in gen_commands.py * add help to gen_commands.py * add autocomplete bash script * autocompletion: add support for module levels and help * remove debugging line * add autocompletion, help to commands, change int [0,1] to bool * copy tests for Caller.cpp. Tests pass * update with the new developer branch changes * fix errors after merging (there is problems with tests) * fixed port/stopport in yaml (intput typo), added '_caller' to the test dac and test on chip dac command in global test for cmdcaller * undo previous test simulator debug change * add documentation for the generated code * reducing the comment to be replaced in length so formatting does not split into 2 lines * removed formatting specific style of C++11 in gen_commands.py to keep with the top level clang format of the project * regeneratign code for commands * automation generated * Redirect deprecated commands (#872) * working implementation, need to fix dac * fixed deprecation redirect for dac command * Detector specific autocomplete (#873) * working implementation, need to fix dac * fixed deprecation redirect for dac command * detector specific completion for dac * added autocomplete using detector specific * fixed error when autocompleting partial words * Generate commands/fix commands (#875) * fix vm_a, im_a etc have deg Celsius suffix, also help missing or changed in some places * dac: require det id for all, arg0 to be printed at output, help for onchip dac and dac, onchipdac: spacing * getscan detid and blocking trigger help * udp_Dstlist det_id fixed, but rx_id invalid * cmdApp in line with cmdLineApp (missing version, receiver_id, not creating det object in help action * added set_command to differentiate between check_det_id and require_det_id (mixed up), args: -1 needs to check for at least one argument * reordering * reordering and checked till integer_command_hex * fixed a lot more commands * fix caller tests for eiger * changes to tests after Bechir left * changing .cmd to .cmdcall for the caller commands * fixed tests for caller, still warning for setexptime about cast input * autocomplete ran * add moench test * regenerating autocomplete and commands * fixing other things from merge conflicts (renaming slsDetectorDefs to defs in commands.yaml) * formatting * added code injection to help (#876) * updated 3 commands to have get output that can be put into put (#877) * updated some commands to have get output that can be put into put * fix tests for clkdiv * adding help to free (#878) * removing old commands and renaming them, (also making it work for parameters command as it was still calling cmdproxy) (#879) * More helpful error messages for unsupported actions (#880) * removing old commands and renaming them, (also making it work for parameters command as it was still calling cmdproxy) * Added specific help for unsupported actions * fixed a vetofile get special exception message. more specific warning for special exception message instead of no function warning * added condition checking true in exceptions for special message --------- Co-authored-by: Bechir Brahem <bachbrahem@gmail.com> Co-authored-by: Erik Frojdh <erik.frojdh@gmail.com> Co-authored-by: Dhanya Thattil <dhanya.thattil@psi.ch> * Generate commands/fix det command rename (#881) * made a link to bash autocompletion script in main folder, and replaced all references to 'det' command with 'sls_detector' * Generate commands/fix detp detg command rename (#882) * replacing detp with sls_Detector_put and detg with sls_detector_get * sls_detector_not implemented, but extended message to ask user to use sls_detector_get or sls_detector_put * autocompletion also for sls_detector or det * Xilinx ctb (#884) * updated registers, arm64 * compiler set to aarch64 for xilinx server * updated RegisterDefs.h * merge into generate branch and resolving conflicts and adding the xilinx changes to callerspecial and commands.yaml * compiles and can print firmware version (using a different csp0 address) * fixing other servers (gotthard, jungfrau, moench, mythen3) that it returns in case of mapping failure, xilinxctb: added that it checks type, prints proper fw version, checks kernel date, added armprocessor define to use in common places, added specifiers to supress overflow and truncation warnings * added detector ip and mac adddress to the printout * fixed tests and recompiled servers * Xilinx client tests (#887) * implemented testbus, testfpga, set/get #frames, triggers, allowed that and for connection to client, also allowed, getnumchannels, configuremac, getrunstatus, setdetectorposition with dummy values * allowing tests for xilinx * binaries in * Dev/xilinx defaults and pattern (#888) * implemented testbus, testfpga, set/get #frames, triggers, allowed that and for connection to client, also allowed, getnumchannels, configuremac, getrunstatus, setdetectorposition with dummy values * connected kernelversion, hardwareversion, versions, framesl, triggersl, dr, timingmode, pattern (except patioctrl) thats there for altera ctb * replaced set/get64Bit to set/getU64bit in all loadpattern.c for (ctb and m3 also) * minor * updated commands generation * formatting * moench default speed set to after init readout configuration (half speed) (#886) * Fixed path when building as submodule * Moench v8 (#892) * new rct structure for moench03 * new moench data structure for offline processing * meonch raw data and zmq process files updated to 7.0.3 version * implemented config file for Zmq file * raw data and zmq work with config file, but only with one file/interface * zmq config change * added config examples for zmq and rawdata * pmod for 7.0.3 and 8.0.0 from previous releases * updated pmod 8.0.1 for rh7 and rh8 * m3 fix to get kernel version properly on nios without an incorrect error msg (#898) * moench: changed max shifts of adc clk from 240 to 200 (#900) * Protect from getenv("HOME") returning nullptr (#907) (#908) * Protect from getenv("HOME") returning nullptr (e.g., in case running in systemd) * Write proper warning in Module.cpp Co-authored-by: Filip Leonarski <filip.leonarski@psi.ch> * Dev/xilinx acq (#901) * period and exptime(patternwaittime level 0) * added new regsieterdefs and updated api version and fixedpattern reg * autogenerate commands * formatting * minor * wip resetflow, readout mode, transceiver mask, transceiver enable * acquisition, but streaming done bit and busy (exposing + read chip to fifo) not known yet from fw * programming fpga and device tree done * most configuration done, need to connect configuretransceiver to client * stuck at resetting transciever timed out * minor * fixed virtual, added chip busyto fifo, streaming busy, set/getnext framenumber * configuretransceiver from client, added help in client * make formatt and command generation * tests for xilinx ctb works * command generation * dacs added and tested, power not done * power added * added temp_fpga * binaries in * ctrlreg is 0 to enable chip=fixed, high dac val = min val= fixed, power regulators in weird order=fixed, device tree could be loaded with dacs before adcs=fixed * start works * virtual server sends * receiver works * tests * python function and enum generation, commands generatorn and autocomplete, formatting, tests * tests fail at start(transceiver not aligned) * tests passed * all binaries compiled * eiger binary in * added --nomodule cehck for xilinx * updated binaries * formatting * moench server: changed default values of adcphase for full speed from 300 to 150 and dac vipre_cds from 800 to 1280 (#922) * client bug fix: m3 multi module bad channel file throws bad allocation when modules skipped, needed to add vectors in 2d vector of bad channel list (#920) Co-authored-by: Erik Fröjdh <erik.frojdh@gmail.com> * developer: blocking acquire stop with slave temporarily in waiting (#926) * client: stopping a blocking acquire of multi modules checks status to catch slaves that might still be in waiting. Problem is (gotthard2 25um at least) slave is in waiting only temporarily before going go idle/stopped. So a 50ms sleep is necessary ot not throw an unnecessary error * client: when stopping blocking acquire, wait up to 1s in 50ms increments for slave to stop waiting temporarily * fix to rapidjson for build with gcc 14 (#929) * Dev: m3 clkdiv0 20 (#924) * m3: clk 0 changed from 10 to 20 (100MHz to 50MHz) * g2: startup clk div back to 10 as in firmware but setting in software startup to 20 * m3: minor print error if clk divider > max * G2: reconfigure chip (#927) * changed common.c readADCFromFile to make it more general and move temperature calculation for Eiger out of this function and inside whereever it is called. * g2 and m2: gethighvoltage was just a variable set in server, it is now moved to a get inside DAC5671 implementation (but not reading a measured value, instead what is set from a file), high voltage variable used inside DAC5671 for virtual servers * g2: switching off hv (ifrom non zero to zero value) will wait for 10s; powering on chip reconfigures chip; powering off chip unconfigures chip; powering off chip also includes check if hv = 0, if not throw exception; chip configuration checked before acquring; at start up: hv switched off and chip powered on, so does not wait 10s to switch off hv; * included test to check powering off chip when hv is on should throw an exception * g2: check if chip configured before acquiring * nios: read hv value set from file and virtual still goes into DAC5671 for conversions to and fro dac to V, change common readadc to readparameter to generalize, make sethighvoltage into a get and set to catch errors in get as well, g2: if not at startup, remmeber hv value before setting it and after check if value was being switched off (from a non zero value) and wait 10s if it was (10s wait only for switching off from non zero and not at startup) * developer: moench empty data callback (#936) * moench (feature to wait for post processing to be done in new sls_detector_acquire_zmq executable) READOUT_ACTION_ZMQ added to action enums sls_detector_acquire_zmq added to executables empty data call back so that client listens to last dummy zmq packet from moench post processor processor: remove NEWZMQ ifdefs and remove connect for zmq publisher socket * fix to compile * cmds generated and parsed * dev: client: status for blocking acquire stop with slave temporarily in waiting (#944) * acq finish call back gets status squashed with default error but before that need to wait for gotthard slaves to catch up from waiting to stopped * bug fixes related to file saving (#931) (#946) * fix the file path resetting issue of GUI in the case where different modules have different fpath setting. * fix stack-buffer-overflow issue when using HDF5 HDF5DataFile::parameterDataTypes have 64bit type (i.e. STD_U64LE), the size of fill_value should be at least 8 bytes. * change the type of fill_value to uint64_t Co-authored-by: Z.H. Li <zhenghenge@gmail.com> * updated documentation from martin (#948) * Dev/xilinx ctb test (#942) * voltage regulators only looks at dac and not at ctrl_reg * xilinx: change dac max to 2048, setting dac ist not inverse conversion from dac to voltage anymore, but setting power is inverse, also there is max and min to power, a different min for vio and this is checked at funcs interface, not printign or converting to mv in dac for power regulators (as its conversion max and min are different) * Use links for dacs/adc and adapt power rglt thresholds * Remove wait for transceiver reset * adc and dac device not used anymore and hence removed * udp restucturing: arm has to be multiple of 16 and no byteswap in udp_gen, option to compile locally in arm architecture, memsize of the second udp memory has to be limited --------- Co-authored-by: Martin Brückner <martin.brueckner@psi.ch> * formatting * dev: jungfrau HW 1.0: adc output clock phase to 120 (#952) * jungfrau: change adc output clock phase from 180 to 120 for v1.0 boards for reliable readout of adc #2 * versioning * formatting * rx: moved creating fpath (if it doesnt exist) from setting file path to at the start of acquisition when creating file. This is done here so that it does not fail if fwrite is disabled anyway. Also fixed it in documentation. Changed in documentation that the default for fwrite is disabled (#957) * added keepalive zmq socket option (after 60s of idle time, 10 probes every sec. Mainly because an issue at Max IV (#956) * Moench mess from developer (#953) * new moench data structure for offline processing * Dev/zmq stream all ipv6 adn remove rx_zmqip (#958) * enable ipv6 in zmq socket * removed rx_zmqip API and field in gui, changed client updaterxrzip to updateclientzmqip to have the rx_hostname ip if 0. * updated command line for rx_zmqip to give a warning. * Replaced 'depreciated' to 'deprecated' everywhere * switching from * to 0.0.0.0 works for rebinding zmq sockets * fixed help in command line for rx_zmqip * to 0.0.0.0 and removed cmd in python * remove publisher zmq socket ip also for moench post processing * fixed tests * publisher zmq ip macros to be reused * fixed a warning about narrowing conversion from size_t to int (#963) * fixed stop server not starting up with setup variables (#949) * m3: fixed stop server not starting up with setup variables * all servers except eiger fixed for virtual stop server to start up with setupDetector function called * virtual tests work * eiger: versions print neednt be in stop server * jungfrau: stop server (not virtual) also needs to read config file * ensuring master is setup for virtual and real servers * Dev/pyctbgui merge (#960) * added empty c extension * added rotation to the decoding * added color map, options and findex * minor * move checks to before acquisition * added pixel map based decoder * cleanup * no thread creation for single thread processing * added rotation and test to compare * allow high and low water mark for zmq (also buffer size) for fast readouts * removed roatation during decoding * added Transpose to image and invert Y False to invert it * retains the zoomed state after the first image of gui, catch and display exception if no detector connected * moved start frame to dockable widget, removed extra frame number label, moved current measurement also to dockable widget, hide frame plot entirely when showing patternviewer * first image dependin on which plot * remember settings of main window size and position, dockewidget if docked, its size and posisiotn as well, then update it next time the gui is opened * change in comment * using c decoder for moench 04 and matterhorn * catch exception from invalid image from decoder * clean up * update row and col when choosing image type, neeeded to show values * fix for previous PR * disable resetting colormap values keep the range selected for every new acquisition * fix typos + tested on virtual matterhorn * minor print * refactored Slow ADCs Tab * refactored DAC tab * refactored power supplies * refactored signals tab * refactored transceiver tab * fix typo * fix typo2 * remove commented code * delete commented code * delete commented code * delete commented signals code * remove commented code for transceiver tab * refactor adc tab * refactor Pattern Tab * Refactor transceivers tab (PR#5) (#118) * refactored transceiver tab * remove commented code for transceiver tab --------- Co-authored-by: Erik Frojdh <erik.frojdh@gmail.com> * refactor adc tab (PR#6) (#119) * refactor adc tab * refactored Plot and Acquisition Tabs * fix the regression issue * restructure project files * applying singleton and renaming tabs to services * working install using pip * applies singleton to tab classes and remove CI erros * added pyzmq and pillow * remove the singleton implementation and keep changes * fix merge errors in mainWindow * moved misplaced init file * rename service to tab * reorganize imports * iterate over tabs * reorder tabs * add slowadc to the list * saving changes (buggy) power supply ui not showing in the gui * split power supply tab * fixed tests * add hardcoded values to defines file * fix error * separate power supply * fix errors for powerSuppliesTab * split dacs * split slow adcs * split signals tab * added tests for bit_utils * add slowAdc class to defines * split transceiver ui file * split adc.ui * split pattern ui file * split plot and acquisition ui file * added basic test for parsing bit names * removed redundant code in read_alias_file * fix dacs ui position * testing for correct exception * cmd and args at split * group radio buttons * fix comments from PR#1 * show legend * added python version and dev requirements to setup.py * fix dac issue * moved _decoder into pkg * added inplace build * removed clear * fixed dependencies * make tests run without slsdet * updated name of action * define colcount * fixed loading of alias file * add yapf and ruff * apply formatting * fix E and F rules * add more ruff rules * change variable name * squashing gh debugging commits and add pre-commit * update label values to mv units * add hook for yapf * reconfigure yapf precommit hook * add format and check_format to makefile * change gh actions * update readme * added check_format * WIP * added linting in github action * updated readme] * add more control for color choice * remove useless file * fix un-updated line after refactoring Defines BIT0_31_MASK is not found in Defines.signals * visually improve the interface * fix last commit * add only selected plots for legend * add hide legend button * change hide legend to show legend checkbox show legend is checked by default * add support for saving in numpy * solve conversations * fix acq index offset * fix browse button in pattern error * fix other browse button errors * finish tests and add usage.md * remove buffer * add file,numpy-like interface and tests * remove useless .npy files * subscriptible npz files * remove useless files * remove repetetive tests * save changes * add mode r+, add with support,remove logging * remove offset of acqIndex between raw and numpy saving * fix only saving last frame * save signals of multiple devices * add comments and move condition for clearer code * fix bug when vieweing pattern file * iterate over enabled and plotted plots * add padestal substraction to transceiver and analog data * init pedestal frames to detector.frames * restore old exception * add pedestal substraction for digital signals * remove frames spinbox from plotTab * remove comments and use str instead of Path * avoid saving all frames * correct exception and log error's trace * add gui tests * add waveform test * add pedestal test * refactor by using fixtures * add tests for moench analog and pattern * add pytest-qt to dependencies * add save and load gui parameters * remove nohup file * fix old bug IndexError * save plot type * a * handle canceling load, loading matterhorn pedestal for moench * remove comparing .png files for pattern test * save plot type * red error on status bar when shape mismatch for loaded pedestal * fix makefile and docstrings * fix PRs conversation * move code into different function * fix wrong function names for power supply * removed old ctbgui * removed unnecessary files --------- Co-authored-by: Erik Frojdh <erik.frojdh@gmail.com> Co-authored-by: Braham Bechir <braham_b@pc11979.psi.ch> Co-authored-by: Bechir <bechir.braham@psi.ch> Co-authored-by: Bechir <bechir.brahem420@gmail.com> * Dev/xilinx mat update (#959) * put back code to obtain adc and dac device indexafter loading device tree and then create folder iio_device_links and create symbolic links there according to device indices found. ln -sf operation not permitted, so folder has to be deleted and created everytime. Also refactored definitions to have all the xilinx name or detector specific stuff out of programbyArm.c * uncommented waittransceiverreset at startup (should work now) and return of powering off chip at startup (error for transceiver alignment reset) * updated registerdefs from firmware * minor prints and updating names from registerdefs * waittransceiverreset has been fixed in firmware and removing warnign for that, transceiver alignment check for powering off chip is not done in fw (giving a warning and returning ok for now) * fixing ipchecksum (not done), removed startperiphery, allowing readout command to be allowed for xilinx when acquiring * dont build doc for Tobi Schluter from libzmq, which uses iso-8859-1 and the umlaut cause compilation to fail on some machines (#973) * 8.0.2 psi modules * missed the rx_zmqip implementations in detector.h and python bindings (#975) * rx_zmqip has been removed. Remove it also for pyctbgui (#979) * format * Dev/rx callbacks (#966) * changed rxr callback signatures to all include structs * removed datamodify call back as size can be changed in the original data call back now * bringing some parameters (set functions) to dataProcessor class for its callback (namely udpport, quad, fliprows, totalframes, jsonheader), resulting in also removing totalframes from 2 other function signatures * updated MultiReceiverApp to reflect the new callback signatures * Dev/reg bit change no validate (#970) - do not validate write reg, setbit and clearbit by default anymore - --validate will force validation on the bitmask or entire reg - remove return value for write reg (across server to client, but thankfully not in the Detector class) - extend validation into writereg, setbit and clearbit for Eiger (always special) - need to check python (TODO) - missed the rx_zmqip implementations in detector.h and python bindings * sleep implemented for command line, mainly for config files for firmware developers (#982) * change gain mode help from dynamicgain to dynamic (#988) * fixing python version. allowing versions to execute even if no detector connected or in shared memory (#990) * Jf: Electron collection mode (#983) * electron collection mode for jungfrau. also removing the config chip when using register command * collectionMode: HOLE/ELECTRON (enum) * Dev/m3 readout speed (#985) * added readoutspeed command to m3 (fullspeed - 10, half speed - 20, quarter speed - 40), removed reaodut pll, moved up system pll clock indices, leaving pll index in common altera code, default speed is half speed, allow only system_c0 to be set, the others can be obtained, same for clkphase, maxclkphaseshift, clkfreq. added to readoutspeedlist commands, updated help and updated tests * updated readoutspeedlist command * jf: timing info decoder (#987) * timing_info_decoder command with options swissfel (default) and shine. added to python, command line generation, autocomplete, tostring, tests. * updated jungfrau timing info decoder mask (#991) * minor. removed warning print at startup for empty eth udp to listen to (#992) * removed 'Caller/CALLER' from test names as there is only one command line now (#993) * formatting * Dev/g2 stop frame number (#980) * get/set next frame number in G2 (firmware only has set, no get) * firmware has issues: each stop keeps 2 frame header in fifo and the resetting frame number happens after that * removed the option to set burstmode to burst external or continuwous internal * needs to be revisited before 9.0.0 * formatting * fix the command help in the command help generator for Gotthard2 about nextframenumber (#994) * first draft at fixing nextframenumber properly with firmware (#995) * fixing nextframenumber properly with firmware * updated firmware to have getnextframenumber and fixed setnextframenumber to reset also the header fifo when stopping * fix tests for gotthard2 * Dev/g2 fix next frame number (#996) * binaries in * formatting * release notes * release notes * updating firmware dates * release notes * package release version and renaming server names * updated client versioning * updated moench fw release version * 900/proper free (#1002) * first draft of fixing the free function available within the class * removed class member function freeSharedmemory for both Detector and Module; made the free function freeSharedmemory accessible to python interface; setHostname if there is already a module in shm will recreate the Detector object while freeing shm completely and keeping detsize and intitialchecks (previous commit), sethostname called from DetectorClass in virtual command to have one point of entry (previous commit), testing Module class frees shared memory using free function * Detector class: added copy and move constructor and assignmentoperators due to explicit destructor (DetectorImpl fwd declared), DetectorImpl class: included ZmqSocket to remove destructor (should not be virtual in any case), Module class: removed explciit destructor to allow compiler generated constructor and operators * formatting * updated client version date * minor fix for readme autocomplete * setting detsize after hostname should throw also for single module for consistency (#999) * 900/autocomplete documentation (#1003) * fixed the gendoc to reflect the new parser, updated documentation to include info about autocomplete in the command line part, error in createing docs * fixed list deprecated, fixed command help (to show properly on a html, fixed other help warnings * minor indents * 900/g2 chip configure at startup (#1008) * g2: chip reconfigure variable not set when powering on at startup because readconfig is the one configuring the chip the first time to default chip settings * cleaning up code * 900/rm volatile (#1006) * Removing volatile and replacing with atomic to ensure atomicity * compiling header include issue * 900/jf firmware rollback (#1010) * jf: rolling back firmware required to v1.5 and 2.5, updated release notes, fixed a bug when updating server (when server name same as link name:throws with no message, pedestal mode check changed for the time being for loops to be 0xFF size * compensating for jf fw bug for pedestalmode where loops should be 16 bit, but is 8 bit in fw. to be fixed in next version * formatting * fixed python test simulator to kill previous servers * gui: hide 'complete image' and just show 'missing packets' when there are missing packets in that image form the receiver (#1013) * release notes update (#1015) * 900/detach pthreads not joining (#1017) * detach the pthreads that are not joining else memory leak * release notes * removed the clean up comment, also refactored the pthread join/detach for ctb 1g * 900/server malloc check (#1020) * usleep in communication to actually relay the err message of memory allocation to the client (weird but test for now), function in server to handle memory allcoation issues (updates mess, ret and sendsit to the client and returns prior from function implementatin, setting fnum in client for the speicific functions that send to detector each argument separtely, they need to remember the fnum else they throw with the incorrect fnum * server: every malloc must check if it succeeded, rearranging so that the free is clear as well (only in funcs so far) * formatting * fixed malloc checks in other places other than funcs.c * bug fix return from previous commit * pointer bug from previous commit * formatting * binaries in * 900/document json ctb file format (#1027) * docs receiver formats rewrite * added documentation for all the receiver files, updated release notes, udpated help in commands help for timing, fixed by throwing exception for aa dividy by 0 error caused by not freeing memory (detsize) when switching between 1d and 2d detectors, removed unnecessary 'recevier up' printout, fixed dbit list 64 bit mask error in master json file (was not 64 bit before), fixed bug in reading gotthard1 data (needs to be tested) * generating commands help and formatting, also fix help for trimen command line * added ctb frame format documentation, added some links to some commands, added documentation about adding expat-devel in installation for rhel8 gui, fixed some indentation issues that screwed up command line help documentation * added ctb frame format documentation * updated documentation about zeromq-devel for <8.0.0 versions * fixed typo in python for vb_pixbuf Jungfrau dac (#1030) * fixed cli documentation (#1037) * 900: legal gain values in jungfrau simulator (#1043) * legal gain values in jungfrau simulator * typo * release notes * 900/jungfrau temp control default enable (#1041) * jungfrau: enabling temp control by default at server startup * 900: fixed invalid arguments to slsmultireceiver (#1039) * wasnt showing error message for invalid arguments to slsmultireceiver * allow 0 arguments to act like an slsReceiver with start tcp port 1954 and just 1 receiver * 9.0.0: version from file to cmake and python (#1024) - renamed conda-recipe folder - added a check to see if build and install folder exists in build.sh (conda recipe) - created VERSION file that has '0.0.0'for developer but can be updated using update_version.py that takes in a version. The script checks for semantic versioning and updates VERSION file - VERSION file also copied along with py files to slsdet in python cmakelist and build_pylib.sh (for conda), also copied in root folder for installations (for no coding purpose) - init.py and setup.py reads this file to get the version (a bit differently to find the VERSION file) - VERSION file read into cmake to get the version and also added to compile definition. So RELEASE removed from versionAPI.h (using SLS_DET_VERSION compile definiton instead) and also removed updateRelease script. - conda getting project version from environment variable SLS_DET_VERSION that is set in build_pylib.sh prior. - added 3.13 python to conda build - anything related to ctb removed from release notes as users will always use developer - sets 9.0.0 to VERSION file by running update_version.py without an argument * formatting * finalized binaries * updated m3 fw version (#1046) * release notes * fix cmake (cannot find VERSION file) when using package as subfolder as cmake_source_dir is not same anymore, add troubleshooting doc for m3 regarding loose control board for waiting status in auto timing mode, fix m3 tests to test register write (previously was read only) (#1047) * 900: bumped pybind11 version and added setuptools on host (#1050) * bumped pybind11 version and added setuptools on host * updated pybind11 tarball to 2.13 and in cmakefile to get 2.13 frpm github, also updated documentation about pybind 2.13 * update release notes, doc * updating readme --------- Co-authored-by: Erik Fröjdh <erik.frojdh@gmail.com> * 900 cmake_source_dir (#1053) * when package used as subdirectory (cmake-subfolder-example) it fails when python is used because the cmake_source_dir is now the one above package. * changed cmake_current_list_dir to cmake_current_source_dir * removing the unnecessary VERSION file installed in the root directory (from PR #1020) * 900: pybind 2.13.6 and python 3.8 (#1054) * changed pybind 2.13.0 to 2.13.6, kept conda at min 2.13.0 * changed min python version from 3.6 to 3.8 * 900/docs (#1056) * minimum python is 3.8, so >= * removed ctb frame documentation. should be in internal wiki * updated release notes * updated releate date --------- Co-authored-by: Erik Fröjdh <erik.frojdh@gmail.com> Co-authored-by: froejdh_e <erik.frojdh@psi.ch> Co-authored-by: anberga <34126852+anberga@users.noreply.github.com> Co-authored-by: Filip Leonarski <filip.leonarski@psi.ch> Co-authored-by: Z.H. Li <zhenghenge@gmail.com> Co-authored-by: Martin Brückner <martin.brueckner@psi.ch> Co-authored-by: Braham Bechir <braham_b@pc11979.psi.ch> Co-authored-by: Bechir <bechir.braham@psi.ch> Co-authored-by: Bechir <bechir.brahem420@gmail.com>
2298 lines
81 KiB
C
2298 lines
81 KiB
C
// SPDX-License-Identifier: LGPL-3.0-or-other
|
|
// Copyright (C) 2021 Contributors to the SLS Detector Package
|
|
#include "FebControl.h"
|
|
#include "Beb.h"
|
|
#include "FebRegisterDefs.h"
|
|
#include "clogger.h"
|
|
#include "sharedMemory.h"
|
|
#include "slsDetectorServer_defs.h"
|
|
|
|
#include <errno.h>
|
|
#include <fcntl.h>
|
|
#include <math.h>
|
|
#include <string.h>
|
|
#include <termios.h> // POSIX terminal control definitions(CS8, CREAD, CLOCAL..)
|
|
#include <time.h>
|
|
#include <unistd.h>
|
|
|
|
const unsigned int Feb_Control_leftAddress = 0x100;
|
|
const unsigned int Feb_Control_rightAddress = 0x200;
|
|
|
|
int Feb_Control_master = -1;
|
|
int Feb_Control_normal = 0;
|
|
int Feb_Control_activated = 1;
|
|
|
|
int Feb_Control_hv_fd = -1;
|
|
unsigned int Feb_Control_idelay[4]; // ll,lr,rl,ll
|
|
int Feb_Control_counter_bit = 1;
|
|
unsigned int Feb_Control_staticBits = 0;
|
|
unsigned int Feb_Control_acquireNReadoutMode = 0;
|
|
unsigned int Feb_Control_triggerMode = 0;
|
|
unsigned int Feb_Control_externalEnableMode = 0;
|
|
unsigned int Feb_Control_subFrameMode = 0;
|
|
unsigned int Feb_Control_quadMode = 0;
|
|
|
|
unsigned int Feb_Control_nimages = 0;
|
|
double Feb_Control_exposure_time_in_sec = 0;
|
|
int64_t Feb_Control_subframe_exposure_time_in_10nsec = 0;
|
|
int64_t Feb_Control_subframe_period_in_10nsec = 0;
|
|
double Feb_Control_exposure_period_in_sec = 0;
|
|
|
|
unsigned int Feb_Control_trimbit_size = 0;
|
|
unsigned int *Feb_Control_last_downloaded_trimbits = 0;
|
|
|
|
int64_t Feb_Control_RateTable_Tau_in_nsec = -1;
|
|
int64_t Feb_Control_RateTable_Period_in_nsec = -1;
|
|
unsigned int Feb_Control_rate_correction_table[1024] = {};
|
|
double Feb_Control_rate_meas[16384] = {};
|
|
double ratemax = -1;
|
|
|
|
// setup
|
|
void Feb_Control_activate(int activate) { Feb_Control_activated = activate; }
|
|
|
|
int Feb_Control_FebControl(int normal) {
|
|
Feb_Control_staticBits = 0;
|
|
Feb_Control_acquireNReadoutMode = 0;
|
|
Feb_Control_triggerMode = 0;
|
|
Feb_Control_externalEnableMode = 0;
|
|
Feb_Control_subFrameMode = 0;
|
|
Feb_Control_trimbit_size = 263680;
|
|
|
|
Feb_Control_last_downloaded_trimbits =
|
|
malloc(Feb_Control_trimbit_size * sizeof(int));
|
|
if (Feb_Control_last_downloaded_trimbits == NULL) {
|
|
LOG(logERROR,
|
|
("Could not allocate memory for last downloaded trimbits\n"));
|
|
return 0;
|
|
}
|
|
|
|
Feb_Control_normal = normal;
|
|
if (!Feb_Interface_SetAddress(Feb_Control_rightAddress,
|
|
Feb_Control_leftAddress))
|
|
return 0;
|
|
if (Feb_Control_activated) {
|
|
return Feb_Interface_SetByteOrder();
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
int Feb_Control_OpenSerialCommunication() {
|
|
LOG(logINFO, ("opening serial communication of hv\n"));
|
|
close(Feb_Control_hv_fd);
|
|
Feb_Control_hv_fd =
|
|
open(SPECIAL9M_HIGHVOLTAGE_PORT, O_RDWR | O_NOCTTY | O_SYNC);
|
|
if (Feb_Control_hv_fd < 0) {
|
|
LOG(logERROR, ("Unable to open port %s to set up high "
|
|
"voltage serial communciation to the blackfin\n",
|
|
SPECIAL9M_HIGHVOLTAGE_PORT));
|
|
return 0;
|
|
}
|
|
LOG(logINFO, ("Serial Port opened at %s\n", SPECIAL9M_HIGHVOLTAGE_PORT));
|
|
struct termios serial_conf;
|
|
// reset structure
|
|
memset(&serial_conf, 0, sizeof(serial_conf));
|
|
// control options
|
|
serial_conf.c_cflag = B2400 | CS8 | CREAD | CLOCAL; // 57600 too high
|
|
// input options
|
|
serial_conf.c_iflag = IGNPAR;
|
|
// output options
|
|
serial_conf.c_oflag = 0;
|
|
// line options
|
|
serial_conf.c_lflag = ICANON;
|
|
// flush input
|
|
if (tcflush(Feb_Control_hv_fd, TCIOFLUSH) < 0) {
|
|
LOG(logERROR, ("error from tcflush %d\n", errno));
|
|
return 0;
|
|
}
|
|
// set new options for the port, TCSANOW:changes occur immediately without
|
|
// waiting for data to complete
|
|
if (tcsetattr(Feb_Control_hv_fd, TCSANOW, &serial_conf) < 0) {
|
|
LOG(logERROR, ("error from tcsetattr %d\n", errno));
|
|
return 0;
|
|
}
|
|
if (tcsetattr(Feb_Control_hv_fd, TCSAFLUSH, &serial_conf) < 0) {
|
|
LOG(logERROR, ("error from tcsetattr %d\n", errno));
|
|
return 0;
|
|
}
|
|
|
|
// send the first message (which will be garbled up)
|
|
char buffer[SPECIAL9M_HIGHVOLTAGE_BUFFERSIZE];
|
|
memset(buffer, 0, SPECIAL9M_HIGHVOLTAGE_BUFFERSIZE);
|
|
buffer[SPECIAL9M_HIGHVOLTAGE_BUFFERSIZE - 1] = '\n';
|
|
strcpy(buffer, "start");
|
|
LOG(logINFO, ("sending start: '%s'\n", buffer));
|
|
int n = write(Feb_Control_hv_fd, buffer, SPECIAL9M_HIGHVOLTAGE_BUFFERSIZE);
|
|
if (n < 0) {
|
|
LOG(logERROR, ("could not write to i2c bus\n"));
|
|
return 0;
|
|
}
|
|
LOG(logDEBUG1, ("Sent: %d bytes\n", n));
|
|
return 1;
|
|
}
|
|
|
|
void Feb_Control_CloseSerialCommunication() {
|
|
if (Feb_Control_hv_fd != -1)
|
|
close(Feb_Control_hv_fd);
|
|
}
|
|
|
|
int Feb_Control_CheckSetup(int master) {
|
|
LOG(logDEBUG1, ("Checking Set up\n"));
|
|
|
|
for (unsigned int j = 0; j < 4; j++) {
|
|
if (Feb_Control_idelay[j] < 0) {
|
|
LOG(logERROR, ("idelay chip %d not set.\n", j));
|
|
return 0;
|
|
}
|
|
}
|
|
int value = 0;
|
|
if ((Feb_Control_master) && (!Feb_Control_GetHighVoltage(&value))) {
|
|
LOG(logERROR, ("high voltage not set.\n"));
|
|
return 0;
|
|
}
|
|
LOG(logDEBUG1, ("Done Checking Set up\n"));
|
|
return 1;
|
|
}
|
|
|
|
unsigned int Feb_Control_AddressToAll() {
|
|
return Feb_Control_leftAddress | Feb_Control_rightAddress;
|
|
}
|
|
|
|
int Feb_Control_SetCommandRegister(unsigned int cmd) {
|
|
if (Feb_Control_activated)
|
|
return Feb_Interface_WriteRegister(Feb_Control_AddressToAll(),
|
|
DAQ_REG_CHIP_CMDS, cmd, 0, 0);
|
|
else
|
|
return 1;
|
|
}
|
|
|
|
int Feb_Control_SetStaticBits() {
|
|
if (Feb_Control_activated) {
|
|
// program=1,m4=2,m8=4,test=8,rotest=16,cs_bar_left=32,cs_bar_right=64
|
|
if (!Feb_Interface_WriteRegister(Feb_Control_AddressToAll(),
|
|
DAQ_REG_STATIC_BITS,
|
|
Feb_Control_staticBits, 0, 0) ||
|
|
!Feb_Control_SetCommandRegister(DAQ_SET_STATIC_BIT) ||
|
|
(Feb_Control_StartDAQOnlyNWaitForFinish(5000) != STATUS_IDLE)) {
|
|
LOG(logERROR, ("Could not set static bits\n"));
|
|
return 0;
|
|
}
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
int Feb_Control_SetStaticBits1(unsigned int the_static_bits) {
|
|
Feb_Control_staticBits = the_static_bits;
|
|
return Feb_Control_SetStaticBits();
|
|
}
|
|
|
|
int Feb_Control_SetInTestModeVariable(int on) {
|
|
if (on)
|
|
Feb_Control_staticBits |=
|
|
DAQ_STATIC_BIT_CHIP_TEST; // setting test bit to high
|
|
else
|
|
Feb_Control_staticBits &=
|
|
(~DAQ_STATIC_BIT_CHIP_TEST); // setting test bit to low
|
|
return 1;
|
|
}
|
|
|
|
int Feb_Control_GetTestModeVariable() {
|
|
return Feb_Control_staticBits & DAQ_STATIC_BIT_CHIP_TEST;
|
|
}
|
|
|
|
// idelay
|
|
int Feb_Control_SetIDelays(unsigned int ndelay_units) {
|
|
int ret = Feb_Control_SetIDelays1(0, ndelay_units) &&
|
|
Feb_Control_SetIDelays1(1, ndelay_units) &&
|
|
Feb_Control_SetIDelays1(2, ndelay_units) &&
|
|
Feb_Control_SetIDelays1(3, ndelay_units);
|
|
if (ret) {
|
|
LOG(logINFO, ("IODelay set to %d\n", ndelay_units));
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int Feb_Control_SetIDelays1(
|
|
unsigned int chip_pos,
|
|
unsigned int ndelay_units) { // chip_pos 0=ll,1=lr,0=rl,1=rr
|
|
if (chip_pos > 3) {
|
|
LOG(logERROR, ("SetIDelay chip_pos %d doesn't exist.\n", chip_pos));
|
|
return 0;
|
|
}
|
|
|
|
if (chip_pos / 2 == 0) { // left fpga
|
|
if (Feb_Control_SendIDelays(Feb_Control_leftAddress, chip_pos % 2 == 0,
|
|
0xffffffff, ndelay_units)) {
|
|
Feb_Control_idelay[chip_pos] = ndelay_units;
|
|
} else {
|
|
LOG(logERROR, ("could not set idelay (left).\n"));
|
|
return 0;
|
|
}
|
|
} else {
|
|
if (Feb_Control_SendIDelays(Feb_Control_rightAddress, chip_pos % 2 == 0,
|
|
0xffffffff, ndelay_units)) {
|
|
Feb_Control_idelay[chip_pos] = ndelay_units;
|
|
} else {
|
|
LOG(logERROR, ("could not set idelay (right).\n"));
|
|
return 0;
|
|
}
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
int Feb_Control_SendIDelays(unsigned int dst_num, int chip_lr,
|
|
unsigned int channels, unsigned int ndelay_units) {
|
|
if (ndelay_units > 0x3ff)
|
|
ndelay_units = 0x3ff;
|
|
// this is global
|
|
unsigned int delay_data_valid_nclks =
|
|
15 - ((ndelay_units & 0x3c0) >> 6); // data valid delay upto 15 clks
|
|
ndelay_units &= 0x3f;
|
|
|
|
unsigned int set_left_delay_channels = chip_lr ? channels : 0;
|
|
unsigned int set_right_delay_channels = chip_lr ? 0 : channels;
|
|
|
|
LOG(logDEBUG1,
|
|
("\tSetting delays of %s chips of dst_num %d, "
|
|
"tracks 0x%x to %d, %d clks and %d units.\n",
|
|
((set_left_delay_channels != 0) ? "left" : "right"), dst_num, channels,
|
|
(((15 - delay_data_valid_nclks) << 6) | ndelay_units),
|
|
delay_data_valid_nclks, ndelay_units));
|
|
|
|
if (Feb_Control_activated) {
|
|
if (!Feb_Interface_WriteRegister(
|
|
dst_num, CHIP_DATA_OUT_DELAY_REG2,
|
|
1 << 31 | delay_data_valid_nclks << 16 | ndelay_units, 0,
|
|
0) || // the 1<<31 time enables the setting of the data valid
|
|
// delays
|
|
!Feb_Interface_WriteRegister(dst_num, CHIP_DATA_OUT_DELAY_REG3,
|
|
set_left_delay_channels, 0, 0) ||
|
|
!Feb_Interface_WriteRegister(dst_num, CHIP_DATA_OUT_DELAY_REG4,
|
|
set_right_delay_channels, 0, 0) ||
|
|
!Feb_Interface_WriteRegister(dst_num, CHIP_DATA_OUT_DELAY_REG_CTRL,
|
|
CHIP_DATA_OUT_DELAY_SET, 1, 1)) {
|
|
LOG(logERROR, ("could not SetChipDataInputDelays(...).\n"));
|
|
return 0;
|
|
}
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
// highvoltage
|
|
// only master gets to call this function
|
|
int Feb_Control_SetHighVoltage(int value) {
|
|
LOG(logDEBUG1, (" Setting High Voltage:\t"));
|
|
/*
|
|
* maximum voltage of the hv dc/dc converter:
|
|
* 300 for single module power distribution board
|
|
* 200 for 9M power distribution board
|
|
* but limit is 200V for both
|
|
*/
|
|
const float vmin = 0;
|
|
float vmax = 200;
|
|
if (Feb_Control_normal)
|
|
vmax = 300;
|
|
const float vlimit = 200;
|
|
const unsigned int ntotalsteps = 256;
|
|
unsigned int nsteps = ntotalsteps * vlimit / vmax;
|
|
unsigned int dacval = 0;
|
|
|
|
// calculate dac value
|
|
if (!Feb_Control_VoltageToDAC(value, &dacval, nsteps, vmin, vlimit)) {
|
|
LOG(logERROR,
|
|
("SetHighVoltage bad value, %d. The range is 0 to %d V.\n", value,
|
|
(int)vlimit));
|
|
return -1;
|
|
}
|
|
LOG(logINFO, ("High Voltage set to %dV\n", value));
|
|
LOG(logDEBUG1, ("High Voltage set to (%d dac):\t%dV\n", dacval, value));
|
|
|
|
return Feb_Control_SendHighVoltage(dacval);
|
|
}
|
|
|
|
int Feb_Control_GetHighVoltage(int *value) {
|
|
LOG(logDEBUG1, (" Getting High Voltage:\t"));
|
|
unsigned int dacval = 0;
|
|
|
|
if (!Feb_Control_ReceiveHighVoltage(&dacval))
|
|
return 0;
|
|
|
|
// ok, convert dac to v
|
|
/*
|
|
* maximum voltage of the hv dc/dc converter:
|
|
* 300 for single module power distribution board
|
|
* 200 for 9M power distribution board
|
|
* but limit is 200V for both
|
|
*/
|
|
const float vmin = 0;
|
|
float vmax = 200;
|
|
if (Feb_Control_normal)
|
|
vmax = 300;
|
|
const float vlimit = 200;
|
|
const unsigned int ntotalsteps = 256;
|
|
unsigned int nsteps = ntotalsteps * vlimit / vmax;
|
|
*value =
|
|
(int)(Feb_Control_DACToVoltage(dacval, nsteps, vmin, vlimit) + 0.5);
|
|
LOG(logINFO, ("High Voltage read %dV\n", *value));
|
|
LOG(logDEBUG1, ("High Voltage read (%d dac)\t%dV\n", dacval, *value));
|
|
return 1;
|
|
}
|
|
|
|
int Feb_Control_SendHighVoltage(int dacvalue) {
|
|
// normal
|
|
if (Feb_Control_normal) {
|
|
// open file
|
|
FILE *fd = fopen(NORMAL_HIGHVOLTAGE_OUTPUTPORT, "w");
|
|
if (fd == NULL) {
|
|
LOG(logERROR,
|
|
("Could not open file for writing to set high voltage\n"));
|
|
return 0;
|
|
}
|
|
// convert to string, add 0 and write to file
|
|
fprintf(fd, "%d0\n", dacvalue);
|
|
fclose(fd);
|
|
}
|
|
|
|
// 9m
|
|
else {
|
|
/*Feb_Control_OpenSerialCommunication();*/
|
|
if (Feb_Control_hv_fd == -1) {
|
|
LOG(logERROR,
|
|
("High voltage serial communication not set up for 9m\n"));
|
|
return 0;
|
|
}
|
|
|
|
char buffer[SPECIAL9M_HIGHVOLTAGE_BUFFERSIZE];
|
|
memset(buffer, 0, SPECIAL9M_HIGHVOLTAGE_BUFFERSIZE);
|
|
buffer[SPECIAL9M_HIGHVOLTAGE_BUFFERSIZE - 1] = '\n';
|
|
int n;
|
|
sprintf(buffer, "p%d", dacvalue);
|
|
LOG(logINFO, ("Sending HV: '%s'\n", buffer));
|
|
n = write(Feb_Control_hv_fd, buffer, SPECIAL9M_HIGHVOLTAGE_BUFFERSIZE);
|
|
if (n < 0) {
|
|
LOG(logERROR, ("writing to i2c bus\n"));
|
|
return 0;
|
|
}
|
|
#ifdef VERBOSEI
|
|
LOG(logINFO, ("Sent %d Bytes\n", n));
|
|
#endif
|
|
// ok/fail
|
|
memset(buffer, 0, SPECIAL9M_HIGHVOLTAGE_BUFFERSIZE);
|
|
buffer[SPECIAL9M_HIGHVOLTAGE_BUFFERSIZE - 1] = '\n';
|
|
n = read(Feb_Control_hv_fd, buffer, SPECIAL9M_HIGHVOLTAGE_BUFFERSIZE);
|
|
if (n < 0) {
|
|
LOG(logERROR, ("reading from i2c bus\n"));
|
|
return 0;
|
|
}
|
|
#ifdef VERBOSEI
|
|
LOG(logINFO, ("Received %d Bytes\n", n));
|
|
#endif
|
|
LOG(logINFO, ("Received HV: '%s'\n", buffer));
|
|
fflush(stdout);
|
|
/*Feb_Control_CloseSerialCommunication();*/
|
|
if (buffer[0] != 's') {
|
|
LOG(logERROR, ("\nError: Failed to set high voltage\n"));
|
|
return 0;
|
|
}
|
|
LOG(logINFO, ("%s\n", buffer));
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
int Feb_Control_ReceiveHighVoltage(unsigned int *value) {
|
|
|
|
// normal
|
|
if (Feb_Control_normal) {
|
|
if (readParameterFromFile(NORMAL_HIGHVOLTAGE_INPUTPORT, "high voltage",
|
|
value) == FAIL) {
|
|
LOG(logERROR, ("Could not get high voltage\n"));
|
|
return 0;
|
|
}
|
|
*value /= 10;
|
|
LOG(logINFO, ("High Voltage: %d\n", (*value)));
|
|
}
|
|
|
|
// 9m
|
|
else {
|
|
/*Feb_Control_OpenSerialCommunication();*/
|
|
|
|
if (Feb_Control_hv_fd == -1) {
|
|
LOG(logERROR,
|
|
("High voltage serial communication not set up for 9m\n"));
|
|
return 0;
|
|
}
|
|
char buffer[SPECIAL9M_HIGHVOLTAGE_BUFFERSIZE];
|
|
buffer[SPECIAL9M_HIGHVOLTAGE_BUFFERSIZE - 1] = '\n';
|
|
int n = 0;
|
|
// request
|
|
|
|
strcpy(buffer, "g ");
|
|
LOG(logINFO, ("\nSending HV: '%s'\n", buffer));
|
|
n = write(Feb_Control_hv_fd, buffer, SPECIAL9M_HIGHVOLTAGE_BUFFERSIZE);
|
|
if (n < 0) {
|
|
LOG(logERROR, ("writing to i2c bus\n"));
|
|
return 0;
|
|
}
|
|
#ifdef VERBOSEI
|
|
LOG(logINFO, ("Sent %d Bytes\n", n));
|
|
#endif
|
|
|
|
// ok/fail
|
|
memset(buffer, 0, SPECIAL9M_HIGHVOLTAGE_BUFFERSIZE);
|
|
buffer[SPECIAL9M_HIGHVOLTAGE_BUFFERSIZE - 1] = '\n';
|
|
n = read(Feb_Control_hv_fd, buffer, SPECIAL9M_HIGHVOLTAGE_BUFFERSIZE);
|
|
if (n < 0) {
|
|
LOG(logERROR, ("reading from i2c bus\n"));
|
|
return 0;
|
|
}
|
|
#ifdef VERBOSEI
|
|
LOG(logINFO, ("Received %d Bytes\n", n));
|
|
#endif
|
|
LOG(logINFO, ("Received HV: '%s'\n", buffer));
|
|
if (buffer[0] != 's') {
|
|
LOG(logERROR, ("failed to read high voltage\n"));
|
|
return 0;
|
|
}
|
|
|
|
memset(buffer, 0, SPECIAL9M_HIGHVOLTAGE_BUFFERSIZE);
|
|
buffer[SPECIAL9M_HIGHVOLTAGE_BUFFERSIZE - 1] = '\n';
|
|
n = read(Feb_Control_hv_fd, buffer, SPECIAL9M_HIGHVOLTAGE_BUFFERSIZE);
|
|
if (n < 0) {
|
|
LOG(logERROR, ("reading from i2c bus\n"));
|
|
return 0;
|
|
}
|
|
#ifdef VERBOSEI
|
|
LOG(logINFO, ("Received %d Bytes\n", n));
|
|
#endif
|
|
LOG(logINFO, ("Received HV: '%s'\n", buffer));
|
|
/*Feb_Control_OpenSerialCommunication();*/
|
|
if (!sscanf(buffer, "%d", value)) {
|
|
LOG(logERROR, ("failed to scan high voltage read\n"));
|
|
return 0;
|
|
}
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
// dacs
|
|
int Feb_Control_VoltageToDAC(float value, unsigned int *digital,
|
|
unsigned int nsteps, float vmin, float vmax) {
|
|
if (value < vmin || value > vmax)
|
|
return 0;
|
|
*digital = (int)(((value - vmin) / (vmax - vmin)) * (nsteps - 1) + 0.5);
|
|
return 1;
|
|
}
|
|
|
|
float Feb_Control_DACToVoltage(unsigned int digital, unsigned int nsteps,
|
|
float vmin, float vmax) {
|
|
return vmin + (vmax - vmin) * digital / (nsteps - 1);
|
|
}
|
|
|
|
int Feb_Control_SetDAC(unsigned int ch, int value) {
|
|
unsigned int dst_num = Feb_Control_rightAddress;
|
|
if (ch < 0 || ch > 15) {
|
|
LOG(logERROR, ("invalid ch for SetDAC.\n"));
|
|
return 0;
|
|
}
|
|
|
|
value &= 0xfff;
|
|
unsigned int dac_ic = (ch < 8) ? 1 : 2;
|
|
unsigned int dac_ch = ch % 8;
|
|
unsigned int r =
|
|
dac_ic << 30 | 3 << 16 | dac_ch << 12 | value; // 3 write and power up
|
|
|
|
if (Feb_Control_activated) {
|
|
if (!Feb_Interface_WriteRegister(dst_num, 0, r, 1, 0)) {
|
|
LOG(logERROR, ("trouble setting dac %d voltage.\n", ch));
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
float voltage = Feb_Control_DACToVoltage(value, 4096, 0, 2048);
|
|
LOG(logINFO, ("\tset to %d (%.2fmV)\n", value, voltage));
|
|
return 1;
|
|
}
|
|
|
|
int Feb_Control_SetTrimbits(unsigned int *trimbits, int top) {
|
|
LOG(logINFO, ("Setting Trimbits (top:%d)\n", top));
|
|
unsigned int trimbits_to_load_l[1024];
|
|
unsigned int trimbits_to_load_r[1024];
|
|
|
|
if (Feb_Control_Reset() == STATUS_ERROR) {
|
|
LOG(logERROR, ("could not reset DAQ.\n"));
|
|
}
|
|
|
|
for (int l_r = 0; l_r < 2; l_r++) { // l_r loop
|
|
unsigned int disable_chip_mask =
|
|
l_r ? DAQ_CS_BAR_LEFT : DAQ_CS_BAR_RIGHT;
|
|
if (Feb_Control_activated) {
|
|
if (!(Feb_Interface_WriteRegister(0xfff, DAQ_REG_STATIC_BITS,
|
|
disable_chip_mask |
|
|
DAQ_STATIC_BIT_PROGRAM |
|
|
DAQ_STATIC_BIT_M8,
|
|
0, 0) &&
|
|
Feb_Control_SetCommandRegister(DAQ_SET_STATIC_BIT) &&
|
|
(Feb_Control_StartDAQOnlyNWaitForFinish(5000) ==
|
|
STATUS_IDLE))) {
|
|
LOG(logERROR, ("Could not select chips\n"));
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
for (int row_set = 0; row_set < 16; row_set++) { // 16 rows at a time
|
|
if (row_set == 0) {
|
|
if (!Feb_Control_SetCommandRegister(
|
|
DAQ_RESET_COMPLETELY | DAQ_SEND_A_TOKEN_IN |
|
|
DAQ_LOAD_16ROWS_OF_TRIMBITS)) {
|
|
LOG(logERROR, ("Could not Feb_Control_SetCommandRegister "
|
|
"for loading trim bits.\n"));
|
|
return 0;
|
|
}
|
|
} else {
|
|
if (!Feb_Control_SetCommandRegister(
|
|
DAQ_LOAD_16ROWS_OF_TRIMBITS)) {
|
|
LOG(logERROR, ("Could not Feb_Control_SetCommandRegister "
|
|
"for loading trim bits.\n"));
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
for (int row = 0; row < 16; row++) { // row loop
|
|
int offset = 2 * 32 * row;
|
|
for (int sc = 0; sc < 32; sc++) { // supercolumn loop sc
|
|
int super_column_start_position_l =
|
|
1030 * row + l_r * 258 + sc * 8;
|
|
int super_column_start_position_r =
|
|
1030 * row + 516 + l_r * 258 + sc * 8;
|
|
|
|
/*
|
|
int super_column_start_position_l = 1024*row + l_r
|
|
*256 + sc*8; //256 per row, 8 per super column int
|
|
super_column_start_position_r = 1024*row + 512 + l_r *256
|
|
+ sc*8; //256 per row, 8 per super column
|
|
*/
|
|
int chip_sc = 31 - sc;
|
|
trimbits_to_load_l[offset + chip_sc] = 0;
|
|
trimbits_to_load_r[offset + chip_sc] = 0;
|
|
trimbits_to_load_l[offset + chip_sc + 32] = 0;
|
|
trimbits_to_load_r[offset + chip_sc + 32] = 0;
|
|
for (int i = 0; i < 8; i++) { // column loop i
|
|
|
|
if (top == 1) {
|
|
trimbits_to_load_l[offset + chip_sc] |=
|
|
(0x7 &
|
|
trimbits[row_set * 16480 +
|
|
super_column_start_position_l + i])
|
|
<< ((7 - i) * 4); // low
|
|
trimbits_to_load_l[offset + chip_sc + 32] |=
|
|
((0x38 &
|
|
trimbits[row_set * 16480 +
|
|
super_column_start_position_l +
|
|
i]) >>
|
|
3)
|
|
<< ((7 - i) * 4); // upper
|
|
trimbits_to_load_r[offset + chip_sc] |=
|
|
(0x7 &
|
|
trimbits[row_set * 16480 +
|
|
super_column_start_position_r + i])
|
|
<< ((7 - i) * 4); // low
|
|
trimbits_to_load_r[offset + chip_sc + 32] |=
|
|
((0x38 &
|
|
trimbits[row_set * 16480 +
|
|
super_column_start_position_r +
|
|
i]) >>
|
|
3)
|
|
<< ((7 - i) * 4); // upper
|
|
} else {
|
|
trimbits_to_load_l[offset + chip_sc] |=
|
|
(0x7 &
|
|
trimbits[263679 -
|
|
(row_set * 16480 +
|
|
super_column_start_position_l + i)])
|
|
<< ((7 - i) * 4); // low
|
|
trimbits_to_load_l[offset + chip_sc + 32] |=
|
|
((0x38 &
|
|
trimbits[263679 -
|
|
(row_set * 16480 +
|
|
super_column_start_position_l +
|
|
i)]) >>
|
|
3)
|
|
<< ((7 - i) * 4); // upper
|
|
trimbits_to_load_r[offset + chip_sc] |=
|
|
(0x7 &
|
|
trimbits[263679 -
|
|
(row_set * 16480 +
|
|
super_column_start_position_r + i)])
|
|
<< ((7 - i) * 4); // low
|
|
trimbits_to_load_r[offset + chip_sc + 32] |=
|
|
((0x38 &
|
|
trimbits[263679 -
|
|
(row_set * 16480 +
|
|
super_column_start_position_r +
|
|
i)]) >>
|
|
3)
|
|
<< ((7 - i) * 4); // upper
|
|
}
|
|
} // end column loop i
|
|
} // end supercolumn loop sc
|
|
} // end row loop
|
|
|
|
if (Feb_Control_activated) {
|
|
if (!Feb_Interface_WriteMemoryInLoops(Feb_Control_leftAddress,
|
|
0, 0, 1024,
|
|
trimbits_to_load_l) ||
|
|
!Feb_Interface_WriteMemoryInLoops(Feb_Control_rightAddress,
|
|
0, 0, 1024,
|
|
trimbits_to_load_r) ||
|
|
(Feb_Control_StartDAQOnlyNWaitForFinish(5000) !=
|
|
STATUS_IDLE)) {
|
|
LOG(logERROR, (" some errror in setting trimbits!\n"));
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
} // end row_set loop (groups of 16 rows)
|
|
} // end l_r loop
|
|
|
|
memcpy(Feb_Control_last_downloaded_trimbits, trimbits,
|
|
Feb_Control_trimbit_size * sizeof(unsigned int));
|
|
|
|
return Feb_Control_SetStaticBits(); // send the static bits
|
|
}
|
|
|
|
int Feb_Control_SaveAllTrimbitsTo(int value, int top) {
|
|
unsigned int chanregs[Feb_Control_trimbit_size];
|
|
for (int i = 0; i < Feb_Control_trimbit_size; i++)
|
|
chanregs[i] = value;
|
|
return Feb_Control_SetTrimbits(chanregs, top);
|
|
}
|
|
|
|
unsigned int *Feb_Control_GetTrimbits() {
|
|
return Feb_Control_last_downloaded_trimbits;
|
|
}
|
|
|
|
int Feb_Control_AcquisitionInProgress() {
|
|
unsigned int status_reg_r = 0, status_reg_l = 0;
|
|
// deactivated should return end of acquisition
|
|
if (!Feb_Control_activated)
|
|
return STATUS_IDLE;
|
|
|
|
if (!(Feb_Control_GetDAQStatusRegister(Feb_Control_rightAddress,
|
|
&status_reg_r))) {
|
|
LOG(logERROR, ("Error: Trouble reading Status register (right)"
|
|
"address\n"));
|
|
return STATUS_ERROR;
|
|
}
|
|
if (!(Feb_Control_GetDAQStatusRegister(Feb_Control_leftAddress,
|
|
&status_reg_l))) {
|
|
LOG(logERROR, ("Error: Trouble reading Status register (left)\n"));
|
|
return STATUS_ERROR;
|
|
}
|
|
// running
|
|
if ((status_reg_r | status_reg_l) & DAQ_STATUS_DAQ_RUNNING) {
|
|
return STATUS_RUNNING;
|
|
}
|
|
// idle
|
|
return STATUS_IDLE;
|
|
}
|
|
|
|
int Feb_Control_ProcessingInProgress() {
|
|
unsigned int regr = 0, regl = 0;
|
|
// deactivated should return end of processing
|
|
if (!Feb_Control_activated)
|
|
return STATUS_IDLE;
|
|
|
|
if (!Feb_Interface_ReadRegister(Feb_Control_rightAddress, FEB_REG_STATUS,
|
|
®r)) {
|
|
LOG(logERROR, ("Could not read right FEB_REG_STATUS to get feb "
|
|
"processing status\n"));
|
|
return STATUS_ERROR;
|
|
}
|
|
if (!Feb_Interface_ReadRegister(Feb_Control_leftAddress, FEB_REG_STATUS,
|
|
®l)) {
|
|
LOG(logERROR, ("Could not read left FEB_REG_STATUS to get feb "
|
|
"processing status\n"));
|
|
return STATUS_ERROR;
|
|
}
|
|
LOG(logDEBUG1, ("regl:0x%x regr:0x%x\n", regl, regr));
|
|
// processing done
|
|
if (regr & regl & FEB_REG_STATUS_ACQ_DONE_MSK) {
|
|
return STATUS_IDLE;
|
|
}
|
|
// processing running
|
|
return STATUS_RUNNING;
|
|
}
|
|
|
|
int Feb_Control_AcquisitionStartedBit() {
|
|
unsigned int status_reg_r = 0, status_reg_l = 0;
|
|
// deactivated should return acquisition started/ready
|
|
if (!Feb_Control_activated)
|
|
return 1;
|
|
|
|
if (!(Feb_Control_GetDAQStatusRegister(Feb_Control_rightAddress,
|
|
&status_reg_r))) {
|
|
LOG(logERROR, ("Error: Trouble reading Status register (right)\n"));
|
|
return -1;
|
|
}
|
|
if (!(Feb_Control_GetDAQStatusRegister(Feb_Control_leftAddress,
|
|
&status_reg_l))) {
|
|
LOG(logERROR, ("Error: Trouble reading Status register (left)\n"));
|
|
return -1;
|
|
}
|
|
// doesnt mean it started, just the bit
|
|
if ((status_reg_r | status_reg_l) & DAQ_STATUS_DAQ_RUN_TOGGLE)
|
|
return 1;
|
|
return 0;
|
|
}
|
|
|
|
int Feb_Control_WaitForStartedFlag(int sleep_time_us, int prev_flag) {
|
|
// deactivated dont wait (otherwise give a toggle value back)
|
|
if (!Feb_Control_activated)
|
|
return 1;
|
|
|
|
// did not start
|
|
if (prev_flag == -1)
|
|
return 0;
|
|
|
|
int value = prev_flag;
|
|
while (value == prev_flag) {
|
|
usleep(sleep_time_us);
|
|
value = Feb_Control_AcquisitionStartedBit();
|
|
}
|
|
|
|
// did not start
|
|
if (value == -1)
|
|
return 0;
|
|
|
|
return 1;
|
|
}
|
|
|
|
int Feb_Control_WaitForFinishedFlag(int sleep_time_us, int tempLock) {
|
|
int is_running = Feb_Control_AcquisitionInProgress();
|
|
// unlock for stop server
|
|
if (tempLock) {
|
|
sharedMemory_unlockLocalLink();
|
|
}
|
|
int check_error = 0;
|
|
|
|
// it will break out if it is idle or if check_error is more than 5 times
|
|
while (is_running != STATUS_IDLE) {
|
|
usleep(sleep_time_us);
|
|
if (tempLock) {
|
|
sharedMemory_lockLocalLink();
|
|
}
|
|
is_running = Feb_Control_AcquisitionInProgress();
|
|
if (tempLock) {
|
|
sharedMemory_unlockLocalLink();
|
|
}
|
|
// check error only 5 times (ensuring it is not something that happens
|
|
// sometimes)
|
|
if (is_running == STATUS_ERROR) {
|
|
if (check_error == 5)
|
|
break;
|
|
check_error++;
|
|
} // reset check_error for next time
|
|
else
|
|
check_error = 0;
|
|
}
|
|
// lock it again to be unlocked later
|
|
if (tempLock) {
|
|
sharedMemory_lockLocalLink();
|
|
}
|
|
return is_running;
|
|
}
|
|
|
|
int Feb_Control_GetDAQStatusRegister(unsigned int dst_address,
|
|
unsigned int *ret_status) {
|
|
// if deactivated, should be handled earlier and should not get into this
|
|
// function
|
|
if (Feb_Control_activated) {
|
|
if (!Feb_Interface_ReadRegister(dst_address, DAQ_REG_STATUS,
|
|
ret_status)) {
|
|
LOG(logERROR, ("Error: reading status register.\n"));
|
|
return 0;
|
|
}
|
|
}
|
|
*ret_status = (0x02FF0000 & *ret_status) >> 16;
|
|
return 1;
|
|
}
|
|
|
|
int Feb_Control_StartDAQOnlyNWaitForFinish(int sleep_time_us) {
|
|
if (Feb_Control_activated) {
|
|
if (!Feb_Interface_WriteRegister(Feb_Control_AddressToAll(),
|
|
DAQ_REG_CTRL, 0, 0, 0) ||
|
|
!Feb_Interface_WriteRegister(Feb_Control_AddressToAll(),
|
|
DAQ_REG_CTRL, DAQ_CTRL_START, 0, 0)) {
|
|
LOG(logERROR, ("could not start.\n"));
|
|
return 0;
|
|
}
|
|
}
|
|
return Feb_Control_WaitForFinishedFlag(sleep_time_us, 0);
|
|
}
|
|
|
|
int Feb_Control_Reset() {
|
|
LOG(logINFO, ("Feb: Reset daq\n"));
|
|
if (Feb_Control_activated) {
|
|
if (!Feb_Interface_WriteRegister(Feb_Control_AddressToAll(),
|
|
DAQ_REG_CTRL, 0, 0, 0) ||
|
|
!Feb_Interface_WriteRegister(Feb_Control_AddressToAll(),
|
|
DAQ_REG_CTRL, DAQ_CTRL_RESET, 0, 0) ||
|
|
!Feb_Interface_WriteRegister(Feb_Control_AddressToAll(),
|
|
DAQ_REG_CTRL, 0, 0, 0)) {
|
|
LOG(logERROR, ("Could not reset daq, no response.\n"));
|
|
return 0;
|
|
}
|
|
}
|
|
return Feb_Control_WaitForFinishedFlag(5000, 0);
|
|
}
|
|
|
|
int Feb_Control_ResetChipCompletely() {
|
|
if (!Feb_Control_SetCommandRegister(DAQ_RESET_COMPLETELY) ||
|
|
(Feb_Control_StartDAQOnlyNWaitForFinish(5000) != STATUS_IDLE)) {
|
|
LOG(logERROR, ("could not ResetChipCompletely() with 0x%x.\n",
|
|
DAQ_RESET_COMPLETELY));
|
|
return 0;
|
|
}
|
|
LOG(logINFO, ("Chip reset completely\n"));
|
|
return 1;
|
|
}
|
|
|
|
int Feb_Control_ResetChipPartially() {
|
|
if (!Feb_Control_SetCommandRegister(DAQ_RESET_PERIPHERY) ||
|
|
(Feb_Control_StartDAQOnlyNWaitForFinish(5000) != STATUS_IDLE)) {
|
|
LOG(logERROR, ("could not ResetChipPartially with periphery\n"));
|
|
return 0;
|
|
}
|
|
LOG(logINFO, ("Chip reset periphery 0x%x\n", DAQ_RESET_PERIPHERY));
|
|
|
|
if (!Feb_Control_SetCommandRegister(DAQ_RESET_COLUMN_SELECT) ||
|
|
(Feb_Control_StartDAQOnlyNWaitForFinish(5000) != STATUS_IDLE)) {
|
|
LOG(logERROR, ("could not ResetChipPartially with column select\n"));
|
|
return 0;
|
|
}
|
|
LOG(logINFO, ("Chip reset column select 0x%x\n", DAQ_RESET_COLUMN_SELECT));
|
|
return 1;
|
|
}
|
|
|
|
int Feb_Control_SendBitModeToBebServer() {
|
|
unsigned int just_bit_mode =
|
|
(DAQ_STATIC_BIT_M4 | DAQ_STATIC_BIT_M8) & Feb_Control_staticBits;
|
|
unsigned int bit_mode = 16; // default
|
|
if (just_bit_mode == DAQ_STATIC_BIT_M4)
|
|
bit_mode = 4;
|
|
else if (just_bit_mode == DAQ_STATIC_BIT_M8)
|
|
bit_mode = 8;
|
|
else if (Feb_Control_subFrameMode &
|
|
DAQ_NEXPOSURERS_ACTIVATE_AUTO_SUBIMAGING)
|
|
bit_mode = 32;
|
|
|
|
if (!Beb_SetUpTransferParameters(bit_mode)) {
|
|
LOG(logERROR, ("Error: sending bit mode to beb\n"));
|
|
return 0;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
unsigned int Feb_Control_ConvertTimeToRegister(float time_in_sec) {
|
|
float n_clk_cycles =
|
|
round(time_in_sec / 10e-9); // 200 MHz ctb clk or 100 MHz feb clk
|
|
|
|
unsigned int decoded_time;
|
|
if (n_clk_cycles > (pow(2, 29) - 1) * pow(10, 7)) {
|
|
float max_time = 10e-9 * (pow(2, 28) - 1) * pow(10, 7);
|
|
LOG(logERROR, ("time exceeds (%f) maximum exposure time of %f sec.\n",
|
|
time_in_sec, max_time));
|
|
LOG(logINFO, ("\t Setting to maximum %f us.\n", max_time));
|
|
decoded_time = 0xffffffff;
|
|
} else {
|
|
int power_of_ten = 0;
|
|
while (n_clk_cycles > pow(2, 29) - 1) {
|
|
power_of_ten++;
|
|
n_clk_cycles = round(n_clk_cycles / 10.0);
|
|
}
|
|
decoded_time = (int)(n_clk_cycles) << 3 | (int)(power_of_ten);
|
|
}
|
|
return decoded_time;
|
|
}
|
|
|
|
int Feb_Control_PrepareForAcquisition() {
|
|
LOG(logINFOBLUE, ("Preparing for Acquisition\n"));
|
|
if (!Feb_Control_PrintAcquisitionSetup()) {
|
|
LOG(logERROR, ("Could not prepare acquisition\n"));
|
|
return 0;
|
|
}
|
|
|
|
if (Feb_Control_Reset() == STATUS_ERROR) {
|
|
LOG(logERROR, ("Trouble reseting daq or data stream\n"));
|
|
return 0;
|
|
}
|
|
|
|
if (!Feb_Control_SetStaticBits1(Feb_Control_staticBits &
|
|
(DAQ_STATIC_BIT_M4 | DAQ_STATIC_BIT_M8))) {
|
|
LOG(logERROR, ("Trouble setting static bits\n"));
|
|
return 0;
|
|
}
|
|
|
|
if (!Feb_Control_SendBitModeToBebServer()) {
|
|
LOG(logERROR, ("Trouble sending static bits to server\n"));
|
|
return 0;
|
|
}
|
|
|
|
int ret = 0;
|
|
if (Feb_Control_counter_bit)
|
|
ret = Feb_Control_ResetChipCompletely();
|
|
else
|
|
ret = Feb_Control_ResetChipPartially();
|
|
if (!ret) {
|
|
LOG(logERROR, ("Trouble resetting chips\n"));
|
|
return 0;
|
|
}
|
|
|
|
unsigned int reg_nums[7];
|
|
unsigned int reg_vals[7];
|
|
reg_nums[0] = DAQ_REG_CTRL;
|
|
reg_vals[0] = 0;
|
|
reg_nums[1] = DAQ_REG_NEXPOSURES;
|
|
reg_vals[1] = Feb_Control_nimages;
|
|
reg_nums[2] = DAQ_REG_EXPOSURE_TIMER;
|
|
reg_vals[2] =
|
|
Feb_Control_ConvertTimeToRegister(Feb_Control_exposure_time_in_sec);
|
|
reg_nums[3] = DAQ_REG_EXPOSURE_REPEAT_TIMER;
|
|
reg_vals[3] =
|
|
Feb_Control_ConvertTimeToRegister(Feb_Control_exposure_period_in_sec);
|
|
reg_nums[4] = DAQ_REG_CHIP_CMDS;
|
|
reg_vals[4] = (Feb_Control_acquireNReadoutMode | Feb_Control_triggerMode |
|
|
Feb_Control_externalEnableMode | Feb_Control_subFrameMode);
|
|
reg_nums[5] = DAQ_REG_SUBFRAME_EXPOSURES;
|
|
reg_vals[5] = Feb_Control_subframe_exposure_time_in_10nsec;
|
|
reg_nums[6] = DAQ_REG_SUBFRAME_PERIOD;
|
|
reg_vals[6] = Feb_Control_subframe_period_in_10nsec;
|
|
if (Feb_Control_activated) {
|
|
if (!Feb_Interface_WriteRegisters(Feb_Control_AddressToAll(), 7,
|
|
reg_nums, reg_vals, 0, 0)) {
|
|
LOG(logERROR, ("Trouble starting acquisition\n"));
|
|
return 0;
|
|
}
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
int Feb_Control_PrintAcquisitionSetup() {
|
|
time_t rawtime;
|
|
time(&rawtime);
|
|
struct tm *timeinfo = localtime(&rawtime);
|
|
int dr = 0;
|
|
if (!Feb_Control_GetDynamicRange(&dr)) {
|
|
LOG(logERROR, ("Could not print acquisition set up\n"));
|
|
return 0;
|
|
}
|
|
LOG(logINFO, ("Starting an exposure: (%s)"
|
|
"\t Dynamic range nbits: %d\n"
|
|
"\t Trigger mode: 0x%x\n"
|
|
"\t Number of exposures: %d\n"
|
|
"\t Exsposure time (if used): %f seconds.\n"
|
|
"\t Exsposure period (if used): %f seconds.\n\n",
|
|
asctime(timeinfo), dr, Feb_Control_triggerMode,
|
|
Feb_Control_GetNExposures(), Feb_Control_exposure_time_in_sec,
|
|
Feb_Control_exposure_period_in_sec));
|
|
|
|
return 1;
|
|
}
|
|
|
|
int Feb_Control_StartAcquisition() {
|
|
LOG(logINFOBLUE, ("Starting Acquisition\n"));
|
|
unsigned int reg_nums[15];
|
|
unsigned int reg_vals[15];
|
|
for (int i = 0; i < 14; i++) {
|
|
reg_nums[i] = DAQ_REG_CTRL;
|
|
reg_vals[i] = 0;
|
|
}
|
|
reg_nums[14] = DAQ_REG_CTRL;
|
|
reg_vals[14] = ACQ_CTRL_START;
|
|
if (Feb_Control_activated) {
|
|
if (!Feb_Interface_WriteRegisters(Feb_Control_AddressToAll(), 15,
|
|
reg_nums, reg_vals, 0, 0)) {
|
|
LOG(logERROR, ("Trouble starting acquisition\n"));
|
|
return 0;
|
|
}
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
int Feb_Control_StopAcquisition() {
|
|
if (Feb_Control_activated) {
|
|
|
|
// sends last frames from fifo
|
|
unsigned int orig_value = 0;
|
|
if (!Feb_Interface_ReadRegister(Feb_Control_AddressToAll(),
|
|
DAQ_REG_CTRL, &orig_value)) {
|
|
LOG(logERROR, ("Could not read DAQ_REG_CTRL to stop acquisition "
|
|
"(send complete frames)\n"));
|
|
return 0;
|
|
}
|
|
if (!Feb_Interface_WriteRegister(Feb_Control_AddressToAll(),
|
|
DAQ_REG_CTRL,
|
|
orig_value | DAQ_CTRL_STOP, 0, 0)) {
|
|
LOG(logERROR, ("Could not send last frames.\n"));
|
|
return 0;
|
|
}
|
|
LOG(logINFO, ("Feb: Command to Flush out images from fifo\n"));
|
|
|
|
// wait for feb processing to be done
|
|
int is_processing = Feb_Control_ProcessingInProgress();
|
|
int check_error = 0;
|
|
int check_stuck = 0;
|
|
while (is_processing != STATUS_IDLE) {
|
|
usleep(500);
|
|
is_processing = Feb_Control_ProcessingInProgress();
|
|
|
|
// check error only 5 times (ensuring it is not something that
|
|
// happens sometimes)
|
|
if (is_processing == STATUS_ERROR) {
|
|
if (check_error == 5)
|
|
break;
|
|
check_error++;
|
|
} // reset check_error for next time
|
|
else {
|
|
check_error = 0;
|
|
}
|
|
|
|
// check stuck only 2000 times (1s)
|
|
if (is_processing == STATUS_RUNNING) {
|
|
if (check_stuck == 2000) {
|
|
LOG(logERROR,
|
|
("Unable to get feb processing done signal\n"));
|
|
// at least it is idle
|
|
if (Feb_Control_AcquisitionInProgress() == STATUS_IDLE) {
|
|
return 1;
|
|
}
|
|
LOG(logERROR, ("Unable to get acquisition done signal\n"));
|
|
return 0;
|
|
}
|
|
check_stuck++;
|
|
} // reset check_stuck for next time
|
|
else {
|
|
check_stuck = 0;
|
|
}
|
|
}
|
|
LOG(logINFO, ("Feb: Processing done (to stop acq)\n"));
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
int Feb_Control_IsReadyForTrigger(int *readyForTrigger) {
|
|
unsigned int addr[2] = {Feb_Control_leftAddress, Feb_Control_rightAddress};
|
|
unsigned int value[2] = {0, 0};
|
|
|
|
for (int i = 0; i < 2; ++i) {
|
|
if (!Feb_Interface_ReadRegister(addr[i], FEB_REG_STATUS, &value[i])) {
|
|
LOG(logERROR, ("Could not read %s FEB_REG_STATUS reg\n",
|
|
(i == 0 ? "left" : "right")));
|
|
return 0;
|
|
}
|
|
}
|
|
*readyForTrigger =
|
|
((value[0] | value[1]) & FEB_REG_STATUS_WAIT_FOR_TRGGR_MSK);
|
|
return 1;
|
|
}
|
|
|
|
int Feb_Control_SendSoftwareTrigger() {
|
|
// read old value in register
|
|
unsigned int orig_value = 0;
|
|
if (!Feb_Interface_ReadRegister(Feb_Control_AddressToAll(),
|
|
DAQ_REG_CHIP_CMDS, &orig_value)) {
|
|
LOG(logERROR, ("Could not read DAQ_REG_CHIP_CMDS to send software "
|
|
"trigger\n"));
|
|
return 0;
|
|
}
|
|
unsigned int cmd = orig_value | DAQ_REG_CHIP_CMDS_INT_TRIGGER;
|
|
|
|
// set trigger bit
|
|
LOG(logDEBUG1, ("Setting Trigger, Register:0x%x\n", cmd));
|
|
if (!Feb_Interface_WriteRegister(Feb_Control_AddressToAll(),
|
|
DAQ_REG_CHIP_CMDS, cmd, 0, 0)) {
|
|
LOG(logERROR, ("Could not give software trigger\n"));
|
|
return 0;
|
|
}
|
|
// unset trigger bit
|
|
LOG(logDEBUG1, ("Unsetting Trigger, Register:0x%x\n", orig_value));
|
|
if (!Feb_Interface_WriteRegister(Feb_Control_AddressToAll(),
|
|
DAQ_REG_CHIP_CMDS, orig_value, 0, 0)) {
|
|
LOG(logERROR, ("Could not give software trigger\n"));
|
|
return 0;
|
|
}
|
|
LOG(logDEBUG1, ("Software Internal Trigger Sent!\n"));
|
|
return 1;
|
|
}
|
|
|
|
int Feb_Control_SoftwareTrigger(int block) {
|
|
if (Feb_Control_activated) {
|
|
// cant read reg
|
|
int readyForTrigger = 0;
|
|
if (!Feb_Control_IsReadyForTrigger(&readyForTrigger)) {
|
|
LOG(logERROR, ("Could not read FEB_REG_STATUS reg!\n"));
|
|
return 0;
|
|
}
|
|
// if not ready for trigger, throw
|
|
if (!readyForTrigger) {
|
|
LOG(logWARNING, ("Not yet ready for trigger!\n"));
|
|
return 0;
|
|
}
|
|
|
|
// send trigger to both fpgas
|
|
Feb_Control_SendSoftwareTrigger();
|
|
|
|
// wait for next trigger ready
|
|
if (block) {
|
|
LOG(logDEBUG1, ("Blocking Software Trigger\n"));
|
|
int readyForTrigger = 0;
|
|
if (!Feb_Control_IsReadyForTrigger(&readyForTrigger)) {
|
|
LOG(logERROR, ("Could not read FEB_REG_STATUS reg after giving "
|
|
"trigger!\n"));
|
|
return 0;
|
|
}
|
|
|
|
while (!readyForTrigger) {
|
|
// end of acquisition (cannot monitor readyForTrigger)
|
|
int status = Feb_Control_AcquisitionInProgress();
|
|
if (status == STATUS_ERROR) {
|
|
LOG(logERROR,
|
|
("Status: ERROR reading DAQ status register\n"));
|
|
return 0;
|
|
} else if (status == STATUS_IDLE) {
|
|
break;
|
|
}
|
|
|
|
usleep(5000);
|
|
if (!Feb_Control_IsReadyForTrigger(&readyForTrigger)) {
|
|
LOG(logERROR, ("Could not read FEB_REG_STATUS reg after "
|
|
"giving trigger!\n"));
|
|
return 0;
|
|
}
|
|
}
|
|
LOG(logDEBUG2, ("Done waiting (wait for trigger)!\n"));
|
|
}
|
|
LOG(logINFO,
|
|
("%s Software Trigger %s\n", (block ? "Blocking" : "Non blocking"),
|
|
(block ? "Acquired" : "Sent")));
|
|
fflush(stdout);
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
// parameters
|
|
int Feb_Control_SetDynamicRange(int dr) {
|
|
static unsigned int everything_but_bit_mode = DAQ_STATIC_BIT_PROGRAM |
|
|
DAQ_STATIC_BIT_CHIP_TEST |
|
|
DAQ_STATIC_BIT_ROTEST;
|
|
switch (dr) {
|
|
case 4:
|
|
Feb_Control_staticBits =
|
|
DAQ_STATIC_BIT_M4 |
|
|
(Feb_Control_staticBits &
|
|
everything_but_bit_mode); // leave test bits in currernt state
|
|
Feb_Control_subFrameMode &= ~DAQ_NEXPOSURERS_ACTIVATE_AUTO_SUBIMAGING;
|
|
break;
|
|
case 8:
|
|
Feb_Control_staticBits = DAQ_STATIC_BIT_M8 | (Feb_Control_staticBits &
|
|
everything_but_bit_mode);
|
|
Feb_Control_subFrameMode &= ~DAQ_NEXPOSURERS_ACTIVATE_AUTO_SUBIMAGING;
|
|
break;
|
|
case 12:
|
|
case 16:
|
|
Feb_Control_staticBits = DAQ_STATIC_BIT_M12 | (Feb_Control_staticBits &
|
|
everything_but_bit_mode);
|
|
Feb_Control_subFrameMode &= ~DAQ_NEXPOSURERS_ACTIVATE_AUTO_SUBIMAGING;
|
|
|
|
// disable 16 bit conversion if 12 bit mode (enable if 16 bit)
|
|
if (!Feb_Control_Disable16bitConversion(dr == 12))
|
|
return 0;
|
|
break;
|
|
case 32:
|
|
Feb_Control_staticBits = DAQ_STATIC_BIT_M12 | (Feb_Control_staticBits &
|
|
everything_but_bit_mode);
|
|
Feb_Control_subFrameMode |= DAQ_NEXPOSURERS_ACTIVATE_AUTO_SUBIMAGING;
|
|
break;
|
|
default:
|
|
LOG(logERROR,
|
|
("dynamic range (%d) not valid, not setting bit mode.\n", dr));
|
|
LOG(logINFO, ("Set dynamic range int must equal 4,8 16, or 32.\n"));
|
|
return 0;
|
|
}
|
|
|
|
LOG(logINFO, ("Dynamic range set to %d\n", dr));
|
|
return 1;
|
|
}
|
|
|
|
int Feb_Control_GetDynamicRange(int *retval) {
|
|
if (Feb_Control_subFrameMode & DAQ_NEXPOSURERS_ACTIVATE_AUTO_SUBIMAGING) {
|
|
*retval = 32;
|
|
} else if (DAQ_STATIC_BIT_M4 & Feb_Control_staticBits) {
|
|
*retval = 4;
|
|
} else if (DAQ_STATIC_BIT_M8 & Feb_Control_staticBits) {
|
|
*retval = 8;
|
|
} else {
|
|
int disable16 = 0;
|
|
if (!Feb_Control_Get16bitConversionDisabled(&disable16)) {
|
|
LOG(logERROR, ("Could not get dynamic range (12 or 16 bit)\n"));
|
|
return 0;
|
|
}
|
|
if (disable16) {
|
|
*retval = 12;
|
|
} else {
|
|
*retval = 16;
|
|
}
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
int Feb_Control_Disable16bitConversion(int disable) {
|
|
LOG(logINFO, ("%s 16 bit expansion\n", disable ? "Disabling" : "Enabling"));
|
|
|
|
uint32_t bitmask = DAQ_REG_HRDWRE_DSBL_16BIT_MSK;
|
|
unsigned int regval = 0;
|
|
if (disable) {
|
|
regval |= bitmask;
|
|
} else {
|
|
regval &= ~bitmask;
|
|
}
|
|
|
|
if (!Feb_Control_WriteRegister_BitMask(DAQ_REG_HRDWRE, regval, bitmask,
|
|
1)) {
|
|
LOG(logERROR, ("Could not %s 16 bit expansion (bit mode)\n",
|
|
(disable ? "disable" : "enable")));
|
|
return 0;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
int Feb_Control_Get16bitConversionDisabled(int *ret) {
|
|
unsigned int regval = 0;
|
|
if (!Feb_Control_ReadRegister_BitMask(DAQ_REG_HRDWRE, ®val,
|
|
DAQ_REG_HRDWRE_DSBL_16BIT_MSK)) {
|
|
LOG(logERROR, ("Could not get 16 bit expansion (bit mode)\n"));
|
|
return 0;
|
|
}
|
|
if (regval) {
|
|
*ret = 1;
|
|
} else {
|
|
*ret = 0;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
int Feb_Control_SetReadoutSpeed(unsigned int readout_speed) {
|
|
// 0->full,1->half,2->quarter or 3->super_slow
|
|
Feb_Control_acquireNReadoutMode &= (~DAQ_CHIP_CONTROLLER_SUPER_SLOW_SPEED);
|
|
if (readout_speed == 1) {
|
|
Feb_Control_acquireNReadoutMode |= DAQ_CHIP_CONTROLLER_HALF_SPEED;
|
|
LOG(logINFO, ("Speed set to half speed (50 MHz)\n"));
|
|
} else if (readout_speed == 2) {
|
|
Feb_Control_acquireNReadoutMode |= DAQ_CHIP_CONTROLLER_QUARTER_SPEED;
|
|
LOG(logINFO, ("Speed set to quarter speed (25 MHz)\n"));
|
|
} else {
|
|
if (readout_speed) {
|
|
LOG(logERROR,
|
|
("readout speed %d unknown, defaulting to full speed.\n",
|
|
readout_speed));
|
|
LOG(logINFO, ("full speed, (100 MHz)\n"));
|
|
return 0;
|
|
}
|
|
LOG(logINFO, ("Speed set to full speed (100 MHz)\n"));
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
int Feb_Control_SetReadoutMode(unsigned int readout_mode) {
|
|
// 0->parallel,1->non-parallel,2-> safe_mode
|
|
Feb_Control_acquireNReadoutMode &= (~DAQ_NEXPOSURERS_PARALLEL_MODE);
|
|
if (readout_mode == 1) {
|
|
Feb_Control_acquireNReadoutMode |=
|
|
DAQ_NEXPOSURERS_NORMAL_NONPARALLEL_MODE;
|
|
LOG(logINFO, ("Readout mode set to Non Parallel\n"));
|
|
} else if (readout_mode == 2) {
|
|
Feb_Control_acquireNReadoutMode |=
|
|
DAQ_NEXPOSURERS_SAFEST_MODE_ROW_CLK_BEFORE_MODE;
|
|
LOG(logINFO, ("Readout mode set to Safe (row clk before main clk "
|
|
"readout sequence)\n"));
|
|
} else {
|
|
Feb_Control_acquireNReadoutMode |= DAQ_NEXPOSURERS_PARALLEL_MODE;
|
|
if (readout_mode) {
|
|
LOG(logERROR,
|
|
("readout mode %d) unknown, defaulting to parallel readout.\n",
|
|
readout_mode));
|
|
LOG(logINFO, ("Readout mode set to Parallel\n"));
|
|
return 0;
|
|
}
|
|
LOG(logINFO, ("Readout mode set to Parallel\n"));
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
int Feb_Control_SetTriggerMode(unsigned int trigger_mode) {
|
|
//"00"-> internal exposure time and period,
|
|
//"01"-> external acquistion start and internal exposure time and period,
|
|
//"10"-> external start trigger and internal exposure time,
|
|
//"11"-> external triggered start and stop of exposures
|
|
Feb_Control_triggerMode = (~DAQ_NEXPOSURERS_EXTERNAL_IMAGE_START_AND_STOP);
|
|
|
|
if (trigger_mode == 1) {
|
|
Feb_Control_triggerMode = DAQ_NEXPOSURERS_EXTERNAL_ACQUISITION_START;
|
|
LOG(logINFO, ("Trigger mode set to Burst Trigger\n"));
|
|
} else if (trigger_mode == 2) {
|
|
Feb_Control_triggerMode = DAQ_NEXPOSURERS_EXTERNAL_IMAGE_START;
|
|
LOG(logINFO, ("Trigger mode set to Trigger Exposure\n"));
|
|
} else if (trigger_mode == 3) {
|
|
Feb_Control_triggerMode = DAQ_NEXPOSURERS_EXTERNAL_IMAGE_START_AND_STOP;
|
|
LOG(logINFO, ("Trigger mode set to Gated\n"));
|
|
} else {
|
|
Feb_Control_triggerMode = DAQ_NEXPOSURERS_INTERNAL_ACQUISITION;
|
|
if (trigger_mode) {
|
|
LOG(logERROR,
|
|
("trigger %d) unknown, defaulting to Auto\n", trigger_mode));
|
|
}
|
|
|
|
LOG(logINFO, ("Trigger mode set to Auto\n"));
|
|
return trigger_mode == 0;
|
|
}
|
|
// polarity
|
|
int polarity = 1; // hard coded (can be configured in future)
|
|
if (polarity) {
|
|
Feb_Control_triggerMode |= DAQ_NEXPOSURERS_EXTERNAL_TRIGGER_POLARITY;
|
|
LOG(logINFO, ("External trigger polarity set to positive\n"));
|
|
} else {
|
|
Feb_Control_triggerMode &= (~DAQ_NEXPOSURERS_EXTERNAL_TRIGGER_POLARITY);
|
|
LOG(logINFO, ("External trigger polarity set to negitive\n"));
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
int Feb_Control_SetExternalEnableMode(int use_external_enable, int polarity) {
|
|
if (use_external_enable) {
|
|
Feb_Control_externalEnableMode |= DAQ_NEXPOSURERS_EXTERNAL_ENABLING;
|
|
if (polarity) {
|
|
Feb_Control_externalEnableMode |=
|
|
DAQ_NEXPOSURERS_EXTERNAL_ENABLING_POLARITY;
|
|
} else {
|
|
Feb_Control_externalEnableMode &=
|
|
(~DAQ_NEXPOSURERS_EXTERNAL_ENABLING_POLARITY);
|
|
}
|
|
LOG(logINFO, ("External enabling enabled, polarity set to %s\n",
|
|
(polarity ? "positive" : "negative")));
|
|
|
|
} else {
|
|
Feb_Control_externalEnableMode = 0;
|
|
LOG(logINFO, ("External enabling disabled\n"));
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
int Feb_Control_SetNExposures(unsigned int n_images) {
|
|
if (!n_images) {
|
|
LOG(logERROR, ("nimages must be greater than zero.%d\n", n_images));
|
|
return 0;
|
|
}
|
|
Feb_Control_nimages = n_images;
|
|
LOG(logDEBUG1, ("Number of images set to %d\n", Feb_Control_nimages));
|
|
return 1;
|
|
}
|
|
unsigned int Feb_Control_GetNExposures() { return Feb_Control_nimages; }
|
|
|
|
int Feb_Control_SetExposureTime(double the_exposure_time_in_sec) {
|
|
Feb_Control_exposure_time_in_sec = the_exposure_time_in_sec;
|
|
LOG(logDEBUG1,
|
|
("Exposure time set to %fs\n", Feb_Control_exposure_time_in_sec));
|
|
return 1;
|
|
}
|
|
|
|
double Feb_Control_GetExposureTime() {
|
|
return Feb_Control_exposure_time_in_sec;
|
|
}
|
|
|
|
int64_t Feb_Control_GetExposureTime_in_nsec() {
|
|
return (int64_t)(Feb_Control_exposure_time_in_sec * (1E9));
|
|
}
|
|
|
|
int Feb_Control_SetSubFrameExposureTime(
|
|
int64_t the_subframe_exposure_time_in_10nsec) {
|
|
Feb_Control_subframe_exposure_time_in_10nsec =
|
|
the_subframe_exposure_time_in_10nsec;
|
|
LOG(logDEBUG1,
|
|
("Sub Frame Exposure time set to %lldns\n",
|
|
(long long int)Feb_Control_subframe_exposure_time_in_10nsec * 10));
|
|
return 1;
|
|
}
|
|
|
|
int64_t Feb_Control_GetSubFrameExposureTime() {
|
|
return Feb_Control_subframe_exposure_time_in_10nsec * 10;
|
|
}
|
|
|
|
int Feb_Control_SetSubFramePeriod(int64_t the_subframe_period_in_10nsec) {
|
|
Feb_Control_subframe_period_in_10nsec = the_subframe_period_in_10nsec;
|
|
LOG(logDEBUG1, ("Sub Frame Period set to %lldns\n",
|
|
(long long int)Feb_Control_subframe_period_in_10nsec * 10));
|
|
return 1;
|
|
}
|
|
int64_t Feb_Control_GetSubFramePeriod() {
|
|
return Feb_Control_subframe_period_in_10nsec * 10;
|
|
}
|
|
|
|
int Feb_Control_SetExposurePeriod(double the_exposure_period_in_sec) {
|
|
Feb_Control_exposure_period_in_sec = the_exposure_period_in_sec;
|
|
LOG(logDEBUG1,
|
|
("Exposure period set to %fs\n", Feb_Control_exposure_period_in_sec));
|
|
return 1;
|
|
}
|
|
double Feb_Control_GetExposurePeriod() {
|
|
return Feb_Control_exposure_period_in_sec;
|
|
}
|
|
|
|
void Feb_Control_Set_Counter_Bit(int value) { Feb_Control_counter_bit = value; }
|
|
|
|
int Feb_Control_Get_Counter_Bit() { return Feb_Control_counter_bit; }
|
|
|
|
int Feb_Control_SetInterruptSubframe(int val) {
|
|
LOG(logINFO, ("Setting Interrupt Subframe to %d\n", val));
|
|
// they need to be written separately because the left and right registers
|
|
// have different values for this particular register
|
|
uint32_t offset = DAQ_REG_HRDWRE;
|
|
uint32_t regVal = 0;
|
|
char side[2][10] = {"right", "left"};
|
|
unsigned int addr[2] = {Feb_Control_rightAddress, Feb_Control_leftAddress};
|
|
for (int iloop = 0; iloop < 2; ++iloop) {
|
|
// get previous value to keep it
|
|
if (!Feb_Interface_ReadRegister(addr[iloop], offset, ®Val)) {
|
|
LOG(logERROR,
|
|
("Could not read %s interrupt subframe\n", side[iloop]));
|
|
return 0;
|
|
}
|
|
uint32_t data = ((val == 0) ? (regVal & ~DAQ_REG_HRDWRE_INTRRPT_SF_MSK)
|
|
: (regVal | DAQ_REG_HRDWRE_INTRRPT_SF_MSK));
|
|
if (!Feb_Interface_WriteRegister(addr[iloop], offset, data, 0, 0)) {
|
|
LOG(logERROR,
|
|
("Could not write 0x%x to %s interrupt subframe addr 0x%x\n",
|
|
data, side[iloop], offset));
|
|
return 0;
|
|
}
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
int Feb_Control_GetInterruptSubframe() {
|
|
// they need to be written separately because the left and right registers
|
|
// have different values for this particular register
|
|
uint32_t offset = DAQ_REG_HRDWRE;
|
|
uint32_t regVal = 0;
|
|
|
|
char side[2][10] = {"right", "left"};
|
|
unsigned int addr[2] = {Feb_Control_rightAddress, Feb_Control_leftAddress};
|
|
uint32_t value[2] = {0, 0};
|
|
for (int iloop = 0; iloop < 2; ++iloop) {
|
|
if (!Feb_Interface_ReadRegister(addr[iloop], offset, ®Val)) {
|
|
LOG(logERROR,
|
|
("Could not read back %s interrupt subframe\n", side[iloop]));
|
|
return -1;
|
|
}
|
|
value[iloop] = (regVal & DAQ_REG_HRDWRE_INTRRPT_SF_MSK) >>
|
|
DAQ_REG_HRDWRE_INTRRPT_SF_OFST;
|
|
}
|
|
// inconsistent
|
|
if (value[0] != value[1]) {
|
|
LOG(logERROR, ("Inconsistent values of interrupt subframe betweeen "
|
|
"right %d and left %d\n",
|
|
value[0], value[1]));
|
|
return -1;
|
|
}
|
|
return value[0];
|
|
}
|
|
|
|
int Feb_Control_SetTop(enum TOPINDEX ind, int left, int right) {
|
|
uint32_t offset = DAQ_REG_HRDWRE;
|
|
unsigned int addr[2] = {0, 0};
|
|
if (left) {
|
|
addr[0] = Feb_Control_leftAddress;
|
|
}
|
|
if (right) {
|
|
addr[1] = Feb_Control_rightAddress;
|
|
}
|
|
char *top_names[] = {TOP_NAMES};
|
|
for (int i = 0; i < 2; ++i) {
|
|
if (addr[i] == 0) {
|
|
continue;
|
|
}
|
|
uint32_t value = 0;
|
|
if (!Feb_Interface_ReadRegister(addr[i], offset, &value)) {
|
|
LOG(logERROR, ("Could not read %s Feb reg to set Top flag\n",
|
|
(i == 0 ? "left" : "right")));
|
|
return 0;
|
|
}
|
|
switch (ind) {
|
|
case TOP_HARDWARE:
|
|
value &= ~DAQ_REG_HRDWRE_OW_TOP_MSK;
|
|
break;
|
|
case OW_TOP:
|
|
value |= DAQ_REG_HRDWRE_OW_TOP_MSK;
|
|
value |= DAQ_REG_HRDWRE_TOP_MSK;
|
|
break;
|
|
case OW_BOTTOM:
|
|
value |= DAQ_REG_HRDWRE_OW_TOP_MSK;
|
|
value &= ~DAQ_REG_HRDWRE_TOP_MSK;
|
|
break;
|
|
default:
|
|
LOG(logERROR, ("Unknown top index in Feb: %d\n", ind));
|
|
return 0;
|
|
}
|
|
if (!Feb_Interface_WriteRegister(addr[i], offset, value, 0, 0)) {
|
|
LOG(logERROR, ("Could not set Top flag to %s in %s Feb\n",
|
|
top_names[ind], (i == 0 ? "left" : "right")));
|
|
return 0;
|
|
}
|
|
}
|
|
if (left && right) {
|
|
LOG(logINFOBLUE, ("%s Top flag to %s Feb\n",
|
|
(ind == TOP_HARDWARE ? "Resetting" : "Overwriting"),
|
|
top_names[ind]));
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
int Feb_Control_SetMaster(enum MASTERINDEX ind) {
|
|
|
|
uint32_t offset = DAQ_REG_HRDWRE;
|
|
unsigned int addr[2] = {Feb_Control_leftAddress, Feb_Control_rightAddress};
|
|
char *master_names[] = {MASTER_NAMES};
|
|
for (int i = 0; i < 2; ++i) {
|
|
uint32_t value = 0;
|
|
if (!Feb_Interface_ReadRegister(addr[i], offset, &value)) {
|
|
LOG(logERROR, ("Could not read %s Feb reg to set Master flag\n",
|
|
(i == 0 ? "left" : "right")));
|
|
return 0;
|
|
}
|
|
switch (ind) {
|
|
case MASTER_HARDWARE:
|
|
value &= ~DAQ_REG_HRDWRE_OW_MASTER_MSK;
|
|
break;
|
|
case OW_MASTER:
|
|
value |= DAQ_REG_HRDWRE_OW_MASTER_MSK;
|
|
value |= DAQ_REG_HRDWRE_MASTER_MSK;
|
|
break;
|
|
case OW_SLAVE:
|
|
value |= DAQ_REG_HRDWRE_OW_MASTER_MSK;
|
|
value &= ~DAQ_REG_HRDWRE_MASTER_MSK;
|
|
break;
|
|
default:
|
|
LOG(logERROR, ("Unknown master index in Feb: %d\n", ind));
|
|
return 0;
|
|
}
|
|
|
|
if (!Feb_Interface_WriteRegister(addr[i], offset, value, 0, 0)) {
|
|
LOG(logERROR, ("Could not set Master flag to %s in %s Feb\n",
|
|
master_names[ind], (i == 0 ? "left" : "right")));
|
|
return 0;
|
|
}
|
|
}
|
|
LOG(logINFOBLUE, ("%s Master flag to %s Feb\n",
|
|
(ind == MASTER_HARDWARE ? "Resetting" : "Overwriting"),
|
|
master_names[ind]));
|
|
|
|
return 1;
|
|
}
|
|
|
|
int Feb_Control_SetMasterEffects(int master, int controlServer) {
|
|
int prevMaster = Feb_Control_master;
|
|
|
|
Feb_Control_master = master;
|
|
// change in master for 9m
|
|
if (controlServer && prevMaster != Feb_Control_master &&
|
|
!Feb_Control_normal) {
|
|
if (prevMaster) {
|
|
Feb_Control_CloseSerialCommunication();
|
|
}
|
|
if (Feb_Control_master) {
|
|
if (!Feb_Control_OpenSerialCommunication()) {
|
|
LOG(logERROR, ("Could not intitalize feb control serial "
|
|
"communication\n"));
|
|
return FAIL;
|
|
}
|
|
}
|
|
}
|
|
return OK;
|
|
}
|
|
|
|
int Feb_Control_SetQuad(int val) {
|
|
LOG(logINFO, ("Setting Quad to %d in Feb\n", val));
|
|
Feb_Control_quadMode = val;
|
|
// only setting on the right feb if quad
|
|
return Feb_Control_SetTop(val == 0 ? TOP_HARDWARE : OW_BOTTOM, 0, 1);
|
|
}
|
|
|
|
int Feb_Control_SetChipSignalsToTrimQuad(int enable) {
|
|
if (Feb_Control_quadMode) {
|
|
LOG(logINFO, ("%s chip signals to trim quad\n",
|
|
enable ? "Enabling" : "Disabling"));
|
|
unsigned int regval = 0;
|
|
// right fpga only
|
|
uint32_t righOffset = DAQ_REG_HRDWRE + Feb_Control_rightAddress;
|
|
if (!Feb_Control_ReadRegister(righOffset, ®val)) {
|
|
LOG(logERROR, ("Could not set chip signals to trim quad\n"));
|
|
return 0;
|
|
}
|
|
if (enable) {
|
|
regval |= (DAQ_REG_HRDWRE_PROGRAM_MSK | DAQ_REG_HRDWRE_M8_MSK);
|
|
} else {
|
|
regval &= ~(DAQ_REG_HRDWRE_PROGRAM_MSK | DAQ_REG_HRDWRE_M8_MSK);
|
|
}
|
|
|
|
if (!Feb_Control_WriteRegister(righOffset, regval, 1)) {
|
|
LOG(logERROR, ("Could not set chip signals to trim quad\n"));
|
|
return 0;
|
|
}
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
int Feb_Control_SetReadNRows(int value) {
|
|
LOG(logINFO, ("Setting number of rows to %d\n", value));
|
|
if (!Feb_Interface_WriteRegister(Feb_Control_AddressToAll(),
|
|
DAQ_REG_READ_N_ROWS, value, 0, 0)) {
|
|
LOG(logERROR, ("Could not write %d to number of rows reg\n", value));
|
|
return 0;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
int Feb_Control_GetReadNRows() {
|
|
uint32_t regVal = 0;
|
|
if (!Feb_Interface_ReadRegister(Feb_Control_AddressToAll(),
|
|
DAQ_REG_READ_N_ROWS, ®Val)) {
|
|
LOG(logERROR, ("Could not read back ReadNRows reg\n"));
|
|
return -1;
|
|
}
|
|
LOG(logDEBUG1, ("Retval ReadNRows: %d\n", regVal));
|
|
return regVal;
|
|
}
|
|
|
|
int Feb_Control_WriteRegister(uint32_t offset, uint32_t data, int validate) {
|
|
if (!Feb_Control_WriteRegister_BitMask(offset, data, BIT32_MSK, validate))
|
|
return 0;
|
|
return 1;
|
|
}
|
|
|
|
int Feb_Control_ReadRegister(uint32_t offset, uint32_t *retval) {
|
|
return Feb_Control_ReadRegister_BitMask(offset, retval, BIT32_MASK);
|
|
}
|
|
|
|
int Feb_Control_WriteRegister_BitMask(uint32_t offset, uint32_t data,
|
|
uint32_t bitmask, int validate) {
|
|
uint32_t actualOffset = offset;
|
|
char side[2][10] = {"right", "left"};
|
|
unsigned int addr[2] = {Feb_Control_rightAddress, Feb_Control_leftAddress};
|
|
|
|
int run[2] = {0, 0};
|
|
// both registers
|
|
if (offset < Feb_Control_leftAddress) {
|
|
run[0] = 1;
|
|
run[1] = 1;
|
|
}
|
|
// right registers only
|
|
else if (offset >= Feb_Control_rightAddress) {
|
|
run[0] = 1;
|
|
actualOffset = offset - Feb_Control_rightAddress;
|
|
}
|
|
// left registers only
|
|
else {
|
|
run[1] = 1;
|
|
actualOffset = offset - Feb_Control_leftAddress;
|
|
}
|
|
|
|
for (int iloop = 0; iloop < 2; ++iloop) {
|
|
if (run[iloop]) {
|
|
LOG(logDEBUG1, ("Writing 0x%x to %s 0x%x (mask:0x%x)\n", data,
|
|
side[iloop], actualOffset, bitmask));
|
|
|
|
uint32_t writeVal = 0;
|
|
if (!Feb_Interface_ReadRegister(addr[iloop], actualOffset,
|
|
&writeVal)) {
|
|
LOG(logERROR, ("Could not read %s addr 0x%x register\n",
|
|
side[iloop], actualOffset));
|
|
return 0;
|
|
}
|
|
// set only the bits in the mask
|
|
writeVal &= ~(bitmask);
|
|
writeVal |= (data & bitmask);
|
|
|
|
LOG(logDEBUG1, ("writing 0x%x to 0x%x\n", writeVal, actualOffset));
|
|
if (!Feb_Interface_WriteRegister(addr[iloop], actualOffset,
|
|
writeVal, 0, 0)) {
|
|
LOG(logERROR, ("Could not write 0x%x to %s addr 0x%x\n",
|
|
writeVal, side[iloop], actualOffset));
|
|
return 0;
|
|
}
|
|
|
|
if (validate) {
|
|
|
|
uint32_t readVal = 0;
|
|
if (!Feb_Interface_ReadRegister(addr[iloop], actualOffset,
|
|
&readVal)) {
|
|
return 0;
|
|
}
|
|
readVal &= bitmask;
|
|
writeVal &= bitmask;
|
|
if (writeVal != readVal) {
|
|
LOG(logERROR,
|
|
("Could not write %s addr 0x%x register. Wrote "
|
|
"0x%x, read 0x%x (mask:0x%x)\n",
|
|
side[iloop], actualOffset, writeVal, readVal,
|
|
bitmask));
|
|
return 0;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
int Feb_Control_ReadRegister_BitMask(uint32_t offset, uint32_t *retval,
|
|
uint32_t bitmask) {
|
|
|
|
uint32_t actualOffset = offset;
|
|
char side[2][10] = {"right", "left"};
|
|
unsigned int addr[2] = {Feb_Control_rightAddress, Feb_Control_leftAddress};
|
|
uint32_t value[2] = {0, 0};
|
|
int run[2] = {0, 0};
|
|
// both registers
|
|
if (offset < Feb_Control_leftAddress) {
|
|
run[0] = 1;
|
|
run[1] = 1;
|
|
}
|
|
// right registers only
|
|
else if (offset >= Feb_Control_rightAddress) {
|
|
run[0] = 1;
|
|
actualOffset = offset - Feb_Control_rightAddress;
|
|
}
|
|
// left registers only
|
|
else {
|
|
run[1] = 1;
|
|
actualOffset = offset - Feb_Control_leftAddress;
|
|
}
|
|
|
|
for (int iloop = 0; iloop < 2; ++iloop) {
|
|
if (run[iloop]) {
|
|
if (!Feb_Interface_ReadRegister(addr[iloop], actualOffset,
|
|
&value[iloop])) {
|
|
LOG(logERROR, ("Could not read from %s addr 0x%x\n",
|
|
side[iloop], actualOffset));
|
|
return 0;
|
|
}
|
|
value[iloop] &= bitmask;
|
|
LOG(logDEBUG1, ("Read 0x%x from %s 0x%x (mask:0x%x)\n",
|
|
value[iloop], side[iloop], actualOffset, bitmask));
|
|
*retval = value[iloop];
|
|
// if not the other (left, not right OR right, not left), return the
|
|
// value
|
|
if (!run[iloop ? 0 : 1]) {
|
|
return 1;
|
|
}
|
|
}
|
|
}
|
|
// Inconsistent values when reading both registers
|
|
if ((run[0] & run[1]) & (value[0] != value[1])) {
|
|
LOG(logERROR, ("Inconsistent values read from %s: 0x%x and %s: 0x%x\n",
|
|
side[0], value[0], side[1], value[1]));
|
|
return 0;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
// pulsing
|
|
int Feb_Control_Pulse_Pixel(int npulses, int x, int y) {
|
|
// this function is not designed for speed
|
|
int pulse_multiple = 0; // has to be 0 or 1
|
|
|
|
if (x < 0) {
|
|
x = -x;
|
|
pulse_multiple = 1;
|
|
LOG(logINFO,
|
|
("Pulsing pixel %d in all super columns below number %d.\n", x % 8,
|
|
x / 8));
|
|
}
|
|
if (x < 0 || x > 255 || y < 0 || y > 255) {
|
|
LOG(logERROR, ("Pixel out of range.\n"));
|
|
return 0;
|
|
}
|
|
|
|
// y = 255 - y;
|
|
int nrowclocks = 0;
|
|
nrowclocks += (Feb_Control_staticBits & DAQ_STATIC_BIT_M4) ? 0 : 2 * y;
|
|
nrowclocks += (Feb_Control_staticBits & DAQ_STATIC_BIT_M8) ? 0 : y;
|
|
|
|
Feb_Control_SetInTestModeVariable(1); // on
|
|
Feb_Control_SetStaticBits();
|
|
Feb_Control_SetCommandRegister(DAQ_RESET_PERIPHERY |
|
|
DAQ_RESET_COLUMN_SELECT);
|
|
if (Feb_Control_StartDAQOnlyNWaitForFinish(5000) != STATUS_IDLE) {
|
|
LOG(logERROR, ("could not pulse pixel as status not idle\n"));
|
|
return 0;
|
|
}
|
|
|
|
unsigned int serial_in = 8 << (4 * (7 - x % 8));
|
|
if (!Feb_Control_Shift32InSerialIn(serial_in)) {
|
|
LOG(logERROR,
|
|
("ChipController::PulsePixel: could shift in the initail 32.\n"));
|
|
return 0;
|
|
}
|
|
|
|
if (!pulse_multiple)
|
|
serial_in = 0;
|
|
for (int i = 0; i < x / 8; i++)
|
|
Feb_Control_Shift32InSerialIn(serial_in);
|
|
|
|
Feb_Control_SendTokenIn();
|
|
Feb_Control_ClockRowClock(nrowclocks);
|
|
Feb_Control_PulsePixelNMove(npulses, 0, 0);
|
|
return 1;
|
|
}
|
|
|
|
int Feb_Control_PulsePixelNMove(int npulses, int inc_x_pos, int inc_y_pos) {
|
|
unsigned int c = DAQ_SEND_N_TEST_PULSES;
|
|
c |= (inc_x_pos) ? DAQ_CLK_MAIN_CLK_TO_SELECT_NEXT_PIXEL : 0;
|
|
c |= (inc_y_pos) ? DAQ_CLK_ROW_CLK_TO_SELECT_NEXT_ROW : 0;
|
|
|
|
if (Feb_Control_activated) {
|
|
if (!Feb_Interface_WriteRegister(Feb_Control_AddressToAll(),
|
|
DAQ_REG_SEND_N_TESTPULSES, npulses, 0,
|
|
0) ||
|
|
!Feb_Control_SetCommandRegister(c) ||
|
|
(Feb_Control_StartDAQOnlyNWaitForFinish(5000) != STATUS_IDLE)) {
|
|
LOG(logERROR, ("could not PulsePixelNMove(...).\n"));
|
|
return 0;
|
|
}
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
int Feb_Control_Shift32InSerialIn(unsigned int value_to_shift_in) {
|
|
if (Feb_Control_activated) {
|
|
if (!Feb_Control_SetCommandRegister(DAQ_SERIALIN_SHIFT_IN_32) ||
|
|
!Feb_Interface_WriteRegister(Feb_Control_AddressToAll(),
|
|
DAQ_REG_SHIFT_IN_32, value_to_shift_in,
|
|
0, 0) ||
|
|
(Feb_Control_StartDAQOnlyNWaitForFinish(5000) != STATUS_IDLE)) {
|
|
LOG(logERROR, ("could not shift in 32.\n"));
|
|
return 0;
|
|
}
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
int Feb_Control_SendTokenIn() {
|
|
if (!Feb_Control_SetCommandRegister(DAQ_SEND_A_TOKEN_IN) ||
|
|
(Feb_Control_StartDAQOnlyNWaitForFinish(5000) != STATUS_IDLE)) {
|
|
LOG(logERROR, ("could not SendTokenIn().\n"));
|
|
return 0;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
int Feb_Control_ClockRowClock(unsigned int ntimes) {
|
|
if (ntimes > 1023) {
|
|
LOG(logERROR, ("Clock row clock ntimes (%d) exceeds the maximum value "
|
|
"of 1023.\n\t Setting ntimes to 1023.\n",
|
|
ntimes));
|
|
ntimes = 1023;
|
|
}
|
|
if (Feb_Control_activated) {
|
|
if (!Feb_Control_SetCommandRegister(DAQ_CLK_ROW_CLK_NTIMES) ||
|
|
!Feb_Interface_WriteRegister(Feb_Control_AddressToAll(),
|
|
DAQ_REG_CLK_ROW_CLK_NTIMES, ntimes, 0,
|
|
0) ||
|
|
(Feb_Control_StartDAQOnlyNWaitForFinish(5000) != STATUS_IDLE)) {
|
|
LOG(logERROR, ("could not clock row clock.\n"));
|
|
return 0;
|
|
}
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
int Feb_Control_PulseChip(int npulses) {
|
|
int on = 1;
|
|
if (npulses == -1) {
|
|
on = 0;
|
|
LOG(logINFO, ("\nResetting to normal mode\n"));
|
|
} else {
|
|
LOG(logINFO, ("\n\nPulsing Chip.\n")); // really just toggles the enable
|
|
LOG(logINFO, ("Vcmp should be set to 2.0 and Vtrim should be 2.\n"));
|
|
}
|
|
|
|
Feb_Control_SetInTestModeVariable(on);
|
|
Feb_Control_SetStaticBits(); // toggle the enable 2x times
|
|
Feb_Control_ResetChipCompletely();
|
|
|
|
for (int i = 0; i < npulses; i++) {
|
|
if (!Feb_Control_SetCommandRegister(
|
|
DAQ_CHIP_CONTROLLER_SUPER_SLOW_SPEED | DAQ_RESET_PERIPHERY |
|
|
DAQ_RESET_COLUMN_SELECT)) {
|
|
LOG(logERROR, ("some set command register error\n"));
|
|
}
|
|
if ((Feb_Control_StartDAQOnlyNWaitForFinish(5000) != STATUS_IDLE)) {
|
|
LOG(logERROR, ("some wait error\n"));
|
|
}
|
|
}
|
|
Feb_Control_SetExternalEnableMode(on, 1);
|
|
Feb_Control_counter_bit = (on ? 0 : 1);
|
|
LOG(logINFO, ("Feb_Control_counter_bit:%d\n", Feb_Control_counter_bit));
|
|
if (on) {
|
|
LOG(logINFO, ("Pulse chip success\n\n"));
|
|
} else {
|
|
LOG(logINFO, ("Reset to normal mode success\n\n"));
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
// rate correction
|
|
int64_t Feb_Control_Get_RateTable_Tau_in_nsec() {
|
|
return Feb_Control_RateTable_Tau_in_nsec;
|
|
}
|
|
|
|
int64_t Feb_Control_Get_RateTable_Period_in_nsec() {
|
|
return Feb_Control_RateTable_Period_in_nsec;
|
|
}
|
|
|
|
int Feb_Control_SetRateCorrectionTau(int64_t tau_in_Nsec) {
|
|
// period = exptime if 16bit, period = subexptime if 32 bit
|
|
int dr = 0;
|
|
if (!Feb_Control_GetDynamicRange(&dr)) {
|
|
LOG(logERROR, ("Could not set rate correction tau\n"));
|
|
return 0;
|
|
}
|
|
double period_in_sec =
|
|
(double)(Feb_Control_GetSubFrameExposureTime()) / (double)1e9;
|
|
if (dr == 16)
|
|
period_in_sec = Feb_Control_GetExposureTime();
|
|
|
|
double tau_in_sec = (double)tau_in_Nsec / (double)1e9;
|
|
LOG(logINFO, (" tau %lf %lf ", (double)tau_in_Nsec, (double)tau_in_sec));
|
|
|
|
unsigned int np = 16384; // max slope 16 * 1024
|
|
double b0[1024];
|
|
double m[1024];
|
|
|
|
if (tau_in_sec < 0 || period_in_sec < 0) {
|
|
if (dr == 32) {
|
|
LOG(logERROR,
|
|
("tau %lf and sub_exposure_time %lf must be greater than 0.\n",
|
|
tau_in_sec, period_in_sec));
|
|
} else {
|
|
LOG(logERROR,
|
|
("tau %lf and exposure_time %lf must be greater than 0.\n",
|
|
tau_in_sec, period_in_sec));
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
LOG(logINFO, ("Changing Rate Correction Table tau:%0.8f sec, period:%f sec",
|
|
tau_in_sec, period_in_sec));
|
|
LOG(logINFO, ("\tCalculating table for tau of %lld ns.\n", tau_in_Nsec));
|
|
for (int i = 0; i < np; i++) {
|
|
Feb_Control_rate_meas[i] = i * exp(-i / period_in_sec * tau_in_sec);
|
|
if (Feb_Control_rate_meas[i] > ratemax)
|
|
ratemax = Feb_Control_rate_meas[i];
|
|
}
|
|
|
|
/*
|
|
b : index/address of block ram/rate correction table
|
|
b0 : base in vhdl
|
|
m : slope in vhdl
|
|
|
|
Firmware:
|
|
data_in(11..2) -> memory address --> memory
|
|
data_in( 1..0) -> lsb
|
|
|
|
mem_data_out(13.. 0) -> base
|
|
mem_data_out(17..14) -> slope
|
|
|
|
delta = slope*lsb
|
|
corr = base+delta
|
|
*/
|
|
|
|
int next_i = 0;
|
|
double beforemax;
|
|
b0[0] = 0;
|
|
m[0] = 1;
|
|
|
|
Feb_Control_rate_correction_table[0] =
|
|
(((int)(m[0] + 0.5) & 0xf) << 14) | ((int)(b0[0] + 0.5) & 0x3fff);
|
|
|
|
for (int b = 1; b < 1024; b++) {
|
|
if (m[b - 1] < 15) {
|
|
double s = 0, sx = 0, sy = 0, sxx = 0, sxy = 0;
|
|
for (;; next_i++) {
|
|
if (next_i >= np) {
|
|
for (; b < 1024; b++) {
|
|
if (beforemax > ratemax)
|
|
b0[b] = beforemax;
|
|
else
|
|
b0[b] = ratemax;
|
|
m[b] = 15;
|
|
Feb_Control_rate_correction_table[b] =
|
|
(((int)(m[b] + 0.5) & 0xf) << 14) |
|
|
((int)(b0[b] + 0.5) & 0x3fff);
|
|
}
|
|
b = 1024;
|
|
break;
|
|
}
|
|
|
|
double x = Feb_Control_rate_meas[next_i] - b * 4;
|
|
double y = next_i;
|
|
/*LOG(logDEBUG1, ("Start Loop x: %f,\t y: %f,\t s: %f,\t sx:
|
|
%f,\t sy: %f,\t sxx: %f,\t sxy: %f,\t " "next_i: %d,\t b: %d,\t
|
|
Feb_Control_rate_meas[next_i]: %f\n", x, y, s, sx, sy, sxx, sxy,
|
|
next_i, b, Feb_Control_rate_meas[next_i]));*/
|
|
|
|
if (x < -0.5)
|
|
continue;
|
|
if (x > 3.5)
|
|
break;
|
|
s += 1;
|
|
sx += x;
|
|
sy += y;
|
|
sxx += x * x;
|
|
sxy += x * y;
|
|
/*LOG(logDEBUG1, ("End Loop x: %f,\t y: %f,\t s: %f,\t sx:
|
|
%f,\t sy: %f,\t sxx: %f,\t sxy: %f,\t " "next_i: %d,\t b: %d,\t
|
|
Feb_Control_rate_meas[next_i]: %f\n", x, y, s, sx, sy, sxx, sxy,
|
|
next_i, b, Feb_Control_rate_meas[next_i]));*/
|
|
}
|
|
double delta = s * sxx - sx * sx;
|
|
b0[b] = (sxx * sy - sx * sxy) / delta;
|
|
m[b] = (s * sxy - sx * sy) / delta;
|
|
beforemax = b0[b];
|
|
|
|
if (m[b] < 0 || m[b] > 15) {
|
|
m[b] = 15;
|
|
if (beforemax > ratemax)
|
|
b0[b] = beforemax;
|
|
else
|
|
b0[b] = ratemax;
|
|
}
|
|
/*LOG(logDEBUG1, ("After Loop s: %f,\t sx: %f,\t sy: %f,\t sxx:
|
|
%f,\t sxy: %f,\t " "next_i: %d,\t b: %d,\t
|
|
Feb_Control_rate_meas[next_i]: %f\n",
|
|
s, sx, sy, sxx, sxy, next_i, b, Feb_Control_rate_meas[next_i]));*/
|
|
// cout<<s<<" "<<sx<<" "<<sy<<" "<<sxx<<" "<<" "<<sxy<<"
|
|
//"<<delta<<" "<<m[b]<<" "<<b0[b]<<endl;
|
|
} else {
|
|
if (beforemax > ratemax)
|
|
b0[b] = beforemax;
|
|
else
|
|
b0[b] = ratemax;
|
|
m[b] = 15;
|
|
}
|
|
Feb_Control_rate_correction_table[b] =
|
|
(((int)(m[b] + 0.5) & 0xf) << 14) | ((int)(b0[b] + 0.5) & 0x3fff);
|
|
/*LOG(logDEBUG1, ("After Loop 4*b: %d\tbase:%d\tslope:%d\n",4*b,
|
|
* (int)(b0[b]+0.5), (int)(m[b]+0.5) ));*/
|
|
}
|
|
|
|
if (Feb_Control_SetRateCorrectionTable(Feb_Control_rate_correction_table)) {
|
|
Feb_Control_RateTable_Tau_in_nsec = tau_in_Nsec;
|
|
Feb_Control_RateTable_Period_in_nsec = period_in_sec * 1e9;
|
|
return 1;
|
|
} else {
|
|
Feb_Control_RateTable_Tau_in_nsec = -1;
|
|
Feb_Control_RateTable_Period_in_nsec = -1;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
int Feb_Control_SetRateCorrectionTable(unsigned int *table) {
|
|
if (!table) {
|
|
LOG(logERROR,
|
|
("Error: could not set rate correction table, point is zero.\n"));
|
|
Feb_Control_SetRateCorrectionVariable(0);
|
|
return 0;
|
|
}
|
|
|
|
LOG(logINFO, ("Setting rate correction table. %d %d %d %d ....\n", table[0],
|
|
table[1], table[2], table[3]));
|
|
|
|
// was added otherwise after an acquire, startdaqonlywatiforfinish waits
|
|
// forever
|
|
if (!Feb_Control_SetCommandRegister(DAQ_RESET_COMPLETELY)) {
|
|
LOG(logERROR, ("Could not Feb_Control_SetCommandRegister for loading "
|
|
"trim bits.\n"));
|
|
return 0;
|
|
}
|
|
LOG(logINFO, ("daq reset completely\n"));
|
|
|
|
if (Feb_Control_activated) {
|
|
if (!Feb_Interface_WriteMemoryInLoops(
|
|
Feb_Control_leftAddress, 1, 0, 1024,
|
|
Feb_Control_rate_correction_table) ||
|
|
!Feb_Interface_WriteMemoryInLoops(
|
|
Feb_Control_rightAddress, 1, 0, 1024,
|
|
Feb_Control_rate_correction_table) ||
|
|
(Feb_Control_StartDAQOnlyNWaitForFinish(5000) != STATUS_IDLE)) {
|
|
LOG(logERROR, ("could not write to memory (top) "
|
|
"::Feb_Control_SetRateCorrectionTable\n"));
|
|
return 0;
|
|
}
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
int Feb_Control_GetRateCorrectionVariable() {
|
|
return (Feb_Control_subFrameMode &
|
|
DAQ_NEXPOSURERS_ACTIVATE_RATE_CORRECTION);
|
|
}
|
|
|
|
void Feb_Control_SetRateCorrectionVariable(int activate_rate_correction) {
|
|
if (activate_rate_correction) {
|
|
Feb_Control_subFrameMode |= DAQ_NEXPOSURERS_ACTIVATE_RATE_CORRECTION;
|
|
LOG(logINFO, ("Rate correction activated\n"));
|
|
} else {
|
|
Feb_Control_subFrameMode &= ~DAQ_NEXPOSURERS_ACTIVATE_RATE_CORRECTION;
|
|
LOG(logINFO, ("Rate correction deactivated\n"));
|
|
}
|
|
}
|
|
|
|
int Feb_Control_PrintCorrectedValues() {
|
|
int delta, slope, base, lsb, corr;
|
|
for (int i = 0; i < 4096; i++) {
|
|
lsb = i & 3;
|
|
base = Feb_Control_rate_correction_table[i >> 2] & 0x3fff;
|
|
slope = ((Feb_Control_rate_correction_table[i >> 2] & 0x3c000) >> 14);
|
|
|
|
delta = slope * lsb;
|
|
corr = delta + base;
|
|
if (slope == 15)
|
|
corr = 3 * slope + base;
|
|
|
|
LOG(logDEBUG1,
|
|
("Readout Input: "
|
|
"%d,\tBase:%d,\tSlope:%d,\tLSB:%d,\tDelta:%d\tResult:%d\tReal:%"
|
|
"lf\n",
|
|
i, base, slope, lsb, delta, corr, Feb_Control_rate_meas[i]));
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
// adcs
|
|
// So if software says now 40.00 you neeed to convert to mdegrees 40000(call it
|
|
// A1) and then A1/65536/0.00198421639-273.15
|
|
int Feb_Control_GetLeftFPGATemp() {
|
|
if (!Feb_Control_activated) {
|
|
return 0;
|
|
}
|
|
unsigned int value = 0;
|
|
if (!Feb_Interface_ReadRegister(Feb_Control_leftAddress, FEB_REG_STATUS,
|
|
&value)) {
|
|
LOG(logERROR, ("Trouble reading FEB_REG_STATUS reg to get left feb "
|
|
"temperature\n"));
|
|
return 0;
|
|
}
|
|
unsigned int temperature =
|
|
((value & FEB_REG_STATUS_TEMP_MSK) >> FEB_REG_STATUS_TEMP_OFST);
|
|
temperature =
|
|
((((float)(temperature) / 65536.0f) / 0.00198421639f) - 273.15f) *
|
|
1000; // Static conversation, copied from xps sysmon standalone driver
|
|
// division done in client to send int over network
|
|
return (int)temperature;
|
|
}
|
|
|
|
int Feb_Control_GetRightFPGATemp() {
|
|
if (!Feb_Control_activated) {
|
|
return 0;
|
|
}
|
|
unsigned int temperature = 0;
|
|
if (!Feb_Interface_ReadRegister(Feb_Control_rightAddress, FEB_REG_STATUS,
|
|
&temperature)) {
|
|
LOG(logERROR, ("Trouble reading FEB_REG_STATUS reg to get right feb "
|
|
"temperature\n"));
|
|
return 0;
|
|
}
|
|
temperature = temperature >> 16;
|
|
temperature =
|
|
((((float)(temperature) / 65536.0f) / 0.00198421639f) - 273.15f) *
|
|
1000; // Static conversation, copied from xps sysmon standalone driver
|
|
// division done in client to send int over network
|
|
return (int)temperature;
|
|
}
|
|
|
|
int Feb_Control_GetFPGAHardwareVersion(int *retval) {
|
|
if (!Feb_Control_activated) {
|
|
return 0;
|
|
}
|
|
unsigned int value = 0;
|
|
if (!Feb_Control_ReadRegister_BitMask(FEB_REG_STATUS, &value,
|
|
FEB_REG_STATUS_FX30_MSK)) {
|
|
LOG(logERROR,
|
|
("Trouble reading FEB_REG_STATUS reg to feb hardware version\n"));
|
|
return 0;
|
|
}
|
|
*retval = (value >> FEB_REG_STATUS_FX30_OFST);
|
|
return 1;
|
|
}
|
|
|
|
int64_t Feb_Control_GetFrontLeftFirmwareVersion() {
|
|
if (!Feb_Control_activated) {
|
|
return 0;
|
|
}
|
|
unsigned int value = 0;
|
|
if (!Feb_Interface_ReadRegister(Feb_Control_leftAddress, FEB_REG_STATUS,
|
|
&value)) {
|
|
LOG(logERROR, ("Trouble reading FEB_REG_STATUS reg to get left feb "
|
|
"fw version\n"));
|
|
return 0;
|
|
}
|
|
return ((value & FEB_REG_STATUS_FW_VERSION_MSK) >>
|
|
FEB_REG_STATUS_FW_VERSION_OFST);
|
|
}
|
|
|
|
int64_t Feb_Control_GetFrontRightFirmwareVersion() {
|
|
if (!Feb_Control_activated) {
|
|
return 0;
|
|
}
|
|
unsigned int value = 0;
|
|
if (!Feb_Interface_ReadRegister(Feb_Control_rightAddress, FEB_REG_STATUS,
|
|
&value)) {
|
|
LOG(logERROR, ("Trouble reading FEB_REG_STATUS reg to get right feb "
|
|
"fw version\n"));
|
|
return 0;
|
|
}
|
|
return ((value & FEB_REG_STATUS_FW_VERSION_MSK) >>
|
|
FEB_REG_STATUS_FW_VERSION_OFST);
|
|
}
|
|
|
|
int64_t Feb_Control_GetMeasuredPeriod() {
|
|
if (!Feb_Control_activated) {
|
|
return 0;
|
|
}
|
|
unsigned int value = 0;
|
|
if (!Feb_Interface_ReadRegister(Feb_Control_leftAddress, MEAS_PERIOD_REG,
|
|
&value)) {
|
|
LOG(logERROR,
|
|
("Trouble reading MEAS_PERIOD_REG reg to get measured period\n"));
|
|
return 0;
|
|
}
|
|
return (int64_t)value * 10;
|
|
}
|
|
|
|
int64_t Feb_Control_GetSubMeasuredPeriod() {
|
|
if (!Feb_Control_activated) {
|
|
return 0;
|
|
}
|
|
unsigned int value = 0;
|
|
if (!Feb_Interface_ReadRegister(Feb_Control_leftAddress, MEAS_SUBPERIOD_REG,
|
|
&value)) {
|
|
LOG(logERROR, ("Trouble reading MEAS_SUBPERIOD_REG reg to get measured "
|
|
"sub period\n"));
|
|
return 0;
|
|
}
|
|
return (int64_t)value * 10;
|
|
}
|