Compare commits

..

175 Commits

Author SHA1 Message Date
c10bc5e530 9.2.0.rc (#1232)
Some checks failed
Native CMake Build / Configure and build using cmake (push) Failing after 3s
* Python module is now built using scikit-build-core: Dev/scikitbuild #1164
* slsdet is available on PyPI from this release onwards
* Fixed broken import in typecaster.h #1181
* Dev/automate version number #1193
* Dev/automate version part2 #1209
* 9111: added expat to host section to fix conda #1216
* fix for gotthard.py to import slsdet properly
* added slsFramesynchronizer to conda copy_lib.sh
* version of release
* update version of client
* removed cmake <=3.28 that was added in 9.1.11 (main_library in meta.yaml in conda-recipes)
* added slsFrameSynchronizer binary to conda
* added numpy dependency to toml
* added documentation for pip in installation

Detailed Commits:
* skeleton pyproject.toml
* moved compiled extension into slsdet
* WIP
* WI{
* separated the recipes
* restored comments, cleanup
* cleaned meta yaml
* added back some python versions
* conda build of main library
* fixed typo
* removed conda build pin
* added zlib
* added workflow for python lib
* patching libzmq and cleaned up cmake
* removed compiler version
* switched patch tool
* reverted to scikit-build in pyproject.toml
* added sls_detector bin
* added sync, renamed action
* update cmake<=3.28 in conda build requirements
* Fixed broken import in typecaster.h (#1181)
- Fixed the broken import _slsdet --> slsdet._slsdet caused by a previous upgrade
- added tests that exercises the conversion from python to C++ and from C++ to python
- Python unit tests now run in CI (!)
* removed 3.28 restriction on cmake in meta.yaml
* from #1216 to 9.1.1.rc that got lost in merge from develoepr, added expat to host section to fix conda build
* back with the cmake restriction
* fixing gotthard1 import
* version number automated for python build
* mistakenly set version back to 0.0.0
* updated github workflow scripts to support automatic version numbering with environment variable
* managed to load VERSION file in yaml file - simplifies things
* saving changes in git workflow failed
* got typo in github workflow
* updatet regex pattern to support postfix
* normalized version to PEP 440 specification in update_version.py
* bug did not support version 0.0.0
* added regex pattern matching to version in toml file
* version now supports . before postfix
* updates api version based on version file & converted shell script files to python
* updated all makefiles
* adresses review comments
* updated release version and the api lib version
* raise an exception if the pull socket python script had errors at startup (for eg if pyzmq was not installed)
* cmake<=3.28 not required anymore
* updated documentation for pip installation as well
* 920/add numpy  (#1226)
* added numpy dependency
* aded build specifications for python version and platform
* release notes
---------
Co-authored-by: froejdh_e <erik.frojdh@psi.ch>
Co-authored-by: Fröjd Lars Erik <froejdh_e@pcmoench03.psi.ch>
Co-authored-by: Erik Fröjdh <erik.frojdh@gmail.com>
Co-authored-by: mazzol_a <mazzol_a@pc17378.psi.ch>
Co-authored-by: AliceMazzoleni99 <alice.mazzoleni@psi.ch>
2025-06-02 13:45:06 +02:00
0d1642c56e 9.1.1: Merge pull request #1217 from slsdetectorgroup/9.1.1.rc
Some checks failed
CMake / Configure and build using cmake (push) Failing after 2s
2025-05-22 11:33:01 +02:00
9bb25445f5 formatting 2025-05-22 10:54:02 +02:00
376514606f updated relase notes 2025-05-22 10:51:57 +02:00
8707196f58 Merge pull request #1216 from slsdetectorgroup/911/fix-conda
Some checks failed
CMake / Configure and build using cmake (push) Failing after 2s
added expat to host section to fix conda build
2025-05-22 10:06:41 +02:00
9f9b1d496c added expat to host section 2025-05-22 09:51:01 +02:00
b2dd964907 Merge pull request #1212 from slsdetectorgroup/911/doc_frame_sync
911/documentation for slsFrameSynchronizer
2025-05-22 08:43:11 +02:00
348d820265 minor 2025-05-21 17:27:31 +02:00
d414c7459b minor aesthetics 2025-05-21 17:05:38 +02:00
8eb2134d9f Merge pull request #1213 from slsdetectorgroup/fix/StaticVector
Some checks failed
CMake / Configure and build using cmake (push) Failing after 2s
911: rewrote end() for StaticVector
2025-05-21 16:34:07 +02:00
b8b067d74b typo 2025-05-21 15:46:49 +02:00
3619a032ac rewrote end() for StaticVector 2025-05-21 15:46:04 +02:00
2ee7e36fb3 rearranged receiver topics, differentiated btween receiver variants and added info about slsFrameSynchronizer 2025-05-21 14:45:01 +02:00
d739453f2b added support to release notes
Some checks failed
CMake / Configure and build using cmake (push) Failing after 1s
2025-05-14 09:10:15 +02:00
3bfa3bfba3 update receiver version
Some checks failed
CMake / Configure and build using cmake (push) Failing after 1s
2025-05-13 23:30:35 +02:00
894c227723 update release notes and package version 2025-05-13 23:26:04 +02:00
f3e5804d02 Merge pull request #1205 from slsdetectorgroup/911/fix_frame_sync
Some checks failed
CMake / Configure and build using cmake (push) Failing after 2s
911/fix frame sync
2025-05-12 01:01:16 +02:00
2c4cd80748 moving the erasure of the fnum to after sending the zmg packets and also deleteing all old frames when end of acquisition
Some checks failed
CMake / Configure and build using cmake (push) Failing after 2s
2025-05-07 16:44:03 +02:00
674865120b typo 2025-05-07 16:03:43 +02:00
c0ae090be0 better error messageS 2025-05-07 16:02:37 +02:00
a85ad6cd84 minor 2025-05-07 16:01:31 +02:00
5f6dea2d6d fix for gotthard to work 2025-05-07 14:06:30 +02:00
f5bf509525 typo 2025-05-07 13:58:21 +02:00
03eded30f9 refactored test_simulator and test_frame_synchronizer tests 2025-05-07 13:57:12 +02:00
684f511bf8 copy in make
Some checks failed
CMake / Configure and build using cmake (push) Failing after 3s
2025-05-06 17:38:07 +02:00
2c93d40e81 moved log out to utils 2025-05-06 17:37:40 +02:00
9889a31f81 works for all detectors
Some checks failed
CMake / Configure and build using cmake (push) Failing after 2s
2025-05-05 17:22:47 +02:00
b00a37bc16 minor 2025-05-05 14:05:08 +02:00
15030ab732 minor 2025-05-05 14:04:06 +02:00
0ecc6030c6 fixed fram sync issue. mainly due to zmq msg being cleaned up before sending it 2025-05-05 14:03:00 +02:00
6c604e2340 small fixes, but bug introduced here '40895b0148'
Some checks failed
CMake / Configure and build using cmake (push) Failing after 2s
2025-05-03 00:11:55 +02:00
0f4d10912b test frame synchonizer now runs for all modules (only jungfrua enableD) with num modules and num frames as arguments (also servers) and checks the output log of pull socket to ensure there are expected number of headers, moduels and series end htypes 2025-05-02 22:48:48 +02:00
af386a736e first draft of frame synchonizer test. also updated tests updated test_simiulator.py 2025-05-02 16:19:34 +02:00
a43f2c946f Merge pull request #1184 from slsdetectorgroup/911/fix_m3_trimbits_badchannels
Some checks failed
CMake / Configure and build using cmake (push) Failing after 11s
911: m3: fix trimbits and badchannels
2025-04-11 10:41:11 +02:00
8d21fd364b Merge pull request #1188 from slsdetectorgroup/911/slsmultireceiver_verbose_size
911: multi receiver: verbose option
2025-04-11 10:37:34 +02:00
9aceb07d80 update the comment about how to modify data on a data call back from the receiver 2025-04-11 10:30:28 +02:00
7b3accf372 commenting out the example in receiver data call back changing size as it affects users using debugging mode to print out headers 2025-04-10 13:11:16 +02:00
cfde194834 fixed versioning in server from preivous commit 2025-04-09 18:38:06 +02:00
8ac9cd6b15 updated release notes and serverbin 2025-04-09 18:16:47 +02:00
3e38de5092 m3 binary in 2025-04-09 18:13:54 +02:00
70e7879dd9 m3 server fix for trimbits and badchannels that are shifted by 1 2025-04-09 17:52:23 +02:00
37b2efb1ed Merge pull request #1178 from slsdetectorgroup/main_910/conda_build_fix
Some checks failed
CMake / Configure and build using cmake (push) Failing after 9s
fixed conda build
2025-03-28 14:39:43 +01:00
7ac18fbad9 update cmake<=3.28 in conda build requirements 2025-03-28 14:21:56 +01:00
6839315a7c release date 2025-03-28 11:38:50 +01:00
527915a2ca fixed conda build 2025-03-28 11:37:11 +01:00
64aad1e196 Merge pull request #1143 from slsdetectorgroup/9.1.0.rc
Some checks failed
CMake / Configure and build using cmake (push) Failing after 10s
9.1.0
2025-03-26 08:38:23 +01:00
d3f847100e updated date on release notes
Some checks failed
CMake / Configure and build using cmake (push) Failing after 11s
2025-03-25 17:08:40 +01:00
e1224936ca udpate api versioning 2025-03-25 17:02:53 +01:00
f29ef9e345 Merge pull request #1165 from slsdetectorgroup/910/multirxr_proper_cleanup_on_ctrlc
910: multirxr dirty destruct leaving arping thread hanging + versioning (multi and framesync)
2025-03-25 16:54:19 +01:00
00e3b196f6 added release notes 2025-03-20 13:40:37 +01:00
0109973e68 missed to commit 2025-03-20 13:38:17 +01:00
ad995b381a multireceiverapp: changed from pointer to destruct properly (or could have used reset() before exit but kept this for consistency with slsReceiver and slsFrameSynchronizer, added --version/ -v for slsMultiReciever and slsFramesynchronizer (in 10, could be done properly, got rid of unnecessary break after an exit in multireceiverapp, removed outdated f: command line option in slsReceiver used previously for config files, updated version print out to print binary in slsReceiver version command 2025-03-20 13:33:04 +01:00
53b84b17a6 Merge pull request #1162 from slsdetectorgroup/910/fix_tests_real_g2
Some checks failed
CMake / Configure and build using cmake (push) Failing after 10s
910: fixed tests for real gotthard2. change in reg address to test
2025-03-19 17:16:19 +01:00
16d404c21b fixed tests for real gotthard2. change in reg address to test 2025-03-19 17:11:05 +01:00
34ce96ffa0 Merge pull request #1157 from slsdetectorgroup/910/jf_timing_decoder_only_hw2.0
Some checks failed
CMake / Configure and build using cmake (push) Failing after 12s
jf: get timing info decoder only for hw 2.0
2025-03-18 12:31:45 +01:00
d5fa26ef9a even get is not supported for timing info decoder for jungfrau hw v1.0. only hw v2.0 is uspported 2025-03-18 12:29:25 +01:00
77f20b4e97 updated jungfrau binary 2025-03-18 11:04:55 +01:00
a295208c12 Merge pull request #1125 from slsdetectorgroup/910/release_notes
release notes
2025-03-12 09:29:48 +01:00
36a6087e1d Update RELEASE.txt
Updated frame sync notes
2025-03-12 08:10:49 +01:00
fb406a7c6c experimental tag on frame syncrhonizer release notes 2025-03-11 15:41:21 +01:00
6e4380db43 updated 910 lib versioning dates 2025-03-11 15:25:40 +01:00
903652bb72 added back the binaries that were missing 2025-03-11 11:04:43 +01:00
1609706093 minor changes in topic 2025-03-11 10:43:39 +01:00
14d2d171bb Merged main to 9.1.0.rc, keeping 9.1.0.rc changes 2025-03-11 10:34:17 +01:00
dd8452b365 jf firmware dates updated in release notes 2025-03-11 09:40:12 +01:00
15a9fb86da Merge pull request #1140 from slsdetectorgroup/910/jf_firmware_dates
910/jf firmware dates
2025-03-11 09:36:02 +01:00
222d2b3fad updated jf binary for fwv 1.6 and 2.6 2025-03-11 09:31:05 +01:00
a57531312f jungfrau firmware dates for fw v 1.6 and fw2.6 2025-03-11 09:29:01 +01:00
85a03a1d72 removed CMakeFiles folder. mistakenly added to repo (#1136) 2025-03-10 14:26:22 +01:00
fc197ed002 changed line 66 in docs/conf.py.in to app.add_css_file(filename) (#1130)
Co-authored-by: AliceMazzoleni99 <l_mazzol_a@pc17378.psi.ch>
2025-03-06 14:41:46 +01:00
a5d242876b m3:default period set to 0, updated serverBin folder as well (#1126) 2025-03-04 16:06:46 +01:00
76ce5de89e added release notes for m3 default period 2025-03-04 15:43:45 +01:00
dbb0dbcbcd release notes 2025-03-04 15:28:09 +01:00
87d40d418e reverted servers of eiger, gotthard, gotthard2, moench and mythen3 as nothing has really changed there other than formatting 2025-03-03 15:30:35 +01:00
c82712b587 prior release notes 2025-03-03 11:40:29 +01:00
9dd1509714 formatting 2025-03-03 11:02:38 +01:00
c8290598db 910: multi ids ignored silently in config file (#1114)
* warn that the multi id is ignored in config file? or throw?

* throw and not just warn with printouts as that could be silent as well

* throw for any multi id command in the file.
2025-02-27 10:41:31 +01:00
ff6a2655a2 when creating the python bindings for Detector class, it should ignore the assignment operators (#1106) 2025-02-26 12:20:35 +01:00
7b2e6ae4ab 910: udpated help on multi module and multi command help (#1116)
* udpated help on multi module and multi command help

* fixed issues with empty lines and other syntax with docuemntation

* fixed some warningsin documentation

* some changes to documentation about command line usage

* minor
2025-02-26 11:13:59 +01:00
706f3a103c jf: removed check to allow chipv1.0 also to set comp disable time (#1117) 2025-02-24 09:38:57 +01:00
5de98b3db0 file from Anna: could be reduce print out in zmq processing when using energy threshold (#1112) 2025-02-21 12:49:18 +01:00
7494e41862 910/frame synchronizer (#1086)
* wip: draft of frame synchronizer, semaphores not done yet

* signal handler not affecting semaphore inside lambda function

* finally works with sem

* install targets cmake error fix

* reducing the number of data call backs. incoming from developer

* WIP: of synchronisation (#969)

* WIP of synchronisation

* working so far if everything goes right

* added all information into json headers

* valid json

* allow frame synchronizer to have access to static libzmq when compiling on conda (libzeromq-devel not installed by default

* upto date with multirecieverapp for invalid arguments and help

* formatting

* remove warnings

* changes to print

* removed prints

* no need for print frames to be called

* minor

* commnet

* adding json header in start callback, imagesize in data callback and formatted

* fixed sanitizer issues. 1 left for ctrl+C
- zmq_msg_t should be deleted, not freed. Same with the char arrays and semaphores.

* fixed sanitizer issues and made it more readable

* moving clearing old frames to new startacq just in case it has to process soem frames before the callback

* created a callback mutex to register the callbacks when using threads for different Receiver objects instead of child processes, remove the clean up of the frames (deleting from a signal is thread unsafe) from the siginterrupt handler, reading or  setting terminate should also be inside the mutex, pass receiver object index so that only the first one   cleans up the shared structure

---------

Co-authored-by: Felix Engelmann <felix-github@nlogn.org>
2025-02-18 11:19:00 +01:00
7607fdc9a7 910 jf : bunch id decoder and auto comp disable (#1096)
* jf wip: bunch id decoder only in pcb v2.0 check and comments

* auto comp disable the same way for both chip versions. compdisabletime also available for 1.1 now

* formatting

* fixed tests

* updated jf binary
2025-02-18 11:16:11 +01:00
1bfffb842d added documentation of order in hostname command in quick start guide, udp header format for row and column values and in command line hostname (#1098) 2025-02-18 11:12:20 +01:00
7c48ae9a49 dont usleep if no transmission delay (#1100) 2025-02-18 11:10:26 +01:00
bf82aeee8d 910/restream stop delay (#1093)
* wait a bit for post processor to process the dummy

* refactoring

* minor
2025-02-11 11:02:32 +01:00
84e83bf551 restream stop if stop called, temp solution (#1092)
* restream stop if stop called, temp solution until new command for it

* chekckrestream is ambiguous when only checking receiver

* moved restreaming in background to receiver stop instead of detector stop (was in stop before due to gui stop button access), increase to 2s time to restream in client acquire

* minor

* moved stop to module class

* fix from before
2025-02-11 09:17:25 +01:00
60ce31bb17 removed .str().c_str() (#1089) 2025-02-11 09:15:18 +01:00
2947b65e02 versioning and formatting 2025-02-04 14:25:21 +01:00
1b41e39ad1 updated client versioning (#1061) 2024-11-26 15:14:03 +01:00
64fea22c2b back to getting version for conda from tag (#1059) 2024-11-26 14:35:46 +01:00
9beaed7813 release notes 2024-11-26 11:16:33 +01:00
0aeb7e4417 9.0.0.rc (#1058)
* 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>
2024-11-26 11:13:45 +01:00
4880f87791 8.0.2.rc (#974)
* moench: changed max shifts of adc clk from 240 to 200 (#909)

* moench server name and version renaming

* 802/moench default speed (#910)

* moench:change default speed to half speed

* Protect from getenv("HOME") returning nullptr  (#907)

* Protect from getenv("HOME") returning nullptr (e.g., in case running in systemd)

* Write proper warning in Module.cpp

* moench: min exptime and also a firmware update required (#911)

* moench server: changed default values of adcphase for full speed from 300 to 150 and dac vipre_cds from 800 to 1280 (#921)

* 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 (#919)

* 8.0.2.rc: client: blocking acquire stop with slave temporarily in waiting (#925)

* 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 (#928)

* 8.0.2.rc: m3 clkdiv0 20 (#923)

* 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

* 8.0.2.rc: moench empty data callback (#935)

* moench: empty data call back so that zmq sockets are still made and listened to in acquire that it waits for the dummy packet to be done

* moench zmq postprocessor: remove NEWZMQ ifdefs and remove connect for publisher socket

* changed enum from READOUT_ACTION_ZMQ to READOUT_ZMQ_ACTION for consistency

* 8.0.2.rc: client: status for blocking acquire stop with slave temporarily in waiting (#943)

* 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)

* 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

* updated documentation from martin (#947)

* 802: jungfrau HW 1.0: adc output clock phase to 120  (#951)

* jungfrau: change adc output clock phase from 180 to 120 for v1.0 boards for reliable readout of adc #2

* formatting

* 802/release notes (#954)

* updated release notes

* versioning

* fixed a warning about narrowing conversion from size_t to int (#962)

* updating client versioning

* dont build doc for Tobi Schluter from libzmq, which uses iso-8859-1 and the umlaut cause compilation to fail on some machines (#972)

* updated release notes

---------

Co-authored-by: Filip Leonarski <filip.leonarski@psi.ch>
Co-authored-by: Erik Fröjdh <erik.frojdh@gmail.com>
Co-authored-by: Z.H. Li <zhenghenge@gmail.com>
2024-09-17 09:44:14 +02:00
97f0c1fe46 8.0.1.rc (#891)
* forward declare zmq_msg_t and moved include

* removed zmq as dependency for slsdet (#870)

* Fixed path when building as submodule

* 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

* update release notes, release versions

---------

Co-authored-by: Erik Frojdh <erik.frojdh@gmail.com>
Co-authored-by: froejdh_e <erik.frojdh@psi.ch>
Co-authored-by: Anna Bergamaschi <anna.bergamaschi@psi.ch>
Co-authored-by: anberga <34126852+anberga@users.noreply.github.com>
2024-01-16 15:31:25 +01:00
a86fd00e59 Merge branch 'main' into 8.0.0.rc 2023-11-13 16:38:25 +01:00
24894667b7 release fw for ctb 2023-11-13 16:03:52 +01:00
4b414bfddb release notes 2023-11-12 15:39:58 +01:00
15d357d9ab release notes 2023-11-12 15:32:28 +01:00
f95de054f9 formatting 2023-11-12 15:29:34 +01:00
0aef8113dd documentation and examples 2023-11-12 15:11:36 +01:00
9785a41048 Merge branch '8.0.0.rc' of github.com:slsdetectorgroup/slsDetectorPackage into 8.0.0.rc 2023-11-10 17:29:47 +01:00
417e1a88a5 fixed doc 2023-11-10 17:29:35 +01:00
9c0dd0385d updating docs 2023-11-10 16:02:21 +01:00
5ab64efe3e added python 3.12 to the conda build variants 2023-11-10 14:18:38 +01:00
8f77e4d4fe added python 3.12 to the conda build variants 2023-11-10 14:17:40 +01:00
41c5b75b10 trigger signal issues handled at acquire (#862)
* 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
2023-11-10 11:24:18 +01:00
bfe53c6693 udpated release notes 2023-11-09 15:10:17 +01:00
f7997dd09a 8.0.0.rc: fix server logic in checking detector idle (#860)
* fix buggy logic in checking detector idle and an argument check
2023-11-09 15:07:03 +01:00
c64e87a2b6 7.0.3.rc: fix server logic in checking detector idle (#859)
* fix buggy logic in checking detector idle and an argument check
2023-11-09 14:21:11 +01:00
5eeb8e29c1 project version change 2023-11-08 17:31:29 +01:00
09697fa325 updated release notes 2023-11-08 17:30:07 +01:00
90b4daef39 updated release notes 2023-11-08 17:28:48 +01:00
2082f1eee7 updated release notes 2023-11-08 17:28:17 +01:00
d3a636b563 updated release notes 2023-11-08 17:24:56 +01:00
50b9b6ca39 update release notes 2023-11-08 14:14:04 +01:00
e86b57cdfc versioning, format, release notes, update test simulator (no need for psutil) 2023-11-08 12:12:17 +01:00
14e11e8b5b formatting and versioning 2023-11-08 11:43:09 +01:00
beafe86554 execute command inside server fixed (from fix simulator tests and exec command PR) (#856) 2023-11-08 09:26:00 +01:00
af3dc1e7f4 7.0.3.rc: execute command inside server fixed (from fix simulator tests and exec command PR) (#855)
* execute command inside server fixed (from fix simulator tests and exec command PR)
2023-11-08 09:25:52 +01:00
573177203b formatting 2023-11-07 14:51:15 +01:00
a3ca9ebce5 updating release notes 2023-11-07 14:35:42 +01:00
8174fc9691 Update RELEASE.txt 2023-11-07 12:34:10 +01:00
d6eac6da71 updated release notes 2023-11-07 11:22:09 +01:00
56c7ae4852 8.0.0.rc: fix py virtual test (#841)
* 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
2023-11-07 09:30:24 +01:00
9b9b09ceaf 703rc/tests/fix execute command (#842)
* fix execute command
* fix for tests for ctb
2023-11-07 09:29:48 +01:00
cfebaee2a5 handling inconsistent fnums to be -1 in gui, so when one sets 0 (change of value) will also give an exception (#853) 2023-11-06 16:11:40 +01:00
4613c54f57 handling inconsistent fnums to be -1 in gui, so when one sets 0 (change of value) will also give an exception (#852) 2023-11-06 16:11:25 +01:00
51f9d6f011 8.0.0rc: : gui acq finished callback for different status (#851)
* 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)
2023-11-06 16:08:23 +01:00
58ac7ac280 7.0.3.rc: gui acq finished callback for different status (#847)
* 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)
2023-11-06 16:07:38 +01:00
82edfa75d3 7.0.3.rc: process the raw data files as a list (#848)
* Added file list option for moenchRawDataProcess
2023-11-03 12:10:20 +01:00
35ed926047 formatting 2023-10-25 09:36:51 +02:00
4023ed0775 updated versioning 2023-10-25 09:36:04 +02:00
b6ef3bc39e updated release notest 2023-10-25 09:15:10 +02:00
2035666792 versioning and binaries updated 2023-10-25 08:43:23 +02:00
1ff4d806e7 minor 2023-10-25 08:25:02 +02:00
3861379653 updated release notes 2023-10-24 17:39:47 +02:00
91140bbb71 formatting 2023-10-24 11:17:18 +02:00
a5632fcbea fix warning for prev_val (variable size array) in tests (#837) 2023-10-23 15:55:13 +02:00
d44329117d fix warning for prev_val (variable size array) in tests (#836) 2023-10-23 15:52:59 +02:00
4a454aa698 tests for jf (#835) 2023-10-19 16:55:29 +02:00
0e43072db8 eiger required fw version to 32: fix for blocking trigger in quad (#833) 2023-10-18 17:04:26 +02:00
6c67025ea8 7.0.3.rc eiger: fw version to 32 (quad blocking trigger) (#832)
* eiger required fw version to 32: fix for blocking trigger in quad
2023-10-18 16:51:17 +02:00
e5ee27dbfa 8.0.0.rc jf: reconfigure chip when touching electron collection mode bit (#830)
* 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
2023-10-18 10:49:44 +02:00
601249cc71 8.0.0.rc jf: change status reg bits (#828)
* 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
2023-10-18 10:36:56 +02:00
ff60b8c379 8.0.0.rc: jf sync: stopping master gives idle (#823)
* 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

* stop on only the positions

---------

Co-authored-by: Erik Fröjdh <erik.frojdh@gmail.com>
2023-10-13 15:25:19 +02:00
37ce3d6f59 7.0.3.rc: jf sync: stopping master gives idle (#822)
* 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 ( not jungfrau, but eiger could)

* 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

* stop on only the positions

---------

Co-authored-by: Erik Fröjdh <erik.frojdh@gmail.com>
2023-10-13 12:27:43 +02:00
bf26533fd8 8.0.0.rc: jf fix pedestal (#820)
* jf pedestal fix: touch enable bit last
2023-10-05 10:28:51 +02:00
7106273521 update 2d gain plot (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 (#817) 2023-10-03 17:22:14 +02:00
1484d038de 7.03.rc: 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 (#818) 2023-10-03 17:22:03 +02:00
fb0090c79e removing the misleading word 'Simulating' when programmig fpga (#814) 2023-09-28 16:20:59 +02:00
adc68cd519 formatting 2023-09-28 15:51:40 +02:00
1566eef247 703rc/fix numeric limits (#812)
* fixed compilation for fedora for numeric_limits

* formatting
2023-09-28 10:49:02 +02:00
e7cd90db78 fixed crashing of moench03RawDataProcess when nframes>0 (#810) 2023-09-27 09:22:40 +02:00
45414149fe binaries in for the previous PR 2023-09-22 15:59:35 +02:00
48759f440e 703rc/fix port size (#802)
* validate port numbers in client

* validate port numbers created at virtual servers and receiver process as tcp ports
2023-09-18 08:59:53 +02:00
b367b7e431 fixed some interpolation issues (#796) 2023-08-28 13:38:19 +02:00
f0b2a6f6f9 update release notes 2023-08-25 14:02:50 +02:00
f761046bfc updated docs and versions 2023-07-12 16:50:13 +02:00
1a859b83db formatting 2023-07-12 16:06:31 +02:00
70bfc875a6 updating release notes 2023-07-11 17:02:27 +02:00
c0755308a4 updating release notes 2023-07-11 17:01:14 +02:00
ab5509e10c updating release notes 2023-07-11 17:00:42 +02:00
004cb26646 updated firmware versions for 7.0.2 2023-07-10 12:21:19 +02:00
a4f47a5945 synced master status running when setting to slave (#747)
* jf: unsync before setting master/slave and then sync (if it was set) to overcome master going into running state when making it a slave and synced

* add tests for this condition

* updated release notes, updated min fw version requirement for v1.0 boards
2023-05-25 11:04:05 +02:00
312f3f473d fix that only master starts second and not all (for start acq), typo with pos and masters list (#743) 2023-05-11 10:20:17 +02:00
5871086cd6 formatting 2023-05-08 17:04:04 +02:00
6a0fe823b3 enable fix g0 when in expert mode (when gain mode enabled and not just visible) (#736) 2023-05-08 14:20:21 +02:00
5912aae53e Rx roi zmq (#726)
adding rx_roi also in the zmq header for external guis to put the "yellow box".. sending full roi instead of -1, and sending for each zmq port. "(multiple yellow boxes)".
2023-05-08 12:23:05 +02:00
8833ccf5cc 7.0.2.rc (#721)
* row and column for jungfrau mixed up

* multi module jungfrau sync must do slaves first then master for start acquisition and send software trigger, and master first and then slaves for stopacquisition

* non blocking to slaves first and only then blocking/nonblocking to the master for sending software trigger(jungfrau multi mod sync)

* fixed get/set timing jungfrau when sync enabled, getsync during blocking acquire (for trigger or stop) will get stuck as it should ask the stop server

* switching between 1 and 2 interfaces did not set gui/client zmq port properly. Resulted in dummy streaming forever. fixed

* formatting, refactoring: const & for positions, multi mod M3 stop first master first

* adding missing cstdint for gcc 13

* Refactoring handle sync out, handling synchronization also for softwaretrigger for m3, for start/sync/stop for g2/g1

---------

Co-authored-by: Erik Frojdh <erik.frojdh@gmail.com>
2023-05-08 12:11:19 +02:00
77c558a7be formatting 2023-03-24 12:54:55 +01:00
378fc301b8 updating client version, release version and project_version in CMakeLists.txt 2023-03-23 15:43:17 +01:00
87d6e16090 7.0.1 fix det server version (#702)
* check server version before initial checks, catch old server version exception, get old server version as 64 bit and print it along with exception
2023-03-23 15:37:01 +01:00
2ef021041c rx_arping sigchld (#701)
* rx_arping pclose gave -1 due to sigchld being ignored, fixed with sig handler doing a wait
2023-03-23 13:58:40 +01:00
574127b5ac fix hdf5 compilation using det spec fields in header (#700)
* fix hdf5 compilation using det spec fields in header
2023-03-23 12:30:38 +01:00
219 changed files with 31199 additions and 29551 deletions

View File

@ -1,29 +0,0 @@
name: Build on RHEL8
on:
push:
workflow_dispatch:
permissions:
contents: read
jobs:
build:
runs-on: "ubuntu-latest"
container:
image: gitea.psi.ch/detectors/rhel8-detectors-dev
steps:
- name: Clone repository
run: |
echo Cloning ${{ github.ref_name }}
git clone https://${{secrets.GITHUB_TOKEN}}@gitea.psi.ch/${{ github.repository }}.git --branch=${{ github.ref_name }} .
- name: Build library
run: |
mkdir build && cd build
cmake .. -DSLS_USE_PYTHON=ON -DSLS_USE_TESTS=ON
make -j 2
- name: C++ unit tests
working-directory: ${{gitea.workspace}}/build
run: ctest

View File

@ -1,27 +0,0 @@
name: Build on RHEL9
on:
push:
workflow_dispatch:
permissions:
contents: read
jobs:
build:
runs-on: "ubuntu-latest"
container:
image: gitea.psi.ch/detectors/rhel9-detectors-dev
steps:
- uses: actions/checkout@v4
- name: Build library
run: |
mkdir build && cd build
cmake .. -DSLS_USE_PYTHON=ON -DSLS_USE_TESTS=ON
make -j 2
- name: C++ unit tests
working-directory: ${{gitea.workspace}}/build
run: ctest

View File

@ -44,10 +44,6 @@ endif()
# Patch is applied in the FetchContent_Declare
set(SLS_LIBZMQ_VERSION "4.3.4")
find_program(PATCH_EXECUTABLE patch)
if(NOT PATCH_EXECUTABLE)
message(FATAL_ERROR "The 'patch' tool is required for patching lib zeromq. Please install it.")
endif()
if(SLS_FETCH_ZMQ_FROM_GITHUB)
# Opt in to pull down a zmq version from github instead of
@ -220,7 +216,7 @@ endif()
# to control options for the libraries
if(NOT TARGET slsProjectOptions)
add_library(slsProjectOptions INTERFACE)
target_compile_features(slsProjectOptions INTERFACE cxx_std_17)
target_compile_features(slsProjectOptions INTERFACE cxx_std_11)
endif()
if (NOT TARGET slsProjectWarnings)
@ -333,8 +329,7 @@ if (SLS_USE_INTEGRATION_TESTS)
endif (SLS_USE_INTEGRATION_TESTS)
if (SLS_USE_PYTHON)
find_package (Python 3.8 COMPONENTS Interpreter Development.Module REQUIRED)
set(PYBIND11_FINDPYTHON ON) # Needed for RH8
find_package (Python 3.8 COMPONENTS Interpreter Development)
if(SLS_FETCH_PYBIND11_FROM_GITHUB)
FetchContent_Declare(
pybind11

View File

@ -1,21 +1,13 @@
SLS Detector Package Major Release x.x.x released on xx.xx.202x
===============================================================
SLS Detector Package Minor Release 9.2.0 released on 02.06.2025
==================================================================
This document describes the differences between vx.x.x and vx.0.2
This document describes the differences between v9.2.0 and v9.1.1
CONTENTS
--------
1 New, Changed or Resolved Features
1.1 Compilation
1.2 Callback
1.3 Python
1.4 Client
1.5 Detector Server
1.6 Simulator
1.7 Receiver
1.8 Gui
1 New or Changed Features
2 On-board Detector Server Compatibility
3 Firmware Requirements
4 Kernel Requirements
@ -24,10 +16,21 @@ This document describes the differences between vx.x.x and vx.0.2
1 New, Changed or Resolved Features
=====================================
1 New or Changed Features
=========================
Python
------
* Python module is now built using scikit-build-core
* slsdet is available on PyPI from this release onwards
* Updated documentation on python module installation
@ -36,9 +39,10 @@ This document describes the differences between vx.x.x and vx.0.2
Eiger 9.0.0
Jungfrau 9.0.0
Mythen3 9.0.0
Jungfrau 9.1.0
Mythen3 9.1.1
Gotthard2 9.0.0
Gotthard 9.0.0
Moench 9.0.0
@ -65,14 +69,17 @@ This document describes the differences between vx.x.x and vx.0.2
Eiger 02.10.2023 (v32) (updated in 7.0.3)
Jungfrau 20.09.2023 (v1.5, HW v1.0) (updated in 8.0.0)
21.09.2023 (v2.5, HW v2.0) (updated in 8.0.0)
Jungfrau 09.02.2025 (v1.6, HW v1.0) (updated in 9.1.0)
08.02.2025 (v2.6, HW v2.0) (updated in 9.1.0)
Mythen3 11.10.2024 (v1.5) (updated in 9.0.0)
Mythen3 13.11.2024 (v2.0) (updated in 9.0.0)
Gotthard2 03.10.2024 (v1.0) (updated in 9.0.0)
Moench 26.10.2023 (v2.0) (updated in 9.0.0)
Moench 26.10.2023 (v2.0) (updated in 8.0.2)
Gotthard 08.02.2018 (50um and 25um Master)
09.02.2018 (25 um Slave)
Detector Upgrade
@ -86,6 +93,8 @@ This document describes the differences between vx.x.x and vx.0.2
Gotthard2 via command <.rbf>
Moench via command <.pof>
Gotthard cannot be upgraded remotely
Except Eiger,
upgrade
Using command 'programfpga' or
@ -206,3 +215,4 @@ This document describes the differences between vx.x.x and vx.0.2
dhanya.thattil@psi.ch
erik.frojdh@psi.ch
alice.mazzoleni@psi.ch

View File

@ -1 +1 @@
0.0.0
9.2.0

View File

@ -28,6 +28,7 @@ requirements:
- libgl-devel # [linux]
- libtiff
- zlib
- expat
run:
- libstdcxx-ng

View File

@ -40,7 +40,6 @@ set(SPHINX_SOURCE_FILES
src/pydetector.rst
src/pyenums.rst
src/pyexamples.rst
src/pyPatternGenerator.rst
src/servers.rst
src/receiver_api.rst
src/result.rst
@ -54,7 +53,6 @@ set(SPHINX_SOURCE_FILES
src/serverdefaults.rst
src/quick_start_guide.rst
src/troubleshooting.rst
src/pattern.rst
src/receivers.rst
src/slsreceiver.rst
src/udpheader.rst

View File

@ -21,7 +21,7 @@ print('\n\n\n\n SERVER CSV')
src = Path('@CMAKE_SOURCE_DIR@')/'slsDetectorServers/'
detectors = ['Mythen3', 'Gotthard2', 'Eiger',
'Jungfrau', 'Moench', 'Ctb']
'Jungfrau', 'Moench', 'Gotthard', 'Ctb']
for det in detectors:

View File

@ -320,6 +320,61 @@ Moench
}
}
Gotthard I
^^^^^^^^^^^
.. code-block:: text
{
"Version": 7.2,
"Timestamp": "Wed Nov 13 15:16:19 2024",
"Detector Type": "Gotthard",
"Timing Mode": "auto",
"Geometry": {
"x": 1,
"y": 1
},
"Image Size in bytes": 2560,
"Pixels": {
"x": 1280,
"y": 1
},
"Max Frames Per File": 20000,
"Frame Discard Policy": "nodiscard",
"Frame Padding": 1,
"Scan Parameters": "[disabled]",
"Total Frames": 1,
"Receiver Roi": {
"xmin": 4294967295,
"xmax": 4294967295,
"ymin": 4294967295,
"ymax": 4294967295
},
"Exptime": "1.00001ms",
"Period": "1s",
"Detector Roi": {
"xmin": 4294967295,
"xmax": 4294967295
},
"Frames in File": 1,
"Frame Header Format": {
"Frame Number": "8 bytes",
"SubFrame Number/ExpLength": "4 bytes",
"Packet Number": "4 bytes",
"Bunch ID": "8 bytes",
"Timestamp": "8 bytes",
"Module Id": "2 bytes",
"Row": "2 bytes",
"Column": "2 bytes",
"Reserved": "2 bytes",
"Debug": "4 bytes",
"Round Robin Number": "2 bytes",
"Detector Type": "1 byte",
"Header Version": "1 byte",
"Packets Caught Mask": "64 bytes"
}
}
Chip Test Board
^^^^^^^^^^^^^^^
@ -359,7 +414,6 @@ Chip Test Board
"Digital Flag": 0,
"Digital Samples": 1000,
"Dbit Offset": 0,
"Dbit Reorder": 1,
"Dbit Bitset": 0,
"Transceiver Mask": "0x3",
"Transceiver Flag": 0,

View File

@ -131,6 +131,42 @@ Program from console
Gotthard I
-----------
Download
^^^^^^^^^^^^^
- detector server corresponding to package in slsDetectorPackage/serverBin
- `pof files <https://github.com/slsdetectorgroup/slsDetectorFirmware>`__
.. _firmware upgrade using blaster for blackfin:
Upgrade
^^^^^^^^
.. warning ::
| Gotthard firmware cannot be upgraded remotely and requires the use of USB-Blaster.
| It is generally updated by us.
#. Download `Altera Quartus software or Quartus programmer <https://fpgasoftware.intel.com/20.1/?edition=standard&platform=linux&product=qprogrammer#tabs-4>`__.
#. Start Quartus programmer, click on Hardware Setup. In the "Currently selected hardware" window, select USB-Blaster.
#. In the Mode combo box, select "Active Serial Programming".
#. Plug the end of your USB-Blaster with the adaptor provided to the connector 'AS config' on the Gotthard board.
#. Click on 'Add file'. Select programming (pof) file provided by us.
#. Check "Program/Configure" and "Verify". Push the start button. Wait until the programming process is finished.
#. In case of error messages, check the polarity of cable (that pin1 corresponds) and that the correct programming connector is selected.
#. Reboot the detector.
Mythen III
-----------
@ -360,3 +396,7 @@ How to get back mtd3 drive remotely (udpating kernel)
more /proc/mtd # verify mtd3 is listed
Last Resort using USB Blaster
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
If none of these steps work, the last resort might be physically upgrading the firmware using a USB blaster, which also requires opening up the detector. Instructions for all the blackfin detectors are the same as the one for :ref:`gotthard firmware upgrade <firmware upgrade using blaster for blackfin>`.

View File

@ -36,8 +36,6 @@ Welcome to slsDetectorPackage's documentation!
pydetector
pyenums
pyexamples
pyPatternGenerator
pattern
.. toctree::
:caption: Command line
@ -81,8 +79,9 @@ Welcome to slsDetectorPackage's documentation!
:caption: Receiver
:maxdepth: 2
receivers
slsreceiver
receivers
.. toctree::
:caption: Receiver Files

View File

@ -6,18 +6,33 @@
Installation
===============
One can either install pre-built binaries using conda or build from source.
.. contents::
:local:
:depth: 2
:backlinks: top
.. warning ::
Before building from source make sure that you have the
:doc:`dependencies <../dependencies>` installed. If installing using conda, conda will
manage the dependencies. Avoid also installing packages with pip.
Overview
--------------
The ``slsDetectorPackage`` provides core detector software implemented in C++, along with Python bindings packaged as the ``slsdet`` Python extension module. Choose the option that best fits your environment and use case.
:ref:`conda pre-built binaries`:
Install pre-built binaries for the C++ client, receiver, GUI and the Python API (``slsdet``), simplifying setup across platforms.
:ref:`pip`:
Install only the Python extension module, either by downloading the pre-built library from PyPI or by building the extension locally from source. Available only from v9.2.0 onwards.
:ref:`build from source`:
Compile the entire package yourself, including both the C++ core and the Python bindings, for maximum control and customization. However, make sure that you have the :doc:`dependencies <../dependencies>` installed. If installing using conda, conda will manage the dependencies. Avoid installing packages with pip and conda simultaneously.
Install binaries using conda
----------------------------------
.. _conda pre-built binaries:
1. Install pre-built binaries using conda (Recommended)
--------------------------------------------------------
Conda is not only useful to manage python environments but can also
be used as a user space package manager. Dates in the tag (for eg. 2020.07.23.dev0)
@ -63,12 +78,29 @@ We have four different packages available:
conda search moenchzmq
.. _pip:
2. Pip
-------
The Python extension module ``slsdet`` can be installed using pip. This is available from v9.2.0 onwards.
.. code-block:: bash
#Install the Python extension module from PyPI
pip install slsdet
# or install the python extension locally from source
git clone https://github.com/slsdetectorgroup/slsDetectorPackage.git --branch 9.2.0
cd slsDetectorPackage
pip install .
Build from source
----------------------
.. _build from source:
1. Download Source Code from github
3. Build from source
-------------------------
3.1. Download Source Code from github
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
.. code-block:: bash
@ -83,12 +115,12 @@ Build from source
2. Build from Source
3.2. Build from Source
^^^^^^^^^^^^^^^^^^^^^^^^^^
One can either build using cmake or use the in-built cmk.sh script.
Build using CMake
3.2.1. Build using CMake
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
.. code-block:: bash
@ -135,7 +167,7 @@ Example cmake options Comment
For v7.x.x of slsDetectorPackage and older, refer :ref:`zeromq notes for cmake option to hint library location. <zeromq for different slsDetectorPackage versions>`
Build using in-built cmk.sh script
3.2.2. Build using in-built cmk.sh script
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@ -185,8 +217,8 @@ Build using in-built cmk.sh script
For v7.x.x of slsDetectorPackage and older, refer :ref:`zeromq notes for cmk script option to hint library location. <zeromq for different slsDetectorPackage versions>`
Build on old distributions
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
3.3. Build on old distributions using conda
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
If your linux distribution doesn't come with a C++11 compiler (gcc>4.8) then
it's possible to install a newer gcc using conda and build the slsDetectorPackage
@ -210,7 +242,7 @@ using this compiler
Build slsDetectorGui (Qt5)
3.4. Build slsDetectorGui (Qt5)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
1. Using pre-built binary on conda
@ -271,7 +303,7 @@ Build slsDetectorGui (Qt5)
Build this documentation
3.5. Build this documentation
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
The documentation for the slsDetectorPackage is build using a combination
@ -294,8 +326,8 @@ is to use conda
make rst # rst only, saves time in case the API did not change
Pybind and Zeromq
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
4. Pybind and Zeromq
-------------------------
.. _pybind for different slsDetectorPackage versions:

View File

@ -288,6 +288,56 @@ Moench
| Frame Header Format | Expected frame header format for the data files |
+-----------------------+-------------------------------------------------+
Gotthard I
^^^^^^^^^^^
+-----------------------+-------------------------------------------------+
| **Key** | **Description** |
+-----------------------+-------------------------------------------------+
| Version | Version of the master file |
| | Current value:8.0 |
+-----------------------+-------------------------------------------------+
| Timestamp | Timestamp of creation of master file |
+-----------------------+-------------------------------------------------+
| Detector Type | Detector type |
+-----------------------+-------------------------------------------------+
| Timing Mode | Timing Mode |
+-----------------------+-------------------------------------------------+
| Geometry | Number of UDP ports in x and y dimension for |
| | complete detector |
+-----------------------+-------------------------------------------------+
| Image Size in bytes | Image size in bytes per UDP port |
+-----------------------+-------------------------------------------------+
| Pixels | Number of pixels in x and y dimension |
| | per UDP port |
+-----------------------+-------------------------------------------------+
| Max Frames Per File | Maximum frames per file |
+-----------------------+-------------------------------------------------+
| Frame Discard Policy | Receiever Frame discard policy |
| | for partial frames |
+-----------------------+-------------------------------------------------+
| Frame Padding | Receiver Frame padding enable |
| | for partial frames |
+-----------------------+-------------------------------------------------+
| Scan Parameters | Scanning mode on detector |
+-----------------------+-------------------------------------------------+
| Total Frames | Total number of frames and triggers expected |
+-----------------------+-------------------------------------------------+
| Receiver Roi | Receiver ROI in file including xmax and ymax |
+-----------------------+-------------------------------------------------+
| Exptime | Exposure time |
+-----------------------+-------------------------------------------------+
| Period | Period between frames |
+-----------------------+-------------------------------------------------+
| Detector Roi | Roi in detector restricted to an ADC. |
| | Includes xmax |
+-----------------------+-------------------------------------------------+
| Burst Mode | Burst mode of detector |
+-----------------------+-------------------------------------------------+
| Frames in File | Number of frames written to file by Receiver 0 |
+-----------------------+-------------------------------------------------+
| Frame Header Format | Expected frame header format for the data files |
+-----------------------+-------------------------------------------------+
Chip Test Board
^^^^^^^^^^^^^^^
@ -345,9 +395,6 @@ Chip Test Board
+-----------------------+-------------------------------------------------+
| Dbit Offset | Digital offset of valid data in bytes |
+-----------------------+-------------------------------------------------+
| Dbit Reorder | Reorder such that it groups each signal (0-63) |
| | from all the different samples together |
+-----------------------+-------------------------------------------------+
| Dbit Bitset | Digital 64 bit mask of bits enabled in receiver |
+-----------------------+-------------------------------------------------+
| Transceiver Mask | Mask of channels enabled in Transceiver |

View File

@ -1,122 +0,0 @@
Pattern
========================
This is a test and development feature implemented only for Ctb, Xilinx_Ctb and Mythen3.
A pattern is a sequence of 64-bit words which is executed using a clock on the FPGA. Each of the 64 bits is connected to a pin or internal signal of the FPGA. The purpose of a pattern is to provide a way to change these 64 signals with precise timing. Commands run by the detector server could manipulate the same signals as the pattern, but they cannot enforce a change in a specific clock cycle.
**Usage**
A pattern is written to memory on the FPGA using the patword command.
.. code-block::
patword 0x0000 0x000000000000000A
patword 0x0001 0x000000000000000B
patword 0x0002 0x000000000000000C
patword 0x0003 0x000000000000000D
patword 0x0004 0x000000000000000E
The example above writes a five-word pattern into FPGA memory. The first argument is the memory address, the second argument is the content to be written into this address. Before executing a pattern one has to set the address limits of the pattern:
.. code-block::
patlimits 0x0000 0x0004
This instructs the firmware to execute the commands from address 0 to 4 (including 0 and 4). The execution can be started from the pyctbgui or with the commands
.. code-block::
start [Ctb, Xilinx_Ctb]
patternstart [Mythen3]
The maximal number of patword addresses is 8192. However, it is possible to extend the length of the pattern sequence using loops and wait commands. Loops can be configured with the following commands:
.. code-block::
patloop 0 0x0001 0x0003
patnloop 0 7
The first argument of both commands is the ID of the loop. Ctb and Xilinx_Ctb can have 6 loops (ID 0-5), Mythen3 can have 4 loop definitions. The commands above configure the loop with ID 0 to run 7 times and jump from the patword with address 3 to the patword with address 1. Important: If patnloop is set to 1, the addresses 0x1-0x3 will execute exactly once; if it is set to 0, the pattern addresses will be skipped.
The same idea is used to introduce wait times. The example below causes the patword at address 0x0002 to be active for 9 clock cycles before the execution continues.
.. code-block::
patwait 0 0x0002
patwaittime 0 9
Waits can be placed inside a loop and loops can be nested.
**patioctrl**
The function of each bit in the sequence of 64-bit words depends on the connected detector and firmware version. Some of the 64 bits might connect directly to pads of a chip. The patioctrl command is used to configure the direction of some of these signals (not all of them !! See tables below). Signals where the corresponding bit in the argument of patioctrl is set to 1 will be driven from the FPGA.
**patsetbit and patmask**
The functions patsetbit and patmask can be used to ignore a specific bit of the pattern.
Example:
.. code-block::
patmask 0x0101
patsetbit 0x0001
Patmask configures bit 0 and 8 of the pattern to be set to their value in patsetbit. These bits will be ignored during pattern execution and will always be 0 (bit 8) and 1 (bit 0).
The mappings of bit positions in the pattern word to signals/pads of the FPGA are listed below for the three detector types where patterns are used. In the case of the two CTB's, connections of the signals to actual pads of a chip depend on the layout of the used detector adapter board. Therefore, each type of detector adapter board adds an additional mapping layer.
**CTB Pattern Bit Mapping**
.. table::
+----+---+------+----+----------+-------------------+----------------+
| 63 | 62| 61-57| 56 | 55-48 | 47-32 | 31-0 |
+----+---+------+----+----------+-------------------+----------------+
| A | D| --- | T | EXTIO | DO, stream source | DIO |
+----+---+------+----+----------+-------------------+----------------+
DIO: Driving the 32 FPGA pins corresponding to the lowest 32 bits of the patioctrl command. If bits in patioctrl are 0, the same bit positions in DIO will switch to input pins and connect to dbit sampling. Additionally, some of these 32 bits have an automatic override by detector-specific statemachines which is active whenever one of these statemachines is running (currently bits 7,8,11,14 and 20).
DO: Directly connected to 16 FPGA pins. Output only. Not influenced by patioctrl. Also connected to bit 47-32 in all Ctb dbit samples. All of them can be used as dbit sample trigger. In addition, every bit of DO can be selected as trigger for sending out a udp packet with samples to the receiver.
EXTIO: Similar to DIO, but not used as input to the fpga. With the corresponding patioctrl bits set to 0 these pins will switch to a high impedance mode and be ignored by the firmware.
T: trigger output
D: enable signal for digital sampling
A: adc enable
**Xilinx_CTB Pattern Bit Mapping**
.. table::
+-------+----------------+
| 63-32 | 31-0 |
+-------+----------------+
| --- | DIO |
+-------+----------------+
DIO: Driving the 32 FPGA pins corresponding to the lowest 32 bits of the patioctrl command. If bits in patioctrl are 0, the same bit positions in DIO will switch to input pins and connect to dbit sampling. Additionally, some of these 32 bits have an automatic override by detector-specific statemachines which is active whenever these sm's are running (currently bits 7,8,11,14 and 20).
**Mythen3 Pattern Bit Mapping**
.. table::
+-------+--------+-------+--------+------------+----------+----------+-----+-----+
| 63-33 | 32 | 31-25 | 24 | 23 | 22 | 21 | 20 | 19 |
+-------+--------+-------+--------+------------+----------+----------+-----+-----+
| --- | signARD| --- | CHSclk | cnt_rst | sto_rst | STATLOAD | STO | SIN |
+-------+--------+-------+--------+------------+----------+----------+-----+-----+
.. table::
+---------+-----+-------+-------+----+-------+---------+--------+
| 18 | 17 | 16-14 | 13 | 12 | 11 | 10 | 9-0 |
+---------+-----+-------+-------+----+-------+---------+--------+
| SR_MODE | clk | EN | PULSE | RD | CHSIN | ANAMode | TBLOAD |
+---------+-----+-------+-------+----+-------+---------+--------+
For Mythen3 the pattern word only connects to output pins of the FPGA when the pattern is running. Afterwards the signals will switch back to other logic in the FPGA. Both CTB's hold the last executed pattern word until a new pattern is started.

View File

@ -1,34 +0,0 @@
PatternGenerator
=====================================================
Python class to generate patterns for the Chip Test Board.
.. code-block:: python
from slsdet import PatternGenerator
p = PatternGenerator()
p.SB(5)
p.PW()
p.SB(8,9)
p.PW()
p.CB(5)
Created a pattern like this:
.. code-block:: bash
patword 0x0000 0x0000000000000020
patword 0x0001 0x0000000000000320
patword 0x0002 0x0000000000000300
patioctrl 0x0000000000000000
patlimits 0x0000 0x0002
...
.. py:currentmodule:: slsdet
.. autoclass:: PatternGenerator
:members:
:undoc-members:
:show-inheritance:
:inherited-members:

View File

@ -1,25 +1,25 @@
Receivers
Custom Receiver
=================
Receiver processes can be run on same or different machines as the client, receives the data from the detector (via UDP packets).
When using the slsReceiver/ slsMultiReceiver, they can be further configured by the client control software (via TCP/IP) to set file name, file path, progress of acquisition etc.
The receiver essentially listens to UDP data packets sent out by the detector.
To know more about detector receiver setup in the config file, please check out :ref:`the detector-receiver UDP configuration in the config file<detector udp header config>` and the :ref:`detector udp format<detector udp header>`.
To know more about detector receiver configuration, please check out :ref:`detector udp header and udp commands in the config file <detector udp header>`
| Please note the following when using a custom receiver:
Custom Receiver
----------------
* **udp_dstmac** must be configured in the config file. This parameter is not required when using an in-built receiver.
| When using custom receiver with our package, ensure that **udp_dstmac** is also configured in the config file. This parameter is not required when using slsReceiver.
* Cannot use "auto" for **udp_dstip**.
| Cannot use "auto" for **udp_dstip**.
* No **rx_** commands in the config file. These commands are for configuring the slsReceiver.
| Also ensure that there are no **rx_** commands in the config file. These commands are for configuring the slsReceiver.
The main difference is the lack of **rx_** commands or file commands (eg. **f**write, **f**path) and the **udp_dstmac** is required in config file.
Example of a custom receiver config file
* The main difference is the lack of **rx_** commands or file commands (eg. fwrite, fpath) and the udp_dstmac is required in config file.
.. code-block:: bash
# detector hostname

View File

@ -89,3 +89,18 @@ DACS
:widths: 35, 35
:header-rows: 1
Gotthard
-------------
.. csv-table:: Default values
:file: gotthard.csv
:widths: 35, 35
:header-rows: 1
DACS
^^^^^^^^^^^^^
.. csv-table:: Gotthard DACS
:file: gotthard-dacs.csv
:widths: 35, 35
:header-rows: 1

View File

@ -27,11 +27,12 @@ Arguments
-p, --port <port> : TCP communication port with client.
-g, --nomodule : [Mythen3][Gotthard2]
Generic or No Module mode. Skips detector type checks.
-f, --phaseshift <value> : [Gotthard] only. Sets phase shift.
-d, --devel : Developer mode. Skips firmware checks.
-u, --update : Update mode. Skips firmware checks and initial detector setup.
-i, --ignore-config : [Eiger][Jungfrau][Gotthard2][Moench]
-i, --ignore-config : [Eiger][Jungfrau][Gotthard][Gotthard2][Moench]
Ignore config file.
-m, --master <master> : [Eiger][Mythen3][Gotthard2]
-m, --master <master> : [Eiger][Mythen3][Gotthard][Gotthard2]
Set Master to 0 or 1. Precedence over config file. Only for virtual servers except Eiger.
-t, --top <top> : [Eiger] Set Top to 0 or 1. Precedence over config file.
-s, --stopserver : Stop server. Do not use as it is created by control server
@ -64,7 +65,7 @@ One can start the on-board detector server automatically upon powering on the bo
/home/root/executables/eigerDetectorServer &> /dev/null &
exit 0
Jungfrau | Moench | CTB
Jungfrau | Moench | CTB | Gotthard I
.. code-block:: bash
# Edit inittab on board

View File

@ -1,4 +1,5 @@
.. _Detector Server Upgrade:
Upgrade
========

View File

@ -1,16 +1,55 @@
slsReceiver/ slsMultiReceiver
In-built Receiver
================================
| One has to start the slsReceiver before loading config file or using any receiver commands (prefix: **rx_** )
The receiver essentially listens to UDP data packets sent out by the detector. It's main features are:
- **Listening**: Receives UDP data from the detector.
- **Writing to File**: Optionally writes received data to disk.
- **Streaming via ZMQ**: Optionally streams out the data using ZeroMQ.
Each of these operations runs asynchronously and in parallel for each UDP port.
.. note ::
* Can be run on the same or different machine as the client.
* Can be configured by the client. (set file name/ discard policy, get progress etc.)
* Has to be started before the client runs any receiver specific command.
Receiver Variants
-----------------
There are three main receiver types. How to start them is described :ref:`below<Starting up the Receiver>`.
+----------------------+--------------------+-----------------------------------------+--------------------------------+
| Receiver Type | slsReceiver | slsMultiReceiver |slsFrameSynchronizer |
+======================+====================+=========================================+================================+
| Modules Supported | 1 | Multiple | Multiple |
+----------------------+--------------------+-----------------------------------------+--------------------------------+
| Internal Architecture| Threads per porttt | Multiple child processes of slsReceiver | Multi-threading of slsReceiver |
+----------------------+--------------------+-----------------------------------------+--------------------------------+
| ZMQ Streaming | Disabled by default| Disabled by default | Enabled, not optional |
+----------------------+--------------------+-----------------------------------------+--------------------------------+
| ZMQ Synchronization | No | No | Yes, across ports |
+----------------------+--------------------+-----------------------------------------+--------------------------------+
| Image Reconstruction | No | No | No |
+----------------------+--------------------+-----------------------------------------+--------------------------------+
.. _Starting up the Receiver:
Starting up the Receiver
-------------------------
For a Single Module
.. code-block:: bash
# default port 1954
slsReceiver
slsReceiver # default port 1954
# custom port 2012
slsReceiver -t2012
slsReceiver -t2012 # custom port 2012
For Multiple Modules
@ -18,57 +57,66 @@ For Multiple Modules
# each receiver (for each module) requires a unique tcp port (if all on same machine)
# using slsReceiver in multiple consoles
# option 1 (one for each module)
slsReceiver
slsReceiver -t1955
# slsMultiReceiver [starting port] [number of receivers]
# option 2
slsMultiReceiver 2012 2
# slsMultiReceiver [starting port] [number of receivers] [print each frame header for debugging]
slsMultiReceiver 2012 2 1
# option 3
slsFrameSynchronizer 2012 2
Client Commands
-----------------
| One can remove **udp_dstmac** from the config file, as the slsReceiver fetches this from the **udp_ip**.
* Client commands to the receiver begin with **rx_** or **f_** (file commands).
| One can use "auto" for **udp_dstip** if one wants to use default ip of **rx_hostname**.
* **rx_hostname** has to be the first command to the receiver so the client knows which receiver process to communicate with.
| The first command to the receiver (**rx_** commands) should be **rx_hostname**. The following are the different ways to establish contact.
* Can use 'auto' for **udp_dstip** if using 1GbE interface or the :ref:`virtual simulators<Virtual Detector Servers>`.
To know more about detector receiver setup in the config file, please check out :ref:`the detector-receiver UDP configuration in the config file<detector udp header config>` and the :ref:`detector udp format<detector udp header>`.
The following are the different ways to establish contact using **rx_hostname** command.
.. code-block:: bash
# default receiver tcp port (1954)
# ---single module---
# default receiver port at 1954
rx_hostname xxx
# custom receiver port
rx_hostname xxx:1957
rx_hostname xxx:1957 # option 1
# custom receiver port
rx_tcpport 1954
rx_tcpport 1957 # option 2
rx_hostname xxx
# multi modules with custom ports
rx_hostname xxx:1955+xxx:1956+
# ---multi module---
# multi modules using increasing tcp ports when using multi detector command
# using increasing tcp ports
rx_tcpport 1955
rx_hostname xxx
# or specify multi modules with custom ports on same rxr pc
0:rx_tcpport 1954
# custom ports
rx_hostname xxx:1955+xxx:1958+ # option 1
0:rx_tcpport 1954 # option 2
1:rx_tcpport 1955
2:rx_tcpport 1956
rx_hostname xxx
# multi modules with custom ports on different rxr pc
# custom ports on different receiver machines
0:rx_tcpport 1954
0:rx_hostname xxx
1:rx_tcpport 1955
1:rx_hostname yyy
1:rx_hostname yyyrxr
| Example commands:
@ -91,6 +139,32 @@ Client Commands
sls_detector_get -h rx_framescaught
Example of a config file using in-built receiver
.. code-block:: bash
# detector hostname
hostname bchip052+bchip053+
# udp destination port (receiver)
# sets increasing destination udp ports starting at 50004
udp_dstport 50004
# udp destination ip (receiver)
0:udp_dstip 10.0.1.100
1:udp_dstip 10.0.2.100
# udp source ip (same subnet as udp_dstip)
0:udp_srcip 10.0.1.184
1:udp_srcip 10.0.2.184
# udp destination mac - not required (picked up from udp_dstip)
#udp_dstmac 22:47:d5:48:ad:ef
# connects to receivers at increasing tcp port starting at 1954
rx_hostname mpc3434
# same as rx_hostname mpc3434:1954+mpc3434:1955+
Performance

View File

@ -385,6 +385,14 @@ Cannot get data without a module attached
You cannot get data without a module attached as a specific pin is floating. Attach module to get data.
Gotthard
----------
Missing first frame or next frame after a delay
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Connect the data link from the Module directly to receiver pc or to a private network.
Mythen3
--------

View File

@ -1,4 +1,4 @@
.. _detector udp header:
.. _detector udp header config:
Config file

View File

@ -92,14 +92,14 @@ Detector Enum
================ ========
GENERIC 0
EIGER 1
GOTTHARD* 2
GOTTHARD 2
JUNGFRAU 3
CHIPTESTBOARD 4
MOENCH 5
MYTHEN3 6
GOTTHARD2 7
================ ========
* deprecated since v10.0.0
Previous Versions

View File

@ -1,4 +1,5 @@
.. _Virtual Detector Servers:
Simulators
===========
@ -22,6 +23,7 @@ Binaries
eigerDetectorServer_virtual
jungfrauDetectorServer_virtual
gotthardDetectorServer_virtual
gotthard2DetectorServer_virtual
mythen3DetectorServer_virtual
moenchDetectorServer_virtual

12
examples/gotthard.config Executable file
View File

@ -0,0 +1,12 @@
# detector hostname
hostname bchip007
# receiver pc hostname of 1Gb IP of the machine
rx_hostname my_receiver_hostname
# output directory
fpath /bigRAID/datadir_gotthard/rec_test_data
# high voltage
highvoltage 120

View File

@ -12,6 +12,5 @@ slsDetectorPackage/8.0.1_rh8 stable cmake/3.15.5 Qt/5.12.10
slsDetectorPackage/8.0.2_rh7 stable cmake/3.15.5 Qt/5.12.10
slsDetectorPackage/8.0.2_rh8 stable cmake/3.15.5 Qt/5.12.10
slsDetectorPackage/9.0.0_rh8 stable cmake/3.15.5 Qt/5.12.10
slsDetectorPackage/9.1.0_rh8 stable cmake/3.15.5 Qt/5.12.10

View File

@ -10,7 +10,6 @@ from matplotlib.backends.backend_qt5agg import NavigationToolbar2QT as Navigatio
from pyctbgui.utils.defines import Defines
from pyctbgui.utils.plotPattern import PlotPattern
from slsdet import DurationWrapper
class PatternTab(QtWidgets.QWidget):
@ -62,10 +61,7 @@ class PatternTab(QtWidgets.QWidget):
getattr(self.view, f"lineEditLoop{i}Wait").editingFinished.connect(partial(self.setPatLoopWaitAddress, i))
getattr(self.view,
f"spinBoxLoop{i}Repetition").editingFinished.connect(partial(self.setPatLoopRepetition, i))
getattr(self.view, f"doubleSpinBoxLoop{i}WaitClocks").editingFinished.connect(partial(self.setPatLoopWaitClocks, i))
getattr(self.view, f"spinBoxLoop{i}WaitInterval").editingFinished.connect(partial(self.setPatLoopWaitInterval, i))
getattr(self.view, f"comboBoxLoop{i}WaitInterval").currentIndexChanged.connect(partial(self.setPatLoopWaitInterval, i))
self.view.toolButtonTogglePageWaitTime.clicked.connect(self.setTogglePageWaitTime)
getattr(self.view, f"spinBoxLoop{i}WaitTime").editingFinished.connect(partial(self.setPatLoopWaitTime, i))
self.view.pushButtonCompiler.clicked.connect(self.setCompiler)
self.view.pushButtonUncompiled.clicked.connect(self.setUncompiledPatternFile)
self.view.pushButtonPatternFile.clicked.connect(self.setPatternFile)
@ -95,8 +91,7 @@ class PatternTab(QtWidgets.QWidget):
self.getPatLoopStartStopAddress(i)
self.getPatLoopWaitAddress(i)
self.getPatLoopRepetition(i)
self.getPatLoopWaitClocks(i)
self.getPatLoopWaitInterval(i)
self.getPatLoopWaitTime(i)
# Pattern Tab functions
@ -187,67 +182,17 @@ class PatternTab(QtWidgets.QWidget):
self.det.patnloop[level] = spinBox.value()
self.getPatLoopRepetition(level)
def getPatLoopWaitClocks(self, level):
def getPatLoopWaitTime(self, level):
retval = self.det.patwaittime[level]
spinBox = getattr(self.view, f"doubleSpinBoxLoop{level}WaitClocks")
spinBox = getattr(self.view, f"spinBoxLoop{level}WaitTime")
spinBox.editingFinished.disconnect()
spinBox.setValue(retval)
spinBox.editingFinished.connect(partial(self.setPatLoopWaitClocks, level))
def setPatLoopWaitClocks(self, level):
spinBox = getattr(self.view, f"doubleSpinBoxLoop{level}WaitClocks")
self.det.patwaittime[level] = int(spinBox.value())
self.getPatLoopWaitClocks(level)
def getPatLoopWaitInterval(self, level):
retval = self.det.getPatternWaitInterval(level)[0].count()
spinBox = getattr(self.view, f"spinBoxLoop{level}WaitInterval")
comboBox = getattr(self.view, f"comboBoxLoop{level}WaitInterval")
spinBox.editingFinished.disconnect()
comboBox.currentIndexChanged.disconnect()
# Converting to right time unit for period
if retval >= 1e9:
comboBox.setCurrentIndex(0)
spinBox.setValue(retval / 1e9)
elif retval >= 1e6:
comboBox.setCurrentIndex(1)
spinBox.setValue(retval / 1e6)
elif retval >= 1e3:
comboBox.setCurrentIndex(2)
spinBox.setValue(retval / 1e3)
else:
comboBox.setCurrentIndex(3)
spinBox.setValue(retval)
spinBox.editingFinished.connect(partial(self.setPatLoopWaitInterval, level))
comboBox.currentIndexChanged.connect(partial(self.setPatLoopWaitInterval, level))
def setPatLoopWaitInterval(self, level):
spinBox = getattr(self.view, f"spinBoxLoop{level}WaitInterval")
comboBox = getattr(self.view, f"comboBoxLoop{level}WaitInterval")
value = spinBox.value()
if comboBox.currentIndex() == 0:
value *= 1e9
elif comboBox.currentIndex() == 1:
value *= 1e6
elif comboBox.currentIndex() == 2:
value *= 1e3
t = DurationWrapper()
t.set_count(int(value))
self.det.patwaittime[level] = t
self.getPatLoopWaitInterval(level)
def setTogglePageWaitTime(self):
if self.view.stackedWidgetWaitTime.currentIndex() == 0:
self.view.stackedWidgetWaitTime.setCurrentIndex(1)
self.view.labelWaitTime.setText("Time")
for i in range(Defines.pattern.loops_count):
self.getPatLoopWaitInterval(i)
else:
self.view.stackedWidgetWaitTime.setCurrentIndex(0)
self.view.labelWaitTime.setText("Clocks")
for i in range(Defines.pattern.loops_count):
self.getPatLoopWaitClocks(i)
spinBox.editingFinished.connect(partial(self.setPatLoopWaitTime, level))
def setPatLoopWaitTime(self, level):
spinBox = getattr(self.view, f"spinBoxLoop{level}WaitTime")
self.det.patwaittime[level] = spinBox.value()
self.getPatLoopWaitTime(level)
def setCompiler(self):
response = QtWidgets.QFileDialog.getOpenFileName(
@ -505,7 +450,7 @@ class PatternTab(QtWidgets.QWidget):
f"{getattr(self.view, f'lineEditLoop{i}Stop').text()}")
commands.append(f"patwait {i} {getattr(self.view, f'lineEditLoop{i}Wait').text()}")
commands.append(f"patwaittime {i} {getattr(self.view, f'doubleSpinBoxLoop{i}WaitClocks').text()}")
commands.append(f"patwaittime {i} {getattr(self.view, f'spinBoxLoop{i}WaitTime').text()}")
commands.append(f"patlimits {self.view.lineEditStartAddress.text()}, {self.view.lineEditStopAddress.text()}")
# commands.append(f"patfname {self.view.lineEditPatternFile.text()}")
return commands

View File

@ -22,7 +22,6 @@ class SignalsTab(QtWidgets.QWidget):
self.plotTab = None
self.legend: LegendItem | None = None
self.rx_dbitoffset = None
self.rx_dbitreorder = None
self.rx_dbitlist = None
def refresh(self):
@ -30,7 +29,6 @@ class SignalsTab(QtWidgets.QWidget):
self.updateDigitalBitEnable()
self.updateIOOut()
self.getDBitOffset()
self.getDBitReorder()
def connect_ui(self):
for i in range(Defines.signals.count):
@ -51,7 +49,6 @@ class SignalsTab(QtWidgets.QWidget):
partial(self.setIOOutRange, Defines.signals.half, Defines.signals.count))
self.view.lineEditPatIOCtrl.editingFinished.connect(self.setIOOutReg)
self.view.spinBoxDBitOffset.editingFinished.connect(self.setDbitOffset)
self.view.checkBoxDBitReorder.stateChanged.connect(self.setDbitReorder)
def setup_ui(self):
self.plotTab = self.mainWindow.plotTab
@ -90,79 +87,60 @@ class SignalsTab(QtWidgets.QWidget):
self.legend.addItem(plot, name)
@recordOrApplyPedestal
def _processWaveformData(self, data, aSamples, dSamples, rx_dbitreorder, rx_dbitlist, isPlottedArray, romode,
def _processWaveformData(self, data, aSamples, dSamples, rx_dbitlist, isPlottedArray, rx_dbitoffset, romode,
nADCEnabled):
#transform raw waveform data into a processed numpy array
#@param data: raw waveform data
start_digital_data = 0
"""
transform raw waveform data into a processed numpy array
@param data: raw waveform data
"""
dbitoffset = rx_dbitoffset
if romode == 2:
start_digital_data += nADCEnabled * 2 * aSamples
digital_array = np.array(np.frombuffer(data, offset=start_digital_data, dtype=np.uint8))
if rx_dbitreorder:
samples_per_bit = np.empty((len(rx_dbitlist), dSamples), dtype=np.uint8) #stored per row all the corresponding signals of all samples
dbitoffset += nADCEnabled * 2 * aSamples
digital_array = np.array(np.frombuffer(data, offset=dbitoffset, dtype=np.uint8))
nbitsPerDBit = dSamples
if nbitsPerDBit % 8 != 0:
nbitsPerDBit += (8 - (dSamples % 8))
bit_index = 0
for idx, i in enumerate(rx_dbitlist):
offset = 0
arr = []
for i in rx_dbitlist:
# where numbits * numsamples is not a multiple of 8
if bit_index % 8 != 0:
bit_index += (8 - (bit_index % 8))
if offset % 8 != 0:
offset += (8 - (offset % 8))
if not isPlottedArray[i]:
bit_index += nbitsPerDBit
samples_per_bit[idx, :] = np.nan
continue
offset += nbitsPerDBit
return None
waveform = np.zeros(dSamples)
for iSample in range(dSamples):
# all samples for digital bit together from slsReceiver
index = int(bit_index / 8)
iBit = bit_index % 8
index = int(offset / 8)
iBit = offset % 8
bit = (digital_array[index] >> iBit) & 1
samples_per_bit[idx,iSample] = bit
bit_index += 1
return samples_per_bit
else:
nbitsPerSample = len(rx_dbitlist) if len(rx_dbitlist) % 8 == 0 else len(rx_dbitlist) + (8 - (len(rx_dbitlist) % 8))
bits_per_sample = np.empty((dSamples, len(rx_dbitlist)), dtype=np.uint8) #store per row all selected bits of a sample
for iSample in range(dSamples):
bit_index = nbitsPerSample * iSample
for idx, i in enumerate(rx_dbitlist):
if not isPlottedArray[i]:
bit_index += 1
bits_per_sample[iSample, idx] = np.nan
index = int(bit_index/8)
iBit = idx % 8
bit = (digital_array[index] >> iBit) & 1
bits_per_sample[iSample, idx] = bit
bit_index += 1
return bits_per_sample.T.copy()
waveform[iSample] = bit
offset += 1
arr.append(waveform)
return np.array(arr)
def processWaveformData(self, data, aSamples, dSamples):
#view function
#plots processed waveform data
#data: raw waveform data
#dsamples: digital samples
#asamples: analog samples
self.refresh()
"""
view function
plots processed waveform data
data: raw waveform data
dsamples: digital samples
asamples: analog samples
"""
waveforms = {}
isPlottedArray = {i: getattr(self.view, f"checkBoxBIT{i}Plot").isChecked() for i in self.rx_dbitlist}
digital_array = self._processWaveformData(data, aSamples, dSamples, self.rx_dbitreorder, self.rx_dbitlist, isPlottedArray,
self.mainWindow.romode.value,
digital_array = self._processWaveformData(data, aSamples, dSamples, self.rx_dbitlist, isPlottedArray,
self.rx_dbitoffset, self.mainWindow.romode.value,
self.mainWindow.nADCEnabled)
irow = 0
for idx, i in enumerate(self.rx_dbitlist):
# bits enabled but not plotting
waveform = digital_array[idx, :]
if np.isnan(waveform[0]):
waveform = digital_array[idx]
if waveform is None:
continue
self.mainWindow.digitalPlots[i].setData(waveform)
plotName = getattr(self.view, f"labelBIT{i}").text()
@ -173,10 +151,8 @@ class SignalsTab(QtWidgets.QWidget):
irow += 1
else:
self.mainWindow.digitalPlots[i].setY(0)
return waveforms
def initializeAllDigitalPlots(self):
self.mainWindow.plotDigitalWaveform = pg.plot()
self.mainWindow.plotDigitalWaveform.addLegend(colCount=Defines.colCount)
@ -384,25 +360,14 @@ class SignalsTab(QtWidgets.QWidget):
self.view.spinBoxDBitOffset.setValue(self.rx_dbitoffset)
self.view.spinBoxDBitOffset.editingFinished.connect(self.setDbitOffset)
def getDBitReorder(self):
self.view.checkBoxDBitReorder.stateChanged.disconnect()
self.rx_dbitreorder = self.det.rx_dbitreorder
self.view.checkBoxDBitReorder.setChecked(self.rx_dbitreorder)
self.view.checkBoxDBitReorder.stateChanged.connect(self.setDbitReorder)
def setDbitOffset(self):
self.det.rx_dbitoffset = self.view.spinBoxDBitOffset.value()
def setDbitReorder(self):
self.det.rx_dbitreorder = self.view.checkBoxDBitReorder.isChecked()
def saveParameters(self) -> list:
commands = []
dblist = [str(i) for i in range(Defines.signals.count) if getattr(self.view, f"checkBoxBIT{i}DB").isChecked()]
if len(dblist) > 0:
commands.append(f"rx_dbitlist {', '.join(dblist)}")
commands.append(f"rx_dbitoffset {self.view.spinBoxDBitOffset.value()}")
commands.append(f"rx_dbitreorder {self.view.checkBoxDBitReorder.isChecked()}")
commands.append(f"patioctrl {self.view.lineEditPatIOCtrl.text()}")
return commands

File diff suppressed because it is too large Load Diff

View File

@ -6074,33 +6074,6 @@
<enum>QFrame::Raised</enum>
</property>
<layout class="QGridLayout" name="gridLayout_17">
<item row="0" column="4">
<widget class="QSpinBox" name="spinBoxDBitOffset">
<property name="minimumSize">
<size>
<width>150</width>
<height>32</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>150</width>
<height>32</height>
</size>
</property>
<property name="font">
<font>
<pointsize>10</pointsize>
</font>
</property>
<property name="styleSheet">
<string notr="true">background-color: rgb(255, 255, 255);</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="0" column="3">
<widget class="QLabel" name="label_66">
<property name="font">
@ -6113,36 +6086,6 @@
</property>
</widget>
</item>
<item row="0" column="6">
<widget class="QCheckBox" name="checkBoxDBitReorder">
<property name="font">
<font>
<pointsize>10</pointsize>
</font>
</property>
<property name="text">
<string>DBit Reorder</string>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label_48">
<property name="minimumSize">
<size>
<width>50</width>
<height>0</height>
</size>
</property>
<property name="font">
<font>
<pointsize>10</pointsize>
</font>
</property>
<property name="text">
<string>IO Control Register:</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLineEdit" name="lineEditPatIOCtrl">
<property name="sizePolicy">
@ -6190,18 +6133,50 @@
</property>
</spacer>
</item>
<item row="0" column="5">
<spacer name="horizontalSpacer_22">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<item row="0" column="4">
<widget class="QSpinBox" name="spinBoxDBitOffset">
<property name="minimumSize">
<size>
<width>40</width>
<height>20</height>
<width>150</width>
<height>32</height>
</size>
</property>
</spacer>
<property name="maximumSize">
<size>
<width>150</width>
<height>32</height>
</size>
</property>
<property name="font">
<font>
<pointsize>10</pointsize>
</font>
</property>
<property name="styleSheet">
<string notr="true">background-color: rgb(255, 255, 255);</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label_48">
<property name="minimumSize">
<size>
<width>50</width>
<height>0</height>
</size>
</property>
<property name="font">
<font>
<pointsize>10</pointsize>
</font>
</property>
<property name="text">
<string>IO Control Register:</string>
</property>
</widget>
</item>
</layout>
</widget>

View File

@ -11,9 +11,13 @@ build-backend = "scikit_build_core.build"
[project]
name = "slsdet"
dynamic = ["version"]
dependencies = [
"numpy",
]
[tool.cibuildwheel]
before-all = "uname -a"
build = "cp{311,312,313}-manylinux_x86_64"
[tool.scikit-build.build]
verbose = true

View File

@ -27,7 +27,6 @@ set_target_properties(_slsdet PROPERTIES
set( PYTHON_FILES
slsdet/__init__.py
slsdet/adcs.py
slsdet/bits.py
slsdet/dacs.py
slsdet/powers.py
slsdet/decorators.py
@ -38,8 +37,8 @@ set( PYTHON_FILES
slsdet/enums.py
slsdet/errors.py
slsdet/gaincaps.py
slsdet/gotthard.py
slsdet/pattern.py
slsdet/PatternGenerator.py
slsdet/gotthard2.py
slsdet/moench.py
slsdet/proxy.py
@ -65,6 +64,10 @@ configure_file( scripts/test_virtual.py
${CMAKE_BINARY_DIR}/test_virtual.py
)
configure_file(scripts/frameSynchronizerPullSocket.py
${CMAKE_BINARY_DIR}/bin/frameSynchronizerPullSocket.py COPYONLY)
configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/../VERSION
${CMAKE_BINARY_DIR}/bin/slsdet/VERSION
)

View File

@ -55,6 +55,7 @@ servers = [
# "jungfrauDetectorServer",
"mythen3DetectorServer",
# "gotthard2DetectorServer",
# "gotthardDetectorServer",
# "ctbDetectorServer",
# "moenchDetectorServer",
]

View File

@ -1,226 +0,0 @@
from . import Detector, Pattern
from .bits import setbit, clearbit
import textwrap
from pathlib import Path
class PatternGenerator:
"""
Class to generate a pattern for the SLS detector. Intents to as closely as possible
mimic the old pattern generation in the C code.
"""
def __init__(self):
self.pattern = Pattern()
self.iaddr = 0
def SB(self, *bits):
"""
Set one or several bits. Change will take affect with the next PW.
"""
for bit in bits:
self.pattern.word[self.iaddr] = setbit(bit, self.pattern.word[self.iaddr])
return self.pattern.word[self.iaddr]
def CB(self, *bits):
"""
Clear one or several bits. Change will take affect with the next PW.
"""
for bit in bits:
self.pattern.word[self.iaddr] = clearbit(bit, self.pattern.word[self.iaddr])
return self.pattern.word[self.iaddr]
def _pw(self, verbose = False):
if verbose:
print(f'{self.iaddr:#06x} {self.pattern.word[self.iaddr]:#018x}')
#Limits are inclusive so we need to increment the address before writing the next word
self.pattern.limits[1] = self.iaddr
self.iaddr += 1
self.pattern.word[self.iaddr] = self.pattern.word[self.iaddr-1]
def PW(self, x = 1, verbose = False):
for i in range(x):
self._pw(verbose)
# def REPEAT(self, x, verbose = False):
# for i in range(x):
# self._pw(verbose)
# def PW2(self, verbose = 0):
# self.REPEAT(2, verbose)
def CLOCKS(self, bit, times = 1, length = 1, verbose = False):
"""
clocks "bit" n "times", every half clock is long "length"
length is optional, default value is 1
"""
for i in range(0, times):
self.SB(bit); self.PW(length, verbose)
self.CB(bit); self.PW(length, verbose)
def CLOCK(self, bit, length = 1, verbose = 0):
self.CLOCKS(bit, 1, length ,verbose)
def serializer(self, value, serInBit, clkBit, nbits, msbfirst = True, length = 1):
"""serializer(value,serInBit,clkBit,nbits,msbfirst=1,length=1)
Produces the .pat file needed to serialize a word into a shift register.
value: value to be serialized
serInBit: control bit corresponding to serial in
clkBit: control bit corresponding to the clock
nbits: number of bits of the target register to load
msbfirst: if 1 pushes in the MSB first (default),
if 0 pushes in the LSB first
length: length of all the PWs in the pattern
It produces no output because it modifies directly the members of the class pat via SB and CB"""
c = value
self.CB(serInBit, clkBit)
self.PW(length) #generate initial line with clk and serIn to 0
start = 0
stop = nbits
step = 1
if msbfirst:
start = nbits - 1
stop = -1
step =- 1 #reverts loop if msb has to be pushed in first
for i in range(start, stop, step):
if c & (1<<i):
self.SB(serInBit)
self.PW(length)
else:
self.CB(serInBit)
self.PW(length)
self.SB(clkBit)
self.PW(length)
self.CB(clkBit)
self.PW(length)
self.CB(serInBit, clkBit)
self.PW(length) #generate final line with clk and serIn to 0
#NOT IMPLEMENTED YET
#TODO! What should setstop do? Or can we remove it?
#def setstop():
#
def setoutput(self, bit):
self.pattern.ioctrl = setbit(bit, self.pattern.ioctrl)
def setinput(self, bit):
self.pattern.ioctrl= clearbit(bit, self.pattern.ioctrl)
#TODO! What should setclk do? Or can we remove it?
# def setclk(bit):
# self.clkctrl=self.setbit(bit,self.clkctrl)
def setinputs(self, *args):
for i in args:
self.setinput(i)
def setoutputs(self, *args):
for i in args:
self.setoutput(i)
#def setclks(self, *args):
# for i in args:
# self.setclk(i)
def setnloop(self, i, reps):
self.pattern.nloop[i] = reps
def setstartloop(self, i):
"""
Set startloop[i] to the current address.
"""
self.pattern.startloop[i] = self.iaddr
def setstoploop(self, i):
"""
Set stoploop[i] to the current address.
"""
self.pattern.stoploop[i] = self.iaddr
def setstart(self):
"""
Set start of pattern to the current address.
"""
self.pattern.limits[0]=self.iaddr
def setstop(self,l):
"""
Set stop of pattern to the current address.
"""
self.pattern.limits[1] = self.iaddr
def setwaitpoint(self, i):
"""
Set wait[i] to the current address.
"""
self.pattern.wait[i] = self.iaddr
def setwaittime(self, i, t):
"""
Set waittime[i] to t.
"""
self.pattern.waittime[i] = t
def setwait(self, i, t):
"""
Set wait[i] to the current address and waittime[i] to t.
"""
self.setwait(i)
self.setwaittime(i, t)
def __repr__(self):
return textwrap.dedent(f"""\
PatternBuilder:
patlimits: {self.pattern.limits}
startloop: {self.pattern.startloop}
stoploop: {self.pattern.stoploop}
nloop: {self.pattern.nloop}
wait: {self.pattern.wait}
waittime: {self.pattern.waittime}""")
def __str__(self):
return self.pattern.str()
def print(self):
print(self)
def save(self, fname):
"""Save pattern to text file"""
fname = str(fname) #Accept also Path objects, but C++ code needs a string
self.pattern.save(fname)
def load(self, fname):
"""Load pattern from text file"""
fname = str(fname) #Accept also Path objects, but C++ code needs a string
n = self.pattern.load(fname)
#If the firs and only word is 0 we assume an empty pattern
if n == 1 and self.pattern.word[0] == 0:
n = 0
self.iaddr = n
#To make PW work as expected we need to set 1+last word to the last word
if n > 0:
self.pattern.word[n] = self.pattern.word[n-1]
def send_to_detector(self, det):
"""
Load the pattern into the detector.
"""
det.setPattern(self.pattern)

View File

@ -9,10 +9,10 @@ from .detector import Detector
from .jungfrau import Jungfrau
from .mythen3 import Mythen3
from .gotthard2 import Gotthard2
from .gotthard import Gotthard
from .moench import Moench
from .pattern import Pattern, patternParameters
from .gaincaps import Mythen3GainCapsWrapper
from .PatternGenerator import PatternGenerator
from . import _slsdet
xy = _slsdet.xy

View File

@ -1,31 +0,0 @@
import numpy as np
def setbit(bit, word):
if isinstance(word, np.generic):
mask = word.dtype.type(1)
mask = mask << bit
else:
mask = 1 << bit
return word | mask
def setbit_arr(bit, arr):
arr |= arr.dtype.type(1 << bit)
def clearbit(bit, word):
"""
Clear the bit at position bit in word.
Two paths to avoid converting the types.
"""
if isinstance(word, np.generic):
mask = word.dtype.type(1)
mask = ~(mask << bit)
else:
mask = ~(1 << bit)
return word & mask
def clearbit_arr(bit, arr):
arr &= arr.dtype.type(~(1 << bit))

View File

@ -274,7 +274,7 @@ class Detector(CppDetectorApi):
@property
@element
def serialnumber(self):
"""Jungfrau][Mythen3][Gotthard2][CTB][Moench] Serial number of detector """
"""Jungfrau][Gotthard][Mythen3][Gotthard2][CTB][Moench] Serial number of detector """
return ut.lhex(self.getSerialNumber())
@property
@ -312,7 +312,7 @@ class Detector(CppDetectorApi):
-----
[Eiger] Options: 4, 8, 12, 16, 32. If set to 32, also sets clkdivider to 2 (quarter speed), else to 0 (full speed)\n
[Mythen3] Options: 8, 16, 32 \n
[Jungfrau][Moench][Ctb][Mythen3][Gotthard2][Xilinx Ctb] 16
[Jungfrau][Moench][Gotthard][Ctb][Mythen3][Gotthard2][Xilinx Ctb] 16
"""
return self.getDynamicRange()
@ -372,6 +372,7 @@ class Detector(CppDetectorApi):
[Eiger] Use threshold command to load settings
[Jungfrau] GAIN0, HIGHGAIN0 \n
[Gotthard] DYNAMICGAIN, HIGHGAIN, LOWGAIN, MEDIUMGAIN, VERYHIGHGAIN \n
[Gotthard2] DYNAMICGAIN, FIXGAIN1, FIXGAIN2 \n
[Eiger] settings loaded from file found in settingspath
[Moench] G1_HIGHGAIN, G1_LOWGAIN, G2_HIGHCAP_HIGHGAIN, G2_HIGHCAP_LOWGAIN, G2_LOWCAP_HIGHGAIN, G2_LOWCAP_LOWGAIN, G4_HIGHGAIN, G4_LOWGAIN
@ -403,7 +404,7 @@ class Detector(CppDetectorApi):
@element
def framesl(self):
"""
[Jungfrau][Moench][Mythen3][Gotthard2][CTB][Xilinx CTB] Number of frames left in acquisition.\n
[Gotthard][Jungfrau][Moench][Mythen3][Gotthard2][CTB][Xilinx CTB] Number of frames left in acquisition.\n
Note
----
@ -634,7 +635,7 @@ class Detector(CppDetectorApi):
@element
def periodl(self):
"""
[Jungfrau][Moench][CTB][Mythen3][Gotthard2][Xilinx Ctb] Period left for current frame.
[Gotthard][Jungfrau][Moench][CTB][Mythen3][Gotthard2][Xilinx Ctb] Period left for current frame.
Note
-----
@ -656,7 +657,7 @@ class Detector(CppDetectorApi):
@element
def delay(self):
"""
[Jungfrau][Moench][CTB][Mythen3][Gotthard2][Xilinx Ctb] Delay after trigger, accepts either a value in seconds, DurationWrapper or datetime.timedelta
[Gotthard][Jungfrau][Moench][CTB][Mythen3][Gotthard2][Xilinx Ctb] Delay after trigger, accepts either a value in seconds, DurationWrapper or datetime.timedelta
:getter: always returns in seconds. To get in DurationWrapper, use getDelayAfterTrigger
@ -698,7 +699,7 @@ class Detector(CppDetectorApi):
@element
def delayl(self):
"""
[Jungfrau][Moench][CTB][Mythen3][Gotthard2][Xilinx Ctb] Delay left after trigger during acquisition, accepts either a value in seconds, datetime.timedelta or DurationWrapper
[Gotthard][Jungfrau][Moench][CTB][Mythen3][Gotthard2][Xilinx Ctb] Delay left after trigger during acquisition, accepts either a value in seconds, datetime.timedelta or DurationWrapper
Note
-----
@ -1443,6 +1444,8 @@ class Detector(CppDetectorApi):
@udp_srcip.setter
def udp_srcip(self, ip):
if ip == "auto":
if self.type == detectorType.GOTTHARD:
raise NotImplementedError('Auto for udp_srcip cannot be used for GotthardI')
ip = socket.gethostbyname(self.hostname[0])
ip = ut.make_ip(ip)
ut.set_using_dict(self.setSourceUDPIP, ip)
@ -1523,6 +1526,7 @@ class Detector(CppDetectorApi):
Note
-----
[Gotthard] 0, 90, 110, 120, 150, 180, 200 \n
[Eiger][Mythen3][Gotthard2] 0 - 200 \n
[Jungfrau][Moench][Ctb] 0, 60 - 200
"""
@ -1650,7 +1654,7 @@ class Detector(CppDetectorApi):
def master(self):
"""
[Eiger][Gotthard2][Jungfrau][Moench] Sets (half) module to master and other(s) to slaves.\n
[Gotthard2][Mythen3][Eiger][Jungfrau][Moench] Gets if the current (half) module is master.
[Gotthard][Gotthard2][Mythen3][Eiger][Jungfrau][Moench] Gets if the current (half) module is master.
"""
return self.getMaster()
@ -1908,7 +1912,7 @@ class Detector(CppDetectorApi):
@property
def adcreg(self):
"""[Jungfrau][Moench][Ctb] Writes to an adc register
"""[Jungfrau][Moench][Ctb][Gotthard] Writes to an adc register
Note
-----
@ -1937,7 +1941,7 @@ class Detector(CppDetectorApi):
@element
def triggersl(self):
"""
[Jungfrau][Moench][Mythen3][Gotthard2][CTB][Xilinx CTB] Number of triggers left in acquisition.\n
[Gotthard][Jungfrau][Moench][Mythen3][Gotthard2][CTB][Xilinx CTB] Number of triggers left in acquisition.\n
Note
----
@ -2202,7 +2206,7 @@ class Detector(CppDetectorApi):
Note
-----
Default: AUTO_TIMING \n
[Jungfrau][Moench][Ctb][Gotthard2][Xilinx Ctb] AUTO_TIMING, TRIGGER_EXPOSURE \n
[Jungfrau][Moench][Gotthard][Ctb][Gotthard2][Xilinx Ctb] AUTO_TIMING, TRIGGER_EXPOSURE \n
[Mythen3] AUTO_TIMING, TRIGGER_EXPOSURE, GATED, TRIGGER_GATED \n
[Eiger] AUTO_TIMING, TRIGGER_EXPOSURE, GATED, BURST_TRIGGER
"""
@ -2259,7 +2263,7 @@ class Detector(CppDetectorApi):
def type(self):
""" Returns detector type.
Enum: detectorType
[EIGER, JUNGFRAU, MOENCH, MYTHEN3, GOTTHARD2, CHIPTESTBOARD]
[EIGER, JUNGFRAU, GOTTHARD, MOENCH, MYTHEN3, GOTTHARD2, CHIPTESTBOARD]
:setter: Not implemented
"""
@ -3463,16 +3467,6 @@ class Detector(CppDetectorApi):
def rx_dbitoffset(self, value):
ut.set_using_dict(self.setRxDbitOffset, value)
@property
@element
def rx_dbitreorder(self):
"""[Ctb] Reorder digital data to group together all samples per signal. Default is 1. Setting to 0 means 'do not reorder' and to keep what the board spits out, which is that all signals in a sample are grouped together."""
return self.getRxDbitReorder()
@rx_dbitreorder.setter
def rx_dbitreorder(self, value):
ut.set_using_dict(self.setRxDbitReorder, value)
@property
@element
def maxadcphaseshift(self):
@ -3485,13 +3479,15 @@ class Detector(CppDetectorApi):
@property
@element
def adcphase(self):
"""[Jungfrau][Moench][CTB] Sets phase shift of ADC clock.
"""[Gotthard][Jungfrau][Moench][CTB] Sets phase shift of ADC clock.
Note
-----
[Jungfrau][Moench] Absolute phase shift. Changing Speed also resets adcphase to recommended defaults.\n
[Ctb] Absolute phase shift. Changing adcclk also resets adcphase and sets it to previous values.
[Ctb] Absolute phase shift. Changing adcclk also resets adcphase and sets it to previous values.\n
[Gotthard] Relative phase shift.
:getter: Not implemented for Gotthard
"""
return self.getADCPhase()
@ -3708,12 +3704,6 @@ class Detector(CppDetectorApi):
"""
[Ctb][Mythen3][Xilinx Ctb] Wait time in clock cycles of loop level provided.
Info
----
:getter: Always return in clock cycles. To get in DurationWrapper, use getPatternWaitInterval
:setter: Accepts either a value in clock cycles or a time unit (timedelta, DurationWrapper)
Example
-------
>>> d.patwaittime[0] = 5
@ -3723,85 +3713,41 @@ class Detector(CppDetectorApi):
0: 5
1: 20
2: 30
>>> # using timedelta (up to microseconds precision)
>>> from datetime import timedelta
>>> d.patwaittime[0] = timedelta(seconds=1, microseconds=3)
>>>
>>> # using DurationWrapper to set in seconds
>>> from slsdet import DurationWrapper
>>> d.patwaittime[0] = DurationWrapper(1.2)
>>>
>>> # using DurationWrapper to set in ns
>>> t = DurationWrapper()
>>> t.set_count(500)
>>> d.patwaittime = t
>>>
>>> # to get in clock cycles
>>> d.patwaittime
1000
>>>
>>> d.getPatternWaitInterval(0)
sls::DurationWrapper(total_seconds: 1.23 count: 1230000000)
"""
return PatWaitTimeProxy(self)
def create_patwaittime_property(level):
docstring_template ="""
Deprecated command. Use patwaittime instead.
[Ctb][Mythen3][Xilinx Ctb] Wait time in clock cycles of loop level {level} provided.
Info
----
:getter: Always return in clock cycles. To get in DurationWrapper, use getPatternWaitInterval
:setter: Accepts either a value in clock cycles or a time unit (timedelta, DurationWrapper)
Example
-------
>>> d.patwaittime{level} = 5
>>> d.patwaittime{level}
5
>>> # using timedelta (up to microseconds precision)
>>> from datetime import timedelta
>>> d.patwaittime{level} = timedelta(seconds=1, microseconds=3)
>>>
>>> # using DurationWrapper to set in seconds
>>> from slsdet import DurationWrapper
>>> d.patwaittime{level} = DurationWrapper(1.2)
>>>
>>> # using DurationWrapper to set in ns
>>> t = DurationWrapper()
>>> t.set_count(500)
>>> d.patwaittime{level} = t
>>>
>>> # to get in clock cycles
>>> d.patwaittime{level}
1000
>>>
>>> d.getPatternWaitInterval(level)
sls::DurationWrapper(total_seconds: 1.23 count: 1230000000)
"""
@property
@element
def patwaittime(self):
return self.getPatternWaitClocks(level)
def patwaittime0(self):
"""[Ctb][Mythen3][Xilinx Ctb] Wait 0 time in clock cycles."""
return self.getPatternWaitTime(0)
@patwaittime.setter
def patwaittime(self, value):
if isinstance(value, (int, float)) and not isinstance(value, bool):
nclk = ut.merge_args(level, value)
ut.set_using_dict(self.setPatternWaitClocks, level, *nclk)
else:
ut.set_time_using_dict(self.setPatternWaitInterval, level, value)
@patwaittime0.setter
def patwaittime0(self, nclk):
nclk = ut.merge_args(0, nclk)
ut.set_using_dict(self.setPatternWaitTime, *nclk)
patwaittime.__doc__ = docstring_template.format(level=level)
@property
@element
def patwaittime1(self):
"""[Ctb][Mythen3][Xilinx Ctb] Wait 1 time in clock cycles."""
return self.getPatternWaitTime(1)
return patwaittime
@patwaittime1.setter
def patwaittime1(self, nclk):
nclk = ut.merge_args(1, nclk)
ut.set_using_dict(self.setPatternWaitTime, *nclk)
patwaittime0 = create_patwaittime_property(0)
patwaittime1 = create_patwaittime_property(1)
patwaittime2 = create_patwaittime_property(2)
@property
@element
def patwaittime2(self):
"""[Ctb][Mythen3][Xilinx Ctb] Wait 2 time in clock cycles."""
return self.getPatternWaitTime(2)
@patwaittime2.setter
def patwaittime2(self, nclk):
nclk = ut.merge_args(2, nclk)
ut.set_using_dict(self.setPatternWaitTime, *nclk)
@property
@ -4092,6 +4038,27 @@ class Detector(CppDetectorApi):
return ClkDivProxy(self)
"""
---------------------------<<<Gotthard specific>>>---------------------------
"""
@property
def exptimel(self):
"""[Gotthard] Exposure time left for current frame.
:getter: always returns in seconds. To get in DurationWrapper, use getExptimeLeft
:setter: Not Implemented
Example
-----------
>>> d.exptimel
181.23
>>> d.getExptimeLeft()
[sls::DurationWrapper(total_seconds: 181.23 count: 181230000000)]
"""
t = self.getExptimeLeft()
return reduce_time(t)
"""
---------------------------<<<Mythen3 specific>>>---------------------------

53
python/slsdet/gotthard.py Normal file
View File

@ -0,0 +1,53 @@
# SPDX-License-Identifier: LGPL-3.0-or-other
# Copyright (C) 2021 Contributors to the SLS Detector Package
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
This file contains the specialization for the Moench detector
"""
from .detector import Detector, freeze
from .dacs import DetectorDacs
from . import _slsdet
dacIndex = _slsdet.slsDetectorDefs.dacIndex
from .detector_property import DetectorProperty
# @freeze
# vref_ds, vcascn_pb, vcascp_pb, vout_cm, vcasc_out, vin_cm, vref_comp, ib_test_c
class GotthardDacs(DetectorDacs):
_dacs = [('vref_ds', dacIndex.VREF_DS, 0, 4000, 660),
('vcascn_pb', dacIndex.VCASCN_PB, 0, 4000, 650),
('vcascp_pb,', dacIndex.VCASCP_PB, 0, 4000, 1480),
('vout_cm', dacIndex.VOUT_CM, 0, 4000, 1520),
('vcasc_out', dacIndex.VCASC_OUT, 0, 4000, 1320),
('vin_cm', dacIndex.VIN_CM, 0, 4000, 1350),
('vref_comp', dacIndex.VREF_COMP, 0, 4000, 350),
('ib_test_c', dacIndex.IB_TESTC, 0, 4000, 2001),
]
_dacnames = [_d[0] for _d in _dacs]
#vthreshold??
@freeze
class Gotthard(Detector):
"""
Subclassing Detector to set up correct dacs and detector specific
functions.
"""
_detector_dynamic_range = [16]
_settings = ['standard', 'highgain', 'lowgain', 'veryhighgain', 'verylowgain']
"""available settings for Eiger, note almost always standard"""
def __init__(self, id=0):
super().__init__(id)
self._frozen = False
self._dacs = GotthardDacs(self)
@property
def dacs(self):
return self._dacs

View File

@ -275,13 +275,10 @@ class PatWaitTimeProxy:
self.det = det
def __getitem__(self, key):
return element_if_equal(self.det.getPatternWaitClocks(key))
return element_if_equal(self.det.getPatternWaitTime(key))
def __setitem__(self, key, value):
if isinstance(value, (int, float)) and not isinstance(value, bool):
set_proxy_using_dict(self.det.setPatternWaitClocks, key, value)
else:
set_proxy_using_dict(self.det.setPatternWaitInterval, key, value)
set_proxy_using_dict(self.det.setPatternWaitTime, key, value)
def __repr__(self):
max_levels = MAX_PATTERN_LEVELS

View File

@ -1293,6 +1293,20 @@ void init_det(py::module &m) {
(void (Detector::*)(defs::collectionMode, sls::Positions)) &
Detector::setCollectionMode,
py::arg(), py::arg() = Positions{});
CppDetectorApi.def("getROI",
(Result<defs::ROI>(Detector::*)(sls::Positions) const) &
Detector::getROI,
py::arg() = Positions{});
CppDetectorApi.def("setROI",
(void (Detector::*)(defs::ROI, int)) & Detector::setROI,
py::arg(), py::arg());
CppDetectorApi.def(
"clearROI", (void (Detector::*)(sls::Positions)) & Detector::clearROI,
py::arg() = Positions{});
CppDetectorApi.def("getExptimeLeft",
(Result<sls::ns>(Detector::*)(sls::Positions) const) &
Detector::getExptimeLeft,
py::arg() = Positions{});
CppDetectorApi.def("getNumberOfBursts",
(Result<int64_t>(Detector::*)(sls::Positions) const) &
Detector::getNumberOfBursts,
@ -1664,14 +1678,6 @@ void init_det(py::module &m) {
(void (Detector::*)(int, sls::Positions)) &
Detector::setRxDbitOffset,
py::arg(), py::arg() = Positions{});
CppDetectorApi.def("getRxDbitReorder",
(Result<bool>(Detector::*)(sls::Positions) const) &
Detector::getRxDbitReorder,
py::arg() = Positions{});
CppDetectorApi.def("setRxDbitReorder",
(void (Detector::*)(bool, sls::Positions)) &
Detector::setRxDbitReorder,
py::arg(), py::arg() = Positions{});
CppDetectorApi.def("setDigitalIODelay",
(void (Detector::*)(uint64_t, int, sls::Positions)) &
Detector::setDigitalIODelay,
@ -1855,22 +1861,13 @@ void init_det(py::module &m) {
Detector::setPatternWaitAddr,
py::arg(), py::arg(), py::arg() = Positions{});
CppDetectorApi.def(
"getPatternWaitClocks",
"getPatternWaitTime",
(Result<uint64_t>(Detector::*)(int, sls::Positions) const) &
Detector::getPatternWaitClocks,
Detector::getPatternWaitTime,
py::arg(), py::arg() = Positions{});
CppDetectorApi.def("setPatternWaitClocks",
CppDetectorApi.def("setPatternWaitTime",
(void (Detector::*)(int, uint64_t, sls::Positions)) &
Detector::setPatternWaitClocks,
py::arg(), py::arg(), py::arg() = Positions{});
CppDetectorApi.def(
"getPatternWaitInterval",
(Result<sls::ns>(Detector::*)(int, sls::Positions) const) &
Detector::getPatternWaitInterval,
py::arg(), py::arg() = Positions{});
CppDetectorApi.def("setPatternWaitInterval",
(void (Detector::*)(int, sls::ns, sls::Positions)) &
Detector::setPatternWaitInterval,
Detector::setPatternWaitTime,
py::arg(), py::arg(), py::arg() = Positions{});
CppDetectorApi.def("getPatternMask",
(Result<uint64_t>(Detector::*)(sls::Positions)) &

View File

@ -121,9 +121,13 @@ void init_enums(py::module &m) {
.value("VTHRESHOLD", slsDetectorDefs::dacIndex::VTHRESHOLD)
.value("IO_DELAY", slsDetectorDefs::dacIndex::IO_DELAY)
.value("VREF_DS", slsDetectorDefs::dacIndex::VREF_DS)
.value("VCASCN_PB", slsDetectorDefs::dacIndex::VCASCN_PB)
.value("VCASCP_PB", slsDetectorDefs::dacIndex::VCASCP_PB)
.value("VOUT_CM", slsDetectorDefs::dacIndex::VOUT_CM)
.value("VCASC_OUT", slsDetectorDefs::dacIndex::VCASC_OUT)
.value("VIN_CM", slsDetectorDefs::dacIndex::VIN_CM)
.value("VREF_COMP", slsDetectorDefs::dacIndex::VREF_COMP)
.value("IB_TESTC", slsDetectorDefs::dacIndex::IB_TESTC)
.value("VB_COMP", slsDetectorDefs::dacIndex::VB_COMP)
.value("VDD_PROT", slsDetectorDefs::dacIndex::VDD_PROT)
.value("VIN_COM", slsDetectorDefs::dacIndex::VIN_COM)

View File

@ -20,10 +20,8 @@ void init_pattern(py::module &m) {
});
py::class_<sls::Pattern> Pattern(m, "Pattern");
Pattern.def(py::init())
.def("load", &sls::Pattern::load)
.def("save", &sls::Pattern::save)
.def("str", &sls::Pattern::str)
.def("data", (pat * (sls::Pattern::*)()) & sls::Pattern::data,
Pattern.def(py::init());
Pattern.def("load", &sls::Pattern::load);
Pattern.def("data", (pat * (sls::Pattern::*)()) & sls::Pattern::data,
py::return_value_policy::reference);
}

View File

@ -1,152 +0,0 @@
import pytest
from slsdet import PatternGenerator
def apply_detconf(p):
"""
Hacky workaround to apply detConf_mh02 to a pattern
"""
DACMON = 0
cnt_en_3 = 1
pulse_counter_en = 2
cnt_en_1 = 3
par_load = 4
pulse_mux_ctr = 5
reset_cnt = 6
reset_periphery = 7
config_load = 8
cnt_en_0 = 9
tbl = 10
clk_ext = 11
trimbit_load_reg = 12
store = 13
data_in = 14
en_pll_clk = 15
cnt_en_2 = 16
DACINT = 17
data_out_slow = 18 #IN
COMP2_MON = 19 #IN
start_read = 20
dac_store = 21
CNT3_MON = 22 #IN
EN_PIX_DIG_MON = 23
clk_sel = 24
BUSY = 25 #IN
COMP3_MON = 26 #IN
CNT2_MON = 27 #IN
dbit_ena=62 #FIFO LATCH
adc_ena=63 #ADC ENABLE
#FPGA input/ouutputs
p.setoutput(DACMON)
p.setoutput(cnt_en_3)
p.setoutput(pulse_counter_en)
p.setoutput(cnt_en_1)
p.setoutput(par_load)
p.setoutput(pulse_mux_ctr)
p.setoutput(reset_cnt)
p.setoutput(reset_periphery)
p.setoutput(cnt_en_0)
p.setoutput(tbl)
p.setoutput(clk_ext)
p.setoutput(config_load)
p.setoutput(trimbit_load_reg)
p.setoutput(store)
p.setoutput(data_in)
p.setoutput(en_pll_clk)
p.setoutput(cnt_en_2)
p.setoutput(DACINT)
p.setinput(data_out_slow)
p.setinput(COMP2_MON)
p.setoutput(start_read)
p.setoutput(dac_store)
p.setinput(CNT3_MON)
p.setoutput(EN_PIX_DIG_MON)
p.setoutput(clk_sel)
p.setinput(BUSY)
p.setinput(COMP3_MON)
p.setinput(CNT2_MON)
#system signals
p.setoutput(adc_ena)
# FIFO LATCH
p.setoutput(dbit_ena)
return p
def test_first_two_PW():
p = PatternGenerator()
#The pattern is created with a single empty word
assert p.pattern.limits[0] == 0
assert p.pattern.limits[1] == 0
p.SB(8)
p.PW()
#When doing the first PW the empty word is overwritten
assert p.pattern.limits[0] == 0
assert p.pattern.limits[1] == 0
assert p.pattern.word[0] == 256
p.SB(9)
p.PW()
#When doing the second PW we add a new word
assert p.pattern.limits[0] == 0
assert p.pattern.limits[1] == 1
assert p.pattern.word[0] == 256
assert p.pattern.word[1] == 768
def test_simple_pattern():
"""
Using enable pll pattern for MH02
"""
en_pll_clk = 15
p = PatternGenerator()
p = apply_detconf(p)
p.SB(en_pll_clk)
p.PW()
p.PW()
lines = str(p).split("\n")
enable_pll_pattern = [
"patword 0x0000 0x0000000000008000",
"patword 0x0001 0x0000000000008000",
"patioctrl 0xc000000001b3ffff",
"patlimits 0x0000 0x0001",
"patloop 0 0x1fff 0x1fff",
"patnloop 0 0",
"patloop 1 0x1fff 0x1fff",
"patnloop 1 0",
"patloop 2 0x1fff 0x1fff",
"patnloop 2 0",
"patloop 3 0x1fff 0x1fff",
"patnloop 3 0",
"patloop 4 0x1fff 0x1fff",
"patnloop 4 0",
"patloop 5 0x1fff 0x1fff",
"patnloop 5 0",
"patwait 0 0x1fff",
"patwaittime 0 0",
"patwait 1 0x1fff",
"patwaittime 1 0",
"patwait 2 0x1fff",
"patwaittime 2 0",
"patwait 3 0x1fff",
"patwaittime 3 0",
"patwait 4 0x1fff",
"patwaittime 4 0",
"patwait 5 0x1fff",
"patwaittime 5 0",
]
assert len(lines) == len(enable_pll_pattern)
for i, line in enumerate(lines):
assert line == enable_pll_pattern[i]

View File

@ -1,50 +0,0 @@
from slsdet.bits import clearbit, clearbit_arr, setbit, setbit_arr
import numpy as np
def test_clearbit_on_python_int():
val = 5 # 0b101
r = clearbit(0, val)
assert r == 4
assert val == 5
def test_setbit_on_python_int():
val = 5 # 0b101
r = setbit(1, val)
assert r == 7
assert val == 5
def test_setbit_doesnt_change_type():
word = np.int32(5)
ret = setbit(0, word)
assert isinstance(ret, np.int32)
def test_clearbit_doesnt_change_type():
word = np.uint8(5)
ret = clearbit(0, word)
assert isinstance(ret, np.uint8)
def test_setbit_on_array_element():
arr = np.zeros(10, dtype=np.uint64)
arr[5] = setbit(0, arr[5])
arr[5] = setbit(1, arr[5])
arr[5] = setbit(4, arr[5])
assert arr[4] == 0
assert arr[5] == 19 # 0b10011
assert arr[6] == 0
def test_setbit_arr():
arr = np.zeros(10, dtype=np.int32)
setbit_arr(3, arr[3:9])
assert all(arr == np.array((0, 0, 0, 8, 8, 8, 8, 8, 8, 0), dtype=np.int32))
def test_clearbit_arr():
arr = np.array((5, 5, 5), dtype=np.int8)
clearbit_arr(0, arr)
assert all(arr == (4, 4, 4))

View File

@ -1 +0,0 @@
../slsDetectorServers/ctbDetectorServer/bin/ctbDetectorServer_developer

View File

@ -0,0 +1 @@
../slsDetectorServers/ctbDetectorServer/bin/ctbDetectorServerv9.1.0

View File

@ -1 +0,0 @@
../slsDetectorServers/eigerDetectorServer/bin/eigerDetectorServer_developer

View File

@ -0,0 +1 @@
../slsDetectorServers/eigerDetectorServer/bin/eigerDetectorServerv9.0.0

View File

@ -1 +0,0 @@
../slsDetectorServers/gotthard2DetectorServer/bin/gotthard2DetectorServer_developer

View File

@ -0,0 +1 @@
../slsDetectorServers/gotthard2DetectorServer/bin/gotthard2DetectorServerv9.0.0

View File

@ -1 +0,0 @@
../slsDetectorServers/gotthardDetectorServer/bin/gotthardDetectorServer_developer

View File

@ -0,0 +1 @@
../slsDetectorServers/gotthardDetectorServer/bin/gotthardDetectorServerv9.0.0

View File

@ -1 +0,0 @@
../slsDetectorServers/jungfrauDetectorServer/bin/jungfrauDetectorServer_developer

View File

@ -0,0 +1 @@
../slsDetectorServers/jungfrauDetectorServer/bin/jungfrauDetectorServerv9.1.0

View File

@ -1 +0,0 @@
../slsDetectorServers/moenchDetectorServer/bin/moenchDetectorServer_developer

View File

@ -0,0 +1 @@
../slsDetectorServers/moenchDetectorServer/bin/moenchDetectorServerv9.0.0

View File

@ -1 +0,0 @@
../slsDetectorServers/mythen3DetectorServer/bin/mythen3DetectorServer_developer

View File

@ -0,0 +1 @@
../slsDetectorServers/mythen3DetectorServer/bin/mythen3DetectorServerv9.1.1

View File

@ -1 +0,0 @@
../slsDetectorServers/xilinx_ctbDetectorServer/bin/xilinx_ctbDetectorServer_developer

View File

@ -0,0 +1 @@
../slsDetectorServers/xilinx_ctbDetectorServer/bin/xilinx_ctbDetectorServerv9.1.0

View File

@ -3,14 +3,14 @@
#ifndef ANALOGDETECTOR_H
#define ANALOGDETECTOR_H
#include <mutex>
//#include <mutex>
#include "commonModeSubtractionNew.h"
#include "ghostSummation.h"
#include "pedestalSubtraction.h"
#include "sls/tiffIO.h"
#include "slsDetectorData.h"
#include "slsInterpolation.h"
#include "sls/tiffIO.h"
#include <pthread.h>
#ifdef ROOTSPECTRUM
@ -90,8 +90,6 @@ template <class dataType> class analogDetector {
ymin = 0;
ymax = ny;
fMode = ePedestal;
dMode = eInterpolating;
// std::cout << "dMode " << dMode << std::endl;
thr = 0;
myFile = NULL;
#ifdef ROOTSPECTRUM
@ -113,20 +111,15 @@ template <class dataType> class analogDetector {
destructor. Deletes the pdestalSubtraction array and the image
*/
virtual ~analogDetector() {
// std::cout << "#### Debug: Destructing analogDetector! ####"
// << std::endl;
for (int i = 0; i < ny; i++) {
if (stat[i]) { delete[] stat[i]; stat[i] = nullptr; }
// delete[] stat[i];
delete[] stat[i];
/* delete [] pedMean[i]; */
/* delete [] pedVariance[i]; */
}
};
/* delete [] pedMean; */
/* delete [] pedVariance; */
// delete[] stat;
// delete[] image;
if (stat) { delete[] stat; stat = nullptr; }
if (image) { delete[] image; image = nullptr; }
delete[] stat;
delete[] image;
#ifdef ROOTSPECTRUM
delete hs;
#ifdef ROOTCLUST
@ -144,8 +137,6 @@ template <class dataType> class analogDetector {
*/
analogDetector(analogDetector *orig) {
/* copy construction from orig*/
// std::cout << "#### Debug: Calling analogDetector cloning method! ####"
// << std::endl;
det = orig->det;
nx = orig->nx;
ny = orig->ny;
@ -161,8 +152,6 @@ template <class dataType> class analogDetector {
thr = orig->thr;
// nSigma=orig->nSigma;
fMode = orig->fMode;
dMode = orig->dMode;
// std::cout << "dMode " << dMode << std::endl;
myFile = orig->myFile;
stat = new pedestalSubtraction *[ny];
@ -227,75 +216,12 @@ template <class dataType> class analogDetector {
ghSum = NULL;
}
/**
constructor creating a deep copy of another analog detector
\param other analog Detector structure to be copied
*/
analogDetector(const analogDetector &other)
: det(other.det), nx(other.nx), ny(other.ny), dataSign(other.dataSign),
iframe(other.iframe), gmap(other.gmap), id(other.id),
xmin(other.xmin), xmax(other.xmax), ymin(other.ymin),
ymax(other.ymax), thr(other.thr), fMode(other.fMode),
dMode(other.dMode), myFile(NULL) {
// std::cout << "#### Debug: Calling analogDetector copy constructor! ####"
// << std::endl;
// Deep copy the stat array
stat = new pedestalSubtraction *[ny];
for (int i = 0; i < ny; i++) {
stat[i] = new pedestalSubtraction[nx];
std::copy(other.stat[i], other.stat[i] + nx, stat[i]);
}
// Deep copy image array
image = new int[nx * ny];
std::copy(other.image, other.image + (nx * ny), image);
// Copy common-mode subtraction object (if it exists)
if (other.cmSub) {
cmSub = other.cmSub->Clone();
std::cout << "Copying cmSub" << std::endl;
} else {
cmSub = nullptr;
}
// Copy ghost summation object (if it exists)
if (other.ghSum) {
ghSum = other.ghSum->Clone();
std::cout << "Copying ghSum" << std::endl;
} else {
ghSum = nullptr;
}
// Ensure pedestal values are copied properly
int nped = other.GetNPedestals(0, 0);
for (int iy = 0; iy < ny; ++iy) {
for (int ix = 0; ix < nx; ++ix) {
stat[iy][ix].SetNPedestals(nped);
setPedestal(ix, iy, other.getPedestal(ix, iy),
other.getPedestalRMS(ix, iy),
other.GetNPedestals(ix, iy));
}
}
}
/**
clone. Must be virtual!
\returns a clone of the original analog detector
*/
virtual analogDetector *Clone() = 0;
/**
Deep copy. Must be virtual!
This is a new addition because of multithreaded storage cell data (where
each sc has its own mutex). If the pure virtual function exists here,
EVERY derived class has to overwrite it! That means a Copy() function
must also be implemented in any derived class. \returns a deep copy of
the original analog detector
*/
virtual analogDetector *Copy() = 0;
/**
Gives an id to the structure. For debugging purposes in case of
multithreading. \param i is to be set \returns current id
@ -622,11 +548,6 @@ template <class dataType> class analogDetector {
return ped;
};
// Const version for use in the copy constructor
virtual double getPedestal(int ix, int iy, int cm = 0) const {
return stat[iy][ix].getPedestal();
};
/**
gets pedestal rms (i.e. noise)
\param ix pixel x coordinate
@ -645,11 +566,6 @@ template <class dataType> class analogDetector {
return ped;
};
// Const version for use in the copy constructor
virtual double getPedestalRMS(int ix, int iy) const {
return stat[iy][ix].getPedestalRMS();
};
/**
sets pedestal
\param ix pixel x coordinate
@ -1310,7 +1226,7 @@ template <class dataType> class analogDetector {
/** gets number of samples for moving average pedestal calculation
\returns actual number of samples
*/
int GetNPedestals(int ix, int iy) const {
int GetNPedestals(int ix, int iy) {
if (ix >= 0 && ix < nx && iy >= 0 && iy < ny)
return stat[iy][ix].GetNPedestals();
else

View File

@ -50,8 +50,6 @@ template <typename Element> class CircularFifo {
mutable sem_t data_mutex;
mutable sem_t free_mutex;
unsigned int increment(unsigned int idx_) const;
int id_;
int thread_id_;
};
template <typename Element> int CircularFifo<Element>::getDataValue() const {
@ -76,18 +74,14 @@ template <typename Element> int CircularFifo<Element>::getFreeValue() const {
template <typename Element>
bool CircularFifo<Element>::push(Element *&item_, bool no_block) {
// check for fifo full
if (no_block && isFull()) {
//std::cout << "Full Fifo at push. Returning." << std::endl;
return false; // No space, return immediately
}
if (no_block && isFull())
return false;
//std::cout << "Thread " << thread_id_ <<" Push Fifo " << id_ << " item " << static_cast<void*>(item_) << std::endl;
sem_wait(&free_mutex); // Wait for space
array[tail] = item_; // Add item to the buffer
tail = increment(tail); // Move the tail pointer
sem_post(&data_mutex); // Signal that there is new data
return true; // Success
sem_wait(&free_mutex);
array[tail] = item_;
tail = increment(tail);
sem_post(&data_mutex);
return true;
}
/** Consumer only: Removes and returns item from the queue
@ -100,18 +94,14 @@ bool CircularFifo<Element>::push(Element *&item_, bool no_block) {
template <typename Element>
bool CircularFifo<Element>::pop(Element *&item_, bool no_block) {
// check for fifo empty
if (no_block && isEmpty()) {
//std::cout << "Empty Fifo at pop. Returning." << std::endl;
return false; // No data in fifo, return immediately
}
if (no_block && isEmpty())
return false;
//std::cout << "Thread " << thread_id_ << " Pop Fifo " << id_ << " item " << static_cast<void*>(item_) << std::endl;
sem_wait(&data_mutex); // Wait for data
item_ = array[head]; // Retreive item from the current head of the buffer
head = increment(head); // Move the head pointer (to point to the next item)
sem_post(&free_mutex); // Signal that there is new free space available
return true; //Success
sem_wait(&data_mutex);
item_ = array[head];
head = increment(head);
sem_post(&free_mutex);
return true;
}
/** Useful for testinng and Consumer check of status

View File

@ -1,482 +0,0 @@
#include "HDF5File.h"
#include "ansi.h"
#include <algorithm>
#include <fmt/ranges.h>
/*
* No class member helper functions
*/
std::string vectorToString(std::vector<hsize_t> const& v) {
return fmt::format("({})", fmt::join(v, ", "));
}
/*
* increment frame offset (if s dimension exists, loop through all before incrementing z)
* should also work if file_dims[1] is not s but x (in that case we ignore it)
*/
void conditionalIncrement(std::vector<hsize_t>& vec, hsize_t max_value) {
if (vec.size() < 3) {
throw std::invalid_argument("Vector must have at least 3 elements.");
}
// If vector has 4 elements, increment vec[1] first
if (vec.size() == 4) {
if (++vec[1] >= max_value) { //max_value is never reached!
vec[1] = 0; // Reset and increment vec[0]
++vec[0];
}
}
// If vector has 3 elements, increment vec[0] directly
else if (vec.size() == 3) {
++vec[0];
}
}
void printDatatypeSize(hid_t dataset) {
hid_t datatype = H5Dget_type(dataset);
H5T_class_t class_id = H5Tget_class(datatype);
size_t type_size = H5Tget_size(datatype);
H5Tclose(datatype);
std::cout << " dataset type class: " << class_id
<< ", size: " << type_size << " bytes\n";
//Ensure the read datatype matches a system native type correctly
//hid_t read_type = (type_size == 8) ? H5T_NATIVE_LLONG : H5T_NATIVE_UINT;
//return read_type;
}
/* **********************
* Class member functions
* **********************
*/
// Default constructor
/*
HDF5File::HDF5File () {
//InitializeParameters(); //old
}
*/
/*
HDF5File::~HDF5File () {
if(current_image)
delete [] current_image;
}
*/
void HDF5File::SetImageDataPath (std::string const& name) {
std::cout << "Image dataset path set to " << name << std::endl;
data_datasetname = name;
}
void HDF5File::SetFrameIndexPath (std::string const& name) {
std::cout << "Frame index dataset path set to " << name << std::endl;
index_datasetname = name;
}
void HDF5File::InitializeDimensions () {
rank = H5Sget_simple_extent_ndims(dataspace);
file_dims.resize(rank);
H5Sget_simple_extent_dims(dataspace, file_dims.data(), nullptr);
std::cout << "Dataset dimensions: " << vectorToString(file_dims) << "\n";
}
std::vector<hsize_t> HDF5File::GetDatasetDimensions() {
return file_dims;
}
std::vector<hsize_t> HDF5File::GetChunkDimensions() {
return chunk_dims;
}
hsize_t HDF5File::GetRank() {
return rank;
}
bool HDF5File::ValidateDimensions () {
// validate rank
if(rank != RANK) {
cprintf(RED,"rank found %llu. Expected %d\n", rank, RANK);
std::cerr << "Error: Rank could not be validated\n";
return false;
}
// validate file dimensions of x and y (assuming those are the last two dimensions of the dataset)
if ( (file_dims[file_dims.size()-2] != DEFAULT_X_DIMS) || (file_dims[file_dims.size()-1] != DEFAULT_Y_DIMS) ) {
cprintf(RED,"file dimensions of x found %llu. Expected %d\n", file_dims[file_dims.size()-2], DEFAULT_X_DIMS);
cprintf(RED,"file dimensions of y found %llu. Expected %d\n", file_dims[file_dims.size()-1], DEFAULT_Y_DIMS);
std::cerr << "Error: Dataset dimensions could not be validated\n";
return false;
}
cprintf(GREEN, "File rank & dimensions validated.");
return true;
}
bool HDF5File::ReadChunkDimensions () {
// Get layout
hid_t plist_id = H5Dget_create_plist(dataset);
if (H5Pget_layout (plist_id) != H5D_CHUNKED) {
cprintf(RED,"NOTE: Dataset is not chunked!\n");
std::cerr << "Error: Dataset is not chunked\n";
return false;
}
// Get Chunk Dimensions
int rank_chunk = H5Pget_chunk (plist_id, 0, nullptr);
chunk_dims.resize(rank_chunk);
H5Pget_chunk (plist_id, rank_chunk, chunk_dims.data());
std::cout << "Chunk dimensions: " << vectorToString(chunk_dims) << "\n";
H5Pclose (plist_id);
return true;
}
bool HDF5File::ValidateChunkDimensions () {
// validate rank
if(chunk_dims.size() != rank) {
cprintf(RED,"Chunk rank does not match dataset rank! Found %lu. Expected %llu\n", chunk_dims.size(), rank);
std::cerr << "Error: Chunk rank does not match dataset rank\n";
return false;
}
// validate chunk dimensions of x and y (assuming those are the last two dimensions of the dataset)
if ( (chunk_dims[chunk_dims.size()-2] != DEFAULT_CHUNK_X_DIMS) || (chunk_dims[chunk_dims.size()-1] != DEFAULT_CHUNK_Y_DIMS) ) {
cprintf(RED,"file dimensions of x found %llu. Expected %d\n", chunk_dims[chunk_dims.size()-2], DEFAULT_CHUNK_X_DIMS);
cprintf(RED,"file dimensions of y found %llu. Expected %d\n", chunk_dims[chunk_dims.size()-1], DEFAULT_CHUNK_Y_DIMS);
std::cerr << "Error: Chunk dimensions could not be validated\n";
return false;
}
cprintf(GREEN, "Chunk rank & dimensions validated.");
return true;
}
bool HDF5File::OpenFrameIndexDataset() {
// Get all the frame numbers
// Open frame index dataset
hid_t fi_dataset = H5Dopen2 (file, index_datasetname.c_str(), H5P_DEFAULT);
if (fi_dataset < 0){
cprintf (RED,"Could not open frame index dataset %s\n", index_datasetname.c_str());
std::cerr << "Error: Could not open frame index dataset\n";
return false;
}
hid_t fi_dataspace = H5Dget_space (fi_dataset);
int fi_rank = H5Sget_simple_extent_ndims(fi_dataspace);
std::vector<hsize_t> fi_dims(fi_rank);
H5Sget_simple_extent_dims (fi_dataspace, fi_dims.data(), nullptr);
std::cout << "Frame index dataset dimensions: " << vectorToString(fi_dims) << "\n";
// validate size
if (fi_dims[0] != file_dims[0]) {
cprintf (RED,"Frame index dimensions of z found %llu. Expected %llu\n", fi_dims[0], file_dims[0]);
std::cerr << "Error: Z dimension of frame index dataset does not align with z dimension of image dataset\n";
H5Sclose (fi_dataspace);
H5Dclose (fi_dataset);
return false;
}
// allocate frame index memory
frame_index_list.resize(fi_dims[0]); //file_dims
// read and print datatype size of dataset
std::cout << "Frame index";
printDatatypeSize(fi_dataset);
// make sure we only read the first column of the frame index dataset (not all storage cells)
//NOTE: For XFEL datasets, this may mean that some frame numbers are skipped
//(because they assign a unique frame number to every storage cell)
//Possibly, there is a cleaner fix for this...
std::vector<hsize_t> start(fi_rank,0);
std::vector<hsize_t> count(fi_rank,1);
count[0] = fi_dims[0];
hid_t memspace = H5Screate_simple (fi_rank, count.data(), nullptr);
if (memspace < 0) {
std::cerr << "Error: Failed to create memory space for HDF5 read operation\n";
H5Sclose(memspace);
H5Sclose(fi_dataspace);
H5Dclose(fi_dataset);
return false;
}
// Create hyperslab selection
if (H5Sselect_hyperslab(fi_dataspace, H5S_SELECT_SET, start.data(), nullptr, count.data(), nullptr) < 0 ) {
cprintf (RED,"Could not create hyperslab for %s\n", vectorToString(start).c_str());
std::cerr << "Error: Hyperslab creation failed for " << vectorToString(start) << "\n";
H5Sclose(memspace);
H5Sclose (fi_dataspace);
H5Dclose(fi_dataset);
return false;
}
//read frame index values
//Is u32 correct? I would think not. But I get a segmentation fault if I use u64.
if (H5Dread (fi_dataset, H5T_STD_U64LE, memspace, fi_dataspace, H5P_DEFAULT, frame_index_list.data()) < 0) {
cprintf (RED,"Could not read frame index dataset %s\n", index_datasetname.c_str());
std::cerr << "Error: Could not read frame index dataset\n";
H5Sclose(memspace);
H5Sclose (fi_dataspace);
H5Dclose (fi_dataset);
return false;
}
H5Sclose(memspace);
H5Sclose (fi_dataspace);
H5Dclose(fi_dataset);
return true;
}
int HDF5File::OpenResources (char const*const fname, bool validate) {
std::cout << "Debug HDF5File.cpp: Attempting to open file " << fname << std::endl;
// Open File
file = H5Fopen (fname, H5F_ACC_RDONLY, H5P_DEFAULT);
if (file < 0) {
cprintf(RED,"Could not open hdf5 file\n");
std::cerr << "Error: H5Fopen failed\n";
return 0;
}
cprintf(BLUE, "Opened File: %s\n", fname);
// Open Dataset
dataset = H5Dopen2 (file, data_datasetname.c_str(), H5P_DEFAULT);
if (dataset < 0){
cprintf(RED,"Could not open dataset\n");
std::cerr << "Error: H5Dopen2 failed\n";
CloseResources ();
return 0;
}
cprintf(BLUE, "Opened Dataset: %s\n", data_datasetname.c_str());
// print datatype size of dataset
std::cout << "Image";
printDatatypeSize(dataset);
// Create Dataspace
dataspace = H5Dget_space (dataset);
if (dataspace < 0){
cprintf(RED,"Could not open dataspace\n");
std::cerr << "Error: H5Dget_space failed\n";
CloseResources ();
return 0;
}
// Get Dimensions
InitializeDimensions();
// Get chunk dimensions
if (!ReadChunkDimensions()) {
CloseResources();
return 0;
}
// validate file dimensions
if (validate) {
if ( !ValidateDimensions() || !ValidateChunkDimensions() ) {
CloseResources();
return 0;
}
}
//Read frame indices
if (!OpenFrameIndexDataset()) {
CloseResources();
return 0;
}
return 1;
}
void HDF5File::CloseResources () {
if (dataspace >=0 ) {
H5Sclose(dataspace);
dataspace = -1;
}
if (dataset >=0 ) {
H5Dclose(dataset);
dataset = -1;
}
if (file >=0 ) {
H5Fclose(file);
file = -1;
}
}
/*
* Function takes uint16_t* argument to make explicit that the caller has to handle memory allocation and deallocation.
* This is legacy caused by the structure with which the slsDetectorCalibration cluster finder is written.
* (Best practice for modern C++ would be using smart pointers.)
*
* Originially, this function took uint16_t** which may lead to memory management issues since image gets redirected
* to point to current_image, which is owned by HDF5File.
* (Good practice in classic C-style. HDF5File needs to clean up the resource at destruction.)
*
* \param image pointer to uint16_t, buffer which the image is read into. (Memory handled by caller!)
* \param offset contains iFrame at [0] and storage cell number at [1],
* depending on dimensionality of the dataset, the storage cell number may not be included.
* Note that frame number (as read from file) may (likely) differ from frame index (in the dataset)!
*/
int HDF5File::ReadImage (uint16_t* image, std::vector<hsize_t>& offset ) {
// Validate input arguments
if (!image) {
std::cerr << "Error: image buffer is null.\n";
return -99;
}
if ( offset.size() != rank-2 ) {
cprintf ( RED,"Offset vector must have size %llu. Found %lu\n", rank-2, offset.size() );
std::cerr << "Error: Wrong offset vector size\n";
CloseResources ();
return -99;
}
// Initialize frame_offset
if (frame_offset.empty())
frame_offset.resize(rank,0);
// Check if we reached the end of file
// Compares that the offsets of frame and storage cell (Z and S) have reached the end of file
// Excludes X and Y indices (of the image dataset) from the comparison
// As it is now, this never triggers, because frame_offset[1] is never equals file_dims[1]=16
/*
if( std::equal( frame_offset.cbegin(), frame_offset.cend()-2, file_dims.cbegin() ) ) {
printf("End of file reached\n");
return -1;
}
*/
if (frame_offset[0] == file_dims[0]) {
printf("End of file reached\n");
return -1;
}
/* //old
if (frame_offset[0] == file_dims[0]-1) {
printf("end of file\n");
return -1;
}
*/
// Validate frame_offset index
if (frame_offset[0] >= frame_index_list.size()) {
std::cerr << "Error: frame_offset[0] = " << frame_offset[0] << " of bounds.\n";
return -99;
}
// Check if images exist at the current frame offset
if (frame_index_list[frame_offset[0]] == 0) {
cprintf (RED,"No images at this frame offset %llu\n", frame_offset[0]);
std::cerr << "Error: Framenumber 0 at this frame offset\n";
CloseResources ();
return -99;
}
// Optional: Ensure dataset and dataspace are valid
if (dataset < 0) {
std::cerr << "Error: Invalid dataset ID.\n";
return -99;
}
if (dataspace < 0) {
std::cerr << "Error: Invalid dataspace.\n";
return -99;
}
// Define the size of the hyperslab to read
std::vector<hsize_t> frame_size(rank, 1);
std::copy(file_dims.begin() + rank-2, file_dims.end(), frame_size.begin() + rank-2);
/*
for ( int d=0; d < rank; ++d ) {
if (d < rank-2)
frame_size[d] = 1;
if ( d >= rank-2 )
frame_size[d] = file_dims[d];
}
*/
// Define memory space
hid_t memspace = H5Screate_simple (rank, frame_size.data(), nullptr);
if (memspace < 0) {
std::cerr << "Error: Failed to create memory space for HDF5 read operation\n";
CloseResources();
return -99;
}
// Create hyperslab selection
// This aligns dataspace such that we read the correct frame
if (H5Sselect_hyperslab(dataspace, H5S_SELECT_SET, frame_offset.data(), nullptr, frame_size.data(), nullptr) < 0 ) {
cprintf (RED,"Could not create hyperslab for frame offset %s\n", vectorToString(frame_offset).c_str());
std::cerr << "Error: Hyperslab creation failed for frame offset " << vectorToString(frame_offset) << "\n";
CloseResources();
H5Sclose(memspace);
return -99;
}
// Read dataset into image buffer (previously read to current_image owned by HDF5File)
if (H5Dread(dataset, H5T_STD_U16LE, memspace, dataspace, H5P_DEFAULT, image) < 0 ) {
cprintf (RED,"Could not read dataset for frame offset %s\n", vectorToString(frame_offset).c_str());
std::cerr << "Error: Reading of dataset failed for given start frame offset " << vectorToString(frame_offset) << "\n";
CloseResources ();
H5Sclose(memspace);
return -99;
}
// Clean up memory space
H5Sclose(memspace);
//*image = current_image; //if uint16_t** is passed, HDF5File owns the resource image points to, which is potentially dangerous
// Return frame number
unsigned int retval = frame_index_list[frame_offset[0]];
// Pass updated frame offset value(s) via offset parameter vector
std::copy_n(frame_offset.begin(), offset.size(), offset.begin());
/*
std::transform( offset.begin(), offset.end(), offset.begin(),
[&, i = 0](size_t) mutable { return frame_offset[i++]; } );
*/
// Increment frame offset correctly
conditionalIncrement(frame_offset, file_dims[1]);
//++frame_offset[0]; //old
return retval;
}
void HDF5File::PrintCurrentImage (uint16_t* image) {
printf("\n");
printf("Frame %llu, Image: %llu\n", frame_offset[0]-1, frame_index_list[frame_offset[0]-1]);
hsize_t size = file_dims[rank-1] * file_dims[rank-2];
for (hsize_t i = 0; i < size; ++i){
printf("%u ", image[i]);
if (!((i+1) % file_dims[rank-2] ))
printf("\n\n");
}
printf("\n\n\n\n");
}

View File

@ -1,159 +0,0 @@
#pragma once
/************************************************
* @file HDF5Fle.h
* @short functions to open/close/read HDF5 File
* Adapted for generalization, accepts rank 3 and 4
* Supports control over storage cells
***********************************************/
/**
*@short functions to open/close/read HDF5 File
*/
#include <iostream>
#include <vector>
#include <string>
#include "hdf5.h"
#include "hdf5_hl.h"
//#define MAX_STR_LENGTH 1000
#define RANK 4 // Dimension of the image dataset, only for validation
#define DEFAULT_Z_DIMS 10000 // only for validation
#define DEFAULT_Y_DIMS 1024 // only for validation
#define DEFAULT_X_DIMS 512 // only for validation
//#define DEFAULT_S_DIMS 1 // Storage cells
#define DEFAULT_CHUNK_Z_DIMS 1 // only for validation
#define DEFAULT_CHUNK_Y_DIMS 1024 // only for validation
#define DEFAULT_CHUNK_X_DIMS 512 // only for validation
//#define DEFAULT_CHUNK_S_DIMS 1
#define DATA_DATASETNAME "/data/JF18T01V01/data" //Furka JF
#define INDEX_DATASETNAME "/data/JF18T01V01/frame_index"
//enum{Z,S,X,Y}; //S is the storage cell //enum is not used
class HDF5File {
public:
/**
* Constructor
*/
//HDF5File () = default; //No need to declare if it is default
/**
* Destructor
*/
//~HDF5File () = default; //Since the destructor is default (and copy and move are default too)
std::vector<hsize_t> GetDatasetDimensions ();
std::vector<hsize_t> GetChunkDimensions ();
hsize_t GetRank ();
void SetImageDataPath (std::string const& name);
void SetFrameIndexPath (std::string const& name);
/**
* Open HDF5 file and dataset,
* reads frame index dataset to array
* @param fname file name
* @param validate true if one must validate if file is
* chunked with dims [? x 128 x 512] and chunk dims [1 x 128 x 512]
* @returns 1 if successful, else 0 if fail
*/
int OpenResources (const char* const fname, bool validate);
/**
* Close Open resources
*/
void CloseResources ();
/**
* Read an image into current_image,
* increment Z-offset (frame) and (if rank==4) storage cell
* @returns frame number read from file,
*/
int ReadImage (uint16_t* image, std::vector<hsize_t>& offset);
/**
* Print current image in memory
*/
void PrintCurrentImage (uint16_t* image);
private:
/**
* Initialize dimensions of image dataset for each new file
*/
void InitializeDimensions ();
bool ReadChunkDimensions ();
bool ValidateDimensions ();
bool ValidateChunkDimensions ();
/**
* Open dataset containing the frame numbers
*/
bool OpenFrameIndexDataset ();
/** file name */
std::string file_name{};
/** dataset name for image data */
std::string data_datasetname = DATA_DATASETNAME;
/** dataset name for frame index data */
std::string index_datasetname = INDEX_DATASETNAME;
/** file handle */
hid_t file{};
/** dataspace handle */
hid_t dataspace{};
/** memory space handle */
//hid_t memspace; //old
/** dataset handle */
hid_t dataset{};
/** file dimensions */
std::vector<hsize_t> file_dims{};
//hsize_t file_dims[RANK]{}; //static array (dimensions are known)
/** chunk dimensions
** not necessarily required
** useful for optimization or validation */
std::vector<hsize_t> chunk_dims{};
//hsize_t chunk_dims[RANK]{};
/** Rank of the image dataset */
hsize_t rank{};
/** number of frames */
unsigned int number_of_frames{};
/** frame index list */
std::vector<hsize_t> frame_index_list{};
/** Current image
** dynamic array
** uint16_t pointer format is chosen to support use with slsDetectorCalibration cluster finder */
//uint16_t* current_image{nullptr};
//uint16_t current_chunk[DEFAULT_CHUNK_Z_DIMS][DEFAULT_CHUNK_Y_DIMS][DEFAULT_CHUNK_X_DIMS];
/** Current frame offset
** (Z-offset, S-offset, 0, 0) or (Z-offset, 0, 0), increments automatically with ReadImage */
std::vector<hsize_t> frame_offset{};
//hsize_t frame_offset[RANK]{};
};

View File

@ -0,0 +1,155 @@
// SPDX-License-Identifier: LGPL-3.0-or-other
// Copyright (C) 2021 Contributors to the SLS Detector Package
#ifndef GOTTHARD2MODULEDATANEW_H
#define GOTTHARD2MODULEDATANEW_H
#include "gotthardModuleDataNew.h"
class gotthardDoubleModuleDataNew : public slsDetectorData<uint16_t> {
private:
const int nModules;
const int offset;
int iframe;
public:
/**
Implements the slsReceiverData structure for the gotthard read out by a module
i.e. using the slsReceiver (1x1280 pixels, 2 packets 1286 large etc.) \param c
crosstalk parameter for the output buffer
*/
gotthardDoubleModuleDataNew(int off = 24 * 2, int nmod = 2)
: slsDetectorData<uint16_t>(1280 * nmod, 1, nmod * (1280 * 2 + off)),
nModules(nmod), offset(off), iframe(0) {
#ifdef BCHIP074_BCHIP075
cout << "This is a bchip074-bchip075 system " << endl;
#endif
uint16_t **dMask;
int **dMap;
int ix, iy;
int ypixels = 1;
int xpixels = 1280 * nmod;
int imod, ipix;
dMask = new uint16_t *[1];
dMap = new int *[1];
dMap[0] = new int[1280 * nmod];
dMask[0] = new uint16_t[1280 * nmod];
for (int ix = 0; ix < xpixels; ix++) {
imod = ix % 2;
if (imod == 0)
ipix = ix / 2;
else
ipix = 1280 - 1 - ix / 2;
if (imod == 0)
dMap[0][ix] = ipix * 2 + offset;
else
dMap[0][ix] = 1280 * 2 + 2 * offset +
ipix * 2; // dataSize-2-ix;//+2*offset;
// dMap[0][ix] = 2*ipix+offset*(imod+1)+1280*2*imod;
dMask[0][ix] = 0x0;
#ifdef BCHIP074_BCHIP075
int ibad = ix / 2 + 1280 * imod;
if ((ibad >= 128 * 4 && ibad < 128 * 5) ||
(ibad >= 9 * 128 && ibad < 10 * 128) ||
(ibad >= (1280 + 128 * 4) && ibad < ibad >= (1280 + 128 * 6)))
dataROIMask[0][ix] = 0;
#endif
}
setDataMap(dMap);
setDataMask(dMask);
};
/**
Returns the frame number for the given dataset.
\param buff pointer to the dataset
\returns frame number
*/
int getFrameNumber(char *buff) {
if (offset >= sizeof(sls_detector_header))
return ((sls_detector_header *)buff)->frameNumber;
return iframe;
}; //*((int*)(buff+5))&0xffffff;};
/**
gets the packets number (last packet is labelled with 0 and is replaced with
40) \param buff pointer to the memory \returns packet number
*/
int getPacketNumber(char *buff) {
if (offset >= sizeof(sls_detector_header))
return ((sls_detector_header *)buff)->packetNumber;
};
/**
Loops over a memory slot until a complete frame is found (i.e. all
packets 0 to nPackets, same frame number). purely virtual func \param
data pointer to the memory to be analyzed \param ndata reference to the
amount of data found for the frame, in case the frame is incomplete at
the end of the memory slot \param dsize size of the memory slot to be
analyzed \returns pointer to the beginning of the last good frame (might
be incomplete if ndata smaller than dataSize), or NULL if no frame is
found
*/
virtual char *findNextFrame(char *data, int &ndata, int dsize) {
if (dsize < dataSize)
ndata = dsize;
else
ndata = dataSize;
return data;
}
virtual char *readNextFrame(ifstream &filebin) {
int ff = -1, np = -1;
return readNextFrame(filebin, ff, np);
};
virtual char *readNextFrame(ifstream &filebin, int &ff) {
int np = -1;
return readNextFrame(filebin, ff, np);
};
virtual char *readNextFrame(ifstream &filebin, int &ff, int &np) {
char *data = new char[dataSize];
char *d = readNextFrame(filebin, ff, np, data);
if (d == NULL) {
delete[] data;
data = NULL;
}
return data;
}
virtual char *readNextFrame(ifstream &filebin, int &ff, int &np,
char *data) {
char *retval = 0;
int nd;
int fnum = -1;
np = 0;
int pn;
// cout << dataSize << endl;
if (ff >= 0)
fnum = ff;
if (filebin.is_open()) {
if (filebin.read(data, dataSize)) {
ff = getFrameNumber(data);
np = getPacketNumber(data);
return data;
}
}
return NULL;
};
};
#endif

View File

@ -0,0 +1,105 @@
// SPDX-License-Identifier: LGPL-3.0-or-other
// Copyright (C) 2021 Contributors to the SLS Detector Package
#ifndef GOTTHARDSHORTMODULEDATA_H
#define GOTTHARDSHORTMODULEDATA_H
#include "slsReceiverData.h"
class gotthardShortModuleData : public slsReceiverData<uint16_t> {
public:
/**
Implements the slsReceiverData structure for the gotthard short read out by a
module i.e. using the slsReceiver (1x256 pixels, 1 packet 256 large etc.)
\param c crosstalk parameter for the output buffer
*/
gotthardShortModuleData(double c = 0)
: slsReceiverData<uint16_t>(xpixels, ypixels, npackets, buffersize),
xtalk(c) {
uint16_t **dMask;
int **dMap;
int ix, iy;
int offset = 2;
dMask = new uint16_t *[ypixels];
dMap = new int *[ypixels];
for (int i = 0; i < ypixels; i++) {
dMap[i] = new int[xpixels];
dMask[i] = new uint16_t[xpixels];
}
for (ix = 0; ix < ypixels; ++ix)
for (iy = 0; iy < xpixels; ++iy)
dMask[ix][iy] = 0x0;
for (ix = 0; ix < ypixels; ++ix)
for (iy = 0; iy < xpixels; ++iy) {
dMap[ix][iy] = offset;
offset++;
}
setDataMap(dMap);
setDataMask(dMask);
};
/**
Returns the frame number for the given dataset.
\param buff pointer to the dataset
\returns frame number
*/
int getFrameNumber(char *buff) { return (*(int *)buff); };
/**
gets the packets number (last packet is labelled with 0 and is replaced with
40) \param buff pointer to the memory \returns packet number
*/
int getPacketNumber(char *buff) { return 1; };
/**
returns the pixel value as double correcting for the output buffer crosstalk
\param data pointer to the memory
\param ix coordinate in the x direction
\param iy coordinate in the y direction
\returns channel value as double
*/
double getValue(char *data, int ix, int iy = 0) {
// check how it is for gotthard
if (xtalk == 0)
return slsDetectorData<uint16_t>::getValue(data, ix, iy);
else
return slsDetectorData<uint16_t>::getValue(data, ix, iy) -
xtalk *
slsDetectorData<uint16_t>::getValue(data, ix - 1, iy);
};
/** sets the output buffer crosstalk correction parameter
\param c output buffer crosstalk correction parameter to be set
\returns current value for the output buffer crosstalk correction parameter
*/
double setXTalk(double c) {
xtalk = c;
return xtalk;
}
/** gets the output buffer crosstalk parameter
\returns current value for the output buffer crosstalk correction parameter
*/
double getXTalk() { return xtalk; }
private:
double xtalk; /**<output buffer crosstalk correction parameter */
const static int xpixels = 256;
const static int ypixels = 1;
const static int npackets = 1;
const static int buffersize = 518;
};
#endif

View File

@ -1,422 +0,0 @@
// SPDX-License-Identifier: LGPL-3.0-or-other
// Copyright (C) 2021 Contributors to the SLS Detector Package
#ifndef JUNGFRAULGADSTRIXELSDATAQUAD_H
#define JUNGFRAULGADSTRIXELSDATAQUAD_H
#ifdef CINT
#include "sls/sls_detector_defs_CINT.h"
#else
#include "sls/sls_detector_defs.h"
#endif
#include "slsDetectorData.h"
// #define VERSION_V2
/**
@short structure for a Detector Packet or Image Header
@li frameNumber is the frame number
@li expLength is the subframe number (32 bit eiger) or real time exposure
time in 100ns (others)
@li packetNumber is the packet number
@li bunchId is the bunch id from beamline
@li timestamp is the time stamp with 10 MHz clock
@li modId is the unique module id (unique even for left, right, top, bottom)
@li xCoord is the x coordinate in the complete detector system
@li yCoord is the y coordinate in the complete detector system
@li zCoord is the z coordinate in the complete detector system
@li debug is for debugging purposes
@li roundRNumber is the round robin set number
@li detType is the detector type see :: detectorType
@li version is the version number of this structure format
*/
#include <algorithm>
#include <numeric>
#include <tuple>
namespace strixelQuad {
constexpr int nc_rawimg = 1024; // for full images //256;
constexpr int nc_quad = 512;
constexpr int nr_rawimg = 512;
constexpr int nr_chip = 256;
constexpr int gr = 9;
//shift due to extra pixels
constexpr int shift_x = 2; //left
constexpr int nc_strixel = ( nc_quad - shift_x - 2*gr ) / 3; //164
constexpr int nr_strixel = ( nr_chip - 1 - gr ) * 3; //one half (-1 because double sided pixel) //738
constexpr int nr_center = 12; //double sided pixels to be skipped
// boundaries in ASIC coordinates (pixels at both bounds are included)
constexpr int xstart = 256 + gr; // 265
constexpr int xend = 255 + nc_quad - gr; // 758
constexpr int bottom_ystart = gr; // 9
constexpr int bottom_yend = nr_chip - 2; // 254
constexpr int top_ystart = nr_chip + 1; // 257
constexpr int top_yend = nr_chip*2 - gr - 1; // 502
// x shift because of 2-pixel strixels on one side
constexpr int shift = 2;
} // namespace strixelQuad
//to account for module rotation
enum rotation {
NORMAL = 0,
INVERSE = 1
};
const int rota = NORMAL;
typedef struct {
uint64_t bunchNumber; /**< is the frame number */
uint64_t pre; /**< something */
} jf_header; // Aldo's header
using namespace strixelQuad;
class jungfrauLGADStrixelsDataQuad : public slsDetectorData<uint16_t> {
private:
int iframe;
int x0, y0, x1, y1, shifty;
struct {
uint16_t xmin;
uint16_t xmax;
uint16_t ymin;
uint16_t ymax;
int nc;
} globalROI;
//to account for the inverted routing of the two different quad halfs
enum location {
BOTTOM = 0,
TOP = 1
};
int multiplicator = 3;
std::vector<int> mods{ 0, 1, 2 };
void reverseVector( std::vector<int>& v ) {
std::reverse( v.begin(), v.end() );
std::cout << "mods reversed ";
for ( auto i : v )
std::cout << i << " ";
std::cout << '\n';
}
void setMappingShifts( const int rot, const int half ) {
x0 = xstart;
x1 = xend;
if (rot==NORMAL) {
x0 += shift;
} else {
x1-=shift;
reverseVector(mods);
}
if (half==BOTTOM) {
y0 = bottom_ystart;
y1 = bottom_yend;
shifty = 0;
} else {
y0 = top_ystart;
y1 = top_yend;
reverseVector(mods);
shifty = nr_strixel + nr_center; //double-sided pixels in the center have to be jumped
}
}
void remap( int xmin=0, int xmax=0, int ymin=0, int ymax=0 ) {
int ix, iy = 0;
// remapping loop
for (int ipy = y0; ipy <= y1; ipy++) {
for (int ipx = x0; ipx <= x1; ipx++) {
ix = int((ipx - x0) / multiplicator);
for (int m = 0; m < multiplicator; ++m) {
if ((ipx - x0) % multiplicator == m)
iy = (ipy - y0) * multiplicator + mods[m] + shifty;
}
// if (iy< 40) cout << iy << " " << ix <<endl;
if (xmin < xmax && ymin < ymax) {
if ( ipx>=xmin && ipx<=xmax && ipy>=ymin && ipy <=ymax )
dataMap[iy][ix] =
sizeof(header) + (globalROI.nc * (ipy - globalROI.ymin) + (ipx - globalROI.xmin)) * 2;
} else {
dataMap[iy][ix] = sizeof(header) + (nc_rawimg * ipy + ipx) * 2;
}
}
}
}
void remapQuad(const int rot) {
setMappingShifts( rot, BOTTOM );
remap();
setMappingShifts( rot, TOP );
remap();
}
std::tuple< uint16_t, uint16_t, uint16_t, uint16_t > adjustROItoLimits(uint16_t xmin,
uint16_t xmax,
uint16_t ymin,
uint16_t ymax,
uint16_t lim_roi_xmin,
uint16_t lim_roi_xmax,
uint16_t lim_roi_ymin,
uint16_t lim_roi_ymax) {
uint16_t xmin_roi, xmax_roi, ymin_roi, ymax_roi;
if ( xmin < lim_roi_xmin)
xmin_roi = lim_roi_xmin;
else
xmin_roi = xmin;
if ( xmax > lim_roi_xmax )
xmax_roi = lim_roi_xmax;
else
xmax_roi = xmax;
if ( ymin < lim_roi_ymin )
ymin_roi = lim_roi_ymin;
else
ymin_roi = ymin;
if ( ymax > lim_roi_ymax )
ymax_roi = lim_roi_ymax;
else
ymax_roi = ymax;
return std::make_tuple(xmin_roi, xmax_roi, ymin_roi, ymax_roi);
}
std::vector < std::tuple< int, uint16_t, uint16_t, uint16_t, uint16_t > > mapSubROIs(uint16_t xmin,
uint16_t xmax,
uint16_t ymin,
uint16_t ymax) {
bool bottom = false;
bool top = false;
for ( int x=xmin; x!=xmax+1; ++x ) {
for ( int y=ymin; y!=ymax; ++y ) {
if ( xstart<=x && x<=xend && bottom_ystart<=y && y<=bottom_yend )
bottom = true;
if ( xstart<=x && x<=xend && top_ystart<=y && y<=top_yend )
top = true;
}
}
uint16_t xmin_roi{}, xmax_roi{}, ymin_roi{}, ymax_roi{};
std::vector < std::tuple< int, uint16_t, uint16_t, uint16_t, uint16_t > > rois{};
if (bottom) {
std::tie( xmin_roi, xmax_roi, ymin_roi, ymax_roi ) =
adjustROItoLimits( xmin, xmax, ymin, ymax,
xstart, xend, bottom_ystart, bottom_yend );
rois.push_back( std::make_tuple( BOTTOM, xmin_roi, xmax_roi, ymin_roi, ymax_roi ) );
}
if (top) {
std::tie( xmin_roi, xmax_roi, ymin_roi, ymax_roi ) =
adjustROItoLimits( xmin, xmax, ymin, ymax,
xstart, xend, top_ystart, top_yend );
rois.push_back( std::make_tuple( TOP, xmin_roi, xmax_roi, ymin_roi, ymax_roi ) );
}
return rois;
}
void remapROI(std::tuple< int, uint16_t, uint16_t, uint16_t, uint16_t > roi, const int rot ) {
int half, xmin, xmax, ymin, ymax;
std::tie( half, xmin, xmax, ymin, ymax ) = roi;
setMappingShifts(rot, half);
std::cout << "remapping roi: "
<< ", x0: " << x0 << ", x1: " << x1 << ", y0: " << y0
<< ", y1: " << y1 << std::endl;
std::cout << "Adjusted roi: [" << xmin << ", " << xmax << ", " << ymin << ", " << ymax << "]" << std::endl;
remap( xmin, xmax, ymin, ymax );
}
public:
using header = sls::defs::sls_receiver_header;
jungfrauLGADStrixelsDataQuad(uint16_t xmin = 0, uint16_t xmax = 0,
uint16_t ymin = 0, uint16_t ymax = 0)
: slsDetectorData<uint16_t>(
nc_strixel,
nr_strixel * 2 + nr_center,
nc_strixel * ( nr_strixel * 2 + nr_center ) * 2 + sizeof(header)) {
std::cout << "Jungfrau strixels quad with full module data "
<< std::endl;
// Fill all strixels with dummy values
for (int ix = 0; ix != nc_strixel; ++ix) {
for (int iy = 0; iy != nr_strixel * 2 + nr_center; ++iy) {
dataMap[iy][ix] = sizeof(header);
}
}
globalROI.xmin = xmin;
globalROI.xmax = xmax;
globalROI.ymin = ymin;
globalROI.ymax = ymax;
std::cout << "sizeofheader = " << sizeof(header) << std::endl;
std::cout << "Jungfrau strixels quad with full module data "
<< std::endl;
if (xmin < xmax && ymin < ymax) {
// get ROI raw image number of columns
globalROI.nc = xmax - xmin + 1;
std::cout << "nc_roi = " << globalROI.nc << std::endl;
dataSize =
(xmax - xmin + 1) * (ymax - ymin + 1) * 2 + sizeof(header);
std::cout << "datasize " << dataSize << std::endl;
auto rois = mapSubROIs(xmin, xmax, ymin, ymax);
//function to fill vector of rois from globalROI
for ( auto roi : rois )
remapROI(roi, rota);
} else {
remapQuad( rota );
}
iframe = 0;
std::cout << "data struct created" << std::endl;
};
/**
Returns the value of the selected channel for the given dataset as
double. \param data pointer to the dataset (including headers etc) \param
ix pixel number in the x direction \param iy pixel number in the y
direction \returns data for the selected channel, with inversion if
required as double
*/
virtual double getValue(char *data, int ix, int iy = 0) {
uint16_t val = getChannel(data, ix, iy) & 0x3fff;
return val;
};
/**
Returns the frame number for the given dataset. Purely virtual func.
\param buff pointer to the dataset
\returns frame number
*/
int getFrameNumber(char *buff) {
#ifdef ALDO // VH
return ((jf_header *)buff)->bunchNumber; // VH
#endif // VH
return ((header *)buff)->detHeader.frameNumber;
};
/**
Returns the packet number for the given dataset. purely virtual func
\param buff pointer to the dataset
\returns packet number number
*/
int getPacketNumber(char *buff) {
#ifdef ALDO // VH
// uint32_t fakePacketNumber = 1000;
// return fakePacketNumber; //VH //TODO: Keep in mind in case of bugs!
// //This is definitely bad!
return 1000;
#endif // VH
return ((header *)buff)->detHeader.packetNumber;
};
char *readNextFrame(std::ifstream &filebin) {
int ff = -1, np = -1;
return readNextFrame(filebin, ff, np);
};
char *readNextFrame(std::ifstream &filebin, int &ff) {
int np = -1;
return readNextFrame(filebin, ff, np);
};
char *readNextFrame(std::ifstream &filebin, int &ff, int &np) {
char *data = new char[dataSize];
char *d = readNextFrame(filebin, ff, np, data);
if (d == NULL) {
delete[] data;
data = NULL;
}
return data;
};
char *readNextFrame(std::ifstream &filebin, int &ff, int &np, char *data) {
//char *retval = 0;
//int nd;
//int fnum = -1;
np = 0;
//int pn;
//std::cout << dataSize << std::endl;
//if (ff >= 0) {
// fnum = ff; }
if (filebin.is_open()) {
if (filebin.read(data, dataSize)) {
std::cout << "*";
ff = getFrameNumber(data);
np = getPacketNumber(data);
return data;
}
std::cout << "#";
} else {
std::cout << "File not open" << std::endl;
}
return NULL;
};
/* Loops over a memory slot until a complete frame is found (i.e. all */
/* packets 0 to nPackets, same frame number). purely virtual func \param
*/
/* data pointer to the memory to be analyzed \param ndata reference to
* the */
/* amount of data found for the frame, in case the frame is incomplete at
*/
/* the end of the memory slot \param dsize size of the memory slot to be
*/
/* analyzed \returns pointer to the beginning of the last good frame
* (might */
/* be incomplete if ndata smaller than dataSize), or NULL if no frame is
*/
/* found */
/* *\/ */
virtual char *findNextFrame(char *data, int &ndata, int dsize) {
if (dsize < dataSize)
ndata = dsize;
else
ndata = dataSize;
return data;
};
// int getPacketNumber(int x, int y) {return dataMap[y][x]/packetSize;};
};
#endif

View File

@ -1,432 +0,0 @@
// SPDX-License-Identifier: LGPL-3.0-or-other
// Copyright (C) 2021 Contributors to the SLS Detector Package
#ifndef JUNGFRAULGADSTRIXELSDATAQUADH5_H
#define JUNGFRAULGADSTRIXELSDATAQUADH5_H
#ifdef CINT
#include "sls/sls_detector_defs_CINT.h"
#else
#include "sls/sls_detector_defs.h"
#endif
#include "slsDetectorData.h"
// This needs to be linked correctly
#include "HDF5File.cpp"
#include "HDF5File.h" //this includes hdf5.h and hdf5_hl.h
// #define VERSION_V2
/**
@short structure for a Detector Packet or Image Header
@li frameNumber is the frame number
@li expLength is the subframe number (32 bit eiger) or real time exposure
time in 100ns (others)
@li packetNumber is the packet number
@li bunchId is the bunch id from beamline
@li timestamp is the time stamp with 10 MHz clock
@li modId is the unique module id (unique even for left, right, top, bottom)
@li xCoord is the x coordinate in the complete detector system
@li yCoord is the y coordinate in the complete detector system
@li zCoord is the z coordinate in the complete detector system
@li debug is for debugging purposes
@li roundRNumber is the round robin set number
@li detType is the detector type see :: detectorType
@li version is the version number of this structure format
*/
// #include <algorithm>
#include <numeric>
#include <tuple>
namespace strixelQuad {
constexpr int nc_rawimg = 1024; // for full images //256;
constexpr int nc_quad = 512;
constexpr int nr_rawimg = 512;
constexpr int nr_chip = 256;
constexpr int gr = 9;
// shift due to extra pixels
constexpr int shift_x = 2; // left
constexpr int nc_strixel = (nc_quad - shift_x - 2 * gr) / 3; // 164
constexpr int nr_strixel =
(nr_chip - 1 - gr) * 3; // one half (-1 because double sided pixel) //738
constexpr int nr_center = 12; // double sided pixels to be skipped
// boundaries in ASIC coordinates (pixels at both bounds are included)
constexpr int xstart = 256 + gr; // 265
constexpr int xend = 255 + nc_quad - gr; // 758
constexpr int bottom_ystart = gr; // 9
constexpr int bottom_yend = nr_chip - 2; // 254
constexpr int top_ystart = nr_chip + 1; // 257
constexpr int top_yend = nr_chip * 2 - gr - 1; // 502
// x shift because of 2-pixel strixels on one side
constexpr int shift = 2;
} // namespace strixelQuad
// to account for module rotation
enum rotation { NORMAL = 0, INVERSE = 1 };
const int rota = NORMAL;
typedef struct {
uint64_t bunchNumber; /**< is the frame number */
uint64_t pre; /**< something */
} jf_header; // Aldo's header
using namespace strixelQuad;
class jungfrauLGADStrixelsDataQuadH5 : public slsDetectorData<uint16_t> {
private:
int iframe;
int x0, y0, x1, y1, shifty;
struct {
uint16_t xmin;
uint16_t xmax;
uint16_t ymin;
uint16_t ymax;
int nc;
} globalROI;
// to account for the inverted routing of the two different quad halfs
enum location { BOTTOM = 0, TOP = 1 };
int multiplicator = 3;
std::vector<int> mods{0, 1, 2};
void reverseVector(std::vector<int> &v) {
std::reverse(v.begin(), v.end());
std::cout << "mods reversed ";
for (auto i : v)
std::cout << i << " ";
std::cout << '\n';
}
void setMappingShifts(const int rot, const int half) {
x0 = xstart;
x1 = xend;
if (rot == NORMAL) {
x0 += shift;
} else {
x1 -= shift;
reverseVector(mods);
}
if (half == BOTTOM) {
y0 = bottom_ystart;
y1 = bottom_yend;
shifty = 0;
} else {
y0 = top_ystart;
y1 = top_yend;
reverseVector(mods);
shifty = nr_strixel + nr_center; // double-sided pixels in the
// center have to be jumped
}
}
void remap(int xmin = 0, int xmax = 0, int ymin = 0, int ymax = 0) {
int ix, iy = 0;
// remapping loop
for (int ipy = y0; ipy <= y1; ++ipy) {
for (int ipx = x0; ipx <= x1; ++ipx) {
ix = int((ipx - x0) / multiplicator);
for (int m = 0; m < multiplicator; ++m) {
if ((ipx - x0) % multiplicator == m)
iy = (ipy - y0) * multiplicator + mods[m] + shifty;
}
// if (iy< 40) cout << iy << " " << ix <<endl;
if (xmin < xmax && ymin < ymax) { // if ROI
if (ipx >= xmin && ipx <= xmax && ipy >= ymin &&
ipy <= ymax)
dataMap[iy][ix] =
(globalROI.nc * (ipy - globalROI.ymin) +
(ipx - globalROI.xmin)) *
2;
} else { // if full Quad
dataMap[iy][ix] = (nc_rawimg * ipy + ipx) * 2;
}
}
}
}
void remapQuad(const int rot) {
setMappingShifts(rot, BOTTOM);
remap();
setMappingShifts(rot, TOP);
remap();
}
std::tuple<uint16_t, uint16_t, uint16_t, uint16_t>
adjustROItoLimits(uint16_t xmin, uint16_t xmax, uint16_t ymin,
uint16_t ymax, uint16_t lim_roi_xmin,
uint16_t lim_roi_xmax, uint16_t lim_roi_ymin,
uint16_t lim_roi_ymax) {
uint16_t xmin_roi, xmax_roi, ymin_roi, ymax_roi;
if (xmin < lim_roi_xmin)
xmin_roi = lim_roi_xmin;
else
xmin_roi = xmin;
if (xmax > lim_roi_xmax)
xmax_roi = lim_roi_xmax;
else
xmax_roi = xmax;
if (ymin < lim_roi_ymin)
ymin_roi = lim_roi_ymin;
else
ymin_roi = ymin;
if (ymax > lim_roi_ymax)
ymax_roi = lim_roi_ymax;
else
ymax_roi = ymax;
return std::make_tuple(xmin_roi, xmax_roi, ymin_roi, ymax_roi);
}
// The strixel Quad has a mirrored symmetry from the center axis
// So we need to distinguish between bottom and top half for remapping
std::vector<std::tuple<int, uint16_t, uint16_t, uint16_t, uint16_t>>
mapSubROIs(uint16_t xmin, uint16_t xmax, uint16_t ymin, uint16_t ymax) {
bool bottom = false;
bool top = false;
for (int x = xmin; x != xmax + 1; ++x) {
for (int y = ymin; y != ymax; ++y) {
if (xstart <= x && x <= xend && bottom_ystart <= y &&
y <= bottom_yend)
bottom = true;
if (xstart <= x && x <= xend && top_ystart <= y &&
y <= top_yend)
top = true;
}
}
uint16_t xmin_roi{}, xmax_roi{}, ymin_roi{}, ymax_roi{};
std::vector<std::tuple<int, uint16_t, uint16_t, uint16_t, uint16_t>>
rois{};
if (bottom) {
std::tie(xmin_roi, xmax_roi, ymin_roi, ymax_roi) =
adjustROItoLimits(xmin, xmax, ymin, ymax, xstart, xend,
bottom_ystart, bottom_yend);
rois.push_back(std::make_tuple(BOTTOM, xmin_roi, xmax_roi, ymin_roi,
ymax_roi));
}
if (top) {
std::tie(xmin_roi, xmax_roi, ymin_roi, ymax_roi) =
adjustROItoLimits(xmin, xmax, ymin, ymax, xstart, xend,
top_ystart, top_yend);
rois.push_back(
std::make_tuple(TOP, xmin_roi, xmax_roi, ymin_roi, ymax_roi));
}
return rois;
}
void remapROI(std::tuple<int, uint16_t, uint16_t, uint16_t, uint16_t> roi,
const int rot) {
int half, xmin, xmax, ymin, ymax;
std::tie(half, xmin, xmax, ymin, ymax) = roi;
setMappingShifts(rot, half);
std::cout << "remapping roi: "
<< ", x0: " << x0 << ", x1: " << x1 << ", y0: " << y0
<< ", y1: " << y1 << std::endl;
std::cout << "Adjusted roi: [" << xmin << ", " << xmax << ", " << ymin
<< ", " << ymax << "]" << std::endl;
remap(xmin, xmax, ymin, ymax);
}
// The following functions are pure virtual in the base class. But I don't
// want them to be accessible here! Implement the functions as private (to
// satisfy the linker) int getFrameNumber(char* buff){return 0;} //This is
// actually needed because the cluster finder writes the framenumber
int getPacketNumber(char *buff) { return 0; } // Not provided
// Mark overwritten functions as override final
char *readNextFrame(std::ifstream &filebin) override final {
return nullptr;
}
public:
using header = sls::defs::sls_receiver_header;
jungfrauLGADStrixelsDataQuadH5(uint16_t xmin = 0, uint16_t xmax = 0,
uint16_t ymin = 0, uint16_t ymax = 0)
: slsDetectorData<uint16_t>(
// nc_strixel,
// nr_strixel * 2 + nr_center,
// nc_strixel * ( nr_strixel * 2 + nr_center ) * 2
512 / 2, 1024 * 2, 512 * 1024 * 2) {
std::cout << "Jungfrau strixels quad with full module data "
<< std::endl;
// Fill all strixels with dummy values
// for (int ix = 0; ix != nc_strixel; ++ix) {
// for (int iy = 0; iy != nr_strixel * 2 + nr_center; ++iy) {
for (int ix = 0; ix != 512 / 2; ++ix) {
for (int iy = 0; iy != 1024 * 2; ++iy) {
// Set everything to dummy value
dataMap[iy][ix] = sizeof(header);
}
}
globalROI.xmin = xmin;
globalROI.xmax = xmax;
globalROI.ymin = ymin;
globalROI.ymax = ymax;
// std::cout << "sizeofheader = " << sizeof(header) << std::endl;
std::cout << "Jungfrau strixels quad with full module data "
<< std::endl;
if (xmin < xmax && ymin < ymax) {
// get ROI raw image number of columns
globalROI.nc = xmax - xmin + 1;
std::cout << "nc_roi = " << globalROI.nc << std::endl;
dataSize = (xmax - xmin + 1) * (ymax - ymin + 1) * 2;
std::cout << "datasize " << dataSize << std::endl;
auto rois = mapSubROIs(xmin, xmax, ymin, ymax);
// function to fill vector of rois from globalROI
for (auto roi : rois)
remapROI(roi, rota);
} else {
remapQuad(rota);
}
iframe = 0;
std::cout << "data struct created" << std::endl;
};
/**
Returns the value of the selected channel for the given dataset as
double. \param data pointer to the dataset (including headers etc) \param
ix pixel number in the x direction \param iy pixel number in the y
direction \returns data for the selected channel, with inversion if
required as double
*/
virtual double getValue(char *data, int ix, int iy = 0) {
uint16_t val = getChannel(data, ix, iy) & 0x3fff;
return val;
};
char *readNextFrame(HDF5File &hfile) {
int fn = 0;
std::vector<hsize_t> h5offset(1);
return readNextFrame(hfile, fn, h5offset);
};
char *readNextFrame(HDF5File &hfile, int &fn) {
std::vector<hsize_t> h5offset(1);
return readNextFrame(hfile, fn, h5offset);
};
char *readNextFrame(HDF5File &hfile, int &fn,
std::vector<hsize_t> &h5offset) {
// Ensure dataSize is a valid size for allocation
if (dataSize <= 0) {
// Handle error case appropriately, e.g., log an error message
return nullptr;
}
char *data = new char[dataSize];
char *readResult = readNextFrame(hfile, fn, h5offset, data);
// Check if reading failed
if (readResult == nullptr) {
delete[] data; // Free allocated memory
data = nullptr; // Set to nullptr to avoid dangling pointer
}
return data; // returning data is equivalent to returning
// reinterpret_cast<char*>(data_ptr) as they both point to
// the same memory
};
/*
* This is the most recent function. This is used in the cluster finder!
* The overloads are legacy!
* Note that caller has to allocate and deallocate memory for data!
* \param hfile object of type HDF5File (reader class)
* \param framenumber frame number as read from the HDF5 file
* \param h5offset vector defining offset parameters for HDF5 hyperslab
* selection (dimensions Z and S), incremented automatially
* \param data pointer to image buffer (converted to hold uint16_t by
* definition of HDF5File)
*/
char *readNextFrame(HDF5File &hfile, int &framenumber,
std::vector<hsize_t> &h5offset, char *data) {
if (framenumber >= 0) {
if (h5offset[0] % 10 == 0)
std::cout << "*";
// Storing the reinterpret_cast in the variable data_ptr ensures
// that I can pass it to a function that expects at uint16_t*
uint16_t *data_ptr = reinterpret_cast<uint16_t *>(
data); // now data_ptr points where data points (thus modifies
// the same memory)
framenumber = hfile.ReadImage(data_ptr, h5offset);
iframe = h5offset[0]; // iframe is a class member!
return data; // return reinterpret_cast<char*>(data_ptr); //
// Equivalent
}
std::cout << "#";
return nullptr;
};
int getFrameNumber(char *buff) {
return iframe;
} // Provided via public method readNextFrame
// It is debatable if one might not instead want to provide the "real" frame
// number as read from the file here For now, this is the frame offset
// counter (that always has to start at 0 for each new file)
/* Loops over a memory slot until a complete frame is found (i.e. all */
/* packets 0 to nPackets, same frame number). purely virtual func \param
*/
/* data pointer to the memory to be analyzed \param ndata reference to
* the */
/* amount of data found for the frame, in case the frame is incomplete at
*/
/* the end of the memory slot \param dsize size of the memory slot to be
*/
/* analyzed \returns pointer to the beginning of the last good frame
* (might */
/* be incomplete if ndata smaller than dataSize), or NULL if no frame is
*/
/* found */
/* *\/ */
virtual char *findNextFrame(char *data, int &ndata, int dsize) {
if (dsize < dataSize)
ndata = dsize;
else
ndata = dataSize;
return data;
};
// int getPacketNumber(int x, int y) {return dataMap[y][x]/packetSize;};
};
#endif

View File

@ -28,10 +28,6 @@
@li version is the version number of this structure format
*/
#include <algorithm>
#include <numeric>
#include <tuple>
namespace strixelSingleChip {
constexpr int nc_rawimg = 1024; // for full images //256;
constexpr int nr_rawimg = 512;
@ -81,7 +77,7 @@ constexpr int c6g1_ystart = c6g2_yend + 1; // 448
constexpr int c6g1_yend = c6g2_yend + 64 - gr; // 502
// y shift due to faulty bonding (relevant for M408)
constexpr int bond_shift_y = 0; // CHANGE IF YOU CHANGE MODULE!
constexpr int bond_shift_y = 1; // CHANGE IF YOU CHANGE MODULE!
} // namespace strixelSingleChip
@ -101,13 +97,6 @@ class jungfrauLGADStrixelsData : public slsDetectorData<uint16_t> {
int chip_x0;
int chip_y0;
int x0, y0, x1, y1, shifty;
struct {
uint16_t xmin;
uint16_t xmax;
uint16_t ymin;
uint16_t ymax;
int nc;
} globalROI;
int getMultiplicator(const int group) {
int multiplicator;
@ -226,113 +215,9 @@ class jungfrauLGADStrixelsData : public slsDetectorData<uint16_t> {
}
}
std::tuple< uint16_t, uint16_t, uint16_t, uint16_t > adjustROItoLimits(uint16_t xmin,
uint16_t xmax,
uint16_t ymin,
uint16_t ymax,
uint16_t lim_roi_xmin,
uint16_t lim_roi_xmax,
uint16_t lim_roi_ymin,
uint16_t lim_roi_ymax) {
uint16_t xmin_roi, xmax_roi, ymin_roi, ymax_roi;
if ( xmin < lim_roi_xmin)
xmin_roi = lim_roi_xmin;
else
xmin_roi = xmin;
if ( xmax > lim_roi_xmax )
xmax_roi = lim_roi_xmax;
else
xmax_roi = xmax;
if ( ymin < lim_roi_ymin )
ymin_roi = lim_roi_ymin;
else
ymin_roi = ymin;
if ( ymax > lim_roi_ymax )
ymax_roi = lim_roi_ymax;
else
ymax_roi = ymax;
return std::make_tuple(xmin_roi, xmax_roi, ymin_roi, ymax_roi);
}
std::vector < std::tuple< int, int, uint16_t, uint16_t, uint16_t, uint16_t > > mapSubROIs(uint16_t xmin,
uint16_t xmax,
uint16_t ymin,
uint16_t ymax) {
bool chip_1_1 = false;
bool chip_1_2 = false;
bool chip_1_3 = false;
bool chip_6_1 = false;
bool chip_6_2 = false;
bool chip_6_3 = false;
for ( int x=xmin; x!=xmax+1; ++x ) {
for ( int y=ymin; y!=ymax; ++y ) {
if ( c1g1_xstart<=x && x<=c1_xend && (c1g1_ystart+bond_shift_y)<=y && y<=(c1g1_yend+bond_shift_y) )
chip_1_1 = true;
if ( c1g2_xstart<=x && x<=c1_xend && (c1g2_ystart+bond_shift_y)<=y && y<=(c1g2_yend+bond_shift_y) )
chip_1_2 = true;
if ( c1g3_xstart<=x && x<=c1_xend && (c1g3_ystart+bond_shift_y)<=y && y<=(c1g3_yend+bond_shift_y) )
chip_1_3 = true;
if ( c6_xstart<=x && x<=c6g1_xend && (c6g1_ystart-bond_shift_y)<=y && y<=(c6g1_yend-bond_shift_y) )
chip_6_1 = true;
if ( c6_xstart<=x && x<=c6g2_xend && (c6g2_ystart-bond_shift_y)<=y && y<=(c6g2_yend-bond_shift_y) )
chip_6_2 = true;
if ( c6_xstart<=x && x<=c6g3_xend && (c6g3_ystart-bond_shift_y)<=y && y<=(c6g3_yend-bond_shift_y) )
chip_6_3 = true;
}
}
uint16_t xmin_roi{}, xmax_roi{}, ymin_roi{}, ymax_roi{};
//[ chip, group, xmin, xmax, ymin, ymax ]
std::vector < std::tuple< int, int, uint16_t, uint16_t, uint16_t, uint16_t > > rois{};
if (chip_1_1) {
std::tie( xmin_roi, xmax_roi, ymin_roi, ymax_roi ) =
adjustROItoLimits( xmin, xmax, ymin, ymax,
c1g1_xstart, c1_xend, 0, c1g1_yend+bond_shift_y );
rois.push_back( std::make_tuple( 1, 1, xmin_roi, xmax_roi, ymin_roi, ymax_roi ) );
}
if (chip_1_2) {
std::tie( xmin_roi, xmax_roi, ymin_roi, ymax_roi ) =
adjustROItoLimits( xmin, xmax, ymin, ymax,
c1g2_xstart, c1_xend, c1g2_ystart+bond_shift_y, c1g2_yend+bond_shift_y );
rois.push_back( std::make_tuple( 1, 2, xmin_roi, xmax_roi, ymin_roi, ymax_roi ) );
}
if (chip_1_3) {
std::tie( xmin_roi, xmax_roi, ymin_roi, ymax_roi ) =
adjustROItoLimits( xmin, xmax, ymin, ymax,
c1g3_xstart, c1_xend, c1g3_ystart+bond_shift_y, c1g3_yend+bond_shift_y );
rois.push_back( std::make_tuple( 1, 3, xmin_roi, xmax_roi, ymin_roi, ymax_roi ) );
}
if (chip_6_3) {
std::tie( xmin_roi, xmax_roi, ymin_roi, ymax_roi ) =
adjustROItoLimits( xmin, xmax, ymin, ymax,
c6_xstart, c6g3_xend, c6g3_ystart-bond_shift_y, c6g3_yend-bond_shift_y );
rois.push_back( std::make_tuple( 6, 3, xmin_roi, xmax_roi, ymin_roi, ymax_roi ) );
}
if (chip_6_2) {
std::tie( xmin_roi, xmax_roi, ymin_roi, ymax_roi ) =
adjustROItoLimits( xmin, xmax, ymin, ymax,
c6_xstart, c6g2_xend, c6g2_ystart-bond_shift_y, c6g2_yend-bond_shift_y );
rois.push_back( std::make_tuple( 6, 2, xmin_roi, xmax_roi, ymin_roi, ymax_roi ) );
}
if (chip_6_1) {
std::tie( xmin_roi, xmax_roi, ymin_roi, ymax_roi ) =
adjustROItoLimits( xmin, xmax, ymin, ymax,
c6_xstart, c6g1_xend, c6g1_ystart-bond_shift_y, 511 );
rois.push_back( std::make_tuple( 6, 1, xmin_roi, xmax_roi, ymin_roi, ymax_roi ) );
}
return rois;
}
void remapROI(std::tuple< int, int, uint16_t, uint16_t, uint16_t, uint16_t > roi) {
void remapROI(uint16_t xmin, uint16_t xmax, uint16_t ymin, uint16_t ymax) {
// determine group and chip selected by ROI
int group, xmin, xmax, ymin, ymax;
std::tie( mchip, group, xmin, xmax, ymin, ymax ) = roi;
/*
int group;
if (ymax <= c1g1_yend + bond_shift_y) {
group = 1;
mchip = 1;
@ -358,17 +243,18 @@ class jungfrauLGADStrixelsData : public slsDetectorData<uint16_t> {
group = -1;
mchip = -1;
}
*/
int multiplicator = getMultiplicator(group);
setMappingShifts(group);
std::cout << "remapping chip: " << mchip << ", group: " << group << ", m: " << multiplicator
std::cout << "chip: " << mchip << ", group: " << group << ", m: " << multiplicator
<< ", x0: " << x0 << ", x1: " << x1 << ", y0: " << y0
<< ", y1: " << y1 << std::endl;
std::cout << "Adjusted roi: [" << xmin << ", " << xmax << ", " << ymin << ", " << ymax << "]" << std::endl;
// get ROI raw image number of columns
int nc_roi = xmax - xmin + 1;
std::cout << "nc_roi = " << nc_roi << std::endl;
// make sure loop bounds are correct
/*
if (y0 < ymin)
std::cout << "Error ymin" << std::endl;
if (y1 > ymax)
@ -378,7 +264,6 @@ class jungfrauLGADStrixelsData : public slsDetectorData<uint16_t> {
std::cout << "Error xmin" << std::endl;
if (x1 > xmax)
std::cout << "Error xmax" << std::endl;
*/
// remapping loop
int ix, iy = 0;
@ -392,10 +277,8 @@ class jungfrauLGADStrixelsData : public slsDetectorData<uint16_t> {
}
// if (iy< 40) cout << iy << " " << ix <<endl;
if ( ipx>=xmin && ipx<=xmax && ipy>=ymin && ipy <=ymax )
dataMap[iy][ix] =
sizeof(header) + (globalROI.nc * (ipy - globalROI.ymin) + (ipx - globalROI.xmin)) * 2;
else dataMap[iy][ix] = sizeof(header);
sizeof(header) + (nc_roi * (ipy - ymin) + (ipx - xmin)) * 2;
groupmap[iy][ix] = group - 1;
}
}
@ -424,31 +307,16 @@ class jungfrauLGADStrixelsData : public slsDetectorData<uint16_t> {
}
}
globalROI.xmin = xmin;
globalROI.xmax = xmax;
globalROI.ymin = ymin;
globalROI.ymax = ymax;
std::cout << "sizeofheader = " << sizeof(header) << std::endl;
std::cout << "Jungfrau strixels 2X single chip with full module data "
<< std::endl;
if (xmin < xmax && ymin < ymax) {
// get ROI raw image number of columns
globalROI.nc = xmax - xmin + 1;
std::cout << "nc_roi = " << globalROI.nc << std::endl;
dataSize =
(xmax - xmin + 1) * (ymax - ymin + 1) * 2 + sizeof(header);
std::cout << "datasize " << dataSize << std::endl;
//[ chip, group, xmin, xmax, ymin, ymax ]
auto rois = mapSubROIs(xmin, xmax, ymin, ymax);
//function to fill vector of rois from globalROI
for ( auto roi : rois )
remapROI(roi);
remapROI(xmin, xmax, ymin, ymax);
} else {

View File

@ -3,7 +3,6 @@
#ifndef JUNGFRAUMODULEDATA_H
#define JUNGFRAUMODULEDATA_H
#include <cstdint>
#include "sls/sls_detector_defs.h"
#include "slsDetectorData.h"
//#define VERSION_V2
@ -28,7 +27,7 @@ typedef struct {
uint64_t bunchNumber; /**< is the frame number */
uint64_t pre; /**< something */
} jf_header; //Aldo's header!
} jf_header;
using namespace std;
class jungfrauModuleData : public slsDetectorData<uint16_t> {
@ -43,56 +42,20 @@ class jungfrauModuleData : public slsDetectorData<uint16_t> {
1286 large etc.) \param c crosstalk parameter for the output buffer
*/
#ifdef ALDO
using header = jf_header;
#else
using header = sls::defs::sls_receiver_header;
#endif
#ifndef ZMQ
#define off sizeof(header)
#define off sizeof(jf_header)
#endif
#ifdef ZMQ
#define off 0
#endif
jungfrauModuleData(uint16_t xmin=0, uint16_t xmax=0,
uint16_t ymin=0, uint16_t ymax=0)
jungfrauModuleData()
: slsDetectorData<uint16_t>(1024, 512,
1024* 512 * 2 + off) {
for (int ix = 0; ix != 1024; ++ix) {
for (int iy = 0; iy != 512; ++iy) {
dataMap[iy][ix] = off;
}
}
if (xmin < xmax && ymin < ymax) {
int nc_roi = xmax - xmin + 1;
int nr_roi = ymax - ymin + 1;
std::cout << "nc_roi = " << nc_roi << std::endl;
std::cout << "nr_roi = " << nr_roi << std::endl;
dataSize =
(xmax - xmin + 1) * (ymax - ymin + 1) * 2 + off;
std::cout << "datasize " << dataSize << std::endl;
for (int ix = xmin; ix < xmax+1; ++ix) {
for (int iy = ymin; iy < ymax+1; ++iy) {
dataMap[iy][ix] = off + (nc_roi * iy + ix) * 2;
#ifdef HIGHZ
dataMask[iy][ix] = 0x3fff;
#endif
}
}
} else {
for (int ix = 0; ix < 1024; ++ix) {
for (int iy = 0; iy < 512; ++iy) {
for (int ix = 0; ix < 1024; ix++) {
for (int iy = 0; iy < 512; iy++) {
dataMap[iy][ix] = off + (1024 * iy + ix) * 2;
#ifdef HIGHZ
dataMask[iy][ix] = 0x3fff;
@ -100,7 +63,7 @@ class jungfrauModuleData : public slsDetectorData<uint16_t> {
}
}
}
iframe = 0;
@ -187,7 +150,7 @@ class jungfrauModuleData : public slsDetectorData<uint16_t> {
//int pn;
// cout << dataSize << endl;
//if (ff >= 0)
if (ff >= 0)
//fnum = ff;
if (filebin.is_open()) {

View File

@ -1,226 +0,0 @@
// SPDX-License-Identifier: LGPL-3.0-or-other
// Copyright (C) 2021 Contributors to the SLS Detector Package
#ifndef JUNGFRAUSINGLECHIPDATA_H
#define JUNGFRAUSINGLECHIPDATA_H
#include <cstdint>
#include "sls/sls_detector_defs.h"
#include "slsDetectorData.h"
//#define VERSION_V2
/**
@short structure for a Detector Packet or Image Header
@li frameNumber is the frame number
@li expLength is the subframe number (32 bit eiger) or real time exposure
time in 100ns (others)
@li packetNumber is the packet number
@li bunchId is the bunch id from beamline
@li timestamp is the time stamp with 10 MHz clock
@li modId is the unique module id (unique even for left, right, top, bottom)
@li xCoord is the x coordinate in the complete detector system
@li yCoord is the y coordinate in the complete detector system
@li zCoord is the z coordinate in the complete detector system
@li debug is for debugging purposes
@li roundRNumber is the round robin set number
@li detType is the detector type see :: detectorType
@li version is the version number of this structure format
*/
typedef struct {
uint64_t bunchNumber; /**< is the frame number */
uint64_t pre; /**< something */
} jf_header; //Aldo's header!
using namespace std;
class jungfrauSingleChipData : public slsDetectorData<uint16_t> {
private:
int iframe;
public:
/**
Implements the slsReceiverData structure for the moench02 prototype read
out by a module i.e. using the slsReceiver (160x160 pixels, 40 packets
1286 large etc.) \param c crosstalk parameter for the output buffer
*/
#ifdef ALDO
using header = jf_header;
#else
using header = sls::defs::sls_receiver_header;
#endif
#ifndef ZMQ
#define off sizeof(header)
#endif
#ifdef ZMQ
#define off 0
#endif
jungfrauSingleChipData(uint16_t xmin=0, uint16_t xmax=0,
uint16_t ymin=0, uint16_t ymax=0)
: slsDetectorData<uint16_t>(256, 256,
256* 256 * 2 + off) {
for (int ix = 0; ix != 256; ++ix) {
for (int iy = 0; iy != 256; ++iy) {
dataMap[iy][ix] = off;
}
}
if (xmin < xmax && ymin < ymax) {
int nc_roi = xmax - xmin + 1;
int nr_roi = ymax - ymin + 1;
std::cout << "nc_roi = " << nc_roi << std::endl;
std::cout << "nr_roi = " << nr_roi << std::endl;
dataSize =
(xmax - xmin + 1) * (ymax - ymin + 1) * 2 + off;
std::cout << "datasize " << dataSize << std::endl;
for (int ix = xmin; ix < xmax+1; ++ix) {
for (int iy = ymin; iy < ymax+1; ++iy) {
dataMap[iy][ix] = off + (nc_roi * iy + ix) * 2;
#ifdef HIGHZ
dataMask[iy][ix] = 0x3fff;
#endif
}
}
} else {
for (int ix = 0; ix < 256; ++ix) {
for (int iy = 0; iy < 256; ++iy) {
dataMap[iy][ix] = off + (256 * iy + ix) * 2;
#ifdef HIGHZ
dataMask[iy][ix] = 0x3fff;
#endif
}
}
}
iframe = 0;
// cout << "data struct created" << endl;
};
/**
Returns the value of the selected channel for the given dataset as
double. \param data pointer to the dataset (including headers etc) \param
ix pixel number in the x direction \param iy pixel number in the y
direction \returns data for the selected channel, with inversion if
required as double
*/
virtual double getValue(char *data, int ix, int iy = 0) {
uint16_t val = getChannel(data, ix, iy) & 0x3fff;
/* if (ix==0 && iy==0) */
/* cout << val << endl; */
return val;
};
/**
Returns the frame number for the given dataset. Purely virtual func.
\param buff pointer to the dataset
\returns frame number
*/
/* class jfrau_packet_header_t { */
/* public: */
/* unsigned char reserved[4]; */
/* unsigned char packetNumber[1]; */
/* unsigned char frameNumber[3]; */
/* unsigned char bunchid[8]; */
/* }; */
int getFrameNumber(char *buff) {
return ((jf_header *)buff)->bunchNumber;
};
/**
Returns the packet number for the given dataset. purely virtual func
\param buff pointer to the dataset
\returns packet number number
*/
int getPacketNumber(char *buff) {
return 0;
};
char *readNextFrame(ifstream &filebin) {
int ff = -1, np = -1;
return readNextFrame(filebin, ff, np);
};
char *readNextFrame(ifstream &filebin, int &ff) {
int np = -1;
return readNextFrame(filebin, ff, np);
};
char *readNextFrame(ifstream &filebin, int &ff, int &np) {
char *data = new char[dataSize];
char *d = readNextFrame(filebin, ff, np, data);
if (d == NULL) {
delete[] data;
data = NULL;
}
return data;
};
char *readNextFrame(ifstream &filebin, int &ff, int &np,char *data) {
//char *retval = 0;
//int nd;
//int fnum = -1;
np = 0;
//int pn;
// cout << dataSize << endl;
//if (ff >= 0)
//fnum = ff;
if (filebin.is_open()) {
if (filebin.read(data, dataSize)) {
ff = getFrameNumber(data);
np = getPacketNumber(data);
return data;
}
}
return NULL;
};
/**
Loops over a memory slot until a complete frame is found (i.e. all
packets 0 to nPackets, same frame number). purely virtual func \param
data pointer to the memory to be analyzed \param ndata reference to the
amount of data found for the frame, in case the frame is incomplete at
the end of the memory slot \param dsize size of the memory slot to be
analyzed \returns pointer to the beginning of the last good frame (might
be incomplete if ndata smaller than dataSize), or NULL if no frame is
found
*/
virtual char *findNextFrame(char *data, int &ndata, int dsize) {
if (dsize < dataSize)
ndata = dsize;
else
ndata = dataSize;
return data;
};
// int getPacketNumber(int x, int y) {return dataMap[y][x]/packetSize;};
};
#endif

View File

@ -54,10 +54,6 @@ class interpolatingDetector : public singlePhotonDetector {
pthread_mutex_init(fi, NULL);
};
/**
pointer-based copy constructor (cloner)
\param orig detector to be copied
*/
interpolatingDetector(interpolatingDetector *orig)
: singlePhotonDetector(orig) {
// if (orig->interp)
@ -70,28 +66,10 @@ class interpolatingDetector : public singlePhotonDetector {
fi = orig->fi;
}
/**
* copy constructor (deep copy)
* stricly, TODO: Implement Rule of Five!
* (copy op=, move ctor, and move op= would need to be defined)
*/
interpolatingDetector(interpolatingDetector const& other)
: singlePhotonDetector(other) {
interp = other.interp;
id = other.id;
fi = other.fi;
}
virtual interpolatingDetector *Clone() {
return new interpolatingDetector(this);
}
virtual interpolatingDetector *Copy() {
return new interpolatingDetector(*this);
}
virtual int setId(int i) {
id = i;
// interp->setId(id);

View File

@ -6,86 +6,18 @@
set(JUNGFRAU_EXECUTABLES)
#find_package(fmt REQUIRED)
#nlohmann_json
#If the library was INSTALLED (i.e. sudo dnf install nlohmann-json3-dev), do stuff described in the repo under CMake -> External
#find_package(nlohmann_json 3.2.0 REQUIRED)
#find_package(nlohmann_json 3.11.2 REQUIRED)
#find_package(nlohmann_json 3.11.3 REQUIRED)
#
#If the library was not installed but just cloned from https://github.com/nlohmann/json.git (possible, because it is a header-only library),
# do stuff described in the repo under CMake -> Embedded
#set(JSON_BuildTests OFF CACHE INTERNAL "")
# If you only include this third party in PRIVATE source files, you do not
# need to install it when your main project gets installed.
# set(JSON_Install OFF CACHE INTERNAL "")
#add_subdirectory(nlohmann_json) #Put the actual path to json
#
#Alternative: Fetch and install it from remote
include(FetchContent)
FetchContent_Declare(
json
GIT_REPOSITORY https://github.com/nlohmann/json.git
GIT_TAG v3.11.3 # Replace with the version you need
)
#FetchContent_Declare(json URL https://github.com/nlohmann/json/releases/download/v3.11.3/json.tar.xz) #Alternative (from the repo documentation)
FetchContent_MakeAvailable(json)
FetchContent_Declare(
fmt
GIT_REPOSITORY https://github.com/fmtlib/fmt.git
GIT_TAG master
)
FetchContent_MakeAvailable(fmt)
# HDF5 file writing
if (SLS_USE_HDF5)
find_package(HDF5 1.10 COMPONENTS CXX REQUIRED)
list (APPEND SOURCES
HDF5File.cpp
)
endif (SLS_USE_HDF5)
find_package(fmt REQUIRED)
# jungfrauRawDataProcess
add_executable(jungfrauRawDataProcess jungfrauRawDataProcess.cpp)
target_compile_definitions(jungfrauRawDataProcess PRIVATE MODULE)
list(APPEND JUNGFRAU_EXECUTABLES jungfrauRawDataProcess)
# jungfrauRawDataProcessChipAldo
add_executable(jungfrauRawDataProcessChipAldo jungfrauRawDataProcess_filetxt.cpp)
target_compile_definitions(jungfrauRawDataProcessChipAldo PRIVATE CHIP ALDO)
list(APPEND JUNGFRAU_EXECUTABLES jungfrauRawDataProcessChipAldo)
# jungfrauRawDataProcessStrx
add_executable(jungfrauRawDataProcessStrx jungfrauRawDataProcess_filetxt.cpp)
target_compile_definitions(jungfrauRawDataProcessStrx PRIVATE JFSTRX)
list(APPEND JUNGFRAU_EXECUTABLES jungfrauRawDataProcessStrx)
# jungfrauRawDataProcessStrxQuad
add_executable(jungfrauRawDataProcessStrxQuad jungfrauRawDataProcess_filetxt.cpp)
target_compile_definitions(jungfrauRawDataProcessStrxQuad PRIVATE JFSTRXQ)
list(APPEND JUNGFRAU_EXECUTABLES jungfrauRawDataProcessStrxQuad)
# jungfrauRawDataProcessStrxQuadH5
# HDF5
if (SLS_USE_HDF5)
if (HDF5_FOUND)
add_executable(jungfrauRawDataProcessStrxQuadH5 jungfrauRawDataProcess_filetxtH5.cpp)
#target_compile_definitions(jungfrauRawDataProcessStrxQuadH5 PRIVATE JFSTRXQH5)
list(APPEND JUNGFRAU_EXECUTABLES jungfrauRawDataProcessStrxQuadH5)
target_include_directories(jungfrauRawDataProcessStrxQuadH5 PRIVATE ${HDF5_INCLUDE_DIRS} ${CMAKE_INSTALL_PREFIX}/include)
target_link_libraries(jungfrauRawDataProcessStrxQuadH5 PRIVATE ${HDF5_LIBRARIES})
add_executable(jungfrauRawDataProcessStrxQuadH5SC jungfrauRawDataProcess_filetxtH5_SC.cpp)
#target_compile_definitions(jungfrauRawDataProcessStrxQuadH5 PRIVATE JFSTRXQH5)
list(APPEND JUNGFRAU_EXECUTABLES jungfrauRawDataProcessStrxQuadH5SC)
target_include_directories(jungfrauRawDataProcessStrxQuadH5SC PRIVATE ${HDF5_INCLUDE_DIRS} ${CMAKE_INSTALL_PREFIX}/include)
target_link_libraries(jungfrauRawDataProcessStrxQuadH5SC PRIVATE ${HDF5_LIBRARIES})
endif ()
endif (SLS_USE_HDF5)
# jungfrauRawDataProcessStrxChip1
add_executable(jungfrauRawDataProcessStrxChip1 jungfrauRawDataProcess.cpp)
@ -126,22 +58,6 @@ list(APPEND JUNGFRAU_EXECUTABLES jungfrauRawDataProcessStrxOldAldo)
# others to be added if needed (might already be there in Makefile.cluster_finder TO BE CHECKED)
if (SLS_USE_HDF5)
if (HDF5_FOUND)
target_include_directories(jungfrauRawDataProcessStrxQuadH5 PRIVATE
${HDF5_INCLUDE_DIRS}
${CMAKE_INSTALL_PREFIX}/include
)
target_link_libraries(jungfrauRawDataProcessStrxQuadH5 PRIVATE ${HDF5_LIBRARIES})
target_include_directories(jungfrauRawDataProcessStrxQuadH5SC PRIVATE
${HDF5_INCLUDE_DIRS}
${CMAKE_INSTALL_PREFIX}/include
)
target_link_libraries(jungfrauRawDataProcessStrxQuadH5SC PRIVATE ${HDF5_LIBRARIES})
endif ()
endif (SLS_USE_HDF5)
foreach(exe ${JUNGFRAU_EXECUTABLES})
@ -151,16 +67,11 @@ foreach(exe ${JUNGFRAU_EXECUTABLES})
../interpolations
../dataStructures
../interpolations/etaVEL
../../slsSupportLib/include/sls/
../../slsSupportLib/include/
../../slsReceiverSoftware/include/
../tiffio/include
${fmt_INCLUDE_DIRS}
)
# if (SLS_USE_HDF5)
# if (HDF5_FOUND)
# target_include_directories(${exe} PRIVATE ${HDF5_INCLUDE_DIRS} ${CMAKE_INSTALL_PREFIX}/include)
# endif ()
# endif (SLS_USE_HDF5)
target_link_libraries(${exe}
PUBLIC
@ -168,7 +79,6 @@ foreach(exe ${JUNGFRAU_EXECUTABLES})
pthread
tiffio
fmt::fmt
nlohmann_json::nlohmann_json
#-L/usr/lib64/
#-lm -lstdc++ -lrt
@ -176,11 +86,7 @@ foreach(exe ${JUNGFRAU_EXECUTABLES})
slsProjectWarnings
slsProjectOptions
)
# if (SLS_USE_HDF5)
# if (HDF5_FOUND)
# target_link_libraries(${exe} PRIVATE ${HDF5_LIBRARIES})
# endif ()
# endif (SLS_USE_HDF5)
set_target_properties(${exe} PROPERTIES
RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin
@ -192,8 +98,4 @@ foreach(exe ${JUNGFRAU_EXECUTABLES})
endforeach(exe ${JUNGFRAU_EXECUTABLES})
install(TARGETS ${JUNGFRAU_EXECUTABLES} DESTINATION bin)

View File

@ -11,7 +11,7 @@
#define RAWDATA
#if !defined JFSTRX && !defined JFSTRXOLD && !defined JFSTRXCHIP1 && \
!defined JFSTRXCHIP6 && !defined CHIP
!defined JFSTRXCHIP6
#ifndef MODULE
#include "jungfrauHighZSingleChipData.h"
#endif
@ -20,10 +20,6 @@
#endif
#endif
#ifdef CHIP
#include "jungfrauSingleChipData.h"
#endif
#ifdef JFSTRX
#include "jungfrauLGADStrixelsData_new.h"
#endif
@ -45,9 +41,6 @@
#include <ctime>
#include <fmt/core.h>
#include <nlohmann/json.hpp>
using json = nlohmann::json;
std::string getRootString( const std::string& filepath ) {
size_t pos1 = filepath.find_last_of("/");
@ -68,24 +61,20 @@ std::string getRootString( const std::string& filepath ) {
std::string createFileName( const std::string& dir, const std::string& fprefix="run", const std::string& fsuffix="", const std::string& fext="raw", int aindex=0, int mindex=0, int findex=0, int outfilecounter=-1 ) {
if (outfilecounter >= 0)
return fmt::format("{:s}/{:s}_d{:d}_f{:d}_{:d}_f{:05d}.{:s}", dir, fprefix, mindex, findex, aindex, outfilecounter, fext);
else if (fsuffix.length()!=0) {
if (fsuffix == "master")
return fmt::format("{:s}/{:s}_master_{:d}.{:s}", dir, fprefix, aindex, fext);
else
else if (fsuffix.length()!=0)
return fmt::format("{:s}/{:s}_{:s}.{:s}", dir, fprefix, fsuffix, fext);
}
else
return fmt::format("{:s}/{:s}_d{:d}_f{:d}_{:d}.{:s}", dir, fprefix, mindex, findex, aindex, fext);
}
int main(int argc, char *argv[]) {
if (argc < 6) {
if (argc < 5) {
std::cout
<< "Usage is " << argv[0]
<< "indir outdir [fprefix(excluding slsDetector standard suffixes and extension)] [fextension] "
"[fmin] [fmax] [runmin] [runmax] [pedfile (raw or tiff)] [threshold] "
"[nframes] [xmin xmax ymin ymax] [optional: bool read rxroi from data file header] [gainmap]"
<< "indir outdir fprefix(excluding slsDetector standard suffixes and extension) fextension "
"[runmin] [runmax] [pedfile (raw or tiff)] [threshold] "
"[nframes] [xmin xmax ymin ymax] [gainmap]"
<< std::endl;
std::cout
<< "threshold <0 means analog; threshold=0 means cluster finder; "
@ -117,95 +106,58 @@ int main(int argc, char *argv[]) {
std::string outdir(argv[2]);
std::string fprefix(argv[3]);
std::string fext(argv[4]);
int fmin = 0;
if (argc >= 6)
fmin = atoi(argv[5]);
int fmax = fmin;
if (argc >= 7)
fmax = atoi(argv[6]);
int runmin = 0;
// cout << "argc is " << argc << endl;
if (argc >= 8) {
runmin = atoi(argv[7]);
if (argc >= 6) {
runmin = atoi(argv[5]);
}
int runmax = runmin;
if (argc >= 9) {
runmax = atoi(argv[8]);
if (argc >= 7) {
runmax = atoi(argv[6]);
}
std::string pedfilename{};
if (argc >= 10) {
pedfilename = argv[9];
if (argc >= 8) {
pedfilename = argv[7];
}
double thr = 0;
double thr1 = 1;
if (argc >= 11) {
thr = atof(argv[10]);
if (argc >= 9) {
thr = atof(argv[8]);
}
int nframes = 0;
if (argc >= 12) {
nframes = atoi(argv[11]);
}
bool readrxroifromdatafile = false;
if (argc >= 17)
readrxroifromdatafile = atoi(argv[16]);
// Receiver ROI
uint16_t rxroi_xmin = 0;
uint16_t rxroi_xmax = 0;
uint16_t rxroi_ymin = 0;
uint16_t rxroi_ymax = 0;
{ //protective scope so ifstream gets destroyed properly
auto jsonmastername = createFileName( indir, fprefix, "master", "json", runmin );
std::cout << "json master file " << jsonmastername << std::endl;
std::ifstream masterfile(jsonmastername); //, ios::in | ios::binary);
if (masterfile.is_open()) {
json j;
masterfile >> j;
rxroi_xmin = j["Receiver Roi"]["xmin"];
rxroi_xmax = j["Receiver Roi"]["xmax"];
rxroi_ymin = j["Receiver Roi"]["ymin"];
rxroi_ymax = j["Receiver Roi"]["ymax"];
masterfile.close();
std::cout << "Read Receiver ROI [" << rxroi_xmin << ", " << rxroi_xmax << ", "
<< rxroi_ymin << ", " << rxroi_ymax << "] from json master file" << std::endl;
} else
std::cout << "Could not open master file " << jsonmastername << std::endl;
if (argc >= 10) {
nframes = atoi(argv[9]);
}
// Define decoders...
#if !defined JFSTRX && !defined JFSTRXOLD && !defined JFSTRXCHIP1 && \
!defined JFSTRXCHIP6 && !defined CHIP
!defined JFSTRXCHIP6
#ifndef MODULE
jungfrauHighZSingleChipData *decoder = new jungfrauHighZSingleChipData();
int nx = 256, ny = 256;
#endif
#ifdef MODULE
jungfrauModuleData *decoder = new jungfrauModuleData(rxroi_xmin, rxroi_xmax, rxroi_ymin, rxroi_ymax);
jungfrauModuleData *decoder = new jungfrauModuleData();
int nx = 1024, ny = 512;
#endif
#endif
#ifdef CHIP
std::cout << "Jungfrau pixel module single chip readout" << std::endl;
jungfrauSingleChipData *decoder = new jungfrauSingleChipData();
int nx = 256, ny = 256;
#endif
#ifdef JFSTRX
std::cout << "Jungfrau strixel full module readout" << std::endl;
cout << "Jungfrau strixel full module readout" << endl;
// ROI
uint16_t xxmin = 0;
uint16_t xxmax = 0;
uint16_t yymin = 0;
uint16_t yymax = 0;
#ifndef ALDO
if (readrxroifromdatafile)
{ //THIS SCOPE IS IMPORTANT! (To ensure proper destruction of ifstream)
using header = sls::defs::sls_receiver_header;
// check if there is a roi in the header
@ -228,10 +180,10 @@ int main(int argc, char *argv[]) {
memcpy(&croi, &hbuffer.detHeader.detSpec1, 8);
std::cout << "Read ROI [" << croi.xmin << ", " << croi.xmax << ", "
<< croi.ymin << ", " << croi.ymax << "]" << std::endl;
rxroi_xmin = croi.xmin;
rxroi_xmax = croi.xmax;
rxroi_ymin = croi.ymin;
rxroi_ymax = croi.ymax;
xxmin = croi.xmin;
xxmax = croi.xmax;
yymin = croi.ymin;
yymax = croi.ymax;
} else
std::cout << "reading error" << std::endl;
firstfile.close();
@ -241,7 +193,7 @@ int main(int argc, char *argv[]) {
#endif
jungfrauLGADStrixelsData *decoder =
new jungfrauLGADStrixelsData(rxroi_xmin, rxroi_xmax, rxroi_ymin, rxroi_ymax);
new jungfrauLGADStrixelsData(xxmin, xxmax, yymin, yymax);
int nx = 1024 / 3, ny = 512 * 5;
#endif
#ifdef JFSTRXCHIP1
@ -266,20 +218,19 @@ int main(int argc, char *argv[]) {
decoder->getDetectorSize(nx, ny);
std::cout << "Detector size is " << nx << " " << ny << std::endl;
//Cluster finder ROI
int xmin = 0, xmax = nx-1, ymin = 0, ymax = ny-1;
if (argc >= 16) {
xmin = atoi(argv[12]);
xmax = atoi(argv[13]);
ymin = atoi(argv[14]);
ymax = atoi(argv[15]);
int xmin = 0, xmax = nx, ymin = 0, ymax = ny;
if (argc >= 14) {
xmin = atoi(argv[10]);
xmax = atoi(argv[11]);
ymin = atoi(argv[12]);
ymax = atoi(argv[13]);
}
std::cout << "Cluster finder ROI: [" << xmin << ", " << xmax << ", " << ymin << ", " << ymax << "]"
std::cout << xmin << " " << xmax << " " << ymin << " " << ymax << " "
<< std::endl;
char *gainfname = NULL;
if (argc > 17) {
gainfname = argv[17];
if (argc > 14) {
gainfname = argv[14];
std::cout << "Gain map file name is: " << gainfname << std::endl;
}
@ -288,8 +239,6 @@ int main(int argc, char *argv[]) {
std::cout << "input directory is " << indir << std::endl;
std::cout << "output directory is " << outdir << std::endl;
std::cout << "input file prefix is " << fprefix << std::endl;
std::cout << "fmin is " << fmin << std::endl;
std::cout << "fmax is " << fmax << std::endl;
std::cout << "runmin is " << runmin << std::endl;
std::cout << "runmax is " << runmax << std::endl;
if (pedfilename.length()!=0)
@ -370,7 +319,7 @@ int main(int argc, char *argv[]) {
mt->setFrameMode(ePedestal);
std::ifstream pedefile(fname, ios::in | ios::binary);
ifstream pedefile(fname, ios::in | ios::binary);
// //open file
if (pedefile.is_open()) {
std::cout << "bbbb " << std::ctime(&end_time) << std::endl;
@ -431,27 +380,26 @@ int main(int argc, char *argv[]) {
}
ifr = 0;
int ioutfile = 0;
int ifile = 0;
mt->setFrameMode(eFrame);
FILE *of = NULL;
for (int irun = runmin; irun <= runmax; ++irun) {
for (int ifile = fmin; ifile <= fmax; ++ifile) {
for (int irun = runmin; irun <= runmax; irun++) {
std::cout << "DATA ";
std::string fsuffix{};
auto fname = createFileName( indir, fprefix, fsuffix, fext, irun, 0, ifile );
auto imgfname = createFileName( outdir, fprefix, fsuffix, "tiff", irun, 0, ifile );
auto cfname = createFileName( outdir, fprefix, fsuffix, "clust", irun, 0, ifile );
auto fname = createFileName( indir, fprefix, fsuffix, fext, irun );
auto imgfname = createFileName( outdir, fprefix, fsuffix, "tiff", irun );
auto cfname = createFileName( outdir, fprefix, fsuffix, "clust", irun );
std::cout << fname << " ";
std::cout << imgfname << std::endl;
std::time(&end_time);
std::cout << std::ctime(&end_time) << std::endl;
// std::cout << fname << " " << outfname << " " << imgfname << std::endl;
std::ifstream filebin(fname, ios::in | ios::binary);
ifstream filebin(fname, ios::in | ios::binary);
// //open file
ioutfile = 0;
ifile = 0;
if (filebin.is_open()) {
if (thr <= 0 && cf != 0) { // cluster finder
if (of == NULL) {
@ -488,10 +436,10 @@ int main(int argc, char *argv[]) {
std::cout << " " << ifr << " " << ff << std::endl;
if (nframes > 0) {
if (ifr % nframes == 0) {
imgfname = createFileName( outdir, fprefix, fsuffix, "tiff", irun, 0, 0, ioutfile );
imgfname = createFileName( outdir, fprefix, fsuffix, "tiff", irun, 0, 0, ifile );
mt->writeImage(imgfname.c_str(), thr1);
mt->clearImage();
ioutfile++;
ifile++;
}
}
// } else
@ -505,7 +453,7 @@ int main(int argc, char *argv[]) {
}
if (nframes >= 0) {
if (nframes > 0)
imgfname = createFileName( outdir, fprefix, fsuffix, "tiff", irun, 0, 0, ioutfile );
imgfname = createFileName( outdir, fprefix, fsuffix, "tiff", irun, 0, 0, ifile );
std::cout << "Writing tiff to " << imgfname << " " << thr1
<< std::endl;
mt->writeImage(imgfname.c_str(), thr1);
@ -522,9 +470,8 @@ int main(int argc, char *argv[]) {
std::cout << "Could not open " << fname << " for reading "
<< std::endl;
}
}
if (nframes < 0) {
auto imgfname = createFileName( outdir, fprefix, "sum", "tiff", runmin, 0, fmin, -1 );
auto imgfname = createFileName( outdir, fprefix, "sum", "tiff", -1, 0, 0, -1 );
std::cout << "Writing tiff to " << imgfname << " " << thr1 << std::endl;
mt->writeImage(imgfname.c_str(), thr1);
}

View File

@ -10,8 +10,8 @@
#define RAWDATA
#if !defined JFSTRX && !defined JFSTRXQ && !defined JFSTRXOLD && !defined JFSTRXCHIP1 && \
!defined JFSTRXCHIP6 && !defined CHIP
#if !defined JFSTRX && !defined JFSTRXOLD && !defined JFSTRXCHIP1 && \
!defined JFSTRXCHIP6
#ifndef MODULE
#include "jungfrauHighZSingleChipData.h"
#endif
@ -20,16 +20,9 @@
#endif
#endif
#ifdef CHIP
#include "jungfrauSingleChipData.h"
#endif
#ifdef JFSTRX
#include "jungfrauLGADStrixelsData_new.h"
#endif
#ifdef JFSTRXQ
#include "jungfrauLGADStrixelsDataQuad.h"
#endif
#if defined JFSTRXCHIP1 || defined JFSTRXCHIP6
#include "jungfrauLGADStrixelsDataSingleChip.h"
#endif
@ -48,9 +41,6 @@
#include <ctime>
#include <fmt/core.h>
#include <nlohmann/json.hpp>
using json = nlohmann::json;
std::string getRootString( const std::string& filepath ) {
size_t pos1;
@ -81,11 +71,11 @@ std::string createFileName( const std::string& dir, const std::string& fprefix="
//NOTE THAT THE DATA FILES HAVE TO BE IN THE RIGHT ORDER SO THAT PEDESTAL TRACKING WORKS!
int main(int argc, char *argv[]) {
if (argc < 11) {
if (argc < 10) {
std::cout
<< "Usage is " << argv[0]
<< " filestxt outdir [json master] [pedfile (raw or tiff)] [xmin xmax ymin ymax] "
"[threshold] [nframes] [optional: bool read rxroi from data file header]"
<< " filestxt outdir [pedfile (raw or tiff)] [xmin xmax ymin ymax] "
"[threshold] [nframes] "
"NOTE THAT THE DATA FILES HAVE TO BE IN THE RIGHT ORDER SO THAT PEDESTAL TRACKING WORKS! "
<< std::endl;
std::cout
@ -115,19 +105,19 @@ int main(int argc, char *argv[]) {
const std::string txtfilename(argv[1]);
const std::string outdir(argv[2]);
const std::string jsonmastername(argv[3]);
const std::string pedfilename(argv[4]);
const std::string pedfilename(argv[3]);
int xmin = atoi(argv[4]);
int xmax = atoi(argv[5]);
int ymin = atoi(argv[6]);
int ymax = atoi(argv[7]);
double thr = 0;
double thr1 = 1;
thr = atof(argv[9]);
thr = atof(argv[8]);
int nframes = 0;
nframes = atoi(argv[10]);
bool readrxroifromdatafile = false;
if (argc > 11)
readrxroifromdatafile = atoi(argv[11]);
nframes = atoi(argv[9]);
//Get vector of filenames from input txt-file
std::vector<std::string> filenames{};
@ -157,33 +147,9 @@ int main(int argc, char *argv[]) {
std::cout << "###############" << std::endl;
// Receiver ROI
uint16_t rxroi_xmin = 0;
uint16_t rxroi_xmax = 0;
uint16_t rxroi_ymin = 0;
uint16_t rxroi_ymax = 0;
{ //protective scope so ifstream gets destroyed properly
std::ifstream masterfile(jsonmastername); //, ios::in | ios::binary);
if (masterfile.is_open()) {
json j;
masterfile >> j;
rxroi_xmin = j["Receiver Roi"]["xmin"];
rxroi_xmax = j["Receiver Roi"]["xmax"];
rxroi_ymin = j["Receiver Roi"]["ymin"];
rxroi_ymax = j["Receiver Roi"]["ymax"];
masterfile.close();
std::cout << "Read rxROI [" << rxroi_xmin << ", " << rxroi_xmax << ", "
<< rxroi_ymin << ", " << rxroi_ymax << "]" << std::endl;
} else
std::cout << "Could not open master file " << jsonmastername << std::endl;
}
// Define decoders...
#if !defined JFSTRX && !defined JFSTRXQ && !defined JFSTRXOLD && !defined JFSTRXCHIP1 && \
!defined JFSTRXCHIP6 && !defined CHIP
#if !defined JFSTRX && !defined JFSTRXOLD && !defined JFSTRXCHIP1 && \
!defined JFSTRXCHIP6
#ifndef MODULE
jungfrauHighZSingleChipData *decoder = new jungfrauHighZSingleChipData();
int nx = 256, ny = 256;
@ -194,17 +160,15 @@ int main(int argc, char *argv[]) {
#endif
#endif
#ifdef CHIP
std::cout << "Jungfrau pixel module single chip readout" << std::endl;
jungfrauSingleChipData *decoder = new jungfrauSingleChipData();
int nx = 256, ny = 256;
#endif
#ifdef JFSTRX
std::cout << "Jungfrau strixel full module readout" << std::endl;
cout << "Jungfrau strixel full module readout" << endl;
// ROI
uint16_t xxmin = 0;
uint16_t xxmax = 0;
uint16_t yymin = 0;
uint16_t yymax = 0;
#ifndef ALDO
if (readrxroifromdatafile)
{ //THIS SCOPE IS IMPORTANT! (To ensure proper destruction of ifstream)
using header = sls::defs::sls_receiver_header;
// check if there is a roi in the header
@ -218,7 +182,7 @@ int main(int argc, char *argv[]) {
//std::string filepath(argv[9]); //This is a problem if the input files have different ROIs!
std::cout << "Reading header of file " << filenames[0] << " to check for ROI "
<< std::endl;
std::ifstream firstfile( filenames[0], ios::in | ios::binary);
ifstream firstfile(filenames[0], ios::in | ios::binary);
if (firstfile.is_open()) {
header hbuffer;
std::cout << "sizeof(header) = " << sizeof(header) << std::endl;
@ -226,10 +190,10 @@ int main(int argc, char *argv[]) {
memcpy(&croi, &hbuffer.detHeader.detSpec1, 8);
std::cout << "Read ROI [" << croi.xmin << ", " << croi.xmax << ", "
<< croi.ymin << ", " << croi.ymax << "]" << std::endl;
rxroi_xmin = croi.xmin;
rxroi_xmax = croi.xmax;
rxroi_ymin = croi.ymin;
rxroi_ymax = croi.ymax;
xxmin = croi.xmin;
xxmax = croi.xmax;
yymin = croi.ymin;
yymax = croi.ymax;
} else
std::cout << "reading error" << std::endl;
firstfile.close();
@ -239,15 +203,9 @@ int main(int argc, char *argv[]) {
#endif
jungfrauLGADStrixelsData *decoder =
new jungfrauLGADStrixelsData(rxroi_xmin, rxroi_xmax, rxroi_ymin, rxroi_ymax);
new jungfrauLGADStrixelsData(xxmin, xxmax, yymin, yymax);
int nx = 1024 / 3, ny = 512 * 5;
#endif
#ifdef JFSTRXQ
std::cout << "Jungfrau strixel quad" << std::endl;
jungfrauLGADStrixelsDataQuad *decoder =
new jungfrauLGADStrixelsDataQuad(rxroi_xmin, rxroi_xmax, rxroi_ymin, rxroi_ymax);
int nx = 1024 / 3, ny = 512 * 3;
#endif
#ifdef JFSTRXCHIP1
std::cout << "Jungfrau strixel LGAD single chip 1" << std::endl;
jungfrauLGADStrixelsDataSingleChip *decoder =
@ -270,16 +228,7 @@ int main(int argc, char *argv[]) {
decoder->getDetectorSize(nx, ny);
std::cout << "Detector size is " << nx << " " << ny << std::endl;
//Cluster finder ROI
int xmin = 0, xmax = nx-1, ymin = 0, ymax = ny-1;
xmin = atoi(argv[5]);
xmax = atoi(argv[6]);
ymin = atoi(argv[7]);
ymax = atoi(argv[8]);
std::cout << "Cluster finder ROI: [" << xmin << ", " << xmax << ", " << ymin << ", " << ymax << "]"
<< std::endl;
/* old
if ( xmin == xmax ) {
xmin = 0;
xmax = nx;
@ -290,7 +239,6 @@ int main(int argc, char *argv[]) {
}
std::cout << xmin << " " << xmax << " " << ymin << " " << ymax << " "
<< std::endl;
*/
/*
char *gainfname = NULL;
@ -462,7 +410,7 @@ int main(int argc, char *argv[]) {
std::time(&end_time);
std::cout << std::ctime(&end_time) << std::endl;
std::ifstream filebin(filenames[ifile], ios::in | ios::binary);
ifstream filebin(filenames[ifile], ios::in | ios::binary);
// //open file
ioutfile = 0;
if (filebin.is_open()) {

View File

@ -1,457 +0,0 @@
// SPDX-License-Identifier: LGPL-3.0-or-other
// Copyright (C) 2021 Contributors to the SLS Detector Package
// #include "sls/ansi.h"
//#include <iostream>
#undef CORR
#define C_GHOST 0.0004
#define CM_ROWS 50
#define RAWDATA
#include "jungfrauLGADStrixelsDataQuadH5.h"
#include "multiThreadedCountingDetector.h"
#include "singlePhotonDetector.h"
#include <fstream>
#include <map>
#include <memory>
#include <stdio.h>
#include <sys/stat.h>
#include <ctime>
#include <fmt/core.h>
/*
#include <nlohmann/json.hpp>
using json = nlohmann::json;
*/
/*Dataset paths according to different beamlines*/
std::string const data_datasetname_furka("/data/JF18T01V01/data");
std::string const index_datasetname_furka("/data/JF18T01V01/frame_index");
std::string const data_datasetname_xfelSCS("/INSTRUMENT/SCS_HRIXS_JUNGF/DET/JNGFR01:daqOutput/data/adc");
std::string const index_datasetname_xfelSCS("/INSTRUMENT/SCS_HRIXS_JUNGF/DET/JNGFR01:daqOutput/data/frameNumber");
std::string getRootString( std::string const& filepath ) {
size_t pos1;
if (filepath.find("/") == std::string::npos )
pos1 = 0;
else
pos1 = filepath.find_last_of("/")+1;
size_t pos2 = filepath.find_last_of(".");
//std::cout << "pos1 " << pos1 << " pos2 " << pos2 << " size " << filepath.length() << std::endl;
return filepath.substr( pos1, pos2-pos1 );
}
//Create file name string
// dir: directory
// fprefix: fileprefix (without extension)
// fsuffix: filesuffix (for output files, e.g. "ped")
// fext: file extension (e.g. "raw")
std::string createFileName( std::string const& dir, std::string const& fprefix="run",
std::string const& fsuffix="", std::string const& fext="raw", int const outfilecounter=-1 ) {
std::string return_string;
if (outfilecounter >= 0)
return_string = fmt::format("{:s}/{:s}_{:s}_f{:05d}", dir, fprefix, fsuffix, outfilecounter);
else if (fsuffix.length()!=0)
return_string = fmt::format("{:s}/{:s}_{:s}", dir, fprefix, fsuffix);
else
return_string = fmt::format("{:s}/{:s}", dir, fprefix);
if (fext.length()!=0)
return_string += "." + fext;
return return_string;
}
//NOTE THAT THE DATA FILES HAVE TO BE IN THE RIGHT ORDER SO THAT PEDESTAL TRACKING WORKS!
int main(int argc, char *argv[]) {
if (argc < 4) {
std::cout
<< "Usage is " << argv[0]
<< " filestxt outdir [pedfile (h5)] "
" optional: [int dataset path; 0 means Furka, 1 means XFEL; overwrites default given in HDF5File.h] "
" [bool validate h5 rank] "
" [xmin xmax ymin ymax] [threshold] [nframes] "
" NOTE THAT THE DATA FILES HAVE TO BE IN THE RIGHT ORDER SO THAT PEDESTAL TRACKING WORKS! "
<< std::endl;
std::cout
<< "threshold <0 means analog; threshold=0 means cluster finder; "
"threshold>0 means photon counting"
<< std::endl;
std::cout
<< "nframes <0 means sum everything; nframes=0 means one file per "
"run; nframes>0 means one file every nframes"
<< std::endl;
return 1;
}
int const fifosize = 100; //1000;
int const nthreads = 10;
int const csize = 3; // 3
int const nsigma = 5;
int const nped = 10000;
int cf = 0;
std::string const txtfilename(argv[1]);
std::string const outdir(argv[2]);
std::string const pedfilename(argv[3]);
std::string datasetpath{};
std::string frameindexpath{};
if (argc > 4) {
switch (atoi(argv[4])) {
case 0:
datasetpath = data_datasetname_furka;
frameindexpath = index_datasetname_furka;
break;
case 1:
datasetpath = data_datasetname_xfelSCS;
frameindexpath = index_datasetname_xfelSCS;
break;
default:
break;
}
}
bool validate_rank=true;
if (argc > 5)
validate_rank = atoi(argv[5]);
double thr = 0;
double thr1 = 1;
if (argc > 9)
thr = atof(argv[9]);
int nframes = 0;
if (argc > 10)
nframes = atoi(argv[10]);
//Get vector of filenames from input txt-file
std::vector<std::string> filenames{};
//filenames.reserve(512);
{ //Safety scope for ifstream
ifstream inputs( txtfilename, std::ios::in );
if (inputs.is_open()) {
std::cout << "Reading imput filenames from txt-file ..." << std::endl;
std::string line{};
while (!inputs.eof()) {
std::getline(inputs, line);
if(line.find(".h5") != std::string::npos) {
filenames.emplace_back(line);
std::cout << line << std::endl; //" line.max_size() " << line.max_size() << " filenames.capacity() " << filenames.capacity() << '\n';
}
}
inputs.close();
std::cout << "---- Reached end of txt-file. ----" << std::endl;
} else
std::cout << "Could not open " << txtfilename << std::endl;
if (filenames.size()>0) {
std::cout << filenames.size() << " filenames found in " << txtfilename << std::endl;
std::cout << "The files will be processed in the same order as found in the txt-file." << std::endl;
} else {
std::cout << "No files found in txt-file!" << std::endl;
return 1;
}
}
std::cout << "###############" << std::endl;
// Define decoder
std::cout << "Jungfrau strixel quad h5" << std::endl;
jungfrauLGADStrixelsDataQuadH5* decoder = new jungfrauLGADStrixelsDataQuadH5();
//auto decoder = std::make_unique<jungfrauLGADStrixelsDataQuadH5>();
int nx = 1024 / 3, ny = 512 * 3;
//Cluster finder ROI
int xmin = 0, xmax = nx-1, ymin = 0, ymax = ny-1;
if (argc > 9) {
xmin = atoi(argv[6]);
xmax = atoi(argv[7]);
ymin = atoi(argv[8]);
ymax = atoi(argv[9]);
}
std::cout << "Cluster finder ROI: [" << xmin << ", " << xmax << ", " << ymin << ", " << ymax << "]"
<< std::endl;
decoder->getDetectorSize(nx, ny);
std::cout << "Detector size is " << nx << " " << ny << std::endl;
std::time_t end_time;
std::cout << "output directory is " << outdir << std::endl;
if (pedfilename.length()!=0)
std::cout << "pedestal file is " << pedfilename << std::endl;
if (thr > 0)
std::cout << "threshold is " << thr << std::endl;
std::cout << "Nframes is " << nframes << std::endl;
uint32_t nnx, nny;
singlePhotonDetector* filter =
new singlePhotonDetector(decoder, 3, nsigma, 1, NULL, nped, 200, -1, -1, NULL, NULL);
//auto filter = std::make_unique<singlePhotonDetector>(decoder.get(), 3, nsigma, 1, nullptr, nped, 200, -1, -1, nullptr, nullptr);
thr = 0.15 * thr;
//filter->newDataSet(); //This only initializes the dataset for the first thread (the other threads are created via cloning)
// int dsize = decoder->getDataSize();
if (thr > 0) {
std::cout << "threshold is " << thr << std::endl;
filter->setThreshold(thr);
cf = 0;
} else
cf = 1;
filter->setROI(xmin, xmax, ymin, ymax);
std::time(&end_time);
std::cout << std::ctime(&end_time) << std::endl;
char* buff;
multiThreadedCountingDetector* mt =
new multiThreadedCountingDetector(filter, nthreads, fifosize);
//auto mt = std::make_unique<multiThreadedCountingDetector>(filter.get(), nthreads, fifosize);
mt->setClusterSize(csize, csize);
mt->newDataSet(); //Initialize new dataset for each thread
#ifndef ANALOG
mt->setDetectorMode(ePhotonCounting);
std::cout << "Counting!" << std::endl;
if (thr > 0) {
cf = 0;
}
#endif
//{
#ifdef ANALOG
mt->setDetectorMode(eAnalog);
std::cout << "Analog!" << std::endl;
cf = 0;
// thr1=thr;
#endif
// }
mt->StartThreads();
mt->popFree(buff);
int ifr = 0; //frame counter of while loop
int framenumber = 0; //framenumber as read from file (detector)
std::vector<hsize_t> h5offset(1,0); //frame counter internal to HDF5File::ReadImage (provided for sanity check/debugging)
if (pedfilename.length()>1) {
std::cout << "PEDESTAL " << std::endl;
if (pedfilename.find(".tif") == std::string::npos) { //not a tiff file
std::string const fname(pedfilename);
std::cout << fname << std::endl;
std::time(&end_time);
std::cout << "aaa " << std::ctime(&end_time) << std::endl;
mt->setFrameMode(ePedestal);
//HDF5File pedefile;
auto pedefile = std::make_unique<HDF5File>();
pedefile->SetFrameIndexPath(frameindexpath);
pedefile->SetImageDataPath(datasetpath);
// //open file
if ( pedefile->OpenResources(fname.c_str(),validate_rank) ) {
std::cout << "bbbb " << std::ctime(&end_time) << std::endl;
framenumber = 0;
while ( decoder->readNextFrame(*pedefile, framenumber, h5offset, buff) ) {
if ((ifr + 1) % 100 == 0) {
std::cout
<< " ****"
<< decoder->getValue(buff, 20, 20); // << std::endl;
}
mt->pushData(buff);
mt->nextThread();
mt->popFree(buff);
++ifr;
if (ifr % 100 == 0) {
std::cout << " ****" << ifr << " " << framenumber << " " << h5offset[0]
<< std::endl;
} // else
if (ifr >= 1000)
break;
//framenumber = 0;
}
pedefile->CloseResources();
while (mt->isBusy()) {
;
}
std::cout << "Writing pedestal to " << getRootString(pedfilename) << "_ped.tiff" << std::endl;
auto imgfname = createFileName( outdir, getRootString(pedfilename), "ped", "");
mt->writePedestal(imgfname.c_str());
std::cout << "Writing pedestal rms to " << getRootString(pedfilename) << "_rms.tiff" << std::endl;
imgfname = createFileName( outdir, getRootString(pedfilename), "rms", "");
mt->writePedestalRMS(imgfname.c_str());
} else
std::cout << "Could not open pedestal file " << fname
<< " for reading " << std::endl;
} else { //is a tiff file
std::vector<double> ped(nx * ny);
float* pp = ReadFromTiff(pedfilename.c_str(), nny, nnx);
if (pp && (int)nnx == nx && (int)nny == ny) {
for (int i = 0; i < nx * ny; i++) {
ped[i] = pp[i];
}
delete[] pp;
mt->setPedestal(ped.data());
std::cout << "Pedestal set from tiff file " << pedfilename
<< std::endl;
} else {
std::cout << "Could not open pedestal tiff file " << pedfilename
<< " for reading " << std::endl;
}
}
std::time(&end_time);
std::cout << std::ctime(&end_time) << std::endl;
}
ifr = 0;
int ioutfile = 0;
mt->setFrameMode(eFrame);
FILE* of = nullptr;
//NOTE THAT THE DATA FILES HAVE TO BE IN THE RIGHT ORDER SO THAT PEDESTAL TRACKING WORKS!
for (unsigned int ifile = 0; ifile != filenames.size(); ++ifile) {
std::cout << "DATA " << filenames[ifile] << " " << std::endl;
auto imgfname( createFileName( outdir, getRootString(filenames[ifile]), "", "" ) );
std::string const cfname( createFileName( outdir, getRootString(filenames[ifile]), "", "clust" ) );
std::time(&end_time);
std::cout << std::ctime(&end_time) << std::endl;
//HDF5File fileh5;
auto fileh5 = std::make_unique<HDF5File>();
fileh5->SetFrameIndexPath(frameindexpath);
fileh5->SetImageDataPath(datasetpath);
// //open file
ioutfile = 0;
if ( fileh5->OpenResources(filenames[ifile].c_str(), validate_rank) ) {
if (thr <= 0 && cf != 0) { // cluster finder
if (of == nullptr) {
of = fopen(cfname.c_str(), "w");
if (of) {
if (mt) {
mt->setFilePointer(of);
std::cout << "file pointer set " << std::endl;
} else {
std::cerr << "Error: mt is null." << std::endl;
return 1;
}
//mt->setFilePointer(of);
//std::cout << "file pointer set " << std::endl;
//std::cout << "Here! " << framenumber << " ";
} else {
std::cout << "Could not open " << cfname
<< " for writing " << std::endl;
mt->setFilePointer(nullptr);
return 1;
}
}
}
// //while read frame
framenumber = 0;
h5offset[0] = 0;
ifr = 0;
//std::cout << "Here! " << framenumber << " ";
while ( decoder->readNextFrame(*fileh5, framenumber, h5offset, buff) ) {
//std::cout << "Here! " << framenumber << " ";
// //push
if ((ifr + 1) % 1000 == 0) {
std::cout << " ****"
<< decoder->getValue(buff, 20, 20); // << std::endl;
}
mt->pushData(buff);
// // //pop
mt->nextThread();
mt->popFree(buff); /* In the last execution of the loop,
* this leaves buff outside of the Fifo!
* Free explicitely at the end! */
++ifr;
if (ifr % 1000 == 0)
std::cout << " " << ifr << " " << framenumber << " " << h5offset[0]
<< std::endl;
if (nframes > 0) {
if (ifr % nframes == 0) {
imgfname = createFileName( outdir, getRootString(filenames[ifile]), "", "", ioutfile );
mt->writeImage(imgfname.c_str(), thr1);
mt->clearImage();
++ioutfile;
}
}
//framenumber = 0;
}
//std::cout << "aa --" << std::endl;
fileh5->CloseResources();
//std::cout << "bb --" << std::endl;
while (mt->isBusy()) {
;
}
//std::cout << "cc --" << std::endl;
if (nframes >= 0) {
if (nframes > 0)
imgfname = createFileName( outdir, getRootString(filenames[ifile]), "", "", ioutfile );
std::cout << "Writing tiff to " << imgfname << " " << thr1 << ".tiff"
<< std::endl;
mt->writeImage(imgfname.c_str(), thr1);
mt->clearImage();
if (of) {
fclose(of);
of = nullptr;
mt->setFilePointer(nullptr);
}
}
std::time(&end_time);
std::cout << std::ctime(&end_time) << std::endl;
} else
std::cout << "Could not open " << filenames[ifile] << " for reading "
<< std::endl;
}
if (nframes < 0) {
//std::string fprefix( getRootString(filenames[0]) ); //Possibly, non-ideal name choice for file
auto imgfname( createFileName( outdir, getRootString(filenames[0]), "sum", "" ) );
std::cout << "Writing tiff to " << imgfname << " " << thr1 << ".tiff" << std::endl;
mt->writeImage(imgfname.c_str(), thr1);
}
//std::cout << "Calling delete..." << std::endl;
/* Info: Previously, 'delete mt' caused crash
(double calls of StopThread() in both destructors of
multiThreadedAnalogDetector and threadedAnalogDetector)
Now fixed! */
delete mt; // triggers cleanup of all threads and singlePhotonDetector instances (delete filter is obsolete)
delete decoder;
free(buff); // Free explicitly as it gets popped out of the Fifo at termination of while(readNextFrame)
return 0;
}

View File

@ -1,468 +0,0 @@
// SPDX-License-Identifier: LGPL-3.0-or-other
// Copyright (C) 2021 Contributors to the SLS Detector Package
// #include "sls/ansi.h"
//#include <iostream>
#undef CORR
#define RAWDATA
#include "jungfrauLGADStrixelsDataQuadH5.h"
#include "multiThreadedCountingDetector.h"
#include "singlePhotonDetector.h"
#include <fstream>
#include <csignal>
#include <map>
#include <memory>
#include <stdio.h>
#include <sys/stat.h>
#include <ctime>
#include <fmt/core.h>
/*Dataset paths according to different beamlines*/
std::string const data_datasetname_furka("/data/JF18T01V01/data");
std::string const index_datasetname_furka("/data/JF18T01V01/frame_index");
std::string const data_datasetname_xfelSCS("/INSTRUMENT/SCS_HRIXS_JUNGF/DET/JNGFR01:daqOutput/data/adc");
std::string const index_datasetname_xfelSCS("/INSTRUMENT/SCS_HRIXS_JUNGF/DET/JNGFR01:daqOutput/data/frameNumber");
std::string getRootString( std::string const& filepath ) {
size_t pos1;
if (filepath.find("/") == std::string::npos )
pos1 = 0;
else
pos1 = filepath.find_last_of("/")+1;
size_t pos2 = filepath.find_last_of(".");
//std::cout << "pos1 " << pos1 << " pos2 " << pos2 << " size " << filepath.length() << std::endl;
return filepath.substr( pos1, pos2-pos1 );
}
/* Create file name string
* \param dir directory
* \param fprefix fileprefix (without extension)
* \param fsuffix filesuffix (for output files, e.g. "ped")
* \param fext file extension (e.g. "raw")
*/
std::string createFileName( std::string const& dir, std::string const& fprefix="run",
std::string const& fsuffix="", std::string const& fext="raw", int const outfilecounter=-1 ) {
std::string return_string;
if (outfilecounter >= 0)
return_string = fmt::format("{:s}/{:s}_{:s}_f{:05d}", dir, fprefix, fsuffix, outfilecounter);
else if (fsuffix.length()!=0)
return_string = fmt::format("{:s}/{:s}_{:s}", dir, fprefix, fsuffix);
else
return_string = fmt::format("{:s}/{:s}", dir, fprefix);
if (fext.length()!=0)
return_string += "." + fext;
return return_string;
}
/* Adjusts number of threads to be a multiple of number of storage cells
* \param requestedThreads number of threads requested by the user
* \param nSC number of storage cells
*/
int adjustThreads(int requestedThreads, int nSC) {
if (nSC <= 0) {
std::cerr << "Error: Number of S values must be greater than zero!" << std::endl;
return requestedThreads; // Return the original value as a fallback
}
// Calculate the remainder
int remainder = requestedThreads % nSC;
// If remainder is non-zero, round up by adding the difference
int adjustedThreads = (remainder == 0) ? requestedThreads : requestedThreads + (nSC - remainder);
// Ensure at least `nSC` threads are used
if (adjustedThreads < nSC) {
adjustedThreads = nSC;
}
std::cout << "Adjusted thread count (rounded up): " << adjustedThreads << " (nearest multiple of "
<< nSC << ")" << std::endl;
return adjustedThreads;
}
// Signal handler for segmentation faults
void signal_handler(int signum) {
std::cerr << "Caught signal " << signum << ": Segmentation fault (core dump)" << std::endl;
// Handle the error (e.g., clean up, abort, etc.)
exit(signum); // Exit program with the signal code
}
int main(int argc, char *argv[]) {
if (argc < 4) {
std::cout
<< "Usage is " << argv[0]
<< " filestxt outdir [pedfile (h5)] "
" optional: [int dataset path; 0 means Furka, 1 means XFEL; overwrites default given in HDF5File.h] "
" [bool validate h5 rank] "
" [xmin xmax ymin ymax] [nframes] "
" NOTE THAT THE DATA FILES HAVE TO BE IN THE RIGHT ORDER SO THAT PEDESTAL TRACKING WORKS! "
<< std::endl;
return 1;
}
// Set up the signal handler for segmentation faults
signal(SIGSEGV, signal_handler);
int const fifosize = 100; //1000;
int const nthreads = 10;
int const csize = 3; // 3
int const nsigma = 5;
int const nped = 10000;
//int cf = 0;
std::string const txtfilename(argv[1]);
std::string const outdir(argv[2]);
std::string const pedfilename(argv[3]);
std::string datasetpath{};
std::string frameindexpath{};
if (argc > 4) {
switch (atoi(argv[4])) {
case 0:
datasetpath = data_datasetname_furka;
frameindexpath = index_datasetname_furka;
break;
case 1:
datasetpath = data_datasetname_xfelSCS;
frameindexpath = index_datasetname_xfelSCS;
break;
default:
break;
}
}
bool validate_rank=true;
if (argc > 5)
validate_rank = atoi(argv[5]);
//Get vector of filenames from input txt-file
std::vector<std::string> filenames{};
{ //Safety scope for ifstream
ifstream inputs( txtfilename, std::ios::in );
if (inputs.is_open()) {
std::cout << "Reading imput filenames from txt-file ..." << std::endl;
std::string line{};
while (!inputs.eof()) {
std::getline(inputs, line);
if(line.find(".h5") != std::string::npos) {
filenames.emplace_back(line);
std::cout << line << std::endl;
}
}
inputs.close();
std::cout << "---- Reached end of txt-file. ----" << std::endl;
} else
std::cout << "Could not open " << txtfilename << std::endl;
if (filenames.size()>0) {
std::cout << filenames.size() << " filenames found in " << txtfilename << std::endl;
std::cout << "The files will be processed in the same order as found in the txt-file." << std::endl;
} else {
std::cout << "No files found in txt-file!" << std::endl;
return 1;
}
}
std::cout << "###############" << std::endl;
// Define decoder
std::cout << "Jungfrau strixel quad h5" << std::endl;
jungfrauLGADStrixelsDataQuadH5* decoder = new jungfrauLGADStrixelsDataQuadH5();
//auto decoder = std::make_unique<jungfrauLGADStrixelsDataQuadH5>();
int nx = 1024 / 3, ny = 512 * 3;
//Cluster finder ROI
int xmin = 0, xmax = nx-1, ymin = 0, ymax = ny-1;
if (argc > 9) {
xmin = atoi(argv[6]);
xmax = atoi(argv[7]);
ymin = atoi(argv[8]);
ymax = atoi(argv[9]);
}
std::cout << "Cluster finder ROI: [" << xmin << ", " << xmax << ", " << ymin << ", " << ymax << "]"
<< std::endl;
decoder->getDetectorSize(nx, ny);
std::cout << "Detector size is " << nx << " " << ny << std::endl;
std::time_t end_time;
std::cout << "Output directory is " << outdir << std::endl;
if (pedfilename.length()!=0)
std::cout << "Pedestal file is " << pedfilename << std::endl;
//uint32_t nnx, nny;
singlePhotonDetector* filter =
new singlePhotonDetector(decoder, 3, nsigma, 1, NULL, nped, 200, -1, -1, NULL, NULL);
//auto filter = std::make_unique<singlePhotonDetector>(decoder.get(), 3, nsigma, 1, nullptr, nped, 200, -1, -1, nullptr, nullptr);
filter->setROI(xmin, xmax, ymin, ymax);
std::time(&end_time);
std::cout << std::ctime(&end_time) << std::endl;
// Validate number of threads for number of storage cells (if applicable)
int nThreads = nthreads;
int nSC = 1;
// Determine the dimensions of the dataset from the first datafile
auto firstfileh5 = std::make_unique<HDF5File>();
firstfileh5->SetFrameIndexPath(frameindexpath);
firstfileh5->SetImageDataPath(datasetpath);
//std::cout << "Debug: Attempting to open file " << filenames[0].c_str() << std::endl;
if ( firstfileh5->OpenResources(filenames[0].c_str(), validate_rank) ) {
// Validate number of threads
if( firstfileh5->GetRank() == 4 ) {
auto h5dims = firstfileh5->GetDatasetDimensions();
nSC = h5dims[1];
nThreads = adjustThreads(nthreads,nSC);
}
firstfileh5->CloseResources();
} else {
std::cerr << "Error: Could not open data file " << filenames[0]
<< " for validating rank " << std::endl;
}
multiThreadedCountingDetector* mt =
new multiThreadedCountingDetector(filter, nThreads, fifosize, nSC);
//auto mt = std::make_unique<multiThreadedCountingDetector>(filter.get(), nthreads, fifosize);
mt->setClusterSize(csize, csize);
mt->newDataSet(); //Initialize new dataset for each thread
mt->setDetectorMode(ePhotonCounting);
char* buff;
mt->StartThreads();
mt->popFree(buff); // Get the first pointer to write image to
size_t ifr = 0; //frame counter of while loop
int framenumber = 0; //framenumber as read from file (detector)
std::vector<hsize_t> h5offset; //hyperslab offset internal to HDF5File::ReadImage
hsize_t h5rank;
if (pedfilename.length()>1) {
std::string froot = getRootString(pedfilename);
std::cout << "PEDESTAL " << pedfilename << std::endl;
std::time(&end_time);
std::cout << "aaa " << std::ctime(&end_time) << std::endl;
mt->setFrameMode(ePedestal);
//HDF5File pedefile;
auto pedefile = std::make_unique<HDF5File>();
pedefile->SetFrameIndexPath(frameindexpath);
pedefile->SetImageDataPath(datasetpath);
// //open file
if ( pedefile->OpenResources(pedfilename.c_str(),validate_rank) ) {
// Initialize offset vector to 0
h5rank = pedefile->GetRank();
h5offset.resize(h5rank-2, 0);
framenumber = 0;
while ( decoder->readNextFrame(*pedefile, framenumber, h5offset, buff) ) {
if ((ifr + 1) % 100 == 0) {
std::cout
<< " ****"
<< decoder->getValue(buff, 20, 20); // << std::endl;
}
int storageCell = 0;
hsize_t n_storageCells = 1;
if (h5rank == 4) {
storageCell = h5offset[1];
n_storageCells = pedefile->GetDatasetDimensions()[1];
}
// push buff into fifoData for a thread corresponding to the active storage cell
mt->pushData(buff, storageCell);
// increment (round-robin) the internal thread counter for that storage cell
mt->nextThread(storageCell);
// get a free memory address from fifoFree of the active storage cell for the next read operation
mt->popFree(buff, storageCell);
/* NOTE: the buff that was popped free from the current thread, will be (likely) pushed into
* the fifoData of a different thread in the next iteration of the loop! */
++ifr;
if (ifr % 100 == 0) {
std::cout << " ****" << ifr << " " << framenumber << " " << h5offset[0];
if (n_storageCells>1)
std::cout << " sc " << storageCell;
std::cout << "\n";
} // else
if (ifr >= 1000*n_storageCells)
break;
//framenumber = 0;
}
pedefile->CloseResources();
while (mt->isBusy()) {
;
}
std::cout << "Writing pedestal to " << getRootString(pedfilename) << "_ped_SCxx.tiff" << std::endl;
auto imgfname = createFileName( outdir, getRootString(pedfilename), "ped", "" );
mt->writePedestal(imgfname.c_str());
std::cout << "Writing pedestal rms to " << getRootString(pedfilename) << "_rms_SCxx.tiff" << std::endl;
imgfname = createFileName( outdir, getRootString(pedfilename), "rms", "");
mt->writePedestalRMS(imgfname.c_str());
} else {
std::cerr << "Error: Could not open pedestal file " << pedfilename
<< " for reading " << std::endl;
}
std::time(&end_time);
std::cout << std::ctime(&end_time) << std::endl;
}
ifr = 0;
//int ioutfile = 0;
mt->setFrameMode(eFrame);
std::vector<FILE*> of(nSC, nullptr);
for (unsigned int ifile = 0; ifile != filenames.size(); ++ifile) {
std::cout << "DATA " << filenames[ifile] << " " << std::endl;
std::time(&end_time);
std::cout << std::ctime(&end_time) << std::endl;
//HDF5File fileh5;
auto fileh5 = std::make_unique<HDF5File>();
fileh5->SetFrameIndexPath(frameindexpath);
fileh5->SetImageDataPath(datasetpath);
// Open HDF5 file
if ( fileh5->OpenResources(filenames[ifile].c_str(), validate_rank) ) {
std::vector<std::string> cfnames(nSC);
for ( int s = 0; s < nSC; ++s ) {
std::string fsuffix = "SC" + std::to_string(s);
cfnames[s] = createFileName( outdir, getRootString(filenames[ifile]), fsuffix, "clust" );
}
//Open output files and set file pointers according to storage cells
for ( size_t f = 0; f < of.size(); ++f ) {
if (!of[f]) {
of[f] = fopen(cfnames[f].c_str(), "w");
if (of[f])
{
if (mt) {
mt->setFilePointer(of[f],f); // assumes f == sc
std::cout << "File pointer set for storage cell " << f << std::endl;
} else {
std::cerr << "Error: mt is null." << std::endl;
return 1;
}
} else {
std::cerr << "Error: could not open " << cfnames[f]
<< " for writing " << std::endl;
mt->setFilePointer(nullptr,f);
return 1;
}
}
}
// Read frames
framenumber = 0;
std::fill(h5offset.begin(), h5offset.end(), 0);
ifr = 0;
while ( decoder->readNextFrame(*fileh5, framenumber, h5offset, buff) ) {
if ((ifr + 1) % 1000 == 0) {
std::cout << " ****"
<< decoder->getValue(buff, 20, 20); // << std::endl;
}
int storageCell = 0;
hsize_t n_storageCells = 1;
if (h5rank == 4) {
storageCell = h5offset[1];
n_storageCells = fileh5->GetDatasetDimensions()[1];
}
// push buff into fifoData for a thread corresponding to the active storage cell
mt->pushData(buff, storageCell);
// increment (round-robin) the internal thread counter for that storage cell
mt->nextThread(storageCell);
// get a free memory address from fifoFree of the active storage cell for the next read operation
mt->popFree(buff, storageCell); /* In the last execution of the loop,
* this leaves buff outside of the Fifo!
* Free explicitely at the end! */
++ifr;
if (ifr % 1000 == 0) {
std::cout << " " << ifr << " " << framenumber << " " << h5offset[0];
if (n_storageCells>1) std::cout << " sc " << storageCell;
std::cout << "\n";
}
//framenumber = 0;
}
//std::cout << "aa --" << std::endl;
fileh5->CloseResources();
//std::cout << "bb --" << std::endl;
while (mt->isBusy()) {
;
}
//std::cout << "cc --" << std::endl;
auto imgfname = createFileName( outdir, getRootString(filenames[ifile]), "", "" );
std::cout << "Writing tiff to " << imgfname << "_SCxx.tiff" << std::endl;
mt->writeImage(imgfname.c_str());
mt->clearImage();
// Close output files
for ( size_t f = 0; f < of.size(); ++f ) {
if (of[f]) {
fclose(of[f]);
mt->setFilePointer(nullptr,f);
of[f] = nullptr;
}
}
std::time(&end_time);
std::cout << std::ctime(&end_time) << std::endl;
} else {
std::cerr << "Error: Could not open " << filenames[ifile] << " for reading "
<< std::endl;
}
}
//std::cout << "Calling delete..." << std::endl;
/* Info: Previously, 'delete mt' caused crash
(double calls of StopThread() in both destructors of
multiThreadedAnalogDetector and threadedAnalogDetector)
Now fixed! */
delete mt; // triggers cleanup of all threads and singlePhotonDetector instances (delete filter is obsolete)
delete decoder;
free(buff); // Free explicitly as it gets popped out of the Fifo at termination of while(readNextFrame)
return 0;
}

View File

@ -336,7 +336,7 @@ int main(int argc, char *argv[]) {
string fname;
// int length;
int *detimage = nullptr;
int *detimage = NULL;
int nnx, nny, nnsx, nnsy;
// uint32_t imageSize = 0, nPixelsX = 0, nPixelsY = 0,
// uint32_t dynamicRange = 0;

View File

@ -23,9 +23,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <mutex>
#include <algorithm>
#include<unordered_map>
//#include <mutex>
using namespace std;
@ -49,20 +47,12 @@ class threadedAnalogDetector {
if (mm) {
// memset(mm,0, det->getDataSize());
/*
if (i == 0) { // debug
first_mm = mm;
}
*/
fifoFree->push(mm);
//std::cout << "Allocated memory at: " << static_cast<void*>(mm) << " (fifoslot " << i << ")" << std::endl;
} else
break;
}
if (i < fs)
std::cout << "Could allocate only " << i << " frames";
cout << "Could allocate only " << i << " frames";
busy = 0;
stop = 1;
@ -112,50 +102,24 @@ class threadedAnalogDetector {
};
virtual ~threadedAnalogDetector() {
// std::cout << "#### Debug: Destructing threadedAnalogDetector! ####" << std::endl;
StopThread();
if (fifoFree) { delete fifoFree; fifoFree = nullptr; }
if (fifoData) { delete fifoData; fifoData = nullptr; }
if (det) {
delete det; // Call destructor for singlePhotonDetector
det = nullptr;
}
delete fifoFree;
delete fifoData;
}
/** Returns true if the thread was successfully started, false if there was
* an error starting the thread */
virtual bool StartThread() {
stop = 0;
std::cout << "Detector number " << det->getId() << std::endl;
std::cout << "common mode is " << det->getCommonModeSubtraction() << std::endl;
std::cout << "ghos summation is " << det->getGhostSummation() << std::endl;
cout << "Detector number " << det->getId() << endl;
cout << "common mode is " << det->getCommonModeSubtraction() << endl;
cout << "ghos summation is " << det->getGhostSummation() << endl;
return (pthread_create(&_thread, NULL, processData, this) == 0);
}
virtual void StopThread() {
stop = 1;
//std::cout << "Attempting to stop thread..." << std::endl;
// Free all remaining allocated memory in fifoFree
char *mm = nullptr;
while (fifoFree->pop(mm, true)) { // Use no_block to avoid waiting
//std::cout << "fifo Free: Freeing memory at: " << static_cast<void*>(mm) << std::endl;
free(mm); // Free the allocated memory
}
if (_thread) {
//(void)pthread_join(_thread, NULL);
//std::cout << "Calling pthread_join for thread: " << det->getId() << std::endl;
pthread_join(_thread, NULL);
_thread = 0;
std::cout << "Thread " << det->getId() << " stopped and joined." << std::endl;
} else {
std::cout << "No thread to join." << std::endl;
}
(void)pthread_join(_thread, NULL);
}
virtual bool pushData(char *&ptr) { return fifoData->push(ptr); }
@ -302,8 +266,6 @@ class threadedAnalogDetector {
char *data;
int *ff;
//char* first_mm = nullptr; // For debug; to track first allocated block
static void *processData(void *ptr) {
threadedAnalogDetector *This = ((threadedAnalogDetector *)ptr);
return This->processData();
@ -316,118 +278,55 @@ class threadedAnalogDetector {
usleep(100);
if (fifoData->isEmpty()) {
busy = 0;
} else {
} else
busy = 1;
}
} else {
} else
busy = 1;
}
if (busy == 1) {
// Check stop flag before making a blocking call
//if (stop) {
// break;
//}
// Blocking call
fifoData->pop(data); // blocking!
// Process data if not stopping
//if (!stop) {
det->processData(data);
fifoFree->push(data);
//}
// busy=0;
}
}
return NULL;
}
};
class multiThreadedAnalogDetector {
public:
multiThreadedAnalogDetector(analogDetector<uint16_t> *d, int num_threads,
int fs = 1000, int num_sc = 1)
: stop(0), nThreads(num_threads), nSC(num_sc) {
/*
multiThreadedAnalogDetector(analogDetector<uint16_t> *d, int n,
int fs = 1000)
: stop(0), nThreads(n), ithread(0) {
dd[0] = d;
if (nThreads == 1)
dd[0]->setId(100);
else
dd[0]->setId(0);
*/
// Create separate detectorObjects for each SC (each owns its mutex)
std::vector< analogDetector<uint16_t>* > sc_detectors(nSC, nullptr);
sc_detectors[0] = d; // First storage cell uses the given detector
// std::cout << "#### Debug: Copied analogDetector object for storage cell 0! ####" << std::endl;
for (int sc = 1; sc < nSC; ++sc) {
sc_detectors[sc] = d->Copy(); // Ensure unique mutex for each SC
// std::cout << "#### Debug: Copied analogDetector object for storage cell " << sc << "! ####" << std::endl;
for (int i = 1; i < nThreads; i++) {
dd[i] = d->Clone();
dd[i]->setId(i);
}
// Distribute threads among storage cells
int threads_per_sc = nThreads / nSC;
int remaining_threads = nThreads % nSC; // additional safety measure if nThreads is not divisible by nSC
sc_to_threads.clear();
for (int s = 0, thread_idx = 0; s < nSC; ++s) {
// Remaining threads (if any) are assigned to the first storage cells
int current_sc_threads = threads_per_sc + (s < remaining_threads ? 1 : 0);
for (int t = 0; t < current_sc_threads; ++t, ++thread_idx) {
if (t == 0) {
dd[thread_idx] = sc_detectors[s]; // First thread gets main SC detector
} else {
dd[thread_idx] = sc_detectors[s]->Clone(); // Other threads get clones
}
std::cout << "Assigned thread " << thread_idx << " to storage cell " << s << std::endl;
dd[thread_idx]->setId(thread_idx);
// Store which threads belong to which SC
sc_to_threads[s].push_back(thread_idx);
}
}
if (nSC == 1 && nThreads == 1) {
dd[0]->setId(100);
}
// Initialize threadedAnalogDetector objects
for (int i = 0; i < nThreads; i++) {
cout << "**" << i << endl;
dets[i] = new threadedAnalogDetector(dd[i], fs);
}
// Set all thread counters to zero for each storage cell
thread_counters_by_sc.resize(nSC,0);
image = nullptr;
image = NULL;
ff = NULL;
ped = NULL;
//std::cout << "Ithread is " << ithread << std::endl;
cout << "Ithread is " << ithread << endl;
}
virtual ~multiThreadedAnalogDetector() {
// std::cout << "#### Debug: Destructing multiThreadedAnalogDetector! ####" << std::endl;
//StopThreads(); // Superfluous, leads to double delete
/* Reverse loop for destruction.
* Deletes clones first, then root object, which owns the mutex
* (ensure shared mutex is deleted last).
* Optional solution: reference counting (safer but more complex) */
for (int i = nThreads - 1; i >= 0; --i) {
delete dets[i]; //StopThread() called by each ~threadedAnalogDetector()
dets[i] = nullptr;
}
StopThreads();
for (int i = 0; i < nThreads; i++)
delete dets[i];
/* for (int i=1; i<nThreads; i++) */
/* delete dd[i]; */
// delete [] image;
}
virtual int setFrameMode(int fm) {
@ -460,52 +359,36 @@ class multiThreadedAnalogDetector {
dets[i]->newDataSet();
};
// Storage cell sensitive
virtual int *getImage(int &nnx, int &nny, int &ns, int &nsy, int sc = 0) {
//int *img;
virtual int *getImage(int &nnx, int &nny, int &ns, int &nsy) {
int *img;
// int nnx, nny, ns;
// int nnx, nny, ns;
int nn = dets[0]->getImageSize(nnx, nny, ns, nsy);
if (sc_images[sc]) {
delete[] sc_images[sc];
sc_images[sc] = nullptr;
if (image) {
delete[] image;
image = NULL;
}
// Allocate memory for image and zero-initialize
sc_images[sc] = new int[nn]();
image = new int[nn];
// int nn=dets[0]->getImageSize(nnx, nny, ns);
// for (i=0; i<nn; i++) image[i]=0;
// Get the threads assigned to this storage cell
auto const& assigned_threads = sc_to_threads[sc];
// Only iterate over threads assigned to this storage cell
for (int thread_id : assigned_threads) {
int* tmp_img = dets[thread_id]->getImage();
if (!tmp_img) continue; // Skip if null
/* std::cout << "## Thread " << ii
<< " # image size " << nn
<< " # nnx " << nnx
<< " # nny " << nny
<< " # ns " << ns; */
// Sum images across threads
for (int ii = 0; ii < nThreads; ii++) {
// cout << ii << " " << nn << " " << nnx << " " << nny << " " << ns
// << endl;
img = dets[ii]->getImage();
for (int i = 0; i < nn; i++) {
/* std::cout << " # pixel " << i
<< " # value " << tmp_img[i]
<< " ## " << std::endl; */
sc_images[sc][i] += tmp_img[i];
if (ii == 0)
// if (img[i]>0)
image[i] = img[i];
// else
// image[i]=0;
else // if (img[i]>0)
image[i] += img[i];
// if (img[i]) cout << "det " << ii << " pix " << i << " val
// " << img[i] << " " << image[i] << endl;
}
}
return sc_images[sc];
return image;
}
virtual void clearImage() {
@ -515,7 +398,7 @@ class multiThreadedAnalogDetector {
}
}
virtual void *writeImage(char const* base_imgname, double t = 1) {
virtual void *writeImage(const char *imgname, double t = 1) {
/* #ifdef SAVE_ALL */
/* for (int ii=0; ii<nThreads; ii++) { */
/* char tit[10000];cout << "m" <<endl; */
@ -524,30 +407,11 @@ class multiThreadedAnalogDetector {
/* } */
/* #endif */
int nnx, nny, ns, nsy;
getImage(nnx, nny, ns, nsy);
// int nnx, nny, ns;
int nn = dets[0]->getImageSize(nnx, nny, ns, nsy);
// Allocate teporary float buffer and zero-initialize
std::vector<float> gm(nn);
// Lambda for pixel conversion
auto convert_pixel = [t](int pixel) -> float {
return (t > 0) ? static_cast<float>(std::max(0, pixel)) / static_cast<float>(t) : pixel;
}; // t ... threshold
// Loop over each storage cell
for (auto const& [sc, _] : sc_to_threads) { // structured bindings [sc, _] only available with -std=c++17
std::string imgname(base_imgname);
if (nSC > 1) imgname += "_SC" + std::to_string(sc);
imgname += ".tiff";
//Retrieve the image for this storage cell
int *image = getImage(nnx, nny, ns, nsy, sc);
if (!image) continue; // Skip if null
// Convert image data to float
std::transform(image, image + nn, gm.begin(), convert_pixel);
/* old loop implementing same logic as convert_pixel
float *gm = new float[nn];
if (gm) {
for (int ix = 0; ix < nn; ix++) {
if (t) {
if (image[ix] < 0)
@ -560,18 +424,11 @@ class multiThreadedAnalogDetector {
// if (image[ix]>0 && ix/nnx<350) cout << ix/nnx << " " <<
// ix%nnx << " " << image[ix]<< " " << gm[ix] << endl;
}
*/
WriteToTiff(gm.data(), imgname.c_str(), nnx, nny);
// Clean up memory for this storage cell
if (sc_images[sc]) {
delete[] sc_images[sc];
sc_images[sc] = nullptr;
}
}
// cout << "image " << nnx << " " << nny << endl;
WriteToTiff(gm, imgname, nnx, nny);
delete[] gm;
} else
cout << "Could not allocate float image " << endl;
return NULL;
}
@ -582,7 +439,6 @@ class multiThreadedAnalogDetector {
}
virtual void StopThreads() {
std::cout << "Stopping all threads ..." << std::endl;
for (int i = 0; i < nThreads; i++)
dets[i]->StopThread();
}
@ -597,133 +453,76 @@ class multiThreadedAnalogDetector {
return ret;
}
/*
virtual std::vector<int> getThreadsForSc(int sc) {
return sc_to_threads[sc];
}
*/
virtual bool pushData(char *&ptr, int sc=0) {
//Additional logic implemented to accommodate storage cells
virtual bool pushData(char *&ptr) { return dets[ithread]->pushData(ptr); }
std::unique_lock<std::mutex> lock(map_mutex);
// Get assigned threads for this storage cell
auto& assigned_threads = sc_to_threads[sc];
auto& counter = thread_counters_by_sc[sc];
// Distribute workload among threads using round-robin
int selected_thread = assigned_threads[counter % assigned_threads.size()];
return dets[selected_thread]->pushData(ptr);
virtual bool popFree(char *&ptr) {
// cout << ithread << endl;
return dets[ithread]->popFree(ptr);
}
virtual bool popFree(char *&ptr, int sc=0) {
//Additional logic implemented to accommodate storage cells
std::unique_lock<std::mutex> lock(map_mutex);
// Get assigned threads for this storage cell
auto& assigned_threads = sc_to_threads[sc];
auto& counter = thread_counters_by_sc[sc];
// Distribute workload among threads using round-robin
int selected_thread = assigned_threads[counter % assigned_threads.size()];
return dets[selected_thread]->popFree(ptr);
virtual int nextThread() {
ithread++;
if (ithread == nThreads)
ithread = 0;
return ithread;
}
virtual int nextThread(int sc=0) {
//Additional logic implemented to accommodate storage cells
auto& counter = thread_counters_by_sc[sc];
//counter++;
if (++counter == nThreads/nSC)
counter = 0;
return counter;
}
// Storage cell sensitive
virtual double *getPedestal(int sc = 0) {
virtual double *getPedestal() {
int nx, ny;
dets[0]->getDetectorSize(nx, ny);
if (sc_pedestals.count(sc) && sc_pedestals[sc]) {
delete[] sc_pedestals[sc];
sc_pedestals[sc] = nullptr;
}
// allocate memory and initialize all values to zero
sc_pedestals[sc] = new double[nx * ny](); // parentheses initialize elements to zero
//std::fill(sc_pedestals[sc], sc_pedestals[sc] + (nx * ny), 0.0); // explicit zero initialization
if (ped)
delete[] ped;
ped = new double[nx * ny];
double *p0 = new double[nx * ny];
// Get the threads assigned to this storage cell
auto const& assigned_threads = sc_to_threads[sc];
int num_threads = assigned_threads.size();
// Only iterate over threads assigned to this storage cell
for ( int thread_id : assigned_threads ) {
for (int i = 0; i < nThreads; i++) {
// inte=(slsInterpolation*)dets[i]->getInterpolation(nb,emi,ema);
// cout << i << endl;
//p0 = dets[thread_id]->getPedestal(p0);
dets[thread_id]->getPedestal(p0);
if (p0) { /*
p0 = dets[i]->getPedestal(p0);
if (p0) {
if (i == 0) {
// If first thread, initialize ped with first thread's values
for (int ib = 0; ib < nx * ny; ib++) {
ped[ib] = p0[ib] / ((double)nThreads);
// cout << p0[ib] << " ";
}
} else {
*/
// For subsequent threads, accumulate pedestal values
// if ( i == 0 ) becomes superfluous if we zero-initialize earlier
for (int ib = 0; ib < nx * ny; ib++) {
sc_pedestals[sc][ib] += p0[ib] / ((double)num_threads);
ped[ib] += p0[ib] / ((double)nThreads);
// cout << p0[ib] << " ";
}
//}
}
}
}
delete[] p0;
return sc_pedestals[sc];
return ped;
};
// Storage cell sensitive
virtual double *getPedestalRMS(int sc = 0) {
virtual double *getPedestalRMS() {
int nx, ny;
dets[0]->getDetectorSize(nx, ny);
if (sc_pedestals_rms.count(sc) && sc_pedestals_rms[sc]) {
delete[] sc_pedestals_rms[sc];
sc_pedestals_rms[sc] = nullptr;
}
// allocate memory and initialize all values to zero
sc_pedestals_rms[sc] = new double[nx * ny](); // Zero-initialize
//std::fill(sc_pedestals_rms[sc], sc_pedestals_rms[sc] + (nx * ny), 0.0); // explicit zero initialization
//double *rms = sc_pedestals_rms[sc];
// if (ped) delete [] ped;
double *rms = new double[nx * ny];
double *p0 = new double[nx * ny];
// Get the threads assigned to this storage cell
auto const& assigned_threads = sc_to_threads[sc];
int num_threads = assigned_threads.size();
// Only iterate over threads assigned to this storage cell
for (int thread_id : assigned_threads) {
for (int i = 0; i < nThreads; i++) {
// inte=(slsInterpolation*)dets[i]->getInterpolation(nb,emi,ema);
// cout << i << endl;
//p0 = dets[thread_id]->getPedestalRMS(p0);
dets[thread_id]->getPedestalRMS(p0);
p0 = dets[i]->getPedestalRMS(p0);
if (p0) {
if (i == 0) {
for (int ib = 0; ib < nx * ny; ib++) {
sc_pedestals_rms[sc][ib] += (p0[ib] * p0[ib]) / ((double)num_threads);
rms[ib] = p0[ib] * p0[ib] / ((double)nThreads);
// cout << p0[ib] << " ";
}
} else {
for (int ib = 0; ib < nx * ny; ib++) {
rms[ib] += p0[ib] * p0[ib] / ((double)nThreads);
// cout << p0[ib] << " ";
}
}
}
}
delete[] p0;
@ -734,117 +533,64 @@ class multiThreadedAnalogDetector {
/* rms[ib]=0; */
/* } */
return sc_pedestals_rms[sc];
return rms;
};
/**
* Sets pedestal for given storage cell
* \param h pedestal
* \param sc storage cell
* \returns NULL
*/
virtual double *setPedestal(double *h = NULL, int sc = 0) {
virtual double *setPedestal(double *h = NULL) {
// int nb=0;
int nx, ny;
dets[0]->getDetectorSize(nx, ny);
if (h == NULL)
h = ped;
for (auto i : sc_to_threads[sc]) {
for (int i = 0; i < nThreads; i++) {
dets[i]->setPedestal(h);
}
return NULL;
};
// Storage cell sensitive
virtual void *writePedestal(char const* base_imgname) {
virtual void *writePedestal(const char *imgname) {
int nx, ny;
dets[0]->getDetectorSize(nx, ny);
//float *gm = new float[nx * ny];
// Loop over each storage cell
for ( auto const& entry : sc_to_threads ) {
int sc = entry.first;
std::string imgname = std::string(base_imgname);
if (nSC>1)
imgname += "_SC" + std::to_string(sc);
imgname += ".tiff";
getPedestal(sc); // Compute pedestal for this storage cell
std::vector<float> gm(nx * ny);
// Copy pedestal data into the float array
/*
getPedestal();
float *gm = new float[nx * ny];
if (gm) {
for (int ix = 0; ix < nx * ny; ix++) {
gm[ix] = sc_pedestals[sc][ix];
}
*/
std::copy(sc_pedestals[sc], sc_pedestals[sc] + (nx * ny), gm.data());
WriteToTiff(gm.data(), imgname.c_str(), nx, ny);
// Clean up memory
if(sc_pedestals[sc]) {
delete[] sc_pedestals[sc];
sc_pedestals[sc] = nullptr;
}
gm[ix] = ped[ix];
}
WriteToTiff(gm, imgname, nx, ny);
delete[] gm;
} else
cout << "Could not allocate float image " << endl;
return NULL;
};
// Storage cell sensitive
virtual void *writePedestalRMS(char const* base_imgname) {
virtual void *writePedestalRMS(const char *imgname) {
int nx, ny;
dets[0]->getDetectorSize(nx, ny);
//float *gm = new float[nx * ny];
// Loop over each stoarge cell
for ( auto const& entry : sc_to_threads ) {
int sc = entry.first;
std::string imgname = std::string(base_imgname);
if (nSC>1)
imgname += "_SC" + std::to_string(sc);
imgname += ".tiff";
double *rms = getPedestalRMS(sc); // Compute pedestal RMS for this storage cell
std::vector<float> gm(nx * ny);
// Copy rms data into the float array
/*
double *rms = getPedestalRMS();
float *gm = new float[nx * ny];
if (gm) {
for (int ix = 0; ix < nx * ny; ix++) {
gm[ix] = rms[ix];
}
*/
std::copy(rms, rms + (nx * ny), gm.data());
WriteToTiff(gm.data(), imgname.c_str(), nx, ny);
// Clean up memory
//delete[] rms; //This would cause double-free since the pointer is already handled by sc_pedestals_rms[sc]
if(sc_pedestals_rms[sc]) {
delete[] sc_pedestals_rms[sc];
sc_pedestals_rms[sc] = nullptr;
}
}
WriteToTiff(gm, imgname, nx, ny);
delete[] gm;
delete[] rms;
} else
cout << "Could not allocate float image " << endl;
return NULL;
};
/**
* Reads pedestal and sets it for given storage cell
* \param imgname name of pedestal file
* \param nb obsolete
* \param emin obsolete
* \param emax obsolete
* \param sc storage cell
* \returns setPedestal(NULL, sc)
* */
virtual void *readPedestal(const char *imgname, int nb = -1,
double emin = 1, double emax = 0, int sc = 0) {
double emin = 1, double emax = 0) {
int nx, ny;
dets[0]->getDetectorSize(nx, ny);
@ -864,68 +610,36 @@ class multiThreadedAnalogDetector {
}
delete[] gm;
return setPedestal(NULL, sc);
return setPedestal();
};
/** Sets file pointer where to write the clusters to
/** sets file pointer where to write the clusters to
\param f file pointer
\param sc storage cell index
\returns current file pointer, or nullptr if invalid
\returns current file pointer
*/
virtual FILE *setFilePointer(FILE *f, int sc = 0) {
// Check if the storage cell exists
if (sc_to_threads.find(sc) == sc_to_threads.end() || sc_to_threads[sc].empty()) {
std::cerr << "Error: Invalid storage cell index " << sc << std::endl;
return nullptr;
}
// Assign file pointer to all threads belonging to this storage cell
for (auto i : sc_to_threads[sc]) {
if(dets[i]) {
virtual FILE *setFilePointer(FILE *f) {
for (int i = 0; i < nThreads; i++) {
dets[i]->setFilePointer(f);
// dets[i]->setMutex(&fmutex);
} else {
std::cerr << "Warning: dets[" << i << "] is null, skipping file pointer set." << std::endl;
}
}
// Return file pointer of the first thread in this storage cell
return dets[sc_to_threads[sc][0]] ? dets[sc_to_threads[sc][0]]->getFilePointer() : nullptr;
return dets[0]->getFilePointer();
};
/** Gets file pointer where to write the clusters to
\param sc storage cell index
\returns current file pointer, or nullptr if invalid
/** gets file pointer where to write the clusters to
\returns current file pointer
*/
virtual FILE *getFilePointer(int sc = 0) {
// Ensure storage cell index is valid
if (sc_to_threads.find(sc) == sc_to_threads.end() || sc_to_threads[sc].empty()) {
std::cerr << "Error: Invalid storage cell index " << sc << std::endl;
return nullptr;
}
// Return file pointer of the first thread in this storage cell
return dets[sc_to_threads[sc][0]] ? dets[sc_to_threads[sc][0]]->getFilePointer() : nullptr;
};
virtual FILE *getFilePointer() { return dets[0]->getFilePointer(); };
protected:
bool stop;
const int nThreads;
threadedAnalogDetector *dets[MAXTHREADS];
analogDetector<uint16_t> *dd[MAXTHREADS];
//int ithread{0}; // Thread index
std::vector<int> thread_counters_by_sc{}; // Counters for threads for each storage cell
int ithread;
int *image;
int *ff;
double *ped;
//pthread_mutex_t fmutex; //unused
std::unordered_map<int,std::vector<int>> sc_to_threads; // Maps storage cell -> vector of assigned thread ids
std::mutex map_mutex; // Ensure thread-safe access to the map
int nSC{1}; // Number of storage cells
std::unordered_map<int,int*> sc_images; // Store images per storage cell
std::unordered_map<int,double*> sc_pedestals; // Store pedestal arrays per storage cell
std::unordered_map<int,double*> sc_pedestals_rms; // Store pedestal RMS arrays per storage cell
// at the moment, these maps could be avoided, but this implementation is more robust in allowing future changes
pthread_mutex_t fmutex;
};
#endif

View File

@ -19,8 +19,8 @@ using namespace std;
class multiThreadedCountingDetector : public multiThreadedAnalogDetector {
public:
multiThreadedCountingDetector(singlePhotonDetector *d, int num_threads, int fs = 1000, int num_sc = 1)
: multiThreadedAnalogDetector(d, num_threads, fs, num_sc){};
multiThreadedCountingDetector(singlePhotonDetector *d, int n, int fs = 1000)
: multiThreadedAnalogDetector(d, n, fs){};
// virtual
// ~multiThreadedCountingDetector{multiThreadedAnalogDetector::~multiThreadedAnalogDetector();};
virtual double setNSigma(double n) {

View File

@ -70,6 +70,7 @@ class multiThreadedInterpolatingDetector
if (getInterpolation() == NULL)
return multiThreadedAnalogDetector::getImage(nnx, nny, nsx, nsy);
// if one interpolates, the whole image is stored in detector 0;
int *img;
// int nnx, nny, ns;
// int nnx, nny, ns;
int nn = dets[0]->getImageSize(nnx, nny, nsx, nsy);
@ -78,9 +79,9 @@ class multiThreadedInterpolatingDetector
image = NULL;
}
image = new int[nn];
int* tmp_img = dets[0]->getImage();
img = dets[0]->getImage();
for (int i = 0; i < nn; i++) {
image[i] = tmp_img[i];
image[i] = img[i];
}
return image;
};

View File

@ -51,6 +51,7 @@ class singlePhotonDetector : public analogDetector<uint16_t> {
*/
singlePhotonDetector(slsDetectorData<uint16_t> *d, int csize = 3,
double nsigma = 5, int sign = 1,
commonModeSubtraction *cm = NULL, int nped = 1000,
@ -59,11 +60,10 @@ class singlePhotonDetector : public analogDetector<uint16_t> {
: analogDetector<uint16_t>(d, sign, cm, nped, nnx, nny, gm, gs),
nDark(nd), eventMask(NULL), nSigma(nsigma), eMin(-1), eMax(-1),
clusterSize(csize), clusterSizeY(csize), c2(1), c3(1), clusters(NULL),
quad(UNDEFINED_QUADRANT), tot(0), quadTot(0), ownsMutex(true) { // The original object owns the mutex {
quad(UNDEFINED_QUADRANT), tot(0), quadTot(0) {
//fm = new pthread_mutex_t;
//pthread_mutex_init(fm, NULL);
fm = new std::mutex();
fm = new pthread_mutex_t;
pthread_mutex_init(fm, NULL);
eventMask = new eventType *[ny];
// val=new double*[ny];
@ -86,31 +86,24 @@ class singlePhotonDetector : public analogDetector<uint16_t> {
nphFrame = 0;
};
/**
Destructor. Deletes the cluster structure, event mask, and destroys the mutex.
destructor. Deletes the cluster structure, the pdestalSubtraction and the
image array
*/
virtual ~singlePhotonDetector() {
// std::cout << "#### Debug: Destructing singlePhotonDetector! ####" << std::endl;
if (clusters) { delete[] clusters; clusters = nullptr; }
for (int i = 0; i < ny; i++) {
if (eventMask[i]) { delete[] eventMask[i]; eventMask[i] = nullptr; }
}
if (eventMask) { delete[] eventMask; eventMask = nullptr; }
if (ownsMutex) {
if (fm) {
//pthread_mutex_destroy(fm); // Destroy the mutex (not necessary with std::mutex)
delete fm; // Free the memory allocated for the mutex
fm = nullptr; // Set the pointer to nullptr to avoid dangling pointer
}
}
delete[] clusters;
for (int i = 0; i < ny; i++)
delete[] eventMask[i];
delete[] eventMask;
};
/**
pointer-based copy constructor (cloner)
copy constructor
\param orig detector to be copied
*/
singlePhotonDetector(singlePhotonDetector *orig)
: analogDetector<uint16_t>(orig), fm(orig->fm), ownsMutex(false) {
: analogDetector<uint16_t>(orig) {
nDark = orig->nDark;
myFile = orig->myFile;
@ -133,12 +126,11 @@ class singlePhotonDetector : public analogDetector<uint16_t> {
c3 = sqrt(clusterSizeY * clusterSize);
clusters = new single_photon_hit[nx * ny];
//std::copy(orig->clusters, orig->clusters + (nx * ny), clusters); //possibly superfluous
// cluster=clusters;
setClusterSize(clusterSize);
//fm = orig->fm;
fm = orig->fm;
quad = UNDEFINED_QUADRANT;
tot = 0;
@ -151,67 +143,13 @@ class singlePhotonDetector : public analogDetector<uint16_t> {
}
/**
* copy constructor (deep copy), creates a new mutex
* stricly, TODO: Implement Rule of Five!
* (copy op=, move ctor, and move op= would need to be defined)
*/
singlePhotonDetector(singlePhotonDetector const& other)
: analogDetector<uint16_t>(other), ownsMutex(true) {
//fm = new pthread_mutex_t; // create a new mutex
//pthread_mutex_init(fm, NULL);
fm = new std::mutex(); // New unique mutex per copy
nDark = other.nDark;
myFile = other.myFile;
eventMask = new eventType *[ny];
for (int i = 0; i < ny; i++) {
eventMask[i] = new eventType[nx];
//std::copy(other.eventMask[i], other.eventMask[i] + nx, eventMask[i]);
}
eMin = other.eMin;
eMax = other.eMax;
nSigma = other.nSigma;
clusterSize = other.clusterSize;
clusterSizeY = other.clusterSizeY;
c2 = sqrt((clusterSizeY + 1) / 2 * (clusterSize + 1) / 2);
c3 = sqrt(clusterSizeY * clusterSize);
clusters = new single_photon_hit[nx * ny];
//std::copy(other.clusters, other.clusters + (nx * ny), clusters);
setClusterSize(clusterSize);
quad = other.quad;
tot = other.tot;
quadTot = other.quadTot;
gmap = other.gmap;
nphTot = other.nphTot;
nphFrame = other.nphFrame;
}
/**
Clones the detector structure
duplicates the detector structure
\returns new single photon detector with same parameters
that shares the mutex of the original
*/
virtual singlePhotonDetector *Clone() {
return new singlePhotonDetector(this);
}
/**
Copies the detector structure
\returns new single photon detector with same parameters
that owns a new mutex
*/
virtual singlePhotonDetector* Copy() {
return new singlePhotonDetector(*this); // Calls the copy constructor
}
/** sets/gets number of rms threshold to detect photons
\param n number of sigma to be set (0 or negative gets)
\returns actual number of sigma parameter
@ -443,7 +381,7 @@ class singlePhotonDetector : public analogDetector<uint16_t> {
// int ir, ic;
eventType ee;
double max = 0, tl = 0, tr = 0, bl = 0, br = 0, v = 0;//, *v;
double max = 0, tl = 0, tr = 0, bl = 0, br = 0, *v;
int cm = 0;
int good = 1;
int ir, ic;
@ -465,8 +403,7 @@ class singlePhotonDetector : public analogDetector<uint16_t> {
cm = 1;
}
//double *val = new double[ny * nx];
std::vector<double> val( ny * nx );
double *val = new double[ny * nx];
for (int iy = ymin; iy < ymax; ++iy) {
for (int ix = xmin; ix < xmax; ++ix) {
@ -505,26 +442,18 @@ class singlePhotonDetector : public analogDetector<uint16_t> {
}
//v = &(val[(iy + ir) * nx + ix + ic]);
v = val[(iy + ir) * nx + ix + ic];
//tot += *v;
tot += v;
v = &(val[(iy + ir) * nx + ix + ic]);
tot += *v;
if (ir <= 0 && ic <= 0)
bl += v;
//bl += *v;
bl += *v;
if (ir <= 0 && ic >= 0)
br += v;
//br += *v;
br += *v;
if (ir >= 0 && ic <= 0)
tl += v;
//tl += *v;
tl += *v;
if (ir >= 0 && ic >= 0)
tr += v;
//tr += *v;
//if (*v > max) //{
//max = *v;
if (v > max)
max = v;
tr += *v;
if (*v > max) //{
max = *v;
//}
}
}
@ -632,7 +561,7 @@ class singlePhotonDetector : public analogDetector<uint16_t> {
// cout <<id << " **********************************"<< iframe << " " <<
// det->getFrameNumber(data) << " " << nphFrame << endl;
writeClusters(det->getFrameNumber(data));
//delete[] val;
delete[] val;
return image;
};
@ -738,14 +667,13 @@ class singlePhotonDetector : public analogDetector<uint16_t> {
void writeClusters(int fn) {
if (myFile) {
// cout << "++" << endl;
//pthread_mutex_lock(fm); // This is dangerous! What if writeClusters() throws? Then the mutex is never unlocked!
std::lock_guard<std::mutex> lock(*fm); // safer, RAII-based locking
pthread_mutex_lock(fm);
// cout <<"**********************************"<< fn << " " <<
// nphFrame << endl;
writeClusters(myFile, clusters, nphFrame, fn);
// for (int i=0; i<nphFrame; i++)
// (clusters+i)->write(myFile);
//pthread_mutex_unlock(fm); // unsafe
pthread_mutex_unlock(fm);
// cout << "--" << endl;
}
};
@ -783,14 +711,7 @@ class singlePhotonDetector : public analogDetector<uint16_t> {
ema = eMax;
};
//void setMutex(pthread_mutex_t *m) { fm = m; };
void setMutex(std::mutex* m) {
if (ownsMutex && fm) {
delete fm; // Cleanup old mutex
}
fm = m;
ownsMutex = false;
};
void setMutex(pthread_mutex_t *m) { fm = m; };
protected:
int nDark; /**< number of frames to be used at the beginning of the dataset
@ -812,9 +733,7 @@ class singlePhotonDetector : public analogDetector<uint16_t> {
int nphFrame;
// double **val;
//pthread_mutex_t* fm; // Pointer to the shared mutex
std::mutex* fm; // Pointer to the shared (or unique) mutex (safer version)
bool ownsMutex; // Flag to indicate ownership
pthread_mutex_t *fm;
};
#endif

View File

@ -72,7 +72,7 @@
<enum>QTabWidget::North</enum>
</property>
<property name="currentIndex">
<number>2</number>
<number>3</number>
</property>
<property name="elideMode">
<enum>Qt::ElideLeft</enum>
@ -178,6 +178,309 @@
</item>
</layout>
</widget>
<widget class="QWidget" name="tab_roi">
<property name="enabled">
<bool>false</bool>
</property>
<property name="font">
<font>
<family>Cantarell</family>
<pointsize>10</pointsize>
</font>
</property>
<attribute name="title">
<string>Region of Interest</string>
</attribute>
<layout class="QGridLayout" name="gridLayout_4">
<item row="1" column="0">
<widget class="QLabel" name="label_2">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="font">
<font>
<family>Cantarell</family>
<pointsize>10</pointsize>
</font>
</property>
<property name="text">
<string>X Min:</string>
</property>
</widget>
</item>
<item row="1" column="8">
<widget class="QPushButton" name="btnClearRoi">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>0</width>
<height>35</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>35</height>
</size>
</property>
<property name="font">
<font>
<family>Cantarell</family>
<pointsize>10</pointsize>
</font>
</property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Clear ROI at detector level&lt;/p&gt;&lt;p&gt;#clearroi#&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Clear ROI </string>
</property>
<property name="icon">
<iconset resource="../include/icons.qrc">
<normaloff>:/icons/images/erase.png</normaloff>:/icons/images/erase.png</iconset>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QSpinBox" name="spinXmin">
<property name="minimumSize">
<size>
<width>120</width>
<height>0</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>120</width>
<height>25</height>
</size>
</property>
<property name="font">
<font>
<family>Cantarell</family>
<pointsize>10</pointsize>
</font>
</property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Set ROI at detector level&lt;/p&gt;&lt;p&gt;#roi#&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="minimum">
<number>-1</number>
</property>
<property name="maximum">
<number>1279</number>
</property>
<property name="value">
<number>-1</number>
</property>
</widget>
</item>
<item row="1" column="7">
<spacer name="horizontalSpacer_5">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="1" column="3">
<widget class="QLabel" name="label_3">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="font">
<font>
<family>Cantarell</family>
<pointsize>10</pointsize>
</font>
</property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Set ROI at detector level&lt;/p&gt;&lt;p&gt;#roi#&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>X Max:</string>
</property>
</widget>
</item>
<item row="1" column="2">
<spacer name="horizontalSpacer_4">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="1" column="4">
<widget class="QSpinBox" name="spinXmax">
<property name="minimumSize">
<size>
<width>120</width>
<height>0</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>120</width>
<height>25</height>
</size>
</property>
<property name="font">
<font>
<family>Cantarell</family>
<pointsize>10</pointsize>
</font>
</property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Set ROI at detector level&lt;/p&gt;&lt;p&gt;#roi#&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="minimum">
<number>-1</number>
</property>
<property name="maximum">
<number>1279</number>
</property>
<property name="value">
<number>-1</number>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="font">
<font>
<family>Cantarell</family>
<pointsize>10</pointsize>
</font>
</property>
<property name="text">
<string>Readout: </string>
</property>
</widget>
</item>
<item row="2" column="3">
<spacer name="verticalSpacer_3">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item row="1" column="6">
<widget class="QPushButton" name="btnSetRoi">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>0</width>
<height>35</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>35</height>
</size>
</property>
<property name="font">
<font>
<family>Cantarell</family>
<pointsize>10</pointsize>
</font>
</property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Set ROI at detector level&lt;/p&gt;&lt;p&gt;#roi#&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Set ROI </string>
</property>
<property name="icon">
<iconset resource="../include/icons.qrc">
<normaloff>:/icons/images/refresh.png</normaloff>:/icons/images/refresh.png</iconset>
</property>
</widget>
</item>
<item row="1" column="5">
<spacer name="horizontalSpacer_6">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="0" column="1" colspan="4">
<widget class="QComboBox" name="comboReadout">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>160</width>
<height>0</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>25</height>
</size>
</property>
<property name="font">
<font>
<family>Cantarell</family>
<pointsize>10</pointsize>
</font>
</property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Select readout to set ROI at detector level&lt;/p&gt;&lt;p&gt;#roi#&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
</widget>
</item>
</layout>
</widget>
<widget class="QWidget" name="tab_network">
<property name="font">
<font>
@ -1935,6 +2238,11 @@ Exposure Time of a sub frame. Only for Eiger in 32 bit mode
</widget>
<tabstops>
<tabstop>spinSetAllTrimbits</tabstop>
<tabstop>comboReadout</tabstop>
<tabstop>spinXmin</tabstop>
<tabstop>spinXmax</tabstop>
<tabstop>btnSetRoi</tabstop>
<tabstop>btnClearRoi</tabstop>
<tabstop>comboDetector</tabstop>
<tabstop>spinControlPort</tabstop>
<tabstop>spinStopPort</tabstop>

View File

@ -38,10 +38,13 @@
<string>Form</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="4" column="5">
<widget class="QSpinBox" name="spinThreshold2">
<property name="enabled">
<bool>false</bool>
<item row="1" column="2" colspan="3">
<widget class="QComboBox" name="comboHV">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
@ -62,42 +65,115 @@
</font>
</property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Threshold energy of 2nd counter&lt;/p&gt;&lt;p&gt;#threshold#&lt;/p&gt;&lt;p&gt;&lt;br/&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;High Voltage&lt;/p&gt;&lt;p&gt; #highvoltage#&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="keyboardTracking">
<bool>false</bool>
<item>
<property name="text">
<string>0</string>
</property>
<property name="suffix">
<string> eV</string>
</item>
<item>
<property name="text">
<string>90</string>
</property>
<property name="minimum">
<number>-100000</number>
</item>
<item>
<property name="text">
<string>110</string>
</property>
<property name="maximum">
<number>100000</number>
</item>
<item>
<property name="text">
<string>120</string>
</property>
<property name="singleStep">
<number>100</number>
</item>
<item>
<property name="text">
<string>150</string>
</property>
<property name="value">
<number>-1</number>
</item>
<item>
<property name="text">
<string>180</string>
</property>
</item>
<item>
<property name="text">
<string>200</string>
</property>
</item>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="lblSettings">
<property name="enabled">
<bool>true</bool>
</property>
<property name="minimumSize">
<size>
<width>110</width>
<height>0</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>110</width>
<height>16777215</height>
</size>
</property>
<property name="font">
<font>
<family>Cantarell</family>
<pointsize>10</pointsize>
</font>
</property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Settings of the detector. &lt;/p&gt;&lt;p&gt; #settings#&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Settings:</string>
</property>
</widget>
</item>
<item row="4" column="9">
<spacer name="horizontalSpacer_4">
<item row="1" column="0">
<widget class="QLabel" name="lblComboHV">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="font">
<font>
<family>Cantarell</family>
<pointsize>10</pointsize>
</font>
</property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;High Voltage&lt;/p&gt;&lt;p&gt; #highvoltage#&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>High Voltage: </string>
</property>
</widget>
</item>
<item row="8" column="2">
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
<enum>Qt::Vertical</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Expanding</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<width>20</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="6" column="4">
<item row="7" column="4">
<widget class="QCheckBox" name="chkCounter3">
<property name="enabled">
<bool>false</bool>
@ -125,7 +201,29 @@
</property>
</widget>
</item>
<item row="4" column="7">
<item row="2" column="0">
<widget class="QLabel" name="lblSpinHV">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="font">
<font>
<family>Cantarell</family>
<pointsize>10</pointsize>
</font>
</property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;High Voltage. Range: 60 - 200V. Swich off high voltage by setting to 0.&lt;/p&gt;&lt;p&gt;-1 corresponds to different values from detectors.&lt;/p&gt;&lt;p&gt;#highvoltage#&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>High Voltage: </string>
</property>
</widget>
</item>
<item row="5" column="7">
<spacer name="horizontalSpacer_3">
<property name="orientation">
<enum>Qt::Horizontal</enum>
@ -141,7 +239,97 @@
</property>
</spacer>
</item>
<item row="1" column="2" colspan="3">
<item row="7" column="2">
<widget class="QCheckBox" name="chkCounter1">
<property name="enabled">
<bool>false</bool>
</property>
<property name="maximumSize">
<size>
<width>50</width>
<height>16777215</height>
</size>
</property>
<property name="font">
<font>
<family>Cantarell</family>
<pointsize>10</pointsize>
</font>
</property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Enable 1st counter&lt;/p&gt;&lt;p&gt;#counters#&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>1</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item row="5" column="0">
<widget class="QLabel" name="lblThreshold">
<property name="enabled">
<bool>false</bool>
</property>
<property name="minimumSize">
<size>
<width>110</width>
<height>0</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>110</width>
<height>16777215</height>
</size>
</property>
<property name="font">
<font>
<family>Cantarell</family>
<pointsize>10</pointsize>
</font>
</property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Threshold energy. The trim energy values need to be loaded first using &amp;quot;trimen&amp;quot;&lt;/p&gt;&lt;p&gt;#threshold#&lt;/p&gt;&lt;p&gt;#trimen#&lt;/p&gt;&lt;p&gt;&lt;br/&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Threshold:</string>
</property>
</widget>
</item>
<item row="6" column="0">
<widget class="QLabel" name="lblDynamicRange">
<property name="enabled">
<bool>false</bool>
</property>
<property name="minimumSize">
<size>
<width>110</width>
<height>0</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>110</width>
<height>16777215</height>
</size>
</property>
<property name="font">
<font>
<family>Cantarell</family>
<pointsize>10</pointsize>
</font>
</property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Dynamic Range of pixel/channel of detector&lt;/p&gt;&lt;p&gt;#dr#&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Dynamic Range:</string>
</property>
</widget>
</item>
<item row="2" column="2" colspan="3">
<widget class="QSpinBox" name="spinHV">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
@ -181,8 +369,8 @@
</property>
</widget>
</item>
<item row="6" column="2">
<widget class="QCheckBox" name="chkCounter1">
<item row="7" column="3">
<widget class="QCheckBox" name="chkCounter2">
<property name="enabled">
<bool>false</bool>
</property>
@ -199,222 +387,17 @@
</font>
</property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Enable 1st counter&lt;/p&gt;&lt;p&gt;#counters#&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Enable 2nd counter&lt;/p&gt;&lt;p&gt;#counters#&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>1</string>
<string>2</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item row="7" column="2">
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Expanding</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="0" column="0">
<spacer name="horizontalSpacer_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="4" column="6">
<widget class="QSpinBox" name="spinThreshold3">
<property name="enabled">
<bool>false</bool>
</property>
<property name="minimumSize">
<size>
<width>140</width>
<height>25</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>140</width>
<height>25</height>
</size>
</property>
<property name="font">
<font>
<family>Cantarell</family>
<pointsize>10</pointsize>
</font>
</property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Threshold energy of 3rd counter&lt;/p&gt;&lt;p&gt;#threshold#&lt;/p&gt;&lt;p&gt;&lt;br/&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="keyboardTracking">
<bool>false</bool>
</property>
<property name="suffix">
<string> eV</string>
</property>
<property name="minimum">
<number>-100000</number>
</property>
<property name="maximum">
<number>100000</number>
</property>
<property name="singleStep">
<number>100</number>
</property>
<property name="value">
<number>-1</number>
</property>
</widget>
</item>
<item row="4" column="2" colspan="3">
<widget class="QSpinBox" name="spinThreshold">
<property name="enabled">
<bool>false</bool>
</property>
<property name="minimumSize">
<size>
<width>140</width>
<height>25</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>140</width>
<height>25</height>
</size>
</property>
<property name="font">
<font>
<family>Cantarell</family>
<pointsize>10</pointsize>
</font>
</property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Threshold energy. The trim energy values need to be loaded first using &amp;quot;trimen&amp;quot;&lt;/p&gt;&lt;p&gt;#threshold#&lt;/p&gt;&lt;p&gt;#trimen#&lt;/p&gt;&lt;p&gt;&lt;br/&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="keyboardTracking">
<bool>false</bool>
</property>
<property name="suffix">
<string> eV</string>
</property>
<property name="minimum">
<number>-100000</number>
</property>
<property name="maximum">
<number>100000</number>
</property>
<property name="singleStep">
<number>100</number>
</property>
<property name="value">
<number>-1</number>
</property>
</widget>
</item>
<item row="5" column="2" colspan="3">
<widget class="QComboBox" name="comboDynamicRange">
<property name="enabled">
<bool>false</bool>
</property>
<property name="minimumSize">
<size>
<width>0</width>
<height>25</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>140</width>
<height>25</height>
</size>
</property>
<property name="font">
<font>
<family>Cantarell</family>
<pointsize>10</pointsize>
</font>
</property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Dynamic Range of pixel/channel of detector&lt;/p&gt;&lt;p&gt;#dr#&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<item>
<property name="text">
<string>1.67772e+07</string>
</property>
</item>
<item>
<property name="text">
<string>65535</string>
</property>
</item>
<item>
<property name="text">
<string>4095</string>
</property>
</item>
<item>
<property name="text">
<string>255</string>
</property>
</item>
<item>
<property name="text">
<string>7</string>
</property>
</item>
</widget>
</item>
<item row="6" column="0">
<widget class="QLabel" name="lblCounter">
<property name="enabled">
<bool>false</bool>
</property>
<property name="minimumSize">
<size>
<width>110</width>
<height>0</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>110</width>
<height>16777215</height>
</size>
</property>
<property name="font">
<font>
<family>Cantarell</family>
<pointsize>10</pointsize>
</font>
</property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Enable counters&lt;/p&gt;&lt;p&gt;#counters#&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Counters:</string>
</property>
</widget>
</item>
<item row="2" column="2" colspan="3">
<item row="3" column="2" colspan="3">
<widget class="QComboBox" name="comboSettings">
<property name="enabled">
<bool>true</bool>
@ -559,7 +542,7 @@
</item>
</widget>
</item>
<item row="4" column="8">
<item row="5" column="8">
<widget class="QPushButton" name="btnSetThreshold">
<property name="enabled">
<bool>true</bool>
@ -643,7 +626,130 @@
</property>
</widget>
</item>
<item row="3" column="2" colspan="3">
<item row="4" column="0">
<widget class="QLabel" name="lblGainMode">
<property name="enabled">
<bool>false</bool>
</property>
<property name="minimumSize">
<size>
<width>110</width>
<height>0</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>110</width>
<height>16777215</height>
</size>
</property>
<property name="font">
<font>
<family>Cantarell</family>
<pointsize>10</pointsize>
</font>
</property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Gain Mode of the detector&lt;/p&gt;&lt;p&gt;#gainmode#&lt;/p&gt;&lt;p&gt;&lt;br/&gt;&lt;/p&gt;&lt;p&gt;Fix G0 is to be used with utmost caution. Can damage the detector!&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Gain Mode:</string>
</property>
</widget>
</item>
<item row="5" column="2" colspan="3">
<widget class="QSpinBox" name="spinThreshold">
<property name="enabled">
<bool>false</bool>
</property>
<property name="minimumSize">
<size>
<width>140</width>
<height>25</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>140</width>
<height>25</height>
</size>
</property>
<property name="font">
<font>
<family>Cantarell</family>
<pointsize>10</pointsize>
</font>
</property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Threshold energy. The trim energy values need to be loaded first using &amp;quot;trimen&amp;quot;&lt;/p&gt;&lt;p&gt;#threshold#&lt;/p&gt;&lt;p&gt;#trimen#&lt;/p&gt;&lt;p&gt;&lt;br/&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="keyboardTracking">
<bool>false</bool>
</property>
<property name="suffix">
<string> eV</string>
</property>
<property name="minimum">
<number>-100000</number>
</property>
<property name="maximum">
<number>100000</number>
</property>
<property name="singleStep">
<number>100</number>
</property>
<property name="value">
<number>-1</number>
</property>
</widget>
</item>
<item row="5" column="5">
<widget class="QSpinBox" name="spinThreshold2">
<property name="enabled">
<bool>false</bool>
</property>
<property name="minimumSize">
<size>
<width>140</width>
<height>25</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>140</width>
<height>25</height>
</size>
</property>
<property name="font">
<font>
<family>Cantarell</family>
<pointsize>10</pointsize>
</font>
</property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Threshold energy of 2nd counter&lt;/p&gt;&lt;p&gt;#threshold#&lt;/p&gt;&lt;p&gt;&lt;br/&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="keyboardTracking">
<bool>false</bool>
</property>
<property name="suffix">
<string> eV</string>
</property>
<property name="minimum">
<number>-100000</number>
</property>
<property name="maximum">
<number>100000</number>
</property>
<property name="singleStep">
<number>100</number>
</property>
<property name="value">
<number>-1</number>
</property>
</widget>
</item>
<item row="4" column="2" colspan="3">
<widget class="QComboBox" name="comboGainMode">
<property name="enabled">
<bool>false</bool>
@ -707,15 +813,21 @@
</item>
</widget>
</item>
<item row="6" column="3">
<widget class="QCheckBox" name="chkCounter2">
<item row="5" column="6">
<widget class="QSpinBox" name="spinThreshold3">
<property name="enabled">
<bool>false</bool>
</property>
<property name="minimumSize">
<size>
<width>140</width>
<height>25</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>50</width>
<height>16777215</height>
<width>140</width>
<height>25</height>
</size>
</property>
<property name="font">
@ -725,31 +837,43 @@
</font>
</property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Enable 2nd counter&lt;/p&gt;&lt;p&gt;#counters#&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Threshold energy of 3rd counter&lt;/p&gt;&lt;p&gt;#threshold#&lt;/p&gt;&lt;p&gt;&lt;br/&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>2</string>
<property name="keyboardTracking">
<bool>false</bool>
</property>
<property name="checked">
<bool>true</bool>
<property name="suffix">
<string> eV</string>
</property>
<property name="minimum">
<number>-100000</number>
</property>
<property name="maximum">
<number>100000</number>
</property>
<property name="singleStep">
<number>100</number>
</property>
<property name="value">
<number>-1</number>
</property>
</widget>
</item>
<item row="5" column="0">
<widget class="QLabel" name="lblDynamicRange">
<item row="6" column="2" colspan="3">
<widget class="QComboBox" name="comboDynamicRange">
<property name="enabled">
<bool>false</bool>
</property>
<property name="minimumSize">
<size>
<width>110</width>
<height>0</height>
<width>0</width>
<height>25</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>110</width>
<height>16777215</height>
<width>140</width>
<height>25</height>
</size>
</property>
<property name="font">
@ -761,43 +885,34 @@
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Dynamic Range of pixel/channel of detector&lt;/p&gt;&lt;p&gt;#dr#&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<item>
<property name="text">
<string>Dynamic Range:</string>
<string>1.67772e+07</string>
</property>
</item>
<item>
<property name="text">
<string>65535</string>
</property>
</item>
<item>
<property name="text">
<string>4095</string>
</property>
</item>
<item>
<property name="text">
<string>255</string>
</property>
</item>
<item>
<property name="text">
<string>7</string>
</property>
</item>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="lblSettings">
<property name="enabled">
<bool>true</bool>
</property>
<property name="minimumSize">
<size>
<width>110</width>
<height>0</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>110</width>
<height>16777215</height>
</size>
</property>
<property name="font">
<font>
<family>Cantarell</family>
<pointsize>10</pointsize>
</font>
</property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Settings of the detector. &lt;/p&gt;&lt;p&gt; #settings#&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Settings:</string>
</property>
</widget>
</item>
<item row="2" column="1">
<item row="3" column="1">
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
@ -813,8 +928,21 @@
</property>
</spacer>
</item>
<item row="4" column="0">
<widget class="QLabel" name="lblThreshold">
<item row="0" column="0">
<spacer name="horizontalSpacer_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="7" column="0">
<widget class="QLabel" name="lblCounter">
<property name="enabled">
<bool>false</bool>
</property>
@ -837,69 +965,30 @@
</font>
</property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Threshold energy. The trim energy values need to be loaded first using &amp;quot;trimen&amp;quot;&lt;/p&gt;&lt;p&gt;#threshold#&lt;/p&gt;&lt;p&gt;#trimen#&lt;/p&gt;&lt;p&gt;&lt;br/&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Enable counters&lt;/p&gt;&lt;p&gt;#counters#&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Threshold:</string>
<string>Counters:</string>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="lblGainMode">
<property name="enabled">
<bool>false</bool>
<item row="5" column="9">
<spacer name="horizontalSpacer_4">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="minimumSize">
<property name="sizeHint" stdset="0">
<size>
<width>110</width>
<height>0</height>
<width>40</width>
<height>20</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>110</width>
<height>16777215</height>
</size>
</property>
<property name="font">
<font>
<family>Cantarell</family>
<pointsize>10</pointsize>
</font>
</property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Gain Mode of the detector&lt;/p&gt;&lt;p&gt;#gainmode#&lt;/p&gt;&lt;p&gt;&lt;br/&gt;&lt;/p&gt;&lt;p&gt;Fix G0 is to be used with utmost caution. Can damage the detector!&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Gain Mode:</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="lblSpinHV">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="font">
<font>
<family>Cantarell</family>
<pointsize>10</pointsize>
</font>
</property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;High Voltage. Range: 60 - 200V. Swich off high voltage by setting to 0.&lt;/p&gt;&lt;p&gt;-1 corresponds to different values from detectors.&lt;/p&gt;&lt;p&gt;#highvoltage#&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>High Voltage: </string>
</property>
</widget>
</spacer>
</item>
</layout>
</widget>
<tabstops>
<tabstop>comboHV</tabstop>
<tabstop>spinHV</tabstop>
<tabstop>comboSettings</tabstop>
<tabstop>comboGainMode</tabstop>

View File

@ -38,6 +38,9 @@ class qTabAdvanced : public QWidget, private Ui::TabAdvancedObject {
void SetRxrUDPMAC(bool force = false);
void ForceSetRxrUDPMAC();
void SetRxrZMQPort(int port);
void GetROI();
void ClearROI();
void SetROI();
void SetAllTrimbits();
void SetNumStoragecells(int value);
void SetSubExposureTime();

View File

@ -192,6 +192,7 @@ void qDetectorMain::SetUpDetector(const std::string &config_file, int multiID) {
actionLoadTrimbits->setEnabled(true);
actionSaveTrimbits->setEnabled(true);
break;
case slsDetectorDefs::GOTTHARD:
case slsDetectorDefs::JUNGFRAU:
case slsDetectorDefs::MOENCH:
case slsDetectorDefs::GOTTHARD2:
@ -404,12 +405,12 @@ void qDetectorMain::ExecuteUtilities(QAction *action) {
void qDetectorMain::ExecuteHelp(QAction *action) {
if (action == actionAbout) {
LOG(logDEBUG) << "About Common GUI for Jungfrau, Eiger, Mythen3, "
"Gotthard2 and Moench detectors";
LOG(logINFO) << "About Common GUI for Jungfrau, Eiger, Mythen3, "
"Gotthard, Gotthard2 and Moench detectors";
std::string packageVersion = "unknown";
std::string clientVersion = "unknown";
try {
packageVersion = det->getPackageVersion();
clientVersion = det->getClientVersion();
}
CATCH_DISPLAY("Could not get client version.",
"qDetectorMain::ExecuteHelp")
@ -418,12 +419,12 @@ void qDetectorMain::ExecuteHelp(QAction *action) {
qDefs::INFORMATION,
"<p style=\"font-family:verdana;\">"
"<b>SLS Detector Package: v" +
packageVersion +
"<b>SLS Detector Client version: " +
clientVersion +
"</b><br><br>"
"Common GUI to control the SLS Detectors: "
"Jungfrau, Eiger, Mythen3, Gotthard2 and "
"Jungfrau, Eiger, Mythen3, Gotthard, Gotthard2 and "
"Moench.<br><br>"
"It can be operated in parallel with the command "

View File

@ -83,7 +83,9 @@ void qDrawPlot::SetupWidgetWindow() {
fileSaveName = "Image";
}
gotthard25 = (detType == slsDetectorDefs::GOTTHARD2 && det->size() == 2);
gotthard25 = ((detType == slsDetectorDefs::GOTTHARD2 ||
detType == slsDetectorDefs::GOTTHARD) &&
det->size() == 2);
SetupPlots();
SetDataCallBack(true);

View File

@ -28,6 +28,9 @@ void qTabAdvanced::SetupWidgetWindow() {
spinSubDeadTime->setEnabled(true);
comboSubDeadTimeUnit->setEnabled(true);
break;
case slsDetectorDefs::GOTTHARD:
tab_roi->setEnabled(true);
break;
case slsDetectorDefs::MYTHEN3:
tab_trimming->setEnabled(true);
lblDiscardBits->setEnabled(true);
@ -111,6 +114,14 @@ void qTabAdvanced::Initialization() {
connect(spinRxrZMQPort, SIGNAL(valueChanged(int)), this,
SLOT(SetRxrZMQPort(int)));
// roi
if (tab_roi->isEnabled()) {
connect(comboReadout, SIGNAL(currentIndexChanged(int)), this,
SLOT(GetROI()));
connect(btnSetRoi, SIGNAL(clicked()), this, SLOT(SetROI()));
connect(btnClearRoi, SIGNAL(clicked()), this, SLOT(ClearROI()));
}
// storage cells
if (lblNumStoragecells->isEnabled()) {
connect(spinNumStoragecells, SIGNAL(valueChanged(int)), this,
@ -162,16 +173,23 @@ void qTabAdvanced::PopulateDetectors() {
LOG(logDEBUG) << "Populating detectors";
disconnect(comboDetector, SIGNAL(currentIndexChanged(int)), this,
SLOT(SetDetector()));
disconnect(comboReadout, SIGNAL(currentIndexChanged(int)), this,
SLOT(GetROI()));
comboDetector->clear();
comboReadout->clear();
auto res = det->getHostname();
for (auto &it : res) {
comboDetector->addItem(QString(it.c_str()));
comboReadout->addItem(QString(it.c_str()));
}
comboDetector->setCurrentIndex(0);
comboReadout->setCurrentIndex(0);
connect(comboDetector, SIGNAL(currentIndexChanged(int)), this,
SLOT(SetDetector()));
connect(comboReadout, SIGNAL(currentIndexChanged(int)), this,
SLOT(GetROI()));
}
void qTabAdvanced::GetControlPort() {
@ -552,6 +570,40 @@ void qTabAdvanced::SetRxrZMQPort(int port) {
&qTabAdvanced::GetRxrZMQPort)
}
void qTabAdvanced::GetROI() {
LOG(logDEBUG) << "Getting ROI";
try {
slsDetectorDefs::ROI roi =
det->getROI({comboReadout->currentIndex()})[0];
spinXmin->setValue(roi.xmin);
spinXmax->setValue(roi.xmax);
}
CATCH_DISPLAY("Could not get ROI.", "qTabAdvanced::GetROI")
}
void qTabAdvanced::ClearROI() {
LOG(logINFO) << "Clearing ROI";
spinXmin->setValue(-1);
spinXmax->setValue(-1);
SetROI();
LOG(logDEBUG) << "ROIs cleared";
}
void qTabAdvanced::SetROI() {
slsDetectorDefs::ROI roi(spinXmin->value(), spinXmax->value());
// set roi
LOG(logINFO) << "Setting ROI: [" << roi.xmin << ", " << roi.xmax << "]";
try {
det->setROI(roi, {comboReadout->currentIndex()});
}
CATCH_DISPLAY("Could not set these ROIs.", "qTabAdvanced::SetROI")
// update corrected list
GetROI();
}
void qTabAdvanced::GetAllTrimbits() {
LOG(logDEBUG) << "Getting all trimbits value";
disconnect(spinSetAllTrimbits, SIGNAL(valueChanged(int)), this,
@ -779,6 +831,11 @@ void qTabAdvanced::Refresh() {
// update all network widgets
SetDetector();
// roi
if (tab_roi->isEnabled()) {
GetROI();
}
// storage cells
if (lblNumStoragecells->isEnabled()) {
GetNumStoragecells();

View File

@ -34,6 +34,15 @@ void qTabDeveloper::SetupWidgetWindow() {
new qDacWidget(this, det, false, sls::ToString(it), it));
}
break;
case slsDetectorDefs::GOTTHARD:
ind = slsDetectorDefs::TEMPERATURE_ADC;
adcWidgets.push_back(
new qDacWidget(this, det, false, sls::ToString(ind), ind));
ind = slsDetectorDefs::TEMPERATURE_FPGA;
adcWidgets.push_back(
new qDacWidget(this, det, false, sls::ToString(ind), ind));
break;
case slsDetectorDefs::JUNGFRAU:
ind = slsDetectorDefs::TEMPERATURE_ADC;
adcWidgets.push_back(

View File

@ -47,6 +47,7 @@ void qTabPlot::SetupWidgetWindow() {
// enabling according to det type
is1d = false;
switch (det->getDetectorType().squash()) {
case slsDetectorDefs::GOTTHARD:
case slsDetectorDefs::MYTHEN3:
is1d = true;
break;

View File

@ -18,6 +18,8 @@ qTabSettings::qTabSettings(QWidget *parent, Detector *detector)
qTabSettings::~qTabSettings() {}
void qTabSettings::SetupWidgetWindow() {
comboHV->hide();
lblComboHV->hide();
lblSpinHV->hide();
spinHV->hide();
hvmin = HV_MIN;
@ -98,6 +100,9 @@ void qTabSettings::SetupWidgetWindow() {
} else if (detType == slsDetectorDefs::MOENCH) {
lblSpinHV->show();
spinHV->show();
} else if (detType == slsDetectorDefs::GOTTHARD) {
comboHV->show();
lblComboHV->show();
} else if (detType == slsDetectorDefs::GOTTHARD2) {
lblSpinHV->show();
spinHV->show();
@ -184,6 +189,8 @@ void qTabSettings::ShowFixG0(bool expertMode) {
void qTabSettings::Initialization() {
// High voltage
connect(comboHV, SIGNAL(currentIndexChanged(int)), this,
SLOT(SetHighVoltage()));
connect(spinHV, SIGNAL(valueChanged(int)), this, SLOT(SetHighVoltage()));
// Settings
@ -224,10 +231,12 @@ void qTabSettings::Initialization() {
void qTabSettings::GetHighVoltage() {
// not enabled for eiger
if (!spinHV->isVisible())
if (!comboHV->isVisible() && !spinHV->isVisible())
return;
LOG(logDEBUG) << "Getting High Voltage";
disconnect(spinHV, SIGNAL(valueChanged(int)), this, SLOT(SetHighVoltage()));
disconnect(comboHV, SIGNAL(currentIndexChanged(int)), this,
SLOT(SetHighVoltage()));
try {
Result<int> retvals = det->getHighVoltage();
@ -249,19 +258,55 @@ void qTabSettings::GetHighVoltage() {
master_retvals.tsquash("Inconsistent values for high voltage.");
}
// spinHV
if (spinHV->isVisible()) {
if (retval != 0 && retval < hvmin && retval > HV_MAX) {
throw RuntimeError(std::string("Unknown High Voltage: ") +
std::to_string(retval));
}
spinHV->setValue(retval);
}
// combo HV
else {
switch (retval) {
case 0:
comboHV->setCurrentIndex(HV_0);
break;
case 90:
comboHV->setCurrentIndex(HV_90);
break;
case 110:
comboHV->setCurrentIndex(HV_110);
break;
case 120:
comboHV->setCurrentIndex(HV_120);
break;
case 150:
comboHV->setCurrentIndex(HV_150);
break;
case 180:
comboHV->setCurrentIndex(HV_180);
break;
case 200:
comboHV->setCurrentIndex(HV_200);
break;
default:
throw RuntimeError(std::string("Unknown High Voltage: ") +
std::to_string(retval));
}
}
}
CATCH_DISPLAY("Could not get high voltage.", "qTabSettings::GetHighVoltage")
connect(spinHV, SIGNAL(valueChanged(int)), this, SLOT(SetHighVoltage()));
connect(comboHV, SIGNAL(currentIndexChanged(int)), this,
SLOT(SetHighVoltage()));
}
void qTabSettings::SetHighVoltage() {
int val = spinHV->value();
int val = (comboHV->isVisible() ? comboHV->currentText().toInt()
: spinHV->value());
LOG(logINFO) << "Setting high voltage:" << val;
try {
det->setHighVoltage(val);
}

View File

@ -13,6 +13,7 @@ install(TARGETS slsProjectCSettings
add_subdirectory(ctbDetectorServer)
add_subdirectory(xilinx_ctbDetectorServer)
add_subdirectory(eigerDetectorServer)
add_subdirectory(gotthardDetectorServer)
add_subdirectory(jungfrauDetectorServer)
add_subdirectory(mythen3DetectorServer)
add_subdirectory(gotthard2DetectorServer)

27
slsDetectorServers/compileAllServers.sh Normal file → Executable file
View File

@ -1,16 +1,20 @@
# SPDX-License-Identifier: LGPL-3.0-or-other
# Copyright (C) 2021 Contributors to the SLS Detector Package
# empty branch = developer branch in updateAPIVersion.sh
branch=""
det_list=("ctbDetectorServer
gotthardDetectorServer
gotthard2DetectorServer
jungfrauDetectorServer
mythen3DetectorServer
moenchDetectorServer
xilinx_ctbDetectorServer"
)
usage="\nUsage: compileAllServers.sh [server|all(opt)] [branch(opt)]. \n\tNo arguments mean all servers with 'developer' branch. \n\tNo 'branch' input means 'developer branch'"
usage="\nUsage: compileAllServers.sh [server|all(opt)] [update_api(opt)]. \n\tNo arguments mean all servers with 'developer' branch. \n\tupdate_api if true updates the api to version in VERSION file"
update_api=true
target=version
# arguments
if [ $# -eq 0 ]; then
@ -34,15 +38,12 @@ elif [ $# -eq 1 ] || [ $# -eq 2 ]; then
declare -a det=("${1}")
#echo "Compiling only $1"
fi
# branch
if [ $# -eq 2 ]; then
# arg in list
if [[ $det_list == *$2* ]]; then
echo -e "Invalid argument 2: $2. $usage"
return 1
update_api=$2
if not $update_api ; then
target=clean
fi
branch+=$2
#echo "with branch $branch"
fi
else
echo -e "Too many arguments.$usage"
@ -53,6 +54,9 @@ declare -a deterror=("OK" "OK" "OK" "OK" "OK" "OK")
echo -e "list is ${det[@]}"
if $update_api; then
echo "updating api to $(cat ../VERSION)"
fi
# compile each server
idet=0
for i in ${det[@]}
@ -62,14 +66,13 @@ do
echo -e "Compiling $dir [$file]"
cd $dir
make clean
if make version API_BRANCH=$branch; then
if make $target; then
deterror[$idet]="OK"
else
deterror[$idet]="FAIL"
fi
mv bin/$dir bin/$file
git add -f bin/$file
cp bin/$file /tftpboot/
cd ..
echo -e "\n\n"
((++idet))

View File

@ -1,86 +0,0 @@
# SPDX-License-Identifier: LGPL-3.0-or-other
# Copyright (C) 2021 Contributors to the SLS Detector Package
# empty branch = developer branch in updateAPIVersion.sh
branch=""
det_list=("ctbDetectorServer"
"gotthard2DetectorServer"
"jungfrauDetectorServer"
"mythen3DetectorServer"
"moenchDetectorServer"
"xilinx_ctbDetectorServer"
)
usage="\nUsage: compileAllServers.sh [server|all(opt)] [branch(opt)]. \n\tNo arguments mean all servers with 'developer' branch. \n\tNo 'branch' input means 'developer branch'"
# arguments
if [ $# -eq 0 ]; then
# no argument, all servers
declare -a det=${det_list[@]}
echo "Compiling all servers"
elif [ $# -eq 1 ] || [ $# -eq 2 ]; then
# 'all' servers
if [[ $1 == "all" ]]; then
declare -a det=${det_list[@]}
echo "Compiling all servers"
else
# only one server
# arg not in list
if [[ $det_list != *$1* ]]; then
echo -e "Invalid argument 1: $1. $usage"
return -1
fi
declare -a det=("${1}")
#echo "Compiling only $1"
fi
# branch
if [ $# -eq 2 ]; then
# arg in list
if [[ $det_list == *$2* ]]; then
echo -e "Invalid argument 2: $2. $usage"
return -1
fi
branch+=$2
#echo "with branch $branch"
fi
else
echo -e "Too many arguments.$usage"
return -1
fi
declare -a deterror=("OK" "OK" "OK" "OK" "OK" "OK")
echo -e "list is ${det[@]}"
# compile each server
idet=0
for i in ${det[@]}
do
dir=$i
file="${i}_developer"
echo -e "Compiling $dir [$file]"
cd $dir
make clean
if make API_BRANCH=$branch; then
deterror[$idet]="OK"
else
deterror[$idet]="FAIL"
fi
mv bin/$dir bin/$file
git add -f bin/$file
cp bin/$file /tftpboot/
cd ..
echo -e "\n\n"
((++idet))
done
echo -e "Results:"
idet=0
for i in ${det[@]}
do
printf "%s\t\t= %s\n" "$i" "${deterror[$idet]}"
((++idet))
done

23
slsDetectorServers/compileEigerServer.sh Normal file → Executable file
View File

@ -3,21 +3,31 @@
deterror="OK"
dir="eigerDetectorServer"
file="${dir}_developer"
branch=""
usage="\nUsage: compileAllServers.sh [update_api(opt)]. \n\t update_api if true updates the api to version in VERSION file"
update_api=true
target=version
# arguments
if [ $# -eq 1 ]; then
branch+=$1
#echo "with branch $branch"
update_api=$1
if not $update_api ; then
target=clean
fi
elif [ ! $# -eq 0 ]; then
echo -e "Only one optional argument allowed for branch."
echo -e "Only one optional argument allowed for update_api."
return -1
fi
if $update_api; then
echo "updating api to $(cat ../VERSION)"
fi
echo -e "Compiling $dir [$file]"
cd $dir
make clean
if make version API_BRANCH=$branch; then
if make $target; then
deterror="OK"
else
deterror="FAIL"
@ -25,7 +35,6 @@ fi
mv bin/$dir bin/$file
git add -f bin/$file
cp bin/$file /tftpboot/
cd ..
echo -e "\n\n"
printf "Result:\t\t= %s\n" "${deterror}"

View File

@ -25,11 +25,10 @@ version: clean versioning $(PROGS)
boot: $(OBJS)
version_branch=$(API_BRANCH)
version_name=APICTB
version_path=slsDetectorServers/ctbDetectorServer
versioning:
cd ../../ && echo $(PWD) && echo `tput setaf 6; ./updateAPIVersion.sh $(version_name) $(version_path) $(version_branch); tput sgr0;`
cd ../../ && echo $(PWD) && echo `tput setaf 6; python updateAPIVersion.py $(version_name) $(version_path); tput sgr0;`
$(PROGS): $(OBJS)

View File

@ -15,7 +15,6 @@
#include "loadPattern.h"
#include <netinet/in.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h> // usleep
#ifdef VIRTUAL
@ -1096,17 +1095,26 @@ int setNumTransceiverSamples(int val) {
int getNumTransceiverSamples() { return ntSamples; }
int setExpTime(int64_t val) {
setPatternWaitInterval(0, val);
if (val < 0) {
LOG(logERROR, ("Invalid exptime: %lld ns\n", (long long int)val));
return FAIL;
}
LOG(logINFO, ("Setting exptime %lld ns\n", (long long int)val));
val *= (1E-3 * clkFrequency[RUN_CLK]);
setPatternWaitTime(0, val);
// validate for tolerance
int64_t retval = getExpTime();
val /= (1E-3 * clkFrequency[RUN_CLK]);
if (val != retval) {
return FAIL;
}
return OK;
}
int64_t getExpTime() { return getPatternWaitInterval(0); }
int64_t getExpTime() {
return getPatternWaitTime(0) / (1E-3 * clkFrequency[RUN_CLK]);
}
int setPeriod(int64_t val) {
if (val < 0) {
@ -2259,23 +2267,11 @@ void *start_timer(void *arg) {
int packetsPerFrame = ceil((double)imageSize / (double)dataSize);
// Generate Data
char *imageData = (char *)malloc(imageSize);
char imageData[imageSize];
memset(imageData, 0, imageSize);
if (imageData == NULL) {
LOG(logERROR, ("Can not allocate image Data RAM."
"Probable cause: Memory Leak.\n"));
return NULL;
}
/*
for (int i = 0; i < imageSize; i += sizeof(uint16_t)) {
*((uint16_t *)(imageData + i)) = i;
}
*/
for (int i = 0; i < imageSize; i += 2 * sizeof(uint64_t)) {
*((uint64_t *)(imageData + i)) = 0xffffffffffffffff;
}
// Send data
uint64_t frameNr = 0;
@ -2332,8 +2328,6 @@ void *start_timer(void *arg) {
setNextFrameNumber(frameNr + numFrames);
}
free(imageData);
closeUDPSocket(0);
sharedMemory_setStatus(IDLE);

View File

@ -25,11 +25,10 @@ version: clean versioning $(PROGS) #hv9m_blackfin_server
boot: $(OBJS)
version_branch=$(API_BRANCH)
version_name=APIEIGER
version_path=slsDetectorServers/eigerDetectorServer
versioning:
cd ../../ && echo $(PWD) && echo `tput setaf 6; ./updateAPIVersion.sh $(version_name) $(version_path) $(version_branch); tput sgr0;`
cd ../../ && echo $(PWD) && echo `tput setaf 6; python updateAPIVersion.py $(version_name) $(version_path); tput sgr0;`
$(PROGS): $(OBJS)

Some files were not shown because too many files have changed in this diff Show More