diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 8fbfdfc0..78c95e6d 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -65,11 +65,11 @@ build:x86:vitis_hls: rules: - if: '$CI_PIPELINE_SOURCE == "push"' changes: - - receiver/hls/* - - receiver/hdl/* - - receiver/scripts/* - - receiver/xdc/* - - receiver/microblaze/* + - fpga/hls/* + - fpga/hdl/* + - fpga/scripts/* + - fpga/xdc/* + - fpga/microblaze/* - common/Definitions.h script: - source /opt/Xilinx/Vitis_HLS/2022.1/settings64.sh @@ -185,8 +185,7 @@ test:x86:xia2.ssx: - source /usr/local/dials-v3-13-0/dials_env.sh - xia2.ssx image=writing_test_master.h5 space_group=P43212 unit_cell=78.551,78.551,36.914,90.000,90.000,90.000 - -synthesis:vivado_pcie: +synthesis:vivado_pcie_100g: stage: synthesis variables: GIT_SUBMODULE_STRATEGY: recursive @@ -196,17 +195,17 @@ synthesis:vivado_pcie: rules: - if: '$CI_PIPELINE_SOURCE == "push"' changes: - - receiver/hls/* - - receiver/hdl/* - - receiver/scripts/* - - receiver/xdc/* + - fpga/hls/* + - fpga/hdl/* + - fpga/scripts/* + - fpga/xdc/* - common/Definitions.h tags: - vivado artifacts: paths: - - build/receiver/*.mcs - - build/receiver/*.bit + - build/fpga/*.mcs + - build/fpga/*.bit expire_in: 1 week script: - source /opt/grpc/grpc.sh diff --git a/.gitmodules b/.gitmodules index 03b3076b..abbb89b9 100644 --- a/.gitmodules +++ b/.gitmodules @@ -11,3 +11,6 @@ path = detector_control/slsDetectorPackage url = https://github.com/slsdetectorgroup/slsDetectorPackage branch = "developer" +[submodule "compression/bitshuffle_hperf"] + path = compression/bitshuffle_hperf + url = https://github.com/kalcutter/bitshuffle diff --git a/CMakeLists.txt b/CMakeLists.txt index 70480655..09362380 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -11,13 +11,15 @@ SET(CMAKE_C_FLAGS_RELEASE "-O3 -march=native -mtune=native") INCLUDE(CheckLanguage) CHECK_LANGUAGE(CUDA) -SET(CMAKE_CUDA_ARCHITECTURES 70 75 80 86) # V100, T4, A100, RTX A4000 +SET(CMAKE_CUDA_ARCHITECTURES 70 75 80 86 89) # V100, T4, A100, RTX A4000, L4 SET(CMAKE_CUDA_STANDARD 17) SET(CMAKE_CUDA_FLAGS_RELEASE "-O3") IF (CMAKE_CUDA_COMPILER) ENABLE_LANGUAGE(CUDA) MESSAGE(STATUS "CUDA VERSION: ${CMAKE_CUDA_COMPILER_VERSION}") + ADD_COMPILE_DEFINITIONS(JFJOCH_USE_CUDA) + FIND_LIBRARY(CUDART_LIBRARY cudart_static PATHS ${CMAKE_CUDA_IMPLICIT_LINK_DIRECTORIES} REQUIRED) ENDIF() SET(JFJOCH_COMPILE_WRITER ON CACHE BOOL "Compile HDF5 writer") @@ -47,6 +49,7 @@ ADD_SUBDIRECTORY(etc) SET(jfjoch_executables jfjoch_broker) IF (JFJOCH_COMPILE_TESTS OR JFJOCH_COMPILE_RECEIVER) + ADD_SUBDIRECTORY(fpga) ADD_SUBDIRECTORY(receiver) ADD_SUBDIRECTORY(image_analysis) LIST(APPEND jfjoch_executables jfjoch_receiver) diff --git a/LICENSE.GPL b/LICENSE.GPL deleted file mode 100644 index 7a3b7c2f..00000000 --- a/LICENSE.GPL +++ /dev/null @@ -1,674 +0,0 @@ - GNU GENERAL PUBLIC LICENSE - Version 3, 29 June 2007 - - Copyright (C) 2007 Free Software Foundation, Inc. - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The GNU General Public License is a free, copyleft license for -software and other kinds of works. - - The licenses for most software and other practical works are designed -to take away your freedom to share and change the works. By contrast, -the GNU General Public License is intended to guarantee your freedom to -share and change all versions of a program--to make sure it remains free -software for all its users. We, the Free Software Foundation, use the -GNU General Public License for most of our software; it applies also to -any other work released this way by its authors. You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -them if you wish), that you receive source code or can get it if you -want it, that you can change the software or use pieces of it in new -free programs, and that you know you can do these things. - - To protect your rights, we need to prevent others from denying you -these rights or asking you to surrender the rights. Therefore, you have -certain responsibilities if you distribute copies of the software, or if -you modify it: responsibilities to respect the freedom of others. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must pass on to the recipients the same -freedoms that you received. You must make sure that they, too, receive -or can get the source code. And you must show them these terms so they -know their rights. - - Developers that use the GNU GPL protect your rights with two steps: -(1) assert copyright on the software, and (2) offer you this License -giving you legal permission to copy, distribute and/or modify it. - - For the developers' and authors' protection, the GPL clearly explains -that there is no warranty for this free software. For both users' and -authors' sake, the GPL requires that modified versions be marked as -changed, so that their problems will not be attributed erroneously to -authors of previous versions. - - Some devices are designed to deny users access to install or run -modified versions of the software inside them, although the manufacturer -can do so. This is fundamentally incompatible with the aim of -protecting users' freedom to change the software. The systematic -pattern of such abuse occurs in the area of products for individuals to -use, which is precisely where it is most unacceptable. Therefore, we -have designed this version of the GPL to prohibit the practice for those -products. If such problems arise substantially in other domains, we -stand ready to extend this provision to those domains in future versions -of the GPL, as needed to protect the freedom of users. - - Finally, every program is threatened constantly by software patents. -States should not allow patents to restrict development and use of -software on general-purpose computers, but in those that do, we wish to -avoid the special danger that patents applied to a free program could -make it effectively proprietary. To prevent this, the GPL assures that -patents cannot be used to render the program non-free. - - The precise terms and conditions for copying, distribution and -modification follow. - - TERMS AND CONDITIONS - - 0. Definitions. - - "This License" refers to version 3 of the GNU General Public License. - - "Copyright" also means copyright-like laws that apply to other kinds of -works, such as semiconductor masks. - - "The Program" refers to any copyrightable work licensed under this -License. Each licensee is addressed as "you". "Licensees" and -"recipients" may be individuals or organizations. - - To "modify" a work means to copy from or adapt all or part of the work -in a fashion requiring copyright permission, other than the making of an -exact copy. The resulting work is called a "modified version" of the -earlier work or a work "based on" the earlier work. - - A "covered work" means either the unmodified Program or a work based -on the Program. - - To "propagate" a work means to do anything with it that, without -permission, would make you directly or secondarily liable for -infringement under applicable copyright law, except executing it on a -computer or modifying a private copy. Propagation includes copying, -distribution (with or without modification), making available to the -public, and in some countries other activities as well. - - To "convey" a work means any kind of propagation that enables other -parties to make or receive copies. Mere interaction with a user through -a computer network, with no transfer of a copy, is not conveying. - - An interactive user interface displays "Appropriate Legal Notices" -to the extent that it includes a convenient and prominently visible -feature that (1) displays an appropriate copyright notice, and (2) -tells the user that there is no warranty for the work (except to the -extent that warranties are provided), that licensees may convey the -work under this License, and how to view a copy of this License. If -the interface presents a list of user commands or options, such as a -menu, a prominent item in the list meets this criterion. - - 1. Source Code. - - The "source code" for a work means the preferred form of the work -for making modifications to it. "Object code" means any non-source -form of a work. - - A "Standard Interface" means an interface that either is an official -standard defined by a recognized standards body, or, in the case of -interfaces specified for a particular programming language, one that -is widely used among developers working in that language. - - The "System Libraries" of an executable work include anything, other -than the work as a whole, that (a) is included in the normal form of -packaging a Major Component, but which is not part of that Major -Component, and (b) serves only to enable use of the work with that -Major Component, or to implement a Standard Interface for which an -implementation is available to the public in source code form. A -"Major Component", in this context, means a major essential component -(kernel, window system, and so on) of the specific operating system -(if any) on which the executable work runs, or a compiler used to -produce the work, or an object code interpreter used to run it. - - The "Corresponding Source" for a work in object code form means all -the source code needed to generate, install, and (for an executable -work) run the object code and to modify the work, including scripts to -control those activities. However, it does not include the work's -System Libraries, or general-purpose tools or generally available free -programs which are used unmodified in performing those activities but -which are not part of the work. For example, Corresponding Source -includes interface definition files associated with source files for -the work, and the source code for shared libraries and dynamically -linked subprograms that the work is specifically designed to require, -such as by intimate data communication or control flow between those -subprograms and other parts of the work. - - The Corresponding Source need not include anything that users -can regenerate automatically from other parts of the Corresponding -Source. - - The Corresponding Source for a work in source code form is that -same work. - - 2. Basic Permissions. - - All rights granted under this License are granted for the term of -copyright on the Program, and are irrevocable provided the stated -conditions are met. This License explicitly affirms your unlimited -permission to run the unmodified Program. The output from running a -covered work is covered by this License only if the output, given its -content, constitutes a covered work. This License acknowledges your -rights of fair use or other equivalent, as provided by copyright law. - - You may make, run and propagate covered works that you do not -convey, without conditions so long as your license otherwise remains -in force. You may convey covered works to others for the sole purpose -of having them make modifications exclusively for you, or provide you -with facilities for running those works, provided that you comply with -the terms of this License in conveying all material for which you do -not control copyright. Those thus making or running the covered works -for you must do so exclusively on your behalf, under your direction -and control, on terms that prohibit them from making any copies of -your copyrighted material outside their relationship with you. - - Conveying under any other circumstances is permitted solely under -the conditions stated below. Sublicensing is not allowed; section 10 -makes it unnecessary. - - 3. Protecting Users' Legal Rights From Anti-Circumvention Law. - - No covered work shall be deemed part of an effective technological -measure under any applicable law fulfilling obligations under article -11 of the WIPO copyright treaty adopted on 20 December 1996, or -similar laws prohibiting or restricting circumvention of such -measures. - - When you convey a covered work, you waive any legal power to forbid -circumvention of technological measures to the extent such circumvention -is effected by exercising rights under this License with respect to -the covered work, and you disclaim any intention to limit operation or -modification of the work as a means of enforcing, against the work's -users, your or third parties' legal rights to forbid circumvention of -technological measures. - - 4. Conveying Verbatim Copies. - - You may convey verbatim copies of the Program's source code as you -receive it, in any medium, provided that you conspicuously and -appropriately publish on each copy an appropriate copyright notice; -keep intact all notices stating that this License and any -non-permissive terms added in accord with section 7 apply to the code; -keep intact all notices of the absence of any warranty; and give all -recipients a copy of this License along with the Program. - - You may charge any price or no price for each copy that you convey, -and you may offer support or warranty protection for a fee. - - 5. Conveying Modified Source Versions. - - You may convey a work based on the Program, or the modifications to -produce it from the Program, in the form of source code under the -terms of section 4, provided that you also meet all of these conditions: - - a) The work must carry prominent notices stating that you modified - it, and giving a relevant date. - - b) The work must carry prominent notices stating that it is - released under this License and any conditions added under section - 7. This requirement modifies the requirement in section 4 to - "keep intact all notices". - - c) You must license the entire work, as a whole, under this - License to anyone who comes into possession of a copy. This - License will therefore apply, along with any applicable section 7 - additional terms, to the whole of the work, and all its parts, - regardless of how they are packaged. This License gives no - permission to license the work in any other way, but it does not - invalidate such permission if you have separately received it. - - d) If the work has interactive user interfaces, each must display - Appropriate Legal Notices; however, if the Program has interactive - interfaces that do not display Appropriate Legal Notices, your - work need not make them do so. - - A compilation of a covered work with other separate and independent -works, which are not by their nature extensions of the covered work, -and which are not combined with it such as to form a larger program, -in or on a volume of a storage or distribution medium, is called an -"aggregate" if the compilation and its resulting copyright are not -used to limit the access or legal rights of the compilation's users -beyond what the individual works permit. Inclusion of a covered work -in an aggregate does not cause this License to apply to the other -parts of the aggregate. - - 6. Conveying Non-Source Forms. - - You may convey a covered work in object code form under the terms -of sections 4 and 5, provided that you also convey the -machine-readable Corresponding Source under the terms of this License, -in one of these ways: - - a) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by the - Corresponding Source fixed on a durable physical medium - customarily used for software interchange. - - b) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by a - written offer, valid for at least three years and valid for as - long as you offer spare parts or customer support for that product - model, to give anyone who possesses the object code either (1) a - copy of the Corresponding Source for all the software in the - product that is covered by this License, on a durable physical - medium customarily used for software interchange, for a price no - more than your reasonable cost of physically performing this - conveying of source, or (2) access to copy the - Corresponding Source from a network server at no charge. - - c) Convey individual copies of the object code with a copy of the - written offer to provide the Corresponding Source. This - alternative is allowed only occasionally and noncommercially, and - only if you received the object code with such an offer, in accord - with subsection 6b. - - d) Convey the object code by offering access from a designated - place (gratis or for a charge), and offer equivalent access to the - Corresponding Source in the same way through the same place at no - further charge. You need not require recipients to copy the - Corresponding Source along with the object code. If the place to - copy the object code is a network server, the Corresponding Source - may be on a different server (operated by you or a third party) - that supports equivalent copying facilities, provided you maintain - clear directions next to the object code saying where to find the - Corresponding Source. Regardless of what server hosts the - Corresponding Source, you remain obligated to ensure that it is - available for as long as needed to satisfy these requirements. - - e) Convey the object code using peer-to-peer transmission, provided - you inform other peers where the object code and Corresponding - Source of the work are being offered to the general public at no - charge under subsection 6d. - - A separable portion of the object code, whose source code is excluded -from the Corresponding Source as a System Library, need not be -included in conveying the object code work. - - A "User Product" is either (1) a "consumer product", which means any -tangible personal property which is normally used for personal, family, -or household purposes, or (2) anything designed or sold for incorporation -into a dwelling. In determining whether a product is a consumer product, -doubtful cases shall be resolved in favor of coverage. For a particular -product received by a particular user, "normally used" refers to a -typical or common use of that class of product, regardless of the status -of the particular user or of the way in which the particular user -actually uses, or expects or is expected to use, the product. A product -is a consumer product regardless of whether the product has substantial -commercial, industrial or non-consumer uses, unless such uses represent -the only significant mode of use of the product. - - "Installation Information" for a User Product means any methods, -procedures, authorization keys, or other information required to install -and execute modified versions of a covered work in that User Product from -a modified version of its Corresponding Source. The information must -suffice to ensure that the continued functioning of the modified object -code is in no case prevented or interfered with solely because -modification has been made. - - If you convey an object code work under this section in, or with, or -specifically for use in, a User Product, and the conveying occurs as -part of a transaction in which the right of possession and use of the -User Product is transferred to the recipient in perpetuity or for a -fixed term (regardless of how the transaction is characterized), the -Corresponding Source conveyed under this section must be accompanied -by the Installation Information. But this requirement does not apply -if neither you nor any third party retains the ability to install -modified object code on the User Product (for example, the work has -been installed in ROM). - - The requirement to provide Installation Information does not include a -requirement to continue to provide support service, warranty, or updates -for a work that has been modified or installed by the recipient, or for -the User Product in which it has been modified or installed. Access to a -network may be denied when the modification itself materially and -adversely affects the operation of the network or violates the rules and -protocols for communication across the network. - - Corresponding Source conveyed, and Installation Information provided, -in accord with this section must be in a format that is publicly -documented (and with an implementation available to the public in -source code form), and must require no special password or key for -unpacking, reading or copying. - - 7. Additional Terms. - - "Additional permissions" are terms that supplement the terms of this -License by making exceptions from one or more of its conditions. -Additional permissions that are applicable to the entire Program shall -be treated as though they were included in this License, to the extent -that they are valid under applicable law. If additional permissions -apply only to part of the Program, that part may be used separately -under those permissions, but the entire Program remains governed by -this License without regard to the additional permissions. - - When you convey a copy of a covered work, you may at your option -remove any additional permissions from that copy, or from any part of -it. (Additional permissions may be written to require their own -removal in certain cases when you modify the work.) You may place -additional permissions on material, added by you to a covered work, -for which you have or can give appropriate copyright permission. - - Notwithstanding any other provision of this License, for material you -add to a covered work, you may (if authorized by the copyright holders of -that material) supplement the terms of this License with terms: - - a) Disclaiming warranty or limiting liability differently from the - terms of sections 15 and 16 of this License; or - - b) Requiring preservation of specified reasonable legal notices or - author attributions in that material or in the Appropriate Legal - Notices displayed by works containing it; or - - c) Prohibiting misrepresentation of the origin of that material, or - requiring that modified versions of such material be marked in - reasonable ways as different from the original version; or - - d) Limiting the use for publicity purposes of names of licensors or - authors of the material; or - - e) Declining to grant rights under trademark law for use of some - trade names, trademarks, or service marks; or - - f) Requiring indemnification of licensors and authors of that - material by anyone who conveys the material (or modified versions of - it) with contractual assumptions of liability to the recipient, for - any liability that these contractual assumptions directly impose on - those licensors and authors. - - All other non-permissive additional terms are considered "further -restrictions" within the meaning of section 10. If the Program as you -received it, or any part of it, contains a notice stating that it is -governed by this License along with a term that is a further -restriction, you may remove that term. If a license document contains -a further restriction but permits relicensing or conveying under this -License, you may add to a covered work material governed by the terms -of that license document, provided that the further restriction does -not survive such relicensing or conveying. - - If you add terms to a covered work in accord with this section, you -must place, in the relevant source files, a statement of the -additional terms that apply to those files, or a notice indicating -where to find the applicable terms. - - Additional terms, permissive or non-permissive, may be stated in the -form of a separately written license, or stated as exceptions; -the above requirements apply either way. - - 8. Termination. - - You may not propagate or modify a covered work except as expressly -provided under this License. Any attempt otherwise to propagate or -modify it is void, and will automatically terminate your rights under -this License (including any patent licenses granted under the third -paragraph of section 11). - - However, if you cease all violation of this License, then your -license from a particular copyright holder is reinstated (a) -provisionally, unless and until the copyright holder explicitly and -finally terminates your license, and (b) permanently, if the copyright -holder fails to notify you of the violation by some reasonable means -prior to 60 days after the cessation. - - Moreover, your license from a particular copyright holder is -reinstated permanently if the copyright holder notifies you of the -violation by some reasonable means, this is the first time you have -received notice of violation of this License (for any work) from that -copyright holder, and you cure the violation prior to 30 days after -your receipt of the notice. - - Termination of your rights under this section does not terminate the -licenses of parties who have received copies or rights from you under -this License. If your rights have been terminated and not permanently -reinstated, you do not qualify to receive new licenses for the same -material under section 10. - - 9. Acceptance Not Required for Having Copies. - - You are not required to accept this License in order to receive or -run a copy of the Program. Ancillary propagation of a covered work -occurring solely as a consequence of using peer-to-peer transmission -to receive a copy likewise does not require acceptance. However, -nothing other than this License grants you permission to propagate or -modify any covered work. These actions infringe copyright if you do -not accept this License. Therefore, by modifying or propagating a -covered work, you indicate your acceptance of this License to do so. - - 10. Automatic Licensing of Downstream Recipients. - - Each time you convey a covered work, the recipient automatically -receives a license from the original licensors, to run, modify and -propagate that work, subject to this License. You are not responsible -for enforcing compliance by third parties with this License. - - An "entity transaction" is a transaction transferring control of an -organization, or substantially all assets of one, or subdividing an -organization, or merging organizations. If propagation of a covered -work results from an entity transaction, each party to that -transaction who receives a copy of the work also receives whatever -licenses to the work the party's predecessor in interest had or could -give under the previous paragraph, plus a right to possession of the -Corresponding Source of the work from the predecessor in interest, if -the predecessor has it or can get it with reasonable efforts. - - You may not impose any further restrictions on the exercise of the -rights granted or affirmed under this License. For example, you may -not impose a license fee, royalty, or other charge for exercise of -rights granted under this License, and you may not initiate litigation -(including a cross-claim or counterclaim in a lawsuit) alleging that -any patent claim is infringed by making, using, selling, offering for -sale, or importing the Program or any portion of it. - - 11. Patents. - - A "contributor" is a copyright holder who authorizes use under this -License of the Program or a work on which the Program is based. The -work thus licensed is called the contributor's "contributor version". - - A contributor's "essential patent claims" are all patent claims -owned or controlled by the contributor, whether already acquired or -hereafter acquired, that would be infringed by some manner, permitted -by this License, of making, using, or selling its contributor version, -but do not include claims that would be infringed only as a -consequence of further modification of the contributor version. For -purposes of this definition, "control" includes the right to grant -patent sublicenses in a manner consistent with the requirements of -this License. - - Each contributor grants you a non-exclusive, worldwide, royalty-free -patent license under the contributor's essential patent claims, to -make, use, sell, offer for sale, import and otherwise run, modify and -propagate the contents of its contributor version. - - In the following three paragraphs, a "patent license" is any express -agreement or commitment, however denominated, not to enforce a patent -(such as an express permission to practice a patent or covenant not to -sue for patent infringement). To "grant" such a patent license to a -party means to make such an agreement or commitment not to enforce a -patent against the party. - - If you convey a covered work, knowingly relying on a patent license, -and the Corresponding Source of the work is not available for anyone -to copy, free of charge and under the terms of this License, through a -publicly available network server or other readily accessible means, -then you must either (1) cause the Corresponding Source to be so -available, or (2) arrange to deprive yourself of the benefit of the -patent license for this particular work, or (3) arrange, in a manner -consistent with the requirements of this License, to extend the patent -license to downstream recipients. "Knowingly relying" means you have -actual knowledge that, but for the patent license, your conveying the -covered work in a country, or your recipient's use of the covered work -in a country, would infringe one or more identifiable patents in that -country that you have reason to believe are valid. - - If, pursuant to or in connection with a single transaction or -arrangement, you convey, or propagate by procuring conveyance of, a -covered work, and grant a patent license to some of the parties -receiving the covered work authorizing them to use, propagate, modify -or convey a specific copy of the covered work, then the patent license -you grant is automatically extended to all recipients of the covered -work and works based on it. - - A patent license is "discriminatory" if it does not include within -the scope of its coverage, prohibits the exercise of, or is -conditioned on the non-exercise of one or more of the rights that are -specifically granted under this License. You may not convey a covered -work if you are a party to an arrangement with a third party that is -in the business of distributing software, under which you make payment -to the third party based on the extent of your activity of conveying -the work, and under which the third party grants, to any of the -parties who would receive the covered work from you, a discriminatory -patent license (a) in connection with copies of the covered work -conveyed by you (or copies made from those copies), or (b) primarily -for and in connection with specific products or compilations that -contain the covered work, unless you entered into that arrangement, -or that patent license was granted, prior to 28 March 2007. - - Nothing in this License shall be construed as excluding or limiting -any implied license or other defenses to infringement that may -otherwise be available to you under applicable patent law. - - 12. No Surrender of Others' Freedom. - - If conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot convey a -covered work so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you may -not convey it at all. For example, if you agree to terms that obligate you -to collect a royalty for further conveying from those to whom you convey -the Program, the only way you could satisfy both those terms and this -License would be to refrain entirely from conveying the Program. - - 13. Use with the GNU Affero General Public License. - - Notwithstanding any other provision of this License, you have -permission to link or combine any covered work with a work licensed -under version 3 of the GNU Affero General Public License into a single -combined work, and to convey the resulting work. The terms of this -License will continue to apply to the part which is the covered work, -but the special requirements of the GNU Affero General Public License, -section 13, concerning interaction through a network will apply to the -combination as such. - - 14. Revised Versions of this License. - - The Free Software Foundation may publish revised and/or new versions of -the GNU General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - - Each version is given a distinguishing version number. If the -Program specifies that a certain numbered version of the GNU General -Public License "or any later version" applies to it, you have the -option of following the terms and conditions either of that numbered -version or of any later version published by the Free Software -Foundation. If the Program does not specify a version number of the -GNU General Public License, you may choose any version ever published -by the Free Software Foundation. - - If the Program specifies that a proxy can decide which future -versions of the GNU General Public License can be used, that proxy's -public statement of acceptance of a version permanently authorizes you -to choose that version for the Program. - - Later license versions may give you additional or different -permissions. However, no additional obligations are imposed on any -author or copyright holder as a result of your choosing to follow a -later version. - - 15. Disclaimer of Warranty. - - THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY -APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT -HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY -OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, -THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM -IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF -ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. Limitation of Liability. - - IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS -THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY -GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE -USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF -DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD -PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), -EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF -SUCH DAMAGES. - - 17. Interpretation of Sections 15 and 16. - - If the disclaimer of warranty and limitation of liability provided -above cannot be given local legal effect according to their terms, -reviewing courts shall apply local law that most closely approximates -an absolute waiver of all civil liability in connection with the -Program, unless a warranty or assumption of liability accompanies a -copy of the Program in return for a fee. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -state the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . - -Also add information on how to contact you by electronic and paper mail. - - If the program does terminal interaction, make it output a short -notice like this when it starts in an interactive mode: - - Copyright (C) - This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, your program's commands -might be different; for a GUI interface, you would use an "about box". - - You should also get your employer (if you work as a programmer) or school, -if any, to sign a "copyright disclaimer" for the program, if necessary. -For more information on this, and how to apply and follow the GNU GPL, see -. - - The GNU General Public License does not permit incorporating your program -into proprietary programs. If your program is a subroutine library, you -may consider it more useful to permit linking proprietary applications with -the library. If this is what you want to do, use the GNU Lesser General -Public License instead of this License. But first, please read -. \ No newline at end of file diff --git a/LICENSE.OHL-S b/LICENSE.OHL-S deleted file mode 100644 index dc764b43..00000000 --- a/LICENSE.OHL-S +++ /dev/null @@ -1,289 +0,0 @@ -CERN Open Hardware Licence Version 2 - Strongly Reciprocal - - -Preamble - -CERN has developed this licence to promote collaboration among -hardware designers and to provide a legal tool which supports the -freedom to use, study, modify, share and distribute hardware designs -and products based on those designs. Version 2 of the CERN Open -Hardware Licence comes in three variants: CERN-OHL-P (permissive); and -two reciprocal licences: CERN-OHL-W (weakly reciprocal) and this -licence, CERN-OHL-S (strongly reciprocal). - -The CERN-OHL-S is copyright CERN 2020. Anyone is welcome to use it, in -unmodified form only. - -Use of this Licence does not imply any endorsement by CERN of any -Licensor or their designs nor does it imply any involvement by CERN in -their development. - - -1 Definitions - - 1.1 'Licence' means this CERN-OHL-S. - - 1.2 'Compatible Licence' means - - a) any earlier version of the CERN Open Hardware licence, or - - b) any version of the CERN-OHL-S, or - - c) any licence which permits You to treat the Source to which - it applies as licensed under CERN-OHL-S provided that on - Conveyance of any such Source, or any associated Product You - treat the Source in question as being licensed under - CERN-OHL-S. - - 1.3 'Source' means information such as design materials or digital - code which can be applied to Make or test a Product or to - prepare a Product for use, Conveyance or sale, regardless of its - medium or how it is expressed. It may include Notices. - - 1.4 'Covered Source' means Source that is explicitly made available - under this Licence. - - 1.5 'Product' means any device, component, work or physical object, - whether in finished or intermediate form, arising from the use, - application or processing of Covered Source. - - 1.6 'Make' means to create or configure something, whether by - manufacture, assembly, compiling, loading or applying Covered - Source or another Product or otherwise. - - 1.7 'Available Component' means any part, sub-assembly, library or - code which: - - a) is licensed to You as Complete Source under a Compatible - Licence; or - - b) is available, at the time a Product or the Source containing - it is first Conveyed, to You and any other prospective - licensees - - i) as a physical part with sufficient rights and - information (including any configuration and - programming files and information about its - characteristics and interfaces) to enable it either to - be Made itself, or to be sourced and used to Make the - Product; or - ii) as part of the normal distribution of a tool used to - design or Make the Product. - - 1.8 'Complete Source' means the set of all Source necessary to Make - a Product, in the preferred form for making modifications, - including necessary installation and interfacing information - both for the Product, and for any included Available Components. - If the format is proprietary, it must also be made available in - a format (if the proprietary tool can create it) which is - viewable with a tool available to potential licensees and - licensed under a licence approved by the Free Software - Foundation or the Open Source Initiative. Complete Source need - not include the Source of any Available Component, provided that - You include in the Complete Source sufficient information to - enable a recipient to Make or source and use the Available - Component to Make the Product. - - 1.9 'Source Location' means a location where a Licensor has placed - Covered Source, and which that Licensor reasonably believes will - remain easily accessible for at least three years for anyone to - obtain a digital copy. - - 1.10 'Notice' means copyright, acknowledgement and trademark notices, - Source Location references, modification notices (subsection - 3.3(b)) and all notices that refer to this Licence and to the - disclaimer of warranties that are included in the Covered - Source. - - 1.11 'Licensee' or 'You' means any person exercising rights under - this Licence. - - 1.12 'Licensor' means a natural or legal person who creates or - modifies Covered Source. A person may be a Licensee and a - Licensor at the same time. - - 1.13 'Convey' means to communicate to the public or distribute. - - -2 Applicability - - 2.1 This Licence governs the use, copying, modification, Conveying - of Covered Source and Products, and the Making of Products. By - exercising any right granted under this Licence, You irrevocably - accept these terms and conditions. - - 2.2 This Licence is granted by the Licensor directly to You, and - shall apply worldwide and without limitation in time. - - 2.3 You shall not attempt to restrict by contract or otherwise the - rights granted under this Licence to other Licensees. - - 2.4 This Licence is not intended to restrict fair use, fair dealing, - or any other similar right. - - -3 Copying, Modifying and Conveying Covered Source - - 3.1 You may copy and Convey verbatim copies of Covered Source, in - any medium, provided You retain all Notices. - - 3.2 You may modify Covered Source, other than Notices, provided that - You irrevocably undertake to make that modified Covered Source - available from a Source Location should You Convey a Product in - circumstances where the recipient does not otherwise receive a - copy of the modified Covered Source. In each case subsection 3.3 - shall apply. - - You may only delete Notices if they are no longer applicable to - the corresponding Covered Source as modified by You and You may - add additional Notices applicable to Your modifications. - Including Covered Source in a larger work is modifying the - Covered Source, and the larger work becomes modified Covered - Source. - - 3.3 You may Convey modified Covered Source (with the effect that You - shall also become a Licensor) provided that You: - - a) retain Notices as required in subsection 3.2; - - b) add a Notice to the modified Covered Source stating that You - have modified it, with the date and brief description of how - You have modified it; - - c) add a Source Location Notice for the modified Covered Source - if You Convey in circumstances where the recipient does not - otherwise receive a copy of the modified Covered Source; and - - d) license the modified Covered Source under the terms and - conditions of this Licence (or, as set out in subsection - 8.3, a later version, if permitted by the licence of the - original Covered Source). Such modified Covered Source must - be licensed as a whole, but excluding Available Components - contained in it, which remain licensed under their own - applicable licences. - - -4 Making and Conveying Products - -You may Make Products, and/or Convey them, provided that You either -provide each recipient with a copy of the Complete Source or ensure -that each recipient is notified of the Source Location of the Complete -Source. That Complete Source is Covered Source, and You must -accordingly satisfy Your obligations set out in subsection 3.3. If -specified in a Notice, the Product must visibly and securely display -the Source Location on it or its packaging or documentation in the -manner specified in that Notice. - - -5 Research and Development - -You may Convey Covered Source, modified Covered Source or Products to -a legal entity carrying out development, testing or quality assurance -work on Your behalf provided that the work is performed on terms which -prevent the entity from both using the Source or Products for its own -internal purposes and Conveying the Source or Products or any -modifications to them to any person other than You. Any modifications -made by the entity shall be deemed to be made by You pursuant to -subsection 3.2. - - -6 DISCLAIMER AND LIABILITY - - 6.1 DISCLAIMER OF WARRANTY -- The Covered Source and any Products - are provided 'as is' and any express or implied warranties, - including, but not limited to, implied warranties of - merchantability, of satisfactory quality, non-infringement of - third party rights, and fitness for a particular purpose or use - are disclaimed in respect of any Source or Product to the - maximum extent permitted by law. The Licensor makes no - representation that any Source or Product does not or will not - infringe any patent, copyright, trade secret or other - proprietary right. The entire risk as to the use, quality, and - performance of any Source or Product shall be with You and not - the Licensor. This disclaimer of warranty is an essential part - of this Licence and a condition for the grant of any rights - granted under this Licence. - - 6.2 EXCLUSION AND LIMITATION OF LIABILITY -- The Licensor shall, to - the maximum extent permitted by law, have no liability for - direct, indirect, special, incidental, consequential, exemplary, - punitive or other damages of any character including, without - limitation, procurement of substitute goods or services, loss of - use, data or profits, or business interruption, however caused - and on any theory of contract, warranty, tort (including - negligence), product liability or otherwise, arising in any way - in relation to the Covered Source, modified Covered Source - and/or the Making or Conveyance of a Product, even if advised of - the possibility of such damages, and You shall hold the - Licensor(s) free and harmless from any liability, costs, - damages, fees and expenses, including claims by third parties, - in relation to such use. - - -7 Patents - - 7.1 Subject to the terms and conditions of this Licence, each - Licensor hereby grants to You a perpetual, worldwide, - non-exclusive, no-charge, royalty-free, irrevocable (except as - stated in subsections 7.2 and 8.4) patent licence to Make, have - Made, use, offer to sell, sell, import, and otherwise transfer - the Covered Source and Products, where such licence applies only - to those patent claims licensable by such Licensor that are - necessarily infringed by exercising rights under the Covered - Source as Conveyed by that Licensor. - - 7.2 If You institute patent litigation against any entity (including - a cross-claim or counterclaim in a lawsuit) alleging that the - Covered Source or a Product constitutes direct or contributory - patent infringement, or You seek any declaration that a patent - licensed to You under this Licence is invalid or unenforceable - then any rights granted to You under this Licence shall - terminate as of the date such process is initiated. - - -8 General - - 8.1 If any provisions of this Licence are or subsequently become - invalid or unenforceable for any reason, the remaining - provisions shall remain effective. - - 8.2 You shall not use any of the name (including acronyms and - abbreviations), image, or logo by which the Licensor or CERN is - known, except where needed to comply with section 3, or where - the use is otherwise allowed by law. Any such permitted use - shall be factual and shall not be made so as to suggest any kind - of endorsement or implication of involvement by the Licensor or - its personnel. - - 8.3 CERN may publish updated versions and variants of this Licence - which it considers to be in the spirit of this version, but may - differ in detail to address new problems or concerns. New - versions will be published with a unique version number and a - variant identifier specifying the variant. If the Licensor has - specified that a given variant applies to the Covered Source - without specifying a version, You may treat that Covered Source - as being released under any version of the CERN-OHL with that - variant. If no variant is specified, the Covered Source shall be - treated as being released under CERN-OHL-S. The Licensor may - also specify that the Covered Source is subject to a specific - version of the CERN-OHL or any later version in which case You - may apply this or any later version of CERN-OHL with the same - variant identifier published by CERN. - - 8.4 This Licence shall terminate with immediate effect if You fail - to comply with any of its terms and conditions. - - 8.5 However, if You cease all breaches of this Licence, then Your - Licence from any Licensor is reinstated unless such Licensor has - terminated this Licence by giving You, while You remain in - breach, a notice specifying the breach and requiring You to cure - it within 30 days, and You have failed to come into compliance - in all material respects by the end of the 30 day period. Should - You repeat the breach after receipt of a cure notice and - subsequent reinstatement, this Licence will terminate - immediately and permanently. Section 6 shall continue to apply - after any termination. - - 8.6 This Licence shall not be enforceable except by a Licensor - acting as such, and third party beneficiary rights are - specifically excluded. \ No newline at end of file diff --git a/README.md b/README.md index 1d372252..63219d37 100644 --- a/README.md +++ b/README.md @@ -6,9 +6,7 @@ Citation: F. Leonarski, M. Bruckner, C. Lopez-Cuenca, A. Mozzanica, H.-C. Stadle ## License -Software components are licensed with GNU Public License version 3. - -Hardware components are licensed with Strongly-reciprocal CERN Open Hardware Licence version 2. +Operating Jungfraujoch, as well as sharing sources code requires explicit license from PSI. ## Hardware requirements 1. JUNGFRAU detector (optimally 4M with 2 kHz enabled read-out boards) diff --git a/broker/JFJochBroker.cpp b/broker/JFJochBroker.cpp index fba68673..1e36f54f 100644 --- a/broker/JFJochBroker.cpp +++ b/broker/JFJochBroker.cpp @@ -1,5 +1,4 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (2019-2023) Paul Scherrer Institute #include "JFJochBroker.h" diff --git a/broker/JFJochBroker.h b/broker/JFJochBroker.h index 4d1bfdff..95efda4e 100644 --- a/broker/JFJochBroker.h +++ b/broker/JFJochBroker.h @@ -1,5 +1,4 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (2019-2023) Paul Scherrer Institute #ifndef JUNGFRAUJOCH_JFJOCHBROKER_H #define JUNGFRAUJOCH_JFJOCHBROKER_H diff --git a/broker/JFJochBrokerParser.cpp b/broker/JFJochBrokerParser.cpp index b3d6868d..f94f906c 100644 --- a/broker/JFJochBrokerParser.cpp +++ b/broker/JFJochBrokerParser.cpp @@ -1,5 +1,4 @@ // Copyright (2019-2023) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later #include "JFJochBrokerParser.h" #include "JFJochBroker.h" diff --git a/broker/JFJochBrokerParser.h b/broker/JFJochBrokerParser.h index 8efbc1b3..b6a6f084 100644 --- a/broker/JFJochBrokerParser.h +++ b/broker/JFJochBrokerParser.h @@ -1,5 +1,4 @@ // Copyright (2019-2023) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later #ifndef JUNGFRAUJOCH_JFJOCHBROKERPARSER_H #define JUNGFRAUJOCH_JFJOCHBROKERPARSER_H diff --git a/broker/JFJochServices.cpp b/broker/JFJochServices.cpp index f4946422..2bcdf7de 100644 --- a/broker/JFJochServices.cpp +++ b/broker/JFJochServices.cpp @@ -1,5 +1,4 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (2019-2023) Paul Scherrer Institute #include "JFJochServices.h" #include "../common/JFJochException.h" diff --git a/broker/JFJochServices.h b/broker/JFJochServices.h index cd7b9421..e11c83d7 100644 --- a/broker/JFJochServices.h +++ b/broker/JFJochServices.h @@ -1,5 +1,4 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (2019-2023) Paul Scherrer Institute #ifndef JUNGFRAUJOCH_JFJOCHSERVICES_H #define JUNGFRAUJOCH_JFJOCHSERVICES_H diff --git a/broker/JFJochStateMachine.cpp b/broker/JFJochStateMachine.cpp index 90f6177b..e034955c 100644 --- a/broker/JFJochStateMachine.cpp +++ b/broker/JFJochStateMachine.cpp @@ -1,5 +1,4 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (2019-2023) Paul Scherrer Institute #include @@ -64,7 +63,11 @@ void JFJochStateMachine::TakePedestalInternalG0(std::unique_lock &ul state = JFJochState::Pedestal; DiffractionExperiment local_experiment(experiment); local_experiment.Mode(DetectorMode::PedestalG0); - local_experiment.StorageCellStart(16 - local_experiment.GetStorageCellNumber()); + + if (local_experiment.GetStorageCellNumber() == 1) + local_experiment.StorageCellStart(15); + else + local_experiment.StorageCellStart(0); if (!cancel_sequence && (local_experiment.GetPedestalG0Frames() > 0)) { services.Start(local_experiment, *calibration); @@ -88,6 +91,8 @@ void JFJochStateMachine::TakePedestalInternalG1(std::unique_lock &ul if (local_experiment.GetStorageCellNumber() == 2) local_experiment.StorageCellStart((storage_cell + 15) % 16); // one previous + else + local_experiment.StorageCellStart(15); if (!cancel_sequence && (local_experiment.GetPedestalG1Frames() > 0)) { services.Start(local_experiment, *calibration); @@ -111,6 +116,8 @@ void JFJochStateMachine::TakePedestalInternalG2(std::unique_lock &ul if (local_experiment.GetStorageCellNumber() == 2) local_experiment.StorageCellStart((storage_cell + 15) % 16); // one previous + else + local_experiment.StorageCellStart(15); if (!cancel_sequence && (local_experiment.GetPedestalG2Frames() > 0)) { services.Start(local_experiment, *calibration); @@ -180,7 +187,10 @@ void JFJochStateMachine::Start(const JFJochProtoBuf::DatasetSettings& settings) ClearAndSetMeasurementStatistics(); cancel_sequence = false; - experiment.StorageCellStart(16 - experiment.GetStorageCellNumber()); + if (experiment.GetStorageCellNumber() == 1) + experiment.StorageCellStart(15); + else + experiment.StorageCellStart(0); try { state = JFJochState::Busy; diff --git a/broker/JFJochStateMachine.h b/broker/JFJochStateMachine.h index 07ff62f8..a8c6b430 100644 --- a/broker/JFJochStateMachine.h +++ b/broker/JFJochStateMachine.h @@ -1,5 +1,4 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (2019-2023) Paul Scherrer Institute #ifndef JUNGFRAUJOCH_JFJOCHSTATEMACHINE_H #define JUNGFRAUJOCH_JFJOCHSTATEMACHINE_H diff --git a/broker/jfjoch_broker.cpp b/broker/jfjoch_broker.cpp index c67a775b..a768596c 100644 --- a/broker/jfjoch_broker.cpp +++ b/broker/jfjoch_broker.cpp @@ -1,5 +1,4 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (2019-2023) Paul Scherrer Institute #include #include diff --git a/common/CMakeLists.txt b/common/CMakeLists.txt index df35a7f9..96eae103 100644 --- a/common/CMakeLists.txt +++ b/common/CMakeLists.txt @@ -43,11 +43,24 @@ ADD_LIBRARY( CommonFunctions STATIC grpcToJson.h jsonToGrpc.h to_fixed.h DetectorGeometry.cpp DetectorGeometry.h DetectorModuleGeometry.cpp DetectorModuleGeometry.h - DetectorSetup.h DetectorSetup.cpp ZeroCopyReturnValue.h Histogram.h) + DetectorSetup.h DetectorSetup.cpp ZeroCopyReturnValue.h Histogram.h DiffractionGeometry.h + ROIFilter.h + CUDAWrapper.cpp + CUDAWrapper.h + NUMAHWPolicy.cpp + NUMAHWPolicy.h) TARGET_LINK_LIBRARIES(CommonFunctions Compression FrameSerialize libzmq JFCalibration JFJochProtoBuf -lrt) -IF(HAS_NUMAIF AND NUMA_LIBRARY) - TARGET_COMPILE_DEFINITIONS(CommonFunctions PRIVATE -DJFJOCH_USE_NUMA) - TARGET_LINK_LIBRARIES(CommonFunctions ${NUMA_LIBRARY}) +IF (CMAKE_CUDA_COMPILER) + TARGET_SOURCES(CommonFunctions PRIVATE CUDAWrapper.cu ) + TARGET_LINK_LIBRARIES(CommonFunctions ${CUDART_LIBRARY} ${CMAKE_DL_LIBS} rt) +ENDIF() + +IF(HAS_NUMAIF AND HAS_NUMA_H AND NUMA_LIBRARY) + TARGET_COMPILE_DEFINITIONS(CommonFunctions PUBLIC JFJOCH_USE_NUMA) + TARGET_LINK_LIBRARIES(CommonFunctions ${NUMA_LIBRARY}) + MESSAGE(STATUS "NUMA memory/CPU pinning enabled") +ELSE() + MESSAGE(WARNING "NUMA memory/CPU pinning disabled") ENDIF() diff --git a/common/CUDAWrapper.cpp b/common/CUDAWrapper.cpp new file mode 100644 index 00000000..fd2cb331 --- /dev/null +++ b/common/CUDAWrapper.cpp @@ -0,0 +1,13 @@ +// Copyright (2019-2023) Paul Scherrer Institute + +#ifndef JFJOCH_USE_CUDA + +#include "CUDAWrapper.h" + +int32_t get_gpu_count() { + return 0; +} + +void set_gpu(int32_t dev_id) {} + +#endif diff --git a/common/CUDAWrapper.cu b/common/CUDAWrapper.cu new file mode 100644 index 00000000..2a259f1c --- /dev/null +++ b/common/CUDAWrapper.cu @@ -0,0 +1,24 @@ +// Copyright (2019-2023) Paul Scherrer Institute + +#include "CUDAWrapper.h" +#include "JFJochException.h" + +inline void cuda_err(cudaError_t val) { + if (val != cudaSuccess) + throw JFJochException(JFJochExceptionCategory::GPUCUDAError, cudaGetErrorString(val)); +} + +int32_t get_gpu_count() { + int device_count; + cuda_err(cudaGetDeviceCount(&device_count)); + return device_count; +} + +void set_gpu(int32_t dev_id) { + auto dev_count = get_gpu_count(); + + if ((dev_id < 0) || (dev_id >= dev_count)) + throw JFJochException(JFJochExceptionCategory::InputParameterInvalid, "Device ID cannot be negative"); + + cuda_err(cudaSetDevice(dev_id)); +} \ No newline at end of file diff --git a/common/CUDAWrapper.h b/common/CUDAWrapper.h new file mode 100644 index 00000000..af422548 --- /dev/null +++ b/common/CUDAWrapper.h @@ -0,0 +1,11 @@ +// Copyright (2019-2023) Paul Scherrer Institute + +#ifndef JUNGFRAUJOCH_CUDAWRAPPER_H +#define JUNGFRAUJOCH_CUDAWRAPPER_H + +#include + +int32_t get_gpu_count(); +void set_gpu(int32_t dev_id); + +#endif //JUNGFRAUJOCH_CUDAWRAPPER_H diff --git a/common/Coord.cpp b/common/Coord.cpp index a46308cb..e529c62d 100644 --- a/common/Coord.cpp +++ b/common/Coord.cpp @@ -1,5 +1,4 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (2019-2023) Paul Scherrer Institute #include #include "Coord.h" diff --git a/common/Coord.h b/common/Coord.h index d7ad8a05..d6e87118 100644 --- a/common/Coord.h +++ b/common/Coord.h @@ -1,5 +1,4 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (2019-2023) Paul Scherrer Institute #ifndef INDEX_COORD_H #define INDEX_COORD_H diff --git a/common/Definitions.h b/common/Definitions.h index f6721194..05263436 100644 --- a/common/Definitions.h +++ b/common/Definitions.h @@ -1,5 +1,4 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (2019-2023) Paul Scherrer Institute #ifndef DEFINITIONS_H #define DEFINITIONS_H @@ -18,12 +17,12 @@ #define FPGA_BUFFER_LOCATION_SIZE (RAW_MODULE_SIZE * sizeof(short)) -#define MIN_COUNT_TIME_IN_US 10 +#define MIN_COUNT_TIME_IN_US 5 #define MIN_FRAME_TIME_HALF_SPEED_IN_US 1000 #define MIN_FRAME_TIME_FULL_SPEED_IN_US 470 #define MAX_FRAME_TIME 2000 #define MAX_SUMMATION 5000 - +#define MIN_STORAGE_CELL_DELAY_IN_NS 2100 #define READOUT_TIME_IN_US 20 #define GRPC_MAX_MESSAGE_SIZE (1000L*1000L*1000L) @@ -49,12 +48,11 @@ #define DEFAULT_G2_FACTOR (-0.1145) // For FPGA -/* This number is unique and is declared in ~snap/ActionTypes.md */ #define ACTION_TYPE 0x52324158 -#define RELEASE_LEVEL 0x0035 +#define RELEASE_LEVEL 0x003C #define MODE_CONV 0x0001L -#define MODE_INTERNAL_PACKET_GEN 0x0002L +#define MODE_NONBLOCKING_ON_WR 0x0002L // Don't block acquisition if there is no WR available #define TASK_NO_DATA_STREAM UINT16_MAX @@ -117,4 +115,12 @@ #define CTRL_REGISTER_IDLE (1<<1u) +#define HANDLE_START (UINT32_MAX - 1) +#define HANDLE_SKIP_FRAME (UINT32_MAX - 2) +#define HANDLE_END (UINT32_MAX ) + +#define INT_PKT_GEN_DEBUG 0x0 +#define INT_PKT_GEN_TIMESTAMP 0xABCDEFABCDEF +#define INT_PKT_GEN_BUNCHID 0xCACACACACA +#define INT_PKT_GEN_EXPTTIME 10000 #endif //DEFINITIONS_H diff --git a/common/DetectorGeometry.cpp b/common/DetectorGeometry.cpp index 05243ab1..75730e33 100644 --- a/common/DetectorGeometry.cpp +++ b/common/DetectorGeometry.cpp @@ -1,5 +1,4 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (2019-2023) Paul Scherrer Institute #include "DetectorGeometry.h" #include "JFJochException.h" @@ -29,6 +28,8 @@ DetectorGeometry::DetectorGeometry(int32_t nmodules, int32_t horizontal_stacking throw JFJochException(JFJochExceptionCategory::InputParameterInvalid, "Gap x has to be non-negative"); if (gap_y < 0) throw JFJochException(JFJochExceptionCategory::InputParameterInvalid, "Gap y has to be non-negative"); + if (nmodules < horizontal_stacking) + horizontal_stacking = nmodules; width = horizontal_stacking * CONVERTED_MODULE_COLS + (horizontal_stacking - 1) * gap_x; int64_t conv_lines = nmodules / horizontal_stacking + (nmodules % horizontal_stacking > 0 ? 1 : 0); diff --git a/common/DetectorGeometry.h b/common/DetectorGeometry.h index 2cae7175..44a1d22d 100644 --- a/common/DetectorGeometry.h +++ b/common/DetectorGeometry.h @@ -1,5 +1,4 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (2019-2023) Paul Scherrer Institute #ifndef JUNGFRAUJOCH_DETECTORGEOMETRY_H #define JUNGFRAUJOCH_DETECTORGEOMETRY_H diff --git a/common/DetectorModuleGeometry.cpp b/common/DetectorModuleGeometry.cpp index 0cc391d7..5240b988 100644 --- a/common/DetectorModuleGeometry.cpp +++ b/common/DetectorModuleGeometry.cpp @@ -1,5 +1,4 @@ // Copyright (2019-2023) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later #include "DetectorModuleGeometry.h" #include "JFJochException.h" diff --git a/common/DetectorModuleGeometry.h b/common/DetectorModuleGeometry.h index f10583aa..74b2eca7 100644 --- a/common/DetectorModuleGeometry.h +++ b/common/DetectorModuleGeometry.h @@ -1,5 +1,4 @@ // Copyright (2019-2023) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later #ifndef JUNGFRAUJOCH_DETECTORMODULEGEOMETRY_H #define JUNGFRAUJOCH_DETECTORMODULEGEOMETRY_H diff --git a/common/DetectorSetup.cpp b/common/DetectorSetup.cpp index e03b4e48..126911ef 100644 --- a/common/DetectorSetup.cpp +++ b/common/DetectorSetup.cpp @@ -1,5 +1,4 @@ // Copyright (2019-2023) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later #include "DetectorSetup.h" #include "JFJochException.h" diff --git a/common/DetectorSetup.h b/common/DetectorSetup.h index 47b6c8c6..60fd1456 100644 --- a/common/DetectorSetup.h +++ b/common/DetectorSetup.h @@ -1,5 +1,4 @@ // Copyright (2019-2023) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later #ifndef JUNGFRAUJOCH_DETECTORSETUP_H #define JUNGFRAUJOCH_DETECTORSETUP_H diff --git a/common/DiffractionExperiment.cpp b/common/DiffractionExperiment.cpp index ad38a9f7..5d4f4351 100644 --- a/common/DiffractionExperiment.cpp +++ b/common/DiffractionExperiment.cpp @@ -1,7 +1,5 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (2019-2023) Paul Scherrer Institute -#include #include #include "NetworkAddressConvert.h" @@ -37,9 +35,6 @@ DiffractionExperiment::DiffractionExperiment() : DiffractionExperiment(DetectorG DiffractionExperiment::DiffractionExperiment(const DetectorSetup& det_setup) { dataset.set_photon_energy_kev(WVL_1A_IN_KEV); dataset.set_detector_distance_mm(100); - dataset.mutable_scattering_vector()->set_x(0); - dataset.mutable_scattering_vector()->set_y(0); - dataset.mutable_scattering_vector()->set_z(1); dataset.set_data_file_count(1); dataset.set_file_prefix("test"); @@ -51,6 +46,12 @@ DiffractionExperiment::DiffractionExperiment(const DetectorSetup& det_setup) { dataset.set_compression(JFJochProtoBuf::BSHUF_LZ4); + dataset.set_rad_int_polarization_corr(false); + dataset.set_rad_int_solid_angle_corr(false); + dataset.set_save_calibration(false); + + internal.set_debug_pixel_mask(false); + internal.set_ndatastreams(1); internal.set_frame_time_us(MIN_FRAME_TIME_HALF_SPEED_IN_US); @@ -73,7 +74,7 @@ DiffractionExperiment::DiffractionExperiment(const DetectorSetup& det_setup) { internal.set_storage_cells(1); internal.set_storage_cell_start(15); - + internal.set_storage_cell_delay_ns(10*1000); Detector(det_setup); Mode(DetectorMode::Conversion); } @@ -106,7 +107,7 @@ DiffractionExperiment &DiffractionExperiment::Mode(DetectorMode input) { } DiffractionExperiment &DiffractionExperiment::DataStreams(int64_t input) { - check_max("Number of data streams", input, 7); + check_max("Number of data streams", input, 16); check_min("Number of data streams", input, 1); internal.set_ndatastreams(input); return *this; @@ -209,19 +210,6 @@ DiffractionExperiment &DiffractionExperiment::DetectorDistance_mm(float input) { return *this; } -DiffractionExperiment &DiffractionExperiment::ScatteringVector(Coord input) { - auto c = input.Normalize(); - dataset.mutable_scattering_vector()->set_x(c.x); - dataset.mutable_scattering_vector()->set_y(c.y); - dataset.mutable_scattering_vector()->set_z(c.z); - return *this; -} - -DiffractionExperiment &DiffractionExperiment::ScatteringVector() { - dataset.clear_scattering_vector(); - return *this; -} - DiffractionExperiment &DiffractionExperiment::FilePrefix(std::string input) { // File prefix with front slash is not allowed for security reasons if (input.front() == '/') @@ -349,9 +337,9 @@ DiffractionExperiment &DiffractionExperiment::SpaceGroupNumber(int64_t input) { DiffractionExperiment &DiffractionExperiment::StorageCells(int64_t input) { check_min("Storage cell number", input, 1); check_max("Storage cell number", input, 16); - if ((input != 1) && (input != 2) && (input != 4) && (input != 8) && (input != 16)) - throw JFJochException(JFJochExceptionCategory::InputParameterInvalid, - "Storage cell count invalid, must be power of 2"); + //if ((input != 1) && (input != 2) && (input != 4) && (input != 8) && (input != 16)) + // throw JFJochException(JFJochExceptionCategory::InputParameterInvalid, + // "Storage cell count invalid, must be power of 2"); internal.set_storage_cells(input); return *this; } @@ -551,11 +539,7 @@ float DiffractionExperiment::GetDetectorDistance_mm() const { } Coord DiffractionExperiment::GetScatteringVector() const { - if (dataset.has_scattering_vector()) - return Coord(dataset.scattering_vector().x(), dataset.scattering_vector().y(), dataset.scattering_vector().z()) - * (dataset.photon_energy_kev() / WVL_1A_IN_KEV); - else - return {0,0,dataset.photon_energy_kev() / WVL_1A_IN_KEV}; + return {0,0,dataset.photon_energy_kev() / WVL_1A_IN_KEV}; } std::string DiffractionExperiment::GetFilePrefix() const { @@ -773,23 +757,6 @@ bool DiffractionExperiment::HasUnitCell() const { return dataset.has_unit_cell(); } -float DiffractionExperiment::ResToPxl(float resolution) const { - if (resolution == 0) - return INFINITY; - - float sin_theta = GetWavelength_A() / (2 * resolution); - float theta = asinf(sin_theta); - float tan_2theta = tanf(2 * theta); - return tan_2theta * GetDetectorDistance_mm() / GetPixelSize_mm(); -} - -float DiffractionExperiment::CalcRadIntSolidAngleCorr(float q) const { - float sin_theta = q * GetWavelength_A() / (4 * static_cast(M_PI)); - float cos_two_theta = 1.0f - 2.0f * sin_theta * sin_theta; // cos(2*alpha) = 1 - 2 * sin(alpha)^2 - float cos_two_theta_3 = cos_two_theta * cos_two_theta * cos_two_theta; - return cos_two_theta_3; -} - Coord DiffractionExperiment::LabCoord(float detector_x, float detector_y) const { // Assumes planar detector, 90 deg towards beam return {(detector_x - GetBeamX_pxl()) * GetPixelSize_mm() , @@ -797,20 +764,6 @@ Coord DiffractionExperiment::LabCoord(float detector_x, float detector_y) const GetDetectorDistance_mm()}; } -float DiffractionExperiment::PxlToRes(float detector_x, float detector_y) const { - auto lab = LabCoord(detector_x, detector_y); - - float beam_path = lab.Length(); - if (beam_path == GetDetectorDistance_mm()) return std::numeric_limits::infinity(); - - float cos_2theta = GetDetectorDistance_mm() / beam_path; - // cos(2theta) = cos(theta)^2 - sin(theta)^2 - // cos(2theta) = 1 - 2*sin(theta)^2 - // Technically two solutions for two theta, but it makes sense only to take positive one in this case - float sin_theta = sqrtf((1-cos_2theta)/2); - return GetWavelength_A() / (2 * sin_theta); -} - int64_t DiffractionExperiment::GetSpaceGroupNumber() const { return dataset.space_group_number(); } @@ -880,7 +833,7 @@ DiffractionExperiment::operator JFJochProtoBuf::DetectorInput() const { } ret.set_storage_cell_start(GetStorageCellStart()); ret.set_storage_cell_number(GetStorageCellNumber()); - ret.set_storage_cell_delay(7.5); + ret.set_storage_cell_delay_ns(GetStorageCellDelay().count()); if (GetStorageCellNumber() > 1) { ret.set_period_us((GetFrameTime().count() +10) * GetStorageCellNumber()); @@ -946,11 +899,9 @@ void DiffractionExperiment::LoadDatasetSettings(const JFJochProtoBuf::DatasetSet SetUnitCell(); SpaceGroupNumber(settings.space_group_number()); SampleName(settings.sample_name()); - if (settings.has_scattering_vector()) - ScatteringVector({0,0,1}); Compression(settings.compression()); - ApplyPixelMaskInFPGA(settings.apply_pixel_mask()); Binning2x2(settings.binning2x2()); + SaveCalibration(settings.save_calibration()); } catch (...) { dataset = tmp; throw; @@ -982,7 +933,8 @@ void DiffractionExperiment::LoadDetectorSettings(const JFJochProtoBuf::DetectorS if (settings.has_pedestal_g2_frames()) PedestalG2Frames(settings.pedestal_g2_frames()); - + if (settings.has_storage_cell_delay_ns()) + StorageCellDelay(std::chrono::nanoseconds(settings.storage_cell_delay_ns())); ConversionOnCPU(settings.conversion_on_cpu()); } catch (...) { internal = tmp; @@ -1000,6 +952,7 @@ JFJochProtoBuf::DetectorSettings DiffractionExperiment::GetDetectorSettings() co ret.set_pedestal_g0_frames(GetPedestalG0Frames()); ret.set_pedestal_g1_frames(GetPedestalG1Frames()); ret.set_pedestal_g2_frames(GetPedestalG2Frames()); + ret.set_storage_cell_delay_ns(GetStorageCellDelay().count()); return ret; } @@ -1079,6 +1032,7 @@ void DiffractionExperiment::FillMessage(StartMessage &message) const { message.compression_block_size = JFJochBitShuffleCompressor::DefaultBlockSize; message.pixel_bit_depth = GetPixelDepth() * 8; message.storage_cell_number = GetStorageCellNumber(); + message.storage_cell_delay_ns = GetStorageCellDelay().count(); message.file_prefix = GetFilePrefix(); message.pixel_signed = IsPixelSigned(); message.sample_name = GetSampleName(); @@ -1111,13 +1065,13 @@ void DiffractionExperiment::FillMessage(StartMessage &message) const { } DiffractionExperiment &DiffractionExperiment::ApplyPixelMaskInFPGA(bool input) { - dataset.set_apply_pixel_mask(input); + internal.set_debug_pixel_mask(!input); return *this; } bool DiffractionExperiment::GetApplyPixelMaskInFPGA() const { if (GetDetectorMode() == DetectorMode::Conversion) - return dataset.apply_pixel_mask(); + return !internal.debug_pixel_mask(); else return false; } @@ -1204,3 +1158,77 @@ bool DiffractionExperiment::GetPedestalWithExternalTrigger() const { return (GetStorageCellNumber() > 1); } +DiffractionExperiment &DiffractionExperiment::ApplySolidAngleCorr(bool input) { + dataset.set_rad_int_solid_angle_corr(input); + return *this; +} + +DiffractionExperiment &DiffractionExperiment::ApplyPolarizationCorr(bool input) { + dataset.set_rad_int_polarization_corr(input); + return *this; +} + +DiffractionExperiment &DiffractionExperiment::PolarizationFactor(float input) { + dataset.set_rad_int_polarization_factor(input); + return *this; +} + +bool DiffractionExperiment::GetApplySolidAngleCorr() const { + return dataset.rad_int_solid_angle_corr(); +} + +bool DiffractionExperiment::GetApplyPolarizationCorr() const { + return dataset.rad_int_polarization_corr(); +} + +float DiffractionExperiment::GetPolarizationFactor() const { + return dataset.rad_int_polarization_factor(); +} + +DiffractionExperiment &DiffractionExperiment::ApplyROI(bool input) { + internal.set_roi_apply(input); + return *this; +} + +DiffractionExperiment &DiffractionExperiment::AddROIRectangle(int32_t x, int32_t y, int32_t width, int32_t height) { + auto *tmp = internal.add_roi_rectangle(); + tmp->set_x0(x); + tmp->set_y0(y); + tmp->set_width(width); + tmp->set_height(height); + return *this; +} + +DiffractionExperiment &DiffractionExperiment::ClearROI() { + internal.clear_roi_rectangle(); + return *this; +} + +bool DiffractionExperiment::GetApplyROI() const { + return internal.roi_apply(); +} + +void DiffractionExperiment::SetupROIFilter(ROIFilter &filter) { + for (const auto& i: internal.roi_rectangle()) + filter.SetRectangle(i.x0(), i.y0(), i.width(), i.height()); +} + +DiffractionExperiment &DiffractionExperiment::SaveCalibration(bool input) { + dataset.set_save_calibration(input); + return *this; +} + +bool DiffractionExperiment::GetSaveCalibration() const { + return dataset.save_calibration(); +} + +DiffractionExperiment &DiffractionExperiment::StorageCellDelay(std::chrono::nanoseconds input) { + check_min("Storage cell delay [ns]", input.count(), MIN_STORAGE_CELL_DELAY_IN_NS); + internal.set_storage_cell_delay_ns(input.count()); + return *this; +} + +std::chrono::nanoseconds DiffractionExperiment::GetStorageCellDelay() const { + return std::chrono::nanoseconds(internal.storage_cell_delay_ns()); +} + diff --git a/common/DiffractionExperiment.h b/common/DiffractionExperiment.h index 8723865e..619e7a78 100644 --- a/common/DiffractionExperiment.h +++ b/common/DiffractionExperiment.h @@ -1,5 +1,4 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (2019-2023) Paul Scherrer Institute #ifndef DIFFRACTIONEXPERIMENT_H #define DIFFRACTIONEXPERIMENT_H @@ -15,9 +14,9 @@ #include "UnitCell.h" #include "Coord.h" #include "Definitions.h" -#include "../frame_serialize/StartMessage.h" -#include "../frame_serialize/EndMessage.h" +#include "../frame_serialize/CBORMessages.h" #include "DetectorSetup.h" +#include "ROIFilter.h" enum class DetectorMode : int { Conversion, Raw, PedestalG0, PedestalG1, PedestalG2 @@ -59,8 +58,6 @@ public: DiffractionExperiment& BeamY_pxl(float input); DiffractionExperiment& DetectorDistance_mm(float input); - DiffractionExperiment& ScatteringVector(Coord input); - DiffractionExperiment& ScatteringVector(); DiffractionExperiment& FilePrefix(std::string input); DiffractionExperiment& DataFileCount(int64_t input); @@ -131,6 +128,9 @@ public: std::chrono::microseconds GetImageCountTime() const; std::chrono::microseconds GetFrameCountTime() const; + DiffractionExperiment& StorageCellDelay(std::chrono::nanoseconds input); + std::chrono::nanoseconds GetStorageCellDelay() const; + float GetPhotonEnergy_keV() const; float GetWavelength_A() const; float GetBeamX_pxl() const; @@ -184,10 +184,7 @@ public: UnitCell GetUnitCell() const; bool HasUnitCell() const; - float ResToPxl(float resolution) const; Coord LabCoord(float detector_x, float detector_y) const; - float PxlToRes(float detector_x, float detector_y) const; - float CalcRadIntSolidAngleCorr(float q) const; float GetLowQForRadialInt_recipA() const; float GetHighQForRadialInt_recipA() const; @@ -217,6 +214,22 @@ public: void GetDetectorModuleHostname(std::vector& output) const; bool GetPedestalWithExternalTrigger() const; + + DiffractionExperiment& ApplySolidAngleCorr(bool input); + DiffractionExperiment& ApplyPolarizationCorr(bool input); + DiffractionExperiment& PolarizationFactor(float input); + bool GetApplySolidAngleCorr() const; + bool GetApplyPolarizationCorr() const; + float GetPolarizationFactor() const; + + DiffractionExperiment& ApplyROI(bool input); + DiffractionExperiment& AddROIRectangle(int32_t x, int32_t y, int32_t width, int32_t height); + DiffractionExperiment& ClearROI(); + bool GetApplyROI() const; + void SetupROIFilter(ROIFilter& filter); + + DiffractionExperiment& SaveCalibration(bool input); + bool GetSaveCalibration() const; }; inline int64_t CalculateStride(const std::chrono::microseconds &frame_time, const std::chrono::microseconds &preview_time) { diff --git a/common/DiffractionGeometry.h b/common/DiffractionGeometry.h new file mode 100644 index 00000000..b89b82d1 --- /dev/null +++ b/common/DiffractionGeometry.h @@ -0,0 +1,99 @@ +// Copyright (2019-2023) Paul Scherrer Institute + +#ifndef JUNGFRAUJOCH_DIFFRACTIONGEOMETRY_H +#define JUNGFRAUJOCH_DIFFRACTIONGEOMETRY_H + +#include "DiffractionExperiment.h" +#include + +inline Coord DetectorToRecip(const DiffractionExperiment &experiment, float x, float y) { + return experiment.LabCoord(x, y).Normalize() / experiment.GetWavelength_A() - experiment.GetScatteringVector(); +} + +inline std::pair RecipToDector(const DiffractionExperiment &experiment, const Coord &recip) { + auto S = recip + experiment.GetScatteringVector(); + float coeff = experiment.GetDetectorDistance_mm() / (S.z * experiment.GetPixelSize_mm()); + float x = experiment.GetBeamX_pxl() + S.x * coeff; + float y = experiment.GetBeamY_pxl() + S.y * coeff; + return {x, y}; +} + +inline float CosTwoTheta(const DiffractionExperiment& experiment, float x, float y) { + auto lab = experiment.LabCoord(x, y); + return experiment.GetDetectorDistance_mm() / lab.Length(); +} + +inline float Phi(const DiffractionExperiment& experiment, float x, float y) { + auto lab = experiment.LabCoord(x, y); + return atan2f(lab.y, lab.x); +} + +inline float PxlToRes(const DiffractionExperiment& experiment, float x, float y) { + float cos_2theta = CosTwoTheta(experiment, x, y); + if (cos_2theta == 1.0f) + return std::numeric_limits::infinity(); + + // cos(2theta) = cos(theta)^2 - sin(theta)^2 + // cos(2theta) = 1 - 2*sin(theta)^2 + // Technically two solutions for two theta, but it makes sense only to take positive one in this case + float sin_theta = sqrtf((1 - cos_2theta)/2); + return experiment.GetWavelength_A() / (2 * sin_theta); +} + +inline float ResToPxl(const DiffractionExperiment& experiment, float d) { + if (d == 0) + return INFINITY; + + float sin_theta = experiment.GetWavelength_A() / (2 * d); + float theta = asinf(sin_theta); + float tan_2theta = tanf(2 * theta); + return tan_2theta * experiment.GetDetectorDistance_mm() / experiment.GetPixelSize_mm(); +} + +inline float DistFromEwaldSphere(const DiffractionExperiment& experiment, const Coord& recip) { + auto S = recip + experiment.GetScatteringVector(); + return fabsf(S.Length() - (1.0f/experiment.GetWavelength_A())); +} + +inline float CalcRadIntSolidAngleCorr(const DiffractionExperiment& experiment, float q) { + float sin_theta = q * experiment.GetWavelength_A() / (4 * static_cast(M_PI)); + float cos_2theta = 1.0f - 2.0f * sin_theta * sin_theta; // cos(2*alpha) = 1 - 2 * sin(alpha)^2 + float cos_2theta_3 = cos_2theta * cos_2theta * cos_2theta; + return cos_2theta_3; +} + +inline float CalcRadIntSolidAngleCorr(const DiffractionExperiment& experiment, float x, float y) { + float cos_2theta = CosTwoTheta(experiment, x, y); + float cos_2theta_3 = cos_2theta * cos_2theta * cos_2theta; + return cos_2theta_3; +} + +inline float CalcRadIntPolarizationCorr(const DiffractionExperiment& experiment, float x, float y) { + auto cos_2theta = CosTwoTheta(experiment, x, y); + float cos_2theta_2 = cos_2theta * cos_2theta; + float cos_2phi = cosf(2.0f * Phi(experiment, x, y)); + return 0.5f * (1.0f + cos_2theta_2 - experiment.GetPolarizationFactor() * cos_2phi * (1.0f - cos_2theta_2)); +} + +inline std::vector CalcRadIntCorr(const DiffractionExperiment& experiment) { + std::vector corr(experiment.GetPixelsNum(), 1.0); + auto xpixels = experiment.GetXPixelsNum(); + auto ypixels = experiment.GetYPixelsNum(); + + for (int y = 0; y < ypixels; y++) { + for (int x = 0; x < xpixels; x++) { + if (experiment.GetApplySolidAngleCorr()) + corr[y * xpixels + x] *= CalcRadIntSolidAngleCorr(experiment, + static_cast(x), + static_cast(y)); + if (experiment.GetApplyPolarizationCorr()) + corr[y * xpixels + x] *= CalcRadIntPolarizationCorr(experiment, + static_cast(x), + static_cast(y)); + } + } + + return corr; +} + +#endif //JUNGFRAUJOCH_DIFFRACTIONGEOMETRY_H diff --git a/common/DiffractionSpot.cpp b/common/DiffractionSpot.cpp index ea6526ae..f408777f 100644 --- a/common/DiffractionSpot.cpp +++ b/common/DiffractionSpot.cpp @@ -1,8 +1,7 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (2019-2023) Paul Scherrer Institute #include "DiffractionSpot.h" -#include "RawToConvertedGeometry.h" +#include "DiffractionGeometry.h" DiffractionSpot::DiffractionSpot(uint32_t col, uint32_t line, int64_t in_photons) { if (in_photons < 0) in_photons = 0; @@ -38,17 +37,16 @@ int64_t DiffractionSpot::PixelCount() const { return pixel_count; } -Coord DiffractionSpot::LabCoord(const DiffractionExperiment &experiment, uint16_t data_stream) const { +Coord DiffractionSpot::LabCoord(const DiffractionExperiment &experiment) const { return experiment.LabCoord(x / (float)photons, y / (float)photons); } -Coord DiffractionSpot::ReciprocalCoord(const DiffractionExperiment &experiment, uint16_t data_stream) const { - return LabCoord(experiment, data_stream).Normalize() / experiment.GetWavelength_A() - - experiment.GetScatteringVector(); +Coord DiffractionSpot::ReciprocalCoord(const DiffractionExperiment &experiment) const { + return DetectorToRecip(experiment, x / (float)photons, y / (float)photons); } -double DiffractionSpot::GetResolution(const DiffractionExperiment &experiment, uint16_t data_stream) const { - return experiment.PxlToRes(x / (float)photons, y / (float)photons); +double DiffractionSpot::GetResolution(const DiffractionExperiment &experiment) const { + return PxlToRes(experiment, x / (float)photons, y / (float)photons); } DiffractionSpot::operator SpotToSave() const { diff --git a/common/DiffractionSpot.h b/common/DiffractionSpot.h index d2359f77..dd138f7f 100644 --- a/common/DiffractionSpot.h +++ b/common/DiffractionSpot.h @@ -1,5 +1,4 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (2019-2023) Paul Scherrer Institute #ifndef JUNGFRAUJOCH_DIFFRACTIONSPOT_H #define JUNGFRAUJOCH_DIFFRACTIONSPOT_H @@ -23,9 +22,9 @@ public: int64_t Count() const; int64_t MaxCount() const; Coord RawCoord() const; - Coord LabCoord(const DiffractionExperiment &experiment, uint16_t data_stream = TASK_NO_DATA_STREAM) const; - double GetResolution(const DiffractionExperiment &experiment, uint16_t data_stream = TASK_NO_DATA_STREAM) const; - Coord ReciprocalCoord(const DiffractionExperiment &experiment, uint16_t data_stream = TASK_NO_DATA_STREAM) const; + Coord LabCoord(const DiffractionExperiment &experiment) const; + double GetResolution(const DiffractionExperiment &experiment) const; + Coord ReciprocalCoord(const DiffractionExperiment &experiment) const; operator SpotToSave() const; void AddPixel(uint32_t col, uint32_t line, int64_t photons); }; diff --git a/common/FrameTransformation.cpp b/common/FrameTransformation.cpp index 924a29a2..7f412eca 100644 --- a/common/FrameTransformation.cpp +++ b/common/FrameTransformation.cpp @@ -1,5 +1,4 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (2019-2023) Paul Scherrer Institute #include @@ -12,7 +11,7 @@ FrameTransformation::FrameTransformation(const DiffractionExperiment &in_experiment) : experiment(in_experiment), summation(experiment.GetSummation()), pixel_depth(experiment.GetPixelDepth()), compressor(in_experiment.GetCompressionAlgorithmEnum()), - binning_2x2(experiment.GetBinning2x2()) { + binning_2x2(experiment.GetBinning2x2()), conversion_buffer(RAW_MODULE_SIZE) { if ((experiment.GetDetectorMode() == DetectorMode::Conversion) && (summation > 1)) { for (int i = 0; i < experiment.GetModulesNum(); i++) @@ -143,6 +142,13 @@ void FrameTransformation::ProcessModule(const int16_t *input, uint16_t module_nu } } +void FrameTransformation::ApplyROI(const ROIFilter &filter) { + if (pixel_depth == 2) + filter.Apply((int16_t *) precompression_buffer.data(), static_cast(INT16_MIN)); + else + filter.Apply((int32_t *) precompression_buffer.data(), static_cast(INT32_MIN)); +} + int16_t *FrameTransformation::GetPreview16BitImage() { if (pixel_depth == 2) return (int16_t *) precompression_buffer.data(); @@ -163,11 +169,15 @@ void FrameTransformation::ProcessModule(JFConversion &conv, const int16_t *input if (experiment.GetDetectorMode() != DetectorMode::Conversion) memcpy(output + RAW_MODULE_SIZE * module_number_abs, input, RAW_MODULE_SIZE * experiment.GetPixelDepth()); - else - conv.ConvertAdjustGeom((int16_t *) output, (uint16_t *) input, - experiment.GetModuleSlowDirectionStep(module_number_abs), - experiment.GetModuleFastDirectionStep(module_number_abs), - experiment.GetPixel0OfModule(module_number_abs)); + else { + conv.ConvertModule(conversion_buffer.data(), (uint16_t *) input); + TransferModuleAdjustMultipixels(output, conversion_buffer.data(), + experiment.GetModuleSlowDirectionStep(module_number_abs), + static_cast(INT16_MIN), + static_cast(INT16_MAX), + experiment.GetModuleFastDirectionStep(module_number_abs), + experiment.GetPixel0OfModule(module_number_abs)); + } } else { throw JFJochException(JFJochExceptionCategory::InputParameterInvalid, "Summation with CPU conversion not supported at the moment"); diff --git a/common/FrameTransformation.h b/common/FrameTransformation.h index 13442a2d..d212d9dd 100644 --- a/common/FrameTransformation.h +++ b/common/FrameTransformation.h @@ -1,5 +1,4 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (2019-2023) Paul Scherrer Institute #ifndef JUNGFRAUJOCH_FRAMETRANSFORMATION_H #define JUNGFRAUJOCH_FRAMETRANSFORMATION_H @@ -7,6 +6,7 @@ #include "DiffractionExperiment.h" #include "../compression/JFJochCompressor.h" #include "../jungfrau/JFConversion.h" +#include "ROIFilter.h" class FrameTransformation { const DiffractionExperiment& experiment; @@ -14,6 +14,7 @@ class FrameTransformation { std::vector > summation_buffer; std::vector precompression_buffer; + std::vector conversion_buffer; std::vector image16bit; const size_t summation; @@ -30,6 +31,7 @@ public: int data_stream); void Pack(); // transfer summed image to converted coordinates, clear summation buffer size_t SaveCompressedImage(void *output); + void ApplyROI(const ROIFilter &filter); int16_t *GetPreview16BitImage(); }; diff --git a/common/GitInfo.cpp.in b/common/GitInfo.cpp.in index 63ec4475..ca5bf312 100644 --- a/common/GitInfo.cpp.in +++ b/common/GitInfo.cpp.in @@ -1,5 +1,4 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (2019-2023) Paul Scherrer Institute #include diff --git a/common/GitInfo.h b/common/GitInfo.h index ff359763..fc87481f 100644 --- a/common/GitInfo.h +++ b/common/GitInfo.h @@ -1,5 +1,4 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (2019-2023) Paul Scherrer Institute #ifndef JUNGFRAUJOCH_GITINFO_H #define JUNGFRAUJOCH_GITINFO_H diff --git a/common/Histogram.h b/common/Histogram.h index 7202c616..477aa646 100644 --- a/common/Histogram.h +++ b/common/Histogram.h @@ -1,5 +1,4 @@ // Copyright (2019-2023) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later #ifndef JUNGFRAUJOCH_HISTOGRAM_H #define JUNGFRAUJOCH_HISTOGRAM_H diff --git a/common/ImagePusher.cpp b/common/ImagePusher.cpp index 64c9f54f..a88ba5c4 100644 --- a/common/ImagePusher.cpp +++ b/common/ImagePusher.cpp @@ -1,5 +1,4 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (2019-2023) Paul Scherrer Institute #include "ImagePusher.h" @@ -12,6 +11,7 @@ void PrepareCBORImage(DataMessage& message, message.image.ypixel = experiment.GetYPixelsNum(); message.image.pixel_depth_bytes = experiment.GetPixelDepth(); message.image.pixel_is_signed = experiment.IsPixelSigned(); + message.image.pixel_is_float = false; message.image.algorithm = experiment.GetCompressionAlgorithmEnum(); message.image.channel = "default"; } diff --git a/common/ImagePusher.h b/common/ImagePusher.h index bde64161..8cc4d514 100644 --- a/common/ImagePusher.h +++ b/common/ImagePusher.h @@ -1,5 +1,4 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (2019-2023) Paul Scherrer Institute #ifndef JUNGFRAUJOCH_IMAGEPUSHER_H #define JUNGFRAUJOCH_IMAGEPUSHER_H @@ -10,8 +9,7 @@ #include "DiffractionExperiment.h" #include "DiffractionSpot.h" #include "../frame_serialize/JFJochFrameSerializer.h" -#include "../frame_serialize/StartMessage.h" -#include "../frame_serialize/EndMessage.h" +#include "../frame_serialize/CBORMessages.h" #include "ZeroCopyReturnValue.h" void PrepareCBORImage(DataMessage& message, diff --git a/common/JFJochException.h b/common/JFJochException.h index 329d65f5..d57f005a 100644 --- a/common/JFJochException.h +++ b/common/JFJochException.h @@ -1,5 +1,4 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (2019-2023) Paul Scherrer Institute #ifndef SLSEXCEPTION_H #define SLSEXCEPTION_H diff --git a/common/Logger.cpp b/common/Logger.cpp index 23cc0485..b426da26 100644 --- a/common/Logger.cpp +++ b/common/Logger.cpp @@ -1,5 +1,4 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (2019-2023) Paul Scherrer Institute #include "spdlog/sinks/daily_file_sink.h" #include "spdlog/sinks/stdout_color_sinks.h" diff --git a/common/Logger.h b/common/Logger.h index fea2c3fd..cf279bca 100644 --- a/common/Logger.h +++ b/common/Logger.h @@ -1,5 +1,4 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (2019-2023) Paul Scherrer Institute #ifndef JUNGFRAUJOCH_LOGGER_H #define JUNGFRAUJOCH_LOGGER_H diff --git a/common/NUMAHWPolicy.cpp b/common/NUMAHWPolicy.cpp new file mode 100644 index 00000000..6aa0433a --- /dev/null +++ b/common/NUMAHWPolicy.cpp @@ -0,0 +1,128 @@ +// Copyright (2019-2023) Paul Scherrer Institute + +#include "NUMAHWPolicy.h" + +#include "../common/CUDAWrapper.h" +#include "JFJochException.h" + +#ifdef JFJOCH_USE_NUMA +#include +#endif + +NUMAHWPolicy::NUMAHWPolicy(const std::string &policy) : name(policy) { + if ((policy.empty()) || (policy == "none")) { + name = "none"; + } else if (policy == "n2g2") { + bindings.emplace_back(NUMABinding{.cpu_node = 0, .mem_node = 0, .gpu = 0}); + bindings.emplace_back(NUMABinding{.cpu_node = 1, .mem_node = 1, .gpu = 1}); + } else if (policy == "n2g4") { + bindings.emplace_back(NUMABinding{.cpu_node = 0, .mem_node = 0, .gpu = 0}); + bindings.emplace_back(NUMABinding{.cpu_node = 1, .mem_node = 1, .gpu = 2}); + bindings.emplace_back(NUMABinding{.cpu_node = 0, .mem_node = 0, .gpu = 1}); + bindings.emplace_back(NUMABinding{.cpu_node = 1, .mem_node = 1, .gpu = 3}); + } else if (policy == "n2g4_hbm") { + bindings.emplace_back(NUMABinding{.cpu_node = 0, .mem_node = 2, .gpu = 0}); + bindings.emplace_back(NUMABinding{.cpu_node = 1, .mem_node = 3, .gpu = 2}); + bindings.emplace_back(NUMABinding{.cpu_node = 0, .mem_node = 2, .gpu = 1}); + bindings.emplace_back(NUMABinding{.cpu_node = 1, .mem_node = 3, .gpu = 3}); + } else if (policy == "n8g4") { + for (int32_t i = 0; i < 8; i++) + bindings.emplace_back(NUMABinding{.cpu_node = i, .mem_node = i, .gpu = i/2}); + } else if (policy == "n8g4_hbm") { + for (int32_t i = 0; i < 8; i++) + bindings.emplace_back(NUMABinding{.cpu_node = i, .mem_node = i + 8, .gpu = i / 2}); + } else if (policy == "g2") { + bindings.emplace_back(NUMABinding{.cpu_node = -1, .mem_node = -1, .gpu = 0}); + bindings.emplace_back(NUMABinding{.cpu_node = -1, .mem_node = -1, .gpu = 1}); + } else if (policy == "g4") { + bindings.emplace_back(NUMABinding{.cpu_node = -1, .mem_node = -1, .gpu = 0}); + bindings.emplace_back(NUMABinding{.cpu_node = -1, .mem_node = -1, .gpu = 1}); + bindings.emplace_back(NUMABinding{.cpu_node = -1, .mem_node = -1, .gpu = 2}); + bindings.emplace_back(NUMABinding{.cpu_node = -1, .mem_node = -1, .gpu = 3}); + } else + throw JFJochException(JFJochExceptionCategory::InputParameterInvalid, "Unknown NUMA policy"); +} + +NUMAHWPolicy::NUMAHWPolicy(const NUMAHWPolicy &other) : bindings(other.bindings), name(other.name), curr_thread(0) {} + +NUMAHWPolicy &NUMAHWPolicy::operator=(const NUMAHWPolicy &other) { + bindings = other.bindings; + name = other.name; + curr_thread = 0; + return *this; +} + +NUMABinding NUMAHWPolicy::GetBinding(uint32_t thread) { + if (bindings.empty()) + return NUMABinding{.cpu_node = -1, .mem_node = -1, .gpu = -1}; + else + return bindings.at(thread % bindings.size()); +} + +NUMABinding NUMAHWPolicy::GetBinding() { + return GetBinding(curr_thread++); +} + +void NUMAHWPolicy::Bind() { + Bind(GetBinding()); +} + +void NUMAHWPolicy::Bind(uint32_t thread) { + Bind(GetBinding(thread)); +} + +void NUMAHWPolicy::Bind(const NUMABinding &binding) { + RunOnNode(binding.cpu_node); + MemOnNode(binding.mem_node); + SelectGPU(binding.gpu); +} + +void NUMAHWPolicy::RunOnNode(int32_t cpu_node) { +#ifdef JFJOCH_USE_NUMA + if (numa_available() != -1) { + auto max_nodes = numa_num_configured_nodes(); + + if (cpu_node >= 0) { + if (cpu_node < max_nodes) + numa_run_on_node(cpu_node); + else + throw JFJochException(JFJochExceptionCategory::InputParameterInvalid, "CPU NUMA node out of bounds"); + } + } +#endif +} + +void NUMAHWPolicy::MemOnNode(int32_t mem_node) { +#ifdef JFJOCH_USE_NUMA + if (numa_available() != -1) { + auto max_nodes = numa_num_configured_nodes(); + + if (mem_node >= 0) { + if (mem_node < max_nodes) { + struct bitmask *mask = numa_allocate_nodemask(); + numa_bitmask_setbit(mask, mem_node); + numa_set_membind(mask); + numa_bitmask_free(mask); + } else + throw JFJochException(JFJochExceptionCategory::InputParameterInvalid, "Memory NUMA node out of bounds"); + } + } +#endif +} + +void NUMAHWPolicy::SelectGPU(int32_t gpu) { +#ifdef JFJOCH_USE_CUDA + if (gpu > 0) { + if (gpu < get_gpu_count()) + set_gpu(gpu); + else + throw JFJochException(JFJochExceptionCategory::InputParameterInvalid, "GPU device out of bounds"); + } +#endif +} + +const std::string &NUMAHWPolicy::GetName() const { + return name; +} + + diff --git a/common/NUMAHWPolicy.h b/common/NUMAHWPolicy.h new file mode 100644 index 00000000..7829eed4 --- /dev/null +++ b/common/NUMAHWPolicy.h @@ -0,0 +1,39 @@ +// Copyright (2019-2023) Paul Scherrer Institute + +#ifndef JUNGFRAUJOCH_NUMAHWPOLICY_H +#define JUNGFRAUJOCH_NUMAHWPOLICY_H + +#include +#include +#include +#include + +struct NUMABinding { + int32_t cpu_node; + int32_t mem_node; + int32_t gpu; +}; + +class NUMAHWPolicy { + std::string name; + std::vector bindings; + std::atomic curr_thread = 0; +public: + NUMAHWPolicy() = default; + explicit NUMAHWPolicy(const std::string& policy); + NUMAHWPolicy(const NUMAHWPolicy& other); + NUMAHWPolicy& operator=(const NUMAHWPolicy& other); + NUMABinding GetBinding(uint32_t thread); + NUMABinding GetBinding(); // round-robin + + const std::string &GetName() const; + + void Bind(uint32_t thread); + void Bind(); // round-robin + static void Bind(const NUMABinding &binding); + static void RunOnNode(int32_t cpu_node); + static void MemOnNode(int32_t mem_node); + static void SelectGPU(int32_t gpu); +}; + +#endif //JUNGFRAUJOCH_NUMAHWPOLICY_H diff --git a/common/NetworkAddressConvert.cpp b/common/NetworkAddressConvert.cpp index c1d2570f..6e0ac0e4 100644 --- a/common/NetworkAddressConvert.cpp +++ b/common/NetworkAddressConvert.cpp @@ -1,5 +1,4 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (2019-2023) Paul Scherrer Institute #include #include diff --git a/common/NetworkAddressConvert.h b/common/NetworkAddressConvert.h index 78854c7b..ea8da982 100644 --- a/common/NetworkAddressConvert.h +++ b/common/NetworkAddressConvert.h @@ -1,5 +1,4 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (2019-2023) Paul Scherrer Institute #ifndef JUNGFRAUJOCH_NETWORKADDRESSCONVERT_H #define JUNGFRAUJOCH_NETWORKADDRESSCONVERT_H diff --git a/common/ROIFilter.h b/common/ROIFilter.h new file mode 100644 index 00000000..3cac8404 --- /dev/null +++ b/common/ROIFilter.h @@ -0,0 +1,79 @@ +// Copyright (2019-2023) Paul Scherrer Institute + +#ifndef JUNGFRAUJOCH_ROIFILTER_H +#define JUNGFRAUJOCH_ROIFILTER_H + +#include +#include +#include +#include "JFJochException.h" + +class ROIFilter { + int32_t width, height; + std::vector mask; +public: + ROIFilter(int32_t in_width, int32_t in_height, uint8_t fill_value = 0) + : width(in_width), height(in_height) { + if ((width < 0) || (height < 0)) + throw JFJochException(JFJochExceptionCategory::InputParameterInvalid, "Negative dimensions are wrong"); + mask = std::vector(in_width * in_height, fill_value); + } + + void SetRectangle(int32_t x0, int32_t y0, int32_t in_width, int32_t in_height, uint8_t mask_value = 1) { + if (x0 < 0) { in_width += x0; x0 = 0; } + if (in_width <= 0) return; + + if (x0 >= width) return; + if (x0 + in_width >= width) in_width = width - x0; + + if (y0 < 0) { in_height += y0; y0 = 0; } + if (in_height <= 0) return; + + if (y0 >= height) return; + if (y0 + in_height >= height) in_height = height - y0; + + for (size_t y = y0; y < y0 + in_height; y++) { + for (size_t x = x0; x < x0 + in_width; x++) { + mask[y * width + x] |= mask_value; + } + } + } + + void ClearRectangle(int32_t x0, int32_t y0, int32_t in_width, int32_t in_height, uint8_t mask_value = 1) { + if (x0 < 0) { in_width += x0; x0 = 0; } + if (in_width <= 0) return; + + if (x0 >= width) return; + if (x0 + in_width >= width) in_width = width - x0; + + if (y0 < 0) { in_height += y0; y0 = 0; } + if (in_height <= 0) return; + + if (y0 >= height) return; + if (y0 + in_height >= height) in_height = height - y0; + + for (size_t y = y0; y < y0 + in_height; y++) { + for (size_t x = x0; x < x0 + in_width; x++) { + mask[y * width + x] &= ~mask_value; + } + } + } + + template + void Apply(T* data, T fill_value) const { + for (size_t i = 0; i < mask.size(); i++) { + if (mask[i] == 0) + data[i] = fill_value; + } + } + + template + void Apply(std::vector &data, T fill_value) const { + if (data.size() != mask.size()) + throw JFJochException(JFJochExceptionCategory::ArrayOutOfBounds, "Mismatch in array size"); + Apply(data.data(), fill_value); + } +}; + + +#endif //JUNGFRAUJOCH_ROIFILTER_H diff --git a/common/RawToConvertedGeometry.h b/common/RawToConvertedGeometry.h index 310f597d..ec59d178 100644 --- a/common/RawToConvertedGeometry.h +++ b/common/RawToConvertedGeometry.h @@ -1,5 +1,4 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (2019-2023) Paul Scherrer Institute #ifndef JUNGFRAUJOCH_RAWTOCONVERTEDGEOMETRY_H #define JUNGFRAUJOCH_RAWTOCONVERTEDGEOMETRY_H diff --git a/common/SpotToSave.h b/common/SpotToSave.h index 5b7dd56d..c63ff7b4 100644 --- a/common/SpotToSave.h +++ b/common/SpotToSave.h @@ -1,5 +1,4 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (2019-2023) Paul Scherrer Institute #ifndef JUNGFRAUJOCH_SPOTTOSAVE_H #define JUNGFRAUJOCH_SPOTTOSAVE_H diff --git a/common/StatusVector.h b/common/StatusVector.h index 980c8a40..9f8206cd 100644 --- a/common/StatusVector.h +++ b/common/StatusVector.h @@ -1,5 +1,4 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (2019-2023) Paul Scherrer Institute #ifndef JUNGFRAUJOCH_STATUSVECTOR_H #define JUNGFRAUJOCH_STATUSVECTOR_H diff --git a/common/TestImagePusher.cpp b/common/TestImagePusher.cpp index 99d4c6bc..fe0aec7e 100644 --- a/common/TestImagePusher.cpp +++ b/common/TestImagePusher.cpp @@ -1,5 +1,4 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (2019-2023) Paul Scherrer Institute #include "TestImagePusher.h" #include "../tests/FPGAUnitTest.h" @@ -106,13 +105,13 @@ bool TestImagePusher::CheckImage(const DiffractionExperiment &x, const std::vect decompressed_image.data(), storage_cell); if (x.GetBinning2x2() && (result > 1.5)) { - logger.Error("Mean conversion error ({}) larger than threshold", result); + logger.Error("Mean conversion error ({:.3f}) larger than threshold", result); no_errors = false; } else if (!x.GetBinning2x2() && (result > 0.5)) { - logger.Error("Mean conversion error ({}) larger than threshold", result); + logger.Error("Mean conversion error ({:.3f}) larger than threshold", result); no_errors = false; } else - logger.Info("Mean conversion error: {}", result); + logger.Info("Mean conversion error: {:.3f}", result); } else if (x.GetDetectorMode() == DetectorMode::Raw) { if (memcmp(raw_reference_image.data(), decompressed_image.data(), sizeof(uint16_t) * x.GetPixelsNum()) != 0) { diff --git a/common/TestImagePusher.h b/common/TestImagePusher.h index 5102b6fa..98098c0b 100644 --- a/common/TestImagePusher.h +++ b/common/TestImagePusher.h @@ -1,5 +1,4 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (2019-2023) Paul Scherrer Institute #ifndef JUNGFRAUJOCH_TESTIMAGEPUSHER_H #define JUNGFRAUJOCH_TESTIMAGEPUSHER_H diff --git a/common/ThreadSafeFIFO.h b/common/ThreadSafeFIFO.h index ca9b0841..b73dd635 100644 --- a/common/ThreadSafeFIFO.h +++ b/common/ThreadSafeFIFO.h @@ -1,5 +1,4 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (2019-2023) Paul Scherrer Institute #ifndef JUNGFRAUJOCH_THREADSAFEFIFO_H #define JUNGFRAUJOCH_THREADSAFEFIFO_H diff --git a/common/UnitCell.h b/common/UnitCell.h index 011fef3f..d9cb1536 100644 --- a/common/UnitCell.h +++ b/common/UnitCell.h @@ -1,5 +1,4 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (2019-2023) Paul Scherrer Institute #ifndef JUNGFRAUJOCH_UNITCELL_H #define JUNGFRAUJOCH_UNITCELL_H diff --git a/common/ZMQImagePusher.cpp b/common/ZMQImagePusher.cpp index 6b7681bf..f45e6d80 100644 --- a/common/ZMQImagePusher.cpp +++ b/common/ZMQImagePusher.cpp @@ -1,5 +1,4 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (2019-2023) Paul Scherrer Institute #include "ZMQImagePusher.h" #include "JFJochException.h" @@ -56,7 +55,7 @@ void ZMQImagePusher::SendImage(const uint8_t *image_data, size_t image_size, int } void ZMQImagePusher::StartDataCollection(const StartMessage& message) { - std::vector serialization_buffer(80*1024*1024); + std::vector serialization_buffer(message.approx_size); JFJochFrameSerializer serializer(serialization_buffer.data(), serialization_buffer.size()); // 80 MiB should be safe even for 16M if (message.data_file_count < 1) diff --git a/common/ZMQImagePusher.h b/common/ZMQImagePusher.h index 9d1af851..eb433cb2 100644 --- a/common/ZMQImagePusher.h +++ b/common/ZMQImagePusher.h @@ -1,5 +1,4 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (2019-2023) Paul Scherrer Institute #ifndef JUNGFRAUJOCH_ZMQIMAGEPUSHER_H #define JUNGFRAUJOCH_ZMQIMAGEPUSHER_H diff --git a/common/ZMQPreviewPublisher.cpp b/common/ZMQPreviewPublisher.cpp index e116cf20..ae298f2f 100644 --- a/common/ZMQPreviewPublisher.cpp +++ b/common/ZMQPreviewPublisher.cpp @@ -1,5 +1,4 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (2019-2023) Paul Scherrer Institute #include "ZMQPreviewPublisher.h" #include "grpcToJson.h" diff --git a/common/ZMQPreviewPublisher.h b/common/ZMQPreviewPublisher.h index 489ee898..004adf47 100644 --- a/common/ZMQPreviewPublisher.h +++ b/common/ZMQPreviewPublisher.h @@ -1,5 +1,4 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (2019-2023) Paul Scherrer Institute #ifndef JUNGFRAUJOCH_ZMQPREVIEWPUBLISHER_H #define JUNGFRAUJOCH_ZMQPREVIEWPUBLISHER_H @@ -9,7 +8,7 @@ #include "ZMQWrappers.h" #include "DiffractionExperiment.h" #include "../jungfrau/JFCalibration.h" -#include "../frame_serialize/ImageMessage.h" +#include "../frame_serialize/CBORMessages.h" class ZMQPreviewPublisher { ZMQSocket socket; diff --git a/common/ZMQWrappers.cpp b/common/ZMQWrappers.cpp index f235d95a..f0d569b9 100644 --- a/common/ZMQWrappers.cpp +++ b/common/ZMQWrappers.cpp @@ -1,5 +1,4 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (2019-2023) Paul Scherrer Institute #include "ZMQWrappers.h" #include diff --git a/common/ZMQWrappers.h b/common/ZMQWrappers.h index 6cc68927..41597d29 100644 --- a/common/ZMQWrappers.h +++ b/common/ZMQWrappers.h @@ -1,5 +1,4 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (2019-2023) Paul Scherrer Institute #ifndef JUNGFRAUJOCH_ZMQWRAPPERS_H #define JUNGFRAUJOCH_ZMQWRAPPERS_H @@ -9,7 +8,6 @@ #include #include #include -#include #include "JFJochException.h" #include "ZeroCopyReturnValue.h" diff --git a/common/ZeroCopyReturnValue.h b/common/ZeroCopyReturnValue.h index 59742d76..ce0fb672 100644 --- a/common/ZeroCopyReturnValue.h +++ b/common/ZeroCopyReturnValue.h @@ -1,5 +1,4 @@ // Copyright (2019-2023) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later #ifndef JUNGFRAUJOCH_ZEROCOPYRETURNVALUE_H #define JUNGFRAUJOCH_ZEROCOPYRETURNVALUE_H diff --git a/common/grpcToJson.h b/common/grpcToJson.h index bac0a040..3614fdb6 100644 --- a/common/grpcToJson.h +++ b/common/grpcToJson.h @@ -1,5 +1,4 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (2019-2023) Paul Scherrer Institute #ifndef JUNGFRAUJOCH_GRPCTOJSON_H #define JUNGFRAUJOCH_GRPCTOJSON_H @@ -18,7 +17,7 @@ inline std::string grpcToJson(const google::protobuf::Message &message) { std::string s; auto status = google::protobuf::util::MessageToJsonString(message, &s, opts); if (!status.ok()) - throw JFJochException(JFJochExceptionCategory::JSON, "Error in generating JSON from ProtoBuf: " + status.message().ToString()); + throw JFJochException(JFJochExceptionCategory::JSON, "Error in generating JSON from ProtoBuf"); return s; } diff --git a/common/jsonToGrpc.h b/common/jsonToGrpc.h index a06accbd..5e88135b 100644 --- a/common/jsonToGrpc.h +++ b/common/jsonToGrpc.h @@ -1,5 +1,4 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (2019-2023) Paul Scherrer Institute #ifndef JUNGFRAUJOCH_JSONTOGRPC_H #define JUNGFRAUJOCH_JSONTOGRPC_H @@ -18,7 +17,7 @@ T jsonToGrpc(const std::string& json) { auto status = google::protobuf::util::JsonStringToMessage(json, &output, opts); if (!status.ok()) - throw JFJochException(JFJochExceptionCategory::JSON, "Error in generating ProtoBuf from JSON: " + status.message().ToString()); + throw JFJochException(JFJochExceptionCategory::JSON, "Error in generating ProtoBuf from JSON"); return output; } diff --git a/common/to_fixed.h b/common/to_fixed.h index 0389a1b4..351d0638 100644 --- a/common/to_fixed.h +++ b/common/to_fixed.h @@ -1,5 +1,4 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (2019-2023) Paul Scherrer Institute #ifndef JUNGFRAUJOCH_TO_FIXED_H #define JUNGFRAUJOCH_TO_FIXED_H diff --git a/compression/CMakeLists.txt b/compression/CMakeLists.txt index e2fc0669..fd1ca7c1 100644 --- a/compression/CMakeLists.txt +++ b/compression/CMakeLists.txt @@ -4,6 +4,8 @@ ADD_LIBRARY(Compression STATIC bitshuffle/bitshuffle.c bitshuffle/bitshuffle_core.c bitshuffle/iochain.c + bitshuffle_hperf/src/bitshuffle.c + bitshuffle_hperf/src/bitshuffle.h JFJochZstdCompressor.cpp JFJochZstdCompressor.h JFJochCompressor.cpp diff --git a/compression/CompressionAlgorithmEnum.h b/compression/CompressionAlgorithmEnum.h index 10321cee..eb9c0fbf 100644 --- a/compression/CompressionAlgorithmEnum.h +++ b/compression/CompressionAlgorithmEnum.h @@ -1,5 +1,4 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (2019-2023) Paul Scherrer Institute #ifndef JUNGFRAUJOCH_COMPRESSIONALGORITHMENUM_H #define JUNGFRAUJOCH_COMPRESSIONALGORITHMENUM_H diff --git a/compression/JFJochCompressor.cpp b/compression/JFJochCompressor.cpp index 1263f251..b9efa8c0 100644 --- a/compression/JFJochCompressor.cpp +++ b/compression/JFJochCompressor.cpp @@ -1,11 +1,11 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (2019-2023) Paul Scherrer Institute #include "JFJochCompressor.h" #include #include #include +#include #include #include @@ -22,8 +22,7 @@ JFJochBitShuffleCompressor::JFJochBitShuffleCompressor(CompressionAlgorithm in_a size_t JFJochBitShuffleCompressor::CompressBlock(char *dest, const char *source, size_t nelements, size_t elem_size) { // Assert nelements < block_size const char *src_ptr; - - int64_t bshuf_ret = bshuf_trans_bit_elem(source, tmp_space.data(), nelements, elem_size); + int64_t bshuf_ret = bitshuf_encode_block(tmp_space.data(), source, scratch, nelements, elem_size); if (bshuf_ret < 0) throw JFJochException(JFJochExceptionCategory::Compression, "bshuf_trans_bit_elem error"); src_ptr = tmp_space.data(); diff --git a/compression/JFJochCompressor.h b/compression/JFJochCompressor.h index 7aff36a5..7da600a7 100644 --- a/compression/JFJochCompressor.h +++ b/compression/JFJochCompressor.h @@ -1,5 +1,4 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (2019-2023) Paul Scherrer Institute #ifndef JUNGFRAUJOCH_JFJOCHCOMPRESSOR_H #define JUNGFRAUJOCH_JFJOCHCOMPRESSOR_H @@ -10,6 +9,7 @@ #include #include #include "CompressionAlgorithmEnum.h" +#include "MaxCompressedSize.h" #include "JFJochZstdCompressor.h" @@ -17,16 +17,29 @@ class JFJochBitShuffleCompressor { JFJochZstdCompressor zstd_compressor; CompressionAlgorithm algorithm; std::vector tmp_space; + size_t CompressBlock(char *dest, const char * source, size_t nelements, size_t elem_size); public: constexpr static const size_t DefaultBlockSize = 4096; - JFJochBitShuffleCompressor(CompressionAlgorithm algorithm); + explicit JFJochBitShuffleCompressor(CompressionAlgorithm algorithm); + template size_t Compress(void *dest, const std::vector &src) { return Compress((char *) dest, (char *) src.data(), src.size(), sizeof(T)); }; + + template + std::vector Compress(const std::vector &src) { + std::vector tmp(MaxCompressedSize(algorithm, src.size(), sizeof(T))); + size_t tmp_size = Compress(tmp.data(), src); + tmp.resize(tmp_size); + return tmp; + } + size_t Compress(char *dest, const char* source, size_t nelements, size_t elem_size); +private: + char scratch[DefaultBlockSize * sizeof(uint64_t)]; }; template std::vector bitshuffle(const std::vector &input, size_t block_size) { diff --git a/compression/JFJochDecompress.h b/compression/JFJochDecompress.h index b373bd72..f6424992 100644 --- a/compression/JFJochDecompress.h +++ b/compression/JFJochDecompress.h @@ -1,5 +1,4 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (2019-2023) Paul Scherrer Institute #ifndef JUNGFRAUJOCH_JFJOCHDECOMPRESS_H #define JUNGFRAUJOCH_JFJOCHDECOMPRESS_H diff --git a/compression/JFJochZstdCompressor.cpp b/compression/JFJochZstdCompressor.cpp index 2ec156b7..8fca994a 100644 --- a/compression/JFJochZstdCompressor.cpp +++ b/compression/JFJochZstdCompressor.cpp @@ -1,5 +1,4 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (2019-2023) Paul Scherrer Institute #include "JFJochZstdCompressor.h" diff --git a/compression/JFJochZstdCompressor.h b/compression/JFJochZstdCompressor.h index 2775e134..28084bea 100644 --- a/compression/JFJochZstdCompressor.h +++ b/compression/JFJochZstdCompressor.h @@ -1,5 +1,4 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (2019-2023) Paul Scherrer Institute #ifndef JUNGFRAUJOCH_JFJOCHZSTDCOMPRESSOR_H #define JUNGFRAUJOCH_JFJOCHZSTDCOMPRESSOR_H diff --git a/compression/MaxCompressedSize.cpp b/compression/MaxCompressedSize.cpp index c21132e9..0646e607 100644 --- a/compression/MaxCompressedSize.cpp +++ b/compression/MaxCompressedSize.cpp @@ -1,5 +1,4 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (2019-2023) Paul Scherrer Institute #include diff --git a/compression/MaxCompressedSize.h b/compression/MaxCompressedSize.h index 52689674..6ecd3e17 100644 --- a/compression/MaxCompressedSize.h +++ b/compression/MaxCompressedSize.h @@ -1,5 +1,4 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (2019-2023) Paul Scherrer Institute #ifndef JUNGFRAUJOCH_MAXCOMPRESSEDSIZE_H #define JUNGFRAUJOCH_MAXCOMPRESSEDSIZE_H diff --git a/compression/bitshuffle_hperf b/compression/bitshuffle_hperf new file mode 160000 index 00000000..be844a76 --- /dev/null +++ b/compression/bitshuffle_hperf @@ -0,0 +1 @@ +Subproject commit be844a76f4d4ed3927fcb240a36c6d52bb3908a3 diff --git a/detector_control/DetectorWrapper.cpp b/detector_control/DetectorWrapper.cpp index cbaf5b9d..b434f059 100644 --- a/detector_control/DetectorWrapper.cpp +++ b/detector_control/DetectorWrapper.cpp @@ -1,5 +1,4 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (2019-2023) Paul Scherrer Institute #include @@ -10,8 +9,17 @@ void DetectorWrapper::Configure(const JFJochProtoBuf::DetectorConfig &request) { logger.Info("Configure"); try { - if (det.size() > 0) + if (det.size() > 0) { + // Only if the detector is already defined + + // Stop the detector InternalStop(); + + // Clear synchronization prior to reconfiguring the detector + det.setMaster(false, 0); + det.setSynchronization(false); + } + if (request.module_hostname_size() > 0) { std::vector module_hostname; for (const auto &iter: request.module_hostname()) @@ -100,7 +108,7 @@ void DetectorWrapper::Start(const JFJochProtoBuf::DetectorInput &request) { det.setNumberOfTriggers(request.num_triggers()); det.setStorageCellStart(request.storage_cell_start()); det.setNumberOfAdditionalStorageCells(request.storage_cell_number() - 1); - det.setStorageCellDelay(std::chrono::nanoseconds(static_cast(request.storage_cell_delay() * 1000))); + det.setStorageCellDelay(std::chrono::nanoseconds(request.storage_cell_delay_ns() - MIN_STORAGE_CELL_DELAY_IN_NS)); if (request.period_us() < MIN_FRAME_TIME_HALF_SPEED_IN_US) det.setReadoutSpeed(slsDetectorDefs::speedLevel::FULL_SPEED); diff --git a/detector_control/DetectorWrapper.h b/detector_control/DetectorWrapper.h index ed8d280d..2bc09426 100644 --- a/detector_control/DetectorWrapper.h +++ b/detector_control/DetectorWrapper.h @@ -1,5 +1,4 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (2019-2023) Paul Scherrer Institute #ifndef JUNGFRAUJOCH_DETECTORWRAPPER_H #define JUNGFRAUJOCH_DETECTORWRAPPER_H diff --git a/detector_control/JFJochDetector.cpp b/detector_control/JFJochDetector.cpp index 45503c8c..fa328863 100644 --- a/detector_control/JFJochDetector.cpp +++ b/detector_control/JFJochDetector.cpp @@ -1,5 +1,4 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (2019-2023) Paul Scherrer Institute #include "JFJochDetector.h" #include "../common/JFJochException.h" diff --git a/detector_control/JFJochDetector.h b/detector_control/JFJochDetector.h index 61e21094..4c88e4a6 100644 --- a/detector_control/JFJochDetector.h +++ b/detector_control/JFJochDetector.h @@ -1,5 +1,4 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (2019-2023) Paul Scherrer Institute #ifndef DETECTORWRAPPER_H #define DETECTORWRAPPER_H diff --git a/detector_control/jfjoch_detector.cpp b/detector_control/jfjoch_detector.cpp index 520d8849..d3f0e133 100644 --- a/detector_control/jfjoch_detector.cpp +++ b/detector_control/jfjoch_detector.cpp @@ -1,5 +1,4 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (2019-2023) Paul Scherrer Institute #include #include diff --git a/detector_control/slsDetectorPackage b/detector_control/slsDetectorPackage index 77c558a7..f761046b 160000 --- a/detector_control/slsDetectorPackage +++ b/detector_control/slsDetectorPackage @@ -1 +1 @@ -Subproject commit 77c558a7be56ff1e7391e35ed4c01dc3a36412a1 +Subproject commit f761046bfc1aa8d3fc4e52730fedfe206b1c79a7 diff --git a/fpga/CMakeLists.txt b/fpga/CMakeLists.txt new file mode 100644 index 00000000..a331b46d --- /dev/null +++ b/fpga/CMakeLists.txt @@ -0,0 +1,30 @@ +FIND_PROGRAM(VIVADO vivado DOC "Xilinx Vivado") +IF (VIVADO) + MESSAGE(STATUS "Xilinx Vivado found: ${VIVADO}") +ELSE() + MESSAGE(STATUS "Xilinx Vivado not found") +ENDIF() + +FIND_PROGRAM(VIVADO_HLS NAMES vitis_hls DOC "Xilinx HLS") +IF (VIVADO_HLS) + MESSAGE(STATUS "Xilinx HLS compiler found: ${VIVADO_HLS}") +ELSE() + MESSAGE(STATUS "Xilinx HLS compiler not found") +ENDIF() + +INCLUDE_DIRECTORIES(include) + +ADD_SUBDIRECTORY(hls) +ADD_SUBDIRECTORY(pcie_driver) + +IF(VIVADO_HLS AND VIVADO) + ADD_CUSTOM_COMMAND(OUTPUT action/hw/hdl/action_config.v + COMMAND ${CMAKE_COMMAND} -E env SRC_DIR=${CMAKE_CURRENT_SOURCE_DIR} HLS_IP_DIR=${CMAKE_CURRENT_BINARY_DIR}/action/ip/hls bash ${CMAKE_CURRENT_SOURCE_DIR}/scripts/setup_action.sh + DEPENDS hls hdl/action_config.v hdl/check_datamover_error.v hdl/check_eth_busy.v hdl/gen_xdma_descriptor.v hdl/refclk300to100.v hdl/action_wrapper.v hdl/resetn_sync.v scripts/bd_pcie.tcl scripts/jfjoch.tcl scripts/network_stack.tcl scripts/hbm_u55c.tcl scripts/mac_100g_pcie.tcl scripts/pcie_dma.tcl scripts/setup_action.sh + ) + + ADD_CUSTOM_TARGET(action_pcie DEPENDS action/hw/hdl/action_config.v hls + COMMAND ${VIVADO} -notrace -mode batch -source ${CMAKE_CURRENT_SOURCE_DIR}/scripts/build_pcie_design.tcl + COMMAND ${CMAKE_COMMAND} -E env FLOW=pcie_100gbit VIV_PROJECT_PATH=${CMAKE_CURRENT_BINARY_DIR}/vivado/jfjoch_pcie.xpr ${VIVADO} -notrace -mode batch -source ${CMAKE_CURRENT_BINARY_DIR}/action/scripts/synth_and_impl.tcl + ) +ENDIF() diff --git a/fpga/README.md b/fpga/README.md new file mode 100644 index 00000000..ac7593e9 --- /dev/null +++ b/fpga/README.md @@ -0,0 +1,136 @@ +# FPGA Smart Network Interface Card + +## Hardware +Currently supported FPGA is only Xilinx Alveo U55C + +## Content of directories + +CPU Part: + +* `pcie_driver` Linux kernel driver for PCIe version of the FPGA board + +FPGA part: + +* `scripts` Scripts for FPGA synthesis +* `xdc` Constraints for FPGA +* `hdl` FPGA design parts developed in Verilog +* `hls` FPGA design parts developed in C++ with high-level synthesis + +Dependencies: + +* `include` External (Xilinx) headers for high-level synthesis code + + +## HLS compilation +Make HLS routines: +``` +mkdir build +cd build +cmake3 .. +make hls +``` + +## Synthesis +Create PCIe bitstream with 2 data stream (200 Gbit/s) and bifurcated 2 x Gen4x8 PCIe design: +``` +mkdir build +cd build +cmake3 .. +make action_pcie +``` + +Create PCIe bitstream with 1 data stream (100 Gbit/s) and single Gen4x8 PCIe interface: +``` +mkdir build +cd build +cmake3 .. +make action_pcie_100g +``` + +## Hardware verification + +To test that FPGA board is working properly without access to a JUNGFRAU detector, you can use `jfjoch_action_test` tool. + +## FPGA reference +FPGA setup can be done via 32-bit registers: + +| Address | Bits | Meaning | Mode | Notes | +|---------------------|------|------------------------------------------------------------------------------------------------------|:-----|----------------------------------------------| +| 0x00000 - 0x0FFFF | | Reserved (in case using MicroBlaze in the future, this has to reserved for internal memory) | | | +| 0x010000 | 32 | Action Control Register | | | +| | | Bit 0 - Action start | R/W | | +| | | Bit 1 - Action idle | R | | +| | | Bit 2 - Action cancel | R/W | cleared on reset or action start | +| | | Bit 3 - Clear network counters | R/W | cleared on reset or action start | +| | | Bit 4 - Host writer idle | R | cleared on reset | +| | | Bit 7 - Design number | R | 0 = PCIe #0, 1 = PCIe #1 | +| | | Bit 16 - AXI Mailbox interrupt 0 | R | | +| | | Bit 17 - AXI Mailbox interrupt 1 | R | | +| | | Bits 24-27 - Various errors in host memory writer | R | cleared on reset or action start | +| 0x010004 | 32 | Reserved | - | | +| 0x01000C | 32 | Action GIT SHA1 | R | | +| 0x010010 | 32 | Action Type | R | | +| 0x010014 | 32 | Action Release Level | R | | +| 0x010020 | 32 | Max. number supported detector modules | R | constant | +| 0x010024 | 32 | Number of modules in internal packet generator memory | R | constant | +| 0x010028 | 64 | Pipeline stalls before writing to host memory | R | reset on action start | +| 0x010030 | 64 | Pipeline stalls before accessing HBM | R | reset on action start | +| 0x010038 | 32 | FIFO status (see action_config.v for details) | R | | +| 0x01003C | 32 | Size of single HBM channel in bytes (default value for the particular card) | R/W | should not be altered for standard operation | +| 0x010040 | 64 | Packets processed by the action | R | cleared on reset or action start | +| 0x010048 | 64 | Valid ethernet packets | R | cleared on reset | +| 0x010050 | 64 | Valid ICMP packets | R | cleared on reset | +| 0x010058 | 64 | Valid UDP packets | R | cleared on reset | +| 0x010060 | 64 | MAC address of FPGA card | R/W | network byte order | +| 0x010068 | 32 | IPv4 address of FPGA card | R/W | network byte order | +| 0x01006C | 32 | Number of detector modules | R/W | | +| 0x010070 | 32 | Data collection mode | R/W | | +| | | Bit 0 - Conversion to photons | | | +| | | Bit 1 - Use internal packet generator | | | +| | | Bit 2 - Nonblocking operation (host writer will ignore frames if there is no available work request) | | | +| | | Bit 16:31 - Data collection ID (carried with completions) | | | +| 0x010074 | 32 | One over energy in keV (in fixed-point:12 int. + 24 frac. bit format) | R/W | | +| 0x010078 | 32 | Number of frames to be generated by internal packet generator | R/W | | +| 0x01007C | 32 | Number of storage cells | R/W | | +| | | | | | +| 0x020000 - 0x02FFFF | | CMAC 100G | | See Xilinx PG203 for register map | +| 0x030000 - 0x03FFFF | | AXI Mailbox for Work Request / Work Completion | | See Xilinx PG114 for register map | +| 0x040000 - 0x04FFFF | | QuadSPI flash | | See Xilinx PG153 for register map | +| 0x060000 - 0x060FFF | 64 | Input calibration memory addresses block RAM | | | +| 0x070000 - 0x07FFFF | | AXI Firewall | | See Xilinx PG293 for register map | +| 0x090000 - 0x09FFFF | | PCIe DMA control | | See Xilinx PG195 for register map | +| 0x0A0000 - 0x0AFFFF | | Transfer between UltraRAM buffer <-> HBM (HLS registers) | | | +| 0x0C0000 - 0x0FFFFF | | Xilinx Card Management Solution Subsystem management subsystem | | See Xilinx PG348 for register map | +| 0x100000 - 0x1FFFFF | 16 | Internal packet generator frame | | | +| 0x200000 - 0x2FFFFF | | UltraRAM buffer for transfers to/from HBM | | | + +### AXI Mailbox + +AXI mailbox is used to send work request from host to action, and receive work completions. Messages are always multiple of 128-bit. See Xilinx PG114 on how to operate AXI Mailbox. + +Work request has the following structure: + +| Bit start | Bit end | Meaning | +|-----------|---------|----------------------------------------------------| +| 0 | 31 | Work request ID (handle) | +| 32 | 95 | Address (Virt: OpenCAPI, DMA: PCIe) | +| 96 | 127 | Includes parity bit, so bits 0-127 are even parity | + +Work completion has the following structure: + +| Bit start | Bit end | Meaning | +|-----------|---------|--------------------------------------------------------------------| +| 0 | 31 | Work request ID (handle) | +| 32 | 39 | Module number | +| 40 | 40 | All packets for the module arrived OK | +| 41 | 41 | Trigger signal high | +| 42 | 62 | Reserved | +| 63 | 63 | Parity bit - bits 0-127 are even parity | +| 64 | 127 | Frame number | +| 128 | 191 | JF Timestamp | +| 192 | 255 | Bunch ID | +| 256 | 287 | Exptime | +| 288 | 319 | JF debug | +| 320 | 351 | Reserved | +| 352 | 383 | Data collection ID (16-bit) | +| 384 | 511 | Packet mask (1 bit per packet: 0 packet missing, 1 packet arrived) | diff --git a/receiver/hdl/action_config.v b/fpga/hdl/action_config.v similarity index 80% rename from receiver/hdl/action_config.v rename to fpga/hdl/action_config.v index 197f9585..d59f65fb 100644 --- a/receiver/hdl/action_config.v +++ b/fpga/hdl/action_config.v @@ -1,21 +1,20 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: CERN-OHL-S-2.0 +// Copyright (2019-2023) Paul Scherrer Institute `timescale 1ns/1ps // parameters imported from source files `define ACTION_TYPE 32'h52324158 -`define RELEASE_LEVEL 32'h00000000 -`define GIT_SHA1 32'h00000000 -`define MAX_MODULES_FPGA 32'd8 +`define RELEASE_LEVEL 32'h +`define GIT_SHA1 32'h +`define MAX_MODULES_FPGA 32'd16 +`define HBM_SIZE_BYTES 32'h20000000 `define ADDR_AP_CTRL 16'h0000 `define ADDR_SET_LED 16'h0008 `define ADDR_GIT_SHA1 16'h000C -`define ADDR_ACTION_TYPE 32'h0010 -`define ADDR_RELEASE_LEVEL 32'h0014 -`define ADDR_HBM_TEMP 16'h0018 +`define ADDR_ACTION_TYPE 16'h0010 +`define ADDR_RELEASE_LEVEL 16'h0014 `define ADDR_MAX_MODULES_FPGA 16'h0020 `define ADDR_MODS_INT_PKT_GEN 16'h0024 @@ -24,6 +23,7 @@ `define ADDR_STALLS_HBM_LO 16'h0030 `define ADDR_STALLS_HBM_HI 16'h0034 `define ADDR_FIFO_STATUS 16'h0038 +`define ADDR_HBM_SIZE 16'h003C `define ADDR_PACKETS_PROC_LO 16'h0040 `define ADDR_PACKETS_PROC_HI 16'h0044 @@ -89,14 +89,13 @@ module action_config output reg [31:0] nframes , output reg [7:0] nmodules , output reg [3:0] nstorage_cells , + output reg [31:0] hbm_size_bytes , output reg data_collection_start , output reg data_collection_cancel , input data_collection_idle , - input [6:0] hbm_temperature , - input hbm_temp_trip , - input apb_complete_0 , + input host_writer_idle , input calib_data_fifo_empty , input calib_data_fifo_full , input calib_addr_fifo_empty , @@ -104,10 +103,14 @@ module action_config input udp_fifo_empty , input udp_fifo_full , - input host_mem_data_fifo_empty , - input host_mem_data_fifo_full , - input host_mem_cmd_fifo_empty , - input host_mem_cmd_fifo_full , + input c2h_data_fifo_empty , + input c2h_data_fifo_full , + input c2h_cmd_fifo_empty , + input c2h_cmd_fifo_full , + input h2c_data_fifo_empty , + input h2c_data_fifo_full , + input h2c_cmd_fifo_empty , + input h2c_cmd_fifo_full , input work_req_fifo_empty , input work_req_fifo_full , input work_compl_fifo_empty , @@ -116,7 +119,10 @@ module action_config input last_data_fifo_full , input last_addr_fifo_empty , input last_addr_fifo_full , - + input frame_generator_fifo_empty , + input frame_generator_fifo_full , + input eth_in_fifo_empty , + input eth_in_fifo_full , input mailbox_interrupt_0 , input mailbox_interrupt_1 , @@ -140,16 +146,8 @@ module action_config input [31:0] udp_err_len , input udp_err_len_valid , - input [3:0] host_writer_err , - input host_writer_err_valid , - input eth_stat_rx_status , - input eth_stat_rx_aligned , - input eth_busy , - input eth_stat_rx_packet_bad_fcs , - input mm2s_error , - input s2mm_error , - output qsfp_led_busy , - output qsfp_led_conn , + input [7:0] host_writer_err , + input host_writer_err_valid , output reg clear_counters ); //------------------------Parameter---------------------- @@ -178,33 +176,8 @@ localparam wire [ADDR_BITS-1:0] raddr; // JFJoch signals - (* ASYNC_REG = "TRUE" *) reg [6:0] reg_hbm_temperature_1; - (* ASYNC_REG = "TRUE" *) reg [6:0] reg_hbm_temperature_2; - - (* ASYNC_REG = "TRUE" *) reg reg_hbm_temp_trip_1; - (* ASYNC_REG = "TRUE" *) reg reg_hbm_temp_trip_2; - - (* ASYNC_REG = "TRUE" *) reg reg_apb_complete_0_1; - (* ASYNC_REG = "TRUE" *) reg reg_apb_complete_0_2; - - (* ASYNC_REG = "TRUE" *) reg reg_eth_busy_1; - (* ASYNC_REG = "TRUE" *) reg reg_eth_busy_2; - - (* ASYNC_REG = "TRUE" *) reg reg_eth_stat_rx_status_1; - (* ASYNC_REG = "TRUE" *) reg reg_eth_stat_rx_aligned_1; - - (* ASYNC_REG = "TRUE" *) reg reg_eth_stat_rx_status_2; - (* ASYNC_REG = "TRUE" *) reg reg_eth_stat_rx_aligned_2; - - (* ASYNC_REG = "TRUE" *) reg reg_eth_stat_rx_packet_bad_fcs_1; - (* ASYNC_REG = "TRUE" *) reg reg_eth_stat_rx_packet_bad_fcs_2; - reg reg_eth_stat_rx_packet_bad_fcs_ever; reg [31:0] reg_ctrl; - reg [6:0] reg_hbm_temperature; - reg reg_hbm_temp_trip; - reg reg_hbm_temp_trip_ever; - reg [63:0] reg_stalls_hbm; reg [63:0] reg_stalls_host; reg [63:0] reg_packets_processed; @@ -217,7 +190,7 @@ localparam reg [31:0] reg_udp_err_eth; reg [31:0] reg_fifo_status; - reg [3:0] reg_host_writer_err; + reg [7:0] reg_host_writer_err; reg reg_data_collection_idle; //------------------------Instantiation------------------ @@ -347,9 +320,6 @@ always @(posedge clk) begin `ADDR_MODS_INT_PKT_GEN: begin rdata <= 32'd1; end - `ADDR_HBM_TEMP: begin - rdata <= reg_hbm_temperature; - end `ADDR_STALLS_HBM_HI: begin rdata <= reg_stalls_hbm[63:32]; end @@ -398,6 +368,9 @@ always @(posedge clk) begin `ADDR_PACKETS_ERR_ETH: begin rdata <= reg_udp_err_eth; end + `ADDR_HBM_SIZE: begin + rdata <= hbm_size_bytes; + end `ADDR_FIFO_STATUS: begin rdata <= reg_fifo_status; end @@ -414,6 +387,17 @@ initial data_collection_start = 1'b0; initial data_collection_cancel = 1'b0; initial reg_ctrl = 32'b0; +initial hbm_size_bytes = `HBM_SIZE_BYTES; + +always @(posedge clk) begin + if (!resetn) + hbm_size_bytes = `HBM_SIZE_BYTES; + else if (reg_data_collection_idle) begin + if (w_hs && waddr == `ADDR_HBM_SIZE) + hbm_size_bytes <= (s_axi_WDATA[31:0] & wmask) | (hbm_size_bytes & !wmask); + end +end + always @(posedge clk) begin if (!resetn) reg_ctrl <= 32'b0; @@ -422,17 +406,8 @@ always @(posedge clk) begin reg_ctrl[1] <= reg_data_collection_idle; reg_ctrl[2] <= data_collection_cancel; reg_ctrl[3] <= clear_counters; + reg_ctrl[4] <= host_writer_idle; reg_ctrl[7] <= DESIGN_NUMBER; - reg_ctrl[8] <= reg_eth_stat_rx_status_2; - reg_ctrl[9] <= reg_eth_stat_rx_aligned_2; - if (mm2s_error) - reg_ctrl[10] <= 1; - if (s2mm_error) - reg_ctrl[11] <= 1; - reg_ctrl[12] <= reg_hbm_temp_trip; - reg_ctrl[13] <= reg_hbm_temp_trip_ever; - reg_ctrl[14] <= reg_apb_complete_0_2; - reg_ctrl[15] <= reg_eth_stat_rx_packet_bad_fcs_ever; reg_ctrl[16] <= mailbox_interrupt_0; reg_ctrl[17] <= mailbox_interrupt_1; reg_ctrl[31:24] <= reg_host_writer_err; @@ -542,31 +517,6 @@ always @(posedge clk) begin end end -always @ (posedge clk) begin - reg_eth_stat_rx_status_1 <= eth_stat_rx_status; - reg_eth_stat_rx_status_2 <= reg_eth_stat_rx_status_1; - - reg_eth_stat_rx_aligned_1 <= eth_stat_rx_aligned; - reg_eth_stat_rx_aligned_2 <= reg_eth_stat_rx_aligned_1; - - reg_eth_stat_rx_packet_bad_fcs_1 <= eth_stat_rx_packet_bad_fcs; - reg_eth_stat_rx_packet_bad_fcs_2 <= reg_eth_stat_rx_packet_bad_fcs_1; - - reg_eth_busy_1 <= eth_busy; - reg_eth_busy_2 <= reg_eth_busy_1; - - reg_apb_complete_0_1 <= apb_complete_0; - reg_apb_complete_0_2 <= reg_apb_complete_0_1; - - reg_hbm_temperature_1 <= hbm_temperature; - reg_hbm_temperature_2 <= reg_hbm_temperature_1; - reg_hbm_temperature <= reg_hbm_temperature_2; - - reg_hbm_temp_trip_1 <= hbm_temp_trip; - reg_hbm_temp_trip_2 <= reg_hbm_temp_trip_1; - reg_hbm_temp_trip <= reg_hbm_temp_trip_2; -end - always @ (posedge clk) begin if (!resetn) begin @@ -604,22 +554,6 @@ always @ (posedge clk) begin end end -// HBM temperature trip is only cleared on card restart to protect the card -always @ (posedge clk) begin - if (!resetn) - reg_hbm_temp_trip_ever <= 0; - else if (reg_hbm_temp_trip_2) - reg_hbm_temp_trip_ever <= 1; -end - -// Ethernet RX packet bad FCS is kept from last reset -always @ (posedge clk) begin - if (!resetn) - reg_eth_stat_rx_packet_bad_fcs_ever <= 0; - else if (reg_eth_stat_rx_packet_bad_fcs_2) - reg_eth_stat_rx_packet_bad_fcs_ever <= 1; -end - // FIFO status always @(posedge clk) begin if (!resetn) @@ -632,10 +566,10 @@ always @(posedge clk) begin reg_fifo_status[3] <= calib_addr_fifo_full; reg_fifo_status[6] <= udp_fifo_empty; reg_fifo_status[7] <= udp_fifo_full; - reg_fifo_status[8] <= host_mem_data_fifo_empty; - reg_fifo_status[9] <= host_mem_data_fifo_full; - reg_fifo_status[10] <= host_mem_cmd_fifo_empty; - reg_fifo_status[11] <= host_mem_cmd_fifo_full; + reg_fifo_status[8] <= c2h_data_fifo_empty; + reg_fifo_status[9] <= c2h_data_fifo_full; + reg_fifo_status[10] <= c2h_cmd_fifo_empty; + reg_fifo_status[11] <= c2h_cmd_fifo_full; reg_fifo_status[12] <= work_req_fifo_empty; reg_fifo_status[13] <= work_req_fifo_full; reg_fifo_status[14] <= work_compl_fifo_empty; @@ -644,10 +578,15 @@ always @(posedge clk) begin reg_fifo_status[17] <= last_data_fifo_full; reg_fifo_status[18] <= last_addr_fifo_empty; reg_fifo_status[19] <= last_addr_fifo_full; + reg_fifo_status[20] <= h2c_data_fifo_empty; + reg_fifo_status[21] <= h2c_data_fifo_full; + reg_fifo_status[22] <= h2c_cmd_fifo_empty; + reg_fifo_status[23] <= h2c_cmd_fifo_full; + reg_fifo_status[24] <= frame_generator_fifo_full; + reg_fifo_status[25] <= frame_generator_fifo_empty; + reg_fifo_status[26] <= eth_in_fifo_full; + reg_fifo_status[27] <= eth_in_fifo_empty; end end -assign qsfp_led_conn = !reg_eth_stat_rx_status_2; -assign qsfp_led_busy = !reg_eth_busy_2; - endmodule diff --git a/receiver/hdl/action_wrapper.v b/fpga/hdl/action_wrapper.v similarity index 99% rename from receiver/hdl/action_wrapper.v rename to fpga/hdl/action_wrapper.v index 7d0c118e..955e8419 100644 --- a/receiver/hdl/action_wrapper.v +++ b/fpga/hdl/action_wrapper.v @@ -1,5 +1,4 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: CERN-OHL-S-2.0 +// Copyright (2019-2023) Paul Scherrer Institute `timescale 1 ps / 1 ps diff --git a/receiver/hdl/check_datamover_error.v b/fpga/hdl/check_datamover_error.v similarity index 92% rename from receiver/hdl/check_datamover_error.v rename to fpga/hdl/check_datamover_error.v index 5d98db12..11b17860 100644 --- a/receiver/hdl/check_datamover_error.v +++ b/fpga/hdl/check_datamover_error.v @@ -1,5 +1,4 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: CERN-OHL-S-2.0 +// Copyright (2019-2023) Paul Scherrer Institute `timescale 1ns / 1ps diff --git a/receiver/hdl/check_eth_busy.v b/fpga/hdl/check_eth_busy.v similarity index 96% rename from receiver/hdl/check_eth_busy.v rename to fpga/hdl/check_eth_busy.v index 9f908e6f..0f9abaa5 100644 --- a/receiver/hdl/check_eth_busy.v +++ b/fpga/hdl/check_eth_busy.v @@ -1,5 +1,4 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: CERN-OHL-S-2.0 +// Copyright (2019-2023) Paul Scherrer Institute `timescale 1ns / 1ps diff --git a/receiver/hdl/gen_xdma_descriptor.v b/fpga/hdl/gen_xdma_descriptor.v similarity index 95% rename from receiver/hdl/gen_xdma_descriptor.v rename to fpga/hdl/gen_xdma_descriptor.v index 14221dba..1ade4b72 100644 --- a/receiver/hdl/gen_xdma_descriptor.v +++ b/fpga/hdl/gen_xdma_descriptor.v @@ -1,5 +1,4 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: CERN-OHL-S-2.0 +// Copyright (2019-2023) Paul Scherrer Institute `timescale 1ns / 1ps diff --git a/receiver/hdl/refclk300to100.v b/fpga/hdl/refclk300to100.v similarity index 84% rename from receiver/hdl/refclk300to100.v rename to fpga/hdl/refclk300to100.v index 7a850bce..7fc8a907 100644 --- a/receiver/hdl/refclk300to100.v +++ b/fpga/hdl/refclk300to100.v @@ -1,5 +1,4 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: CERN-OHL-S-2.0 +// Copyright (2019-2023) Paul Scherrer Institute `timescale 1ns / 1ps diff --git a/receiver/hdl/resetn_sync.v b/fpga/hdl/resetn_sync.v similarity index 88% rename from receiver/hdl/resetn_sync.v rename to fpga/hdl/resetn_sync.v index 920363a1..9825a723 100644 --- a/receiver/hdl/resetn_sync.v +++ b/fpga/hdl/resetn_sync.v @@ -1,5 +1,4 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: CERN-OHL-S-2.0 +// Copyright (2019-2023) Paul Scherrer Institute `timescale 1ns / 1ps diff --git a/receiver/hls/CMakeLists.txt b/fpga/hls/CMakeLists.txt similarity index 88% rename from receiver/hls/CMakeLists.txt rename to fpga/hls/CMakeLists.txt index 098f9084..72a190e5 100644 --- a/receiver/hls/CMakeLists.txt +++ b/fpga/hls/CMakeLists.txt @@ -5,14 +5,15 @@ ADD_LIBRARY( HLSSimulation STATIC hls_jfjoch.h ../../common/Definitions.h load_calibration.cpp - internal_packet_generator.cpp host_writer.cpp ethernet.cpp ipv4.cpp icmp.cpp arp.cpp ip_header_checksum.h udp.cpp - sls_detector.cpp) + sls_detector.cpp + frame_generator.cpp + stream_merge.cpp) TARGET_INCLUDE_DIRECTORIES(HLSSimulation PUBLIC ../include) TARGET_LINK_LIBRARIES(HLSSimulation CommonFunctions) @@ -34,31 +35,31 @@ ENDFUNCTION(MAKE_HLS_MODULE) MAKE_HLS_MODULE(data_collection_fsm.cpp data_collection_fsm) MAKE_HLS_MODULE(timer.cpp timer_host) -MAKE_HLS_MODULE(timer.cpp timer_hbm) MAKE_HLS_MODULE(jf_conversion.cpp jf_conversion) MAKE_HLS_MODULE(load_calibration.cpp load_calibration) MAKE_HLS_MODULE(host_writer.cpp host_writer) -MAKE_HLS_MODULE(internal_packet_generator.cpp internal_packet_generator) MAKE_HLS_MODULE(icmp.cpp icmp) MAKE_HLS_MODULE(ipv4.cpp ipv4) MAKE_HLS_MODULE(ethernet.cpp ethernet) MAKE_HLS_MODULE(arp.cpp arp) MAKE_HLS_MODULE(udp.cpp udp) MAKE_HLS_MODULE(sls_detector.cpp sls_detector) +MAKE_HLS_MODULE(frame_generator.cpp frame_generator) +MAKE_HLS_MODULE(stream_merge.cpp stream_merge) SET (HLS_IPS psi_ch_hls_data_collection_fsm_1_0.zip psi_ch_hls_timer_host_1_0.zip - psi_ch_hls_timer_hbm_1_0.zip psi_ch_hls_jf_conversion_1_0.zip psi_ch_hls_load_calibration_1_0.zip - psi_ch_hls_internal_packet_generator_1_0.zip psi_ch_hls_ethernet_1_0.zip psi_ch_hls_ipv4_1_0.zip psi_ch_hls_arp_1_0.zip psi_ch_hls_udp_1_0.zip psi_ch_hls_sls_detector_1_0.zip psi_ch_hls_icmp_1_0.zip - psi_ch_hls_host_writer_1_0.zip) + psi_ch_hls_host_writer_1_0.zip + psi_ch_hls_frame_generator_1_0.zip + psi_ch_hls_stream_merge_1_0.zip) SET (HLS_IPS ${HLS_IPS} PARENT_SCOPE) ADD_CUSTOM_TARGET(hls DEPENDS ${HLS_IPS}) diff --git a/receiver/hls/arp.cpp b/fpga/hls/arp.cpp similarity index 97% rename from receiver/hls/arp.cpp rename to fpga/hls/arp.cpp index 70dbd9b5..9abaa612 100644 --- a/receiver/hls/arp.cpp +++ b/fpga/hls/arp.cpp @@ -1,5 +1,5 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: CERN-OHL-S-2.0 or GPL-3.0-or-later +// Copyright (2019-2023) Paul Scherrer Institute + #include "hls_jfjoch.h" diff --git a/receiver/hls/data_collection_fsm.cpp b/fpga/hls/data_collection_fsm.cpp similarity index 85% rename from receiver/hls/data_collection_fsm.cpp rename to fpga/hls/data_collection_fsm.cpp index db921757..a4688336 100644 --- a/receiver/hls/data_collection_fsm.cpp +++ b/fpga/hls/data_collection_fsm.cpp @@ -1,13 +1,12 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: CERN-OHL-S-2.0 or GPL-3.0-or-later +// Copyright (2019-2023) Paul Scherrer Institute + -#include #include "hls_jfjoch.h" void data_collection_fsm(AXI_STREAM ð_in, STREAM_512 &data_out, - hls::stream > &addr_in, - hls::stream > &addr_out, + hls::stream &addr_in, + hls::stream &addr_out, volatile ap_uint<1> &in_run, volatile ap_uint<1> &in_cancel, volatile ap_uint<1> &out_idle, @@ -15,7 +14,8 @@ void data_collection_fsm(AXI_STREAM ð_in, ap_uint<32> one_over_energy, ap_uint<32> nframes, ap_uint<8> nmodules, - ap_uint<4> nstorage_cells) { + ap_uint<4> nstorage_cells, + ap_uint<32> hbm_size_bytes) { #pragma HLS INTERFACE ap_ctrl_none port=return #pragma HLS INTERFACE axis register both port=eth_in @@ -31,12 +31,13 @@ void data_collection_fsm(AXI_STREAM ð_in, #pragma HLS INTERFACE ap_none register port=nframes #pragma HLS INTERFACE ap_none register port=nmodules #pragma HLS INTERFACE ap_none register port=nstorage_cells +#pragma HLS INTERFACE ap_none register port=hbm_size_bytes #pragma HLS PIPELINE II=1 style=flp packet_512_t packet_in; packet_512_t packet_out; - ap_uint addr; + axis_addr addr; enum rcv_state_t {RCV_WAIT_FOR_START = 0, RCV_WAIT_FOR_START_LOW = 1, RCV_START = 2, RCV_INIT = 3, RCV_GOOD = 4, RCV_FLUSH = 5, RCV_LAST = 6, RCV_FLUSH_IDLE = 7, RCV_IGNORE = 8}; @@ -76,21 +77,18 @@ void data_collection_fsm(AXI_STREAM ð_in, ACT_REG_NFRAMES(packet_out.data) = nframes; ACT_REG_NMODULES(packet_out.data) = nmodules; ACT_REG_NSTORAGE_CELLS(packet_out.data) = nstorage_cells + 1; + ACT_REG_HBM_SIZE_256b(packet_out.data) = hbm_size_bytes / 32; + packet_out.user = 0; packet_out.last = 0; packet_out.dest = 0; packet_out.id = 1; data_out << packet_out; - addr = 0; - addr(63, 0) = mode; - addr(79,64) = nmodules; + addr.last = 0; addr_out << addr; - if (mode & MODE_INTERNAL_PACKET_GEN) - rcv_state = RCV_LAST; - else - rcv_state = RCV_INIT; + rcv_state = RCV_INIT; break; case RCV_INIT: out_idle = 0; @@ -99,7 +97,7 @@ void data_collection_fsm(AXI_STREAM ð_in, else if (!addr_in.empty()) { addr_in >> addr; - if (addr_frame_number(addr) >= nframes + DELAY_FRAMES_STOP_AND_QUIT) + if (addr.frame_number >= nframes + DELAY_FRAMES_STOP_AND_QUIT) rcv_state = RCV_FLUSH; else { addr_out << addr; @@ -130,8 +128,7 @@ void data_collection_fsm(AXI_STREAM ð_in, break; case RCV_LAST: out_idle = 0; - addr = 0; - addr_last_flag(addr) = 1; + addr.last = 1; addr_out << addr; // Finish data collection diff --git a/receiver/include/datamover_model.h b/fpga/hls/datamover_model.h similarity index 96% rename from receiver/include/datamover_model.h rename to fpga/hls/datamover_model.h index 603eabff..f01938e5 100644 --- a/receiver/include/datamover_model.h +++ b/fpga/hls/datamover_model.h @@ -1,11 +1,10 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (2019-2023) Paul Scherrer Institute #ifndef JUNGFRAUJOCH_DATAMOVER_MODEL_H #define JUNGFRAUJOCH_DATAMOVER_MODEL_H -#include "../hls/hls_jfjoch.h" #include +#include "hls_jfjoch.h" enum class Direction {Input, Output}; @@ -84,4 +83,5 @@ public: hls::stream >& GetDataStream() { return data; } ~Datamover() { Stop(); } }; + #endif //JUNGFRAUJOCH_DATAMOVER_MODEL_H diff --git a/receiver/hls/ethernet.cpp b/fpga/hls/ethernet.cpp similarity index 85% rename from receiver/hls/ethernet.cpp rename to fpga/hls/ethernet.cpp index 9030761c..2cb7719a 100644 --- a/receiver/hls/ethernet.cpp +++ b/fpga/hls/ethernet.cpp @@ -1,5 +1,5 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: CERN-OHL-S-2.0 or GPL-3.0-or-later +// Copyright (2019-2023) Paul Scherrer Institute + #include "hls_jfjoch.h" @@ -37,10 +37,9 @@ void ethernet(AXI_STREAM ð_in, if (state == INSPECT_HEADER) { dest = DEST_IGNORE; if (fpga_mac_addr != 0) { - ap_uint < 48 > dest_mac = get_mac_addr(packet_in.data, 0); - ap_uint < 48 > src_mac = get_mac_addr(packet_in.data, 48); - - ap_uint < 16 > ether_type = get_header_field_16(packet_in.data, 12 * 8); + ap_uint<48> dest_mac = packet_in.data(47, 0); + ap_uint<48> src_mac = packet_in.data(95, 48); + ap_uint<16> ether_type = get_header_field_16(packet_in.data, 12 * 8); if ((dest_mac == fpga_mac_addr) && (ether_type == ETHER_IP)) { state = FORWARD; diff --git a/fpga/hls/frame_generator.cpp b/fpga/hls/frame_generator.cpp new file mode 100644 index 00000000..ce3e8218 --- /dev/null +++ b/fpga/hls/frame_generator.cpp @@ -0,0 +1,117 @@ +// Copyright (2019-2023) Paul Scherrer Institute + +#include "hls_jfjoch.h" +#include "ip_header_checksum.h" + +void generate_packet(STREAM_512 &data_out, + ap_uint<512> *uram, + ap_uint<32> frame, + ap_uint<8> module, + ap_uint<7> eth_packet, + ap_uint<48> src_mac_addr, + ap_uint<48> dest_mac_addr, + ap_uint<32> src_ipv4_addr, + ap_uint<32> dest_ipv4_addr, + ap_uint<64> bunchid, + ap_uint<32> exptime, + ap_uint<64> timestamp, + ap_uint<32> debug) { +#pragma HLS PIPELINE II=130 + ap_uint<720> header = 0; + + header(47 , 0) = dest_mac_addr; + header(95 , 48) = src_mac_addr; + header(111, 96) = 0x0008; // ETHER_IP = IPv4 + header(eth_payload_pos+3 , eth_payload_pos ) = 0x5; // header len of 5 + header(eth_payload_pos+7 , eth_payload_pos+4 ) = 0x4; // IPv4 + header(eth_payload_pos+31 , eth_payload_pos+16 ) = 0x4C20; // total length = 8268 + header(eth_payload_pos+79 , eth_payload_pos+72 ) = PROTOCOL_UDP; // UDP + header(eth_payload_pos+127, eth_payload_pos+96 ) = src_ipv4_addr; + header(eth_payload_pos+159, eth_payload_pos+128) = dest_ipv4_addr; + header(eth_payload_pos+95 , eth_payload_pos+80 ) = computeCheckSum20B(header(eth_payload_pos + 159, eth_payload_pos)); + + header(ipv4_payload_pos+47, ipv4_payload_pos+32) = 0x3820; // UDP length = 8248 + header(udp_payload_pos+63, udp_payload_pos) = frame + 1; + header(udp_payload_pos+95, udp_payload_pos+64) = exptime; + header(udp_payload_pos+127, udp_payload_pos+96) = eth_packet; + header(udp_payload_pos+2*64+63, udp_payload_pos+2*64) = bunchid; + header(udp_payload_pos+3*64+63, udp_payload_pos+3*64) = timestamp; + header(udp_payload_pos+4*64+31, udp_payload_pos+4*64+16) = 2 * module; + header(udp_payload_pos+5*64+31, udp_payload_pos+5*64) = debug; + + packet_512_t packet; + packet.data = header(511 ,0); + packet.last = 0; + packet.dest = 0; + packet.id = 0; + packet.strb = UINT64_MAX; + packet.keep = UINT64_MAX; + packet.user = 0; + + data_out << packet; + + ap_uint<208> remainder = header(719, 512); + for (int i = 0; i < 128; i++) { + ap_uint<512> tmp = uram[eth_packet * 128 + i]; + //tmp(255, 0) = d_hbm_p0[eth_packet * 128 + i]; + //tmp(511, 256) = d_hbm_p1[eth_packet * 128 + i]; + packet.data(207, 0) = remainder; + packet.data(511, 208) = tmp(303, 0); + data_out << packet; + remainder = tmp(511, 304); + } + packet.data(207, 0) = remainder; + packet.data(511, 208) = 0; + packet.keep(63, 26) = 0; + packet.last = 1; + data_out << packet; +} + +void frame_generator(STREAM_512 &data_out, + ap_uint<512> *uram, + ap_uint<32> frames, + ap_uint<5> modules, + ap_uint<48> src_mac_addr, + ap_uint<48> dest_mac_addr, + ap_uint<32> src_ipv4_addr, + ap_uint<32> dest_ipv4_addr, + ap_uint<64> bunchid, + ap_uint<32> exptime, + ap_uint<32> debug) { +#pragma HLS INTERFACE mode=s_axilite port=return +#pragma HLS INTERFACE mode=s_axilite port=frames +#pragma HLS INTERFACE mode=s_axilite port=modules +#pragma HLS INTERFACE mode=s_axilite port=bunchid +#pragma HLS INTERFACE mode=s_axilite port=exptime +#pragma HLS INTERFACE mode=s_axilite port=debug +#pragma HLS INTERFACE mode=s_axilite port=dest_mac_addr +#pragma HLS INTERFACE mode=s_axilite port=dest_ipv4_addr +#pragma HLS INTERFACE mode=ap_none port=src_mac_addr +#pragma HLS INTERFACE mode=ap_none port=src_ipv4_addr + +#pragma HLS INTERFACE register both axis port=data_out +#pragma HLS INTERFACE m_axi port=uram bundle=uram depth=512 offset=off \ + max_read_burst_length=64 max_write_burst_length=2 latency=5 num_write_outstanding=2 num_read_outstanding=2 +//#pragma HLS INTERFACE m_axi port=d_hbm_p0 bundle=d_hbm_p0 depth=512 offset=off \ +// max_read_burst_length=16 max_write_burst_length=2 latency=120 num_write_outstanding=2 num_read_outstanding=9 +//#pragma HLS INTERFACE m_axi port=d_hbm_p1 bundle=d_hbm_p1 depth=512 offset=off \ +// max_read_burst_length=16 max_write_burst_length=2 latency=120 num_write_outstanding=2 num_read_outstanding=9 + + for (uint32_t f = 0; f < frames; f++) { + for (uint32_t p = 0; p < 128; p++) { + for (uint32_t m = 0; m < modules; m++) { + generate_packet(data_out, + uram, + f, m, p, + src_mac_addr, + dest_mac_addr, + src_ipv4_addr, + dest_ipv4_addr, + bunchid + f, + exptime, + exptime * f, + debug); + } + } + } +} diff --git a/receiver/hls/hls_jfjoch.h b/fpga/hls/hls_jfjoch.h similarity index 68% rename from receiver/hls/hls_jfjoch.h rename to fpga/hls/hls_jfjoch.h index 7ac8519f..d8994d48 100644 --- a/receiver/hls/hls_jfjoch.h +++ b/fpga/hls/hls_jfjoch.h @@ -1,5 +1,5 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: CERN-OHL-S-2.0 or GPL-3.0-or-later +// Copyright (2019-2023) Paul Scherrer Institute + #ifndef JUNGFRAUJOCH_HLS_JFJOCH_H #define JUNGFRAUJOCH_HLS_JFJOCH_H @@ -14,7 +14,7 @@ #include #else #include "../include/hls_burst_maxi.h" -#include +#include "parallel_stream.h" #endif #include "../../common/Definitions.h" @@ -22,8 +22,6 @@ // Number of modules that can be simultaneously handled by the FPGA #define MAX_MODULES_FPGA 16 -#define ADDR_STREAM_WIDTH 320 - typedef ap_ufixed<16,2, AP_RND_CONV> gainG0_t; typedef ap_ufixed<16,4, AP_RND_CONV> gainG1_t; typedef ap_ufixed<16,6, AP_RND_CONV> gainG2_t; @@ -50,48 +48,68 @@ typedef ap_axiu<512,1, 1, 1> packet_512_t; typedef hls::stream AXI_STREAM; typedef hls::stream STREAM_512; -#define addr_frame_number(x) x(63, 0) -#define addr_eth_packet(x) x(70, 64) -#define addr_module(x) x(76, 72) -#define addr_last_flag(x) x[79] -#define addr_jf_debug(x) x(127, 96) -#define addr_timestamp(x) x(191,128) -#define addr_bunch_id(x) x(255,192) -#define addr_exptime(x) x(256+63, 256) - -#define ACT_REG_MODE(x) ((x)(63, 0)) // 64 bit -#define ACT_REG_ONE_OVER_ENERGY(x) ((x)(95, 64)) // 32 bit -#define ACT_REG_NFRAMES(x) ((x)(127, 96)) // 32 bit +#define ACT_REG_MODE(x) ((x)(32 , 0)) // 32 bit +#define ACT_REG_ONE_OVER_ENERGY(x) ((x)(63 , 32)) // 32 bit +#define ACT_REG_NFRAMES(x) ((x)(95 , 64)) // 32 bit #define ACT_REG_NMODULES(x) ((x)(132, 128)) // 5 bit (0..31) #define ACT_REG_NSTORAGE_CELLS(x) ((x)(148, 144)) // 5 bit +#define ACT_REG_HBM_SIZE_256b(x) ((x)(191, 160)) // 32 bit struct axis_datamover_ctrl { ap_uint<40+64> data; }; +struct axis_addr { + ap_uint<64> frame_number; + ap_uint<64> exptime; + ap_uint<64> timestamp; + ap_uint<64> bunchid; + ap_uint<32> debug; + ap_uint<5> module; + ap_uint<7> eth_packet; + ap_uint<1> last; +}; + void setup_datamover (hls::stream &datamover_cmd_stream, uint64_t address, size_t bytes_to_write); void data_collection_fsm(AXI_STREAM ð_in, STREAM_512 &data_out, - hls::stream > &addr_in, - hls::stream > &addr_out, + hls::stream &addr_in, + hls::stream &addr_out, volatile ap_uint<1> &in_run, volatile ap_uint<1> &in_cancel, volatile ap_uint<1> &out_idle, ap_uint<32> mode, ap_uint<32> one_over_energy, - ap_uint<32> frames_per_trigger, + ap_uint<32> nframes, ap_uint<8> nmodules, - ap_uint<4> nstorage_cells); + ap_uint<4> nstorage_cells, + ap_uint<32> hbm_size_bytes); -void load_calibration(STREAM_512 &data_in, STREAM_512 &data_out, +void load_calibration(ap_uint<256> *d_hbm_p0, + ap_uint<256> *d_hbm_p1, + ap_uint<8> modules, + ap_uint<5> storage_cells, + ap_uint<32> hbm_size_bytes, hls::stream &datamover_in_cmd, hls::stream > &host_memory_in, uint64_t in_mem_location[LOAD_CALIBRATION_BRAM_SIZE]); +void frame_generator(STREAM_512 &data_out, + ap_uint<512> *uram, + ap_uint<32> frames, + ap_uint<5> modules, + ap_uint<48> src_mac_addr, + ap_uint<48> dest_mac_addr, + ap_uint<32> src_ipv4_addr, + ap_uint<32> dest_ipv4_addr, + ap_uint<64> bunchid, + ap_uint<32> exptime, + ap_uint<32> debug); + void jf_conversion(STREAM_512 &data_in, STREAM_512 &data_out, - hls::stream > &addr_in, - hls::stream > &addr_out, + hls::stream &addr_in, + hls::stream &addr_out, hls::burst_maxi d_hbm_p0, hls::burst_maxi d_hbm_p1, hls::burst_maxi d_hbm_p2, hls::burst_maxi d_hbm_p3, hls::burst_maxi d_hbm_p4, hls::burst_maxi d_hbm_p5, @@ -100,21 +118,22 @@ void jf_conversion(STREAM_512 &data_in, STREAM_512 &data_out, hls::burst_maxi d_hbm_p10, hls::burst_maxi d_hbm_p11); void host_writer(STREAM_512 &data_in, - hls::stream > &addr_in, + hls::stream &addr_in, hls::stream > &host_memory_out, hls::stream &datamover_out_cmd, hls::stream > &s_axis_work_request, hls::stream > &m_axis_completion, volatile uint64_t &packets_processed, + volatile ap_uint<1> &idle, ap_uint<8> &err_reg); -void timer_hbm(STREAM_512 &in, STREAM_512 &data_out, uint64_t &counter); -void timer_host(STREAM_512 &data_in, STREAM_512 &data_out, uint64_t &counter); +void timer_host(STREAM_512 &data_in, + STREAM_512 &data_out, + volatile uint64_t &counter); -void internal_packet_generator(STREAM_512 &data_in, STREAM_512 &data_out, - hls::stream > &addr_in, - hls::stream > &addr_out, - volatile ap_uint<1> &in_cancel); +void stream_merge(AXI_STREAM &input_0, + AXI_STREAM &input_1, + AXI_STREAM &output); template ap_uint pack32(ap_int in[32]) { #pragma HLS INLINE @@ -144,25 +163,6 @@ inline void setup_datamover (hls::stream &datamover_cmd_str datamover_cmd_stream << msg; } -inline ap_uint addr_packet(ap_uint<8> eth_packet, - ap_uint<5> module, - ap_uint<64> frame, - ap_uint<32> jf_debug, - ap_uint<64> timestamp, - ap_uint<64> bunchid, - ap_uint<32> expttime) { -#pragma HLS INLINE - ap_uint retval = 0; - addr_eth_packet(retval) = eth_packet; - addr_module(retval) = module; - addr_frame_number(retval) = frame; - addr_jf_debug(retval) = jf_debug; - addr_timestamp(retval) = timestamp; - addr_bunch_id(retval) = bunchid; - addr_exptime(retval) = expttime; - return retval; -} - inline ap_uint<16> get_header_field_16(ap_uint<512> data, size_t position) { ap_uint<16> tmp = data(position+15, position); ap_uint<16> retval; @@ -172,14 +172,6 @@ inline ap_uint<16> get_header_field_16(ap_uint<512> data, size_t position) { return retval; } -inline ap_uint<48> get_mac_addr(ap_uint<512> data, size_t position) { - return data(position+47,position); -} - -inline ap_uint<32> get_header_field_32_network_order(ap_uint<512> data, size_t position) { - return data(position+31, position); -} - static const uint8_t ECHO_REQUEST = 0x08; static const uint8_t ECHO_REPLY = 0x00; static const uint8_t PROTOCOL_ICMP = 0x01; @@ -192,7 +184,6 @@ static const uint32_t eth_payload_pos = 14 * 8; // 112 bits static const uint32_t ipv4_payload_pos = eth_payload_pos + 160; // 112 + 160 = 272 bits static const uint32_t udp_payload_pos = ipv4_payload_pos + 64; // 112 + 160 + 64 = 336 bits (42 bytes) - // Network cores #define UDP_METADATA_STREAM_WIDTH 48 #define udp_metadata_dest_port(x) x(15, 0) @@ -231,10 +222,9 @@ void udp(AXI_STREAM ð_in, void sls_detector(AXI_STREAM &udp_payload_in, hls::stream > &udp_metadata_in, AXI_STREAM &data_out, - hls::stream > &addr_out, + hls::stream &addr_out, uint64_t& counter, uint32_t& counter_eth_error, uint32_t& counter_len_error, volatile ap_uint<1> &in_clear_counters); - #endif diff --git a/receiver/hls/host_writer.cpp b/fpga/hls/host_writer.cpp similarity index 53% rename from receiver/hls/host_writer.cpp rename to fpga/hls/host_writer.cpp index 13898579..284c7b45 100644 --- a/receiver/hls/host_writer.cpp +++ b/fpga/hls/host_writer.cpp @@ -1,5 +1,5 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: CERN-OHL-S-2.0 or GPL-3.0-or-later +// Copyright (2019-2023) Paul Scherrer Institute + #include "hls_jfjoch.h" @@ -10,44 +10,48 @@ #define PACKET_SIZE 8192 inline void write_completion(hls::stream > &m_axis_completion, - const ap_uint<32> &handle, - const ap_uint<8> &module, - const ap_uint<64> &frame_num, - const ap_uint<256> &packet_mask, - const ap_uint<16> &packet_count, - const ap_uint<32> &debug, - const ap_uint<64> ×tamp, - const ap_uint<64> &bunchid, - const ap_uint<32> &exptime) { + const ap_uint<32> &handle, + const ap_uint<8> &module_number, + const ap_uint<64> &frame_num, + const ap_uint<128> &packet_mask, + const ap_uint<16> &packet_count, + const ap_uint<32> &debug, + const ap_uint<64> ×tamp, + const ap_uint<64> &bunchid, + const ap_uint<32> &exptime, + const ap_uint<32> &data_collection_id, + const ap_uint<1> &flushing) { #pragma HLS INLINE ap_uint<1> all_packets_ok = packet_mask.and_reduce(); ap_uint<1> any_packets_received = packet_mask.or_reduce(); ap_uint<8> status = 0; status[0] = all_packets_ok; status[1] = any_packets_received; - - ap_uint<128> tmp = (handle, packet_count, status, module, frame_num); + status[2] = flushing; + ap_uint<128> tmp = (handle, packet_count, status, module_number, frame_num); status[7] = tmp.xor_reduce(); // ensure completion has even parity - m_axis_completion << handle; - m_axis_completion << (packet_count, status, module); - m_axis_completion << frame_num(63, 32); - m_axis_completion << frame_num(31, 0); + if (handle != HANDLE_SKIP_FRAME) { + m_axis_completion << handle; + m_axis_completion << (packet_count, status, module_number); + m_axis_completion << frame_num(63, 32); + m_axis_completion << frame_num(31, 0); - m_axis_completion << timestamp(63,32); - m_axis_completion << timestamp(31,0); - m_axis_completion << bunchid(63,32); - m_axis_completion << bunchid(31,0); + m_axis_completion << timestamp(63,32); + m_axis_completion << timestamp(31,0); + m_axis_completion << bunchid(63,32); + m_axis_completion << bunchid(31,0); - m_axis_completion << exptime; - m_axis_completion << debug; - m_axis_completion << 0; - m_axis_completion << 0; + m_axis_completion << exptime; + m_axis_completion << debug; + m_axis_completion << 0; + m_axis_completion << data_collection_id; - m_axis_completion << packet_mask(127,96); - m_axis_completion << packet_mask( 95,64); - m_axis_completion << packet_mask( 63,32); - m_axis_completion << packet_mask( 31, 0); + m_axis_completion << packet_mask(127,96); + m_axis_completion << packet_mask( 95,64); + m_axis_completion << packet_mask( 63,32); + m_axis_completion << packet_mask( 31, 0); + } } @@ -74,12 +78,13 @@ inline ap_uint<1> read_request(hls::stream > &s_axis_work_request, } void host_writer(STREAM_512 &data_in, - hls::stream > &addr_in, + hls::stream &addr_in, hls::stream > &host_memory_out, hls::stream &datamover_out_cmd, hls::stream > &s_axis_work_request, hls::stream > &m_axis_completion, volatile uint64_t &packets_processed, + volatile ap_uint<1> &idle, ap_uint<8> &err_reg) { #pragma HLS INTERFACE ap_ctrl_none port=return #pragma HLS INTERFACE register both axis port=data_in @@ -90,15 +95,7 @@ void host_writer(STREAM_512 &data_in, #pragma HLS INTERFACE register both axis port=s_axis_work_request #pragma HLS INTERFACE register ap_vld port=packets_processed #pragma HLS INTERFACE register ap_vld port=err_reg - - ap_uint addr; - addr_in >> addr; - - packet_512_t packet_in; - data_in >> packet_in; - - ap_uint<8> internal_err_reg = 0; - err_reg = internal_err_reg; +#pragma HLS INTERFACE register ap_none port=idle ap_uint<128> packet_mask[MAX_MODULES_FPGA*2]; #pragma HLS RESOURCE variable=packet_mask core=RAM_1P @@ -119,6 +116,8 @@ void host_writer(STREAM_512 &data_in, ap_uint<64> curr_offset[MAX_MODULES_FPGA*2]; #pragma HLS RESOURCE variable=curr_offset core=RAM_1P + idle = 1; + for (int i = 0; i < MAX_MODULES_FPGA*2; i++) { #pragma HLS UNROLL curr_frame[i] = UINT64_MAX; @@ -132,8 +131,32 @@ void host_writer(STREAM_512 &data_in, jf_bunchid[i] = 0; } - write_completion(m_axis_completion, UINT32_MAX - 1, 0, 0, 0, 0, 0, 0, 0, 0); + ap_uint<32> req_handle; + ap_uint<64> req_host_offset; + while (data_in.empty()) { +#pragma HLS PIPELINE II=4 + if (!s_axis_work_request.empty()) + read_request(s_axis_work_request, req_handle, req_host_offset); + } + + axis_addr addr; + addr_in >> addr; + + packet_512_t packet_in; + data_in >> packet_in; + ap_uint<5> nmodules = ACT_REG_NMODULES(packet_in.data); + ap_uint<32> data_collection_mode = ACT_REG_MODE(packet_in.data); + ap_uint<32> data_collection_id = data_collection_mode(31, 16); // upper 16-bit of mode + + ap_uint<1> mode_nonblocking = (data_collection_mode & MODE_NONBLOCKING_ON_WR) ? 1 : 0; + + ap_uint<8> internal_err_reg = 0; + err_reg = internal_err_reg; + + write_completion(m_axis_completion, HANDLE_START, 0, 0, 0, 0, 0, 0, 0, 0, data_collection_id, 0); + + idle = 0; uint64_t total_counter = 0; packets_processed = 0; addr_in >> addr; @@ -144,28 +167,15 @@ void host_writer(STREAM_512 &data_in, packet_out.dest = 0; packet_out.id = 0; packet_out.user = 0; - - ap_uint<32> req_handle; - ap_uint<64> req_host_offset; Loop_good_packet: - while (!addr_last_flag(addr)) { + while (!addr.last) { // Process one UDP packet per iteration #pragma HLS PIPELINE II=128 - ap_uint<64> frame_number = addr_frame_number(addr); - ap_uint<4> module = addr_module(addr); - ap_uint<7> eth_packet = addr_eth_packet(addr); - ap_uint<5> id = module * 2 + (frame_number % 2); - - for (int i = 0; i < 128; i++) { - data_in >> packet_in; - packet_out.data = packet_in.data; - packet_out.last = packet_in.last; - host_memory_out << packet_out; - } - - if (packet_in.last != 1) - internal_err_reg[1] = 1; + ap_uint<64> frame_number = addr.frame_number; + ap_uint<4> module_number = addr.module; + ap_uint<7> eth_packet = addr.eth_packet; + ap_uint<5> id = module_number * 2 + (frame_number % 2); if (curr_frame[id] != frame_number) { if (packet_mask[id] != 0) { @@ -178,26 +188,37 @@ void host_writer(STREAM_512 &data_in, ap_uint<64> comp_bunchid = jf_bunchid[id]; ap_uint<32> comp_exptime = exptime[id]; - write_completion(m_axis_completion, comp_handle, module, + write_completion(m_axis_completion, comp_handle, module_number, comp_frame, comp_packet_mask, comp_packet_count, comp_debug, comp_timestamp, comp_bunchid, - comp_exptime); + comp_exptime, data_collection_id, 0); } - if (read_request(s_axis_work_request, req_handle, req_host_offset)) - internal_err_reg[2] = 1; - - if (req_handle == UINT32_MAX) - internal_err_reg[4] = 1; + if (module_number >= nmodules) { + req_handle = HANDLE_SKIP_FRAME; + req_host_offset = 0; + internal_err_reg[5] = 1; + } else if (s_axis_work_request.empty() && mode_nonblocking) { + req_handle = HANDLE_SKIP_FRAME; + req_host_offset = 0; + } else { + if (read_request(s_axis_work_request, req_handle, req_host_offset)) + internal_err_reg[2] = 1; + if (req_handle >= HANDLE_SKIP_FRAME) { + req_handle = HANDLE_SKIP_FRAME; + req_host_offset = 0; + internal_err_reg[4] = 1; + } + } handle[id] = req_handle; curr_frame[id] = frame_number; curr_offset[id] = req_host_offset; - debug[id] = addr_jf_debug(addr); - timestamp[id] = addr_timestamp(addr); - jf_bunchid[id] = addr_bunch_id(addr); - exptime[id] = addr_exptime(addr); + debug[id] = addr.debug; + timestamp[id] = addr.timestamp; + jf_bunchid[id] = addr.bunchid; + exptime[id] = addr.exptime; packet_mask[id] = ap_uint<128>(1) << eth_packet; packet_count[id] = 1; @@ -206,13 +227,31 @@ void host_writer(STREAM_512 &data_in, packet_mask[id] |= ap_uint<128>(1) << eth_packet; } - size_t out_frame_addr = curr_offset[id] + eth_packet * PACKET_SIZE; + if (handle[id] != HANDLE_SKIP_FRAME) { + for (int i = 0; i < 128; i++) { + data_in >> packet_in; + packet_out.data = packet_in.data; + packet_out.last = packet_in.last; + host_memory_out << packet_out; + } - if (out_frame_addr % 128 != 0) internal_err_reg[0] = 1; - if (curr_offset[id] == 0) internal_err_reg[3] = 1; - packets_processed = ++total_counter; + if (packet_in.last != 1) + internal_err_reg[1] = 1; - setup_datamover(datamover_out_cmd, out_frame_addr, PACKET_SIZE); + size_t out_frame_addr = curr_offset[id] + eth_packet * PACKET_SIZE; + + if (out_frame_addr % 128 != 0) internal_err_reg[0] = 1; + if (curr_offset[id] == 0) internal_err_reg[3] = 1; + total_counter++; + packets_processed = total_counter; + setup_datamover(datamover_out_cmd, out_frame_addr, PACKET_SIZE); + } else { + for (int i = 0; i < 128; i++) + data_in >> packet_in; + + if (packet_in.last != 1) + internal_err_reg[1] = 1; + } addr_in >> addr; err_reg = internal_err_reg; } @@ -222,23 +261,17 @@ void host_writer(STREAM_512 &data_in, std::this_thread::sleep_for(std::chrono::milliseconds(100)); #endif - for (ap_uint<8> m = 0; m < MAX_MODULES_FPGA * 2; m++) { + for (ap_uint<8> m = 0; m < nmodules * 2; m++) { #pragma HLS PIPELINE II=16 - if (packet_mask[m] > 0) + if (packet_mask[m] != 0) write_completion(m_axis_completion, handle[m], m / 2, curr_frame[m], packet_mask[m], packet_count[m], debug[m], timestamp[m], jf_bunchid[m], - exptime[m]); + exptime[m], data_collection_id, 1); } data_in >> packet_in; - write_completion(m_axis_completion, UINT32_MAX, 0, total_counter, 0, 0, 0, 0, 0, 0); - - read_request(s_axis_work_request, req_handle, req_host_offset); - - while (req_handle != UINT32_MAX) { -#pragma HLS PIPELINE II=4 - read_request(s_axis_work_request, req_handle, req_host_offset); - } + write_completion(m_axis_completion, HANDLE_END, 0, 0, 0, 0, 0, 0, 0, 0, data_collection_id, 0); + idle = 1; } diff --git a/receiver/hls/icmp.cpp b/fpga/hls/icmp.cpp similarity index 93% rename from receiver/hls/icmp.cpp rename to fpga/hls/icmp.cpp index 563fc18a..c3f81161 100755 --- a/receiver/hls/icmp.cpp +++ b/fpga/hls/icmp.cpp @@ -34,7 +34,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ************************************************/ // With modifications from Paul Scherrer Insitute -// SPDX-License-Identifier: CERN-OHL-S-2.0 or GPL-3.0-or-later + #include "hls_jfjoch.h" #include "ip_header_checksum.h" @@ -111,8 +111,8 @@ void icmp(AXI_STREAM& eth_in, AXI_STREAM& eth_out, uint64_t& counter, if (eth_in.read_nb(packet)) { if (state == INSPECT_HEADER) { - ap_uint < 48 > dest_mac = get_mac_addr(packet.data, 0); - ap_uint < 48 > src_mac = get_mac_addr(packet.data, 48); + ap_uint<48> dest_mac = packet.data(47, 0); + ap_uint<48> src_mac = packet.data(95, 48); // Swap MAC addresses for reply packet.data(47, 0) = src_mac; @@ -127,8 +127,8 @@ void icmp(AXI_STREAM& eth_in, AXI_STREAM& eth_out, uint64_t& counter, if ((icmp_type == ECHO_REQUEST) && (icmp_code == 0)) { - ap_uint < 32 > ipv4_src_ip = packet.data(eth_payload_pos + 127, eth_payload_pos + 96); - ap_uint < 32 > ipv4_dest_ip = packet.data(eth_payload_pos + 159, eth_payload_pos + 128); + ap_uint<32> ipv4_src_ip = packet.data(eth_payload_pos + 127, eth_payload_pos + 96); + ap_uint<32> ipv4_dest_ip = packet.data(eth_payload_pos + 159, eth_payload_pos + 128); packet.data(eth_payload_pos + 71, eth_payload_pos + 64) = 128; // IP time to live packet.data(eth_payload_pos + 95, eth_payload_pos + 80) = 0; diff --git a/receiver/hls/ip_header_checksum.h b/fpga/hls/ip_header_checksum.h similarity index 97% rename from receiver/hls/ip_header_checksum.h rename to fpga/hls/ip_header_checksum.h index 53adbf04..e594c8d3 100644 --- a/receiver/hls/ip_header_checksum.h +++ b/fpga/hls/ip_header_checksum.h @@ -34,7 +34,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ************************************************/ // With modifications from Paul Scherrer Institute -// SPDX-License-Identifier: CERN-OHL-S-2.0 or GPL-3.0-or-later + #ifndef JUNGFRAUJOCH_IP_HEADER_CHECKSUM_H #define JUNGFRAUJOCH_IP_HEADER_CHECKSUM_H diff --git a/receiver/hls/ipv4.cpp b/fpga/hls/ipv4.cpp similarity index 90% rename from receiver/hls/ipv4.cpp rename to fpga/hls/ipv4.cpp index 281f3b1d..eab00a9e 100644 --- a/receiver/hls/ipv4.cpp +++ b/fpga/hls/ipv4.cpp @@ -1,5 +1,5 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: CERN-OHL-S-2.0 or GPL-3.0-or-later +// Copyright (2019-2023) Paul Scherrer Institute + #include "hls_jfjoch.h" #include "ip_header_checksum.h" @@ -28,7 +28,7 @@ void ipv4(AXI_STREAM ð_in, ap_uint<4> ip_version = packet_in.data(eth_payload_pos + 8 - 1, eth_payload_pos + 4); ap_uint<8> ipv4_protocol = packet_in.data(eth_payload_pos + 80 - 1, eth_payload_pos + 72); - ap_uint<32> ipv4_dest_ip = get_header_field_32_network_order(packet_in.data, eth_payload_pos + 128); + ap_uint<32> ipv4_dest_ip = packet_in.data(eth_payload_pos + 128 + 31, eth_payload_pos + 128); ap_uint<16> ipv4_header_checksum_check = computeCheckSum20B(packet_in.data(eth_payload_pos + 159, eth_payload_pos)); if ((ip_version == 4) && (ipv4_dest_ip == fpga_ipv4_addr) && (ipv4_header_checksum_check == 0)) { diff --git a/receiver/hls/jf_conversion.cpp b/fpga/hls/jf_conversion.cpp similarity index 56% rename from receiver/hls/jf_conversion.cpp rename to fpga/hls/jf_conversion.cpp index 263d844f..b24d80ab 100644 --- a/receiver/hls/jf_conversion.cpp +++ b/fpga/hls/jf_conversion.cpp @@ -1,5 +1,5 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: CERN-OHL-S-2.0 or GPL-3.0-or-later +// Copyright (2019-2023) Paul Scherrer Institute + #include "hls_jfjoch.h" @@ -100,8 +100,8 @@ ap_uint<512> convert(ap_uint<512> data_in, } void jf_conversion(STREAM_512 &data_in, STREAM_512 &data_out, - hls::stream > &addr_in, - hls::stream > &addr_out, + hls::stream &addr_in, + hls::stream &addr_out, hls::burst_maxi d_hbm_p0, hls::burst_maxi d_hbm_p1, hls::burst_maxi d_hbm_p2, hls::burst_maxi d_hbm_p3, hls::burst_maxi d_hbm_p4, hls::burst_maxi d_hbm_p5, @@ -116,33 +116,33 @@ void jf_conversion(STREAM_512 &data_in, STREAM_512 &data_out, #pragma HLS INTERFACE register both axis port=addr_out #pragma HLS INTERFACE m_axi port=d_hbm_p0 bundle=d_hbm_p0 depth=512 offset=off \ - max_read_burst_length=16 max_write_burst_length=16 latency=120 num_write_outstanding=8 num_read_outstanding=9 + max_read_burst_length=16 max_write_burst_length=2 latency=120 num_write_outstanding=2 num_read_outstanding=9 #pragma HLS INTERFACE m_axi port=d_hbm_p1 bundle=d_hbm_p1 depth=512 offset=off \ - max_read_burst_length=16 max_write_burst_length=16 latency=120 num_write_outstanding=8 num_read_outstanding=9 + max_read_burst_length=16 max_write_burst_length=2 latency=120 num_write_outstanding=2 num_read_outstanding=9 #pragma HLS INTERFACE m_axi port=d_hbm_p2 bundle=d_hbm_p2 depth=512 offset=off \ - max_read_burst_length=16 max_write_burst_length=16 latency=120 num_write_outstanding=8 num_read_outstanding=9 + max_read_burst_length=16 max_write_burst_length=2 latency=120 num_write_outstanding=2 num_read_outstanding=9 #pragma HLS INTERFACE m_axi port=d_hbm_p3 bundle=d_hbm_p3 depth=512 offset=off \ - max_read_burst_length=16 max_write_burst_length=16 latency=120 num_write_outstanding=8 num_read_outstanding=9 + max_read_burst_length=16 max_write_burst_length=2 latency=120 num_write_outstanding=2 num_read_outstanding=9 #pragma HLS INTERFACE m_axi port=d_hbm_p4 bundle=d_hbm_p4 depth=512 offset=off \ - max_read_burst_length=16 max_write_burst_length=16 latency=120 num_write_outstanding=8 num_read_outstanding=9 + max_read_burst_length=16 max_write_burst_length=2 latency=120 num_write_outstanding=2 num_read_outstanding=9 #pragma HLS INTERFACE m_axi port=d_hbm_p5 bundle=d_hbm_p5 depth=512 offset=off \ - max_read_burst_length=16 max_write_burst_length=16 latency=120 num_write_outstanding=8 num_read_outstanding=9 + max_read_burst_length=16 max_write_burst_length=2 latency=120 num_write_outstanding=2 num_read_outstanding=9 #pragma HLS INTERFACE m_axi port=d_hbm_p6 bundle=d_hbm_p6 depth=512 offset=off \ - max_read_burst_length=16 max_write_burst_length=16 latency=120 num_write_outstanding=8 num_read_outstanding=9 + max_read_burst_length=16 max_write_burst_length=2 latency=120 num_write_outstanding=2 num_read_outstanding=9 #pragma HLS INTERFACE m_axi port=d_hbm_p7 bundle=d_hbm_p7 depth=512 offset=off \ - max_read_burst_length=16 max_write_burst_length=16 latency=120 num_write_outstanding=8 num_read_outstanding=9 + max_read_burst_length=16 max_write_burst_length=2 latency=120 num_write_outstanding=2 num_read_outstanding=9 #pragma HLS INTERFACE m_axi port=d_hbm_p8 bundle=d_hbm_p8 depth=512 offset=off \ - max_read_burst_length=16 max_write_burst_length=16 latency=120 num_write_outstanding=8 num_read_outstanding=9 + max_read_burst_length=16 max_write_burst_length=2 latency=120 num_write_outstanding=2 num_read_outstanding=9 #pragma HLS INTERFACE m_axi port=d_hbm_p9 bundle=d_hbm_p9 depth=512 offset=off \ - max_read_burst_length=16 max_write_burst_length=16 latency=120 num_write_outstanding=8 num_read_outstanding=9 + max_read_burst_length=16 max_write_burst_length=2 latency=120 num_write_outstanding=2 num_read_outstanding=9 #pragma HLS INTERFACE m_axi port=d_hbm_p10 bundle=d_hbm_p10 depth=512 offset=off \ - max_read_burst_length=16 max_write_burst_length=16 latency=120 num_write_outstanding=8 num_read_outstanding=9 + max_read_burst_length=16 max_write_burst_length=2 latency=120 num_write_outstanding=2 num_read_outstanding=9 #pragma HLS INTERFACE m_axi port=d_hbm_p11 bundle=d_hbm_p11 depth=512 offset=off \ - max_read_burst_length=16 max_write_burst_length=16 latency=120 num_write_outstanding=8 num_read_outstanding=9 + max_read_burst_length=16 max_write_burst_length=2 latency=120 num_write_outstanding=2 num_read_outstanding=9 packet_512_t packet_in; - ap_uint addr; + axis_addr addr; addr_in >> addr; addr_out << addr; @@ -152,6 +152,19 @@ void jf_conversion(STREAM_512 &data_in, STREAM_512 &data_out, ap_uint<5> modules = ACT_REG_NMODULES(packet_in.data); ap_uint<32> in_one_over_energy = ACT_REG_ONE_OVER_ENERGY(packet_in.data); ap_uint<5> storage_cells = ACT_REG_NSTORAGE_CELLS(packet_in.data); + ap_uint<32> hbm_size_256b = ACT_REG_HBM_SIZE_256b(packet_in.data); + ap_uint<32> offset_hbm_0 = 0 * hbm_size_256b; + ap_uint<32> offset_hbm_1 = 1 * hbm_size_256b; + ap_uint<32> offset_hbm_2 = 2 * hbm_size_256b; + ap_uint<32> offset_hbm_3 = 3 * hbm_size_256b; + ap_uint<32> offset_hbm_4 = 4 * hbm_size_256b; + ap_uint<32> offset_hbm_5 = 5 * hbm_size_256b; + ap_uint<32> offset_hbm_6 = 6 * hbm_size_256b; + ap_uint<32> offset_hbm_7 = 7 * hbm_size_256b; + ap_uint<32> offset_hbm_8 = 8 * hbm_size_256b; + ap_uint<32> offset_hbm_9 = 9 * hbm_size_256b; + ap_uint<32> offset_hbm_10 = 10 * hbm_size_256b; + ap_uint<32> offset_hbm_11 = 11 * hbm_size_256b; one_over_energy_t one_over_energy; for (int i = 0; i < 32; i++) @@ -160,141 +173,35 @@ void jf_conversion(STREAM_512 &data_in, STREAM_512 &data_out, data_out << packet_in; if (conversion) { - // Load calibration into HBM - save_gainG0: - for (int i = 0; i < modules * (RAW_MODULE_SIZE * 2 / 64); i++) { -#pragma HLS PIPELINE II=1 - data_in >> packet_in; - if (i % HBM_BURST == 0) { - d_hbm_p0.write_request(i, HBM_BURST); - d_hbm_p1.write_request(i, HBM_BURST); - } - d_hbm_p0.write(packet_in.data(255, 0)); - d_hbm_p1.write(packet_in.data(511, 256)); - if (i % HBM_BURST == HBM_BURST - 1) { - d_hbm_p0.write_response(); - d_hbm_p1.write_response(); - } - } - - save_gainG1: - for (int i = 0; i < modules * (RAW_MODULE_SIZE * 2 / 64); i++) { -#pragma HLS PIPELINE II=1 - data_in >> packet_in; - if (i % HBM_BURST == 0) { - d_hbm_p2.write_request(i, HBM_BURST); - d_hbm_p3.write_request(i, HBM_BURST); - } - d_hbm_p2.write(packet_in.data(255, 0)); - d_hbm_p3.write(packet_in.data(511, 256)); - if (i % HBM_BURST == HBM_BURST - 1) { - d_hbm_p2.write_response(); - d_hbm_p3.write_response(); - } - } - - save_gainG2: - for (int i = 0; i < modules * (RAW_MODULE_SIZE * 2 / 64); i++) { -#pragma HLS PIPELINE II=1 - data_in >> packet_in; - if (i % HBM_BURST == 0) { - d_hbm_p4.write_request(i, HBM_BURST); - d_hbm_p5.write_request(i, HBM_BURST); - } - d_hbm_p4.write(packet_in.data(255, 0)); - d_hbm_p5.write(packet_in.data(511, 256)); - if (i % HBM_BURST == HBM_BURST - 1) { - d_hbm_p4.write_response(); - d_hbm_p5.write_response(); - } - } - - save_pedeG0: - for (int i = 0; i < modules * storage_cells * (RAW_MODULE_SIZE * 2 / 64); i++) { -#pragma HLS PIPELINE II=1 - data_in >> packet_in; - if (i % HBM_BURST == 0) { - d_hbm_p6.write_request(i, HBM_BURST); - d_hbm_p7.write_request(i, HBM_BURST); - } - d_hbm_p6.write(packet_in.data(255, 0)); - d_hbm_p7.write(packet_in.data(511, 256)); - if (i % HBM_BURST == HBM_BURST - 1) { - d_hbm_p6.write_response(); - d_hbm_p7.write_response(); - } - } - - save_pedeG1: - for (int i = 0; i < modules * storage_cells * (RAW_MODULE_SIZE * 2 / 64); i++) { -#pragma HLS PIPELINE II=1 - data_in >> packet_in; - if (i % HBM_BURST == 0) { - d_hbm_p8.write_request(i, HBM_BURST); - d_hbm_p9.write_request(i, HBM_BURST); - } - d_hbm_p8.write(packet_in.data(255, 0)); - d_hbm_p9.write(packet_in.data(511, 256)); - if (i % HBM_BURST == HBM_BURST - 1) { - d_hbm_p8.write_response(); - d_hbm_p9.write_response(); - } - } - - save_pedeG2: - for (int i = 0; i < modules * storage_cells * (RAW_MODULE_SIZE * 2 / 64); i++) { -#pragma HLS PIPELINE II=1 - data_in >> packet_in; - if (i % HBM_BURST == 0) { - d_hbm_p10.write_request(i, HBM_BURST); - d_hbm_p11.write_request(i, HBM_BURST); - } - d_hbm_p10.write(packet_in.data(255, 0)); - d_hbm_p11.write(packet_in.data(511, 256)); - if (i % HBM_BURST == HBM_BURST - 1) { - d_hbm_p10.write_response(); - d_hbm_p11.write_response(); - } - } - ap_uint<7> counter = 0; addr_in >> addr; pixel_conversion: - while (!addr_last_flag(addr)) { + while (!addr.last) { #pragma HLS PIPELINE II=1 //ap_uint<17> offset = packet_in.user(16,0); if (counter % 16 == 0) { - ap_uint<17> gain_offset = (addr_module(addr), addr_eth_packet(addr), counter); - ap_uint<12> pedestal_location = addr_module(addr); + ap_uint<19> gain_offset = (addr.module, addr.eth_packet, counter); + ap_uint<12> pedestal_location = addr.module; - if (storage_cells == 2) { - ap_uint<4> storage_cell_id = (addr_frame_number(addr) - 1) % 2; - pedestal_location += modules * storage_cell_id; - } else if (storage_cells == 4) { - ap_uint<4> storage_cell_id = (addr_frame_number(addr) - 1) % 4; - pedestal_location += modules * storage_cell_id; - } else if (storage_cells == 8) { - ap_uint<4> storage_cell_id = (addr_frame_number(addr) - 1) % 8; - pedestal_location += modules * storage_cell_id; - } else if (storage_cells == 16) { - ap_uint<4> storage_cell_id = (addr_frame_number(addr) - 1) % 16; + if (storage_cells > 1) { + ap_uint<4> storage_cell_id = (addr.frame_number - 1) % storage_cells; pedestal_location += modules * storage_cell_id; } - ap_uint<26> pedestal_offset = (pedestal_location, addr_eth_packet(addr), counter); + ap_uint<26> pedestal_offset = (pedestal_location, addr.eth_packet, counter); - d_hbm_p0.read_request(gain_offset, 16); - d_hbm_p1.read_request(gain_offset, 16); - d_hbm_p2.read_request(gain_offset, 16); - d_hbm_p3.read_request(gain_offset, 16); - d_hbm_p4.read_request(gain_offset, 16); - d_hbm_p5.read_request(gain_offset, 16); - d_hbm_p6.read_request(pedestal_offset, 16); - d_hbm_p7.read_request(pedestal_offset, 16); - d_hbm_p8.read_request(pedestal_offset, 16); - d_hbm_p9.read_request(pedestal_offset, 16); - d_hbm_p10.read_request(pedestal_offset, 16); - d_hbm_p11.read_request(pedestal_offset, 16); + d_hbm_p0.read_request(offset_hbm_0 + gain_offset, 16); + d_hbm_p1.read_request(offset_hbm_1 + gain_offset, 16); + d_hbm_p2.read_request(offset_hbm_2 + gain_offset, 16); + d_hbm_p3.read_request(offset_hbm_3 + gain_offset, 16); + d_hbm_p4.read_request(offset_hbm_4 + gain_offset, 16); + d_hbm_p5.read_request(offset_hbm_5 + gain_offset, 16); + d_hbm_p6.read_request(offset_hbm_6 + pedestal_offset, 16); + d_hbm_p7.read_request(offset_hbm_7 + pedestal_offset, 16); + d_hbm_p8.read_request(offset_hbm_8 + pedestal_offset, 16); + d_hbm_p9.read_request(offset_hbm_9 + pedestal_offset, 16); + d_hbm_p10.read_request(offset_hbm_10 + pedestal_offset, 16); + d_hbm_p11.read_request(offset_hbm_11 + pedestal_offset, 16); } ap_uint<256> packed_gainG0_1 = d_hbm_p0.read(); ap_uint<256> packed_gainG0_2 = d_hbm_p1.read(); @@ -330,7 +237,7 @@ void jf_conversion(STREAM_512 &data_in, STREAM_512 &data_out, } else { addr_in >> addr; forward_packets: - while (!addr_last_flag(addr)) { + while (!addr.last) { #pragma HLS PIPELINE II=1 data_in >> packet_in; data_out << packet_in; diff --git a/fpga/hls/load_calibration.cpp b/fpga/hls/load_calibration.cpp new file mode 100644 index 00000000..5b7dbb13 --- /dev/null +++ b/fpga/hls/load_calibration.cpp @@ -0,0 +1,74 @@ +// Copyright (2019-2023) Paul Scherrer Institute + + +#include "hls_jfjoch.h" + +// Loads calibration from host memory based on 64-bit memory addresses loaded in in_mem_location +// Expected structure in in_mem_location array: +// +// * gain factors for module m at location: 2 + gain level * NMODULES + m +// * pedestal factors for module m and storage cell s at location: 2 + 3 * NMODULES + (gain level * 16 + s ) * NMODULES + m + +void read_module(ap_uint<256> *d_hbm_p0, + ap_uint<256> *d_hbm_p1, + hls::stream > &host_memory_in, + size_t offset_hbm_0, + size_t offset_hbm_1) { +#pragma HLS INLINE OFF + for (int i = 0; i < RAW_MODULE_SIZE * sizeof(int16_t) / 64; i++) { +#pragma HLS PIPELINE II=1 + ap_axiu<512, 1, 1, 1> data_packet; + host_memory_in >> data_packet; + + d_hbm_p0[offset_hbm_0 + i] = data_packet.data(255, 0); + d_hbm_p1[offset_hbm_1 + i] = data_packet.data(511, 256); + } +} + +void load_calibration(ap_uint<256> *d_hbm_p0, + ap_uint<256> *d_hbm_p1, + ap_uint<8> modules, + ap_uint<5> storage_cells, + ap_uint<32> hbm_size_bytes, + hls::stream &datamover_in_cmd, + hls::stream > &host_memory_in, + uint64_t in_mem_location[(3 * 16 + 3) * MAX_MODULES_FPGA]) { +#pragma HLS INTERFACE mode=s_axilite port=return +#pragma HLS INTERFACE mode=s_axilite port=in_mem_location +#pragma HLS INTERFACE register both axis port=datamover_in_cmd +#pragma HLS INTERFACE register both axis port=host_memory_in + +#pragma HLS INTERFACE mode=s_axilite port=modules +#pragma HLS INTERFACE mode=s_axilite port=storage_cells +#pragma HLS INTERFACE mode=ap_none port=hbm_size_bytes + +#pragma HLS INTERFACE mode=m_axi port=d_hbm_p0 bundle=d_hbm_p0 depth=512 offset=off \ + max_read_burst_length=2 max_write_burst_length=16 latency=120 num_write_outstanding=8 num_read_outstanding=2 +#pragma HLS INTERFACE mode=m_axi port=d_hbm_p1 bundle=d_hbm_p1 depth=512 offset=off \ + max_read_burst_length=2 max_write_burst_length=16 latency=120 num_write_outstanding=8 num_read_outstanding=2 + + if (storage_cells > 16) + return; + if (modules > MAX_MODULES_FPGA) + return; + + for (int c = 0; c < 3; c++) { + for (int m = 0; m < modules; m++) { +#pragma HLS PIPELINE OFF + setup_datamover(datamover_in_cmd, in_mem_location[c * modules + m], RAW_MODULE_SIZE * sizeof(int16_t)); + size_t offset_hbm_0 = (2 * c) * hbm_size_bytes / 32 + m * RAW_MODULE_SIZE * sizeof(int16_t) / 64; + size_t offset_hbm_1 = (2 * c + 1) * hbm_size_bytes / 32 + m * RAW_MODULE_SIZE * sizeof(int16_t) / 64; + read_module(d_hbm_p0, d_hbm_p1, host_memory_in, offset_hbm_0, offset_hbm_1); + } + } + + for (int c = 0; c < 3; c++) { + for (int m = 0; m < modules * storage_cells; m++) { +#pragma HLS PIPELINE OFF + setup_datamover(datamover_in_cmd, in_mem_location[3 * modules + c * modules * storage_cells + m], RAW_MODULE_SIZE * sizeof(int16_t)); + size_t offset_hbm_0 = (6 + 2 * c) * hbm_size_bytes / 32 + m * RAW_MODULE_SIZE * sizeof(int16_t) / 64; + size_t offset_hbm_1 = (6 + 2 * c + 1) * hbm_size_bytes / 32 + m * RAW_MODULE_SIZE * sizeof(int16_t) / 64; + read_module(d_hbm_p0, d_hbm_p1, host_memory_in, offset_hbm_0, offset_hbm_1); + } + } +} diff --git a/receiver/include/parallel_stream.h b/fpga/hls/parallel_stream.h similarity index 96% rename from receiver/include/parallel_stream.h rename to fpga/hls/parallel_stream.h index edfbb741..ac50b37b 100644 --- a/receiver/include/parallel_stream.h +++ b/fpga/hls/parallel_stream.h @@ -1,5 +1,4 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (2019-2023) Paul Scherrer Institute #ifndef JUNGFRAUJOCH_PARALLEL_STREAM_H #define JUNGFRAUJOCH_PARALLEL_STREAM_H diff --git a/receiver/hls/sls_detector.cpp b/fpga/hls/sls_detector.cpp similarity index 80% rename from receiver/hls/sls_detector.cpp rename to fpga/hls/sls_detector.cpp index 74783036..3707d8a7 100644 --- a/receiver/hls/sls_detector.cpp +++ b/fpga/hls/sls_detector.cpp @@ -1,12 +1,12 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: CERN-OHL-S-2.0 or GPL-3.0-or-later +// Copyright (2019-2023) Paul Scherrer Institute + #include "hls_jfjoch.h" void sls_detector(AXI_STREAM &udp_payload_in, hls::stream > &udp_metadata_in, AXI_STREAM &data_out, - hls::stream > &addr_out, + hls::stream &addr_out, uint64_t& counter, uint32_t& counter_eth_error, uint32_t& counter_len_error, @@ -65,19 +65,22 @@ void sls_detector(AXI_STREAM &udp_payload_in, && (udp_metadata_len_err(udp_metadata) == 0)) { ap_uint<16> column = packet_in.data(4 * 64 + 31, 4 * 64 + 16); - - ap_uint<64> frame_number = packet_in.data(63, 0); - ap_uint<32> jf_debug = packet_in.data(5 * 64 + 31, 5 * 64); - ap_uint<64> timestamp = packet_in.data(3 * 64 + 63, 3 * 64); - ap_uint<64> bunchid = packet_in.data(2 * 64 + 63, 2 * 64); - ap_uint<5> module = (column % 32) / 2; ap_uint<1> module_part = column[0]; - ap_uint<7> eth_packet = (packet_in.data(127, 96) % 128) | (module_part * 64); - ap_uint<32> exptime = packet_in.data(95, 64); + beat_counter = 0; reminder = packet_in.data(511, 384); - addr_out << addr_packet(eth_packet, module, frame_number, jf_debug, timestamp, bunchid,exptime); + axis_addr addr; + addr.frame_number = packet_in.data(63, 0); + addr.debug = packet_in.data(5 * 64 + 31, 5 * 64); + addr.timestamp = packet_in.data(3 * 64 + 63, 3 * 64); + addr.bunchid = packet_in.data(2 * 64 + 63, 2 * 64); + addr.module = (column % 32) / 2; + addr.eth_packet = (packet_in.data(127, 96) % 128) | (module_part * 64); + addr.exptime = packet_in.data(95, 64); + addr.last = 0; + addr_out << addr; + state = FORWARD; internal_counter++; } else { diff --git a/fpga/hls/stream_merge.cpp b/fpga/hls/stream_merge.cpp new file mode 100644 index 00000000..688b90b3 --- /dev/null +++ b/fpga/hls/stream_merge.cpp @@ -0,0 +1,45 @@ +// Copyright (2019-2023) Paul Scherrer Institute + +#include "hls_jfjoch.h" + +void stream_merge(AXI_STREAM &input_0, + AXI_STREAM &input_1, + AXI_STREAM &output) { +#pragma HLS INTERFACE ap_ctrl_none port=return +#pragma HLS INTERFACE axis register both port=input_0 +#pragma HLS INTERFACE axis register both port=input_1 +#pragma HLS INTERFACE axis register both port=output + +#pragma HLS PIPELINE II=1 style=flp + enum state {ARBITRATE, FORWARD}; + static state state = ARBITRATE; + static ap_uint<1> select_input = 0; + + packet_512_t packet_in; +#pragma HLS RESET variable=state + switch (state) { + case ARBITRATE: + if (input_0.read_nb(packet_in)) { + select_input = 0; + if (!packet_in.last) + state = FORWARD; + output.write(packet_in); + } else if (input_1.read_nb(packet_in)) { + select_input = 1; + if (!packet_in.last) + state = FORWARD; + output.write(packet_in); + } + break; + case FORWARD: + if (select_input == 0) { + input_0.read(packet_in); + } else + input_1.read(packet_in); + output.write(packet_in); + + if (packet_in.last) + state = ARBITRATE; + break; + } +} diff --git a/fpga/hls/timer.cpp b/fpga/hls/timer.cpp new file mode 100644 index 00000000..e8051a99 --- /dev/null +++ b/fpga/hls/timer.cpp @@ -0,0 +1,31 @@ +// Copyright (2019-2023) Paul Scherrer Institute + + +#include "hls_jfjoch.h" + +void timer_host(STREAM_512 &data_in, STREAM_512 &data_out, volatile uint64_t &counter) { +#pragma HLS INTERFACE register both axis port=data_in +#pragma HLS INTERFACE register both axis port=data_out +#pragma HLS INTERFACE register ap_vld port=counter +#pragma HLS INTERFACE ap_ctrl_none port=return + packet_512_t packet_in; + + data_in >> packet_in; + uint64_t counter_internal = 0; + counter = 0; + data_out << packet_in; + + data_in >> packet_in; + while (!packet_in.user) { +#pragma HLS PIPELINE II=1 + if (data_out.full()) { + if (counter_internal < UINT64_MAX) + counter_internal++; + } else { + data_out << packet_in; + data_in >> packet_in; + } + counter = counter_internal; + } + data_out << packet_in; +} diff --git a/receiver/hls/udp.cpp b/fpga/hls/udp.cpp similarity index 96% rename from receiver/hls/udp.cpp rename to fpga/hls/udp.cpp index 32250aac..9f84389c 100644 --- a/receiver/hls/udp.cpp +++ b/fpga/hls/udp.cpp @@ -1,5 +1,5 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: CERN-OHL-S-2.0 or GPL-3.0-or-later +// Copyright (2019-2023) Paul Scherrer Institute + #include "hls_jfjoch.h" diff --git a/receiver/include/LICENSE.HLS_Headers b/fpga/include/LICENSE.HLS_Headers similarity index 100% rename from receiver/include/LICENSE.HLS_Headers rename to fpga/include/LICENSE.HLS_Headers diff --git a/receiver/include/ap_common.h b/fpga/include/ap_common.h similarity index 100% rename from receiver/include/ap_common.h rename to fpga/include/ap_common.h diff --git a/receiver/include/ap_decl.h b/fpga/include/ap_decl.h similarity index 100% rename from receiver/include/ap_decl.h rename to fpga/include/ap_decl.h diff --git a/receiver/include/ap_fixed.h b/fpga/include/ap_fixed.h similarity index 100% rename from receiver/include/ap_fixed.h rename to fpga/include/ap_fixed.h diff --git a/receiver/include/ap_fixed_base.h b/fpga/include/ap_fixed_base.h similarity index 100% rename from receiver/include/ap_fixed_base.h rename to fpga/include/ap_fixed_base.h diff --git a/receiver/include/ap_fixed_ref.h b/fpga/include/ap_fixed_ref.h similarity index 100% rename from receiver/include/ap_fixed_ref.h rename to fpga/include/ap_fixed_ref.h diff --git a/receiver/include/ap_fixed_special.h b/fpga/include/ap_fixed_special.h similarity index 100% rename from receiver/include/ap_fixed_special.h rename to fpga/include/ap_fixed_special.h diff --git a/receiver/include/ap_int.h b/fpga/include/ap_int.h similarity index 100% rename from receiver/include/ap_int.h rename to fpga/include/ap_int.h diff --git a/receiver/include/ap_int_base.h b/fpga/include/ap_int_base.h similarity index 100% rename from receiver/include/ap_int_base.h rename to fpga/include/ap_int_base.h diff --git a/receiver/include/ap_int_ref.h b/fpga/include/ap_int_ref.h similarity index 100% rename from receiver/include/ap_int_ref.h rename to fpga/include/ap_int_ref.h diff --git a/receiver/include/ap_int_special.h b/fpga/include/ap_int_special.h similarity index 100% rename from receiver/include/ap_int_special.h rename to fpga/include/ap_int_special.h diff --git a/receiver/include/ap_shift_reg.h b/fpga/include/ap_shift_reg.h similarity index 100% rename from receiver/include/ap_shift_reg.h rename to fpga/include/ap_shift_reg.h diff --git a/receiver/include/etc/ap_private.h b/fpga/include/etc/ap_private.h similarity index 100% rename from receiver/include/etc/ap_private.h rename to fpga/include/etc/ap_private.h diff --git a/receiver/include/hls_burst_maxi.h b/fpga/include/hls_burst_maxi.h similarity index 86% rename from receiver/include/hls_burst_maxi.h rename to fpga/include/hls_burst_maxi.h index 627b965b..9d8541fb 100644 --- a/receiver/include/hls_burst_maxi.h +++ b/fpga/include/hls_burst_maxi.h @@ -1,4 +1,9 @@ // 67d7842dbbe25473c3c32b93c0da8047785f30d78e8a024de1b57352245f9689 + +// Modified by Filip Leonarski (Paul Scherrer Institute +// to allow for multiple parallel bursts to the same pointer +// (via independent HBM channels) + #ifndef X_HLS_BURST_MAXI_SIM_H #define X_HLS_BURST_MAXI_SIM_H @@ -27,9 +32,6 @@ struct MAXIAccessRecord { std::list> WriteRespQ; }; -// A global map between pointer and MAXAccessRecord. -std::map MAXIPointer2AccessRecordMap __attribute__((weak)); - template class burst_maxi { public: @@ -38,7 +40,6 @@ public: assert(bitwidth != 0 && !(bitwidth & (bitwidth - 1)) && "Error: bit width of hls::burst_maxi is not poower-of-2."); // Reset the MAXI access record to this pointer - MAXIAccessRecord &R = MAXIPointer2AccessRecordMap[p]; R.read_disp = 0; R.write_disp = 0; R.ReadQ.clear(); @@ -48,7 +49,6 @@ public: void read_request(size_t offset, unsigned len) { assert(len > 0); - MAXIAccessRecord &R = MAXIPointer2AccessRecordMap[Ptr]; R.ReadQ.push_back(std::make_pair(offset, len)); std::list> CurrentWriteQ = R.WriteQ; CurrentWriteQ.insert(CurrentWriteQ.end(), @@ -62,8 +62,7 @@ public: } T read() { - MAXIAccessRecord &R = MAXIPointer2AccessRecordMap[Ptr]; - assert(!R.ReadQ.empty() && "Error: MAXI read without request."); + assert(!R.ReadQ.empty() && "Error: MAXI read without request."); auto Pair = R.ReadQ.front(); T V = Ptr[Pair.first + (R.read_disp++)]; if (R.read_disp == Pair.second) { @@ -75,7 +74,6 @@ public: void write_request(size_t offset, unsigned len) { assert(len > 0); - MAXIAccessRecord &R = MAXIPointer2AccessRecordMap[Ptr]; for (auto Pair : R.ReadQ) { if (overlap(offset, len, Pair.first, Pair.second)) { std::cerr << "Error: MAXI write request(offset = " << offset << ", len = " << len << ") overlaps with previous read request(offset = " << Pair.first << ", len = " << Pair.second << ")." << std::endl; @@ -86,8 +84,7 @@ public: } void write(const T &val, ap_int byte_enable_mask = -1) { - MAXIAccessRecord &R = MAXIPointer2AccessRecordMap[Ptr]; - assert(!R.WriteQ.empty() && "Error: MAXI write without request."); + assert(!R.WriteQ.empty() && "Error: MAXI write without request."); auto Pair = R.WriteQ.front(); T *DstP = &Ptr[Pair.first + R.write_disp++]; T Src = val; @@ -104,13 +101,13 @@ public: } void write_response() { - MAXIAccessRecord &R = MAXIPointer2AccessRecordMap[Ptr]; assert(!R.WriteRespQ.empty() && "Error: bad MAXI write response. Possible: 1) no corresponding write request; 2) some data still not written."); R.WriteRespQ.pop_front(); } private: T *Ptr; + MAXIAccessRecord R; bool overlap(size_t a, unsigned a_len, size_t b, unsigned b_len) { return a <= b ? a + a_len > b : b + b_len > a; } diff --git a/receiver/host/ActionConfig.h b/fpga/pcie_driver/ActionConfig.h similarity index 83% rename from receiver/host/ActionConfig.h rename to fpga/pcie_driver/ActionConfig.h index 422cb3ef..f248ed5f 100644 --- a/receiver/host/ActionConfig.h +++ b/fpga/pcie_driver/ActionConfig.h @@ -1,5 +1,4 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (2019-2023) Paul Scherrer Institute #ifndef JUNGFRAUJOCH_ACTIONCONFIG_H #define JUNGFRAUJOCH_ACTIONCONFIG_H @@ -29,14 +28,14 @@ struct ActionStatus { uint32_t git_sha1; uint32_t action_type; uint32_t release_level; - uint32_t hbm_temperature; - uint32_t hbm_max_temperature; + uint32_t reserved_3; + uint32_t reserved_1; uint32_t max_modules; uint32_t modules_internal_packet_generator; uint64_t pipeline_stalls_host; uint64_t pipeline_stalls_hbm; uint32_t fifo_status; - uint32_t reserved_1; + uint32_t hbm_size_bytes; uint64_t packets_processed; uint64_t packets_eth; uint64_t packets_icmp; @@ -69,6 +68,17 @@ struct ActionEnvParams { bool ethernet_aligned; }; + +struct FrameGeneratorConfig { + uint32_t frames; + uint32_t modules; + uint64_t dest_mac_addr; + uint32_t dest_ipv4_addr; + uint64_t bunchid; + uint32_t exptime; + uint32_t debug; +}; + #pragma pack(pop) #endif //JUNGFRAUJOCH_ACTIONCONFIG_H diff --git a/receiver/pcie_driver/CMakeLists.txt b/fpga/pcie_driver/CMakeLists.txt similarity index 100% rename from receiver/pcie_driver/CMakeLists.txt rename to fpga/pcie_driver/CMakeLists.txt diff --git a/receiver/pcie_driver/Makefile b/fpga/pcie_driver/Makefile similarity index 100% rename from receiver/pcie_driver/Makefile rename to fpga/pcie_driver/Makefile diff --git a/receiver/pcie_driver/jfjoch_drv.c b/fpga/pcie_driver/jfjoch_drv.c similarity index 94% rename from receiver/pcie_driver/jfjoch_drv.c rename to fpga/pcie_driver/jfjoch_drv.c index 21e6fbd9..6d89ff70 100644 --- a/receiver/pcie_driver/jfjoch_drv.c +++ b/fpga/pcie_driver/jfjoch_drv.c @@ -1,5 +1,4 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (2019-2023) Paul Scherrer Institute #include #include @@ -82,10 +81,6 @@ static int jfjoch_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id drvdata->git_sha1 = status.git_sha1; drvdata->max_modules = status.max_modules; - err = jfjoch_setup_calibration(pdev); - if (err) - goto deregister_misc; - jfjoch_setup_cms(drvdata); jfjoch_setup_network(drvdata); @@ -114,7 +109,6 @@ void jfjoch_reset(struct jfjoch_drvdata *drvdata) { pci_reset_function(drvdata->pdev); jfjoch_setup_cms(drvdata); - jfjoch_setup_calibration(drvdata->pdev); dev_info(drvdata->miscdev.this_device, "Jungfraujoch FPGA restarted"); } diff --git a/receiver/pcie_driver/jfjoch_drv.h b/fpga/pcie_driver/jfjoch_drv.h similarity index 67% rename from receiver/pcie_driver/jfjoch_drv.h rename to fpga/pcie_driver/jfjoch_drv.h index 3827847d..508b84cb 100644 --- a/receiver/pcie_driver/jfjoch_drv.h +++ b/fpga/pcie_driver/jfjoch_drv.h @@ -1,5 +1,4 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (2019-2023) Paul Scherrer Institute #ifndef JUNGFRAUJOCH_JFJOCH_DRV_H #define JUNGFRAUJOCH_JFJOCH_DRV_H @@ -11,7 +10,7 @@ #include #include -#include "../host/ActionConfig.h" +#include "ActionConfig.h" // From Xilinx XDMA /* obtain the 32 most significant (high) bits of a 32-bit or 64-bit address */ @@ -35,12 +34,33 @@ // Offset for BAR #0 for action configuration -#define ACTION_CONFIG_OFFSET (0x10000) -#define MAILBOX_OFFSET (0x30000) -#define CALIB_BRAM_OFFSET (0x60000) -#define CMS_OFFSET (0xC0000) -#define CMAC_OFFSET (0x20000) -#define PCIE_OFFSET (0x90000) +#define ACTION_CONFIG_OFFSET (0x010000) +#define MAILBOX_OFFSET (0x030000) +#define LOAD_CALIBRATION_OFFSET (0x060000) +#define CMS_OFFSET (0x0C0000) +#define CMAC_OFFSET (0x020000) +#define PCIE_OFFSET (0x090000) +#define INT_PKT_GEN_OFFSET (0x100000) +#define FRAME_GEN_OFFSET (0x080000) + +#define ADDR_LOAD_CALIBRATION_CTRL (LOAD_CALIBRATION_OFFSET | 0x000000) +#define ADDR_LOAD_CALIBRATION_MOD (LOAD_CALIBRATION_OFFSET | 0x000010) +#define ADDR_LOAD_CALIBRATION_SC (LOAD_CALIBRATION_OFFSET | 0x000018) +#define ADDR_LOAD_CALIBRATION_MEM (LOAD_CALIBRATION_OFFSET | 0x002000) + +#define ADDR_FRAME_GEN_CTRL (FRAME_GEN_OFFSET | 0x000000) +#define ADDR_FRAME_GEN_FRAMES (FRAME_GEN_OFFSET | 0x000010) +#define ADDR_FRAME_GEN_MODULES (FRAME_GEN_OFFSET | 0x000018) +#define ADDR_FRAME_GEN_DEST_MAC_LO (FRAME_GEN_OFFSET | 0x000020) +#define ADDR_FRAME_GEN_DEST_MAC_HI (FRAME_GEN_OFFSET | 0x000024) +#define ADDR_FRAME_GEN_DEST_IPV4_ADDR (FRAME_GEN_OFFSET | 0x00002C) +#define ADDR_FRAME_GEN_BUNCHID_LO (FRAME_GEN_OFFSET | 0x000034) +#define ADDR_FRAME_GEN_BUNCHID_HI (FRAME_GEN_OFFSET | 0x000038) +#define ADDR_FRAME_GEN_EXPTIME (FRAME_GEN_OFFSET | 0x000040) +#define ADDR_FRAME_GEN_DEBUG (FRAME_GEN_OFFSET | 0x000048) + +#define JFJOCH_DMA_SETTINGS (XDMA_CTRL_RUN_STOP | XDMA_CTRL_IE_DESC_ALIGN_MISMATCH | XDMA_CTRL_IE_DESC_ERROR | XDMA_CTRL_IE_READ_ERROR \ + | XDMA_CTRL_IE_WRITE_ERROR | XDMA_CTRL_IE_DESC_COMPLETED | XDMA_CTRL_STM_MODE_WB) #define ADDR_CMS_CONTROL_REG 0x028018 #define ADDR_CMS_MB_RESETN_REG 0x020000 @@ -52,6 +72,8 @@ #define ADDR_CMS_HBM_TEMP1_INS_REG 0x028268 // in C #define ADDR_CMS_HBM_TEMP2_INS_REG 0x0282BC // in C +#define INT_PKT_GEN_FRAME_SIZE_BYTES (512U*1024U*2UL) + struct jfjoch_buf { dma_addr_t dma_address; void *kernel_address; @@ -83,7 +105,6 @@ int jfjoch_cdev_mmap(struct file *file, struct vm_area_struct *vma); int jfjoch_cdev_release(struct inode *inode, struct file *file); int jfjoch_cdev_open(struct inode *inode, struct file *file); -int jfjoch_setup_calibration(struct pci_dev *pdev); void jfjoch_setup_cms(struct jfjoch_drvdata *drvdata); void jfjoch_setup_network(struct jfjoch_drvdata *drvdata); @@ -100,6 +121,10 @@ void jfjoch_set_mac_addr(struct jfjoch_drvdata *drvdata, u64 *mac_addr); void jfjoch_get_mac_addr(struct jfjoch_drvdata *drvdata, u64 *mac_addr); void jfjoch_set_ipv4_addr(struct jfjoch_drvdata *drvdata, const u32 *addr); void jfjoch_get_ipv4_addr(struct jfjoch_drvdata *drvdata, u32 *addr); +void jfjoch_load_int_pkt_gen(struct jfjoch_drvdata *drvdata, char* output); +void jfjoch_save_int_pkt_gen(struct jfjoch_drvdata *drvdata, const char* input); +int jfjoch_load_calibration(struct jfjoch_drvdata *drvdata, struct ActionConfig *config); +int jfjoch_run_frame_gen(struct jfjoch_drvdata *drvdata, struct FrameGeneratorConfig *config); u64 jfjoch_read_mac_addr(struct jfjoch_drvdata *drvdata); diff --git a/receiver/pcie_driver/jfjoch_function.c b/fpga/pcie_driver/jfjoch_function.c similarity index 73% rename from receiver/pcie_driver/jfjoch_function.c rename to fpga/pcie_driver/jfjoch_function.c index e546eeb0..29c82cbc 100644 --- a/receiver/pcie_driver/jfjoch_function.c +++ b/fpga/pcie_driver/jfjoch_function.c @@ -1,5 +1,4 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (2019-2023) Paul Scherrer Institute #include "jfjoch_drv.h" #include "../../common/Definitions.h" @@ -13,31 +12,19 @@ DEFINE_MUTEX(set_mac_mutex); DEFINE_MUTEX(send_wr_mutex); DEFINE_MUTEX(read_wc_mutex); -u32 parity(uint32_t values[4]) { - return (hweight32(values[0]) + hweight32(values[1]) + hweight32(values[2])) % 2; -} - void jfjoch_start(struct jfjoch_drvdata *drvdata) { - u32 run_val = XDMA_CTRL_RUN_STOP | XDMA_CTRL_IE_DESC_ALIGN_MISMATCH | XDMA_CTRL_IE_DESC_ERROR | XDMA_CTRL_IE_READ_ERROR - | XDMA_CTRL_IE_WRITE_ERROR | XDMA_CTRL_IE_DESC_COMPLETED - | XDMA_CTRL_STM_MODE_WB; // Disable stream writeback - // Set PCIe beats counters - iowrite32((1 << 1), drvdata->bar0 + PCIE_OFFSET + (0<<12) + 0xC0); - iowrite32((1 << 2), drvdata->bar0 + PCIE_OFFSET + (0<<12) + 0xC0); - iowrite32((1 << 1), drvdata->bar0 + PCIE_OFFSET + (1<<12) + 0xC0); iowrite32((1 << 2), drvdata->bar0 + PCIE_OFFSET + (1<<12) + 0xC0); // Start DMA - // RUN + enable logging of certain error conditions ==> H2C channel 0 control register - iowrite32(run_val, drvdata->bar0 + PCIE_OFFSET + (0<<12) + 0x04); - // RUN ==> C2H channel 0 control register - iowrite32(run_val, drvdata->bar0 + PCIE_OFFSET + (1<<12) + 0x04); + // Run C2H + iowrite32(JFJOCH_DMA_SETTINGS, drvdata->bar0 + PCIE_OFFSET + (1<<12) + 0x04); - // Set Mailbox FIFOs, so interrupt threshold is 4 messages - iowrite32(251, drvdata->bar0 + MAILBOX_OFFSET + ADDR_MAILBOX_SIT); - iowrite32(11, drvdata->bar0 + MAILBOX_OFFSET + ADDR_MAILBOX_RIT); + // Set Mailbox FIFOs, so interrupt threshold is 16 messages + // => This way it ensures that one can always execute read/write operation on the FIFO + iowrite32(255-16, drvdata->bar0 + MAILBOX_OFFSET + ADDR_MAILBOX_SIT); + iowrite32(15 , drvdata->bar0 + MAILBOX_OFFSET + ADDR_MAILBOX_RIT); // Write Start value to action config register iowrite32(0x1, drvdata->bar0 + ACTION_CONFIG_OFFSET); @@ -47,8 +34,6 @@ void jfjoch_end(struct jfjoch_drvdata *drvdata) { // Write cancel register iowrite32(0x4, drvdata->bar0 + ACTION_CONFIG_OFFSET); - // RUN ==> H2C channel 0 control register - iowrite32(0, drvdata->bar0 + PCIE_OFFSET + (0<<12) + 0x04); // RUN ==> C2H channel 0 control register iowrite32(0, drvdata->bar0 + PCIE_OFFSET + (1<<12) + 0x04); } @@ -88,6 +73,14 @@ int jfjoch_send_wr(struct jfjoch_drvdata *drvdata, u32 handle) { return 0; } +void jfjoch_load_int_pkt_gen(struct jfjoch_drvdata *drvdata, char* output) { + memcpy_fromio(output, drvdata->bar0 + INT_PKT_GEN_OFFSET, INT_PKT_GEN_FRAME_SIZE_BYTES); +} + +void jfjoch_save_int_pkt_gen(struct jfjoch_drvdata *drvdata, const char* input) { + memcpy_toio(drvdata->bar0 + INT_PKT_GEN_OFFSET, input, INT_PKT_GEN_FRAME_SIZE_BYTES); +} + int jfjoch_read_wc(struct jfjoch_drvdata *drvdata, u32 *output) { u32 rta; int i; @@ -283,10 +276,78 @@ void jfjoch_get_env_data(struct jfjoch_drvdata *drvdata, struct ActionEnvParams env_params->hbm_0_temp_C = ioread32(drvdata->bar0 + CMS_OFFSET + ADDR_CMS_HBM_TEMP1_INS_REG); env_params->hbm_1_temp_C = ioread32(drvdata->bar0 + CMS_OFFSET + ADDR_CMS_HBM_TEMP2_INS_REG); + // Somehow it is better to ask twice + env_params->ethernet_aligned = ioread32(drvdata->bar0 + CMAC_OFFSET + 0x0204) & 0x2; env_params->ethernet_aligned = ioread32(drvdata->bar0 + CMAC_OFFSET + 0x0204) & 0x2; } void jfjoch_clr_net_counters(struct jfjoch_drvdata *drvdata) { iowrite32(1 << 3, drvdata->bar0 + ACTION_CONFIG_OFFSET); iowrite32(0, drvdata->bar0 + ACTION_CONFIG_OFFSET); +} + +int jfjoch_load_calibration(struct jfjoch_drvdata *drvdata, struct ActionConfig *config) { + struct device *const dev = &drvdata->pdev->dev; + u32 i; + u32 cell_count = config->nmodules * (3 + 3 * config->nstorage_cells); + + if (cell_count > drvdata->nbuf) { + dev_err(dev, "Not enough buffers to support this card\n"); + return -EINVAL; + } + + for (i = 0; i < cell_count; i++) { + u64 addr = drvdata->bufs[i].dma_address; + iowrite32(PCI_DMA_L(addr), drvdata->bar0 + ADDR_LOAD_CALIBRATION_MEM + i * 2 * 4); + iowrite32(PCI_DMA_H(addr), drvdata->bar0 + ADDR_LOAD_CALIBRATION_MEM + (i * 2 + 1) * 4); + } + + // Start DMA + // Clear counters and RUN H2C + iowrite32((1 << 1), drvdata->bar0 + PCIE_OFFSET + (0<<12) + 0xC0); + iowrite32((1 << 2), drvdata->bar0 + PCIE_OFFSET + (0<<12) + 0xC0); + iowrite32(JFJOCH_DMA_SETTINGS, drvdata->bar0 + PCIE_OFFSET + (0<<12) + 0x04); + + iowrite32(config->nmodules, drvdata->bar0 + ADDR_LOAD_CALIBRATION_MOD); + iowrite32(config->nstorage_cells, drvdata->bar0 + ADDR_LOAD_CALIBRATION_SC); + iowrite32(0x1, drvdata->bar0 + ADDR_LOAD_CALIBRATION_CTRL); + + i = 0; + while (i < 1000) { + if (ioread32(drvdata->bar0 + ADDR_LOAD_CALIBRATION_CTRL) & (1 << 1)) + break; + msleep(10); + i++; + } + + // STOP H2C channel + iowrite32(0, drvdata->bar0 + PCIE_OFFSET + (0<<12) + 0x04); + + if (i == 1000) { + dev_err(dev, "Load calibration didn't finish in 10 seconds\n"); + return -ETIMEDOUT; + } + + return 0; +} + +int jfjoch_run_frame_gen(struct jfjoch_drvdata *drvdata, struct FrameGeneratorConfig *config) { + struct device *const dev = &drvdata->pdev->dev; + + if (ioread32(drvdata->bar0 + ADDR_FRAME_GEN_CTRL) & 0x1) { + dev_err(dev, "Frame generator busy\n"); + return -EBUSY; + } + + iowrite32(config->frames, drvdata->bar0 + ADDR_FRAME_GEN_FRAMES); + iowrite32(config->modules, drvdata->bar0 + ADDR_FRAME_GEN_MODULES); + iowrite32(config->dest_ipv4_addr, drvdata->bar0 + ADDR_FRAME_GEN_DEST_IPV4_ADDR); + iowrite32(config->dest_mac_addr & 0xFFFFFFFF, drvdata->bar0 + ADDR_FRAME_GEN_DEST_MAC_LO); + iowrite32(config->dest_mac_addr >> 32, drvdata->bar0 + ADDR_FRAME_GEN_DEST_MAC_HI); + iowrite32(config->bunchid & 0xFFFFFFFF, drvdata->bar0 + ADDR_FRAME_GEN_BUNCHID_LO); + iowrite32(config->bunchid >> 32, drvdata->bar0 + ADDR_FRAME_GEN_BUNCHID_HI); + iowrite32(config->exptime, drvdata->bar0 + ADDR_FRAME_GEN_EXPTIME); + iowrite32(config->debug, drvdata->bar0 + ADDR_FRAME_GEN_DEBUG); + iowrite32(0x1, drvdata->bar0 + ADDR_FRAME_GEN_CTRL); + return 0; } \ No newline at end of file diff --git a/receiver/pcie_driver/jfjoch_ioctl.c b/fpga/pcie_driver/jfjoch_ioctl.c similarity index 73% rename from receiver/pcie_driver/jfjoch_ioctl.c rename to fpga/pcie_driver/jfjoch_ioctl.c index ac899287..13411599 100644 --- a/receiver/pcie_driver/jfjoch_ioctl.c +++ b/fpga/pcie_driver/jfjoch_ioctl.c @@ -1,5 +1,4 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (2019-2023) Paul Scherrer Institute #include "jfjoch_drv.h" #include "jfjoch_ioctl.h" @@ -9,8 +8,10 @@ long jfjoch_cdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { struct ActionStatus status; struct ActionConfig config; struct ActionEnvParams env_params; + struct FrameGeneratorConfig frame_generator_config; u32 exchange[16]; int err; + void *tmp = NULL; switch (cmd) { case IOCTL_JFJOCH_START: @@ -37,6 +38,10 @@ long jfjoch_cdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { return -EFAULT; jfjoch_set_config(drvdata, &config); return 0; + case IOCTL_JFJOCH_LOAD_CALIB: + if (copy_from_user(&config, (char *) arg, sizeof(struct ActionConfig)) != 0) + return -EFAULT; + return jfjoch_load_calibration(drvdata, &config); case IOCTL_JFJOCH_GET_ENV_DATA: jfjoch_get_env_data(drvdata, &env_params); if (copy_to_user((char *) arg, &env_params, sizeof(struct ActionEnvParams)) != 0) @@ -96,6 +101,32 @@ long jfjoch_cdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { case IOCTL_JFJOCH_DEFAULT_MAC: jfjoch_read_mac_addr(drvdata); return 0; + case IOCTL_JFJOCH_RUN_FRAME_GEN: + if (copy_from_user(&frame_generator_config, (char *) arg, sizeof(struct FrameGeneratorConfig)) != 0) + return -EFAULT; + return jfjoch_run_frame_gen(drvdata, &frame_generator_config); + case IOCTL_JFJOCH_SET_INT_PKT: + tmp = vmalloc(INT_PKT_GEN_FRAME_SIZE_BYTES); + if (tmp == NULL) + return -ENOMEM; + if (copy_from_user(tmp, (char *) arg, INT_PKT_GEN_FRAME_SIZE_BYTES) != 0) { + vfree(tmp); + return -EFAULT; + } + jfjoch_save_int_pkt_gen(drvdata, tmp); + vfree(tmp); + return 0; + case IOCTL_JFJOCH_GET_INT_PKT: + tmp = vmalloc(INT_PKT_GEN_FRAME_SIZE_BYTES); + if (tmp == NULL) + return -ENOMEM; + jfjoch_load_int_pkt_gen(drvdata, tmp); + if (copy_to_user((char *) arg, tmp, INT_PKT_GEN_FRAME_SIZE_BYTES) != 0) { + vfree(tmp); + return -EFAULT; + } + vfree(tmp); + return 0; default: return -ENOTTY; } diff --git a/receiver/pcie_driver/jfjoch_ioctl.h b/fpga/pcie_driver/jfjoch_ioctl.h similarity index 80% rename from receiver/pcie_driver/jfjoch_ioctl.h rename to fpga/pcie_driver/jfjoch_ioctl.h index 3667db83..4d15f461 100644 --- a/receiver/pcie_driver/jfjoch_ioctl.h +++ b/fpga/pcie_driver/jfjoch_ioctl.h @@ -1,10 +1,9 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (2019-2023) Paul Scherrer Institute #ifndef JUNGFRAUJOCH_JFJOCH_IOCTL_H #define JUNGFRAUJOCH_JFJOCH_IOCTL_H -#include "../host/ActionConfig.h" +#include "ActionConfig.h" #ifdef __KERNEL__ #include @@ -33,5 +32,9 @@ #define IOCTL_JFJOCH_DEFAULT_MAC _IO (IOCTL_JFJOCH_MAGIC, 16) #define IOCTL_JFJOCH_SET_IPV4 _IOW(IOCTL_JFJOCH_MAGIC, 17, uint32_t) #define IOCTL_JFJOCH_GET_IPV4 _IOR(IOCTL_JFJOCH_MAGIC, 18, uint32_t) +#define IOCTL_JFJOCH_SET_INT_PKT _IOW(IOCTL_JFJOCH_MAGIC, 19, char *) +#define IOCTL_JFJOCH_GET_INT_PKT _IOR(IOCTL_JFJOCH_MAGIC, 20, char *) +#define IOCTL_JFJOCH_LOAD_CALIB _IOW(IOCTL_JFJOCH_MAGIC, 21, struct ActionConfig) +#define IOCTL_JFJOCH_RUN_FRAME_GEN _IOW(IOCTL_JFJOCH_MAGIC, 22, struct FrameGeneratorConfig) #endif //JUNGFRAUJOCH_JFJOCH_IOCTL_H diff --git a/receiver/pcie_driver/jfjoch_memory.c b/fpga/pcie_driver/jfjoch_memory.c similarity index 79% rename from receiver/pcie_driver/jfjoch_memory.c rename to fpga/pcie_driver/jfjoch_memory.c index b6f2e1c2..ffbec00c 100644 --- a/receiver/pcie_driver/jfjoch_memory.c +++ b/fpga/pcie_driver/jfjoch_memory.c @@ -1,5 +1,4 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (2019-2023) Paul Scherrer Institute #include "jfjoch_drv.h" #include "../../common/Definitions.h" @@ -53,25 +52,6 @@ void jfjoch_free_phys_continous_buf(struct pci_dev *pdev) { kfree(drvdata->bufs); } -int jfjoch_setup_calibration(struct pci_dev *pdev) { - struct jfjoch_drvdata *drvdata = pci_get_drvdata(pdev); - u32 i; - u32 cell_count = drvdata->max_modules * (3 + 3 * 16) + 1; - - if ((cell_count > nbuffer) || (cell_count >= LOAD_CALIBRATION_BRAM_SIZE)) { - dev_err(&pdev->dev, "Not enough buffers to support this card\n"); - return -EINVAL; - } - - for (i = 0; i < cell_count; i++) { - u64 addr = drvdata->bufs[i].dma_address; - iowrite32(PCI_DMA_L(addr), drvdata->bar0 + CALIB_BRAM_OFFSET + i * 2 * 4); - iowrite32(PCI_DMA_H(addr), drvdata->bar0 + CALIB_BRAM_OFFSET + (i * 2 + 1) * 4); - } - - return 0; -} - int jfjoch_cdev_mmap(struct file *file, struct vm_area_struct *vma) { unsigned long offset, buffer_number, len; diff --git a/receiver/pcie_driver/jfjoch_miscdev.c b/fpga/pcie_driver/jfjoch_miscdev.c similarity index 83% rename from receiver/pcie_driver/jfjoch_miscdev.c rename to fpga/pcie_driver/jfjoch_miscdev.c index d1840eb5..2ccb1e5e 100644 --- a/receiver/pcie_driver/jfjoch_miscdev.c +++ b/fpga/pcie_driver/jfjoch_miscdev.c @@ -1,5 +1,4 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (2019-2023) Paul Scherrer Institute #include "jfjoch_drv.h" #include @@ -33,5 +32,7 @@ int jfjoch_cdev_open(struct inode *inode, struct file *file) { } int jfjoch_cdev_release(struct inode *inode, struct file *file) { + struct jfjoch_drvdata *drvdata = container_of(file->private_data, struct jfjoch_drvdata, miscdev); + jfjoch_cancel(drvdata); return 0; } diff --git a/receiver/pcie_driver/jfjoch_pcie_setup.c b/fpga/pcie_driver/jfjoch_pcie_setup.c similarity index 95% rename from receiver/pcie_driver/jfjoch_pcie_setup.c rename to fpga/pcie_driver/jfjoch_pcie_setup.c index 5725347e..fa57e396 100644 --- a/receiver/pcie_driver/jfjoch_pcie_setup.c +++ b/fpga/pcie_driver/jfjoch_pcie_setup.c @@ -1,5 +1,4 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (2019-2023) Paul Scherrer Institute #include "jfjoch_drv.h" #include "../../common/Definitions.h" diff --git a/receiver/scripts/bd_pcie.tcl b/fpga/scripts/bd_pcie.tcl similarity index 55% rename from receiver/scripts/bd_pcie.tcl rename to fpga/scripts/bd_pcie.tcl index 224faf87..dff19983 100644 --- a/receiver/scripts/bd_pcie.tcl +++ b/fpga/scripts/bd_pcie.tcl @@ -1,5 +1,4 @@ -## Copyright (2019-2022) Paul Scherrer Institute -## SPDX-License-Identifier: CERN-OHL-S-2.0 +## Copyright (2019-2023) Paul Scherrer Institute ################################################################ # This is a generated script based on design: jfjoch_pcie @@ -143,20 +142,20 @@ xilinx.com:ip:xlconcat:2.1\ xilinx.com:ip:axi_protocol_converter:2.1\ xilinx.com:ip:axi_register_slice:2.1\ xilinx.com:ip:hbm:1.0\ -xilinx.com:ip:util_vector_logic:2.0\ xilinx.com:ip:axi_bram_ctrl:4.1\ xilinx.com:ip:axis_data_fifo:2.0\ xilinx.com:ip:axis_register_slice:1.1\ -xilinx.com:ip:blk_mem_gen:8.4\ psi.ch:hls:data_collection_fsm:1.0\ +psi.ch:hls:frame_generator:1.0\ psi.ch:hls:host_writer:1.0\ -psi.ch:hls:internal_packet_generator:1.0\ +xilinx.com:ip:blk_mem_gen:8.4\ psi.ch:hls:jf_conversion:1.0\ psi.ch:hls:load_calibration:1.0\ xilinx.com:ip:mailbox:2.1\ -psi.ch:hls:timer_hbm:1.0\ +psi.ch:hls:stream_merge:1.0\ psi.ch:hls:timer_host:1.0\ xilinx.com:ip:cmac_usplus:3.1\ +xilinx.com:ip:util_vector_logic:2.0\ xilinx.com:ip:axi_firewall:1.2\ xilinx.com:ip:axis_clock_converter:1.1\ xilinx.com:ip:util_ds_buf:2.2\ @@ -224,99 +223,6 @@ if { $bCheckIPsPassed != 1 } { # DESIGN PROCs ################################################################## - -# Hierarchical cell: gain_uram_0 -proc create_hier_cell_gain_uram_0 { parentCell nameHier } { - - variable script_folder - - if { $parentCell eq "" || $nameHier eq "" } { - catch {common::send_gid_msg -ssname BD::TCL -id 2092 -severity "ERROR" "create_hier_cell_gain_uram_0() - Empty argument(s)!"} - return - } - - # Get object for parentCell - set parentObj [get_bd_cells $parentCell] - if { $parentObj == "" } { - catch {common::send_gid_msg -ssname BD::TCL -id 2090 -severity "ERROR" "Unable to find parent cell <$parentCell>!"} - return - } - - # Make sure parentObj is hier blk - set parentType [get_property TYPE $parentObj] - if { $parentType ne "hier" } { - catch {common::send_gid_msg -ssname BD::TCL -id 2091 -severity "ERROR" "Parent <$parentObj> has TYPE = <$parentType>. Expected to be ."} - return - } - - # Save current instance; Restore later - set oldCurInst [current_bd_instance .] - - # Set parent object as current - current_bd_instance $parentObj - - # Create cell and set as current instance - set hier_obj [create_bd_cell -type hier $nameHier] - current_bd_instance $hier_obj - - # Create interface pins - create_bd_intf_pin -mode Slave -vlnv xilinx.com:interface:aximm_rtl:1.0 s_axi - - - # Create pins - create_bd_pin -dir I axi_aresetn - create_bd_pin -dir I axi_clk - - # Create instance: axi_bram_ctrl_0, and set properties - set axi_bram_ctrl_0 [ create_bd_cell -type ip -vlnv xilinx.com:ip:axi_bram_ctrl:4.1 axi_bram_ctrl_0 ] - set_property -dict [ list \ - CONFIG.DATA_WIDTH {256} \ - CONFIG.READ_LATENCY {3} \ - ] $axi_bram_ctrl_0 - - # Create instance: axi_register_slice_0, and set properties - set axi_register_slice_0 [ create_bd_cell -type ip -vlnv xilinx.com:ip:axi_register_slice:2.1 axi_register_slice_0 ] - set_property -dict [ list \ - CONFIG.REG_AR {15} \ - CONFIG.REG_AW {15} \ - CONFIG.REG_B {15} \ - CONFIG.REG_R {15} \ - CONFIG.REG_W {15} \ - CONFIG.USE_AUTOPIPELINING {1} \ - ] $axi_register_slice_0 - - # Create instance: blk_mem_gen_0, and set properties - set blk_mem_gen_0 [ create_bd_cell -type ip -vlnv xilinx.com:ip:blk_mem_gen:8.4 blk_mem_gen_0 ] - set_property -dict [ list \ - CONFIG.Assume_Synchronous_Clk {true} \ - CONFIG.EN_SAFETY_CKT {false} \ - CONFIG.Enable_B {Use_ENB_Pin} \ - CONFIG.Memory_Type {True_Dual_Port_RAM} \ - CONFIG.Operating_Mode_A {NO_CHANGE} \ - CONFIG.Operating_Mode_B {NO_CHANGE} \ - CONFIG.PRIM_type_to_Implement {URAM} \ - CONFIG.Port_B_Clock {100} \ - CONFIG.Port_B_Enable_Rate {100} \ - CONFIG.Port_B_Write_Rate {50} \ - CONFIG.READ_LATENCY_A {3} \ - CONFIG.READ_LATENCY_B {3} \ - CONFIG.Use_RSTB_Pin {true} \ - ] $blk_mem_gen_0 - - # Create interface connections - connect_bd_intf_net -intf_net axi_bram_ctrl_0_BRAM_PORTA [get_bd_intf_pins axi_bram_ctrl_0/BRAM_PORTA] [get_bd_intf_pins blk_mem_gen_0/BRAM_PORTA] - connect_bd_intf_net -intf_net axi_bram_ctrl_0_BRAM_PORTB [get_bd_intf_pins axi_bram_ctrl_0/BRAM_PORTB] [get_bd_intf_pins blk_mem_gen_0/BRAM_PORTB] - connect_bd_intf_net -intf_net axi_register_slice_0_M_AXI [get_bd_intf_pins axi_bram_ctrl_0/S_AXI] [get_bd_intf_pins axi_register_slice_0/M_AXI] - connect_bd_intf_net -intf_net s_axi_1 [get_bd_intf_pins s_axi] [get_bd_intf_pins axi_register_slice_0/S_AXI] - - # Create port connections - connect_bd_net -net axi_aresetn_1 [get_bd_pins axi_aresetn] [get_bd_pins axi_bram_ctrl_0/s_axi_aresetn] [get_bd_pins axi_register_slice_0/aresetn] - connect_bd_net -net axi_clk_1 [get_bd_pins axi_clk] [get_bd_pins axi_bram_ctrl_0/s_axi_aclk] [get_bd_pins axi_register_slice_0/aclk] - - # Restore current instance - current_bd_instance $oldCurInst -} - # Procedure to create entire design; Provide argument to make # procedure reusable. If parentCell is "", will use root. proc create_root_design { parentCell } { @@ -354,10 +260,6 @@ proc create_root_design { parentCell } { set pcie0_ref [ create_bd_intf_port -mode Slave -vlnv xilinx.com:interface:diff_clock_rtl:1.0 pcie0_ref ] - set pcie1_mgt [ create_bd_intf_port -mode Master -vlnv xilinx.com:interface:pcie_7x_mgt_rtl:1.0 pcie1_mgt ] - - set pcie1_ref [ create_bd_intf_port -mode Slave -vlnv xilinx.com:interface:diff_clock_rtl:1.0 pcie1_ref ] - set qsfp0 [ create_bd_intf_port -mode Master -vlnv xilinx.com:interface:gt_rtl:1.0 qsfp0 ] set qsfp0_ref [ create_bd_intf_port -mode Slave -vlnv xilinx.com:interface:diff_clock_rtl:1.0 qsfp0_ref ] @@ -365,13 +267,6 @@ proc create_root_design { parentCell } { CONFIG.FREQ_HZ {161132812} \ ] $qsfp0_ref - set qsfp1 [ create_bd_intf_port -mode Master -vlnv xilinx.com:interface:gt_rtl:1.0 qsfp1 ] - - set qsfp1_ref [ create_bd_intf_port -mode Slave -vlnv xilinx.com:interface:diff_clock_rtl:1.0 qsfp1_ref ] - set_property -dict [ list \ - CONFIG.FREQ_HZ {161132812} \ - ] $qsfp1_ref - set ref100 [ create_bd_intf_port -mode Slave -vlnv xilinx.com:interface:diff_clock_rtl:1.0 ref100 ] set_property -dict [ list \ CONFIG.FREQ_HZ {100000000} \ @@ -385,8 +280,6 @@ proc create_root_design { parentCell } { set pcie_perstn [ create_bd_port -dir I -type rst pcie_perstn ] set qsfp0_led_busy [ create_bd_port -dir O -from 0 -to 0 qsfp0_led_busy ] set qsfp0_led_conn [ create_bd_port -dir O -from 0 -to 0 qsfp0_led_conn ] - set qsfp1_led_busy [ create_bd_port -dir O -from 0 -to 0 qsfp1_led_busy ] - set qsfp1_led_conn [ create_bd_port -dir O -from 0 -to 0 qsfp1_led_conn ] set satellite_gpio_0 [ create_bd_port -dir I -from 3 -to 0 -type intr satellite_gpio_0 ] set_property -dict [ list \ CONFIG.PortWidth {4} \ @@ -400,13 +293,6 @@ proc create_root_design { parentCell } { CONFIG.C_NUM_SW_INTR {2} \ ] $axi_intc_0 - # Create instance: axi_intc_1, and set properties - set axi_intc_1 [ create_bd_cell -type ip -vlnv xilinx.com:ip:axi_intc:4.1 axi_intc_1 ] - set_property -dict [ list \ - CONFIG.C_IRQ_CONNECTION {1} \ - CONFIG.C_NUM_SW_INTR {2} \ - ] $axi_intc_1 - # Create instance: axi_quad_spi_0, and set properties set axi_quad_spi_0 [ create_bd_cell -type ip -vlnv xilinx.com:ip:axi_quad_spi:3.2 axi_quad_spi_0 ] set_property -dict [ list \ @@ -444,72 +330,33 @@ proc create_root_design { parentCell } { # Create instance: cms_subsystem_0, and set properties set cms_subsystem_0 [ create_bd_cell -type ip -vlnv xilinx.com:ip:cms_subsystem:4.0 cms_subsystem_0 ] - # Create instance: gain_uram_0 - create_hier_cell_gain_uram_0 [current_bd_instance .] gain_uram_0 - - # Create instance: gain_uram_1 - create_hier_cell_gain_uram_0 [current_bd_instance .] gain_uram_1 - - # Create instance: gain_uram_2 - create_hier_cell_gain_uram_0 [current_bd_instance .] gain_uram_2 - - # Create instance: gain_uram_3 - create_hier_cell_gain_uram_0 [current_bd_instance .] gain_uram_3 - - # Create instance: gain_uram_4 - create_hier_cell_gain_uram_0 [current_bd_instance .] gain_uram_4 - - # Create instance: gain_uram_5 - create_hier_cell_gain_uram_0 [current_bd_instance .] gain_uram_5 - # Create instance: hbm_infrastructure create_hier_cell_hbm_infrastructure [current_bd_instance .] hbm_infrastructure # Create instance: jungfraujoch_0 create_hier_cell_jungfraujoch [current_bd_instance .] jungfraujoch_0 - # Create instance: jungfraujoch_1 - create_hier_cell_jungfraujoch [current_bd_instance .] jungfraujoch_1 - # Create instance: mac_100g create_hier_cell_mac_100g [current_bd_instance .] mac_100g - # Create instance: mac_100g_1 - create_hier_cell_mac_100g [current_bd_instance .] mac_100g_1 - # Create instance: one, and set properties set one [ create_bd_cell -type ip -vlnv xilinx.com:ip:xlconstant:1.1 one ] # Create instance: pcie_dma_0 create_hier_cell_pcie_dma_0 [current_bd_instance .] pcie_dma_0 - # Create instance: pcie_dma_1 - create_hier_cell_pcie_dma_1 [current_bd_instance .] pcie_dma_1 - # Create instance: proc_sys_reset_pcie_0, and set properties set proc_sys_reset_pcie_0 [ create_bd_cell -type ip -vlnv xilinx.com:ip:proc_sys_reset:5.0 proc_sys_reset_pcie_0 ] set_property -dict [ list \ CONFIG.C_EXT_RST_WIDTH {1} \ ] $proc_sys_reset_pcie_0 - # Create instance: proc_sys_reset_pcie_1, and set properties - set proc_sys_reset_pcie_1 [ create_bd_cell -type ip -vlnv xilinx.com:ip:proc_sys_reset:5.0 proc_sys_reset_pcie_1 ] - set_property -dict [ list \ - CONFIG.C_EXT_RST_WIDTH {1} \ - ] $proc_sys_reset_pcie_1 - # Create instance: proc_sys_reset_refclk, and set properties set proc_sys_reset_refclk [ create_bd_cell -type ip -vlnv xilinx.com:ip:proc_sys_reset:5.0 proc_sys_reset_refclk ] set_property -dict [ list \ CONFIG.C_EXT_RST_WIDTH {1} \ ] $proc_sys_reset_refclk - # Create instance: proc_sys_reset_refclk1, and set properties - set proc_sys_reset_refclk1 [ create_bd_cell -type ip -vlnv xilinx.com:ip:proc_sys_reset:5.0 proc_sys_reset_refclk1 ] - set_property -dict [ list \ - CONFIG.C_EXT_RST_WIDTH {1} \ - ] $proc_sys_reset_refclk1 - # Create instance: smartconnect_0, and set properties set smartconnect_0 [ create_bd_cell -type ip -vlnv xilinx.com:ip:smartconnect:1.0 smartconnect_0 ] set_property -dict [ list \ @@ -518,20 +365,6 @@ proc create_root_design { parentCell } { CONFIG.NUM_SI {1} \ ] $smartconnect_0 - # Create instance: smartconnect_1, and set properties - set smartconnect_1 [ create_bd_cell -type ip -vlnv xilinx.com:ip:smartconnect:1.0 smartconnect_1 ] - set_property -dict [ list \ - CONFIG.NUM_CLKS {4} \ - CONFIG.NUM_MI {5} \ - CONFIG.NUM_SI {1} \ - ] $smartconnect_1 - - # Create instance: smartconnect_2, and set properties - set smartconnect_2 [ create_bd_cell -type ip -vlnv xilinx.com:ip:smartconnect:1.0 smartconnect_2 ] - set_property -dict [ list \ - CONFIG.NUM_CLKS {3} \ - ] $smartconnect_2 - # Create instance: xlconcat_irq, and set properties set xlconcat_irq [ create_bd_cell -type ip -vlnv xilinx.com:ip:xlconcat:2.1 xlconcat_irq ] @@ -559,82 +392,42 @@ proc create_root_design { parentCell } { connect_bd_intf_net -intf_net jungfraujoch_0_m_axis_c2h_data [get_bd_intf_pins jungfraujoch_0/m_axis_c2h_data] [get_bd_intf_pins pcie_dma_0/s_axis_c2h_data] connect_bd_intf_net -intf_net jungfraujoch_0_m_axis_c2h_datamover_cmd [get_bd_intf_pins jungfraujoch_0/m_axis_c2h_datamover_cmd] [get_bd_intf_pins pcie_dma_0/s_axis_c2h_cmd] connect_bd_intf_net -intf_net jungfraujoch_0_m_axis_h2c_datamover_cmd [get_bd_intf_pins jungfraujoch_0/m_axis_h2c_datamover_cmd] [get_bd_intf_pins pcie_dma_0/s_axis_h2c_cmd] - connect_bd_intf_net -intf_net jungfraujoch_1_m_axis_c2h_data [get_bd_intf_pins jungfraujoch_1/m_axis_c2h_data] [get_bd_intf_pins pcie_dma_1/s_axis_c2h_data] - connect_bd_intf_net -intf_net jungfraujoch_1_m_axis_c2h_datamover_cmd [get_bd_intf_pins jungfraujoch_1/m_axis_c2h_datamover_cmd] [get_bd_intf_pins pcie_dma_1/s_axis_c2h_cmd] - connect_bd_intf_net -intf_net jungfraujoch_1_m_axis_h2c_datamover_cmd [get_bd_intf_pins jungfraujoch_1/m_axis_h2c_datamover_cmd] [get_bd_intf_pins pcie_dma_1/s_axis_h2c_cmd] connect_bd_intf_net -intf_net mac_100g_1_M_AXIS_100G [get_bd_intf_pins jungfraujoch_0/eth_in] [get_bd_intf_pins mac_100g/m_axis_eth_in] - connect_bd_intf_net -intf_net mac_100g_1_m_axis_eth_in [get_bd_intf_pins jungfraujoch_1/eth_in] [get_bd_intf_pins mac_100g_1/m_axis_eth_in] connect_bd_intf_net -intf_net mac_100g_1_qsfp0 [get_bd_intf_ports qsfp0] [get_bd_intf_pins mac_100g/qsfp] - connect_bd_intf_net -intf_net mac_100g_1_qsfp1 [get_bd_intf_ports qsfp1] [get_bd_intf_pins mac_100g_1/qsfp] connect_bd_intf_net -intf_net pcie0_ref_1 [get_bd_intf_ports pcie0_ref] [get_bd_intf_pins pcie_dma_0/pcie_refclk] - connect_bd_intf_net -intf_net pcie1_ref_1 [get_bd_intf_ports pcie1_ref] [get_bd_intf_pins pcie_dma_1/pcie_refclk] connect_bd_intf_net -intf_net pcie_dma_0_M_AXI [get_bd_intf_pins pcie_dma_0/m_axi_ctrl] [get_bd_intf_pins smartconnect_0/S00_AXI] connect_bd_intf_net -intf_net pcie_dma_0_pcie0_mgt [get_bd_intf_ports pcie0_mgt] [get_bd_intf_pins pcie_dma_0/pcie_mgt] - connect_bd_intf_net -intf_net pcie_dma_1_m_axi_ctrl [get_bd_intf_pins pcie_dma_1/m_axi_ctrl] [get_bd_intf_pins smartconnect_1/S00_AXI] - connect_bd_intf_net -intf_net pcie_dma_1_pcie_mgt [get_bd_intf_ports pcie1_mgt] [get_bd_intf_pins pcie_dma_1/pcie_mgt] connect_bd_intf_net -intf_net qsfp0_ref_1 [get_bd_intf_ports qsfp0_ref] [get_bd_intf_pins mac_100g/qsfp_ref] - connect_bd_intf_net -intf_net qsfp1_ref_1 [get_bd_intf_ports qsfp1_ref] [get_bd_intf_pins mac_100g_1/qsfp_ref] connect_bd_intf_net -intf_net ref100_1 [get_bd_intf_ports ref100] [get_bd_intf_pins clk_wiz_0/CLK_IN1_D] connect_bd_intf_net -intf_net s_axi_1 [get_bd_intf_pins jungfraujoch_0/s_axi] [get_bd_intf_pins smartconnect_0/M00_AXI] connect_bd_intf_net -intf_net s_axi_2 [get_bd_intf_pins mac_100g/s_axi] [get_bd_intf_pins smartconnect_0/M02_AXI] - connect_bd_intf_net -intf_net s_axi_3 [get_bd_intf_pins jungfraujoch_1/s_axi] [get_bd_intf_pins smartconnect_1/M00_AXI] - connect_bd_intf_net -intf_net jungfraujoch_1_m_axi_d_hbm_p0 [get_bd_intf_pins gain_uram_0/s_axi] [get_bd_intf_pins jungfraujoch_1/m_axi_d_hbm_p0] - connect_bd_intf_net -intf_net jungfraujoch_1_m_axi_d_hbm_p1 [get_bd_intf_pins gain_uram_1/s_axi] [get_bd_intf_pins jungfraujoch_1/m_axi_d_hbm_p1] - connect_bd_intf_net -intf_net jungfraujoch_1_m_axi_d_hbm_p2 [get_bd_intf_pins gain_uram_2/s_axi] [get_bd_intf_pins jungfraujoch_1/m_axi_d_hbm_p2] - connect_bd_intf_net -intf_net jungfraujoch_1_m_axi_d_hbm_p3 [get_bd_intf_pins gain_uram_3/s_axi] [get_bd_intf_pins jungfraujoch_1/m_axi_d_hbm_p3] - connect_bd_intf_net -intf_net jungfraujoch_1_m_axi_d_hbm_p4 [get_bd_intf_pins gain_uram_4/s_axi] [get_bd_intf_pins jungfraujoch_1/m_axi_d_hbm_p4] - connect_bd_intf_net -intf_net jungfraujoch_1_m_axi_d_hbm_p5 [get_bd_intf_pins gain_uram_5/s_axi] [get_bd_intf_pins jungfraujoch_1/m_axi_d_hbm_p5] - connect_bd_intf_net -intf_net jungfraujoch_1_m_axi_d_hbm_p6 [get_bd_intf_pins hbm_infrastructure/s_axi_hbm_12] [get_bd_intf_pins jungfraujoch_1/m_axi_d_hbm_p6] - connect_bd_intf_net -intf_net jungfraujoch_1_m_axi_d_hbm_p7 [get_bd_intf_pins hbm_infrastructure/s_axi_hbm_13] [get_bd_intf_pins jungfraujoch_1/m_axi_d_hbm_p7] - connect_bd_intf_net -intf_net jungfraujoch_1_m_axi_d_hbm_p8 [get_bd_intf_pins hbm_infrastructure/s_axi_hbm_14] [get_bd_intf_pins jungfraujoch_1/m_axi_d_hbm_p8] - connect_bd_intf_net -intf_net jungfraujoch_1_m_axi_d_hbm_p9 [get_bd_intf_pins hbm_infrastructure/s_axi_hbm_15] [get_bd_intf_pins jungfraujoch_1/m_axi_d_hbm_p9] - connect_bd_intf_net -intf_net jungfraujoch_1_m_axi_d_hbm_p10 [get_bd_intf_pins hbm_infrastructure/s_axi_hbm_16] [get_bd_intf_pins jungfraujoch_1/m_axi_d_hbm_p10] - connect_bd_intf_net -intf_net jungfraujoch_1_m_axi_d_hbm_p11 [get_bd_intf_pins hbm_infrastructure/s_axi_hbm_17] [get_bd_intf_pins jungfraujoch_1/m_axi_d_hbm_p11] - connect_bd_intf_net -intf_net s_axis_eth_out_1 [get_bd_intf_pins jungfraujoch_1/eth_out] [get_bd_intf_pins mac_100g_1/s_axis_eth_out] connect_bd_intf_net -intf_net s_axis_h2c_data_1 [get_bd_intf_pins jungfraujoch_0/s_axis_h2c_data] [get_bd_intf_pins pcie_dma_0/m_axis_h2c_data] - connect_bd_intf_net -intf_net s_axis_h2c_data_2 [get_bd_intf_pins jungfraujoch_1/s_axis_h2c_data] [get_bd_intf_pins pcie_dma_1/m_axis_h2c_data] - connect_bd_intf_net -intf_net smartconnect_0_M01_AXI [get_bd_intf_pins smartconnect_0/M01_AXI] [get_bd_intf_pins smartconnect_2/S01_AXI] + connect_bd_intf_net -intf_net smartconnect_0_M01_AXI [get_bd_intf_pins smartconnect_0/M01_AXI] [get_bd_intf_pins cms_subsystem_0/s_axi_ctrl] connect_bd_intf_net -intf_net smartconnect_0_M03_AXI [get_bd_intf_pins axi_quad_spi_0/AXI_LITE] [get_bd_intf_pins smartconnect_0/M03_AXI] connect_bd_intf_net -intf_net smartconnect_0_M04_AXI [get_bd_intf_pins axi_intc_0/s_axi] [get_bd_intf_pins smartconnect_0/M04_AXI] connect_bd_intf_net -intf_net smartconnect_0_M05_AXI [get_bd_intf_pins pcie_dma_0/s_axi_dma_ctrl] [get_bd_intf_pins smartconnect_0/M05_AXI] - connect_bd_intf_net -intf_net smartconnect_1_M01_AXI [get_bd_intf_pins mac_100g_1/s_axi] [get_bd_intf_pins smartconnect_1/M01_AXI] - connect_bd_intf_net -intf_net smartconnect_1_M02_AXI [get_bd_intf_pins pcie_dma_1/s_axi_dma_ctrl] [get_bd_intf_pins smartconnect_1/M02_AXI] - connect_bd_intf_net -intf_net smartconnect_1_M03_AXI [get_bd_intf_pins smartconnect_1/M03_AXI] [get_bd_intf_pins smartconnect_2/S00_AXI] - connect_bd_intf_net -intf_net smartconnect_1_M04_AXI [get_bd_intf_pins axi_intc_1/s_axi] [get_bd_intf_pins smartconnect_1/M04_AXI] - connect_bd_intf_net -intf_net smartconnect_2_M00_AXI [get_bd_intf_pins cms_subsystem_0/s_axi_ctrl] [get_bd_intf_pins smartconnect_2/M00_AXI] # Create port connections - connect_bd_net -net axi_clk_1 [get_bd_pins pcie_dma_0/axi_aclk] [get_bd_pins proc_sys_reset_pcie_0/slowest_sync_clk] [get_bd_pins smartconnect_0/aclk3] [get_bd_pins smartconnect_2/aclk1] + connect_bd_net -net axi_clk_1 [get_bd_pins pcie_dma_0/axi_aclk] [get_bd_pins proc_sys_reset_pcie_0/slowest_sync_clk] [get_bd_pins smartconnect_0/aclk3] connect_bd_net -net axi_quad_spi_0_ip2intc_irpt [get_bd_pins axi_quad_spi_0/ip2intc_irpt] [get_bd_pins xlconcat_irq/In0] connect_bd_net -net cms_subsystem_0_interrupt_host [get_bd_pins cms_subsystem_0/interrupt_host] [get_bd_pins xlconcat_irq/In1] - connect_bd_net -net hbm_infrastructure_apb_complete_0 [get_bd_pins hbm_infrastructure/apb_complete_0] [get_bd_pins jungfraujoch_0/apb_complete] - connect_bd_net -net hbm_infrastructure_apb_complete_1 [get_bd_pins hbm_infrastructure/apb_complete_1] [get_bd_pins jungfraujoch_1/apb_complete] connect_bd_net -net hbm_infrastructure_hbm_temp_trip_1 [get_bd_ports hbm_cattrip] [get_bd_pins cms_subsystem_0/interrupt_hbm_cattrip] [get_bd_pins hbm_infrastructure/hbm_cattrip] connect_bd_net -net hbm_infrastructure_hbm_temperature_1 [get_bd_pins cms_subsystem_0/hbm_temp_1] [get_bd_pins hbm_infrastructure/hbm_temperature_0] - connect_bd_net -net hbm_infrastructure_hbm_temperature_2 [get_bd_pins cms_subsystem_0/hbm_temp_2] [get_bd_pins hbm_infrastructure/hbm_temperature_1] - connect_bd_net -net mac_100g_1_eth_busy_n [get_bd_ports qsfp1_led_busy] [get_bd_pins mac_100g_1/eth_busy_n] - connect_bd_net -net mac_100g_1_stat_rx_aligned_n [get_bd_ports qsfp1_led_conn] [get_bd_pins mac_100g_1/stat_rx_aligned_n] connect_bd_net -net mac_100g_eth_busy_n [get_bd_ports qsfp0_led_busy] [get_bd_pins mac_100g/eth_busy_n] connect_bd_net -net mac_100g_stat_rx_aligned_n [get_bd_ports qsfp0_led_conn] [get_bd_pins mac_100g/stat_rx_aligned_n] - connect_bd_net -net net_refclk50 [get_bd_pins axi_intc_0/s_axi_aclk] [get_bd_pins axi_intc_1/s_axi_aclk] [get_bd_pins axi_quad_spi_0/s_axi_aclk] [get_bd_pins clk_wiz_0/clk_out1] [get_bd_pins cms_subsystem_0/aclk_ctrl] [get_bd_pins proc_sys_reset_refclk/slowest_sync_clk] [get_bd_pins proc_sys_reset_refclk1/slowest_sync_clk] [get_bd_pins smartconnect_0/aclk2] [get_bd_pins smartconnect_1/aclk1] [get_bd_pins smartconnect_2/aclk] - connect_bd_net -net net_refclk100 [get_bd_pins axi_quad_spi_0/ext_spi_clk] [get_bd_pins clk_wiz_0/clk_out2] [get_bd_pins hbm_infrastructure/refclk100] [get_bd_pins mac_100g/refclk100] [get_bd_pins mac_100g_1/refclk100] [get_bd_pins smartconnect_0/aclk1] [get_bd_pins smartconnect_1/aclk2] - connect_bd_net -net net_refclk200 [get_bd_pins clk_wiz_0/clk_out3] [get_bd_pins gain_uram_0/axi_clk] [get_bd_pins gain_uram_1/axi_clk] [get_bd_pins gain_uram_2/axi_clk] [get_bd_pins gain_uram_3/axi_clk] [get_bd_pins gain_uram_4/axi_clk] [get_bd_pins gain_uram_5/axi_clk] [get_bd_pins hbm_infrastructure/axi_clk] [get_bd_pins jungfraujoch_0/axi_clk] [get_bd_pins jungfraujoch_1/axi_clk] [get_bd_pins mac_100g/axiclk] [get_bd_pins mac_100g_1/axiclk] [get_bd_pins pcie_dma_0/refclk200] [get_bd_pins pcie_dma_1/refclk200] [get_bd_pins smartconnect_0/aclk] [get_bd_pins smartconnect_1/aclk] - connect_bd_net -net one_dout [get_bd_pins one/dout] [get_bd_pins cms_subsystem_0/aresetn_ctrl] [get_bd_pins smartconnect_2/aresetn] [get_bd_pins proc_sys_reset_pcie_0/dcm_locked] [get_bd_pins proc_sys_reset_pcie_1/dcm_locked] [get_bd_pins proc_sys_reset_refclk/dcm_locked] [get_bd_pins proc_sys_reset_refclk1/dcm_locked] + connect_bd_net -net net_refclk50 [get_bd_pins axi_intc_0/s_axi_aclk] [get_bd_pins axi_intc_1/s_axi_aclk] [get_bd_pins axi_quad_spi_0/s_axi_aclk] [get_bd_pins clk_wiz_0/clk_out1] [get_bd_pins cms_subsystem_0/aclk_ctrl] [get_bd_pins proc_sys_reset_refclk/slowest_sync_clk] [get_bd_pins proc_sys_reset_refclk1/slowest_sync_clk] [get_bd_pins smartconnect_0/aclk2] + connect_bd_net -net net_refclk100 [get_bd_pins axi_quad_spi_0/ext_spi_clk] [get_bd_pins clk_wiz_0/clk_out2] [get_bd_pins hbm_infrastructure/refclk100] [get_bd_pins mac_100g/refclk100] [get_bd_pins smartconnect_0/aclk1] + connect_bd_net -net net_refclk200 [get_bd_pins clk_wiz_0/clk_out3] [get_bd_pins hbm_infrastructure/axi_clk] [get_bd_pins jungfraujoch_0/axi_clk] [get_bd_pins mac_100g/axiclk] [get_bd_pins pcie_dma_0/refclk200] [get_bd_pins smartconnect_0/aclk] + connect_bd_net -net one_dout [get_bd_pins one/dout] [get_bd_pins cms_subsystem_0/aresetn_ctrl] [get_bd_pins proc_sys_reset_pcie_0/dcm_locked] [get_bd_pins proc_sys_reset_refclk/dcm_locked] connect_bd_net -net pcie_dma_0_axi_aresetn [get_bd_pins pcie_dma_0/axi_aresetn] [get_bd_pins proc_sys_reset_pcie_0/ext_reset_in] [get_bd_pins proc_sys_reset_refclk/ext_reset_in] [get_bd_pins smartconnect_0/aresetn] - connect_bd_net -net pcie_dma_1_axi_aclk [get_bd_pins pcie_dma_1/axi_aclk] [get_bd_pins proc_sys_reset_pcie_1/slowest_sync_clk] [get_bd_pins smartconnect_1/aclk3] [get_bd_pins smartconnect_2/aclk2] - connect_bd_net -net pcie_dma_1_axi_aresetn [get_bd_pins pcie_dma_1/axi_aresetn] [get_bd_pins proc_sys_reset_pcie_1/ext_reset_in] [get_bd_pins proc_sys_reset_refclk1/ext_reset_in] [get_bd_pins smartconnect_1/aresetn] - connect_bd_net -net pcie_perstn_1 [get_bd_ports pcie_perstn] [get_bd_pins pcie_dma_0/pcie_perstn] [get_bd_pins pcie_dma_1/pcie_perstn] + connect_bd_net -net pcie_perstn_1 [get_bd_ports pcie_perstn] [get_bd_pins pcie_dma_0/pcie_perstn] connect_bd_net -net proc_sys_reset_pcie_0_interconnect_aresetn [get_bd_pins pcie_dma_0/axi_clk_resetn] [get_bd_pins proc_sys_reset_pcie_0/interconnect_aresetn] - connect_bd_net -net proc_sys_reset_pcie_1_interconnect_aresetn [get_bd_pins pcie_dma_1/axi_clk_resetn] [get_bd_pins proc_sys_reset_pcie_1/interconnect_aresetn] - connect_bd_net -net proc_sys_reset_refclk1_interconnect_aresetn [get_bd_pins gain_uram_0/axi_aresetn] [get_bd_pins gain_uram_1/axi_aresetn] [get_bd_pins gain_uram_2/axi_aresetn] [get_bd_pins gain_uram_3/axi_aresetn] [get_bd_pins gain_uram_4/axi_aresetn] [get_bd_pins gain_uram_5/axi_aresetn] [get_bd_pins jungfraujoch_1/axi_rst_n] [get_bd_pins mac_100g_1/ap_rst_n] [get_bd_pins pcie_dma_1/refclk200_resetn] [get_bd_pins proc_sys_reset_refclk1/interconnect_aresetn] - connect_bd_net -net proc_sys_reset_refclk1_peripheral_aresetn [get_bd_pins axi_intc_1/s_axi_aresetn] [get_bd_pins hbm_infrastructure/axi_resetn_1] [get_bd_pins jungfraujoch_1/ap_rst_n] [get_bd_pins mac_100g_1/resetn] [get_bd_pins proc_sys_reset_refclk1/peripheral_aresetn] connect_bd_net -net proc_sys_reset_refclk_peripheral_aresetn [get_bd_pins axi_intc_0/s_axi_aresetn] [get_bd_pins axi_quad_spi_0/s_axi_aresetn] [get_bd_pins hbm_infrastructure/axi_resetn] [get_bd_pins jungfraujoch_0/ap_rst_n] [get_bd_pins mac_100g/ap_rst_n] [get_bd_pins proc_sys_reset_refclk/peripheral_aresetn] connect_bd_net -net resetn_1 [get_bd_pins jungfraujoch_0/axi_rst_n] [get_bd_pins mac_100g/resetn] [get_bd_pins pcie_dma_0/refclk200_resetn] [get_bd_pins proc_sys_reset_refclk/interconnect_aresetn] connect_bd_net -net satellite_gpio_0_1 [get_bd_ports satellite_gpio_0] [get_bd_pins cms_subsystem_0/satellite_gpio] connect_bd_net -net usr_irq_req_1 [get_bd_pins axi_intc_0/irq] [get_bd_pins pcie_dma_0/usr_irq_req] - connect_bd_net -net usr_irq_req_2 [get_bd_pins axi_intc_1/irq] [get_bd_pins pcie_dma_1/usr_irq_req] connect_bd_net -net xlconcat_irq_dout [get_bd_pins axi_intc_0/intr] [get_bd_pins axi_intc_1/intr] [get_bd_pins xlconcat_irq/dout] - connect_bd_net -net zero_dout [get_bd_pins axi_quad_spi_0/usrcclkts] [get_bd_pins jungfraujoch_0/eth_busy] [get_bd_pins jungfraujoch_0/eth_stat_rx_aligned] [get_bd_pins jungfraujoch_0/eth_stat_rx_packet_bad_fcs] [get_bd_pins jungfraujoch_0/eth_stat_rx_status] [get_bd_pins jungfraujoch_0/hbm_temp_trip] [get_bd_pins jungfraujoch_0/hbm_temperature] [get_bd_pins jungfraujoch_0/mm2s_error] [get_bd_pins jungfraujoch_0/s2mm_error] [get_bd_pins jungfraujoch_1/eth_busy] [get_bd_pins jungfraujoch_1/eth_stat_rx_aligned] [get_bd_pins jungfraujoch_1/eth_stat_rx_packet_bad_fcs] [get_bd_pins jungfraujoch_1/eth_stat_rx_status] [get_bd_pins jungfraujoch_1/hbm_temp_trip] [get_bd_pins jungfraujoch_1/hbm_temperature] [get_bd_pins jungfraujoch_1/mm2s_error] [get_bd_pins jungfraujoch_1/s2mm_error] [get_bd_pins zero/dout] + connect_bd_net -net zero_dout [get_bd_pins axi_quad_spi_0/usrcclkts] [get_bd_pins zero/dout] [get_bd_pins cms_subsystem_0/hbm_temp_2] # Create address segments assign_bd_address -offset 0x00010000 -range 0x00010000 -target_address_space [get_bd_addr_spaces pcie_dma_0/xdma_0/M_AXI_LITE] [get_bd_addr_segs jungfraujoch_0/action_config_0/s_axi/reg0] -force @@ -642,48 +435,21 @@ proc create_root_design { parentCell } { assign_bd_address -offset 0x00030000 -range 0x00010000 -target_address_space [get_bd_addr_spaces pcie_dma_0/xdma_0/M_AXI_LITE] [get_bd_addr_segs jungfraujoch_0/mailbox_0/S0_AXI/Reg] -force assign_bd_address -offset 0x00040000 -range 0x00010000 -target_address_space [get_bd_addr_spaces pcie_dma_0/xdma_0/M_AXI_LITE] [get_bd_addr_segs axi_quad_spi_0/AXI_LITE/Reg] -force assign_bd_address -offset 0x00050000 -range 0x00010000 -target_address_space [get_bd_addr_spaces pcie_dma_0/xdma_0/M_AXI_LITE] [get_bd_addr_segs axi_intc_0/S_AXI/Reg] -force - assign_bd_address -offset 0x00060000 -range 0x00010000 -target_address_space [get_bd_addr_spaces pcie_dma_0/xdma_0/M_AXI_LITE] [get_bd_addr_segs jungfraujoch_0/axi_bram_ctrl_0/S_AXI/Mem0] -force + assign_bd_address -offset 0x00060000 -range 0x00010000 -target_address_space [get_bd_addr_spaces pcie_dma_0/xdma_0/M_AXI_LITE] [get_bd_addr_segs jungfraujoch_0/load_calibration_0/s_axi_control/Reg] -force assign_bd_address -offset 0x00070000 -range 0x00010000 -target_address_space [get_bd_addr_spaces pcie_dma_0/xdma_0/M_AXI_LITE] [get_bd_addr_segs pcie_dma_0/axi_firewall_0/S_AXI_CTL/Control] -force + assign_bd_address -offset 0x00080000 -range 0x00010000 -target_address_space [get_bd_addr_spaces pcie_dma_0/xdma_0/M_AXI_LITE] [get_bd_addr_segs jungfraujoch_0/frame_generator_0/s_axi_control/Reg] -force assign_bd_address -offset 0x00090000 -range 0x00010000 -target_address_space [get_bd_addr_spaces pcie_dma_0/xdma_0/M_AXI_LITE] [get_bd_addr_segs pcie_dma_0/xdma_0/S_AXI_LITE/CTL0] -force assign_bd_address -offset 0x000C0000 -range 0x00040000 -target_address_space [get_bd_addr_spaces pcie_dma_0/xdma_0/M_AXI_LITE] [get_bd_addr_segs cms_subsystem_0/s_axi_ctrl/Mem] -force + assign_bd_address -offset 0x00100000 -range 0x00100000 -target_address_space [get_bd_addr_spaces pcie_dma_0/xdma_0/M_AXI_LITE] [get_bd_addr_segs jungfraujoch_0/axi_bram_ctrl_internal_packet_generator_0/S_AXI/Mem0] -force + assign_bd_address -offset 0x00000000 -range 0x00100000 -target_address_space [get_bd_addr_spaces jungfraujoch_0/frame_generator_0/Data_m_axi_uram] [get_bd_addr_segs jungfraujoch_0/axi_bram_ctrl_internal_packet_generator_1/S_AXI/Mem0] -force - assign_bd_address -offset 0x00010000 -range 0x00010000 -target_address_space [get_bd_addr_spaces pcie_dma_1/xdma_0/M_AXI_LITE] [get_bd_addr_segs jungfraujoch_1/action_config_0/s_axi/reg0] -force - assign_bd_address -offset 0x00020000 -range 0x00010000 -target_address_space [get_bd_addr_spaces pcie_dma_1/xdma_0/M_AXI_LITE] [get_bd_addr_segs mac_100g_1/cmac_usplus_0/s_axi/Reg] -force - assign_bd_address -offset 0x00030000 -range 0x00010000 -target_address_space [get_bd_addr_spaces pcie_dma_1/xdma_0/M_AXI_LITE] [get_bd_addr_segs jungfraujoch_1/mailbox_0/S0_AXI/Reg] -force - assign_bd_address -offset 0x00050000 -range 0x00010000 -target_address_space [get_bd_addr_spaces pcie_dma_1/xdma_0/M_AXI_LITE] [get_bd_addr_segs axi_intc_1/S_AXI/Reg] -force - assign_bd_address -offset 0x00060000 -range 0x00010000 -target_address_space [get_bd_addr_spaces pcie_dma_1/xdma_0/M_AXI_LITE] [get_bd_addr_segs jungfraujoch_1/axi_bram_ctrl_0/S_AXI/Mem0] -force - assign_bd_address -offset 0x00070000 -range 0x00010000 -target_address_space [get_bd_addr_spaces pcie_dma_1/xdma_0/M_AXI_LITE] [get_bd_addr_segs pcie_dma_1/axi_firewall_0/S_AXI_CTL/Control] -force - assign_bd_address -offset 0x00090000 -range 0x00010000 -target_address_space [get_bd_addr_spaces pcie_dma_1/xdma_0/M_AXI_LITE] [get_bd_addr_segs pcie_dma_1/xdma_0/S_AXI_LITE/CTL0] -force - assign_bd_address -offset 0x000C0000 -range 0x00040000 -target_address_space [get_bd_addr_spaces pcie_dma_1/xdma_0/M_AXI_LITE] [get_bd_addr_segs cms_subsystem_0/s_axi_ctrl/Mem] -force - - assign_bd_address -offset 0x00000000 -range 0x00200000 -target_address_space [get_bd_addr_spaces jungfraujoch_1/jf_conversion_0/Data_m_axi_d_hbm_p0] [get_bd_addr_segs gain_uram_0/axi_bram_ctrl_0/S_AXI/Mem0] -force - assign_bd_address -offset 0x00000000 -range 0x00200000 -target_address_space [get_bd_addr_spaces jungfraujoch_1/jf_conversion_0/Data_m_axi_d_hbm_p1] [get_bd_addr_segs gain_uram_1/axi_bram_ctrl_0/S_AXI/Mem0] -force - assign_bd_address -offset 0x00000000 -range 0x00200000 -target_address_space [get_bd_addr_spaces jungfraujoch_1/jf_conversion_0/Data_m_axi_d_hbm_p2] [get_bd_addr_segs gain_uram_2/axi_bram_ctrl_0/S_AXI/Mem0] -force - assign_bd_address -offset 0x00000000 -range 0x00200000 -target_address_space [get_bd_addr_spaces jungfraujoch_1/jf_conversion_0/Data_m_axi_d_hbm_p3] [get_bd_addr_segs gain_uram_3/axi_bram_ctrl_0/S_AXI/Mem0] -force - assign_bd_address -offset 0x00000000 -range 0x00200000 -target_address_space [get_bd_addr_spaces jungfraujoch_1/jf_conversion_0/Data_m_axi_d_hbm_p4] [get_bd_addr_segs gain_uram_4/axi_bram_ctrl_0/S_AXI/Mem0] -force - assign_bd_address -offset 0x00000000 -range 0x00200000 -target_address_space [get_bd_addr_spaces jungfraujoch_1/jf_conversion_0/Data_m_axi_d_hbm_p5] [get_bd_addr_segs gain_uram_5/axi_bram_ctrl_0/S_AXI/Mem0] -force assign_bd_address - set_property -dict [ list \ - CONFIG.CMAC_CORE_SELECT {CMACE4_X0Y3} \ - CONFIG.GT_GROUP_SELECT {X0Y24~X0Y27} \ - ] [get_bd_cells mac_100g/cmac_usplus_0] - - set_property -dict [ list \ - CONFIG.CMAC_CORE_SELECT {CMACE4_X0Y4} \ - CONFIG.GT_GROUP_SELECT {X0Y28~X0Y31} \ - ] [get_bd_cells mac_100g_1/cmac_usplus_0] - set_property -dict [list \ CONFIG.MAX_MODULES_FPGA_PARAM {0x00000010} \ CONFIG.DESIGN_NUMBER {0} \ ] [get_bd_cells jungfraujoch_0/action_config_0] - set_property -dict [list \ - CONFIG.MAX_MODULES_FPGA_PARAM {0x00000004} \ - CONFIG.DESIGN_NUMBER {1} \ - ] [get_bd_cells jungfraujoch_1/action_config_0] - # Restore current instance current_bd_instance $oldCurInst diff --git a/receiver/scripts/build_pcie_design.tcl b/fpga/scripts/build_pcie_design.tcl similarity index 96% rename from receiver/scripts/build_pcie_design.tcl rename to fpga/scripts/build_pcie_design.tcl index b53bf9b9..eb490e0d 100644 --- a/receiver/scripts/build_pcie_design.tcl +++ b/fpga/scripts/build_pcie_design.tcl @@ -1,5 +1,4 @@ -## Copyright (2019-2022) Paul Scherrer Institute -## SPDX-License-Identifier: CERN-OHL-S-2.0 +## Copyright (2019-2023) Paul Scherrer Institute set origin_dir [file dirname [file normalize [info script]]] diff --git a/receiver/scripts/check_hls.sh b/fpga/scripts/check_hls.sh similarity index 100% rename from receiver/scripts/check_hls.sh rename to fpga/scripts/check_hls.sh diff --git a/receiver/scripts/hbm_u55c.tcl b/fpga/scripts/hbm_u55c.tcl similarity index 73% rename from receiver/scripts/hbm_u55c.tcl rename to fpga/scripts/hbm_u55c.tcl index 15442109..7a1463df 100644 --- a/receiver/scripts/hbm_u55c.tcl +++ b/fpga/scripts/hbm_u55c.tcl @@ -1,5 +1,4 @@ -## Copyright (2019-2022) Paul Scherrer Institute -## SPDX-License-Identifier: CERN-OHL-S-2.0 +## Copyright (2019-2023) Paul Scherrer Institute # Inspired on Apache License based SNAP/OC-Accel design from IBM @@ -37,16 +36,12 @@ proc create_hier_cell_hbm_infrastructure { parentCell nameHier } { set hier_obj [create_bd_cell -type hier $nameHier] current_bd_instance $hier_obj - create_bd_pin -dir O apb_complete_0 - create_bd_pin -dir O apb_complete_1 create_bd_pin -dir I -type clk axi_clk create_bd_pin -dir I -type rst axi_resetn - create_bd_pin -dir I -type rst axi_resetn_1 create_bd_pin -dir I -type clk refclk100 create_bd_pin -dir O hbm_cattrip set hbm_temperature_0 [ create_bd_pin -dir O -from 6 -to 0 hbm_temperature_0 ] - set hbm_temperature_1 [ create_bd_pin -dir O -from 6 -to 0 hbm_temperature_1 ] # Create instance: hbm, and set properties set hbm [ create_bd_cell -type ip -vlnv xilinx.com:ip:hbm:1.0 hbm ] @@ -59,31 +54,31 @@ proc create_hier_cell_hbm_infrastructure { parentCell nameHier } { CONFIG.USER_APB_PCLK_0 {100} \ CONFIG.USER_APB_PCLK_PERIOD_0 {10.0} \ CONFIG.USER_AUTO_POPULATE {yes} \ - CONFIG.USER_CLK_SEL_LIST0 {AXI_07_ACLK} \ - CONFIG.USER_CLK_SEL_LIST1 {AXI_19_ACLK} \ + CONFIG.USER_CLK_SEL_LIST0 {AXI_05_ACLK} \ + CONFIG.USER_CLK_SEL_LIST1 {AXI_16_ACLK} \ CONFIG.USER_DFI_CLK0_FREQ {450.000} \ CONFIG.USER_HBM_CP_0 {6} \ - CONFIG.USER_HBM_CP_1 {6} \ - CONFIG.USER_HBM_DENSITY {16GB} \ + CONFIG.USER_HBM_CP_1 {3} \ + CONFIG.USER_HBM_DENSITY {8GB} \ CONFIG.USER_HBM_FBDIV_0 {36} \ - CONFIG.USER_HBM_FBDIV_1 {36} \ + CONFIG.USER_HBM_FBDIV_1 {5} \ CONFIG.USER_HBM_HEX_CP_RES_0 {0x0000A600} \ - CONFIG.USER_HBM_HEX_CP_RES_1 {0x0000A600} \ + CONFIG.USER_HBM_HEX_CP_RES_1 {0x0000B300} \ CONFIG.USER_HBM_HEX_FBDIV_CLKOUTDIV_0 {0x00000902} \ - CONFIG.USER_HBM_HEX_FBDIV_CLKOUTDIV_1 {0x00000902} \ + CONFIG.USER_HBM_HEX_FBDIV_CLKOUTDIV_1 {0x00000142} \ CONFIG.USER_HBM_HEX_LOCK_FB_REF_DLY_0 {0x00001f1f} \ - CONFIG.USER_HBM_HEX_LOCK_FB_REF_DLY_1 {0x00001f1f} \ + CONFIG.USER_HBM_HEX_LOCK_FB_REF_DLY_1 {0x00000a0a} \ CONFIG.USER_HBM_LOCK_FB_DLY_0 {31} \ - CONFIG.USER_HBM_LOCK_FB_DLY_1 {31} \ + CONFIG.USER_HBM_LOCK_FB_DLY_1 {10} \ CONFIG.USER_HBM_LOCK_REF_DLY_0 {31} \ - CONFIG.USER_HBM_LOCK_REF_DLY_1 {31} \ + CONFIG.USER_HBM_LOCK_REF_DLY_1 {10} \ CONFIG.USER_HBM_REF_CLK_0 {100} \ CONFIG.USER_HBM_REF_CLK_PS_0 {5000.00} \ CONFIG.USER_HBM_REF_CLK_XDC_0 {10.00} \ CONFIG.USER_HBM_REF_OUT_CLK_0 {1800} \ CONFIG.USER_HBM_RES_0 {10} \ - CONFIG.USER_HBM_RES_1 {10} \ - CONFIG.USER_HBM_STACK {2} \ + CONFIG.USER_HBM_RES_1 {11} \ + CONFIG.USER_HBM_STACK {1} \ CONFIG.USER_HBM_TCK_0 {900} \ CONFIG.USER_HBM_TCK_0_PERIOD {1.1111111111111112} \ CONFIG.USER_MC0_ENABLE_ECC_CORRECTION {true} \ @@ -222,6 +217,7 @@ proc create_hier_cell_hbm_infrastructure { parentCell nameHier } { CONFIG.USER_MC9_LOOKAHEAD_SBRF {true} \ CONFIG.USER_MC9_REF_TEMP_COMP {false} \ CONFIG.USER_MC9_TRAFFIC_OPTION {Linear} \ + CONFIG.USER_MC_ENABLE_08 {FALSE} \ CONFIG.USER_MC_ENABLE_09 {FALSE} \ CONFIG.USER_MC_ENABLE_10 {FALSE} \ CONFIG.USER_MC_ENABLE_11 {FALSE} \ @@ -230,16 +226,20 @@ proc create_hier_cell_hbm_infrastructure { parentCell nameHier } { CONFIG.USER_MC_ENABLE_14 {FALSE} \ CONFIG.USER_MC_ENABLE_15 {FALSE} \ CONFIG.USER_MC_ENABLE_APB_01 {FALSE} \ - CONFIG.USER_MEMORY_DISPLAY {16384} \ - CONFIG.USER_PHY_ENABLE_08 {TRUE} \ - CONFIG.USER_PHY_ENABLE_09 {TRUE} \ - CONFIG.USER_PHY_ENABLE_10 {TRUE} \ - CONFIG.USER_PHY_ENABLE_11 {TRUE} \ - CONFIG.USER_PHY_ENABLE_12 {TRUE} \ - CONFIG.USER_PHY_ENABLE_13 {TRUE} \ - CONFIG.USER_PHY_ENABLE_14 {TRUE} \ - CONFIG.USER_PHY_ENABLE_15 {TRUE} \ - CONFIG.USER_SWITCH_ENABLE_00 {FALSE} \ + CONFIG.USER_MEMORY_DISPLAY {8192} \ + CONFIG.USER_PHY_ENABLE_08 {FALSE} \ + CONFIG.USER_PHY_ENABLE_09 {FALSE} \ + CONFIG.USER_PHY_ENABLE_10 {FALSE} \ + CONFIG.USER_PHY_ENABLE_11 {FALSE} \ + CONFIG.USER_PHY_ENABLE_12 {FALSE} \ + CONFIG.USER_PHY_ENABLE_13 {FALSE} \ + CONFIG.USER_PHY_ENABLE_14 {FALSE} \ + CONFIG.USER_PHY_ENABLE_15 {FALSE} \ + CONFIG.USER_SAXI_12 {false} \ + CONFIG.USER_SAXI_13 {false} \ + CONFIG.USER_SAXI_14 {false} \ + CONFIG.USER_SAXI_15 {false} \ + CONFIG.USER_SWITCH_ENABLE_00 {TRUE} \ CONFIG.USER_SWITCH_ENABLE_01 {FALSE} \ CONFIG.USER_TEMP_POLL_CNT_0 {100000} \ CONFIG.USER_XSDB_INTF_EN {TRUE} \ @@ -256,26 +256,13 @@ proc create_hier_cell_hbm_infrastructure { parentCell nameHier } { CONFIG.USER_tRREFD_0 {0x8} \ CONFIG.USER_tWR_0 {0x0F} \ CONFIG.USER_tXP_0 {0x07} \ - ] $hbm - - # Create instance: util_vector_logic_0, and set properties - set util_vector_logic_0 [ create_bd_cell -type ip -vlnv xilinx.com:ip:util_vector_logic:2.0 util_vector_logic_0 ] - set_property -dict [ list \ - CONFIG.C_OPERATION {or} \ - CONFIG.C_SIZE {1} \ - CONFIG.LOGO_FILE {data/sym_orgate.png} \ - ] $util_vector_logic_0 + ] $hbm connect_bd_net [get_bd_pins hbm_temperature_0] [get_bd_pins hbm/DRAM_0_STAT_TEMP] - connect_bd_net [get_bd_pins hbm_temperature_1] [get_bd_pins hbm/DRAM_1_STAT_TEMP] - connect_bd_net -net hbm_DRAM_0_STAT_CATTRIP [get_bd_pins hbm/DRAM_0_STAT_CATTRIP] [get_bd_pins util_vector_logic_0/Op1] - connect_bd_net -net hbm_DRAM_1_STAT_CATTRIP [get_bd_pins hbm/DRAM_1_STAT_CATTRIP] [get_bd_pins util_vector_logic_0/Op2] - connect_bd_net -net util_vector_logic_0_Res [get_bd_pins hbm_cattrip] [get_bd_pins util_vector_logic_0/Res] - connect_bd_net -net hbm_apb_complete_0 [get_bd_pins apb_complete_0] [get_bd_pins hbm/apb_complete_0] - connect_bd_net -net hbm_apb_complete_1 [get_bd_pins apb_complete_1] [get_bd_pins hbm/apb_complete_1] + connect_bd_net -net hbm_DRAM_0_STAT_CATTRIP [get_bd_pins hbm/DRAM_0_STAT_CATTRIP] [get_bd_pins hbm_cattrip] - connect_bd_net [get_bd_pins axi_resetn] [get_bd_pins hbm/APB_0_PRESET_N] [get_bd_pins hbm/APB_1_PRESET_N] - connect_bd_net [get_bd_pins refclk100] [get_bd_pins hbm/APB_0_PCLK] [get_bd_pins hbm/APB_1_PCLK] [get_bd_pins hbm/HBM_REF_CLK_0] [get_bd_pins hbm/HBM_REF_CLK_1] + connect_bd_net [get_bd_pins axi_resetn] [get_bd_pins hbm/APB_0_PRESET_N] + connect_bd_net [get_bd_pins refclk100] [get_bd_pins hbm/APB_0_PCLK] [get_bd_pins hbm/HBM_REF_CLK_0] for {set i 0} {$i < 12} {incr i} { create_bd_intf_pin -mode Slave -vlnv xilinx.com:interface:aximm_rtl:1.0 s_axi_hbm_$i @@ -291,7 +278,7 @@ proc create_hier_cell_hbm_infrastructure { parentCell nameHier } { set axi_prot_conv [create_bd_cell -type ip -vlnv {xilinx.com:ip:axi_protocol_converter:*} axi4_to_axi3_$i] set_property -dict [ list \ - CONFIG.TRANSLATION_MODE {0} \ + CONFIG.TRANSLATION_MODE {2} \ ] $axi_prot_conv connect_bd_net [get_bd_pins axi_clk] [get_bd_pins axi4_to_axi3_$i/aclk] [get_bd_pins axi_register_slice_$i/aclk] @@ -311,40 +298,6 @@ proc create_hier_cell_hbm_infrastructure { parentCell nameHier } { } } - for {set i 12} {$i < 18} {incr i} { - create_bd_intf_pin -mode Slave -vlnv xilinx.com:interface:aximm_rtl:1.0 s_axi_hbm_$i - - set cell [create_bd_cell -type ip -vlnv {xilinx.com:ip:axi_register_slice:*} axi_register_slice_$i ] - set_property -dict [ list \ - CONFIG.REG_AW {15} \ - CONFIG.REG_AR {15} \ - CONFIG.REG_W {15} \ - CONFIG.REG_R {15} \ - CONFIG.REG_B {15} \ - ] $cell - - set axi_prot_conv [create_bd_cell -type ip -vlnv {xilinx.com:ip:axi_protocol_converter:*} axi4_to_axi3_$i] - set_property -dict [ list \ - CONFIG.TRANSLATION_MODE {0} \ - ] $axi_prot_conv - - connect_bd_net [get_bd_pins axi_clk] [get_bd_pins axi4_to_axi3_$i/aclk] [get_bd_pins axi_register_slice_$i/aclk] - - connect_bd_net [get_bd_pins axi_resetn_1] [get_bd_pins axi_register_slice_$i/aresetn] - connect_bd_net [get_bd_pins axi_resetn_1] [get_bd_pins axi4_to_axi3_$i/aresetn] - connect_bd_intf_net [get_bd_intf_pins axi4_to_axi3_$i/M_AXI] [get_bd_intf_pins axi_register_slice_$i/S_AXI] - connect_bd_intf_net [get_bd_intf_pins axi4_to_axi3_$i/S_AXI] [get_bd_intf_pins s_axi_hbm_$i] - if {$i < 10} { - connect_bd_net [get_bd_pins axi_resetn_1] [get_bd_pins hbm/AXI_0${i}_ARESET_N] - connect_bd_net [get_bd_pins axi_clk] [get_bd_pins hbm/AXI_0${i}_ACLK] - connect_bd_intf_net [get_bd_intf_pins axi_register_slice_$i/M_AXI] [get_bd_intf_pins hbm/SAXI_0${i}*] - } else { - connect_bd_net [get_bd_pins axi_resetn_1] [get_bd_pins hbm/AXI_${i}_ARESET_N] - connect_bd_net [get_bd_pins axi_clk] [get_bd_pins hbm/AXI_${i}_ACLK] - connect_bd_intf_net [get_bd_intf_pins axi_register_slice_$i/M_AXI] [get_bd_intf_pins hbm/SAXI_${i}*] - } - } - # Restore current instance current_bd_instance $oldCurInst } diff --git a/receiver/scripts/jfjoch.tcl b/fpga/scripts/jfjoch.tcl similarity index 64% rename from receiver/scripts/jfjoch.tcl rename to fpga/scripts/jfjoch.tcl index 0b87e910..763aafb0 100644 --- a/receiver/scripts/jfjoch.tcl +++ b/fpga/scripts/jfjoch.tcl @@ -1,5 +1,4 @@ -## Copyright (2019-2022) Paul Scherrer Institute -## SPDX-License-Identifier: CERN-OHL-S-2.0 +## Copyright (2019-2023) Paul Scherrer Institute # Hierarchical cell: jungfraujoch proc create_hier_cell_jungfraujoch { parentCell nameHier } { @@ -7,7 +6,7 @@ proc create_hier_cell_jungfraujoch { parentCell nameHier } { variable script_folder if { $parentCell eq "" || $nameHier eq "" } { - catch {common::send_gid_msg -ssname BD::TCL -id 2092 -severity "ERROR" "create_hier_cell_jungfraujoch() - Empty argument(s)!"} + catch {common::send_gid_msg -ssname BD::TCL -id 2092 -severity "ERROR" "create_hier_cell_jungfraujoch_0() - Empty argument(s)!"} return } @@ -77,19 +76,8 @@ proc create_hier_cell_jungfraujoch { parentCell nameHier } { # Create pins create_bd_pin -dir I -type rst ap_rst_n - create_bd_pin -dir I apb_complete create_bd_pin -dir I -type clk axi_clk create_bd_pin -dir I -type rst axi_rst_n - create_bd_pin -dir I eth_busy - create_bd_pin -dir I eth_stat_rx_aligned - create_bd_pin -dir I eth_stat_rx_packet_bad_fcs - create_bd_pin -dir I eth_stat_rx_status - create_bd_pin -dir I hbm_temp_trip - create_bd_pin -dir I -from 6 -to 0 hbm_temperature - create_bd_pin -dir I mm2s_error - create_bd_pin -dir O qsfp_led_busy - create_bd_pin -dir O qsfp_led_conn - create_bd_pin -dir I s2mm_error # Create instance: action_config_0, and set properties set block_name action_config @@ -101,20 +89,36 @@ proc create_hier_cell_jungfraujoch { parentCell nameHier } { catch {common::send_gid_msg -ssname BD::TCL -id 2096 -severity "ERROR" "Unable to referenced block <$block_name>. Please add the files for ${block_name}'s definition into the project."} return 1 } + set_property -dict [ list \ + CONFIG.DESIGN_NUMBER {0} \ + CONFIG.MAX_MODULES_FPGA_PARAM {0x00000010} \ + ] $action_config_0 - # Create instance: axi_bram_ctrl_0, and set properties - set axi_bram_ctrl_0 [ create_bd_cell -type ip -vlnv xilinx.com:ip:axi_bram_ctrl:4.1 axi_bram_ctrl_0 ] + # Create instance: axi_bram_ctrl_internal_packet_generator_0, and set properties + set axi_bram_ctrl_internal_packet_generator_0 [ create_bd_cell -type ip -vlnv xilinx.com:ip:axi_bram_ctrl:4.1 axi_bram_ctrl_internal_packet_generator_0 ] set_property -dict [ list \ - CONFIG.PROTOCOL {AXI4LITE} \ - CONFIG.READ_LATENCY {1} \ + CONFIG.DATA_WIDTH {512} \ + CONFIG.PROTOCOL {AXI4} \ + CONFIG.READ_LATENCY {3} \ CONFIG.SINGLE_PORT_BRAM {1} \ - ] $axi_bram_ctrl_0 + ] $axi_bram_ctrl_internal_packet_generator_0 + + # Create instance: axi_bram_ctrl_internal_packet_generator_1, and set properties + set axi_bram_ctrl_internal_packet_generator_1 [ create_bd_cell -type ip -vlnv xilinx.com:ip:axi_bram_ctrl:4.1 axi_bram_ctrl_internal_packet_generator_1 ] + set_property -dict [ list \ + CONFIG.DATA_WIDTH {512} \ + CONFIG.PROTOCOL {AXI4} \ + CONFIG.READ_LATENCY {3} \ + CONFIG.SINGLE_PORT_BRAM {1} \ + ] $axi_bram_ctrl_internal_packet_generator_1 # Create instance: axis_addr_fifo_0, and set properties set axis_addr_fifo_0 [ create_bd_cell -type ip -vlnv xilinx.com:ip:axis_data_fifo:2.0 axis_addr_fifo_0 ] set_property -dict [ list \ CONFIG.FIFO_DEPTH {128} \ CONFIG.FIFO_MEMORY_TYPE {block} \ + CONFIG.HAS_AEMPTY {1} \ + CONFIG.HAS_AFULL {1} \ ] $axis_addr_fifo_0 # Create instance: axis_addr_fifo_1, and set properties @@ -126,19 +130,10 @@ proc create_hier_cell_jungfraujoch { parentCell nameHier } { CONFIG.HAS_AFULL {1} \ ] $axis_addr_fifo_1 - # Create instance: axis_addr_fifo_2, and set properties - set axis_addr_fifo_2 [ create_bd_cell -type ip -vlnv xilinx.com:ip:axis_data_fifo:2.0 axis_addr_fifo_2 ] - set_property -dict [ list \ - CONFIG.FIFO_DEPTH {256} \ - CONFIG.FIFO_MEMORY_TYPE {block} \ - CONFIG.HAS_AEMPTY {1} \ - CONFIG.HAS_AFULL {1} \ - ] $axis_addr_fifo_2 - # Create instance: axis_data_fifo_0, and set properties set axis_data_fifo_0 [ create_bd_cell -type ip -vlnv xilinx.com:ip:axis_data_fifo:2.0 axis_data_fifo_0 ] set_property -dict [ list \ - CONFIG.FIFO_DEPTH {16384} \ + CONFIG.FIFO_DEPTH {4096} \ CONFIG.FIFO_MEMORY_TYPE {ultra} \ ] $axis_data_fifo_0 @@ -147,6 +142,8 @@ proc create_hier_cell_jungfraujoch { parentCell nameHier } { set_property -dict [ list \ CONFIG.FIFO_DEPTH {256} \ CONFIG.FIFO_MEMORY_TYPE {block} \ + CONFIG.HAS_AEMPTY {1} \ + CONFIG.HAS_AFULL {1} \ ] $axis_data_fifo_1 # Create instance: axis_data_fifo_2, and set properties @@ -159,27 +156,11 @@ proc create_hier_cell_jungfraujoch { parentCell nameHier } { # Create instance: axis_data_fifo_3, and set properties set axis_data_fifo_3 [ create_bd_cell -type ip -vlnv xilinx.com:ip:axis_data_fifo:2.0 axis_data_fifo_3 ] set_property -dict [ list \ - CONFIG.FIFO_DEPTH {256} \ - CONFIG.FIFO_MEMORY_TYPE {block} \ - CONFIG.HAS_AEMPTY {1} \ - CONFIG.HAS_AFULL {1} \ - ] $axis_data_fifo_3 - - # Create instance: axis_data_fifo_4, and set properties - set axis_data_fifo_4 [ create_bd_cell -type ip -vlnv xilinx.com:ip:axis_data_fifo:2.0 axis_data_fifo_4 ] - set_property -dict [ list \ - CONFIG.FIFO_DEPTH {256} \ - CONFIG.FIFO_MEMORY_TYPE {block} \ - ] $axis_data_fifo_4 - - # Create instance: axis_data_fifo_5, and set properties - set axis_data_fifo_5 [ create_bd_cell -type ip -vlnv xilinx.com:ip:axis_data_fifo:2.0 axis_data_fifo_5 ] - set_property -dict [ list \ - CONFIG.FIFO_DEPTH {16384} \ + CONFIG.FIFO_DEPTH {32768} \ CONFIG.FIFO_MEMORY_TYPE {ultra} \ CONFIG.HAS_AEMPTY {1} \ CONFIG.HAS_AFULL {1} \ - ] $axis_data_fifo_5 + ] $axis_data_fifo_3 # Create instance: axis_data_fifo_c2h_cmd, and set properties set axis_data_fifo_c2h_cmd [ create_bd_cell -type ip -vlnv xilinx.com:ip:axis_data_fifo:2.0 axis_data_fifo_c2h_cmd ] @@ -203,23 +184,33 @@ proc create_hier_cell_jungfraujoch { parentCell nameHier } { set axis_data_fifo_h2c_cmd [ create_bd_cell -type ip -vlnv xilinx.com:ip:axis_data_fifo:2.0 axis_data_fifo_h2c_cmd ] set_property -dict [ list \ CONFIG.FIFO_DEPTH {64} \ + CONFIG.HAS_AEMPTY {1} \ + CONFIG.HAS_AFULL {1} \ ] $axis_data_fifo_h2c_cmd # Create instance: axis_data_fifo_h2c_data, and set properties set axis_data_fifo_h2c_data [ create_bd_cell -type ip -vlnv xilinx.com:ip:axis_data_fifo:2.0 axis_data_fifo_h2c_data ] set_property -dict [ list \ - CONFIG.FIFO_DEPTH {128} \ + CONFIG.FIFO_DEPTH {256} \ CONFIG.FIFO_MEMORY_TYPE {block} \ CONFIG.HAS_AEMPTY {1} \ CONFIG.HAS_AFULL {1} \ CONFIG.TDATA_NUM_BYTES {64} \ ] $axis_data_fifo_h2c_data - # Create instance: axis_register_slice_addr_0, and set properties - set axis_register_slice_addr_0 [ create_bd_cell -type ip -vlnv xilinx.com:ip:axis_register_slice:1.1 axis_register_slice_addr_0 ] + # Create instance: axis_eth_in_fifo, and set properties + set axis_eth_in_fifo [ create_bd_cell -type ip -vlnv xilinx.com:ip:axis_data_fifo:2.0 axis_eth_in_fifo ] set_property -dict [ list \ - CONFIG.REG_CONFIG {16} \ - ] $axis_register_slice_addr_0 + CONFIG.HAS_AEMPTY {1} \ + CONFIG.HAS_AFULL {1} \ + ] $axis_eth_in_fifo + + # Create instance: axis_frame_generator_fifo_0, and set properties + set axis_frame_generator_fifo_0 [ create_bd_cell -type ip -vlnv xilinx.com:ip:axis_data_fifo:2.0 axis_frame_generator_fifo_0 ] + set_property -dict [ list \ + CONFIG.HAS_AEMPTY {1} \ + CONFIG.HAS_AFULL {1} \ + ] $axis_frame_generator_fifo_0 # Create instance: axis_register_slice_addr_1, and set properties set axis_register_slice_addr_1 [ create_bd_cell -type ip -vlnv xilinx.com:ip:axis_register_slice:1.1 axis_register_slice_addr_1 ] @@ -227,12 +218,6 @@ proc create_hier_cell_jungfraujoch { parentCell nameHier } { CONFIG.REG_CONFIG {16} \ ] $axis_register_slice_addr_1 - # Create instance: axis_register_slice_data_0, and set properties - set axis_register_slice_data_0 [ create_bd_cell -type ip -vlnv xilinx.com:ip:axis_register_slice:1.1 axis_register_slice_data_0 ] - set_property -dict [ list \ - CONFIG.REG_CONFIG {16} \ - ] $axis_register_slice_data_0 - # Create instance: axis_register_slice_data_1, and set properties set axis_register_slice_data_1 [ create_bd_cell -type ip -vlnv xilinx.com:ip:axis_register_slice:1.1 axis_register_slice_data_1 ] set_property -dict [ list \ @@ -275,8 +260,8 @@ proc create_hier_cell_jungfraujoch { parentCell nameHier } { # Create instance: axis_work_completion_fifo_0, and set properties set axis_work_completion_fifo_0 [ create_bd_cell -type ip -vlnv xilinx.com:ip:axis_data_fifo:2.0 axis_work_completion_fifo_0 ] set_property -dict [ list \ - CONFIG.FIFO_DEPTH {1024} \ - CONFIG.FIFO_MEMORY_TYPE {auto} \ + CONFIG.FIFO_DEPTH {8192} \ + CONFIG.FIFO_MEMORY_TYPE {ultra} \ CONFIG.HAS_AEMPTY {1} \ CONFIG.HAS_AFULL {1} \ ] $axis_work_completion_fifo_0 @@ -291,28 +276,36 @@ proc create_hier_cell_jungfraujoch { parentCell nameHier } { CONFIG.HAS_PROG_FULL {0} \ ] $axis_work_request_fifo_0 - # Create instance: calibration_addr_bram, and set properties - set calibration_addr_bram [ create_bd_cell -type ip -vlnv xilinx.com:ip:blk_mem_gen:8.4 calibration_addr_bram ] - set_property -dict [ list \ - CONFIG.Assume_Synchronous_Clk {true} \ - CONFIG.Enable_B {Use_ENB_Pin} \ - CONFIG.Memory_Type {True_Dual_Port_RAM} \ - CONFIG.Port_A_Write_Rate {50} \ - CONFIG.Port_B_Clock {100} \ - CONFIG.Port_B_Enable_Rate {100} \ - CONFIG.Port_B_Write_Rate {50} \ - CONFIG.Use_Byte_Write_Enable {true} \ - CONFIG.Use_RSTB_Pin {true} \ - ] $calibration_addr_bram - # Create instance: data_collection_fsm_0, and set properties set data_collection_fsm_0 [ create_bd_cell -type ip -vlnv psi.ch:hls:data_collection_fsm:1.0 data_collection_fsm_0 ] + # Create instance: frame_generator_0, and set properties + set frame_generator_0 [ create_bd_cell -type ip -vlnv psi.ch:hls:frame_generator:1.0 frame_generator_0 ] + # Create instance: host_writer_0, and set properties set host_writer_0 [ create_bd_cell -type ip -vlnv psi.ch:hls:host_writer:1.0 host_writer_0 ] - # Create instance: internal_packet_generator_0, and set properties - set internal_packet_generator_0 [ create_bd_cell -type ip -vlnv psi.ch:hls:internal_packet_generator:1.0 internal_packet_generator_0 ] + # Create instance: internal_packet_generator_uram, and set properties + set internal_packet_generator_uram [ create_bd_cell -type ip -vlnv xilinx.com:ip:blk_mem_gen:8.4 internal_packet_generator_uram ] + set_property -dict [ list \ + CONFIG.Assume_Synchronous_Clk {true} \ + CONFIG.EN_SAFETY_CKT {false} \ + CONFIG.Enable_B {Use_ENB_Pin} \ + CONFIG.Memory_Type {True_Dual_Port_RAM} \ + CONFIG.Operating_Mode_A {NO_CHANGE} \ + CONFIG.Operating_Mode_B {NO_CHANGE} \ + CONFIG.PRIM_type_to_Implement {URAM} \ + CONFIG.Port_A_Write_Rate {50} \ + CONFIG.Port_B_Clock {100} \ + CONFIG.Port_B_Enable_Rate {100} \ + CONFIG.Port_B_Write_Rate {50} \ + CONFIG.READ_LATENCY_A {3} \ + CONFIG.READ_LATENCY_B {3} \ + CONFIG.Read_Width_B {512} \ + CONFIG.Use_Byte_Write_Enable {true} \ + CONFIG.Use_RSTB_Pin {true} \ + CONFIG.Write_Width_B {512} \ + ] $internal_packet_generator_uram # Create instance: jf_conversion_0, and set properties set jf_conversion_0 [ create_bd_cell -type ip -vlnv psi.ch:hls:jf_conversion:1.0 jf_conversion_0 ] @@ -335,39 +328,45 @@ proc create_hier_cell_jungfraujoch { parentCell nameHier } { set smartconnect_0 [ create_bd_cell -type ip -vlnv xilinx.com:ip:smartconnect:1.0 smartconnect_0 ] set_property -dict [ list \ CONFIG.NUM_CLKS {1} \ - CONFIG.NUM_MI {3} \ + CONFIG.NUM_MI {5} \ CONFIG.NUM_SI {1} \ ] $smartconnect_0 - # Create instance: timer_hbm_0, and set properties - set timer_hbm_0 [ create_bd_cell -type ip -vlnv psi.ch:hls:timer_hbm:1.0 timer_hbm_0 ] + # Create instance: smartconnect_1, and set properties + set smartconnect_1 [ create_bd_cell -type ip -vlnv xilinx.com:ip:smartconnect:1.0 smartconnect_1 ] - # Create instance: timer_host_0, and set properties - set timer_host_0 [ create_bd_cell -type ip -vlnv psi.ch:hls:timer_host:1.0 timer_host_0 ] + # Create instance: smartconnect_2, and set properties + set smartconnect_2 [ create_bd_cell -type ip -vlnv xilinx.com:ip:smartconnect:1.0 smartconnect_2 ] + + # Create instance: stream_merge_0, and set properties + set stream_merge_0 [ create_bd_cell -type ip -vlnv psi.ch:hls:stream_merge:1.0 stream_merge_0 ] + + # Create instance: timer_hbm, and set properties + set timer_hbm [ create_bd_cell -type ip -vlnv psi.ch:hls:timer_host:1.0 timer_hbm ] + + # Create instance: timer_host, and set properties + set timer_host [ create_bd_cell -type ip -vlnv psi.ch:hls:timer_host:1.0 timer_host ] # Create interface connections connect_bd_intf_net -intf_net Conn2 [get_bd_intf_pins eth_out] [get_bd_intf_pins network_stack/M00_AXIS] - connect_bd_intf_net -intf_net Conn3 [get_bd_intf_pins eth_in] [get_bd_intf_pins network_stack/eth_in] connect_bd_intf_net -intf_net S_AXIS_1 [get_bd_intf_pins s_axis_h2c_data] [get_bd_intf_pins axis_data_fifo_h2c_data/S_AXIS] - connect_bd_intf_net -intf_net axi_bram_ctrl_0_BRAM_PORTA [get_bd_intf_pins axi_bram_ctrl_0/BRAM_PORTA] [get_bd_intf_pins calibration_addr_bram/BRAM_PORTB] - connect_bd_intf_net -intf_net axis_addr_fifo_0_M_AXIS [get_bd_intf_pins axis_addr_fifo_0/M_AXIS] [get_bd_intf_pins internal_packet_generator_0/addr_in] - connect_bd_intf_net -intf_net axis_addr_fifo_2_M_AXIS [get_bd_intf_pins axis_addr_fifo_1/M_AXIS] [get_bd_intf_pins jf_conversion_0/addr_in] - connect_bd_intf_net -intf_net axis_addr_fifo_3_M_AXIS [get_bd_intf_pins axis_addr_fifo_2/M_AXIS] [get_bd_intf_pins host_writer_0/addr_in] - connect_bd_intf_net -intf_net axis_data_fifo_0_M_AXIS [get_bd_intf_pins axis_data_fifo_0/M_AXIS] [get_bd_intf_pins load_calibration_0/data_in] - connect_bd_intf_net -intf_net axis_data_fifo_1_M_AXIS [get_bd_intf_pins axis_data_fifo_1/M_AXIS] [get_bd_intf_pins internal_packet_generator_0/data_in] - connect_bd_intf_net -intf_net axis_data_fifo_2_M_AXIS [get_bd_intf_pins axis_data_fifo_2/M_AXIS] [get_bd_intf_pins timer_hbm_0/data_in] - connect_bd_intf_net -intf_net axis_data_fifo_4_M_AXIS [get_bd_intf_pins axis_data_fifo_3/M_AXIS] [get_bd_intf_pins jf_conversion_0/data_in] - connect_bd_intf_net -intf_net axis_data_fifo_4_M_AXIS1 [get_bd_intf_pins axis_data_fifo_4/M_AXIS] [get_bd_intf_pins timer_host_0/data_in] - connect_bd_intf_net -intf_net axis_data_fifo_8_M_AXIS [get_bd_intf_pins axis_data_fifo_5/M_AXIS] [get_bd_intf_pins host_writer_0/data_in] + connect_bd_intf_net -intf_net axi_bram_ctrl_internal_packet_generator_1_BRAM_PORTA [get_bd_intf_pins axi_bram_ctrl_internal_packet_generator_1/BRAM_PORTA] [get_bd_intf_pins internal_packet_generator_uram/BRAM_PORTB] + connect_bd_intf_net -intf_net axi_bram_ctrl_internal_packet_generator_BRAM_PORTA [get_bd_intf_pins axi_bram_ctrl_internal_packet_generator_0/BRAM_PORTA] [get_bd_intf_pins internal_packet_generator_uram/BRAM_PORTA] + connect_bd_intf_net -intf_net axis_addr_fifo_0_M_AXIS [get_bd_intf_pins axis_addr_fifo_0/M_AXIS] [get_bd_intf_pins jf_conversion_0/addr_in] + connect_bd_intf_net -intf_net axis_addr_fifo_1_M_AXIS1 [get_bd_intf_pins axis_addr_fifo_1/M_AXIS] [get_bd_intf_pins host_writer_0/addr_in] + connect_bd_intf_net -intf_net axis_data_fifo_0_M_AXIS [get_bd_intf_pins axis_data_fifo_0/M_AXIS] [get_bd_intf_pins timer_hbm/data_in] + connect_bd_intf_net -intf_net axis_data_fifo_1_M_AXIS [get_bd_intf_pins axis_data_fifo_1/M_AXIS] [get_bd_intf_pins jf_conversion_0/data_in] + connect_bd_intf_net -intf_net axis_data_fifo_2_M_AXIS1 [get_bd_intf_pins axis_data_fifo_2/M_AXIS] [get_bd_intf_pins timer_host/data_in] + connect_bd_intf_net -intf_net axis_data_fifo_3_M_AXIS [get_bd_intf_pins axis_data_fifo_3/M_AXIS] [get_bd_intf_pins host_writer_0/data_in] connect_bd_intf_net -intf_net axis_data_fifo_c2h_cmd_M_AXIS [get_bd_intf_pins m_axis_c2h_datamover_cmd] [get_bd_intf_pins axis_data_fifo_c2h_cmd/M_AXIS] connect_bd_intf_net -intf_net axis_data_fifo_c2h_data_M_AXIS [get_bd_intf_pins m_axis_c2h_data] [get_bd_intf_pins axis_data_fifo_c2h_data/M_AXIS] connect_bd_intf_net -intf_net axis_data_fifo_h2c_cmd_M_AXIS [get_bd_intf_pins m_axis_h2c_datamover_cmd] [get_bd_intf_pins axis_data_fifo_h2c_cmd/M_AXIS] connect_bd_intf_net -intf_net axis_data_fifo_h2c_data_M_AXIS [get_bd_intf_pins axis_data_fifo_h2c_data/M_AXIS] [get_bd_intf_pins axis_register_slice_data_in_0/S_AXIS] - connect_bd_intf_net -intf_net axis_register_slice_0_M_AXIS [get_bd_intf_pins axis_addr_fifo_2/S_AXIS] [get_bd_intf_pins axis_register_slice_addr_1/M_AXIS] - connect_bd_intf_net -intf_net axis_register_slice_0_M_AXIS1 [get_bd_intf_pins axis_register_slice_data_in_0/M_AXIS] [get_bd_intf_pins load_calibration_0/host_memory_in] - connect_bd_intf_net -intf_net axis_register_slice_1_M_AXIS [get_bd_intf_pins axis_data_fifo_5/S_AXIS] [get_bd_intf_pins axis_register_slice_data_1/M_AXIS] - connect_bd_intf_net -intf_net axis_register_slice_2_M_AXIS [get_bd_intf_pins axis_addr_fifo_1/S_AXIS] [get_bd_intf_pins axis_register_slice_addr_0/M_AXIS] - connect_bd_intf_net -intf_net axis_register_slice_data_0_M_AXIS [get_bd_intf_pins axis_data_fifo_2/S_AXIS] [get_bd_intf_pins axis_register_slice_data_0/M_AXIS] + connect_bd_intf_net -intf_net axis_eth_in_fifo_M_AXIS [get_bd_intf_pins axis_eth_in_fifo/M_AXIS] [get_bd_intf_pins network_stack/eth_in] + connect_bd_intf_net -intf_net axis_frame_generator_fifo_0_M_AXIS [get_bd_intf_pins axis_frame_generator_fifo_0/M_AXIS] [get_bd_intf_pins stream_merge_0/input_0] + connect_bd_intf_net -intf_net axis_register_slice_addr_1_M_AXIS [get_bd_intf_pins axis_addr_fifo_1/S_AXIS] [get_bd_intf_pins axis_register_slice_addr_1/M_AXIS] + connect_bd_intf_net -intf_net axis_register_slice_data_1_M_AXIS [get_bd_intf_pins axis_data_fifo_3/S_AXIS] [get_bd_intf_pins axis_register_slice_data_1/M_AXIS] + connect_bd_intf_net -intf_net axis_register_slice_data_in_0_M_AXIS1 [get_bd_intf_pins axis_register_slice_data_in_0/M_AXIS] [get_bd_intf_pins load_calibration_0/host_memory_in] connect_bd_intf_net -intf_net axis_register_slice_host_mem_M_AXIS [get_bd_intf_pins axis_data_fifo_c2h_data/S_AXIS] [get_bd_intf_pins axis_register_slice_host_mem/M_AXIS] connect_bd_intf_net -intf_net axis_register_slice_udp_M_AXIS [get_bd_intf_pins axis_register_slice_udp/M_AXIS] [get_bd_intf_pins data_collection_fsm_0/eth_in] connect_bd_intf_net -intf_net axis_udp_addr_fifo_0_M_AXIS [get_bd_intf_pins axis_udp_addr_fifo_0/M_AXIS] [get_bd_intf_pins data_collection_fsm_0/addr_in] @@ -376,16 +375,17 @@ proc create_hier_cell_jungfraujoch { parentCell nameHier } { connect_bd_intf_net -intf_net axis_work_request_fifo_0_M_AXIS [get_bd_intf_pins axis_work_request_fifo_0/M_AXIS] [get_bd_intf_pins host_writer_0/s_axis_work_request] connect_bd_intf_net -intf_net data_collection_fsm_0_addr_out [get_bd_intf_pins axis_addr_fifo_0/S_AXIS] [get_bd_intf_pins data_collection_fsm_0/addr_out] connect_bd_intf_net -intf_net data_collection_fsm_0_data_out [get_bd_intf_pins axis_data_fifo_0/S_AXIS] [get_bd_intf_pins data_collection_fsm_0/data_out] + connect_bd_intf_net -intf_net eth_in_1 [get_bd_intf_pins eth_in] [get_bd_intf_pins stream_merge_0/input_1] + connect_bd_intf_net -intf_net frame_generator_0_data_out [get_bd_intf_pins axis_frame_generator_fifo_0/S_AXIS] [get_bd_intf_pins frame_generator_0/data_out] + connect_bd_intf_net -intf_net frame_generator_0_m_axi_uram [get_bd_intf_pins axi_bram_ctrl_internal_packet_generator_1/S_AXI] [get_bd_intf_pins frame_generator_0/m_axi_uram] connect_bd_intf_net -intf_net host_writer_0_datamover_out_cmd [get_bd_intf_pins axis_data_fifo_c2h_cmd/S_AXIS] [get_bd_intf_pins host_writer_0/datamover_out_cmd] connect_bd_intf_net -intf_net host_writer_0_host_memory_out [get_bd_intf_pins axis_register_slice_host_mem/S_AXIS] [get_bd_intf_pins host_writer_0/host_memory_out] connect_bd_intf_net -intf_net host_writer_0_m_axis_completion [get_bd_intf_pins axis_work_completion_fifo_0/S_AXIS] [get_bd_intf_pins host_writer_0/m_axis_completion] - connect_bd_intf_net -intf_net internal_packet_generator_0_addr_out [get_bd_intf_pins axis_register_slice_addr_0/S_AXIS] [get_bd_intf_pins internal_packet_generator_0/addr_out] - connect_bd_intf_net -intf_net internal_packet_generator_0_data_out [get_bd_intf_pins axis_register_slice_data_0/S_AXIS] [get_bd_intf_pins internal_packet_generator_0/data_out] connect_bd_intf_net -intf_net jf_conversion_0_addr_out [get_bd_intf_pins axis_register_slice_addr_1/S_AXIS] [get_bd_intf_pins jf_conversion_0/addr_out] - connect_bd_intf_net -intf_net jf_conversion_0_data_out [get_bd_intf_pins axis_data_fifo_4/S_AXIS] [get_bd_intf_pins jf_conversion_0/data_out] - connect_bd_intf_net -intf_net jf_conversion_0_m_axi_d_hbm_p0 [get_bd_intf_pins m_axi_d_hbm_p0] [get_bd_intf_pins jf_conversion_0/m_axi_d_hbm_p0] + connect_bd_intf_net -intf_net jf_conversion_0_data_out [get_bd_intf_pins axis_data_fifo_2/S_AXIS] [get_bd_intf_pins jf_conversion_0/data_out] + connect_bd_intf_net -intf_net jf_conversion_0_m_axi_d_hbm_p0 [get_bd_intf_pins jf_conversion_0/m_axi_d_hbm_p0] [get_bd_intf_pins smartconnect_1/S00_AXI] connect_bd_intf_net -intf_net jf_conversion_0_m_axi_d_hbm_p1 [get_bd_intf_pins m_axi_d_hbm_p1] [get_bd_intf_pins jf_conversion_0/m_axi_d_hbm_p1] - connect_bd_intf_net -intf_net jf_conversion_0_m_axi_d_hbm_p2 [get_bd_intf_pins m_axi_d_hbm_p2] [get_bd_intf_pins jf_conversion_0/m_axi_d_hbm_p2] + connect_bd_intf_net -intf_net jf_conversion_0_m_axi_d_hbm_p2 [get_bd_intf_pins jf_conversion_0/m_axi_d_hbm_p2] [get_bd_intf_pins smartconnect_2/S00_AXI] connect_bd_intf_net -intf_net jf_conversion_0_m_axi_d_hbm_p3 [get_bd_intf_pins m_axi_d_hbm_p3] [get_bd_intf_pins jf_conversion_0/m_axi_d_hbm_p3] connect_bd_intf_net -intf_net jf_conversion_0_m_axi_d_hbm_p4 [get_bd_intf_pins m_axi_d_hbm_p4] [get_bd_intf_pins jf_conversion_0/m_axi_d_hbm_p4] connect_bd_intf_net -intf_net jf_conversion_0_m_axi_d_hbm_p5 [get_bd_intf_pins m_axi_d_hbm_p5] [get_bd_intf_pins jf_conversion_0/m_axi_d_hbm_p5] @@ -395,48 +395,57 @@ proc create_hier_cell_jungfraujoch { parentCell nameHier } { connect_bd_intf_net -intf_net jf_conversion_0_m_axi_d_hbm_p9 [get_bd_intf_pins m_axi_d_hbm_p9] [get_bd_intf_pins jf_conversion_0/m_axi_d_hbm_p9] connect_bd_intf_net -intf_net jf_conversion_0_m_axi_d_hbm_p10 [get_bd_intf_pins m_axi_d_hbm_p10] [get_bd_intf_pins jf_conversion_0/m_axi_d_hbm_p10] connect_bd_intf_net -intf_net jf_conversion_0_m_axi_d_hbm_p11 [get_bd_intf_pins m_axi_d_hbm_p11] [get_bd_intf_pins jf_conversion_0/m_axi_d_hbm_p11] - connect_bd_intf_net -intf_net load_calibration_0_data_out [get_bd_intf_pins axis_data_fifo_1/S_AXIS] [get_bd_intf_pins load_calibration_0/data_out] connect_bd_intf_net -intf_net load_calibration_0_datamover_in_cmd [get_bd_intf_pins axis_data_fifo_h2c_cmd/S_AXIS] [get_bd_intf_pins load_calibration_0/datamover_in_cmd] - connect_bd_intf_net -intf_net load_calibration_0_in_mem_location_PORTA [get_bd_intf_pins calibration_addr_bram/BRAM_PORTA] [get_bd_intf_pins load_calibration_0/in_mem_location_PORTA] + connect_bd_intf_net -intf_net load_calibration_0_m_axi_d_hbm_p0 [get_bd_intf_pins load_calibration_0/m_axi_d_hbm_p0] [get_bd_intf_pins smartconnect_1/S01_AXI] + connect_bd_intf_net -intf_net load_calibration_0_m_axi_d_hbm_p1 [get_bd_intf_pins load_calibration_0/m_axi_d_hbm_p1] [get_bd_intf_pins smartconnect_2/S01_AXI] connect_bd_intf_net -intf_net mailbox_0_M1_AXIS [get_bd_intf_pins axis_work_request_fifo_0/S_AXIS] [get_bd_intf_pins mailbox_0/M1_AXIS] connect_bd_intf_net -intf_net network_stack_udp_addr_out [get_bd_intf_pins axis_udp_addr_fifo_0/S_AXIS] [get_bd_intf_pins network_stack/udp_addr_out] connect_bd_intf_net -intf_net network_stack_udp_out [get_bd_intf_pins axis_udp_fifo_0/S_AXIS] [get_bd_intf_pins network_stack/udp_out] connect_bd_intf_net -intf_net s_axi_1 [get_bd_intf_pins s_axi] [get_bd_intf_pins smartconnect_0/S00_AXI] connect_bd_intf_net -intf_net smartconnect_0_M00_AXI [get_bd_intf_pins action_config_0/s_axi] [get_bd_intf_pins smartconnect_0/M00_AXI] connect_bd_intf_net -intf_net smartconnect_0_M01_AXI [get_bd_intf_pins mailbox_0/S0_AXI] [get_bd_intf_pins smartconnect_0/M01_AXI] - connect_bd_intf_net -intf_net smartconnect_0_M02_AXI [get_bd_intf_pins axi_bram_ctrl_0/S_AXI] [get_bd_intf_pins smartconnect_0/M02_AXI] - connect_bd_intf_net -intf_net timer_hbm_0_data_out [get_bd_intf_pins axis_data_fifo_3/S_AXIS] [get_bd_intf_pins timer_hbm_0/data_out] - connect_bd_intf_net -intf_net timer_host_0_data_out [get_bd_intf_pins axis_register_slice_data_1/S_AXIS] [get_bd_intf_pins timer_host_0/data_out] + connect_bd_intf_net -intf_net smartconnect_0_M02_AXI [get_bd_intf_pins load_calibration_0/s_axi_control] [get_bd_intf_pins smartconnect_0/M02_AXI] + connect_bd_intf_net -intf_net smartconnect_0_M03_AXI [get_bd_intf_pins axi_bram_ctrl_internal_packet_generator_0/S_AXI] [get_bd_intf_pins smartconnect_0/M03_AXI] + connect_bd_intf_net -intf_net smartconnect_0_M04_AXI [get_bd_intf_pins frame_generator_0/s_axi_control] [get_bd_intf_pins smartconnect_0/M04_AXI] + connect_bd_intf_net -intf_net smartconnect_1_M00_AXI [get_bd_intf_pins m_axi_d_hbm_p0] [get_bd_intf_pins smartconnect_1/M00_AXI] + connect_bd_intf_net -intf_net smartconnect_2_M00_AXI [get_bd_intf_pins m_axi_d_hbm_p2] [get_bd_intf_pins smartconnect_2/M00_AXI] + connect_bd_intf_net -intf_net stream_merge_0_output_r [get_bd_intf_pins axis_eth_in_fifo/S_AXIS] [get_bd_intf_pins stream_merge_0/output_r] + connect_bd_intf_net -intf_net timer_hbm_data_out [get_bd_intf_pins axis_data_fifo_1/S_AXIS] [get_bd_intf_pins timer_hbm/data_out] + connect_bd_intf_net -intf_net timer_host_data_out [get_bd_intf_pins axis_register_slice_data_1/S_AXIS] [get_bd_intf_pins timer_host/data_out] # Create port connections connect_bd_net -net action_config_0_clear_counters [get_bd_pins action_config_0/clear_counters] [get_bd_pins network_stack/clear_counters] - connect_bd_net -net action_config_0_data_collection_cancel [get_bd_pins action_config_0/data_collection_cancel] [get_bd_pins data_collection_fsm_0/in_cancel] [get_bd_pins internal_packet_generator_0/in_cancel] + connect_bd_net -net action_config_0_data_collection_cancel [get_bd_pins action_config_0/data_collection_cancel] [get_bd_pins data_collection_fsm_0/in_cancel] connect_bd_net -net action_config_0_data_collection_fsm_start [get_bd_pins action_config_0/data_collection_start] [get_bd_pins data_collection_fsm_0/in_run] [get_bd_pins network_stack/data_collection_start] connect_bd_net -net action_config_0_data_collection_mode [get_bd_pins action_config_0/data_collection_mode] [get_bd_pins data_collection_fsm_0/mode] - connect_bd_net -net action_config_0_fpga_ipv4_addr [get_bd_pins action_config_0/fpga_ipv4_addr] [get_bd_pins network_stack/fpga_ipv4_addr] - connect_bd_net -net action_config_0_fpga_mac_addr [get_bd_pins action_config_0/fpga_mac_addr] [get_bd_pins network_stack/fpga_mac_addr] + connect_bd_net -net action_config_0_fpga_ipv4_addr [get_bd_pins action_config_0/fpga_ipv4_addr] [get_bd_pins frame_generator_0/src_ipv4_addr] [get_bd_pins network_stack/fpga_ipv4_addr] + connect_bd_net -net action_config_0_fpga_mac_addr [get_bd_pins action_config_0/fpga_mac_addr] [get_bd_pins frame_generator_0/src_mac_addr] [get_bd_pins network_stack/fpga_mac_addr] connect_bd_net -net action_config_0_frames_per_trigger [get_bd_pins action_config_0/nframes] [get_bd_pins data_collection_fsm_0/nframes] + connect_bd_net -net action_config_0_hbm_size_bytes [get_bd_pins action_config_0/hbm_size_bytes] [get_bd_pins data_collection_fsm_0/hbm_size_bytes] [get_bd_pins load_calibration_0/hbm_size_bytes] connect_bd_net -net action_config_0_nmodules [get_bd_pins action_config_0/nmodules] [get_bd_pins data_collection_fsm_0/nmodules] connect_bd_net -net action_config_0_nstorage_cells [get_bd_pins action_config_0/nstorage_cells] [get_bd_pins data_collection_fsm_0/nstorage_cells] connect_bd_net -net action_config_0_one_over_energy [get_bd_pins action_config_0/one_over_energy] [get_bd_pins data_collection_fsm_0/one_over_energy] - connect_bd_net -net ap_clk_1 [get_bd_pins axi_clk] [get_bd_pins action_config_0/clk] [get_bd_pins axi_bram_ctrl_0/s_axi_aclk] [get_bd_pins axis_addr_fifo_0/s_axis_aclk] [get_bd_pins axis_addr_fifo_1/s_axis_aclk] [get_bd_pins axis_addr_fifo_2/s_axis_aclk] [get_bd_pins axis_data_fifo_0/s_axis_aclk] [get_bd_pins axis_data_fifo_1/s_axis_aclk] [get_bd_pins axis_data_fifo_2/s_axis_aclk] [get_bd_pins axis_data_fifo_3/s_axis_aclk] [get_bd_pins axis_data_fifo_4/s_axis_aclk] [get_bd_pins axis_data_fifo_5/s_axis_aclk] [get_bd_pins axis_data_fifo_c2h_cmd/s_axis_aclk] [get_bd_pins axis_data_fifo_c2h_data/s_axis_aclk] [get_bd_pins axis_data_fifo_h2c_cmd/s_axis_aclk] [get_bd_pins axis_data_fifo_h2c_data/s_axis_aclk] [get_bd_pins axis_register_slice_addr_0/aclk] [get_bd_pins axis_register_slice_addr_1/aclk] [get_bd_pins axis_register_slice_data_0/aclk] [get_bd_pins axis_register_slice_data_1/aclk] [get_bd_pins axis_register_slice_data_in_0/aclk] [get_bd_pins axis_register_slice_host_mem/aclk] [get_bd_pins axis_register_slice_udp/aclk] [get_bd_pins axis_udp_addr_fifo_0/s_axis_aclk] [get_bd_pins axis_udp_fifo_0/s_axis_aclk] [get_bd_pins axis_work_completion_fifo_0/s_axis_aclk] [get_bd_pins axis_work_request_fifo_0/s_axis_aclk] [get_bd_pins data_collection_fsm_0/ap_clk] [get_bd_pins host_writer_0/ap_clk] [get_bd_pins internal_packet_generator_0/ap_clk] [get_bd_pins jf_conversion_0/ap_clk] [get_bd_pins load_calibration_0/ap_clk] [get_bd_pins mailbox_0/M1_AXIS_ACLK] [get_bd_pins mailbox_0/S0_AXI_ACLK] [get_bd_pins mailbox_0/S1_AXIS_ACLK] [get_bd_pins network_stack/axiclk] [get_bd_pins smartconnect_0/aclk] [get_bd_pins timer_hbm_0/ap_clk] [get_bd_pins timer_host_0/ap_clk] - connect_bd_net -net apb_complete_1 [get_bd_pins apb_complete] [get_bd_pins action_config_0/apb_complete_0] - connect_bd_net -net axilite_ctrl_infrastructure_qsfp_led_busy [get_bd_pins qsfp_led_busy] [get_bd_pins action_config_0/qsfp_led_busy] - connect_bd_net -net axilite_ctrl_infrastructure_qsfp_led_conn [get_bd_pins qsfp_led_conn] [get_bd_pins action_config_0/qsfp_led_conn] - connect_bd_net -net aximm_host_infrastructure_err_encountered [get_bd_pins mm2s_error] [get_bd_pins action_config_0/mm2s_error] - connect_bd_net -net aximm_host_infrastructure_err_encountered1 [get_bd_pins s2mm_error] [get_bd_pins action_config_0/s2mm_error] - connect_bd_net -net axis_addr_fifo_2_almost_empty [get_bd_pins action_config_0/calib_addr_fifo_empty] [get_bd_pins axis_addr_fifo_1/almost_empty] - connect_bd_net -net axis_addr_fifo_2_almost_full [get_bd_pins action_config_0/calib_addr_fifo_full] [get_bd_pins axis_addr_fifo_1/almost_full] - connect_bd_net -net axis_addr_fifo_4_almost_empty [get_bd_pins action_config_0/last_addr_fifo_empty] [get_bd_pins axis_addr_fifo_2/almost_empty] - connect_bd_net -net axis_addr_fifo_4_almost_full [get_bd_pins action_config_0/last_addr_fifo_full] [get_bd_pins axis_addr_fifo_2/almost_full] - connect_bd_net -net axis_data_fifo_10_almost_empty [get_bd_pins action_config_0/last_data_fifo_empty] [get_bd_pins axis_data_fifo_5/almost_empty] - connect_bd_net -net axis_data_fifo_10_almost_full [get_bd_pins action_config_0/last_data_fifo_full] [get_bd_pins axis_data_fifo_5/almost_full] - connect_bd_net -net axis_data_fifo_4_almost_empty [get_bd_pins action_config_0/calib_data_fifo_empty] [get_bd_pins axis_data_fifo_3/almost_empty] - connect_bd_net -net axis_data_fifo_4_almost_full [get_bd_pins action_config_0/calib_data_fifo_full] [get_bd_pins axis_data_fifo_3/almost_full] - connect_bd_net -net axis_data_fifo_c2h_cmd_almost_empty [get_bd_pins action_config_0/host_mem_cmd_fifo_empty] [get_bd_pins axis_data_fifo_c2h_cmd/almost_empty] - connect_bd_net -net axis_data_fifo_c2h_cmd_almost_full [get_bd_pins action_config_0/host_mem_cmd_fifo_full] [get_bd_pins axis_data_fifo_c2h_cmd/almost_full] - connect_bd_net -net axis_data_fifo_c2h_data_almost_empty [get_bd_pins action_config_0/host_mem_data_fifo_empty] [get_bd_pins axis_data_fifo_c2h_data/almost_empty] - connect_bd_net -net axis_data_fifo_c2h_data_almost_full [get_bd_pins action_config_0/host_mem_data_fifo_full] [get_bd_pins axis_data_fifo_c2h_data/almost_full] + connect_bd_net -net ap_clk_1 [get_bd_pins axi_clk] [get_bd_pins action_config_0/clk] [get_bd_pins axi_bram_ctrl_internal_packet_generator_0/s_axi_aclk] [get_bd_pins axi_bram_ctrl_internal_packet_generator_1/s_axi_aclk] [get_bd_pins axis_addr_fifo_0/s_axis_aclk] [get_bd_pins axis_addr_fifo_1/s_axis_aclk] [get_bd_pins axis_data_fifo_0/s_axis_aclk] [get_bd_pins axis_data_fifo_1/s_axis_aclk] [get_bd_pins axis_data_fifo_2/s_axis_aclk] [get_bd_pins axis_data_fifo_3/s_axis_aclk] [get_bd_pins axis_data_fifo_c2h_cmd/s_axis_aclk] [get_bd_pins axis_data_fifo_c2h_data/s_axis_aclk] [get_bd_pins axis_data_fifo_h2c_cmd/s_axis_aclk] [get_bd_pins axis_data_fifo_h2c_data/s_axis_aclk] [get_bd_pins axis_eth_in_fifo/s_axis_aclk] [get_bd_pins axis_frame_generator_fifo_0/s_axis_aclk] [get_bd_pins axis_register_slice_addr_1/aclk] [get_bd_pins axis_register_slice_data_1/aclk] [get_bd_pins axis_register_slice_data_in_0/aclk] [get_bd_pins axis_register_slice_host_mem/aclk] [get_bd_pins axis_register_slice_udp/aclk] [get_bd_pins axis_udp_addr_fifo_0/s_axis_aclk] [get_bd_pins axis_udp_fifo_0/s_axis_aclk] [get_bd_pins axis_work_completion_fifo_0/s_axis_aclk] [get_bd_pins axis_work_request_fifo_0/s_axis_aclk] [get_bd_pins data_collection_fsm_0/ap_clk] [get_bd_pins frame_generator_0/ap_clk] [get_bd_pins host_writer_0/ap_clk] [get_bd_pins jf_conversion_0/ap_clk] [get_bd_pins load_calibration_0/ap_clk] [get_bd_pins mailbox_0/M1_AXIS_ACLK] [get_bd_pins mailbox_0/S0_AXI_ACLK] [get_bd_pins mailbox_0/S1_AXIS_ACLK] [get_bd_pins network_stack/axiclk] [get_bd_pins smartconnect_0/aclk] [get_bd_pins smartconnect_1/aclk] [get_bd_pins smartconnect_2/aclk] [get_bd_pins stream_merge_0/ap_clk] [get_bd_pins timer_hbm/ap_clk] [get_bd_pins timer_host/ap_clk] + connect_bd_net -net axis_addr_fifo_0_almost_empty [get_bd_pins action_config_0/calib_addr_fifo_empty] [get_bd_pins axis_addr_fifo_0/almost_empty] + connect_bd_net -net axis_addr_fifo_0_almost_full [get_bd_pins action_config_0/calib_addr_fifo_full] [get_bd_pins axis_addr_fifo_0/almost_full] + connect_bd_net -net axis_addr_fifo_4_almost_empty [get_bd_pins action_config_0/last_addr_fifo_empty] [get_bd_pins axis_addr_fifo_1/almost_empty] + connect_bd_net -net axis_addr_fifo_4_almost_full [get_bd_pins action_config_0/last_addr_fifo_full] [get_bd_pins axis_addr_fifo_1/almost_full] + connect_bd_net -net axis_data_fifo_10_almost_empty [get_bd_pins action_config_0/last_data_fifo_empty] [get_bd_pins axis_data_fifo_3/almost_empty] + connect_bd_net -net axis_data_fifo_10_almost_full [get_bd_pins action_config_0/last_data_fifo_full] [get_bd_pins axis_data_fifo_3/almost_full] + connect_bd_net -net axis_data_fifo_4_almost_empty [get_bd_pins action_config_0/calib_data_fifo_empty] [get_bd_pins axis_data_fifo_1/almost_empty] + connect_bd_net -net axis_data_fifo_4_almost_full [get_bd_pins action_config_0/calib_data_fifo_full] [get_bd_pins axis_data_fifo_1/almost_full] + connect_bd_net -net axis_data_fifo_c2h_cmd_almost_empty [get_bd_pins action_config_0/c2h_cmd_fifo_empty] [get_bd_pins axis_data_fifo_c2h_cmd/almost_empty] + connect_bd_net -net axis_data_fifo_c2h_cmd_almost_full [get_bd_pins action_config_0/c2h_cmd_fifo_full] [get_bd_pins axis_data_fifo_c2h_cmd/almost_full] + connect_bd_net -net axis_data_fifo_c2h_data_almost_empty [get_bd_pins action_config_0/c2h_data_fifo_empty] [get_bd_pins axis_data_fifo_c2h_data/almost_empty] + connect_bd_net -net axis_data_fifo_c2h_data_almost_full [get_bd_pins action_config_0/c2h_data_fifo_full] [get_bd_pins axis_data_fifo_c2h_data/almost_full] + connect_bd_net -net axis_data_fifo_h2c_cmd_almost_empty [get_bd_pins action_config_0/h2c_cmd_fifo_empty] [get_bd_pins axis_data_fifo_h2c_cmd/almost_empty] + connect_bd_net -net axis_data_fifo_h2c_cmd_almost_full [get_bd_pins action_config_0/h2c_cmd_fifo_full] [get_bd_pins axis_data_fifo_h2c_cmd/almost_full] + connect_bd_net -net axis_data_fifo_h2c_data_almost_empty [get_bd_pins action_config_0/h2c_data_fifo_empty] [get_bd_pins axis_data_fifo_h2c_data/almost_empty] + connect_bd_net -net axis_data_fifo_h2c_data_almost_full [get_bd_pins action_config_0/h2c_data_fifo_full] [get_bd_pins axis_data_fifo_h2c_data/almost_full] + connect_bd_net -net axis_eth_in_fifo_almost_empty [get_bd_pins action_config_0/eth_in_fifo_empty] [get_bd_pins axis_eth_in_fifo/almost_empty] + connect_bd_net -net axis_eth_in_fifo_almost_full [get_bd_pins action_config_0/eth_in_fifo_full] [get_bd_pins axis_eth_in_fifo/almost_full] + connect_bd_net -net axis_frame_generator_fifo_0_almost_empty [get_bd_pins action_config_0/frame_generator_fifo_empty] [get_bd_pins axis_frame_generator_fifo_0/almost_empty] + connect_bd_net -net axis_frame_generator_fifo_0_almost_full [get_bd_pins action_config_0/frame_generator_fifo_full] [get_bd_pins axis_frame_generator_fifo_0/almost_full] connect_bd_net -net axis_udp_fifo_0_almost_empty [get_bd_pins action_config_0/udp_fifo_empty] [get_bd_pins axis_udp_fifo_0/almost_empty] connect_bd_net -net axis_udp_fifo_0_almost_full [get_bd_pins action_config_0/udp_fifo_full] [get_bd_pins axis_udp_fifo_0/almost_full] connect_bd_net -net axis_work_completion_fifo_0_almost_empty [get_bd_pins action_config_0/work_compl_fifo_empty] [get_bd_pins axis_work_completion_fifo_0/almost_empty] @@ -444,14 +453,9 @@ proc create_hier_cell_jungfraujoch { parentCell nameHier } { connect_bd_net -net axis_work_request_fifo_0_almost_empty [get_bd_pins action_config_0/work_req_fifo_empty] [get_bd_pins axis_work_request_fifo_0/almost_empty] connect_bd_net -net axis_work_request_fifo_0_almost_full [get_bd_pins action_config_0/work_req_fifo_full] [get_bd_pins axis_work_request_fifo_0/almost_full] connect_bd_net -net data_collection_fsm_0_out_idle_V [get_bd_pins action_config_0/data_collection_idle] [get_bd_pins data_collection_fsm_0/out_idle] - connect_bd_net -net eth_busy_1 [get_bd_pins eth_busy] [get_bd_pins action_config_0/eth_busy] - connect_bd_net -net eth_stat_rx_aligned_1 [get_bd_pins eth_stat_rx_aligned] [get_bd_pins action_config_0/eth_stat_rx_aligned] - connect_bd_net -net eth_stat_rx_packet_bad_fcs_1 [get_bd_pins eth_stat_rx_packet_bad_fcs] [get_bd_pins action_config_0/eth_stat_rx_packet_bad_fcs] - connect_bd_net -net eth_stat_rx_status_1 [get_bd_pins eth_stat_rx_status] [get_bd_pins action_config_0/eth_stat_rx_status] - connect_bd_net -net hbm_temp_trip_1 [get_bd_pins hbm_temp_trip] [get_bd_pins action_config_0/hbm_temp_trip] - connect_bd_net -net hbm_temperature_1 [get_bd_pins hbm_temperature] [get_bd_pins action_config_0/hbm_temperature] connect_bd_net -net host_writer_0_err_reg_V [get_bd_pins action_config_0/host_writer_err] [get_bd_pins host_writer_0/err_reg] connect_bd_net -net host_writer_0_err_reg_V_ap_vld [get_bd_pins action_config_0/host_writer_err_valid] [get_bd_pins host_writer_0/err_reg_ap_vld] + connect_bd_net -net host_writer_0_idle [get_bd_pins action_config_0/host_writer_idle] [get_bd_pins host_writer_0/idle] connect_bd_net -net host_writer_0_packets_processed [get_bd_pins action_config_0/packets_processed] [get_bd_pins host_writer_0/packets_processed] connect_bd_net -net host_writer_0_packets_processed_ap_vld [get_bd_pins action_config_0/packets_processed_valid] [get_bd_pins host_writer_0/packets_processed_ap_vld] connect_bd_net -net mailbox_0_Interrupt_0 [get_bd_pins action_config_0/mailbox_interrupt_0] [get_bd_pins mailbox_0/Interrupt_0] @@ -468,13 +472,13 @@ proc create_hier_cell_jungfraujoch { parentCell nameHier } { connect_bd_net -net network_stack_packets_sls_ap_vld [get_bd_pins action_config_0/packets_sls_valid] [get_bd_pins network_stack/packets_sls_ap_vld] connect_bd_net -net network_stack_packets_udp [get_bd_pins action_config_0/packets_udp] [get_bd_pins network_stack/packets_udp] connect_bd_net -net network_stack_packets_udp_ap_vld [get_bd_pins action_config_0/packets_udp_valid] [get_bd_pins network_stack/packets_udp_ap_vld] - connect_bd_net -net reset_axi [get_bd_pins axi_rst_n] [get_bd_pins action_config_0/resetn] [get_bd_pins axis_addr_fifo_0/s_axis_aresetn] [get_bd_pins axis_addr_fifo_1/s_axis_aresetn] [get_bd_pins axis_addr_fifo_2/s_axis_aresetn] [get_bd_pins axis_data_fifo_0/s_axis_aresetn] [get_bd_pins axis_data_fifo_1/s_axis_aresetn] [get_bd_pins axis_data_fifo_2/s_axis_aresetn] [get_bd_pins axis_data_fifo_3/s_axis_aresetn] [get_bd_pins axis_data_fifo_4/s_axis_aresetn] [get_bd_pins axis_data_fifo_5/s_axis_aresetn] [get_bd_pins axis_data_fifo_c2h_cmd/s_axis_aresetn] [get_bd_pins axis_data_fifo_c2h_data/s_axis_aresetn] [get_bd_pins axis_data_fifo_h2c_cmd/s_axis_aresetn] [get_bd_pins axis_data_fifo_h2c_data/s_axis_aresetn] [get_bd_pins axis_register_slice_addr_0/aresetn] [get_bd_pins axis_register_slice_addr_1/aresetn] [get_bd_pins axis_register_slice_data_0/aresetn] [get_bd_pins axis_register_slice_data_1/aresetn] [get_bd_pins axis_register_slice_data_in_0/aresetn] [get_bd_pins axis_register_slice_host_mem/aresetn] [get_bd_pins axis_register_slice_udp/aresetn] [get_bd_pins axis_udp_addr_fifo_0/s_axis_aresetn] [get_bd_pins axis_udp_fifo_0/s_axis_aresetn] [get_bd_pins axis_work_completion_fifo_0/s_axis_aresetn] [get_bd_pins axis_work_request_fifo_0/s_axis_aresetn] [get_bd_pins network_stack/resetn] [get_bd_pins smartconnect_0/aresetn] - connect_bd_net -net reset_hls [get_bd_pins ap_rst_n] [get_bd_pins axi_bram_ctrl_0/s_axi_aresetn] [get_bd_pins data_collection_fsm_0/ap_rst_n] [get_bd_pins host_writer_0/ap_rst_n] [get_bd_pins internal_packet_generator_0/ap_rst_n] [get_bd_pins jf_conversion_0/ap_rst_n] [get_bd_pins load_calibration_0/ap_rst_n] [get_bd_pins mailbox_0/S0_AXI_ARESETN] [get_bd_pins network_stack/ap_rst_n] [get_bd_pins timer_hbm_0/ap_rst_n] [get_bd_pins timer_host_0/ap_rst_n] - connect_bd_net -net timer_hbm_0_counter [get_bd_pins action_config_0/stalls_hbm] [get_bd_pins timer_hbm_0/counter] - connect_bd_net -net timer_hbm_0_counter_ap_vld [get_bd_pins action_config_0/stalls_hbm_valid] [get_bd_pins timer_hbm_0/counter_ap_vld] - connect_bd_net -net timer_host_0_counter [get_bd_pins action_config_0/stalls_host] [get_bd_pins timer_host_0/counter] - connect_bd_net -net timer_host_0_counter_ap_vld [get_bd_pins action_config_0/stalls_host_valid] [get_bd_pins timer_host_0/counter_ap_vld] + connect_bd_net -net reset_axi [get_bd_pins axi_rst_n] [get_bd_pins action_config_0/resetn] [get_bd_pins axis_addr_fifo_0/s_axis_aresetn] [get_bd_pins axis_addr_fifo_1/s_axis_aresetn] [get_bd_pins axis_data_fifo_0/s_axis_aresetn] [get_bd_pins axis_data_fifo_1/s_axis_aresetn] [get_bd_pins axis_data_fifo_2/s_axis_aresetn] [get_bd_pins axis_data_fifo_3/s_axis_aresetn] [get_bd_pins axis_data_fifo_c2h_cmd/s_axis_aresetn] [get_bd_pins axis_data_fifo_c2h_data/s_axis_aresetn] [get_bd_pins axis_data_fifo_h2c_cmd/s_axis_aresetn] [get_bd_pins axis_data_fifo_h2c_data/s_axis_aresetn] [get_bd_pins axis_eth_in_fifo/s_axis_aresetn] [get_bd_pins axis_frame_generator_fifo_0/s_axis_aresetn] [get_bd_pins axis_register_slice_addr_1/aresetn] [get_bd_pins axis_register_slice_data_1/aresetn] [get_bd_pins axis_register_slice_data_in_0/aresetn] [get_bd_pins axis_register_slice_host_mem/aresetn] [get_bd_pins axis_register_slice_udp/aresetn] [get_bd_pins axis_udp_addr_fifo_0/s_axis_aresetn] [get_bd_pins axis_udp_fifo_0/s_axis_aresetn] [get_bd_pins axis_work_completion_fifo_0/s_axis_aresetn] [get_bd_pins axis_work_request_fifo_0/s_axis_aresetn] [get_bd_pins network_stack/resetn] [get_bd_pins smartconnect_0/aresetn] [get_bd_pins smartconnect_1/aresetn] [get_bd_pins smartconnect_2/aresetn] + connect_bd_net -net reset_hls [get_bd_pins ap_rst_n] [get_bd_pins axi_bram_ctrl_internal_packet_generator_0/s_axi_aresetn] [get_bd_pins axi_bram_ctrl_internal_packet_generator_1/s_axi_aresetn] [get_bd_pins data_collection_fsm_0/ap_rst_n] [get_bd_pins frame_generator_0/ap_rst_n] [get_bd_pins host_writer_0/ap_rst_n] [get_bd_pins jf_conversion_0/ap_rst_n] [get_bd_pins load_calibration_0/ap_rst_n] [get_bd_pins mailbox_0/S0_AXI_ARESETN] [get_bd_pins network_stack/ap_rst_n] [get_bd_pins stream_merge_0/ap_rst_n] [get_bd_pins timer_hbm/ap_rst_n] [get_bd_pins timer_host/ap_rst_n] + connect_bd_net -net timer_hbm_counter [get_bd_pins action_config_0/stalls_hbm] [get_bd_pins timer_hbm/counter] + connect_bd_net -net timer_hbm_counter_ap_vld [get_bd_pins action_config_0/stalls_hbm_valid] [get_bd_pins timer_hbm/counter_ap_vld] + connect_bd_net -net timer_host_counter [get_bd_pins action_config_0/stalls_host] [get_bd_pins timer_host/counter] + connect_bd_net -net timer_host_counter_ap_vld [get_bd_pins action_config_0/stalls_host_valid] [get_bd_pins timer_host/counter_ap_vld] # Restore current instance current_bd_instance $oldCurInst -} \ No newline at end of file +} diff --git a/receiver/scripts/mac_100g_pcie.tcl b/fpga/scripts/mac_100g_pcie.tcl similarity index 99% rename from receiver/scripts/mac_100g_pcie.tcl rename to fpga/scripts/mac_100g_pcie.tcl index 0a157394..8a6f64c5 100644 --- a/receiver/scripts/mac_100g_pcie.tcl +++ b/fpga/scripts/mac_100g_pcie.tcl @@ -1,5 +1,4 @@ -## Copyright (2019-2022) Paul Scherrer Institute -## SPDX-License-Identifier: CERN-OHL-S-2.0 +## Copyright (2019-2023) Paul Scherrer Institute # Hierarchical cell: mac_100g proc create_hier_cell_mac_100g { parentCell nameHier } { diff --git a/receiver/scripts/network_stack.tcl b/fpga/scripts/network_stack.tcl similarity index 99% rename from receiver/scripts/network_stack.tcl rename to fpga/scripts/network_stack.tcl index fb5b842a..3fe69d9e 100644 --- a/receiver/scripts/network_stack.tcl +++ b/fpga/scripts/network_stack.tcl @@ -1,5 +1,4 @@ -## Copyright (2019-2022) Paul Scherrer Institute -## SPDX-License-Identifier: CERN-OHL-S-2.0 +## Copyright (2019-2023) Paul Scherrer Institute # Hierarchical cell: network_stack proc create_hier_cell_network_stack { parentCell nameHier } { diff --git a/fpga/scripts/pcie_dma.tcl b/fpga/scripts/pcie_dma.tcl new file mode 100644 index 00000000..ad976b87 --- /dev/null +++ b/fpga/scripts/pcie_dma.tcl @@ -0,0 +1,221 @@ +## Copyright (2019-2023) Paul Scherrer Institute + +# Hierarchical cell: pcie_dma_0 +proc create_hier_cell_pcie_dma_0 { parentCell nameHier } { + + variable script_folder + + if { $parentCell eq "" || $nameHier eq "" } { + catch {common::send_gid_msg -ssname BD::TCL -id 2092 -severity "ERROR" "create_hier_cell_pcie_dma() - Empty argument(s)!"} + return + } + + # Get object for parentCell + set parentObj [get_bd_cells $parentCell] + if { $parentObj == "" } { + catch {common::send_gid_msg -ssname BD::TCL -id 2090 -severity "ERROR" "Unable to find parent cell <$parentCell>!"} + return + } + + # Make sure parentObj is hier blk + set parentType [get_property TYPE $parentObj] + if { $parentType ne "hier" } { + catch {common::send_gid_msg -ssname BD::TCL -id 2091 -severity "ERROR" "Parent <$parentObj> has TYPE = <$parentType>. Expected to be ."} + return + } + + # Save current instance; Restore later + set oldCurInst [current_bd_instance .] + + # Set parent object as current + current_bd_instance $parentObj + + # Create cell and set as current instance + set hier_obj [create_bd_cell -type hier $nameHier] + current_bd_instance $hier_obj + + # Create interface pins + create_bd_intf_pin -mode Master -vlnv xilinx.com:interface:aximm_rtl:1.0 m_axi_ctrl + + create_bd_intf_pin -mode Master -vlnv xilinx.com:interface:axis_rtl:1.0 m_axis_h2c_data + + create_bd_intf_pin -mode Master -vlnv xilinx.com:interface:pcie_7x_mgt_rtl:1.0 pcie_mgt + + create_bd_intf_pin -mode Slave -vlnv xilinx.com:interface:diff_clock_rtl:1.0 pcie_refclk + + create_bd_intf_pin -mode Slave -vlnv xilinx.com:interface:aximm_rtl:1.0 s_axi_dma_ctrl + + create_bd_intf_pin -mode Slave -vlnv xilinx.com:interface:axis_rtl:1.0 s_axis_c2h_cmd + + create_bd_intf_pin -mode Slave -vlnv xilinx.com:interface:axis_rtl:1.0 s_axis_c2h_data + + create_bd_intf_pin -mode Slave -vlnv xilinx.com:interface:axis_rtl:1.0 s_axis_h2c_cmd + + + # Create pins + create_bd_pin -dir O -type clk axi_aclk + create_bd_pin -dir O -type rst axi_aresetn + create_bd_pin -dir I -type rst axi_clk_resetn + create_bd_pin -dir I -type rst pcie_perstn + create_bd_pin -dir I -type clk refclk200 + create_bd_pin -dir I -type rst refclk200_resetn + create_bd_pin -dir I usr_irq_req + + # Create instance: axi_firewall_0, and set properties + set axi_firewall_0 [ create_bd_cell -type ip -vlnv xilinx.com:ip:axi_firewall:1.2 axi_firewall_0 ] + + # Create instance: axis_clock_converter_c2h_cmd, and set properties + set axis_clock_converter_c2h_cmd [ create_bd_cell -type ip -vlnv xilinx.com:ip:axis_clock_converter:1.1 axis_clock_converter_c2h_cmd ] + set_property -dict [ list \ + CONFIG.SYNCHRONIZATION_STAGES {3} \ + ] $axis_clock_converter_c2h_cmd + + # Create instance: axis_clock_converter_c2h_data, and set properties + set axis_clock_converter_c2h_data [ create_bd_cell -type ip -vlnv xilinx.com:ip:axis_clock_converter:1.1 axis_clock_converter_c2h_data ] + set_property -dict [ list \ + CONFIG.SYNCHRONIZATION_STAGES {3} \ + ] $axis_clock_converter_c2h_data + + # Create instance: axis_clock_converter_h2c_cmd, and set properties + set axis_clock_converter_h2c_cmd [ create_bd_cell -type ip -vlnv xilinx.com:ip:axis_clock_converter:1.1 axis_clock_converter_h2c_cmd ] + set_property -dict [ list \ + CONFIG.SYNCHRONIZATION_STAGES {3} \ + ] $axis_clock_converter_h2c_cmd + + # Create instance: axis_clock_converter_h2c_data, and set properties + set axis_clock_converter_h2c_data [ create_bd_cell -type ip -vlnv xilinx.com:ip:axis_clock_converter:1.1 axis_clock_converter_h2c_data ] + set_property -dict [ list \ + CONFIG.SYNCHRONIZATION_STAGES {3} \ + ] $axis_clock_converter_h2c_data + + # Create instance: gen_xdma_descriptor_c2h, and set properties + set block_name gen_xdma_descriptor + set block_cell_name gen_xdma_descriptor_c2h + if { [catch {set gen_xdma_descriptor_c2h [create_bd_cell -type module -reference $block_name $block_cell_name] } errmsg] } { + catch {common::send_gid_msg -ssname BD::TCL -id 2095 -severity "ERROR" "Unable to add referenced block <$block_name>. Please add the files for ${block_name}'s definition into the project."} + return 1 + } elseif { $gen_xdma_descriptor_c2h eq "" } { + catch {common::send_gid_msg -ssname BD::TCL -id 2096 -severity "ERROR" "Unable to referenced block <$block_name>. Please add the files for ${block_name}'s definition into the project."} + return 1 + } + + # Create instance: gen_xdma_descriptor_h2c, and set properties + set block_name gen_xdma_descriptor + set block_cell_name gen_xdma_descriptor_h2c + if { [catch {set gen_xdma_descriptor_h2c [create_bd_cell -type module -reference $block_name $block_cell_name] } errmsg] } { + catch {common::send_gid_msg -ssname BD::TCL -id 2095 -severity "ERROR" "Unable to add referenced block <$block_name>. Please add the files for ${block_name}'s definition into the project."} + return 1 + } elseif { $gen_xdma_descriptor_h2c eq "" } { + catch {common::send_gid_msg -ssname BD::TCL -id 2096 -severity "ERROR" "Unable to referenced block <$block_name>. Please add the files for ${block_name}'s definition into the project."} + return 1 + } + + # Create instance: pcie_clk_buf_inst, and set properties + set pcie_clk_buf_inst [ create_bd_cell -type ip -vlnv xilinx.com:ip:util_ds_buf:2.2 pcie_clk_buf_inst ] + set_property -dict [ list \ + CONFIG.C_BUF_TYPE {IBUFDSGTE} \ + ] $pcie_clk_buf_inst + + # Create instance: smartconnect_0, and set properties + set smartconnect_0 [ create_bd_cell -type ip -vlnv xilinx.com:ip:smartconnect:1.0 smartconnect_0 ] + set_property -dict [ list \ + CONFIG.NUM_MI {2} \ + CONFIG.NUM_SI {1} \ + ] $smartconnect_0 + + # Create instance: xdma_0, and set properties + set xdma_0 [ create_bd_cell -type ip -vlnv xilinx.com:ip:xdma:4.1 xdma_0 ] + set_property -dict [ list \ + CONFIG.INS_LOSS_NYQ {15} \ + CONFIG.PF0_DEVICE_ID_mqdma {9048} \ + CONFIG.PF0_SRIOV_VF_DEVICE_ID {A048} \ + CONFIG.PF1_SRIOV_VF_DEVICE_ID {A148} \ + CONFIG.PF2_DEVICE_ID_mqdma {9248} \ + CONFIG.PF2_SRIOV_VF_DEVICE_ID {A248} \ + CONFIG.PF3_DEVICE_ID_mqdma {9348} \ + CONFIG.PF3_SRIOV_VF_DEVICE_ID {A348} \ + CONFIG.axi_data_width {512_bit} \ + CONFIG.axi_id_width {2} \ + CONFIG.axil_master_64bit_en {false} \ + CONFIG.axilite_master_en {true} \ + CONFIG.axilite_master_size {16} \ + CONFIG.axisten_freq {250} \ + CONFIG.cfg_mgmt_if {false} \ + CONFIG.copy_pf0 {true} \ + CONFIG.coreclk_freq {500} \ + CONFIG.dsc_bypass_rd {0001} \ + CONFIG.dsc_bypass_wr {0001} \ + CONFIG.en_gt_selection {true} \ + CONFIG.ins_loss_profile {Add-in_Card} \ + CONFIG.mode_selection {Advanced} \ + CONFIG.pcie_blk_locn {PCIE4C_X1Y1} \ + CONFIG.pf0_base_class_menu {Processing_accelerators} \ + CONFIG.pf0_class_code {120000} \ + CONFIG.pf0_class_code_base {12} \ + CONFIG.pf0_class_code_interface {00} \ + CONFIG.pf0_class_code_sub {00} \ + CONFIG.pf0_device_id {9048} \ + CONFIG.pf0_msix_cap_pba_bir {BAR_1} \ + CONFIG.pf0_msix_cap_pba_offset {00008FE0} \ + CONFIG.pf0_msix_cap_table_bir {BAR_1} \ + CONFIG.pf0_msix_cap_table_offset {00008000} \ + CONFIG.pf0_msix_cap_table_size {01F} \ + CONFIG.pf0_msix_enabled {true} \ + CONFIG.pf0_sub_class_interface_menu {Unknown} \ + CONFIG.pf0_subsystem_id {5232} \ + CONFIG.pf0_subsystem_vendor_id {10EE} \ + CONFIG.pf1_msix_cap_pba_offset {00000000} \ + CONFIG.pf1_msix_cap_table_offset {00000000} \ + CONFIG.pf1_msix_cap_table_size {000} \ + CONFIG.pl_link_cap_max_link_speed {16.0_GT/s} \ + CONFIG.pl_link_cap_max_link_width {X8} \ + CONFIG.plltype {QPLL0} \ + CONFIG.runbit_fix {false} \ + CONFIG.select_quad {GTY_Quad_227} \ + CONFIG.vendor_id {10EE} \ + CONFIG.xdma_axi_intf_mm {AXI_Stream} \ + CONFIG.xdma_axilite_slave {true} \ + CONFIG.xdma_wnum_chnl {1} \ + ] $xdma_0 + + # Create interface connections + connect_bd_intf_net -intf_net Conn1 [get_bd_intf_pins s_axis_c2h_cmd] [get_bd_intf_pins axis_clock_converter_c2h_cmd/S_AXIS] + connect_bd_intf_net -intf_net Conn2 [get_bd_intf_pins m_axi_ctrl] [get_bd_intf_pins axi_firewall_0/M_AXI] + connect_bd_intf_net -intf_net Conn3 [get_bd_intf_pins pcie_mgt] [get_bd_intf_pins xdma_0/pcie_mgt] + connect_bd_intf_net -intf_net Conn4 [get_bd_intf_pins s_axis_c2h_data] [get_bd_intf_pins axis_clock_converter_c2h_data/S_AXIS] + connect_bd_intf_net -intf_net Conn5 [get_bd_intf_pins pcie_refclk] [get_bd_intf_pins pcie_clk_buf_inst/CLK_IN_D] + connect_bd_intf_net -intf_net Conn6 [get_bd_intf_pins m_axis_h2c_data] [get_bd_intf_pins axis_clock_converter_h2c_data/M_AXIS] + connect_bd_intf_net -intf_net Conn7 [get_bd_intf_pins s_axis_h2c_cmd] [get_bd_intf_pins axis_clock_converter_h2c_cmd/S_AXIS] + connect_bd_intf_net -intf_net axis_clock_converter_c2h_cmd_M_AXIS [get_bd_intf_pins axis_clock_converter_c2h_cmd/M_AXIS] [get_bd_intf_pins gen_xdma_descriptor_c2h/S_AXIS] + connect_bd_intf_net -intf_net axis_clock_converter_c2h_data_M_AXIS [get_bd_intf_pins axis_clock_converter_c2h_data/M_AXIS] [get_bd_intf_pins xdma_0/S_AXIS_C2H_0] + connect_bd_intf_net -intf_net axis_clock_converter_h2c_cmd_M_AXIS [get_bd_intf_pins axis_clock_converter_h2c_cmd/M_AXIS] [get_bd_intf_pins gen_xdma_descriptor_h2c/S_AXIS] + connect_bd_intf_net -intf_net s_axi_dma_ctrl_1 [get_bd_intf_pins s_axi_dma_ctrl] [get_bd_intf_pins xdma_0/S_AXI_LITE] + connect_bd_intf_net -intf_net smartconnect_0_M00_AXI [get_bd_intf_pins axi_firewall_0/S_AXI] [get_bd_intf_pins smartconnect_0/M00_AXI] + connect_bd_intf_net -intf_net smartconnect_0_M01_AXI [get_bd_intf_pins axi_firewall_0/S_AXI_CTL] [get_bd_intf_pins smartconnect_0/M01_AXI] + connect_bd_intf_net -intf_net xdma_0_M_AXIS_H2C_0 [get_bd_intf_pins axis_clock_converter_h2c_data/S_AXIS] [get_bd_intf_pins xdma_0/M_AXIS_H2C_0] + connect_bd_intf_net -intf_net xdma_0_M_AXI_LITE [get_bd_intf_pins smartconnect_0/S00_AXI] [get_bd_intf_pins xdma_0/M_AXI_LITE] + + # Create port connections + connect_bd_net -net gen_xdma_descriptor_c2h_0_dsc_addr [get_bd_pins gen_xdma_descriptor_c2h/dsc_addr] [get_bd_pins xdma_0/c2h_dsc_byp_dst_addr_0] [get_bd_pins xdma_0/c2h_dsc_byp_src_addr_0] + connect_bd_net -net gen_xdma_descriptor_c2h_0_dsc_ctl [get_bd_pins gen_xdma_descriptor_c2h/dsc_ctl] [get_bd_pins xdma_0/c2h_dsc_byp_ctl_0] + connect_bd_net -net gen_xdma_descriptor_c2h_0_dsc_len [get_bd_pins gen_xdma_descriptor_c2h/dsc_len] [get_bd_pins xdma_0/c2h_dsc_byp_len_0] + connect_bd_net -net gen_xdma_descriptor_c2h_0_dsc_load [get_bd_pins gen_xdma_descriptor_c2h/dsc_load] [get_bd_pins xdma_0/c2h_dsc_byp_load_0] + connect_bd_net -net gen_xdma_descriptor_h2c_0_dsc_addr [get_bd_pins gen_xdma_descriptor_h2c/dsc_addr] [get_bd_pins xdma_0/h2c_dsc_byp_dst_addr_0] [get_bd_pins xdma_0/h2c_dsc_byp_src_addr_0] + connect_bd_net -net gen_xdma_descriptor_h2c_0_dsc_ctl [get_bd_pins gen_xdma_descriptor_h2c/dsc_ctl] [get_bd_pins xdma_0/h2c_dsc_byp_ctl_0] + connect_bd_net -net gen_xdma_descriptor_h2c_0_dsc_len [get_bd_pins gen_xdma_descriptor_h2c/dsc_len] [get_bd_pins xdma_0/h2c_dsc_byp_len_0] + connect_bd_net -net gen_xdma_descriptor_h2c_0_dsc_load [get_bd_pins gen_xdma_descriptor_h2c/dsc_load] [get_bd_pins xdma_0/h2c_dsc_byp_load_0] + connect_bd_net -net pcie_clk_buf_inst_IBUF_DS_ODIV2 [get_bd_pins pcie_clk_buf_inst/IBUF_DS_ODIV2] [get_bd_pins xdma_0/sys_clk] + connect_bd_net -net pcie_clk_buf_inst_IBUF_OUT [get_bd_pins pcie_clk_buf_inst/IBUF_OUT] [get_bd_pins xdma_0/sys_clk_gt] + connect_bd_net -net pcie_perstn_1 [get_bd_pins pcie_perstn] [get_bd_pins xdma_0/sys_rst_n] + connect_bd_net -net net_refclk200 [get_bd_pins refclk200] [get_bd_pins axis_clock_converter_c2h_cmd/s_axis_aclk] [get_bd_pins axis_clock_converter_c2h_data/s_axis_aclk] [get_bd_pins axis_clock_converter_h2c_cmd/s_axis_aclk] [get_bd_pins axis_clock_converter_h2c_data/m_axis_aclk] + connect_bd_net -net net_refclk200_resetn [get_bd_pins refclk200_resetn] [get_bd_pins axis_clock_converter_c2h_cmd/s_axis_aresetn] [get_bd_pins axis_clock_converter_c2h_data/s_axis_aresetn] [get_bd_pins axis_clock_converter_h2c_cmd/s_axis_aresetn] [get_bd_pins axis_clock_converter_h2c_data/m_axis_aresetn] + connect_bd_net -net s_axis_aresetn_1 [get_bd_pins axi_clk_resetn] [get_bd_pins axi_firewall_0/aresetn] [get_bd_pins axis_clock_converter_c2h_cmd/m_axis_aresetn] [get_bd_pins axis_clock_converter_c2h_data/m_axis_aresetn] [get_bd_pins axis_clock_converter_h2c_cmd/m_axis_aresetn] [get_bd_pins axis_clock_converter_h2c_data/s_axis_aresetn] [get_bd_pins gen_xdma_descriptor_c2h/resetn] [get_bd_pins gen_xdma_descriptor_h2c/resetn] [get_bd_pins smartconnect_0/aresetn] + connect_bd_net -net usr_irq_req_1 [get_bd_pins usr_irq_req] [get_bd_pins xdma_0/usr_irq_req] + connect_bd_net -net xdma_0_axi_aclk [get_bd_pins axi_aclk] [get_bd_pins axi_firewall_0/aclk] [get_bd_pins axis_clock_converter_c2h_cmd/m_axis_aclk] [get_bd_pins axis_clock_converter_c2h_data/m_axis_aclk] [get_bd_pins axis_clock_converter_h2c_cmd/m_axis_aclk] [get_bd_pins axis_clock_converter_h2c_data/s_axis_aclk] [get_bd_pins gen_xdma_descriptor_c2h/clk] [get_bd_pins gen_xdma_descriptor_h2c/clk] [get_bd_pins smartconnect_0/aclk] [get_bd_pins xdma_0/axi_aclk] + connect_bd_net -net xdma_0_axi_aresetn [get_bd_pins axi_aresetn] [get_bd_pins xdma_0/axi_aresetn] + connect_bd_net -net xdma_0_c2h_dsc_byp_ready_0 [get_bd_pins gen_xdma_descriptor_c2h/dsc_ready] [get_bd_pins xdma_0/c2h_dsc_byp_ready_0] + connect_bd_net -net xdma_0_h2c_dsc_byp_ready_0 [get_bd_pins gen_xdma_descriptor_h2c/dsc_ready] [get_bd_pins xdma_0/h2c_dsc_byp_ready_0] + + # Restore current instance + current_bd_instance $oldCurInst +} diff --git a/receiver/scripts/setup_action.sh b/fpga/scripts/setup_action.sh similarity index 91% rename from receiver/scripts/setup_action.sh rename to fpga/scripts/setup_action.sh index 11ce5888..8ad1ba63 100644 --- a/receiver/scripts/setup_action.sh +++ b/fpga/scripts/setup_action.sh @@ -26,12 +26,6 @@ clean: echo -n "" EOF -cat < ${SRC_DIR}/oc-accel/snap_env.sh -export ACTION_ROOT=$PWD/action -export TIMING_LABLIMIT="-100" -export OCSE_ROOT=$SRC_DIR/ocse -EOF - cp ${SRC_DIR}/hdl/*.v action/hw/hdl # Update action type and release level based on Definitions.h diff --git a/receiver/scripts/synth_and_impl.tcl b/fpga/scripts/synth_and_impl.tcl similarity index 97% rename from receiver/scripts/synth_and_impl.tcl rename to fpga/scripts/synth_and_impl.tcl index eaa34bb6..f159d4a0 100644 --- a/receiver/scripts/synth_and_impl.tcl +++ b/fpga/scripts/synth_and_impl.tcl @@ -1,5 +1,4 @@ -## Copyright (2019-2022) Paul Scherrer Institute -## SPDX-License-Identifier: CERN-OHL-S-2.0 +## Copyright (2019-2023) Paul Scherrer Institute ## open_project $::env(VIV_PROJECT_PATH) diff --git a/receiver/scripts/synth_hls_function.tcl b/fpga/scripts/synth_hls_function.tcl similarity index 85% rename from receiver/scripts/synth_hls_function.tcl rename to fpga/scripts/synth_hls_function.tcl index c53c2881..c940b88b 100644 --- a/receiver/scripts/synth_hls_function.tcl +++ b/fpga/scripts/synth_hls_function.tcl @@ -1,5 +1,4 @@ -## Copyright (2019-2022) Paul Scherrer Institute -## SPDX-License-Identifier: CERN-OHL-S-2.0 +## Copyright (2019-2023) Paul Scherrer Institute open_project $env(HLS_TOP_FUNCTION) -reset diff --git a/receiver/xdc/pcie_timing.xdc b/fpga/xdc/pcie_timing.xdc similarity index 100% rename from receiver/xdc/pcie_timing.xdc rename to fpga/xdc/pcie_timing.xdc diff --git a/receiver/xdc/pcie_u55c.xdc b/fpga/xdc/pcie_u55c.xdc similarity index 100% rename from receiver/xdc/pcie_u55c.xdc rename to fpga/xdc/pcie_u55c.xdc diff --git a/frame_serialize/CBORMessages.h b/frame_serialize/CBORMessages.h new file mode 100644 index 00000000..897aff29 --- /dev/null +++ b/frame_serialize/CBORMessages.h @@ -0,0 +1,156 @@ +// Copyright (2019-2023) Paul Scherrer Institute + +#ifndef JUNGFRAUJOCH_CBORMESSAGES_H +#define JUNGFRAUJOCH_CBORMESSAGES_H + +#include +#include +#include +#include +#include "../compression/CompressionAlgorithmEnum.h" +#include "../common/SpotToSave.h" + +constexpr const uint64_t user_data_release = 1; +constexpr const uint64_t user_data_magic_number = 0x52320000UL | user_data_release; + +struct CBORImage { + const uint8_t *data; + size_t size; // Including compression + size_t xpixel; + size_t ypixel; + size_t pixel_depth_bytes; + bool pixel_is_signed; + bool pixel_is_float = false; + CompressionAlgorithm algorithm; + std::string channel; +}; + +struct DataMessage { + int64_t number = INT64_MIN; + CBORImage image; + std::vector spots; + std::vector rad_int_profile; + uint64_t indexing_result; // 0 - not tried, 1 - tried and failed, 2 - tried and success + std::vector indexing_lattice; + + uint64_t bunch_id; + uint32_t jf_info; + float receiver_available_send_buffers; + int64_t receiver_aq_dev_delay; + + uint64_t timestamp; + uint32_t timestamp_base; + + uint32_t storage_cell; + + uint32_t exptime; + uint32_t exptime_base; + + std::string series_unique_id; + uint64_t series_id; +}; + +struct GoniometerAxis { + float increment; + float start; +}; + +struct StartMessage { + uint64_t data_file_count; // user data + + float detector_distance; + float beam_center_x; + float beam_center_y; + + uint64_t number_of_images; + + uint64_t image_size_x; + uint64_t image_size_y; + uint64_t pixel_bit_depth; // user data + bool pixel_signed; // user data + + float incident_energy; + float incident_wavelength; + + float frame_time; + float count_time; + + int64_t saturation_value; + int64_t min_value; // user data + + float pixel_size_x; + float pixel_size_y; + float sensor_thickness; + std::string sensor_material; + + CompressionAlgorithm compression_algorithm; // user data + uint64_t compression_block_size; // user data + + float unit_cell[6]; // user data + uint64_t space_group_number; // user data + uint64_t max_spot_count; // user data + + uint64_t storage_cell_number; // user data + uint64_t storage_cell_delay_ns; + + bool pixel_mask_enabled; + + std::string arm_date; + + std::string sample_name; // user data + std::string file_prefix; // user data + + std::vector channels; + + std::string detector_description; + std::string detector_serial_number; + std::string series_unique_id; + uint64_t series_id; + + std::map goniometer; + float detector_translation[3]; + + std::string source_name; + std::string source_name_short; + std::string instrument_name; + std::string instrument_name_short; + + uint64_t rad_int_bin_number; + uint64_t summation; + + std::vector rad_int_bin_to_q; + std::vector rad_int_solid_angle_corr; + + std::vector pixel_mask; + std::vector calibration; + + size_t approx_size = 1024*1024; + + // Use function below to update approx_size + void AddPixelMask(CBORImage image) { + approx_size += image.size; + pixel_mask.emplace_back(std::move(image)); + } + + void AddCalibration(CBORImage image) { + approx_size += image.size; + calibration.emplace_back(std::move(image)); + } +}; + +struct EndMessage { + uint64_t number_of_images; + uint64_t max_receiver_delay; + float efficiency; + + bool write_master_file; + + std::string end_date; + + std::string series_unique_id; + uint64_t series_id; + + std::map> rad_int_result; +}; + +#endif //JUNGFRAUJOCH_CBORMESSAGES_H diff --git a/frame_serialize/CMakeLists.txt b/frame_serialize/CMakeLists.txt index 0d9b62ee..c4d541f8 100644 --- a/frame_serialize/CMakeLists.txt +++ b/frame_serialize/CMakeLists.txt @@ -1,7 +1,6 @@ ADD_LIBRARY(FrameSerialize STATIC JFJochFrameSerializer.cpp JFJochFrameSerializer.h JFJochFrameDeserializer.cpp JFJochFrameDeserializer.h - ImageMessage.h tinycbor/src/cborparser_dup_string.c tinycbor/src/cborencoder.c tinycbor/src/cborencoder_close_container_checked.c @@ -11,4 +10,4 @@ ADD_LIBRARY(FrameSerialize STATIC tinycbor/src/cborpretty.c tinycbor/src/cborerrorstrings.c tinycbor/src/cbor.h - tinycbor/src/tinycbor-version.h CborErr.h StartMessage.h EndMessage.h CborUtil.h) + tinycbor/src/tinycbor-version.h CborErr.h CborUtil.h CBORMessages.h) diff --git a/frame_serialize/CborErr.h b/frame_serialize/CborErr.h index 7a387013..d91ebf8f 100644 --- a/frame_serialize/CborErr.h +++ b/frame_serialize/CborErr.h @@ -1,5 +1,4 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (2019-2023) Paul Scherrer Institute #ifndef JUNGFRAUJOCH_CBORERR_H #define JUNGFRAUJOCH_CBORERR_H diff --git a/frame_serialize/CborUtil.h b/frame_serialize/CborUtil.h index 9f5c29a0..b19656d2 100644 --- a/frame_serialize/CborUtil.h +++ b/frame_serialize/CborUtil.h @@ -1,5 +1,4 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (2019-2023) Paul Scherrer Institute #ifndef JUNGFRAUJOCH_CBORUTIL_H #define JUNGFRAUJOCH_CBORUTIL_H diff --git a/frame_serialize/EndMessage.h b/frame_serialize/EndMessage.h deleted file mode 100644 index e6bb462c..00000000 --- a/frame_serialize/EndMessage.h +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later - -#ifndef JUNGFRAUJOCH_ENDMESSAGE_H -#define JUNGFRAUJOCH_ENDMESSAGE_H - -#include -#include - -struct EndMessage { - uint64_t number_of_images; - uint64_t max_receiver_delay; - float efficiency; - - bool write_master_file; - - std::string end_date; - - std::string series_unique_id; - uint64_t series_id; - - std::map> rad_int_result; -}; - -#endif //JUNGFRAUJOCH_ENDMESSAGE_H diff --git a/frame_serialize/ImageMessage.h b/frame_serialize/ImageMessage.h deleted file mode 100644 index ca0c54bf..00000000 --- a/frame_serialize/ImageMessage.h +++ /dev/null @@ -1,50 +0,0 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later - -#ifndef JUNGFRAUJOCH_IMAGEMESSAGE_H -#define JUNGFRAUJOCH_IMAGEMESSAGE_H - -#include -#include -#include -#include -#include "../compression/CompressionAlgorithmEnum.h" -#include "../common/SpotToSave.h" - -struct CBORImage { - const uint8_t *data; - size_t size; // Including compression - size_t xpixel; - size_t ypixel; - size_t pixel_depth_bytes; - bool pixel_is_signed; - CompressionAlgorithm algorithm; - std::string channel; -}; - -struct DataMessage { - int64_t number = INT64_MIN; - CBORImage image; - std::vector spots; - std::vector rad_int_profile; - uint64_t indexing_result; // 0 - not tried, 1 - tried and failed, 2 - tried and success - std::vector indexing_lattice; - - uint64_t bunch_id; - uint32_t jf_info; - float receiver_available_send_buffers; - int64_t receiver_aq_dev_delay; - - uint64_t timestamp; - uint32_t timestamp_base; - - uint32_t storage_cell; - - uint32_t exptime; - uint32_t exptime_base; - - std::string series_unique_id; - uint64_t series_id; -}; - -#endif //JUNGFRAUJOCH_IMAGEMESSAGE_H diff --git a/frame_serialize/JFJochFrameDeserializer.cpp b/frame_serialize/JFJochFrameDeserializer.cpp index d1a5acf2..78af72c6 100644 --- a/frame_serialize/JFJochFrameDeserializer.cpp +++ b/frame_serialize/JFJochFrameDeserializer.cpp @@ -1,5 +1,4 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (2019-2023) Paul Scherrer Institute #include "JFJochFrameDeserializer.h" #include "tinycbor/src/cbor.h" @@ -184,29 +183,40 @@ inline void GetCBORTypedArray(CBORImage &v, CborValue &value) { CborTag tag = GetCBORTag(value); switch (tag) { + case TagFloatLE: + v.pixel_is_signed = true; + v.pixel_depth_bytes = sizeof(float); + v.pixel_is_float = true; + break; case TagSignedInt8Bit: v.pixel_is_signed = true; v.pixel_depth_bytes = 1; + v.pixel_is_float = false; break; case TagUnsignedInt8Bit: v.pixel_is_signed = false; v.pixel_depth_bytes = 1; + v.pixel_is_float = false; break; case TagSignedInt16BitLE: v.pixel_is_signed = true; v.pixel_depth_bytes = 2; + v.pixel_is_float = false; break; case TagUnsignedInt16BitLE: v.pixel_is_signed = false; v.pixel_depth_bytes = 2; + v.pixel_is_float = false; break; case TagSignedInt32BitLE: v.pixel_is_signed = true; v.pixel_depth_bytes = 4; + v.pixel_is_float = false; break; case TagUnsignedInt32BitLE: v.pixel_is_signed = false; v.pixel_depth_bytes = 4; + v.pixel_is_float = false; break; default: throw JFJochException(JFJochExceptionCategory::CBORError, @@ -268,6 +278,16 @@ void GetCBORMultidimTypedArray(CBORImage &v, CborValue &value) { cborErr(cbor_value_leave_container(&value, &array_value)); } +bool CheckMagicNumber(CborValue &v) { + auto key = GetCBORString(v); + if (key != "magic_number") { + cbor_value_advance(&v); + return false; + } else { + return GetCBORUInt(v) == user_data_magic_number; + } +} + void JFJochFrameDeserializer::GetCBORSpots(CborValue &value) { size_t array_len = GetCBORArrayLen(value); @@ -354,6 +374,12 @@ void JFJochFrameDeserializer::ProcessDetTranslation(CborValue &value) { void JFJochFrameDeserializer::ProcessImageMessageUserDataElement(CborValue &value) { CborValue map_value; cborErr(cbor_value_enter_container(&value, &map_value)); + + if (!CheckMagicNumber(map_value)) { + cborErr(cbor_value_leave_container(&value, &map_value)); + return; + } + while (!cbor_value_at_end(&map_value)) { auto key = GetCBORString(map_value); @@ -411,24 +437,29 @@ bool JFJochFrameDeserializer::ProcessImageMessageElement(CborValue &value) { } } +void JFJochFrameDeserializer::ProcessCalibration(CborValue &value) { + CborValue map_value; + cborErr(cbor_value_enter_container(&value, &map_value)); + while (! cbor_value_at_end(&map_value)) { + auto key = GetCBORString(map_value); + CBORImage image; + image.channel = key; + GetCBORMultidimTypedArray(image, map_value); + start_message.calibration.push_back(image); + } + cborErr(cbor_value_leave_container(&value, &map_value)); + +} + void JFJochFrameDeserializer::ProcessPixelMaskElement(CborValue &value) { CborValue map_value; cborErr(cbor_value_enter_container(&value, &map_value)); while (! cbor_value_at_end(&map_value)) { auto key = GetCBORString(map_value); - CBORImage cbor_multidim_array; - GetCBORMultidimTypedArray(cbor_multidim_array, map_value); - - if (cbor_multidim_array.size != cbor_multidim_array.xpixel * cbor_multidim_array.ypixel - * cbor_multidim_array.pixel_depth_bytes) - throw JFJochException(JFJochExceptionCategory::CBORError, "Pixel mask size mismatch"); - - if (cbor_multidim_array.pixel_depth_bytes != sizeof(uint32_t)) - throw JFJochException(JFJochExceptionCategory::CBORError, "Pixel mask must be 32-bit"); - - std::vector v(cbor_multidim_array.xpixel * cbor_multidim_array.ypixel); - memcpy(v.data(), cbor_multidim_array.data, cbor_multidim_array.size); - start_message.pixel_mask[key] = v; + CBORImage image; + image.channel = key; + GetCBORMultidimTypedArray(image, map_value); + start_message.pixel_mask.push_back(image); } cborErr(cbor_value_leave_container(&value, &map_value)); } @@ -485,6 +516,12 @@ void JFJochFrameDeserializer::ProcessUnitCellElement(CborValue &value) { void JFJochFrameDeserializer::ProcessStartMessageUserDataElement(CborValue &value) { CborValue map_value; cborErr(cbor_value_enter_container(&value, &map_value)); + + if (!CheckMagicNumber(map_value)) { + cborErr(cbor_value_leave_container(&value, &map_value)); + return; + } + while (!cbor_value_at_end(&map_value)) { auto key = GetCBORString(map_value); @@ -524,6 +561,8 @@ void JFJochFrameDeserializer::ProcessStartMessageUserDataElement(CborValue &valu start_message.summation = GetCBORUInt(map_value); else if (key == "storage_cell_number") start_message.storage_cell_number = GetCBORUInt(map_value); + else if (key == "storage_cell_delay") + start_message.storage_cell_delay_ns = GetRational(map_value).first; else if (key == "compression_algorithm") { auto tmp = GetCBORString(map_value); if (tmp == "bslz4") @@ -536,6 +575,8 @@ void JFJochFrameDeserializer::ProcessStartMessageUserDataElement(CborValue &valu throw JFJochException(JFJochExceptionCategory::CBORError, "Unsupported compression"); } else if (key == "compression_block_size") start_message.compression_block_size = GetCBORUInt(map_value); + else if (key == "calibration") + ProcessCalibration(map_value); else cbor_value_advance(&map_value); } @@ -606,27 +647,46 @@ bool JFJochFrameDeserializer::ProcessStartMessageElement(CborValue &value) { } } +void JFJochFrameDeserializer::ProcessEndMessageUserDataElement(CborValue &value) { + CborValue map_value; + cborErr(cbor_value_enter_container(&value, &map_value)); + + if (!CheckMagicNumber(map_value)) { + cborErr(cbor_value_leave_container(&value, &map_value)); + return; + } + + while (!cbor_value_at_end(&map_value)) { + auto key = GetCBORString(map_value); + if (key == "number_of_images") + end_message.number_of_images = GetCBORUInt(map_value); + else if (key == "max_receiver_delay") + end_message.max_receiver_delay = GetCBORUInt(map_value); + else if (key == "receiver_efficiency") + end_message.efficiency = GetCBORFloat(map_value); + else if (key == "write_master_file") + end_message.write_master_file = GetCBORBool(map_value); + else if (key == "rad_int_result") + ProcessRadIntResultElement(map_value); + else + cbor_value_advance(&map_value); + } + cborErr(cbor_value_leave_container(&value, &map_value)); +} + bool JFJochFrameDeserializer::ProcessEndMessageElement(CborValue &value) { if (cbor_value_at_end(&value)) return false; else { auto key = GetCBORString(value); - if (key == "number_of_images") - end_message.number_of_images = GetCBORUInt(value); - else if (key == "max_receiver_delay") - end_message.max_receiver_delay = GetCBORUInt(value); - else if (key == "receiver_efficiency") - end_message.efficiency = GetCBORFloat(value); - else if (key == "write_master_file") - end_message.write_master_file = GetCBORBool(value); - else if (key == "end_date") + if (key == "end_date") end_message.end_date = GetCBORString(value); else if (key == "series_unique_id") end_message.series_unique_id = GetCBORString(value); else if (key == "series_id") end_message.series_id = GetCBORUInt(value); - else if (key == "rad_int_result") - ProcessRadIntResultElement(value); + else if (key == "user_data") + ProcessEndMessageUserDataElement(value); else cbor_value_advance(&value); return true; diff --git a/frame_serialize/JFJochFrameDeserializer.h b/frame_serialize/JFJochFrameDeserializer.h index e78ce8d0..df79cf29 100644 --- a/frame_serialize/JFJochFrameDeserializer.h +++ b/frame_serialize/JFJochFrameDeserializer.h @@ -1,5 +1,4 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (2019-2023) Paul Scherrer Institute #ifndef JUNGFRAUJOCH_JFJOCHFRAMEDESERIALIZER_H #define JUNGFRAUJOCH_JFJOCHFRAMEDESERIALIZER_H @@ -11,9 +10,7 @@ #include "../common/SpotToSave.h" #include "tinycbor/src/cbor.h" -#include "EndMessage.h" -#include "StartMessage.h" -#include "ImageMessage.h" +#include "CBORMessages.h" #include class JFJochFrameDeserializer { @@ -36,6 +33,7 @@ private: GoniometerAxis ProcessGoniometer(CborValue &value); void ProcessDetTranslation(CborValue &value); + void ProcessCalibration(CborValue &value); void ProcessChannels(CborValue &value); void ProcessImageData(CborValue &value); void ProcessPixelMaskElement(CborValue &value); @@ -43,6 +41,7 @@ private: void ProcessUnitCellElement(CborValue &value); void ProcessStartMessageUserDataElement(CborValue &value); void ProcessImageMessageUserDataElement(CborValue &value); + void ProcessEndMessageUserDataElement(CborValue &value); bool ProcessImageMessageElement(CborValue &value); bool ProcessStartMessageElement(CborValue &value); bool ProcessEndMessageElement(CborValue &value); diff --git a/frame_serialize/JFJochFrameSerializer.cpp b/frame_serialize/JFJochFrameSerializer.cpp index 5db632fd..9ff86ebb 100644 --- a/frame_serialize/JFJochFrameSerializer.cpp +++ b/frame_serialize/JFJochFrameSerializer.cpp @@ -1,5 +1,4 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (2019-2023) Paul Scherrer Institute #include "JFJochFrameSerializer.h" #include "tinycbor/src/cbor.h" @@ -78,41 +77,43 @@ void CBOR_ENC_COMPRESSED(CborEncoder &encoder, } } -inline void CBOR_ENC_MULTIDIM_TYPED_ARRAY(CborEncoder &encoder, const char* key, - const void *image, size_t image_size, - size_t xpixel, size_t ypixel, CompressionAlgorithm algorithm, - size_t elem_size, bool elem_sign) { +inline void CBOR_ENC_2D_TYPED_ARRAY(CborEncoder &encoder, const CBORImage& image) { //if ((algorithm == CompressionAlgorithm::NO_COMPRESSION) && (xpixel * ypixel != image_size / elem_size)) // throw JFJochException(JFJochExceptionCategory::CBORError, "Mismatch in array size"); CborEncoder arrayEncoder, arrayEncoder_2; - cborErr(cbor_encode_text_stringz(&encoder, key)); + cborErr(cbor_encode_text_stringz(&encoder, image.channel.c_str())); cbor_encode_tag(&encoder, TagMultiDimArray); cborErr(cbor_encoder_create_array(&encoder, &arrayEncoder, 2)); cborErr(cbor_encoder_create_array(&arrayEncoder, &arrayEncoder_2, 2)); - cborErr(cbor_encode_uint(&arrayEncoder_2, ypixel)); - cborErr(cbor_encode_uint(&arrayEncoder_2, xpixel)); + cborErr(cbor_encode_uint(&arrayEncoder_2, image.ypixel)); + cborErr(cbor_encode_uint(&arrayEncoder_2, image.xpixel)); cborErr(cbor_encoder_close_container(&arrayEncoder, &arrayEncoder_2)); CborTag typed_array_tag; - if (elem_sign) { - if (elem_size == 4) + if (image.pixel_is_float) { + if (image.pixel_depth_bytes == 4) + typed_array_tag = TagFloatLE; + else + throw JFJochException(JFJochExceptionCategory::CBORError, "Array size not supported"); + } else if (image.pixel_is_signed) { + if (image.pixel_depth_bytes == 4) typed_array_tag = TagSignedInt32BitLE; - else if (elem_size == 2) + else if (image.pixel_depth_bytes == 2) typed_array_tag = TagSignedInt16BitLE; - else if (elem_size == 1) + else if (image.pixel_depth_bytes == 1) typed_array_tag = TagSignedInt8Bit; else throw JFJochException(JFJochExceptionCategory::CBORError, "Array size not supported"); } else { - if (elem_size == 4) + if (image.pixel_depth_bytes == 4) typed_array_tag = TagUnsignedInt32BitLE; - else if (elem_size == 2) + else if (image.pixel_depth_bytes == 2) typed_array_tag = TagUnsignedInt16BitLE; - else if (elem_size == 1) + else if (image.pixel_depth_bytes == 1) typed_array_tag = TagUnsignedInt8Bit; else throw JFJochException(JFJochExceptionCategory::CBORError, "Array size not supported"); @@ -120,29 +121,10 @@ inline void CBOR_ENC_MULTIDIM_TYPED_ARRAY(CborEncoder &encoder, const char* key, cbor_encode_tag(&arrayEncoder, typed_array_tag); - CBOR_ENC_COMPRESSED(arrayEncoder, image, image_size, algorithm, elem_size); + CBOR_ENC_COMPRESSED(arrayEncoder, image.data, image.size, image.algorithm, image.pixel_depth_bytes); cborErr(cbor_encoder_close_container(&encoder, &arrayEncoder)); } -inline void CBOR_ENC_PIXEL_MASK(CborEncoder &encoder, const char* key, - const std::map> &pixel_mask, - size_t xpixel, size_t ypixel) { - CborEncoder mapEncoder; - cborErr(cbor_encode_text_stringz(&encoder, key)); - cborErr(cbor_encoder_create_map(&encoder, &mapEncoder, pixel_mask.size())); - for (auto &[pixel_mask_key, pixel_mask_array]: pixel_mask) - CBOR_ENC_MULTIDIM_TYPED_ARRAY(mapEncoder, - pixel_mask_key.c_str(), - pixel_mask_array.data(), - pixel_mask_array.size() * sizeof(uint32_t), - xpixel, ypixel, - CompressionAlgorithm::NO_COMPRESSION, - sizeof(uint32_t), - false); - - cborErr(cbor_encoder_close_container(&encoder, &mapEncoder)); -} - inline void CBOR_ENC(CborEncoder &encoder, const char* key, const std::vector& v) { CborEncoder arrayEncoder; @@ -195,16 +177,7 @@ inline void CBOR_ENC(CborEncoder &encoder, const char* key, const CBORImage& mes cborErr(cbor_encode_text_stringz(&encoder, key)); cborErr(cbor_encoder_create_map(&encoder, &mapEncoder, 1)); - CBOR_ENC_MULTIDIM_TYPED_ARRAY(mapEncoder, - message.channel.c_str(), - (uint8_t *) message.data, - message.size, - message.xpixel, - message.ypixel, - message.algorithm, - message.pixel_depth_bytes, - message.pixel_is_signed); - + CBOR_ENC_2D_TYPED_ARRAY(mapEncoder, message); cborErr(cbor_encoder_close_container(&encoder, &mapEncoder)); } @@ -267,11 +240,22 @@ inline void CBOR_ENC_UNIT_CELL(CborEncoder &encoder, const char* key, const floa cborErr(cbor_encoder_close_container(&encoder, &mapEncoder)); } +inline void CBOR_ENC(CborEncoder &encoder, const char* key, const std::vector &v) { + CborEncoder mapEncoder; + + cborErr(cbor_encode_text_stringz(&encoder, key)); + cborErr(cbor_encoder_create_map(&encoder, &mapEncoder, v.size())); + for (const auto &i: v) + CBOR_ENC_2D_TYPED_ARRAY(mapEncoder, i); + cborErr(cbor_encoder_close_container(&encoder, &mapEncoder)); +} + inline void CBOR_ENC_USER_DATA(CborEncoder &encoder, const StartMessage& message) { CborEncoder mapEncoder; cborErr(cbor_encode_text_stringz(&encoder, "user_data")); - cborErr(cbor_encoder_create_map(&encoder, &mapEncoder, 20)); + cborErr(cbor_encoder_create_map(&encoder, &mapEncoder, 23)); + CBOR_ENC(mapEncoder, "magic_number", user_data_magic_number); CBOR_ENC(mapEncoder, "file_prefix", message.file_prefix); CBOR_ENC(mapEncoder, "sample_name", message.sample_name); @@ -279,6 +263,8 @@ inline void CBOR_ENC_USER_DATA(CborEncoder &encoder, const StartMessage& message CBOR_ENC(mapEncoder, "max_spot_count", message.max_spot_count); CBOR_ENC(mapEncoder, "data_file_count", message.data_file_count); CBOR_ENC(mapEncoder, "storage_cell_number", message.storage_cell_number); + CBOR_ENC_RATIONAL(mapEncoder, "storage_cell_delay", message.storage_cell_delay_ns, 1000*1000*1000UL); + CBOR_ENC(mapEncoder, "pixel_bit_depth", message.pixel_bit_depth); CBOR_ENC(mapEncoder, "pixel_signed", message.pixel_signed); CBOR_ENC(mapEncoder, "min_value", message.min_value); @@ -306,6 +292,7 @@ inline void CBOR_ENC_USER_DATA(CborEncoder &encoder, const StartMessage& message CBOR_ENC(mapEncoder, "rad_int_bin_to_q", message.rad_int_bin_to_q); CBOR_ENC(mapEncoder, "rad_int_solid_angle_corr", message.rad_int_solid_angle_corr); CBOR_ENC(mapEncoder, "summation", message.summation); + CBOR_ENC(mapEncoder, "calibration", message.calibration); cborErr(cbor_encoder_close_container(&encoder, &mapEncoder)); } @@ -383,7 +370,7 @@ void JFJochFrameSerializer::SerializeSequenceStart(const StartMessage& message) CBOR_ENC_GONIOMETER_MAP(mapEncoder, "goniometer", message.goniometer); CBOR_ENC_USER_DATA(mapEncoder, message); - CBOR_ENC_PIXEL_MASK(mapEncoder, "pixel_mask", message.pixel_mask, message.image_size_x, message.image_size_y); + CBOR_ENC(mapEncoder, "pixel_mask", message.pixel_mask); CBOR_ENC_CHANNELS(mapEncoder, "channels", message.channels); cborErr(cbor_encoder_close_container(&encoder, &mapEncoder)); @@ -391,20 +378,26 @@ void JFJochFrameSerializer::SerializeSequenceStart(const StartMessage& message) } void JFJochFrameSerializer::SerializeSequenceEnd(const EndMessage& message) { - CborEncoder encoder, mapEncoder; + CborEncoder encoder, mapEncoder, userDataMapEncoder; cbor_encoder_init(&encoder, buffer, max_buffer_size, 0); - cborErr(cbor_encode_tag(&encoder,CborSignatureTag )); - cborErr(cbor_encoder_create_map(&encoder, &mapEncoder, 9)); + cborErr(cbor_encode_tag(&encoder, CborSignatureTag)); + cborErr(cbor_encoder_create_map(&encoder, &mapEncoder, 5)); CBOR_ENC(mapEncoder, "type", "end"); CBOR_ENC(mapEncoder, "series_unique_id", message.series_unique_id); CBOR_ENC(mapEncoder, "series_id", message.series_id); - CBOR_ENC(mapEncoder, "number_of_images", message.number_of_images); - CBOR_ENC(mapEncoder, "max_receiver_delay", message.max_receiver_delay); - CBOR_ENC(mapEncoder, "receiver_efficiency", message.efficiency); - CBOR_ENC(mapEncoder, "write_master_file", message.write_master_file); CBOR_ENC(mapEncoder, "end_date", message.end_date); - CBOR_ENC_RAD_INT_RESULT(mapEncoder, "rad_int_result", message.rad_int_result); + + cborErr(cbor_encode_text_stringz(&mapEncoder, "user_data")); + cborErr(cbor_encoder_create_map(&mapEncoder, &userDataMapEncoder, 6)); + CBOR_ENC(userDataMapEncoder, "magic_number", user_data_magic_number); + CBOR_ENC(userDataMapEncoder, "number_of_images", message.number_of_images); + CBOR_ENC(userDataMapEncoder, "max_receiver_delay", message.max_receiver_delay); + CBOR_ENC(userDataMapEncoder, "receiver_efficiency", message.efficiency); + CBOR_ENC(userDataMapEncoder, "write_master_file", message.write_master_file); + CBOR_ENC_RAD_INT_RESULT(userDataMapEncoder, "rad_int_result", message.rad_int_result); + cborErr(cbor_encoder_close_container(&mapEncoder, &userDataMapEncoder)); + cborErr(cbor_encoder_close_container(&encoder, &mapEncoder)); curr_size = cbor_encoder_get_buffer_size(&encoder, buffer); @@ -429,8 +422,9 @@ void JFJochFrameSerializer::SerializeImage(const DataMessage& message) { message.timestamp_base); cborErr(cbor_encode_text_stringz(&mapEncoder, "user_data")); - cborErr(cbor_encoder_create_map(&mapEncoder, &userDataMapEncoder, 9)); + cborErr(cbor_encoder_create_map(&mapEncoder, &userDataMapEncoder, 10)); + CBOR_ENC(userDataMapEncoder, "magic_number", user_data_magic_number); CBOR_ENC(userDataMapEncoder, "spots", message.spots); CBOR_ENC(userDataMapEncoder, "rad_int_profile", message.rad_int_profile); CBOR_ENC(userDataMapEncoder, "indexing_result", message.indexing_result); diff --git a/frame_serialize/JFJochFrameSerializer.h b/frame_serialize/JFJochFrameSerializer.h index 8ecc5472..83746add 100644 --- a/frame_serialize/JFJochFrameSerializer.h +++ b/frame_serialize/JFJochFrameSerializer.h @@ -1,5 +1,4 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (2019-2023) Paul Scherrer Institute #ifndef JUNGFRAUJOCH_JFJOCHFRAMESERIALIZER_H #define JUNGFRAUJOCH_JFJOCHFRAMESERIALIZER_H @@ -8,9 +7,7 @@ #include #include #include "../common/SpotToSave.h" -#include "StartMessage.h" -#include "EndMessage.h" -#include "ImageMessage.h" +#include "CBORMessages.h" class JFJochFrameSerializer { uint8_t *buffer = nullptr; diff --git a/frame_serialize/StartMessage.h b/frame_serialize/StartMessage.h deleted file mode 100644 index 870cdff9..00000000 --- a/frame_serialize/StartMessage.h +++ /dev/null @@ -1,85 +0,0 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later - -#ifndef JUNGFRAUJOCH_STARTMESSAGE_H -#define JUNGFRAUJOCH_STARTMESSAGE_H - -#include -#include -#include -#include -#include "../compression/CompressionAlgorithmEnum.h" - -struct GoniometerAxis { - float increment; - float start; -}; - -struct StartMessage { - uint64_t data_file_count; // user data - - float detector_distance; - float beam_center_x; - float beam_center_y; - - uint64_t number_of_images; - - uint64_t image_size_x; - uint64_t image_size_y; - uint64_t pixel_bit_depth; // user data - bool pixel_signed; // user data - - float incident_energy; - float incident_wavelength; - - float frame_time; - float count_time; - - int64_t saturation_value; - int64_t min_value; // user data - - float pixel_size_x; - float pixel_size_y; - float sensor_thickness; - std::string sensor_material; - - CompressionAlgorithm compression_algorithm; // user data - uint64_t compression_block_size; // user data - - float unit_cell[6]; // user data - uint64_t space_group_number; // user data - uint64_t max_spot_count; // user data - - uint64_t storage_cell_number; // user data - - std::map> pixel_mask; - bool pixel_mask_enabled; - - std::string arm_date; - - std::string sample_name; // user data - std::string file_prefix; // user data - - std::vector channels; - - std::string detector_description; - std::string detector_serial_number; - std::string series_unique_id; - uint64_t series_id; - - std::map goniometer; - float detector_translation[3]; - - std::string source_name; - std::string source_name_short; - std::string instrument_name; - std::string instrument_name_short; - - uint64_t rad_int_bin_number; - uint64_t summation; - - std::vector rad_int_bin_to_q; - std::vector rad_int_solid_angle_corr; -}; - -#endif //JUNGFRAUJOCH_STARTMESSAGE_H diff --git a/frontend_ui/src/components/BkgEstimatePlot.tsx b/frontend_ui/src/components/BkgEstimatePlot.tsx index 25a2b3f8..db4e459c 100644 --- a/frontend_ui/src/components/BkgEstimatePlot.tsx +++ b/frontend_ui/src/components/BkgEstimatePlot.tsx @@ -1,6 +1,6 @@ /* * Copyright (2019-2023) Paul Scherrer Institute - * SPDX-License-Identifier: GPL-3.0-or-later + * */ import Paper from "@mui/material/Paper"; diff --git a/frontend_ui/src/components/DataProcessingPlots.tsx b/frontend_ui/src/components/DataProcessingPlots.tsx index e7dfc31c..5ae10905 100644 --- a/frontend_ui/src/components/DataProcessingPlots.tsx +++ b/frontend_ui/src/components/DataProcessingPlots.tsx @@ -6,7 +6,7 @@ import DataProcessingPlot from "./DataProcessingPlot"; import Toolbar from "@mui/material/Toolbar"; import MenuItem from "@mui/material/MenuItem"; import FormControl from "@mui/material/FormControl"; -import InputLabel from "@mui/material/InputLabel"; +import RadialIntegrationProfilePlots from "./RadialIntegrationProfilePlots"; import Select, {SelectChangeEvent} from "@mui/material/Select"; type MyProps = { @@ -50,11 +50,14 @@ class DataProcessingPlots extends Component { this.setState({type: "SPOT_COUNT", xlabel: "Image number", ylabel: "Spot count" }); break; case 3: - this.setState({type: "RAD_INT", xlabel: "Q [A^-1]", ylabel: "Photon count"}); + this.setState({type: "RAD_INT", xlabel: "Q [A-1]", ylabel: "Photon count"}); break; case 4: this.setState({type: "INDEXING_RATE_PER_FILE", xlabel: "File number", ylabel: "Indexing rate"}); break; + case 5: + this.setState({type: "RAD_INT_PER_FILE", xlabel: "Q [A^-1]", ylabel: "Photon count"}); + break; } } @@ -63,14 +66,15 @@ class DataProcessingPlots extends Component { }; render() { - return + return - + - + + @@ -94,9 +98,13 @@ class DataProcessingPlots extends Component { - - + + { + (this.state.type === "RAD_INT_PER_FILE") ? + : + + } } diff --git a/frontend_ui/src/components/DataProcessingSettings.tsx b/frontend_ui/src/components/DataProcessingSettings.tsx index 49e634ee..38c560d5 100644 --- a/frontend_ui/src/components/DataProcessingSettings.tsx +++ b/frontend_ui/src/components/DataProcessingSettings.tsx @@ -120,7 +120,7 @@ class DataProcessingSettings extends Component { } render() { - return + return diff --git a/frontend_ui/src/components/DetectorSettings.tsx b/frontend_ui/src/components/DetectorSettings.tsx index e4ac48ca..0ba6dbc7 100644 --- a/frontend_ui/src/components/DetectorSettings.tsx +++ b/frontend_ui/src/components/DetectorSettings.tsx @@ -22,11 +22,13 @@ type MyState = { countTimeUs: number | string, pedestalG0Frames: number | string, pedestalG1Frames: number | string, - pedestalG2Frames: number | string + pedestalG2Frames: number | string, + storageCellDelayNs: number | string }, storage_cell_list_value: string, frame_time_error: boolean, count_time_error: boolean, + storage_cell_delay_error: boolean, connection_error: boolean } @@ -46,11 +48,13 @@ class DetectorSettings extends Component { countTimeUs: 980, pedestalG0Frames: 2000, pedestalG1Frames: 300, - pedestalG2Frames: 300 + pedestalG2Frames: 300, + storageCellDelayNs: 10000 }, storage_cell_list_value: "1", frame_time_error: false, count_time_error: false, + storage_cell_delay_error: false, connection_error: true } @@ -72,7 +76,7 @@ class DetectorSettings extends Component { } if (!count_err) { - if (Number(count_time) < 0) + if (Number(count_time) < 5) count_err = true; } @@ -88,6 +92,22 @@ class DetectorSettings extends Component { )); } + updateStorageCellDelay = (event: React.ChangeEvent) => { + let num_val = Number(event.target.value); + let err = !Number.isInteger(num_val); + if (!err) { + if (num_val < 2100) err = true; + } + + this.setState(prevState => ( + { + storage_cell_delay_error: err, + s : {...prevState.s, + storageCellDelayNs: event.target.value + } + } + )); + } updateFrameTime = (event: React.ChangeEvent) => { this.updateCollectionTime(event.target.value, this.state.s.countTimeUs); @@ -183,10 +203,14 @@ class DetectorSettings extends Component { }}/>

- +
+ + + Storage cell count

+
+ + ns + }}/> +

+
+ + + Collect raw data

@@ -210,7 +254,9 @@ class DetectorSettings extends Component {    + disabled={this.state.count_time_error + || this.state.frame_time_error + || this.state.storage_cell_delay_error}>Upload

diff --git a/frontend_ui/src/components/MultiLinePlotWrapper.js b/frontend_ui/src/components/MultiLinePlotWrapper.js new file mode 100644 index 00000000..ec1dca80 --- /dev/null +++ b/frontend_ui/src/components/MultiLinePlotWrapper.js @@ -0,0 +1,22 @@ +import React, {Component} from 'react'; + +import Plot from "react-plotly.js"; + +// Not using TypeScript, as plotly is not TypeScript :( + +class MultiLinePlotWrapper extends Component { + render() { + return + } +} + +export default MultiLinePlotWrapper; \ No newline at end of file diff --git a/frontend_ui/src/components/RadialIntegrationProfilePlots.tsx b/frontend_ui/src/components/RadialIntegrationProfilePlots.tsx new file mode 100644 index 00000000..f3b79f50 --- /dev/null +++ b/frontend_ui/src/components/RadialIntegrationProfilePlots.tsx @@ -0,0 +1,98 @@ +import React, {Component} from 'react'; + +import MultiLinePlotWrapper from "./MultiLinePlotWrapper"; +import {handleErrors} from "./handleErrors"; + +type MyProps = { + addr: string; +}; + +type Plot = { + x: number[], + y: number[] +} + +type RadialProfile = { + plot: Plot, + title: string +} + +type RadialProfiles = RadialProfile[] + +type PlotlyPlot = { + x: number[], + y: number[], + type: string, + mode: string, + name: string +} + +type PlotlyData = PlotlyPlot[] + +type MyState = { + profiles : RadialProfiles, + connection_error: boolean +} + +class RadialIntegrationProfilePlots extends Component { + addr: string; + interval: undefined | NodeJS.Timer; + + state: MyState = { + profiles: [ + { + plot: { + x: [0, 100, 200, 300, 400, 500], + y: [0.1, 0.3, 0.5, 0.2, 0.0, 0.1] + }, + title: "dataset" + } + ], + connection_error: true + } + + constructor(props: MyProps) { + super(props); + this.addr = props.addr; + } + + getValues() { + fetch(this.addr + 'data_processing/rad_int_profiles', { + method: "GET" + }).then(handleErrors) + .then(res => res.json()) + .then(data => this.setState({profiles: data.profiles, connection_error: false})) + .catch(error => { + console.log(error); + this.setState({connection_error: true}); + }); + } + componentDidMount() { + this.getValues(); + this.interval = setInterval(() => this.getValues(), 500); + } + + componentWillUnmount() { + clearInterval(this.interval); + } + + render() { + if (this.state.profiles !== undefined) { + let data: PlotlyData = []; + this.state.profiles.map(d => + data.push({ + x: d.plot.x, + y: d.plot.y, + type: "scatter", + mode: "line", + name: d.title + })); + + console.log(data); + return + } else + return
; + } +} + +export default RadialIntegrationProfilePlots; \ No newline at end of file diff --git a/grpc/JFJochDetectorClient.cpp b/grpc/JFJochDetectorClient.cpp index 2c8a6121..8c4b81f4 100644 --- a/grpc/JFJochDetectorClient.cpp +++ b/grpc/JFJochDetectorClient.cpp @@ -1,5 +1,4 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (2019-2023) Paul Scherrer Institute #include diff --git a/grpc/JFJochDetectorClient.h b/grpc/JFJochDetectorClient.h index bdca076a..814ec97d 100644 --- a/grpc/JFJochDetectorClient.h +++ b/grpc/JFJochDetectorClient.h @@ -1,5 +1,4 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (2019-2023) Paul Scherrer Institute #ifndef JUNGFRAUJOCH_JFJOCHDETECTORCLIENT_H #define JUNGFRAUJOCH_JFJOCHDETECTORCLIENT_H diff --git a/grpc/JFJochReceiverClient.cpp b/grpc/JFJochReceiverClient.cpp index 25c88f4e..fe72f283 100644 --- a/grpc/JFJochReceiverClient.cpp +++ b/grpc/JFJochReceiverClient.cpp @@ -1,5 +1,4 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (2019-2023) Paul Scherrer Institute #include #include "JFJochReceiverClient.h" @@ -154,8 +153,54 @@ JFJochProtoBuf::RadialIntegrationProfiles JFJochReceiverClient::GetRadialIntegra if (!status.ok()) throw JFJochException(JFJochExceptionCategory::gRPCError, "JFJochReceiver: " + status.error_message()); } else { - // TODO: Write some dummy plots + auto p = ret.add_profiles(); + p->set_title("dataset"); + *p->mutable_plot() = GenerateGaussianPlot(50, 0.1, 2.5, 0.2); + + p = ret.add_profiles(); + p->set_title("file0"); + *p->mutable_plot() = GenerateGaussianPlot(50, 0.1, 3.0, 0.2); + + p = ret.add_profiles(); + p->set_title("file1"); + *p->mutable_plot() = GenerateGaussianPlot(50, 0.1, 2.0, 0.2); + + p = ret.add_profiles(); + p->set_title("file2"); + *p->mutable_plot() = GenerateGaussianPlot(50, 0.1, 2.5, 0.1); + + p = ret.add_profiles(); + p->set_title("file3"); + *p->mutable_plot() = GenerateGaussianPlot(50, 0.1, 2.5, 0.5); + + for (int i = 4; i < 16; i++) { + p = ret.add_profiles(); + p->set_title("file" + std::to_string(i)); + *p->mutable_plot() = GenerateGaussianPlot(50, 0.1, 2.3, 0.1 + 0.02 * i); + } + } return ret; +} + +JFJochProtoBuf::Plot JFJochReceiverClient::GenerateGaussianPlot(uint64_t n_elements, float spacing, float mean, float std) { + + std::vector x(n_elements); + std::vector y(n_elements); + + constexpr float inv_sqrt_2pi = 0.3989422804; + + for (int i = 0; i < n_elements; i++) { + x[i] = spacing * i; + float a = (x[i] - mean) / std; + y[i] = inv_sqrt_2pi / std * expf(-0.5f * a * a);; + } + + JFJochProtoBuf::Plot ret; + if (n_elements > 0) { + *ret.mutable_x() = {x.begin(), x.end()}; + *ret.mutable_y() = {y.begin(), y.end()}; + } + return ret; +} -} \ No newline at end of file diff --git a/grpc/JFJochReceiverClient.h b/grpc/JFJochReceiverClient.h index cc939bfe..a1945de6 100644 --- a/grpc/JFJochReceiverClient.h +++ b/grpc/JFJochReceiverClient.h @@ -1,5 +1,4 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (2019-2023) Paul Scherrer Institute #ifndef JUNGFRAUJOCH_JFJOCHRECEIVERCLIENT_H #define JUNGFRAUJOCH_JFJOCHRECEIVERCLIENT_H @@ -12,6 +11,8 @@ class JFJochReceiverClient { std::unique_ptr _stub; + + static JFJochProtoBuf::Plot GenerateGaussianPlot(uint64_t n_elements, float spacing, float max, float std); public: void Connect(const std::string& addr); void Start(const DiffractionExperiment &experiment, const JFCalibration *calibration); diff --git a/grpc/JFJochWriterClient.cpp b/grpc/JFJochWriterClient.cpp index 3f6f4fbc..6403d8ae 100644 --- a/grpc/JFJochWriterClient.cpp +++ b/grpc/JFJochWriterClient.cpp @@ -1,5 +1,4 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (2019-2023) Paul Scherrer Institute #include diff --git a/grpc/JFJochWriterClient.h b/grpc/JFJochWriterClient.h index e1d0b9fd..8f8658e3 100644 --- a/grpc/JFJochWriterClient.h +++ b/grpc/JFJochWriterClient.h @@ -1,5 +1,4 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (2019-2023) Paul Scherrer Institute #ifndef JUNGFRAUJOCH_JFJOCHWRITERCLIENT_H #define JUNGFRAUJOCH_JFJOCHWRITERCLIENT_H diff --git a/grpc/JFJochWriterGroupClient.cpp b/grpc/JFJochWriterGroupClient.cpp index f3bf1bf0..4fbc2c11 100644 --- a/grpc/JFJochWriterGroupClient.cpp +++ b/grpc/JFJochWriterGroupClient.cpp @@ -1,5 +1,4 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (2019-2023) Paul Scherrer Institute #include "JFJochWriterGroupClient.h" diff --git a/grpc/JFJochWriterGroupClient.h b/grpc/JFJochWriterGroupClient.h index 96586ef4..6f7b57e2 100644 --- a/grpc/JFJochWriterGroupClient.h +++ b/grpc/JFJochWriterGroupClient.h @@ -1,5 +1,4 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (2019-2023) Paul Scherrer Institute #ifndef JUNGFRAUJOCH_JFJOCHWRITERGROUPCLIENT_H #define JUNGFRAUJOCH_JFJOCHWRITERGROUPCLIENT_H diff --git a/grpc/gRPCServer_Template.h b/grpc/gRPCServer_Template.h index c481085a..85641458 100644 --- a/grpc/gRPCServer_Template.h +++ b/grpc/gRPCServer_Template.h @@ -1,5 +1,4 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (2019-2023) Paul Scherrer Institute #ifndef JUNGFRAUJOCH_GRPCSERVER_TEMPLATE_H #define JUNGFRAUJOCH_GRPCSERVER_TEMPLATE_H diff --git a/grpc/jfjoch.proto b/grpc/jfjoch.proto index 0468b606..f892bec4 100644 --- a/grpc/jfjoch.proto +++ b/grpc/jfjoch.proto @@ -1,5 +1,4 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (2019-2023) Paul Scherrer Institute syntax = "proto3"; @@ -25,7 +24,7 @@ enum DetectorMode { PEDESTAL_G2 = 4; }; -enum FPGAFIFOStatus { +enum FPGAFIFOStatusEnum { EMPTY = 0; FULL = 1; PARTIAL = 2; @@ -70,6 +69,13 @@ message Plot { repeated float y = 2; } +message ROIRectangle { + int32 x0 = 1; + int32 y0 = 2; + int32 width = 3; + int32 height = 4; +} + // DiffractionExperiment message DatasetSettings { @@ -95,11 +101,15 @@ message DatasetSettings { optional UnitCell unit_cell = 13; int64 space_group_number = 14; - optional Vector scattering_vector = 15; - - bool apply_pixel_mask = 16; - bool binning2x2 = 17; + + bool rad_int_solid_angle_corr = 18; + bool rad_int_polarization_corr = 19; + float rad_int_polarization_factor = 20; + + bool save_calibration = 21; + + repeated ROIRectangle user_mask = 22; } message DetectorSettings { @@ -115,6 +125,7 @@ message DetectorSettings { optional int64 pedestal_g2_frames = 8; bool conversion_on_cpu = 9; + optional int64 storage_cell_delay_ns = 10; } message DetectorModuleGeometry { @@ -151,7 +162,7 @@ message InternalSettings { bool internal_fpga_packet_generator = 9; int64 storage_cells = 10; int64 storage_cell_start = 11; - + int64 storage_cell_delay_ns = 39; int64 pedestal_g0_frames = 12; int64 pedestal_g1_frames = 13; int64 pedestal_g2_frames = 14; @@ -179,6 +190,11 @@ message InternalSettings { string instrument_name = 34; string instrument_name_short = 35; + repeated ROIRectangle roi_rectangle = 36; + bool roi_apply = 37; + + bool debug_pixel_mask = 38; + } @@ -273,12 +289,15 @@ enum PlotType { message PlotRequest { PlotType type = 1; uint64 binning = 2; - bool solid_angle_correction = 3; +} + +message RadialIntegrationProfile { + string title = 1; + Plot plot = 2; } message RadialIntegrationProfiles { - map plots = 1; - repeated float solid_angle_correction = 2; + repeated RadialIntegrationProfile profiles = 1; } // Writer @@ -325,7 +344,7 @@ message DetectorInput { int64 num_triggers = 4; int64 storage_cell_number = 5; int64 storage_cell_start = 6; - double storage_cell_delay = 7; + int64 storage_cell_delay_ns = 7; int64 period_us = 9; int64 count_time_us = 10; } @@ -340,6 +359,11 @@ message DetectorStatus { string server_version = 3; } +message FPGAFIFOStatus { + string name = 1; + FPGAFIFOStatusEnum value = 2; +} + message FPGAStatus { uint64 packets_ether = 2; uint64 packets_udp = 3; @@ -352,16 +376,12 @@ message FPGAStatus { uint64 stalls_host = 10; bool ethernet_rx_aligned = 11; uint32 full_status_register = 13; - map fifo_status = 14; + repeated FPGAFIFOStatus fifo_status = 14; uint64 max_modules = 15; uint32 git_sha1 = 16; uint32 mailbox_err_reg = 17; uint32 mailbox_status_reg = 18; - bool datamover_mm2s_error = 19; - bool datamover_s2mm_error = 20; - bool frame_statistics_alignment_err = 21; - bool frame_statistics_tlast_err = 22; - bool frame_statistics_work_req_err = 23; + repeated string host_writer_err = 21; uint64 slowest_head = 24; float fpga_temp_degC = 26; @@ -381,6 +401,11 @@ message FPGAStatus { uint64 packets_sls = 37; uint32 error_eth = 38; uint32 error_packet_len = 39; + + bool host_writer_idle = 41; + bool cancel_bit = 42; + + uint32 hbm_size_bytes = 43; } message DataProcessingSettings { diff --git a/image_analysis/CMakeLists.txt b/image_analysis/CMakeLists.txt index e51c0b95..0977a096 100644 --- a/image_analysis/CMakeLists.txt +++ b/image_analysis/CMakeLists.txt @@ -4,7 +4,7 @@ ADD_LIBRARY(ImageAnalysis STATIC GPUImageAnalysis.h RadialIntegration.cpp RadialIntegration.h RadialIntegrationMapping.cpp RadialIntegrationMapping.h - StrongPixelSet.cpp StrongPixelSet.h GPUImageAnalysis_Alt.cpp RadialIntegrationProfile.cpp RadialIntegrationProfile.h) + StrongPixelSet.cpp StrongPixelSet.h GPUImageAnalysis.cpp RadialIntegrationProfile.cpp RadialIntegrationProfile.h PredictSpotsOnDetector.h) TARGET_LINK_LIBRARIES(ImageAnalysis CommonFunctions) @@ -13,8 +13,6 @@ TARGET_INCLUDE_DIRECTORIES(ImageAnalysis PUBLIC fast-feedback-indexer/eigen) IF (CMAKE_CUDA_COMPILER) TARGET_SOURCES(ImageAnalysis PRIVATE GPUImageAnalysis.cu ) - TARGET_COMPILE_DEFINITIONS(ImageAnalysis PUBLIC -DJFJOCH_USE_CUDA) - TARGET_SOURCES(ImageAnalysis PRIVATE fast-feedback-indexer/indexer/src/indexer.cpp fast-feedback-indexer/indexer/src/indexer_gpu.cu @@ -29,7 +27,6 @@ IF (CMAKE_CUDA_COMPILER) TARGET_INCLUDE_DIRECTORIES(ImageAnalysis PUBLIC fast-feedback-indexer/indexer/src/) - FIND_LIBRARY(CUDART_LIBRARY cudart_static PATHS ${CMAKE_CUDA_IMPLICIT_LINK_DIRECTORIES} REQUIRED) TARGET_LINK_LIBRARIES(ImageAnalysis ${CUDART_LIBRARY} ${CMAKE_DL_LIBS} rt) ELSE() MESSAGE(WARNING "CUDA is strongly recommended for image analysis." ) diff --git a/image_analysis/CrystalLattice.cpp b/image_analysis/CrystalLattice.cpp index 1ebf46e3..22aaf337 100644 --- a/image_analysis/CrystalLattice.cpp +++ b/image_analysis/CrystalLattice.cpp @@ -1,5 +1,4 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (2019-2023) Paul Scherrer Institute #include #include "CrystalLattice.h" diff --git a/image_analysis/CrystalLattice.h b/image_analysis/CrystalLattice.h index 7509eb55..7895a84b 100644 --- a/image_analysis/CrystalLattice.h +++ b/image_analysis/CrystalLattice.h @@ -1,5 +1,4 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (2019-2023) Paul Scherrer Institute #ifndef JUNGFRAUJOCH_CRYSTALLATTICE_H #define JUNGFRAUJOCH_CRYSTALLATTICE_H diff --git a/image_analysis/GPUImageAnalysis_Alt.cpp b/image_analysis/GPUImageAnalysis.cpp similarity index 90% rename from image_analysis/GPUImageAnalysis_Alt.cpp rename to image_analysis/GPUImageAnalysis.cpp index b2b12019..a1a029ae 100644 --- a/image_analysis/GPUImageAnalysis_Alt.cpp +++ b/image_analysis/GPUImageAnalysis.cpp @@ -1,5 +1,4 @@ // Copyright (2019-2023) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later #ifndef JFJOCH_USE_CUDA @@ -50,11 +49,11 @@ void GPUImageAnalysis::RunRadialIntegration() {} void GPUImageAnalysis::GetRadialIntegrationProfile(std::vector &result) {} -std::vector GPUImageAnalysis::GetRadialIntegrationSum() const { +std::vector GPUImageAnalysis::GetRadialIntegrationSum() const { return {}; } -std::vector GPUImageAnalysis::GetRadialIntegrationCount() const { +std::vector GPUImageAnalysis::GetRadialIntegrationCount() const { return {}; } @@ -62,6 +61,6 @@ float GPUImageAnalysis::GetRadialIntegrationRangeValue(uint16_t min_bin, uint16_ return 0; } -std::atomic GPUImageAnalysis::threadid{0}; +void GPUImageAnalysis::LoadRadialIntegrationCorr(const std::vector& v) {} #endif diff --git a/image_analysis/GPUImageAnalysis.cu b/image_analysis/GPUImageAnalysis.cu index f42e9a01..45226352 100644 --- a/image_analysis/GPUImageAnalysis.cu +++ b/image_analysis/GPUImageAnalysis.cu @@ -1,9 +1,11 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (2019-2023) Paul Scherrer Institute #include "GPUImageAnalysis.h" #include "../common/JFJochException.h" +#include "../common/DiffractionGeometry.h" + #include +#include "../common/CUDAWrapper.h" // input X x Y pixels array // output X x Y byte array @@ -177,25 +179,25 @@ __global__ void analyze_pixel(const int16_t *in, uint8_t *out, const spot_parame } __global__ void gpu_radial_integration(const int16_t *image, const uint16_t *rad_integration_mapping, - int32_t *bin_sum, int32_t *bin_count, uint32_t npixel, + float *corr, float *bin_sum, float *bin_count, uint32_t npixel, uint16_t nbins) { - extern __shared__ int32_t shared_mem[]; - int32_t* shared_sum = shared_mem; // shared buffer [nbins] - int32_t* shared_count = &shared_sum[nbins]; // shared buffer [nbins] + extern __shared__ float shared_mem_fp[]; + float* shared_sum = shared_mem_fp; // shared buffer [nbins] + float* shared_count = &shared_sum[nbins]; // shared buffer [nbins] uint32_t idx = blockDim.x*blockIdx.x + threadIdx.x; for (uint32_t i = threadIdx.x; i < 2 * nbins; i += blockDim.x) - shared_mem[i] = 0; + shared_mem_fp[i] = 0; __syncthreads(); for (uint32_t i = idx; i < npixel; i += blockDim.x * gridDim.x) { uint16_t bin = rad_integration_mapping[i]; - int32_t value = image[i]; - if ((value > INT16_MIN + 4) && (value < INT16_MAX - 4) && (bin < nbins)) { + float value = static_cast(image[i]) * corr[i]; + if ((image[i] > INT16_MIN + 4) && (image[i] < INT16_MAX - 4) && (bin < nbins)) { atomicAdd(&shared_sum[bin], value); - atomicAdd(&shared_count[bin], 1); + atomicAdd(&shared_count[bin], 1.0f); } } __syncthreads(); @@ -226,22 +228,12 @@ __global__ void apply_pixel_mask(int16_t *image, const uint8_t *mask, uint32_t n } } -GPUImageAnalysis::GPUImageAnalysis(int32_t in_xpixels, int32_t in_ypixels, const std::vector &mask, - int32_t gpu_device) : - xpixels(in_xpixels), ypixels(in_ypixels), gpu_out(nullptr), rad_integration_nbins(0) { +GPUImageAnalysis::GPUImageAnalysis(int32_t in_xpixels, int32_t in_ypixels, const std::vector &mask) : + xpixels(in_xpixels), ypixels(in_ypixels), gpu_out(nullptr), rad_integration_nbins(0), numberOfSMs(1) { - int device_count; - cuda_err(cudaGetDeviceCount(&device_count)); - - if (device_count == 0) + if (get_gpu_count() == 0) throw JFJochException(JFJochExceptionCategory::GPUCUDAError, "No CUDA devices found"); - if (gpu_device < 0) - gpu_device = threadid++; - - if (device_count > 1) - cuda_err(cudaSetDevice(gpu_device % device_count)); - int deviceId; cuda_err(cudaGetDevice(&deviceId)); cudaDeviceGetAttribute(&numberOfSMs, cudaDevAttrMultiProcessorCount, deviceId); @@ -269,8 +261,8 @@ GPUImageAnalysis::GPUImageAnalysis(int32_t in_xpixels, int32_t in_ypixels, const } GPUImageAnalysis::GPUImageAnalysis(int32_t xpixels, int32_t ypixels, const std::vector &mask, - const std::vector &rad_int_mapping, uint16_t rad_int_nbins, - int32_t gpu_device) : GPUImageAnalysis(xpixels, ypixels, mask, gpu_device) { + const std::vector &rad_int_mapping, uint16_t rad_int_nbins) + : GPUImageAnalysis(xpixels, ypixels, mask) { rad_integration_nbins = rad_int_nbins; if (rad_int_mapping.size() != xpixels * ypixels) @@ -278,22 +270,25 @@ GPUImageAnalysis::GPUImageAnalysis(int32_t xpixels, int32_t ypixels, const std:: if (rad_integration_nbins > 0) { cuda_err(cudaMalloc(&gpu_rad_integration_bin_map, xpixels * ypixels * sizeof(int16_t))); - cuda_err(cudaMalloc(&gpu_rad_integration_count, rad_integration_nbins * sizeof(int32_t))); - cuda_err(cudaMalloc(&gpu_rad_integration_sum, rad_integration_nbins * sizeof(int32_t))); + cuda_err(cudaMalloc(&gpu_rad_integration_corr, xpixels * ypixels * sizeof(float))); - cuda_err(cudaHostAlloc(&host_rad_integration_count, rad_integration_nbins * sizeof(int32_t), cudaHostAllocPortable)); - cuda_err(cudaHostAlloc(&host_rad_integration_sum, rad_integration_nbins * sizeof(int32_t), cudaHostAllocPortable)); + cuda_err(cudaMalloc(&gpu_rad_integration_count, rad_integration_nbins * sizeof(float))); + cuda_err(cudaMalloc(&gpu_rad_integration_sum, rad_integration_nbins * sizeof(float))); + cuda_err(cudaHostAlloc(&host_rad_integration_count, rad_integration_nbins * sizeof(float), cudaHostAllocPortable)); + cuda_err(cudaHostAlloc(&host_rad_integration_sum, rad_integration_nbins * sizeof(float), cudaHostAllocPortable)); cudaMemcpy(gpu_rad_integration_bin_map, rad_int_mapping.data(), xpixels*ypixels * sizeof(uint16_t), cudaMemcpyHostToDevice); + + std::vector corr(xpixels * ypixels, 1.0f); + cudaMemcpy(gpu_rad_integration_corr, corr.data(), + xpixels * ypixels * sizeof(float), cudaMemcpyHostToDevice); } } GPUImageAnalysis::GPUImageAnalysis(int32_t xpixels, int32_t ypixels, const std::vector &mask, - const RadialIntegrationMapping& mapping, - int32_t gpu_device) - : GPUImageAnalysis(xpixels, ypixels, mask, mapping.GetPixelToBinMapping(), - mapping.GetBinNumber(), gpu_device) {} + const RadialIntegrationMapping& mapping) + : GPUImageAnalysis(xpixels, ypixels, mask, mapping.GetPixelToBinMapping(),mapping.GetBinNumber()) {} GPUImageAnalysis::~GPUImageAnalysis() { cudaStreamDestroy(cudastream->v); @@ -303,6 +298,7 @@ GPUImageAnalysis::~GPUImageAnalysis() { cudaFree(gpu_rad_integration_bin_map); cudaFree(gpu_rad_integration_count); cudaFree(gpu_rad_integration_sum); + cudaFree(gpu_rad_integration_corr); cudaFreeHost(host_rad_integration_count); cudaFreeHost(host_rad_integration_sum); } @@ -423,6 +419,15 @@ void GPUImageAnalysis::LoadDataToGPU(bool apply_pixel_mask_on_gpu) { } } +void GPUImageAnalysis::LoadRadialIntegrationCorr(const std::vector& v) { + if (rad_integration_nbins == 0) + throw JFJochException(JFJochExceptionCategory::SpotFinderError, "Radial integration not initialized"); + if (v.size() != xpixels * ypixels) + throw JFJochException(JFJochExceptionCategory::SpotFinderError, "Mismatch in correction input size"); + + cudaMemcpy(gpu_rad_integration_corr, v.data(), xpixels * ypixels * sizeof(float), cudaMemcpyHostToDevice); +} + void GPUImageAnalysis::RunRadialIntegration() { if (rad_integration_nbins == 0) throw JFJochException(JFJochExceptionCategory::SpotFinderError, "Radial integration not initialized"); @@ -430,8 +435,9 @@ void GPUImageAnalysis::RunRadialIntegration() { cuda_err(cudaMemsetAsync(gpu_rad_integration_sum, 0, rad_integration_nbins * sizeof(int32_t), cudastream->v)); cuda_err(cudaMemsetAsync(gpu_rad_integration_count, 0, rad_integration_nbins * sizeof(int32_t), cudastream->v)); - gpu_radial_integration<<<40, numberOfCudaThreads, rad_integration_nbins * sizeof(uint32_t) * 2, cudastream->v>>>( - gpu_in, gpu_rad_integration_bin_map, gpu_rad_integration_sum, gpu_rad_integration_count, xpixels*ypixels, + gpu_radial_integration<<v>>>( + gpu_in, gpu_rad_integration_bin_map, gpu_rad_integration_corr, + gpu_rad_integration_sum, gpu_rad_integration_count, xpixels*ypixels, rad_integration_nbins); cuda_err(cudaMemcpyAsync(host_rad_integration_count, gpu_rad_integration_count, @@ -459,24 +465,24 @@ void GPUImageAnalysis::GetRadialIntegrationProfile(std::vector &result) { } } -std::vector GPUImageAnalysis::GetRadialIntegrationSum() const { +std::vector GPUImageAnalysis::GetRadialIntegrationSum() const { if (rad_integration_nbins == 0) throw JFJochException(JFJochExceptionCategory::SpotFinderError, "Radial integration not initialized"); cuda_err(cudaStreamSynchronize(cudastream->v)); - std::vector out(rad_integration_nbins); + std::vector out(rad_integration_nbins); memcpy(out.data(), host_rad_integration_sum, rad_integration_nbins * sizeof(int32_t)); return out; } -std::vector GPUImageAnalysis::GetRadialIntegrationCount() const { +std::vector GPUImageAnalysis::GetRadialIntegrationCount() const { if (rad_integration_nbins == 0) throw JFJochException(JFJochExceptionCategory::SpotFinderError, "Radial integration not initialized"); cuda_err(cudaStreamSynchronize(cudastream->v)); - std::vector out(rad_integration_nbins); + std::vector out(rad_integration_nbins); memcpy(out.data(), host_rad_integration_count, rad_integration_nbins * sizeof(int32_t)); return out; } @@ -487,8 +493,8 @@ float GPUImageAnalysis::GetRadialIntegrationRangeValue(uint16_t min_bin, uint16_ cuda_err(cudaStreamSynchronize(cudastream->v)); - int64_t ret_sum = 0; - int64_t ret_count = 0; + float ret_sum = 0; + float ret_count = 0; for (int i = std::min(rad_integration_nbins,min_bin); i <= std::min((uint16_t)(rad_integration_nbins-1),max_bin); @@ -500,7 +506,5 @@ float GPUImageAnalysis::GetRadialIntegrationRangeValue(uint16_t min_bin, uint16_ if (ret_count == 0) return 0; else - return static_cast(ret_sum) / static_cast(ret_count); + return ret_sum / ret_count; } - -std::atomic GPUImageAnalysis::threadid{0}; diff --git a/image_analysis/GPUImageAnalysis.h b/image_analysis/GPUImageAnalysis.h index b5af0929..683132a4 100644 --- a/image_analysis/GPUImageAnalysis.h +++ b/image_analysis/GPUImageAnalysis.h @@ -1,5 +1,4 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (2019-2023) Paul Scherrer Institute #ifndef JUNGFRAUJOCH_GPUIMAGEANALYSIS_H #define JUNGFRAUJOCH_GPUIMAGEANALYSIS_H @@ -25,8 +24,6 @@ class GPUImageAnalysis { std::mutex m; CudaStreamWrapper *cudastream; - static std::atomic threadid; - const int32_t xpixels; const int32_t ypixels; @@ -41,9 +38,12 @@ class GPUImageAnalysis { uint16_t rad_integration_nbins; uint16_t *gpu_rad_integration_bin_map = nullptr; - int32_t *gpu_rad_integration_sum = nullptr; - int32_t *gpu_rad_integration_count = nullptr; - int32_t *host_rad_integration_sum = nullptr, *host_rad_integration_count = nullptr; + float *gpu_rad_integration_sum = nullptr; + float *gpu_rad_integration_count = nullptr; + float *gpu_rad_integration_corr = nullptr; + + float *host_rad_integration_sum = nullptr, *host_rad_integration_count = nullptr; + int numberOfSMs; const int numberOfCudaThreads = 128; // #threads per block that works well for Nvidia T4 const int numberOfWaves = 40; // #waves that works well for Nvidia T4 @@ -51,12 +51,11 @@ class GPUImageAnalysis { const int maxStrongPixel = 65536; public: - GPUImageAnalysis(int32_t xpixels, int32_t ypixels, const std::vector &mask, int32_t gpu_device = -1); + GPUImageAnalysis(int32_t xpixels, int32_t ypixels, const std::vector &mask); GPUImageAnalysis(int32_t xpixels, int32_t ypixels, const std::vector &mask, - const std::vector &rad_int_mapping, uint16_t rad_int_nbins, - int32_t gpu_device = -1); + const std::vector &rad_int_mapping, uint16_t rad_int_nbins); GPUImageAnalysis(int32_t xpixels, int32_t ypixels, const std::vector &mask, - const RadialIntegrationMapping& mapping,int32_t gpu_device = -1); + const RadialIntegrationMapping& mapping); ~GPUImageAnalysis(); @@ -68,10 +67,11 @@ public: void GetSpotFinderResults(const DiffractionExperiment &experiment, const JFJochProtoBuf::DataProcessingSettings &settings, std::vector &vec); + void LoadRadialIntegrationCorr(const std::vector& v); void RunRadialIntegration(); void GetRadialIntegrationProfile(std::vector &result); - [[nodiscard]] std::vector GetRadialIntegrationSum() const; - [[nodiscard]] std::vector GetRadialIntegrationCount() const; + [[nodiscard]] std::vector GetRadialIntegrationSum() const; + [[nodiscard]] std::vector GetRadialIntegrationCount() const; [[nodiscard]] float GetRadialIntegrationRangeValue(uint16_t min_bin, uint16_t max_bin); static bool GPUPresent(); diff --git a/image_analysis/IndexerWrapper.cpp b/image_analysis/IndexerWrapper.cpp index ec11922e..50692dac 100644 --- a/image_analysis/IndexerWrapper.cpp +++ b/image_analysis/IndexerWrapper.cpp @@ -1,5 +1,4 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (2019-2023) Paul Scherrer Institute #include "IndexerWrapper.h" @@ -9,22 +8,6 @@ void IndexerWrapper::Setup(const UnitCell &cell) { #endif } -// Select spots that belong to indexing solution -// - cell cell in real space -// - spots spots in reciprocal space -// - threshold radius around approximated miller indices -template -inline auto select_indexed_spots(const Eigen::MatrixBase& cell, - const Eigen::MatrixBase& spots, - float_type threshold=.02f) -{ - using M3x = Eigen::MatrixX3; - M3x resid = spots * cell.transpose(); - const M3x miller = round(resid.array()); - resid -= miller; - return resid.rowwise().norm().array() < threshold; -} - std::vector IndexerWrapper::Run(const std::vector &coord) { #ifdef JFJOCH_USE_CUDA std::vector ret; @@ -46,10 +29,15 @@ std::vector IndexerWrapper::Run(const std::vector &coord) // Get best cell auto id = fast_feedback::refine::best_cell(indexer.oScoreV()); - // Get indexed spots - auto arr = select_indexed_spots(indexer.oCell(id), indexer.Spots(), threshold); + // get indexed spots + using M3x = Eigen::MatrixX3; + M3x resid = indexer.Spots() * indexer.oCell(id).transpose(); + const M3x miller = round(resid.array()); + resid -= miller; + auto arr = resid.rowwise().norm().array() < threshold; auto indexed_spot_count = arr.count(); + // Check if result is viable if (indexed_spot_count > min_spots) { IndexingResult result; diff --git a/image_analysis/IndexerWrapper.h b/image_analysis/IndexerWrapper.h index e2afb100..e6766ac6 100644 --- a/image_analysis/IndexerWrapper.h +++ b/image_analysis/IndexerWrapper.h @@ -1,5 +1,4 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (2019-2023) Paul Scherrer Institute #ifndef JUNGFRAUJOCH_INDEXERWRAPPER_H #define JUNGFRAUJOCH_INDEXERWRAPPER_H @@ -18,7 +17,7 @@ struct IndexingResult { CrystalLattice l; - std::vector indexed_spots; + std::vector indexed_spots; uint64_t indexed_spots_count; }; diff --git a/image_analysis/PredictSpotsOnDetector.h b/image_analysis/PredictSpotsOnDetector.h new file mode 100644 index 00000000..c47072a9 --- /dev/null +++ b/image_analysis/PredictSpotsOnDetector.h @@ -0,0 +1,58 @@ +// Copyright (2019-2023) Paul Scherrer Institute + +#ifndef JUNGFRAUJOCH_PREDICTSPOTSONDETECTOR_H +#define JUNGFRAUJOCH_PREDICTSPOTSONDETECTOR_H + +#include +#include "../common/DiffractionGeometry.h" +#include "../common/ROIFilter.h" +#include "CrystalLattice.h" + +std::vector> PredictSpotsOnDetector(const DiffractionExperiment& experiment, + const CrystalLattice& lattice, + int32_t max_hkl = 30, + float epsilon = 4e-4) { + CrystalLattice recip_l = lattice.ReciprocalLattice(); + std::vector> ret; + for (int h = -max_hkl; h < max_hkl; h++) { + for (int k = -max_hkl; k < max_hkl; k++) { + for (int l = -max_hkl; l < max_hkl; l++) { + Coord recip = static_cast(h) * recip_l.Vec0() + + static_cast(k) * recip_l.Vec1() + + static_cast(l) * recip_l.Vec2(); + + if (DistFromEwaldSphere(experiment, recip) < epsilon) + ret.push_back(RecipToDector(experiment, recip)); + } + } + } + return ret; +} + +void PredictSpotsOnDetector(ROIFilter &filter, + const DiffractionExperiment& experiment, + const CrystalLattice& lattice, + int32_t max_hkl = 30, + float epsilon = 4e-4, + uint16_t box_size = 7) { + CrystalLattice recip_l = lattice.ReciprocalLattice(); + std::vector> ret; + for (int h = -max_hkl; h < max_hkl; h++) { + for (int k = -max_hkl; k < max_hkl; k++) { + for (int l = -max_hkl; l < max_hkl; l++) { + Coord recip = static_cast(h) * recip_l.Vec0() + + static_cast(k) * recip_l.Vec1() + + static_cast(l) * recip_l.Vec2(); + + if (DistFromEwaldSphere(experiment, recip) < epsilon) { + auto [x,y] = RecipToDector(experiment, recip); + auto x0 = static_cast(std::lroundf(x - static_cast(box_size))); + auto y0 = static_cast(std::lroundf(y - static_cast(box_size))); + filter.SetRectangle(x0, y0, 2 * box_size + 1, 2 * box_size + 1); + } + } + } + } +} + +#endif //JUNGFRAUJOCH_PREDICTSPOTSONDETECTOR_H diff --git a/image_analysis/RadialIntegration.cpp b/image_analysis/RadialIntegration.cpp index 7118af15..7b92b2b2 100644 --- a/image_analysis/RadialIntegration.cpp +++ b/image_analysis/RadialIntegration.cpp @@ -1,16 +1,44 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (2019-2023) Paul Scherrer Institute #include "RadialIntegration.h" #include "../common/JFJochException.h" -RadialIntegration::RadialIntegration(const std::vector& in_mapping, uint16_t in_nbins) : - pixel_to_bin(in_mapping), nbins(in_nbins), sum(in_nbins, 0), count(in_nbins, 0) +RadialIntegration::RadialIntegration(const std::vector& in_mapping, uint32_t in_nbins, uint32_t in_pixel_split) : + pixel_to_bin(in_mapping), nbins(in_nbins), sum(in_nbins, 0), count(in_nbins, 0), + pixel_split(in_pixel_split) +{ + + if (pixel_split == 4) { + if (pixel_to_bin.size() % 4 != 0) + throw JFJochException(JFJochExceptionCategory::InputParameterInvalid, + "With pixel split of 4 input array must be of size multiple of 4"); + } else if (pixel_split != 1) + throw JFJochException(JFJochExceptionCategory::InputParameterInvalid, + "Only pixel split of 1 and 4 allowed at the moment for radial integration"); + + coeff = (float *) std::aligned_alloc(64, in_mapping.size() * sizeof(float)); + if (coeff == nullptr) + throw JFJochException(JFJochExceptionCategory::InputParameterInvalid, + "Memory allocation error"); + + for (int i = 0; i < in_mapping.size(); i++) + coeff[i] = 1.0f; +} + +RadialIntegration::RadialIntegration(const RadialIntegrationMapping &mapping, uint32_t in_pixel_split) : + RadialIntegration(mapping.GetPixelToBinMapping(), mapping.GetBinNumber(), in_pixel_split) {} -RadialIntegration::RadialIntegration(const RadialIntegrationMapping &mapping) : - RadialIntegration(mapping.GetPixelToBinMapping(), mapping.GetBinNumber()) -{} +RadialIntegration::~RadialIntegration() { + std::free(coeff); +} + +void RadialIntegration::LoadRadialIntegrationCorr(const std::vector &v) { + if (v.size() != pixel_to_bin.size() * pixel_split) + throw JFJochException(JFJochExceptionCategory::InputParameterInvalid, + "Mismatch in size of pixel-to-bin mapping and correction"); + memcpy(coeff, v.data(), pixel_to_bin.size() * pixel_split * sizeof(float)); +} void RadialIntegration::Clear() { for (auto &i : sum) @@ -20,17 +48,36 @@ void RadialIntegration::Clear() { i = 0; } -void RadialIntegration::Process(const int16_t *data, size_t npixel) { - if (npixel != pixel_to_bin.size()) +void RadialIntegration::Process(const int16_t *__restrict data, size_t npixel) { + if (npixel != pixel_to_bin.size() / pixel_split) throw JFJochException(JFJochExceptionCategory::InputParameterInvalid, "Mismatch in size of pixel-to-bin mapping and image"); - for (int i = 0; i < npixel; i++) { - auto bin = pixel_to_bin[i]; - auto value = data[i]; - if ((value > INT16_MIN + 4) && (value < INT16_MAX - 4) && (bin < nbins)) { - sum[bin] += value; - count[bin] += 1; + const auto coeff_aligned = std::assume_aligned<64>(coeff); + + if (pixel_split == 1) { + for (int i = 0; i < npixel; i++) { + auto value = data[i]; + if ((value > INT16_MIN + 4) && (value < INT16_MAX - 4)) { + auto bin = pixel_to_bin[i]; + if (bin < nbins) { + sum[bin] += coeff_aligned[i] * value; + count[bin] += 1.0f; + } + } + } + } else if (pixel_split == 4) { + for (int i = 0; i < npixel; i++) { + auto value = data[i]; + if ((value > INT16_MIN + 4) && (value < INT16_MAX - 4)) { + for (int p = 0; p < 4; p++) { + auto bin = pixel_to_bin[i * pixel_split + p]; + if (bin < nbins) { + sum[bin] += coeff_aligned[i * pixel_split + p] * value * 0.25f; + count[bin] += 0.25f; + } + } + } } } } @@ -51,19 +98,19 @@ void RadialIntegration::GetResult(std::vector &result) const { } } -const std::vector &RadialIntegration::GetSum() const { +const std::vector &RadialIntegration::GetSum() const { return sum; } -const std::vector &RadialIntegration::GetCount() const { +const std::vector &RadialIntegration::GetCount() const { return count; } -float RadialIntegration::GetRangeValue(uint16_t min_bin, uint16_t max_bin) { - int64_t ret_sum = 0; - int64_t ret_count = 0; +float RadialIntegration::GetRangeValue(uint32_t min_bin, uint32_t max_bin) { + float ret_sum = 0; + float ret_count = 0; - for (int i = std::min(nbins,min_bin); i <= std::min((uint16_t)(nbins-1),max_bin); i++) { + for (int i = std::min(nbins,min_bin); i <= std::min(nbins-1,max_bin); i++) { ret_sum += sum[i]; ret_count += count[i]; } diff --git a/image_analysis/RadialIntegration.h b/image_analysis/RadialIntegration.h index 80f18bbb..6843559f 100644 --- a/image_analysis/RadialIntegration.h +++ b/image_analysis/RadialIntegration.h @@ -1,5 +1,4 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (2019-2023) Paul Scherrer Institute #ifndef JUNGFRAUJOCH_RADIALINTEGRATION_H #define JUNGFRAUJOCH_RADIALINTEGRATION_H @@ -12,20 +11,24 @@ #include "RadialIntegrationMapping.h" class RadialIntegration { - const std::vector& pixel_to_bin; - const uint16_t nbins; - std::vector sum; - std::vector count; + const std::vector pixel_to_bin; + float *coeff; + const uint32_t nbins; + const uint32_t pixel_split; + std::vector sum; + std::vector count; public: - RadialIntegration(const RadialIntegrationMapping& mapping); - RadialIntegration(const std::vector& mapping, uint16_t nbins); + RadialIntegration(const RadialIntegrationMapping& mapping, uint32_t pixel_split = 1); + RadialIntegration(const std::vector& mapping, uint32_t nbins, uint32_t pixel_split = 1); + ~RadialIntegration(); void Clear(); void Process(const int16_t *data, size_t npixel); void ProcessOneImage(const int16_t *data, size_t npixel); // Process + Clear void GetResult(std::vector &result) const; - [[nodiscard]] float GetRangeValue(uint16_t min_bin, uint16_t max_bin); - [[nodiscard]] const std::vector& GetSum() const; - [[nodiscard]] const std::vector& GetCount() const; + void LoadRadialIntegrationCorr(const std::vector &v); + [[nodiscard]] float GetRangeValue(uint32_t min_bin, uint32_t max_bin); + [[nodiscard]] const std::vector& GetSum() const; + [[nodiscard]] const std::vector& GetCount() const; }; diff --git a/image_analysis/RadialIntegrationMapping.cpp b/image_analysis/RadialIntegrationMapping.cpp index 5ceca4bb..ac98f06d 100644 --- a/image_analysis/RadialIntegrationMapping.cpp +++ b/image_analysis/RadialIntegrationMapping.cpp @@ -1,10 +1,10 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (2019-2023) Paul Scherrer Institute #include #include "RadialIntegrationMapping.h" #include "../common/JFJochException.h" +#include "../common/DiffractionGeometry.h" RadialIntegrationMapping::RadialIntegrationMapping(const DiffractionExperiment& experiment, const uint8_t *one_byte_mask) : low_q(experiment.GetLowQForRadialInt_recipA()), @@ -34,7 +34,7 @@ RadialIntegrationMapping::RadialIntegrationMapping(const DiffractionExperiment& for (int x = 0; x < experiment.GetXPixelsNum(); x++) { int64_t pixel_number = y * experiment.GetXPixelsNum() + x; - double pixel_q = 2 * M_PI / experiment.PxlToRes(x, y); + double pixel_q = 2 * M_PI / PxlToRes(experiment, x, y); if (((one_byte_mask != nullptr) && (one_byte_mask[pixel_number] == 0)) || (pixel_q < low_q) || (pixel_q >= high_q)) @@ -57,7 +57,7 @@ RadialIntegrationMapping::RadialIntegrationMapping(const DiffractionExperiment& solid_angle_corr.resize(max_bin_number + 1); for (int i = 0; i < max_bin_number + 1; i++) - solid_angle_corr[i] = 1.0f / experiment.CalcRadIntSolidAngleCorr(bin_to_q[i]); + solid_angle_corr[i] = 1.0f / CalcRadIntSolidAngleCorr(experiment, bin_to_q[i]); } uint16_t RadialIntegrationMapping::GetBinNumber() const { @@ -78,4 +78,13 @@ const std::vector &RadialIntegrationMapping::GetSolidAngleCorr() const { double RadialIntegrationMapping::QToBin(double q) const { return std::min(static_cast(max_bin_number), std::max(0.0, (q - low_q) / q_spacing)); -} \ No newline at end of file +} + +std::vector RadialIntegrationMapping::GetPixelToBinMappingSplitTo4() const { + std::vector ret(pixel_to_bin.size() * 4); + for (int i = 0; i < pixel_to_bin.size(); i++) { + for (int j = 0; j < 4; j++) + ret[i * 4 + j] = pixel_to_bin[i]; + } + return ret; +} diff --git a/image_analysis/RadialIntegrationMapping.h b/image_analysis/RadialIntegrationMapping.h index 4c185b19..12076f68 100644 --- a/image_analysis/RadialIntegrationMapping.h +++ b/image_analysis/RadialIntegrationMapping.h @@ -1,5 +1,4 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (2019-2023) Paul Scherrer Institute #ifndef JUNGFRAUJOCH_RADIALINTEGRATIONMAPPING_H #define JUNGFRAUJOCH_RADIALINTEGRATIONMAPPING_H @@ -17,6 +16,7 @@ public: RadialIntegrationMapping(const DiffractionExperiment& experiment, const uint8_t *one_byte_mask = nullptr); [[nodiscard]] uint16_t GetBinNumber() const; [[nodiscard]] const std::vector &GetPixelToBinMapping() const; + [[nodiscard]] std::vector GetPixelToBinMappingSplitTo4() const; [[nodiscard]] const std::vector &GetBinToQ() const; [[nodiscard]] const std::vector &GetSolidAngleCorr() const; [[nodiscard]] double QToBin(double q) const; diff --git a/image_analysis/RadialIntegrationProfile.cpp b/image_analysis/RadialIntegrationProfile.cpp index cbd66737..599ead54 100644 --- a/image_analysis/RadialIntegrationProfile.cpp +++ b/image_analysis/RadialIntegrationProfile.cpp @@ -1,5 +1,4 @@ // Copyright (2019-2023) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later #include "RadialIntegrationProfile.h" #include "../common/JFJochException.h" @@ -8,15 +7,10 @@ RadialIntegrationProfile::RadialIntegrationProfile(RadialIntegrationMapping &map const DiffractionExperiment& experiment) : bin_to_q(mapping.GetBinToQ()), sum(mapping.GetBinNumber(), 0), - count(mapping.GetBinNumber(), 0), - corrections(mapping.GetSolidAngleCorr()) { + count(mapping.GetBinNumber(), 0){ } -const std::vector &RadialIntegrationProfile::GetSolidAngleCorr() const { - return corrections; -} - -void RadialIntegrationProfile::Add(const std::vector &in_sum, const std::vector &in_count) { +void RadialIntegrationProfile::Add(const std::vector &in_sum, const std::vector &in_count) { std::unique_lock ul(m); if ((in_sum.size() == sum.size()) && (in_count.size() == count.size())) { @@ -28,25 +22,19 @@ void RadialIntegrationProfile::Add(const std::vector &in_sum, const std throw JFJochException(JFJochExceptionCategory::InputParameterInvalid, "Mismatch in size of sum/count datasets"); } -std::vector RadialIntegrationProfile::GetResult(bool solid_angle_correction) const { +std::vector RadialIntegrationProfile::GetResult() const { std::vector rad_int_profile(sum.size(), 0); for (int i = 0; i < sum.size(); i++) { - float tmp = 0; - - if (count[i] > 0) { - tmp = static_cast(sum[i]) / static_cast(count[i]); - if (solid_angle_correction) - tmp *= corrections[i]; - } - rad_int_profile[i] = tmp; + if (count[i] > 0) + rad_int_profile[i] = static_cast(sum[i]) / static_cast(count[i]); } return rad_int_profile; } -void RadialIntegrationProfile::GetPlot(JFJochProtoBuf::Plot &plot, bool solid_angle_correction) const { +void RadialIntegrationProfile::GetPlot(JFJochProtoBuf::Plot &plot) const { std::unique_lock ul(m); - std::vector rad_int_profile = GetResult(solid_angle_correction); + std::vector rad_int_profile = GetResult(); *plot.mutable_x() = {bin_to_q.begin(), bin_to_q.end()}; *plot.mutable_y() = {rad_int_profile.begin(), rad_int_profile.end()}; diff --git a/image_analysis/RadialIntegrationProfile.h b/image_analysis/RadialIntegrationProfile.h index f8b00c62..75dcec40 100644 --- a/image_analysis/RadialIntegrationProfile.h +++ b/image_analysis/RadialIntegrationProfile.h @@ -1,5 +1,4 @@ // Copyright (2019-2023) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later #ifndef JUNGFRAUJOCH_RADIALINTEGRATIONPROFILE_H #define JUNGFRAUJOCH_RADIALINTEGRATIONPROFILE_H @@ -12,16 +11,14 @@ class RadialIntegrationProfile { mutable std::mutex m; - std::vector sum; - std::vector count; + std::vector sum; + std::vector count; std::vector bin_to_q; - std::vector corrections; public: explicit RadialIntegrationProfile(RadialIntegrationMapping &mapping, const DiffractionExperiment &experiment); - void Add(const std::vector &sum, const std::vector &count); - std::vector GetResult(bool solid_angle_correction) const; - void GetPlot(JFJochProtoBuf::Plot &plot, bool solid_angle_correction) const; - const std::vector &GetSolidAngleCorr() const; + void Add(const std::vector &sum, const std::vector &count); + std::vector GetResult() const; + void GetPlot(JFJochProtoBuf::Plot &plot) const; }; #endif //JUNGFRAUJOCH_RADIALINTEGRATIONPROFILE_H diff --git a/image_analysis/StrongPixelSet.cpp b/image_analysis/StrongPixelSet.cpp index 34fe8513..880e6372 100644 --- a/image_analysis/StrongPixelSet.cpp +++ b/image_analysis/StrongPixelSet.cpp @@ -1,5 +1,4 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (2019-2023) Paul Scherrer Institute #include #include "StrongPixelSet.h" diff --git a/image_analysis/StrongPixelSet.h b/image_analysis/StrongPixelSet.h index 745fa06b..a78f310a 100644 --- a/image_analysis/StrongPixelSet.h +++ b/image_analysis/StrongPixelSet.h @@ -1,5 +1,4 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (2019-2023) Paul Scherrer Institute #ifndef JUNGFRAUJOCH_STRONGPIXELSET_H #define JUNGFRAUJOCH_STRONGPIXELSET_H diff --git a/image_analysis/fast-feedback-indexer b/image_analysis/fast-feedback-indexer index 0db516f1..6eccc70b 160000 --- a/image_analysis/fast-feedback-indexer +++ b/image_analysis/fast-feedback-indexer @@ -1 +1 @@ -Subproject commit 0db516f124dd868297e49f4942f3e6c1fa4895cb +Subproject commit 6eccc70b524ba7a0207aa2c93b85769c1c9f5a62 diff --git a/jungfrau/CMakeLists.txt b/jungfrau/CMakeLists.txt index 10e032ac..bc556467 100644 --- a/jungfrau/CMakeLists.txt +++ b/jungfrau/CMakeLists.txt @@ -6,8 +6,14 @@ ADD_LIBRARY(JFCalibration STATIC JFModulePedestal.cpp JFModulePedestal.h JFModuleGainCalibration.cpp JFModuleGainCalibration.h JFPedestalCalc.cpp JFPedestalCalc.h - ProcessJFPacket.cpp ProcessJFPacket.h) + ProcessJFPacket.cpp ProcessJFPacket.h + JFConversionGPU.h JFConversionGPU.cpp) SET_SOURCE_FILES_PROPERTIES(JFPedestalCalc.cpp JFConversionFloatingPoint.cpp JFConversionFixedPoint.cpp PROPERTIES COMPILE_FLAGS -Ofast) -TARGET_LINK_LIBRARIES(JFCalibration JFJochProtoBuf Compression) \ No newline at end of file +TARGET_LINK_LIBRARIES(JFCalibration JFJochProtoBuf Compression) + +IF (CMAKE_CUDA_COMPILER) + TARGET_SOURCES(JFCalibration PRIVATE JFConversionGPU.cu ) + TARGET_LINK_LIBRARIES(JFCalibration ${CUDART_LIBRARY} ${CMAKE_DL_LIBS} rt) +ENDIF() diff --git a/jungfrau/JFCalibration.cpp b/jungfrau/JFCalibration.cpp index 13a0f754..865070af 100644 --- a/jungfrau/JFCalibration.cpp +++ b/jungfrau/JFCalibration.cpp @@ -1,5 +1,4 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (2019-2023) Paul Scherrer Institute #include "JFCalibration.h" diff --git a/jungfrau/JFCalibration.h b/jungfrau/JFCalibration.h index 3f44e015..8f5b1c06 100644 --- a/jungfrau/JFCalibration.h +++ b/jungfrau/JFCalibration.h @@ -1,5 +1,4 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (2019-2023) Paul Scherrer Institute #ifndef JUNGFRAUJOCH_JFCALIBRATION_H #define JUNGFRAUJOCH_JFCALIBRATION_H diff --git a/jungfrau/JFConversion.h b/jungfrau/JFConversion.h index ccccb057..79046bbb 100644 --- a/jungfrau/JFConversion.h +++ b/jungfrau/JFConversion.h @@ -1,5 +1,4 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (2019-2023) Paul Scherrer Institute #ifndef JUNGFRAUJOCH_JFCONVERSION_H #define JUNGFRAUJOCH_JFCONVERSION_H @@ -16,14 +15,8 @@ public: const JFModulePedestal &pedestal_g2, double energy) = 0; - virtual void ConvertPacket(int16_t* dest, const uint16_t* source, uint16_t packet_number) = 0; - void Convert(int16_t* dest, const uint16_t* source) { - for (int i = 0; i < 128; i++) - ConvertPacket(dest + i * 4 * RAW_MODULE_COLS, source + i * 4 * RAW_MODULE_COLS, i); - } - - virtual void ConvertAdjustGeom(int16_t* dest, const uint16_t* source, int64_t slow_dir_step, - int64_t fast_dir_step, int64_t offset) = 0; + virtual void ConvertModule(int16_t* dest, const uint16_t* source) = 0; + virtual void Sync() {}; }; #endif //JUNGFRAUJOCH_JFCONVERSION_H diff --git a/jungfrau/JFConversionFixedPoint.cpp b/jungfrau/JFConversionFixedPoint.cpp index 4da70ce1..7d431c22 100644 --- a/jungfrau/JFConversionFixedPoint.cpp +++ b/jungfrau/JFConversionFixedPoint.cpp @@ -1,5 +1,4 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (2019-2023) Paul Scherrer Institute #include "JFConversionFixedPoint.h" #include "../common/RawToConvertedGeometry.h" @@ -51,14 +50,18 @@ void JFConversionFixedPoint::Setup(const JFModuleGainCalibration &gain_calibrati inline int32_t jf_round(int32_t in) { const int32_t half = (1L << (FIXED_PRECISION-1)); - if (in > 0) + + if (in <= INT16_MIN * (1L << FIXED_PRECISION)) + return INT16_MIN * (1L << FIXED_PRECISION); + else if (in >= INT16_MAX * (1L << FIXED_PRECISION)) + return INT16_MAX * (1L << FIXED_PRECISION); + else if (in > 0) return in + half; else return in - half; } -void JFConversionFixedPoint::ConvertLine(int16_t *dest, const uint16_t *source, int line) { - +void JFConversionFixedPoint::ConvertModule(int16_t *__restrict dest, const uint16_t *source) { auto gain_g0_aligned = std::assume_aligned<64>(gain_g0); auto gain_g1_aligned = std::assume_aligned<64>(gain_g1); auto gain_g2_aligned = std::assume_aligned<64>(gain_g2); @@ -66,64 +69,37 @@ void JFConversionFixedPoint::ConvertLine(int16_t *dest, const uint16_t *source, auto pedestal_g1_aligned = std::assume_aligned<64>(pedestal_g1); auto pedestal_g2_aligned = std::assume_aligned<64>(pedestal_g2); - for (int i = 0; i < RAW_MODULE_COLS; i++) { +#pragma ivdep + for (int i = 0; i < RAW_MODULE_SIZE; i++) { uint16_t gainbits = source[i] & 0xc000; int32_t adc = source[i] & 0x3fff; - int32_t val = 0; - bool overflow = false; - bool wrong = false; + dest[i] = static_cast(jf_round((adc - pedestal_g0_aligned[i]) * gain_g0_aligned[i]) + / (1L << FIXED_PRECISION)); - if ((source[i] == 0x4000) || (source[i] == 0xffff)) wrong = true; - else if (source[i] == 0xc000) overflow = true; + int16_t val_1 = jf_round((adc - pedestal_g1_aligned[i]) * gain_g1_aligned[i]) + / (1L << FIXED_PRECISION); - switch (gainbits) { - case 0: - [[likely]] - val = jf_round((adc - pedestal_g0_aligned[i + line * RAW_MODULE_COLS]) * gain_g0_aligned[i + line * RAW_MODULE_COLS]); - break; - case 0x4000: - val = jf_round((adc - pedestal_g1_aligned[i + line * RAW_MODULE_COLS]) * gain_g1_aligned[i + line * RAW_MODULE_COLS]); - break; - case 0xc000: - val = jf_round((adc - pedestal_g2_aligned[i + line * RAW_MODULE_COLS]) * gain_g2_aligned[i + line * RAW_MODULE_COLS]); - break; - default: - wrong = true; - break; - } + int16_t val_2 = jf_round((adc - pedestal_g2_aligned[i]) * gain_g2_aligned[i]) + / (1L << FIXED_PRECISION); - if (wrong || (val <= INT16_MIN * (1L << FIXED_PRECISION))) - [[unlikely]] - dest[i] = INT16_MIN; - else if (overflow || (val >= INT16_MAX * (1L << FIXED_PRECISION))) - [[unlikely]] - dest[i] = INT16_MAX; - else - dest[i] = static_cast(val / (1L << FIXED_PRECISION)); - } -} + if (gainbits == 0x4000) + dest[i] = val_1; -void JFConversionFixedPoint::ConvertPacket(int16_t *dest, const uint16_t *source, uint16_t packet_number) { - for (int i = 0; i < 4; i++) - ConvertLine(dest + i * RAW_MODULE_COLS, source + i * RAW_MODULE_COLS, 4 * packet_number + i); -} + if (gainbits == 0xc000) + dest[i] = val_2; -void JFConversionFixedPoint::ConvertAdjustGeom(int16_t *dest, const uint16_t *source, int64_t slow_dir_step, - int64_t fast_dir_step, int64_t offset) { - for (int line = 0; line < RAW_MODULE_LINES; line++) { - int16_t tmp[RAW_MODULE_COLS]; - ConvertLine(tmp, source + line * RAW_MODULE_COLS, line); + if (gainbits == 0x8000) + dest[i] = INT16_MIN; - if ((line != 255) && (line != 256)) { - LineCopyAndAdjustMultipixel(dest + slow_dir_step * (line + ((line > 255) ? 2 : 0)), - tmp, INT16_MIN, INT16_MAX, fast_dir_step, offset); - } else { - LineCopyAndAdjustMultipixelMidRow(dest + slow_dir_step * (line + 1), - tmp, INT16_MIN, INT16_MAX, fast_dir_step, offset); - LineCopyAndAdjustMultipixelMidRow(dest + slow_dir_step * (line + ((line > 255) ? 2 : 0)), - tmp, INT16_MIN, INT16_MAX, fast_dir_step, offset); - } + if (source[i] == 0xffff) + dest[i] = INT16_MIN; + + if (source[i] == 0x4000) + dest[i] = INT16_MIN; + + if (source[i] == 0xc000) + dest[i] = INT16_MAX; } } diff --git a/jungfrau/JFConversionFixedPoint.h b/jungfrau/JFConversionFixedPoint.h index c268e9a4..ae171114 100644 --- a/jungfrau/JFConversionFixedPoint.h +++ b/jungfrau/JFConversionFixedPoint.h @@ -1,5 +1,4 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (2019-2023) Paul Scherrer Institute #include "JFConversion.h" @@ -13,7 +12,6 @@ class JFConversionFixedPoint : public JFConversion { int32_t *gain_g0; int32_t *gain_g1; int32_t *gain_g2; - void ConvertLine(int16_t *dest, const uint16_t *source, int line); public: JFConversionFixedPoint(); ~JFConversionFixedPoint(); @@ -26,9 +24,7 @@ public: const JFModulePedestal &pedestal_g1, const JFModulePedestal &pedestal_g2, double energy) override; - void ConvertPacket(int16_t* dest, const uint16_t* source, uint16_t packet_number) override; - void ConvertAdjustGeom(int16_t *dest, const uint16_t *source, int64_t slow_dir_step, - int64_t fast_dir_step, int64_t offset) override; + void ConvertModule(int16_t *dest, const uint16_t *source) override; }; diff --git a/jungfrau/JFConversionFloatingPoint.cpp b/jungfrau/JFConversionFloatingPoint.cpp index ced82014..5cb677bb 100644 --- a/jungfrau/JFConversionFloatingPoint.cpp +++ b/jungfrau/JFConversionFloatingPoint.cpp @@ -1,5 +1,4 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (2019-2023) Paul Scherrer Institute #include "JFConversionFloatingPoint.h" #include "../common/RawToConvertedGeometry.h" @@ -11,7 +10,7 @@ pedestal_g0(RAW_MODULE_SIZE), pedestal_g1(RAW_MODULE_SIZE), pedestal_g2(RAW_MODU inline float one_over_gain_energy(double gain_factor, double energy) { double tmp = gain_factor * energy; if (!std::isfinite(tmp) || (tmp == 0.0)) - return std::numeric_limits::infinity(); + return 0.0; else return static_cast(1.0 / (gain_factor * energy)); } @@ -33,9 +32,52 @@ void JFConversionFloatingPoint::Setup(const JFModuleGainCalibration &gain_calibr } } -void JFConversionFloatingPoint::ConvertPacket(int16_t* dest, const uint16_t* source, uint16_t packet_number) { - for (int i = 0; i < 4; i++) - ConvertLine(dest + i * RAW_MODULE_COLS, source + i * RAW_MODULE_COLS, 4 * packet_number + i); +void JFConversionFloatingPoint::ConvertModule(int16_t *dest, const uint16_t *source) { + for (size_t i = 0; i < RAW_MODULE_SIZE; i++) { + uint16_t gainbits = source[i] & 0xc000; + uint16_t adc = source[i] & 0x3fff; + int16_t pedestal_subtracted_adu; + + float expected = PIXEL_OUT_LOST; + + switch (gainbits) { + case 0: + [[likely]] + pedestal_subtracted_adu = adc - pedestal_g0[i]; + expected = static_cast(pedestal_subtracted_adu) * gain_g0[i]; + if (gain_g0[i] == 0.0) + expected = INT16_MIN; + break; + case 0x4000: + pedestal_subtracted_adu = adc - pedestal_g1[i]; + expected = static_cast(pedestal_subtracted_adu) * gain_g1[i]; + if (adc == 0) [[unlikely]] expected = PIXEL_OUT_G1_SATURATION; + if (gain_g1[i] == 0.0) + expected = INT16_MIN; + break; + case 0xc000: + pedestal_subtracted_adu = adc - pedestal_g2[i]; + expected = static_cast(pedestal_subtracted_adu) * gain_g2[i]; + if (adc == 0) [[unlikely]] expected = PIXEL_OUT_SATURATION; + else if (adc == 0x3fff) [[unlikely]] expected = PIXEL_OUT_0xFFFF; + if (gain_g0[i] == 0.0) + expected = INT16_MIN; + break; + default: + expected = PIXEL_OUT_GAINBIT_2; + break; + } + + if (expected == INT16_MIN) + dest[i] = PIXEL_OUT_LOST; + else if (expected > INT16_MAX) + dest[i] = INT16_MAX; + else if (expected >= 0.0) + [[likely]] + dest[i] = static_cast(expected + 0.5f); + else + dest[i] = static_cast(expected - 0.5f); + } } void JFConversionFloatingPoint::ConvertFP(float *dest, const uint16_t *source) { @@ -51,89 +93,31 @@ void JFConversionFloatingPoint::ConvertFP(float *dest, const uint16_t *source) { case 0: pedestal_subtracted_adu = adc - pedestal_g0[i]; expected = static_cast(pedestal_subtracted_adu) * gain_g0[i]; + if (gain_g0[i] == 0.0) + expected = INT16_MIN, special_val = true; break; case 0x4000: pedestal_subtracted_adu = adc - pedestal_g1[i]; expected = static_cast(pedestal_subtracted_adu) * gain_g1[i]; if (adc == 0) expected = PIXEL_OUT_G1_SATURATION, special_val = true; + if (gain_g1[i] == 0.0) + expected = INT16_MIN, special_val = true; break; case 0xc000: pedestal_subtracted_adu = adc - pedestal_g2[i]; expected = static_cast(pedestal_subtracted_adu) * gain_g2[i]; if (adc == 0) expected = PIXEL_OUT_SATURATION, special_val = true; else if (adc == 0x3fff) expected = PIXEL_OUT_0xFFFF, special_val = true; + if (gain_g2[i] == 0.0) + expected = INT16_MIN, special_val = true; break; default: expected = PIXEL_OUT_GAINBIT_2, special_val = true;; break; } - if (std::isinf(expected)) - expected = PIXEL_OUT_LOST; - else if ((expected > PIXEL_OUT_SATURATION) && !special_val) + if ((expected > PIXEL_OUT_SATURATION) && !special_val) expected = PIXEL_OUT_SATURATION; dest[i] = expected; } } - -void JFConversionFloatingPoint::ConvertAdjustGeom(int16_t *dest, const uint16_t *source, int64_t slow_dir_step, - int64_t fast_dir_step, int64_t offset) { - for (int line = 0; line < RAW_MODULE_LINES; line++) { - int16_t tmp[RAW_MODULE_COLS]; - ConvertLine(tmp, source + line * RAW_MODULE_COLS, line); - - if ((line != 255) && (line != 256)) { - LineCopyAndAdjustMultipixel(dest + slow_dir_step * (line + ((line > 255) ? 2 : 0)), - tmp, INT16_MIN, INT16_MAX, fast_dir_step, offset); - } else { - LineCopyAndAdjustMultipixelMidRow(dest + slow_dir_step * (line + 1), tmp, - INT16_MIN, INT16_MAX, - fast_dir_step, offset); - LineCopyAndAdjustMultipixelMidRow(dest + slow_dir_step * ((line > 255) ? 2 : 0), tmp, - INT16_MIN, INT16_MAX, - fast_dir_step, offset); - } - } -} - -void JFConversionFloatingPoint::ConvertLine(int16_t *dest, const uint16_t *source, int line) { - for (size_t i = 0; i < RAW_MODULE_COLS; i++) { - uint16_t gainbits = source[i] & 0xc000; - uint16_t adc = source[i] & 0x3fff; - int16_t pedestal_subtracted_adu; - - float expected = PIXEL_OUT_LOST; - - switch (gainbits) { - case 0: - [[likely]] - pedestal_subtracted_adu = adc - pedestal_g0[i + line * RAW_MODULE_COLS]; - expected = static_cast(pedestal_subtracted_adu) * gain_g0[i + line * RAW_MODULE_COLS]; - break; - case 0x4000: - pedestal_subtracted_adu = adc - pedestal_g1[i + line * RAW_MODULE_COLS]; - expected = static_cast(pedestal_subtracted_adu) * gain_g1[i + line * RAW_MODULE_COLS]; - if (adc == 0) [[unlikely]] expected = PIXEL_OUT_G1_SATURATION; - break; - case 0xc000: - pedestal_subtracted_adu = adc - pedestal_g2[i + line * RAW_MODULE_COLS]; - expected = static_cast(pedestal_subtracted_adu) * gain_g2[i + line * RAW_MODULE_COLS]; - if (adc == 0) [[unlikely]] expected = PIXEL_OUT_SATURATION; - else if (adc == 0x3fff) [[unlikely]] expected = PIXEL_OUT_0xFFFF; - break; - default: - expected = PIXEL_OUT_GAINBIT_2; - break; - } - - if (std::isinf(expected) || (expected == INT16_MIN)) - dest[i] = PIXEL_OUT_LOST; - else if (expected > INT16_MAX) - dest[i] = INT16_MAX; - else if (expected >= 0.0) - [[likely]] - dest[i] = static_cast(expected + 0.5f); - else - dest[i] = static_cast(expected - 0.5f); - } -} \ No newline at end of file diff --git a/jungfrau/JFConversionFloatingPoint.h b/jungfrau/JFConversionFloatingPoint.h index d74795be..b5c262db 100644 --- a/jungfrau/JFConversionFloatingPoint.h +++ b/jungfrau/JFConversionFloatingPoint.h @@ -1,5 +1,4 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (2019-2023) Paul Scherrer Institute #ifndef JUNGFRAUJOCH_JFCONVERSIONFLOATINGPOINT_H #define JUNGFRAUJOCH_JFCONVERSIONFLOATINGPOINT_H @@ -14,7 +13,6 @@ class JFConversionFloatingPoint : public JFConversion { std::vector gain_g0; std::vector gain_g1; std::vector gain_g2; - void ConvertLine(int16_t *dest, const uint16_t *source, int line); public: JFConversionFloatingPoint(); @@ -23,10 +21,8 @@ public: const JFModulePedestal &pedestal_g1, const JFModulePedestal &pedestal_g2, double energy) override; - void ConvertPacket(int16_t* dest, const uint16_t* source, uint16_t packet_number) override; + void ConvertModule(int16_t *dest, const uint16_t *source) override; void ConvertFP(float *dest, const uint16_t *source); - void ConvertAdjustGeom(int16_t *dest, const uint16_t *source, int64_t slow_dir_step, - int64_t fast_dir_step, int64_t offset) override; }; diff --git a/jungfrau/JFConversionGPU.cpp b/jungfrau/JFConversionGPU.cpp new file mode 100644 index 00000000..c7fecc5e --- /dev/null +++ b/jungfrau/JFConversionGPU.cpp @@ -0,0 +1,22 @@ +// Copyright (2019-2023) Paul Scherrer Institute + +#ifndef JFJOCH_USE_CUDA + +#include "JFConversionGPU.h" + +JFConversionGPU::JFConversionGPU() {} + +JFConversionGPU::~JFConversionGPU() {} + +void JFConversionGPU::Setup(const JFModuleGainCalibration &gain_calibration, const JFModulePedestal &pedestal_g0, + const JFModulePedestal &pedestal_g1, const JFModulePedestal &pedestal_g2, double energy) { + alt_conv.Setup(gain_calibration, pedestal_g0, pedestal_g1, pedestal_g2, energy); +} + +void JFConversionGPU::ConvertModule(int16_t *dest, const uint16_t *source) { + alt_conv.ConvertModule(dest, source); +} + +void JFConversionGPU::Sync() {} + +#endif diff --git a/jungfrau/JFConversionGPU.cu b/jungfrau/JFConversionGPU.cu new file mode 100644 index 00000000..b079c8c9 --- /dev/null +++ b/jungfrau/JFConversionGPU.cu @@ -0,0 +1,135 @@ +// Copyright (2019-2023) Paul Scherrer Institute + +#include "JFConversionGPU.h" +#include "../common/JFJochException.h" + +inline void cuda_err(cudaError_t val) { + if (val != cudaSuccess) + throw JFJochException(JFJochExceptionCategory::GPUCUDAError, cudaGetErrorString(val)); +} + +struct CudaStreamWrapper { + cudaStream_t v; +}; + +inline float one_over_gain_energy(double gain_factor, double energy) { + double tmp = gain_factor * energy; + if (!std::isfinite(tmp) || (tmp == 0.0)) + return std::numeric_limits::infinity(); + else + return static_cast(1.0 / (gain_factor * energy)); +} + +__global__ void gpu_jf_convert(int16_t *output, const uint16_t* input, + const uint16_t *pedestal_g0, + const uint16_t *pedestal_g1, + const uint16_t *pedestal_g2, + const float *gain_g0, + const float *gain_g1, + const float *gain_g2) { + uint32_t idx = blockDim.x*blockIdx.x + threadIdx.x; + + uint16_t gainbits = input[idx] & 0xc000; + uint16_t adc = input[idx] & 0x3fff; + int16_t pedestal_subtracted_adu; + + float expected = PIXEL_OUT_LOST; + + switch (gainbits) { + case 0: + pedestal_subtracted_adu = adc - pedestal_g0[idx]; + expected = static_cast(pedestal_subtracted_adu) * gain_g0[idx]; + break; + case 0x4000: + pedestal_subtracted_adu = adc - pedestal_g1[idx]; + expected = static_cast(pedestal_subtracted_adu) * gain_g1[idx]; + if (adc == 0) [[unlikely]] expected = PIXEL_OUT_G1_SATURATION; + break; + case 0xc000: + pedestal_subtracted_adu = adc - pedestal_g2[idx]; + expected = static_cast(pedestal_subtracted_adu) * gain_g2[idx]; + if (adc == 0) [[unlikely]] expected = PIXEL_OUT_SATURATION; + else if (adc == 0x3fff) [[unlikely]] expected = PIXEL_OUT_0xFFFF; + break; + default: + expected = PIXEL_OUT_GAINBIT_2; + break; + } + + output[idx] = std::round(expected); + + if (expected <= INT16_MIN) + output[idx] = PIXEL_OUT_LOST; + else if (expected >= INT16_MAX) + output[idx] = INT16_MAX; +} + +JFConversionGPU::JFConversionGPU() { + cudastream = new(CudaStreamWrapper); + + cuda_err(cudaStreamCreate(&cudastream->v)); + cuda_err(cudaMalloc(&gpu_pedestal_g0, RAW_MODULE_SIZE * sizeof(uint16_t))); + cuda_err(cudaMalloc(&gpu_pedestal_g1, RAW_MODULE_SIZE * sizeof(uint16_t))); + cuda_err(cudaMalloc(&gpu_pedestal_g2, RAW_MODULE_SIZE * sizeof(uint16_t))); + + cuda_err(cudaMalloc(&gpu_gain_g0, RAW_MODULE_SIZE * sizeof(float))); + cuda_err(cudaMalloc(&gpu_gain_g1, RAW_MODULE_SIZE * sizeof(float))); + cuda_err(cudaMalloc(&gpu_gain_g2, RAW_MODULE_SIZE * sizeof(float))); + + cuda_err(cudaMallocHost(&host_gain_g0, RAW_MODULE_SIZE * sizeof(float))); + cuda_err(cudaMallocHost(&host_gain_g1, RAW_MODULE_SIZE * sizeof(float))); + cuda_err(cudaMallocHost(&host_gain_g2, RAW_MODULE_SIZE * sizeof(float))); + + cuda_err(cudaMalloc(&gpu_input, RAW_MODULE_SIZE * sizeof(uint16_t))); + cuda_err(cudaMalloc(&gpu_output, RAW_MODULE_SIZE * sizeof(int16_t))); +} + +JFConversionGPU::~JFConversionGPU() { + cudaStreamSynchronize(cudastream->v); + cudaStreamDestroy(cudastream->v); + delete cudastream; + + cudaFree(gpu_pedestal_g0); + cudaFree(gpu_pedestal_g1); + cudaFree(gpu_pedestal_g2); + + cudaFree(gpu_gain_g0); + cudaFree(gpu_gain_g1); + cudaFree(gpu_gain_g2); + + cudaFreeHost(host_gain_g0); + cudaFreeHost(host_gain_g1); + cudaFreeHost(host_gain_g2); + + cudaFree(gpu_input); + cudaFree(gpu_output); +} + +void JFConversionGPU::Setup(const JFModuleGainCalibration &gain_calibration, const JFModulePedestal &pedestal_g0, + const JFModulePedestal &pedestal_g1, const JFModulePedestal &pedestal_g2, double energy) { + auto &gain_arr = gain_calibration.GetGainCalibration(); + + for (int i = 0; i < RAW_MODULE_SIZE; i++) { + host_gain_g0[i] = one_over_gain_energy(gain_arr[i], energy); + host_gain_g1[i] = one_over_gain_energy(gain_arr[i + RAW_MODULE_SIZE], energy); + host_gain_g2[i] = one_over_gain_energy(gain_arr[i + 2 * RAW_MODULE_SIZE], energy); + } + cudaMemcpy(gpu_pedestal_g0, pedestal_g0.GetPedestal(), RAW_MODULE_SIZE * sizeof(uint16_t), cudaMemcpyHostToDevice); + cudaMemcpy(gpu_pedestal_g1, pedestal_g1.GetPedestal(), RAW_MODULE_SIZE * sizeof(uint16_t), cudaMemcpyHostToDevice); + cudaMemcpy(gpu_pedestal_g2, pedestal_g2.GetPedestal(), RAW_MODULE_SIZE * sizeof(uint16_t), cudaMemcpyHostToDevice); + cudaMemcpy(gpu_gain_g0, host_gain_g0, RAW_MODULE_SIZE * sizeof(float), cudaMemcpyHostToDevice); + cudaMemcpy(gpu_gain_g1, host_gain_g1, RAW_MODULE_SIZE * sizeof(float), cudaMemcpyHostToDevice); + cudaMemcpy(gpu_gain_g2, host_gain_g2, RAW_MODULE_SIZE * sizeof(float), cudaMemcpyHostToDevice); +} + +void JFConversionGPU::ConvertModule(int16_t *dest, const uint16_t *source) { + cudaMemcpy(gpu_input, source, RAW_MODULE_SIZE * sizeof(uint16_t), cudaMemcpyHostToDevice); + gpu_jf_convert<<>>(gpu_output, gpu_input, + gpu_pedestal_g0, gpu_pedestal_g1, gpu_pedestal_g2, + gpu_gain_g0, gpu_gain_g1, gpu_gain_g2); + cudaMemcpy(dest, gpu_output, RAW_MODULE_SIZE * sizeof(uint16_t), cudaMemcpyDeviceToHost); +} + +void JFConversionGPU::Sync() { + cudaStreamSynchronize(cudastream->v); +} \ No newline at end of file diff --git a/jungfrau/JFConversionGPU.h b/jungfrau/JFConversionGPU.h new file mode 100644 index 00000000..23fa8187 --- /dev/null +++ b/jungfrau/JFConversionGPU.h @@ -0,0 +1,48 @@ +// Copyright (2019-2023) Paul Scherrer Institute + +#ifndef JUNGFRAUJOCH_JFCONVERSIONGPU_CUH +#define JUNGFRAUJOCH_JFCONVERSIONGPU_CUH + +#include "JFConversion.h" +#include "JFConversionFixedPoint.h" + +struct CudaStreamWrapper; + +class JFConversionGPU : public JFConversion { +#ifdef JFJOCH_USE_CUDA + CudaStreamWrapper *cudastream = nullptr; + + uint16_t *gpu_pedestal_g0 = nullptr; + uint16_t *gpu_pedestal_g1 = nullptr; + uint16_t *gpu_pedestal_g2 = nullptr; + float *gpu_gain_g0 = nullptr; + float *gpu_gain_g1 = nullptr; + float *gpu_gain_g2 = nullptr; + + float *host_gain_g0 = nullptr; + float *host_gain_g1 = nullptr; + float *host_gain_g2 = nullptr; + + + uint16_t *gpu_input = nullptr; + int16_t *gpu_output = nullptr; +#else + JFConversionFixedPoint alt_conv; +#endif +public: + JFConversionGPU(); + JFConversionGPU(JFConversionGPU& other) = delete; + JFConversionGPU& operator=(JFConversionGPU& other) = delete; + ~JFConversionGPU(); + void Setup(const JFModuleGainCalibration &gain_calibration, + const JFModulePedestal &pedestal_g0, + const JFModulePedestal &pedestal_g1, + const JFModulePedestal &pedestal_g2, + double energy) override; + + void ConvertModule(int16_t *dest, const uint16_t *source) override; + void Sync() override; +}; + + +#endif //JUNGFRAUJOCH_JFCONVERSIONGPU_CUH diff --git a/jungfrau/JFModuleGainCalibration.cpp b/jungfrau/JFModuleGainCalibration.cpp index 76f53992..b30c78cd 100644 --- a/jungfrau/JFModuleGainCalibration.cpp +++ b/jungfrau/JFModuleGainCalibration.cpp @@ -1,5 +1,4 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (2019-2023) Paul Scherrer Institute #include "JFModuleGainCalibration.h" diff --git a/jungfrau/JFModuleGainCalibration.h b/jungfrau/JFModuleGainCalibration.h index 00e66f7e..c60f3f39 100644 --- a/jungfrau/JFModuleGainCalibration.h +++ b/jungfrau/JFModuleGainCalibration.h @@ -1,5 +1,4 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (2019-2023) Paul Scherrer Institute #ifndef JUNGFRAUJOCH_JFMODULEGAINCALIBRATION_H #define JUNGFRAUJOCH_JFMODULEGAINCALIBRATION_H diff --git a/jungfrau/JFModulePedestal.cpp b/jungfrau/JFModulePedestal.cpp index 36fb7bf0..9dfa72a1 100644 --- a/jungfrau/JFModulePedestal.cpp +++ b/jungfrau/JFModulePedestal.cpp @@ -1,5 +1,4 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (2019-2023) Paul Scherrer Institute #include "JFModulePedestal.h" diff --git a/jungfrau/JFModulePedestal.h b/jungfrau/JFModulePedestal.h index 2b097343..7c136e9c 100644 --- a/jungfrau/JFModulePedestal.h +++ b/jungfrau/JFModulePedestal.h @@ -1,5 +1,4 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (2019-2023) Paul Scherrer Institute #ifndef JUNGFRAUJOCH_JFMODULEPEDESTAL_H #define JUNGFRAUJOCH_JFMODULEPEDESTAL_H diff --git a/jungfrau/JFPedestalCalc.cpp b/jungfrau/JFPedestalCalc.cpp index 09c959c5..dc7a57f1 100644 --- a/jungfrau/JFPedestalCalc.cpp +++ b/jungfrau/JFPedestalCalc.cpp @@ -1,5 +1,4 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (2019-2023) Paul Scherrer Institute #include "JFPedestalCalc.h" #include "../common/JFJochException.h" diff --git a/jungfrau/JFPedestalCalc.h b/jungfrau/JFPedestalCalc.h index 0c7fc73c..c08a1f22 100644 --- a/jungfrau/JFPedestalCalc.h +++ b/jungfrau/JFPedestalCalc.h @@ -1,5 +1,4 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (2019-2023) Paul Scherrer Institute #ifndef JUNGFRAUJOCH_JFPEDESTALCALC_H #define JUNGFRAUJOCH_JFPEDESTALCALC_H diff --git a/jungfrau/ProcessJFPacket.cpp b/jungfrau/ProcessJFPacket.cpp index 5c0a2001..00c41b2e 100644 --- a/jungfrau/ProcessJFPacket.cpp +++ b/jungfrau/ProcessJFPacket.cpp @@ -1,11 +1,11 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (2019-2023) Paul Scherrer Institute #include #include "ProcessJFPacket.h" #include "jf_packet.h" #include "../common/JFJochException.h" +#include "JFConversionFixedPoint.h" ProcessJFPacket::ProcessJFPacket(ThreadSafeFIFO &in_c, ThreadSafeFIFO &in_wr, uint32_t nmodules) @@ -31,7 +31,7 @@ void ProcessJFPacket::ProcessPacket(jf_udp_payload *datagram) { uint64_t frame_number = datagram->framenum - 1; - uint32_t module_number = (datagram->xCoord % 32) / 2; + uint32_t module_number = (datagram->xCoord % 64) / 2; bool second_half_module = (datagram->xCoord % 2 == 1); uint32_t packetnum = datagram->packetnum | (second_half_module ? 64 : 0); uint64_t module_info_location = (module_number * 2) | (frame_number % 2); @@ -56,7 +56,7 @@ void ProcessJFPacket::ProcessPacket(jf_udp_payload *datagram) { module_info[module_info_location].c.packet_mask[0] = 0; module_info[module_info_location].c.packet_mask[1] = 0; module_info[module_info_location].c.packet_count = 0; - module_info[module_info_location].c.module = module_number; + module_info[module_info_location].c.module_number = module_number; module_info[module_info_location].c.handle = wr.handle; module_info[module_info_location].ptr = wr.ptr; @@ -65,7 +65,8 @@ void ProcessJFPacket::ProcessPacket(jf_udp_payload *datagram) { module_info[module_info_location].c.packet_count++; module_info[module_info_location].c.packet_mask[packetnum >= 64 ? 1 : 0] |= (1LU << (packetnum % 64)); - memcpy(module_info[module_info_location].ptr + 4096 * packetnum, datagram->data, 4096 * sizeof(uint16_t)); + uint16_t* dst = module_info[module_info_location].ptr + 4096 * packetnum; + memcpy(dst, datagram->data, 4096 * sizeof(uint16_t)); } packet_counter++; } diff --git a/jungfrau/ProcessJFPacket.h b/jungfrau/ProcessJFPacket.h index a6e72f66..9fb316c2 100644 --- a/jungfrau/ProcessJFPacket.h +++ b/jungfrau/ProcessJFPacket.h @@ -1,12 +1,13 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (2019-2023) Paul Scherrer Institute #ifndef JUNGFRAUJOCH_PROCESSJFPACKET_H #define JUNGFRAUJOCH_PROCESSJFPACKET_H #include "../common/ThreadSafeFIFO.h" -#include "../receiver/host/Completion.h" +#include "../common/DiffractionExperiment.h" +#include "../receiver/Completion.h" #include "JFConversion.h" +#include "JFCalibration.h" #include "jf_packet.h" #include diff --git a/jungfrau/jf_packet.h b/jungfrau/jf_packet.h index 4a8e0e58..71ccb618 100644 --- a/jungfrau/jf_packet.h +++ b/jungfrau/jf_packet.h @@ -1,5 +1,4 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (2019-2023) Paul Scherrer Institute #ifndef JUNGFRAUJOCH_JF_PACKET_H #define JUNGFRAUJOCH_JF_PACKET_H diff --git a/python/jfjoch_grpc2http.py b/python/jfjoch_grpc2http.py index f97eb410..2edefaa6 100644 --- a/python/jfjoch_grpc2http.py +++ b/python/jfjoch_grpc2http.py @@ -1,5 +1,5 @@ -# Copyright (2019-2022) Paul Scherrer Institute -# SPDX-License-Identifier: GPL-3.0-or-later +# Copyright (2019-2023) Paul Scherrer Institute +# from io import BytesIO diff --git a/python/jfjoch_pb2.py b/python/jfjoch_pb2.py index 026617bb..d5223dfc 100644 --- a/python/jfjoch_pb2.py +++ b/python/jfjoch_pb2.py @@ -13,29 +13,25 @@ _sym_db = _symbol_database.Default() -DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x0cjfjoch.proto\x12\x0eJFJochProtoBuf\"\x07\n\x05\x45mpty\"W\n\x08UnitCell\x12\t\n\x01\x61\x18\x01 \x01(\x02\x12\t\n\x01\x62\x18\x02 \x01(\x02\x12\t\n\x01\x63\x18\x03 \x01(\x02\x12\r\n\x05\x61lpha\x18\x04 \x01(\x02\x12\x0c\n\x04\x62\x65ta\x18\x05 \x01(\x02\x12\r\n\x05gamma\x18\x06 \x01(\x02\")\n\x06Vector\x12\t\n\x01x\x18\x01 \x01(\x02\x12\t\n\x01y\x18\x02 \x01(\x02\x12\t\n\x01z\x18\x03 \x01(\x02\"|\n\x10RotationSettings\x12\x17\n\x0fstart_angle_deg\x18\x01 \x01(\x02\x12 \n\x18\x61ngle_incr_per_image_deg\x18\x02 \x01(\x02\x12-\n\rrotation_axis\x18\x03 \x01(\x0b\x32\x16.JFJochProtoBuf.Vector\"\x1c\n\x04Plot\x12\t\n\x01x\x18\x01 \x03(\x02\x12\t\n\x01y\x18\x02 \x03(\x02\"\xa5\x04\n\x0f\x44\x61tasetSettings\x12\x1a\n\x12images_per_trigger\x18\x01 \x01(\x03\x12\x10\n\x08ntrigger\x18\x02 \x01(\x03\x12\x13\n\tsummation\x18\x03 \x01(\x03H\x00\x12\x17\n\rimage_time_us\x18\x04 \x01(\x03H\x00\x12\x12\n\nbeam_x_pxl\x18\x05 \x01(\x02\x12\x12\n\nbeam_y_pxl\x18\x06 \x01(\x02\x12\x1c\n\x14\x64\x65tector_distance_mm\x18\x07 \x01(\x02\x12\x19\n\x11photon_energy_keV\x18\x08 \x01(\x02\x12\x13\n\x0b\x66ile_prefix\x18\t \x01(\t\x12\x17\n\x0f\x64\x61ta_file_count\x18\n \x01(\x03\x12\x30\n\x0b\x63ompression\x18\x0b \x01(\x0e\x32\x1b.JFJochProtoBuf.Compression\x12\x13\n\x0bsample_name\x18\x0c \x01(\t\x12\x30\n\tunit_cell\x18\r \x01(\x0b\x32\x18.JFJochProtoBuf.UnitCellH\x01\x88\x01\x01\x12\x1a\n\x12space_group_number\x18\x0e \x01(\x03\x12\x36\n\x11scattering_vector\x18\x0f \x01(\x0b\x32\x16.JFJochProtoBuf.VectorH\x02\x88\x01\x01\x12\x18\n\x10\x61pply_pixel_mask\x18\x10 \x01(\x08\x12\x12\n\nbinning2x2\x18\x11 \x01(\x08\x42\x08\n\x06timingB\x0c\n\n_unit_cellB\x14\n\x12_scattering_vector\"\xf7\x02\n\x10\x44\x65tectorSettings\x12\x15\n\rframe_time_us\x18\x01 \x01(\x03\x12\x1a\n\rcount_time_us\x18\x02 \x01(\x03H\x00\x88\x01\x01\x12\x1a\n\x12storage_cell_count\x18\x03 \x01(\x03\x12%\n\x1duse_internal_packet_generator\x18\x04 \x01(\x08\x12\x18\n\x10\x63ollect_raw_data\x18\x05 \x01(\x08\x12\x1f\n\x12pedestal_g0_frames\x18\x06 \x01(\x03H\x01\x88\x01\x01\x12\x1f\n\x12pedestal_g1_frames\x18\x07 \x01(\x03H\x02\x88\x01\x01\x12\x1f\n\x12pedestal_g2_frames\x18\x08 \x01(\x03H\x03\x88\x01\x01\x12\x19\n\x11\x63onversion_on_cpu\x18\t \x01(\x08\x42\x10\n\x0e_count_time_usB\x15\n\x13_pedestal_g0_framesB\x15\n\x13_pedestal_g1_framesB\x15\n\x13_pedestal_g2_frames\"b\n\x16\x44\x65tectorModuleGeometry\x12\x0e\n\x06pixel0\x18\x01 \x01(\x03\x12\x1b\n\x13\x66\x61st_direction_step\x18\x02 \x01(\x03\x12\x1b\n\x13slow_direction_step\x18\x03 \x01(\x03\"z\n\x10\x44\x65tectorGeometry\x12\x11\n\twidth_pxl\x18\x01 \x01(\x03\x12\x12\n\nheight_pxl\x18\x02 \x01(\x03\x12?\n\x0fmodule_geometry\x18\x03 \x03(\x0b\x32&.JFJochProtoBuf.DetectorModuleGeometry\"\xc1\x01\n\x08\x44\x65tector\x12\x10\n\x08nmodules\x18\x01 \x01(\x03\x12\x13\n\x0b\x64\x65scription\x18\x02 \x01(\t\x12\x15\n\rpixel_size_mm\x18\x03 \x01(\x02\x12\x17\n\x0fmodule_hostname\x18\x04 \x03(\t\x12\x32\n\x08geometry\x18\x05 \x01(\x0b\x32 .JFJochProtoBuf.DetectorGeometry\x12*\n\x04type\x18\x06 \x01(\x0e\x32\x1c.JFJochProtoBuf.DetectorType\"\xe1\x05\n\x10InternalSettings\x12\"\n\x1a\x66rame_time_pedestalG1G2_us\x18\x01 \x01(\x03\x12\x15\n\rframe_time_us\x18\x03 \x01(\x03\x12\x15\n\rcount_time_us\x18\x04 \x01(\x03\x12*\n\x08\x64\x65tector\x18\x05 \x01(\x0b\x32\x18.JFJochProtoBuf.Detector\x12\x14\n\x0cndatastreams\x18\x06 \x01(\x03\x12&\n\x1einternal_fpga_packet_generator\x18\t \x01(\x08\x12\x15\n\rstorage_cells\x18\n \x01(\x03\x12\x1a\n\x12storage_cell_start\x18\x0b \x01(\x03\x12\x1a\n\x12pedestal_g0_frames\x18\x0c \x01(\x03\x12\x1a\n\x12pedestal_g1_frames\x18\r \x01(\x03\x12\x1a\n\x12pedestal_g2_frames\x18\x0e \x01(\x03\x12\x19\n\x11preview_period_us\x18\x0f \x01(\x03\x12\x1e\n\x16spot_finding_period_us\x18\x10 \x01(\x03\x12*\n\x04mode\x18\x13 \x01(\x0e\x32\x1c.JFJochProtoBuf.DetectorMode\x12\x19\n\x11mask_module_edges\x18\x14 \x01(\x08\x12\x17\n\x0fmask_chip_edges\x18\x15 \x01(\x08\x12\x16\n\x0eipv4_base_addr\x18\x16 \x01(\x03\x12\r\n\x05low_q\x18\x1a \x01(\x02\x12\x0e\n\x06high_q\x18\x1b \x01(\x02\x12\x11\n\tq_spacing\x18\x1c \x01(\x02\x12\x10\n\x08git_sha1\x18\x1d \x01(\t\x12\x10\n\x08git_date\x18\x1e \x01(\t\x12\x19\n\x11\x63onversion_on_cpu\x18\x1f \x01(\x08\x12\x13\n\x0bsource_name\x18 \x01(\t\x12\x19\n\x11source_name_short\x18! \x01(\t\x12\x17\n\x0finstrument_name\x18\" \x01(\t\x12\x1d\n\x15instrument_name_short\x18# \x01(\t\"|\n\x14JungfraujochSettings\x12\x30\n\x07\x64\x61taset\x18\x01 \x01(\x0b\x32\x1f.JFJochProtoBuf.DatasetSettings\x12\x32\n\x08internal\x18\x02 \x01(\x0b\x32 .JFJochProtoBuf.InternalSettings\"\x1e\n\nJFPedestal\x12\x10\n\x08pedestal\x18\x01 \x01(\x0c\"-\n\x11JFGainCalibration\x12\x18\n\x10gain_calibration\x18\x01 \x01(\x0c\"\xb2\x01\n\rJFCalibration\x12\x10\n\x08nmodules\x18\x01 \x01(\x04\x12\x16\n\x0enstorage_cells\x18\x02 \x01(\x04\x12,\n\x08pedestal\x18\x03 \x03(\x0b\x32\x1a.JFJochProtoBuf.JFPedestal\x12\x0c\n\x04mask\x18\x04 \x01(\x0c\x12;\n\x10gain_calibration\x18\x05 \x03(\x0b\x32!.JFJochProtoBuf.JFGainCalibration\"V\n\x17JFCalibrationStatistics\x12;\n\x11module_statistics\x18\x01 \x03(\x0b\x32 .JFJochProtoBuf.ModuleStatistics\"\x91\x02\n\x1b\x41\x63quisitionDeviceStatistics\x12\x14\n\x0cgood_packets\x18\x01 \x01(\x04\x12\x18\n\x10packets_expected\x18\x0c \x01(\x04\x12\x12\n\nefficiency\x18\x04 \x01(\x02\x12\x16\n\x0e\x62ytes_received\x18\x05 \x01(\x04\x12\x17\n\x0fstart_timestamp\x18\x06 \x01(\x04\x12\x15\n\rend_timestamp\x18\x07 \x01(\x04\x12/\n\x0b\x66pga_status\x18\x08 \x01(\x0b\x32\x1a.JFJochProtoBuf.FPGAStatus\x12\x10\n\x08nmodules\x18\t \x01(\x04\x12#\n\x1bpackets_received_per_module\x18\x10 \x03(\x04\"\x88\x01\n\rReceiverInput\x12\x43\n\x15jungfraujoch_settings\x18\x01 \x01(\x0b\x32$.JFJochProtoBuf.JungfraujochSettings\x12\x32\n\x0b\x63\x61libration\x18\x02 \x01(\x0b\x32\x1d.JFJochProtoBuf.JFCalibration\"\xd6\x03\n\x0eReceiverOutput\x12\x46\n\x11\x64\x65vice_statistics\x18\x01 \x03(\x0b\x32+.JFJochProtoBuf.AcquisitionDeviceStatistics\x12\x19\n\x11max_receive_delay\x18\x02 \x01(\x04\x12\x17\n\x0f\x63ompressed_size\x18\x03 \x01(\x04\x12\x18\n\x10\x63ompressed_ratio\x18\x04 \x01(\x02\x12\x13\n\x0bimages_sent\x18\x05 \x01(\x04\x12\x15\n\rstart_time_ms\x18\x06 \x01(\x04\x12\x13\n\x0b\x65nd_time_ms\x18\x07 \x01(\x04\x12\x12\n\nefficiency\x18\x08 \x01(\x02\x12\x1d\n\x15max_image_number_sent\x18\t \x01(\x04\x12\x11\n\tcancelled\x18\n \x01(\x08\x12\x18\n\x10master_file_name\x18\x0b \x01(\t\x12\x33\n\x0fpedestal_result\x18\x0c \x03(\x0b\x32\x1a.JFJochProtoBuf.JFPedestal\x12\x1a\n\rindexing_rate\x18\r \x01(\x02H\x00\x88\x01\x01\x12\x19\n\x0c\x62kg_estimate\x18\x0e \x01(\x02H\x01\x88\x01\x01\x42\x10\n\x0e_indexing_rateB\x0f\n\r_bkg_estimate\"T\n\x1bReceiverNetworkConfigDevice\x12\x10\n\x08mac_addr\x18\x01 \x01(\t\x12\x11\n\tipv4_addr\x18\x02 \x01(\t\x12\x10\n\x08udp_port\x18\x03 \x01(\x04\"T\n\x15ReceiverNetworkConfig\x12;\n\x06\x64\x65vice\x18\x01 \x03(\x0b\x32+.JFJochProtoBuf.ReceiverNetworkConfigDevice\"\xcb\x01\n\x0eReceiverStatus\x12\x15\n\x08progress\x18\x01 \x01(\x02H\x00\x88\x01\x01\x12/\n\x0b\x66pga_status\x18\x02 \x03(\x0b\x32\x1a.JFJochProtoBuf.FPGAStatus\x12\x1a\n\rindexing_rate\x18\x03 \x01(\x02H\x01\x88\x01\x01\x12\x1f\n\x12send_buffers_avail\x18\x04 \x01(\x02H\x02\x88\x01\x01\x42\x0b\n\t_progressB\x10\n\x0e_indexing_rateB\x15\n\x13_send_buffers_avail\"f\n\x0bPlotRequest\x12&\n\x04type\x18\x01 \x01(\x0e\x32\x18.JFJochProtoBuf.PlotType\x12\x0f\n\x07\x62inning\x18\x02 \x01(\x04\x12\x1e\n\x16solid_angle_correction\x18\x03 \x01(\x08\"\xc4\x01\n\x19RadialIntegrationProfiles\x12\x43\n\x05plots\x18\x01 \x03(\x0b\x32\x34.JFJochProtoBuf.RadialIntegrationProfiles.PlotsEntry\x12\x1e\n\x16solid_angle_correction\x18\x02 \x03(\x02\x1a\x42\n\nPlotsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12#\n\x05value\x18\x02 \x01(\x0b\x32\x14.JFJochProtoBuf.Plot:\x02\x38\x01\">\n\x0bWriterInput\x12\x1c\n\x14zmq_receiver_address\x18\x01 \x01(\t\x12\x11\n\tseries_id\x18\x02 \x01(\x03\"3\n\x12\x44\x61taFileStatistics\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x0f\n\x07nimages\x18\x02 \x01(\x03\"\x8d\x01\n\x0cWriterOutput\x12\x0f\n\x07nimages\x18\x01 \x01(\x03\x12\x17\n\x0fperformance_MBs\x18\x02 \x01(\x02\x12\x16\n\x0eperformance_Hz\x18\x03 \x01(\x02\x12;\n\x0f\x66ile_statistics\x18\x04 \x03(\x0b\x32\".JFJochProtoBuf.DataFileStatistics\"\x82\x02\n\x14\x44\x65tectorModuleConfig\x12\x17\n\x0fudp_dest_port_1\x18\x01 \x01(\x04\x12\x17\n\x0fudp_dest_port_2\x18\x02 \x01(\x04\x12\x17\n\x0fipv4_src_addr_1\x18\x03 \x01(\t\x12\x17\n\x0fipv4_src_addr_2\x18\x04 \x01(\t\x12\x18\n\x10ipv4_dest_addr_1\x18\x05 \x01(\t\x12\x18\n\x10ipv4_dest_addr_2\x18\x06 \x01(\t\x12\x17\n\x0fmac_addr_dest_1\x18\x07 \x01(\t\x12\x17\n\x0fmac_addr_dest_2\x18\x08 \x01(\t\x12 \n\x18module_id_in_data_stream\x18\t \x01(\x04\"`\n\x0e\x44\x65tectorConfig\x12\x35\n\x07modules\x18\x01 \x03(\x0b\x32$.JFJochProtoBuf.DetectorModuleConfig\x12\x17\n\x0fmodule_hostname\x18\x02 \x03(\t\"\xf9\x01\n\rDetectorInput\x12\x13\n\x0bmodules_num\x18\x01 \x01(\x03\x12*\n\x04mode\x18\x02 \x01(\x0e\x32\x1c.JFJochProtoBuf.DetectorMode\x12\x12\n\nnum_frames\x18\x03 \x01(\x03\x12\x14\n\x0cnum_triggers\x18\x04 \x01(\x03\x12\x1b\n\x13storage_cell_number\x18\x05 \x01(\x03\x12\x1a\n\x12storage_cell_start\x18\x06 \x01(\x03\x12\x1a\n\x12storage_cell_delay\x18\x07 \x01(\x01\x12\x11\n\tperiod_us\x18\t \x01(\x03\x12\x15\n\rcount_time_us\x18\n \x01(\x03\"\x10\n\x0e\x44\x65tectorOutput\"b\n\x0e\x44\x65tectorStatus\x12$\n\x05state\x18\x01 \x01(\x0e\x32\x15.JFJochProtoBuf.State\x12\x12\n\nfw_version\x18\x02 \x01(\x03\x12\x16\n\x0eserver_version\x18\x03 \x01(\t\"\xae\x08\n\nFPGAStatus\x12\x15\n\rpackets_ether\x18\x02 \x01(\x04\x12\x13\n\x0bpackets_udp\x18\x03 \x01(\x04\x12\x16\n\x0epackets_jfjoch\x18\x04 \x01(\x04\x12\x14\n\x0cpackets_icmp\x18\x05 \x01(\x04\x12\x11\n\tfpga_idle\x18\x06 \x01(\x08\x12\x17\n\x0fhbm_temp_0_degC\x18\x07 \x01(\x04\x12\x17\n\x0fhbm_temp_1_degC\x18\x08 \x01(\x04\x12\x12\n\nstalls_hbm\x18\t \x01(\x04\x12\x13\n\x0bstalls_host\x18\n \x01(\x04\x12\x1b\n\x13\x65thernet_rx_aligned\x18\x0b \x01(\x08\x12\x1c\n\x14\x66ull_status_register\x18\r \x01(\r\x12?\n\x0b\x66ifo_status\x18\x0e \x03(\x0b\x32*.JFJochProtoBuf.FPGAStatus.FifoStatusEntry\x12\x13\n\x0bmax_modules\x18\x0f \x01(\x04\x12\x10\n\x08git_sha1\x18\x10 \x01(\r\x12\x17\n\x0fmailbox_err_reg\x18\x11 \x01(\r\x12\x1a\n\x12mailbox_status_reg\x18\x12 \x01(\r\x12\x1c\n\x14\x64\x61tamover_mm2s_error\x18\x13 \x01(\x08\x12\x1c\n\x14\x64\x61tamover_s2mm_error\x18\x14 \x01(\x08\x12&\n\x1e\x66rame_statistics_alignment_err\x18\x15 \x01(\x08\x12\"\n\x1a\x66rame_statistics_tlast_err\x18\x16 \x01(\x08\x12%\n\x1d\x66rame_statistics_work_req_err\x18\x17 \x01(\x08\x12\x14\n\x0cslowest_head\x18\x18 \x01(\x04\x12\x16\n\x0e\x66pga_temp_degC\x18\x1a \x01(\x02\x12\x1a\n\x12\x63urrent_edge_12V_A\x18\x1b \x01(\x02\x12\x1a\n\x12voltage_edge_12V_V\x18\x1c \x01(\x02\x12\x1b\n\x13\x63urrent_edge_3p3V_A\x18\x1d \x01(\x02\x12\x1b\n\x13voltage_edge_3p3V_V\x18\x1e \x01(\x02\x12\x1c\n\x14pcie_h2c_descriptors\x18\x1f \x01(\x04\x12\x1c\n\x14pcie_c2h_descriptors\x18 \x01(\x04\x12\x16\n\x0epcie_h2c_beats\x18! \x01(\x04\x12\x16\n\x0epcie_c2h_beats\x18\" \x01(\x04\x12\x17\n\x0fpcie_h2c_status\x18# \x01(\x04\x12\x17\n\x0fpcie_c2h_status\x18$ \x01(\x04\x12\x13\n\x0bpackets_sls\x18% \x01(\x04\x12\x11\n\terror_eth\x18& \x01(\r\x12\x18\n\x10\x65rror_packet_len\x18\' \x01(\r\x1aQ\n\x0f\x46ifoStatusEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12-\n\x05value\x18\x02 \x01(\x0e\x32\x1e.JFJochProtoBuf.FPGAFIFOStatus:\x02\x38\x01\"\xda\x02\n\x16\x44\x61taProcessingSettings\x12!\n\x19signal_to_noise_threshold\x18\x01 \x01(\x02\x12\x1e\n\x16photon_count_threshold\x18\x02 \x01(\x03\x12\x18\n\x10min_pix_per_spot\x18\x03 \x01(\x03\x12\x18\n\x10max_pix_per_spot\x18\x04 \x01(\x03\x12\x16\n\x0elocal_bkg_size\x18\x05 \x01(\x03\x12\"\n\x15high_resolution_limit\x18\x06 \x01(\x02H\x00\x88\x01\x01\x12!\n\x14low_resolution_limit\x18\x07 \x01(\x02H\x01\x88\x01\x01\x12\x1a\n\x12\x62kg_estimate_low_q\x18\x08 \x01(\x02\x12\x1b\n\x13\x62kg_estimate_high_q\x18\t \x01(\x02\x42\x18\n\x16_high_resolution_limitB\x17\n\x15_low_resolution_limit\"9\n\x10PreviewFrameSpot\x12\t\n\x01x\x18\x01 \x01(\x02\x12\t\n\x01y\x18\x02 \x01(\x02\x12\x0f\n\x07indexed\x18\x03 \x01(\x08\"\xbe\x02\n\x0cPreviewFrame\x12\x14\n\x0cimage_number\x18\x01 \x01(\x03\x12\x14\n\x0ctotal_images\x18\x02 \x01(\x03\x12\x14\n\x0cwavelength_A\x18\x03 \x01(\x02\x12\x12\n\nbeam_x_pxl\x18\x04 \x01(\x02\x12\x12\n\nbeam_y_pxl\x18\x05 \x01(\x02\x12\x1c\n\x14\x64\x65tector_distance_mm\x18\x06 \x01(\x02\x12\x18\n\x10saturation_value\x18\x07 \x01(\x03\x12\x13\n\x0b\x66ile_prefix\x18\x08 \x01(\t\x12\r\n\x05width\x18\t \x01(\x03\x12\x0e\n\x06height\x18\n \x01(\x03\x12\x13\n\x0bpixel_depth\x18\x0b \x01(\x03\x12\x0c\n\x04\x64\x61ta\x18\r \x01(\x0c\x12/\n\x05spots\x18\x0e \x03(\x0b\x32 .JFJochProtoBuf.PreviewFrameSpotJ\x04\x08\x0c\x10\r\"\xed\x01\n\x10ModuleStatistics\x12\x15\n\rmodule_number\x18\x01 \x01(\x03\x12\x1b\n\x13storage_cell_number\x18\x02 \x01(\x03\x12\x18\n\x10pedestal_g0_mean\x18\x03 \x01(\x02\x12\x18\n\x10pedestal_g1_mean\x18\x04 \x01(\x02\x12\x18\n\x10pedestal_g2_mean\x18\x05 \x01(\x02\x12\x14\n\x0cgain_g0_mean\x18\x06 \x01(\x02\x12\x14\n\x0cgain_g1_mean\x18\x07 \x01(\x02\x12\x14\n\x0cgain_g2_mean\x18\x08 \x01(\x02\x12\x15\n\rmasked_pixels\x18\t \x01(\x04\"I\n\x05Image\x12\x0c\n\x04\x64\x61ta\x18\x01 \x01(\x0c\x12\r\n\x05width\x18\x02 \x01(\x03\x12\x0e\n\x06height\x18\x03 \x01(\x03\x12\x13\n\x0bpixel_depth\x18\x04 \x01(\x03\".\n\nMaskToLoad\x12\x0c\n\x04mask\x18\x01 \x03(\r\x12\x12\n\nbit_to_set\x18\x02 \x01(\x05\"\xe5\x04\n\x15MeasurementStatistics\x12\x13\n\x0b\x66ile_prefix\x18\x01 \x01(\t\x12\x18\n\x10images_collected\x18\x02 \x01(\x03\x12\x1d\n\x15max_image_number_sent\x18\x03 \x01(\x03\x12\x1d\n\x15\x63ollection_efficiency\x18\x04 \x01(\x02\x12\x19\n\x11\x63ompression_ratio\x18\x05 \x01(\x02\x12\x11\n\tcancelled\x18\x06 \x01(\x08\x12\x19\n\x11max_receive_delay\x18\x07 \x01(\x03\x12#\n\x16writer_performance_MBs\x18\x08 \x01(\x02H\x00\x88\x01\x01\x12\x1b\n\x0eimages_written\x18\t \x01(\x03H\x01\x88\x01\x01\x12\x1a\n\rindexing_rate\x18\n \x01(\x02H\x02\x88\x01\x01\x12$\n\x17indexing_performance_ms\x18\x0b \x01(\x02H\x03\x88\x01\x01\x12\x16\n\x0e\x64\x65tector_width\x18\x0c \x01(\x03\x12\x17\n\x0f\x64\x65tector_height\x18\r \x01(\x03\x12\x1c\n\x14\x64\x65tector_pixel_depth\x18\x0e \x01(\x03\x12;\n\x0f\x66ile_statistics\x18\x0f \x03(\x0b\x32\".JFJochProtoBuf.DataFileStatistics\x12\x19\n\x0c\x62kg_estimate\x18\x10 \x01(\x02H\x04\x88\x01\x01\x42\x19\n\x17_writer_performance_MBsB\x11\n\x0f_images_writtenB\x10\n\x0e_indexing_rateB\x1a\n\x18_indexing_performance_msB\x0f\n\r_bkg_estimate\"\xd7\x01\n\x0c\x42rokerStatus\x12+\n\x0c\x62roker_state\x18\x01 \x01(\x0e\x32\x15.JFJochProtoBuf.State\x12\x15\n\x08progress\x18\x02 \x01(\x02H\x00\x88\x01\x01\x12\x1a\n\rindexing_rate\x18\x03 \x01(\x02H\x01\x88\x01\x01\x12(\n\x1breceiver_send_buffers_avail\x18\x04 \x01(\x02H\x02\x88\x01\x01\x42\x0b\n\t_progressB\x10\n\x0e_indexing_rateB\x1e\n\x1c_receiver_send_buffers_avail\"\xa4\x01\n\x10\x42rokerFullStatus\x12\x30\n\x08receiver\x18\x01 \x01(\x0b\x32\x1e.JFJochProtoBuf.ReceiverOutput\x12\x30\n\x08\x64\x65tector\x18\x02 \x01(\x0b\x32\x1e.JFJochProtoBuf.DetectorOutput\x12,\n\x06writer\x18\x03 \x03(\x0b\x32\x1c.JFJochProtoBuf.WriterOutput\"H\n\x13\x44\x65tectorListElement\x12\x13\n\x0b\x64\x65scription\x18\x01 \x01(\t\x12\x10\n\x08nmodules\x18\x02 \x01(\x03\x12\n\n\x02id\x18\x03 \x01(\x03\"v\n\x0c\x44\x65tectorList\x12\x35\n\x08\x64\x65tector\x18\x01 \x03(\x0b\x32#.JFJochProtoBuf.DetectorListElement\x12\x12\n\ncurrent_id\x18\x02 \x01(\x03\x12\x1b\n\x13\x63urrent_description\x18\x03 \x01(\t\"\x1f\n\x11\x44\x65tectorSelection\x12\n\n\x02id\x18\x01 \x01(\x03*T\n\x0b\x43ompression\x12\r\n\tBSHUF_LZ4\x10\x00\x12\x0e\n\nBSHUF_ZSTD\x10\x01\x12\x12\n\x0e\x42SHUF_ZSTD_RLE\x10\x02\x12\x12\n\x0eNO_COMPRESSION\x10\x03*\'\n\x0c\x44\x65tectorType\x12\x0c\n\x08JUNGFRAU\x10\x00\x12\t\n\x05\x45IGER\x10\x01*Z\n\x0c\x44\x65tectorMode\x12\x0e\n\nCONVERSION\x10\x00\x12\x07\n\x03RAW\x10\x01\x12\x0f\n\x0bPEDESTAL_G0\x10\x02\x12\x0f\n\x0bPEDESTAL_G1\x10\x03\x12\x0f\n\x0bPEDESTAL_G2\x10\x04*2\n\x0e\x46PGAFIFOStatus\x12\t\n\x05\x45MPTY\x10\x00\x12\x08\n\x04\x46ULL\x10\x01\x12\x0b\n\x07PARTIAL\x10\x02*^\n\x05State\x12\x13\n\x0fNOT_INITIALIZED\x10\x00\x12\x08\n\x04IDLE\x10\x01\x12\x08\n\x04\x42USY\x10\x02\x12\x0c\n\x08PEDESTAL\x10\x03\x12\x13\n\x0f\x44\x41TA_COLLECTION\x10\x04\x12\t\n\x05\x45RROR\x10\x05*h\n\x08PlotType\x12\x10\n\x0c\x42KG_ESTIMATE\x10\x00\x12\x0b\n\x07RAD_INT\x10\x01\x12\x0e\n\nSPOT_COUNT\x10\x02\x12\x11\n\rINDEXING_RATE\x10\x03\x12\x1a\n\x16INDEXING_RATE_PER_FILE\x10\x04\x32\xff\x05\n\x13gRPC_JFJochReceiver\x12?\n\x05Start\x12\x1d.JFJochProtoBuf.ReceiverInput\x1a\x15.JFJochProtoBuf.Empty\"\x00\x12\x37\n\x05\x41\x62ort\x12\x15.JFJochProtoBuf.Empty\x1a\x15.JFJochProtoBuf.Empty\"\x00\x12\x38\n\x06\x43\x61ncel\x12\x15.JFJochProtoBuf.Empty\x1a\x15.JFJochProtoBuf.Empty\"\x00\x12?\n\x04Stop\x12\x15.JFJochProtoBuf.Empty\x1a\x1e.JFJochProtoBuf.ReceiverOutput\"\x00\x12\x44\n\tGetStatus\x12\x15.JFJochProtoBuf.Empty\x1a\x1e.JFJochProtoBuf.ReceiverStatus\"\x00\x12\\\n\x19SetDataProcessingSettings\x12&.JFJochProtoBuf.DataProcessingSettings\x1a\x15.JFJochProtoBuf.Empty\"\x00\x12M\n\x16GetDataProcessingPlots\x12\x1b.JFJochProtoBuf.PlotRequest\x1a\x14.JFJochProtoBuf.Plot\"\x00\x12\x62\n\x1cGetRadialIntegrationProfiles\x12\x15.JFJochProtoBuf.Empty\x1a).JFJochProtoBuf.RadialIntegrationProfiles\"\x00\x12H\n\x0fGetPreviewFrame\x12\x15.JFJochProtoBuf.Empty\x1a\x1c.JFJochProtoBuf.PreviewFrame\"\x00\x12R\n\x10GetNetworkConfig\x12\x15.JFJochProtoBuf.Empty\x1a%.JFJochProtoBuf.ReceiverNetworkConfig\"\x00\x32\xca\x01\n\x11gRPC_JFJochWriter\x12=\n\x05Start\x12\x1b.JFJochProtoBuf.WriterInput\x1a\x15.JFJochProtoBuf.Empty\"\x00\x12\x37\n\x05\x41\x62ort\x12\x15.JFJochProtoBuf.Empty\x1a\x15.JFJochProtoBuf.Empty\"\x00\x12=\n\x04Stop\x12\x15.JFJochProtoBuf.Empty\x1a\x1c.JFJochProtoBuf.WriterOutput\"\x00\x32\x82\x03\n\x13gRPC_JFJochDetector\x12?\n\x05Start\x12\x1d.JFJochProtoBuf.DetectorInput\x1a\x15.JFJochProtoBuf.Empty\"\x00\x12\x36\n\x04Stop\x12\x15.JFJochProtoBuf.Empty\x1a\x15.JFJochProtoBuf.Empty\"\x00\x12\x41\n\x06Status\x12\x15.JFJochProtoBuf.Empty\x1a\x1e.JFJochProtoBuf.DetectorStatus\"\x00\x12=\n\x02On\x12\x1e.JFJochProtoBuf.DetectorConfig\x1a\x15.JFJochProtoBuf.Empty\"\x00\x12\x35\n\x03Off\x12\x15.JFJochProtoBuf.Empty\x1a\x15.JFJochProtoBuf.Empty\"\x00\x12\x39\n\x07Trigger\x12\x15.JFJochProtoBuf.Empty\x1a\x15.JFJochProtoBuf.Empty\"\x00\x32\x99\r\n\x11gRPC_JFJochBroker\x12\x41\n\x05Start\x12\x1f.JFJochProtoBuf.DatasetSettings\x1a\x15.JFJochProtoBuf.Empty\"\x00\x12\x36\n\x04Stop\x12\x15.JFJochProtoBuf.Empty\x1a\x15.JFJochProtoBuf.Empty\"\x00\x12:\n\x08Pedestal\x12\x15.JFJochProtoBuf.Empty\x1a\x15.JFJochProtoBuf.Empty\"\x00\x12<\n\nInitialize\x12\x15.JFJochProtoBuf.Empty\x1a\x15.JFJochProtoBuf.Empty\"\x00\x12\x38\n\x06\x43\x61ncel\x12\x15.JFJochProtoBuf.Empty\x1a\x15.JFJochProtoBuf.Empty\"\x00\x12<\n\nDeactivate\x12\x15.JFJochProtoBuf.Empty\x1a\x15.JFJochProtoBuf.Empty\"\x00\x12\x39\n\x07Trigger\x12\x15.JFJochProtoBuf.Empty\x1a\x15.JFJochProtoBuf.Empty\"\x00\x12\x42\n\tGetStatus\x12\x15.JFJochProtoBuf.Empty\x1a\x1c.JFJochProtoBuf.BrokerStatus\"\x00\x12\\\n\x18GetCalibrationStatistics\x12\x15.JFJochProtoBuf.Empty\x1a\'.JFJochProtoBuf.JFCalibrationStatistics\"\x00\x12P\n\x13GetDetectorSettings\x12\x15.JFJochProtoBuf.Empty\x1a .JFJochProtoBuf.DetectorSettings\"\x00\x12P\n\x13PutDetectorSettings\x12 .JFJochProtoBuf.DetectorSettings\x1a\x15.JFJochProtoBuf.Empty\"\x00\x12Z\n\x18GetMeasurementStatistics\x12\x15.JFJochProtoBuf.Empty\x1a%.JFJochProtoBuf.MeasurementStatistics\"\x00\x12\\\n\x19GetDataProcessingSettings\x12\x15.JFJochProtoBuf.Empty\x1a&.JFJochProtoBuf.DataProcessingSettings\"\x00\x12\\\n\x19PutDataProcessingSettings\x12&.JFJochProtoBuf.DataProcessingSettings\x1a\x15.JFJochProtoBuf.Empty\"\x00\x12?\n\x08GetPlots\x12\x1b.JFJochProtoBuf.PlotRequest\x1a\x14.JFJochProtoBuf.Plot\"\x00\x12\x62\n\x1cGetRadialIntegrationProfiles\x12\x15.JFJochProtoBuf.Empty\x1a).JFJochProtoBuf.RadialIntegrationProfiles\"\x00\x12\x43\n\nGetPreview\x12\x15.JFJochProtoBuf.Empty\x1a\x1c.JFJochProtoBuf.PreviewFrame\"\x00\x12?\n\rGetPedestalG0\x12\x15.JFJochProtoBuf.Empty\x1a\x15.JFJochProtoBuf.Image\"\x00\x12?\n\rGetPedestalG1\x12\x15.JFJochProtoBuf.Empty\x1a\x15.JFJochProtoBuf.Image\"\x00\x12?\n\rGetPedestalG2\x12\x15.JFJochProtoBuf.Empty\x1a\x15.JFJochProtoBuf.Image\"\x00\x12\x39\n\x07GetMask\x12\x15.JFJochProtoBuf.Empty\x1a\x15.JFJochProtoBuf.Image\"\x00\x12H\n\x0fGetDetectorList\x12\x15.JFJochProtoBuf.Empty\x1a\x1c.JFJochProtoBuf.DetectorList\"\x00\x12L\n\x0eSelectDetector\x12!.JFJochProtoBuf.DetectorSelection\x1a\x15.JFJochProtoBuf.Empty\"\x00\x62\x06proto3') +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x0cjfjoch.proto\x12\x0eJFJochProtoBuf\"\x07\n\x05\x45mpty\"W\n\x08UnitCell\x12\t\n\x01\x61\x18\x01 \x01(\x02\x12\t\n\x01\x62\x18\x02 \x01(\x02\x12\t\n\x01\x63\x18\x03 \x01(\x02\x12\r\n\x05\x61lpha\x18\x04 \x01(\x02\x12\x0c\n\x04\x62\x65ta\x18\x05 \x01(\x02\x12\r\n\x05gamma\x18\x06 \x01(\x02\")\n\x06Vector\x12\t\n\x01x\x18\x01 \x01(\x02\x12\t\n\x01y\x18\x02 \x01(\x02\x12\t\n\x01z\x18\x03 \x01(\x02\"|\n\x10RotationSettings\x12\x17\n\x0fstart_angle_deg\x18\x01 \x01(\x02\x12 \n\x18\x61ngle_incr_per_image_deg\x18\x02 \x01(\x02\x12-\n\rrotation_axis\x18\x03 \x01(\x0b\x32\x16.JFJochProtoBuf.Vector\"\x1c\n\x04Plot\x12\t\n\x01x\x18\x01 \x03(\x02\x12\t\n\x01y\x18\x02 \x03(\x02\"E\n\x0cROIRectangle\x12\n\n\x02x0\x18\x01 \x01(\x05\x12\n\n\x02y0\x18\x02 \x01(\x05\x12\r\n\x05width\x18\x03 \x01(\x05\x12\x0e\n\x06height\x18\x04 \x01(\x05\"\xf2\x04\n\x0f\x44\x61tasetSettings\x12\x1a\n\x12images_per_trigger\x18\x01 \x01(\x03\x12\x10\n\x08ntrigger\x18\x02 \x01(\x03\x12\x13\n\tsummation\x18\x03 \x01(\x03H\x00\x12\x17\n\rimage_time_us\x18\x04 \x01(\x03H\x00\x12\x12\n\nbeam_x_pxl\x18\x05 \x01(\x02\x12\x12\n\nbeam_y_pxl\x18\x06 \x01(\x02\x12\x1c\n\x14\x64\x65tector_distance_mm\x18\x07 \x01(\x02\x12\x19\n\x11photon_energy_keV\x18\x08 \x01(\x02\x12\x13\n\x0b\x66ile_prefix\x18\t \x01(\t\x12\x17\n\x0f\x64\x61ta_file_count\x18\n \x01(\x03\x12\x30\n\x0b\x63ompression\x18\x0b \x01(\x0e\x32\x1b.JFJochProtoBuf.Compression\x12\x13\n\x0bsample_name\x18\x0c \x01(\t\x12\x30\n\tunit_cell\x18\r \x01(\x0b\x32\x18.JFJochProtoBuf.UnitCellH\x01\x88\x01\x01\x12\x1a\n\x12space_group_number\x18\x0e \x01(\x03\x12\x12\n\nbinning2x2\x18\x11 \x01(\x08\x12 \n\x18rad_int_solid_angle_corr\x18\x12 \x01(\x08\x12!\n\x19rad_int_polarization_corr\x18\x13 \x01(\x08\x12#\n\x1brad_int_polarization_factor\x18\x14 \x01(\x02\x12\x18\n\x10save_calibration\x18\x15 \x01(\x08\x12/\n\tuser_mask\x18\x16 \x03(\x0b\x32\x1c.JFJochProtoBuf.ROIRectangleB\x08\n\x06timingB\x0c\n\n_unit_cell\"\xb5\x03\n\x10\x44\x65tectorSettings\x12\x15\n\rframe_time_us\x18\x01 \x01(\x03\x12\x1a\n\rcount_time_us\x18\x02 \x01(\x03H\x00\x88\x01\x01\x12\x1a\n\x12storage_cell_count\x18\x03 \x01(\x03\x12%\n\x1duse_internal_packet_generator\x18\x04 \x01(\x08\x12\x18\n\x10\x63ollect_raw_data\x18\x05 \x01(\x08\x12\x1f\n\x12pedestal_g0_frames\x18\x06 \x01(\x03H\x01\x88\x01\x01\x12\x1f\n\x12pedestal_g1_frames\x18\x07 \x01(\x03H\x02\x88\x01\x01\x12\x1f\n\x12pedestal_g2_frames\x18\x08 \x01(\x03H\x03\x88\x01\x01\x12\x19\n\x11\x63onversion_on_cpu\x18\t \x01(\x08\x12\"\n\x15storage_cell_delay_ns\x18\n \x01(\x03H\x04\x88\x01\x01\x42\x10\n\x0e_count_time_usB\x15\n\x13_pedestal_g0_framesB\x15\n\x13_pedestal_g1_framesB\x15\n\x13_pedestal_g2_framesB\x18\n\x16_storage_cell_delay_ns\"b\n\x16\x44\x65tectorModuleGeometry\x12\x0e\n\x06pixel0\x18\x01 \x01(\x03\x12\x1b\n\x13\x66\x61st_direction_step\x18\x02 \x01(\x03\x12\x1b\n\x13slow_direction_step\x18\x03 \x01(\x03\"z\n\x10\x44\x65tectorGeometry\x12\x11\n\twidth_pxl\x18\x01 \x01(\x03\x12\x12\n\nheight_pxl\x18\x02 \x01(\x03\x12?\n\x0fmodule_geometry\x18\x03 \x03(\x0b\x32&.JFJochProtoBuf.DetectorModuleGeometry\"\xc1\x01\n\x08\x44\x65tector\x12\x10\n\x08nmodules\x18\x01 \x01(\x03\x12\x13\n\x0b\x64\x65scription\x18\x02 \x01(\t\x12\x15\n\rpixel_size_mm\x18\x03 \x01(\x02\x12\x17\n\x0fmodule_hostname\x18\x04 \x03(\t\x12\x32\n\x08geometry\x18\x05 \x01(\x0b\x32 .JFJochProtoBuf.DetectorGeometry\x12*\n\x04type\x18\x06 \x01(\x0e\x32\x1c.JFJochProtoBuf.DetectorType\"\xe2\x06\n\x10InternalSettings\x12\"\n\x1a\x66rame_time_pedestalG1G2_us\x18\x01 \x01(\x03\x12\x15\n\rframe_time_us\x18\x03 \x01(\x03\x12\x15\n\rcount_time_us\x18\x04 \x01(\x03\x12*\n\x08\x64\x65tector\x18\x05 \x01(\x0b\x32\x18.JFJochProtoBuf.Detector\x12\x14\n\x0cndatastreams\x18\x06 \x01(\x03\x12&\n\x1einternal_fpga_packet_generator\x18\t \x01(\x08\x12\x15\n\rstorage_cells\x18\n \x01(\x03\x12\x1a\n\x12storage_cell_start\x18\x0b \x01(\x03\x12\x1d\n\x15storage_cell_delay_ns\x18\' \x01(\x03\x12\x1a\n\x12pedestal_g0_frames\x18\x0c \x01(\x03\x12\x1a\n\x12pedestal_g1_frames\x18\r \x01(\x03\x12\x1a\n\x12pedestal_g2_frames\x18\x0e \x01(\x03\x12\x19\n\x11preview_period_us\x18\x0f \x01(\x03\x12\x1e\n\x16spot_finding_period_us\x18\x10 \x01(\x03\x12*\n\x04mode\x18\x13 \x01(\x0e\x32\x1c.JFJochProtoBuf.DetectorMode\x12\x19\n\x11mask_module_edges\x18\x14 \x01(\x08\x12\x17\n\x0fmask_chip_edges\x18\x15 \x01(\x08\x12\x16\n\x0eipv4_base_addr\x18\x16 \x01(\x03\x12\r\n\x05low_q\x18\x1a \x01(\x02\x12\x0e\n\x06high_q\x18\x1b \x01(\x02\x12\x11\n\tq_spacing\x18\x1c \x01(\x02\x12\x10\n\x08git_sha1\x18\x1d \x01(\t\x12\x10\n\x08git_date\x18\x1e \x01(\t\x12\x19\n\x11\x63onversion_on_cpu\x18\x1f \x01(\x08\x12\x13\n\x0bsource_name\x18 \x01(\t\x12\x19\n\x11source_name_short\x18! \x01(\t\x12\x17\n\x0finstrument_name\x18\" \x01(\t\x12\x1d\n\x15instrument_name_short\x18# \x01(\t\x12\x33\n\rroi_rectangle\x18$ \x03(\x0b\x32\x1c.JFJochProtoBuf.ROIRectangle\x12\x11\n\troi_apply\x18% \x01(\x08\x12\x18\n\x10\x64\x65\x62ug_pixel_mask\x18& \x01(\x08\"|\n\x14JungfraujochSettings\x12\x30\n\x07\x64\x61taset\x18\x01 \x01(\x0b\x32\x1f.JFJochProtoBuf.DatasetSettings\x12\x32\n\x08internal\x18\x02 \x01(\x0b\x32 .JFJochProtoBuf.InternalSettings\"\x1e\n\nJFPedestal\x12\x10\n\x08pedestal\x18\x01 \x01(\x0c\"-\n\x11JFGainCalibration\x12\x18\n\x10gain_calibration\x18\x01 \x01(\x0c\"\xb2\x01\n\rJFCalibration\x12\x10\n\x08nmodules\x18\x01 \x01(\x04\x12\x16\n\x0enstorage_cells\x18\x02 \x01(\x04\x12,\n\x08pedestal\x18\x03 \x03(\x0b\x32\x1a.JFJochProtoBuf.JFPedestal\x12\x0c\n\x04mask\x18\x04 \x01(\x0c\x12;\n\x10gain_calibration\x18\x05 \x03(\x0b\x32!.JFJochProtoBuf.JFGainCalibration\"V\n\x17JFCalibrationStatistics\x12;\n\x11module_statistics\x18\x01 \x03(\x0b\x32 .JFJochProtoBuf.ModuleStatistics\"\x91\x02\n\x1b\x41\x63quisitionDeviceStatistics\x12\x14\n\x0cgood_packets\x18\x01 \x01(\x04\x12\x18\n\x10packets_expected\x18\x0c \x01(\x04\x12\x12\n\nefficiency\x18\x04 \x01(\x02\x12\x16\n\x0e\x62ytes_received\x18\x05 \x01(\x04\x12\x17\n\x0fstart_timestamp\x18\x06 \x01(\x04\x12\x15\n\rend_timestamp\x18\x07 \x01(\x04\x12/\n\x0b\x66pga_status\x18\x08 \x01(\x0b\x32\x1a.JFJochProtoBuf.FPGAStatus\x12\x10\n\x08nmodules\x18\t \x01(\x04\x12#\n\x1bpackets_received_per_module\x18\x10 \x03(\x04\"\x88\x01\n\rReceiverInput\x12\x43\n\x15jungfraujoch_settings\x18\x01 \x01(\x0b\x32$.JFJochProtoBuf.JungfraujochSettings\x12\x32\n\x0b\x63\x61libration\x18\x02 \x01(\x0b\x32\x1d.JFJochProtoBuf.JFCalibration\"\xd6\x03\n\x0eReceiverOutput\x12\x46\n\x11\x64\x65vice_statistics\x18\x01 \x03(\x0b\x32+.JFJochProtoBuf.AcquisitionDeviceStatistics\x12\x19\n\x11max_receive_delay\x18\x02 \x01(\x04\x12\x17\n\x0f\x63ompressed_size\x18\x03 \x01(\x04\x12\x18\n\x10\x63ompressed_ratio\x18\x04 \x01(\x02\x12\x13\n\x0bimages_sent\x18\x05 \x01(\x04\x12\x15\n\rstart_time_ms\x18\x06 \x01(\x04\x12\x13\n\x0b\x65nd_time_ms\x18\x07 \x01(\x04\x12\x12\n\nefficiency\x18\x08 \x01(\x02\x12\x1d\n\x15max_image_number_sent\x18\t \x01(\x04\x12\x11\n\tcancelled\x18\n \x01(\x08\x12\x18\n\x10master_file_name\x18\x0b \x01(\t\x12\x33\n\x0fpedestal_result\x18\x0c \x03(\x0b\x32\x1a.JFJochProtoBuf.JFPedestal\x12\x1a\n\rindexing_rate\x18\r \x01(\x02H\x00\x88\x01\x01\x12\x19\n\x0c\x62kg_estimate\x18\x0e \x01(\x02H\x01\x88\x01\x01\x42\x10\n\x0e_indexing_rateB\x0f\n\r_bkg_estimate\"T\n\x1bReceiverNetworkConfigDevice\x12\x10\n\x08mac_addr\x18\x01 \x01(\t\x12\x11\n\tipv4_addr\x18\x02 \x01(\t\x12\x10\n\x08udp_port\x18\x03 \x01(\x04\"T\n\x15ReceiverNetworkConfig\x12;\n\x06\x64\x65vice\x18\x01 \x03(\x0b\x32+.JFJochProtoBuf.ReceiverNetworkConfigDevice\"\xcb\x01\n\x0eReceiverStatus\x12\x15\n\x08progress\x18\x01 \x01(\x02H\x00\x88\x01\x01\x12/\n\x0b\x66pga_status\x18\x02 \x03(\x0b\x32\x1a.JFJochProtoBuf.FPGAStatus\x12\x1a\n\rindexing_rate\x18\x03 \x01(\x02H\x01\x88\x01\x01\x12\x1f\n\x12send_buffers_avail\x18\x04 \x01(\x02H\x02\x88\x01\x01\x42\x0b\n\t_progressB\x10\n\x0e_indexing_rateB\x15\n\x13_send_buffers_avail\"F\n\x0bPlotRequest\x12&\n\x04type\x18\x01 \x01(\x0e\x32\x18.JFJochProtoBuf.PlotType\x12\x0f\n\x07\x62inning\x18\x02 \x01(\x04\"M\n\x18RadialIntegrationProfile\x12\r\n\x05title\x18\x01 \x01(\t\x12\"\n\x04plot\x18\x02 \x01(\x0b\x32\x14.JFJochProtoBuf.Plot\"W\n\x19RadialIntegrationProfiles\x12:\n\x08profiles\x18\x01 \x03(\x0b\x32(.JFJochProtoBuf.RadialIntegrationProfile\">\n\x0bWriterInput\x12\x1c\n\x14zmq_receiver_address\x18\x01 \x01(\t\x12\x11\n\tseries_id\x18\x02 \x01(\x03\"3\n\x12\x44\x61taFileStatistics\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x0f\n\x07nimages\x18\x02 \x01(\x03\"\x8d\x01\n\x0cWriterOutput\x12\x0f\n\x07nimages\x18\x01 \x01(\x03\x12\x17\n\x0fperformance_MBs\x18\x02 \x01(\x02\x12\x16\n\x0eperformance_Hz\x18\x03 \x01(\x02\x12;\n\x0f\x66ile_statistics\x18\x04 \x03(\x0b\x32\".JFJochProtoBuf.DataFileStatistics\"\x82\x02\n\x14\x44\x65tectorModuleConfig\x12\x17\n\x0fudp_dest_port_1\x18\x01 \x01(\x04\x12\x17\n\x0fudp_dest_port_2\x18\x02 \x01(\x04\x12\x17\n\x0fipv4_src_addr_1\x18\x03 \x01(\t\x12\x17\n\x0fipv4_src_addr_2\x18\x04 \x01(\t\x12\x18\n\x10ipv4_dest_addr_1\x18\x05 \x01(\t\x12\x18\n\x10ipv4_dest_addr_2\x18\x06 \x01(\t\x12\x17\n\x0fmac_addr_dest_1\x18\x07 \x01(\t\x12\x17\n\x0fmac_addr_dest_2\x18\x08 \x01(\t\x12 \n\x18module_id_in_data_stream\x18\t \x01(\x04\"`\n\x0e\x44\x65tectorConfig\x12\x35\n\x07modules\x18\x01 \x03(\x0b\x32$.JFJochProtoBuf.DetectorModuleConfig\x12\x17\n\x0fmodule_hostname\x18\x02 \x03(\t\"\xfc\x01\n\rDetectorInput\x12\x13\n\x0bmodules_num\x18\x01 \x01(\x03\x12*\n\x04mode\x18\x02 \x01(\x0e\x32\x1c.JFJochProtoBuf.DetectorMode\x12\x12\n\nnum_frames\x18\x03 \x01(\x03\x12\x14\n\x0cnum_triggers\x18\x04 \x01(\x03\x12\x1b\n\x13storage_cell_number\x18\x05 \x01(\x03\x12\x1a\n\x12storage_cell_start\x18\x06 \x01(\x03\x12\x1d\n\x15storage_cell_delay_ns\x18\x07 \x01(\x03\x12\x11\n\tperiod_us\x18\t \x01(\x03\x12\x15\n\rcount_time_us\x18\n \x01(\x03\"\x10\n\x0e\x44\x65tectorOutput\"b\n\x0e\x44\x65tectorStatus\x12$\n\x05state\x18\x01 \x01(\x0e\x32\x15.JFJochProtoBuf.State\x12\x12\n\nfw_version\x18\x02 \x01(\x03\x12\x16\n\x0eserver_version\x18\x03 \x01(\t\"Q\n\x0e\x46PGAFIFOStatus\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x31\n\x05value\x18\x02 \x01(\x0e\x32\".JFJochProtoBuf.FPGAFIFOStatusEnum\"\xff\x06\n\nFPGAStatus\x12\x15\n\rpackets_ether\x18\x02 \x01(\x04\x12\x13\n\x0bpackets_udp\x18\x03 \x01(\x04\x12\x16\n\x0epackets_jfjoch\x18\x04 \x01(\x04\x12\x14\n\x0cpackets_icmp\x18\x05 \x01(\x04\x12\x11\n\tfpga_idle\x18\x06 \x01(\x08\x12\x17\n\x0fhbm_temp_0_degC\x18\x07 \x01(\x04\x12\x17\n\x0fhbm_temp_1_degC\x18\x08 \x01(\x04\x12\x12\n\nstalls_hbm\x18\t \x01(\x04\x12\x13\n\x0bstalls_host\x18\n \x01(\x04\x12\x1b\n\x13\x65thernet_rx_aligned\x18\x0b \x01(\x08\x12\x1c\n\x14\x66ull_status_register\x18\r \x01(\r\x12\x33\n\x0b\x66ifo_status\x18\x0e \x03(\x0b\x32\x1e.JFJochProtoBuf.FPGAFIFOStatus\x12\x13\n\x0bmax_modules\x18\x0f \x01(\x04\x12\x10\n\x08git_sha1\x18\x10 \x01(\r\x12\x17\n\x0fmailbox_err_reg\x18\x11 \x01(\r\x12\x1a\n\x12mailbox_status_reg\x18\x12 \x01(\r\x12\x17\n\x0fhost_writer_err\x18\x15 \x03(\t\x12\x14\n\x0cslowest_head\x18\x18 \x01(\x04\x12\x16\n\x0e\x66pga_temp_degC\x18\x1a \x01(\x02\x12\x1a\n\x12\x63urrent_edge_12V_A\x18\x1b \x01(\x02\x12\x1a\n\x12voltage_edge_12V_V\x18\x1c \x01(\x02\x12\x1b\n\x13\x63urrent_edge_3p3V_A\x18\x1d \x01(\x02\x12\x1b\n\x13voltage_edge_3p3V_V\x18\x1e \x01(\x02\x12\x1c\n\x14pcie_h2c_descriptors\x18\x1f \x01(\x04\x12\x1c\n\x14pcie_c2h_descriptors\x18 \x01(\x04\x12\x16\n\x0epcie_h2c_beats\x18! \x01(\x04\x12\x16\n\x0epcie_c2h_beats\x18\" \x01(\x04\x12\x17\n\x0fpcie_h2c_status\x18# \x01(\x04\x12\x17\n\x0fpcie_c2h_status\x18$ \x01(\x04\x12\x13\n\x0bpackets_sls\x18% \x01(\x04\x12\x11\n\terror_eth\x18& \x01(\r\x12\x18\n\x10\x65rror_packet_len\x18\' \x01(\r\x12\x18\n\x10host_writer_idle\x18) \x01(\x08\x12\x12\n\ncancel_bit\x18* \x01(\x08\x12\x16\n\x0ehbm_size_bytes\x18+ \x01(\r\"\xda\x02\n\x16\x44\x61taProcessingSettings\x12!\n\x19signal_to_noise_threshold\x18\x01 \x01(\x02\x12\x1e\n\x16photon_count_threshold\x18\x02 \x01(\x03\x12\x18\n\x10min_pix_per_spot\x18\x03 \x01(\x03\x12\x18\n\x10max_pix_per_spot\x18\x04 \x01(\x03\x12\x16\n\x0elocal_bkg_size\x18\x05 \x01(\x03\x12\"\n\x15high_resolution_limit\x18\x06 \x01(\x02H\x00\x88\x01\x01\x12!\n\x14low_resolution_limit\x18\x07 \x01(\x02H\x01\x88\x01\x01\x12\x1a\n\x12\x62kg_estimate_low_q\x18\x08 \x01(\x02\x12\x1b\n\x13\x62kg_estimate_high_q\x18\t \x01(\x02\x42\x18\n\x16_high_resolution_limitB\x17\n\x15_low_resolution_limit\"9\n\x10PreviewFrameSpot\x12\t\n\x01x\x18\x01 \x01(\x02\x12\t\n\x01y\x18\x02 \x01(\x02\x12\x0f\n\x07indexed\x18\x03 \x01(\x08\"\xbe\x02\n\x0cPreviewFrame\x12\x14\n\x0cimage_number\x18\x01 \x01(\x03\x12\x14\n\x0ctotal_images\x18\x02 \x01(\x03\x12\x14\n\x0cwavelength_A\x18\x03 \x01(\x02\x12\x12\n\nbeam_x_pxl\x18\x04 \x01(\x02\x12\x12\n\nbeam_y_pxl\x18\x05 \x01(\x02\x12\x1c\n\x14\x64\x65tector_distance_mm\x18\x06 \x01(\x02\x12\x18\n\x10saturation_value\x18\x07 \x01(\x03\x12\x13\n\x0b\x66ile_prefix\x18\x08 \x01(\t\x12\r\n\x05width\x18\t \x01(\x03\x12\x0e\n\x06height\x18\n \x01(\x03\x12\x13\n\x0bpixel_depth\x18\x0b \x01(\x03\x12\x0c\n\x04\x64\x61ta\x18\r \x01(\x0c\x12/\n\x05spots\x18\x0e \x03(\x0b\x32 .JFJochProtoBuf.PreviewFrameSpotJ\x04\x08\x0c\x10\r\"\xed\x01\n\x10ModuleStatistics\x12\x15\n\rmodule_number\x18\x01 \x01(\x03\x12\x1b\n\x13storage_cell_number\x18\x02 \x01(\x03\x12\x18\n\x10pedestal_g0_mean\x18\x03 \x01(\x02\x12\x18\n\x10pedestal_g1_mean\x18\x04 \x01(\x02\x12\x18\n\x10pedestal_g2_mean\x18\x05 \x01(\x02\x12\x14\n\x0cgain_g0_mean\x18\x06 \x01(\x02\x12\x14\n\x0cgain_g1_mean\x18\x07 \x01(\x02\x12\x14\n\x0cgain_g2_mean\x18\x08 \x01(\x02\x12\x15\n\rmasked_pixels\x18\t \x01(\x04\"I\n\x05Image\x12\x0c\n\x04\x64\x61ta\x18\x01 \x01(\x0c\x12\r\n\x05width\x18\x02 \x01(\x03\x12\x0e\n\x06height\x18\x03 \x01(\x03\x12\x13\n\x0bpixel_depth\x18\x04 \x01(\x03\".\n\nMaskToLoad\x12\x0c\n\x04mask\x18\x01 \x03(\r\x12\x12\n\nbit_to_set\x18\x02 \x01(\x05\"\xe5\x04\n\x15MeasurementStatistics\x12\x13\n\x0b\x66ile_prefix\x18\x01 \x01(\t\x12\x18\n\x10images_collected\x18\x02 \x01(\x03\x12\x1d\n\x15max_image_number_sent\x18\x03 \x01(\x03\x12\x1d\n\x15\x63ollection_efficiency\x18\x04 \x01(\x02\x12\x19\n\x11\x63ompression_ratio\x18\x05 \x01(\x02\x12\x11\n\tcancelled\x18\x06 \x01(\x08\x12\x19\n\x11max_receive_delay\x18\x07 \x01(\x03\x12#\n\x16writer_performance_MBs\x18\x08 \x01(\x02H\x00\x88\x01\x01\x12\x1b\n\x0eimages_written\x18\t \x01(\x03H\x01\x88\x01\x01\x12\x1a\n\rindexing_rate\x18\n \x01(\x02H\x02\x88\x01\x01\x12$\n\x17indexing_performance_ms\x18\x0b \x01(\x02H\x03\x88\x01\x01\x12\x16\n\x0e\x64\x65tector_width\x18\x0c \x01(\x03\x12\x17\n\x0f\x64\x65tector_height\x18\r \x01(\x03\x12\x1c\n\x14\x64\x65tector_pixel_depth\x18\x0e \x01(\x03\x12;\n\x0f\x66ile_statistics\x18\x0f \x03(\x0b\x32\".JFJochProtoBuf.DataFileStatistics\x12\x19\n\x0c\x62kg_estimate\x18\x10 \x01(\x02H\x04\x88\x01\x01\x42\x19\n\x17_writer_performance_MBsB\x11\n\x0f_images_writtenB\x10\n\x0e_indexing_rateB\x1a\n\x18_indexing_performance_msB\x0f\n\r_bkg_estimate\"\xd7\x01\n\x0c\x42rokerStatus\x12+\n\x0c\x62roker_state\x18\x01 \x01(\x0e\x32\x15.JFJochProtoBuf.State\x12\x15\n\x08progress\x18\x02 \x01(\x02H\x00\x88\x01\x01\x12\x1a\n\rindexing_rate\x18\x03 \x01(\x02H\x01\x88\x01\x01\x12(\n\x1breceiver_send_buffers_avail\x18\x04 \x01(\x02H\x02\x88\x01\x01\x42\x0b\n\t_progressB\x10\n\x0e_indexing_rateB\x1e\n\x1c_receiver_send_buffers_avail\"\xa4\x01\n\x10\x42rokerFullStatus\x12\x30\n\x08receiver\x18\x01 \x01(\x0b\x32\x1e.JFJochProtoBuf.ReceiverOutput\x12\x30\n\x08\x64\x65tector\x18\x02 \x01(\x0b\x32\x1e.JFJochProtoBuf.DetectorOutput\x12,\n\x06writer\x18\x03 \x03(\x0b\x32\x1c.JFJochProtoBuf.WriterOutput\"H\n\x13\x44\x65tectorListElement\x12\x13\n\x0b\x64\x65scription\x18\x01 \x01(\t\x12\x10\n\x08nmodules\x18\x02 \x01(\x03\x12\n\n\x02id\x18\x03 \x01(\x03\"v\n\x0c\x44\x65tectorList\x12\x35\n\x08\x64\x65tector\x18\x01 \x03(\x0b\x32#.JFJochProtoBuf.DetectorListElement\x12\x12\n\ncurrent_id\x18\x02 \x01(\x03\x12\x1b\n\x13\x63urrent_description\x18\x03 \x01(\t\"\x1f\n\x11\x44\x65tectorSelection\x12\n\n\x02id\x18\x01 \x01(\x03*T\n\x0b\x43ompression\x12\r\n\tBSHUF_LZ4\x10\x00\x12\x0e\n\nBSHUF_ZSTD\x10\x01\x12\x12\n\x0e\x42SHUF_ZSTD_RLE\x10\x02\x12\x12\n\x0eNO_COMPRESSION\x10\x03*\'\n\x0c\x44\x65tectorType\x12\x0c\n\x08JUNGFRAU\x10\x00\x12\t\n\x05\x45IGER\x10\x01*Z\n\x0c\x44\x65tectorMode\x12\x0e\n\nCONVERSION\x10\x00\x12\x07\n\x03RAW\x10\x01\x12\x0f\n\x0bPEDESTAL_G0\x10\x02\x12\x0f\n\x0bPEDESTAL_G1\x10\x03\x12\x0f\n\x0bPEDESTAL_G2\x10\x04*6\n\x12\x46PGAFIFOStatusEnum\x12\t\n\x05\x45MPTY\x10\x00\x12\x08\n\x04\x46ULL\x10\x01\x12\x0b\n\x07PARTIAL\x10\x02*^\n\x05State\x12\x13\n\x0fNOT_INITIALIZED\x10\x00\x12\x08\n\x04IDLE\x10\x01\x12\x08\n\x04\x42USY\x10\x02\x12\x0c\n\x08PEDESTAL\x10\x03\x12\x13\n\x0f\x44\x41TA_COLLECTION\x10\x04\x12\t\n\x05\x45RROR\x10\x05*h\n\x08PlotType\x12\x10\n\x0c\x42KG_ESTIMATE\x10\x00\x12\x0b\n\x07RAD_INT\x10\x01\x12\x0e\n\nSPOT_COUNT\x10\x02\x12\x11\n\rINDEXING_RATE\x10\x03\x12\x1a\n\x16INDEXING_RATE_PER_FILE\x10\x04\x32\xff\x05\n\x13gRPC_JFJochReceiver\x12?\n\x05Start\x12\x1d.JFJochProtoBuf.ReceiverInput\x1a\x15.JFJochProtoBuf.Empty\"\x00\x12\x37\n\x05\x41\x62ort\x12\x15.JFJochProtoBuf.Empty\x1a\x15.JFJochProtoBuf.Empty\"\x00\x12\x38\n\x06\x43\x61ncel\x12\x15.JFJochProtoBuf.Empty\x1a\x15.JFJochProtoBuf.Empty\"\x00\x12?\n\x04Stop\x12\x15.JFJochProtoBuf.Empty\x1a\x1e.JFJochProtoBuf.ReceiverOutput\"\x00\x12\x44\n\tGetStatus\x12\x15.JFJochProtoBuf.Empty\x1a\x1e.JFJochProtoBuf.ReceiverStatus\"\x00\x12\\\n\x19SetDataProcessingSettings\x12&.JFJochProtoBuf.DataProcessingSettings\x1a\x15.JFJochProtoBuf.Empty\"\x00\x12M\n\x16GetDataProcessingPlots\x12\x1b.JFJochProtoBuf.PlotRequest\x1a\x14.JFJochProtoBuf.Plot\"\x00\x12\x62\n\x1cGetRadialIntegrationProfiles\x12\x15.JFJochProtoBuf.Empty\x1a).JFJochProtoBuf.RadialIntegrationProfiles\"\x00\x12H\n\x0fGetPreviewFrame\x12\x15.JFJochProtoBuf.Empty\x1a\x1c.JFJochProtoBuf.PreviewFrame\"\x00\x12R\n\x10GetNetworkConfig\x12\x15.JFJochProtoBuf.Empty\x1a%.JFJochProtoBuf.ReceiverNetworkConfig\"\x00\x32\xca\x01\n\x11gRPC_JFJochWriter\x12=\n\x05Start\x12\x1b.JFJochProtoBuf.WriterInput\x1a\x15.JFJochProtoBuf.Empty\"\x00\x12\x37\n\x05\x41\x62ort\x12\x15.JFJochProtoBuf.Empty\x1a\x15.JFJochProtoBuf.Empty\"\x00\x12=\n\x04Stop\x12\x15.JFJochProtoBuf.Empty\x1a\x1c.JFJochProtoBuf.WriterOutput\"\x00\x32\x82\x03\n\x13gRPC_JFJochDetector\x12?\n\x05Start\x12\x1d.JFJochProtoBuf.DetectorInput\x1a\x15.JFJochProtoBuf.Empty\"\x00\x12\x36\n\x04Stop\x12\x15.JFJochProtoBuf.Empty\x1a\x15.JFJochProtoBuf.Empty\"\x00\x12\x41\n\x06Status\x12\x15.JFJochProtoBuf.Empty\x1a\x1e.JFJochProtoBuf.DetectorStatus\"\x00\x12=\n\x02On\x12\x1e.JFJochProtoBuf.DetectorConfig\x1a\x15.JFJochProtoBuf.Empty\"\x00\x12\x35\n\x03Off\x12\x15.JFJochProtoBuf.Empty\x1a\x15.JFJochProtoBuf.Empty\"\x00\x12\x39\n\x07Trigger\x12\x15.JFJochProtoBuf.Empty\x1a\x15.JFJochProtoBuf.Empty\"\x00\x32\x99\r\n\x11gRPC_JFJochBroker\x12\x41\n\x05Start\x12\x1f.JFJochProtoBuf.DatasetSettings\x1a\x15.JFJochProtoBuf.Empty\"\x00\x12\x36\n\x04Stop\x12\x15.JFJochProtoBuf.Empty\x1a\x15.JFJochProtoBuf.Empty\"\x00\x12:\n\x08Pedestal\x12\x15.JFJochProtoBuf.Empty\x1a\x15.JFJochProtoBuf.Empty\"\x00\x12<\n\nInitialize\x12\x15.JFJochProtoBuf.Empty\x1a\x15.JFJochProtoBuf.Empty\"\x00\x12\x38\n\x06\x43\x61ncel\x12\x15.JFJochProtoBuf.Empty\x1a\x15.JFJochProtoBuf.Empty\"\x00\x12<\n\nDeactivate\x12\x15.JFJochProtoBuf.Empty\x1a\x15.JFJochProtoBuf.Empty\"\x00\x12\x39\n\x07Trigger\x12\x15.JFJochProtoBuf.Empty\x1a\x15.JFJochProtoBuf.Empty\"\x00\x12\x42\n\tGetStatus\x12\x15.JFJochProtoBuf.Empty\x1a\x1c.JFJochProtoBuf.BrokerStatus\"\x00\x12\\\n\x18GetCalibrationStatistics\x12\x15.JFJochProtoBuf.Empty\x1a\'.JFJochProtoBuf.JFCalibrationStatistics\"\x00\x12P\n\x13GetDetectorSettings\x12\x15.JFJochProtoBuf.Empty\x1a .JFJochProtoBuf.DetectorSettings\"\x00\x12P\n\x13PutDetectorSettings\x12 .JFJochProtoBuf.DetectorSettings\x1a\x15.JFJochProtoBuf.Empty\"\x00\x12Z\n\x18GetMeasurementStatistics\x12\x15.JFJochProtoBuf.Empty\x1a%.JFJochProtoBuf.MeasurementStatistics\"\x00\x12\\\n\x19GetDataProcessingSettings\x12\x15.JFJochProtoBuf.Empty\x1a&.JFJochProtoBuf.DataProcessingSettings\"\x00\x12\\\n\x19PutDataProcessingSettings\x12&.JFJochProtoBuf.DataProcessingSettings\x1a\x15.JFJochProtoBuf.Empty\"\x00\x12?\n\x08GetPlots\x12\x1b.JFJochProtoBuf.PlotRequest\x1a\x14.JFJochProtoBuf.Plot\"\x00\x12\x62\n\x1cGetRadialIntegrationProfiles\x12\x15.JFJochProtoBuf.Empty\x1a).JFJochProtoBuf.RadialIntegrationProfiles\"\x00\x12\x43\n\nGetPreview\x12\x15.JFJochProtoBuf.Empty\x1a\x1c.JFJochProtoBuf.PreviewFrame\"\x00\x12?\n\rGetPedestalG0\x12\x15.JFJochProtoBuf.Empty\x1a\x15.JFJochProtoBuf.Image\"\x00\x12?\n\rGetPedestalG1\x12\x15.JFJochProtoBuf.Empty\x1a\x15.JFJochProtoBuf.Image\"\x00\x12?\n\rGetPedestalG2\x12\x15.JFJochProtoBuf.Empty\x1a\x15.JFJochProtoBuf.Image\"\x00\x12\x39\n\x07GetMask\x12\x15.JFJochProtoBuf.Empty\x1a\x15.JFJochProtoBuf.Image\"\x00\x12H\n\x0fGetDetectorList\x12\x15.JFJochProtoBuf.Empty\x1a\x1c.JFJochProtoBuf.DetectorList\"\x00\x12L\n\x0eSelectDetector\x12!.JFJochProtoBuf.DetectorSelection\x1a\x15.JFJochProtoBuf.Empty\"\x00\x62\x06proto3') _builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, globals()) _builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'jfjoch_pb2', globals()) if _descriptor._USE_C_DESCRIPTORS == False: DESCRIPTOR._options = None - _RADIALINTEGRATIONPROFILES_PLOTSENTRY._options = None - _RADIALINTEGRATIONPROFILES_PLOTSENTRY._serialized_options = b'8\001' - _FPGASTATUS_FIFOSTATUSENTRY._options = None - _FPGASTATUS_FIFOSTATUSENTRY._serialized_options = b'8\001' - _COMPRESSION._serialized_start=8845 - _COMPRESSION._serialized_end=8929 - _DETECTORTYPE._serialized_start=8931 - _DETECTORTYPE._serialized_end=8970 - _DETECTORMODE._serialized_start=8972 - _DETECTORMODE._serialized_end=9062 - _FPGAFIFOSTATUS._serialized_start=9064 - _FPGAFIFOSTATUS._serialized_end=9114 - _STATE._serialized_start=9116 - _STATE._serialized_end=9210 - _PLOTTYPE._serialized_start=9212 - _PLOTTYPE._serialized_end=9316 + _COMPRESSION._serialized_start=9032 + _COMPRESSION._serialized_end=9116 + _DETECTORTYPE._serialized_start=9118 + _DETECTORTYPE._serialized_end=9157 + _DETECTORMODE._serialized_start=9159 + _DETECTORMODE._serialized_end=9249 + _FPGAFIFOSTATUSENUM._serialized_start=9251 + _FPGAFIFOSTATUSENUM._serialized_end=9305 + _STATE._serialized_start=9307 + _STATE._serialized_end=9401 + _PLOTTYPE._serialized_start=9403 + _PLOTTYPE._serialized_end=9507 _EMPTY._serialized_start=32 _EMPTY._serialized_end=39 _UNITCELL._serialized_start=41 @@ -46,96 +42,98 @@ if _descriptor._USE_C_DESCRIPTORS == False: _ROTATIONSETTINGS._serialized_end=297 _PLOT._serialized_start=299 _PLOT._serialized_end=327 - _DATASETSETTINGS._serialized_start=330 - _DATASETSETTINGS._serialized_end=879 - _DETECTORSETTINGS._serialized_start=882 - _DETECTORSETTINGS._serialized_end=1257 - _DETECTORMODULEGEOMETRY._serialized_start=1259 - _DETECTORMODULEGEOMETRY._serialized_end=1357 - _DETECTORGEOMETRY._serialized_start=1359 - _DETECTORGEOMETRY._serialized_end=1481 - _DETECTOR._serialized_start=1484 - _DETECTOR._serialized_end=1677 - _INTERNALSETTINGS._serialized_start=1680 - _INTERNALSETTINGS._serialized_end=2417 - _JUNGFRAUJOCHSETTINGS._serialized_start=2419 - _JUNGFRAUJOCHSETTINGS._serialized_end=2543 - _JFPEDESTAL._serialized_start=2545 - _JFPEDESTAL._serialized_end=2575 - _JFGAINCALIBRATION._serialized_start=2577 - _JFGAINCALIBRATION._serialized_end=2622 - _JFCALIBRATION._serialized_start=2625 - _JFCALIBRATION._serialized_end=2803 - _JFCALIBRATIONSTATISTICS._serialized_start=2805 - _JFCALIBRATIONSTATISTICS._serialized_end=2891 - _ACQUISITIONDEVICESTATISTICS._serialized_start=2894 - _ACQUISITIONDEVICESTATISTICS._serialized_end=3167 - _RECEIVERINPUT._serialized_start=3170 - _RECEIVERINPUT._serialized_end=3306 - _RECEIVEROUTPUT._serialized_start=3309 - _RECEIVEROUTPUT._serialized_end=3779 - _RECEIVERNETWORKCONFIGDEVICE._serialized_start=3781 - _RECEIVERNETWORKCONFIGDEVICE._serialized_end=3865 - _RECEIVERNETWORKCONFIG._serialized_start=3867 - _RECEIVERNETWORKCONFIG._serialized_end=3951 - _RECEIVERSTATUS._serialized_start=3954 - _RECEIVERSTATUS._serialized_end=4157 - _PLOTREQUEST._serialized_start=4159 - _PLOTREQUEST._serialized_end=4261 - _RADIALINTEGRATIONPROFILES._serialized_start=4264 - _RADIALINTEGRATIONPROFILES._serialized_end=4460 - _RADIALINTEGRATIONPROFILES_PLOTSENTRY._serialized_start=4394 - _RADIALINTEGRATIONPROFILES_PLOTSENTRY._serialized_end=4460 - _WRITERINPUT._serialized_start=4462 - _WRITERINPUT._serialized_end=4524 - _DATAFILESTATISTICS._serialized_start=4526 - _DATAFILESTATISTICS._serialized_end=4577 - _WRITEROUTPUT._serialized_start=4580 - _WRITEROUTPUT._serialized_end=4721 - _DETECTORMODULECONFIG._serialized_start=4724 - _DETECTORMODULECONFIG._serialized_end=4982 - _DETECTORCONFIG._serialized_start=4984 - _DETECTORCONFIG._serialized_end=5080 - _DETECTORINPUT._serialized_start=5083 - _DETECTORINPUT._serialized_end=5332 - _DETECTOROUTPUT._serialized_start=5334 - _DETECTOROUTPUT._serialized_end=5350 - _DETECTORSTATUS._serialized_start=5352 - _DETECTORSTATUS._serialized_end=5450 - _FPGASTATUS._serialized_start=5453 - _FPGASTATUS._serialized_end=6523 - _FPGASTATUS_FIFOSTATUSENTRY._serialized_start=6442 - _FPGASTATUS_FIFOSTATUSENTRY._serialized_end=6523 - _DATAPROCESSINGSETTINGS._serialized_start=6526 - _DATAPROCESSINGSETTINGS._serialized_end=6872 - _PREVIEWFRAMESPOT._serialized_start=6874 - _PREVIEWFRAMESPOT._serialized_end=6931 - _PREVIEWFRAME._serialized_start=6934 - _PREVIEWFRAME._serialized_end=7252 - _MODULESTATISTICS._serialized_start=7255 - _MODULESTATISTICS._serialized_end=7492 - _IMAGE._serialized_start=7494 - _IMAGE._serialized_end=7567 - _MASKTOLOAD._serialized_start=7569 - _MASKTOLOAD._serialized_end=7615 - _MEASUREMENTSTATISTICS._serialized_start=7618 - _MEASUREMENTSTATISTICS._serialized_end=8231 - _BROKERSTATUS._serialized_start=8234 - _BROKERSTATUS._serialized_end=8449 - _BROKERFULLSTATUS._serialized_start=8452 - _BROKERFULLSTATUS._serialized_end=8616 - _DETECTORLISTELEMENT._serialized_start=8618 - _DETECTORLISTELEMENT._serialized_end=8690 - _DETECTORLIST._serialized_start=8692 - _DETECTORLIST._serialized_end=8810 - _DETECTORSELECTION._serialized_start=8812 - _DETECTORSELECTION._serialized_end=8843 - _GRPC_JFJOCHRECEIVER._serialized_start=9319 - _GRPC_JFJOCHRECEIVER._serialized_end=10086 - _GRPC_JFJOCHWRITER._serialized_start=10089 - _GRPC_JFJOCHWRITER._serialized_end=10291 - _GRPC_JFJOCHDETECTOR._serialized_start=10294 - _GRPC_JFJOCHDETECTOR._serialized_end=10680 - _GRPC_JFJOCHBROKER._serialized_start=10683 - _GRPC_JFJOCHBROKER._serialized_end=12372 + _ROIRECTANGLE._serialized_start=329 + _ROIRECTANGLE._serialized_end=398 + _DATASETSETTINGS._serialized_start=401 + _DATASETSETTINGS._serialized_end=1027 + _DETECTORSETTINGS._serialized_start=1030 + _DETECTORSETTINGS._serialized_end=1467 + _DETECTORMODULEGEOMETRY._serialized_start=1469 + _DETECTORMODULEGEOMETRY._serialized_end=1567 + _DETECTORGEOMETRY._serialized_start=1569 + _DETECTORGEOMETRY._serialized_end=1691 + _DETECTOR._serialized_start=1694 + _DETECTOR._serialized_end=1887 + _INTERNALSETTINGS._serialized_start=1890 + _INTERNALSETTINGS._serialized_end=2756 + _JUNGFRAUJOCHSETTINGS._serialized_start=2758 + _JUNGFRAUJOCHSETTINGS._serialized_end=2882 + _JFPEDESTAL._serialized_start=2884 + _JFPEDESTAL._serialized_end=2914 + _JFGAINCALIBRATION._serialized_start=2916 + _JFGAINCALIBRATION._serialized_end=2961 + _JFCALIBRATION._serialized_start=2964 + _JFCALIBRATION._serialized_end=3142 + _JFCALIBRATIONSTATISTICS._serialized_start=3144 + _JFCALIBRATIONSTATISTICS._serialized_end=3230 + _ACQUISITIONDEVICESTATISTICS._serialized_start=3233 + _ACQUISITIONDEVICESTATISTICS._serialized_end=3506 + _RECEIVERINPUT._serialized_start=3509 + _RECEIVERINPUT._serialized_end=3645 + _RECEIVEROUTPUT._serialized_start=3648 + _RECEIVEROUTPUT._serialized_end=4118 + _RECEIVERNETWORKCONFIGDEVICE._serialized_start=4120 + _RECEIVERNETWORKCONFIGDEVICE._serialized_end=4204 + _RECEIVERNETWORKCONFIG._serialized_start=4206 + _RECEIVERNETWORKCONFIG._serialized_end=4290 + _RECEIVERSTATUS._serialized_start=4293 + _RECEIVERSTATUS._serialized_end=4496 + _PLOTREQUEST._serialized_start=4498 + _PLOTREQUEST._serialized_end=4568 + _RADIALINTEGRATIONPROFILE._serialized_start=4570 + _RADIALINTEGRATIONPROFILE._serialized_end=4647 + _RADIALINTEGRATIONPROFILES._serialized_start=4649 + _RADIALINTEGRATIONPROFILES._serialized_end=4736 + _WRITERINPUT._serialized_start=4738 + _WRITERINPUT._serialized_end=4800 + _DATAFILESTATISTICS._serialized_start=4802 + _DATAFILESTATISTICS._serialized_end=4853 + _WRITEROUTPUT._serialized_start=4856 + _WRITEROUTPUT._serialized_end=4997 + _DETECTORMODULECONFIG._serialized_start=5000 + _DETECTORMODULECONFIG._serialized_end=5258 + _DETECTORCONFIG._serialized_start=5260 + _DETECTORCONFIG._serialized_end=5356 + _DETECTORINPUT._serialized_start=5359 + _DETECTORINPUT._serialized_end=5611 + _DETECTOROUTPUT._serialized_start=5613 + _DETECTOROUTPUT._serialized_end=5629 + _DETECTORSTATUS._serialized_start=5631 + _DETECTORSTATUS._serialized_end=5729 + _FPGAFIFOSTATUS._serialized_start=5731 + _FPGAFIFOSTATUS._serialized_end=5812 + _FPGASTATUS._serialized_start=5815 + _FPGASTATUS._serialized_end=6710 + _DATAPROCESSINGSETTINGS._serialized_start=6713 + _DATAPROCESSINGSETTINGS._serialized_end=7059 + _PREVIEWFRAMESPOT._serialized_start=7061 + _PREVIEWFRAMESPOT._serialized_end=7118 + _PREVIEWFRAME._serialized_start=7121 + _PREVIEWFRAME._serialized_end=7439 + _MODULESTATISTICS._serialized_start=7442 + _MODULESTATISTICS._serialized_end=7679 + _IMAGE._serialized_start=7681 + _IMAGE._serialized_end=7754 + _MASKTOLOAD._serialized_start=7756 + _MASKTOLOAD._serialized_end=7802 + _MEASUREMENTSTATISTICS._serialized_start=7805 + _MEASUREMENTSTATISTICS._serialized_end=8418 + _BROKERSTATUS._serialized_start=8421 + _BROKERSTATUS._serialized_end=8636 + _BROKERFULLSTATUS._serialized_start=8639 + _BROKERFULLSTATUS._serialized_end=8803 + _DETECTORLISTELEMENT._serialized_start=8805 + _DETECTORLISTELEMENT._serialized_end=8877 + _DETECTORLIST._serialized_start=8879 + _DETECTORLIST._serialized_end=8997 + _DETECTORSELECTION._serialized_start=8999 + _DETECTORSELECTION._serialized_end=9030 + _GRPC_JFJOCHRECEIVER._serialized_start=9510 + _GRPC_JFJOCHRECEIVER._serialized_end=10277 + _GRPC_JFJOCHWRITER._serialized_start=10280 + _GRPC_JFJOCHWRITER._serialized_end=10482 + _GRPC_JFJOCHDETECTOR._serialized_start=10485 + _GRPC_JFJOCHDETECTOR._serialized_end=10871 + _GRPC_JFJOCHBROKER._serialized_start=10874 + _GRPC_JFJOCHBROKER._serialized_end=12563 # @@protoc_insertion_point(module_scope) diff --git a/python/jungfraujoch.py b/python/jungfraujoch.py index 91f4cc18..80c4fec7 100644 --- a/python/jungfraujoch.py +++ b/python/jungfraujoch.py @@ -1,5 +1,5 @@ -# Copyright (2019-2022) Paul Scherrer Institute -# SPDX-License-Identifier: GPL-3.0-or-later +# Copyright (2019-2023) Paul Scherrer Institute +# import requests diff --git a/python/jungfraujoch_metadata.py b/python/jungfraujoch_metadata.py index c6afd720..6c4c7522 100644 --- a/python/jungfraujoch_metadata.py +++ b/python/jungfraujoch_metadata.py @@ -1,5 +1,5 @@ -# Copyright (2019-2022) Paul Scherrer Institute -# SPDX-License-Identifier: GPL-3.0-or-later +# Copyright (2019-2023) Paul Scherrer Institute +# import h5py import sys diff --git a/receiver/host/AcquisitionOnlineCounters.cpp b/receiver/AcquisitionCounters.cpp similarity index 55% rename from receiver/host/AcquisitionOnlineCounters.cpp rename to receiver/AcquisitionCounters.cpp index b1d682d2..b26dbb94 100644 --- a/receiver/host/AcquisitionOnlineCounters.cpp +++ b/receiver/AcquisitionCounters.cpp @@ -1,15 +1,14 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (2019-2023) Paul Scherrer Institute #include -#include "AcquisitionOnlineCounters.h" -#include "../../common/JFJochException.h" +#include "AcquisitionCounters.h" +#include "../common/JFJochException.h" -AcquisitionOnlineCounters::AcquisitionOnlineCounters() -: head(max_modules, 0), slowest_head(0) {} +AcquisitionCounters::AcquisitionCounters() + : head(max_modules, 0), slowest_head(0), total_packets(0), expected_frames(0), acquisition_finished(false) {} -void AcquisitionOnlineCounters::Reset(const DiffractionExperiment &experiment, uint16_t data_stream) { +void AcquisitionCounters::Reset(const DiffractionExperiment &experiment, uint16_t data_stream) { std::unique_lock ul(m); acquisition_finished = false; @@ -30,24 +29,23 @@ void AcquisitionOnlineCounters::Reset(const DiffractionExperiment &experiment, u handle_for_frame = std::vector((expected_frames+1) * nmodules, HandleNotFound); full_module_collected = std::vector(expected_frames * nmodules); - bunch_id = std::vector(expected_frames * nmodules); - jf_info = std::vector(expected_frames * nmodules); - timestamp = std::vector(expected_frames * nmodules); - exptime = std::vector(expected_frames * nmodules); + saved_completions = std::vector(expected_frames * nmodules); + packets_per_module = std::vector(nmodules); + total_packets = 0; } -void AcquisitionOnlineCounters::UpdateCounters(const Completion *c) { +void AcquisitionCounters::UpdateCounters(const Completion *c) { std::unique_lock ul(m); - if (c->module >= nmodules) + if (c->module_number >= nmodules) throw JFJochException(JFJochExceptionCategory::InputParameterInvalid, - "UpdateCounters wrong module number: " + std::to_string(c->module) + " for frame " + std::to_string(c->frame_number)); + "UpdateCounters wrong module number: " + std::to_string(c->module_number) + " for frame " + std::to_string(c->frame_number)); if (c->frame_number >= expected_frames) throw JFJochException(JFJochExceptionCategory::InputParameterInvalid, - "UpdateCounters frame number is out of bounds"); + "UpdateCounters frame number is out of bounds"); else { - if (head.at(c->module) < c->frame_number) - head.at(c->module) = c->frame_number; + if (head.at(c->module_number) < c->frame_number) + head.at(c->module_number) = c->frame_number; if (c->frame_number > slowest_head) { slowest_head = head[0]; @@ -56,24 +54,24 @@ void AcquisitionOnlineCounters::UpdateCounters(const Completion *c) { slowest_head = head[i]; } - full_module_collected.at(c->frame_number * nmodules + c->module) = (c->packet_count == expected_packets_per_module); - handle_for_frame.at(c->frame_number * nmodules + c->module) = c->handle; - bunch_id.at(c->frame_number * nmodules + c->module) = c->bunchid; - jf_info.at(c->frame_number * nmodules + c->module) = c->debug; - timestamp.at(c->frame_number * nmodules + c->module) = c->timestamp; - exptime.at(c->frame_number * nmodules + c->module) = c->exptime; + full_module_collected.at(c->frame_number * nmodules + c->module_number) = (c->packet_count == expected_packets_per_module); + handle_for_frame.at(c->frame_number * nmodules + c->module_number) = c->handle; + saved_completions.at(c->frame_number * nmodules + c->module_number) = *c; + + total_packets += c->packet_count; + packets_per_module[c->module_number] += c->packet_count; } data_updated.notify_all(); } -void AcquisitionOnlineCounters::SetAcquisitionFinished() { +void AcquisitionCounters::SetAcquisitionFinished() { std::unique_lock ul(m); acquisition_finished = true; data_updated.notify_all(); } -uint64_t AcquisitionOnlineCounters::GetBufferHandle(size_t frame, uint16_t module_number) const { +uint64_t AcquisitionCounters::GetBufferHandle(size_t frame, uint16_t module_number) const { if (frame >= expected_frames) throw JFJochException(JFJochExceptionCategory::ArrayOutOfBounds, "GetBufferHandle Wrong frame number: " + std::to_string(frame)); @@ -84,7 +82,7 @@ uint64_t AcquisitionOnlineCounters::GetBufferHandle(size_t frame, uint16_t modul return handle_for_frame.at(frame * nmodules + module_number); } -uint64_t AcquisitionOnlineCounters::GetBufferHandleAndClear(size_t frame, uint16_t module_number) { +uint64_t AcquisitionCounters::GetBufferHandleAndClear(size_t frame, uint16_t module_number) { std::unique_lock ul(m); if (frame >= expected_frames) throw JFJochException(JFJochExceptionCategory::ArrayOutOfBounds, @@ -92,24 +90,24 @@ uint64_t AcquisitionOnlineCounters::GetBufferHandleAndClear(size_t frame, uint16 if (module_number >= nmodules) throw JFJochException(JFJochExceptionCategory::ArrayOutOfBounds, "GetBufferHandleAndClear Wrong module number: " + std::to_string(module_number) - + " for frame " + std::to_string(frame)); + + " for frame " + std::to_string(frame)); uint64_t ret_val = handle_for_frame.at(frame * nmodules + module_number); handle_for_frame.at(frame * nmodules + module_number) = HandleNotFound; return ret_val; } -uint64_t AcquisitionOnlineCounters::GetHead(uint16_t module_number) const { +uint64_t AcquisitionCounters::GetHead(uint16_t module_number) const { if (module_number >= max_modules) throw JFJochException(JFJochExceptionCategory::ArrayOutOfBounds, "GetHead Wrong module number: " + std::to_string(module_number)); return head[module_number]; } -uint64_t AcquisitionOnlineCounters::GetSlowestHead() const { +uint64_t AcquisitionCounters::GetSlowestHead() const { return slowest_head; } -void AcquisitionOnlineCounters::WaitForFrame(size_t curr_frame, uint16_t module_number) const { +void AcquisitionCounters::WaitForFrame(size_t curr_frame, uint16_t module_number) const { uint64_t slowest_head_tmp = (module_number == UINT16_MAX) ? GetSlowestHead() : GetHead(module_number); while (!acquisition_finished && (slowest_head_tmp < curr_frame)) { std::this_thread::sleep_for(std::chrono::microseconds(100)); @@ -117,7 +115,7 @@ void AcquisitionOnlineCounters::WaitForFrame(size_t curr_frame, uint16_t module_ } } -int64_t AcquisitionOnlineCounters::CalculateDelay(size_t curr_frame, uint16_t module_number) const { +int64_t AcquisitionCounters::CalculateDelay(size_t curr_frame, uint16_t module_number) const { uint64_t slowest_head_tmp; if (module_number == UINT16_MAX) @@ -128,11 +126,11 @@ int64_t AcquisitionOnlineCounters::CalculateDelay(size_t curr_frame, uint16_t mo return slowest_head_tmp - curr_frame; } -bool AcquisitionOnlineCounters::IsAcquisitionFinished() const { +bool AcquisitionCounters::IsAcquisitionFinished() const { return acquisition_finished; } -bool AcquisitionOnlineCounters::IsFullModuleCollected(size_t frame, uint16_t module_number) const { +bool AcquisitionCounters::IsFullModuleCollected(size_t frame, uint16_t module_number) const { if (frame >= expected_frames) throw JFJochException(JFJochExceptionCategory::ArrayOutOfBounds, "IsFullModuleCollected Wrong frame number: " + std::to_string(frame)); @@ -145,7 +143,7 @@ bool AcquisitionOnlineCounters::IsFullModuleCollected(size_t frame, uint16_t mod return full_module_collected[frame * nmodules + module_number]; } -uint64_t AcquisitionOnlineCounters::GetBunchID(size_t frame, uint16_t module_number) const { +Completion AcquisitionCounters::GetCompletion(size_t frame, uint16_t module_number) const { if (frame >= expected_frames) throw JFJochException(JFJochExceptionCategory::ArrayOutOfBounds, "GetBunchID Wrong frame number: " + std::to_string(frame)); @@ -155,41 +153,27 @@ uint64_t AcquisitionOnlineCounters::GetBunchID(size_t frame, uint16_t module_num "GetBunchID Wrong module number: " + std::to_string(module_number) + " for frame " + std::to_string(frame)); - return bunch_id[frame * nmodules + module_number]; + return saved_completions[frame * nmodules + module_number]; } -uint32_t AcquisitionOnlineCounters::GetExptime(size_t frame, uint16_t module_number) const { - if (frame >= expected_frames) - throw JFJochException(JFJochExceptionCategory::ArrayOutOfBounds, - "GetExptime Wrong frame number: " + std::to_string(frame)); +uint64_t AcquisitionCounters::GetTotalPackets() const { + return total_packets; +} + +uint64_t AcquisitionCounters::GetTotalPackets(uint16_t module_number) const { + std::unique_lock ul(m); if (module_number >= nmodules) throw JFJochException(JFJochExceptionCategory::ArrayOutOfBounds, - "GetExptime Wrong module number: " + std::to_string(module_number) - + " for frame " + std::to_string(frame)); + "GetTotalPackets Wrong module number: " + std::to_string(module_number));\ - return exptime[frame * nmodules + module_number]; -} -uint32_t AcquisitionOnlineCounters::GetJFInfo(size_t frame, uint16_t module_number) const { - if (frame >= expected_frames) - throw JFJochException(JFJochExceptionCategory::ArrayOutOfBounds, - "GetJFInfo Wrong frame number: " + std::to_string(frame)); - - if (module_number >= nmodules) - throw JFJochException(JFJochExceptionCategory::ArrayOutOfBounds, - "GetJFInfo Wrong module number: " + std::to_string(module_number) - + " for frame " + std::to_string(frame)); - return jf_info[frame * nmodules + module_number]; + return packets_per_module[module_number]; } -uint64_t AcquisitionOnlineCounters::GetTimestamp(size_t frame, uint16_t module_number) const { - if (frame >= expected_frames) - throw JFJochException(JFJochExceptionCategory::ArrayOutOfBounds, - "GetTimestamp Wrong frame number: " + std::to_string(frame)); - - if (module_number >= nmodules) - throw JFJochException(JFJochExceptionCategory::ArrayOutOfBounds, - "GetTimestamp Wrong module number: " + std::to_string(module_number) - + " for frame " + std::to_string(frame)); - return timestamp[frame * nmodules + module_number]; +uint64_t AcquisitionCounters::GetExpectedPackets() const { + return GetExpectedPacketsPerModule() * nmodules; +} + +uint64_t AcquisitionCounters::GetExpectedPacketsPerModule() const { + return expected_frames * expected_packets_per_module; } diff --git a/receiver/host/AcquisitionOnlineCounters.h b/receiver/AcquisitionCounters.h similarity index 58% rename from receiver/host/AcquisitionOnlineCounters.h rename to receiver/AcquisitionCounters.h index fd8ac11c..4400ec15 100644 --- a/receiver/host/AcquisitionOnlineCounters.h +++ b/receiver/AcquisitionCounters.h @@ -1,21 +1,20 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (2019-2023) Paul Scherrer Institute -#ifndef JUNGFRAUJOCH_ACQUISITIONONLINECOUNTERS_H -#define JUNGFRAUJOCH_ACQUISITIONONLINECOUNTERS_H +#ifndef JUNGFRAUJOCH_ACQUISITIONCOUNTERS_H +#define JUNGFRAUJOCH_ACQUISITIONCOUNTERS_H #include #include #include -#include "../../common/DiffractionExperiment.h" -#include "../../common/Definitions.h" +#include "../common/DiffractionExperiment.h" +#include "../common/Definitions.h" #include "Completion.h" -// AcquisitionOnlineCounters are used for information that needs to be accessed during data collection, -// so has more stringent mutex requirements than AcquisitionOfflineCounters +// AcquisitionCounters are used for information that needs to be accessed during data collection, +// so uses mutex to ensure consistency -class AcquisitionOnlineCounters { +class AcquisitionCounters { constexpr static const uint16_t expected_packets_per_module = 128; constexpr static const uint64_t max_modules = 32; @@ -25,39 +24,44 @@ class AcquisitionOnlineCounters { std::vector handle_for_frame; std::vector full_module_collected; // vector of bool might have weird concurrency behavior - std::vector bunch_id; - std::vector jf_info; - std::vector timestamp; - std::vector exptime; + std::vector saved_completions; + + uint64_t total_packets; + std::vector packets_per_module; uint64_t slowest_head; std::vector head; bool acquisition_finished; uint64_t expected_frames; uint64_t nmodules = max_modules; + public: static constexpr const uint64_t HandleNotFound = UINT64_MAX; - AcquisitionOnlineCounters(); + AcquisitionCounters(); void Reset(const DiffractionExperiment &experiment, uint16_t data_stream); void UpdateCounters(const Completion *c); void SetAcquisitionFinished(); + uint64_t GetBufferHandleAndClear(size_t frame, uint16_t module_number); + uint64_t GetHead(uint16_t module_number) const; uint64_t GetSlowestHead() const; void WaitForFrame(size_t curr_frame, uint16_t module_number = UINT16_MAX) const; int64_t CalculateDelay(size_t curr_frame, uint16_t module_number = UINT16_MAX) const; // mutex acquired indirectly uint64_t GetBufferHandle(size_t frame, uint16_t module_number) const; - uint64_t GetBufferHandleAndClear(size_t frame, uint16_t module_number); bool IsFullModuleCollected(size_t frame, uint16_t module_number) const; bool IsAcquisitionFinished() const; - uint64_t GetBunchID(size_t curr_frame, uint16_t module_number) const; - uint32_t GetJFInfo(size_t curr_frame, uint16_t module_number) const; - uint64_t GetTimestamp(size_t curr_frame, uint16_t module_number) const; - uint32_t GetExptime(size_t curr_frame, uint16_t module_number) const; + Completion GetCompletion(size_t curr_frame, uint16_t module_number) const; + + uint64_t GetTotalPackets() const; + uint64_t GetTotalPackets(uint16_t module_number) const; + + uint64_t GetExpectedPackets() const; + uint64_t GetExpectedPacketsPerModule() const; }; -#endif //JUNGFRAUJOCH_ACQUISITIONONLINECOUNTERS_H +#endif //JUNGFRAUJOCH_ACQUISITIONCOUNTERS_H diff --git a/receiver/AcquisitionDevice.cpp b/receiver/AcquisitionDevice.cpp new file mode 100644 index 00000000..95c1217e --- /dev/null +++ b/receiver/AcquisitionDevice.cpp @@ -0,0 +1,217 @@ +// Copyright (2019-2023) Paul Scherrer Institute + +#ifdef JFJOCH_USE_NUMA +#include +#endif + +#include +#include +#include +#include +#include + +#include "../common/JFJochException.h" +#include "AcquisitionDevice.h" +#include "../common/NetworkAddressConvert.h" + +void *mmap_acquisition_buffer(size_t size, int16_t numa_node) { + void *ret = mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + if (ret == nullptr) { + throw JFJochException(JFJochExceptionCategory::MemAllocFailed, "frame_buffer"); + } +#ifdef JFJOCH_USE_NUMA + if (numa_node >= 0) { + unsigned long nodemask = 1L << numa_node;; + if (numa_node > sizeof(nodemask)*8) + throw JFJochException(JFJochExceptionCategory::MemAllocFailed, "Mask too small for NUMA node"); + if (mbind(ret, size, MPOL_BIND, &nodemask, sizeof(nodemask)*8, MPOL_MF_STRICT) == -1) + throw JFJochException(JFJochExceptionCategory::MemAllocFailed, "Cannot apply NUMA policy"); + } +#endif + memset(ret, 0, size); + return ret; +} + +AcquisitionDevice::AcquisitionDevice(uint16_t in_data_stream) : +buffer_err(RAW_MODULE_SIZE) { + logger = nullptr; + data_stream = in_data_stream; +} + +void AcquisitionDevice::PrepareAction(const DiffractionExperiment &experiment) { + if (experiment.GetModulesNum(data_stream) > max_modules) + throw(JFJochException(JFJochExceptionCategory::InputParameterAboveMax, + "Number of modules exceeds max possible for FPGA")); + + counters.Reset(experiment, data_stream); +} + +void AcquisitionDevice::StartAction(const DiffractionExperiment &experiment) { + Cancel(); + + if (experiment.GetModulesNum(data_stream) > max_modules) + throw(JFJochException(JFJochExceptionCategory::InputParameterAboveMax, + "Number of modules exceeds max possible for FPGA")); + + for (int i = 0; i < RAW_MODULE_SIZE; i++) { + if (experiment.GetDetectorMode() == DetectorMode::Conversion) + buffer_err[i] = PIXEL_OUT_LOST; + else + buffer_err[i] = -1; + } + + counters.Reset(experiment, data_stream); + expected_frames = experiment.GetFrameNum(); + + // Ensure internal WR queue is empty + work_request_queue.Clear(); + + Start(experiment); + + for (uint32_t i = 0; i < buffer_device.size(); i++) + SendWorkRequest(i); + + auto c = work_completion_queue.GetBlocking(); + if (c.type != Completion::Type::Start) + throw JFJochException(JFJochExceptionCategory::AcquisitionDeviceError, "Mismatch in work completions"); + + StartSendingWorkRequests(); + + start_time = std::chrono::system_clock::now(); + + if (logger) + logger->Info("Started"); +} + +void AcquisitionDevice::WaitForActionComplete() { + auto c = work_completion_queue.GetBlocking(); + + while (c.type != Completion::Type::End) { + if (c.frame_number >= expected_frames) { + Cancel(); + // this frame is not of any interest, therefore its location can be immediately released + SendWorkRequest(c.handle); + } else if (c.module_number >= max_modules) { + // Module number out of bounds, don't process + if (logger != nullptr) + logger->Error("Completion with wrong module number data stream {} completion frame number {} module {} handle {} timestamp {} status {}", + data_stream, c.frame_number, c.module_number, c.handle, c.timestamp, c.status); + SendWorkRequest(c.handle); + } else + counters.UpdateCounters(&c); + + if (logger != nullptr) + logger->Debug("Data stream {} completion frame number {} module {} handle {} timestamp {} status {}", + data_stream, c.frame_number, c.module_number, c.handle, c.timestamp, c.status); + + c = work_completion_queue.GetBlocking(); + } + counters.SetAcquisitionFinished(); + + end_time = std::chrono::system_clock::now(); + Cancel(); + Finalize(); +} + +void AcquisitionDevice::SendWorkRequest(uint32_t handle) { + work_request_queue.Put(WorkRequest{ + .ptr = buffer_device.at(handle), + .handle = handle + }); +} + +uint64_t AcquisitionDevice::GetBytesReceived() const { + return counters.GetTotalPackets() * 8192LU; +} + +void AcquisitionDevice::SaveStatistics(const DiffractionExperiment &experiment, + JFJochProtoBuf::AcquisitionDeviceStatistics &statistics) const { + + statistics.set_bytes_received(GetBytesReceived()); + statistics.set_start_timestamp(start_time.time_since_epoch().count()); + statistics.set_end_timestamp(end_time.time_since_epoch().count()); + + auto nmodules = experiment.GetModulesNum(data_stream); + auto expected_packets = counters.GetExpectedPackets(); + auto total_packets = counters.GetTotalPackets(); + + statistics.set_nmodules(nmodules); + statistics.set_packets_expected(expected_packets); + statistics.set_good_packets(total_packets); + + for (int i = 0; i < nmodules; i++) + statistics.add_packets_received_per_module(counters.GetTotalPackets(i)); + + if ((expected_packets == 0) || (total_packets == expected_packets)) + statistics.set_efficiency(1.0); + else + statistics.set_efficiency(static_cast(total_packets) / static_cast(expected_packets)); + + *statistics.mutable_fpga_status() = GetStatus(); +} + +const int16_t *AcquisitionDevice::GetFrameBuffer(size_t frame_number, uint16_t module_number) const { + auto handle = counters.GetBufferHandle(frame_number, module_number); + if (handle != HandleNotValid) + return (int16_t *) buffer_device.at(handle); + else + return GetErrorFrameBuffer(); +} + +const int16_t *AcquisitionDevice::GetErrorFrameBuffer() const { + return buffer_err.data(); +} + +int16_t *AcquisitionDevice::GetDeviceBuffer(size_t handle) { + if (handle >= buffer_device.size()) + throw JFJochException(JFJochExceptionCategory::ArrayOutOfBounds, "Handle outside of range"); + else + return (int16_t *) buffer_device.at(handle); +} + +void AcquisitionDevice::InitializeCalibration(const DiffractionExperiment &experiment, const JFCalibration &calib) {} + +void AcquisitionDevice::MapBuffersStandard(size_t c2h_buffer_count, size_t h2c_buffer_count, int16_t numa_node) { + try { + for (int i = 0; i < std::max(c2h_buffer_count, h2c_buffer_count); i++) + buffer_device.emplace_back((uint16_t *) mmap_acquisition_buffer(FPGA_BUFFER_LOCATION_SIZE, numa_node)); + } catch (const JFJochException &e) { + UnmapBuffers(); + throw; + } +} + +void AcquisitionDevice::UnmapBuffers() { + for (auto &i: buffer_device) + if (i != nullptr) munmap(i, FPGA_BUFFER_LOCATION_SIZE); +} + +void AcquisitionDevice::FrameBufferRelease(size_t frame_number, uint16_t module_number) { + auto handle = counters.GetBufferHandleAndClear(frame_number, module_number); + if (handle != AcquisitionCounters::HandleNotFound) + SendWorkRequest(handle); +} + +void AcquisitionDevice::EnableLogging(Logger *in_logger) { + logger = in_logger; +} + +int32_t AcquisitionDevice::GetNUMANode() const { + return -1; +} + +uint16_t AcquisitionDevice::GetUDPPort() const { + return 1234; +} + +const AcquisitionCounters &AcquisitionDevice::Counters() const { + return counters; +} + +std::string AcquisitionDevice::GetIPv4Address() const { + return IPv4AddressToStr(ipv4_addr); +} + +std::string AcquisitionDevice::GetMACAddress() const { + return MacAddressToStr(mac_addr); +} diff --git a/receiver/AcquisitionDevice.h b/receiver/AcquisitionDevice.h new file mode 100644 index 00000000..4a41d078 --- /dev/null +++ b/receiver/AcquisitionDevice.h @@ -0,0 +1,95 @@ +// Copyright (2019-2023) Paul Scherrer Institute + +#ifndef JUNGFRAUJOCH_ACQUISITIONDEVICE_H +#define JUNGFRAUJOCH_ACQUISITIONDEVICE_H + +#include +#include +#include +#include + +#include "jfjoch.pb.h" + +#include "../common/Definitions.h" +#include "../common/DiffractionExperiment.h" +#include "../common/Logger.h" + +#include "../common/ThreadSafeFIFO.h" +#include "../jungfrau/JFCalibration.h" + +#include "AcquisitionCounters.h" +#include "Completion.h" + +class AcquisitionDevice { + std::vector buffer_err; + + std::chrono::time_point start_time; + std::chrono::time_point end_time; + + int64_t expected_frames; + + virtual void Start(const DiffractionExperiment& experiment) = 0; + virtual void Finalize() {}; // do clean-up after action is done + virtual void StartSendingWorkRequests() {}; + void SendWorkRequest(uint32_t handle); +protected: + AcquisitionCounters counters; + + ThreadSafeFIFO work_completion_queue; + ThreadSafeFIFO work_request_queue; + + std::vector buffer_device; + Logger *logger; + + uint16_t data_stream; + uint32_t max_modules = 1; + uint64_t mac_addr; + uint32_t ipv4_addr; + + explicit AcquisitionDevice(uint16_t data_stream); + + void UnmapBuffers(); + void MapBuffersStandard(size_t c2h_buffer_count, size_t h2c_buffer_count, int16_t numa_node); +public: + static constexpr const uint64_t HandleNotValid = UINT64_MAX; + + virtual ~AcquisitionDevice() { UnmapBuffers(); }; + + void StartAction(const DiffractionExperiment &experiment); + void PrepareAction(const DiffractionExperiment &experiment); + + void WaitForActionComplete(); + virtual void Cancel() = 0; + + void EnableLogging(Logger *logger); + + // Post measurement statistics - only guaranteed valid after WaitForActionComplete ends + uint64_t GetBytesReceived() const; + + void SaveStatistics(const DiffractionExperiment &experiment, JFJochProtoBuf::AcquisitionDeviceStatistics &statistics) const; + virtual JFJochProtoBuf::FPGAStatus GetStatus() const { return {}; }; + + const int16_t *GetFrameBuffer(size_t frame_number, uint16_t module_number) const; + + void FrameBufferRelease(size_t frame_number, uint16_t module_number); + const int16_t *GetErrorFrameBuffer() const; + + int16_t *GetDeviceBuffer(size_t handle); + + // Calibration + virtual void InitializeCalibration(const DiffractionExperiment &experiment, const JFCalibration &calib); + + const AcquisitionCounters& Counters() const; + + virtual std::string GetIPv4Address() const; + virtual std::string GetMACAddress() const; + virtual uint16_t GetUDPPort() const; + virtual int32_t GetNUMANode() const; + + virtual std::vector GetInternalGeneratorFrame() const { + return {}; + } +}; + + +#endif //JUNGFRAUJOCH_ACQUISITIONDEVICE_H diff --git a/receiver/CMakeLists.txt b/receiver/CMakeLists.txt index 3a619260..999b8d4a 100644 --- a/receiver/CMakeLists.txt +++ b/receiver/CMakeLists.txt @@ -1,34 +1,53 @@ -FIND_PROGRAM(VIVADO vivado DOC "Xilinx Vivado") -IF (VIVADO) - MESSAGE(STATUS "Xilinx Vivado found: ${VIVADO}") -ELSE() - MESSAGE(STATUS "Xilinx Vivado not found") +ADD_LIBRARY(JungfraujochHost STATIC + AcquisitionDevice.cpp AcquisitionDevice.h + AcquisitionCounters.cpp AcquisitionCounters.h + MockAcquisitionDevice.cpp MockAcquisitionDevice.h + HLSSimulatedDevice.cpp HLSSimulatedDevice.h + Completion.cpp Completion.h ../fpga/pcie_driver/ActionConfig.h + PCIExpressDevice.cpp PCIExpressDevice.h + IBWrappers.cpp IBWrappers.h + MlxRawEthDevice.cpp MlxRawEthDevice.h + ../jungfrau/jf_packet.h + LinuxSocketDevice.cpp LinuxSocketDevice.h + FPGAAcquisitionDevice.cpp FPGAAcquisitionDevice.h) + +TARGET_LINK_LIBRARIES(JungfraujochHost CommonFunctions HLSSimulation JFCalibration) + +FIND_LIBRARY(IBVERBS NAMES ibverbs DOC "Infiniband verbs") + +IF(IBVERBS) + TARGET_COMPILE_DEFINITIONS(JungfraujochHost PUBLIC -DJFJOCH_USE_IBVERBS) + TARGET_LINK_LIBRARIES(JungfraujochHost ${IBVERBS}) + MESSAGE(STATUS "JFJochReceiver compiled with IBVerbs support") + + ADD_EXECUTABLE(jfjoch_mlx_test jfjoch_mlx_test.cpp) + TARGET_LINK_LIBRARIES(jfjoch_mlx_test JungfraujochHost) + INSTALL(TARGETS jfjoch_mlx_test RUNTIME) ENDIF() -FIND_PROGRAM(VIVADO_HLS NAMES vitis_hls DOC "Xilinx HLS") -IF (VIVADO_HLS) - MESSAGE(STATUS "Xilinx HLS compiler found: ${VIVADO_HLS}") -ELSE() - MESSAGE(STATUS "Xilinx HLS compiler not found") -ENDIF() +ADD_EXECUTABLE(jfjoch_lxsocket_test jfjoch_lxsocket_test.cpp) +TARGET_LINK_LIBRARIES(jfjoch_lxsocket_test JungfraujochHost) +INSTALL(TARGETS jfjoch_lxsocket_test RUNTIME) -INCLUDE_DIRECTORIES(include) +ADD_EXECUTABLE(jfjoch_pcie_status jfjoch_pcie_status.cpp) +TARGET_LINK_LIBRARIES(jfjoch_pcie_status JungfraujochHost) +INSTALL(TARGETS jfjoch_pcie_status RUNTIME) -ADD_SUBDIRECTORY(hls) -ADD_SUBDIRECTORY(host) -ADD_SUBDIRECTORY(pcie_driver) +ADD_EXECUTABLE(jfjoch_pcie_set_network jfjoch_pcie_set_network.cpp) +TARGET_LINK_LIBRARIES(jfjoch_pcie_set_network JungfraujochHost) +INSTALL(TARGETS jfjoch_pcie_set_network RUNTIME) -IF(VIVADO_HLS AND VIVADO) - ADD_CUSTOM_COMMAND(OUTPUT action/hw/hdl/action_config.v - COMMAND ${CMAKE_COMMAND} -E env SRC_DIR=${CMAKE_CURRENT_SOURCE_DIR} HLS_IP_DIR=${CMAKE_CURRENT_BINARY_DIR}/action/ip/hls bash ${CMAKE_CURRENT_SOURCE_DIR}/scripts/setup_action.sh - DEPENDS hls hdl/action_config.v hdl/check_datamover_error.v hdl/check_eth_busy.v hdl/gen_xdma_descriptor.v hdl/refclk300to100.v hdl/action_wrapper.v hdl/resetn_sync.v scripts/bd_pcie.tcl scripts/jfjoch.tcl scripts/network_stack.tcl scripts/hbm_u55c.tcl scripts/mac_100g_pcie.tcl scripts/pcie_dma.tcl scripts/setup_action.sh - ) +ADD_EXECUTABLE(jfjoch_pcie_cancel_data_collection jfjoch_pcie_cancel_data_collection.cpp) +TARGET_LINK_LIBRARIES(jfjoch_pcie_cancel_data_collection JungfraujochHost) +INSTALL(TARGETS jfjoch_pcie_cancel_data_collection RUNTIME) - ADD_CUSTOM_TARGET(action_pcie DEPENDS action/hw/hdl/action_config.v hls - COMMAND ${VIVADO} -notrace -mode batch -source ${CMAKE_CURRENT_SOURCE_DIR}/scripts/build_pcie_design.tcl - COMMAND ${CMAKE_COMMAND} -E env FLOW=pcie VIV_PROJECT_PATH=${CMAKE_CURRENT_BINARY_DIR}/vivado/jfjoch_pcie.xpr ${VIVADO} -notrace -mode batch -source ${CMAKE_CURRENT_BINARY_DIR}/action/scripts/synth_and_impl.tcl - ) -ENDIF() +ADD_EXECUTABLE(jfjoch_pcie_clear_net_counters jfjoch_pcie_clear_net_counters.cpp) +TARGET_LINK_LIBRARIES(jfjoch_pcie_clear_net_counters JungfraujochHost) +INSTALL(TARGETS jfjoch_pcie_clear_net_counters RUNTIME) + +ADD_EXECUTABLE(jfjoch_pcie_read_int_packet_gen jfjoch_pcie_read_int_packet_gen.cpp) +TARGET_LINK_LIBRARIES(jfjoch_pcie_read_int_packet_gen JungfraujochHost) +INSTALL(TARGETS jfjoch_pcie_read_int_packet_gen RUNTIME) ADD_LIBRARY(JFJochReceiver STATIC JFJochReceiverService.cpp JFJochReceiverService.h @@ -37,10 +56,9 @@ ADD_LIBRARY(JFJochReceiver STATIC TARGET_LINK_LIBRARIES(JFJochReceiver ImageAnalysis JungfraujochHost CommonFunctions HLSSimulation) -IF(HAS_NUMA_H AND NUMA_LIBRARY) - TARGET_COMPILE_DEFINITIONS(JFJochReceiver PRIVATE -DJFJOCH_USE_NUMA_H) - TARGET_LINK_LIBRARIES(JFJochReceiver ${NUMA_LIBRARY}) - MESSAGE(STATUS "JFJochReceiver compiled with NUMA thread pinning") +SET(JFJOCH_RECV_CONVERSION_LOCAL ON CACHE BOOL "Jungfraujoch receiver uses conversion locally per thread") +IF(JFJOCH_RECV_CONVERSION_LOCAL) + TARGET_COMPILE_DEFINITIONS(JFJochReceiver PRIVATE -DJFJOCH_RECV_CONVERSION_LOCAL) ENDIF() ADD_EXECUTABLE(jfjoch_receiver jfjoch_receiver.cpp) @@ -49,4 +67,4 @@ INSTALL(TARGETS jfjoch_receiver RUNTIME) ADD_EXECUTABLE(jfjoch_action_test jfjoch_action_test.cpp) TARGET_LINK_LIBRARIES(jfjoch_action_test JungfraujochHost JFJochReceiver) -INSTALL(TARGETS jfjoch_action_test RUNTIME) \ No newline at end of file +INSTALL(TARGETS jfjoch_action_test RUNTIME) diff --git a/receiver/host/Completion.cpp b/receiver/Completion.cpp similarity index 76% rename from receiver/host/Completion.cpp rename to receiver/Completion.cpp index f64a0056..dfea0249 100644 --- a/receiver/host/Completion.cpp +++ b/receiver/Completion.cpp @@ -1,10 +1,10 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (2019-2023) Paul Scherrer Institute #include #include "Completion.h" -#include "../../common/JFJochException.h" +#include "../common/JFJochException.h" +#include "../common/Definitions.h" inline uint64_t bit_concat(uint32_t high, uint32_t low) { return (uint64_t(high) << 32) | low; @@ -13,9 +13,11 @@ inline uint64_t bit_concat(uint32_t high, uint32_t low) { Completion parse_hw_completion(uint32_t tmp[16]) { Completion c{}; - c.handle = tmp[0]; - c.module = tmp[1] & 0xFF; - c.packet_count = (tmp[1] & (0xFFFF0000)) >> 16; + c.handle = tmp[0]; + c.module_number = tmp[1] & 0xFF; + c.packet_count = (tmp[1] & (0xFFFF0000)) >> 16; + c.status = (tmp[1] >> 8) & 0xFF; + c.data_collection_id = tmp[11] & UINT16_MAX; uint64_t detector_frame_number = bit_concat(tmp[2], tmp[3]); @@ -25,14 +27,13 @@ Completion parse_hw_completion(uint32_t tmp[16]) { if (parity == 1) throw JFJochException(JFJochExceptionCategory::HardwareParityError, "Wrong parity in work completion"); - if (c.handle == UINT32_MAX -1) { + if (c.handle == HANDLE_START) { c.type = Completion::Type::Start; - } else if (c.handle == UINT32_MAX) { + } else if (c.handle == HANDLE_END) { c.type = Completion::Type::End; c.frame_number = detector_frame_number; } else { c.type = Completion::Type::Image; - if (detector_frame_number == 0) throw JFJochException(JFJochExceptionCategory::HardwareParityError, "Detector frame number cannot be zero"); else diff --git a/receiver/host/Completion.h b/receiver/Completion.h similarity index 79% rename from receiver/host/Completion.h rename to receiver/Completion.h index af450947..66ce8170 100644 --- a/receiver/host/Completion.h +++ b/receiver/Completion.h @@ -1,5 +1,4 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (2019-2023) Paul Scherrer Institute #ifndef JUNGFRAUJOCH_COMPLETION_H #define JUNGFRAUJOCH_COMPLETION_H @@ -22,7 +21,9 @@ struct Completion { uint32_t debug; uint32_t handle; uint16_t packet_count; - uint8_t module; + uint16_t data_collection_id; + uint16_t status; + uint16_t module_number; }; Completion parse_hw_completion(uint32_t hw_input[16]); diff --git a/receiver/FPGAAcquisitionDevice.cpp b/receiver/FPGAAcquisitionDevice.cpp new file mode 100644 index 00000000..9f9eddb8 --- /dev/null +++ b/receiver/FPGAAcquisitionDevice.cpp @@ -0,0 +1,271 @@ +// Copyright (2019-2023) Paul Scherrer Institute + +#include "FPGAAcquisitionDevice.h" +#include +#include + +void FPGAAcquisitionDevice::StartSendingWorkRequests() { + stop_work_requests = false; + send_work_request_future = std::async(std::launch::async, &FPGAAcquisitionDevice::SendWorkRequestThread, this); +} + +void FPGAAcquisitionDevice::Finalize() { + read_work_completion_future.get(); + + stop_work_requests = true; + send_work_request_future.get(); + + FPGA_EndAction(); + + while (!HW_IsIdle()) + std::this_thread::sleep_for(std::chrono::milliseconds(1)); +} + +void FPGAAcquisitionDevice::ReadWorkCompletionThread() { + uint32_t values[16]; + + Completion c{}; + bool quit_loop = false; + do { + while (!HW_ReadMailbox(values)) + std::this_thread::sleep_for(std::chrono::microseconds(10)); + + c = parse_hw_completion(values); + if (c.data_collection_id == data_collection_id) { + work_completion_queue.PutBlocking(c); + if (c.type == Completion::Type::End) + quit_loop = true; + } + } while (!quit_loop); +} + +void FPGAAcquisitionDevice::SendWorkRequestThread() { + while (!stop_work_requests) { + WorkRequest wr{}; + if (work_request_queue.Get(wr)) { + if ( !HW_SendWorkRequest(wr.handle)) { + work_request_queue.Put(wr); + std::this_thread::sleep_for(std::chrono::microseconds(10)); + } + } else { + std::this_thread::sleep_for(std::chrono::microseconds(10)); + } + } +} + +void FPGAAcquisitionDevice::InitializeCalibration(const DiffractionExperiment &experiment, const JFCalibration &calib) { + auto offset = experiment.GetFirstModuleOfDataStream(data_stream); + + if (calib.GetModulesNum() != experiment.GetModulesNum()) + throw JFJochException(JFJochExceptionCategory::InputParameterInvalid, + "Mismatch regarding module count in calibration and experiment description"); + + if (calib.GetStorageCellNum() != experiment.GetStorageCellNumber()) + throw JFJochException(JFJochExceptionCategory::InputParameterInvalid, + "Mismatch regarding storage cell count in calibration and experiment description"); + + size_t modules = experiment.GetModulesNum(data_stream); + size_t storage_cells = experiment.GetStorageCellNumber(); + + if (modules * (3 + 3 * storage_cells) > buffer_device.size()) + throw JFJochException(JFJochExceptionCategory::InputParameterInvalid, + "Not enough host/FPGA buffers to load all calibration constants"); + + for (int m = 0; m < modules; m++) { + calib.GainCalibration(m).ExportG0(buffer_device[m]); + calib.GainCalibration(m).ExportG1(buffer_device[m + modules]); + calib.GainCalibration(m).ExportG2(buffer_device[m + modules * 2]); + } + + for (int s = 0; s < storage_cells; s++) { + auto mask = calib.CalculateMask(experiment, s); + for (int m = 0; m < modules; m++) { + auto pedestal_g0 = calib.Pedestal(offset + m, 0, s).GetPedestal(); + auto pedestal_g1 = calib.Pedestal(offset + m, 1, s).GetPedestal(); + auto pedestal_g2 = calib.Pedestal(offset + m, 2, s).GetPedestal(); + for (int i = 0; i < RAW_MODULE_SIZE; i++) { + if (experiment.GetApplyPixelMaskInFPGA() && (mask[(offset + m) * RAW_MODULE_SIZE + i] != 0)) { + buffer_device[(3 + 0 * storage_cells + s) * modules + m][i] = 16384; + buffer_device[(3 + 1 * storage_cells + s) * modules + m][i] = 16384; + buffer_device[(3 + 2 * storage_cells + s) * modules + m][i] = 16384; + } else { + buffer_device[(3 + 0 * storage_cells + s) * modules + m][i] = pedestal_g0[i]; + buffer_device[(3 + 1 * storage_cells + s) * modules + m][i] = pedestal_g1[i]; + buffer_device[(3 + 2 * storage_cells + s) * modules + m][i] = pedestal_g2[i]; + } + } + + } + } + HW_LoadCalibration(modules, storage_cells); +} + + +void FPGAAcquisitionDevice::FillActionRegister(const DiffractionExperiment& x, ActionConfig &job) { + std::random_device rd; + std::uniform_int_distribution dist; + data_collection_id = dist(rd); + + job.nmodules = x.GetModulesNum(data_stream); + job.nframes = x.GetFrameNum(); + job.one_over_energy = std::lround((1<<20)/ x.GetPhotonEnergy_keV()); + job.nstorage_cells = x.GetStorageCellNumber() - 1; + job.mode = data_collection_id << 16; + + if (fpga_non_blocking_mode) + job.mode |= MODE_NONBLOCKING_ON_WR; + + if ((x.GetDetectorMode() == DetectorMode::Conversion) && x.GetConversionOnFPGA()) + job.mode |= MODE_CONV; +} + + +void FPGAAcquisitionDevice::Start(const DiffractionExperiment &experiment) { + if (!HW_IsIdle()) + throw(JFJochException(JFJochExceptionCategory::AcquisitionDeviceError, + "Hardware action running prior to start of data acquisition")); + ActionConfig cfg_in{}, cfg_out{}; + + FillActionRegister(experiment, cfg_in); + HW_WriteActionRegister(&cfg_in); + HW_ReadActionRegister(&cfg_out); + + if (cfg_out.mode != cfg_in.mode) + throw JFJochException(JFJochExceptionCategory::AcquisitionDeviceError, + "Mismatch between expected and actual values of configuration registers (mode)"); + if (cfg_out.nframes != cfg_in.nframes) + throw JFJochException(JFJochExceptionCategory::AcquisitionDeviceError, + "Mismatch between expected and actual values of configuration registers (Frames per trigger)"); + if (cfg_out.nmodules != cfg_in.nmodules) + throw JFJochException(JFJochExceptionCategory::AcquisitionDeviceError, + "Mismatch between expected and actual values of configuration registers (#modules)"); + + FPGA_StartAction(experiment); + + read_work_completion_future = std::async(std::launch::async, &FPGAAcquisitionDevice::ReadWorkCompletionThread, this); +} + +ActionConfig FPGAAcquisitionDevice::ReadActionRegister() { + ActionConfig cfg{}; + HW_ReadActionRegister(&cfg); + return cfg; +} + +inline void FIFO_check(JFJochProtoBuf::FPGAStatus &fpga_status, + const std::string &name, + uint32_t fifo_register, + uint16_t pos_empty, + uint16_t pos_full) { + auto fifo_status = fpga_status.add_fifo_status(); + fifo_status->set_name(name); + + if (std::bitset<32>(fifo_register).test(pos_empty)) + fifo_status->set_value(JFJochProtoBuf::FPGAFIFOStatusEnum::EMPTY); + else if (std::bitset<32>(fifo_register).test(pos_full)) + fifo_status->set_value(JFJochProtoBuf::FPGAFIFOStatusEnum::FULL); + else + fifo_status->set_value(JFJochProtoBuf::FPGAFIFOStatusEnum::PARTIAL); +} + +inline void CheckHostWriterErr(JFJochProtoBuf::FPGAStatus &output, uint32_t status_register, + uint32_t bit, const std::string &name) { + if (status_register & (1 << (24+bit))) + output.add_host_writer_err(name); +} + +JFJochProtoBuf::FPGAStatus FPGAAcquisitionDevice::GetStatus() const { + + ActionStatus status{}; + ActionEnvParams env{}; + + HW_GetStatus(&status); + HW_GetEnvParams(&env); + + JFJochProtoBuf::FPGAStatus ret; + auto full_status_register = status.ctrl_reg; + ret.set_full_status_register(full_status_register); + + ret.set_stalls_hbm(status.pipeline_stalls_hbm); + ret.set_stalls_host(status.pipeline_stalls_host); + + ret.set_max_modules(status.max_modules); + ret.set_git_sha1(status.git_sha1); + ret.set_hbm_size_bytes(status.hbm_size_bytes); + + FIFO_check(ret, "UDP", status.fifo_status, 6, 7); + FIFO_check(ret, "Conversion input (data)", status.fifo_status, 0, 1); + FIFO_check(ret, "Conversion input (cmd)", status.fifo_status, 2, 3); + FIFO_check(ret, "Work Request", status.fifo_status, 12, 13); + FIFO_check(ret, "Work Completion", status.fifo_status, 14, 15); + FIFO_check(ret, "Writer input (data)", status.fifo_status, 16, 17); + FIFO_check(ret, "Writer input (cmd)", status.fifo_status, 18, 19); + FIFO_check(ret, "C2H (data)", status.fifo_status, 8, 9); + FIFO_check(ret, "C2H (cmd)", status.fifo_status, 10, 11); + FIFO_check(ret, "H2C (data)", status.fifo_status, 20, 21); + FIFO_check(ret, "H2C (cmd)", status.fifo_status, 22, 23); + + ret.set_fpga_idle(HW_IsIdle()); + + ret.set_packets_ether(status.packets_eth); + ret.set_packets_udp(status.packets_udp); + ret.set_packets_icmp(status.packets_icmp); + ret.set_packets_jfjoch(status.packets_processed); + ret.set_packets_sls(status.packets_sls); + ret.set_error_eth(status.udp_err_eth); + ret.set_error_packet_len(status.udp_err_len); + ret.set_cancel_bit(full_status_register & (1<<2)); + ret.set_host_writer_idle(full_status_register & (1<<4)); + CheckHostWriterErr(ret, full_status_register, 0, "Alignment error"); + CheckHostWriterErr(ret, full_status_register, 1, "TLAST error"); + CheckHostWriterErr(ret, full_status_register, 2, "Work request parity error"); + CheckHostWriterErr(ret, full_status_register, 3, "Handle error"); + CheckHostWriterErr(ret, full_status_register, 4, "Null pointer"); + CheckHostWriterErr(ret, full_status_register, 5, "Module number exceeded"); + + ret.set_mailbox_status_reg(env.mailbox_status_reg); + ret.set_mailbox_err_reg(env.mailbox_err_reg); + + ret.set_fpga_temp_degc(env.fpga_temp_C); + + ret.set_current_edge_12v_a(static_cast(env.fpga_pcie_12V_I_mA) / 1000.0); + ret.set_voltage_edge_12v_v(static_cast(env.fpga_pcie_12V_V_mV) / 1000.0); + + ret.set_current_edge_3p3v_a(static_cast(env.fpga_pcie_3p3V_I_mA) / 1000.0); + ret.set_voltage_edge_3p3v_v(static_cast(env.fpga_pcie_3p3V_V_mV) / 1000.0); + + ret.set_pcie_c2h_beats(env.pcie_c2h_beats); + ret.set_pcie_h2c_beats(env.pcie_h2c_beats); + ret.set_pcie_c2h_descriptors(env.pcie_c2h_descriptors); + ret.set_pcie_h2c_descriptors(env.pcie_h2c_descriptors); + ret.set_pcie_c2h_status(env.pcie_c2h_status); + ret.set_pcie_h2c_status(env.pcie_h2c_status); + + ret.set_ethernet_rx_aligned(env.ethernet_aligned); + ret.set_hbm_temp_0_degc(env.hbm_0_temp_C); + ret.set_hbm_temp_1_degc(env.hbm_1_temp_C); + ret.set_slowest_head(counters.GetSlowestHead()); + return ret; +} + +void FPGAAcquisitionDevice::SetFPGANonBlockingMode(bool input) { + fpga_non_blocking_mode = input; +} + +void FPGAAcquisitionDevice::SetCustomInternalGeneratorFrame(const std::vector &v) { + if (v.size() != RAW_MODULE_SIZE) + throw JFJochException(JFJochExceptionCategory::InputParameterInvalid, + "Error in size of custom internal generator frame"); + for (int i = 0; i < RAW_MODULE_SIZE; i++) + internal_pkt_gen_frame[i] = v[i]; +} + +std::vector FPGAAcquisitionDevice::GetInternalGeneratorFrame() const { + return internal_pkt_gen_frame; +} + +FPGAAcquisitionDevice::FPGAAcquisitionDevice(uint16_t data_stream) +: AcquisitionDevice(data_stream), +internal_pkt_gen_frame(RAW_MODULE_SIZE) { + for (int i = 0; i < RAW_MODULE_SIZE; i++) + internal_pkt_gen_frame[i] = i % 65536; +} \ No newline at end of file diff --git a/receiver/FPGAAcquisitionDevice.h b/receiver/FPGAAcquisitionDevice.h new file mode 100644 index 00000000..0826d1ed --- /dev/null +++ b/receiver/FPGAAcquisitionDevice.h @@ -0,0 +1,52 @@ +// Copyright (2019-2023) Paul Scherrer Institute + +#ifndef JUNGFRAUJOCH_FPGAACQUISITIONDEVICE_H +#define JUNGFRAUJOCH_FPGAACQUISITIONDEVICE_H + +#include "AcquisitionDevice.h" +#include "../fpga/pcie_driver/ActionConfig.h" + +class FPGAAcquisitionDevice : public AcquisitionDevice { + uint16_t data_collection_id = 0; + bool fpga_non_blocking_mode = true; + + virtual void FPGA_StartAction(const DiffractionExperiment &experiment) = 0; + virtual void FPGA_EndAction() = 0; + + virtual void HW_WriteActionRegister(const ActionConfig *job) = 0; + virtual void HW_ReadActionRegister(ActionConfig *job) = 0; + virtual bool HW_IsIdle() const = 0; + void FillActionRegister(const DiffractionExperiment& x, ActionConfig& job); + + void Finalize() final; + + std::future read_work_completion_future; + void ReadWorkCompletionThread(); + + std::future send_work_request_future; + volatile bool stop_work_requests = false; + void SendWorkRequestThread(); + + virtual void HW_LoadCalibration(uint32_t modules, uint32_t storage_cells) = 0; + virtual bool HW_ReadMailbox(uint32_t values[16]) = 0; + virtual bool HW_SendWorkRequest(uint32_t handle) = 0; + void StartSendingWorkRequests() override; + void Start(const DiffractionExperiment &experiment) override; +protected: + std::vector internal_pkt_gen_frame; + explicit FPGAAcquisitionDevice(uint16_t data_stream); + virtual void HW_GetStatus(ActionStatus *status) const = 0; + virtual void HW_GetEnvParams(ActionEnvParams *status) const { + memset(status, 0, sizeof(ActionEnvParams)); + } +public: + ActionConfig ReadActionRegister(); + JFJochProtoBuf::FPGAStatus GetStatus() const override; + void InitializeCalibration(const DiffractionExperiment &experiment, const JFCalibration &calib) override; + + void SetFPGANonBlockingMode(bool input); + void SetCustomInternalGeneratorFrame(const std::vector &v); + std::vector GetInternalGeneratorFrame() const override; +}; + +#endif //JUNGFRAUJOCH_FPGAACQUISITIONDEVICE_H diff --git a/receiver/host/HLSSimulatedDevice.cpp b/receiver/HLSSimulatedDevice.cpp similarity index 70% rename from receiver/host/HLSSimulatedDevice.cpp rename to receiver/HLSSimulatedDevice.cpp index fe7a50c0..53127bd9 100644 --- a/receiver/host/HLSSimulatedDevice.cpp +++ b/receiver/HLSSimulatedDevice.cpp @@ -1,11 +1,11 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (2019-2023) Paul Scherrer Institute #include "HLSSimulatedDevice.h" #include #include -#include "datamover_model.h" +#include "../fpga/hls/datamover_model.h" +#include "../fpga/hls/hls_jfjoch.h" uint16_t checksum(const uint16_t *addr, size_t count) { /* Compute Internet Checksum for "count" bytes @@ -31,23 +31,14 @@ HLSSimulatedDevice::HLSSimulatedDevice(uint16_t data_stream, size_t in_frame_buf : FPGAAcquisitionDevice(data_stream), datamover_in(Direction::Input), datamover_out(Direction::Output, nullptr, 256), - idle(true) { + idle(true), hbm(hbm_if_size / 32 * hbm_if_count) { + mac_addr = 0xCCAA11223344; + ipv4_addr = 0x0132010A; max_modules = MAX_MODULES_FPGA; MapBuffersStandard(in_frame_buffer_size_modules, (3 + 3 * 16) * max_modules + 2, numa_node); - - auto in_mem_location32 = (uint32_t *) in_mem_location; - - for (int i = 0; i < max_modules * (3 + 3 * 16) + 2; i++) { - in_mem_location32[2 * i ] = ((uint64_t) buffer_device[i]) & UINT32_MAX; - in_mem_location32[2 * i + 1] = ((uint64_t) buffer_device[i]) >> 32; - } - - for (auto &i: hbm_memory) - // i.resize(SIZE_OF_HBM_BLOCK_IN_BYTES); - i.resize(32*1024*1024); // only 32 MiB instead of 256 MiB per HBM interface (should be more than enough for all the tests anyway) } void HLSSimulatedDevice::CreateFinalPacket(const DiffractionExperiment& experiment) { @@ -79,7 +70,7 @@ void HLSSimulatedDevice::CreatePacketJF(const DiffractionExperiment& experiment, packet->ether_type = htons(0x0800); packet->sour_mac[0] = 0x00; // module 0 - uint64_t tmp_mac = fpga_mac_addr; + uint64_t tmp_mac = mac_addr; for (int i = 0; i < 6; i++) packet->dest_mac[i] = (tmp_mac >> (8*i)) % 256; @@ -87,7 +78,7 @@ void HLSSimulatedDevice::CreatePacketJF(const DiffractionExperiment& experiment, packet->ipv4_header_h = htons(0x4500); // Big endian in IP header! packet->ipv4_header_total_length = htons(8268); // Big endian in IP header! - packet->ipv4_header_dest_ip = fpga_ipv4_addr; + packet->ipv4_header_dest_ip = ipv4_addr; packet->ipv4_header_sour_ip = experiment.GetSrcIPv4Address(data_stream, half_module); packet->ipv4_header_ttl_protocol = htons(0x0011); @@ -135,13 +126,26 @@ void HLSSimulatedDevice::HW_WriteActionRegister(const ActionConfig *job) { memcpy(&cfg, job, sizeof(ActionConfig)); } -void HLSSimulatedDevice::FPGA_StartAction() { +void HLSSimulatedDevice::FPGA_StartAction(const DiffractionExperiment &experiment) { if (action_thread.joinable()) action_thread.join(); run_data_collection = 1; cancel_data_collection = 0; idle = false; + if (experiment.IsUsingInternalPacketGen()) { + frame_generator(din_frame_generator, + reinterpret_cast *>(internal_pkt_gen_frame.data()), + experiment.GetFrameNum() + DELAY_FRAMES_STOP_AND_QUIT + 1, + experiment.GetModulesNum(data_stream), + mac_addr, + mac_addr, + ipv4_addr, + ipv4_addr, + INT_PKT_GEN_BUNCHID, + INT_PKT_GEN_EXPTTIME, + INT_PKT_GEN_DEBUG); + } action_thread = std::thread(&HLSSimulatedDevice::HLSMainThread, this ); } @@ -165,7 +169,7 @@ bool HLSSimulatedDevice::HW_ReadMailbox(uint32_t values[16]) { return true; } -void HLSSimulatedDevice::HW_SetCancelDataCollectionBit() { +void HLSSimulatedDevice::Cancel() { cancel_data_collection = 1; } @@ -203,55 +207,54 @@ void HLSSimulatedDevice::HLSMainThread() { STREAM_512 ip1, udp1, udp2, icmp1, arp1; + STREAM_512 network0; + STREAM_512 raw0; STREAM_512 raw1; STREAM_512 raw2; STREAM_512 raw3; - STREAM_512 raw4; - - hls::stream > pedestalG0_subtracted; STREAM_512 converted_1; STREAM_512 converted_2; - hls::stream > addr0; - hls::stream > addr1; - hls::stream > addr2; - hls::stream > addr3; + hls::stream addr0; + hls::stream addr1; + hls::stream addr2; + hls::stream addr3; hls::stream > udp_metadata; ap_uint<1> idle_data_collection; ap_uint<8> err_reg; - std::vector> d_uram_p0(MAX_MODULES_FPGA * RAW_MODULE_SIZE / 32); - std::vector> d_uram_p1(MAX_MODULES_FPGA * RAW_MODULE_SIZE / 32); + while ((!din_eth.empty()) || (!din_frame_generator.empty())) + stream_merge(din_eth, din_frame_generator, network0); - while(!din_eth.empty()) - ethernet(din_eth, ip1, arp1, fpga_mac_addr, eth_packets, clear_counters); + while(!network0.empty()) + ethernet(network0, ip1, arp1, mac_addr, eth_packets, clear_counters); while(!ip1.empty()) - ipv4(ip1, udp1, icmp1, fpga_ipv4_addr); + ipv4(ip1, udp1, icmp1, ipv4_addr); arp(arp1, dout_eth, - fpga_mac_addr, - fpga_ipv4_addr, + mac_addr, + ipv4_addr, 1, run_data_collection); while (!arp1.empty()) { arp(arp1, dout_eth, - fpga_mac_addr, - fpga_ipv4_addr, + mac_addr, + ipv4_addr, 1, run_data_collection); } // reset static counter arp(arp1, dout_eth, - fpga_mac_addr, - fpga_ipv4_addr, + mac_addr, + ipv4_addr, 0, run_data_collection); while(!icmp1.empty()) @@ -266,7 +269,7 @@ void HLSSimulatedDevice::HLSMainThread() { // 1. Parse incoming UDP packets idle_data_collection = 0; hls_cores.emplace_back([&] { - while (idle_data_collection == 0) { + while ((idle_data_collection == 0) || (!raw0.empty())) { data_collection_fsm(raw0, raw1, addr0, addr1, run_data_collection, @@ -276,40 +279,39 @@ void HLSSimulatedDevice::HLSMainThread() { cfg.one_over_energy, cfg.nframes, cfg.nmodules, - cfg.nstorage_cells); + cfg.nstorage_cells, + hbm_if_size); run_data_collection = 0; } }); - // Load external calibration - hls_cores.emplace_back([&] { load_calibration(raw1, raw2, datamover_in.GetCtrlStream(), datamover_in.GetDataStream(), - in_mem_location); }); - - // Generate internal packets - hls_cores.emplace_back([&] { internal_packet_generator(raw2, raw3, addr1, addr2, cancel_data_collection); }); - // Timer procedure - count how many times pedestal_corr/gain_corr is not accepting input (to help track down latency issues) - hls_cores.emplace_back([&] { timer_hbm(raw3, raw4, counter_hbm); }); + hls_cores.emplace_back([&] { timer_host(raw1, raw2, counter_hbm); }); // 2. Apply pedestal & gain corrections - hls_cores.emplace_back([&] { jf_conversion(raw4, converted_1, - addr2, addr3, - d_uram_p0.data(), d_uram_p1.data(), - (hbm256_t *) (hbm_memory[0].data()), (hbm256_t *) (hbm_memory[1].data()), - (hbm256_t *) (hbm_memory[2].data()), (hbm256_t *) (hbm_memory[3].data()), - (hbm256_t *) (hbm_memory[4].data()), (hbm256_t *) (hbm_memory[5].data()), - (hbm256_t *) (hbm_memory[6].data()), (hbm256_t *) (hbm_memory[7].data()), - (hbm256_t *) (hbm_memory[8].data()), (hbm256_t *) (hbm_memory[9].data())); }); + hls_cores.emplace_back([&] { jf_conversion(raw2, converted_1, + addr1, addr2, + hbm.data(), + hbm.data(), + hbm.data(), + hbm.data(), + hbm.data(), + hbm.data(), + hbm.data(), + hbm.data(), + hbm.data(), + hbm.data(), + hbm.data(), + hbm.data()); }); // Timer procedure - count how many times write_data is not accepting input (to help track down latency issues) hls_cores.emplace_back([&] { timer_host(converted_1, converted_2, counter_host); }); - // 3. Prepare data to write to host memory hls_cores.emplace_back([&] { - host_writer(converted_2, addr3, datamover_out.GetDataStream(), + host_writer(converted_2, addr2, datamover_out.GetDataStream(), datamover_out.GetCtrlStream(), work_request_stream, completion_stream, - packets_processed, err_reg); }); + packets_processed, host_writer_idle, err_reg); }); for (auto &i : hls_cores) i.join(); @@ -335,12 +337,6 @@ void HLSSimulatedDevice::HLSMainThread() { if (!raw3.empty()) throw std::runtime_error("Raw3 queue not empty"); - if (!raw4.empty()) - throw std::runtime_error("Raw4 queue not empty"); - - if (!pedestalG0_subtracted.empty()) - throw std::runtime_error("PedestalG0_subtracted queue not empty"); - if (!converted_1.empty()) throw std::runtime_error("Converted_1 queue not empty"); @@ -350,29 +346,50 @@ void HLSSimulatedDevice::HLSMainThread() { if (!datamover_in.GetDataStream().empty()) throw std::runtime_error("Datamover queue is not empty"); - if (!work_request_stream.empty()) - throw std::runtime_error("Work request stream is not empty"); - - if (err_reg != 0) + if (err_reg != 0) throw std::runtime_error("Error reg for frame_statistics not zero, val=" + std::to_string(err_reg)); while (!datamover_out.IsIdle()) std::this_thread::sleep_for(std::chrono::milliseconds(100)); + if (logger) + logger->Info("Packets Eth {} UDP {} SLS {} Proc {}", eth_packets, udp_packets, sls_packets, packets_processed); + idle = true; } -uint32_t HLSSimulatedDevice::HW_GetIPv4Address() const { - return fpga_ipv4_addr; -} - -uint64_t HLSSimulatedDevice::HW_GetMACAddress() const { - return fpga_mac_addr; -} - void HLSSimulatedDevice::HW_GetStatus(ActionStatus *status) const { memset(status, 0, sizeof(ActionStatus)); + status->ctrl_reg = ap_uint<1>(host_writer_idle) ? (1 << 4) : 0; status->modules_internal_packet_generator = 1; status->max_modules = max_modules; + status->hbm_size_bytes = hbm_if_size; +} + +void HLSSimulatedDevice::HW_LoadCalibration(uint32_t modules, uint32_t storage_cells) { + + if (logger) + logger->Info("Load calibration start"); + + auto in_mem_location32 = (uint32_t *) calibration_addr_bram; + + for (int i = 0; i < modules * (3 + 3 * storage_cells); i++) { + in_mem_location32[2 * i ] = ((uint64_t) buffer_device[i]) & UINT32_MAX; + in_mem_location32[2 * i + 1] = ((uint64_t) buffer_device[i]) >> 32; + } + + load_calibration(hbm.data(), + hbm.data(), + modules, + storage_cells, + hbm_if_size, + datamover_in.GetCtrlStream(), + datamover_in.GetDataStream(), + calibration_addr_bram); + if (logger) + logger->Info("Load calibration done"); + + if (!datamover_in.GetDataStream().empty()) + throw std::runtime_error("Datamover queue is not empty"); } \ No newline at end of file diff --git a/receiver/host/HLSSimulatedDevice.h b/receiver/HLSSimulatedDevice.h similarity index 69% rename from receiver/host/HLSSimulatedDevice.h rename to receiver/HLSSimulatedDevice.h index fd1fcf38..7f323bc6 100644 --- a/receiver/host/HLSSimulatedDevice.h +++ b/receiver/HLSSimulatedDevice.h @@ -1,28 +1,30 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (2019-2023) Paul Scherrer Institute #ifndef JUNGFRAUJOCH_HLSSIMULATEDDEVICE_H #define JUNGFRAUJOCH_HLSSIMULATEDDEVICE_H #include -#include "datamover_model.h" -#include "../../common/DiffractionExperiment.h" +#include "../fpga/hls/hls_jfjoch.h" +#include "../fpga/hls/datamover_model.h" +#include "../common/DiffractionExperiment.h" #include "FPGAAcquisitionDevice.h" -#include "../../jungfrau/jf_packet.h" - - +#include "../jungfrau/jf_packet.h" uint16_t checksum(const uint16_t *addr, size_t count); class HLSSimulatedDevice : public FPGAAcquisitionDevice { AXI_STREAM din_eth; + AXI_STREAM din_frame_generator; AXI_STREAM dout_eth; ActionConfig cfg; volatile bool idle; - std::vector hbm_memory[10]; + + constexpr static const size_t hbm_if_count = 16; + constexpr static const size_t hbm_if_size = 32*1024*1024LU; + std::vector> hbm; hls::stream > work_request_stream; hls::stream > completion_stream; @@ -32,23 +34,22 @@ class HLSSimulatedDevice : public FPGAAcquisitionDevice { Datamover<512> datamover_out; ap_uint<1> run_data_collection; ap_uint<1> cancel_data_collection; - uint64_t in_mem_location[LOAD_CALIBRATION_BRAM_SIZE]; - static const uint64_t fpga_mac_addr = 0xCCAA11223344; - static const uint32_t fpga_ipv4_addr = 0x0132010A; + volatile ap_uint<1> host_writer_idle; + + uint64_t calibration_addr_bram[LOAD_CALIBRATION_BRAM_SIZE]; void HW_ReadActionRegister(ActionConfig *job) override; void HW_WriteActionRegister(const ActionConfig *job) override; - void FPGA_StartAction() override; + void FPGA_StartAction(const DiffractionExperiment &experiment) override; void FPGA_EndAction() override; bool HW_IsIdle() const override; - bool HW_ReadMailbox(uint32_t values[16]); - void HW_SetCancelDataCollectionBit() override; + bool HW_ReadMailbox(uint32_t values[16]) override; bool HW_SendWorkRequest(uint32_t handle) override; - uint64_t HW_GetMACAddress() const override; - uint32_t HW_GetIPv4Address() const override; + void HW_LoadCalibration(uint32_t modules, uint32_t storage_cells) override; void HW_GetStatus(ActionStatus *status) const override; void HLSMainThread() ; + void RunFrameGenerator(const FrameGeneratorConfig& config); public: HLSSimulatedDevice(uint16_t data_stream, size_t in_frame_buffer_size_modules, int16_t numa_node = -1); ~HLSSimulatedDevice(); @@ -61,6 +62,7 @@ public: uint8_t user = 0); void CreateFinalPacket(const DiffractionExperiment& experiment); AXI_STREAM &OutputStream(); + void Cancel() override; }; diff --git a/receiver/host/IBWrappers.cpp b/receiver/IBWrappers.cpp similarity index 98% rename from receiver/host/IBWrappers.cpp rename to receiver/IBWrappers.cpp index b09e35a6..89843163 100644 --- a/receiver/host/IBWrappers.cpp +++ b/receiver/IBWrappers.cpp @@ -1,5 +1,4 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (2019-2023) Paul Scherrer Institute #ifdef JFJOCH_USE_IBVERBS @@ -13,7 +12,7 @@ #endif #include "IBWrappers.h" -#include "../../common/JFJochException.h" +#include "../common/JFJochException.h" IBContext::IBContext(const std::string &dev_name) { struct ibv_device **dev_list; diff --git a/receiver/host/IBWrappers.h b/receiver/IBWrappers.h similarity index 95% rename from receiver/host/IBWrappers.h rename to receiver/IBWrappers.h index 902b0777..99b9e692 100644 --- a/receiver/host/IBWrappers.h +++ b/receiver/IBWrappers.h @@ -1,5 +1,4 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (2019-2023) Paul Scherrer Institute #ifdef JFJOCH_USE_IBVERBS #ifndef JUNGFRAUJOCH_IBWRAPPERS_H diff --git a/receiver/JFJochReceiver.cpp b/receiver/JFJochReceiver.cpp index e6b29941..7e4c6715 100644 --- a/receiver/JFJochReceiver.cpp +++ b/receiver/JFJochReceiver.cpp @@ -1,5 +1,4 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (2019-2023) Paul Scherrer Institute #include "JFJochReceiver.h" @@ -8,10 +7,7 @@ #include "../image_analysis/GPUImageAnalysis.h" #include "../jungfrau/JFPedestalCalc.h" #include "../image_analysis/IndexerWrapper.h" - -#ifdef JFJOCH_USE_NUMA -#include -#endif +#include "../common/DiffractionGeometry.h" inline std::string time_UTC(const std::chrono::time_point &input) { auto time_ms = std::chrono::duration_cast(input.time_since_epoch()).count(); @@ -29,7 +25,8 @@ JFJochReceiver::JFJochReceiver(const JFJochProtoBuf::ReceiverInput &settings, Logger &in_logger, int64_t in_forward_and_sum_nthreads, int64_t in_send_buffer_count, ZMQPreviewPublisher* in_preview_publisher, - ZMQPreviewPublisher* in_preview_publisher_indexed) : + ZMQPreviewPublisher* in_preview_publisher_indexed, + const NUMAHWPolicy &in_numa_policy) : experiment(settings.jungfraujoch_settings()), acquisition_device(in_aq_device), logger(in_logger), @@ -42,155 +39,218 @@ JFJochReceiver::JFJochReceiver(const JFJochProtoBuf::ReceiverInput &settings, data_acquisition_ready(ndatastreams), frame_transformation_ready((experiment.GetImageNum() > 0) ? frame_transformation_nthreads : 0), send_buffer_count(in_send_buffer_count), - send_buffer(send_buffer_size * send_buffer_count), - indexing_solution_per_file(experiment.GetDataFileCount()) + indexing_solution_per_file(experiment.GetDataFileCount()), + numa_policy(in_numa_policy) { - if (settings.has_calibration()) { - calib.emplace(settings.calibration()); - one_byte_mask = calib->CalculateOneByteMask(experiment); - } else { - one_byte_mask.resize(experiment.GetPixelsNum()); - for (auto &i: one_byte_mask) i = 1; - } + send_buffer = (uint8_t *) malloc(send_buffer_size * send_buffer_count); - for (uint32_t i = 0; i < send_buffer_count; i++) { - send_buffer_avail.Put(i); - send_buffer_zero_copy_ret_val.emplace_back(send_buffer_avail, i); - } - - if (experiment.GetConversionOnCPU()) - PrepareConversionOnCPU(); - - if (!experiment.CheckGitSha1Consistent()) - logger.Warning(experiment.CheckGitSha1Msg()); - - push_images_to_writer = (experiment.GetImageNum() > 0) && (!experiment.GetFilePrefix().empty()); - - if (acquisition_device.size() < ndatastreams) - throw JFJochException(JFJochExceptionCategory::InputParameterInvalid, - "Number of acquisition devices has to match data streams"); - if (frame_transformation_nthreads <= 0) - throw JFJochException(JFJochExceptionCategory::InputParameterInvalid, - "Number of threads must be more than zero"); - - preview_stride = experiment.GetPreviewStride(); - spotfinder_stride = experiment.GetSpotFindingStride(); - - logger.Info("Image stride for data analysis: preview {}, spot finding/radial integration {}", - preview_stride, spotfinder_stride); - if (experiment.GetDetectorMode() == DetectorMode::Conversion) { - if (preview_publisher != nullptr) - preview_publisher->Start(experiment, calib.value()); - if (preview_publisher_indexed != nullptr) - preview_publisher_indexed->Start(experiment, calib.value()); - - if (!GPUImageAnalysis::GPUPresent()) - logger.Info("GPU support missing"); - - rad_int_mapping = std::make_unique(experiment, one_byte_mask.data()); - rad_int_profile = std::make_unique(*rad_int_mapping, experiment); - - for (int i = 0; i < experiment.GetDataFileCount(); i++) - rad_int_profile_per_file.emplace_back(std::make_unique(*rad_int_mapping, experiment)); - - spot_finder_mask = calib->CalculateOneByteMask(experiment); - } - - for (int d = 0; d < ndatastreams; d++) { - if (calib) - acquisition_device[d]->InitializeCalibration(experiment, calib.value()); - acquisition_device[d]->PrepareAction(experiment); - - logger.Debug("Acquisition device {} prepared", d); - } - - for (int d = 0; d < ndatastreams; d++) - data_acquisition_futures.emplace_back(std::async(std::launch::async, &JFJochReceiver::AcquireThread, - this, d)); - - logger.Info("Data acquisition devices ready"); - - if ((experiment.GetDetectorMode() == DetectorMode::PedestalG0) - || (experiment.GetDetectorMode() == DetectorMode::PedestalG1) - || (experiment.GetDetectorMode() == DetectorMode::PedestalG2)) { - - if (experiment.GetImageNum() > 0) { - throw JFJochException(JFJochExceptionCategory::InputParameterInvalid, - "Saving and calculating pedestal is not supported for the time being"); + try { + if (settings.has_calibration()) { + calib.emplace(settings.calibration()); + one_byte_mask = calib->CalculateOneByteMask(experiment); + } else { + one_byte_mask.resize(experiment.GetPixelsNum()); + for (auto &i: one_byte_mask) i = 1; } - if (experiment.GetDetectorMode() == DetectorMode::PedestalG0) { - pedestal_result.resize(experiment.GetModulesNum() * experiment.GetStorageCellNumber()); - for (int s = 0; s < experiment.GetStorageCellNumber(); s++) { + for (uint32_t i = 0; i < send_buffer_count; i++) { + send_buffer_avail.Put(i); + send_buffer_zero_copy_ret_val.emplace_back(send_buffer_avail, i); + } + +#ifndef JFJOCH_RECV_CONVERSION_LOCAL + PrepareConversionOnCPU(fixed_point_conversion); +#endif + + if (!experiment.CheckGitSha1Consistent()) + logger.Warning(experiment.CheckGitSha1Msg()); + + push_images_to_writer = (experiment.GetImageNum() > 0) && (!experiment.GetFilePrefix().empty()); + + if (acquisition_device.size() < ndatastreams) + throw JFJochException(JFJochExceptionCategory::InputParameterInvalid, + "Number of acquisition devices has to match data streams"); + if (frame_transformation_nthreads <= 0) + throw JFJochException(JFJochExceptionCategory::InputParameterInvalid, + "Number of threads must be more than zero"); + + preview_stride = experiment.GetPreviewStride(); + spotfinder_stride = experiment.GetSpotFindingStride(); + + logger.Info("NUMA policy: {}", numa_policy.GetName()); + logger.Info("Image stride for data analysis: preview {}, spot finding/radial integration {}", + preview_stride, spotfinder_stride); + + if (experiment.GetDetectorMode() == DetectorMode::Conversion) { + if (preview_publisher != nullptr) + preview_publisher->Start(experiment, calib.value()); + if (preview_publisher_indexed != nullptr) + preview_publisher_indexed->Start(experiment, calib.value()); + + if (!GPUImageAnalysis::GPUPresent()) + logger.Info("GPU support missing"); + + rad_int_mapping = std::make_unique(experiment, one_byte_mask.data()); + rad_int_profile = std::make_unique(*rad_int_mapping, experiment); + rad_int_corr = CalcRadIntCorr(experiment); + + for (int i = 0; i < experiment.GetDataFileCount(); i++) + rad_int_profile_per_file.emplace_back( + std::make_unique(*rad_int_mapping, experiment)); + + spot_finder_mask = calib->CalculateOneByteMask(experiment); + } + + for (int d = 0; d < ndatastreams; d++) { + if (calib) + acquisition_device[d]->InitializeCalibration(experiment, calib.value()); + acquisition_device[d]->PrepareAction(experiment); + + logger.Debug("Acquisition device {} prepared", d); + } + + for (int d = 0; d < ndatastreams; d++) + data_acquisition_futures.emplace_back(std::async(std::launch::async, &JFJochReceiver::AcquireThread, + this, d)); + + logger.Info("Data acquisition devices ready"); + + if ((experiment.GetDetectorMode() == DetectorMode::PedestalG0) + || (experiment.GetDetectorMode() == DetectorMode::PedestalG1) + || (experiment.GetDetectorMode() == DetectorMode::PedestalG2)) { + + if (experiment.GetImageNum() > 0) { + throw JFJochException(JFJochExceptionCategory::InputParameterInvalid, + "Saving and calculating pedestal is not supported for the time being"); + } + + if (experiment.GetDetectorMode() == DetectorMode::PedestalG0) { + pedestal_result.resize(experiment.GetModulesNum() * experiment.GetStorageCellNumber()); + for (int s = 0; s < experiment.GetStorageCellNumber(); s++) { + for (int d = 0; d < ndatastreams; d++) { + for (int m = 0; m < experiment.GetModulesNum(d); m++) { + auto handle = std::async(std::launch::async, &JFJochReceiver::MeasurePedestalThread, this, + d, m, + s); + frame_transformation_futures.emplace_back(std::move(handle)); + } + } + } + } else { + pedestal_result.resize(experiment.GetModulesNum()); for (int d = 0; d < ndatastreams; d++) { for (int m = 0; m < experiment.GetModulesNum(d); m++) { auto handle = std::async(std::launch::async, &JFJochReceiver::MeasurePedestalThread, this, d, m, - s); + 0); frame_transformation_futures.emplace_back(std::move(handle)); } } } - } else { - pedestal_result.resize(experiment.GetModulesNum()); - for (int d = 0; d < ndatastreams; d++) { - for (int m = 0; m < experiment.GetModulesNum(d); m++) { - auto handle = std::async(std::launch::async, &JFJochReceiver::MeasurePedestalThread, this, d, m, 0); - frame_transformation_futures.emplace_back(std::move(handle)); + + logger.Info("Pedestal threads ready"); + } + + if (experiment.GetImageNum() > 0) { + logger.Info("Data file count {}", experiment.GetDataFileCount()); + + if (push_images_to_writer) { + StartMessage message{}; + experiment.FillMessage(message); + message.arm_date = time_UTC(std::chrono::system_clock::now()); + + JFJochBitShuffleCompressor compressor(CompressionAlgorithm::BSHUF_LZ4); + std::vector pixel_mask; + std::vector > pedestal; + + if (calib) { + size_t xpixel = experiment.GetXPixelsNum(); + size_t ypixel = experiment.GetYPixelsNum(); + + pixel_mask = compressor.Compress(calib->CalculateNexusMask(experiment, 0)); + message.AddPixelMask(CBORImage{ + .data = pixel_mask.data(), + .size = pixel_mask.size(), + .xpixel = (size_t) xpixel, + .ypixel = (size_t) ypixel, + .pixel_depth_bytes = 4, + .pixel_is_signed = false, + .pixel_is_float = false, + .algorithm = CompressionAlgorithm::BSHUF_LZ4, + .channel = "sc0" + }); + if (experiment.GetSaveCalibration()) { + for (int sc = 0; sc < experiment.GetStorageCellNumber(); sc++) { + for (int gain = 0; gain < 3; gain++) { + auto tmp = compressor.Compress(calib->GetPedestal(gain, sc)); + pedestal.emplace_back(tmp); + std::string channel = "pedestal_G" + std::to_string(gain); + + if (experiment.GetStorageCellNumber() > 1) + channel += "_sc" + std::to_string(sc); + + CBORImage image{ + .data = pedestal.at(pedestal.size() - 1).data(), + .size = pedestal.at(pedestal.size() - 1).size(), + .xpixel = (size_t) xpixel, + .ypixel = (size_t) ypixel, + .pixel_depth_bytes = 2, + .pixel_is_signed = false, + .pixel_is_float = false, + .algorithm = CompressionAlgorithm::BSHUF_LZ4, + .channel = channel + }; + + message.AddCalibration(image); + } + } + } } + + if (rad_int_mapping) { + message.rad_int_bin_number = rad_int_mapping->GetBinNumber(); + message.rad_int_bin_to_q = rad_int_mapping->GetBinToQ(); + message.rad_int_solid_angle_corr = rad_int_mapping->GetSolidAngleCorr(); + } else + message.rad_int_bin_number = 0; + + image_pusher.StartDataCollection(message); } + + for (int i = 0; i < experiment.GetImageNum(); i++) + images_to_go.Put(i); + + // Setup frames summation and forwarding + for (int i = 0; i < frame_transformation_nthreads; i++) { + auto handle = std::async(std::launch::async, &JFJochReceiver::FrameTransformationThread, this); + frame_transformation_futures.emplace_back(std::move(handle)); + } + + logger.Info("Image compression/forwarding threads started"); + + frame_transformation_ready.wait(); + logger.Info("Image compression/forwarding threads ready"); } - logger.Info("Pedestal threads ready"); + data_acquisition_ready.wait(); + + logger.Info("Acquisition devices ready"); + + start_time = std::chrono::system_clock::now(); + logger.Info("Receiving data started"); + + measurement = std::async(std::launch::async, &JFJochReceiver::FinalizeMeasurement, this); + } catch (...) { + free(send_buffer); + throw; } - - if (experiment.GetImageNum() > 0) { - logger.Info("Data file count {}", experiment.GetDataFileCount()); - - if (push_images_to_writer) { - StartMessage message{}; - experiment.FillMessage(message); - message.arm_date = time_UTC(std::chrono::system_clock::now()); - - if (calib) - message.pixel_mask["sc0"] = calib->CalculateNexusMask(experiment, 0); - - if (rad_int_mapping) { - message.rad_int_bin_number = rad_int_mapping->GetBinNumber(); - message.rad_int_bin_to_q = rad_int_mapping->GetBinToQ(); - message.rad_int_solid_angle_corr = rad_int_mapping->GetSolidAngleCorr(); - } else - message.rad_int_bin_number = 0; - - image_pusher.StartDataCollection(message); - } - - for (int i = 0; i < experiment.GetImageNum(); i++) - images_to_go.Put(i); - - // Setup frames summation and forwarding - for (int i = 0; i < frame_transformation_nthreads; i++) { - auto handle = std::async(std::launch::async, &JFJochReceiver::FrameTransformationThread, this); - frame_transformation_futures.emplace_back(std::move(handle)); - } - - logger.Info("Image compression/forwarding threads started"); - - frame_transformation_ready.wait(); - logger.Info("Image compression/forwarding threads ready"); - } - - data_acquisition_ready.wait(); - - logger.Info("Acquisition devices ready"); - - start_time = std::chrono::system_clock::now(); - logger.Info("Receiving data started"); - - measurement = std::async(std::launch::async, &JFJochReceiver::FinalizeMeasurement, this); } void JFJochReceiver::AcquireThread(uint16_t data_stream) { - PinThreadToDevice(data_stream); + try { + NUMAHWPolicy::RunOnNode(acquisition_device[data_stream]->GetNUMANode()); + } catch (const JFJochException &e) { + logger.Error("HW bind error {}", e.what()); + } try { frame_transformation_ready.wait(); @@ -209,12 +269,20 @@ void JFJochReceiver::AcquireThread(uint16_t data_stream) { } catch (const JFJochException &e) { Cancel(e); } - + auto status = acquisition_device[data_stream]->GetStatus(); + if (!status.host_writer_err().empty()) { + for (const auto &i: status.host_writer_err()) + logger.Error("Device thread {}: host writer error {}", data_stream, i); + } logger.Info("Device thread {} done", data_stream); } void JFJochReceiver::MeasurePedestalThread(uint16_t data_stream, uint16_t module_number, uint16_t storage_cell) { - PinThreadToDevice(data_stream); + try { + NUMAHWPolicy::RunOnNode(acquisition_device[data_stream]->GetNUMANode()); + } catch (const JFJochException &e) { + logger.Error("HW bind error {}", e.what()); + } JFPedestalCalc pedestal_calc(experiment); @@ -240,19 +308,19 @@ void JFJochReceiver::MeasurePedestalThread(uint16_t data_stream, uint16_t module try { for (size_t frame = staring_frame; frame < experiment.GetFrameNum(); frame += frame_stride) { // Frame will be processed only if one already collects frame+2 - acquisition_device[data_stream]->WaitForFrame(frame + 2, module_number); + acquisition_device[data_stream]->Counters().WaitForFrame(frame + 2, module_number); if (!storage_cell_G1G2 || (frame % 2 == 1)) { // Partial packets will bring more problems, than benefit - if (acquisition_device[data_stream]->IsFullModuleCollected(frame, module_number)) { + if (acquisition_device[data_stream]->Counters().IsFullModuleCollected(frame, module_number)) { pedestal_calc.AnalyzeImage((uint16_t *) acquisition_device[data_stream]->GetFrameBuffer(frame, module_number)); } - auto tmp = acquisition_device[data_stream]->GetJFInfo(frame, module_number); + auto tmp = acquisition_device[data_stream]->Counters().GetCompletion(frame, module_number).debug; storage_cell_header = (tmp >> 8) & 0xF; } acquisition_device[data_stream]->FrameBufferRelease(frame, module_number); - UpdateMaxDelay(acquisition_device[data_stream]->CalculateDelay(frame, module_number)); + UpdateMaxDelay(acquisition_device[data_stream]->Counters().CalculateDelay(frame, module_number)); UpdateMaxImage(frame); } @@ -264,54 +332,73 @@ void JFJochReceiver::MeasurePedestalThread(uint16_t data_stream, uint16_t module pedestal_result[offset].SetCollectionTime(start_time.time_since_epoch().count() / 1e9); } catch (const JFJochException &e) { Cancel(e); } logger.Info("Pedestal calculation thread for data stream {} module {} storage cell {} -> header {} done", - data_stream, module_number, storage_cell, storage_cell_header); + data_stream, module_number, storage_cell, storage_cell_header); } void JFJochReceiver::MiniSummationThread(int d, int m, size_t image_number, bool &send_image, - FrameTransformation &transformation, DataMessage &message) { + FrameTransformation &transformation, DataMessage &message, + std::vector &conversion) { for (int j = 0; j < experiment.GetSummation(); j++) { size_t frame_number = image_number * experiment.GetSummation() + j; - acquisition_device[d]->WaitForFrame(frame_number + 2); + acquisition_device[d]->Counters().WaitForFrame(frame_number + 2); const int16_t *src; - if (acquisition_device[d]->IsFullModuleCollected(frame_number, m)) { + if (acquisition_device[d]->Counters().IsFullModuleCollected(frame_number, m)) { src = acquisition_device[d]->GetFrameBuffer(frame_number, m); if (!send_image) { + Completion c = acquisition_device[d]->Counters().GetCompletion(frame_number, m); // the information is for first module/frame that was collected in full - message.bunch_id = acquisition_device[d]->GetBunchID(frame_number, m); - message.jf_info = acquisition_device[d]->GetJFInfo(frame_number, m); + message.bunch_id = c.bunchid; + message.jf_info = c.debug; message.storage_cell = (message.jf_info >> 8) & 0xF; - message.timestamp = acquisition_device[d]->GetTimestamp(frame_number, m); - message.exptime = acquisition_device[d]->GetExptime(frame_number, m); + message.timestamp = c.timestamp; + message.exptime = c.exptime; } send_image = true; } else src = acquisition_device[d]->GetErrorFrameBuffer(); if (experiment.GetConversionOnCPU()) { - auto &conv = fixed_point_conversion.at(experiment.GetFirstModuleOfDataStream(d) + m); + auto &conv = conversion.at(experiment.GetFirstModuleOfDataStream(d) + m); transformation.ProcessModule(conv, src, m, d); } else transformation.ProcessModule(src, m, d); acquisition_device[d]->FrameBufferRelease(frame_number, m); - UpdateMaxDelay(acquisition_device[d]->CalculateDelay(frame_number, m)); + UpdateMaxDelay(acquisition_device[d]->Counters().CalculateDelay(frame_number, m)); } } void JFJochReceiver::FrameTransformationThread() { - FrameTransformation transformation(experiment); - - std::unique_ptr spot_finder; + std::vector *conversion = nullptr; try { - if (rad_int_mapping) + numa_policy.Bind(); + } catch (const JFJochException &e) { + logger.Error("HW bind error {}", e.what()); + } + +#ifdef JFJOCH_RECV_CONVERSION_LOCAL + std::vector v; + PrepareConversionOnCPU(v); + conversion = &v; +#else + conversion = &fixed_point_conversion; +#endif + + FrameTransformation transformation(experiment); + + std::unique_ptr spot_finder; + + try { + if (rad_int_mapping) { spot_finder = std::make_unique(experiment.GetXPixelsNum(), experiment.GetYPixelsNum(), one_byte_mask, *rad_int_mapping); - else + spot_finder->LoadRadialIntegrationCorr(rad_int_corr); + } else spot_finder = std::make_unique(experiment.GetXPixelsNum(), experiment.GetYPixelsNum(), one_byte_mask); @@ -368,42 +455,43 @@ void JFJochReceiver::FrameTransformationThread() { mini_summation_threads.emplace_back(std::async(std::launch::async, &JFJochReceiver::MiniSummationThread, this, d, m, image_number, std::ref(send_image), std::ref(transformation), - std::ref(message))); + std::ref(message), std::ref(*conversion))); message.receiver_aq_dev_delay = max_delay; } else { for (int j = 0; j < experiment.GetSummation(); j++) { size_t frame_number = image_number * experiment.GetSummation() + j; for (int d = 0; d < ndatastreams; d++) { - acquisition_device[d]->WaitForFrame(frame_number + 2); + acquisition_device[d]->Counters().WaitForFrame(frame_number + 2); for (int m = 0; m < experiment.GetModulesNum(d); m++) { const int16_t *src; - if (acquisition_device[d]->IsFullModuleCollected(frame_number, m)) { + if (acquisition_device[d]->Counters().IsFullModuleCollected(frame_number, m)) { src = acquisition_device[d]->GetFrameBuffer(frame_number, m); if (!send_image) { + Completion c = acquisition_device[d]->Counters().GetCompletion(frame_number, m); // the information is for first module/frame that was collected in full - message.bunch_id = acquisition_device[d]->GetBunchID(frame_number, m); - message.jf_info = acquisition_device[d]->GetJFInfo(frame_number, m); - message.timestamp = acquisition_device[d]->GetTimestamp(frame_number, m); - message.exptime = acquisition_device[d]->GetExptime(frame_number, m); + message.bunch_id = c.bunchid; + message.jf_info = c.debug; message.storage_cell = (message.jf_info >> 8) & 0xF; + message.timestamp = c.timestamp; + message.exptime = c.exptime; } send_image = true; } else src = acquisition_device[d]->GetErrorFrameBuffer(); if (experiment.GetConversionOnCPU()) { - auto &conv = fixed_point_conversion.at(experiment.GetFirstModuleOfDataStream(d) + m); + auto &conv = conversion->at(experiment.GetFirstModuleOfDataStream(d) + m); transformation.ProcessModule(conv, src, m, d); } else transformation.ProcessModule(src, m, d); acquisition_device[d]->FrameBufferRelease(frame_number, m); } - auto delay = acquisition_device[d]->CalculateDelay(frame_number); + auto delay = acquisition_device[d]->Counters().CalculateDelay(frame_number); UpdateMaxDelay(delay); if (delay > message.receiver_aq_dev_delay) message.receiver_aq_dev_delay = delay; @@ -474,7 +562,7 @@ void JFJochReceiver::FrameTransformationThread() { if (image_number % experiment.GetDataFileCount() < rad_int_profile_per_file.size()) rad_int_profile_per_file[image_number % experiment.GetDataFileCount()] ->Add(spot_finder->GetRadialIntegrationSum(), - spot_finder->GetRadialIntegrationCount()); + spot_finder->GetRadialIntegrationCount()); } if (send_preview) @@ -486,7 +574,7 @@ void JFJochReceiver::FrameTransformationThread() { message.receiver_available_send_buffers = GetAvailableSendBuffers(); auto send_buffer_handle = send_buffer_avail.GetBlocking(); - auto ptr = send_buffer.data() + send_buffer_size * send_buffer_handle; + auto ptr = send_buffer + send_buffer_size * send_buffer_handle; JFJochFrameSerializer serializer(ptr, send_buffer_size); PrepareCBORImage(message, experiment, nullptr, 0); serializer.SerializeImage(message); @@ -565,7 +653,7 @@ void JFJochReceiver::Cancel() { cancelled = true; for (int d = 0; d < ndatastreams; d++) - acquisition_device[d]->ActionAbort(); + acquisition_device[d]->Cancel(); } void JFJochReceiver::Cancel(const JFJochException &e) { @@ -575,7 +663,7 @@ void JFJochReceiver::Cancel(const JFJochException &e) { cancelled = true; for (int d = 0; d < ndatastreams; d++) - acquisition_device[d]->ActionAbort(); + acquisition_device[d]->Cancel(); } float JFJochReceiver::GetIndexingRate() const { @@ -612,10 +700,10 @@ void JFJochReceiver::FinalizeMeasurement() { message.write_master_file = true; if (rad_int_profile) - message.rad_int_result["dataset"] = rad_int_profile->GetResult(true); + message.rad_int_result["dataset"] = rad_int_profile->GetResult(); for (int i = 0; i < rad_int_profile_per_file.size(); i++) message.rad_int_result["file" + std::to_string(i)] - = rad_int_profile_per_file[i]->GetResult(true); + = rad_int_profile_per_file[i]->GetResult(); image_pusher.EndDataCollection(message); logger.Info("Disconnected from writers"); @@ -628,7 +716,7 @@ void JFJochReceiver::FinalizeMeasurement() { preview_publisher_indexed->Stop(experiment); for (int d = 0; d < ndatastreams; d++) - acquisition_device[d]->ActionAbort(); + acquisition_device[d]->Cancel(); end_time = std::chrono::system_clock::now(); @@ -658,6 +746,7 @@ void JFJochReceiver::StopReceiver() { JFJochReceiver::~JFJochReceiver() { if (measurement.valid()) measurement.get(); + free(send_buffer); } JFJochProtoBuf::DataProcessingSettings JFJochReceiver::GetDataProcessingSettings() { @@ -674,7 +763,7 @@ JFJochProtoBuf::Plot JFJochReceiver::GetPlots(const JFJochProtoBuf::PlotRequest switch (request.type()) { case JFJochProtoBuf::RAD_INT: if (rad_int_profile) - rad_int_profile->GetPlot(ret, request.solid_angle_correction()); + rad_int_profile->GetPlot(ret); break; case JFJochProtoBuf::SPOT_COUNT: spot_count.GetPlot(ret, nbins); @@ -698,23 +787,25 @@ JFJochProtoBuf::Plot JFJochReceiver::GetPlots(const JFJochProtoBuf::PlotRequest JFJochProtoBuf::RadialIntegrationProfiles JFJochReceiver::GetRadialIntegrationProfiles() { JFJochProtoBuf::RadialIntegrationProfiles ret; - auto &map = *ret.mutable_plots(); - if (rad_int_profile) { - rad_int_profile->GetPlot(map["dataset"], true); - auto &corr = rad_int_profile->GetSolidAngleCorr(); - for (const auto &i: corr) - ret.add_solid_angle_correction(i); + auto p = ret.add_profiles(); + p->set_title("dataset"); + rad_int_profile->GetPlot(*p->mutable_plot()); } - for (int i = 0; i < rad_int_profile_per_file.size(); i++) - rad_int_profile_per_file[i]->GetPlot(map["file" + std::to_string(i)], true); - + for (int i = 0; i < rad_int_profile_per_file.size(); i++) { + auto p = ret.add_profiles(); + p->set_title("file" + std::to_string(i)); + rad_int_profile_per_file[i]->GetPlot(*p->mutable_plot()); + } return ret; } -void JFJochReceiver::PrepareConversionOnCPU() { +void JFJochReceiver::PrepareConversionOnCPU(std::vector &conv) { + if (!experiment.GetConversionOnCPU()) + return; + if (experiment.GetStorageCellNumber() != 1) throw JFJochException(JFJochExceptionCategory::InputParameterInvalid, "CPU conversion currently doesn't support storage cells"); @@ -723,20 +814,13 @@ void JFJochReceiver::PrepareConversionOnCPU() { throw JFJochException(JFJochExceptionCategory::InputParameterInvalid, "Calibration not provided"); - fixed_point_conversion.resize(experiment.GetModulesNum()); + conv.resize(experiment.GetModulesNum()); for (int i = 0 ; i < experiment.GetModulesNum(); i++) - fixed_point_conversion[i].Setup(calib->GainCalibration(i), - calib->Pedestal(i, 0, 0), - calib->Pedestal(i, 1, 0), - calib->Pedestal(i, 2, 0), - experiment.GetPhotonEnergy_keV()); -} - -void JFJochReceiver::PinThreadToDevice(uint16_t data_stream) { -#ifdef JFJOCH_USE_NUMA - if (numa_available() != -1) - numa_run_on_node(acquisition_device[data_stream]->GetNUMANode()); -#endif + conv[i].Setup(calib->GainCalibration(i), + calib->Pedestal(i, 0, 0), + calib->Pedestal(i, 1, 0), + calib->Pedestal(i, 2, 0), + experiment.GetPhotonEnergy_keV()); } void JFJochReceiver::UpdateMaxImage(int64_t image_number) { @@ -753,4 +837,4 @@ void JFJochReceiver::UpdateMaxDelay(int64_t delay) { float JFJochReceiver::GetAvailableSendBuffers() const { return static_cast(send_buffer_avail.Size()) / static_cast(send_buffer_count); -} \ No newline at end of file +} diff --git a/receiver/JFJochReceiver.h b/receiver/JFJochReceiver.h index 5b71608e..680e25cf 100644 --- a/receiver/JFJochReceiver.h +++ b/receiver/JFJochReceiver.h @@ -1,5 +1,4 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (2019-2023) Paul Scherrer Institute #ifndef JUNGFRAUJOCH_JFJOCHRECEIVER_H #define JUNGFRAUJOCH_JFJOCHRECEIVER_H @@ -11,23 +10,24 @@ #include #include +#include "AcquisitionDevice.h" + #include "../common/DiffractionExperiment.h" #include "../common/JFJochException.h" #include "../common/FrameTransformation.h" -#include "../image_analysis/StrongPixelSet.h" -#include "../jungfrau/JFCalibration.h" #include "../common/ImagePusher.h" - -#include "host/AcquisitionDevice.h" #include "../common/Logger.h" #include "../common/ThreadSafeFIFO.h" #include "../common/ZMQPreviewPublisher.h" +#include "../common/NUMAHWPolicy.h" +#include "../common/StatusVector.h" +#include "../common/Histogram.h" +#include "../image_analysis/StrongPixelSet.h" #include "../image_analysis/RadialIntegrationMapping.h" #include "../image_analysis/RadialIntegrationProfile.h" -#include "../common/StatusVector.h" -#include "../common/Histogram.h" +#include "../jungfrau/JFCalibration.h" #include "../jungfrau/JFConversionFixedPoint.h" class JFJochReceiver { @@ -45,6 +45,7 @@ class JFJochReceiver { std::unique_ptr rad_int_mapping; std::unique_ptr rad_int_profile; std::vector> rad_int_profile_per_file; + std::vector rad_int_corr; std::vector spot_finder_mask; @@ -97,16 +98,18 @@ class JFJochReceiver { const size_t send_buffer_count; ThreadSafeFIFO send_buffer_avail; - std::vector send_buffer; + uint8_t *send_buffer; std::vector send_buffer_zero_copy_ret_val; - void PinThreadToDevice(uint16_t data_stream); - void PrepareConversionOnCPU(); + NUMAHWPolicy numa_policy; + + void PrepareConversionOnCPU(std::vector &conv); void AcquireThread(uint16_t data_stream); void FrameTransformationThread(); void MeasurePedestalThread(uint16_t data_stream, uint16_t module_number, uint16_t storage_cell); void MiniSummationThread(int d, int m, size_t image_number, bool &send_image, - FrameTransformation &transformation, DataMessage &message); + FrameTransformation &transformation, DataMessage &message, + std::vector &conversion); void Cancel(const JFJochException &e); void FinalizeMeasurement(); JFJochProtoBuf::DataProcessingSettings GetDataProcessingSettings(); @@ -122,7 +125,8 @@ public: Logger &logger, int64_t forward_and_sum_nthreads, int64_t send_buffer_count, ZMQPreviewPublisher* preview_publisher, - ZMQPreviewPublisher* preview_publisher_indexed); + ZMQPreviewPublisher* preview_publisher_indexed, + const NUMAHWPolicy &numa_policy); ~JFJochReceiver(); JFJochReceiver(const JFJochReceiver &other) = delete; JFJochReceiver& operator=(const JFJochReceiver &other) = delete; diff --git a/receiver/JFJochReceiverService.cpp b/receiver/JFJochReceiverService.cpp index b7263eb5..6eed1ecf 100644 --- a/receiver/JFJochReceiverService.cpp +++ b/receiver/JFJochReceiverService.cpp @@ -1,5 +1,4 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (2019-2023) Paul Scherrer Institute #include "JFJochReceiverService.h" @@ -22,7 +21,8 @@ grpc::Status JFJochReceiverService::Start(grpc::ServerContext *context, const JF receiver.reset(); receiver = std::make_unique(*request, aq_devices, image_pusher, logger, nthreads, send_buffer_count, - preview_publisher, preview_publisher_indexed); + preview_publisher, preview_publisher_indexed, + numa_policy); try { // Don't want to stop receiver->SetDataProcessingSettings(data_processing_settings); @@ -119,6 +119,16 @@ JFJochReceiverService& JFJochReceiverService::PreviewPublisherIndexed(ZMQPreview return *this; } +JFJochReceiverService &JFJochReceiverService::NUMAPolicy(const NUMAHWPolicy &policy) { + numa_policy = policy; + return *this; +} + +JFJochReceiverService &JFJochReceiverService::NUMAPolicy(const std::string &policy) { + numa_policy = NUMAHWPolicy(policy); + return *this; +} + grpc::Status JFJochReceiverService::GetStatus(grpc::ServerContext *context, const JFJochProtoBuf::Empty *request, JFJochProtoBuf::ReceiverStatus *response) { // FPGA status can be polled outside the state mutex @@ -196,4 +206,5 @@ grpc::Status JFJochReceiverService::GetNetworkConfig(grpc::ServerContext *contex dev_net_cfg->set_udp_port(aq->GetUDPPort()); } return grpc::Status::OK; -} \ No newline at end of file +} + diff --git a/receiver/JFJochReceiverService.h b/receiver/JFJochReceiverService.h index abef96ac..da4581b7 100644 --- a/receiver/JFJochReceiverService.h +++ b/receiver/JFJochReceiverService.h @@ -1,14 +1,17 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (2019-2023) Paul Scherrer Institute #ifndef JUNGFRAUJOCH_JFJOCHRECEIVERSERVICE_H #define JUNGFRAUJOCH_JFJOCHRECEIVERSERVICE_H #include "JFJochReceiver.h" #include "jfjoch.grpc.pb.h" + #include +#include "../common/NUMAHWPolicy.h" + class JFJochReceiverService final : public JFJochProtoBuf::gRPC_JFJochReceiver::Service { + NUMAHWPolicy numa_policy; std::unique_ptr receiver; std::vector &aq_devices; @@ -35,6 +38,8 @@ public: JFJochReceiverService& PreviewPublisherIndexed(ZMQPreviewPublisher *in_preview_writer); JFJochReceiverService& NumThreads(int64_t input); JFJochReceiverService& SendBufferCount(int64_t input); + JFJochReceiverService& NUMAPolicy(const NUMAHWPolicy& policy); + JFJochReceiverService& NUMAPolicy(const std::string& policy); grpc::Status Start(grpc::ServerContext* context, const JFJochProtoBuf::ReceiverInput* request, JFJochProtoBuf::Empty* response) override; diff --git a/receiver/JFJochReceiverTest.cpp b/receiver/JFJochReceiverTest.cpp index 664bcb2e..c73de6ac 100644 --- a/receiver/JFJochReceiverTest.cpp +++ b/receiver/JFJochReceiverTest.cpp @@ -1,5 +1,4 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (2019-2023) Paul Scherrer Institute #include "JFJochReceiverTest.h" #include "JFJochReceiverService.h" @@ -12,7 +11,8 @@ JFJochProtoBuf::ReceiverOutput RunJFJochReceiverTest(std::vector> &aq_devices, const DiffractionExperiment &x, uint16_t nthreads, bool abort, - bool verbose, ZMQPreviewPublisher *in_preview_writer) { + bool verbose, ZMQPreviewPublisher *in_preview_writer, + const std::string &numa_policy) { std::vector tmp_aq_devices; for (const auto &i: aq_devices) tmp_aq_devices.emplace_back(i.get()); return JFJochReceiverTest(output, logger, tmp_aq_devices, x, nthreads, - abort, verbose, in_preview_writer); + abort, verbose, in_preview_writer, numa_policy); } static JFCalibration GeneratePedestalCalibration(const DiffractionExperiment &x) { @@ -86,14 +86,17 @@ static JFCalibration GeneratePedestalCalibration(const DiffractionExperiment &x) bool JFJochReceiverTest(JFJochProtoBuf::ReceiverOutput &output, Logger &logger, std::vector &aq_devices, const DiffractionExperiment &x, uint16_t nthreads, bool abort, - bool verbose, ZMQPreviewPublisher *in_preview_writer) { + bool verbose, ZMQPreviewPublisher *in_preview_writer, + const std::string &numa_policy) { std::vector raw_expected_image(RAW_MODULE_SIZE * x.GetModulesNum()); for (int i = 0; i < x.GetDataStreamsNum(); i++) { uint32_t module0 = x.GetFirstModuleOfDataStream(i); for (int m = 0; m < x.GetModulesNum(i); m++) { - memcpy(raw_expected_image.data() + (module0 + m) * RAW_MODULE_SIZE, - aq_devices[i]->GetInternalGeneratorFrame().data(), RAW_MODULE_SIZE * sizeof(uint16_t)); + auto int_gen_frame = aq_devices[i]->GetInternalGeneratorFrame(); + if (int_gen_frame.size() == RAW_MODULE_SIZE) + memcpy(raw_expected_image.data() + (module0 + m) * RAW_MODULE_SIZE, int_gen_frame.data(), + RAW_MODULE_SIZE * sizeof(uint16_t)); } } @@ -110,7 +113,7 @@ bool JFJochReceiverTest(JFJochProtoBuf::ReceiverOutput &output, Logger &logger, TestImagePusher pusher(image_number); output = RunJFJochReceiverTest(aq_devices, pusher, x, logger, calib, nthreads, abort, - in_preview_writer); + in_preview_writer, numa_policy); bool no_errors = true; diff --git a/receiver/JFJochReceiverTest.h b/receiver/JFJochReceiverTest.h index 90aaf6de..23280ecb 100644 --- a/receiver/JFJochReceiverTest.h +++ b/receiver/JFJochReceiverTest.h @@ -1,5 +1,4 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (2019-2023) Paul Scherrer Institute #include "JFJochReceiver.h" @@ -9,16 +8,19 @@ JFJochProtoBuf::ReceiverOutput RunJFJochReceiverTest(std::vector &aq_devices, ImagePusher &pusher, const DiffractionExperiment &x, Logger &logger, JFCalibration &calib, uint16_t nthreads, bool abort = false, - ZMQPreviewPublisher *in_preview_writer = nullptr); + ZMQPreviewPublisher *in_preview_writer = nullptr, + const std::string &numa_policy = ""); bool JFJochReceiverTest(JFJochProtoBuf::ReceiverOutput &output, Logger &logger, std::vector &aq_devices, const DiffractionExperiment &x, uint16_t nthreads, bool abort = false, - bool verbose = true, ZMQPreviewPublisher *in_preview_writer = nullptr); + bool verbose = true, ZMQPreviewPublisher *in_preview_writer = nullptr, + const std::string &numa_policy = ""); bool JFJochReceiverTest(JFJochProtoBuf::ReceiverOutput &output, Logger &logger, std::vector> &aq_devices, const DiffractionExperiment &x, uint16_t nthreads, bool abort = false, - bool verbose = true, ZMQPreviewPublisher *in_preview_writer = nullptr); + bool verbose = true, ZMQPreviewPublisher *in_preview_writer = nullptr, + const std::string &numa_policy = ""); #endif //JUNGFRAUJOCH_JFJOCHRECEIVERTEST_H diff --git a/receiver/host/LinuxSocketDevice.cpp b/receiver/LinuxSocketDevice.cpp similarity index 73% rename from receiver/host/LinuxSocketDevice.cpp rename to receiver/LinuxSocketDevice.cpp index d13c9e71..033c57fe 100644 --- a/receiver/host/LinuxSocketDevice.cpp +++ b/receiver/LinuxSocketDevice.cpp @@ -1,5 +1,4 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (2019-2023) Paul Scherrer Institute #include "LinuxSocketDevice.h" @@ -8,15 +7,14 @@ #include #include -#include "../common/JFJochException.h" - -#define MAX_MODULES 16 +#include "../common/NetworkAddressConvert.h" LinuxSocketDevice::LinuxSocketDevice(uint32_t in_ipv4_addr, uint16_t in_udp_port, uint16_t data_stream, size_t in_frame_buffer_size_modules, int32_t in_rcv_buf_size, int16_t in_numa_node) : - AcquisitionDevice(data_stream), ipv4_addr(in_ipv4_addr), udp_port(in_udp_port), + AcquisitionDevice(data_stream), udp_port(in_udp_port), numa_node(in_numa_node), rcv_buf_size(in_rcv_buf_size) { + ipv4_addr = in_ipv4_addr; max_modules = 16; MapBuffersStandard(in_frame_buffer_size_modules, 1, numa_node); mac_addr = 0; @@ -26,8 +24,6 @@ LinuxSocketDevice::LinuxSocketDevice(uint32_t in_ipv4_addr, uint16_t in_udp_port void LinuxSocketDevice::MeasureThread(int fd) { jf_udp_payload jf{}; - uint64_t packet_count = 0; - work_completion_queue.Put(Completion{ .type = Completion::Type::Start }); @@ -37,10 +33,8 @@ void LinuxSocketDevice::MeasureThread(int fd) { while (!cancel) { auto count = recv(fd, &jf, sizeof(jf_udp_payload), 0); - if (count == sizeof(jf_udp_payload)) { process.ProcessPacket(&jf); - packet_count++; } else if ((count == -1) && (errno != EAGAIN) && (errno != EWOULDBLOCK)) throw JFJochException(JFJochExceptionCategory::UDPError, "Error in UDP receiving"); } @@ -50,23 +44,13 @@ void LinuxSocketDevice::MeasureThread(int fd) { } // End message should be sent always work_completion_queue.Put(Completion{ - .type = Completion::Type::End, - .frame_number = packet_count + .type = Completion::Type::End }); close(fd); - idle = true; } -void LinuxSocketDevice::HW_WriteActionRegister(const ActionConfig *job) { - memcpy(&cfg, job, sizeof(ActionConfig)); -} - -void LinuxSocketDevice::HW_ReadActionRegister(ActionConfig *job) { - memcpy(job, &cfg, sizeof(ActionConfig)); -} - -void LinuxSocketDevice::HW_StartAction() { - if (cfg.mode & MODE_CONV) +void LinuxSocketDevice::Start(const DiffractionExperiment& experiment) { + if (experiment.GetConversionOnFPGA()) throw JFJochException(JFJochExceptionCategory::InputParameterInvalid, "Conversion on CPU flag has to be enabled for Raw Ethernet device"); @@ -96,47 +80,19 @@ void LinuxSocketDevice::HW_StartAction() { throw JFJochException(JFJochExceptionCategory::UDPError, "Cannot bind to UDP port"); cancel = false; - idle = false; measure = std::async(std::launch::async, &LinuxSocketDevice::MeasureThread, this, fd); } -bool LinuxSocketDevice::HW_IsIdle() const { - return idle; -} - -void LinuxSocketDevice::HW_SetCancelDataCollectionBit() { +void LinuxSocketDevice::Cancel() { cancel = true; } -void LinuxSocketDevice::HW_GetStatus(ActionStatus *status) const { - memset(status, 0, sizeof(ActionStatus)); - - status->modules_internal_packet_generator = 1; - status->max_modules = max_modules; -} - -uint64_t LinuxSocketDevice::HW_GetMACAddress() const { - return mac_addr; -} - -uint32_t LinuxSocketDevice::HW_GetIPv4Address() const { - return ipv4_addr; -} - -void LinuxSocketDevice::HW_EndAction() { +void LinuxSocketDevice::Finalize() { if (measure.valid()) measure.get(); } -void LinuxSocketDevice::CopyInternalPacketGenFrameToDeviceBuffer() { - // Do nothing -} - -void LinuxSocketDevice::InitializeCalibration(const DiffractionExperiment &experiment, const JFCalibration &calib) { - // Do nothing -} - int32_t LinuxSocketDevice::GetNUMANode() const { return numa_node; } diff --git a/receiver/LinuxSocketDevice.h b/receiver/LinuxSocketDevice.h new file mode 100644 index 00000000..02ab1516 --- /dev/null +++ b/receiver/LinuxSocketDevice.h @@ -0,0 +1,35 @@ +// Copyright (2019-2023) Paul Scherrer Institute + +#ifndef JUNGFRAUJOCH_LINUXSOCKETDEVICE_H +#define JUNGFRAUJOCH_LINUXSOCKETDEVICE_H + +#include +#include "../jungfrau/ProcessJFPacket.h" +#include "AcquisitionDevice.h" + +class LinuxSocketDevice : public AcquisitionDevice { + int32_t rcv_buf_size; + uint16_t udp_port; + const int16_t numa_node; + + std::future measure; + + volatile bool cancel = false; + + void Start(const DiffractionExperiment& experiment) override; + + void Finalize() override; + void MeasureThread(int fd); + void FindMACAddress(); +public: + LinuxSocketDevice(uint32_t ipv4_addr, uint16_t udp_port, + uint16_t data_stream, size_t frame_buffer_size_modules, + int32_t rcv_buf_size = -1, int16_t in_numa_node = -1); + ~LinuxSocketDevice() override = default; + + int32_t GetNUMANode() const override; + uint16_t GetUDPPort() const override; + void Cancel() override; +}; + +#endif //JUNGFRAUJOCH_LINUXSOCKETDEVICE_H diff --git a/receiver/host/MlxRawEthDevice.cpp b/receiver/MlxRawEthDevice.cpp similarity index 77% rename from receiver/host/MlxRawEthDevice.cpp rename to receiver/MlxRawEthDevice.cpp index 2ddd55e7..835f57c1 100644 --- a/receiver/host/MlxRawEthDevice.cpp +++ b/receiver/MlxRawEthDevice.cpp @@ -1,8 +1,8 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (2019-2023) Paul Scherrer Institute #ifdef JFJOCH_USE_IBVERBS #include "MlxRawEthDevice.h" +#include "../common/NetworkAddressConvert.h" #include @@ -21,26 +21,11 @@ MlxRawEthDevice::MlxRawEthDevice(uint16_t dev_id, uint16_t data_stream, size_t i mac_addr = (static_cast(dev_id) << 8*5) | 0x00DDCCBBAA06; } -void MlxRawEthDevice::InitializeCalibration(const DiffractionExperiment &experiment, const JFCalibration &calib) { - // Do nothing -} - int32_t MlxRawEthDevice::GetNUMANode() const { return numa_node; } -void MlxRawEthDevice::HW_WriteActionRegister(const ActionConfig *job) { - memcpy(&cfg, job, sizeof(ActionConfig)); -} - -void MlxRawEthDevice::HW_ReadActionRegister(ActionConfig *job) { - memcpy(job, &cfg, sizeof(ActionConfig)); -} - void MlxRawEthDevice::MeasureThread() { - - uint64_t packet_count = 0; - work_completion_queue.Put(Completion{ .type = Completion::Type::Start }); @@ -50,7 +35,7 @@ void MlxRawEthDevice::MeasureThread() { IBCompletionQueue cq(context, BUFFER_COUNT+2); IBQueuePair qp(pd, cq, 16, BUFFER_COUNT); IBRegBuffer buffer(pd, BUFFER_COUNT, BUFFER_SIZE, numa_node); - ProcessJFPacket process(work_completion_queue, work_request_queue, cfg.nmodules); + ProcessJFPacket process(work_completion_queue, work_request_queue, max_modules); qp.Init(); qp.ReadyToReceive(); @@ -73,7 +58,7 @@ void MlxRawEthDevice::MeasureThread() { std::ref(buffer), std::ref(qp)); - packet_count = cq_poll_future.get(); + cq_poll_future.get(); arp_future.get(); } catch (const JFJochException &e) { @@ -83,46 +68,28 @@ void MlxRawEthDevice::MeasureThread() { } work_completion_queue.Put(Completion{ - .type = Completion::Type::End, - .frame_number = packet_count + .type = Completion::Type::End }); - idle = true; } -void MlxRawEthDevice::HW_StartAction() { - if (cfg.mode & MODE_CONV) +void MlxRawEthDevice::Start(const DiffractionExperiment& experiment) { + if (experiment.GetConversionOnFPGA()) throw JFJochException(JFJochExceptionCategory::InputParameterInvalid, "Conversion on CPU flag has to be enabled for Raw Ethernet device"); cancel = false; - idle = false; measure = std::async(std::launch::async, &MlxRawEthDevice::MeasureThread, this); } -bool MlxRawEthDevice::HW_IsIdle() const { - return idle; -} - -void MlxRawEthDevice::HW_SetCancelDataCollectionBit() { +void MlxRawEthDevice::Cancel() { cancel = true; } -void MlxRawEthDevice::HW_GetStatus(ActionStatus *status) const { - memset(status, 0, sizeof(ActionStatus)); - - status->modules_internal_packet_generator = 1; - status->max_modules = max_modules; -} - -void MlxRawEthDevice::HW_EndAction() { +void MlxRawEthDevice::Finalize() { if (measure.valid()) measure.get(); } -void MlxRawEthDevice::CopyInternalPacketGenFrameToDeviceBuffer() { - // Do nothing -} - void MlxRawEthDevice::SetMACAddress(uint64_t mac_addr_network_order) { mac_addr = mac_addr_network_order; } @@ -131,22 +98,12 @@ void MlxRawEthDevice::SetIPv4Address(uint32_t ipv4_addr_network_order) { ipv4_addr = ipv4_addr_network_order; } -uint64_t MlxRawEthDevice::HW_GetMACAddress() const { - return mac_addr; -} - -uint32_t MlxRawEthDevice::HW_GetIPv4Address() const { - return ipv4_addr; -} - -uint64_t MlxRawEthDevice::PollCQ(IBRegBuffer &buffer, IBQueuePair &qp, IBCompletionQueue &cq, ProcessJFPacket &process) { +void MlxRawEthDevice::PollCQ(IBRegBuffer &buffer, IBQueuePair &qp, IBCompletionQueue &cq, ProcessJFPacket &process) { #ifdef JFJOCH_USE_NUMA if (numa_available() != -1) numa_run_on_node(numa_node); #endif - uint64_t packet_counter = 0; - while (!cancel) { int64_t i; size_t size; @@ -155,13 +112,10 @@ uint64_t MlxRawEthDevice::PollCQ(IBRegBuffer &buffer, IBQueuePair &qp, IBComplet auto ptr = (jf_raw_packet *) buffer.GetLocation(i); process.ProcessPacket(&ptr->jf); qp.PostReceiveWR(*buffer.GetMemoryRegion(), i, buffer.GetLocation(i), BUFFER_SIZE); - packet_counter++; } } else std::this_thread::sleep_for(std::chrono::microseconds(10)); } - - return packet_counter; } // ARP packet - from if_arp.h @@ -214,4 +168,5 @@ void MlxRawEthDevice::SendARP(IBRegBuffer &buffer, IBQueuePair &qp) { } } + #endif //JFJOCH_USE_IBVERBS \ No newline at end of file diff --git a/receiver/host/MlxRawEthDevice.h b/receiver/MlxRawEthDevice.h similarity index 55% rename from receiver/host/MlxRawEthDevice.h rename to receiver/MlxRawEthDevice.h index a3f126e1..8de9d6a6 100644 --- a/receiver/host/MlxRawEthDevice.h +++ b/receiver/MlxRawEthDevice.h @@ -1,5 +1,4 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (2019-2023) Paul Scherrer Institute #ifdef JFJOCH_USE_IBVERBS @@ -10,7 +9,7 @@ #include "AcquisitionDevice.h" #include "IBWrappers.h" -#include "../../jungfrau/ProcessJFPacket.h" +#include "../jungfrau/ProcessJFPacket.h" class MlxRawEthDevice : public AcquisitionDevice { @@ -19,42 +18,30 @@ class MlxRawEthDevice : public AcquisitionDevice { std::mutex m; IBContext context; - uint64_t mac_addr; - uint32_t ipv4_addr; - ActionConfig cfg; + const int16_t numa_node; + volatile bool cancel = false; std::future measure; - volatile bool cancel = false; - volatile bool idle = true; - void SendARP(IBRegBuffer &buffer, IBQueuePair &qp); - uint64_t PollCQ(IBRegBuffer &buffer, + void PollCQ(IBRegBuffer &buffer, IBQueuePair &qp, IBCompletionQueue &cq, ProcessJFPacket &process); void MeasureThread(); - void HW_WriteActionRegister(const ActionConfig *job) override; - void HW_ReadActionRegister(ActionConfig *job) override; - void HW_StartAction() override; - bool HW_IsIdle() const override; - void HW_SetCancelDataCollectionBit() override; - void HW_GetStatus(ActionStatus *status) const override; - uint64_t HW_GetMACAddress() const override; - uint32_t HW_GetIPv4Address() const override; - void HW_EndAction() override; - void CopyInternalPacketGenFrameToDeviceBuffer() override; + void Start(const DiffractionExperiment& experiment) override; + void Finalize() override; public: MlxRawEthDevice(uint16_t dev_id, uint16_t data_stream, size_t in_frame_buffer_size_modules, int16_t numa_node = -1); ~MlxRawEthDevice() override = default; - void InitializeCalibration(const DiffractionExperiment &experiment, const JFCalibration &calib) override; int32_t GetNUMANode() const override; void SetMACAddress(uint64_t mac_addr_network_order); void SetIPv4Address(uint32_t ipv4_addr_network_order); + void Cancel() override; }; #endif //JUNGFRAUJOCH_RAWETHDEVICE_H diff --git a/receiver/MockAcquisitionDevice.cpp b/receiver/MockAcquisitionDevice.cpp new file mode 100644 index 00000000..79cd7411 --- /dev/null +++ b/receiver/MockAcquisitionDevice.cpp @@ -0,0 +1,170 @@ +// Copyright (2019-2023) Paul Scherrer Institute + +#include "MockAcquisitionDevice.h" +#include "../common/JFJochException.h" +#include +#include "../jungfrau/JFConversionFloatingPoint.h" + +void MockAcquisitionDevice::Start(const DiffractionExperiment& experiment) { + idle = false; + cancel = false; + + if (experiment.IsUsingInternalPacketGen()) { + if (experiment.GetConversionOnFPGA() && (experiment.GetDetectorMode() == DetectorMode::Conversion)) { + for (auto &i: buffer_device) + memcpy(i, internal_pkt_gen_frame_conv.data(), RAW_MODULE_SIZE * sizeof(uint16_t)); + } else { + for (auto &i: buffer_device) + memcpy(i, internal_pkt_gen_frame.data(), RAW_MODULE_SIZE * sizeof(uint16_t)); + } + measure = std::async(std::launch::async, &MockAcquisitionDevice::InternalPacketGeneratorThread, this, + experiment.GetModulesNum(data_stream), experiment.GetFrameNum()); + } else { + measure = std::async(std::launch::async, &MockAcquisitionDevice::MeasureThread, this); + } +} + +void MockAcquisitionDevice::Cancel() { + if (!idle) { + if (logger) + logger->Info("MockAcquisitionDevice cancelling " + std::to_string(data_stream)); + cancel = true; + } +} + +MockAcquisitionDevice::MockAcquisitionDevice(uint16_t data_stream, size_t in_frame_buffer_size_modules, + int16_t in_numa_node) +: AcquisitionDevice(data_stream), internal_pkt_gen_frame(RAW_MODULE_SIZE), internal_pkt_gen_frame_conv(RAW_MODULE_SIZE) { + max_modules = 16; + MapBuffersStandard(in_frame_buffer_size_modules, 1, in_numa_node); + max_handle = in_frame_buffer_size_modules; + + for (int i = 0; i < RAW_MODULE_SIZE; i++) { + internal_pkt_gen_frame[i] = i % 65536; + internal_pkt_gen_frame_conv[i] = i % 65536; + } +} + +void MockAcquisitionDevice::SendCompletion(uint32_t handle, uint16_t module_number, uint64_t frame_number) { + Completion c; + c.handle = handle; + c.module_number = module_number; + c.frame_number = frame_number - 1; + c.type = Completion::Type::Image; + c.packet_mask[0] = UINT64_MAX; + c.packet_mask[1] = UINT64_MAX; + c.packet_count = 128; + mock_completions.Put(c); +} + +void MockAcquisitionDevice::AddModule(uint64_t frame_number, uint16_t module_number, const uint16_t *data) { + + if (module_number >= max_modules) + throw JFJochException(JFJochExceptionCategory::ArrayOutOfBounds, + "Module number exceeding limit"); + + if (current_handle < max_handle) { + memcpy(buffer_device.at(current_handle), data, RAW_MODULE_SIZE * sizeof(uint16_t)); + SendCompletion(current_handle, module_number, frame_number); + current_handle++; + } else { + throw JFJochException(JFJochExceptionCategory::ArrayOutOfBounds, "No buffer handles left"); + } +} + +void MockAcquisitionDevice::MeasureThread() { + work_completion_queue.Put(Completion{.type = Completion::Type::Start}); + + while (!cancel) { + Completion c{}; + + if (mock_completions.Get(c)) { + if (c.type == Completion::Type::Image) + work_completion_queue.Put(c); + else + cancel = true; + } else + std::this_thread::sleep_for(std::chrono::microseconds(100)); + } + + work_completion_queue.Put(Completion{ + .type = Completion::Type::End + }); + idle = true; +} + +void MockAcquisitionDevice::InternalPacketGeneratorThread(uint32_t nmodules, uint32_t nframes) { + work_completion_queue.Put(Completion{.type = Completion::Type::Start}); + uint32_t curr_module = 0; + uint32_t curr_frame = 0; + + while ((!cancel) && (curr_frame < nframes)) { + WorkRequest wr{}; + if (work_request_queue.Get(wr)) { + Completion c{}; + + c.handle = wr.handle; + c.module_number = curr_module; + c.frame_number = curr_frame; + c.type = Completion::Type::Image; + c.packet_mask[0] = UINT64_MAX; + c.packet_mask[1] = UINT64_MAX; + c.packet_count = 128; + work_completion_queue.Put(c); + + curr_module++; + if (curr_module == nmodules) { + curr_module = 0; + curr_frame++; + } + } else + std::this_thread::sleep_for(std::chrono::microseconds(100)); + } + + work_completion_queue.Put(Completion{ + .type = Completion::Type::End + }); + idle = true; +} + +void MockAcquisitionDevice::Terminate() { + mock_completions.Put(Completion{ + .type = Completion::Type::End + }); +} + +std::string MockAcquisitionDevice::GetMACAddress() const { + return "00:00:00:00:00:00"; +} + +std::string MockAcquisitionDevice::GetIPv4Address() const { + return "127.0.0.1"; +} + +void MockAcquisitionDevice::Finalize() { + if (measure.valid()) + measure.get(); +} + +void MockAcquisitionDevice::SetCustomInternalGeneratorFrame(const std::vector &v) { + if (v.size() != RAW_MODULE_SIZE) + throw JFJochException(JFJochExceptionCategory::InputParameterInvalid, + "Error in size of custom internal generator frame"); + + internal_pkt_gen_frame = v; + internal_pkt_gen_frame_conv = v; +} + +void MockAcquisitionDevice::InitializeCalibration(const DiffractionExperiment &experiment, const JFCalibration &calib) { + JFConversionFloatingPoint conv; + conv.Setup(calib.GainCalibration(experiment.GetFirstModuleOfDataStream(data_stream)), + calib.Pedestal(experiment.GetFirstModuleOfDataStream(data_stream),0), + calib.Pedestal(experiment.GetFirstModuleOfDataStream(data_stream),1), + calib.Pedestal(experiment.GetFirstModuleOfDataStream(data_stream),2), + experiment.GetPhotonEnergy_keV()); + conv.ConvertModule((int16_t *) internal_pkt_gen_frame_conv.data(), internal_pkt_gen_frame.data()); +} + +std::vector MockAcquisitionDevice::GetInternalGeneratorFrame() const { + return internal_pkt_gen_frame; +} diff --git a/receiver/MockAcquisitionDevice.h b/receiver/MockAcquisitionDevice.h new file mode 100644 index 00000000..045fe81a --- /dev/null +++ b/receiver/MockAcquisitionDevice.h @@ -0,0 +1,43 @@ +// Copyright (2019-2023) Paul Scherrer Institute + +#ifndef JUNGFRAUJOCH_MOCKACQUISITIONDEVICE_H +#define JUNGFRAUJOCH_MOCKACQUISITIONDEVICE_H + +#include "AcquisitionDevice.h" +#include "../common/ThreadSafeFIFO.h" +#include + +class MockAcquisitionDevice : public AcquisitionDevice { + uint32_t current_handle = 0; + uint32_t max_handle = 0; + + bool idle = true; + std::future measure; + volatile bool cancel = false; + std::vector internal_pkt_gen_frame; + std::vector internal_pkt_gen_frame_conv; + ThreadSafeFIFO mock_completions; + + void SendCompletion(uint32_t handle, uint16_t module_number, uint64_t frame_number); + void Start(const DiffractionExperiment& experiment) override; + void MeasureThread(); + void InternalPacketGeneratorThread(uint32_t nmodules, uint32_t nframes); +public: + MockAcquisitionDevice(uint16_t data_stream, size_t in_frame_buffer_size_modules, + int16_t numa_node = -1); + void AddModule(uint64_t frame, uint16_t module_number, const uint16_t *data); + void Terminate(); + std::string GetMACAddress() const override; + std::string GetIPv4Address() const override; + void Cancel() override; + void Finalize() override; + + // Warning - internal packet generator in MockAcquisitionDevice has one limitation: + // it assumes the same calibration for all modules of the device + // For routine receiver tests one should always set one module per device + void SetCustomInternalGeneratorFrame(const std::vector &v); + std::vector GetInternalGeneratorFrame() const override; + void InitializeCalibration(const DiffractionExperiment &experiment, const JFCalibration &calib) override; +}; + +#endif //JUNGFRAUJOCH_MOCKACQUISITIONDEVICE_H diff --git a/receiver/host/PCIExpressDevice.cpp b/receiver/PCIExpressDevice.cpp similarity index 74% rename from receiver/host/PCIExpressDevice.cpp rename to receiver/PCIExpressDevice.cpp index fd5c6249..90c0925d 100644 --- a/receiver/host/PCIExpressDevice.cpp +++ b/receiver/PCIExpressDevice.cpp @@ -1,15 +1,13 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (2019-2023) Paul Scherrer Institute #include #include #include +#include #include "PCIExpressDevice.h" -#include "../../common/JFJochException.h" -#include "../pcie_driver/jfjoch_ioctl.h" -#include -#include "../../common/NetworkAddressConvert.h" +#include "../fpga/pcie_driver/jfjoch_ioctl.h" +#include "../common/NetworkAddressConvert.h" PCIExpressDevice::PCIExpressDevice(uint16_t data_stream, uint16_t pci_slot) : PCIExpressDevice("/dev/jfjoch" + std::to_string(pci_slot), data_stream) { @@ -32,7 +30,7 @@ PCIExpressDevice::PCIExpressDevice(const std::string &device_name, uint16_t data uint32_t num_buf = GetNumKernelBuffers(); - if (num_buf < max_modules * (3 + 3 * 16) + 2) + if (num_buf < max_modules * (3 + 3 * 16)) throw JFJochException(JFJochExceptionCategory::PCIeError, "Need to increase number of host-device buffers"); @@ -76,7 +74,7 @@ bool PCIExpressDevice::HW_ReadMailbox(uint32_t *values) { } -void PCIExpressDevice::HW_SetCancelDataCollectionBit() { +void PCIExpressDevice::Cancel() { if (ioctl(fd, IOCTL_JFJOCH_CANCEL) != 0) throw JFJochException(JFJochExceptionCategory::PCIeError, "Failed setting cancel bit", errno); @@ -93,10 +91,31 @@ bool PCIExpressDevice::HW_SendWorkRequest(uint32_t handle) { return true; } -void PCIExpressDevice::FPGA_StartAction() { +void PCIExpressDevice::FPGA_StartAction(const DiffractionExperiment &experiment) { + if (experiment.IsUsingInternalPacketGen()) { + if (ioctl(fd, IOCTL_JFJOCH_SET_INT_PKT, internal_pkt_gen_frame.data()) != 0) + throw JFJochException(JFJochExceptionCategory::PCIeError, + "Failed loading internal packet generator frame", errno); + } + if (ioctl(fd, IOCTL_JFJOCH_START) != 0) - throw JFJochException(JFJochExceptionCategory::PCIeError, - "Failed starting action", errno); + throw JFJochException(JFJochExceptionCategory::PCIeError, "Failed starting action", errno); + + if (experiment.IsUsingInternalPacketGen()) { + FrameGeneratorConfig config{}; + config.frames = experiment.GetFrameNum() + DELAY_FRAMES_STOP_AND_QUIT + 1; + config.modules = experiment.GetModulesNum(data_stream); + + if (ioctl(fd, IOCTL_JFJOCH_GET_MAC, &config.dest_mac_addr) != 0) + throw JFJochException(JFJochExceptionCategory::PCIeError, + "Failed getting MAC address", errno); + if (ioctl(fd, IOCTL_JFJOCH_GET_IPV4, &config.dest_ipv4_addr) != 0) + throw JFJochException(JFJochExceptionCategory::PCIeError, + "Failed getting MAC address", errno); + + if (ioctl(fd, IOCTL_JFJOCH_RUN_FRAME_GEN, &config) != 0) + throw JFJochException(JFJochExceptionCategory::PCIeError, "Failed starting frame generator", errno); + } } void PCIExpressDevice::FPGA_EndAction() { @@ -125,12 +144,12 @@ void PCIExpressDevice::HW_ReadActionRegister(ActionConfig *config) { "Failed reading config", errno); } -uint64_t PCIExpressDevice::HW_GetMACAddress() const { +std::string PCIExpressDevice::GetMACAddress() const { uint64_t tmp; if (ioctl(fd, IOCTL_JFJOCH_GET_MAC, &tmp) != 0) throw JFJochException(JFJochExceptionCategory::PCIeError, "Failed getting MAC address", errno); - return tmp; + return MacAddressToStr(tmp); } void PCIExpressDevice::SetMACAddress(uint64_t mac_addr_network_order) { @@ -195,10 +214,26 @@ void PCIExpressDevice::SetIPv4Address(uint32_t ipv4_addr_network_order) { "Failed setting IPv4 address", errno); } -uint32_t PCIExpressDevice::HW_GetIPv4Address() const { +std::string PCIExpressDevice::GetIPv4Address() const { uint32_t tmp; if (ioctl(fd, IOCTL_JFJOCH_GET_IPV4, &tmp) != 0) throw JFJochException(JFJochExceptionCategory::PCIeError, "Failed getting MAC address", errno); - return tmp; + return IPv4AddressToStr(tmp); } + +void PCIExpressDevice::HW_ReadInternalPacketGen(uint16_t *tmp) const { + if (ioctl(fd, IOCTL_JFJOCH_GET_INT_PKT, tmp) != 0) + throw JFJochException(JFJochExceptionCategory::PCIeError, + "Failed getting internal packet generator frame", errno); +} + +void PCIExpressDevice::HW_LoadCalibration(uint32_t in_modules, uint32_t in_storage_cells) { + ActionConfig config{ + .nmodules = in_modules, + .nstorage_cells = in_storage_cells + }; + if (ioctl(fd, IOCTL_JFJOCH_LOAD_CALIB, &config) != 0) + throw JFJochException(JFJochExceptionCategory::PCIeError, + "Failed writing config", errno); +} \ No newline at end of file diff --git a/receiver/host/PCIExpressDevice.h b/receiver/PCIExpressDevice.h similarity index 73% rename from receiver/host/PCIExpressDevice.h rename to receiver/PCIExpressDevice.h index 993ba7c0..511f28cc 100644 --- a/receiver/host/PCIExpressDevice.h +++ b/receiver/PCIExpressDevice.h @@ -1,5 +1,4 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (2019-2023) Paul Scherrer Institute #ifndef JUNGFRAUJOCH_PCIEXPRESSDEVICE_H #define JUNGFRAUJOCH_PCIEXPRESSDEVICE_H @@ -9,15 +8,13 @@ class PCIExpressDevice : public FPGAAcquisitionDevice { int fd; - bool HW_ReadMailbox(uint32_t values[16]); - void HW_SetCancelDataCollectionBit() override; + bool HW_ReadMailbox(uint32_t values[16]) override; bool HW_SendWorkRequest(uint32_t handle) override; - void FPGA_StartAction() override; + void FPGA_StartAction(const DiffractionExperiment &experiment) override; bool HW_IsIdle() const final; void HW_WriteActionRegister(const ActionConfig *job) override; void HW_ReadActionRegister(ActionConfig *job) override; - uint64_t HW_GetMACAddress() const override; - uint32_t HW_GetIPv4Address() const override; + void HW_LoadCalibration(uint32_t modules, uint32_t storage_cells) override; void FPGA_EndAction() override; void Reset(); @@ -30,8 +27,10 @@ public: PCIExpressDevice(const std::string &device_name, uint16_t data_stream); ~PCIExpressDevice() override; + void Cancel() override; void HW_GetStatus(ActionStatus *status) const override; void HW_GetEnvParams(ActionEnvParams *status) const override; + void HW_ReadInternalPacketGen(uint16_t *tmp) const; uint32_t GetNumKernelBuffers() const; int32_t GetNUMANode() const override; @@ -40,7 +39,9 @@ public: void SetMACAddress(uint64_t mac_addr_network_order); void SetDefaultMAC() const; void SetIPv4Address(uint32_t ipv4_addr_network_order); + + std::string GetMACAddress() const override; + std::string GetIPv4Address() const override; }; - #endif //JUNGFRAUJOCH_PCIEXPRESSDEVICE_H diff --git a/receiver/README.md b/receiver/README.md deleted file mode 100644 index 235dfe48..00000000 --- a/receiver/README.md +++ /dev/null @@ -1,120 +0,0 @@ -# Image receiver - -## Content of directories - -CPU Part: - -* `host` Host side API to access the acquisition device, implements high level operations -* `pcie_driver` Linux kernel driver for PCIe version of the FPGA board - -FPGA part: - -* `scripts` Scripts for FPGA synthesis -* `xdc` Constraints for FPGA -* `hdl` FPGA design parts developed in Verilog -* `hls` FPGA design parts developed in C++ with high-level synthesis - -Dependencies: - -* `include` External (Xilinx) headers for high-level synthesis code - - -## HLS compilation -Make HLS routines: -``` -mkdir build -cd build -cmake3 .. -make hls -``` - -## Synthesis -Create PCIe bitstream: -``` -mkdir build -cd build -cmake3 .. -make action_pcie -``` - -## Hardware verification - -To test that FPGA board is working properly without access to a JUNGFRAU detector, you can use `jfjoch_action_test` tool. - -## FPGA reference -FPGA setup can be done via 32-bit registers: - -| Address | Bits | Meaning | Mode | Notes | -|-------------------|------|-----------------------------------------------------------------------|:-----|-----------------------------------| -| 0x00000 - 0x0FFFF | | Reserved for internal memory of MicroBlaze | | | -| 0x10000 | 32 | Action Control Register | | | -| | | Bit 0 - Action start | R/W | | -| | | Bit 1 - Action idle | R | | -| | | Bit 2 - Action cancel | R/W | cleared on reset or action start | -| | | Bit 12 - HBM catastrophic temp. error | R | | -| | | Bit 13 - HBM catastrophic temp. error | R | cleared on reset or action start | -| | | Bit 14 - HBM setup complete | R | | -| | | Bit 16 - AXI Mailbox interrupt 0 | R | | -| | | Bit 17 - AXI Mailbox interrupt 1 | R | | -| | | Bits 24-27 - Various errors in host memory writer | R | cleared on reset or action start | -| 0x10004 | 32 | Reserved | - | | -| 0x10008 | 32 | Set user LED G0 (yellow or green), 1 is on, 0 is off | R/W | | -| 0x1000C | 32 | Action GIT SHA1 | R | | -| 0x10010 | 32 | Action Type | R | | -| 0x10014 | 32 | Action Release Level | R | | -| 0x10018 | 32 | HBM current temperature | R | | -| 0x1001C | 32 | HBM max. temperature | R | reset on action start | -| 0x10020 | 32 | Max. number supported detector modules | R | constant | -| 0x10024 | 32 | Number of modules in internal packet generator memory | R | constant | -| 0x10028 | 64 | Pipeline stalls before writing to host memory | R | reset on action start | -| 0x10030 | 64 | Pipeline stalls before accessing HBM | R | reset on action start | -| 0x10038 | 32 | FIFO status (see action_config.v for details) | R/W | | -| 0x1003C | 32 | Reserved | - | | -| 0x10040 | 64 | Packets processed by the action | R/W | cleared on reset or action start | -| 0x10048 | 64 | Valid ethernet packets | R/W | cleared on reset | -| 0x10050 | 64 | Valid ICMP packets | R/W | cleared on reset | -| 0x10058 | 64 | Valid UDP packets | R/W | cleared on reset | -| 0x10060 | 64 | MAC address of FPGA card | R/W | network byte order | -| 0x10068 | 32 | IPv4 address of FPGA card | R/W | network byte order | -| 0x1006C | 32 | Number of detector modules | R/W | | -| 0x10070 | 32 | Data collection mode | R/W | | -| 0x10074 | 32 | One over energy in keV (in fixed-point:12 int. + 24 frac. bit format) | R/W | | -| 0x10078 | 32 | Number of frames to be generated by internal packet generator | R/W | | -| 0x1007C | 32 | Number of storage cells | R/W | | -| | | | | | -| 0x20000 - 0x2FFFF | | CMAC 100G | | See Xilinx PG203 for register map | -| 0x30000 - 0x3FFFF | | AXI Mailbox for Work Request / Work Completion | | See Xilinx PG114 for register map | -| 0x40000 - 0x4FFFF | | QuadSPI flash | | See Xilinx PG153 for register map | -| 0x60000 - 0x60FFF | 64 | Input calibration memory addresses block RAM | | | -| 0x70000 - 0x7FFFF | | AXI Firewall | | See Xilinx PG293 for register map | -| 0x80000 - 0x8FFFF | | Interrupt controller | | See Xilinx PG099 for register map | -| 0x70000 - 0x7FFFF | | PCIe DMA control | | See Xilinx PG195 for register map | -| 0xC0000 - 0xFFFFF | | Xilinx Card Management Solution Subsystem management subsystem | | See Xilinx PG348 for register map | - -### AXI Mailbox - -AXI mailbox is used to send work request from host to action, and receive work completions. Messages are always multiple of 128-bit. See Xilinx PG114 on how to operate AXI Mailbox. - -Work request has the following structure: - -| Bit start | Bit end | Meaning | -|-----------|---------|----------------------------------------------------| -| 0 | 31 | Work request ID (handle) | -| 32 | 95 | Address (Virt: OpenCAPI, DMA: PCIe) | -| 96 | 127 | Includes parity bit, so bits 0-127 are even parity | - -Work completion has the following structure: - -| Bit start | Bit end | Meaning | -|-----------|---------|--------------------------------------------------------------------------------------------------------------| -| 0 | 31 | Work request ID (handle) | -| 32 | 39 | Module number | -| 40 | 40 | All packets for the module arrived OK | -| 41 | 41 | Trigger signal high | -| 42 | 62 | Reserved | -| 63 | 63 | Parity bit - bits 0-127 are even parity | -| 64 | 127 | Frame number | -| 128 | 159 | JF debug | -| 160 | 191 | JF Timestamp (low 32-bit) | -| 192 | 255 | Bunch ID | -| 256 | 383 | Optional packet mask (1 bit per packet: 0 packet missing, 1 packet arrived); transmitted only if bit 40 is 0 | diff --git a/receiver/hls/internal_packet_generator.cpp b/receiver/hls/internal_packet_generator.cpp deleted file mode 100644 index 4f462af7..00000000 --- a/receiver/hls/internal_packet_generator.cpp +++ /dev/null @@ -1,99 +0,0 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: CERN-OHL-S-2.0 or GPL-3.0-or-later - -#include "hls_jfjoch.h" - -void internal_packet_generator(STREAM_512 &data_in, STREAM_512 &data_out, - hls::stream > &addr_in, - hls::stream > &addr_out, - volatile ap_uint<1> &in_cancel) { -#pragma HLS INTERFACE ap_ctrl_none port=return -#pragma HLS INTERFACE register both axis port=data_in -#pragma HLS INTERFACE register both axis port=data_out -#pragma HLS INTERFACE register both axis port=addr_in -#pragma HLS INTERFACE register both axis port=addr_out -#pragma HLS INTERFACE ap_none register port=in_cancel - - packet_512_t packet_in; - packet_512_t packet_out; - -#ifdef __SYNTHESIS__ - ap_uint<512> module_cache[RAW_MODULE_SIZE * 2 / 64]; -#pragma HLS RESOURCE variable=module_cache core=RAM_2P_URAM latency=3 -#else - std::vector > module_cache(RAW_MODULE_SIZE * 2 / 64); -#endif - - // Read and forward packet #0 - data_in >> packet_in; - ap_uint<5> modules = ACT_REG_NMODULES(packet_in.data); - ap_uint<64> mode = ACT_REG_MODE(packet_in.data); - ap_uint<1> internal_packet_generator = (mode & MODE_INTERNAL_PACKET_GEN) ? 1 : 0; - ap_uint<32> nframes = ACT_REG_NFRAMES(packet_in.data); - ap_uint<5> storage_cells = ACT_REG_NSTORAGE_CELLS(packet_in.data); - ap_uint<1> conversion = (mode & MODE_CONV) ? 1 : 0; - - data_out << packet_in; - ap_uint addr; - addr_in >> addr; - addr_out << addr; - - save_frame: - for (int i = 0; i < RAW_MODULE_SIZE * 2 / 64; i++) { -#pragma HLS PIPELINE II=1 - data_in >> packet_in; - module_cache[i] = packet_in.data; - } - - if (conversion) { - forward_gain: - for (int i = 0; i < modules * (3 + storage_cells * 3) * (RAW_MODULE_SIZE * 2 / 64); i++) { -#pragma HLS PIPELINE II=1 - data_in >> packet_in; - data_out << packet_in; - } - } - - if (internal_packet_generator) { - generate_frames: - for (uint32_t frame_number = 1; frame_number <= nframes; frame_number++ ) { - - for (uint8_t module = 0; module < modules; module++) { - ap_uint<1> cancel = in_cancel; - if (cancel) - break; - - for (uint32_t i = 0; i < RAW_MODULE_SIZE * 2 / 64; i++) { -#pragma HLS PIPELINE II=1 - uint32_t eth_packet = i / 128; - uint32_t axis_packet = i % 128; - if (axis_packet == 0) - addr_out << addr_packet(eth_packet, module, frame_number, 0, - 0xABCDEFABCDEF, 0xCACACACACA, 10000); - packet_out.user = 0; - packet_out.id = 0; - packet_out.last = (axis_packet == 127) ? 1 : 0; - packet_out.data = module_cache[i]; - data_out << packet_out; - } - } - } - } - - addr_in >> addr; - - forward_packets: - while (!addr_last_flag(addr)) { -#pragma HLS PIPELINE II=1 - data_in >> packet_in; - data_out << packet_in; - if (packet_in.last) { - addr_out << addr; - addr_in >> addr; - } - } - - addr_out << addr; - data_in >> packet_in; - data_out << packet_in; -} diff --git a/receiver/hls/load_calibration.cpp b/receiver/hls/load_calibration.cpp deleted file mode 100644 index 6f99f169..00000000 --- a/receiver/hls/load_calibration.cpp +++ /dev/null @@ -1,85 +0,0 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: CERN-OHL-S-2.0 or GPL-3.0-or-later - -#include "hls_jfjoch.h" - -// Loads calibration from host memory based on 64-bit memory addresses loaded in in_mem_location -// Expected structure in in_mem_location array: -// -// * pixel mask for all modules(1 bit/pixel) -// * internal packet generator frame -// * gain factors for module m at location: 2 + gain level * NMODULES + m -// * pedestal factors for module m and storage cell s at location: 2 + 3 * NMODULES + (gain level * 16 + s ) * NMODULES + m - -void load_data(STREAM_512 &data_out, - hls::stream &datamover_in_cmd, - hls::stream > &host_memory_in, - uint64_t memory_addr, - uint64_t size_in_512bit_packets) { - setup_datamover(datamover_in_cmd, memory_addr, size_in_512bit_packets * 64); - read_internal_pkt_gen_content: - for (int j = 0; j < size_in_512bit_packets; j++) { -#pragma HLS PIPELINE II=1 - ap_axiu<512,1,1,1> data_packet; - host_memory_in >> data_packet; - packet_512_t packet_out; - packet_out.last = 0; - packet_out.user = 0; - packet_out.id = 0; - packet_out.data = data_packet.data; - data_out << packet_out; - } -} - -void load_calibration(STREAM_512 &data_in, STREAM_512 &data_out, - hls::stream &datamover_in_cmd, - hls::stream > &host_memory_in, - uint64_t in_mem_location[LOAD_CALIBRATION_BRAM_SIZE]) { -#pragma HLS INTERFACE ap_ctrl_none port=return -#pragma HLS INTERFACE register both axis port=datamover_in_cmd -#pragma HLS INTERFACE register both axis port=host_memory_in -#pragma HLS INTERFACE register both axis port=data_in -#pragma HLS INTERFACE register both axis port=data_out -#pragma HLS INTERFACE bram port=in_mem_location storage_type=rom_1p - - packet_512_t packet_in; - - data_in >> packet_in; - ap_uint<5> modules = ACT_REG_NMODULES(packet_in.data); - ap_uint<5> storage_cells = ACT_REG_NSTORAGE_CELLS(packet_in.data); - ap_uint<1> conversion = (ACT_REG_MODE(packet_in.data) & MODE_CONV) ? 1 : 0; - data_out << packet_in; - - load_data(data_out, datamover_in_cmd, host_memory_in, in_mem_location[0], RAW_MODULE_SIZE * sizeof(int16_t) / 64); - - if (conversion) { - read_gain: - for (int c = 0; c < 3; c++) { - // 3 gain levels - for (int m = 0; m < modules; m++) { - load_data(data_out, datamover_in_cmd, host_memory_in, in_mem_location[m + c * modules + 1], - RAW_MODULE_SIZE * sizeof(int16_t) / 64); - } - } - - read_pedestal: - for (int c = 0; c < 3; c++) { - ap_uint<16> offset = (c * 16 + 3) * modules + 1; - for (int s = 0; s < storage_cells; s++) { - for (int m = 0; m < modules; m++) { - load_data(data_out, datamover_in_cmd, host_memory_in, - in_mem_location[offset + s * modules + m], - RAW_MODULE_SIZE * sizeof(int16_t) / 64); - } - } - } - } - - data_in >> packet_in; - while (!packet_in.user) { -#pragma HLS PIPELINE II=1 - data_out << packet_in; - data_in >> packet_in; - } - data_out << packet_in; -} \ No newline at end of file diff --git a/receiver/hls/timer.cpp b/receiver/hls/timer.cpp deleted file mode 100644 index 53f27b98..00000000 --- a/receiver/hls/timer.cpp +++ /dev/null @@ -1,88 +0,0 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: CERN-OHL-S-2.0 or GPL-3.0-or-later - -#ifdef __SYNTHESIS__ -#include "ap_utils.h" -#else -#define ap_wait() -#endif - -#include "hls_jfjoch.h" - -#define HBM_CALIB_DELAY 256 - -void timer_hbm(STREAM_512 &data_in, STREAM_512 &data_out, uint64_t &counter) { -#pragma HLS INTERFACE register both axis port=data_in -#pragma HLS INTERFACE register both axis port=data_out -#pragma HLS INTERFACE register ap_vld port=counter -#pragma HLS INTERFACE ap_ctrl_none port=return - packet_512_t packet_in; - - // Read and forward packet #0 - data_in >> packet_in; - uint64_t counter_internal = 0; - counter = 0; // Counter is regenerated when action is starting, not earlier - ap_uint<5> modules = ACT_REG_NMODULES(packet_in.data); - ap_uint<5> storage_cells = ACT_REG_NSTORAGE_CELLS(packet_in.data); - ap_uint<1> conversion = (ACT_REG_MODE(packet_in.data) & MODE_CONV) ? 1 : 0; - - data_out << packet_in; - - // Don't care about pipeline stalls when gain & pedestal are transferred - - if (conversion) { - forward_calibration: - for (int i = 0; i < modules * (3 + 3 * storage_cells) * (RAW_MODULE_SIZE * 2 / 64); i++) { -#pragma HLS PIPELINE II=1 - data_in >> packet_in; - data_out << packet_in; - } - } - - for (int i = 0; i < HBM_CALIB_DELAY; i++) { - ap_wait(); - } - - data_in >> packet_in; - - while (!packet_in.user) { -#pragma HLS PIPELINE - if (data_out.full()) { - if (counter_internal < UINT64_MAX) - counter_internal++; - counter = counter_internal; - } else { - data_out << packet_in; - data_in >> packet_in; - } - } - data_out << packet_in; -} - -void timer_host(STREAM_512 &data_in, STREAM_512 &data_out, uint64_t &counter) { -#pragma HLS INTERFACE register both axis port=data_in -#pragma HLS INTERFACE register both axis port=data_out -#pragma HLS INTERFACE register ap_vld port=counter -#pragma HLS INTERFACE ap_ctrl_none port=return - packet_512_t packet_in; - - data_in >> packet_in; - uint64_t counter_internal = 0; - counter = 0; - data_out << packet_in; - - data_in >> packet_in; - - while (!packet_in.user) { -#pragma HLS PIPELINE - if (data_out.full()) { - if (counter_internal < UINT64_MAX) - counter_internal++; - counter = counter_internal; - } else { - data_out << packet_in; - data_in >> packet_in; - } - } - data_out << packet_in; -} diff --git a/receiver/host/AcquisitionDevice.cpp b/receiver/host/AcquisitionDevice.cpp deleted file mode 100644 index 1426dd57..00000000 --- a/receiver/host/AcquisitionDevice.cpp +++ /dev/null @@ -1,437 +0,0 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later - -#ifdef JFJOCH_USE_NUMA -#include -#endif - -#include -#include -#include -#include -#include -#include -#include - -#include "../../common/JFJochException.h" -#include "AcquisitionDevice.h" -#include "../../common/NetworkAddressConvert.h" - -void *mmap_acquisition_buffer(size_t size, int16_t numa_node) { - void *ret = mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); - if (ret == nullptr) { - throw JFJochException(JFJochExceptionCategory::MemAllocFailed, "frame_buffer"); - } -#ifdef JFJOCH_USE_NUMA - if (numa_node >= 0) { - unsigned long nodemask = 1L << numa_node;; - if (numa_node > sizeof(nodemask)*8) - throw JFJochException(JFJochExceptionCategory::MemAllocFailed, "Mask too small for NUMA node"); - if (mbind(ret, size, MPOL_BIND, &nodemask, sizeof(nodemask)*8, MPOL_MF_STRICT) == -1) - throw JFJochException(JFJochExceptionCategory::MemAllocFailed, "Cannot apply NUMA policy"); - } -#endif - memset(ret, 0, size); - return ret; -} - -AcquisitionDevice::AcquisitionDevice(uint16_t in_data_stream) : -buffer_err(RAW_MODULE_SIZE), internal_pkt_gen_frame(RAW_MODULE_SIZE) { - logger = nullptr; - data_stream = in_data_stream; - - for (int i = 0; i < RAW_MODULE_SIZE; i++) - internal_pkt_gen_frame[i] = i % 65536; -} - -bool AcquisitionDevice::IsFullModuleCollected(size_t frame, uint8_t module_number) const { - return counters.IsFullModuleCollected(frame, module_number); -} - -uint64_t AcquisitionDevice::GetBufferHandle(size_t frame, uint8_t module_number) const { - return counters.GetBufferHandle(frame, module_number); -} - -void AcquisitionDevice::FillActionRegister(const DiffractionExperiment& x, ActionConfig &job) { - - job.nmodules = x.GetModulesNum(data_stream); - job.nframes = x.GetFrameNum(); - job.one_over_energy = std::lround((1<<20)/ x.GetPhotonEnergy_keV()); - job.nstorage_cells = x.GetStorageCellNumber() - 1; - job.mode = 0; - - if ((x.GetDetectorMode() == DetectorMode::Conversion) && x.GetConversionOnFPGA()) - job.mode |= MODE_CONV; - - if (x.IsUsingInternalPacketGen()) - job.mode |= MODE_INTERNAL_PACKET_GEN; -} - -void AcquisitionDevice::PrepareAction(const DiffractionExperiment &experiment) { - if (!HW_IsIdle()) - throw(JFJochException(JFJochExceptionCategory::AcquisitionDeviceError, - "Hardware action running prior to start of data acquisition")); - - if (experiment.GetModulesNum(data_stream) > max_modules) - throw(JFJochException(JFJochExceptionCategory::InputParameterAboveMax, - "Number of modules exceeds max possible for FPGA")); - - counters.Reset(experiment, data_stream); -} - -void AcquisitionDevice::StartAction(const DiffractionExperiment &experiment) { - if (!HW_IsIdle()) - throw(JFJochException(JFJochExceptionCategory::AcquisitionDeviceError, - "Hardware action running prior to start of data acquisition")); - - if (experiment.GetModulesNum(data_stream) > max_modules) - throw(JFJochException(JFJochExceptionCategory::InputParameterAboveMax, - "Number of modules exceeds max possible for FPGA")); - - for (int i = 0; i < RAW_MODULE_SIZE; i++) { - if (experiment.GetDetectorMode() == DetectorMode::Conversion) - buffer_err[i] = PIXEL_OUT_LOST; - else - buffer_err[i] = -1; - } - - counters.Reset(experiment, data_stream); - completion_vector.Reset(experiment, data_stream); - expected_frames = experiment.GetFrameNum(); - - ActionConfig cfg_in{}, cfg_out{}; - - FillActionRegister(experiment, cfg_in); - HW_WriteActionRegister(&cfg_in); - HW_ReadActionRegister(&cfg_out); - - if (experiment.IsUsingInternalPacketGen()) - CopyInternalPacketGenFrameToDeviceBuffer(); - - if (cfg_out.mode != cfg_in.mode) - throw JFJochException(JFJochExceptionCategory::AcquisitionDeviceError, - "Mismatch between expected and actual values of configuration registers (mode)"); - if (cfg_out.nframes != cfg_in.nframes) - throw JFJochException(JFJochExceptionCategory::AcquisitionDeviceError, - "Mismatch between expected and actual values of configuration registers (Frames per trigger)"); - if (cfg_out.nmodules != cfg_in.nmodules) - throw JFJochException(JFJochExceptionCategory::AcquisitionDeviceError, - "Mismatch between expected and actual values of configuration registers (#modules)"); - - // Ensure internal WR queue is empty - work_request_queue.Clear(); - - HW_StartAction(); - - for (uint32_t i = 0; i < buffer_device.size(); i++) - SendWorkRequest(i); - - auto c = work_completion_queue.GetBlocking(); - if (c.type != Completion::Type::Start) - throw JFJochException(JFJochExceptionCategory::AcquisitionDeviceError, "Mismatch in completion queue"); - - start_time = std::chrono::system_clock::now(); - - if (logger) - logger->Info("Started"); -} - -void AcquisitionDevice::CopyInternalPacketGenFrameToDeviceBuffer() { - memcpy(buffer_device[0], internal_pkt_gen_frame.data(), - RAW_MODULE_SIZE * sizeof(uint16_t)); -} - -int64_t AcquisitionDevice::CalculateDelay(size_t curr_frame, uint16_t module_number) const { - return counters.CalculateDelay(curr_frame, module_number); -} - -void AcquisitionDevice::WaitForFrame(size_t curr_frame, uint16_t module_number) const { - counters.WaitForFrame(curr_frame, module_number); -} - -void AcquisitionDevice::SetCustomInternalGeneratorFrame(const std::vector &v) { - if (v.size() != RAW_MODULE_SIZE) - throw JFJochException(JFJochExceptionCategory::InputParameterInvalid, - "Error in size of custom internal generator frame"); - for (int i = 0; i < RAW_MODULE_SIZE; i++) - internal_pkt_gen_frame[i] = v[i]; -} - -const std::vector &AcquisitionDevice::GetInternalGeneratorFrame() const { - return internal_pkt_gen_frame; -} - -void AcquisitionDevice::WaitForActionComplete() { - auto c = work_completion_queue.GetBlocking(); - - while (c.type != Completion::Type::End) { - if (c.frame_number >= expected_frames) { - HW_SetCancelDataCollectionBit(); - // this frame is not of any interest, therefore its location can be immediately released - SendWorkRequest(c.handle); - } else { - counters.UpdateCounters(&c); - completion_vector.Add(c); - } - - if (logger != nullptr) - logger->Debug("Data stream " + std::to_string(data_stream) - + " completion frame number " + std::to_string(c.frame_number) - + " module " + std::to_string(c.module) - + " handle " + std::to_string(c.handle) - + " timestamp " + std::to_string(c.timestamp)); - - c = work_completion_queue.GetBlocking(); - } - bytes_received = c.frame_number * 8192LU; - - counters.SetAcquisitionFinished(); - - end_time = std::chrono::system_clock::now(); - HW_SetCancelDataCollectionBit(); - HW_EndAction(); - while (!HW_IsIdle()) - std::this_thread::sleep_for(std::chrono::milliseconds(1)); -} - -void AcquisitionDevice::SendWorkRequest(uint32_t handle) { - work_request_queue.Put(WorkRequest{ - .ptr = buffer_device.at(handle), - .handle = handle - }); -} - -uint64_t AcquisitionDevice::GetBytesReceived() const { - return bytes_received; -} - -void AcquisitionDevice::SaveStatistics(const DiffractionExperiment &experiment, - JFJochProtoBuf::AcquisitionDeviceStatistics &statistics) const { - - statistics.set_bytes_received(GetBytesReceived()); - statistics.set_start_timestamp(start_time.time_since_epoch().count()); - statistics.set_end_timestamp(end_time.time_since_epoch().count()); - - completion_vector.FillStatistics(experiment, data_stream, statistics); - *statistics.mutable_fpga_status() = GetStatus(); -} - -uint64_t AcquisitionDevice::GetHead(uint8_t module_number) const { - return counters.GetHead(module_number); -} - -uint64_t AcquisitionDevice::GetSlowestHead() const { - return counters.GetSlowestHead(); -} - -bool AcquisitionDevice::IsDone() const { - return counters.IsAcquisitionFinished(); -} - -void AcquisitionDevice::ActionAbort() { - HW_SetCancelDataCollectionBit(); -} - -const int16_t *AcquisitionDevice::GetFrameBuffer(size_t frame_number, uint16_t module_number) const { - auto handle = GetBufferHandle(frame_number, module_number); - if (handle != HandleNotValid) - return (int16_t *) buffer_device.at(handle); - else - return GetErrorFrameBuffer(); -} - -const int16_t *AcquisitionDevice::GetErrorFrameBuffer() const { - return buffer_err.data(); -} - -int16_t *AcquisitionDevice::GetDeviceBuffer(size_t handle) { - if (handle >= buffer_device.size()) - throw JFJochException(JFJochExceptionCategory::ArrayOutOfBounds, "Handle outside of range"); - else - return (int16_t *) buffer_device.at(handle); -} - -void AcquisitionDevice::InitializeCalibration(const DiffractionExperiment &experiment, const JFCalibration &calib) { - auto offset = experiment.GetFirstModuleOfDataStream(data_stream); - - if (calib.GetModulesNum() != experiment.GetModulesNum()) - throw JFJochException(JFJochExceptionCategory::InputParameterInvalid, - "Mismatch regarding module count in calibration and experiment description"); - - if (calib.GetStorageCellNum() != experiment.GetStorageCellNumber()) - throw JFJochException(JFJochExceptionCategory::InputParameterInvalid, - "Mismatch regarding storage cell count in calibration and experiment description"); - - size_t modules = experiment.GetModulesNum(data_stream); - - if (1 + modules * (3 + 3 * experiment.GetStorageCellNumber()) > buffer_device.size()) - throw JFJochException(JFJochExceptionCategory::InputParameterInvalid, - "Not enough host/FPGA buffers to load all calibration constants"); - - for (int m = 0; m < modules; m++) { - calib.GainCalibration(m).ExportG0(buffer_device[1 + m]); - calib.GainCalibration(m).ExportG1(buffer_device[1 + m + modules]); - calib.GainCalibration(m).ExportG2(buffer_device[1 + m + modules * 2]); - } - - for (int s = 0; s < experiment.GetStorageCellNumber(); s++) { - auto mask = calib.CalculateMask(experiment, s); - for (int m = 0; m < modules; m++) { - auto pedestal_g0 = calib.Pedestal(offset + m, 0, s).GetPedestal(); - auto pedestal_g1 = calib.Pedestal(offset + m, 1, s).GetPedestal(); - auto pedestal_g2 = calib.Pedestal(offset + m, 2, s).GetPedestal(); - for (int i = 0; i < RAW_MODULE_SIZE; i++) { - if (experiment.GetApplyPixelMaskInFPGA() && (mask[(offset + m) * RAW_MODULE_SIZE + i] != 0)) { - buffer_device[1 + m + (3 + 0 * 16 + s) * modules][i] = 16384; - buffer_device[1 + m + (3 + 1 * 16 + s) * modules][i] = 16384; - buffer_device[1 + m + (3 + 2 * 16 + s) * modules][i] = 16384; - } else { - buffer_device[1 + m + (3 + 0 * 16 + s) * modules][i] = pedestal_g0[i]; - buffer_device[1 + m + (3 + 1 * 16 + s) * modules][i] = pedestal_g1[i]; - buffer_device[1 + m + (3 + 2 * 16 + s) * modules][i] = pedestal_g2[i]; - } - } - - } - } -} - -void AcquisitionDevice::MapBuffersStandard(size_t c2h_buffer_count, size_t h2c_buffer_count, int16_t numa_node) { - try { - for (int i = 0; i < std::max(c2h_buffer_count, h2c_buffer_count); i++) - buffer_device.emplace_back((uint16_t *) mmap_acquisition_buffer(FPGA_BUFFER_LOCATION_SIZE, numa_node)); - } catch (const JFJochException &e) { - UnmapBuffers(); - throw; - } -} - -void AcquisitionDevice::UnmapBuffers() { - for (auto &i: buffer_device) - if (i != nullptr) munmap(i, FPGA_BUFFER_LOCATION_SIZE); -} - -void AcquisitionDevice::FrameBufferRelease(size_t frame_number, uint16_t module_number) { - auto handle = counters.GetBufferHandleAndClear(frame_number, module_number); - if (handle != AcquisitionOnlineCounters::HandleNotFound) - SendWorkRequest(handle); -} - -void AcquisitionDevice::EnableLogging(Logger *in_logger) { - logger = in_logger; -} - -inline JFJochProtoBuf::FPGAFIFOStatus FIFO_check(uint32_t fifo_register, uint16_t pos_empty, uint16_t pos_full) { - if (std::bitset<32>(fifo_register).test(pos_empty)) - return JFJochProtoBuf::FPGAFIFOStatus::EMPTY; - if (std::bitset<32>(fifo_register).test(pos_full)) - return JFJochProtoBuf::FPGAFIFOStatus::FULL; - return JFJochProtoBuf::FPGAFIFOStatus::PARTIAL; -} - -JFJochProtoBuf::FPGAStatus AcquisitionDevice::GetStatus() const { - ActionStatus status{}; - ActionEnvParams env{}; - - HW_GetStatus(&status); - HW_GetEnvParams(&env); - - JFJochProtoBuf::FPGAStatus ret; - auto full_status_register = status.ctrl_reg; - ret.set_full_status_register(full_status_register); - - ret.set_stalls_hbm(status.pipeline_stalls_hbm); - ret.set_stalls_host(status.pipeline_stalls_host); - - ret.set_max_modules(status.max_modules); - ret.set_git_sha1(status.git_sha1); - - (*ret.mutable_fifo_status())["Conversion input (data)"] = FIFO_check(status.fifo_status, 0, 1); - (*ret.mutable_fifo_status())["Conversion input (cmd)"] = FIFO_check(status.fifo_status, 2, 3); - (*ret.mutable_fifo_status())["UDP"] = FIFO_check(status.fifo_status, 6, 7); - (*ret.mutable_fifo_status())["Work Request"] = FIFO_check(status.fifo_status, 12, 13); - (*ret.mutable_fifo_status())["Work Completion"] = FIFO_check(status.fifo_status, 14, 15); - (*ret.mutable_fifo_status())["Host mem (data)"] = FIFO_check(status.fifo_status, 8, 9); - (*ret.mutable_fifo_status())["Host mem (cmd)"] = FIFO_check(status.fifo_status, 10, 11); - (*ret.mutable_fifo_status())["Data FIFO #8"] = FIFO_check(status.fifo_status, 16, 17); - (*ret.mutable_fifo_status())["Addr FIFO #3"] = FIFO_check(status.fifo_status, 18, 19); - - ret.set_fpga_idle(HW_IsIdle()); - - ret.set_packets_ether(status.packets_eth); - ret.set_packets_udp(status.packets_udp); - ret.set_packets_icmp(status.packets_icmp); - ret.set_packets_jfjoch(status.packets_processed); - ret.set_packets_sls(status.packets_sls); - ret.set_error_eth(status.udp_err_eth); - ret.set_error_packet_len(status.udp_err_len); - - ret.set_datamover_mm2s_error(full_status_register & (1 << 10)); - ret.set_datamover_s2mm_error(full_status_register & (1 << 11)); - - ret.set_frame_statistics_alignment_err(full_status_register & (1 << 24)); - ret.set_frame_statistics_tlast_err(full_status_register & (1 << 25)); - ret.set_frame_statistics_work_req_err(full_status_register & (1 << 26)); - - ret.set_mailbox_status_reg(env.mailbox_status_reg); - ret.set_mailbox_err_reg(env.mailbox_err_reg); - - ret.set_fpga_temp_degc(env.fpga_temp_C); - - ret.set_current_edge_12v_a(static_cast(env.fpga_pcie_12V_I_mA) / 1000.0); - ret.set_voltage_edge_12v_v(static_cast(env.fpga_pcie_12V_V_mV) / 1000.0); - - ret.set_current_edge_3p3v_a(static_cast(env.fpga_pcie_3p3V_I_mA) / 1000.0); - ret.set_voltage_edge_3p3v_v(static_cast(env.fpga_pcie_3p3V_V_mV) / 1000.0); - - ret.set_pcie_c2h_beats(env.pcie_c2h_beats); - ret.set_pcie_h2c_beats(env.pcie_h2c_beats); - ret.set_pcie_c2h_descriptors(env.pcie_c2h_descriptors); - ret.set_pcie_h2c_descriptors(env.pcie_h2c_descriptors); - ret.set_pcie_c2h_status(env.pcie_c2h_status); - ret.set_pcie_h2c_status(env.pcie_h2c_status); - - ret.set_ethernet_rx_aligned(env.ethernet_aligned); - ret.set_hbm_temp_0_degc(env.hbm_0_temp_C); - ret.set_hbm_temp_1_degc(env.hbm_1_temp_C); - ret.set_slowest_head(GetSlowestHead()); - return ret; -} - -std::string AcquisitionDevice::GetMACAddress() const { - return MacAddressToStr(HW_GetMACAddress()); -} - -std::string AcquisitionDevice::GetIPv4Address() const { - return IPv4AddressToStr(HW_GetIPv4Address()); -} - -ActionConfig AcquisitionDevice::ReadActionRegister() { - ActionConfig cfg{}; - HW_ReadActionRegister(&cfg); - return cfg; -} - -int32_t AcquisitionDevice::GetNUMANode() const { - return -1; -} - -uint16_t AcquisitionDevice::GetUDPPort() const { - return 1234; -} - -uint64_t AcquisitionDevice::GetBunchID(size_t curr_frame, uint16_t module_number) const { - return counters.GetBunchID(curr_frame, module_number); -} - -uint32_t AcquisitionDevice::GetJFInfo(size_t curr_frame, uint16_t module_number) const { - return counters.GetJFInfo(curr_frame, module_number); -} - -uint32_t AcquisitionDevice::GetExptime(size_t curr_frame, uint16_t module_number) const { - return counters.GetExptime(curr_frame, module_number); -} - -uint64_t AcquisitionDevice::GetTimestamp(size_t curr_frame, uint16_t module_number) const { - return counters.GetTimestamp(curr_frame, module_number); -} \ No newline at end of file diff --git a/receiver/host/AcquisitionDevice.h b/receiver/host/AcquisitionDevice.h deleted file mode 100644 index e75ccb89..00000000 --- a/receiver/host/AcquisitionDevice.h +++ /dev/null @@ -1,128 +0,0 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later - -#ifndef JUNGFRAUJOCH_ACQUISITIONDEVICE_H -#define JUNGFRAUJOCH_ACQUISITIONDEVICE_H - -#include -#include -#include -#include - -#include - -#include "../../common/Definitions.h" -#include "../../common/DiffractionExperiment.h" -#include "../../common/Logger.h" -#include "../../jungfrau/JFCalibration.h" -#include "../../common/ThreadSafeFIFO.h" -#include "../../jungfrau/JFModuleGainCalibration.h" - -#include "ActionConfig.h" -#include "AcquisitionOnlineCounters.h" -#include "Completion.h" -#include "AcquisitionOfflineCounters.h" - -void *mmap_acquisition_buffer(size_t size, int16_t numa_node); - -class AcquisitionDevice { - uint64_t bytes_received = 0; - - std::vector buffer_err; - - std::chrono::time_point start_time; - std::chrono::time_point end_time; - - void FillActionRegister(const DiffractionExperiment& x, ActionConfig& job); - - int64_t expected_frames; - AcquisitionOnlineCounters counters; - AcquisitionOfflineCounters completion_vector; - - void EndWorkRequestAndSignalQueues(); - - virtual void HW_WriteActionRegister(const ActionConfig *job) = 0; - virtual void HW_ReadActionRegister(ActionConfig *job) = 0; - virtual void HW_StartAction() = 0; - - virtual bool HW_IsIdle() const = 0; - virtual void HW_SetCancelDataCollectionBit() = 0; - virtual void HW_GetStatus(ActionStatus *status) const = 0; - virtual void HW_GetEnvParams(ActionEnvParams *status) const { - memset(status, 0, sizeof(ActionEnvParams)); - } - virtual uint32_t HW_GetIPv4Address() const = 0; - virtual uint64_t HW_GetMACAddress() const = 0; - virtual void HW_EndAction() {}; // do clean-up after action is done - virtual void CopyInternalPacketGenFrameToDeviceBuffer(); -protected: - ThreadSafeFIFO work_completion_queue; - ThreadSafeFIFO work_request_queue; - - std::vector buffer_device; - std::vector internal_pkt_gen_frame; - - uint16_t data_stream; - Logger *logger; - uint32_t max_modules = 1; - - explicit AcquisitionDevice(uint16_t data_stream); - - void UnmapBuffers(); - void MapBuffersStandard(size_t c2h_buffer_count, size_t h2c_buffer_count, int16_t numa_node); -public: - static constexpr const uint64_t HandleNotValid = UINT64_MAX; - - virtual ~AcquisitionDevice() { UnmapBuffers(); }; - - void StartAction(const DiffractionExperiment &experiment); - void PrepareAction(const DiffractionExperiment &experiment); - - void WaitForActionComplete(); - void ActionAbort(); - - void SendWorkRequest(uint32_t handle); - void EnableLogging(Logger *logger); - - // Post measurement statistics - only guaranteed valid after WaitForActionComplete ends - uint64_t GetBytesReceived() const; - - void SaveStatistics(const DiffractionExperiment &experiment, JFJochProtoBuf::AcquisitionDeviceStatistics &statistics) const; - JFJochProtoBuf::FPGAStatus GetStatus() const; - - // Internal frame generator - void SetCustomInternalGeneratorFrame(const std::vector &v); - const std::vector &GetInternalGeneratorFrame() const; - - const int16_t *GetFrameBuffer(size_t frame_number, uint16_t module_number) const; - - void FrameBufferRelease(size_t frame_number, uint16_t module_number); - const int16_t *GetErrorFrameBuffer() const; - - int16_t *GetDeviceBuffer(size_t handle); - - // Calibration - virtual void InitializeCalibration(const DiffractionExperiment &experiment, const JFCalibration &calib); - - uint64_t GetHead(uint8_t module_number) const; - uint64_t GetSlowestHead() const; - void WaitForFrame(size_t curr_frame, uint16_t module_number = UINT16_MAX) const; - int64_t CalculateDelay(size_t curr_frame, uint16_t module_number = UINT16_MAX) const; // mutex acquired indirectly - uint64_t GetBufferHandle(size_t frame, uint8_t module_number) const; - uint64_t GetBunchID(size_t curr_frame, uint16_t module_number) const; - uint32_t GetJFInfo(size_t curr_frame, uint16_t module_number) const; - uint64_t GetTimestamp(size_t curr_frame, uint16_t module_number) const; - uint32_t GetExptime(size_t curr_frame, uint16_t module_number) const; - - bool IsFullModuleCollected(size_t frame, uint8_t module_number) const; - ActionConfig ReadActionRegister(); - bool IsDone() const; - - std::string GetIPv4Address() const; - std::string GetMACAddress() const; - virtual uint16_t GetUDPPort() const; - virtual int32_t GetNUMANode() const; -}; - - -#endif //JUNGFRAUJOCH_ACQUISITIONDEVICE_H diff --git a/receiver/host/AcquisitionOfflineCounters.cpp b/receiver/host/AcquisitionOfflineCounters.cpp deleted file mode 100644 index 2e72bfe8..00000000 --- a/receiver/host/AcquisitionOfflineCounters.cpp +++ /dev/null @@ -1,72 +0,0 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later - -#include "AcquisitionOfflineCounters.h" -#include - -void AcquisitionOfflineCounters::Reset(const DiffractionExperiment &x, uint16_t data_stream) { - std::unique_lock ul(m); - - auto max_entries = x.GetFrameNum() * x.GetModulesNum(data_stream); - completion.clear(); - completion.reserve(max_entries); -} - -void AcquisitionOfflineCounters::Add(Completion c) { - std::unique_lock ul(m); - completion.push_back(c); -} - -void AcquisitionOfflineCounters::FillStatistics(const DiffractionExperiment &x, uint16_t data_stream, - JFJochProtoBuf::AcquisitionDeviceStatistics& statistics) const { - std::unique_lock ul(m); - - if (x.GetFrameNum() == 0) - return; - - auto nmodules = x.GetModulesNum(data_stream); - auto max_entries = x.GetFrameNum() * x.GetModulesNum(data_stream); - - const int masks_per_module = 2; - const int64_t expected_packets_per_module = 128; - - std::vector timestamp(max_entries, UINT32_MAX); - std::vector debug(max_entries, UINT32_MAX); - std::vector bunchid(max_entries, UINT64_MAX); - std::vector packet_mask(masks_per_module * max_entries, 0); - std::vector packet_count(max_entries, 0); - std::vector packets_received_per_module(x.GetModulesNum(data_stream)); - uint64_t total_packets = 0; - - for (const auto &c: completion) { - size_t i = c.frame_number * nmodules + c.module; - timestamp[i] = c.timestamp; - debug[i] = c.debug; - bunchid[i] = c.bunchid; - packet_count[i] = c.packet_count; - total_packets += packet_count[i]; - packets_received_per_module[c.module] += packet_count[i]; - - for (int j = 0; j < masks_per_module; j++) - packet_mask[i * masks_per_module + j] = c.packet_mask[j]; - } - - size_t expected_images = x.GetImageNum(); - if ((x.GetDetectorMode() == DetectorMode::PedestalG0) || - (x.GetDetectorMode() == DetectorMode::PedestalG1) || - (x.GetDetectorMode() == DetectorMode::PedestalG2)) - expected_images = x.GetFrameNum(); - - uint32_t expected_packets = max_entries * expected_packets_per_module; - statistics.set_nmodules(x.GetModulesNum(data_stream)); - statistics.set_packets_expected(expected_packets); - - if ((expected_images == 0) || (total_packets == expected_packets)) - statistics.set_efficiency(1.0); - else - statistics.set_efficiency(static_cast(total_packets) / static_cast(expected_packets)); - - *statistics.mutable_packets_received_per_module() = {packets_received_per_module.begin(), - packets_received_per_module.end()}; - statistics.set_good_packets(total_packets); -} diff --git a/receiver/host/AcquisitionOfflineCounters.h b/receiver/host/AcquisitionOfflineCounters.h deleted file mode 100644 index b4d812bb..00000000 --- a/receiver/host/AcquisitionOfflineCounters.h +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later - -#ifndef JUNGFRAUJOCH_ACQUISITIONOFFLINECOUNTERS_H -#define JUNGFRAUJOCH_ACQUISITIONOFFLINECOUNTERS_H - -#include -#include - -#include - -#include "Completion.h" -#include "../../common/DiffractionExperiment.h" - - -// AcquisitionOfflineCounters is used to store information that will be used AFTER data collection -class AcquisitionOfflineCounters { - std::vector completion; - mutable std::mutex m; -public: - void Reset(const DiffractionExperiment &x, uint16_t data_stream); - void Add(Completion c); - void FillStatistics(const DiffractionExperiment &x, uint16_t data_stream, - JFJochProtoBuf::AcquisitionDeviceStatistics& statistics) const; -}; - - -#endif //JUNGFRAUJOCH_ACQUISITIONOFFLINECOUNTERS_H diff --git a/receiver/host/CMakeLists.txt b/receiver/host/CMakeLists.txt deleted file mode 100644 index 254ee2e7..00000000 --- a/receiver/host/CMakeLists.txt +++ /dev/null @@ -1,50 +0,0 @@ -ADD_LIBRARY(JungfraujochHost STATIC - AcquisitionDevice.cpp AcquisitionDevice.h - AcquisitionOnlineCounters.cpp AcquisitionOnlineCounters.h - MockAcquisitionDevice.cpp MockAcquisitionDevice.h - HLSSimulatedDevice.cpp HLSSimulatedDevice.h - Completion.cpp Completion.h ActionConfig.h - PCIExpressDevice.cpp PCIExpressDevice.h - AcquisitionOfflineCounters.cpp AcquisitionOfflineCounters.h - IBWrappers.cpp IBWrappers.h - MlxRawEthDevice.cpp MlxRawEthDevice.h - ../../jungfrau/jf_packet.h LinuxSocketDevice.cpp LinuxSocketDevice.h FPGAAcquisitionDevice.cpp FPGAAcquisitionDevice.h) - -TARGET_LINK_LIBRARIES(JungfraujochHost CommonFunctions HLSSimulation ${IBVERBS} JFCalibration) - -TARGET_INCLUDE_DIRECTORIES(JungfraujochHost PUBLIC ../../include) - -FIND_LIBRARY(IBVERBS NAMES ibverbs DOC "Infiniband verbs") -IF(IBVERBS) - TARGET_COMPILE_DEFINITIONS(JungfraujochHost PUBLIC -DJFJOCH_USE_IBVERBS) - TARGET_LINK_LIBRARIES(JungfraujochHost ${IBVERBS}) - MESSAGE(STATUS "JFJochReceiver compiled with IBVerbs support") - - ADD_EXECUTABLE(jfjoch_mlx_test jfjoch_mlx_test.cpp) - TARGET_LINK_LIBRARIES(jfjoch_mlx_test JungfraujochHost) - INSTALL(TARGETS jfjoch_mlx_test RUNTIME) -ENDIF() - -ADD_EXECUTABLE(jfjoch_lxsocket_test jfjoch_lxsocket_test.cpp) -TARGET_LINK_LIBRARIES(jfjoch_lxsocket_test JungfraujochHost) -INSTALL(TARGETS jfjoch_lxsocket_test RUNTIME) - -IF(HAS_NUMAIF AND HAS_NUMA_H AND NUMA_LIBRARY) - TARGET_COMPILE_DEFINITIONS(JungfraujochHost PUBLIC -DJFJOCH_USE_NUMA) - TARGET_LINK_LIBRARIES(JungfraujochHost ${NUMA_LIBRARY}) - MESSAGE(STATUS "NUMA memory/CPU pinning enabled") -ELSE() - MESSAGE(WARNING "NUMA memory/CPU pinning disabled") -ENDIF() - -ADD_EXECUTABLE(jfjoch_pcie_status jfjoch_pcie_status.cpp) -TARGET_LINK_LIBRARIES(jfjoch_pcie_status JungfraujochHost) -INSTALL(TARGETS jfjoch_pcie_status RUNTIME) - -ADD_EXECUTABLE(jfjoch_pcie_set_network jfjoch_pcie_set_network.cpp) -TARGET_LINK_LIBRARIES(jfjoch_pcie_set_network JungfraujochHost) -INSTALL(TARGETS jfjoch_pcie_set_network RUNTIME) - -ADD_EXECUTABLE(jfjoch_pcie_clear_net_counters jfjoch_pcie_clear_net_counters.cpp) -TARGET_LINK_LIBRARIES(jfjoch_pcie_clear_net_counters JungfraujochHost) -INSTALL(TARGETS jfjoch_pcie_clear_net_counters RUNTIME) \ No newline at end of file diff --git a/receiver/host/FPGAAcquisitionDevice.cpp b/receiver/host/FPGAAcquisitionDevice.cpp deleted file mode 100644 index a97aeaaa..00000000 --- a/receiver/host/FPGAAcquisitionDevice.cpp +++ /dev/null @@ -1,52 +0,0 @@ -// Copyright (2019-2023) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later - -#include "FPGAAcquisitionDevice.h" - -void FPGAAcquisitionDevice::HW_StartAction() { - FPGA_StartAction(); - - stop_work_requests = false; - send_work_request_future = std::async(std::launch::async, &FPGAAcquisitionDevice::SendWorkRequestThread, this); - - read_work_completion_future = std::async(std::launch::async, &FPGAAcquisitionDevice::ReadWorkCompletionThread, this); -} - -void FPGAAcquisitionDevice::HW_EndAction() { - read_work_completion_future.get(); - - stop_work_requests = true; - send_work_request_future.get(); - - while (!HW_SendWorkRequest(UINT32_MAX)) - std::this_thread::sleep_for(std::chrono::microseconds(10)); - - FPGA_EndAction(); -} - -void FPGAAcquisitionDevice::ReadWorkCompletionThread() { - uint32_t values[12]; - - Completion c; - do { - while (!HW_ReadMailbox(values)) - std::this_thread::sleep_for(std::chrono::microseconds(10)); - - c = parse_hw_completion(values); - work_completion_queue.PutBlocking(c); - } while (c.type != Completion::Type::End); -} - -void FPGAAcquisitionDevice::SendWorkRequestThread() { - while (!stop_work_requests) { - WorkRequest wr{}; - if (work_request_queue.Get(wr)) { - if ( !HW_SendWorkRequest(wr.handle)) { - work_request_queue.Put(wr); - std::this_thread::sleep_for(std::chrono::microseconds(10)); - } - } else { - std::this_thread::sleep_for(std::chrono::microseconds(10)); - } - } -} \ No newline at end of file diff --git a/receiver/host/FPGAAcquisitionDevice.h b/receiver/host/FPGAAcquisitionDevice.h deleted file mode 100644 index 4df98d2c..00000000 --- a/receiver/host/FPGAAcquisitionDevice.h +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright (2019-2023) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later - -#ifndef JUNGFRAUJOCH_FPGAACQUISITIONDEVICE_H -#define JUNGFRAUJOCH_FPGAACQUISITIONDEVICE_H - -#include "AcquisitionDevice.h" - -class FPGAAcquisitionDevice : public AcquisitionDevice { - virtual void FPGA_StartAction() = 0; - virtual void FPGA_EndAction() = 0; - - void HW_StartAction() final; - void HW_EndAction() final; - - std::future read_work_completion_future; - void ReadWorkCompletionThread(); - - std::future send_work_request_future; - volatile bool stop_work_requests = false; - void SendWorkRequestThread(); - - virtual bool HW_ReadMailbox(uint32_t values[16]) = 0; - virtual bool HW_SendWorkRequest(uint32_t handle) = 0; -protected: - explicit FPGAAcquisitionDevice(uint16_t data_stream) : AcquisitionDevice(data_stream) {} -}; - - -#endif //JUNGFRAUJOCH_FPGAACQUISITIONDEVICE_H diff --git a/receiver/host/LinuxSocketDevice.h b/receiver/host/LinuxSocketDevice.h deleted file mode 100644 index f56f7c77..00000000 --- a/receiver/host/LinuxSocketDevice.h +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later - -#ifndef JUNGFRAUJOCH_LINUXSOCKETDEVICE_H -#define JUNGFRAUJOCH_LINUXSOCKETDEVICE_H - -#include -#include "../../jungfrau/ProcessJFPacket.h" -#include "AcquisitionDevice.h" - -class LinuxSocketDevice : public AcquisitionDevice { - int32_t rcv_buf_size; - - uint64_t mac_addr; - uint32_t ipv4_addr; - uint16_t udp_port; - ActionConfig cfg; - const int16_t numa_node; - - std::future measure; - - volatile bool cancel = false; - volatile bool idle = true; - - void HW_WriteActionRegister(const ActionConfig *job) override; - void HW_ReadActionRegister(ActionConfig *job) override; - void HW_StartAction() override; - bool HW_IsIdle() const override; - void HW_SetCancelDataCollectionBit() override; - void HW_GetStatus(ActionStatus *status) const override; - uint64_t HW_GetMACAddress() const override; - uint32_t HW_GetIPv4Address() const override; - void HW_EndAction() override; - void CopyInternalPacketGenFrameToDeviceBuffer() override; - void MeasureThread(int fd); - void FindMACAddress(); -public: - LinuxSocketDevice(uint32_t ipv4_addr, uint16_t udp_port, - uint16_t data_stream, size_t frame_buffer_size_modules, - int32_t rcv_buf_size = -1, int16_t in_numa_node = -1); - ~LinuxSocketDevice() override = default; - - void InitializeCalibration(const DiffractionExperiment &experiment, const JFCalibration &calib) override; - int32_t GetNUMANode() const override; - uint16_t GetUDPPort() const override; -}; - - -#endif //JUNGFRAUJOCH_LINUXSOCKETDEVICE_H diff --git a/receiver/host/MockAcquisitionDevice.cpp b/receiver/host/MockAcquisitionDevice.cpp deleted file mode 100644 index 1571aab9..00000000 --- a/receiver/host/MockAcquisitionDevice.cpp +++ /dev/null @@ -1,86 +0,0 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later - -#include "MockAcquisitionDevice.h" -#include "../../common/JFJochException.h" -#include - -void MockAcquisitionDevice::HW_ReadActionRegister(ActionConfig *job) { - memcpy(job, &cfg, sizeof(ActionConfig)); -} - -void MockAcquisitionDevice::HW_WriteActionRegister(const ActionConfig *job) { - memcpy(&cfg, job, sizeof(ActionConfig)); -} - -void MockAcquisitionDevice::HW_StartAction() {} - -void MockAcquisitionDevice::HW_SetCancelDataCollectionBit() { - if (logger) - logger->Info("MockAcquisitionDevice cancelling " + std::to_string(data_stream)); - Terminate(); -} - -bool MockAcquisitionDevice::HW_IsIdle() const { - return true; -} - -MockAcquisitionDevice::MockAcquisitionDevice(uint16_t data_stream, size_t in_frame_buffer_size_modules) -: AcquisitionDevice(data_stream) { - max_modules = 16; - MapBuffersStandard(in_frame_buffer_size_modules, 1, -1); - max_handle = in_frame_buffer_size_modules; - work_completion_queue.Put(Completion{.type = Completion::Type::Start}); -} - -void MockAcquisitionDevice::SendCompletion(uint32_t handle, uint16_t module_number, uint64_t frame_number) { - Completion c; - c.handle = handle; - c.module = module_number; - c.frame_number = frame_number - 1; - c.type = Completion::Type::Image; - c.packet_mask[0] = UINT64_MAX; - c.packet_mask[1] = UINT64_MAX; - c.packet_count = 128; - work_completion_queue.Put(c); -} - -void MockAcquisitionDevice::AddModule(uint64_t frame_number, uint16_t module_number, const uint16_t *data) { - - if (module_number >= max_modules) - throw JFJochException(JFJochExceptionCategory::ArrayOutOfBounds, - "Module number exceeding limit"); - - if (current_handle < max_handle) { - memcpy(buffer_device.at(current_handle), data, RAW_MODULE_SIZE * sizeof(uint16_t)); - SendCompletion(current_handle, module_number, frame_number); - current_handle++; - } else { - throw JFJochException(JFJochExceptionCategory::ArrayOutOfBounds, "No buffer handles left"); - } -} - -void MockAcquisitionDevice::Terminate() { - work_completion_queue.Put(Completion{ - .type = Completion::Type::End, - .frame_number = current_handle * 128 - }); - work_completion_queue.Put(Completion{.type = Completion::Type::Start}); -} - -uint64_t MockAcquisitionDevice::HW_GetMACAddress() const { - return 0; // Doesn't matter -} - -uint32_t MockAcquisitionDevice::HW_GetIPv4Address() const { - return 0; -} - -void MockAcquisitionDevice::HW_GetStatus(ActionStatus *status) const { - memset(status, 0, sizeof(ActionStatus)); - status->max_modules = max_modules; - status->modules_internal_packet_generator = 1; -} - -void MockAcquisitionDevice::CopyInternalPacketGenFrameToDeviceBuffer() {} -void MockAcquisitionDevice::InitializeCalibration(const DiffractionExperiment &experiment, const JFCalibration &calib) {} diff --git a/receiver/host/MockAcquisitionDevice.h b/receiver/host/MockAcquisitionDevice.h deleted file mode 100644 index 0af04f15..00000000 --- a/receiver/host/MockAcquisitionDevice.h +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later - -#ifndef JUNGFRAUJOCH_MOCKACQUISITIONDEVICE_H -#define JUNGFRAUJOCH_MOCKACQUISITIONDEVICE_H - -#include "AcquisitionDevice.h" -#include "../../common/ThreadSafeFIFO.h" - -class MockAcquisitionDevice : public AcquisitionDevice { - uint32_t current_handle = 0; - uint32_t max_handle = 0; - ActionConfig cfg; - - void SendCompletion(uint32_t handle, uint16_t module_number, uint64_t frame_number); - constexpr static const uint32_t frames_int_pkt_gen = 1; - void HW_ReadActionRegister(ActionConfig *job) override; - void HW_WriteActionRegister(const ActionConfig *job) override; - void HW_StartAction() override; - - void HW_SetCancelDataCollectionBit() override; - bool HW_IsIdle() const override; - uint64_t HW_GetMACAddress() const override; - uint32_t HW_GetIPv4Address() const override; - void HW_GetStatus(ActionStatus *status) const override; - void CopyInternalPacketGenFrameToDeviceBuffer() override; -public: - MockAcquisitionDevice(uint16_t data_stream, size_t in_frame_buffer_size_modules); - void AddModule(uint64_t frame, uint16_t module_number, const uint16_t *data); - void Terminate(); - void InitializeCalibration(const DiffractionExperiment &experiment, const JFCalibration &calib) override; -}; - -#endif //JUNGFRAUJOCH_MOCKACQUISITIONDEVICE_H diff --git a/receiver/jfjoch_action_test.cpp b/receiver/jfjoch_action_test.cpp index af6b27bd..5c4980a4 100644 --- a/receiver/jfjoch_action_test.cpp +++ b/receiver/jfjoch_action_test.cpp @@ -1,71 +1,167 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (2019-2023) Paul Scherrer Institute #include -#include "host/PCIExpressDevice.h" +#include "PCIExpressDevice.h" +#include "MockAcquisitionDevice.h" #include "JFJochReceiverTest.h" #include "../tests/FPGAUnitTest.h" +void print_usage(Logger &logger) { + logger.Info("Usage ./jfjoch_action_test {} "); + logger.Info("Options:"); + logger.Info(" -C conversion on CPU"); + logger.Info(" -M use mock device"); + logger.Info(" -B blocking mode (FPGA)"); + logger.Info(" -v verbose"); + logger.Info(" -H mock aq. dev. with HBM (DL380 with Intel MAX only)"); + logger.Info(" -D mock aq. dev. with DDR (2 NUMA node machines only)"); + logger.Info(" -s number of data streams (acquisition devices)"); + logger.Info(" -m number of modules per data stream"); + logger.Info(" -i number of images"); + logger.Info(" -p data processing period"); + logger.Info(" -N number of image processing threads"); + logger.Info(" -P NUMA Policy (none|n2g2|n8g4|n8g4_hbm), none is default"); +} + int main(int argc, char **argv) { + Logger logger("ActionTest"); + logger.Verbose(true); + + constexpr uint64_t clock_MHz = 200; uint16_t nstreams = 1; uint16_t nmodules = 1; size_t nimages = 2; uint64_t processing_period = 20; + uint16_t nthreads = 64; + bool conversion_on_cpu = false; + bool use_mock_device = false; + bool nonblocking_mode = true; + bool verbose = false; + std::string numa_policy_name; + bool use_hbm_for_aq_dev = false; + bool use_ddr_for_aq_dev = false; - Logger logger("ActionTest"); - logger.Verbose(true); + if (argc == 1) + print_usage(logger); - bool abort_test = false; - - if ((argc == 1) || (argc > 6)) { - logger.Error("Usage ./jfjoch_action_test {<# of images> {<# of modules> {<# of streams> {}}}}"); - exit(EXIT_FAILURE); + int opt; + while ((opt = getopt(argc, argv, "s:i:m:p:N:P:CMBvHD")) != -1) { + switch (opt) { + case 'C': + conversion_on_cpu = true; + break; + case 'M': + use_mock_device = true; + break; + case 'B': + nonblocking_mode = false; + break; + case 'i': + nimages = atol(optarg); + break; + case 'm': + nmodules = atol(optarg); + break; + case 's': + nstreams = atol(optarg); + break; + case 'p': + processing_period = atol(optarg); + break; + case 'N': + nthreads = atol(optarg); + break; + case 'v': + verbose = true; + break; + case 'P': + numa_policy_name = std::string(optarg); + break; + case 'H': + use_hbm_for_aq_dev = true; + break; + case 'D': + use_ddr_for_aq_dev = true; + break; + default: /* '?' */ + print_usage(logger); + exit(EXIT_FAILURE); + } } - if (argc >= 3) nimages = atol(argv[2]); - if (argc >= 4) nmodules = atol(argv[3]); - if (argc >= 5) nstreams = atoi(argv[4]); - if (argc >= 6) processing_period = atoi(argv[5]); + if (optind != argc - 1) { + print_usage(logger); + exit(EXIT_FAILURE); + } DiffractionExperiment x(DetectorGeometry(nmodules*nstreams, 2, 8, 36, true)); x.Mode(DetectorMode::Conversion); x.ImagesPerTrigger(nimages).PedestalG0Frames(0).UseInternalPacketGenerator(true).PhotonEnergy_keV(12.4).NumTriggers(1); - x.SpotFindingPeriod(std::chrono::milliseconds(processing_period)).MaskModuleEdges(false).MaskChipEdges(false); + x.SpotFindingPeriod(std::chrono::milliseconds(processing_period)).MaskModuleEdges(false).MaskChipEdges(false).ConversionOnCPU(conversion_on_cpu); x.Compression(JFJochProtoBuf::BSHUF_LZ4).DataStreams(nstreams); + logger.Info("Data streams {} Total modules {} Total images {} Threads {}", nstreams, nstreams * nmodules, nimages, nthreads); + std::vector dev_name = { "/dev/jfjoch0", "/dev/jfjoch2", "/dev/jfjoch1", "/dev/jfjoch3" }; - std::vector numa_node = {0,1,0,1}; - bool verbose = false; - bool print_status_updates = true; - uint16_t nthreads = 64; - uint64_t clock_MHz = 200; logger.Verbose(verbose); - if (nstreams > dev_name.size()) { - logger.Error("Only {} data streams allowed on this platform", dev_name.size()); - exit(EXIT_FAILURE); - } - - std::vector> oc_devices; + std::vector> pcie_devices; + std::vector> mock_devices; std::vector aq_devices; - std::string image_path = std::string(argv[1]) + "/tests/test_data/mod5_raw0.bin"; + std::string image_path = std::string(argv[optind]) + "/tests/test_data/mod5_raw0.bin"; std::vector input(RAW_MODULE_SIZE, 0); LoadBinaryFile(image_path, input.data(), RAW_MODULE_SIZE); - for (int i = 0; i < nstreams; i++) { - oc_devices.push_back(std::make_unique(dev_name[i], i)); - oc_devices[i]->SetCustomInternalGeneratorFrame(input); - oc_devices[i]->EnableLogging(&logger); - aq_devices.push_back(oc_devices[i].get()); + if (use_mock_device) { + if (nmodules > 1) { + logger.Warning("Conversion results will be wrong with more than 1 module per stream"); + } + + for (int i = 0; i < nstreams; i++) { + int16_t numa_node = -1; + + if (use_hbm_for_aq_dev) + numa_node = 2 + (i % 2); + else if (use_ddr_for_aq_dev) + numa_node = i % 2; + + if (numa_node != -1) + logger.Info("Pinning stream {} to NUMA node {}", i, numa_node); + + mock_devices.push_back(std::make_unique(i, 1024, numa_node)); + mock_devices[i]->SetCustomInternalGeneratorFrame(input); + mock_devices[i]->EnableLogging(&logger); + aq_devices.push_back(mock_devices[i].get()); + } + + } else { + if (nstreams > dev_name.size()) { + logger.Error("Only {} data streams allowed on this platform", dev_name.size()); + exit(EXIT_FAILURE); + } + + for (int i = 0; i < nstreams; i++) { + pcie_devices.push_back(std::make_unique(dev_name[i], i)); + pcie_devices[i]->SetCustomInternalGeneratorFrame(input); + pcie_devices[i]->EnableLogging(&logger); + pcie_devices[i]->SetFPGANonBlockingMode(nonblocking_mode); + pcie_devices[i]->SetDefaultMAC(); + pcie_devices[i]->SetIPv4Address((i << 24) + 0x010a0a0a); + aq_devices.push_back(pcie_devices[i].get()); + } + + if (!nonblocking_mode) + logger.Warning( + "FPGA uses blocking mode - in case data acquisition is aborted, it is necessary to cold reboot the machine"); } volatile bool done = false; @@ -73,7 +169,7 @@ int main(int argc, char **argv) { bool ret; std::thread run_thread([&] { try { - ret = JFJochReceiverTest(output, logger, aq_devices, x, nthreads,abort_test, verbose); + ret = JFJochReceiverTest(output, logger, aq_devices, x, nthreads, false, verbose, nullptr, numa_policy_name); } catch (std::exception &e) { logger.Error(e.what()); ret = false; @@ -81,10 +177,10 @@ int main(int argc, char **argv) { done = true; }); - if (print_status_updates) { + if (!use_mock_device) { while (!done) { for (int i = 0; i < nstreams; i++) { - auto status = oc_devices[i]->GetStatus(); + auto status = pcie_devices[i]->GetStatus(); logger.Info("Device {}: Head packet: {:8d} Power: {:5.1f} W FPGA Temp: {:d} degC HBM Temp: {:d}/{:d} degC Stalls: {:15d}", i, status.slowest_head(), status.current_edge_12v_a() * status.voltage_edge_12v_v() + status.current_edge_3p3v_a() * status.voltage_edge_3p3v_v(), @@ -99,38 +195,41 @@ int main(int argc, char **argv) { double receiving_time = static_cast(output.end_time_ms() - output.start_time_ms())/1000.0; + logger.Info("Efficiency: {:.2f}%", output.efficiency() * 100.f); logger.Info("Max delay: {}",output.max_receive_delay()); - logger.Info("Compression ratio: {}", output.compressed_ratio()); + logger.Info("Compression factor: {}x", output.compressed_ratio()); logger.Info("Receiving time: {} s", receiving_time); logger.Info("Frame rate: {} Hz", static_cast(nimages)/receiving_time); logger.Info("Total throughput: {:.2f} GB/s", static_cast(nimages*nstreams*nmodules*RAW_MODULE_SIZE*sizeof(uint16_t)) / (receiving_time * 1e9)); - logger.Info(""); - for (int i = 0; i < nstreams; i++) { - auto stalls_hbm = output.device_statistics(i).fpga_status().stalls_hbm(); - auto stalls_host = output.device_statistics(i).fpga_status().stalls_host(); - uint64_t throughput_MBs = nimages * nmodules * RAW_MODULE_SIZE*sizeof(uint16_t) * clock_MHz / (nimages * nmodules * 128 * 128 + stalls_hbm); - double performance = static_cast(throughput_MBs) / 1000; - // Assuming 250 MHz clock - logger.Info("Device {}: stalls HBM: {} stalls host: {} est. performance: {:.2f} GB/s", i, stalls_hbm, stalls_host, performance); + if (!use_mock_device) { + logger.Info(""); + for (int i = 0; i < nstreams; i++) { + auto stalls_hbm = output.device_statistics(i).fpga_status().stalls_hbm(); + auto stalls_host = output.device_statistics(i).fpga_status().stalls_host(); - if (output.device_statistics(i).fpga_status().frame_statistics_alignment_err()) - logger.Error("Device {}: memory alignment error", i); - if (output.device_statistics(i).fpga_status().frame_statistics_tlast_err()) - logger.Error("Device {}: error in AXI-Stream sequence", i); - if (output.device_statistics(i).fpga_status().frame_statistics_work_req_err()) - logger.Error("Device {}: parity error in work request", i); - if (output.device_statistics(i).fpga_status().datamover_s2mm_error()) - logger.Error("Device {}: AXI-Stream to AXImm error", i); - if (output.device_statistics(i).fpga_status().mailbox_err_reg() != 0) - logger.Error("Device {}: Mailbox error {:x}", i, - output.device_statistics(i).fpga_status().mailbox_err_reg()); + uint64_t throughput_MBs = nimages * nmodules * RAW_MODULE_SIZE * sizeof(uint16_t) * clock_MHz / + (nimages * nmodules * 128 * 128 + stalls_hbm); + double performance = static_cast(throughput_MBs) / 1000; + + logger.Info("Device {}: stalls HBM: {} stalls host: {} est. performance: {:.2f} GB/s", i, stalls_hbm, + stalls_host, performance); + + for (const auto &iter: output.device_statistics(i).fpga_status().host_writer_err()) + logger.Error("Device {}: FPGA host writer error {}", i, iter); + + if (output.device_statistics(i).fpga_status().mailbox_err_reg() != 0) + logger.Error("Device {}: Mailbox error {:x}", i, + output.device_statistics(i).fpga_status().mailbox_err_reg()); + } } - if (ret) { + logger.Info(""); logger.Info("Test properly executed! (check stall values manually)"); exit(EXIT_SUCCESS); - } else + } else { + logger.Info("Test finished with errors! (check stall values manually)"); exit(EXIT_FAILURE); + } } diff --git a/receiver/host/jfjoch_lxsocket_test.cpp b/receiver/jfjoch_lxsocket_test.cpp similarity index 92% rename from receiver/host/jfjoch_lxsocket_test.cpp rename to receiver/jfjoch_lxsocket_test.cpp index 650552bc..a1eb4cba 100644 --- a/receiver/host/jfjoch_lxsocket_test.cpp +++ b/receiver/jfjoch_lxsocket_test.cpp @@ -1,5 +1,4 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (2019-2023) Paul Scherrer Institute #include "LinuxSocketDevice.h" #include "../common/NetworkAddressConvert.h" diff --git a/receiver/host/jfjoch_mlx_test.cpp b/receiver/jfjoch_mlx_test.cpp similarity index 90% rename from receiver/host/jfjoch_mlx_test.cpp rename to receiver/jfjoch_mlx_test.cpp index 899127f5..7733c9b3 100644 --- a/receiver/host/jfjoch_mlx_test.cpp +++ b/receiver/jfjoch_mlx_test.cpp @@ -1,5 +1,4 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (2019-2023) Paul Scherrer Institute #include "MlxRawEthDevice.h" #include "../common/NetworkAddressConvert.h" diff --git a/receiver/jfjoch_pcie_cancel_data_collection.cpp b/receiver/jfjoch_pcie_cancel_data_collection.cpp new file mode 100644 index 00000000..0a578299 --- /dev/null +++ b/receiver/jfjoch_pcie_cancel_data_collection.cpp @@ -0,0 +1,25 @@ +// Copyright (2019-2023) Paul Scherrer Institute + +#include + +#include "../common/JFJochException.h" +#include "PCIExpressDevice.h" +#include "../common/Logger.h" + +int main(int argc, char **argv) { + Logger logger("jfjoch_pcie_cancel_data_collection"); + + if (argc != 2) { + logger.Error("Usage: ./jfjoch_pcie_cancel_data_collection "); + exit(EXIT_FAILURE); + } + logger.Info("Device {}", argv[1]); + std::cout << std::endl; + try { + PCIExpressDevice test(argv[1], 0); + test.Cancel(); + logger.Info("Done"); + } catch (const JFJochException &e) { + logger.ErrorException(e); + } +} \ No newline at end of file diff --git a/receiver/host/jfjoch_pcie_clear_net_counters.cpp b/receiver/jfjoch_pcie_clear_net_counters.cpp similarity index 86% rename from receiver/host/jfjoch_pcie_clear_net_counters.cpp rename to receiver/jfjoch_pcie_clear_net_counters.cpp index f0ef230f..ea6692fd 100644 --- a/receiver/host/jfjoch_pcie_clear_net_counters.cpp +++ b/receiver/jfjoch_pcie_clear_net_counters.cpp @@ -1,5 +1,4 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (2019-2023) Paul Scherrer Institute #include diff --git a/receiver/jfjoch_pcie_read_int_packet_gen.cpp b/receiver/jfjoch_pcie_read_int_packet_gen.cpp new file mode 100644 index 00000000..7a2fbfc3 --- /dev/null +++ b/receiver/jfjoch_pcie_read_int_packet_gen.cpp @@ -0,0 +1,34 @@ +// Copyright (2019-2023) Paul Scherrer Institute + +#include + +#include "../common/JFJochException.h" +#include "PCIExpressDevice.h" +#include "../common/Logger.h" +#include + +int main(int argc, char **argv) { + Logger logger("jfjoch_pcie_read_int_packet_gen"); + + if (argc != 2) { + logger.Error("Usage: ./jfjoch_pcie_read_int_packet_gen "); + exit(EXIT_FAILURE); + } + logger.Info("Device {}", argv[1]); + std::cout << std::endl; + try { + PCIExpressDevice test(argv[1], 0); + + std::vector data(RAW_MODULE_SIZE*2); + + test.HW_ReadInternalPacketGen((uint16_t *) data.data()); + + std::ofstream file("out.bin", std::ios::binary); + file.write((char *) data.data(), data.size()); + file.close(); + + logger.Info("Done"); + } catch (const JFJochException &e) { + logger.ErrorException(e); + } +} \ No newline at end of file diff --git a/receiver/host/jfjoch_pcie_set_network.cpp b/receiver/jfjoch_pcie_set_network.cpp similarity index 73% rename from receiver/host/jfjoch_pcie_set_network.cpp rename to receiver/jfjoch_pcie_set_network.cpp index 2534b95e..bc8c38e3 100644 --- a/receiver/host/jfjoch_pcie_set_network.cpp +++ b/receiver/jfjoch_pcie_set_network.cpp @@ -1,10 +1,9 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (2019-2023) Paul Scherrer Institute -#include "../../common/Logger.h" -#include "../../common/JFJochException.h" +#include "../common/Logger.h" +#include "../common/JFJochException.h" #include "PCIExpressDevice.h" -#include "../../common/NetworkAddressConvert.h" +#include "../common/NetworkAddressConvert.h" int main(int argc, char **argv) { Logger logger("jfjoch_pcie_set_network"); diff --git a/receiver/host/jfjoch_pcie_status.cpp b/receiver/jfjoch_pcie_status.cpp similarity index 76% rename from receiver/host/jfjoch_pcie_status.cpp rename to receiver/jfjoch_pcie_status.cpp index 6869963b..7a159b72 100644 --- a/receiver/host/jfjoch_pcie_status.cpp +++ b/receiver/jfjoch_pcie_status.cpp @@ -1,5 +1,4 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (2019-2023) Paul Scherrer Institute #include #include @@ -33,7 +32,10 @@ int main(int argc, char **argv) { std::cout << "FPGA temperature " << status.fpga_temp_degc() << std::endl; std::cout << "HBM temperature #0 " << status.hbm_temp_0_degc() << std::endl; std::cout << "HBM temperature #1 " << status.hbm_temp_1_degc() << std::endl; - std::cout << "Idle " << status.fpga_idle() << std::endl; + std::cout << "HBM size (MiB) " << status.hbm_size_bytes() / static_cast(1024 * 1024) << std::endl; + std::cout << "Data collection idle " << status.fpga_idle() << std::endl; + std::cout << "Host writer idle " << status.host_writer_idle() << std::endl; + std::cout << "Data collection cancel " << status.cancel_bit() << std::endl; std::cout << "Full status register " << std::bitset<32>(status.full_status_register()) << std::endl; @@ -43,28 +45,37 @@ int main(int argc, char **argv) { ActionConfig cfg = test.ReadActionRegister(); std::cout << "MAC address " << test.GetMACAddress() << std::endl; std::cout << "IPv4 address " << test.GetIPv4Address() << std::endl; - std::cout << "Mode " << std::hex << cfg.mode << std::dec << std::endl; + std::cout << "Data collection mode (hex) " << std::hex << (cfg.mode & 0xFFFF) << std::dec << std::endl; + std::cout << "Data collection ID (hex) " << std::hex << ((cfg.mode & 0xFFFF0000) >> 16) << std::dec << std::endl; std::cout << "Modules " << std::dec << cfg.nmodules << std::endl; std::cout << "Frames int. pkt. gen. " << std::dec << cfg.nframes << std::endl; std::cout << std::endl; std::cout << "FPGA FIFO status: " << std::endl; - for (const auto &[x,y]: status.fifo_status()) { - std::string s = x; + for (const auto &i: status.fifo_status()) { + std::string s = i.name(); s.resize(28, ' '); - switch (y) { - case JFJochProtoBuf::FPGAFIFOStatus::PARTIAL: - s += "Partial"; - break; - case JFJochProtoBuf::FPGAFIFOStatus::EMPTY: + switch (i.value()) { + case JFJochProtoBuf::FPGAFIFOStatusEnum::EMPTY: s += "Empty"; break; - case JFJochProtoBuf::FPGAFIFOStatus::FULL: + case JFJochProtoBuf::FPGAFIFOStatusEnum::FULL: s += "Full"; break; + case JFJochProtoBuf::FPGAFIFOStatusEnum::PARTIAL: + s += "Partial"; + break; + default: + break; } std::cout << s << std::endl; } + if (!status.host_writer_err().empty()) { + std::cout << "FPGA host writer errors: " << std::endl; + for (const auto &i: status.host_writer_err()) + std::cout << " " << i << std::endl; + } + std::cout << std::endl; std::cout << "Packet counters - ETH " << status.packets_ether() << std::endl; std::cout << " - UDP " << status.packets_udp() << std::endl; diff --git a/receiver/jfjoch_receiver.cpp b/receiver/jfjoch_receiver.cpp index d50c7a33..6d8271fa 100644 --- a/receiver/jfjoch_receiver.cpp +++ b/receiver/jfjoch_receiver.cpp @@ -1,17 +1,16 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (2019-2023) Paul Scherrer Institute #include "nlohmann/json.hpp" #include #include "../grpc/gRPCServer_Template.h" #include "../common/ZMQImagePusher.h" -#include "host/PCIExpressDevice.h" -#include "host/MlxRawEthDevice.h" -#include "host/LinuxSocketDevice.h" +#include "PCIExpressDevice.h" +#include "MlxRawEthDevice.h" +#include "LinuxSocketDevice.h" #include "JFJochReceiverService.h" -#include "host/HLSSimulatedDevice.h" +#include "HLSSimulatedDevice.h" #include "../common/NetworkAddressConvert.h" AcquisitionDevice *SetupAcquisitionDevice(const nlohmann::json &input, uint16_t data_stream) { @@ -48,9 +47,18 @@ AcquisitionDevice *SetupAcquisitionDevice(const nlohmann::json &input, uint16_t pci_dev->SetMACAddress(MacAddressFromStr(input["mac_addr"].get())); else pci_dev->SetDefaultMAC(); + + if (input.contains("custom_test_frame")) { + std::vector tmp(RAW_MODULE_SIZE); + auto filename = input["custom_test_frame"].get(); + std::fstream file(filename.c_str(), std::fstream::in | std::fstream::binary); + file.read((char *) tmp.data(), RAW_MODULE_SIZE * sizeof(uint16_t)); + pci_dev->SetCustomInternalGeneratorFrame(tmp); + } ret = pci_dev; + } #ifdef JFJOCH_USE_IBVERBS - } else if (input.contains("type") && (input["type"] == "mlx_raw_eth")) { + else if (input.contains("type") && (input["type"] == "mlx_raw_eth")) { auto mlx_dev = new MlxRawEthDevice(pci_slot, data_stream, frame_buffer_size, numa_node); mlx_dev->SetIPv4Address(ipv4_addr); mlx_dev->SetMACAddress(MacAddressFromStr(input["mac_addr"].get())); @@ -59,14 +67,6 @@ AcquisitionDevice *SetupAcquisitionDevice(const nlohmann::json &input, uint16_t #endif else throw JFJochException(JFJochExceptionCategory::InputParameterInvalid, "Unsupported device type"); - if (input.contains("custom_test_frame")) { - std::vector tmp(RAW_MODULE_SIZE); - auto filename = input["custom_test_frame"].get(); - std::fstream file(filename.c_str(), std::fstream::in | std::fstream::binary); - file.read((char *) tmp.data(),RAW_MODULE_SIZE * sizeof(uint16_t)); - ret->SetCustomInternalGeneratorFrame(tmp); - } - return ret; } @@ -152,9 +152,9 @@ int main(int argc, char **argv) { } if (input.contains("preview_indexed_zmq_addr")) { - preview_indexed = std::make_unique(context, input["preview_zmq_addr"]); - service.PreviewPublisher(preview_indexed.get()); - logger.Info("Preview available on ZMQ addr " + input["preview_indexed_zmq_addr"].get()); + preview_indexed = std::make_unique(context, input["preview_indexed_zmq_addr"]); + service.PreviewPublisherIndexed(preview_indexed.get()); + logger.Info("Preview available for indexed frames on ZMQ addr " + input["preview_indexed_zmq_addr"].get()); } if (input.contains("compression_threads")) { diff --git a/receiver/scripts/pcie_dma.tcl b/receiver/scripts/pcie_dma.tcl deleted file mode 100644 index f4dc738a..00000000 --- a/receiver/scripts/pcie_dma.tcl +++ /dev/null @@ -1,442 +0,0 @@ -## Copyright (2019-2022) Paul Scherrer Institute -## SPDX-License-Identifier: CERN-OHL-S-2.0 - -# Hierarchical cell: pcie_dma_0 -proc create_hier_cell_pcie_dma_0 { parentCell nameHier } { - - variable script_folder - - if { $parentCell eq "" || $nameHier eq "" } { - catch {common::send_gid_msg -ssname BD::TCL -id 2092 -severity "ERROR" "create_hier_cell_pcie_dma() - Empty argument(s)!"} - return - } - - # Get object for parentCell - set parentObj [get_bd_cells $parentCell] - if { $parentObj == "" } { - catch {common::send_gid_msg -ssname BD::TCL -id 2090 -severity "ERROR" "Unable to find parent cell <$parentCell>!"} - return - } - - # Make sure parentObj is hier blk - set parentType [get_property TYPE $parentObj] - if { $parentType ne "hier" } { - catch {common::send_gid_msg -ssname BD::TCL -id 2091 -severity "ERROR" "Parent <$parentObj> has TYPE = <$parentType>. Expected to be ."} - return - } - - # Save current instance; Restore later - set oldCurInst [current_bd_instance .] - - # Set parent object as current - current_bd_instance $parentObj - - # Create cell and set as current instance - set hier_obj [create_bd_cell -type hier $nameHier] - current_bd_instance $hier_obj - - # Create interface pins - create_bd_intf_pin -mode Master -vlnv xilinx.com:interface:aximm_rtl:1.0 m_axi_ctrl - - create_bd_intf_pin -mode Master -vlnv xilinx.com:interface:axis_rtl:1.0 m_axis_h2c_data - - create_bd_intf_pin -mode Master -vlnv xilinx.com:interface:pcie_7x_mgt_rtl:1.0 pcie_mgt - - create_bd_intf_pin -mode Slave -vlnv xilinx.com:interface:diff_clock_rtl:1.0 pcie_refclk - - create_bd_intf_pin -mode Slave -vlnv xilinx.com:interface:aximm_rtl:1.0 s_axi_dma_ctrl - - create_bd_intf_pin -mode Slave -vlnv xilinx.com:interface:axis_rtl:1.0 s_axis_c2h_cmd - - create_bd_intf_pin -mode Slave -vlnv xilinx.com:interface:axis_rtl:1.0 s_axis_c2h_data - - create_bd_intf_pin -mode Slave -vlnv xilinx.com:interface:axis_rtl:1.0 s_axis_h2c_cmd - - - # Create pins - create_bd_pin -dir O -type clk axi_aclk - create_bd_pin -dir O -type rst axi_aresetn - create_bd_pin -dir I -type rst axi_clk_resetn - create_bd_pin -dir I -type rst pcie_perstn - create_bd_pin -dir I -type clk refclk200 - create_bd_pin -dir I -type rst refclk200_resetn - create_bd_pin -dir I usr_irq_req - - # Create instance: axi_firewall_0, and set properties - set axi_firewall_0 [ create_bd_cell -type ip -vlnv xilinx.com:ip:axi_firewall:1.2 axi_firewall_0 ] - - # Create instance: axis_clock_converter_c2h_cmd, and set properties - set axis_clock_converter_c2h_cmd [ create_bd_cell -type ip -vlnv xilinx.com:ip:axis_clock_converter:1.1 axis_clock_converter_c2h_cmd ] - set_property -dict [ list \ - CONFIG.SYNCHRONIZATION_STAGES {3} \ - ] $axis_clock_converter_c2h_cmd - - # Create instance: axis_clock_converter_c2h_data, and set properties - set axis_clock_converter_c2h_data [ create_bd_cell -type ip -vlnv xilinx.com:ip:axis_clock_converter:1.1 axis_clock_converter_c2h_data ] - set_property -dict [ list \ - CONFIG.SYNCHRONIZATION_STAGES {3} \ - ] $axis_clock_converter_c2h_data - - # Create instance: axis_clock_converter_h2c_cmd, and set properties - set axis_clock_converter_h2c_cmd [ create_bd_cell -type ip -vlnv xilinx.com:ip:axis_clock_converter:1.1 axis_clock_converter_h2c_cmd ] - set_property -dict [ list \ - CONFIG.SYNCHRONIZATION_STAGES {3} \ - ] $axis_clock_converter_h2c_cmd - - # Create instance: axis_clock_converter_h2c_data, and set properties - set axis_clock_converter_h2c_data [ create_bd_cell -type ip -vlnv xilinx.com:ip:axis_clock_converter:1.1 axis_clock_converter_h2c_data ] - set_property -dict [ list \ - CONFIG.SYNCHRONIZATION_STAGES {3} \ - ] $axis_clock_converter_h2c_data - - # Create instance: gen_xdma_descriptor_c2h, and set properties - set block_name gen_xdma_descriptor - set block_cell_name gen_xdma_descriptor_c2h - if { [catch {set gen_xdma_descriptor_c2h [create_bd_cell -type module -reference $block_name $block_cell_name] } errmsg] } { - catch {common::send_gid_msg -ssname BD::TCL -id 2095 -severity "ERROR" "Unable to add referenced block <$block_name>. Please add the files for ${block_name}'s definition into the project."} - return 1 - } elseif { $gen_xdma_descriptor_c2h eq "" } { - catch {common::send_gid_msg -ssname BD::TCL -id 2096 -severity "ERROR" "Unable to referenced block <$block_name>. Please add the files for ${block_name}'s definition into the project."} - return 1 - } - - # Create instance: gen_xdma_descriptor_h2c, and set properties - set block_name gen_xdma_descriptor - set block_cell_name gen_xdma_descriptor_h2c - if { [catch {set gen_xdma_descriptor_h2c [create_bd_cell -type module -reference $block_name $block_cell_name] } errmsg] } { - catch {common::send_gid_msg -ssname BD::TCL -id 2095 -severity "ERROR" "Unable to add referenced block <$block_name>. Please add the files for ${block_name}'s definition into the project."} - return 1 - } elseif { $gen_xdma_descriptor_h2c eq "" } { - catch {common::send_gid_msg -ssname BD::TCL -id 2096 -severity "ERROR" "Unable to referenced block <$block_name>. Please add the files for ${block_name}'s definition into the project."} - return 1 - } - - # Create instance: pcie_clk_buf_inst, and set properties - set pcie_clk_buf_inst [ create_bd_cell -type ip -vlnv xilinx.com:ip:util_ds_buf:2.2 pcie_clk_buf_inst ] - set_property -dict [ list \ - CONFIG.C_BUF_TYPE {IBUFDSGTE} \ - ] $pcie_clk_buf_inst - - # Create instance: smartconnect_0, and set properties - set smartconnect_0 [ create_bd_cell -type ip -vlnv xilinx.com:ip:smartconnect:1.0 smartconnect_0 ] - set_property -dict [ list \ - CONFIG.NUM_MI {2} \ - CONFIG.NUM_SI {1} \ - ] $smartconnect_0 - - # Create instance: xdma_0, and set properties - set xdma_0 [ create_bd_cell -type ip -vlnv xilinx.com:ip:xdma:4.1 xdma_0 ] - set_property -dict [ list \ - CONFIG.INS_LOSS_NYQ {15} \ - CONFIG.PF0_DEVICE_ID_mqdma {9048} \ - CONFIG.PF0_SRIOV_VF_DEVICE_ID {A048} \ - CONFIG.PF1_SRIOV_VF_DEVICE_ID {A148} \ - CONFIG.PF2_DEVICE_ID_mqdma {9248} \ - CONFIG.PF2_SRIOV_VF_DEVICE_ID {A248} \ - CONFIG.PF3_DEVICE_ID_mqdma {9348} \ - CONFIG.PF3_SRIOV_VF_DEVICE_ID {A348} \ - CONFIG.axi_data_width {512_bit} \ - CONFIG.axi_id_width {2} \ - CONFIG.axil_master_64bit_en {false} \ - CONFIG.axilite_master_en {true} \ - CONFIG.axilite_master_size {4} \ - CONFIG.axisten_freq {250} \ - CONFIG.cfg_mgmt_if {false} \ - CONFIG.copy_pf0 {true} \ - CONFIG.coreclk_freq {500} \ - CONFIG.dsc_bypass_rd {0001} \ - CONFIG.dsc_bypass_wr {0001} \ - CONFIG.en_gt_selection {true} \ - CONFIG.ins_loss_profile {Add-in_Card} \ - CONFIG.mode_selection {Advanced} \ - CONFIG.pcie_blk_locn {PCIE4C_X1Y1} \ - CONFIG.pf0_base_class_menu {Processing_accelerators} \ - CONFIG.pf0_class_code {120000} \ - CONFIG.pf0_class_code_base {12} \ - CONFIG.pf0_class_code_interface {00} \ - CONFIG.pf0_class_code_sub {00} \ - CONFIG.pf0_device_id {9048} \ - CONFIG.pf0_msix_cap_pba_bir {BAR_1} \ - CONFIG.pf0_msix_cap_pba_offset {00008FE0} \ - CONFIG.pf0_msix_cap_table_bir {BAR_1} \ - CONFIG.pf0_msix_cap_table_offset {00008000} \ - CONFIG.pf0_msix_cap_table_size {01F} \ - CONFIG.pf0_msix_enabled {true} \ - CONFIG.pf0_sub_class_interface_menu {Unknown} \ - CONFIG.pf0_subsystem_id {5232} \ - CONFIG.pf0_subsystem_vendor_id {10EE} \ - CONFIG.pf1_msix_cap_pba_offset {00000000} \ - CONFIG.pf1_msix_cap_table_offset {00000000} \ - CONFIG.pf1_msix_cap_table_size {000} \ - CONFIG.pl_link_cap_max_link_speed {16.0_GT/s} \ - CONFIG.pl_link_cap_max_link_width {X8} \ - CONFIG.plltype {QPLL0} \ - CONFIG.runbit_fix {false} \ - CONFIG.select_quad {GTY_Quad_227} \ - CONFIG.vendor_id {10EE} \ - CONFIG.xdma_axi_intf_mm {AXI_Stream} \ - CONFIG.xdma_axilite_slave {true} \ - CONFIG.xdma_wnum_chnl {1} \ - ] $xdma_0 - - # Create interface connections - connect_bd_intf_net -intf_net Conn1 [get_bd_intf_pins s_axis_c2h_cmd] [get_bd_intf_pins axis_clock_converter_c2h_cmd/S_AXIS] - connect_bd_intf_net -intf_net Conn2 [get_bd_intf_pins m_axi_ctrl] [get_bd_intf_pins axi_firewall_0/M_AXI] - connect_bd_intf_net -intf_net Conn3 [get_bd_intf_pins pcie_mgt] [get_bd_intf_pins xdma_0/pcie_mgt] - connect_bd_intf_net -intf_net Conn4 [get_bd_intf_pins s_axis_c2h_data] [get_bd_intf_pins axis_clock_converter_c2h_data/S_AXIS] - connect_bd_intf_net -intf_net Conn5 [get_bd_intf_pins pcie_refclk] [get_bd_intf_pins pcie_clk_buf_inst/CLK_IN_D] - connect_bd_intf_net -intf_net Conn6 [get_bd_intf_pins m_axis_h2c_data] [get_bd_intf_pins axis_clock_converter_h2c_data/M_AXIS] - connect_bd_intf_net -intf_net Conn7 [get_bd_intf_pins s_axis_h2c_cmd] [get_bd_intf_pins axis_clock_converter_h2c_cmd/S_AXIS] - connect_bd_intf_net -intf_net axis_clock_converter_c2h_cmd_M_AXIS [get_bd_intf_pins axis_clock_converter_c2h_cmd/M_AXIS] [get_bd_intf_pins gen_xdma_descriptor_c2h/S_AXIS] - connect_bd_intf_net -intf_net axis_clock_converter_c2h_data_M_AXIS [get_bd_intf_pins axis_clock_converter_c2h_data/M_AXIS] [get_bd_intf_pins xdma_0/S_AXIS_C2H_0] - connect_bd_intf_net -intf_net axis_clock_converter_h2c_cmd_M_AXIS [get_bd_intf_pins axis_clock_converter_h2c_cmd/M_AXIS] [get_bd_intf_pins gen_xdma_descriptor_h2c/S_AXIS] - connect_bd_intf_net -intf_net s_axi_dma_ctrl_1 [get_bd_intf_pins s_axi_dma_ctrl] [get_bd_intf_pins xdma_0/S_AXI_LITE] - connect_bd_intf_net -intf_net smartconnect_0_M00_AXI [get_bd_intf_pins axi_firewall_0/S_AXI] [get_bd_intf_pins smartconnect_0/M00_AXI] - connect_bd_intf_net -intf_net smartconnect_0_M01_AXI [get_bd_intf_pins axi_firewall_0/S_AXI_CTL] [get_bd_intf_pins smartconnect_0/M01_AXI] - connect_bd_intf_net -intf_net xdma_0_M_AXIS_H2C_0 [get_bd_intf_pins axis_clock_converter_h2c_data/S_AXIS] [get_bd_intf_pins xdma_0/M_AXIS_H2C_0] - connect_bd_intf_net -intf_net xdma_0_M_AXI_LITE [get_bd_intf_pins smartconnect_0/S00_AXI] [get_bd_intf_pins xdma_0/M_AXI_LITE] - - # Create port connections - connect_bd_net -net gen_xdma_descriptor_c2h_0_dsc_addr [get_bd_pins gen_xdma_descriptor_c2h/dsc_addr] [get_bd_pins xdma_0/c2h_dsc_byp_dst_addr_0] [get_bd_pins xdma_0/c2h_dsc_byp_src_addr_0] - connect_bd_net -net gen_xdma_descriptor_c2h_0_dsc_ctl [get_bd_pins gen_xdma_descriptor_c2h/dsc_ctl] [get_bd_pins xdma_0/c2h_dsc_byp_ctl_0] - connect_bd_net -net gen_xdma_descriptor_c2h_0_dsc_len [get_bd_pins gen_xdma_descriptor_c2h/dsc_len] [get_bd_pins xdma_0/c2h_dsc_byp_len_0] - connect_bd_net -net gen_xdma_descriptor_c2h_0_dsc_load [get_bd_pins gen_xdma_descriptor_c2h/dsc_load] [get_bd_pins xdma_0/c2h_dsc_byp_load_0] - connect_bd_net -net gen_xdma_descriptor_h2c_0_dsc_addr [get_bd_pins gen_xdma_descriptor_h2c/dsc_addr] [get_bd_pins xdma_0/h2c_dsc_byp_dst_addr_0] [get_bd_pins xdma_0/h2c_dsc_byp_src_addr_0] - connect_bd_net -net gen_xdma_descriptor_h2c_0_dsc_ctl [get_bd_pins gen_xdma_descriptor_h2c/dsc_ctl] [get_bd_pins xdma_0/h2c_dsc_byp_ctl_0] - connect_bd_net -net gen_xdma_descriptor_h2c_0_dsc_len [get_bd_pins gen_xdma_descriptor_h2c/dsc_len] [get_bd_pins xdma_0/h2c_dsc_byp_len_0] - connect_bd_net -net gen_xdma_descriptor_h2c_0_dsc_load [get_bd_pins gen_xdma_descriptor_h2c/dsc_load] [get_bd_pins xdma_0/h2c_dsc_byp_load_0] - connect_bd_net -net pcie_clk_buf_inst_IBUF_DS_ODIV2 [get_bd_pins pcie_clk_buf_inst/IBUF_DS_ODIV2] [get_bd_pins xdma_0/sys_clk] - connect_bd_net -net pcie_clk_buf_inst_IBUF_OUT [get_bd_pins pcie_clk_buf_inst/IBUF_OUT] [get_bd_pins xdma_0/sys_clk_gt] - connect_bd_net -net pcie_perstn_1 [get_bd_pins pcie_perstn] [get_bd_pins xdma_0/sys_rst_n] - connect_bd_net -net net_refclk200 [get_bd_pins refclk200] [get_bd_pins axis_clock_converter_c2h_cmd/s_axis_aclk] [get_bd_pins axis_clock_converter_c2h_data/s_axis_aclk] [get_bd_pins axis_clock_converter_h2c_cmd/s_axis_aclk] [get_bd_pins axis_clock_converter_h2c_data/m_axis_aclk] - connect_bd_net -net net_refclk200_resetn [get_bd_pins refclk200_resetn] [get_bd_pins axis_clock_converter_c2h_cmd/s_axis_aresetn] [get_bd_pins axis_clock_converter_c2h_data/s_axis_aresetn] [get_bd_pins axis_clock_converter_h2c_cmd/s_axis_aresetn] [get_bd_pins axis_clock_converter_h2c_data/m_axis_aresetn] - connect_bd_net -net s_axis_aresetn_1 [get_bd_pins axi_clk_resetn] [get_bd_pins axi_firewall_0/aresetn] [get_bd_pins axis_clock_converter_c2h_cmd/m_axis_aresetn] [get_bd_pins axis_clock_converter_c2h_data/m_axis_aresetn] [get_bd_pins axis_clock_converter_h2c_cmd/m_axis_aresetn] [get_bd_pins axis_clock_converter_h2c_data/s_axis_aresetn] [get_bd_pins gen_xdma_descriptor_c2h/resetn] [get_bd_pins gen_xdma_descriptor_h2c/resetn] [get_bd_pins smartconnect_0/aresetn] - connect_bd_net -net usr_irq_req_1 [get_bd_pins usr_irq_req] [get_bd_pins xdma_0/usr_irq_req] - connect_bd_net -net xdma_0_axi_aclk [get_bd_pins axi_aclk] [get_bd_pins axi_firewall_0/aclk] [get_bd_pins axis_clock_converter_c2h_cmd/m_axis_aclk] [get_bd_pins axis_clock_converter_c2h_data/m_axis_aclk] [get_bd_pins axis_clock_converter_h2c_cmd/m_axis_aclk] [get_bd_pins axis_clock_converter_h2c_data/s_axis_aclk] [get_bd_pins gen_xdma_descriptor_c2h/clk] [get_bd_pins gen_xdma_descriptor_h2c/clk] [get_bd_pins smartconnect_0/aclk] [get_bd_pins xdma_0/axi_aclk] - connect_bd_net -net xdma_0_axi_aresetn [get_bd_pins axi_aresetn] [get_bd_pins xdma_0/axi_aresetn] - connect_bd_net -net xdma_0_c2h_dsc_byp_ready_0 [get_bd_pins gen_xdma_descriptor_c2h/dsc_ready] [get_bd_pins xdma_0/c2h_dsc_byp_ready_0] - connect_bd_net -net xdma_0_h2c_dsc_byp_ready_0 [get_bd_pins gen_xdma_descriptor_h2c/dsc_ready] [get_bd_pins xdma_0/h2c_dsc_byp_ready_0] - - # Restore current instance - current_bd_instance $oldCurInst -} - -# Hierarchical cell: pcie_dma_1 -proc create_hier_cell_pcie_dma_1 { parentCell nameHier } { - - variable script_folder - - if { $parentCell eq "" || $nameHier eq "" } { - catch {common::send_gid_msg -ssname BD::TCL -id 2092 -severity "ERROR" "create_hier_cell_pcie_dma() - Empty argument(s)!"} - return - } - - # Get object for parentCell - set parentObj [get_bd_cells $parentCell] - if { $parentObj == "" } { - catch {common::send_gid_msg -ssname BD::TCL -id 2090 -severity "ERROR" "Unable to find parent cell <$parentCell>!"} - return - } - - # Make sure parentObj is hier blk - set parentType [get_property TYPE $parentObj] - if { $parentType ne "hier" } { - catch {common::send_gid_msg -ssname BD::TCL -id 2091 -severity "ERROR" "Parent <$parentObj> has TYPE = <$parentType>. Expected to be ."} - return - } - - # Save current instance; Restore later - set oldCurInst [current_bd_instance .] - - # Set parent object as current - current_bd_instance $parentObj - - # Create cell and set as current instance - set hier_obj [create_bd_cell -type hier $nameHier] - current_bd_instance $hier_obj - - # Create interface pins - create_bd_intf_pin -mode Master -vlnv xilinx.com:interface:aximm_rtl:1.0 m_axi_ctrl - - create_bd_intf_pin -mode Master -vlnv xilinx.com:interface:axis_rtl:1.0 m_axis_h2c_data - - create_bd_intf_pin -mode Master -vlnv xilinx.com:interface:pcie_7x_mgt_rtl:1.0 pcie_mgt - - create_bd_intf_pin -mode Slave -vlnv xilinx.com:interface:diff_clock_rtl:1.0 pcie_refclk - - create_bd_intf_pin -mode Slave -vlnv xilinx.com:interface:aximm_rtl:1.0 s_axi_dma_ctrl - - create_bd_intf_pin -mode Slave -vlnv xilinx.com:interface:axis_rtl:1.0 s_axis_c2h_cmd - - create_bd_intf_pin -mode Slave -vlnv xilinx.com:interface:axis_rtl:1.0 s_axis_c2h_data - - create_bd_intf_pin -mode Slave -vlnv xilinx.com:interface:axis_rtl:1.0 s_axis_h2c_cmd - - - # Create pins - create_bd_pin -dir O -type clk axi_aclk - create_bd_pin -dir O -type rst axi_aresetn - create_bd_pin -dir I -type rst axi_clk_resetn - create_bd_pin -dir I -type rst pcie_perstn - create_bd_pin -dir I -type clk refclk200 - create_bd_pin -dir I -type rst refclk200_resetn - create_bd_pin -dir I usr_irq_req - - # Create instance: axi_firewall_0, and set properties - set axi_firewall_0 [ create_bd_cell -type ip -vlnv xilinx.com:ip:axi_firewall:1.2 axi_firewall_0 ] - - # Create instance: axis_clock_converter_c2h_cmd, and set properties - set axis_clock_converter_c2h_cmd [ create_bd_cell -type ip -vlnv xilinx.com:ip:axis_clock_converter:1.1 axis_clock_converter_c2h_cmd ] - set_property -dict [ list \ - CONFIG.SYNCHRONIZATION_STAGES {3} \ - ] $axis_clock_converter_c2h_cmd - - # Create instance: axis_clock_converter_c2h_data, and set properties - set axis_clock_converter_c2h_data [ create_bd_cell -type ip -vlnv xilinx.com:ip:axis_clock_converter:1.1 axis_clock_converter_c2h_data ] - set_property -dict [ list \ - CONFIG.SYNCHRONIZATION_STAGES {3} \ - ] $axis_clock_converter_c2h_data - - # Create instance: axis_clock_converter_h2c_cmd, and set properties - set axis_clock_converter_h2c_cmd [ create_bd_cell -type ip -vlnv xilinx.com:ip:axis_clock_converter:1.1 axis_clock_converter_h2c_cmd ] - set_property -dict [ list \ - CONFIG.SYNCHRONIZATION_STAGES {3} \ - ] $axis_clock_converter_h2c_cmd - - # Create instance: axis_clock_converter_h2c_data, and set properties - set axis_clock_converter_h2c_data [ create_bd_cell -type ip -vlnv xilinx.com:ip:axis_clock_converter:1.1 axis_clock_converter_h2c_data ] - set_property -dict [ list \ - CONFIG.SYNCHRONIZATION_STAGES {3} \ - ] $axis_clock_converter_h2c_data - - # Create instance: gen_xdma_descriptor_c2h, and set properties - set block_name gen_xdma_descriptor - set block_cell_name gen_xdma_descriptor_c2h - if { [catch {set gen_xdma_descriptor_c2h [create_bd_cell -type module -reference $block_name $block_cell_name] } errmsg] } { - catch {common::send_gid_msg -ssname BD::TCL -id 2095 -severity "ERROR" "Unable to add referenced block <$block_name>. Please add the files for ${block_name}'s definition into the project."} - return 1 - } elseif { $gen_xdma_descriptor_c2h eq "" } { - catch {common::send_gid_msg -ssname BD::TCL -id 2096 -severity "ERROR" "Unable to referenced block <$block_name>. Please add the files for ${block_name}'s definition into the project."} - return 1 - } - - # Create instance: gen_xdma_descriptor_h2c, and set properties - set block_name gen_xdma_descriptor - set block_cell_name gen_xdma_descriptor_h2c - if { [catch {set gen_xdma_descriptor_h2c [create_bd_cell -type module -reference $block_name $block_cell_name] } errmsg] } { - catch {common::send_gid_msg -ssname BD::TCL -id 2095 -severity "ERROR" "Unable to add referenced block <$block_name>. Please add the files for ${block_name}'s definition into the project."} - return 1 - } elseif { $gen_xdma_descriptor_h2c eq "" } { - catch {common::send_gid_msg -ssname BD::TCL -id 2096 -severity "ERROR" "Unable to referenced block <$block_name>. Please add the files for ${block_name}'s definition into the project."} - return 1 - } - - # Create instance: pcie_clk_buf_inst, and set properties - set pcie_clk_buf_inst [ create_bd_cell -type ip -vlnv xilinx.com:ip:util_ds_buf:2.2 pcie_clk_buf_inst ] - set_property -dict [ list \ - CONFIG.C_BUF_TYPE {IBUFDSGTE} \ - ] $pcie_clk_buf_inst - - # Create instance: smartconnect_0, and set properties - set smartconnect_0 [ create_bd_cell -type ip -vlnv xilinx.com:ip:smartconnect:1.0 smartconnect_0 ] - set_property -dict [ list \ - CONFIG.NUM_MI {2} \ - CONFIG.NUM_SI {1} \ - ] $smartconnect_0 - - # Create instance: xdma_0, and set properties - set xdma_0 [ create_bd_cell -type ip -vlnv xilinx.com:ip:xdma:4.1 xdma_0 ] - set_property -dict [ list \ - CONFIG.INS_LOSS_NYQ {15} \ - CONFIG.PF0_DEVICE_ID_mqdma {9048} \ - CONFIG.PF0_SRIOV_VF_DEVICE_ID {A048} \ - CONFIG.PF1_SRIOV_VF_DEVICE_ID {A148} \ - CONFIG.PF2_DEVICE_ID_mqdma {9248} \ - CONFIG.PF2_SRIOV_VF_DEVICE_ID {A248} \ - CONFIG.PF3_DEVICE_ID_mqdma {9348} \ - CONFIG.PF3_SRIOV_VF_DEVICE_ID {A348} \ - CONFIG.axi_data_width {512_bit} \ - CONFIG.axi_id_width {2} \ - CONFIG.axil_master_64bit_en {false} \ - CONFIG.axilite_master_en {true} \ - CONFIG.axilite_master_size {4} \ - CONFIG.axisten_freq {250} \ - CONFIG.cfg_mgmt_if {false} \ - CONFIG.copy_pf0 {true} \ - CONFIG.coreclk_freq {500} \ - CONFIG.dsc_bypass_rd {0001} \ - CONFIG.dsc_bypass_wr {0001} \ - CONFIG.en_gt_selection {true} \ - CONFIG.ins_loss_profile {Add-in_Card} \ - CONFIG.mode_selection {Advanced} \ - CONFIG.pcie_blk_locn {PCIE4C_X1Y0} \ - CONFIG.pf0_base_class_menu {Processing_accelerators} \ - CONFIG.pf0_class_code {120000} \ - CONFIG.pf0_class_code_base {12} \ - CONFIG.pf0_class_code_interface {00} \ - CONFIG.pf0_class_code_sub {00} \ - CONFIG.pf0_device_id {9048} \ - CONFIG.pf0_msix_cap_pba_bir {BAR_1} \ - CONFIG.pf0_msix_cap_pba_offset {00008FE0} \ - CONFIG.pf0_msix_cap_table_bir {BAR_1} \ - CONFIG.pf0_msix_cap_table_offset {00008000} \ - CONFIG.pf0_msix_cap_table_size {01F} \ - CONFIG.pf0_msix_enabled {true} \ - CONFIG.pf0_sub_class_interface_menu {Unknown} \ - CONFIG.pf0_subsystem_id {5232} \ - CONFIG.pf0_subsystem_vendor_id {10EE} \ - CONFIG.pf1_msix_cap_pba_offset {00000000} \ - CONFIG.pf1_msix_cap_table_offset {00000000} \ - CONFIG.pf1_msix_cap_table_size {000} \ - CONFIG.pl_link_cap_max_link_speed {16.0_GT/s} \ - CONFIG.pl_link_cap_max_link_width {X8} \ - CONFIG.plltype {QPLL0} \ - CONFIG.runbit_fix {false} \ - CONFIG.select_quad {GTY_Quad_225} \ - CONFIG.vendor_id {10EE} \ - CONFIG.xdma_axi_intf_mm {AXI_Stream} \ - CONFIG.xdma_axilite_slave {true} \ - CONFIG.xdma_wnum_chnl {1} \ - ] $xdma_0 - - # Create interface connections - connect_bd_intf_net -intf_net Conn1 [get_bd_intf_pins s_axis_c2h_cmd] [get_bd_intf_pins axis_clock_converter_c2h_cmd/S_AXIS] - connect_bd_intf_net -intf_net Conn2 [get_bd_intf_pins m_axi_ctrl] [get_bd_intf_pins axi_firewall_0/M_AXI] - connect_bd_intf_net -intf_net Conn3 [get_bd_intf_pins pcie_mgt] [get_bd_intf_pins xdma_0/pcie_mgt] - connect_bd_intf_net -intf_net Conn4 [get_bd_intf_pins s_axis_c2h_data] [get_bd_intf_pins axis_clock_converter_c2h_data/S_AXIS] - connect_bd_intf_net -intf_net Conn5 [get_bd_intf_pins pcie_refclk] [get_bd_intf_pins pcie_clk_buf_inst/CLK_IN_D] - connect_bd_intf_net -intf_net Conn6 [get_bd_intf_pins m_axis_h2c_data] [get_bd_intf_pins axis_clock_converter_h2c_data/M_AXIS] - connect_bd_intf_net -intf_net Conn7 [get_bd_intf_pins s_axis_h2c_cmd] [get_bd_intf_pins axis_clock_converter_h2c_cmd/S_AXIS] - connect_bd_intf_net -intf_net axis_clock_converter_c2h_cmd_M_AXIS [get_bd_intf_pins axis_clock_converter_c2h_cmd/M_AXIS] [get_bd_intf_pins gen_xdma_descriptor_c2h/S_AXIS] - connect_bd_intf_net -intf_net axis_clock_converter_c2h_data_M_AXIS [get_bd_intf_pins axis_clock_converter_c2h_data/M_AXIS] [get_bd_intf_pins xdma_0/S_AXIS_C2H_0] - connect_bd_intf_net -intf_net axis_clock_converter_h2c_cmd_M_AXIS [get_bd_intf_pins axis_clock_converter_h2c_cmd/M_AXIS] [get_bd_intf_pins gen_xdma_descriptor_h2c/S_AXIS] - connect_bd_intf_net -intf_net s_axi_dma_ctrl_1 [get_bd_intf_pins s_axi_dma_ctrl] [get_bd_intf_pins xdma_0/S_AXI_LITE] - connect_bd_intf_net -intf_net smartconnect_0_M00_AXI [get_bd_intf_pins axi_firewall_0/S_AXI] [get_bd_intf_pins smartconnect_0/M00_AXI] - connect_bd_intf_net -intf_net smartconnect_0_M01_AXI [get_bd_intf_pins axi_firewall_0/S_AXI_CTL] [get_bd_intf_pins smartconnect_0/M01_AXI] - connect_bd_intf_net -intf_net xdma_0_M_AXIS_H2C_0 [get_bd_intf_pins axis_clock_converter_h2c_data/S_AXIS] [get_bd_intf_pins xdma_0/M_AXIS_H2C_0] - connect_bd_intf_net -intf_net xdma_0_M_AXI_LITE [get_bd_intf_pins smartconnect_0/S00_AXI] [get_bd_intf_pins xdma_0/M_AXI_LITE] - - # Create port connections - connect_bd_net -net gen_xdma_descriptor_c2h_0_dsc_addr [get_bd_pins gen_xdma_descriptor_c2h/dsc_addr] [get_bd_pins xdma_0/c2h_dsc_byp_dst_addr_0] [get_bd_pins xdma_0/c2h_dsc_byp_src_addr_0] - connect_bd_net -net gen_xdma_descriptor_c2h_0_dsc_ctl [get_bd_pins gen_xdma_descriptor_c2h/dsc_ctl] [get_bd_pins xdma_0/c2h_dsc_byp_ctl_0] - connect_bd_net -net gen_xdma_descriptor_c2h_0_dsc_len [get_bd_pins gen_xdma_descriptor_c2h/dsc_len] [get_bd_pins xdma_0/c2h_dsc_byp_len_0] - connect_bd_net -net gen_xdma_descriptor_c2h_0_dsc_load [get_bd_pins gen_xdma_descriptor_c2h/dsc_load] [get_bd_pins xdma_0/c2h_dsc_byp_load_0] - connect_bd_net -net gen_xdma_descriptor_h2c_0_dsc_addr [get_bd_pins gen_xdma_descriptor_h2c/dsc_addr] [get_bd_pins xdma_0/h2c_dsc_byp_dst_addr_0] [get_bd_pins xdma_0/h2c_dsc_byp_src_addr_0] - connect_bd_net -net gen_xdma_descriptor_h2c_0_dsc_ctl [get_bd_pins gen_xdma_descriptor_h2c/dsc_ctl] [get_bd_pins xdma_0/h2c_dsc_byp_ctl_0] - connect_bd_net -net gen_xdma_descriptor_h2c_0_dsc_len [get_bd_pins gen_xdma_descriptor_h2c/dsc_len] [get_bd_pins xdma_0/h2c_dsc_byp_len_0] - connect_bd_net -net gen_xdma_descriptor_h2c_0_dsc_load [get_bd_pins gen_xdma_descriptor_h2c/dsc_load] [get_bd_pins xdma_0/h2c_dsc_byp_load_0] - connect_bd_net -net pcie_clk_buf_inst_IBUF_DS_ODIV2 [get_bd_pins pcie_clk_buf_inst/IBUF_DS_ODIV2] [get_bd_pins xdma_0/sys_clk] - connect_bd_net -net pcie_clk_buf_inst_IBUF_OUT [get_bd_pins pcie_clk_buf_inst/IBUF_OUT] [get_bd_pins xdma_0/sys_clk_gt] - connect_bd_net -net pcie_perstn_1 [get_bd_pins pcie_perstn] [get_bd_pins xdma_0/sys_rst_n] - connect_bd_net -net net_refclk200 [get_bd_pins refclk200] [get_bd_pins axis_clock_converter_c2h_cmd/s_axis_aclk] [get_bd_pins axis_clock_converter_c2h_data/s_axis_aclk] [get_bd_pins axis_clock_converter_h2c_cmd/s_axis_aclk] [get_bd_pins axis_clock_converter_h2c_data/m_axis_aclk] - connect_bd_net -net net_refclk200_resetn [get_bd_pins refclk200_resetn] [get_bd_pins axis_clock_converter_c2h_cmd/s_axis_aresetn] [get_bd_pins axis_clock_converter_c2h_data/s_axis_aresetn] [get_bd_pins axis_clock_converter_h2c_cmd/s_axis_aresetn] [get_bd_pins axis_clock_converter_h2c_data/m_axis_aresetn] - connect_bd_net -net s_axis_aresetn_1 [get_bd_pins axi_clk_resetn] [get_bd_pins axi_firewall_0/aresetn] [get_bd_pins axis_clock_converter_c2h_cmd/m_axis_aresetn] [get_bd_pins axis_clock_converter_c2h_data/m_axis_aresetn] [get_bd_pins axis_clock_converter_h2c_cmd/m_axis_aresetn] [get_bd_pins axis_clock_converter_h2c_data/s_axis_aresetn] [get_bd_pins gen_xdma_descriptor_c2h/resetn] [get_bd_pins gen_xdma_descriptor_h2c/resetn] [get_bd_pins smartconnect_0/aresetn] - connect_bd_net -net usr_irq_req_1 [get_bd_pins usr_irq_req] [get_bd_pins xdma_0/usr_irq_req] - connect_bd_net -net xdma_0_axi_aclk [get_bd_pins axi_aclk] [get_bd_pins axi_firewall_0/aclk] [get_bd_pins axis_clock_converter_c2h_cmd/m_axis_aclk] [get_bd_pins axis_clock_converter_c2h_data/m_axis_aclk] [get_bd_pins axis_clock_converter_h2c_cmd/m_axis_aclk] [get_bd_pins axis_clock_converter_h2c_data/s_axis_aclk] [get_bd_pins gen_xdma_descriptor_c2h/clk] [get_bd_pins gen_xdma_descriptor_h2c/clk] [get_bd_pins smartconnect_0/aclk] [get_bd_pins xdma_0/axi_aclk] - connect_bd_net -net xdma_0_axi_aresetn [get_bd_pins axi_aresetn] [get_bd_pins xdma_0/axi_aresetn] - connect_bd_net -net xdma_0_c2h_dsc_byp_ready_0 [get_bd_pins gen_xdma_descriptor_c2h/dsc_ready] [get_bd_pins xdma_0/c2h_dsc_byp_ready_0] - connect_bd_net -net xdma_0_h2c_dsc_byp_ready_0 [get_bd_pins gen_xdma_descriptor_h2c/dsc_ready] [get_bd_pins xdma_0/h2c_dsc_byp_ready_0] - - # Restore current instance - current_bd_instance $oldCurInst -} diff --git a/receiver/scripts/snap_env.sh b/receiver/scripts/snap_env.sh deleted file mode 100644 index b049f37c..00000000 --- a/receiver/scripts/snap_env.sh +++ /dev/null @@ -1,3 +0,0 @@ -export ACTION_ROOT=@ACTION_ROOT@ -export TIMING_LABLIMIT="-100" -export OCSE_ROOT=@OCSE_ROOT@ diff --git a/tests/AcquisitionCountersTest.cpp b/tests/AcquisitionCountersTest.cpp index 08d30516..453e0620 100644 --- a/tests/AcquisitionCountersTest.cpp +++ b/tests/AcquisitionCountersTest.cpp @@ -1,14 +1,13 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (2019-2023) Paul Scherrer Institute #include -#include "../receiver/host/AcquisitionOnlineCounters.h" +#include "../receiver/AcquisitionCounters.h" -TEST_CASE("AcquisitionDeviceCountersTest","[AcquisitionDeviceCounters]") { +TEST_CASE("AcquisitionCountersTest","[AcquisitionDeviceCounters]") { DiffractionExperiment x(DetectorGeometry(2)); x.NumTriggers(1).ImagesPerTrigger(50); - AcquisitionOnlineCounters counters; + AcquisitionCounters counters; counters.Reset(x, 0); REQUIRE(counters.GetSlowestHead() == 0); REQUIRE(counters.GetHead(0) == 0); @@ -20,7 +19,7 @@ TEST_CASE("AcquisitionDeviceCountersTest","[AcquisitionDeviceCounters]") { Completion c{}; c.frame_number = 32; - c.module = 1; + c.module_number = 1; c.handle = 17; c.bunchid = 1ul<<56; c.debug = 1u<<31; @@ -34,13 +33,13 @@ TEST_CASE("AcquisitionDeviceCountersTest","[AcquisitionDeviceCounters]") { REQUIRE(counters.CalculateDelay(31, 1) == 1); REQUIRE(counters.CalculateDelay(33, 1) == -1); REQUIRE(counters.GetBufferHandle(32, 1) == 17); - REQUIRE(counters.GetBufferHandle(32, 0) == AcquisitionOnlineCounters::HandleNotFound); - REQUIRE(counters.GetBunchID(32, 1) == c.bunchid); - REQUIRE(counters.GetJFInfo(32, 1) == c.debug); - REQUIRE(counters.GetTimestamp(32, 1) == c.timestamp); + REQUIRE(counters.GetBufferHandle(32, 0) == AcquisitionCounters::HandleNotFound); + REQUIRE(counters.GetCompletion(32, 1).bunchid == c.bunchid); + REQUIRE(counters.GetCompletion(32, 1).debug == c.debug); + REQUIRE(counters.GetCompletion(32, 1).timestamp == c.timestamp); c.frame_number = 15; - c.module = 0; + c.module_number = 0; counters.UpdateCounters(&c); REQUIRE(counters.GetSlowestHead() == 15); @@ -65,11 +64,11 @@ TEST_CASE("AcquisitionDeviceCountersTest","[AcquisitionDeviceCounters]") { REQUIRE(counters.CalculateDelay(50) == 15-50); } -TEST_CASE("AcquisitionDeviceCountersTest_OutOfBounds","[AcquisitionDeviceCounters]") { +TEST_CASE("AcquisitionCountersTest_OutOfBounds","[AcquisitionDeviceCounters]") { DiffractionExperiment x(DetectorGeometry(2)); x.NumTriggers(1).ImagesPerTrigger(50); - AcquisitionOnlineCounters counters; + AcquisitionCounters counters; counters.Reset(x, 0); Completion c{}; @@ -80,6 +79,38 @@ TEST_CASE("AcquisitionDeviceCountersTest_OutOfBounds","[AcquisitionDeviceCounter REQUIRE_THROWS(counters.UpdateCounters(&c)); c.frame_number = 20; - c.module = 2; + c.module_number = 2; REQUIRE_THROWS(counters.UpdateCounters(&c)); +} + +TEST_CASE("AcquisitionCountersTest_PacketCount","[AcquisitionDeviceCounters]") { + DiffractionExperiment x(DetectorGeometry(2)); + x.NumTriggers(1).ImagesPerTrigger(25).Summation(2); + + AcquisitionCounters counters; + counters.Reset(x, 0); + REQUIRE(counters.GetTotalPackets() == 0); + + Completion c{}; + c.frame_number = 32; + c.module_number = 1; + c.handle = 17; + c.packet_count = 86; + counters.UpdateCounters(&c); + + REQUIRE(counters.GetTotalPackets() == 86); + REQUIRE(counters.GetTotalPackets(0) == 0); + REQUIRE(counters.GetTotalPackets(1) == 86); + + c.frame_number = 15; + c.module_number = 0; + c.packet_count = 128; + counters.UpdateCounters(&c); + + REQUIRE(counters.GetTotalPackets() == 86 + 128); + REQUIRE(counters.GetTotalPackets(0) == 128); + REQUIRE(counters.GetTotalPackets(1) == 86); + + REQUIRE(counters.GetExpectedPackets() == 50 * 2 * 128); + REQUIRE(counters.GetExpectedPacketsPerModule() == 50 * 128); } \ No newline at end of file diff --git a/tests/ActionConfigTest.cpp b/tests/ActionConfigTest.cpp index 47430f90..bf2ba30d 100644 --- a/tests/ActionConfigTest.cpp +++ b/tests/ActionConfigTest.cpp @@ -1,9 +1,8 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (2019-2023) Paul Scherrer Institute #include #include "../common/Definitions.h" -#include "../receiver/host/ActionConfig.h" +#include "../fpga/pcie_driver/ActionConfig.h" TEST_CASE("ActionStatus") { ActionStatus status{}; diff --git a/tests/CBORTest.cpp b/tests/CBORTest.cpp index 2be10aae..0720dfab 100644 --- a/tests/CBORTest.cpp +++ b/tests/CBORTest.cpp @@ -1,5 +1,4 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (2019-2023) Paul Scherrer Institute #include @@ -39,6 +38,7 @@ TEST_CASE("CBORSerialize_Start", "[CBOR]") { .space_group_number = 154, .max_spot_count = 250, .storage_cell_number = 16, + .storage_cell_delay_ns = 15345, .pixel_mask_enabled = true, .arm_date = "abc", .sample_name = "lyso", @@ -62,7 +62,6 @@ TEST_CASE("CBORSerialize_Start", "[CBOR]") { .rad_int_bin_to_q = {0.1, 0.2, 0.3, 0.5}, .rad_int_solid_angle_corr = {10, 20, 30, 50} }; - message.pixel_mask["sc0"] = std::vector(456*457, 15); REQUIRE_NOTHROW(serializer.SerializeSequenceStart(message)); @@ -72,7 +71,6 @@ TEST_CASE("CBORSerialize_Start", "[CBOR]") { StartMessage output_message; REQUIRE_NOTHROW(output_message = deserializer.GetStartMessage()); - REQUIRE(output_message.pixel_mask.contains("sc0")); CHECK(output_message.data_file_count == message.data_file_count); CHECK(output_message.detector_distance == Approx(message.detector_distance)); CHECK(output_message.beam_center_x == Approx(message.beam_center_x)); @@ -91,13 +89,13 @@ TEST_CASE("CBORSerialize_Start", "[CBOR]") { CHECK(output_message.pixel_size_y == Approx(message.pixel_size_y)); CHECK(output_message.sensor_thickness == Approx(message.sensor_thickness)); CHECK(output_message.sensor_material == message.sensor_material); - CHECK(output_message.pixel_mask == message.pixel_mask); CHECK(output_message.pixel_mask_enabled == message.pixel_mask_enabled); CHECK(output_message.compression_algorithm == message.compression_algorithm); CHECK(output_message.compression_block_size == message.compression_block_size); CHECK(output_message.space_group_number == message.space_group_number); CHECK(output_message.arm_date == message.arm_date); CHECK(output_message.storage_cell_number == message.storage_cell_number); + CHECK(output_message.storage_cell_delay_ns == message.storage_cell_delay_ns); CHECK(output_message.pixel_signed == message.pixel_signed); CHECK(output_message.sample_name == message.sample_name); CHECK(output_message.file_prefix == message.file_prefix); @@ -127,6 +125,104 @@ TEST_CASE("CBORSerialize_Start", "[CBOR]") { } +TEST_CASE("CBORSerialize_Start_PixelMask", "[CBOR]") { + std::vector buffer(8*1024*1024); + JFJochFrameSerializer serializer(buffer.data(), buffer.size()); + + std::vector mask(456*457, 15); + + CBORImage image_mask { + .data = reinterpret_cast(mask.data()), + .size = 456 * 457 * sizeof(uint32_t), + .xpixel = 456, + .ypixel = 457, + .pixel_depth_bytes = 4, + .pixel_is_signed = false, + .pixel_is_float = false, + .algorithm = CompressionAlgorithm::NO_COMPRESSION, + .channel = "sc0" + }; + + StartMessage message {}; + + message.AddPixelMask(image_mask); + REQUIRE_NOTHROW(serializer.SerializeSequenceStart(message)); + + JFJochFrameDeserializer deserializer; + REQUIRE_NOTHROW(deserializer.Process(buffer.data(), serializer.GetBufferSize())); + REQUIRE(deserializer.GetType() == JFJochFrameDeserializer::Type::START); + + StartMessage output_message; + REQUIRE_NOTHROW(output_message = deserializer.GetStartMessage()); + REQUIRE(output_message.pixel_mask.size() == 1); + CHECK(!output_message.pixel_mask[0].pixel_is_float); + CHECK(output_message.pixel_mask[0].xpixel == 456); + CHECK(output_message.pixel_mask[0].ypixel == 457); + CHECK(output_message.pixel_mask[0].channel == "sc0"); + CHECK(memcmp(output_message.pixel_mask[0].data, mask.data(), mask.size() * sizeof(float)) == 0); +} + +TEST_CASE("CBORSerialize_Start_Calibration", "[CBOR]") { + std::vector buffer(8*1024*1024); + JFJochFrameSerializer serializer(buffer.data(), buffer.size()); + + std::vector calib1(256); + std::vector calib2(256); + + for (int i = 0; i < 256; i++) { + calib1[i] = i * 34.567; + calib2[i] = i * 76.33456; + } + + CBORImage image1 { + .data = reinterpret_cast(calib1.data()), + .size = 16 * 16 * sizeof(float), + .xpixel = 16, + .ypixel = 16, + .pixel_depth_bytes = 4, + .pixel_is_signed = true, + .pixel_is_float = true, + .algorithm = CompressionAlgorithm::NO_COMPRESSION, + .channel = "calib1" + }; + + CBORImage image2 { + .data = reinterpret_cast(calib2.data()), + .size = 16 * 16 * sizeof(float), + .xpixel = 16, + .ypixel = 16, + .pixel_depth_bytes = 4, + .pixel_is_signed = true, + .pixel_is_float = true, + .algorithm = CompressionAlgorithm::NO_COMPRESSION, + .channel = "calib2" + }; + + StartMessage message {}; + + message.AddCalibration(image2); + message.AddCalibration(image1); + REQUIRE_NOTHROW(serializer.SerializeSequenceStart(message)); + + JFJochFrameDeserializer deserializer; + REQUIRE_NOTHROW(deserializer.Process(buffer.data(), serializer.GetBufferSize())); + REQUIRE(deserializer.GetType() == JFJochFrameDeserializer::Type::START); + + StartMessage output_message; + REQUIRE_NOTHROW(output_message = deserializer.GetStartMessage()); + REQUIRE(output_message.calibration.size() == 2); + CHECK(output_message.calibration[0].pixel_is_float); + CHECK(output_message.calibration[1].pixel_is_float); + CHECK(output_message.calibration[0].xpixel == 16); + CHECK(output_message.calibration[0].ypixel == 16); + CHECK(output_message.calibration[1].xpixel == 16); + CHECK(output_message.calibration[1].ypixel == 16); + CHECK(output_message.calibration[0].channel == "calib2"); + CHECK(output_message.calibration[1].channel == "calib1"); + CHECK(memcmp(output_message.calibration[0].data, calib2.data(), 256 * sizeof(float)) == 0); + CHECK(memcmp(output_message.calibration[1].data, calib1.data(), 256 * sizeof(float)) == 0); +} + TEST_CASE("CBORSerialize_End", "[CBOR]") { std::vector buffer(8*1024*1024); JFJochFrameSerializer serializer(buffer.data(), buffer.size()); @@ -208,6 +304,7 @@ JFJochFrameSerializer serializer(buffer.data(), buffer.size()); .ypixel = 2, .pixel_depth_bytes = 2, .pixel_is_signed = true, + .pixel_is_float = false, .algorithm = CompressionAlgorithm::NO_COMPRESSION, .channel = "default" }; @@ -240,6 +337,7 @@ JFJochFrameSerializer serializer(buffer.data(), buffer.size()); REQUIRE(image_array.image.ypixel == 2); REQUIRE(image_array.image.pixel_depth_bytes == 2); REQUIRE(image_array.image.pixel_is_signed); + REQUIRE(!image_array.image.pixel_is_float); REQUIRE(image_array.image.channel == "default"); REQUIRE(image_array.image.size == test.size()); REQUIRE(image_array.indexing_result == message.indexing_result); @@ -274,6 +372,7 @@ JFJochFrameSerializer serializer(buffer.data(), buffer.size()); .ypixel = 512, .pixel_depth_bytes = 1, .pixel_is_signed = false, + .pixel_is_float = false, .algorithm = CompressionAlgorithm::NO_COMPRESSION, .channel = "default" }; @@ -297,6 +396,7 @@ JFJochFrameSerializer serializer(buffer.data(), buffer.size()); REQUIRE(image_array.image.ypixel == 512); REQUIRE(image_array.image.pixel_depth_bytes == 1); REQUIRE(!image_array.image.pixel_is_signed); + REQUIRE(!image_array.image.pixel_is_float); REQUIRE(image_array.image.channel == "default"); REQUIRE(image_array.image.size == test.size()); REQUIRE(image_array.indexing_result == message.indexing_result); @@ -305,6 +405,56 @@ JFJochFrameSerializer serializer(buffer.data(), buffer.size()); REQUIRE(memcmp(image_array.image.data, test.data(), test.size()) == 0); } +TEST_CASE("CBORSerialize_Image_Float", "[CBOR]") { + std::vector buffer(8*1024*1024); + JFJochFrameSerializer serializer(buffer.data(), buffer.size()); + + std::vector spots; + + std::vector test(512*1024); + for (int i = 0; i < test.size(); i++) + test[i] = i * 0.1f; + + CBORImage image { + .data = reinterpret_cast(test.data()), + .size = 1024 * 512 * sizeof(float), + .xpixel = 1024, + .ypixel = 512, + .pixel_depth_bytes = 4, + .pixel_is_signed = true, + .pixel_is_float = true, + .algorithm = CompressionAlgorithm::NO_COMPRESSION, + .channel = "default" + }; + + DataMessage message { + .number = 480, + .image = image, + .spots = spots, + .indexing_result = 3 + }; + + REQUIRE_NOTHROW(serializer.SerializeImage(message)); + + JFJochFrameDeserializer deserializer; + REQUIRE_NOTHROW(deserializer.Process(buffer.data(), serializer.GetBufferSize())); + REQUIRE(deserializer.GetType() == JFJochFrameDeserializer::Type::IMAGE); + + auto image_array = deserializer.GetDataMessage(); + REQUIRE(image_array.image.algorithm == CompressionAlgorithm::NO_COMPRESSION); + REQUIRE(image_array.image.xpixel == 1024); + REQUIRE(image_array.image.ypixel == 512); + REQUIRE(image_array.image.pixel_is_float); + REQUIRE(image_array.image.pixel_depth_bytes == 4); + REQUIRE(image_array.image.pixel_is_signed); + REQUIRE(image_array.image.channel == "default"); + REQUIRE(image_array.image.size == test.size() * sizeof(float)); + REQUIRE(image_array.indexing_result == message.indexing_result); + REQUIRE(image_array.receiver_available_send_buffers == message.receiver_available_send_buffers); + REQUIRE(image_array.number == 480); + REQUIRE(memcmp(image_array.image.data, test.data(), test.size() * sizeof(float)) == 0); +} + TEST_CASE("CBORSerialize_Image_Append", "[CBOR]") { std::vector buffer(8*1024*1024); JFJochFrameSerializer serializer(buffer.data(), buffer.size()); @@ -322,6 +472,7 @@ JFJochFrameSerializer serializer(buffer.data(), buffer.size()); .ypixel = 512, .pixel_depth_bytes = 1, .pixel_is_signed = false, + .pixel_is_float = false, .algorithm = CompressionAlgorithm::NO_COMPRESSION, .channel = "default" }; @@ -347,6 +498,7 @@ JFJochFrameSerializer serializer(buffer.data(), buffer.size()); REQUIRE(image_array.image.ypixel == 512); REQUIRE(image_array.image.pixel_depth_bytes == 1); REQUIRE(!image_array.image.pixel_is_signed); + REQUIRE(!image_array.image.pixel_is_float); REQUIRE(image_array.image.channel == "default"); REQUIRE(image_array.image.size == test.size()); REQUIRE(image_array.indexing_result == message.indexing_result); @@ -371,6 +523,7 @@ JFJochFrameSerializer serializer(buffer.data(), buffer.size()); .ypixel = 2, .pixel_depth_bytes = 4, .pixel_is_signed = true, + .pixel_is_float = false, .algorithm = CompressionAlgorithm::BSHUF_LZ4, .channel = "default" }; @@ -392,6 +545,7 @@ JFJochFrameSerializer serializer(buffer.data(), buffer.size()); REQUIRE(image_array.image.xpixel == 256); REQUIRE(image_array.image.ypixel == 2); REQUIRE(image_array.image.pixel_depth_bytes == 4); + REQUIRE(!image_array.image.pixel_is_float); REQUIRE(image_array.image.channel == "default"); REQUIRE(image_array.image.size == test.size()); REQUIRE(image_array.image.pixel_is_signed == true); @@ -494,7 +648,21 @@ inline bool CmpString(const char *str1, const std::string& str2) { TEST_CASE("CBORSerialize_Start_stream2", "[CBOR]") { std::vector buffer(8*1024*1024); -JFJochFrameSerializer serializer(buffer.data(), buffer.size()); + JFJochFrameSerializer serializer(buffer.data(), buffer.size()); + + std::vector mask(456*457, 15); + + CBORImage image_mask { + .data = reinterpret_cast(mask.data()), + .size = 456 * 457 * sizeof(uint32_t), + .xpixel = 456, + .ypixel = 457, + .pixel_depth_bytes = 4, + .pixel_is_signed = false, + .pixel_is_float = false, + .algorithm = CompressionAlgorithm::NO_COMPRESSION, + .channel = "sc0" + }; StartMessage message { .data_file_count = 3, @@ -543,7 +711,8 @@ JFJochFrameSerializer serializer(buffer.data(), buffer.size()); .rad_int_bin_number = 35, .summation = 567 }; - message.pixel_mask["sc0"] = std::vector(456*457, 15); + + message.AddPixelMask(image_mask); REQUIRE_NOTHROW(serializer.SerializeSequenceStart(message)); @@ -572,8 +741,7 @@ JFJochFrameSerializer serializer(buffer.data(), buffer.size()); CHECK(msg2->pixel_mask.ptr[0].pixel_mask.dim[0] == 457); CHECK(msg2->pixel_mask.ptr[0].pixel_mask.dim[1] == 456); CHECK(msg2->pixel_mask.ptr[0].pixel_mask.array.data.len == 456 * 457 * sizeof(uint32_t)); - CHECK(memcmp(msg2->pixel_mask.ptr[0].pixel_mask.array.data.ptr, message.pixel_mask["sc0"].data(), - 456 * 457 * sizeof(uint32_t)) == 0); + CHECK(memcmp(msg2->pixel_mask.ptr[0].pixel_mask.array.data.ptr, mask.data(), 456 * 457 * sizeof(uint32_t)) == 0); CHECK(msg2->pixel_mask.ptr[0].pixel_mask.array.tag == TagUnsignedInt32BitLE); stream2_free_msg(msg); } @@ -630,6 +798,7 @@ JFJochFrameSerializer serializer(buffer.data(), buffer.size()); .ypixel = 512, .pixel_depth_bytes = 2, .pixel_is_signed = false, + .pixel_is_float = false, .algorithm = CompressionAlgorithm::BSHUF_LZ4, .channel = "default" }; @@ -681,6 +850,7 @@ JFJochFrameSerializer serializer(buffer.data(), buffer.size()); .ypixel = 512, .pixel_depth_bytes = 1, .pixel_is_signed = false, + .pixel_is_float = false, .algorithm = CompressionAlgorithm::NO_COMPRESSION, .channel = "default" }; diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 381bdafd..e589acd7 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -25,7 +25,7 @@ ADD_EXECUTABLE(CatchTest RadialIntegrationTest.cpp StatusVectorTest.cpp ProcessRawPacketTest.cpp CBORTest.cpp ../tests/stream2.h ../tests/stream2.c - JFConversionTest.cpp DetectorGeometryTest.cpp JFJochBrokerParserTest.cpp DetectorSetupTest.cpp) + JFConversionTest.cpp DetectorGeometryTest.cpp JFJochBrokerParserTest.cpp DetectorSetupTest.cpp DiffractionGeometryTest.cpp ROIFilterTest.cpp) target_link_libraries(CatchTest JFJochBroker JFJochReceiver JFJochWriter ImageAnalysis CommonFunctions HLSSimulation) target_include_directories(CatchTest PRIVATE .) diff --git a/tests/CoordTest.cpp b/tests/CoordTest.cpp index 99efb958..3ff31b1a 100644 --- a/tests/CoordTest.cpp +++ b/tests/CoordTest.cpp @@ -1,5 +1,4 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (2019-2023) Paul Scherrer Institute #include #include "../common/Coord.h" @@ -103,8 +102,8 @@ TEST_CASE("Coord_operator_bracket","[LinearAlgebra][Coord]") { TEST_CASE("Coord_normalize","[LinearAlgebra][Coord]") { Coord a{4,0,0}; REQUIRE(a.Length() == 4.0); - REQUIRE(a.Normalize().Length() == 1.0); - REQUIRE(a.Normalize().x == 1.0); + REQUIRE(a.Normalize().Length() == Approx(1.0)); + REQUIRE(a.Normalize().x == Approx(1.0)); REQUIRE(a.Normalize().y == 0.0); REQUIRE(a.Normalize().z == 0.0); diff --git a/tests/DetectorGeometryTest.cpp b/tests/DetectorGeometryTest.cpp index d3ff8981..a41bc93e 100644 --- a/tests/DetectorGeometryTest.cpp +++ b/tests/DetectorGeometryTest.cpp @@ -1,5 +1,4 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (2019-2023) Paul Scherrer Institute #include #include "../common/DetectorGeometry.h" @@ -20,6 +19,35 @@ TEST_CASE("DetectorGeometry_Regular", "[DetectorGeometry]") { REQUIRE(pbuf.module_geometry(15).slow_direction_step() == pbuf.width_pxl()); } +TEST_CASE("DetectorGeometry_Regular_1Module", "[DetectorGeometry]") { + DetectorGeometry geometry(1, 3, 8, 36, false); + + const JFJochProtoBuf::DetectorGeometry pbuf = geometry; + REQUIRE(pbuf.module_geometry_size() == 1); + + REQUIRE(pbuf.width_pxl() == CONVERTED_MODULE_COLS); + REQUIRE(pbuf.height_pxl() == CONVERTED_MODULE_LINES); + REQUIRE(pbuf.module_geometry(0).pixel0() == 0); + + REQUIRE(pbuf.module_geometry(0).fast_direction_step() == 1); + REQUIRE(pbuf.module_geometry(0).slow_direction_step() == CONVERTED_MODULE_COLS); +} + +TEST_CASE("DetectorGeometry_Regular_2Module", "[DetectorGeometry]") { + DetectorGeometry geometry(2, 2, 8, 36, false); + + const JFJochProtoBuf::DetectorGeometry pbuf = geometry; + REQUIRE(pbuf.module_geometry_size() == 2); + + REQUIRE(pbuf.width_pxl() == CONVERTED_MODULE_COLS * 2 + 8); + REQUIRE(pbuf.height_pxl() == CONVERTED_MODULE_LINES); + REQUIRE(pbuf.module_geometry(0).pixel0() == 0); + REQUIRE(pbuf.module_geometry(1).pixel0() == CONVERTED_MODULE_COLS + 8); + + REQUIRE(pbuf.module_geometry(0).fast_direction_step() == 1); + REQUIRE(pbuf.module_geometry(0).slow_direction_step() == CONVERTED_MODULE_COLS * 2 + 8); +} + TEST_CASE("DetectorGeometry_RegularMirror", "[DetectorGeometry]") { DetectorGeometry geometry(18, 3, 8, 36, true); diff --git a/tests/DetectorSetupTest.cpp b/tests/DetectorSetupTest.cpp index 50cd3fff..fc1d14e9 100644 --- a/tests/DetectorSetupTest.cpp +++ b/tests/DetectorSetupTest.cpp @@ -1,5 +1,4 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (2019-2023) Paul Scherrer Institute #include #include "../common/DetectorSetup.h" diff --git a/tests/DiffractionExperimentTest.cpp b/tests/DiffractionExperimentTest.cpp index 58f5cce1..1a9616b1 100644 --- a/tests/DiffractionExperimentTest.cpp +++ b/tests/DiffractionExperimentTest.cpp @@ -1,5 +1,4 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (2019-2023) Paul Scherrer Institute #define CATCH_CONFIG_MAIN #include @@ -368,16 +367,12 @@ TEST_CASE("DiffractionExperiment_Metadata","[DiffractionExperiment]") { REQUIRE(x.GetPhotonEnergy_keV() == 6.0); REQUIRE(x.GetWavelength_A() == Approx(12.39854 / 6.0)); - x.DetectorDistance_mm(30.0).BeamX_pxl(1200).BeamY_pxl(1000) - .ScatteringVector({1,2,3}).Summation(3).FrameTime(900us); + x.DetectorDistance_mm(30.0).BeamX_pxl(1200).BeamY_pxl(1000).Summation(3).FrameTime(900us); REQUIRE(x.GetBeamX_pxl() == Approx(1200)); REQUIRE(x.GetBeamY_pxl() == Approx(1000)); REQUIRE(x.GetDetectorDistance_mm() == Approx(30.0)); - REQUIRE(x.GetScatteringVector().x == Approx(1.0/sqrt(14.0) / x.GetWavelength_A())); - REQUIRE(x.GetScatteringVector().y == Approx(2.0/sqrt(14.0) / x.GetWavelength_A())); - REQUIRE(x.GetScatteringVector().z == Approx(3.0/sqrt(14.0) / x.GetWavelength_A())); REQUIRE_THROWS(x.PedestalG0Frames(-1)); REQUIRE_THROWS(x.PedestalG1Frames(-1)); @@ -559,21 +554,6 @@ TEST_CASE("DiffractionExperiment_CopyConstructor", "[DiffractionExperiment]") { REQUIRE (c.GetBeamX_pxl() == 10.0); } -TEST_CASE("DiffractionExperiment_ResToPxl","[DiffractionExperiment]") { - DiffractionExperiment x(DetectorGeometry(8, 2, 8, 36)); - x.DetectorDistance_mm(75).PhotonEnergy_keV(WVL_1A_IN_KEV); - - // sin(theta) = 1/2 - // theta = 30 deg - // tan(2 * theta) = sqrt(3) - REQUIRE(x.ResToPxl(1.0) == Approx(1000 * sqrt(3))); - - // sin(theta) = 1/4 - // theta = 14.47 deg - // tan(2 * theta) = 0.55328333517 - REQUIRE(x.ResToPxl(2.0) == Approx(1000 * 0.55328333517)); -} - TEST_CASE("DiffractionExperiment_RadialIntegration_LowQ","[DiffractionExperiment]") { DiffractionExperiment x(DetectorGeometry(8, 2, 8, 36)); @@ -633,12 +613,17 @@ TEST_CASE("DiffractionExperiment_StorageCells","[DiffractionExperiment]") { REQUIRE(x.GetImageNumPerTrigger() == 5); REQUIRE(x.GetNumTriggers() == num_triggers); - REQUIRE_THROWS(x.StorageCells(5)); + REQUIRE_NOTHROW(x.StorageCells(5)); + REQUIRE(x.GetStorageCellNumber() == 5); + REQUIRE_THROWS(x.StorageCells(0)); REQUIRE_THROWS(x.StorageCells(-1)); REQUIRE_THROWS(x.StorageCells(32)); - REQUIRE_THROWS(x.StorageCells(3)); - REQUIRE_THROWS(x.StorageCells(15)); + REQUIRE_NOTHROW(x.StorageCells(3)); + REQUIRE(x.GetStorageCellNumber() == 3); + + REQUIRE_NOTHROW(x.StorageCells(15)); + REQUIRE(x.GetStorageCellNumber() == 15); REQUIRE_NOTHROW(x.StorageCells(4)); REQUIRE(x.GetStorageCellNumber() == 4); @@ -724,7 +709,7 @@ TEST_CASE("DiffractionExperiment_DetectorInput_PedestalG2","[DiffractionExperime TEST_CASE("DiffractionExperiment_DetectorInput_StorageCell","[DiffractionExperiment]") { DiffractionExperiment x(DetectorGeometry(8, 2, 8, 36)); - x.FrameTime(1200us).Summation(1).NumTriggers(4560).StorageCells(8); + x.FrameTime(1200us).Summation(1).NumTriggers(4560).StorageCells(8).StorageCellDelay(7000ns); JFJochProtoBuf::DetectorInput ret = x; REQUIRE(ret.modules_num() == 8); REQUIRE(ret.period_us() == 8 * (x.GetFrameTime().count() + 10)); @@ -732,14 +717,13 @@ TEST_CASE("DiffractionExperiment_DetectorInput_StorageCell","[DiffractionExperim REQUIRE(ret.num_triggers() == 4560 + 1); REQUIRE(ret.num_frames() == 1); REQUIRE(ret.storage_cell_number() == 8); - REQUIRE(ret.storage_cell_delay() == 7.5); + REQUIRE(ret.storage_cell_delay_ns() == 7000); REQUIRE(ret.storage_cell_start() == x.GetStorageCellStart()); } TEST_CASE("DiffractionExperiment_LoadDatasetSettings", "[DiffractionExperiment]") { DiffractionExperiment x; - x.ImagesPerTrigger(567).BeamY_pxl(324).ScatteringVector({1,0,0}) - .Compression(JFJochProtoBuf::BSHUF_ZSTD); + x.ImagesPerTrigger(567).BeamY_pxl(324).Compression(JFJochProtoBuf::BSHUF_ZSTD); JFJochProtoBuf::DatasetSettings settings; settings.set_images_per_trigger(234); settings.set_ntrigger(56); @@ -751,12 +735,10 @@ TEST_CASE("DiffractionExperiment_LoadDatasetSettings", "[DiffractionExperiment]" settings.set_data_file_count(5); settings.set_space_group_number(45); settings.set_sample_name("lyso1"); - settings.set_apply_pixel_mask(true); settings.set_binning2x2(true); REQUIRE_NOTHROW(x.LoadDatasetSettings(settings)); - REQUIRE(x.GetScatteringVector().x == 0); REQUIRE(x.GetImageNumPerTrigger() == 234); REQUIRE(x.GetBeamX_pxl() == Approx(23.4/2)); REQUIRE(x.GetBeamY_pxl() == Approx(123.4/2)); @@ -765,7 +747,6 @@ TEST_CASE("DiffractionExperiment_LoadDatasetSettings", "[DiffractionExperiment]" REQUIRE(x.GetSampleName() == "lyso1"); REQUIRE(x.GetDataFileCount() == 5); REQUIRE(x.GetDetectorDistance_mm() == Approx(57.6)); - REQUIRE(x.GetApplyPixelMaskInFPGA()); REQUIRE(x.GetBinning2x2()); } @@ -801,8 +782,7 @@ TEST_CASE("DiffractionExperiment_ImageTimeUs", "[DiffractionExperiment]") { TEST_CASE("DiffractionExperiment_LoadDatasetSettings_Invalid", "[DiffractionExperiment]") { DiffractionExperiment x; - x.ImagesPerTrigger(567).BeamY_pxl(324).ScatteringVector({1,0,0}) - .Compression(JFJochProtoBuf::BSHUF_ZSTD); + x.ImagesPerTrigger(567).BeamY_pxl(324).Compression(JFJochProtoBuf::BSHUF_ZSTD); JFJochProtoBuf::DatasetSettings settings; settings.set_images_per_trigger(-1); settings.set_ntrigger(56); @@ -817,7 +797,6 @@ TEST_CASE("DiffractionExperiment_LoadDatasetSettings_Invalid", "[DiffractionExpe REQUIRE_THROWS(x.LoadDatasetSettings(settings)); - REQUIRE(x.GetScatteringVector().x == Approx(1)); REQUIRE(x.GetImageNumPerTrigger() == 567); REQUIRE(x.GetBeamY_pxl() == Approx(324)); REQUIRE(x.GetSpaceGroupNumber() == 0); @@ -825,7 +804,7 @@ TEST_CASE("DiffractionExperiment_LoadDatasetSettings_Invalid", "[DiffractionExpe TEST_CASE("DiffractionExperiment_LoadDetectorSettings", "[DiffractionExperiment]") { DiffractionExperiment x; - x.PedestalG0Frames(456).PedestalG1Frames(1234).PedestalG2Frames(123); + x.PedestalG0Frames(456).PedestalG1Frames(1234).PedestalG2Frames(123).StorageCellDelay(2500ns); JFJochProtoBuf::DetectorSettings settings; settings.set_frame_time_us(600); @@ -846,6 +825,22 @@ TEST_CASE("DiffractionExperiment_LoadDetectorSettings", "[DiffractionExperiment] REQUIRE(x.GetPedestalG0Frames() == 5000); REQUIRE(x.GetPedestalG1Frames() == 100); REQUIRE(x.GetPedestalG2Frames() == 150); + REQUIRE(x.GetStorageCellDelay().count() == 2500); +} + +TEST_CASE("DiffractionExperiment_LoadDetectorSettings_StorageCellDelay", "[DiffractionExperiment]") { + DiffractionExperiment x; + x.PedestalG0Frames(456).PedestalG1Frames(1234).PedestalG2Frames(123).StorageCellDelay(5000ns); + + JFJochProtoBuf::DetectorSettings settings; + settings.set_frame_time_us(600); + settings.set_count_time_us(400); + settings.set_storage_cell_count(8); + settings.set_use_internal_packet_generator(true); + settings.set_collect_raw_data(true); + settings.set_storage_cell_delay_ns(7000); + REQUIRE_NOTHROW(x.LoadDetectorSettings(settings)); + REQUIRE(x.GetStorageCellDelay().count() == 7000); } TEST_CASE("DiffractionExperiment_LoadDetectorSettings_invalid", "[DiffractionExperiment]") { @@ -982,9 +977,3 @@ TEST_CASE("DiffractionExperiment_DetectorModuleHostname","[DiffractionExperiment REQUIRE_NOTHROW(det_cfg = x.DetectorConfig(net_cfg)); } -TEST_CASE("DiffractionExperiment_SolidAngleCorrection","[DiffractionExperiment]") { - DiffractionExperiment x; - x.PhotonEnergy_keV(WVL_1A_IN_KEV); - REQUIRE(x.CalcRadIntSolidAngleCorr(0.0) == 1.0f); - REQUIRE(x.CalcRadIntSolidAngleCorr(2*M_PI) == Approx(0.5f*0.5f*0.5f)); -} diff --git a/tests/DiffractionGeometryTest.cpp b/tests/DiffractionGeometryTest.cpp new file mode 100644 index 00000000..f8af967e --- /dev/null +++ b/tests/DiffractionGeometryTest.cpp @@ -0,0 +1,132 @@ +// Copyright (2019-2023) Paul Scherrer Institute + +#include +#include "../common/DiffractionGeometry.h" + +TEST_CASE("RecipToDetector_1", "[LinearAlgebra][Coord]") { + DiffractionExperiment x(DetectorGeometry(8, 2)); + x.BeamX_pxl(1024).BeamY_pxl(1024).DetectorDistance_mm(120); + + float pos_x = 512, pos_y = 512; + + auto recip = DetectorToRecip(x, pos_x, pos_y); + auto [proj_x, proj_y] = RecipToDector(x, recip); + REQUIRE(proj_x == Approx(pos_x)); + REQUIRE(proj_y == Approx(pos_y)); + REQUIRE((recip - DetectorToRecip(x, proj_x, proj_y)).Length() < 0.00000001f); + REQUIRE(DistFromEwaldSphere(x, recip) < 4e-4); +} + +TEST_CASE("RecipToDetector_2", "[LinearAlgebra][Coord]") { + DiffractionExperiment x(DetectorGeometry(8, 2)); + x.BeamX_pxl(1024).BeamY_pxl(1024).DetectorDistance_mm(120); + float pos_x = 1023, pos_y = 1023; + + auto recip = DetectorToRecip(x, pos_x, pos_y); + auto [proj_x, proj_y] = RecipToDector(x, recip); + REQUIRE(proj_x == Approx(pos_x)); + REQUIRE(proj_y == Approx(pos_y)); + REQUIRE((recip - DetectorToRecip(x, proj_x, proj_y)).Length() < 0.00000001f); + REQUIRE(DistFromEwaldSphere(x, recip) < 4e-4); +} + +TEST_CASE("RecipToDetector_3", "[LinearAlgebra][Coord]") { + DiffractionExperiment x(DetectorGeometry(8, 2)); + x.BeamX_pxl(1024).BeamY_pxl(1024).DetectorDistance_mm(120); + float pos_x = 30, pos_y = 30; + + auto recip = DetectorToRecip(x, pos_x, pos_y); + auto [proj_x, proj_y] = RecipToDector(x, recip); + REQUIRE(proj_x == Approx(pos_x)); + REQUIRE(proj_y == Approx(pos_y)); + REQUIRE((recip - DetectorToRecip(x, proj_x, proj_y)).Length() < 0.00000001f); + REQUIRE(DistFromEwaldSphere(x, recip) < 4e-4); +} + +TEST_CASE("Phi","") { + DiffractionExperiment x(DetectorGeometry(8, 2, 8, 36)); + x.DetectorDistance_mm(75).PhotonEnergy_keV(WVL_1A_IN_KEV); + x.BeamX_pxl(1000).BeamY_pxl(1000); + + REQUIRE(Phi(x, 2000, 1000) == Approx(0.0)); + REQUIRE(Phi(x, 1000, 2000) == Approx(M_PI_2)); + REQUIRE(Phi(x, 2000, 2000) == Approx(M_PI_4)); +} + +TEST_CASE("Cos2Theta","") { + DiffractionExperiment x(DetectorGeometry(8, 2, 8, 36)); + x.DetectorDistance_mm(75).PhotonEnergy_keV(WVL_1A_IN_KEV); + x.BeamX_pxl(1000).BeamY_pxl(1000); + + // det distance == 1000 pixel + // theta = 30 deg + // tan(2 * theta) = sqrt(3) + REQUIRE(CosTwoTheta(x, 1000, 1000 * (1.0 + sqrt(3))) == Approx(0.5f)); +} + +TEST_CASE("PxlToRes","") { + DiffractionExperiment x(DetectorGeometry(8, 2, 8, 36)); + x.DetectorDistance_mm(75).PhotonEnergy_keV(WVL_1A_IN_KEV); + + // sin(theta) = 1/2 + // theta = 30 deg + // tan(2 * theta) = sqrt(3) + REQUIRE(PxlToRes(x, 0, 1000 * sqrt(3)) == Approx(1.0)); + + // sin(theta) = 1/4 + // theta = 14.47 deg + // tan(2 * theta) = 0.55328333517 + + REQUIRE(PxlToRes(x, 1000 * 0.55328333517 * cosf(1), 1000 * 0.55328333517 * sinf(1)) == Approx(2.0)); +} + +TEST_CASE("ResToPxl","") { + DiffractionExperiment x(DetectorGeometry(8, 2, 8, 36)); + x.DetectorDistance_mm(75).PhotonEnergy_keV(WVL_1A_IN_KEV); + + // sin(theta) = 1/2 + // theta = 30 deg + // tan(2 * theta) = sqrt(3) + REQUIRE(ResToPxl(x, 1.0) == Approx(1000 * sqrt(3))); + + // sin(theta) = 1/4 + // theta = 14.47 deg + // tan(2 * theta) = 0.55328333517 + REQUIRE(ResToPxl(x, 2.0) == Approx(1000 * 0.55328333517)); +} + +TEST_CASE("SolidAngleCorrection","") { + DiffractionExperiment x; + x.PhotonEnergy_keV(WVL_1A_IN_KEV); + x.BeamX_pxl(1000).BeamY_pxl(1000).DetectorDistance_mm(75); + + REQUIRE(CalcRadIntSolidAngleCorr(x, 0.0) == 1.0f); + REQUIRE(CalcRadIntSolidAngleCorr(x, 2*M_PI) == Approx(0.5f*0.5f*0.5f)); + + // theta = 30 deg + // cos (2 * theta) = 1/2 + REQUIRE(CalcRadIntSolidAngleCorr(x, 1000, 1000) == 1.0f); + REQUIRE(CalcRadIntSolidAngleCorr(x, 1000 * (1.0 + sqrt(3)), 1000) == Approx(0.5f*0.5f*0.5f)); +} + +TEST_CASE("PolarizationCorrection","") { + DiffractionExperiment x; + x.PhotonEnergy_keV(WVL_1A_IN_KEV); + x.BeamX_pxl(1000).BeamY_pxl(1000).DetectorDistance_mm(75); + + // Circular polarization 0.5*(1+cos(2theta)^2) + x.PolarizationFactor(0); + REQUIRE(CalcRadIntPolarizationCorr(x, 1000 * (1.0 + sqrt(3)), 1000) == Approx(0.5f*(1+0.5f*0.5f))); + REQUIRE(CalcRadIntPolarizationCorr(x, 1000, 1000* (1.0 + sqrt(3))) == Approx(0.5f*(1+0.5f*0.5f))); + + // Horizontal polarization + x.PolarizationFactor(1); + + // No correction in vertical direction + REQUIRE(CalcRadIntPolarizationCorr(x, 1000, 1000 * (1.0 + sqrt(3))) == Approx(1.0f)); + REQUIRE(CalcRadIntPolarizationCorr(x, 1000, 1000 * (1.0 - sqrt(3))) == Approx(1.0f)); + + // cos(2*theta)^2 in horizontal direction + REQUIRE(CalcRadIntPolarizationCorr(x, 1000 * (1.0 + sqrt(3)), 1000) == Approx(0.5f*0.5f)); + REQUIRE(CalcRadIntPolarizationCorr(x, 1000 * (1.0 - sqrt(3)), 1000) == Approx(0.5f*0.5f)); +} diff --git a/tests/FPGAIntegrationTest.cpp b/tests/FPGAIntegrationTest.cpp index 1647bc37..eb0d135e 100644 --- a/tests/FPGAIntegrationTest.cpp +++ b/tests/FPGAIntegrationTest.cpp @@ -1,12 +1,11 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (2019-2023) Paul Scherrer Institute #include #include #include #include "../jungfrau/JFPedestalCalc.h" -#include "../receiver/host/HLSSimulatedDevice.h" +#include "../receiver/HLSSimulatedDevice.h" #include "FPGAUnitTest.h" using namespace std::literals::chrono_literals; @@ -20,7 +19,7 @@ TEST_CASE("HLS_C_Simulation_internal_packet_generator", "[FPGA][Full]") { x.UseInternalPacketGenerator(true).ImagesPerTrigger(4).PedestalG0Frames(0); HLSSimulatedDevice test(0, 64); - + test.SetFPGANonBlockingMode(false); REQUIRE_NOTHROW(test.StartAction(x)); REQUIRE_NOTHROW(test.WaitForActionComplete()); @@ -39,6 +38,26 @@ TEST_CASE("HLS_C_Simulation_internal_packet_generator", "[FPGA][Full]") { } } +TEST_CASE("HLS_C_Simulation_internal_packet_generator_skip_packets", "[FPGA][Full]") { + const uint16_t nmodules = 1; + + DiffractionExperiment x((DetectorGeometry(nmodules))); + + x.Mode(DetectorMode::Raw); + x.UseInternalPacketGenerator(true).ImagesPerTrigger(1000).PedestalG0Frames(0); + + HLSSimulatedDevice test(0, 64); + + REQUIRE_NOTHROW(test.StartAction(x)); + REQUIRE_NOTHROW(test.WaitForActionComplete()); + + REQUIRE(test.OutputStream().size() == 1); + + JFJochProtoBuf::AcquisitionDeviceStatistics device_statistics; + REQUIRE_NOTHROW(test.SaveStatistics(x, device_statistics)); + REQUIRE(device_statistics.efficiency() < 1.0); +} + TEST_CASE("HLS_C_Simulation_internal_packet_generator_custom_frame", "[FPGA][Full]") { const uint16_t nmodules = 4; @@ -57,6 +76,7 @@ TEST_CASE("HLS_C_Simulation_internal_packet_generator_custom_frame", "[FPGA][Ful HLSSimulatedDevice test(0, 64); test.SetCustomInternalGeneratorFrame(test_frame); + test.SetFPGANonBlockingMode(false); REQUIRE_NOTHROW(test.StartAction(x)); REQUIRE_NOTHROW(test.WaitForActionComplete()); @@ -67,14 +87,12 @@ TEST_CASE("HLS_C_Simulation_internal_packet_generator_custom_frame", "[FPGA][Ful for (int image = 0; image < 4; image++) { for (int m = 0; m < nmodules; m++) { - REQUIRE(test.GetTimestamp(image, m) == 0xABCDEFABCDEF); - REQUIRE(test.GetBunchID(image,m) == 0xCACACACACA); - REQUIRE(test.GetExptime(image, m) == 10000); + REQUIRE(test.Counters().GetCompletion(image, m).timestamp == INT_PKT_GEN_EXPTTIME * image); + REQUIRE(test.Counters().GetCompletion(image, m).bunchid == INT_PKT_GEN_BUNCHID + image); + REQUIRE(test.Counters().GetCompletion(image, m).exptime == INT_PKT_GEN_EXPTTIME); auto imageBuf = (uint16_t *) test.GetFrameBuffer(image, m); for (int i = 0; i < RAW_MODULE_SIZE; i++) { - if (imageBuf[i] != test_frame[i]) - std::cout << m << " " << i << " " << imageBuf[i] << std::endl; REQUIRE(imageBuf[i] == test_frame[i]); } } @@ -98,11 +116,11 @@ TEST_CASE("HLS_C_Simulation_check_raw", "[FPGA][Full]") { HLSSimulatedDevice test(0, 64); test.CreatePackets(x, 1, 5, 0, raw_frames.data(), true); test.CreateFinalPacket(x); - + test.SetFPGANonBlockingMode(false); REQUIRE_NOTHROW(test.StartAction(x)); REQUIRE_NOTHROW(test.WaitForActionComplete()); - REQUIRE(test.GetSlowestHead() == 0); + REQUIRE(test.Counters().GetSlowestHead() == 0); REQUIRE_NOTHROW(test.OutputStream().read()); REQUIRE(test.OutputStream().size() == 0); @@ -137,11 +155,11 @@ TEST_CASE("HLS_C_Simulation_check_cancel", "[FPGA][Full]") { HLSSimulatedDevice test(0, 64); REQUIRE_NOTHROW(test.StartAction(x)); - test.ActionAbort(); + test.Cancel(); REQUIRE_NOTHROW(test.WaitForActionComplete()); - REQUIRE(test.GetSlowestHead() == 0); + REQUIRE(test.Counters().GetSlowestHead() == 0); REQUIRE_NOTHROW(test.OutputStream().read()); REQUIRE(test.OutputStream().size() == 0); @@ -162,11 +180,11 @@ TEST_CASE("HLS_C_Simulation_check_cancel_conversion", "[FPGA][Full]") { HLSSimulatedDevice test(0, 64); REQUIRE_NOTHROW(test.StartAction(x)); - test.ActionAbort(); + test.Cancel(); REQUIRE_NOTHROW(test.WaitForActionComplete()); - REQUIRE(test.GetSlowestHead() == 0); + REQUIRE(test.Counters().GetSlowestHead() == 0); REQUIRE_NOTHROW(test.OutputStream().read()); REQUIRE(test.OutputStream().size() == 0); @@ -177,8 +195,6 @@ TEST_CASE("HLS_C_Simulation_check_cancel_conversion", "[FPGA][Full]") { TEST_CASE("HLS_C_Simulation_check_delay", "[FPGA][Full]") { std::vector raw_frames(RAW_MODULE_SIZE*20); - Completion c; - const uint16_t nmodules = 4; DiffractionExperiment x((DetectorGeometry(nmodules))); @@ -210,12 +226,12 @@ TEST_CASE("HLS_C_Simulation_check_delay", "[FPGA][Full]") { REQUIRE_NOTHROW(test.WaitForActionComplete()); - REQUIRE(test.CalculateDelay(0) == 2); - REQUIRE(test.CalculateDelay(0, 0) == 2); - REQUIRE(test.CalculateDelay(1) == 1); - REQUIRE(test.CalculateDelay(1, 0) == 1); - REQUIRE(test.CalculateDelay(2) == 0); - REQUIRE(test.CalculateDelay(2, 0) == 0); + REQUIRE(test.Counters().CalculateDelay(0) == 2); + REQUIRE(test.Counters().CalculateDelay(0, 0) == 2); + REQUIRE(test.Counters().CalculateDelay(1) == 1); + REQUIRE(test.Counters().CalculateDelay(1, 0) == 1); + REQUIRE(test.Counters().CalculateDelay(2) == 0); + REQUIRE(test.Counters().CalculateDelay(2, 0) == 0); } TEST_CASE("HLS_C_Simulation_check_lost_frame_raw", "[FPGA][Full]") { @@ -234,6 +250,7 @@ TEST_CASE("HLS_C_Simulation_check_lost_frame_raw", "[FPGA][Full]") { test.CreatePacketJF(x, 1, 0, 0, data, false); test.CreateFinalPacket(x); + test.SetFPGANonBlockingMode(false); REQUIRE_NOTHROW(test.StartAction(x)); REQUIRE_NOTHROW(test.WaitForActionComplete()); @@ -317,6 +334,7 @@ TEST_CASE("HLS_C_Simulation_check_single_packet", "[FPGA][Full]") { test.CreatePacketJF(x, 4, 1, 0, data, false); test.CreateFinalPacket(x); + test.SetFPGANonBlockingMode(false); REQUIRE_NOTHROW(test.StartAction(x)); REQUIRE_NOTHROW(test.WaitForActionComplete()); @@ -324,12 +342,12 @@ TEST_CASE("HLS_C_Simulation_check_single_packet", "[FPGA][Full]") { REQUIRE_NOTHROW(test.OutputStream().read()); REQUIRE(test.OutputStream().size() == 0); - REQUIRE(test.GetBytesReceived() == 16 * JUNGFRAU_PACKET_SIZE_BYTES); + REQUIRE(test.GetBytesReceived() == 15 * JUNGFRAU_PACKET_SIZE_BYTES); JFJochProtoBuf::AcquisitionDeviceStatistics device_statistics; REQUIRE_NOTHROW(test.SaveStatistics(x, device_statistics)); - REQUIRE(device_statistics.good_packets() == 15); - REQUIRE(device_statistics.bytes_received() == 16 * JUNGFRAU_PACKET_SIZE_BYTES); + REQUIRE(device_statistics.good_packets() == 15); + REQUIRE(device_statistics.bytes_received() == 15 * JUNGFRAU_PACKET_SIZE_BYTES); } TEST_CASE("HLS_C_Simulation_check_convert_full_range", "[FPGA][Full]") { @@ -384,13 +402,11 @@ TEST_CASE("HLS_C_Simulation_check_convert_full_range", "[FPGA][Full]") { TEST_CASE("HLS_C_Simulation_internal_packet_generator_convert_full_range", "[FPGA][Full]") { double energy = 6.0; - - const uint16_t nmodules = 1; - DiffractionExperiment x((DetectorGeometry(nmodules))); + const uint16_t nmodules = 4; + DiffractionExperiment x((DetectorGeometry(nmodules, 2, 8, 36, true))); std::vector data(RAW_MODULE_SIZE); JFModulePedestal pedestal_g0, pedestal_g1, pedestal_g2; - std::vector gain(3 * RAW_MODULE_SIZE); for (int i = 0; i < RAW_MODULE_SIZE; i++) { pedestal_g0.GetPedestal()[i] = 0 + (i / 65536) * 1000 + 100 * (i % 5); @@ -409,12 +425,12 @@ TEST_CASE("HLS_C_Simulation_internal_packet_generator_convert_full_range", "[FPG auto gain_from_file = GainCalibrationFromTestFile(); JFCalibration c(x); - c.Pedestal(0,0) = pedestal_g0; - c.Pedestal(0,1) = pedestal_g1; - c.Pedestal(0,2) = pedestal_g2; - - for (int i = 0; i < x.GetModulesNum(); i++) + for (int i = 0; i < x.GetModulesNum(); i++) { + c.Pedestal(i, 0) = pedestal_g0; + c.Pedestal(i, 1) = pedestal_g1; + c.Pedestal(i, 2) = pedestal_g2; c.GainCalibration(i) = gain_from_file; + } HLSSimulatedDevice test(0, 64); @@ -425,7 +441,7 @@ TEST_CASE("HLS_C_Simulation_internal_packet_generator_convert_full_range", "[FPG REQUIRE_NOTHROW(test.OutputStream().read()); REQUIRE(test.OutputStream().size() == 0); - REQUIRE(test.GetBytesReceived() == 128 * JUNGFRAU_PACKET_SIZE_BYTES); + REQUIRE(test.GetBytesReceived() == nmodules * 128 * JUNGFRAU_PACKET_SIZE_BYTES); double mean_error = CheckConversion(x, c, data.data(), test.GetFrameBuffer(0,0)); @@ -541,17 +557,17 @@ TEST_CASE("HLS_C_Simulation_check_2_trigger_convert", "[FPGA][Full]") { REQUIRE_NOTHROW(test.StartAction(x)); - REQUIRE(!test.IsDone()); + REQUIRE(!test.Counters().IsAcquisitionFinished()); test.WaitForActionComplete(); - REQUIRE(test.IsDone()); + REQUIRE(test.Counters().IsAcquisitionFinished()); // address properly aligned REQUIRE((uint64_t) test.GetFrameBuffer(0, 0) % 128 == 0); - REQUIRE(test.GetSlowestHead() == 0); - REQUIRE(test.GetHead(0) == 9); + REQUIRE(test.Counters().GetSlowestHead() == 0); + REQUIRE(test.Counters().GetHead(0) == 9); REQUIRE_NOTHROW(test.OutputStream().read()); REQUIRE(test.OutputStream().size() == 0); @@ -592,11 +608,11 @@ TEST_CASE("HLS_C_Simulation_check_detect_last_frame", "[FPGA][Full]") { test.CreatePacketJF(x, 15, 0, 0, data, true); REQUIRE_NOTHROW(test.StartAction(x)); - REQUIRE(!test.IsDone()); + REQUIRE(!test.Counters().IsAcquisitionFinished()); test.WaitForActionComplete(); - REQUIRE(test.IsDone()); + REQUIRE(test.Counters().IsAcquisitionFinished()); REQUIRE_NOTHROW(test.OutputStream().read()); REQUIRE(test.OutputStream().size() == 0); @@ -634,11 +650,11 @@ TEST_CASE("HLS_C_Simulation_check_wrong_packet_size", "[FPGA][Full]") { REQUIRE_NOTHROW(test.StartAction(x)); - REQUIRE(!test.IsDone()); + REQUIRE(!test.Counters().IsAcquisitionFinished()); test.WaitForActionComplete(); - REQUIRE(test.IsDone()); + REQUIRE(test.Counters().IsAcquisitionFinished()); REQUIRE(test.GetBytesReceived() == 6 * JUNGFRAU_PACKET_SIZE_BYTES); } @@ -649,13 +665,13 @@ TEST_CASE("HLS_DataCollectionFSM","[OpenCAPI]") { STREAM_512 raw0; STREAM_512 raw1; - hls::stream > addr0; - hls::stream > addr1; + hls::stream addr0; + hls::stream addr1; ap_uint<1> run_data_collection = 0; ap_uint<1> cancel_data_collection = 0; ap_uint<1> idle_data_collection; - + uint32_t save_data_collection_counter; act_reg.mode = MODE_CONV; // state = WAIT_FOR_START @@ -669,7 +685,8 @@ TEST_CASE("HLS_DataCollectionFSM","[OpenCAPI]") { act_reg.one_over_energy, act_reg.nframes, act_reg.nmodules, - act_reg.nstorage_cells); + act_reg.nstorage_cells, + 0); REQUIRE(idle_data_collection == 1); REQUIRE(addr1.empty()); REQUIRE(raw1.empty()); @@ -686,7 +703,8 @@ TEST_CASE("HLS_DataCollectionFSM","[OpenCAPI]") { act_reg.one_over_energy, act_reg.nframes, act_reg.nmodules, - act_reg.nstorage_cells); + act_reg.nstorage_cells, + 0); REQUIRE(idle_data_collection == 0); REQUIRE(addr1.empty()); REQUIRE(raw1.empty()); @@ -701,7 +719,8 @@ TEST_CASE("HLS_DataCollectionFSM","[OpenCAPI]") { act_reg.one_over_energy, act_reg.nframes, act_reg.nmodules, - act_reg.nstorage_cells); + act_reg.nstorage_cells, + 0); REQUIRE(idle_data_collection == 0); REQUIRE(addr1.empty()); REQUIRE(raw1.empty()); @@ -719,7 +738,8 @@ TEST_CASE("HLS_DataCollectionFSM","[OpenCAPI]") { act_reg.one_over_energy, act_reg.nframes, act_reg.nmodules, - act_reg.nstorage_cells); + act_reg.nstorage_cells, + 0); REQUIRE(idle_data_collection == 0); REQUIRE(addr1.empty()); REQUIRE(raw1.empty()); @@ -734,7 +754,8 @@ TEST_CASE("HLS_DataCollectionFSM","[OpenCAPI]") { act_reg.one_over_energy, act_reg.nframes, act_reg.nmodules, - act_reg.nstorage_cells); + act_reg.nstorage_cells, + 0); REQUIRE(idle_data_collection == 0); REQUIRE(addr1.size() == 1); @@ -751,7 +772,8 @@ TEST_CASE("HLS_DataCollectionFSM","[OpenCAPI]") { act_reg.one_over_energy, act_reg.nframes, act_reg.nmodules, - act_reg.nstorage_cells); + act_reg.nstorage_cells, + 0); REQUIRE(idle_data_collection == 0); REQUIRE(addr1.size() == 1); @@ -770,7 +792,8 @@ TEST_CASE("HLS_DataCollectionFSM","[OpenCAPI]") { act_reg.one_over_energy, act_reg.nframes, act_reg.nmodules, - act_reg.nstorage_cells); + act_reg.nstorage_cells, + 0); REQUIRE(idle_data_collection == 0); REQUIRE(addr1.size() == 1); @@ -787,7 +810,8 @@ TEST_CASE("HLS_DataCollectionFSM","[OpenCAPI]") { act_reg.one_over_energy, act_reg.nframes, act_reg.nmodules, - act_reg.nstorage_cells); + act_reg.nstorage_cells, + 0); REQUIRE(idle_data_collection == 0); REQUIRE(addr1.size() == 2); @@ -804,7 +828,8 @@ TEST_CASE("HLS_DataCollectionFSM","[OpenCAPI]") { act_reg.one_over_energy, act_reg.nframes, act_reg.nmodules, - act_reg.nstorage_cells); + act_reg.nstorage_cells, + 0); REQUIRE(idle_data_collection == 1); REQUIRE(addr1.size() == 2); @@ -820,18 +845,24 @@ TEST_CASE("HLS_DataCollectionFSM","[OpenCAPI]") { auto addr = addr1.read(); addr = addr1.read(); - REQUIRE(addr_last_flag(addr)); + REQUIRE(addr.last); } -TEST_CASE("HLS_C_Simulation_internal_packet_generator_storage_cell_convert_G0", "[FPGA][Full]") { + +TEST_CASE("HLS_C_Simulation_internal_packet_generator_15_storage_cell_convert_G0", "[FPGA][Full]") { const uint16_t nmodules = 2; + const uint16_t ntrigger = 2; + const uint16_t nstoragecells = 15; + DiffractionExperiment x((DetectorGeometry(nmodules))); x.Mode(DetectorMode::Conversion); - x.PedestalG0Frames(0).NumTriggers(1).ImagesPerTrigger(16).UseInternalPacketGenerator(true) - .PhotonEnergy_keV(10.0).StorageCells(16); + x.PedestalG0Frames(0).NumTriggers(ntrigger).ImagesPerTrigger(nstoragecells).UseInternalPacketGenerator(true) + .PhotonEnergy_keV(10.0).StorageCells(nstoragecells); - HLSSimulatedDevice test(0, 64); + REQUIRE(x.GetImageNum() == ntrigger * nstoragecells); + + HLSSimulatedDevice test(0, ntrigger * nstoragecells); std::vector tmp(3 * RAW_MODULE_SIZE, 50); JFModuleGainCalibration gain(tmp); @@ -842,7 +873,7 @@ TEST_CASE("HLS_C_Simulation_internal_packet_generator_storage_cell_convert_G0", REQUIRE_NOTHROW(test.SetCustomInternalGeneratorFrame(data)); JFCalibration c(x); - for (int i = 0; i < 16; i++) { + for (int i = 0; i < nstoragecells; i++) { for (int j = 0; j < RAW_MODULE_SIZE; j++) { c.Pedestal(0, 0, i).GetPedestal()[j] = (15 - i) * 500; c.Pedestal(1, 0, i).GetPedestal()[j] = i * 1000; @@ -858,11 +889,108 @@ TEST_CASE("HLS_C_Simulation_internal_packet_generator_storage_cell_convert_G0", REQUIRE_NOTHROW(test.OutputStream().read()); REQUIRE(test.OutputStream().size() == 0); - REQUIRE(test.GetBytesReceived() == 2*16*128 * JUNGFRAU_PACKET_SIZE_BYTES); + REQUIRE(test.GetBytesReceived() == ntrigger * nmodules * nstoragecells * 128 * JUNGFRAU_PACKET_SIZE_BYTES); - for (int i = 0; i < 16; i++) { - REQUIRE(test.GetFrameBuffer(i,0)[511*764] == 32 - 15 + (i % 16)); - REQUIRE(test.GetFrameBuffer(i,1)[200*145] == 32 - 2 * (i % 16)); + for (int i = 0; i < ntrigger * nstoragecells; i++) { + REQUIRE(test.GetFrameBuffer(i, 0)[511 * 764] == 32 - 15 + (i % nstoragecells)); + REQUIRE(test.GetFrameBuffer(i, 1)[200 * 145] == 32 - 2 * (i % nstoragecells)); + } +} + +TEST_CASE("HLS_C_Simulation_internal_packet_generator_8_storage_cell_convert_G0", "[FPGA][Full]") { + const uint16_t nmodules = 2; + const uint16_t ntrigger = 2; + const uint16_t nstoragecells = 8; + + DiffractionExperiment x((DetectorGeometry(nmodules))); + + x.Mode(DetectorMode::Conversion); + x.PedestalG0Frames(0).NumTriggers(ntrigger).ImagesPerTrigger(nstoragecells).UseInternalPacketGenerator(true) + .PhotonEnergy_keV(10.0).StorageCells(nstoragecells); + + REQUIRE(x.GetImageNum() == ntrigger * nstoragecells); + + HLSSimulatedDevice test(0, ntrigger * nstoragecells); + + std::vector tmp(3 * RAW_MODULE_SIZE, 50); + JFModuleGainCalibration gain(tmp); + + std::vector data(RAW_MODULE_SIZE); + for (auto &i: data) + i = 16000; + REQUIRE_NOTHROW(test.SetCustomInternalGeneratorFrame(data)); + + JFCalibration c(x); + for (int i = 0; i < nstoragecells; i++) { + for (int j = 0; j < RAW_MODULE_SIZE; j++) { + c.Pedestal(0, 0, i).GetPedestal()[j] = (15 - i) * 500; + c.Pedestal(1, 0, i).GetPedestal()[j] = i * 1000; + } + } + c.GainCalibration(0) = gain; + c.GainCalibration(1) = gain; + + REQUIRE_NOTHROW(test.InitializeCalibration(x, c)); + REQUIRE_NOTHROW(test.StartAction(x)); + REQUIRE_NOTHROW(test.WaitForActionComplete()); + + REQUIRE_NOTHROW(test.OutputStream().read()); + REQUIRE(test.OutputStream().size() == 0); + + REQUIRE(test.GetBytesReceived() == ntrigger * nmodules * nstoragecells * 128 * JUNGFRAU_PACKET_SIZE_BYTES); + + for (int i = 0; i < ntrigger * nstoragecells; i++) { + REQUIRE(test.GetFrameBuffer(i, 0)[511 * 764] == 32 - 15 + (i % nstoragecells)); + REQUIRE(test.GetFrameBuffer(i, 1)[200 * 145] == 32 - 2 * (i % nstoragecells)); + } +} + + +TEST_CASE("HLS_C_Simulation_internal_packet_generator_16_storage_cell_convert_G0", "[FPGA][Full]") { + const uint16_t nmodules = 2; + const uint16_t ntrigger = 4; + const uint16_t nstoragecells = 16; + + DiffractionExperiment x((DetectorGeometry(nmodules))); + + x.Mode(DetectorMode::Conversion); + x.PedestalG0Frames(0).NumTriggers(ntrigger).ImagesPerTrigger(nstoragecells).UseInternalPacketGenerator(true) + .PhotonEnergy_keV(10.0).StorageCells(nstoragecells); + + REQUIRE(x.GetImageNum() == ntrigger * nstoragecells); + + HLSSimulatedDevice test(0, ntrigger * nstoragecells); + test.SetFPGANonBlockingMode(false); + std::vector tmp(3 * RAW_MODULE_SIZE, 50); + JFModuleGainCalibration gain(tmp); + + std::vector data(RAW_MODULE_SIZE); + for (auto &i: data) + i = 16000; + REQUIRE_NOTHROW(test.SetCustomInternalGeneratorFrame(data)); + + JFCalibration c(x); + for (int i = 0; i < nstoragecells; i++) { + for (int j = 0; j < RAW_MODULE_SIZE; j++) { + c.Pedestal(0, 0, i).GetPedestal()[j] = (15 - i) * 500; + c.Pedestal(1, 0, i).GetPedestal()[j] = i * 1000; + } + } + c.GainCalibration(0) = gain; + c.GainCalibration(1) = gain; + + REQUIRE_NOTHROW(test.InitializeCalibration(x, c)); + REQUIRE_NOTHROW(test.StartAction(x)); + REQUIRE_NOTHROW(test.WaitForActionComplete()); + + REQUIRE_NOTHROW(test.OutputStream().read()); + REQUIRE(test.OutputStream().size() == 0); + + REQUIRE(test.GetBytesReceived() == ntrigger * nmodules * nstoragecells * 128 * JUNGFRAU_PACKET_SIZE_BYTES); + + for (int i = 0; i < ntrigger * nstoragecells; i++) { + REQUIRE(test.GetFrameBuffer(i, 0)[511 * 764] == 32 - 15 + (i % nstoragecells)); + REQUIRE(test.GetFrameBuffer(i, 1)[200 * 145] == 32 - 2 * (i % nstoragecells)); } } @@ -908,3 +1036,4 @@ TEST_CASE("HLS_C_Simulation_internal_packet_generator_storage_cell_convert_G1", REQUIRE(test.GetFrameBuffer(i,1)[200*145] == 2 * (i % 16) - 1); } } + diff --git a/tests/FPGANetworkTest.cpp b/tests/FPGANetworkTest.cpp index 8fad2465..3e494eaa 100644 --- a/tests/FPGANetworkTest.cpp +++ b/tests/FPGANetworkTest.cpp @@ -1,12 +1,11 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (2019-2023) Paul Scherrer Institute #include #include #include #include -#include "../receiver/host/HLSSimulatedDevice.h" +#include "../receiver/HLSSimulatedDevice.h" // ARP packet - from if_arp.h #pragma pack(push) @@ -205,7 +204,7 @@ TEST_CASE("HLS_Network_UDP_SLS_detector_1") { hls::stream > udp_metadata; STREAM_512 raw_out; - hls::stream > addr0; + hls::stream addr0; uint64_t packet_counter; uint64_t sls_packet_counter; @@ -239,9 +238,9 @@ TEST_CASE("HLS_Network_UDP_SLS_detector_1") { } auto addr = addr0.read(); - REQUIRE(addr_frame_number(addr) == jf_packet->jf.framenum); - REQUIRE(addr_module(addr) == 5 / 2); - REQUIRE(addr_eth_packet(addr) == (jf_packet->jf.packetnum | 64)); + REQUIRE(addr.frame_number == jf_packet->jf.framenum); + REQUIRE(addr.module == 5 / 2); + REQUIRE(addr.eth_packet == (jf_packet->jf.packetnum | 64)); } TEST_CASE("HLS_Network_UDP_SLS_detector_2") { @@ -264,7 +263,7 @@ TEST_CASE("HLS_Network_UDP_SLS_detector_2") { hls::stream > udp_metadata; STREAM_512 raw_out; - hls::stream > addr0; + hls::stream addr0; auto jf_packet_axi = (ap_uint<512> *) packet; @@ -298,9 +297,9 @@ TEST_CASE("HLS_Network_UDP_SLS_detector_2") { } auto addr = addr0.read(); - REQUIRE(addr_frame_number(addr) == jf_packet->jf.framenum); - REQUIRE(addr_module(addr) == 2); - REQUIRE(addr_eth_packet(addr) == jf_packet->jf.packetnum); + REQUIRE(addr.frame_number == jf_packet->jf.framenum); + REQUIRE(addr.module == 2); + REQUIRE(addr.eth_packet == jf_packet->jf.packetnum); } TEST_CASE("HLS_Network_UDP_SLS_detector_2_packets") { @@ -323,7 +322,7 @@ TEST_CASE("HLS_Network_UDP_SLS_detector_2_packets") { hls::stream > udp_metadata; STREAM_512 raw_out; - hls::stream > addr0; + hls::stream addr0; auto jf_packet_axi = (ap_uint<512> *) packet; @@ -368,9 +367,9 @@ TEST_CASE("HLS_Network_UDP_SLS_detector_2_packets") { } auto addr = addr0.read(); - REQUIRE(addr_frame_number(addr) == jf_packet->jf.framenum); - REQUIRE(addr_module(addr) == 1); - REQUIRE(addr_eth_packet(addr) == jf_packet->jf.packetnum); + REQUIRE(addr.frame_number == jf_packet->jf.framenum); + REQUIRE(addr.module == 1); + REQUIRE(addr.eth_packet == jf_packet->jf.packetnum); } } @@ -394,7 +393,7 @@ TEST_CASE("HLS_Network_UDP_SLS_detector_packets_err") { hls::stream > udp_metadata; STREAM_512 raw_out; - hls::stream > addr0; + hls::stream addr0; auto jf_packet_axi = (ap_uint<512> *) packet; @@ -460,9 +459,9 @@ TEST_CASE("HLS_Network_UDP_SLS_detector_packets_err") { } auto addr = addr0.read(); - REQUIRE(addr_frame_number(addr) == jf_packet->jf.framenum); - REQUIRE(addr_module(addr) == 2); - REQUIRE(addr_eth_packet(addr) == jf_packet->jf.packetnum); + REQUIRE(addr.frame_number == jf_packet->jf.framenum); + REQUIRE(addr.module == 2); + REQUIRE(addr.eth_packet == jf_packet->jf.packetnum); REQUIRE(udp_packet_counter == 4); REQUIRE(sls_packet_counter == 1); diff --git a/tests/FPGAUnitTest.h b/tests/FPGAUnitTest.h index 3e8a476b..4b2262ea 100644 --- a/tests/FPGAUnitTest.h +++ b/tests/FPGAUnitTest.h @@ -1,5 +1,4 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (2019-2023) Paul Scherrer Institute #ifndef FPGAUNITTEST_H #define FPGAUNITTEST_H @@ -66,8 +65,11 @@ template double CheckConversionWithGeomTransform(const DiffractionExpe const JFCalibration &calib, const uint16_t *raw, T *converted, size_t storage_cell = 0) { + T fill_value = INT16_MIN; + if (experiment.GetPixelDepth() == 4) + fill_value = INT32_MIN; std::vector conversion_ref(experiment.GetModulesNum() * RAW_MODULE_SIZE); - std::vector conversion_ref_transformed(experiment.GetPixelsNum()); + std::vector conversion_ref_transformed(experiment.GetPixelsNum(), fill_value); JFConversionFloatingPoint conversion; @@ -78,7 +80,6 @@ template double CheckConversionWithGeomTransform(const DiffractionExpe calib.Pedestal(m, 2, storage_cell), experiment.GetPhotonEnergy_keV()); conversion.ConvertFP(conversion_ref.data() + m * RAW_MODULE_SIZE, raw); - } RawToConvertedGeometryAdjustMultipixels(experiment, conversion_ref_transformed.data(), conversion_ref.data() ); diff --git a/tests/FrameTransformationTest.cpp b/tests/FrameTransformationTest.cpp index 5b02bc04..94c04fd4 100644 --- a/tests/FrameTransformationTest.cpp +++ b/tests/FrameTransformationTest.cpp @@ -1,5 +1,4 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (2019-2023) Paul Scherrer Institute #include #include @@ -168,6 +167,122 @@ TEST_CASE("FrameTransformation_Converted_bshuf_lz4" ,"") { REQUIRE(input_1[(511+512)*1024 + 800] == output[CONVERTED_MODULE_SIZE * (nmodules - 2) + 1030 + 800 + 6]); } + +TEST_CASE("FrameTransformation_Converted_bshuf_lz4_roi" ,"") { + const uint16_t nmodules = 4; + const uint16_t ndatastreams = 2; + DiffractionExperiment experiment(DetectorGeometry(ndatastreams * nmodules, 2)); + experiment.DataStreams(ndatastreams); + + experiment.Mode(DetectorMode::Conversion).Compression(JFJochProtoBuf::BSHUF_LZ4); + + FrameTransformation transformation(experiment); + + ROIFilter filter(experiment.GetXPixelsNum(), experiment.GetYPixelsNum(), 0); + filter.SetRectangle(100, 20, 10, 10); + + std::vector input_0(nmodules*RAW_MODULE_SIZE); + for (int i = 0; i < nmodules*RAW_MODULE_SIZE; i++) + input_0[i] = 50; + + std::vector input_1(nmodules*RAW_MODULE_SIZE); + for (int i = 0; i < nmodules*RAW_MODULE_SIZE; i++) + input_1[i] = 50; + + std::vector output_compressed(experiment.GetMaxCompressedSize()); + + for (int i = 0; i < nmodules; i++) { + REQUIRE_NOTHROW(transformation.ProcessModule(input_0.data() + i * RAW_MODULE_SIZE, i, 0)); + REQUIRE_NOTHROW(transformation.ProcessModule(input_1.data() + i * RAW_MODULE_SIZE, i, 1)); + } + + size_t compressed_size; + transformation.Pack(); + transformation.ApplyROI(filter); + REQUIRE_NOTHROW(compressed_size = transformation.SaveCompressedImage(output_compressed.data())); + output_compressed.resize(compressed_size); + + REQUIRE(bshuf_read_uint64_BE(output_compressed.data()) == experiment.GetPixelsNum() * experiment.GetPixelDepth()); + REQUIRE(bshuf_read_uint32_BE(output_compressed.data()+8) == JFJochBitShuffleCompressor::DefaultBlockSize * experiment.GetPixelDepth()); + + std::vector output; + REQUIRE_NOTHROW(JFJochDecompress(output, experiment.GetCompressionAlgorithmEnum(), output_compressed, + experiment.GetPixelsNum())); + + size_t diff = 0; + for (int y = 0; y < experiment.GetYPixelsNum(); y++) { + for (int x = 0; x < experiment.GetXPixelsNum(); x++) { + if ((y >= 20 ) && (y < 30) && (x >= 100) && (x < 110)) { + if (output[y * experiment.GetXPixelsNum() + x] != 50) + diff++; + } else { + if (output[y * experiment.GetXPixelsNum() + x] != INT16_MIN) + diff++; + } + } + } + REQUIRE(diff == 0); +} + +TEST_CASE("FrameTransformation_Converted_bshuf_lz4_roi_summation" ,"") { + const uint16_t nmodules = 4; + const uint16_t ndatastreams = 2; + const uint16_t nframes = 4; + DiffractionExperiment experiment(DetectorGeometry(ndatastreams * nmodules, 2)); + experiment.DataStreams(ndatastreams); + + experiment.Mode(DetectorMode::Conversion).Compression(JFJochProtoBuf::BSHUF_LZ4).Summation(nframes); + + FrameTransformation transformation(experiment); + + ROIFilter filter(experiment.GetXPixelsNum(), experiment.GetYPixelsNum(), 0); + filter.SetRectangle(100, 20, 10, 10); + + std::vector input_0(nmodules*RAW_MODULE_SIZE); + for (int i = 0; i < nmodules*RAW_MODULE_SIZE; i++) + input_0[i] = 50; + + std::vector input_1(nmodules*RAW_MODULE_SIZE); + for (int i = 0; i < nmodules*RAW_MODULE_SIZE; i++) + input_1[i] = 50; + + std::vector output_compressed(experiment.GetMaxCompressedSize()); + + for (int f = 0; f < nframes; f++) { + for (int i = 0; i < nmodules; i++) { + REQUIRE_NOTHROW(transformation.ProcessModule(input_0.data() + i * RAW_MODULE_SIZE, i, 0)); + REQUIRE_NOTHROW(transformation.ProcessModule(input_1.data() + i * RAW_MODULE_SIZE, i, 1)); + } + } + + size_t compressed_size; + transformation.Pack(); + transformation.ApplyROI(filter); + REQUIRE_NOTHROW(compressed_size = transformation.SaveCompressedImage(output_compressed.data())); + output_compressed.resize(compressed_size); + + REQUIRE(bshuf_read_uint64_BE(output_compressed.data()) == experiment.GetPixelsNum() * experiment.GetPixelDepth()); + REQUIRE(bshuf_read_uint32_BE(output_compressed.data()+8) == JFJochBitShuffleCompressor::DefaultBlockSize * experiment.GetPixelDepth()); + + std::vector output; + REQUIRE_NOTHROW(JFJochDecompress(output, experiment.GetCompressionAlgorithmEnum(), output_compressed, + experiment.GetPixelsNum())); + + size_t diff = 0; + for (int y = 0; y < experiment.GetYPixelsNum(); y++) { + for (int x = 0; x < experiment.GetXPixelsNum(); x++) { + if ((y >= 20 ) && (y < 30) && (x >= 100) && (x < 110)) { + if (output[y * experiment.GetXPixelsNum() + x] != nframes * 50) + diff++; + } else { + if (output[y * experiment.GetXPixelsNum() + x] != INT32_MIN) + diff++; + } + } + } + REQUIRE(diff == 0); +} + TEST_CASE("FrameTransformation_Converted_bshuf_zstd" ,"") { const uint16_t nmodules = 4; const uint16_t ndatastreams = 2; diff --git a/tests/HDF5WritingTest.cpp b/tests/HDF5WritingTest.cpp index 04266367..7198119b 100644 --- a/tests/HDF5WritingTest.cpp +++ b/tests/HDF5WritingTest.cpp @@ -1,5 +1,4 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (2019-2023) Paul Scherrer Institute #include #include @@ -155,8 +154,8 @@ TEST_CASE("HDF5MasterFile_RadInt", "[HDF5][Full]") { start_message.rad_int_bin_to_q = mapping.GetBinToQ(); EndMessage end_message; end_message.number_of_images = x.GetImageNum(); - end_message.rad_int_result["avg1"] = profile.GetResult(false); - end_message.rad_int_result["avg2"] = profile.GetResult(false); + end_message.rad_int_result["avg1"] = profile.GetResult(); + end_message.rad_int_result["avg2"] = profile.GetResult(); REQUIRE_NOTHROW(HDF5Metadata::NXmx(start_message, end_message)); } diff --git a/tests/IndexingUnitTest.cpp b/tests/IndexingUnitTest.cpp index 01243b71..790241d1 100644 --- a/tests/IndexingUnitTest.cpp +++ b/tests/IndexingUnitTest.cpp @@ -1,5 +1,4 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (2019-2023) Paul Scherrer Institute #include #include "../writer/HDF5Objects.h" diff --git a/tests/JFCalibrationTest.cpp b/tests/JFCalibrationTest.cpp index 55b86165..2f93d9e8 100644 --- a/tests/JFCalibrationTest.cpp +++ b/tests/JFCalibrationTest.cpp @@ -1,5 +1,4 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (2019-2023) Paul Scherrer Institute #include "catch2/catch.hpp" #include diff --git a/tests/JFConversionTest.cpp b/tests/JFConversionTest.cpp index 72da2ab1..4beaf223 100644 --- a/tests/JFConversionTest.cpp +++ b/tests/JFConversionTest.cpp @@ -1,10 +1,10 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (2019-2023) Paul Scherrer Institute #include #include "../tests/FPGAUnitTest.h" #include "../jungfrau/JFConversionFloatingPoint.h" +#include "../jungfrau/JFConversionGPU.h" #include "../jungfrau/JFConversionFixedPoint.h" void SetupPedestal( JFModulePedestal &pedestal_g0, JFModulePedestal &pedestal_g1, JFModulePedestal &pedestal_g2) { @@ -41,7 +41,7 @@ TEST_CASE("JFConversionFloatingPoint_G0","[JFConversion]") { input[i] = i % 16384; for (int i = 0; i < 128; i++) - conv.Convert(output_16bit.data(), input.data()); + conv.ConvertModule(output_16bit.data(), input.data()); conv.ConvertFP(output_fp.data(), input.data()); auto err = Compare(output_16bit.data(), output_fp, RAW_MODULE_SIZE); @@ -76,7 +76,7 @@ TEST_CASE("JFConversionFixedPoint_G0","[JFConversion]") { for (int i = 0; i < RAW_MODULE_SIZE; i++) input[i] = i % 16384; - conv.Convert(output_16bit.data(), input.data()); + conv.ConvertModule(output_16bit.data(), input.data()); conv_fp.ConvertFP(output_fp.data(), input.data()); auto err = Compare(output_16bit.data(), output_fp, RAW_MODULE_SIZE); @@ -88,6 +88,42 @@ TEST_CASE("JFConversionFixedPoint_G0","[JFConversion]") { } } +TEST_CASE("JFConversionGPU_G0","[JFConversion]") { + JFConversionGPU conv; + JFConversionFloatingPoint conv_fp; + + JFModulePedestal pedestal_g0; + JFModulePedestal pedestal_g1; + JFModulePedestal pedestal_g2; + + SetupPedestal(pedestal_g0, pedestal_g1, pedestal_g2); + + JFModuleGainCalibration gain; + + std::vector energy{4.0, 6.0, 12.4, 25.0}; + for (auto &e: energy) { + conv.Setup(gain, pedestal_g0, pedestal_g1, pedestal_g2, e); + conv_fp.Setup(gain, pedestal_g0, pedestal_g1, pedestal_g2, e); + + std::vector input(RAW_MODULE_SIZE); + std::vector output_fp(RAW_MODULE_SIZE); + std::vector output_16bit(RAW_MODULE_SIZE); + + for (int i = 0; i < RAW_MODULE_SIZE; i++) + input[i] = i % 16384; + + conv.ConvertModule(output_16bit.data(), input.data()); + conv_fp.ConvertFP(output_fp.data(), input.data()); + conv.Sync(); + + auto err = Compare(output_16bit.data(), output_fp, RAW_MODULE_SIZE); + auto max_err = MaxErrorOnConversion(output_16bit.data(), output_fp, RAW_MODULE_SIZE); + std::cout << "Error on conversion " << err << " max error " << max_err << std::endl; + REQUIRE(err < 0.5); + REQUIRE(max_err <= 1.0); + } +} + TEST_CASE("JFConversionFixedPoint_G0_TestFile","[JFConversion]") { JFConversionFixedPoint conv; JFConversionFloatingPoint conv_fp; @@ -112,7 +148,7 @@ TEST_CASE("JFConversionFixedPoint_G0_TestFile","[JFConversion]") { for (int i = 0; i < RAW_MODULE_SIZE; i++) input[i] = i % 16384; - conv.Convert(output_16bit.data(), input.data()); + conv.ConvertModule(output_16bit.data(), input.data()); conv_fp.ConvertFP(output_fp.data(), input.data()); auto err = Compare(output_16bit.data(), output_fp, RAW_MODULE_SIZE); @@ -144,7 +180,7 @@ TEST_CASE("JFConversionFloatingPoint_G1","[JFConversion]") { for (int i = 0; i < RAW_MODULE_SIZE; i++) input[i] = (i % 16384) | 0x4000; - conv.Convert(output_16bit.data(), input.data()); + conv.ConvertModule(output_16bit.data(), input.data()); conv.ConvertFP(output_fp.data(), input.data()); auto err = Compare(output_16bit.data(), output_fp, RAW_MODULE_SIZE); @@ -179,7 +215,7 @@ TEST_CASE("JFConversionFixedPoint_G1","[JFConversion]") { for (int i = 0; i < RAW_MODULE_SIZE; i++) input[i] = (i % 16384) | 0x4000; - conv.Convert(output_16bit.data(), input.data()); + conv.ConvertModule(output_16bit.data(), input.data()); conv_fp.ConvertFP(output_fp.data(), input.data()); auto err = Compare(output_16bit.data(), output_fp, RAW_MODULE_SIZE); @@ -191,6 +227,43 @@ TEST_CASE("JFConversionFixedPoint_G1","[JFConversion]") { } } +TEST_CASE("JFConversionGPU_G1","[JFConversion]") { + JFConversionGPU conv; + JFConversionFloatingPoint conv_fp; + + JFModulePedestal pedestal_g0; + JFModulePedestal pedestal_g1; + JFModulePedestal pedestal_g2; + + SetupPedestal(pedestal_g0, pedestal_g1, pedestal_g2); + + JFModuleGainCalibration gain; + + std::vector energy{4.0, 6.0, 12.4, 25.0}; + for (auto &e: energy) { + conv.Setup(gain, pedestal_g0, pedestal_g1, pedestal_g2, e); + conv_fp.Setup(gain, pedestal_g0, pedestal_g1, pedestal_g2, e); + + std::vector input(RAW_MODULE_SIZE); + std::vector output_fp(RAW_MODULE_SIZE); + std::vector output_16bit(RAW_MODULE_SIZE); + + for (int i = 0; i < RAW_MODULE_SIZE; i++) + input[i] = (i % 16384) | 0x4000; + + conv.ConvertModule(output_16bit.data(), input.data()); + conv_fp.ConvertFP(output_fp.data(), input.data()); + conv.Sync(); + + auto err = Compare(output_16bit.data(), output_fp, RAW_MODULE_SIZE); + auto max_err = MaxErrorOnConversion(output_16bit.data(), output_fp, RAW_MODULE_SIZE); + + std::cout << "Error on conversion " << err << " max error " << max_err << std::endl; + REQUIRE(err < 0.5); + REQUIRE(max_err <= 1.0); + } +} + TEST_CASE("JFConversionFloatingPoint_G2","[JFConversion]") { JFConversionFloatingPoint conv; @@ -211,7 +284,7 @@ TEST_CASE("JFConversionFloatingPoint_G2","[JFConversion]") { for (int i = 0; i < RAW_MODULE_SIZE; i++) input[i] = (i % 16384) | 0xC000; - conv.Convert(output_16bit.data(), input.data()); + conv.ConvertModule(output_16bit.data(), input.data()); conv.ConvertFP(output_fp.data(), input.data()); auto err = Compare(output_16bit.data(), output_fp, RAW_MODULE_SIZE); @@ -246,7 +319,7 @@ TEST_CASE("JFConversionFixedPoint_G2","[JFConversion]") { for (int i = 0; i < RAW_MODULE_SIZE; i++) input[i] = (i % 16384) | 0xC000; - conv.Convert(output_16bit.data(), input.data()); + conv.ConvertModule(output_16bit.data(), input.data()); conv_fp.ConvertFP(output_fp.data(), input.data()); auto err = Compare(output_16bit.data(), output_fp, RAW_MODULE_SIZE); @@ -258,6 +331,43 @@ TEST_CASE("JFConversionFixedPoint_G2","[JFConversion]") { } } +TEST_CASE("JFConversionGPU_G2","[JFConversion]") { + JFConversionGPU conv; + JFConversionFloatingPoint conv_fp; + + JFModulePedestal pedestal_g0; + JFModulePedestal pedestal_g1; + JFModulePedestal pedestal_g2; + + SetupPedestal(pedestal_g0, pedestal_g1, pedestal_g2); + + JFModuleGainCalibration gain; + + std::vector energy{4.0, 6.0, 12.4, 25.0}; + for (auto &e: energy) { + conv.Setup(gain, pedestal_g0, pedestal_g1, pedestal_g2, e); + conv_fp.Setup(gain, pedestal_g0, pedestal_g1, pedestal_g2, e); + + std::vector input(RAW_MODULE_SIZE); + std::vector output_fp(RAW_MODULE_SIZE); + std::vector output_16bit(RAW_MODULE_SIZE); + + for (int i = 0; i < RAW_MODULE_SIZE; i++) + input[i] = (i % 16384) | 0xC000; + + conv.ConvertModule(output_16bit.data(), input.data()); + conv_fp.ConvertFP(output_fp.data(), input.data()); + conv.Sync(); + + auto err = Compare(output_16bit.data(), output_fp, RAW_MODULE_SIZE); + auto max_err = MaxErrorOnConversion(output_16bit.data(), output_fp, RAW_MODULE_SIZE); + + std::cout << "Error on conversion " << err << " max error " << max_err << std::endl; + REQUIRE(err < 0.5); + REQUIRE(max_err <= 1.0); + } +} + TEST_CASE("JFConversionFixedPoint_G1_TestFile","[JFConversion]") { JFConversionFixedPoint conv; JFConversionFloatingPoint conv_fp; @@ -282,7 +392,7 @@ TEST_CASE("JFConversionFixedPoint_G1_TestFile","[JFConversion]") { for (int i = 0; i < RAW_MODULE_SIZE; i++) input[i] = (i % 16384) | 0x4000; - conv.Convert(output_16bit.data(), input.data()); + conv.ConvertModule(output_16bit.data(), input.data()); conv_fp.ConvertFP(output_fp.data(), input.data()); auto err = Compare(output_16bit.data(), output_fp, RAW_MODULE_SIZE); @@ -318,7 +428,7 @@ TEST_CASE("JFConversionFixedPoint_G2_TestFile","[JFConversion]") { for (int i = 0; i < RAW_MODULE_SIZE; i++) input[i] = (i % 16384) | 0xC000; - conv.Convert(output_16bit.data(), input.data()); + conv.ConvertModule(output_16bit.data(), input.data()); conv_fp.ConvertFP(output_fp.data(), input.data()); auto err = Compare(output_16bit.data(), output_fp, RAW_MODULE_SIZE); diff --git a/tests/JFJochBrokerParserTest.cpp b/tests/JFJochBrokerParserTest.cpp index 5b1d90b0..765543e6 100644 --- a/tests/JFJochBrokerParserTest.cpp +++ b/tests/JFJochBrokerParserTest.cpp @@ -1,5 +1,4 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (2019-2023) Paul Scherrer Institute #include #include "../broker/JFJochBrokerParser.h" diff --git a/tests/JFJochBrokerTest.cpp b/tests/JFJochBrokerTest.cpp index 27ac5fc1..d37864bb 100644 --- a/tests/JFJochBrokerTest.cpp +++ b/tests/JFJochBrokerTest.cpp @@ -1,5 +1,4 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (2019-2023) Paul Scherrer Institute #include #include "../broker/JFJochStateMachine.h" diff --git a/tests/JFJochFullIntegrationTest.cpp b/tests/JFJochFullIntegrationTest.cpp index 1bdf5037..676b2265 100644 --- a/tests/JFJochFullIntegrationTest.cpp +++ b/tests/JFJochFullIntegrationTest.cpp @@ -1,5 +1,4 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (2019-2023) Paul Scherrer Institute #include @@ -9,7 +8,7 @@ #include "../writer/HDF5Objects.h" #include "../receiver/JFJochReceiverService.h" #include "FPGAUnitTest.h" -#include "../receiver/host/MockAcquisitionDevice.h" +#include "../receiver/MockAcquisitionDevice.h" #include "../common/ZMQImagePusher.h" #include "../common/jsonToGrpc.h" @@ -110,6 +109,103 @@ TEST_CASE("JFJochIntegrationTest_ZMQ", "[JFJochReceiver]") { writer_server->Shutdown(); } + +TEST_CASE("JFJochIntegrationTest_ZMQ_save_calibration", "[JFJochReceiver]") { + Logger logger("JFJochIntegrationTest_ZMQ_save_calibration"); + ZMQContext zmq_context; + + RegisterHDF5Filter(); + + int64_t nimages = 5; + int64_t ndatastream = 2; + int64_t nmodules = 4; + + JFJochServices services(logger); + JFJochStateMachine state_machine(services, logger); + + REQUIRE(!state_machine.GetMeasurementStatistics().has_value()); + state_machine.AddDetectorSetup(DetectorGeometry(ndatastream * nmodules, 2, 8, 36)); + + state_machine.NotThreadSafe_Experiment().DataStreams(ndatastream); + state_machine.NotThreadSafe_Experiment().PedestalG0Frames(0).PedestalG1Frames(0).PedestalG2Frames(0); + services.Writer("unix:writer_test", "inproc://#1").Receiver("unix:fpga_receiver_test"); + + logger.Verbose(true); + + std::vector image(RAW_MODULE_SIZE); + + std::vector> aq_devices; + + for (int i = 0; i < ndatastream; i++) { + auto *test = new MockAcquisitionDevice(i, 256); + aq_devices.emplace_back(test); + } + + std::vector tmp_devices; + for (const auto &i: aq_devices) + tmp_devices.emplace_back(i.get()); + + ZMQImagePusher pusher(zmq_context, {"inproc://#1"}); + JFJochReceiverService fpga_receiver(tmp_devices, logger, pusher); + + JFJochWriterService writer(zmq_context, logger); + + auto fpga_receiver_server = gRPCServer("unix:fpga_receiver_test", fpga_receiver); + auto writer_server = gRPCServer("unix:writer_test", writer); + + REQUIRE_NOTHROW(state_machine.Initialize()); + logger.Info("Initialized"); + + JFJochProtoBuf::DatasetSettings setup; + setup.set_ntrigger(1); + setup.set_images_per_trigger(5); + setup.set_detector_distance_mm(100); + setup.set_file_prefix("integration_test_with_calibration"); + setup.set_photon_energy_kev(12.4); + setup.set_data_file_count(2); + setup.set_summation(1); + setup.set_save_calibration(true); + + REQUIRE_NOTHROW(state_machine.Start(setup)); + logger.Info("Started measurement"); + + JFJochProtoBuf::BrokerStatus status; + status = state_machine.GetStatus(); + REQUIRE(status.progress() == Approx(0.0)); + REQUIRE(status.broker_state() == JFJochProtoBuf::DATA_COLLECTION); + + for (int i = 0; i < ndatastream; i++) { + for (int m = 0; m < state_machine.NotThreadSafe_Experiment().GetModulesNum(i); m++) { + for (int image_num = 1; image_num <= nimages; image_num++) + aq_devices[i]->AddModule(image_num, m, image.data()); + } + aq_devices[i]->Terminate(); + } + + REQUIRE_NOTHROW(state_machine.Stop()); + logger.Info("Stopped measurement"); + + status = state_machine.GetStatus(); + REQUIRE(status.broker_state() == JFJochProtoBuf::IDLE); + + auto tmp = state_machine.GetMeasurementStatistics(); + REQUIRE(tmp.has_value()); + auto statistics = tmp.value(); + + REQUIRE(statistics.collection_efficiency() == 1.0); + REQUIRE(statistics.images_collected() == 5); + REQUIRE(statistics.images_written() == 5); + REQUIRE(statistics.max_image_number_sent() == 4); + REQUIRE(!statistics.cancelled()); + REQUIRE(statistics.file_prefix() == "integration_test_with_calibration"); + REQUIRE(statistics.detector_width() == 2068); + REQUIRE(statistics.detector_height() == 2164); + REQUIRE(statistics.detector_pixel_depth() == 2); + REQUIRE(statistics.file_statistics_size() == 2); + fpga_receiver_server->Shutdown(); + writer_server->Shutdown(); +} + TEST_CASE("JFJochIntegrationTest_ZMQ_2DataStreams_4Devices", "[JFJochReceiver]") { Logger logger("JFJochIntegrationTest_ZMQ_2DataStreams_4Devices"); ZMQContext zmq_context; @@ -1493,14 +1589,20 @@ TEST_CASE("JFJochIntegrationTest_ZMQ_lysozyme_rad_int", "[JFJochReceiver]") { logger.Info("Stopped measurement"); auto rad_int = state_machine.GetRadialIntegrationProfiles(); - REQUIRE(rad_int.plots_size() == 4+1); - auto &plot_map = rad_int.plots(); - REQUIRE(plot_map.at("file0").x_size() == 3); - REQUIRE(plot_map.at("file0").y_size() == 3); - REQUIRE(plot_map.at("file3").x_size() == 3); - REQUIRE(plot_map.at("file3").y_size() == 3); - REQUIRE(plot_map.at("file3").x(0) == Approx(1.0)); - REQUIRE(plot_map.at("dataset").x_size() == 3); + REQUIRE(rad_int.profiles_size() == 4+1); + auto &plot_map = rad_int.profiles(); + + CHECK(plot_map[1].title() == "file0"); + CHECK(plot_map[1].plot().x_size() == 3); + CHECK(plot_map[1].plot().y_size() == 3); + + CHECK(plot_map[4].title() == "file3"); + REQUIRE(plot_map[4].plot().x_size() == 3); + CHECK(plot_map[4].plot().x(0) == Approx(1.0)); + CHECK(plot_map[4].plot().y_size() == 3); + + CHECK(plot_map[0].title() == "dataset"); + CHECK(plot_map[0].plot().x_size() == 3); fpga_receiver_server->Shutdown(); writer_server->Shutdown(); diff --git a/tests/JFJochReceiverIntegrationTest.cpp b/tests/JFJochReceiverIntegrationTest.cpp index d5821afd..6a5925a2 100644 --- a/tests/JFJochReceiverIntegrationTest.cpp +++ b/tests/JFJochReceiverIntegrationTest.cpp @@ -1,10 +1,9 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (2019-2023) Paul Scherrer Institute #include #include "../receiver/JFJochReceiverTest.h" -#include "../receiver/host/HLSSimulatedDevice.h" +#include "../receiver/HLSSimulatedDevice.h" #include "../jungfrau/JFPedestalCalc.h" #include "../common/TestImagePusher.h" @@ -20,8 +19,9 @@ TEST_CASE("JFJochReceiverTest_Raw", "[JFJochReceiver]") { std::vector> aq_devices; for (int i = 0; i < x.GetDataStreamsNum(); i++) { - AcquisitionDevice *test; + HLSSimulatedDevice *test; test = new HLSSimulatedDevice(i, 64); + test->SetFPGANonBlockingMode(false); aq_devices.emplace_back(test); } @@ -51,9 +51,10 @@ TEST_CASE("JFJochReceiverTest_Conversion", "[JFJochReceiver]") { std::vector> aq_devices; for (int i = 0; i < x.GetDataStreamsNum(); i++) { - AcquisitionDevice *test; + HLSSimulatedDevice *test; test = new HLSSimulatedDevice(i, 64); test->EnableLogging(&logger); + test->SetFPGANonBlockingMode(false); aq_devices.emplace_back(test); } @@ -79,8 +80,9 @@ TEST_CASE("JFJochReceiverTest_Conversion_Bin2x2", "[JFJochReceiver]") { std::vector> aq_devices; for (int i = 0; i < x.GetDataStreamsNum(); i++) { - AcquisitionDevice *test; + HLSSimulatedDevice *test; test = new HLSSimulatedDevice(i, 64); + test->SetFPGANonBlockingMode(false); test->EnableLogging(&logger); aq_devices.emplace_back(test); } @@ -107,9 +109,10 @@ TEST_CASE("JFJochReceiverTest_ConversionOnCPU", "[JFJochReceiver]") { std::vector> aq_devices; for (int i = 0; i < x.GetDataStreamsNum(); i++) { - AcquisitionDevice *test; + HLSSimulatedDevice *test; test = new HLSSimulatedDevice(i, 64); test->EnableLogging(&logger); + test->SetFPGANonBlockingMode(false); aq_devices.emplace_back(test); } @@ -136,9 +139,10 @@ TEST_CASE("JFJochReceiverTest_ConversionOnCPU_Bin2x2", "[JFJochReceiver]") { std::vector> aq_devices; for (int i = 0; i < x.GetDataStreamsNum(); i++) { - AcquisitionDevice *test; + HLSSimulatedDevice *test; test = new HLSSimulatedDevice(i, 64); test->EnableLogging(&logger); + test->SetFPGANonBlockingMode(false); aq_devices.emplace_back(test); } @@ -167,9 +171,10 @@ TEST_CASE("JFJochReceiverTest_Conversion_StorageCell", "[JFJochReceiver]") { std::vector> aq_devices; for (int i = 0; i < x.GetDataStreamsNum(); i++) { - AcquisitionDevice *test; + HLSSimulatedDevice *test; test = new HLSSimulatedDevice(i, 64); test->EnableLogging(&logger); + test->SetFPGANonBlockingMode(false); aq_devices.emplace_back(test); } @@ -214,6 +219,7 @@ TEST_CASE("JFJochReceiverTest_PedestalG1", "[JFJochReceiver]") { test = new HLSSimulatedDevice(i, 64); test->CreatePackets(x, 1, nframes, 0, pedestal_in.data(), false); test->CreateFinalPacket(x); + test->SetFPGANonBlockingMode(false); aq_devices.emplace_back(test); } @@ -274,7 +280,7 @@ TEST_CASE("JFJochReceiverTest_PedestalG2_storage_cell", "[JFJochReceiver]") { std::vector> aq_devices; for (int i = 0; i < x.GetDataStreamsNum(); i++) { HLSSimulatedDevice *test; - test = new HLSSimulatedDevice(i, 64); + test = new HLSSimulatedDevice(i, nframes * 2); for (int j = 0; j < nframes; j++) { test->CreatePackets(x, 2 * j + 1, 1, 0, pedestal_in2.data() + j * RAW_MODULE_SIZE, false); @@ -282,6 +288,7 @@ TEST_CASE("JFJochReceiverTest_PedestalG2_storage_cell", "[JFJochReceiver]") { pedestal_in.data() + j * RAW_MODULE_SIZE, false); } test->CreateFinalPacket(x); + test->SetFPGANonBlockingMode(false); aq_devices.emplace_back(test); } @@ -336,6 +343,7 @@ TEST_CASE("JFJochReceiverTest_PedestalG0", "[JFJochReceiver]") { test = new HLSSimulatedDevice(i, 64); test->CreatePackets(x, 1, nframes, 0, pedestal_in.data(), false); test->CreateFinalPacket(x); + test->SetFPGANonBlockingMode(false); aq_devices.emplace_back(test); } @@ -388,6 +396,7 @@ TEST_CASE("JFJochReceiverTest_PedestalG0_StorageCell", "[JFJochReceiver]") { test->CreatePackets(x, i*4+4, 1, 0, pedestal_in_3.data(), false); } test->CreateFinalPacket(x); + test->SetFPGANonBlockingMode(false); aq_devices.emplace_back(test); Logger logger("JFJochReceiverTest_PedestalG0_StorageCell"); @@ -469,6 +478,7 @@ TEST_CASE("JFJochReceiverTest_PacketLost_Raw", "[JFJochReceiver]") { test->CreatePackets(x, 4, 1, 1, frame_in.data(), false); test->CreateFinalPacket(x); + test->SetFPGANonBlockingMode(false); aq_devices.emplace_back(test); } Logger logger("JFJochReceiverTest_PacketLost_Raw"); diff --git a/tests/JFPedestalTest.cpp b/tests/JFPedestalTest.cpp index 4e638610..0c5a36e3 100644 --- a/tests/JFPedestalTest.cpp +++ b/tests/JFPedestalTest.cpp @@ -1,5 +1,4 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (2019-2023) Paul Scherrer Institute #include #include diff --git a/tests/MockAcquisitionDeviceTest.cpp b/tests/MockAcquisitionDeviceTest.cpp index e54b8cfe..bfaa210f 100644 --- a/tests/MockAcquisitionDeviceTest.cpp +++ b/tests/MockAcquisitionDeviceTest.cpp @@ -1,8 +1,8 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (2019-2023) Paul Scherrer Institute #include -#include "../receiver/host/MockAcquisitionDevice.h" +#include "../receiver/MockAcquisitionDevice.h" +#include "../receiver/JFJochReceiverTest.h" TEST_CASE("MockAcquisitionDevice") { std::vector module_data(RAW_MODULE_SIZE, 765); @@ -37,3 +37,70 @@ TEST_CASE("MockAcquisitionDevice") { RAW_MODULE_SIZE * sizeof(uint16_t)) == 0); } +TEST_CASE("JFJochReceiverTest_Raw_MockAcquisitionDevice", "[JFJochReceiver]") { + Logger logger("JFJochReceiverTest_Raw_MockAcquisitionDevice"); + logger.Verbose(true); + + std::mt19937 g1(1387); + std::uniform_int_distribution dist(0, 65535); + + DiffractionExperiment x(DetectorGeometry(4)); + const uint16_t nthreads = 4; + + std::vector test_frame(RAW_MODULE_SIZE); + + x.Mode(DetectorMode::Raw); + x.PedestalG0Frames(0).NumTriggers(1).UseInternalPacketGenerator(true) + .ImagesPerTrigger(100).DataFileCount(16).PhotonEnergy_keV(12.4).Compression(JFJochProtoBuf::NO_COMPRESSION); + + std::vector> aq_devices; + for (int i = 0; i < x.GetDataStreamsNum(); i++) { + for (auto &j: test_frame) + j = dist(g1); + + auto *test = new MockAcquisitionDevice(i, 64); + test->EnableLogging(&logger); + test->SetCustomInternalGeneratorFrame(test_frame); + aq_devices.emplace_back(test); + } + + JFJochProtoBuf::ReceiverOutput output; + bool ret; + REQUIRE_NOTHROW(ret = JFJochReceiverTest(output, logger, aq_devices, x, nthreads, false)); + REQUIRE(ret); + REQUIRE(output.efficiency() == 1.0); + REQUIRE(output.images_sent() == x.GetImageNum()); + REQUIRE(output.compressed_ratio() == 1.0); + REQUIRE(output.compressed_size() == x.GetImageNum() * x.GetPixelDepth() * x.GetPixelsNum()); + REQUIRE(output.max_image_number_sent() == x.GetImageNum() - 1); + REQUIRE(!output.cancelled()); +} + + +TEST_CASE("JFJochReceiverTest_Conversion_MockAcquisitionDevice", "[JFJochReceiver]") { + Logger logger("JFJochReceiverTest_Conversion"); + + DiffractionExperiment x(DetectorGeometry(8)); + const uint16_t nthreads = 4; + + x.Mode(DetectorMode::Conversion); + x.PedestalG0Frames(0).NumTriggers(1).UseInternalPacketGenerator(true).DataStreams(x.GetModulesNum()) + .ImagesPerTrigger(32).DataFileCount(16).PhotonEnergy_keV(12.4).Compression(JFJochProtoBuf::BSHUF_ZSTD); + + std::vector> aq_devices; + for (int i = 0; i < x.GetDataStreamsNum(); i++) { + AcquisitionDevice *test; + test = new MockAcquisitionDevice(i, 64); + test->EnableLogging(&logger); + aq_devices.emplace_back(test); + } + + JFJochProtoBuf::ReceiverOutput output; + bool ret; + REQUIRE_NOTHROW(ret = JFJochReceiverTest(output, logger, aq_devices, x, nthreads, false)); + REQUIRE(ret); + REQUIRE(output.efficiency() == 1.0); + REQUIRE(output.images_sent() == x.GetImageNum()); + + REQUIRE(!output.cancelled()); +} diff --git a/tests/PedestalCalcTest.cpp b/tests/PedestalCalcTest.cpp index 3c7a23dd..9d9846ea 100644 --- a/tests/PedestalCalcTest.cpp +++ b/tests/PedestalCalcTest.cpp @@ -1,5 +1,4 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (2019-2023) Paul Scherrer Institute #include #include "../jungfrau/JFPedestalCalc.h" diff --git a/tests/ProcessRawPacketTest.cpp b/tests/ProcessRawPacketTest.cpp index 935a0ce5..9e47a5c8 100644 --- a/tests/ProcessRawPacketTest.cpp +++ b/tests/ProcessRawPacketTest.cpp @@ -1,5 +1,4 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (2019-2023) Paul Scherrer Institute #include @@ -64,7 +63,7 @@ TEST_CASE("ProcessRawPacketTest") { Completion c; REQUIRE(c_fifo.Get(c)); - CHECK(c.module == 2); + CHECK(c.module_number == 2); CHECK(c.bunchid == 84); CHECK(c.frame_number == 0); CHECK(c.packet_count == 1); @@ -72,7 +71,7 @@ TEST_CASE("ProcessRawPacketTest") { CHECK(c.packet_mask[1] == 0); REQUIRE(c_fifo.Get(c)); - CHECK(c.module == 2); + CHECK(c.module_number == 2); CHECK(c.bunchid == 84); CHECK(c.frame_number == 1); CHECK(c.packet_count == 1); @@ -81,7 +80,7 @@ TEST_CASE("ProcessRawPacketTest") { REQUIRE(c_fifo.Get(c)); - CHECK(c.module == 3); + CHECK(c.module_number == 3); CHECK(c.bunchid == 84); CHECK(c.frame_number == 2); CHECK(c.packet_count == 1); @@ -91,4 +90,4 @@ TEST_CASE("ProcessRawPacketTest") { CHECK(array_0[4096*36] == 6789); CHECK(array_1[4096*(36+64)] == 6345); CHECK(array_2[4096*(16+64)] == 6346); -} \ No newline at end of file +} diff --git a/tests/ROIFilterTest.cpp b/tests/ROIFilterTest.cpp new file mode 100644 index 00000000..3ad620b9 --- /dev/null +++ b/tests/ROIFilterTest.cpp @@ -0,0 +1,175 @@ +// Copyright (2019-2023) Paul Scherrer Institute + +#include + +#include "../common/ROIFilter.h" +#include "../common/DiffractionExperiment.h" + +TEST_CASE("ROIFilter") { + int32_t width = 4; + int32_t height = 5; + std::vector v(width * height, 1); + + ROIFilter filter(width, height); + + filter.SetRectangle(1, 1, 2, 3); + + filter.Apply(v, (uint32_t) 55); + + REQUIRE(v[0] == 55); + REQUIRE(v[2] == 55); + + REQUIRE(v[width * 1 + 0] == 55); + REQUIRE(v[width * 1 + 1] == 1); + REQUIRE(v[width * 1 + 2] == 1); + REQUIRE(v[width * 1 + 3] == 55); + + REQUIRE(v[width * 3 + 2] == 1); + REQUIRE(v[width * 4 + 2] == 55); +} + +TEST_CASE("ROIFilter_out_of_bounds") { + int32_t width = 4; + int32_t height = 5; + std::vector v(width * height, 1); + + ROIFilter filter(width, height); + + filter.SetRectangle(1, 5, 2, 3); + + filter.SetRectangle(4, 1, 2, 3); + + filter.Apply(v, (uint32_t) 55); + size_t diff = 0; + for (auto &i: v) { + if (i != 55) + diff++; + } + REQUIRE(diff == 0); +} + +TEST_CASE("ROIFilter_negative_out_of_bounds") { + int32_t width = 4; + int32_t height = 5; + std::vector v(width * height, 1); + + ROIFilter filter(width, height); + + filter.SetRectangle(1, -9, 2, 3); + + filter.SetRectangle(-3, 1, 2, 3); + + filter.Apply(v, (uint32_t) 55); + size_t diff = 0; + for (auto &i: v) { + if (i != 55) + diff++; + } + REQUIRE(diff == 0); +} + +TEST_CASE("ROIFilter_on_bounds") { + int32_t width = 4; + int32_t height = 5; + std::vector v(width * height, 1); + + ROIFilter filter(width, height); + + filter.SetRectangle(2, 3, 10, 10); + + filter.Apply(v, (uint32_t) 55); + + REQUIRE(v[1 * width + 0] == 55); + REQUIRE(v[1 * width + 1] == 55); + REQUIRE(v[1 * width + 2] == 55); + REQUIRE(v[1 * width + 3] == 55); + + REQUIRE(v[2 * width + 0] == 55); + REQUIRE(v[2 * width + 1] == 55); + REQUIRE(v[2 * width + 2] == 55); + REQUIRE(v[2 * width + 3] == 55); + + REQUIRE(v[3 * width + 0] == 55); + REQUIRE(v[3 * width + 1] == 55); + REQUIRE(v[3 * width + 2] == 1); + REQUIRE(v[3 * width + 3] == 1); + + REQUIRE(v[4 * width + 0] == 55); + REQUIRE(v[4 * width + 1] == 55); + REQUIRE(v[4 * width + 2] == 1); + REQUIRE(v[4 * width + 3] == 1); +} + +TEST_CASE("ROIFilter_negative_start") { + int32_t width = 4; + int32_t height = 5; + std::vector v(width * height, 1); + + ROIFilter filter(width, height); + + filter.SetRectangle(-1, -1, 3, 4); + + filter.Apply(v, (uint32_t) 55); + + CHECK(v[0 * width + 0] == 1); + CHECK(v[0 * width + 1] == 1); + CHECK(v[0 * width + 2] == 55); + CHECK(v[0 * width + 3] == 55); + + CHECK(v[1 * width + 0] == 1); + CHECK(v[1 * width + 1] == 1); + CHECK(v[1 * width + 2] == 55); + CHECK(v[1 * width + 3] == 55); + + CHECK(v[2 * width + 0] == 1); + CHECK(v[2 * width + 1] == 1); + CHECK(v[2 * width + 2] == 55); + CHECK(v[2 * width + 3] == 55); + + CHECK(v[3 * width + 0] == 55); + CHECK(v[3 * width + 1] == 55); + CHECK(v[3 * width + 2] == 55); + CHECK(v[3 * width + 3] == 55); + + CHECK(v[4 * width + 0] == 55); + CHECK(v[4 * width + 1] == 55); + CHECK(v[4 * width + 2] == 55); + CHECK(v[4 * width + 3] == 55); +} + +TEST_CASE("ROIFilter_DiffractionExperiment_ApplyROI") { + DiffractionExperiment x(DetectorGeometry(1)); + + REQUIRE(!x.GetApplyROI()); + x.ApplyROI(true); + REQUIRE(x.GetApplyROI()); + +} + +TEST_CASE("ROIFilter_DiffractionExperiment") { + DiffractionExperiment x(DetectorGeometry(1)); + x.Mode(DetectorMode::Raw); + + x.AddROIRectangle(0, 0, 1024, 1024); + x.ClearROI(); + x.AddROIRectangle(0, 0, 256, 256); + x.AddROIRectangle(768, 0, 256, 256); + + std::vector v(x.GetPixelsNum(), 1); + + ROIFilter filter(x.GetXPixelsNum(), x.GetYPixelsNum()); + x.SetupROIFilter(filter); + filter.Apply(v, (uint32_t) 55); + + CHECK(v[ 0*1024 + 0] == 1); + CHECK(v[ 0*1024 + 255] == 1); + CHECK(v[ 0*1024 + 256] == 55); + CHECK(v[ 0*1024 + 767] == 55); + CHECK(v[ 0*1024 + 768] == 1); + CHECK(v[128*1024 + 255] == 1); + CHECK(v[128*1024 + 256] == 55); + CHECK(v[255*1024 + 255] == 1); + CHECK(v[256*1024 + 255] == 55); + CHECK(v[255*1024 + 767] == 55); + CHECK(v[255*1024 + 768] == 1); +} \ No newline at end of file diff --git a/tests/RadialIntegrationTest.cpp b/tests/RadialIntegrationTest.cpp index 4f83a1a1..963ab7fa 100644 --- a/tests/RadialIntegrationTest.cpp +++ b/tests/RadialIntegrationTest.cpp @@ -1,5 +1,4 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (2019-2023) Paul Scherrer Institute #include @@ -87,8 +86,8 @@ TEST_CASE("RadialIntegrationProfile","[RadialIntegration]") { RadialIntegrationProfile profile(mapping, x); - std::vector sum(mapping.GetBinNumber()); - std::vector count(mapping.GetBinNumber()); + std::vector sum(mapping.GetBinNumber()); + std::vector count(mapping.GetBinNumber()); for (int i = 0; i < mapping.GetBinNumber(); i++) { sum[i] = i * i * 4; @@ -96,11 +95,11 @@ TEST_CASE("RadialIntegrationProfile","[RadialIntegration]") { } REQUIRE_NOTHROW(profile.Add(sum, count)); - std::vector sum_wr(mapping.GetBinNumber() - 1); + std::vector sum_wr(mapping.GetBinNumber() - 1); REQUIRE_THROWS(profile.Add(sum_wr, count)); JFJochProtoBuf::Plot plot; - profile.GetPlot(plot, false); + profile.GetPlot(plot); REQUIRE(plot.x_size() == mapping.GetBinNumber()); REQUIRE(plot.y_size() == mapping.GetBinNumber()); @@ -133,6 +132,34 @@ TEST_CASE("RadialIntegration_Process","[RadialIntegration]") { REQUIRE(radial.GetSum()[1] == 6+2); } +TEST_CASE("RadialIntegration_Process_PxlSplit4","[RadialIntegration]") { + std::vector pixel_to_bin = {0, 1, 2, 3, 2, 2, 1, 4, 0, 0, 0, 0, 5, 5, 5, 5}; + std::vector test_image = {5, 7, INT16_MIN, 123}; + std::vector result; + + RadialIntegration radial(pixel_to_bin, 5, 4); + radial.ProcessOneImage(test_image.data(), 4); + + REQUIRE(radial.GetCount().size() == 5); + REQUIRE(radial.GetSum().size() == 5); + + float count = 0; + for (const auto &i: radial.GetCount()) + count += i; + REQUIRE(count == Approx(2.0f)); + + REQUIRE(radial.GetCount()[0] == Approx(0.25f)); + REQUIRE(radial.GetCount()[1] == Approx(0.5f)); + REQUIRE(radial.GetCount()[2] == Approx(0.75f)); + REQUIRE(radial.GetCount()[3] == Approx(0.25f)); + REQUIRE(radial.GetCount()[4] == Approx(0.25f)); + + REQUIRE(radial.GetSum()[0] == Approx(5 * 0.25f)); + REQUIRE(radial.GetSum()[1] == Approx(5 * 0.25f + 7 * 0.25f)); + REQUIRE(radial.GetSum()[2] == Approx(5 * 0.25f + 7 * 0.5f)); + REQUIRE(radial.GetSum()[4] == Approx(7 * 0.25f)); +} + TEST_CASE("RadialIntegration_GetResult","[RadialIntegration]") { std::vector pixel_to_bin = {0,1,2,4,3,1,2,3}; std::vector test_image = {7,6,5,4,3,2,1,0}; @@ -190,6 +217,30 @@ TEST_CASE("RadialIntegrationGPU_Process","[RadialIntegration]") { REQUIRE(image_analysis.GetRadialIntegrationSum()[1] == 6+2); } +TEST_CASE("RadialIntegrationGPU_Process_Corr","[RadialIntegration]") { + std::vector pixel_to_bin = {0,1,2,4,3,1,2,3}; + std::vector test_image = {7,6,5,4,3,2,1,0}; + std::vector one_byte_mask = {1,1,1,1,1,1,1,1}; + + std::vector corr = {0.5f, 0.3f, 0.5f, 0.2f, 0.8f, 0.9f, 1.0f, 0.5f}; + GPUImageAnalysis image_analysis(8, 1, one_byte_mask, pixel_to_bin, 4); + image_analysis.SetInputBuffer(test_image.data()); + image_analysis.LoadRadialIntegrationCorr(corr); + image_analysis.LoadDataToGPU(); + image_analysis.RunRadialIntegration(); + + REQUIRE(image_analysis.GetRadialIntegrationCount().size() == 4); + REQUIRE(image_analysis.GetRadialIntegrationSum().size() == 4); + + REQUIRE(image_analysis.GetRadialIntegrationCount()[0] == 1); + REQUIRE(image_analysis.GetRadialIntegrationCount()[1] == 2); + + REQUIRE(image_analysis.GetRadialIntegrationSum()[0] == Approx(7 * 0.5f)); + REQUIRE(image_analysis.GetRadialIntegrationSum()[1] == Approx(6*0.3f + 2*0.9f)); + REQUIRE(image_analysis.GetRadialIntegrationSum()[2] == Approx(5*0.5f + 1*1.0f)); + REQUIRE(image_analysis.GetRadialIntegrationSum()[3] == Approx(3*0.8f)); +} + TEST_CASE("RadialIntegrationGPU_Process_Mask","[RadialIntegration]") { std::vector pixel_to_bin = {0,1,2,4,3,1,2,3}; std::vector test_image = {7,6,5,4,3,2,1,0}; diff --git a/tests/RawToConvertedGeometryTest.cpp b/tests/RawToConvertedGeometryTest.cpp index 46ccd27f..cebec8c2 100644 --- a/tests/RawToConvertedGeometryTest.cpp +++ b/tests/RawToConvertedGeometryTest.cpp @@ -1,5 +1,4 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (2019-2023) Paul Scherrer Institute #include diff --git a/tests/SpotAnalyzeUnitTest.cpp b/tests/SpotAnalyzeUnitTest.cpp index 694948e3..cea1ac58 100644 --- a/tests/SpotAnalyzeUnitTest.cpp +++ b/tests/SpotAnalyzeUnitTest.cpp @@ -1,5 +1,4 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (2019-2023) Paul Scherrer Institute #include #include "../image_analysis/StrongPixelSet.h" diff --git a/tests/SpotFinderIntegration.cpp b/tests/SpotFinderIntegration.cpp index 3dd32629..354dfe73 100644 --- a/tests/SpotFinderIntegration.cpp +++ b/tests/SpotFinderIntegration.cpp @@ -1,5 +1,4 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (2019-2023) Paul Scherrer Institute #include diff --git a/tests/StatusVectorTest.cpp b/tests/StatusVectorTest.cpp index 05afa186..efb6f949 100644 --- a/tests/StatusVectorTest.cpp +++ b/tests/StatusVectorTest.cpp @@ -1,5 +1,4 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (2019-2023) Paul Scherrer Institute #include #include "../common/StatusVector.h" diff --git a/tests/StreamWriterTest.cpp b/tests/StreamWriterTest.cpp index 492e7a3e..91722497 100644 --- a/tests/StreamWriterTest.cpp +++ b/tests/StreamWriterTest.cpp @@ -1,5 +1,4 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (2019-2023) Paul Scherrer Institute #include #include @@ -9,7 +8,7 @@ #include "../writer/HDF5Objects.h" #include "../common/ZMQImagePusher.h" #include "../receiver/JFJochReceiverService.h" -#include "../receiver/host/HLSSimulatedDevice.h" +#include "../receiver/HLSSimulatedDevice.h" TEST_CASE("StreamWriterTest_ZMQ","[JFJochWriter]") { RegisterHDF5Filter(); @@ -32,6 +31,7 @@ TEST_CASE("StreamWriterTest_ZMQ","[JFJochWriter]") { std::vector> aq_devices; for (int i = 0; i < x.GetDataStreamsNum(); i++) { auto test = new HLSSimulatedDevice(i, 64); + test->SetFPGANonBlockingMode(false); aq_devices.emplace_back(test); } @@ -99,6 +99,7 @@ TEST_CASE("JFJochWriterServiceTest_ZMQ","[JFJochWriter]") { std::vector> aq_devices; for (int i = 0; i < x.GetDataStreamsNum(); i++) { auto test = new HLSSimulatedDevice(i, 64); + test->SetFPGANonBlockingMode(false); aq_devices.emplace_back(test); } diff --git a/tests/ThreadSafeFIFOSetTest.cpp b/tests/ThreadSafeFIFOSetTest.cpp index 51dac368..7f03ec01 100644 --- a/tests/ThreadSafeFIFOSetTest.cpp +++ b/tests/ThreadSafeFIFOSetTest.cpp @@ -1,5 +1,4 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (2019-2023) Paul Scherrer Institute #include #include <../common/ThreadSafeFIFO.h> diff --git a/tests/ZMQImagePusherTest.cpp b/tests/ZMQImagePusherTest.cpp index 0a4efc90..93b46772 100644 --- a/tests/ZMQImagePusherTest.cpp +++ b/tests/ZMQImagePusherTest.cpp @@ -1,5 +1,4 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (2019-2023) Paul Scherrer Institute #include #include "../writer/ZMQImagePuller.h" diff --git a/tests/ZMQPreviewPublisherTest.cpp b/tests/ZMQPreviewPublisherTest.cpp index 1652ed05..6986a70d 100644 --- a/tests/ZMQPreviewPublisherTest.cpp +++ b/tests/ZMQPreviewPublisherTest.cpp @@ -1,5 +1,4 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (2019-2023) Paul Scherrer Institute #include #include "../common/ZMQPreviewPublisher.h" diff --git a/tests/ZSTDCompressorTest.cpp b/tests/ZSTDCompressorTest.cpp index 47215120..3fa76ae7 100644 --- a/tests/ZSTDCompressorTest.cpp +++ b/tests/ZSTDCompressorTest.cpp @@ -1,5 +1,4 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (2019-2023) Paul Scherrer Institute #include #include diff --git a/tests/gRPCServerTest.cpp b/tests/gRPCServerTest.cpp index 0c0b3b05..6b22038b 100644 --- a/tests/gRPCServerTest.cpp +++ b/tests/gRPCServerTest.cpp @@ -1,5 +1,4 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (2019-2023) Paul Scherrer Institute #include @@ -8,7 +7,7 @@ #include "../common/Logger.h" #include "../receiver/JFJochReceiverService.h" #include "../grpc/JFJochReceiverClient.h" -#include "../receiver/host/HLSSimulatedDevice.h" +#include "../receiver/HLSSimulatedDevice.h" #include #include "../../common/ZMQImagePusher.h" diff --git a/tests/stream2.c b/tests/stream2.c index 7940c19e..a16e16b2 100644 --- a/tests/stream2.c +++ b/tests/stream2.c @@ -1,5 +1,4 @@ // Copyright (2019-2023) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later // DECTRIS proprietary license diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt index f57b58b6..6c3ad3c0 100644 --- a/tools/CMakeLists.txt +++ b/tools/CMakeLists.txt @@ -13,6 +13,9 @@ target_link_libraries(HDF5DatasetWriteTest JFJochWriter CommonFunctions) ADD_EXECUTABLE(DataAnalysisPerfTest DataAnalysisPerfTest.cpp) TARGET_LINK_LIBRARIES(DataAnalysisPerfTest ImageAnalysis JFJochWriter CommonFunctions) +ADD_EXECUTABLE(RadialIntegrationCPUTest RadialIntegrationCPUTest.cpp) +TARGET_LINK_LIBRARIES(RadialIntegrationCPUTest ImageAnalysis JFJochWriter CommonFunctions) + ADD_EXECUTABLE(PreviewTest PreviewTest.cpp) TARGET_LINK_LIBRARIES(PreviewTest JFJochWriter CommonFunctions) diff --git a/tools/CompressionBenchmark.cpp b/tools/CompressionBenchmark.cpp index fcf37e21..08339715 100644 --- a/tools/CompressionBenchmark.cpp +++ b/tools/CompressionBenchmark.cpp @@ -1,7 +1,7 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (2019-2023) Paul Scherrer Institute #include +#include #include "bitshuffle/bitshuffle_core.h" #include "zstd/lib/zstd.h" @@ -10,23 +10,43 @@ #include "../common/RawToConvertedGeometry.h" #include "JFJochDecompress.h" -std::string CheckCompression(const DiffractionExperiment &x, size_t nimages, const std::vector &image) { +double CheckCompressionThread(const DiffractionExperiment &x, + int32_t nimages, + int32_t image0, + int32_t stride, + const std::vector &image, + std::vector &output) { + double ret = 0; + + FrameTransformation transformation(x); + for (int32_t i = image0; i < nimages; i += stride) { + for (int j = 0; j < x.GetModulesNum(); j++ ) { + transformation.ProcessModule(image.data() + (j + i * x.GetModulesNum()) * RAW_MODULE_SIZE, j, 0); + } + transformation.Pack(); + ret += transformation.SaveCompressedImage(output.data() + i * x.GetMaxCompressedSize()); + } + return ret; +} + +std::string CheckCompression(const DiffractionExperiment &x, int32_t nimages, const std::vector &image, uint16_t nthreads) { double original_size = nimages * x.GetModulesNum() * RAW_MODULE_SIZE * x.GetPixelDepth(); - FrameTransformation transformation(x); std::vector output(nimages * x.GetMaxCompressedSize()); double compressed_size = 0; auto start_time = std::chrono::system_clock::now(); - for (int i = 0; i < nimages; i++) { - for (int j = 0; j < x.GetModulesNum(); j++ ) { - transformation.ProcessModule(image.data() + (j + i * x.GetModulesNum()) * RAW_MODULE_SIZE, j, 0); - } - transformation.Pack(); - compressed_size += transformation.SaveCompressedImage(output.data() + i * x.GetMaxCompressedSize()); - } + std::vector> futures; + + for (int i = 0; i < nthreads; i++) + futures.emplace_back(std::async(std::launch::async, &CheckCompressionThread, std::ref(x), + nimages, i, nthreads, + std::ref(image), std::ref(output))); + + for (int i = 0; i < nthreads; i++) + compressed_size += futures[i].get(); auto end_time = std::chrono::system_clock::now(); auto elapsed = std::chrono::duration_cast(end_time - start_time); @@ -73,8 +93,21 @@ int main(int argc, char **argv) { RegisterHDF5Filter(); - if (argc != 2) { - std::cout << "Usage: ./CompressionBenchmark " << std::endl; + if ((argc != 2) && (argc != 3) && (argc != 4)) { + std::cout << "Usage: ./CompressionBenchmark {}" << std::endl; + exit(EXIT_FAILURE); + } + + uint32_t nthreads = 1; + if (argc >= 3) + nthreads = atol(argv[2]); + + uint64_t nimages = 25; + if (argc == 4) + nimages = atol(argv[3]); + + if ((nthreads <= 0) || (nimages <= 0)) { + std::cerr << "Error in input parameters" << std::endl; exit(EXIT_FAILURE); } @@ -98,34 +131,36 @@ int main(int argc, char **argv) { exit(EXIT_FAILURE); } - uint64_t nimages = file_space.GetDimensions()[0]; - std::cout << "Number of images in the dataset: " << nimages << std::endl; - if (nimages > 200) { - nimages = 200; - std::cout << "Using only " << nimages << " images" << std::endl; - + uint64_t nimages_dataset = file_space.GetDimensions()[0]; + std::cout << "Number of images in the dataset: " << nimages_dataset << std::endl; + if (nimages_dataset > 200) { + nimages_dataset = 200; + std::cout << "Using only " << nimages_dataset << " images" << std::endl; } x.Mode(DetectorMode::Conversion); - std::vector image_conv ( nimages * file_space.GetDimensions()[1] * file_space.GetDimensions()[2]); + std::vector image_conv ( nimages_dataset * file_space.GetDimensions()[1] * file_space.GetDimensions()[2]); + std::vector start = {0,0,0}; - std::vector dim = {nimages, file_space.GetDimensions()[1], file_space.GetDimensions()[2]}; + std::vector dim = {nimages_dataset, file_space.GetDimensions()[1], file_space.GetDimensions()[2]}; auto start_time = std::chrono::system_clock::now(); dataset.ReadVector(image_conv, start, dim); auto end_time = std::chrono::system_clock::now(); auto elapsed = std::chrono::duration_cast(end_time - start_time); - std::cout << "Images loaded " << elapsed.count() / nimages << " ms/image " + std::cout << "Images loaded " << elapsed.count() / nimages_dataset << " ms/image " << (image_conv.size() * sizeof(uint16_t)) / (1000.0 * elapsed.count()) << " MB/s" << std::endl; + + std::cout << "Images to benchmark " << nimages << std::endl << "Threads: " << nthreads << std::endl << std::endl; std::vector image( nimages * x.GetModulesNum() * RAW_MODULE_SIZE); for (int i = 0; i < nimages; i++) { ConvertedToRawGeometry(x, image.data() + i * RAW_MODULE_SIZE * x.GetModulesNum(), - image_conv.data() + i * file_space.GetDimensions()[1] * file_space.GetDimensions()[2]); + image_conv.data() + (i % nimages_dataset) * file_space.GetDimensions()[1] * file_space.GetDimensions()[2]); } auto image_shuffled = bitshuffle(image, 4096); @@ -133,19 +168,26 @@ int main(int argc, char **argv) { x.MaskChipEdges(false); x.Compression(JFJochProtoBuf::NO_COMPRESSION); - std::cout << "None (geom transform) " << CheckCompression(x, nimages, image); + for (int i = 0; i < 3; i++) + CheckCompression(x, nimages, image, nthreads); - x.Compression(JFJochProtoBuf::BSHUF_LZ4); - std::cout << "BSHUF/LZ4 " << CheckCompression(x, nimages, image); + for (int i = 0; i <3; i++) { + x.Compression(JFJochProtoBuf::NO_COMPRESSION).Mode(DetectorMode::Raw); + std::cout << "None (memcpy) " << CheckCompression(x, nimages, image, nthreads); + x.Compression(JFJochProtoBuf::NO_COMPRESSION).Mode(DetectorMode::Conversion); - x.Compression(JFJochProtoBuf::BSHUF_ZSTD); - std::cout << "BSHUF/ZSTD (0) " << CheckCompression(x, nimages, image); + std::cout << "None (geom transform) " << CheckCompression(x, nimages, image, nthreads); - x.Compression(JFJochProtoBuf::BSHUF_ZSTD_RLE); - std::cout << "BSHUF/ZSTD (RLE) " << CheckCompression(x, nimages, image); + x.Compression(JFJochProtoBuf::BSHUF_LZ4); + std::cout << "BSHUF/LZ4 " << CheckCompression(x, nimages, image, nthreads); - x.Compression(JFJochProtoBuf::NO_COMPRESSION); - std::cout << "None (geom transform) " << CheckCompression(x, nimages, image); + x.Compression(JFJochProtoBuf::BSHUF_ZSTD); + std::cout << "BSHUF/ZSTD (0) " << CheckCompression(x, nimages, image, nthreads); + + x.Compression(JFJochProtoBuf::BSHUF_ZSTD_RLE); + std::cout << "BSHUF/ZSTD (RLE) " << CheckCompression(x, nimages, image, nthreads); + std::cout << std::endl; + } std::cout << std::endl << std::endl << "Decompression" << std::endl << std::endl; @@ -163,14 +205,14 @@ int main(int argc, char **argv) { x.Binning2x2(true); x.Compression(JFJochProtoBuf::NO_COMPRESSION); - std::cout << "None (geom transform) " << CheckCompression(x, nimages, image); + std::cout << "None (geom transform) " << CheckCompression(x, nimages, image, nthreads); x.Compression(JFJochProtoBuf::BSHUF_LZ4); - std::cout << "BSHUF/LZ4 " << CheckCompression(x, nimages, image); + std::cout << "BSHUF/LZ4 " << CheckCompression(x, nimages, image, nthreads); x.Compression(JFJochProtoBuf::BSHUF_ZSTD); - std::cout << "BSHUF/ZSTD (0) " << CheckCompression(x, nimages, image); + std::cout << "BSHUF/ZSTD (0) " << CheckCompression(x, nimages, image, nthreads); x.Compression(JFJochProtoBuf::BSHUF_ZSTD_RLE); - std::cout << "BSHUF/ZSTD (RLE) " << CheckCompression(x, nimages, image); + std::cout << "BSHUF/ZSTD (RLE) " << CheckCompression(x, nimages, image, nthreads); } \ No newline at end of file diff --git a/tools/DataAnalysisPerfTest.cpp b/tools/DataAnalysisPerfTest.cpp index 6c976355..8f9852b6 100644 --- a/tools/DataAnalysisPerfTest.cpp +++ b/tools/DataAnalysisPerfTest.cpp @@ -1,5 +1,4 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (2019-2023) Paul Scherrer Institute #include #include @@ -13,6 +12,7 @@ #include "../image_analysis/RadialIntegration.h" #include "../common/Logger.h" +#include "../image_analysis/PredictSpotsOnDetector.h" #define make_unit_cell(a1,a2,a3,a4,a5,a6) UnitCell{.a = a1, .b = a2, .c = a3, .alpha = a4, .beta = a5, .gamma = a6} @@ -44,7 +44,47 @@ auto TestAll(const DiffractionExperiment &experiment, const JFJochProtoBuf::Data auto elapsed = std::chrono::duration_cast(end_time - start_time); std::ostringstream strstream; - logger.Info("{:20s} {:8.1f} ms/image", "Full", + logger.Info("{:30s} {:8.1f} ms/image", "Full", + elapsed.count() / (1000.0 * (double) nimages)); + + return strstream.str(); +} + +auto TestAllWithROI(const DiffractionExperiment &experiment, const JFJochProtoBuf::DataProcessingSettings &settings, + GPUImageAnalysis &spot_finder, int16_t* image, size_t nimages) { + IndexerWrapper indexer; + indexer.Setup(experiment.GetUnitCell()); + + spot_finder.SetInputBuffer(image); + + std::vector roi_image(experiment.GetPixelsNum()); + + auto start_time = std::chrono::system_clock::now(); + for (int i = 0; i < nimages; i++) { + ROIFilter filter(experiment.GetXPixelsNum(), experiment.GetYPixelsNum()); + + std::vector spots; + std::vector result; + spot_finder.LoadDataToGPU(); + spot_finder.RunSpotFinder(settings); + spot_finder.GetSpotFinderResults(experiment, settings, spots); + spot_finder.RunRadialIntegration(); + std::vector recip; + for (const auto& s: spots) + recip.emplace_back(s.ReciprocalCoord(experiment)); + auto indexer_ret = indexer.Run(recip); + spot_finder.GetRadialIntegrationProfile(result); + if (!indexer_ret.empty()) { + PredictSpotsOnDetector(filter, experiment, indexer_ret[0].l); + filter.Apply(roi_image, INT16_MIN); + } + } + + auto end_time = std::chrono::system_clock::now(); + auto elapsed = std::chrono::duration_cast(end_time - start_time); + + std::ostringstream strstream; + logger.Info("{:30s} {:8.1f} ms/image", "Full+ROI", elapsed.count() / (1000.0 * (double) nimages)); return strstream.str(); @@ -86,7 +126,7 @@ void TestIndexing() { auto end_time = std::chrono::system_clock::now(); auto elapsed = std::chrono::duration_cast(end_time - start_time); - logger.Info("Fast feedback index. {:8.1f} ms/image", elapsed.count() / (1000.0 * nexec)); + logger.Info("{:30s} {:8.1f} ms/image", "Fast feedback index.", elapsed.count() / (1000.0 * nexec)); } } @@ -108,7 +148,7 @@ auto TestSpotFinder(const DiffractionExperiment &experiment, const JFJochProtoBu auto elapsed = std::chrono::duration_cast(end_time - start_time); std::ostringstream strstream; - logger.Info("{:20s} {:8.1f} ms/image {:5d} spots", "Spot finding", + logger.Info("{:30s} {:8.1f} ms/image {:5d} spots", "Spot finding", elapsed.count() / (1000.0 * (double) nimages), spots.size()); return strstream.str(); @@ -132,7 +172,7 @@ auto TestSpotFinderWithoutCopyToDevice(const DiffractionExperiment &experiment, auto elapsed = std::chrono::duration_cast(end_time - start_time); std::ostringstream strstream; - logger.Info("{:20s} {:8.1f} ms/image {:5d} spots", "Spot finding", + logger.Info("{:30s} {:8.1f} ms/image {:5d} spots", "Spot finding", elapsed.count() / (1000.0 * (double) nimages), spots.size()); return strstream.str(); @@ -196,18 +236,29 @@ auto TestRadialIntegrationGPUWithoutCopyToDevice(const DiffractionExperiment &x, } -auto TestRadialIntegration(const DiffractionExperiment &experiment, const JFJochProtoBuf::DataProcessingSettings &settings, - int16_t* image, size_t nimages) { +auto TestRadialIntegration(const DiffractionExperiment &experiment, + const JFJochProtoBuf::DataProcessingSettings &settings, + int16_t* image, size_t nimages, + uint32_t pixel_split = 1) { uint32_t nredo = 20; RadialIntegrationMapping mapping(experiment); - RadialIntegration integration(mapping); + std::unique_ptr integration; + + if (pixel_split == 1) { + integration = std::make_unique(mapping); + } else { + integration = std::make_unique(mapping.GetPixelToBinMappingSplitTo4(), + mapping.GetBinNumber(), + 4); + } + std::vector result; auto start_time = std::chrono::system_clock::now(); for (int redo = 0; redo < nredo; redo++) { for (int i = 0; i < nimages; i++) { - integration.ProcessOneImage(image + i * experiment.GetPixelsNum(), experiment.GetPixelsNum()); + integration->ProcessOneImage(image + i * experiment.GetPixelsNum(), experiment.GetPixelsNum()); //integration.GetResult(result); } } @@ -291,19 +342,23 @@ int main(int argc, char **argv) { TestSpotFinder(x, settings, local_peakfinder_gpu,image_conv.data(), nimages); } - logger.Info("{:20s} {:8.1f} ms/image", "Radial int. (GPU)", TestRadialIntegrationGPU(x, settings, + logger.Info("{:30s} {:8.1f} ms/image", "Radial int. (GPU)", TestRadialIntegrationGPU(x, settings, image_conv.data(), nimages)); - logger.Info("{:20s} {:8.1f} ms/image", "Radial int. (GPU/nocopy)", TestRadialIntegrationGPUWithoutCopyToDevice(x, settings, + logger.Info("{:30s} {:8.1f} ms/image", "Radial int. (GPU/nocpy)", TestRadialIntegrationGPUWithoutCopyToDevice(x, settings, image_conv.data(), nimages)); - logger.Info("{:20s} {:8.1f} ms/image", "Radial int. (CPU)", TestRadialIntegration(x, settings, + logger.Info("{:30s} {:8.1f} ms/image", "Radial int. (CPU)", TestRadialIntegration(x, settings, image_conv.data(), nimages)); + logger.Info("{:30s} {:8.1f} ms/image", "Radial int. pxlspl 2 (CPU)", TestRadialIntegration(x, settings, + image_conv.data(), nimages, 4)); + TestIndexing(); logger.Info("Full package"); if (GPUImageAnalysis::GPUPresent()) { GPUImageAnalysis local_peakfinder_gpu(x.GetXPixelsNum(), x.GetYPixelsNum(), one_byte_mask, mapping); TestAll(x, settings, local_peakfinder_gpu,image_conv.data(), nimages); + TestAllWithROI(x, settings, local_peakfinder_gpu,image_conv.data(), nimages); } } diff --git a/tools/HDF5DatasetWriteTest.cpp b/tools/HDF5DatasetWriteTest.cpp index 7fcac68f..7aabe0be 100644 --- a/tools/HDF5DatasetWriteTest.cpp +++ b/tools/HDF5DatasetWriteTest.cpp @@ -1,5 +1,4 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (2019-2023) Paul Scherrer Institute #include #include @@ -100,7 +99,22 @@ int main(int argc, char **argv) { x.FillMessage(start_message); JFCalibration calib(x); - start_message.pixel_mask = {{"sc0", calib.CalculateNexusMask(x, 0)}}; + auto pixel_mask = calib.CalculateNexusMask(x, 0); + { + size_t xpixel = x.GetXPixelsNum(); + size_t ypixel = x.GetYPixelsNum(); + start_message.AddPixelMask(CBORImage{ + .data = reinterpret_cast(pixel_mask.data()), + .size = pixel_mask.size() * sizeof(uint32_t), + .xpixel = xpixel, + .ypixel = ypixel, + .pixel_depth_bytes = 4, + .pixel_is_signed = false, + .pixel_is_float = false, + .algorithm = CompressionAlgorithm::NO_COMPRESSION, + .channel = "sc0" + }); + } // Master & calibration files are written outside of timing routine auto fileset = std::make_unique(start_message); diff --git a/tools/JFCalibrationPerfTest.cpp b/tools/JFCalibrationPerfTest.cpp index 6f31e96b..6405a9b3 100644 --- a/tools/JFCalibrationPerfTest.cpp +++ b/tools/JFCalibrationPerfTest.cpp @@ -1,16 +1,18 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (2019-2023) Paul Scherrer Institute #include #include #include #include +#include + #include "../jungfrau/JFPedestalCalc.h" #include "../common/Logger.h" #include "../jungfrau/JFCalibration.h" #include "../jungfrau/JFConversionFloatingPoint.h" #include "../jungfrau/JFConversionFixedPoint.h" +#include "../jungfrau/JFConversionGPU.h" #include "../tests/FPGAUnitTest.h" #include "../jungfrau/jf_packet.h" #include "../jungfrau/ProcessJFPacket.h" @@ -18,23 +20,12 @@ void test_pedestal(Logger &logger) { size_t nframes = 5000; DiffractionExperiment x(DetectorGeometry(1)); + x.Mode(DetectorMode::Conversion); std::vector data(nframes * RAW_MODULE_SIZE); - x.Mode(DetectorMode::Conversion); - double mean = 1000.0; - double stddev = 50.0; - - // Predictable random number generator - std::mt19937 g1(5423); - std::normal_distribution distribution(mean, stddev); - - for (size_t i = 0; i < nframes * RAW_MODULE_SIZE; i++) { - double number = distribution(g1); - if (number < 20) number = 20; - if (number > 16300) number = 16300; - data[i] = number; - } + for (size_t i = 0; i < nframes * RAW_MODULE_SIZE; i++) + data[i] = 3000 + (i % 881) + (i % 557); JFPedestalCalc calc_cpu(x); auto start_time = std::chrono::system_clock::now(); @@ -82,71 +73,19 @@ template void test_conversion(Logger &logger) { x.Mode(DetectorMode::Conversion); - logger.Info("JF FP conversion input prepared"); auto start_time = std::chrono::system_clock::now(); for (int z = 0; z < ntries; z++) { for (int i = 0; i < nframes; i++) { for (int m = 0; m < nmodules; m++) { - v[m].Convert(output.data() + (i * nmodules + m) * RAW_MODULE_SIZE, + v[m].ConvertModule(output.data() + (i * nmodules + m) * RAW_MODULE_SIZE, input.data() + (i * nmodules + m) * RAW_MODULE_SIZE); } } } - auto end_time = std::chrono::system_clock::now(); - auto elapsed = std::chrono::duration_cast(end_time - start_time); - logger.Info("Conversion performance: {:5d} us/module {:5.2f} GB/s", std::lround(elapsed.count() / ((double) (ntries * nframes * nmodules))), - ntries * nframes * nmodules * RAW_MODULE_SIZE * sizeof(uint16_t) * 1000 * 1000/ ((double) elapsed.count() * 1024 * 1024 * 1024)); -} + for (int m = 0; m < nmodules; m++) + v[m].Sync(); - -template void test_conversion_with_geom(Logger &logger) { - size_t nframes = 128; - int64_t nmodules = 8; - int64_t ntries = 8; - - DiffractionExperiment x(DetectorGeometry(nmodules, 1, 0, 0, false)); - - std::vector input(nframes * nmodules * RAW_MODULE_SIZE); - std::vector output(nframes * nmodules * CONVERTED_MODULE_SIZE); - - for (int i = 0; i < nmodules * nframes; i++) { - std::string image_path = "../../tests/test_data/mod5_raw" + std::to_string(i % 20) + ".bin"; - LoadBinaryFile(image_path, input.data() + i * RAW_MODULE_SIZE, RAW_MODULE_SIZE); - } - - std::vector v(nmodules); - - JFModuleGainCalibration gain_calib = GainCalibrationFromTestFile(); - - for (int m = 0; m < nmodules; m++) { - JFModulePedestal pedestal_g0; - JFModulePedestal pedestal_g1; - JFModulePedestal pedestal_g2; - - for (int i = 0; i < RAW_MODULE_SIZE; i++) { - pedestal_g0.GetPedestal()[i] = 3000 + i % 50 + m * 135; - pedestal_g1.GetPedestal()[i] = 15000 + i % 50 - m * 135; - pedestal_g2.GetPedestal()[i] = 14000 + i % 50 - m * 135; - } - v[m].Setup(gain_calib, pedestal_g0, pedestal_g1, pedestal_g2, 12.4); - } - - x.Mode(DetectorMode::Conversion); - - logger.Info("JF FP conversion input prepared"); - auto start_time = std::chrono::system_clock::now(); - for (int z = 0; z < ntries; z++) { - for (int i = 0; i < nframes; i++) { - for (int m = 0; m < nmodules; m++) { - v[m].ConvertAdjustGeom(output.data() + (i * nmodules + m) * CONVERTED_MODULE_SIZE, - input.data() + (i * nmodules + m) * RAW_MODULE_SIZE, - x.GetModuleSlowDirectionStep(m), - x.GetModuleFastDirectionStep(m), - 0); - } - } - } auto end_time = std::chrono::system_clock::now(); auto elapsed = std::chrono::duration_cast(end_time - start_time); @@ -208,9 +147,9 @@ int main () { logger.Info("Fixed point conversion"); test_conversion(logger); - logger.Info("Fixed point conversion (with geom)"); - test_conversion_with_geom(logger); + logger.Info("Floating point conversion (GPU)"); + test_conversion(logger); - logger.Info("Packet processing without conversion"); + logger.Info("Packet processing"); test_packet_processing(logger); } diff --git a/tools/PreviewTest.cpp b/tools/PreviewTest.cpp index cf3f08e6..e767a6ff 100644 --- a/tools/PreviewTest.cpp +++ b/tools/PreviewTest.cpp @@ -1,5 +1,4 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (2019-2023) Paul Scherrer Institute #include "../common/ZMQPreviewPublisher.h" #include "../writer/HDF5Objects.h" @@ -62,9 +61,10 @@ int main(int argc, char **argv) { publisher.Start(x, calibration); for (int i = 0; i < nimages; i++) { + DataMessage message{.number = i}; publisher.Publish(x, image_conv.data() + i * file_space.GetDimensions()[1] * file_space.GetDimensions()[2], - i); + message); std::this_thread::sleep_for(std::chrono::seconds(1)); } diff --git a/tools/RadialIntDataset.cpp b/tools/RadialIntDataset.cpp index e68e4496..956d5ef2 100644 --- a/tools/RadialIntDataset.cpp +++ b/tools/RadialIntDataset.cpp @@ -1,10 +1,7 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (2019-2023) Paul Scherrer Institute #include -// Copyright (2019-2021) Paul Scherrer Institute - #include #include #include "../writer/HDF5Objects.h" diff --git a/tools/RadialIntegrationCPUTest.cpp b/tools/RadialIntegrationCPUTest.cpp new file mode 100644 index 00000000..15408fca --- /dev/null +++ b/tools/RadialIntegrationCPUTest.cpp @@ -0,0 +1,88 @@ +// Copyright (2019-2023) Paul Scherrer Institute + +#include + +#include "../image_analysis/RadialIntegration.h" +#include "../common/Logger.h" +#include "../writer/HDF5Objects.h" + +Logger logger{"RadialIntegrationCPUTest"}; + +void RunRadialIntegrationThread(RadialIntegration *integration, + int16_t* image, size_t nimages, + size_t image0, size_t stride, + size_t npixel) { + for (size_t i = image0; i < nimages; i += stride) + integration->ProcessOneImage(image + i * npixel, npixel); +} + +auto TestRadialIntegration(const DiffractionExperiment &experiment, + int16_t* image, size_t nimages, + uint32_t nthreads, + uint32_t pixel_split) { + uint32_t nredo = 5; + RadialIntegrationMapping mapping(experiment); + + std::vector result; + std::vector> integration; + for (int i = 0; i < nthreads; i++) { + if (pixel_split == 1) + integration.emplace_back(std::make_unique(mapping)); + else + integration.emplace_back(std::make_unique(mapping.GetPixelToBinMappingSplitTo4(), + mapping.GetBinNumber(), 4)); + } + + auto start_time = std::chrono::system_clock::now(); + for (int redo = 0; redo < nredo; redo++) { + std::vector> futures; + for (int i = 0; i < nthreads; i++) { + futures.emplace_back(std::async(std::launch::async, &RunRadialIntegrationThread, + integration[i].get(), image, nimages, i, nthreads, + experiment.GetPixelsNum())); + } + for (auto &f: futures) + f.get(); + } + auto end_time = std::chrono::system_clock::now(); + auto elapsed = std::chrono::duration_cast(end_time - start_time); + + return elapsed.count() / (1000.0 * (double) nimages * nredo); +} + +int main(int argc, char **argv) { + if (argc > 3) { + logger.Info("Usage: ./DataAnalysisPerfTest {} {}"); + exit(EXIT_FAILURE); + } + + uint32_t nthreads = 1; + if (argc >= 2) + nthreads = atol(argv[1]); + + uint64_t nimages = 100; + if (argc == 3) + nimages = atol(argv[2]); + + if ((nthreads <= 0) || (nimages <= 0)) { + std::cerr << "Error in input parameters" << std::endl; + exit(EXIT_FAILURE); + } + + DiffractionExperiment x(DetectorGeometry(8, 2, 8, 36)); + + logger.Info("Number of threads: {}", nthreads); + logger.Info("Number of images in the dataset: {}", nimages); + + x.Mode(DetectorMode::Conversion); + + std::vector image_conv ( nimages * x.GetPixelsNum(), 30); + + x.BeamX_pxl(1090).BeamY_pxl(1136).DetectorDistance_mm(75).PhotonEnergy_keV(WVL_1A_IN_KEV); + std::vector one_byte_mask(x.GetPixelsNum(), 1); + + logger.Info("{:30s} {:8.2f} ms/image", "Radial int. pxlspl 1 (CPU)", + TestRadialIntegration(x, image_conv.data(), nimages, nthreads, 1)); + logger.Info("{:30s} {:8.2f} ms/image", "Radial int. pxlspl 2 (CPU)", + TestRadialIntegration(x, image_conv.data(), nimages, nthreads, 4)); +} diff --git a/tools/UDPSimulator.cpp b/tools/UDPSimulator.cpp index 1419154d..38deae23 100644 --- a/tools/UDPSimulator.cpp +++ b/tools/UDPSimulator.cpp @@ -1,5 +1,4 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (2019-2023) Paul Scherrer Institute #include "UDPSimulator.h" #include diff --git a/tools/UDPSimulator.h b/tools/UDPSimulator.h index 95751bf2..791a569e 100644 --- a/tools/UDPSimulator.h +++ b/tools/UDPSimulator.h @@ -1,5 +1,4 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (2019-2023) Paul Scherrer Institute #ifndef JUNGFRAUJOCH_UDPSIMULATOR_H #define JUNGFRAUJOCH_UDPSIMULATOR_H diff --git a/tools/jfjoch_udp_simulator.cpp b/tools/jfjoch_udp_simulator.cpp index 60068d7a..64defe9d 100644 --- a/tools/jfjoch_udp_simulator.cpp +++ b/tools/jfjoch_udp_simulator.cpp @@ -1,5 +1,4 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (2019-2023) Paul Scherrer Institute #include "UDPSimulator.h" diff --git a/writer/HDF5DataFile.cpp b/writer/HDF5DataFile.cpp index a4241faa..ce76b2e4 100644 --- a/writer/HDF5DataFile.cpp +++ b/writer/HDF5DataFile.cpp @@ -1,5 +1,4 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (2019-2023) Paul Scherrer Institute #include "HDF5DataFile.h" #include "../compression/JFJochCompressor.h" diff --git a/writer/HDF5DataFile.h b/writer/HDF5DataFile.h index bd43a00e..13548b9a 100644 --- a/writer/HDF5DataFile.h +++ b/writer/HDF5DataFile.h @@ -1,5 +1,4 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (2019-2023) Paul Scherrer Institute #ifndef HDF5DATAFILE_H #define HDF5DATAFILE_H @@ -10,7 +9,7 @@ #include "HDF5Objects.h" #include "../common/SpotToSave.h" -#include "../frame_serialize/ImageMessage.h" +#include "../frame_serialize/CBORMessages.h" struct HDF5DataFileStatistics { std::string filename; diff --git a/writer/HDF5NXmx.cpp b/writer/HDF5NXmx.cpp index 68f82595..2e326259 100644 --- a/writer/HDF5NXmx.cpp +++ b/writer/HDF5NXmx.cpp @@ -1,5 +1,4 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (2019-2023) Paul Scherrer Institute #include #include "HDF5NXmx.h" @@ -93,7 +92,8 @@ void HDF5Metadata::Detector(HDF5File *hdf5_file, const StartMessage &start, cons SaveScalar(det_specific, "software_git_commit", jfjoch_git_sha1()); SaveScalar(det_specific, "software_git_date", jfjoch_git_date()); SaveScalar(det_specific, "storage_cell_number", static_cast(start.storage_cell_number)); - + if (start.storage_cell_number > 1) + SaveScalar(det_specific, "storage_cell_delay", static_cast(start.storage_cell_delay_ns))->Units("ns"); SaveScalar(det_specific, "data_collection_efficiency", end.efficiency); SaveScalar(det_specific, "max_receiver_delay", end.max_receiver_delay); } @@ -192,14 +192,33 @@ void HDF5Metadata::DetectorModule(HDF5File *hdf5_file, const std::string &name, "", "", "translation", {0,0,0}); } +void HDF5Metadata::SaveCBORImage(HDF5File *hdf5_file, const std::string &hdf5_path, const CBORImage &image) { + std::vector dims = {image.ypixel, image.xpixel}; + + HDF5DataType data_type(image.pixel_depth_bytes, image.pixel_is_signed); + HDF5Dcpl dcpl; + + dcpl.SetCompression(image.algorithm, H5Tget_size(data_type.GetID()), 0); + dcpl.SetChunking(dims); + + HDF5DataSpace data_space(dims); + auto dataset = std::make_unique(*hdf5_file, hdf5_path, data_type, data_space, dcpl); + + if (image.algorithm == CompressionAlgorithm::NO_COMPRESSION) + dataset->Write(data_type, image.data); + else + dataset->WriteDirectChunk(image.data, image.size, {0,0}); +} + void HDF5Metadata::Calibration(HDF5File *hdf5_file, const StartMessage &start, const EndMessage &end) { - if (start.pixel_mask.count("sc0") == 1) { - auto v = start.pixel_mask.at("sc0"); - std::vector dims = {start.image_size_y, start.image_size_x}; - SaveVector(*hdf5_file, "/entry/instrument/detector/pixel_mask", v, dims, CompressionAlgorithm::BSHUF_LZ4); + if (!start.pixel_mask.empty()) { + SaveCBORImage(hdf5_file, "/entry/instrument/detector/pixel_mask", start.pixel_mask[0]); hdf5_file->HardLink("/entry/instrument/detector/pixel_mask", "/entry/instrument/detector/detectorSpecific/pixel_mask"); } + + for (const auto &i: start.calibration) + SaveCBORImage(hdf5_file, "/entry/instrument/detector/detectorSpecific/" + i.channel, i); } void HDF5Metadata::LinkToData(HDF5File *hdf5_file, const StartMessage &start, const EndMessage &end) { diff --git a/writer/HDF5NXmx.h b/writer/HDF5NXmx.h index 05516b87..580897bd 100644 --- a/writer/HDF5NXmx.h +++ b/writer/HDF5NXmx.h @@ -1,11 +1,9 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (2019-2023) Paul Scherrer Institute #ifndef JUNGFRAUJOCH_HDF5NXMX_H #define JUNGFRAUJOCH_HDF5NXMX_H -#include "../frame_serialize/StartMessage.h" -#include "../frame_serialize/EndMessage.h" +#include "../frame_serialize/CBORMessages.h" #include "HDF5Objects.h" @@ -27,6 +25,7 @@ namespace HDF5Metadata { void Mask(HDF5File *hdf5_file, const StartMessage &start, const EndMessage &end); void Calibration(HDF5File *hdf5_file, const StartMessage &start, const EndMessage &end); + void SaveCBORImage(HDF5File *hdf5_file, const std::string& hdf5_path, const CBORImage &image); void RadInt(HDF5File *hdf5_file, const StartMessage &start, const EndMessage &end); std::string DataFileName(const std::string& prefix, int64_t file_number); } diff --git a/writer/HDF5Objects.cpp b/writer/HDF5Objects.cpp index 23899ed9..f7aa4938 100644 --- a/writer/HDF5Objects.cpp +++ b/writer/HDF5Objects.cpp @@ -1,5 +1,4 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (2019-2023) Paul Scherrer Institute #include #include diff --git a/writer/HDF5Objects.h b/writer/HDF5Objects.h index 424c9e88..d23849e6 100644 --- a/writer/HDF5Objects.h +++ b/writer/HDF5Objects.h @@ -1,5 +1,4 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (2019-2023) Paul Scherrer Institute #ifndef JUNGFRAUJOCH_HDF5OBJECTS_H #define JUNGFRAUJOCH_HDF5OBJECTS_H diff --git a/writer/HDF5Sum.cpp b/writer/HDF5Sum.cpp index 4e229bb2..c28a9cd7 100644 --- a/writer/HDF5Sum.cpp +++ b/writer/HDF5Sum.cpp @@ -1,5 +1,4 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (2019-2023) Paul Scherrer Institute #include diff --git a/writer/HDF5Writer.cpp b/writer/HDF5Writer.cpp index cc779066..63102cb9 100644 --- a/writer/HDF5Writer.cpp +++ b/writer/HDF5Writer.cpp @@ -1,5 +1,4 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (2019-2023) Paul Scherrer Institute #include "HDF5Writer.h" #include "HDF5NXmx.h" diff --git a/writer/HDF5Writer.h b/writer/HDF5Writer.h index a85fbd10..ed39191f 100644 --- a/writer/HDF5Writer.h +++ b/writer/HDF5Writer.h @@ -1,5 +1,4 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (2019-2023) Paul Scherrer Institute #ifndef JUNGFRAUJOCH_HDF5WRITER_H #define JUNGFRAUJOCH_HDF5WRITER_H @@ -7,8 +6,7 @@ #include #include "HDF5DataFile.h" -#include "../frame_serialize/StartMessage.h" -#include "../frame_serialize/ImageMessage.h" +#include "../frame_serialize/CBORMessages.h" class HDF5Writer { std::vector > files; diff --git a/writer/JFJochWriterService.cpp b/writer/JFJochWriterService.cpp index 1abc43f8..5633c325 100644 --- a/writer/JFJochWriterService.cpp +++ b/writer/JFJochWriterService.cpp @@ -1,5 +1,4 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (2019-2023) Paul Scherrer Institute #include "JFJochWriterService.h" diff --git a/writer/JFJochWriterService.h b/writer/JFJochWriterService.h index f67863b4..802ac2aa 100644 --- a/writer/JFJochWriterService.h +++ b/writer/JFJochWriterService.h @@ -1,5 +1,4 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (2019-2023) Paul Scherrer Institute #ifndef JUNGFRAUJOCH_JFJOCHWRITERSERVICE_H #define JUNGFRAUJOCH_JFJOCHWRITERSERVICE_H diff --git a/writer/MakeDirectory.h b/writer/MakeDirectory.h index 9eaa8546..efa5419c 100644 --- a/writer/MakeDirectory.h +++ b/writer/MakeDirectory.h @@ -1,5 +1,4 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (2019-2023) Paul Scherrer Institute #ifndef JUNGFRAUJOCH_MAKEDIRECTORY_H #define JUNGFRAUJOCH_MAKEDIRECTORY_H diff --git a/writer/StreamWriter.cpp b/writer/StreamWriter.cpp index f63dfe0d..d4e0709d 100644 --- a/writer/StreamWriter.cpp +++ b/writer/StreamWriter.cpp @@ -1,5 +1,4 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (2019-2023) Paul Scherrer Institute #include "../common/JFJochException.h" #include "StreamWriter.h" diff --git a/writer/StreamWriter.h b/writer/StreamWriter.h index e85c36e9..7fc18c3c 100644 --- a/writer/StreamWriter.h +++ b/writer/StreamWriter.h @@ -1,5 +1,4 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (2019-2023) Paul Scherrer Institute #ifndef JUNGFRAUJOCH_STREAMWRITER_H #define JUNGFRAUJOCH_STREAMWRITER_H diff --git a/writer/ZMQImagePuller.cpp b/writer/ZMQImagePuller.cpp index b783ce94..12db14fa 100644 --- a/writer/ZMQImagePuller.cpp +++ b/writer/ZMQImagePuller.cpp @@ -1,5 +1,4 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (2019-2023) Paul Scherrer Institute #include #include "ZMQImagePuller.h" diff --git a/writer/ZMQImagePuller.h b/writer/ZMQImagePuller.h index 6ad5851a..1db85b98 100644 --- a/writer/ZMQImagePuller.h +++ b/writer/ZMQImagePuller.h @@ -1,5 +1,4 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (2019-2023) Paul Scherrer Institute #ifndef JUNGFRAUJOCH_ZMQIMAGEPULLER_H #define JUNGFRAUJOCH_ZMQIMAGEPULLER_H diff --git a/writer/jfjoch_writer.cpp b/writer/jfjoch_writer.cpp index c77e99af..021e81c3 100644 --- a/writer/jfjoch_writer.cpp +++ b/writer/jfjoch_writer.cpp @@ -1,5 +1,4 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (2019-2023) Paul Scherrer Institute #include #include diff --git a/writer/jfjoch_writer_multi.cpp b/writer/jfjoch_writer_multi.cpp index 6476d09a..9f45b91e 100644 --- a/writer/jfjoch_writer_multi.cpp +++ b/writer/jfjoch_writer_multi.cpp @@ -1,5 +1,4 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (2019-2023) Paul Scherrer Institute #include #include diff --git a/writer/jfjoch_writer_test.cpp b/writer/jfjoch_writer_test.cpp index 14a2fc8f..afa6c352 100644 --- a/writer/jfjoch_writer_test.cpp +++ b/writer/jfjoch_writer_test.cpp @@ -1,5 +1,4 @@ -// Copyright (2019-2022) Paul Scherrer Institute -// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (2019-2023) Paul Scherrer Institute #include #include