Compare commits
24 Commits
1.0.0-test
...
1.0.0_rc.8
| Author | SHA1 | Date | |
|---|---|---|---|
| 8809b8d0d5 | |||
| 86b3934387 | |||
| 7d9dcf2721 | |||
| 953c3fa972 | |||
| 5d7a4e1ff2 | |||
| f85b87bfd2 | |||
| 500222bdcc | |||
| c4d677f05b | |||
| 76ff39c012 | |||
| 3ef89483e8 | |||
| e185fbb3f5 | |||
| 701c083739 | |||
| 03662506c6 | |||
| 1b297babe9 | |||
| adc7aa7c7d | |||
| 27e17c316d | |||
| d7d66dc85c | |||
| 2a8fc3a466 | |||
| e4acd93b88 | |||
| 4ca397bd42 | |||
| 4d780c1dda | |||
| 949f693311 | |||
| 2b945f6dfa | |||
| 91fd44bff7 |
3
.gitignore
vendored
Normal file
3
.gitignore
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
cmake-build-debug/
|
||||
cmake-build-release/
|
||||
build*/
|
||||
117
.gitlab-ci.yml
117
.gitlab-ci.yml
@@ -2,11 +2,11 @@ stages:
|
||||
- build
|
||||
- test
|
||||
- synthesis
|
||||
- release
|
||||
|
||||
build:x86:gcc:
|
||||
stage: build
|
||||
variables:
|
||||
GIT_SUBMODULE_STRATEGY: recursive
|
||||
CC: gcc
|
||||
CXX: g++
|
||||
tags:
|
||||
@@ -23,7 +23,6 @@ build:x86:gcc:
|
||||
build:x86:gcc_writer:
|
||||
stage: build
|
||||
variables:
|
||||
GIT_SUBMODULE_STRATEGY: recursive
|
||||
CC: gcc
|
||||
CXX: g++
|
||||
tags:
|
||||
@@ -35,12 +34,11 @@ build:x86:gcc_writer:
|
||||
- cd build
|
||||
- source /opt/rh/gcc-toolset-12/enable
|
||||
- cmake -DCMAKE_BUILD_TYPE=Release -DJFJOCH_WRITER_ONLY=ON ..
|
||||
- make -j48 jfjoch
|
||||
- make -j48
|
||||
|
||||
build:x86:driver:
|
||||
stage: build
|
||||
variables:
|
||||
GIT_SUBMODULE_STRATEGY: recursive
|
||||
CC: gcc
|
||||
CXX: g++
|
||||
tags:
|
||||
@@ -49,18 +47,16 @@ build:x86:driver:
|
||||
needs: []
|
||||
artifacts:
|
||||
paths:
|
||||
- "jfjoch_driver_*.tar.gz"
|
||||
- "jfjoch_driver.tar.gz"
|
||||
expire_in: 1 week
|
||||
script:
|
||||
- cd fpga/pcie_driver
|
||||
- make
|
||||
- bash pack.sh
|
||||
- mv jfjoch_driver_*.tar.gz ../..
|
||||
- mv jfjoch_driver.tar.gz ../..
|
||||
|
||||
build:x86:vitis_hls:
|
||||
stage: build
|
||||
variables:
|
||||
GIT_SUBMODULE_STRATEGY: recursive
|
||||
tags:
|
||||
- x86
|
||||
needs: []
|
||||
@@ -83,27 +79,43 @@ build:x86:vitis_hls:
|
||||
|
||||
build:x86:frontend:
|
||||
stage: build
|
||||
variables:
|
||||
GIT_SUBMODULE_STRATEGY: recursive
|
||||
tags:
|
||||
- x86
|
||||
needs: []
|
||||
script:
|
||||
- cd frontend_ui
|
||||
- npm install
|
||||
- npm run build
|
||||
- mkdir build
|
||||
- cd build
|
||||
- zip -r ../../frontend.${CI_COMMIT_SHORT_SHA}.zip *
|
||||
- /usr/bin/cmake ..
|
||||
- make frontend
|
||||
- cd ../frontend_ui/build
|
||||
- tar czf ../../jfjoch_frontend.tar.gz *
|
||||
artifacts:
|
||||
paths:
|
||||
- frontend.${CI_COMMIT_SHORT_SHA}.zip
|
||||
- jfjoch_frontend.tar.gz
|
||||
expire_in: 1 week
|
||||
|
||||
build:x86:rpm:
|
||||
stage: build
|
||||
tags:
|
||||
- x86
|
||||
needs: []
|
||||
script:
|
||||
- mkdir build
|
||||
- cd build
|
||||
- source /opt/rh/gcc-toolset-12/enable
|
||||
- cmake -DCMAKE_BUILD_TYPE=Release ..
|
||||
- make frontend
|
||||
- make -j48 package
|
||||
- mv *.rpm ..
|
||||
artifacts:
|
||||
paths:
|
||||
- "*.rpm"
|
||||
expire_in: 1 week
|
||||
|
||||
test:x86:gcc:
|
||||
stage: test
|
||||
timeout: 90m
|
||||
variables:
|
||||
GIT_SUBMODULE_STRATEGY: recursive
|
||||
CTEST_OUTPUT_ON_FAILURE: 1
|
||||
CC: gcc
|
||||
CXX: g++
|
||||
@@ -112,18 +124,16 @@ test:x86:gcc:
|
||||
tags:
|
||||
- gcc
|
||||
- x86
|
||||
- ib
|
||||
script:
|
||||
- source /opt/rh/gcc-toolset-12/enable
|
||||
- mkdir -p build
|
||||
- cd build
|
||||
- cmake -DCMAKE_BUILD_TYPE=Release ..
|
||||
- make -j48 CatchTest CompressionBenchmark HDF5DatasetWriteTest
|
||||
- make -j48 jfjoch_test HDF5DatasetWriteTest
|
||||
- cd tests
|
||||
- ./CatchTest -r junit -o report.xml
|
||||
- ./jfjoch_test -r junit -o report.xml
|
||||
- cd ../tools
|
||||
- ./HDF5DatasetWriteTest ../../tests/test_data/compression_benchmark.h5
|
||||
- numactl -m 0 -N 0 ./CompressionBenchmark ../../tests/test_data/compression_benchmark.h5
|
||||
artifacts:
|
||||
expire_in: 1 week
|
||||
reports:
|
||||
@@ -133,7 +143,6 @@ test:x86:crystfel:
|
||||
stage: test
|
||||
timeout: 90m
|
||||
variables:
|
||||
GIT_SUBMODULE_STRATEGY: recursive
|
||||
CTEST_OUTPUT_ON_FAILURE: 1
|
||||
CC: gcc
|
||||
CXX: g++
|
||||
@@ -157,7 +166,6 @@ test:x86:xds_durin:
|
||||
stage: test
|
||||
timeout: 90m
|
||||
variables:
|
||||
GIT_SUBMODULE_STRATEGY: recursive
|
||||
CTEST_OUTPUT_ON_FAILURE: 1
|
||||
CC: gcc
|
||||
CXX: g++
|
||||
@@ -181,7 +189,6 @@ test:x86:xds_neggia:
|
||||
stage: test
|
||||
timeout: 90m
|
||||
variables:
|
||||
GIT_SUBMODULE_STRATEGY: recursive
|
||||
CTEST_OUTPUT_ON_FAILURE: 1
|
||||
CC: gcc
|
||||
CXX: g++
|
||||
@@ -205,7 +212,6 @@ test:x86:xia2.ssx:
|
||||
stage: test
|
||||
timeout: 90m
|
||||
variables:
|
||||
GIT_SUBMODULE_STRATEGY: recursive
|
||||
CTEST_OUTPUT_ON_FAILURE: 1
|
||||
CC: gcc
|
||||
CXX: g++
|
||||
@@ -229,43 +235,43 @@ test:x86:xia2.ssx:
|
||||
|
||||
synthesis:vivado_pcie_100g:
|
||||
stage: synthesis
|
||||
dependencies: []
|
||||
variables:
|
||||
GIT_SUBMODULE_STRATEGY: recursive
|
||||
CC: gcc
|
||||
CXX: g++
|
||||
allow_failure: true
|
||||
rules:
|
||||
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
|
||||
- if: $CI_PIPELINE_SOURCE == "push"
|
||||
allow_failure: true
|
||||
changes:
|
||||
- fpga/hls/*
|
||||
- fpga/hdl/*
|
||||
- fpga/scripts/*
|
||||
- fpga/xdc/*
|
||||
- fpga/include/jfjoch_fpga.h
|
||||
- fpga/pcie_driver/jfjoch_fpga.h
|
||||
tags:
|
||||
- vivado
|
||||
artifacts:
|
||||
paths:
|
||||
- "*.mcs"
|
||||
- "jfjoch_fpga_pcie_100g.mcs"
|
||||
expire_in: 1 week
|
||||
script:
|
||||
- source /opt/rh/gcc-toolset-12/enable
|
||||
- source /opt/Xilinx/Vivado/2022.1/settings64.sh
|
||||
- touch jfjoch_fpga_pcie_100g.mcs
|
||||
- mkdir -p build
|
||||
- cd build
|
||||
- /usr/bin/cmake ..
|
||||
- make pcie_100g
|
||||
- mv fpga/*.mcs ..
|
||||
needs: ["build:x86:gcc", "build:x86:vitis_hls", "test:x86:gcc"]
|
||||
- make -j4 pcie_100g
|
||||
- mv fpga/jfjoch_fpga_pcie_100g.mcs ..
|
||||
needs: ["build:x86:gcc", "test:x86:gcc"]
|
||||
|
||||
synthesis:vivado_pcie_8x10g:
|
||||
stage: synthesis
|
||||
dependencies: []
|
||||
variables:
|
||||
GIT_SUBMODULE_STRATEGY: recursive
|
||||
CC: gcc
|
||||
CXX: g++
|
||||
allow_failure: true
|
||||
rules:
|
||||
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
|
||||
- if: $CI_PIPELINE_SOURCE == "push"
|
||||
@@ -274,19 +280,54 @@ synthesis:vivado_pcie_8x10g:
|
||||
- fpga/hdl/*
|
||||
- fpga/scripts/*
|
||||
- fpga/xdc/*
|
||||
- fpga/include/jfjoch_fpga.h
|
||||
- fpga/pcie_driver/jfjoch_fpga.h
|
||||
allow_failure: true
|
||||
tags:
|
||||
- vivado
|
||||
artifacts:
|
||||
paths:
|
||||
- "*.mcs"
|
||||
- "jfjoch_fpga_pcie_8x10g.mcs"
|
||||
expire_in: 1 week
|
||||
script:
|
||||
- source /opt/rh/gcc-toolset-12/enable
|
||||
- source /opt/Xilinx/Vivado/2022.1/settings64.sh
|
||||
- touch jfjoch_fpga_pcie_8x10g.mcs
|
||||
- mkdir -p build
|
||||
- cd build
|
||||
- /usr/bin/cmake ..
|
||||
- make pcie_8x10g
|
||||
- mv fpga/*.mcs ..
|
||||
needs: [ "build:x86:gcc", "build:x86:vitis_hls", "test:x86:gcc" ]
|
||||
- make -j4 pcie_8x10g
|
||||
- mv fpga/jfjoch_fpga_pcie_8x10g.mcs ..
|
||||
needs: [ "build:x86:gcc", "test:x86:gcc" ]
|
||||
|
||||
release:
|
||||
stage: release
|
||||
rules:
|
||||
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
|
||||
when: manual
|
||||
tags:
|
||||
- x86
|
||||
dependencies:
|
||||
- synthesis:vivado_pcie_8x10g
|
||||
- synthesis:vivado_pcie_100g
|
||||
- build:x86:frontend
|
||||
- build:x86:driver
|
||||
- build:x86:rpm
|
||||
script:
|
||||
- export PACKAGE_VERSION=`head -n1 VERSION`
|
||||
- export PACKAGE_REGISTRY_URL="${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/packages/generic/jungfraujoch/${PACKAGE_VERSION}"
|
||||
- 'curl --header "JOB-TOKEN: $CI_JOB_TOKEN" --upload-file jfjoch-driver-dkms-${PACKAGE_VERSION}-1.el8.noarch.rpm "${PACKAGE_REGISTRY_URL}/jfjoch-driver-dkms-${PACKAGE_VERSION}-1.el8.noarch.rpm"'
|
||||
- 'curl --header "JOB-TOKEN: $CI_JOB_TOKEN" --upload-file jfjoch-writer-${PACKAGE_VERSION}-1.el8.x86_64.rpm "${PACKAGE_REGISTRY_URL}/jfjoch-writer-${PACKAGE_VERSION}-1.el8.x86_64.rpm"'
|
||||
- 'curl --header "JOB-TOKEN: $CI_JOB_TOKEN" --upload-file jfjoch-${PACKAGE_VERSION}-1.el8.x86_64.rpm "${PACKAGE_REGISTRY_URL}/jfjoch-${PACKAGE_VERSION}-1.el8.x86_64.rpm"'
|
||||
- 'curl --header "JOB-TOKEN: $CI_JOB_TOKEN" --upload-file jfjoch_driver.tar.gz "${PACKAGE_REGISTRY_URL}/jfjoch_driver.tar.gz"'
|
||||
- 'curl --header "JOB-TOKEN: $CI_JOB_TOKEN" --upload-file jfjoch_frontend.tar.gz "${PACKAGE_REGISTRY_URL}/jfjoch_frontend.tar.gz"'
|
||||
- 'curl --header "JOB-TOKEN: $CI_JOB_TOKEN" --upload-file jfjoch_fpga_pcie_100g.mcs "${PACKAGE_REGISTRY_URL}/jfjoch_fpga_pcie_100g.mcs"'
|
||||
- 'curl --header "JOB-TOKEN: $CI_JOB_TOKEN" --upload-file jfjoch_fpga_pcie_8x10g.mcs "${PACKAGE_REGISTRY_URL}/jfjoch_fpga_pcie_8x10g.mcs"'
|
||||
- >
|
||||
release-cli create --name "Release $PACKAGE_VERSION" --tag-name $PACKAGE_VERSION
|
||||
--assets-link "{\"name\":\"jfjoch_driver.tar.gz\",\"url\":\"${PACKAGE_REGISTRY_URL}/jfjoch_driver.tar.gz\"}"
|
||||
--assets-link "{\"name\":\"jfjoch_frontend.tar.gz\",\"url\":\"${PACKAGE_REGISTRY_URL}/jfjoch_frontend.tar.gz\"}"
|
||||
--assets-link "{\"name\":\"jfjoch_fpga_pcie_8x10g.mcs\",\"url\":\"${PACKAGE_REGISTRY_URL}/jfjoch_fpga_pcie_8x10g.mcs\"}"
|
||||
--assets-link "{\"name\":\"jfjoch_fpga_pcie_100g.mcs\",\"url\":\"${PACKAGE_REGISTRY_URL}/jfjoch_fpga_pcie_100g.mcs\"}"
|
||||
--assets-link "{\"name\":\"jfjoch-${PACKAGE_VERSION}-1.el8.x86_64.rpm\",\"url\":\"${PACKAGE_REGISTRY_URL}/jfjoch-${PACKAGE_VERSION}-1.el8.x86_64.rpm\",\"link_type\":\"package\"}"
|
||||
--assets-link "{\"name\":\"jfjoch-writer-${PACKAGE_VERSION}-1.el8.x86_64.rpm\",\"url\":\"${PACKAGE_REGISTRY_URL}/jfjoch-writer-${PACKAGE_VERSION}-1.el8.x86_64.rpm\",\"link_type\":\"package\"}"
|
||||
--assets-link "{\"name\":\"jfjoch-driver-dkms-${PACKAGE_VERSION}-1.el8.noarch.rpm\",\"url\":\"${PACKAGE_REGISTRY_URL}/jfjoch-driver-dkms-${PACKAGE_VERSION}-1.el8.noarch.rpm\",\"link_type\":\"package\"}"
|
||||
|
||||
19
.gitmodules
vendored
19
.gitmodules
vendored
@@ -1,19 +0,0 @@
|
||||
[submodule "image_analysis/fast-feedback-indexer"]
|
||||
path = image_analysis/fast-feedback-indexer
|
||||
url = https://github.com/paulscherrerinstitute/fast-feedback-indexer/
|
||||
[submodule "frame_serialize/tinycbor"]
|
||||
path = frame_serialize/tinycbor
|
||||
url = https://github.com/intel/tinycbor
|
||||
[submodule "compression/zstd"]
|
||||
path = compression/zstd
|
||||
url = https://github.com/facebook/zstd
|
||||
[submodule "detector_control/slsDetectorPackage"]
|
||||
path = detector_control/slsDetectorPackage
|
||||
url = https://github.com/fleon-psi/slsDetectorPackage
|
||||
branch = "jfjoch-shmem"
|
||||
[submodule "compression/bitshuffle_hperf"]
|
||||
path = compression/bitshuffle_hperf
|
||||
url = https://github.com/kalcutter/bitshuffle
|
||||
[submodule "broker/pistache"]
|
||||
path = broker/pistache
|
||||
url = https://github.com/fleon-psi/pistache
|
||||
134
CMakeLists.txt
134
CMakeLists.txt
@@ -1,7 +1,9 @@
|
||||
CMAKE_MINIMUM_REQUIRED(VERSION 3.19)
|
||||
|
||||
PROJECT(Jungfraujoch VERSION 1.0 LANGUAGES C CXX)
|
||||
LIST(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
|
||||
FILE(STRINGS VERSION JFJOCH_VERSION)
|
||||
|
||||
PROJECT(jfjoch VERSION 1.0.0 LANGUAGES C CXX)
|
||||
SET(CMAKE_POLICY_DEFAULT_CMP0077 NEW)
|
||||
|
||||
SET(CMAKE_CXX_STANDARD 20)
|
||||
SET(CMAKE_CXX_STANDARD_REQUIRED True)
|
||||
@@ -9,6 +11,32 @@ SET(CMAKE_CXX_STANDARD_REQUIRED True)
|
||||
SET(CMAKE_CXX_FLAGS_RELEASE "-O3 -march=native -mtune=native -Wno-deprecated-enum-enum-conversion")
|
||||
SET(CMAKE_C_FLAGS_RELEASE "-O3 -march=native -mtune=native")
|
||||
|
||||
SET(BUILD_SHARED_LIBS OFF)
|
||||
SET(BUILD_TESTING OFF)
|
||||
|
||||
SET(ZSTD_LEGACY_SUPPORT OFF)
|
||||
SET(ZSTD_MULTITHREAD_SUPPORT OFF)
|
||||
SET(ZSTD_BUILD_PROGRAMS OFF)
|
||||
SET(ZSTD_BUILD_SHARED OFF)
|
||||
|
||||
SET(SLS_USE_RECEIVER OFF)
|
||||
SET(SLS_USE_RECEIVER_BINARIES OFF)
|
||||
SET(SLS_BUILD_SHARED_LIBRARIES OFF)
|
||||
|
||||
SET(BUILD_FAST_INDEXER OFF)
|
||||
SET(BUILD_FAST_INDEXER_STATIC ON)
|
||||
|
||||
SET(HDF5_ENABLE_SZIP_SUPPORT OFF)
|
||||
SET(HDF5_ENABLE_SZIP_ENCODING OFF)
|
||||
SET(HDF5_BUILD_EXAMPLES OFF)
|
||||
SET(HDF5_BUILD_CPP_LIB OFF)
|
||||
SET(HDF5_ENABLE_Z_LIB_SUPPORT OFF)
|
||||
SET(HDF5_EXTERNALLY_CONFIGURED 1)
|
||||
|
||||
SET(jbig OFF)
|
||||
SET(zstd OFF)
|
||||
SET(lzma OFF)
|
||||
|
||||
INCLUDE(CheckLanguage)
|
||||
CHECK_LANGUAGE(CUDA)
|
||||
|
||||
@@ -28,19 +56,52 @@ SET(JFJOCH_WRITER_ONLY OFF CACHE BOOL "Compile HDF5 writer only")
|
||||
INCLUDE_DIRECTORIES(include)
|
||||
INCLUDE(CheckIncludeFile)
|
||||
|
||||
#This is to supress error in TORCH
|
||||
|
||||
IF ((NOT EXISTS /usr/bin/python) AND (EXISTS /usr/bin/python3))
|
||||
SET(PYTHON_EXECUTABLE /usr/bin/python3)
|
||||
ENDIF()
|
||||
|
||||
FIND_PACKAGE(Torch HINTS /opt/libtorch/share/cmake/Torch/)
|
||||
FIND_LIBRARY(NUMA_LIBRARY NAMES numa DOC "NUMA Library")
|
||||
CHECK_INCLUDE_FILE(numaif.h HAS_NUMAIF)
|
||||
CHECK_INCLUDE_FILE(numa.h HAS_NUMA_H)
|
||||
|
||||
LIST(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
|
||||
#FIND_PACKAGE(ZeroMQ 4 REQUIRED)
|
||||
include(FetchContent)
|
||||
|
||||
FetchContent_Declare(tiff
|
||||
GIT_REPOSITORY https://github.com/fleon-psi/libtiff
|
||||
GIT_TAG v4.6.0
|
||||
EXCLUDE_FROM_ALL)
|
||||
|
||||
FetchContent_Declare(hdf5
|
||||
GIT_REPOSITORY https://github.com/HDFGroup/hdf5/
|
||||
GIT_TAG hdf5_1.14.4.2
|
||||
GIT_SHALLOW 1
|
||||
EXCLUDE_FROM_ALL)
|
||||
|
||||
FetchContent_Declare(
|
||||
pistache_http
|
||||
GIT_REPOSITORY https://github.com/fleon-psi/pistache
|
||||
GIT_TAG 51553b92cc7bb25ac792462722ddd4fae33d14b1
|
||||
EXCLUDE_FROM_ALL
|
||||
)
|
||||
|
||||
FetchContent_Declare(
|
||||
zstd
|
||||
GIT_REPOSITORY https://github.com/facebook/zstd
|
||||
GIT_TAG 794ea1b0afca0f020f4e57b6732332231fb23c70
|
||||
SOURCE_SUBDIR build/cmake
|
||||
EXCLUDE_FROM_ALL
|
||||
)
|
||||
|
||||
FetchContent_Declare(
|
||||
sls_detector_package
|
||||
GIT_REPOSITORY https://github.com/fleon-psi/slsDetectorPackage
|
||||
GIT_TAG bae261433241ff2f458350e26ab026f00f01c427
|
||||
)
|
||||
|
||||
FetchContent_Declare(
|
||||
catch2
|
||||
GIT_REPOSITORY https://github.com/catchorg/Catch2
|
||||
GIT_TAG 4e8d92b
|
||||
EXCLUDE_FROM_ALL
|
||||
)
|
||||
|
||||
FetchContent_MakeAvailable(pistache_http zstd sls_detector_package catch2 hdf5 tiff)
|
||||
|
||||
ADD_SUBDIRECTORY(jungfrau)
|
||||
ADD_SUBDIRECTORY(compression)
|
||||
@@ -48,11 +109,9 @@ ADD_SUBDIRECTORY(common)
|
||||
ADD_SUBDIRECTORY(writer)
|
||||
ADD_SUBDIRECTORY(frame_serialize)
|
||||
|
||||
ADD_SUBDIRECTORY(broker/pistache)
|
||||
ADD_SUBDIRECTORY(detector_control)
|
||||
IF (JFJOCH_WRITER_ONLY)
|
||||
MESSAGE(STATUS "Compiling HDF5 writer only")
|
||||
SET(jfjoch_executables jfjoch_writer)
|
||||
ELSE()
|
||||
ADD_SUBDIRECTORY(broker)
|
||||
ADD_SUBDIRECTORY(fpga)
|
||||
@@ -62,17 +121,52 @@ ELSE()
|
||||
ADD_SUBDIRECTORY(tests)
|
||||
ADD_SUBDIRECTORY(tools)
|
||||
ADD_SUBDIRECTORY(preview)
|
||||
ADD_SUBDIRECTORY(resonet)
|
||||
SET(jfjoch_executables jfjoch_broker jfjoch_writer CatchTest CompressionBenchmark HDF5DatasetWriteTest jfjoch_udp_simulator sls_detector_put sls_detector_get)
|
||||
ENDIF()
|
||||
|
||||
ADD_CUSTOM_COMMAND(OUTPUT frontend_ui/build/index.html
|
||||
COMMAND npm run build
|
||||
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/frontend_ui)
|
||||
ADD_CUSTOM_TARGET(frontend DEPENDS frontend_ui/build/index.html)
|
||||
IF (NOT JFJOCH_WRITER_ONLY)
|
||||
ADD_CUSTOM_COMMAND(OUTPUT frontend_ui/build/index.html
|
||||
COMMAND npm install
|
||||
COMMAND npm run build
|
||||
COMMAND npm run redocly
|
||||
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/frontend_ui)
|
||||
ADD_CUSTOM_TARGET(frontend DEPENDS frontend_ui/build/index.html)
|
||||
|
||||
ADD_CUSTOM_TARGET(jfjoch DEPENDS ${jfjoch_executables})
|
||||
INSTALL(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/fpga/pcie_driver/
|
||||
DESTINATION /usr/src/jfjoch-1.0.0
|
||||
COMPONENT driver-dkms
|
||||
FILES_MATCHING PATTERN "*.c" PATTERN "*.h" PATTERN "Makefile" PATTERN "dkms.conf")
|
||||
|
||||
FILE(MAKE_DIRECTORY ${CMAKE_SOURCE_DIR}/frontend_ui/build/)
|
||||
INSTALL(DIRECTORY ${CMAKE_SOURCE_DIR}/frontend_ui/build/ DESTINATION share/jfjoch/frontend COMPONENT jfjoch )
|
||||
ENDIF()
|
||||
|
||||
IF(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)
|
||||
SET(CMAKE_INSTALL_PREFIX /opt/jfjoch CACHE PATH "Default directory" FORCE)
|
||||
ENDIF(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)
|
||||
|
||||
# Set Package Name
|
||||
set(CPACK_PACKAGE_NAME "jfjoch")
|
||||
|
||||
SET(CPACK_COMPONENTS_ALL jfjoch writer driver-dkms)
|
||||
SET(CPACK_GENERATOR RPM)
|
||||
SET(CPACK_RPM_COMPONENT_INSTALL ON)
|
||||
SET(CPACK_RPM_MAIN_COMPONENT jfjoch)
|
||||
SET(CPACK_RPM_PACKAGE_RELEASE_DIST ON)
|
||||
SET(CPACK_RPM_FILE_NAME "RPM-DEFAULT")
|
||||
SET(CPACK_RPM_PACKAGE_VERSION ${JFJOCH_VERSION})
|
||||
SET(CPACK_RPM_PACKAGE_RELEASE 1)
|
||||
SET(CPACK_RPM_PACKAGE_SUMMARY "Jungfraujoch data acquisition system")
|
||||
SET(CPACK_RPM_PACKAGE_DESCRIPTION "Jungfraujoch")
|
||||
SET(CPACK_RPM_DRIVER-DKMS_PACKAGE_REQUIRES "dkms, gcc, bash, sed")
|
||||
SET(CPACK_RPM_DRIVER-DKMS_PACKAGE_ARCHITECTURE "noarch")
|
||||
SET(CPACK_RPM_DRIVER-DKMS_POST_INSTALL_SCRIPT_FILE ${CMAKE_CURRENT_SOURCE_DIR}/fpga/pcie_driver/postinstall.sh)
|
||||
SET(CPACK_RPM_DRIVER-DKMS_PRE_UNINSTALL_SCRIPT_FILE ${CMAKE_CURRENT_SOURCE_DIR}/fpga/pcie_driver/preuninstall.sh)
|
||||
SET(CPACK_RPM_EXCLUDE_FROM_AUTO_FILELIST_ADDITION /usr/src)
|
||||
|
||||
# Set The Vendor Name
|
||||
SET(CPACK_PACKAGE_VENDOR "Paul Scherrer Institut")
|
||||
|
||||
# Set The License Information
|
||||
SET(CPACK_RPM_PACKAGE_LICENSE "Proprietary")
|
||||
|
||||
INCLUDE(CPack)
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
# MAX IV docker config
|
||||
|
||||
FROM harbor.maxiv.lu.se/dockerhub/library/ubuntu:22.04
|
||||
|
||||
RUN set -ex; \
|
||||
apt-get update; \
|
||||
apt-get install -y pkg-config git cmake make g++ libhdf5-dev libczmq-dev;\
|
||||
apt-get install -y pkg-config git cmake make g++;\
|
||||
rm -rf /var/lib/apt/lists/*
|
||||
|
||||
|
||||
|
||||
48
README.md
48
README.md
@@ -7,6 +7,7 @@ Citation: F. Leonarski, M. Bruckner, C. Lopez-Cuenca, A. Mozzanica, H.-C. Stadle
|
||||
The project is supported by :
|
||||
* Innosuisse via Innovation Project "NextGenDCU high data rate acquisition system for X-ray detectors in structural biology applications" (101.535.1 IP-ENG; Apr 2023 - Sep 2025).
|
||||
* ETH Domain via Open Research Data Contribute project (Jan - Dec 2023)
|
||||
* AMD University Program with donation of licenses of Ethernet IP cores and Vivado software
|
||||
|
||||
## License
|
||||
|
||||
@@ -33,32 +34,31 @@ Other linux platforms should work, but no tests were done so far.
|
||||
### Dependencies
|
||||
Required:
|
||||
* C++20 compiler and C++20 standard library; recommended GCC 11+ or clang 14+ (Intel OneAPI, AMD AOCC)
|
||||
* CMake version 3.21 or newer + GNU make tool
|
||||
* HDF5 library version 1.10 or newer
|
||||
* TIFF library (with C++ headers)
|
||||
* CMake version 3.21 or newer + GNU make tool
|
||||
* JPEG library (turbo-jpeg is also OK)
|
||||
|
||||
Optional:
|
||||
* CUDA compiler version 11 or newer - required for MX indexing and ML resolution estimation
|
||||
* CUDA compiler version 11 or newer - required for MX fast feedback indexer
|
||||
* NUMA library - to pin threads to nodes/CPUs
|
||||
* Node.js - to make frontend
|
||||
* libtorch - for resolution estimation using model from Stanford - see below
|
||||
|
||||
Provided as GIT submodules:
|
||||
Automatically downloaded by CMake and statically linked:
|
||||
* SLS Detector Package - see [github.com/slsdetectorgroup/slsDetectorPackage](https://github.com/slsdetectorgroup/slsDetectorPackage)
|
||||
* tinycbor (Intel) - see [github.com/intel/tinycbor](https://github.com/intel/tinycbor)
|
||||
* Zstandard (Facebook) - see [github.com/facebook/zstd](https://github.com/facebook/zstd)
|
||||
* Pistache webserver - see [github.com/pistacheio/pistache](https://github.com/pistacheio/pistache)
|
||||
* Fast feedback indexer (Hans-Christian Stadler, PSI) - see [github.com/paulscherrerinstitute/fast-feedback-indexer](https://github.com/paulscherrerinstitute/fast-feedback-indexer)
|
||||
* fast replacement for Bitshuffle pre-compression filter (Kal Cutter, DECTRIS) - see [github.com/kalcutter/bitshuffle](https://github.com/kalcutter/bitshuffle)
|
||||
* Catch2 testing library - see [github.com/catchorg/Catch2](https://github.com/catchorg/Catch2)
|
||||
* HDF5 library - see [github.com/HDFGroup/hdf5](https://github.com/HDFGroup/hdf5)
|
||||
* TIFF library - see [gitlab.com/libtiff/libtiff](https://gitlab.com/libtiff/libtiff)
|
||||
|
||||
For license check LICENSE file in respective directory
|
||||
Please follow the link provided above to check for LICENSE file. Building code with dependencies above requires access from the build system to github.com.
|
||||
|
||||
Directly included in the repository:
|
||||
* JSON parser/writer from N. Lohmann - see [github.com/nlohmann/json](https://github.com/nlohmann/json)
|
||||
* Catch2 testing library - see [github.com/catchorg/Catch2](https://github.com/catchorg/Catch2)
|
||||
* Xilinx arbitrary precision arithmetic headers - see [github.com/Xilinx/HLS_arbitrary_Precision_Types](https://github.com/Xilinx/HLS_arbitrary_Precision_Types)
|
||||
* Bitshuffle filter from K. Masui - see [github.com/kiyo-masui/bitshuffle](https://github.com/kiyo-masui/bitshuffle)
|
||||
* Fast replacement for Bitshuffle pre-compression filter (Kal Cutter, DECTRIS) - see [github.com/kalcutter/bitshuffle](https://github.com/kalcutter/bitshuffle)
|
||||
* Tinycbor (Intel) - see [github.com/intel/tinycbor](https://github.com/intel/tinycbor)
|
||||
* LZ4 compression by Y.Collet - see [github.com/lz4/lz4](https://github.com/lz4/lz4)
|
||||
* Spdlog logging library - see [github.com/gabime/spdlog](https://github.com/gabime/spdlog)
|
||||
* ZeroMQ library (through slsDetectorPackage) - see [github.com/zeromq/libzmq](https://github.com/zeromq/libzmq)
|
||||
@@ -68,15 +68,14 @@ For license check LICENSE file in respective directory
|
||||
### Software components
|
||||
|
||||
* `jfjoch_broker` in `broker` - main service running on the Jungfraujoch server, responsible for control of the detector and data acquisition;
|
||||
Example configuration `jfjoch_broker` for the modules is given in configuration files present in `etc` directory.
|
||||
Example configuration `jfjoch_broker` for the modules is given in configuration files present in `etc` directory. See [details](broker/README.md).
|
||||
* `jfjoch_writer` in `writer` - HDF5 writer; HDF5 writer is designed to work on the same or separate server system. It has rather limited requirements in terms of performance and memory.
|
||||
The goal is to separate data acquisition node with custom FPGA hardware and file system node with stronger security/stability requirements.
|
||||
The goal is to separate data acquisition node with custom FPGA hardware and file system node with stronger security/stability requirements. See [details](writer/README.md).
|
||||
|
||||
### Compilation
|
||||
Use the following commands:
|
||||
|
||||
```
|
||||
git submodule update --init --recursive
|
||||
mkdir build
|
||||
cd build
|
||||
cmake ..
|
||||
@@ -85,10 +84,9 @@ make jfjoch
|
||||
|
||||
### Compilation (writer only)
|
||||
In most use cases it is better to have a separate machine, with access to distributed file system, for writing.
|
||||
Such machine needs only a HDF5 writer service with less dependencies. For compilation use the following commands:
|
||||
Such machine needs only a HDF5 writer service with fewer dependencies. For compilation use the following commands:
|
||||
|
||||
```
|
||||
git submodule update --init --recursive
|
||||
mkdir build
|
||||
cd build
|
||||
cmake -DJFJOCH_WRITER_ONLY=ON ..
|
||||
@@ -96,8 +94,7 @@ make jfjoch
|
||||
```
|
||||
|
||||
## Versions
|
||||
**FPGA release** is as hexadecimal number indicted in the [jfjoch_fpga.h](fpga/pcie_driver/jfjoch_fpga.h) as JFJOCH_FPGA_RELEASE constant.
|
||||
It is also included in the name of FPGA firmware file (.mcs) and kernel driver archive. This number indicated breaking changes in the FPGA firmware interface.
|
||||
**FPGA release** is as hexadecimal number indicted in the [jfjoch_fpga.h](fpga/pcie_driver/jfjoch_fpga.h) as JFJOCH_FPGA_RELEASE constant. This number indicated breaking changes in the FPGA firmware interface.
|
||||
FPGA release has to be consistent between FPGA firmware, kernel driver and `jfjoch_broker` - both kernel driver and software won't work in case of version mismatch.
|
||||
Commits to `main` branch with the same FPGA release version are OK to mix between components.
|
||||
|
||||
@@ -113,7 +110,6 @@ Frontend is written in TypeScript. For details see [frontend_ui/](frontend_ui) d
|
||||
|
||||
Jungfraujoch Cmake scripts have an option to start frontend build with the following command:
|
||||
```
|
||||
git submodule update --init --recursive
|
||||
mkdir build
|
||||
cd build
|
||||
cmake ..
|
||||
@@ -123,25 +119,11 @@ Contrary to standard CMake way, frontend will be built in "source" `frontend_ui/
|
||||
|
||||
## Tests
|
||||
|
||||
Automated test routine is then accessible as `tests/CatchTest`. There are also benchmark routines:
|
||||
Automated test routine is then accessible as `tests/jfjoch_test`. There are also benchmark routines:
|
||||
|
||||
* `CompressionBenchmark` to measure compression bandwidth (single threaded)
|
||||
* `HDF5DatasetWriteTest` to measure HDF5 dataset writing speed (single threaded)
|
||||
* `jfjoch_spot_finding_test` to apply spot finding and indexing routines in Jungfraujoch to an example dataset - this is equivalent to FPGA spot finding algorithm, but NOT performance equivalent as it is particularly not-efficient
|
||||
* `jfjoch_action_test` to test quality/performance of FPGA card(s) and software routines
|
||||
|
||||
In addition, tests are executed to verify that datasets written by Jungfraujoch are readable with XDS Durin plugin, XDS Neggia plygin and CrystFEL.
|
||||
Input files for these programs are placed in `xds_durin`, `xds_neggia` and `crystfel` folders. See `.gitlab-ci.yml` for details.
|
||||
|
||||
## Resolution estimation
|
||||
|
||||
Resolution estimation can be done with a recent deep learning model by D. Mendez et al.
|
||||
(see [Acta Cryst D, 80, 26-43](https://doi.org/10.1107/S2059798323010586)), adapted to Jungfraujoch.
|
||||
Model used in the original paper is located in the [resonet/](resonet) directory, after converting to TorchScript format.
|
||||
|
||||
To use the feature it is necessary to install [libtorch](https://pytorch.org/) library, preferably in `/opt/libtorch` location. The C++11 ABI version needs to be chosen.
|
||||
For RHEL 8 systems, please download older version 2.1.0, as version 2.2.0 requires newer `glibc` library than available with the operating system.
|
||||
Version 2.1.0 can be downloaded with the following command:
|
||||
```
|
||||
wget https://download.pytorch.org/libtorch/cu121/libtorch-cxx11-abi-shared-with-deps-2.1.0%2Bcu121.zip
|
||||
```
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
AUX_SOURCE_DIRECTORY(gen/model MODEL_SOURCES)
|
||||
|
||||
ADD_LIBRARY(JFJochAPI STATIC ${MODEL_SOURCES} gen/api/DefaultApi.cpp gen/api/DefaultApi.h)
|
||||
|
||||
TARGET_LINK_LIBRARIES(JFJochAPI pistache_static)
|
||||
@@ -14,6 +15,6 @@ TARGET_LINK_LIBRARIES(JFJochBroker JFJochReceiver JFJochDetector JFJochCommon JF
|
||||
ADD_EXECUTABLE(jfjoch_broker jfjoch_broker.cpp)
|
||||
TARGET_LINK_LIBRARIES(jfjoch_broker JFJochBroker)
|
||||
|
||||
INSTALL(TARGETS jfjoch_broker RUNTIME)
|
||||
|
||||
INSTALL(TARGETS jfjoch_broker RUNTIME COMPONENT jfjoch)
|
||||
|
||||
INSTALL(FILES redoc-static.html DESTINATION jfjoch/frontend COMPONENT jfjoch )
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include <nlohmann/json.hpp>
|
||||
#include "JFJochBrokerHttp.h"
|
||||
#include "gen/model/Error_message.h"
|
||||
#include "../preview/JFJochTIFF.h"
|
||||
|
||||
// From https://en.cppreference.com/w/cpp/string/byte/tolower
|
||||
inline std::string str_tolower(std::string s) {
|
||||
@@ -22,6 +23,10 @@ inline SpotFindingSettings Convert(const org::openapitools::server::model::Spot_
|
||||
ret.enable = input.isEnable();
|
||||
ret.indexing = input.isIndexing();
|
||||
ret.indexing_tolerance = input.getIndexingTolerance();
|
||||
if (input.filterPowderRingsIsSet())
|
||||
ret.filter_spots_powder_ring = input.isFilterPowderRings();
|
||||
if (input.minSpotCountPowderRingIsSet())
|
||||
ret.min_spot_count_powder_ring = input.getMinSpotCountPowderRing();
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -36,6 +41,8 @@ inline org::openapitools::server::model::Spot_finding_settings Convert(const Spo
|
||||
ret.setEnable(input.enable);
|
||||
ret.setIndexing(input.indexing);
|
||||
ret.setIndexingTolerance(input.indexing_tolerance);
|
||||
ret.setFilterPowderRings(input.filter_spots_powder_ring);
|
||||
ret.setMinSpotCountPowderRing(input.min_spot_count_powder_ring);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -67,6 +74,7 @@ inline org::openapitools::server::model::Measurement_statistics Convert(const Me
|
||||
|
||||
if (input.bkg_estimate)
|
||||
ret.setBkgEstimate(input.bkg_estimate.value());
|
||||
ret.setUnitCell(input.unit_cell);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -316,6 +324,9 @@ inline PreviewJPEGSettings Convert(const org::openapitools::server::model::Previ
|
||||
ret.saturation_value = input.getSaturation();
|
||||
ret.show_roi = input.isShowRoi();
|
||||
ret.show_indexed = input.isShowIndexed();
|
||||
ret.show_user_mask = input.isShowUserMask();
|
||||
if (input.resolutionRingIsSet())
|
||||
ret.resolution_ring = input.getResolutionRing();
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -649,25 +660,36 @@ void JFJochBrokerHttp::preview_image_tiff_get(Pistache::Http::ResponseWriter &re
|
||||
response.send(Pistache::Http::Code::Not_Found);
|
||||
}
|
||||
|
||||
void JFJochBrokerHttp::plot_resolution_estimate_histogram_get(Pistache::Http::ResponseWriter &response) {
|
||||
GenericPlot(PlotType::ResEstimation, 0, response);
|
||||
}
|
||||
|
||||
void JFJochBrokerHttp::config_internal_generator_image_put(const Pistache::Rest::Request &request,
|
||||
Pistache::Http::ResponseWriter &response) {
|
||||
int64_t image_number = 0;
|
||||
auto number_query = request.query().get("number");
|
||||
auto number_query = request.query().get("id");
|
||||
if (number_query)
|
||||
image_number = std::stoi(number_query.value());
|
||||
|
||||
if ((image_number < 0) || (image_number > 127))
|
||||
throw JFJochException(JFJochExceptionCategory::InputParameterInvalid, "image_number must be in range 0-127");
|
||||
throw JFJochException(JFJochExceptionCategory::InputParameterInvalid, "id must be in range 0-127");
|
||||
|
||||
state_machine.LoadInternalGeneratorImage(request.body().data(), request.body().size(), image_number);
|
||||
logger.Info("Internal generator image #{} loaded", image_number);
|
||||
response.send(Pistache::Http::Code::Ok);
|
||||
}
|
||||
|
||||
|
||||
void JFJochBrokerHttp::config_internal_generator_image_tiff_put(const Pistache::Rest::Request &request,
|
||||
Pistache::Http::ResponseWriter &response) {
|
||||
int64_t image_number = 0;
|
||||
auto number_query = request.query().get("id");
|
||||
if (number_query)
|
||||
image_number = std::stoi(number_query.value());
|
||||
|
||||
if ((image_number < 0) || (image_number > 127))
|
||||
throw JFJochException(JFJochExceptionCategory::InputParameterInvalid, "id must be in range 0-127");
|
||||
|
||||
state_machine.LoadInternalGeneratorImageTIFF(request.body(), image_number);
|
||||
response.send(Pistache::Http::Code::Ok);
|
||||
}
|
||||
|
||||
void JFJochBrokerHttp::roi_box_get(Pistache::Http::ResponseWriter &response) {
|
||||
ProcessOutput(Convert(state_machine.GetBoxROI()), response);
|
||||
}
|
||||
@@ -783,3 +805,19 @@ void JFJochBrokerHttp::plot_strong_pixel_get(const std::optional<int32_t> &binni
|
||||
Pistache::Http::ResponseWriter &response) {
|
||||
GenericPlot(PlotType::StrongPixels, binning, response);
|
||||
}
|
||||
|
||||
void JFJochBrokerHttp::config_mask_tiff_get(Pistache::Http::ResponseWriter &response) {
|
||||
std::string s = state_machine.GetFullPixelMaskTIFF();
|
||||
response.send(Pistache::Http::Code::Ok, s, Pistache::Http::Mime::MediaType::fromString("image/tiff"));
|
||||
}
|
||||
|
||||
void JFJochBrokerHttp::config_user_mask_tiff_get(Pistache::Http::ResponseWriter &response) {
|
||||
std::string s = state_machine.GetUserPixelMaskTIFF();
|
||||
response.send(Pistache::Http::Code::Ok, s, Pistache::Http::Mime::MediaType::fromString("image/tiff"));
|
||||
}
|
||||
|
||||
void JFJochBrokerHttp::config_user_mask_tiff_put(const Pistache::Rest::Request &request,
|
||||
Pistache::Http::ResponseWriter &response) {
|
||||
state_machine.SetUserPixelMask(request.body());
|
||||
response.send(Pistache::Http::Code::Ok);
|
||||
}
|
||||
|
||||
@@ -7,11 +7,12 @@
|
||||
#include <pistache/endpoint.h>
|
||||
#include <pistache/router.h>
|
||||
#include <pistache/client.h>
|
||||
#include <pistache/http.h>
|
||||
|
||||
#include "../common/Logger.h"
|
||||
#include "JFJochStateMachine.h"
|
||||
#include "gen/api/DefaultApi.h"
|
||||
#include "pistache/include/pistache/http.h"
|
||||
|
||||
|
||||
class JFJochBrokerHttp : public org::openapitools::server::api::DefaultApi {
|
||||
Logger logger{"JFJochBroker"};
|
||||
@@ -74,8 +75,6 @@ class JFJochBrokerHttp : public org::openapitools::server::api::DefaultApi {
|
||||
|
||||
void plot_rad_int_per_file_get(Pistache::Http::ResponseWriter &response) override;
|
||||
|
||||
void plot_resolution_estimate_histogram_get(Pistache::Http::ResponseWriter &response) override;
|
||||
|
||||
void statistics_calibration_get(Pistache::Http::ResponseWriter &response) override;
|
||||
|
||||
void statistics_data_collection_get(Pistache::Http::ResponseWriter &response) override;
|
||||
@@ -119,6 +118,16 @@ class JFJochBrokerHttp : public org::openapitools::server::api::DefaultApi {
|
||||
void xfel_event_code_get(Pistache::Http::ResponseWriter &response) override;
|
||||
void xfel_pulse_id_get(Pistache::Http::ResponseWriter &response) override;
|
||||
|
||||
void config_mask_tiff_get(Pistache::Http::ResponseWriter &response) override;
|
||||
|
||||
void config_user_mask_tiff_get(Pistache::Http::ResponseWriter &response) override;
|
||||
|
||||
void config_user_mask_tiff_put(const Pistache::Rest::Request &request,
|
||||
Pistache::Http::ResponseWriter &response) override;
|
||||
|
||||
void config_internal_generator_image_tiff_put(const Pistache::Rest::Request &request,
|
||||
Pistache::Http::ResponseWriter &response) override;
|
||||
|
||||
void GetStaticFile(const Pistache::Rest::Request &request, Pistache::Http::ResponseWriter response);
|
||||
std::pair<Pistache::Http::Code, std::string> handleOperationException(const std::exception &ex) const noexcept override;
|
||||
|
||||
|
||||
@@ -319,7 +319,6 @@ void ParseFacilityConfiguration(const nlohmann::json &input, const std::string&
|
||||
"omega_axis must be float array of 3");
|
||||
}
|
||||
|
||||
experiment.NeuralNetModelPath(GET_STR(j, "neural_net_model", ""));
|
||||
if (j.contains("pedestal_g0_frames"))
|
||||
experiment.PedestalG0Frames(GET_I64(j, "pedestal_g0_frames"));
|
||||
if (j.contains("pedestal_g1_frames"))
|
||||
|
||||
@@ -5,15 +5,17 @@
|
||||
|
||||
JFJochServices::JFJochServices(Logger &in_logger) : logger(in_logger) {}
|
||||
|
||||
void JFJochServices::Start(const DiffractionExperiment& experiment, const JFCalibration &calibration) {
|
||||
void JFJochServices::Start(const DiffractionExperiment& experiment,
|
||||
const PixelMask &pixel_mask,
|
||||
const JFCalibration &calibration) {
|
||||
logger.Info("Measurement start for: {}", experiment.GetFilePrefix());
|
||||
|
||||
if (receiver != nullptr) {
|
||||
logger.Info(" ... receiver start");
|
||||
if (experiment.GetDetectorMode() == DetectorMode::Conversion)
|
||||
receiver->Start(experiment, &calibration);
|
||||
receiver->Start(experiment, pixel_mask, &calibration);
|
||||
else
|
||||
receiver->Start(experiment, nullptr);
|
||||
receiver->Start(experiment, pixel_mask, nullptr);
|
||||
|
||||
if (detector && !experiment.IsUsingInternalPacketGen()) {
|
||||
logger.Info(" ... detector start");
|
||||
|
||||
@@ -23,7 +23,9 @@ public:
|
||||
void On(const DiffractionExperiment& experiment);
|
||||
void Off();
|
||||
void ConfigureDetector(const DiffractionExperiment& experiment);
|
||||
void Start(const DiffractionExperiment& experiment, const JFCalibration &calibration);
|
||||
void Start(const DiffractionExperiment& experiment,
|
||||
const PixelMask &pixel_mask,
|
||||
const JFCalibration &calibration);
|
||||
JFJochServicesOutput Stop();
|
||||
void Cancel();
|
||||
void Trigger();
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
#include <thread>
|
||||
|
||||
#include "JFJochStateMachine.h"
|
||||
#include "../preview/WriteTIFF.h"
|
||||
#include "../preview/JFJochTIFF.h"
|
||||
|
||||
void ApplyDetectorSettings(DiffractionExperiment& experiment, const DetectorSettings &settings) {
|
||||
auto tmp = experiment;
|
||||
@@ -66,8 +66,10 @@ void ApplyRadialIntegrationSettings(DiffractionExperiment& experiment, const Rad
|
||||
}
|
||||
|
||||
JFJochStateMachine::JFJochStateMachine(JFJochServices &in_services, Logger &in_logger)
|
||||
: services(in_services), logger(in_logger),
|
||||
data_processing_settings(DiffractionExperiment::DefaultDataProcessingSettings()) {
|
||||
: services(in_services),
|
||||
logger(in_logger),
|
||||
data_processing_settings(DiffractionExperiment::DefaultDataProcessingSettings()),
|
||||
pixel_mask(experiment) {
|
||||
|
||||
}
|
||||
|
||||
@@ -126,6 +128,7 @@ void JFJochStateMachine::TakePedestalInternalAll(std::unique_lock<std::mutex> &u
|
||||
}
|
||||
}
|
||||
services.ConfigureDetector(experiment);
|
||||
pixel_mask.LoadDetectorBadPixelMask(calibration->CalculateMask());
|
||||
} catch (const std::exception &e) {
|
||||
logger.Error("Pedestal sequence error {}", e.what());
|
||||
state = JFJochState::Error;
|
||||
@@ -158,7 +161,7 @@ void JFJochStateMachine::TakePedestalInternalG0(std::unique_lock<std::mutex> &ul
|
||||
|
||||
state = JFJochState::Pedestal;
|
||||
services.ConfigureDetector(local_experiment);
|
||||
services.Start(local_experiment, *calibration);
|
||||
services.Start(local_experiment, pixel_mask, *calibration);
|
||||
|
||||
services.Trigger();
|
||||
|
||||
@@ -197,7 +200,7 @@ void JFJochStateMachine::TakePedestalInternalG1(std::unique_lock<std::mutex> &ul
|
||||
|
||||
state = JFJochState::Pedestal;
|
||||
services.ConfigureDetector(local_experiment);
|
||||
services.Start(local_experiment, *calibration);
|
||||
services.Start(local_experiment, pixel_mask, *calibration);
|
||||
|
||||
services.Trigger();
|
||||
|
||||
@@ -236,7 +239,7 @@ void JFJochStateMachine::TakePedestalInternalG2(std::unique_lock<std::mutex> &ul
|
||||
|
||||
state = JFJochState::Pedestal;
|
||||
services.ConfigureDetector(local_experiment);
|
||||
services.Start(local_experiment, *calibration);
|
||||
services.Start(local_experiment, pixel_mask, *calibration);
|
||||
|
||||
services.Trigger();
|
||||
|
||||
@@ -326,7 +329,7 @@ void JFJochStateMachine::Start(const DatasetSettings& settings) {
|
||||
try {
|
||||
state = JFJochState::Busy;
|
||||
services.SetSpotFindingSettings(GetSpotFindingSettings());
|
||||
services.Start(experiment, *calibration);
|
||||
services.Start(experiment, pixel_mask, *calibration);
|
||||
|
||||
state = JFJochState::Measuring;
|
||||
measurement = std::async(std::launch::async, &JFJochStateMachine::MeasurementThread, this);
|
||||
@@ -402,6 +405,8 @@ void JFJochStateMachine::SetFullMeasurementOutput(const JFJochServicesOutput &ou
|
||||
tmp.detector_height = experiment.GetYPixelsNum();
|
||||
tmp.detector_pixel_depth = experiment.GetPixelDepth();
|
||||
tmp.images_expected = experiment.GetImageNum();
|
||||
tmp.unit_cell = experiment.GetUnitCellString();
|
||||
|
||||
|
||||
tmp.compression_ratio = output.receiver_output.status.compressed_ratio;
|
||||
tmp.collection_efficiency = output.receiver_output.efficiency;
|
||||
@@ -426,6 +431,8 @@ void JFJochStateMachine::ClearAndSetMeasurementStatistics() {
|
||||
tmp.detector_width = experiment.GetYPixelsNum();
|
||||
tmp.detector_pixel_depth = experiment.GetPixelDepth();
|
||||
tmp.images_expected = experiment.GetImageNum();
|
||||
tmp.unit_cell = experiment.GetUnitCellString();
|
||||
|
||||
measurement_statistics = tmp;
|
||||
}
|
||||
|
||||
@@ -445,6 +452,7 @@ std::optional<MeasurementStatistics> JFJochStateMachine::GetMeasurementStatistic
|
||||
tmp.detector_height = experiment.GetYPixelsNum();
|
||||
tmp.detector_pixel_depth = experiment.GetPixelDepth();
|
||||
tmp.images_expected = experiment.GetImageNum();
|
||||
tmp.unit_cell = experiment.GetUnitCellString();
|
||||
|
||||
tmp.compression_ratio = rcv_status->compressed_ratio;
|
||||
tmp.images_collected = rcv_status->images_collected;
|
||||
@@ -557,6 +565,7 @@ void JFJochStateMachine::AddDetectorSetup(const DetectorSetup &setup) {
|
||||
experiment.Detector(setup);
|
||||
gain_calibration = setup.GetGainCalibration();
|
||||
current_detector_setup = 0;
|
||||
pixel_mask = PixelMask(setup);
|
||||
}
|
||||
detector_setup.emplace_back(setup);
|
||||
}
|
||||
@@ -594,6 +603,7 @@ void JFJochStateMachine::SelectDetector(int64_t id) {
|
||||
try {
|
||||
experiment.Detector(detector_setup[id]);
|
||||
gain_calibration = detector_setup[id].GetGainCalibration();
|
||||
pixel_mask = PixelMask(detector_setup[id]);
|
||||
state = JFJochState::Inactive;
|
||||
current_detector_setup = id;
|
||||
} catch (JFJochException &e) {
|
||||
@@ -700,6 +710,21 @@ void JFJochStateMachine::LoadInternalGeneratorImage(const void *data, size_t siz
|
||||
services.LoadInternalGeneratorImage(experiment, image, image_number);
|
||||
}
|
||||
|
||||
void JFJochStateMachine::LoadInternalGeneratorImageTIFF(const std::string &s, uint64_t image_number) {
|
||||
std::unique_lock<std::mutex> ul(m);
|
||||
|
||||
if (state != JFJochState::Idle)
|
||||
throw WrongDAQStateException ("Can change internal generator image only when detector in Idle state");
|
||||
|
||||
uint32_t cols, lines;
|
||||
auto v = ReadTIFFFromString16(s, cols, lines);
|
||||
if (((cols == experiment.GetXPixelsNum()) && (lines == experiment.GetYPixelsNum()))
|
||||
|| ((cols == RAW_MODULE_SIZE) && (lines == RAW_MODULE_LINES * experiment.GetModulesNum())))
|
||||
services.LoadInternalGeneratorImage(experiment, v, image_number);
|
||||
else
|
||||
throw JFJochException(JFJochExceptionCategory::InputParameterInvalid, "Image size doesn't match current detector");
|
||||
}
|
||||
|
||||
void JFJochStateMachine::SetBoxROI(const std::vector<ROIBox> &input) {
|
||||
std::unique_lock<std::mutex> ul(m);
|
||||
|
||||
@@ -739,3 +764,33 @@ std::vector<uint64_t> JFJochStateMachine::GetXFELEventCode() const {
|
||||
services.GetXFELEventCode(ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::string JFJochStateMachine::GetFullPixelMaskTIFF() const {
|
||||
std::unique_lock<std::mutex> ul(m);
|
||||
std::vector v = pixel_mask.GetMask(experiment);
|
||||
return WriteTIFFToString(v.data(), experiment.GetXPixelsNum(), experiment.GetYPixelsNum(),
|
||||
sizeof(uint32_t), false);
|
||||
}
|
||||
|
||||
std::string JFJochStateMachine::GetUserPixelMaskTIFF() const {
|
||||
std::unique_lock<std::mutex> ul(m);
|
||||
std::vector v = pixel_mask.GetUserMask(experiment);
|
||||
return WriteTIFFToString(v.data(), experiment.GetXPixelsNum(), experiment.GetYPixelsNum(),
|
||||
sizeof(uint32_t), false);
|
||||
}
|
||||
|
||||
void JFJochStateMachine::SetUserPixelMask(const std::string &s) {
|
||||
std::unique_lock<std::mutex> ul(m);
|
||||
|
||||
if (state != JFJochState::Idle)
|
||||
throw WrongDAQStateException ("User mask can be only modified in Idle state");
|
||||
|
||||
try {
|
||||
uint32_t cols, lines;
|
||||
auto v = ReadTIFFFromString32(s, cols, lines);
|
||||
pixel_mask.LoadUserMask(experiment, v);
|
||||
} catch (const JFJochException &e) {
|
||||
throw JFJochException(JFJochExceptionCategory::InputParameterInvalid,
|
||||
"Problem handling user mask " + std::string(e.what()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -56,6 +56,8 @@ struct MeasurementStatistics {
|
||||
|
||||
std::optional<float> bkg_estimate;
|
||||
std::optional<std::pair<float, float>> beam_center_drift_pxl;
|
||||
|
||||
std::string unit_cell;
|
||||
};
|
||||
|
||||
struct DetectorSettings {
|
||||
@@ -96,6 +98,8 @@ class JFJochStateMachine {
|
||||
volatile JFJochState state = JFJochState::Inactive;
|
||||
volatile bool cancel_sequence = false;
|
||||
std::unique_ptr<JFCalibration> calibration;
|
||||
PixelMask pixel_mask;
|
||||
|
||||
std::vector<JFModuleGainCalibration> gain_calibration;
|
||||
std::vector<DetectorSetup> detector_setup;
|
||||
int64_t current_detector_setup;
|
||||
@@ -170,6 +174,7 @@ public:
|
||||
std::string GetPedestalTIFF(size_t gain_level, size_t sc) const;
|
||||
|
||||
void LoadInternalGeneratorImage(const void *data, size_t size, uint64_t image_number);
|
||||
void LoadInternalGeneratorImageTIFF(const std::string &s, uint64_t image_number);
|
||||
|
||||
// Not thread safe - only for configuration in serial context
|
||||
DiffractionExperiment& NotThreadSafe_Experiment();
|
||||
@@ -185,6 +190,10 @@ public:
|
||||
|
||||
std::vector<uint64_t> GetXFELPulseID() const;
|
||||
std::vector<uint64_t> GetXFELEventCode() const;
|
||||
|
||||
std::string GetFullPixelMaskTIFF() const;
|
||||
std::string GetUserPixelMaskTIFF() const;
|
||||
void SetUserPixelMask(const std::string &v);
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -15,11 +15,16 @@ Till this happens, it is recommended to go through example files in the [etc/](.
|
||||
## Setting up a local test for Jungfraujoch
|
||||
For development, it is possible to setup a local installation of Jungfraujoch.
|
||||
This will work without FPGA installed in the computer and allows to test Jungfraujoch software layer, including
|
||||
ZeroMQ streaming and file writing. There are few necessary steps:
|
||||
ZeroMQ streaming and file writing.
|
||||
|
||||
The workflow simulates FPGA behavior, by running high-level synthesis code on the CPU - the performance is therefore
|
||||
very low, as fixed-point calculations have large performance penalty on CPU. In the CPU simulation mode, one can simulate
|
||||
using only a single FPGA device.
|
||||
|
||||
To run the test:
|
||||
|
||||
### Compile Jungfraujoch with frontend
|
||||
```
|
||||
git submodule update --init --recursive
|
||||
mkdir build
|
||||
cd build
|
||||
cmake ..
|
||||
@@ -38,6 +43,7 @@ Start writer:
|
||||
cd build/writer
|
||||
./jfjoch_writer tcp://127.0.0.1:5500
|
||||
```
|
||||
|
||||
### Run tests
|
||||
To run test a Python script is provided:
|
||||
```
|
||||
@@ -45,3 +51,7 @@ cd tests/test_data
|
||||
python jfjoch_broker_test.py
|
||||
```
|
||||
The script will initialize Jungfraujoch, import test image and start data collection.
|
||||
|
||||
### Expected result
|
||||
You can observe online data analysis by opening the following web page: [http://localhost:5232](http://localhost:5232).
|
||||
Also in the `build/writer` subdirectory a dataset with images should be written.
|
||||
|
||||
@@ -37,12 +37,16 @@ void DefaultApi::setupRoutes() {
|
||||
Routes::Get(*router, base + "/config/detector", Routes::bind(&DefaultApi::config_detector_get_handler, this));
|
||||
Routes::Put(*router, base + "/config/detector", Routes::bind(&DefaultApi::config_detector_put_handler, this));
|
||||
Routes::Put(*router, base + "/config/internal_generator_image", Routes::bind(&DefaultApi::config_internal_generator_image_put_handler, this));
|
||||
Routes::Put(*router, base + "/config/internal_generator_image.tiff", Routes::bind(&DefaultApi::config_internal_generator_image_tiff_put_handler, this));
|
||||
Routes::Get(*router, base + "/config/mask.tiff", Routes::bind(&DefaultApi::config_mask_tiff_get_handler, this));
|
||||
Routes::Get(*router, base + "/config/rad_int", Routes::bind(&DefaultApi::config_rad_int_get_handler, this));
|
||||
Routes::Put(*router, base + "/config/rad_int", Routes::bind(&DefaultApi::config_rad_int_put_handler, this));
|
||||
Routes::Get(*router, base + "/config/select_detector", Routes::bind(&DefaultApi::config_select_detector_get_handler, this));
|
||||
Routes::Put(*router, base + "/config/select_detector", Routes::bind(&DefaultApi::config_select_detector_put_handler, this));
|
||||
Routes::Get(*router, base + "/config/spot_finding", Routes::bind(&DefaultApi::config_spot_finding_get_handler, this));
|
||||
Routes::Put(*router, base + "/config/spot_finding", Routes::bind(&DefaultApi::config_spot_finding_put_handler, this));
|
||||
Routes::Get(*router, base + "/config/user_mask.tiff", Routes::bind(&DefaultApi::config_user_mask_tiff_get_handler, this));
|
||||
Routes::Put(*router, base + "/config/user_mask.tiff", Routes::bind(&DefaultApi::config_user_mask_tiff_put_handler, this));
|
||||
Routes::Post(*router, base + "/deactivate", Routes::bind(&DefaultApi::deactivate_post_handler, this));
|
||||
Routes::Get(*router, base + "/detector/status", Routes::bind(&DefaultApi::detector_status_get_handler, this));
|
||||
Routes::Post(*router, base + "/initialize", Routes::bind(&DefaultApi::initialize_post_handler, this));
|
||||
@@ -56,7 +60,6 @@ void DefaultApi::setupRoutes() {
|
||||
Routes::Get(*router, base + "/plot/rad_int_per_file", Routes::bind(&DefaultApi::plot_rad_int_per_file_get_handler, this));
|
||||
Routes::Get(*router, base + "/plot/receiver_delay", Routes::bind(&DefaultApi::plot_receiver_delay_get_handler, this));
|
||||
Routes::Get(*router, base + "/plot/receiver_free_send_buffers", Routes::bind(&DefaultApi::plot_receiver_free_send_buffers_get_handler, this));
|
||||
Routes::Get(*router, base + "/plot/resolution_estimate_histogram", Routes::bind(&DefaultApi::plot_resolution_estimate_histogram_get_handler, this));
|
||||
Routes::Get(*router, base + "/plot/roi_max_count", Routes::bind(&DefaultApi::plot_roi_max_count_get_handler, this));
|
||||
Routes::Get(*router, base + "/plot/roi_sum", Routes::bind(&DefaultApi::plot_roi_sum_get_handler, this));
|
||||
Routes::Get(*router, base + "/plot/roi_valid_pixels", Routes::bind(&DefaultApi::plot_roi_valid_pixels_get_handler, this));
|
||||
@@ -193,6 +196,45 @@ void DefaultApi::config_internal_generator_image_put_handler(const Pistache::Res
|
||||
response.send(Pistache::Http::Code::Internal_Server_Error, e.what());
|
||||
}
|
||||
|
||||
}
|
||||
void DefaultApi::config_internal_generator_image_tiff_put_handler(const Pistache::Rest::Request &request, Pistache::Http::ResponseWriter response) {
|
||||
try {
|
||||
|
||||
try {
|
||||
this->config_internal_generator_image_tiff_put(request, response);
|
||||
} catch (Pistache::Http::HttpError &e) {
|
||||
response.send(static_cast<Pistache::Http::Code>(e.code()), e.what());
|
||||
return;
|
||||
} catch (std::exception &e) {
|
||||
const std::pair<Pistache::Http::Code, std::string> errorInfo = this->handleOperationException(e);
|
||||
response.send(errorInfo.first, errorInfo.second);
|
||||
return;
|
||||
}
|
||||
|
||||
} catch (std::exception &e) {
|
||||
response.send(Pistache::Http::Code::Internal_Server_Error, e.what());
|
||||
}
|
||||
|
||||
}
|
||||
void DefaultApi::config_mask_tiff_get_handler(const Pistache::Rest::Request &, Pistache::Http::ResponseWriter response) {
|
||||
try {
|
||||
|
||||
|
||||
try {
|
||||
this->config_mask_tiff_get(response);
|
||||
} catch (Pistache::Http::HttpError &e) {
|
||||
response.send(static_cast<Pistache::Http::Code>(e.code()), e.what());
|
||||
return;
|
||||
} catch (std::exception &e) {
|
||||
const std::pair<Pistache::Http::Code, std::string> errorInfo = this->handleOperationException(e);
|
||||
response.send(errorInfo.first, errorInfo.second);
|
||||
return;
|
||||
}
|
||||
|
||||
} catch (std::exception &e) {
|
||||
response.send(Pistache::Http::Code::Internal_Server_Error, e.what());
|
||||
}
|
||||
|
||||
}
|
||||
void DefaultApi::config_rad_int_get_handler(const Pistache::Rest::Request &, Pistache::Http::ResponseWriter response) {
|
||||
try {
|
||||
@@ -352,6 +394,45 @@ void DefaultApi::config_spot_finding_put_handler(const Pistache::Rest::Request &
|
||||
response.send(Pistache::Http::Code::Internal_Server_Error, e.what());
|
||||
}
|
||||
|
||||
}
|
||||
void DefaultApi::config_user_mask_tiff_get_handler(const Pistache::Rest::Request &, Pistache::Http::ResponseWriter response) {
|
||||
try {
|
||||
|
||||
|
||||
try {
|
||||
this->config_user_mask_tiff_get(response);
|
||||
} catch (Pistache::Http::HttpError &e) {
|
||||
response.send(static_cast<Pistache::Http::Code>(e.code()), e.what());
|
||||
return;
|
||||
} catch (std::exception &e) {
|
||||
const std::pair<Pistache::Http::Code, std::string> errorInfo = this->handleOperationException(e);
|
||||
response.send(errorInfo.first, errorInfo.second);
|
||||
return;
|
||||
}
|
||||
|
||||
} catch (std::exception &e) {
|
||||
response.send(Pistache::Http::Code::Internal_Server_Error, e.what());
|
||||
}
|
||||
|
||||
}
|
||||
void DefaultApi::config_user_mask_tiff_put_handler(const Pistache::Rest::Request &request, Pistache::Http::ResponseWriter response) {
|
||||
try {
|
||||
|
||||
try {
|
||||
this->config_user_mask_tiff_put(request, response);
|
||||
} catch (Pistache::Http::HttpError &e) {
|
||||
response.send(static_cast<Pistache::Http::Code>(e.code()), e.what());
|
||||
return;
|
||||
} catch (std::exception &e) {
|
||||
const std::pair<Pistache::Http::Code, std::string> errorInfo = this->handleOperationException(e);
|
||||
response.send(errorInfo.first, errorInfo.second);
|
||||
return;
|
||||
}
|
||||
|
||||
} catch (std::exception &e) {
|
||||
response.send(Pistache::Http::Code::Internal_Server_Error, e.what());
|
||||
}
|
||||
|
||||
}
|
||||
void DefaultApi::deactivate_post_handler(const Pistache::Rest::Request &, Pistache::Http::ResponseWriter response) {
|
||||
try {
|
||||
@@ -672,26 +753,6 @@ void DefaultApi::plot_receiver_free_send_buffers_get_handler(const Pistache::Res
|
||||
response.send(Pistache::Http::Code::Internal_Server_Error, e.what());
|
||||
}
|
||||
|
||||
}
|
||||
void DefaultApi::plot_resolution_estimate_histogram_get_handler(const Pistache::Rest::Request &, Pistache::Http::ResponseWriter response) {
|
||||
try {
|
||||
|
||||
|
||||
try {
|
||||
this->plot_resolution_estimate_histogram_get(response);
|
||||
} catch (Pistache::Http::HttpError &e) {
|
||||
response.send(static_cast<Pistache::Http::Code>(e.code()), e.what());
|
||||
return;
|
||||
} catch (std::exception &e) {
|
||||
const std::pair<Pistache::Http::Code, std::string> errorInfo = this->handleOperationException(e);
|
||||
response.send(errorInfo.first, errorInfo.second);
|
||||
return;
|
||||
}
|
||||
|
||||
} catch (std::exception &e) {
|
||||
response.send(Pistache::Http::Code::Internal_Server_Error, e.what());
|
||||
}
|
||||
|
||||
}
|
||||
void DefaultApi::plot_roi_max_count_get_handler(const Pistache::Rest::Request &request, Pistache::Http::ResponseWriter response) {
|
||||
try {
|
||||
|
||||
@@ -61,12 +61,16 @@ private:
|
||||
void config_detector_get_handler(const Pistache::Rest::Request &request, Pistache::Http::ResponseWriter response);
|
||||
void config_detector_put_handler(const Pistache::Rest::Request &request, Pistache::Http::ResponseWriter response);
|
||||
void config_internal_generator_image_put_handler(const Pistache::Rest::Request &request, Pistache::Http::ResponseWriter response);
|
||||
void config_internal_generator_image_tiff_put_handler(const Pistache::Rest::Request &request, Pistache::Http::ResponseWriter response);
|
||||
void config_mask_tiff_get_handler(const Pistache::Rest::Request &request, Pistache::Http::ResponseWriter response);
|
||||
void config_rad_int_get_handler(const Pistache::Rest::Request &request, Pistache::Http::ResponseWriter response);
|
||||
void config_rad_int_put_handler(const Pistache::Rest::Request &request, Pistache::Http::ResponseWriter response);
|
||||
void config_select_detector_get_handler(const Pistache::Rest::Request &request, Pistache::Http::ResponseWriter response);
|
||||
void config_select_detector_put_handler(const Pistache::Rest::Request &request, Pistache::Http::ResponseWriter response);
|
||||
void config_spot_finding_get_handler(const Pistache::Rest::Request &request, Pistache::Http::ResponseWriter response);
|
||||
void config_spot_finding_put_handler(const Pistache::Rest::Request &request, Pistache::Http::ResponseWriter response);
|
||||
void config_user_mask_tiff_get_handler(const Pistache::Rest::Request &request, Pistache::Http::ResponseWriter response);
|
||||
void config_user_mask_tiff_put_handler(const Pistache::Rest::Request &request, Pistache::Http::ResponseWriter response);
|
||||
void deactivate_post_handler(const Pistache::Rest::Request &request, Pistache::Http::ResponseWriter response);
|
||||
void detector_status_get_handler(const Pistache::Rest::Request &request, Pistache::Http::ResponseWriter response);
|
||||
void initialize_post_handler(const Pistache::Rest::Request &request, Pistache::Http::ResponseWriter response);
|
||||
@@ -80,7 +84,6 @@ private:
|
||||
void plot_rad_int_per_file_get_handler(const Pistache::Rest::Request &request, Pistache::Http::ResponseWriter response);
|
||||
void plot_receiver_delay_get_handler(const Pistache::Rest::Request &request, Pistache::Http::ResponseWriter response);
|
||||
void plot_receiver_free_send_buffers_get_handler(const Pistache::Rest::Request &request, Pistache::Http::ResponseWriter response);
|
||||
void plot_resolution_estimate_histogram_get_handler(const Pistache::Rest::Request &request, Pistache::Http::ResponseWriter response);
|
||||
void plot_roi_max_count_get_handler(const Pistache::Rest::Request &request, Pistache::Http::ResponseWriter response);
|
||||
void plot_roi_sum_get_handler(const Pistache::Rest::Request &request, Pistache::Http::ResponseWriter response);
|
||||
void plot_roi_valid_pixels_get_handler(const Pistache::Rest::Request &request, Pistache::Http::ResponseWriter response);
|
||||
@@ -151,6 +154,20 @@ private:
|
||||
/// </remarks>
|
||||
virtual void config_internal_generator_image_put(const Pistache::Rest::Request &request, Pistache::Http::ResponseWriter &response) = 0;
|
||||
/// <summary>
|
||||
/// Load TIFF image for internal FPGA generator
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Load image for internal FPGA generator. This can only happen in Idle state of the detector. Requires TIFF with 16-bit integer numbers of size of detector in raw/converted coordinates (depending on detector settings).
|
||||
/// </remarks>
|
||||
virtual void config_internal_generator_image_tiff_put(const Pistache::Rest::Request &request, Pistache::Http::ResponseWriter &response) = 0;
|
||||
/// <summary>
|
||||
/// Get mask of the detector
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Get full pixel mask of the detector See NXmx standard for meaning of pixel values
|
||||
/// </remarks>
|
||||
virtual void config_mask_tiff_get(Pistache::Http::ResponseWriter &response) = 0;
|
||||
/// <summary>
|
||||
/// Get radial integration configuration
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
@@ -196,6 +213,20 @@ private:
|
||||
/// <param name="spotFindingSettings"> (optional)</param>
|
||||
virtual void config_spot_finding_put(const org::openapitools::server::model::Spot_finding_settings &spotFindingSettings, Pistache::Http::ResponseWriter &response) = 0;
|
||||
/// <summary>
|
||||
/// Get user mask of the detector
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Get user pixel mask of the detector in the actual detector coordinates: 0 - good pixel, 1 - masked
|
||||
/// </remarks>
|
||||
virtual void config_user_mask_tiff_get(Pistache::Http::ResponseWriter &response) = 0;
|
||||
/// <summary>
|
||||
/// Upload user mask of the detector
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Should be in `Idle` state. Upload user mask of the detector - this is for example to account for beam stop shadow or misbehaving regions. If detector is conversion mode the mask can be both in raw (1024x512; stacked modules) or converted coordinates. In the latter case - module gaps are ignored and don't need to be assigned value. Mask is expected as TIFF (4-byte; unsigned). 0 - good pixel, other value - masked User mask is stored in NXmx pixel mask (bit 8), as well as used in spot finding and azimuthal integration. User mask is not automatically applied - i.e. pixels with user mask will have a valid pixel value in the images.
|
||||
/// </remarks>
|
||||
virtual void config_user_mask_tiff_put(const Pistache::Rest::Request &request, Pistache::Http::ResponseWriter &response) = 0;
|
||||
/// <summary>
|
||||
/// Prepare detector to turn off
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
@@ -293,13 +324,6 @@ private:
|
||||
/// <param name="binning">Binning of frames for the plot (0 = default binning) (optional, default to 0)</param>
|
||||
virtual void plot_receiver_free_send_buffers_get(const std::optional<int32_t> &binning, Pistache::Http::ResponseWriter &response) = 0;
|
||||
/// <summary>
|
||||
/// Generate resolution estimate histogram
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Generate histogram of crystal resolutions from 1.0 to 5.0 A based on ML model
|
||||
/// </remarks>
|
||||
virtual void plot_resolution_estimate_histogram_get(Pistache::Http::ResponseWriter &response) = 0;
|
||||
/// <summary>
|
||||
/// Generate plot of ROI max count
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
|
||||
@@ -51,6 +51,8 @@ Measurement_statistics::Measurement_statistics()
|
||||
m_Detector_pixel_depthIsSet = false;
|
||||
m_Bkg_estimate = 0.0f;
|
||||
m_Bkg_estimateIsSet = false;
|
||||
m_Unit_cell = "";
|
||||
m_Unit_cellIsSet = false;
|
||||
|
||||
}
|
||||
|
||||
@@ -106,7 +108,7 @@ bool Measurement_statistics::validate(std::stringstream& msg, const std::string&
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
@@ -158,7 +160,10 @@ bool Measurement_statistics::operator==(const Measurement_statistics& rhs) const
|
||||
((!detectorPixelDepthIsSet() && !rhs.detectorPixelDepthIsSet()) || (detectorPixelDepthIsSet() && rhs.detectorPixelDepthIsSet() && getDetectorPixelDepth() == rhs.getDetectorPixelDepth())) &&
|
||||
|
||||
|
||||
((!bkgEstimateIsSet() && !rhs.bkgEstimateIsSet()) || (bkgEstimateIsSet() && rhs.bkgEstimateIsSet() && getBkgEstimate() == rhs.getBkgEstimate()))
|
||||
((!bkgEstimateIsSet() && !rhs.bkgEstimateIsSet()) || (bkgEstimateIsSet() && rhs.bkgEstimateIsSet() && getBkgEstimate() == rhs.getBkgEstimate())) &&
|
||||
|
||||
|
||||
((!unitCellIsSet() && !rhs.unitCellIsSet()) || (unitCellIsSet() && rhs.unitCellIsSet() && getUnitCell() == rhs.getUnitCell()))
|
||||
|
||||
;
|
||||
}
|
||||
@@ -201,6 +206,8 @@ void to_json(nlohmann::json& j, const Measurement_statistics& o)
|
||||
j["detector_pixel_depth"] = o.m_Detector_pixel_depth;
|
||||
if(o.bkgEstimateIsSet())
|
||||
j["bkg_estimate"] = o.m_Bkg_estimate;
|
||||
if(o.unitCellIsSet())
|
||||
j["unit_cell"] = o.m_Unit_cell;
|
||||
|
||||
}
|
||||
|
||||
@@ -281,6 +288,11 @@ void from_json(const nlohmann::json& j, Measurement_statistics& o)
|
||||
j.at("bkg_estimate").get_to(o.m_Bkg_estimate);
|
||||
o.m_Bkg_estimateIsSet = true;
|
||||
}
|
||||
if(j.find("unit_cell") != j.end())
|
||||
{
|
||||
j.at("unit_cell").get_to(o.m_Unit_cell);
|
||||
o.m_Unit_cellIsSet = true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -539,6 +551,23 @@ void Measurement_statistics::unsetBkg_estimate()
|
||||
{
|
||||
m_Bkg_estimateIsSet = false;
|
||||
}
|
||||
std::string Measurement_statistics::getUnitCell() const
|
||||
{
|
||||
return m_Unit_cell;
|
||||
}
|
||||
void Measurement_statistics::setUnitCell(std::string const& value)
|
||||
{
|
||||
m_Unit_cell = value;
|
||||
m_Unit_cellIsSet = true;
|
||||
}
|
||||
bool Measurement_statistics::unitCellIsSet() const
|
||||
{
|
||||
return m_Unit_cellIsSet;
|
||||
}
|
||||
void Measurement_statistics::unsetUnit_cell()
|
||||
{
|
||||
m_Unit_cellIsSet = false;
|
||||
}
|
||||
|
||||
|
||||
} // namespace org::openapitools::server::model
|
||||
|
||||
@@ -163,6 +163,13 @@ public:
|
||||
void setBkgEstimate(float const value);
|
||||
bool bkgEstimateIsSet() const;
|
||||
void unsetBkg_estimate();
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
std::string getUnitCell() const;
|
||||
void setUnitCell(std::string const& value);
|
||||
bool unitCellIsSet() const;
|
||||
void unsetUnit_cell();
|
||||
|
||||
friend void to_json(nlohmann::json& j, const Measurement_statistics& o);
|
||||
friend void from_json(const nlohmann::json& j, Measurement_statistics& o);
|
||||
@@ -197,6 +204,8 @@ protected:
|
||||
bool m_Detector_pixel_depthIsSet;
|
||||
float m_Bkg_estimate;
|
||||
bool m_Bkg_estimateIsSet;
|
||||
std::string m_Unit_cell;
|
||||
bool m_Unit_cellIsSet;
|
||||
|
||||
};
|
||||
|
||||
|
||||
@@ -26,10 +26,14 @@ Preview_settings::Preview_settings()
|
||||
m_Show_spotsIsSet = false;
|
||||
m_Show_roi = false;
|
||||
m_Show_roiIsSet = false;
|
||||
m_Jpeg_quality = 0L;
|
||||
m_Jpeg_quality = 100L;
|
||||
m_Jpeg_qualityIsSet = false;
|
||||
m_Show_indexed = false;
|
||||
m_Show_indexedIsSet = false;
|
||||
m_Show_user_mask = false;
|
||||
m_Show_user_maskIsSet = false;
|
||||
m_Resolution_ring = 0.1f;
|
||||
m_Resolution_ringIsSet = false;
|
||||
|
||||
}
|
||||
|
||||
@@ -90,7 +94,26 @@ bool Preview_settings::validate(std::stringstream& msg, const std::string& pathP
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (resolutionRingIsSet())
|
||||
{
|
||||
const float& value = m_Resolution_ring;
|
||||
const std::string currentValuePath = _pathPrefix + ".resolutionRing";
|
||||
|
||||
|
||||
if (value < static_cast<float>(0.1))
|
||||
{
|
||||
success = false;
|
||||
msg << currentValuePath << ": must be greater than or equal to 0.1;";
|
||||
}
|
||||
if (value > static_cast<float>(100.0))
|
||||
{
|
||||
success = false;
|
||||
msg << currentValuePath << ": must be less than or equal to 100.0;";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
@@ -112,7 +135,13 @@ bool Preview_settings::operator==(const Preview_settings& rhs) const
|
||||
((!jpegQualityIsSet() && !rhs.jpegQualityIsSet()) || (jpegQualityIsSet() && rhs.jpegQualityIsSet() && getJpegQuality() == rhs.getJpegQuality())) &&
|
||||
|
||||
|
||||
((!showIndexedIsSet() && !rhs.showIndexedIsSet()) || (showIndexedIsSet() && rhs.showIndexedIsSet() && isShowIndexed() == rhs.isShowIndexed()))
|
||||
((!showIndexedIsSet() && !rhs.showIndexedIsSet()) || (showIndexedIsSet() && rhs.showIndexedIsSet() && isShowIndexed() == rhs.isShowIndexed())) &&
|
||||
|
||||
|
||||
((!showUserMaskIsSet() && !rhs.showUserMaskIsSet()) || (showUserMaskIsSet() && rhs.showUserMaskIsSet() && isShowUserMask() == rhs.isShowUserMask())) &&
|
||||
|
||||
|
||||
((!resolutionRingIsSet() && !rhs.resolutionRingIsSet()) || (resolutionRingIsSet() && rhs.resolutionRingIsSet() && getResolutionRing() == rhs.getResolutionRing()))
|
||||
|
||||
;
|
||||
}
|
||||
@@ -134,6 +163,10 @@ void to_json(nlohmann::json& j, const Preview_settings& o)
|
||||
j["jpeg_quality"] = o.m_Jpeg_quality;
|
||||
if(o.showIndexedIsSet())
|
||||
j["show_indexed"] = o.m_Show_indexed;
|
||||
if(o.showUserMaskIsSet())
|
||||
j["show_user_mask"] = o.m_Show_user_mask;
|
||||
if(o.resolutionRingIsSet())
|
||||
j["resolution_ring"] = o.m_Resolution_ring;
|
||||
|
||||
}
|
||||
|
||||
@@ -160,6 +193,16 @@ void from_json(const nlohmann::json& j, Preview_settings& o)
|
||||
j.at("show_indexed").get_to(o.m_Show_indexed);
|
||||
o.m_Show_indexedIsSet = true;
|
||||
}
|
||||
if(j.find("show_user_mask") != j.end())
|
||||
{
|
||||
j.at("show_user_mask").get_to(o.m_Show_user_mask);
|
||||
o.m_Show_user_maskIsSet = true;
|
||||
}
|
||||
if(j.find("resolution_ring") != j.end())
|
||||
{
|
||||
j.at("resolution_ring").get_to(o.m_Resolution_ring);
|
||||
o.m_Resolution_ringIsSet = true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -239,6 +282,40 @@ void Preview_settings::unsetShow_indexed()
|
||||
{
|
||||
m_Show_indexedIsSet = false;
|
||||
}
|
||||
bool Preview_settings::isShowUserMask() const
|
||||
{
|
||||
return m_Show_user_mask;
|
||||
}
|
||||
void Preview_settings::setShowUserMask(bool const value)
|
||||
{
|
||||
m_Show_user_mask = value;
|
||||
m_Show_user_maskIsSet = true;
|
||||
}
|
||||
bool Preview_settings::showUserMaskIsSet() const
|
||||
{
|
||||
return m_Show_user_maskIsSet;
|
||||
}
|
||||
void Preview_settings::unsetShow_user_mask()
|
||||
{
|
||||
m_Show_user_maskIsSet = false;
|
||||
}
|
||||
float Preview_settings::getResolutionRing() const
|
||||
{
|
||||
return m_Resolution_ring;
|
||||
}
|
||||
void Preview_settings::setResolutionRing(float const value)
|
||||
{
|
||||
m_Resolution_ring = value;
|
||||
m_Resolution_ringIsSet = true;
|
||||
}
|
||||
bool Preview_settings::resolutionRingIsSet() const
|
||||
{
|
||||
return m_Resolution_ringIsSet;
|
||||
}
|
||||
void Preview_settings::unsetResolution_ring()
|
||||
{
|
||||
m_Resolution_ringIsSet = false;
|
||||
}
|
||||
|
||||
|
||||
} // namespace org::openapitools::server::model
|
||||
|
||||
@@ -90,6 +90,20 @@ public:
|
||||
void setShowIndexed(bool const value);
|
||||
bool showIndexedIsSet() const;
|
||||
void unsetShow_indexed();
|
||||
/// <summary>
|
||||
/// Show user mask
|
||||
/// </summary>
|
||||
bool isShowUserMask() const;
|
||||
void setShowUserMask(bool const value);
|
||||
bool showUserMaskIsSet() const;
|
||||
void unsetShow_user_mask();
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
float getResolutionRing() const;
|
||||
void setResolutionRing(float const value);
|
||||
bool resolutionRingIsSet() const;
|
||||
void unsetResolution_ring();
|
||||
|
||||
friend void to_json(nlohmann::json& j, const Preview_settings& o);
|
||||
friend void from_json(const nlohmann::json& j, Preview_settings& o);
|
||||
@@ -104,6 +118,10 @@ protected:
|
||||
bool m_Jpeg_qualityIsSet;
|
||||
bool m_Show_indexed;
|
||||
bool m_Show_indexedIsSet;
|
||||
bool m_Show_user_mask;
|
||||
bool m_Show_user_maskIsSet;
|
||||
float m_Resolution_ring;
|
||||
bool m_Resolution_ringIsSet;
|
||||
|
||||
};
|
||||
|
||||
|
||||
@@ -23,6 +23,10 @@ Spot_finding_settings::Spot_finding_settings()
|
||||
{
|
||||
m_Enable = true;
|
||||
m_Indexing = true;
|
||||
m_Filter_powder_rings = false;
|
||||
m_Filter_powder_ringsIsSet = false;
|
||||
m_Min_spot_count_powder_ring = 20L;
|
||||
m_Min_spot_count_powder_ringIsSet = false;
|
||||
m_Signal_to_noise_threshold = 0.0f;
|
||||
m_Photon_count_threshold = 0L;
|
||||
m_Min_pix_per_spot = 0L;
|
||||
@@ -52,7 +56,21 @@ bool Spot_finding_settings::validate(std::stringstream& msg, const std::string&
|
||||
bool success = true;
|
||||
const std::string _pathPrefix = pathPrefix.empty() ? "Spot_finding_settings" : pathPrefix;
|
||||
|
||||
|
||||
|
||||
if (minSpotCountPowderRingIsSet())
|
||||
{
|
||||
const int64_t& value = m_Min_spot_count_powder_ring;
|
||||
const std::string currentValuePath = _pathPrefix + ".minSpotCountPowderRing";
|
||||
|
||||
|
||||
if (value < 5ll)
|
||||
{
|
||||
success = false;
|
||||
msg << currentValuePath << ": must be greater than or equal to 5;";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/* Signal_to_noise_threshold */ {
|
||||
const float& value = m_Signal_to_noise_threshold;
|
||||
@@ -142,6 +160,12 @@ bool Spot_finding_settings::operator==(const Spot_finding_settings& rhs) const
|
||||
(isIndexing() == rhs.isIndexing())
|
||||
&&
|
||||
|
||||
|
||||
((!filterPowderRingsIsSet() && !rhs.filterPowderRingsIsSet()) || (filterPowderRingsIsSet() && rhs.filterPowderRingsIsSet() && isFilterPowderRings() == rhs.isFilterPowderRings())) &&
|
||||
|
||||
|
||||
((!minSpotCountPowderRingIsSet() && !rhs.minSpotCountPowderRingIsSet()) || (minSpotCountPowderRingIsSet() && rhs.minSpotCountPowderRingIsSet() && getMinSpotCountPowderRing() == rhs.getMinSpotCountPowderRing())) &&
|
||||
|
||||
(getSignalToNoiseThreshold() == rhs.getSignalToNoiseThreshold())
|
||||
&&
|
||||
|
||||
@@ -176,6 +200,10 @@ void to_json(nlohmann::json& j, const Spot_finding_settings& o)
|
||||
j = nlohmann::json();
|
||||
j["enable"] = o.m_Enable;
|
||||
j["indexing"] = o.m_Indexing;
|
||||
if(o.filterPowderRingsIsSet())
|
||||
j["filter_powder_rings"] = o.m_Filter_powder_rings;
|
||||
if(o.minSpotCountPowderRingIsSet())
|
||||
j["min_spot_count_powder_ring"] = o.m_Min_spot_count_powder_ring;
|
||||
j["signal_to_noise_threshold"] = o.m_Signal_to_noise_threshold;
|
||||
j["photon_count_threshold"] = o.m_Photon_count_threshold;
|
||||
j["min_pix_per_spot"] = o.m_Min_pix_per_spot;
|
||||
@@ -190,6 +218,16 @@ void from_json(const nlohmann::json& j, Spot_finding_settings& o)
|
||||
{
|
||||
j.at("enable").get_to(o.m_Enable);
|
||||
j.at("indexing").get_to(o.m_Indexing);
|
||||
if(j.find("filter_powder_rings") != j.end())
|
||||
{
|
||||
j.at("filter_powder_rings").get_to(o.m_Filter_powder_rings);
|
||||
o.m_Filter_powder_ringsIsSet = true;
|
||||
}
|
||||
if(j.find("min_spot_count_powder_ring") != j.end())
|
||||
{
|
||||
j.at("min_spot_count_powder_ring").get_to(o.m_Min_spot_count_powder_ring);
|
||||
o.m_Min_spot_count_powder_ringIsSet = true;
|
||||
}
|
||||
j.at("signal_to_noise_threshold").get_to(o.m_Signal_to_noise_threshold);
|
||||
j.at("photon_count_threshold").get_to(o.m_Photon_count_threshold);
|
||||
j.at("min_pix_per_spot").get_to(o.m_Min_pix_per_spot);
|
||||
@@ -216,6 +254,40 @@ void Spot_finding_settings::setIndexing(bool const value)
|
||||
{
|
||||
m_Indexing = value;
|
||||
}
|
||||
bool Spot_finding_settings::isFilterPowderRings() const
|
||||
{
|
||||
return m_Filter_powder_rings;
|
||||
}
|
||||
void Spot_finding_settings::setFilterPowderRings(bool const value)
|
||||
{
|
||||
m_Filter_powder_rings = value;
|
||||
m_Filter_powder_ringsIsSet = true;
|
||||
}
|
||||
bool Spot_finding_settings::filterPowderRingsIsSet() const
|
||||
{
|
||||
return m_Filter_powder_ringsIsSet;
|
||||
}
|
||||
void Spot_finding_settings::unsetFilter_powder_rings()
|
||||
{
|
||||
m_Filter_powder_ringsIsSet = false;
|
||||
}
|
||||
int64_t Spot_finding_settings::getMinSpotCountPowderRing() const
|
||||
{
|
||||
return m_Min_spot_count_powder_ring;
|
||||
}
|
||||
void Spot_finding_settings::setMinSpotCountPowderRing(int64_t const value)
|
||||
{
|
||||
m_Min_spot_count_powder_ring = value;
|
||||
m_Min_spot_count_powder_ringIsSet = true;
|
||||
}
|
||||
bool Spot_finding_settings::minSpotCountPowderRingIsSet() const
|
||||
{
|
||||
return m_Min_spot_count_powder_ringIsSet;
|
||||
}
|
||||
void Spot_finding_settings::unsetMin_spot_count_powder_ring()
|
||||
{
|
||||
m_Min_spot_count_powder_ringIsSet = false;
|
||||
}
|
||||
float Spot_finding_settings::getSignalToNoiseThreshold() const
|
||||
{
|
||||
return m_Signal_to_noise_threshold;
|
||||
|
||||
@@ -58,16 +58,30 @@ public:
|
||||
/// Spot_finding_settings members
|
||||
|
||||
/// <summary>
|
||||
/// Enable spot finding
|
||||
/// Enable spot finding. This is temporary setting, i.e. can be changed anytime during data collection. Even if disabled spot finding information will still be send and written, though always with zero spots.
|
||||
/// </summary>
|
||||
bool isEnable() const;
|
||||
void setEnable(bool const value);
|
||||
/// <summary>
|
||||
/// Enable indexing
|
||||
/// Enable indexing. This is temporary setting, i.e. can be changed anytime during data collection.
|
||||
/// </summary>
|
||||
bool isIndexing() const;
|
||||
void setIndexing(bool const value);
|
||||
/// <summary>
|
||||
/// Filter spots which form powder rings (e.g., ice rings)
|
||||
/// </summary>
|
||||
bool isFilterPowderRings() const;
|
||||
void setFilterPowderRings(bool const value);
|
||||
bool filterPowderRingsIsSet() const;
|
||||
void unsetFilter_powder_rings();
|
||||
/// <summary>
|
||||
/// Minimum number of spots to consider a thin resolution shell (0.01 A^-1) a powder ring and filter out.
|
||||
/// </summary>
|
||||
int64_t getMinSpotCountPowderRing() const;
|
||||
void setMinSpotCountPowderRing(int64_t const value);
|
||||
bool minSpotCountPowderRingIsSet() const;
|
||||
void unsetMin_spot_count_powder_ring();
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
float getSignalToNoiseThreshold() const;
|
||||
@@ -110,6 +124,10 @@ protected:
|
||||
|
||||
bool m_Indexing;
|
||||
|
||||
bool m_Filter_powder_rings;
|
||||
bool m_Filter_powder_ringsIsSet;
|
||||
int64_t m_Min_spot_count_powder_ring;
|
||||
bool m_Min_spot_count_powder_ringIsSet;
|
||||
float m_Signal_to_noise_threshold;
|
||||
|
||||
int64_t m_Photon_count_threshold;
|
||||
|
||||
@@ -333,11 +333,23 @@ components:
|
||||
enable:
|
||||
type: boolean
|
||||
default: true
|
||||
description: Enable spot finding
|
||||
description: |
|
||||
Enable spot finding. This is temporary setting, i.e. can be changed anytime during data collection.
|
||||
Even if disabled spot finding information will still be send and written, though always with zero spots.
|
||||
indexing:
|
||||
type: boolean
|
||||
default: true
|
||||
description: Enable indexing
|
||||
description: |
|
||||
Enable indexing. This is temporary setting, i.e. can be changed anytime during data collection.
|
||||
filter_powder_rings:
|
||||
type: boolean
|
||||
default: false
|
||||
description: Filter spots which form powder rings (e.g., ice rings)
|
||||
min_spot_count_powder_ring:
|
||||
type: integer
|
||||
format: int64
|
||||
minimum: 5
|
||||
description: Minimum number of spots to consider a thin resolution shell (0.01 A^-1) a powder ring and filter out.
|
||||
signal_to_noise_threshold:
|
||||
type: number
|
||||
format: float
|
||||
@@ -500,6 +512,8 @@ components:
|
||||
bkg_estimate:
|
||||
type: number
|
||||
format: float
|
||||
unit_cell:
|
||||
type: string
|
||||
broker_status:
|
||||
type: object
|
||||
required:
|
||||
@@ -618,12 +632,23 @@ components:
|
||||
type: integer
|
||||
description: "Quality of JPEG image (100 - highest; 0 - lowest)"
|
||||
format: int64
|
||||
default: 100
|
||||
minimum: 0
|
||||
maximum: 100
|
||||
show_indexed:
|
||||
type: boolean
|
||||
description: "Preview indexed images only"
|
||||
|
||||
default: false
|
||||
show_user_mask:
|
||||
type: boolean
|
||||
description: "Show user mask"
|
||||
default: false
|
||||
resolution_ring:
|
||||
type: number
|
||||
format: float
|
||||
default: 0.1
|
||||
minimum: 0.1
|
||||
maximum: 100.0
|
||||
error_message:
|
||||
type: object
|
||||
required:
|
||||
@@ -961,9 +986,9 @@ paths:
|
||||
Requires binary blob with 16-bit integer numbers of size of detector in raw/converted coordinates
|
||||
(depending on detector settings).
|
||||
parameters:
|
||||
- name: number
|
||||
- name: id
|
||||
in: query
|
||||
description: Image number to upload
|
||||
description: Image id to upload
|
||||
required: false
|
||||
schema:
|
||||
type: integer
|
||||
@@ -986,6 +1011,38 @@ paths:
|
||||
schema:
|
||||
type: string
|
||||
description: Exception error
|
||||
/config/internal_generator_image.tiff:
|
||||
put:
|
||||
summary: Load TIFF image for internal FPGA generator
|
||||
description: |
|
||||
Load image for internal FPGA generator. This can only happen in Idle state of the detector.
|
||||
Requires TIFF with 16-bit integer numbers of size of detector in raw/converted coordinates
|
||||
(depending on detector settings).
|
||||
parameters:
|
||||
- in: query
|
||||
name: id
|
||||
description: Image ID to upload
|
||||
required: false
|
||||
schema:
|
||||
type: integer
|
||||
minimum: 0
|
||||
maximum: 127
|
||||
requestBody:
|
||||
content:
|
||||
image/tiff:
|
||||
schema:
|
||||
type: string
|
||||
format: binary
|
||||
responses:
|
||||
"200":
|
||||
description: Everything OK
|
||||
"400":
|
||||
description: Input parsing or validation error
|
||||
content:
|
||||
text/plain:
|
||||
schema:
|
||||
type: string
|
||||
description: Exception error
|
||||
/config/select_detector:
|
||||
put:
|
||||
summary: Select detector
|
||||
@@ -1441,17 +1498,6 @@ paths:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/plots'
|
||||
/plot/resolution_estimate_histogram:
|
||||
get:
|
||||
summary: Generate resolution estimate histogram
|
||||
description: Generate histogram of crystal resolutions from 1.0 to 5.0 A based on ML model
|
||||
responses:
|
||||
"200":
|
||||
description: Everything OK
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/plots'
|
||||
/plot/rad_int:
|
||||
get:
|
||||
summary: Generate radial integration profile
|
||||
@@ -1569,6 +1615,63 @@ paths:
|
||||
format: binary
|
||||
"404":
|
||||
description: No preview image recorded so far
|
||||
/config/mask.tiff:
|
||||
get:
|
||||
summary: Get mask of the detector
|
||||
description: |
|
||||
Get full pixel mask of the detector
|
||||
See NXmx standard for meaning of pixel values
|
||||
responses:
|
||||
"200":
|
||||
description: Pixel mask in TIFF format (4 byte; unsigned)
|
||||
content:
|
||||
image/tiff:
|
||||
schema:
|
||||
type: string
|
||||
format: binary
|
||||
/config/user_mask.tiff:
|
||||
get:
|
||||
summary: Get user mask of the detector
|
||||
description: "Get user pixel mask of the detector in the actual detector coordinates: 0 - good pixel, 1 - masked"
|
||||
responses:
|
||||
"200":
|
||||
description: User mask in TIFF format (4 byte; unsigned)
|
||||
content:
|
||||
image/tiff:
|
||||
schema:
|
||||
type: string
|
||||
format: binary
|
||||
put:
|
||||
summary: Upload user mask of the detector
|
||||
description: |
|
||||
Should be in `Idle` state.
|
||||
Upload user mask of the detector - this is for example to account for beam stop shadow or misbehaving regions.
|
||||
If detector is conversion mode the mask can be both in raw (1024x512; stacked modules) or converted coordinates.
|
||||
In the latter case - module gaps are ignored and don't need to be assigned value.
|
||||
Mask is expected as TIFF (4-byte; unsigned).
|
||||
0 - good pixel, other value - masked
|
||||
User mask is stored in NXmx pixel mask (bit 8), as well as used in spot finding and azimuthal integration.
|
||||
User mask is not automatically applied - i.e. pixels with user mask will have a valid pixel value in the images.
|
||||
requestBody:
|
||||
content:
|
||||
application/octet-stream:
|
||||
schema:
|
||||
type: string
|
||||
format: binary
|
||||
responses:
|
||||
"200":
|
||||
description: All good
|
||||
content:
|
||||
image/tiff:
|
||||
schema:
|
||||
type: string
|
||||
format: binary
|
||||
"500":
|
||||
description: Error within Jungfraujoch code - see output message.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/error_message'
|
||||
/preview/pedestal.tiff:
|
||||
get:
|
||||
parameters:
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
// Using OpenAPI licensed with Apache License 2.0
|
||||
|
||||
#include <vector>
|
||||
#include <signal.h>
|
||||
#include <csignal>
|
||||
#include <fstream>
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
#include "JFJochBrokerHttp.h"
|
||||
|
||||
#include "JFJochBrokerParser.h"
|
||||
#include "../frame_serialize/ZMQStream2PusherGroup.h"
|
||||
#include "../frame_serialize/ZMQStream2Pusher.h"
|
||||
#include "../frame_serialize/DumpCBORToFilePusher.h"
|
||||
|
||||
static Pistache::Http::Endpoint *httpEndpoint;
|
||||
@@ -73,8 +73,6 @@ int main (int argc, char **argv) {
|
||||
std::unique_ptr<JFJochReceiverService> receiver;
|
||||
std::unique_ptr<ImagePusher> image_pusher;
|
||||
|
||||
ZMQContext context;
|
||||
|
||||
DiffractionExperiment experiment;
|
||||
experiment.MaskChipEdges(true).MaskModuleEdges(true);
|
||||
|
||||
@@ -88,9 +86,15 @@ int main (int argc, char **argv) {
|
||||
int32_t zmq_send_watermark = ParseInt32(input, "zmq_send_watermark", 100);
|
||||
int32_t zmq_send_buffer_size = ParseInt32(input, "zmq_send_buffer_size", -1);
|
||||
|
||||
image_pusher = std::make_unique<ZMQStream2PusherGroup>(ParseStringArray(input, "zmq_image_addr"),
|
||||
auto tmp = std::make_unique<ZMQStream2Pusher>(ParseStringArray(input, "zmq_image_addr"),
|
||||
zmq_send_watermark,
|
||||
zmq_send_buffer_size);
|
||||
|
||||
std::string preview_addr = ParseString(input, "zmq_preview_addr", "");
|
||||
if (!preview_addr.empty())
|
||||
tmp->PreviewSocket(preview_addr);
|
||||
|
||||
image_pusher = std::move(tmp);
|
||||
} else if (pusher_type == "dump_cbor") {
|
||||
image_pusher = std::make_unique<DumpCBORToFilePusher>();
|
||||
} else
|
||||
|
||||
Submodule broker/pistache deleted from 51553b92cc
File diff suppressed because one or more lines are too long
@@ -1,27 +0,0 @@
|
||||
#From: https://github.com/zeromq/cppzmq/
|
||||
set(PKG_CONFIG_USE_CMAKE_PREFIX_PATH ON)
|
||||
find_package(PkgConfig)
|
||||
pkg_check_modules(PC_LIBZMQ QUIET libzmq)
|
||||
|
||||
set(ZeroMQ_VERSION ${PC_LIBZMQ_VERSION})
|
||||
find_library(ZeroMQ_LIBRARY NAMES libzmq.so libzmq.dylib libzmq.dll
|
||||
PATHS ${PC_LIBZMQ_LIBDIR} ${PC_LIBZMQ_LIBRARY_DIRS})
|
||||
find_library(ZeroMQ_STATIC_LIBRARY NAMES libzmq-static.a libzmq.a libzmq.dll.a
|
||||
PATHS ${PC_LIBZMQ_LIBDIR} ${PC_LIBZMQ_LIBRARY_DIRS})
|
||||
|
||||
if(ZeroMQ_LIBRARY OR ZeroMQ_STATIC_LIBRARY)
|
||||
set(ZeroMQ_FOUND ON)
|
||||
endif()
|
||||
|
||||
if (TARGET libzmq)
|
||||
# avoid errors defining targets twice
|
||||
return()
|
||||
endif()
|
||||
|
||||
add_library(libzmq SHARED IMPORTED)
|
||||
set_property(TARGET libzmq PROPERTY INTERFACE_INCLUDE_DIRECTORIES ${PC_LIBZMQ_INCLUDE_DIRS})
|
||||
set_property(TARGET libzmq PROPERTY IMPORTED_LOCATION ${ZeroMQ_LIBRARY})
|
||||
|
||||
add_library(libzmq-static STATIC IMPORTED ${PC_LIBZMQ_INCLUDE_DIRS})
|
||||
set_property(TARGET libzmq-static PROPERTY INTERFACE_INCLUDE_DIRECTORIES ${PC_LIBZMQ_INCLUDE_DIRS})
|
||||
set_property(TARGET libzmq-static PROPERTY IMPORTED_LOCATION ${ZeroMQ_STATIC_LIBRARY})
|
||||
@@ -16,19 +16,26 @@ EXECUTE_PROCESS(COMMAND
|
||||
OUTPUT_VARIABLE GIT_DATE
|
||||
ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||
|
||||
MESSAGE(STATUS "Git SHA1: ${GIT_SHA1}")
|
||||
MESSAGE(STATUS "Git date: ${GIT_DATE}")
|
||||
FILE(STRINGS ../VERSION PACKAGE_VERSION)
|
||||
MESSAGE(STATUS "Jungfraujoch git SHA1: ${GIT_SHA1}")
|
||||
MESSAGE(STATUS "Jungfraujoch git date: ${GIT_DATE}")
|
||||
MESSAGE(STATUS "Jungfraujoch version: ${PACKAGE_VERSION}")
|
||||
|
||||
CONFIGURE_FILE("${CMAKE_CURRENT_SOURCE_DIR}/GitInfo.cpp.in" "${CMAKE_CURRENT_BINARY_DIR}/GitInfo.cpp" @ONLY)
|
||||
|
||||
ADD_LIBRARY( JFJochCommon STATIC
|
||||
ADD_LIBRARY(JFJochLogger STATIC
|
||||
Logger.cpp Logger.h
|
||||
${CMAKE_CURRENT_BINARY_DIR}/GitInfo.cpp GitInfo.h
|
||||
)
|
||||
|
||||
ADD_LIBRARY(JFJochZMQ STATIC ZMQWrappers.cpp ZMQWrappers.h)
|
||||
|
||||
ADD_LIBRARY(JFJochCommon STATIC
|
||||
Coord.cpp Coord.h
|
||||
DiffractionExperiment.cpp DiffractionExperiment.h
|
||||
RawToConvertedGeometry.h
|
||||
JFJochException.h
|
||||
Definitions.h
|
||||
${CMAKE_CURRENT_BINARY_DIR}/GitInfo.cpp GitInfo.h
|
||||
ThreadSafeFIFO.h
|
||||
DiffractionSpot.cpp DiffractionSpot.h
|
||||
StatusVector.h
|
||||
@@ -43,7 +50,6 @@ ADD_LIBRARY( JFJochCommon STATIC
|
||||
RawToConvertedGeometryCore.h
|
||||
Plot.h
|
||||
../fpga/pcie_driver/jfjoch_fpga.h
|
||||
ZMQWrappers.cpp ZMQWrappers.h
|
||||
DatasetSettings.cpp DatasetSettings.h
|
||||
ROIMap.cpp ROIMap.h
|
||||
ROIElement.cpp ROIElement.h
|
||||
@@ -55,7 +61,9 @@ ADD_LIBRARY( JFJochCommon STATIC
|
||||
PixelMask.cpp PixelMask.h
|
||||
)
|
||||
|
||||
TARGET_LINK_LIBRARIES(JFJochCommon Compression JFCalibration "$<BUILD_INTERFACE:libzmq-static>" -lrt)
|
||||
TARGET_LINK_LIBRARIES(JFJochCommon JFJochLogger Compression JFCalibration -lrt)
|
||||
|
||||
TARGET_LINK_LIBRARIES(JFJochZMQ "$<BUILD_INTERFACE:libzmq-static>")
|
||||
|
||||
IF (CMAKE_CUDA_COMPILER)
|
||||
TARGET_SOURCES(JFJochCommon PRIVATE CUDAWrapper.cu )
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include "JFJochException.h"
|
||||
#include "RawToConvertedGeometry.h"
|
||||
#include "../fpga/pcie_driver/jfjoch_fpga.h"
|
||||
#include "../include/spdlog/fmt/fmt.h"
|
||||
|
||||
using namespace std::literals::chrono_literals;
|
||||
|
||||
@@ -28,8 +29,6 @@ DiffractionExperiment::DiffractionExperiment(const DetectorSetup& det_setup)
|
||||
internal_fpga_packet_generator = false;
|
||||
internal_fpga_packet_generator_images = 1;
|
||||
|
||||
debug_pixel_mask = false;
|
||||
|
||||
ndatastreams = 1;
|
||||
|
||||
frame_time = std::chrono::microseconds(MIN_FRAME_TIME_HALF_SPEED_IN_US);
|
||||
@@ -597,6 +596,20 @@ std::optional<UnitCell> DiffractionExperiment::GetUnitCell() const {
|
||||
return dataset.GetUnitCell();
|
||||
}
|
||||
|
||||
std::string DiffractionExperiment::GetUnitCellString() const {
|
||||
auto uc = dataset.GetUnitCell();
|
||||
if (uc.has_value()) {
|
||||
return fmt::format("{:.1f}, {:.1f}, {:.1f}, {:.1f}, {:.1f} {:.1f}",
|
||||
uc.value().a,
|
||||
uc.value().b,
|
||||
uc.value().c,
|
||||
uc.value().alpha,
|
||||
uc.value().beta,
|
||||
uc.value().gamma);
|
||||
} else
|
||||
return "-";
|
||||
}
|
||||
|
||||
Coord DiffractionExperiment::LabCoord(float detector_x, float detector_y) const {
|
||||
// Assumes planar detector, 90 deg towards beam
|
||||
return {(detector_x - GetBeamX_pxl()) * GetPixelSize_mm() ,
|
||||
@@ -669,6 +682,7 @@ void DiffractionExperiment::CheckDataProcessingSettings(const SpotFindingSetting
|
||||
check_min("Spot finding low resolution limit", settings.low_resolution_limit, 1.0);
|
||||
check_max("Spot finding low resolution limit", settings.low_resolution_limit, 50.0);
|
||||
}
|
||||
check_min("min spot count for powder ring detection", settings.min_spot_count_powder_ring, 5);
|
||||
check_min("indexing tolerance", settings.indexing_tolerance, 0.0);
|
||||
check_max("indexing tolerance", settings.indexing_tolerance, 1.0);
|
||||
}
|
||||
@@ -737,6 +751,8 @@ void DiffractionExperiment::FillMessage(StartMessage &message) const {
|
||||
|
||||
for (const auto &[x, y]: roi_mask.GetROINameMap())
|
||||
message.roi_names.emplace_back(x);
|
||||
|
||||
message.data_reduction_factor_serialmx = GetDataReductionFactorSerialMX();
|
||||
}
|
||||
|
||||
float DiffractionExperiment::GetPixelSize_mm() const {
|
||||
@@ -1064,15 +1080,6 @@ const DetectorSetup &DiffractionExperiment::GetDetectorSetup() const {
|
||||
return detector;
|
||||
}
|
||||
|
||||
DiffractionExperiment &DiffractionExperiment::NeuralNetModelPath(const std::string &input) {
|
||||
neural_net_model_path = input;
|
||||
return *this;
|
||||
}
|
||||
|
||||
std::string DiffractionExperiment::GetNeuralNetModelPath() const {
|
||||
return neural_net_model_path;
|
||||
}
|
||||
|
||||
DiffractionExperiment &DiffractionExperiment::PulsedSource(bool input) {
|
||||
pulsed_source = input;
|
||||
return *this;
|
||||
|
||||
@@ -82,15 +82,12 @@ class DiffractionExperiment {
|
||||
std::string instrument_name_short;
|
||||
bool pulsed_source;
|
||||
|
||||
bool debug_pixel_mask;
|
||||
Coord default_omega_axis;
|
||||
|
||||
bool conversion_on_fpga;
|
||||
|
||||
uint64_t series_id;
|
||||
|
||||
std::string neural_net_model_path;
|
||||
|
||||
bool rad_int_solid_angle_corr;
|
||||
bool rad_int_polarization_corr;
|
||||
float rad_int_polarization_factor{};
|
||||
@@ -144,7 +141,6 @@ public:
|
||||
DiffractionExperiment& FixedGainG1(bool input);
|
||||
DiffractionExperiment& IncrementSeriesID();
|
||||
DiffractionExperiment& ConversionOnFPGA(bool input);
|
||||
DiffractionExperiment& NeuralNetModelPath(const std::string& input);
|
||||
DiffractionExperiment& PulsedSource(bool input);
|
||||
|
||||
DiffractionExperiment& ImagesPerTrigger(int64_t input);
|
||||
@@ -282,7 +278,6 @@ public:
|
||||
bool IsConversionOnFPGA() const;
|
||||
|
||||
const DetectorSetup& GetDetectorSetup() const;
|
||||
std::string GetNeuralNetModelPath() const;
|
||||
|
||||
bool IsPulsedSource() const;
|
||||
|
||||
@@ -299,6 +294,7 @@ public:
|
||||
std::string GetImageAppendix() const;
|
||||
float GetPhotonEnergyMultiplier() const;
|
||||
std::optional<UnitCell> GetUnitCell() const;
|
||||
std::string GetUnitCellString() const;
|
||||
int64_t GetSpaceGroupNumber() const;
|
||||
bool GetSaveCalibration() const;
|
||||
int64_t GetSummation() const;
|
||||
|
||||
@@ -9,3 +9,7 @@ std::string jfjoch_git_sha1() {
|
||||
std::string jfjoch_git_date() {
|
||||
return "@GIT_DATE@";
|
||||
}
|
||||
|
||||
std::string jfjoch_version() {
|
||||
return "@PACKAGE_VERSION@";
|
||||
}
|
||||
@@ -7,5 +7,6 @@
|
||||
|
||||
std::string jfjoch_git_sha1();
|
||||
std::string jfjoch_git_date();
|
||||
std::string jfjoch_version();
|
||||
|
||||
#endif //JUNGFRAUJOCH_GITINFO_H
|
||||
|
||||
@@ -16,7 +16,10 @@ Logger::Logger(const std::string &service_name, const std::string &file_name) {
|
||||
sinks.push_back(std::make_shared<spdlog::sinks::daily_file_sink_mt>(file_name, 23, 59));
|
||||
|
||||
spdlog_logger = std::make_shared<spdlog::logger>(service_name, std::begin(sinks), std::end(sinks));
|
||||
spdlog_logger->info("Git sha {} ({})", jfjoch_git_sha1().substr(0, 6), jfjoch_git_date());
|
||||
if (jfjoch_git_sha1().empty())
|
||||
spdlog_logger->info("Version {}", jfjoch_version());
|
||||
else
|
||||
spdlog_logger->info("Version {} (git {} {})", jfjoch_version(), jfjoch_git_sha1().substr(0, 6), jfjoch_git_date());
|
||||
}
|
||||
|
||||
void Logger::ErrorException(const std::exception &e) {
|
||||
|
||||
@@ -46,15 +46,6 @@ NUMAHWPolicy::NUMAHWPolicy(const std::string &policy) : name(policy) {
|
||||
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};
|
||||
@@ -62,14 +53,6 @@ NUMABinding NUMAHWPolicy::GetBinding(uint32_t thread) {
|
||||
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));
|
||||
}
|
||||
|
||||
@@ -17,19 +17,14 @@ struct NUMABinding {
|
||||
class NUMAHWPolicy {
|
||||
std::string name;
|
||||
std::vector<NUMABinding> bindings;
|
||||
std::atomic<uint32_t> 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);
|
||||
|
||||
@@ -12,7 +12,7 @@ PixelMask::PixelMask(const DetectorSetup &detector)
|
||||
PixelMask::PixelMask(const DiffractionExperiment& experiment)
|
||||
: PixelMask(experiment.GetDetectorSetup()) {}
|
||||
|
||||
void PixelMask::LoadDetectorBadPixelMask(const std::vector<uint32_t> &input_mask, uint8_t bit) {
|
||||
void PixelMask::LoadMask(const std::vector<uint32_t> &input_mask, uint8_t bit) {
|
||||
if (input_mask.size() != mask.size())
|
||||
throw JFJochException(JFJochExceptionCategory::InputParameterInvalid,
|
||||
"Input match doesn't fit the detector ");
|
||||
@@ -25,7 +25,11 @@ void PixelMask::LoadDetectorBadPixelMask(const std::vector<uint32_t> &input_mask
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<uint32_t> PixelMask::GetMask(const DiffractionExperiment &experiment) {
|
||||
void PixelMask::LoadDetectorBadPixelMask(const std::vector<uint32_t> &input_mask) {
|
||||
LoadMask(input_mask, ErrorPixelBit);
|
||||
}
|
||||
|
||||
std::vector<uint32_t> PixelMask::GetMask(const DiffractionExperiment &experiment, bool conv) const {
|
||||
std::vector<uint32_t> mask_out = mask;
|
||||
|
||||
// apply edge mask
|
||||
@@ -39,7 +43,7 @@ std::vector<uint32_t> PixelMask::GetMask(const DiffractionExperiment &experiment
|
||||
|| (line == RAW_MODULE_LINES - 1)
|
||||
|| (col == 0)
|
||||
|| (col == RAW_MODULE_COLS - 1))
|
||||
mask_out[pixel] |= (1 << 30);
|
||||
mask_out[pixel] |= (1 << ModuleEdgePixelBit);
|
||||
}
|
||||
|
||||
if (experiment.GetMaskChipEdges()) {
|
||||
@@ -47,33 +51,39 @@ std::vector<uint32_t> PixelMask::GetMask(const DiffractionExperiment &experiment
|
||||
|| (col == 511) || (col == 512)
|
||||
|| (col == 767) || (col == 768)
|
||||
|| (line == 255) || (line== 256))
|
||||
mask_out[pixel] |= (1 << 31);
|
||||
mask_out[pixel] |= (1 << ChipGapPixelBit);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (experiment.GetDetectorMode() == DetectorMode::Conversion) {
|
||||
std::vector<uint32_t> tmp(experiment.GetPixelsNum(), 1); // nonfuctional areas (i.e. gaps) are filled with 1
|
||||
if (conv && (experiment.GetDetectorMode() == DetectorMode::Conversion)) {
|
||||
std::vector<uint32_t> tmp(experiment.GetPixelsNum(), 1<<ModuleGapPixelBit); // nonfunctional areas (i.e. gaps) are filled with 1
|
||||
RawToConvertedGeometry<uint32_t, uint32_t>(experiment, tmp.data(), mask_out.data());
|
||||
return tmp;
|
||||
} else
|
||||
return mask_out;
|
||||
}
|
||||
|
||||
std::vector<uint32_t> PixelMask::GetUserMask(const DiffractionExperiment &experiment, bool conv) const {
|
||||
std::vector<uint32_t> ret = GetMask(experiment, conv);
|
||||
for (auto &i: ret)
|
||||
i = ((i & (1 << UserMaskedPixelBit)) != 0) ? 1 : 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
void PixelMask::LoadUserMask(const DiffractionExperiment &experiment,
|
||||
const std::vector<uint32_t> &in_mask,
|
||||
uint8_t bit) {
|
||||
const std::vector<uint32_t> &in_mask) {
|
||||
if (experiment.GetModulesNum() != nmodules)
|
||||
throw JFJochException(JFJochExceptionCategory::InputParameterInvalid,
|
||||
"Mismatch in module size");
|
||||
|
||||
if (in_mask.size() == nmodules * RAW_MODULE_SIZE) {
|
||||
LoadDetectorBadPixelMask(in_mask, bit);
|
||||
LoadMask(in_mask, UserMaskedPixelBit);
|
||||
} else if (in_mask.size() == experiment.GetPixelsNum()) {
|
||||
std::vector<uint32_t> raw_mask(nmodules * RAW_MODULE_SIZE);
|
||||
ConvertedToRawGeometry(experiment, raw_mask.data(), in_mask.data());
|
||||
LoadDetectorBadPixelMask(in_mask, bit);
|
||||
LoadMask(raw_mask, UserMaskedPixelBit);
|
||||
} else
|
||||
throw JFJochException(JFJochExceptionCategory::InputParameterInvalid,
|
||||
"Size of input user mask invalid");
|
||||
|
||||
@@ -9,12 +9,21 @@
|
||||
class PixelMask {
|
||||
size_t nmodules;
|
||||
std::vector<uint32_t> mask;
|
||||
void LoadMask(const std::vector<uint32_t>& mask, uint8_t bit);
|
||||
public:
|
||||
// NXmx bits
|
||||
constexpr static const uint8_t ModuleGapPixelBit = 0;
|
||||
constexpr static const uint8_t ErrorPixelBit = 1;
|
||||
constexpr static const uint8_t UserMaskedPixelBit = 8;
|
||||
constexpr static const uint8_t ChipGapPixelBit = 31;
|
||||
constexpr static const uint8_t ModuleEdgePixelBit = 30;
|
||||
|
||||
PixelMask(const DetectorSetup& detector);
|
||||
PixelMask(const DiffractionExperiment& experiment);
|
||||
void LoadUserMask(const DiffractionExperiment& experiment, const std::vector<uint32_t>& mask, uint8_t bit);
|
||||
void LoadDetectorBadPixelMask(const std::vector<uint32_t>& mask, uint8_t bit);
|
||||
std::vector<uint32_t> GetMask(const DiffractionExperiment& experiment);
|
||||
void LoadUserMask(const DiffractionExperiment& experiment, const std::vector<uint32_t>& mask);
|
||||
void LoadDetectorBadPixelMask(const std::vector<uint32_t>& mask);
|
||||
std::vector<uint32_t> GetMask(const DiffractionExperiment& experiment, bool conv = true) const;
|
||||
std::vector<uint32_t> GetUserMask(const DiffractionExperiment& experiment, bool conv = true) const;
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -7,9 +7,12 @@
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
|
||||
enum class PlotType {BkgEstimate, RadInt, RadIntPerTimePoint, SpotCount, IndexingRate, IndexingRatePerTimePoint,
|
||||
ErrorPixels, ImageCollectionEfficiency, ReceiverDelay, ReceiverFreeSendBuf, StrongPixels,
|
||||
ROISum, ROIMaxCount, ROIPixels, ResEstimation};
|
||||
enum class PlotType {
|
||||
BkgEstimate, RadInt, RadIntPerTimePoint, SpotCount, SpotCountInRings,
|
||||
IndexingRate, IndexingRatePerTimePoint,
|
||||
ErrorPixels, ImageCollectionEfficiency, ReceiverDelay, ReceiverFreeSendBuf, StrongPixels,
|
||||
ROISum, ROIMaxCount, ROIPixels
|
||||
};
|
||||
|
||||
struct PlotRequest {
|
||||
PlotType type;
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include <map>
|
||||
#include <mutex>
|
||||
#include <cmath>
|
||||
#include <optional>
|
||||
|
||||
#include "Plot.h"
|
||||
|
||||
@@ -37,6 +38,11 @@ template <class T> class StatusVector {
|
||||
return ret;
|
||||
}
|
||||
public:
|
||||
void AddElement(uint32_t id, std::optional<T> val) {
|
||||
if (val.has_value())
|
||||
AddElement(id, val.value());
|
||||
}
|
||||
|
||||
void AddElement(uint32_t id, T val) {
|
||||
std::unique_lock<std::mutex> ul(m);
|
||||
if (id >= content.size()) {
|
||||
|
||||
@@ -8,8 +8,7 @@ ZMQContext::ZMQContext() {
|
||||
|
||||
// Default is to have 2 I/O threads per ZMQ context
|
||||
if (zmq_ctx_set(context, ZMQ_IO_THREADS, 2) != 0)
|
||||
throw JFJochException(JFJochExceptionCategory::ZeroMQ,
|
||||
"Cannot set number of I/O threads");
|
||||
throw JFJochException(JFJochExceptionCategory::ZeroMQ, "Cannot set number of I/O threads");
|
||||
}
|
||||
|
||||
ZMQContext &ZMQContext::NumThreads(int32_t threads) {
|
||||
@@ -27,7 +26,7 @@ void *ZMQContext::GetContext() const {
|
||||
return context;
|
||||
}
|
||||
|
||||
ZMQSocket::ZMQSocket(ZMQContext &context, ZMQSocketType in_socket_type) : socket_type(in_socket_type) {
|
||||
ZMQSocket::ZMQSocket(ZMQSocketType in_socket_type) : socket_type(in_socket_type) {
|
||||
socket = zmq_socket(context.GetContext(), static_cast<int>(socket_type));
|
||||
|
||||
if (socket == nullptr)
|
||||
|
||||
@@ -42,14 +42,15 @@ public:
|
||||
|
||||
class ZMQSocket {
|
||||
std::mutex m;
|
||||
ZMQContext context;
|
||||
ZMQSocketType socket_type;
|
||||
void *socket;
|
||||
void SetSocketOption(int32_t option_name, int32_t value);
|
||||
public:
|
||||
ZMQSocket(ZMQSocket &socket) = delete;
|
||||
const ZMQSocket& operator=(ZMQSocket &socket) = delete;
|
||||
ZMQSocket(ZMQContext &context, ZMQSocketType socket_type);
|
||||
~ZMQSocket();
|
||||
explicit ZMQSocket(ZMQSocketType socket_type);
|
||||
~ZMQSocket();
|
||||
void Connect(const std::string& addr);
|
||||
void Disconnect(const std::string& addr);
|
||||
void Bind(const std::string& addr);
|
||||
|
||||
@@ -4,8 +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
|
||||
bitshuffle_hperf/bitshuffle.c
|
||||
bitshuffle_hperf/bitshuffle.h
|
||||
JFJochZstdCompressor.cpp
|
||||
JFJochZstdCompressor.h
|
||||
JFJochCompressor.cpp
|
||||
@@ -14,10 +14,7 @@ ADD_LIBRARY(Compression STATIC
|
||||
MaxCompressedSize.cpp
|
||||
MaxCompressedSize.h)
|
||||
|
||||
SET(ZSTD_LEGACY_SUPPORT OFF)
|
||||
SET(ZSTD_MULTITHREAD_SUPPORT OFF)
|
||||
|
||||
TARGET_COMPILE_DEFINITIONS(Compression PUBLIC -DZSTD_SUPPORT -DUSE_ZSTD)
|
||||
TARGET_LINK_LIBRARIES(Compression libzstd_static)
|
||||
TARGET_INCLUDE_DIRECTORIES(Compression PUBLIC . zstd/lib)
|
||||
ADD_SUBDIRECTORY(zstd/build/cmake)
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
#include <stdexcept>
|
||||
#include <cstring>
|
||||
#include <bitshuffle/bitshuffle_internals.h>
|
||||
#include <bitshuffle_hperf/src/bitshuffle.h>
|
||||
#include <bitshuffle_hperf/bitshuffle.h>
|
||||
#include <zstd.h>
|
||||
#include <lz4/lz4.h>
|
||||
|
||||
|
||||
Submodule compression/bitshuffle_hperf deleted from 7be5b2005f
202
compression/bitshuffle_hperf/LICENSE-APACHE
Normal file
202
compression/bitshuffle_hperf/LICENSE-APACHE
Normal file
@@ -0,0 +1,202 @@
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright 2023 Kal Conley
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
1728
compression/bitshuffle_hperf/bitshuffle.c
Normal file
1728
compression/bitshuffle_hperf/bitshuffle.c
Normal file
File diff suppressed because it is too large
Load Diff
68
compression/bitshuffle_hperf/bitshuffle.h
Normal file
68
compression/bitshuffle_hperf/bitshuffle.h
Normal file
@@ -0,0 +1,68 @@
|
||||
/* SPDX-License-Identifier: MIT OR Apache-2.0 */
|
||||
/* Copyright (c) 2023 Kal Conley
|
||||
*/
|
||||
#ifndef BITSHUFFLE_H_
|
||||
#define BITSHUFFLE_H_
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Transpose bits for compression.
|
||||
*
|
||||
* This function performs Bitshuffle transposition of a single block. The block
|
||||
* size in bytes is given by the product of `size` and `elem_size`.
|
||||
*
|
||||
* If required, the `scratch` argument must point to a buffer that the function
|
||||
* uses for scratch purposes. The size of this buffer is given by the block
|
||||
* size.
|
||||
*
|
||||
* On success, the function returns 0; otherwise, -1 is returned to indicate an
|
||||
* error. In case of error, the memory pointed to by `out` and `scratch` is left
|
||||
* unmodified.
|
||||
*
|
||||
* Pointer arguments of this function have C99 `restrict` semantics. If the
|
||||
* `out`, `in`, or `scratch` buffers overlap, the behavior is undefined.
|
||||
*
|
||||
* Errors
|
||||
* ------
|
||||
* The function returns -1 to indicate an error if:
|
||||
*
|
||||
* - The `scratch` argument is `NULL` and a scratch buffer is required for the
|
||||
* specified element size.
|
||||
* - The `size` argument is not a multiple of 8.
|
||||
*/
|
||||
int bitshuf_encode_block(char* out, const char* in, char* scratch, size_t size, size_t elem_size);
|
||||
|
||||
/* Untranspose bits after decompression.
|
||||
*
|
||||
* This function performs the inverse of `bitshuf_encode_block()`.
|
||||
*
|
||||
* If required, the `scratch` argument must point to a buffer that the function
|
||||
* uses for scratch purposes. The size of this buffer is given by the block
|
||||
* size.
|
||||
*
|
||||
* On success, the function returns 0; otherwise, -1 is returned to indicate an
|
||||
* error. In case of error, the memory pointed to by `out` and `scratch` is left
|
||||
* unmodified.
|
||||
*
|
||||
* Pointer arguments of this function have C99 `restrict` semantics. If the
|
||||
* `out`, `in`, or `scratch` buffers overlap, the behavior is undefined.
|
||||
*
|
||||
* Errors
|
||||
* ------
|
||||
* The function returns -1 to indicate an error if:
|
||||
*
|
||||
* - The `scratch` argument is `NULL` and a scratch buffer is required for the
|
||||
* specified element size.
|
||||
* - The `size` argument is not a multiple of 8.
|
||||
*/
|
||||
int bitshuf_decode_block(char* out, const char* in, char* scratch, size_t size, size_t elem_size);
|
||||
|
||||
#if defined(__cplusplus)
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* BITSHUFFLE_H_ */
|
||||
Submodule compression/zstd deleted from 794ea1b0af
@@ -1,7 +1,2 @@
|
||||
ADD_SUBDIRECTORY(slsDetectorPackage)
|
||||
INSTALL(TARGETS sls_detector_put sls_detector_get RUNTIME)
|
||||
|
||||
ADD_LIBRARY(JFJochDetector STATIC DetectorWrapper.cpp DetectorWrapper.h)
|
||||
TARGET_LINK_LIBRARIES(JFJochDetector JFJochCommon slsSupportShared slsDetectorShared)
|
||||
|
||||
|
||||
TARGET_LINK_LIBRARIES(JFJochDetector JFJochCommon slsDetectorStatic slsSupportStatic)
|
||||
|
||||
Submodule detector_control/slsDetectorPackage deleted from bae2614332
@@ -13,13 +13,18 @@
|
||||
struct spot_finder_packet {
|
||||
ap_uint<768> data;
|
||||
ap_uint<32> mask;
|
||||
ap_uint<32> strong_pixel;
|
||||
ap_int<32> count_threshold;
|
||||
ap_uint<32> snr_threshold;
|
||||
ap_uint<1> user;
|
||||
ap_uint<1> last;
|
||||
};
|
||||
|
||||
void spot_finder_in_stream(STREAM_768 &data_in,
|
||||
hls::stream<ap_uint<32>> &mask_in,
|
||||
hls::stream<spot_finder_packet> &data_out) {
|
||||
hls::stream<spot_finder_packet> &data_out,
|
||||
volatile ap_int<32> &in_count_threshold,
|
||||
volatile ap_uint<32> &in_snr_threshold) {
|
||||
ap_uint<32> mask;
|
||||
packet_768_t packet_in;
|
||||
{
|
||||
@@ -33,12 +38,53 @@ void spot_finder_in_stream(STREAM_768 &data_in,
|
||||
while (!packet_in.user) {
|
||||
#pragma HLS PIPELINE II=1
|
||||
mask_in >> mask;
|
||||
data_out << spot_finder_packet{.data = packet_in.data, .mask = mask, .user = packet_in.user, .last = packet_in.last};
|
||||
data_out << spot_finder_packet{
|
||||
.data = packet_in.data,
|
||||
.mask = mask,
|
||||
.strong_pixel = 0,
|
||||
.count_threshold = in_count_threshold,
|
||||
.snr_threshold = in_snr_threshold,
|
||||
.user = packet_in.user,
|
||||
.last = packet_in.last
|
||||
};
|
||||
data_in >> packet_in;
|
||||
}
|
||||
data_out << spot_finder_packet{.data = packet_in.data, .mask = 0, .user = packet_in.user, .last = packet_in.last};
|
||||
}
|
||||
|
||||
void spot_finder_out_stream(hls::stream<spot_finder_packet> &data_in,
|
||||
STREAM_768 &data_out,
|
||||
hls::stream<ap_axiu<32,1,1,1>> &strong_pixel_out) {
|
||||
spot_finder_packet packet_in;
|
||||
{
|
||||
#pragma HLS PROTOCOL fixed
|
||||
data_in >> packet_in;
|
||||
ap_wait();
|
||||
data_out << packet_768_t{.data = packet_in.data, .user = packet_in.user, .last = packet_in.last};
|
||||
ap_wait();
|
||||
}
|
||||
|
||||
data_in >> packet_in;
|
||||
while (!packet_in.user) {
|
||||
ap_uint<32> count_threshold = packet_in.count_threshold;
|
||||
ap_uint<32> snr_threshold_u32 = packet_in.snr_threshold;
|
||||
for (int i = 0; i < RAW_MODULE_SIZE * sizeof(uint16_t) / 64; i++) {
|
||||
#pragma HLS PIPELINE II=1
|
||||
data_out << packet_768_t{.data = packet_in.data, .user = packet_in.user, .last = packet_in.last};
|
||||
strong_pixel_out << ap_axiu<32,1,1,1>{.data = packet_in.strong_pixel, .user = 0};
|
||||
data_in >> packet_in;
|
||||
}
|
||||
|
||||
// Save module statistics
|
||||
strong_pixel_out << ap_axiu<32,1,1,1>{.data = count_threshold, .user = 0};
|
||||
strong_pixel_out << ap_axiu<32,1,1,1>{.data = snr_threshold_u32, .user = 0};
|
||||
for (int i = 0; i < 14;i++)
|
||||
strong_pixel_out << ap_axiu<32,1,1,1>{.data = 0, .user = 0};
|
||||
}
|
||||
strong_pixel_out << ap_axiu<32,1,1,1>{.data = 0, .user = 1};
|
||||
data_out << packet_768_t{.data = packet_in.data, .user = packet_in.user, .last = packet_in.last};
|
||||
}
|
||||
|
||||
ap_int<SUM_BITWIDTH> calc_sum(ap_int<24> val[32], ap_uint<32> mask) {
|
||||
#pragma HLS PIPELINE II=1
|
||||
ap_int<SUM_BITWIDTH> ret = 0;
|
||||
@@ -73,6 +119,8 @@ void spot_finder_prepare(hls::stream<spot_finder_packet> &data_in,
|
||||
hls::stream<ap_int<SUM_BITWIDTH>> &sum_out,
|
||||
hls::stream<ap_int<SUM2_BITWIDTH>> &sum2_out,
|
||||
hls::stream<ap_int<VALID_BITWIDTH>> &valid_out) {
|
||||
ap_uint<32> strong_pixel;
|
||||
|
||||
spot_finder_packet packet;
|
||||
{
|
||||
#pragma HLS PROTOCOL fixed
|
||||
@@ -95,6 +143,7 @@ void spot_finder_prepare(hls::stream<spot_finder_packet> &data_in,
|
||||
for (ap_uint<15> i = 0; i < RAW_MODULE_SIZE * sizeof(uint16_t) / 64; i++) {
|
||||
#pragma HLS PIPELINE II=1
|
||||
data_out << packet;
|
||||
|
||||
ap_int<24> val[32];
|
||||
unpack32(packet.data, val);
|
||||
ap_uint<32> mask = packet.mask;
|
||||
@@ -167,31 +216,28 @@ ap_uint<32> spot_finder_count_threshold(ap_int<24> val[32], ap_int<32> &count_th
|
||||
}
|
||||
|
||||
void spot_finder_apply_threshold(hls::stream<spot_finder_packet> &data_in,
|
||||
STREAM_768 &data_out,
|
||||
hls::stream<spot_finder_packet> &data_out,
|
||||
hls::stream<ap_int<SUM_BITWIDTH>> &sum_in,
|
||||
hls::stream<ap_int<SUM2_BITWIDTH>> &sum2_in,
|
||||
hls::stream<ap_int<VALID_BITWIDTH>> &valid_in,
|
||||
hls::stream<ap_axiu<32,1,1,1>> &strong_pixel_out,
|
||||
volatile ap_int<32> &in_count_threshold,
|
||||
volatile ap_uint<32> &in_snr_threshold) {
|
||||
hls::stream<ap_int<VALID_BITWIDTH>> &valid_in) {
|
||||
ap_uint<32> strong_pixel_prev;
|
||||
spot_finder_packet packet_in;
|
||||
{
|
||||
#pragma HLS PROTOCOL fixed
|
||||
data_in >> packet_in;
|
||||
ap_wait();
|
||||
data_out << packet_768_t{.data = packet_in.data, .user = packet_in.user, .last = packet_in.last};
|
||||
data_out << packet_in;
|
||||
ap_wait();
|
||||
}
|
||||
|
||||
|
||||
ap_int<SUM_BITWIDTH> sum[32];
|
||||
ap_int<SUM2_BITWIDTH> sum2[32];
|
||||
ap_int<VALID_BITWIDTH> valid[32];
|
||||
|
||||
data_in >> packet_in;
|
||||
while (!packet_in.user) {
|
||||
ap_int<32> count_threshold = in_count_threshold;
|
||||
ap_uint<32> snr_threshold_u32 = in_snr_threshold;
|
||||
ap_int<32> count_threshold = packet_in.count_threshold;
|
||||
ap_uint<32> snr_threshold_u32 = packet_in.snr_threshold;
|
||||
float_uint32 thr;
|
||||
thr.u = snr_threshold_u32;
|
||||
ap_ufixed<10,8, AP_RND_CONV> snr_threshold = thr.f;
|
||||
@@ -212,34 +258,28 @@ void spot_finder_apply_threshold(hls::stream<spot_finder_packet> &data_in,
|
||||
valid_in >> valid[i % 32];
|
||||
}
|
||||
|
||||
data_out << packet_768_t{.data = packet_in.data, .user = packet_in.user, .last = packet_in.last};
|
||||
ap_int<24> data_unpacked[32];
|
||||
unpack32(packet_in.data, data_unpacked);
|
||||
|
||||
ap_uint<32> strong_pixel = spot_finder_count_threshold(data_unpacked, count_threshold) &
|
||||
spot_finder_snr_threshold(data_unpacked, snr_threshold_2,
|
||||
sum[i % 32], sum2[i % 32], valid[i % 32]);
|
||||
|
||||
strong_pixel = strong_pixel & packet_in.mask;
|
||||
spot_finder_snr_threshold(data_unpacked, snr_threshold_2,
|
||||
sum[i % 32], sum2[i % 32], valid[i % 32]);
|
||||
|
||||
if ((snr_threshold == 0) && (count_threshold <= 0))
|
||||
strong_pixel = 0;
|
||||
|
||||
strong_pixel_out << ap_axiu<32,1,1,1>{.data = strong_pixel, .user = 0};
|
||||
strong_pixel = strong_pixel & packet_in.mask;
|
||||
|
||||
packet_in.mask |= strong_pixel; // mask strong pixels
|
||||
packet_in.strong_pixel |= strong_pixel; // add strong pixels to the output
|
||||
|
||||
data_out << packet_in;
|
||||
data_in >> packet_in;
|
||||
}
|
||||
|
||||
// Save module statistics
|
||||
strong_pixel_out << ap_axiu<32,1,1,1>{.data = count_threshold, .user = 0};
|
||||
strong_pixel_out << ap_axiu<32,1,1,1>{.data = snr_threshold_u32, .user = 0};
|
||||
for (int i = 0; i < 14;i++)
|
||||
strong_pixel_out << ap_axiu<32,1,1,1>{.data = 0, .user = 0};
|
||||
}
|
||||
strong_pixel_out << ap_axiu<32,1,1,1>{.data = 0, .user = 1};
|
||||
data_out << packet_768_t{.data = packet_in.data, .user = packet_in.user, .last = packet_in.last};
|
||||
data_out << packet_in;
|
||||
}
|
||||
|
||||
|
||||
void spot_finder(STREAM_768 &data_in,
|
||||
hls::stream<ap_uint<32>> &mask_in,
|
||||
STREAM_768 &data_out,
|
||||
@@ -256,22 +296,38 @@ void spot_finder(STREAM_768 &data_in,
|
||||
|
||||
hls::stream<spot_finder_packet, 2> data_0;
|
||||
hls::stream<spot_finder_packet, 1080> data_1;
|
||||
hls::stream<spot_finder_packet, 8> data_2;
|
||||
hls::stream<spot_finder_packet, 1080> data_3;
|
||||
hls::stream<spot_finder_packet, 8> data_4;
|
||||
|
||||
#pragma HLS BIND_STORAGE variable=data_1 type=fifo impl=bram
|
||||
#pragma HLS BIND_STORAGE variable=data_3 type=fifo impl=bram
|
||||
|
||||
hls::stream<ap_int<SUM_BITWIDTH>, 24> sum_0;
|
||||
hls::stream<ap_int<SUM2_BITWIDTH>, 24> sum2_0;
|
||||
hls::stream<ap_int<VALID_BITWIDTH>, 24> valid_0;
|
||||
|
||||
hls::stream<ap_int<SUM_BITWIDTH>, 24> sum_1;
|
||||
hls::stream<ap_int<SUM2_BITWIDTH>, 24> sum2_1;
|
||||
hls::stream<ap_int<VALID_BITWIDTH>, 24> valid_1;
|
||||
|
||||
#ifndef JFJOCH_HLS_NOSYNTH
|
||||
spot_finder_in_stream(data_in, mask_in, data_0);
|
||||
spot_finder_in_stream(data_in, mask_in, data_0, in_count_threshold, in_snr_threshold);
|
||||
spot_finder_prepare(data_0, data_1, sum_0, sum2_0, valid_0);
|
||||
spot_finder_apply_threshold(data_1, data_out, sum_0, sum2_0, valid_0, strong_pixel_out,
|
||||
in_count_threshold, in_snr_threshold);
|
||||
spot_finder_apply_threshold(data_1, data_2, sum_0, sum2_0, valid_0);
|
||||
spot_finder_prepare(data_2, data_3, sum_1, sum2_1, valid_1);
|
||||
spot_finder_apply_threshold(data_3, data_4, sum_1, sum2_1, valid_1);
|
||||
spot_finder_out_stream(data_4, data_out, strong_pixel_out);
|
||||
#else
|
||||
std::vector<std::thread> spot_finder_cores;
|
||||
spot_finder_cores.emplace_back([&] {spot_finder_in_stream(data_in, mask_in, data_0);});
|
||||
spot_finder_cores.emplace_back([&] {spot_finder_in_stream(data_in, mask_in, data_0, in_count_threshold,
|
||||
in_snr_threshold);});
|
||||
spot_finder_cores.emplace_back([&] {spot_finder_prepare(data_0, data_1, sum_0, sum2_0, valid_0);});
|
||||
spot_finder_cores.emplace_back([&] {spot_finder_apply_threshold(data_1, data_out, sum_0, sum2_0, valid_0,
|
||||
strong_pixel_out, in_count_threshold,
|
||||
in_snr_threshold);});
|
||||
spot_finder_cores.emplace_back([&] {spot_finder_apply_threshold(data_1, data_2, sum_0, sum2_0, valid_0);});
|
||||
spot_finder_cores.emplace_back([&] {spot_finder_prepare(data_2, data_3, sum_1, sum2_1, valid_1);});
|
||||
spot_finder_cores.emplace_back([&] {spot_finder_apply_threshold(data_3, data_4, sum_1, sum2_1, valid_1);});
|
||||
spot_finder_cores.emplace_back([&] {spot_finder_out_stream(data_4, data_out, strong_pixel_out);});
|
||||
|
||||
for (auto &i : spot_finder_cores)
|
||||
i.join();
|
||||
#endif
|
||||
|
||||
@@ -66,14 +66,16 @@ void spot_finder_mask(STREAM_768 &data_in,
|
||||
ap_uint<5> col = i % 32;
|
||||
|
||||
for (int j = 0; j < 32; j++) {
|
||||
if ((line == 255)
|
||||
if ((line == 0)
|
||||
|| (line == 255)
|
||||
|| (line == 256)
|
||||
|| (((col == 7) || (col == 15) || (col == 23)) && (j == 31))
|
||||
|| (((col == 8) || (col == 16) || (col == 24)) && (j == 0))
|
||||
|| (line == 511)
|
||||
|| (((col == 7) || (col == 15) || (col == 23) || (col == 31)) && (j == 31))
|
||||
|| (((col == 0) || (col == 8) || (col == 16) || (col == 24)) && (j == 0))
|
||||
|| (pixel_val[j] == INT24_MIN)
|
||||
|| (pixel_val[j] == INT24_MAX)
|
||||
|| ((d[j] != 0) && (d[j] < min_d_value))
|
||||
|| ((d[j] != 0) && (d[j] > max_d_value)))
|
||||
|| (d[j] < min_d_value)
|
||||
|| (d[j] > max_d_value))
|
||||
mask_val[j] = 0;
|
||||
else
|
||||
mask_val[j] = 1;
|
||||
|
||||
@@ -4,7 +4,7 @@ TARGET_LINK_LIBRARIES(JFJochDevice JFJochCommon)
|
||||
|
||||
ADD_EXECUTABLE(jfjoch_pcie_status jfjoch_pcie_status.cpp)
|
||||
TARGET_LINK_LIBRARIES(jfjoch_pcie_status JFJochDevice )
|
||||
INSTALL(TARGETS jfjoch_pcie_status RUNTIME)
|
||||
INSTALL(TARGETS jfjoch_pcie_status RUNTIME COMPONENT jfjoch)
|
||||
|
||||
ADD_EXECUTABLE(jfjoch_pcie_set_network jfjoch_pcie_set_network.cpp)
|
||||
TARGET_LINK_LIBRARIES(jfjoch_pcie_set_network JFJochDevice )
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
PACKAGE_NAME=jfjoch
|
||||
PACKAGE_VERSION=0.1
|
||||
PACKAGE_VERSION=1.0.0
|
||||
|
||||
DEST_MODULE_LOCATION=/extra
|
||||
BUILT_MODULE_NAME=jfjoch
|
||||
@@ -7,4 +7,4 @@ BUILT_MODULE_LOCATION=src/
|
||||
|
||||
MAKE="'make' -C src/ all"
|
||||
CLEAN="'make' -C src/ clean"
|
||||
AUTOINSTALL="yes"
|
||||
AUTOINSTALL="yes"
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Copyright (2019-2023) Paul Scherrer Institute
|
||||
VERSION=0.1
|
||||
VERSION=1.0.0
|
||||
|
||||
mkdir -p /usr/src/jfjoch-${VERSION}/src
|
||||
cp dkms.conf /usr/src/jfjoch-${VERSION}
|
||||
cp *.c *.h Makefile ../../common/Definitions.h /usr/src/jfjoch-0.1/src
|
||||
sed -i "s,../../common/Definitions.h,Definitions.h," /usr/src/jfjoch-0.1/src/jfjoch_drv.h
|
||||
cp *.c *.h Makefile /usr/src/jfjoch-${VERSION}/src
|
||||
|
||||
dkms add -m jfjoch -v ${VERSION}
|
||||
dkms install -m jfjoch -v ${VERSION}
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
MODULE_AUTHOR("Filip Leonarski; Paul Scherrer Institute");
|
||||
MODULE_DESCRIPTION("Jungfraujoch device module");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_VERSION("0.1");
|
||||
MODULE_VERSION("1.0.0");
|
||||
|
||||
#define XDMA_GEN4_x8 (0x9048)
|
||||
#define XDMA_GEN3_x16 (0x903F)
|
||||
|
||||
@@ -54,12 +54,13 @@ int jfjoch_check_version(struct pci_dev *pdev) {
|
||||
release_level = ioread32(drvdata->bar0 + ACTION_CONFIG_OFFSET + ADDR_RELEASE_LEVEL);
|
||||
|
||||
if (action_type != JFJOCH_FPGA_MAGIC) {
|
||||
dev_err(dev, "Mismatch in JFJoch action type (%x)\n", action_type);
|
||||
dev_err(dev, "Very likely the FPGA is not flashed with Jungfraujoch design, given that action type register value is wrong (%x).\n", action_type);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (release_level != JFJOCH_FPGA_RELEASE) {
|
||||
dev_err(dev, "Mismatch in JFJoch release level (%x)\n", release_level);
|
||||
dev_err(dev, "Jungfraujoch FPGA is flashed with design made with release %x, while driver is compiled with release %x.\n", release_level, JFJOCH_FPGA_RELEASE);
|
||||
dev_err(dev, "Given FPGA releases have braking changes in FPGA-driver interface (register map, data structure size, etc.)\n it is not safe and not supported at the moment to operate multiple releases with one driver.\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
return 0;
|
||||
|
||||
@@ -3,4 +3,4 @@
|
||||
GIT_SHA1=`git describe --match=NeVeRmAtCh --always --abbrev=8`
|
||||
RELEASE_LEVEL=`grep "#define JFJOCH_FPGA_RELEASE" jfjoch_fpga.h | awk -F"0x" '{print $2}'`
|
||||
|
||||
tar cvzf jfjoch_driver_rel${RELEASE_LEVEL}_${GIT_SHA1}.tar.gz *.c *.h README.md Makefile dkms.conf install_dkms.sh >/dev/null 2>&1
|
||||
tar cvzf jfjoch_driver.tar.gz *.c *.h README.md Makefile dkms.conf install_dkms.sh >/dev/null 2>&1
|
||||
|
||||
14
fpga/pcie_driver/postinstall.sh
Normal file
14
fpga/pcie_driver/postinstall.sh
Normal file
@@ -0,0 +1,14 @@
|
||||
#!/bin/bash
|
||||
# Taken from https://schneide.blog/2015/08/10/packaging-kernel-modulesdrivers-using-dkms/
|
||||
|
||||
VERSION="1.0.0"
|
||||
|
||||
occurrences=`/usr/sbin/dkms status | grep jfjoch | grep ${VERSION} | wc -l`
|
||||
|
||||
if [ ! occurrences > 0 ]; then
|
||||
/usr/sbin/dkms add -m jfjoch -v ${VERSION}
|
||||
fi
|
||||
/usr/sbin/dkms build -m jfjoch -v ${VERSION}
|
||||
/usr/sbin/dkms install -m jfjoch -v ${VERSION}
|
||||
|
||||
exit 0
|
||||
8
fpga/pcie_driver/preuninstall.sh
Normal file
8
fpga/pcie_driver/preuninstall.sh
Normal file
@@ -0,0 +1,8 @@
|
||||
#!/bin/bash
|
||||
# Taken from https://schneide.blog/2015/08/10/packaging-kernel-modulesdrivers-using-dkms/
|
||||
|
||||
VERSION="1.0.0"
|
||||
|
||||
/usr/sbin/dkms remove -m jfjoch -v ${VERSION} --all
|
||||
|
||||
exit 0
|
||||
@@ -33,7 +33,12 @@ ACTION_TYPE=`grep "#define JFJOCH_FPGA_MAGIC" ${SRC_DIR}/pcie_driver/jfjoch_fpga
|
||||
RELEASE_LEVEL=`grep "#define JFJOCH_FPGA_RELEASE" ${SRC_DIR}/pcie_driver/jfjoch_fpga.h | awk -F"0x" '{print $2}'`
|
||||
MAX_MODULES_FPGA=`grep "#define MAX_MODULES_FPGA" ${SRC_DIR}/pcie_driver/jfjoch_fpga.h |tr -s " " |cut -f3 -d" "`
|
||||
|
||||
GIT_SHA1=`git describe --match=NeVeRmAtCh --always --abbrev=8`
|
||||
git describe --match=NeVeRmAtCh --always --abbrev=8
|
||||
if [ $? -eq 0 ]; then
|
||||
GIT_SHA1=`git describe --match=NeVeRmAtCh --always --abbrev=8`
|
||||
else
|
||||
GIT_SHA1=0
|
||||
fi
|
||||
|
||||
SRC="define JFJOCH_MAGIC 32'h.*"
|
||||
DST="define JFJOCH_MAGIC 32'h${ACTION_TYPE}"
|
||||
|
||||
@@ -23,7 +23,7 @@ if {$part eq {xcvu35p-fsvh2104-2-e}} {
|
||||
set interface "SPIx8"
|
||||
}
|
||||
|
||||
set bitstream_name jfjoch_${flow}_${fpga_name}_rel@RELEASE_LEVEL@_@GIT_SHA1@
|
||||
set bitstream_name jfjoch_fpga_${flow}
|
||||
|
||||
puts "Part $part Flash size ${fpga_flash_size} Flow ${flow} Image name ${bitstream_name}"
|
||||
set log_file synth.log
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
// Copyright (2019-2023) Paul Scherrer Institute
|
||||
|
||||
#include "CBORStream2Deserializer.h"
|
||||
#include "tinycbor/src/cbor.h"
|
||||
#include "CborErr.h"
|
||||
#include "CborUtil.h"
|
||||
#include <nlohmann/json.hpp>
|
||||
@@ -457,6 +456,8 @@ namespace {
|
||||
message.user_data = GetCBORString(value);
|
||||
else if (key == "spots")
|
||||
GetCBORSpots(message, value);
|
||||
else if (key == "spot_count_in_rings")
|
||||
message.spot_count_in_rings = GetCBORUInt(value);
|
||||
else if (key == "az_int_profile")
|
||||
GetCBORFloatArray(value, message.az_int_profile);
|
||||
else if (key == "indexing_result")
|
||||
@@ -637,6 +638,8 @@ namespace {
|
||||
message.roi_names = j["roi_names"];
|
||||
if (j.contains("write_master_file"))
|
||||
message.write_master_file = j["write_master_file"];
|
||||
if (j.contains("data_reduction_factor_serialmx"))
|
||||
message.data_reduction_factor_serialmx = j["data_reduction_factor_serialmx"];
|
||||
} catch (const std::exception &e) {
|
||||
throw JFJochException(JFJochExceptionCategory::CBORError,
|
||||
"Cannot parse user_data as valid JSON " + std::string(e.what()));
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
#include <memory>
|
||||
|
||||
#include "../common/SpotToSave.h"
|
||||
#include "tinycbor/src/cbor.h"
|
||||
#include "tinycbor/cbor.h"
|
||||
#include "JFJochMessages.h"
|
||||
#include <mutex>
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Copyright (2019-2023) Paul Scherrer Institute
|
||||
|
||||
#include "CBORStream2Serializer.h"
|
||||
#include "tinycbor/src/cbor.h"
|
||||
#include "tinycbor/cbor.h"
|
||||
#include "CborErr.h"
|
||||
#include "CborUtil.h"
|
||||
#include <nlohmann/json.hpp>
|
||||
@@ -316,6 +316,8 @@ inline void CBOR_ENC_START_USER_DATA(CborEncoder& encoder, const char* key,
|
||||
j["gain_file_names"] = message.gain_file_names;
|
||||
if (message.write_master_file)
|
||||
j["write_master_file"] = message.write_master_file.value();
|
||||
if (message.data_reduction_factor_serialmx)
|
||||
j["data_reduction_factor_serialmx"] = message.data_reduction_factor_serialmx.value();
|
||||
|
||||
auto str = j.dump();
|
||||
|
||||
@@ -448,6 +450,8 @@ void CBORStream2Serializer::SerializeImage(const DataMessage& message) {
|
||||
CBOR_ENC_RATIONAL(mapEncoder, "end_time", message.timestamp + message.exptime, message.timestamp_base);
|
||||
|
||||
CBOR_ENC(mapEncoder, "spots", message.spots);
|
||||
CBOR_ENC(mapEncoder, "spot_count_in_rings", message.spot_count_in_rings);
|
||||
|
||||
CBOR_ENC(mapEncoder, "az_int_profile", message.az_int_profile);
|
||||
CBOR_ENC(mapEncoder, "indexing_result", message.indexing_result);
|
||||
if (!message.indexing_lattice.empty())
|
||||
|
||||
@@ -1,24 +1,27 @@
|
||||
ADD_LIBRARY(tinycbor STATIC
|
||||
tinycbor/cborparser_dup_string.c
|
||||
tinycbor/cborencoder.c
|
||||
tinycbor/cborencoder_close_container_checked.c
|
||||
tinycbor/cborencoder_float.c
|
||||
tinycbor/cborparser.c
|
||||
tinycbor/cborparser_float.c
|
||||
tinycbor/cborpretty.c
|
||||
tinycbor/cborerrorstrings.c
|
||||
tinycbor/cbor.h
|
||||
tinycbor/tinycbor-version.h)
|
||||
|
||||
ADD_LIBRARY(CBORStream2FrameSerialize STATIC
|
||||
CBORStream2Serializer.cpp CBORStream2Serializer.h
|
||||
CBORStream2Deserializer.cpp CBORStream2Deserializer.h
|
||||
tinycbor/src/cborparser_dup_string.c
|
||||
tinycbor/src/cborencoder.c
|
||||
tinycbor/src/cborencoder_close_container_checked.c
|
||||
tinycbor/src/cborencoder_float.c
|
||||
tinycbor/src/cborparser.c
|
||||
tinycbor/src/cborparser_float.c
|
||||
tinycbor/src/cborpretty.c
|
||||
tinycbor/src/cborerrorstrings.c
|
||||
tinycbor/src/cbor.h
|
||||
tinycbor/src/tinycbor-version.h CborErr.h CborUtil.h JFJochMessages.h)
|
||||
CborErr.h CborUtil.h JFJochMessages.h)
|
||||
|
||||
TARGET_LINK_LIBRARIES(CBORStream2FrameSerialize tinycbor)
|
||||
|
||||
ADD_LIBRARY(ImagePusher STATIC
|
||||
ImagePusher.cpp ImagePusher.h
|
||||
TestImagePusher.cpp TestImagePusher.h
|
||||
ZMQStream2PusherGroup.cpp ZMQStream2PusherGroup.h
|
||||
ZMQStream2Pusher.cpp
|
||||
ZMQStream2Pusher.h
|
||||
ZMQStream2Pusher.cpp ZMQStream2Pusher.h
|
||||
DumpCBORToFilePusher.cpp
|
||||
DumpCBORToFilePusher.h)
|
||||
|
||||
TARGET_LINK_LIBRARIES(ImagePusher CBORStream2FrameSerialize JFJochCommon Compression)
|
||||
TARGET_LINK_LIBRARIES(ImagePusher JFJochZMQ CBORStream2FrameSerialize JFJochCommon Compression)
|
||||
@@ -3,7 +3,7 @@
|
||||
#ifndef JUNGFRAUJOCH_CBORERR_H
|
||||
#define JUNGFRAUJOCH_CBORERR_H
|
||||
|
||||
#include "tinycbor/src/cbor.h"
|
||||
#include "tinycbor/cbor.h"
|
||||
#include "../common/JFJochException.h"
|
||||
|
||||
inline void cborErr(CborError err) {
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
#ifndef JUNGFRAUJOCH_CBORUTIL_H
|
||||
#define JUNGFRAUJOCH_CBORUTIL_H
|
||||
|
||||
#include "tinycbor/src/cbor.h"
|
||||
#include "tinycbor/cbor.h"
|
||||
|
||||
constexpr const CborTag TagMultiDimArray = 40;
|
||||
constexpr const CborTag TagDECTRISCompression = 56500;
|
||||
|
||||
@@ -45,6 +45,7 @@ struct DataMessage {
|
||||
float image_collection_efficiency;
|
||||
|
||||
std::vector<SpotToSave> spots;
|
||||
std::optional<uint64_t> spot_count_in_rings = 0;
|
||||
|
||||
std::vector<float> az_int_profile;
|
||||
float bkg_estimate;
|
||||
@@ -75,8 +76,6 @@ struct DataMessage {
|
||||
std::optional<uint64_t> receiver_free_send_buf;
|
||||
std::optional<uint64_t> storage_cell;
|
||||
|
||||
std::optional<float> resolution_estimation;
|
||||
|
||||
std::optional<uint64_t> xfel_pulse_id;
|
||||
std::optional<uint64_t> xfel_event_code;
|
||||
|
||||
@@ -170,6 +169,8 @@ struct StartMessage {
|
||||
}
|
||||
|
||||
std::string user_data;
|
||||
|
||||
std::optional<float> data_reduction_factor_serialmx;
|
||||
};
|
||||
|
||||
struct EndMessage {
|
||||
|
||||
@@ -1,66 +1,117 @@
|
||||
// Copyright (2019-2024) Paul Scherrer Institute
|
||||
|
||||
#include "ZMQStream2Pusher.h"
|
||||
#include "CBORStream2Serializer.h"
|
||||
|
||||
ZMQStream2Pusher::ZMQStream2Pusher(ZMQContext &context, const std::string &addr, int32_t send_buffer_high_watermark,
|
||||
int32_t send_buffer_size)
|
||||
: socket(context, ZMQSocketType::Push) {
|
||||
Bind(addr, send_buffer_high_watermark, send_buffer_size);
|
||||
}
|
||||
ZMQStream2Pusher::ZMQStream2Pusher(const std::vector<std::string> &addr,
|
||||
int32_t send_buffer_high_watermark, int32_t send_buffer_size)
|
||||
: serialization_buffer(256*1024*1024),
|
||||
serializer(serialization_buffer.data(), serialization_buffer.size()),
|
||||
preview_counter(std::chrono::seconds(1)) {
|
||||
if (addr.empty())
|
||||
throw JFJochException(JFJochExceptionCategory::InputParameterInvalid, "No writer ZMQ address provided");
|
||||
|
||||
ZMQStream2Pusher::ZMQStream2Pusher(const std::string &addr, int32_t send_buffer_high_watermark,
|
||||
int32_t send_buffer_size)
|
||||
: context(std::make_unique<ZMQContext>()),
|
||||
socket(*context, ZMQSocketType::Push) {
|
||||
Bind(addr, send_buffer_high_watermark, send_buffer_size);
|
||||
}
|
||||
|
||||
void ZMQStream2Pusher::Bind(const std::string &addr, int32_t send_buffer_high_watermark, int32_t send_buffer_size) {
|
||||
|
||||
if (send_buffer_size > 0)
|
||||
socket.SendBufferSize(send_buffer_size);
|
||||
if (send_buffer_high_watermark > 0)
|
||||
socket.SendWaterMark(send_buffer_high_watermark);
|
||||
socket.SendTimeout(std::chrono::seconds(5)); // 5 seconds should be more than enough to flush buffers and to still give fast response
|
||||
socket.Bind(addr);
|
||||
}
|
||||
|
||||
void ZMQStream2Pusher::StartDataCollection(StartMessage &message) {
|
||||
size_t approx_size = 1024*1024;
|
||||
for (const auto &x : message.pixel_mask)
|
||||
approx_size += x.size;
|
||||
|
||||
std::vector<uint8_t> serialization_buffer(approx_size);
|
||||
CBORStream2Serializer serializer(serialization_buffer.data(), serialization_buffer.size());
|
||||
serializer.SerializeSequenceStart(message);
|
||||
if (!socket.Send(serialization_buffer.data(), serializer.GetBufferSize(), true))
|
||||
throw JFJochException(JFJochExceptionCategory::ZeroMQ, "Timeout on pushing start message on addr " + GetAddress());
|
||||
for (const auto &a : addr) {
|
||||
auto s = std::make_unique<ZMQSocket>(ZMQSocketType::Push);
|
||||
if (send_buffer_size > 0)
|
||||
s->SendBufferSize(send_buffer_size);
|
||||
if (send_buffer_high_watermark > 0)
|
||||
s->SendWaterMark(send_buffer_high_watermark);
|
||||
s->SendTimeout(std::chrono::seconds(5)); // 5 seconds should be more than enough to flush buffers and to still give fast response
|
||||
s->Bind(a);
|
||||
socket.emplace_back(std::move(s));
|
||||
}
|
||||
}
|
||||
|
||||
bool ZMQStream2Pusher::SendImage(const uint8_t *image_data, size_t image_size, int64_t image_number) {
|
||||
return socket.Send(image_data, image_size, false);
|
||||
if (preview_socket) {
|
||||
if (preview_counter.GeneratePreview())
|
||||
preview_socket->Send(image_data, image_size, false);
|
||||
}
|
||||
|
||||
if (!socket.empty()) {
|
||||
auto socket_number = (image_number / images_per_file) % socket.size();
|
||||
return socket[socket_number]->Send(image_data, image_size, false);
|
||||
} else
|
||||
return false;
|
||||
}
|
||||
|
||||
void ZMQStream2Pusher::SendImage(const uint8_t *image_data, size_t image_size, int64_t image_number,
|
||||
ZeroCopyReturnValue *z) {
|
||||
socket.SendZeroCopy(image_data,image_size, z);
|
||||
ZeroCopyReturnValue *z) {
|
||||
if (preview_socket) {
|
||||
if (preview_counter.GeneratePreview())
|
||||
preview_socket->Send(image_data, image_size, false);
|
||||
}
|
||||
|
||||
if (!socket.empty()) {
|
||||
auto socket_number = (image_number / images_per_file) % socket.size();
|
||||
socket[socket_number]->SendZeroCopy(image_data, image_size, z);
|
||||
} else
|
||||
z->release();
|
||||
}
|
||||
|
||||
bool ZMQStream2Pusher::EndDataCollection(const EndMessage &message) {
|
||||
std::vector<uint8_t> serialization_buffer(80 * 1024 * 1024);
|
||||
CBORStream2Serializer serializer(serialization_buffer.data(), serialization_buffer.size());
|
||||
void ZMQStream2Pusher::StartDataCollection(StartMessage& message) {
|
||||
if (message.images_per_file < 1)
|
||||
throw JFJochException(JFJochExceptionCategory::InputParameterInvalid,
|
||||
"Images per file cannot be zero or negative");
|
||||
images_per_file = message.images_per_file;
|
||||
|
||||
serializer.SerializeSequenceEnd(message);
|
||||
return socket.Send(serialization_buffer.data(), serializer.GetBufferSize(), true); // Blocking
|
||||
serializer.SerializeSequenceStart(message);
|
||||
|
||||
for (auto &s: socket) {
|
||||
if (!s->Send(serialization_buffer.data(), serializer.GetBufferSize(), true))
|
||||
throw JFJochException(JFJochExceptionCategory::ZeroMQ, "Timeout on pushing start message on addr "
|
||||
+ s->GetEndpointName());
|
||||
if (message.write_master_file) {
|
||||
message.write_master_file = false;
|
||||
serializer.SerializeSequenceStart(message);
|
||||
}
|
||||
}
|
||||
|
||||
if (preview_socket)
|
||||
preview_socket->Send(serialization_buffer.data(), serializer.GetBufferSize(), true);
|
||||
}
|
||||
|
||||
bool ZMQStream2Pusher::SendCalibration(const CompressedImage &message) {
|
||||
std::vector<uint8_t> serialization_buffer(80 * 1024 * 1024);
|
||||
CBORStream2Serializer serializer(serialization_buffer.data(), serialization_buffer.size());
|
||||
if (socket.empty())
|
||||
return false;
|
||||
|
||||
serializer.SerializeCalibration(message);
|
||||
return socket.Send(serialization_buffer.data(), serializer.GetBufferSize(), true); // Blocking
|
||||
|
||||
return socket[0]->Send(serialization_buffer.data(), serializer.GetBufferSize(), true);
|
||||
}
|
||||
|
||||
std::string ZMQStream2Pusher::GetAddress() {
|
||||
return socket.GetEndpointName();
|
||||
bool ZMQStream2Pusher::EndDataCollection(const EndMessage& message) {
|
||||
serializer.SerializeSequenceEnd(message);
|
||||
|
||||
bool ret = true;
|
||||
for (auto &s: socket) {
|
||||
if (!s->Send(serialization_buffer.data(), serializer.GetBufferSize(), true))
|
||||
ret = false;
|
||||
}
|
||||
|
||||
if (preview_socket)
|
||||
preview_socket->Send(serialization_buffer.data(), serializer.GetBufferSize(), true);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::vector<std::string> ZMQStream2Pusher::GetAddress() {
|
||||
std::vector<std::string> ret;
|
||||
for (auto &p: socket)
|
||||
ret.push_back(p->GetEndpointName());
|
||||
return ret;
|
||||
}
|
||||
|
||||
ZMQStream2Pusher &ZMQStream2Pusher::PreviewSocket(const std::string &addr) {
|
||||
preview_socket = std::make_unique<ZMQSocket>(ZMQSocketType::Pub);
|
||||
preview_socket->Bind(addr);
|
||||
return *this;
|
||||
}
|
||||
|
||||
std::string ZMQStream2Pusher::GetPreviewAddress() {
|
||||
if (preview_socket)
|
||||
return preview_socket->GetEndpointName();
|
||||
else
|
||||
return "";
|
||||
}
|
||||
|
||||
@@ -3,30 +3,40 @@
|
||||
#ifndef JUNGFRAUJOCH_ZMQSTREAM2PUSHER_H
|
||||
#define JUNGFRAUJOCH_ZMQSTREAM2PUSHER_H
|
||||
|
||||
#include <mutex>
|
||||
|
||||
#include "ImagePusher.h"
|
||||
#include "../common/ZMQWrappers.h"
|
||||
#include "../preview/PreviewCounter.h"
|
||||
|
||||
class ZMQStream2Pusher : public ImagePusher {
|
||||
std::unique_ptr<ZMQContext> context;
|
||||
ZMQSocket socket;
|
||||
public:
|
||||
ZMQStream2Pusher(ZMQContext& context,
|
||||
const std::string& addr,
|
||||
int32_t send_buffer_high_watermark = -1,
|
||||
int32_t send_buffer_size = -1);
|
||||
std::vector<uint8_t> serialization_buffer;
|
||||
CBORStream2Serializer serializer;
|
||||
|
||||
explicit ZMQStream2Pusher(const std::string& addr,
|
||||
std::vector<std::unique_ptr<ZMQSocket>> socket;
|
||||
|
||||
std::unique_ptr<ZMQSocket> preview_socket;
|
||||
PreviewCounter preview_counter;
|
||||
|
||||
int64_t images_per_file = 1;
|
||||
public:
|
||||
explicit ZMQStream2Pusher(const std::vector<std::string>& addr,
|
||||
int32_t send_buffer_high_watermark = -1,
|
||||
int32_t send_buffer_size = -1);
|
||||
void Bind(const std::string& addr, int32_t send_buffer_high_watermark, int32_t send_buffer_size);
|
||||
|
||||
ZMQStream2Pusher& PreviewSocket(const std::string& addr);
|
||||
std::string GetPreviewAddress();
|
||||
|
||||
std::vector<std::string> GetAddress();
|
||||
|
||||
// Strictly serial, as order of these is important
|
||||
void StartDataCollection(StartMessage& message) override;
|
||||
bool SendImage(const uint8_t *image_data, size_t image_size, int64_t image_number) override;
|
||||
void SendImage(const uint8_t *image_data, size_t image_size, int64_t image_number, ZeroCopyReturnValue *z) override;
|
||||
bool EndDataCollection(const EndMessage &message) override;
|
||||
bool EndDataCollection(const EndMessage& message) override;
|
||||
bool SendCalibration(const CompressedImage& message) override;
|
||||
|
||||
std::string GetAddress();
|
||||
// Thread-safe
|
||||
void SendImage(const uint8_t *image_data, size_t image_size, int64_t image_number, ZeroCopyReturnValue *z) override;
|
||||
bool SendImage(const uint8_t *image_data, size_t image_size, int64_t image_number) override;
|
||||
};
|
||||
|
||||
|
||||
#endif //JUNGFRAUJOCH_ZMQSTREAM2PUSHER_H
|
||||
|
||||
@@ -1,75 +0,0 @@
|
||||
// Copyright (2019-2024) Paul Scherrer Institute
|
||||
|
||||
#include "ZMQStream2PusherGroup.h"
|
||||
#include "CBORStream2Serializer.h"
|
||||
|
||||
ZMQStream2PusherGroup::ZMQStream2PusherGroup(ZMQContext &zmq_context, const std::vector<std::string> &addr,
|
||||
int32_t send_buffer_high_watermark, int32_t send_buffer_size) {
|
||||
if (addr.empty())
|
||||
throw JFJochException(JFJochExceptionCategory::InputParameterInvalid,
|
||||
"No writer ZMQ address provided");
|
||||
|
||||
for (const auto &a : addr)
|
||||
pusher.emplace_back(std::make_unique<ZMQStream2Pusher>
|
||||
(zmq_context, a, send_buffer_high_watermark, send_buffer_size));
|
||||
}
|
||||
|
||||
ZMQStream2PusherGroup::ZMQStream2PusherGroup(const std::vector<std::string> &addr,
|
||||
int32_t send_buffer_high_watermark, int32_t send_buffer_size) {
|
||||
if (addr.empty())
|
||||
throw JFJochException(JFJochExceptionCategory::InputParameterInvalid,
|
||||
"No writer ZMQ address provided");
|
||||
for (const auto &a : addr)
|
||||
pusher.emplace_back(std::make_unique<ZMQStream2Pusher>
|
||||
(a, send_buffer_high_watermark, send_buffer_size));
|
||||
}
|
||||
|
||||
bool ZMQStream2PusherGroup::SendImage(const uint8_t *image_data, size_t image_size, int64_t image_number) {
|
||||
if (!pusher.empty()) {
|
||||
auto socket_number = (image_number / images_per_file) % pusher.size();
|
||||
return pusher[socket_number]->SendImage(image_data, image_size, image_number);
|
||||
} else
|
||||
return false;
|
||||
}
|
||||
|
||||
void ZMQStream2PusherGroup::SendImage(const uint8_t *image_data, size_t image_size, int64_t image_number,
|
||||
ZeroCopyReturnValue *z) {
|
||||
if (!pusher.empty()) {
|
||||
auto socket_number = (image_number / images_per_file) % pusher.size();
|
||||
pusher[socket_number]->SendImage(image_data, image_size, image_number, z);
|
||||
}
|
||||
}
|
||||
|
||||
void ZMQStream2PusherGroup::StartDataCollection(StartMessage& message) {
|
||||
if (message.images_per_file < 1)
|
||||
throw JFJochException(JFJochExceptionCategory::InputParameterInvalid,
|
||||
"Images per file cannot be zero or negative");
|
||||
images_per_file = message.images_per_file;
|
||||
|
||||
for (auto &p: pusher) {
|
||||
p->StartDataCollection(message);
|
||||
message.write_master_file = false;
|
||||
}
|
||||
}
|
||||
|
||||
bool ZMQStream2PusherGroup::SendCalibration(const CompressedImage &message) {
|
||||
if (pusher.empty())
|
||||
return false;
|
||||
return pusher[0]->SendCalibration(message);
|
||||
}
|
||||
|
||||
bool ZMQStream2PusherGroup::EndDataCollection(const EndMessage& message) {
|
||||
bool ret = true;
|
||||
for (auto &p: pusher) {
|
||||
if (!p->EndDataCollection(message))
|
||||
ret = false;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::vector<std::string> ZMQStream2PusherGroup::GetAddress() {
|
||||
std::vector<std::string> ret;
|
||||
for (auto &p: pusher)
|
||||
ret.push_back(p->GetAddress());
|
||||
return ret;
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
// Copyright (2019-2024) Paul Scherrer Institute
|
||||
|
||||
#ifndef JUNGFRAUJOCH_ZMQSTREAM2PUSHERGROUP_H
|
||||
#define JUNGFRAUJOCH_ZMQSTREAM2PUSHERGROUP_H
|
||||
|
||||
#include "ImagePusher.h"
|
||||
#include "ZMQStream2Pusher.h"
|
||||
#include "../common/ZMQWrappers.h"
|
||||
|
||||
class ZMQStream2PusherGroup : public ImagePusher {
|
||||
std::vector<std::unique_ptr<ZMQStream2Pusher>> pusher;
|
||||
int64_t images_per_file = 1;
|
||||
public:
|
||||
ZMQStream2PusherGroup(ZMQContext &context, const std::vector<std::string>& addr,
|
||||
int32_t send_buffer_high_watermark = -1, int32_t send_buffer_size = -1);
|
||||
// High performance implementation, where each socket has dedicated ZMQ context
|
||||
explicit ZMQStream2PusherGroup(const std::vector<std::string>& addr,
|
||||
int32_t send_buffer_high_watermark = -1, int32_t send_buffer_size = -1);
|
||||
|
||||
void StartDataCollection(StartMessage& message) override;
|
||||
void SendImage(const uint8_t *image_data, size_t image_size, int64_t image_number, ZeroCopyReturnValue *z) override;
|
||||
bool SendImage(const uint8_t *image_data, size_t image_size, int64_t image_number) override;
|
||||
bool EndDataCollection(const EndMessage& message) override;
|
||||
bool SendCalibration(const CompressedImage& message) override;
|
||||
|
||||
std::vector<std::string> GetAddress();
|
||||
};
|
||||
|
||||
#endif //JUNGFRAUJOCH_ZMQSTREAM2PUSHERGROUP_H
|
||||
Submodule frame_serialize/tinycbor deleted from 3cba6b11aa
21
frame_serialize/tinycbor/LICENSE
Normal file
21
frame_serialize/tinycbor/LICENSE
Normal file
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2017 Intel Corporation
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
724
frame_serialize/tinycbor/cbor.h
Normal file
724
frame_serialize/tinycbor/cbor.h
Normal file
@@ -0,0 +1,724 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2021 Intel Corporation
|
||||
**
|
||||
** Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
** of this software and associated documentation files (the "Software"), to deal
|
||||
** in the Software without restriction, including without limitation the rights
|
||||
** to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
** copies of the Software, and to permit persons to whom the Software is
|
||||
** furnished to do so, subject to the following conditions:
|
||||
**
|
||||
** The above copyright notice and this permission notice shall be included in
|
||||
** all copies or substantial portions of the Software.
|
||||
**
|
||||
** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
** OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
** THE SOFTWARE.
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef CBOR_H
|
||||
#define CBOR_H
|
||||
|
||||
#ifndef assert
|
||||
#include <assert.h>
|
||||
#endif
|
||||
#include <limits.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "tinycbor-version.h"
|
||||
|
||||
#define TINYCBOR_VERSION ((TINYCBOR_VERSION_MAJOR << 16) | (TINYCBOR_VERSION_MINOR << 8) | TINYCBOR_VERSION_PATCH)
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#else
|
||||
#include <stdbool.h>
|
||||
#endif
|
||||
|
||||
#ifndef SIZE_MAX
|
||||
/* Some systems fail to define SIZE_MAX in <stdint.h>, even though C99 requires it...
|
||||
* Conversion from signed to unsigned is defined in 6.3.1.3 (Signed and unsigned integers) p2,
|
||||
* which says: "the value is converted by repeatedly adding or subtracting one more than the
|
||||
* maximum value that can be represented in the new type until the value is in the range of the
|
||||
* new type."
|
||||
* So -1 gets converted to size_t by adding SIZE_MAX + 1, which results in SIZE_MAX.
|
||||
*/
|
||||
# define SIZE_MAX ((size_t)-1)
|
||||
#endif
|
||||
|
||||
#ifndef CBOR_API
|
||||
# define CBOR_API
|
||||
#endif
|
||||
#ifndef CBOR_PRIVATE_API
|
||||
# define CBOR_PRIVATE_API
|
||||
#endif
|
||||
#ifndef CBOR_INLINE_API
|
||||
# if defined(__cplusplus)
|
||||
# define CBOR_INLINE inline
|
||||
# define CBOR_INLINE_API inline
|
||||
# else
|
||||
# define CBOR_INLINE_API static CBOR_INLINE
|
||||
# if defined(_MSC_VER)
|
||||
# define CBOR_INLINE __inline
|
||||
# elif defined(__GNUC__)
|
||||
# define CBOR_INLINE __inline__
|
||||
# elif defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
|
||||
# define CBOR_INLINE inline
|
||||
# else
|
||||
# define CBOR_INLINE
|
||||
# endif
|
||||
# endif
|
||||
#endif
|
||||
|
||||
typedef enum CborType {
|
||||
CborIntegerType = 0x00,
|
||||
CborByteStringType = 0x40,
|
||||
CborTextStringType = 0x60,
|
||||
CborArrayType = 0x80,
|
||||
CborMapType = 0xa0,
|
||||
CborTagType = 0xc0,
|
||||
CborSimpleType = 0xe0,
|
||||
CborBooleanType = 0xf5,
|
||||
CborNullType = 0xf6,
|
||||
CborUndefinedType = 0xf7,
|
||||
CborHalfFloatType = 0xf9,
|
||||
CborFloatType = 0xfa,
|
||||
CborDoubleType = 0xfb,
|
||||
|
||||
CborInvalidType = 0xff /* equivalent to the break byte, so it will never be used */
|
||||
} CborType;
|
||||
|
||||
typedef uint64_t CborTag;
|
||||
typedef enum CborKnownTags {
|
||||
CborDateTimeStringTag = 0,
|
||||
CborUnixTime_tTag = 1,
|
||||
CborPositiveBignumTag = 2,
|
||||
CborNegativeBignumTag = 3,
|
||||
CborDecimalTag = 4,
|
||||
CborBigfloatTag = 5,
|
||||
CborCOSE_Encrypt0Tag = 16,
|
||||
CborCOSE_Mac0Tag = 17,
|
||||
CborCOSE_Sign1Tag = 18,
|
||||
CborExpectedBase64urlTag = 21,
|
||||
CborExpectedBase64Tag = 22,
|
||||
CborExpectedBase16Tag = 23,
|
||||
CborEncodedCborTag = 24,
|
||||
CborUrlTag = 32,
|
||||
CborBase64urlTag = 33,
|
||||
CborBase64Tag = 34,
|
||||
CborRegularExpressionTag = 35,
|
||||
CborMimeMessageTag = 36,
|
||||
CborCOSE_EncryptTag = 96,
|
||||
CborCOSE_MacTag = 97,
|
||||
CborCOSE_SignTag = 98,
|
||||
CborSignatureTag = 55799
|
||||
} CborKnownTags;
|
||||
|
||||
/* #define the constants so we can check with #ifdef */
|
||||
#define CborDateTimeStringTag CborDateTimeStringTag
|
||||
#define CborUnixTime_tTag CborUnixTime_tTag
|
||||
#define CborPositiveBignumTag CborPositiveBignumTag
|
||||
#define CborNegativeBignumTag CborNegativeBignumTag
|
||||
#define CborDecimalTag CborDecimalTag
|
||||
#define CborBigfloatTag CborBigfloatTag
|
||||
#define CborCOSE_Encrypt0Tag CborCOSE_Encrypt0Tag
|
||||
#define CborCOSE_Mac0Tag CborCOSE_Mac0Tag
|
||||
#define CborCOSE_Sign1Tag CborCOSE_Sign1Tag
|
||||
#define CborExpectedBase64urlTag CborExpectedBase64urlTag
|
||||
#define CborExpectedBase64Tag CborExpectedBase64Tag
|
||||
#define CborExpectedBase16Tag CborExpectedBase16Tag
|
||||
#define CborEncodedCborTag CborEncodedCborTag
|
||||
#define CborUrlTag CborUrlTag
|
||||
#define CborBase64urlTag CborBase64urlTag
|
||||
#define CborBase64Tag CborBase64Tag
|
||||
#define CborRegularExpressionTag CborRegularExpressionTag
|
||||
#define CborMimeMessageTag CborMimeMessageTag
|
||||
#define CborCOSE_EncryptTag CborCOSE_EncryptTag
|
||||
#define CborCOSE_MacTag CborCOSE_MacTag
|
||||
#define CborCOSE_SignTag CborCOSE_SignTag
|
||||
#define CborSignatureTag CborSignatureTag
|
||||
|
||||
/* Error API */
|
||||
|
||||
typedef enum CborError {
|
||||
CborNoError = 0,
|
||||
|
||||
/* errors in all modes */
|
||||
CborUnknownError,
|
||||
CborErrorUnknownLength, /* request for length in array, map, or string with indeterminate length */
|
||||
CborErrorAdvancePastEOF,
|
||||
CborErrorIO,
|
||||
|
||||
/* parser errors streaming errors */
|
||||
CborErrorGarbageAtEnd = 256,
|
||||
CborErrorUnexpectedEOF,
|
||||
CborErrorUnexpectedBreak,
|
||||
CborErrorUnknownType, /* can only happen in major type 7 */
|
||||
CborErrorIllegalType, /* type not allowed here */
|
||||
CborErrorIllegalNumber,
|
||||
CborErrorIllegalSimpleType, /* types of value less than 32 encoded in two bytes */
|
||||
CborErrorNoMoreStringChunks,
|
||||
|
||||
/* parser errors in strict mode parsing only */
|
||||
CborErrorUnknownSimpleType = 512,
|
||||
CborErrorUnknownTag,
|
||||
CborErrorInappropriateTagForType,
|
||||
CborErrorDuplicateObjectKeys,
|
||||
CborErrorInvalidUtf8TextString,
|
||||
CborErrorExcludedType,
|
||||
CborErrorExcludedValue,
|
||||
CborErrorImproperValue,
|
||||
CborErrorOverlongEncoding,
|
||||
CborErrorMapKeyNotString,
|
||||
CborErrorMapNotSorted,
|
||||
CborErrorMapKeysNotUnique,
|
||||
|
||||
/* encoder errors */
|
||||
CborErrorTooManyItems = 768,
|
||||
CborErrorTooFewItems,
|
||||
|
||||
/* internal implementation errors */
|
||||
CborErrorDataTooLarge = 1024,
|
||||
CborErrorNestingTooDeep,
|
||||
CborErrorUnsupportedType,
|
||||
CborErrorUnimplementedValidation,
|
||||
|
||||
/* errors in converting to JSON */
|
||||
CborErrorJsonObjectKeyIsAggregate = 1280,
|
||||
CborErrorJsonObjectKeyNotString,
|
||||
CborErrorJsonNotImplemented,
|
||||
|
||||
CborErrorOutOfMemory = (int) (~0U / 2 + 1),
|
||||
CborErrorInternalError = (int) (~0U / 2) /* INT_MAX on two's complement machines */
|
||||
} CborError;
|
||||
|
||||
CBOR_API const char *cbor_error_string(CborError error);
|
||||
|
||||
/* Encoder API */
|
||||
|
||||
typedef enum CborEncoderAppendType
|
||||
{
|
||||
CborEncoderAppendCborData = 0,
|
||||
CborEncoderAppendStringData = 1
|
||||
} CborEncoderAppendType;
|
||||
|
||||
typedef CborError (*CborEncoderWriteFunction)(void *, const void *, size_t, CborEncoderAppendType);
|
||||
|
||||
enum CborEncoderFlags
|
||||
{
|
||||
CborIteratorFlag_WriterFunction = 0x01,
|
||||
CborIteratorFlag_ContainerIsMap_ = 0x20
|
||||
};
|
||||
|
||||
struct CborEncoder
|
||||
{
|
||||
union {
|
||||
uint8_t *ptr;
|
||||
ptrdiff_t bytes_needed;
|
||||
CborEncoderWriteFunction writer;
|
||||
} data;
|
||||
uint8_t *end;
|
||||
size_t remaining;
|
||||
int flags;
|
||||
};
|
||||
typedef struct CborEncoder CborEncoder;
|
||||
|
||||
static const size_t CborIndefiniteLength = SIZE_MAX;
|
||||
|
||||
#ifndef CBOR_NO_ENCODER_API
|
||||
CBOR_API void cbor_encoder_init(CborEncoder *encoder, uint8_t *buffer, size_t size, int flags);
|
||||
CBOR_API void cbor_encoder_init_writer(CborEncoder *encoder, CborEncoderWriteFunction writer, void *);
|
||||
CBOR_API CborError cbor_encode_uint(CborEncoder *encoder, uint64_t value);
|
||||
CBOR_API CborError cbor_encode_int(CborEncoder *encoder, int64_t value);
|
||||
CBOR_API CborError cbor_encode_negative_int(CborEncoder *encoder, uint64_t absolute_value);
|
||||
CBOR_API CborError cbor_encode_simple_value(CborEncoder *encoder, uint8_t value);
|
||||
CBOR_API CborError cbor_encode_tag(CborEncoder *encoder, CborTag tag);
|
||||
CBOR_API CborError cbor_encode_text_string(CborEncoder *encoder, const char *string, size_t length);
|
||||
CBOR_INLINE_API CborError cbor_encode_text_stringz(CborEncoder *encoder, const char *string)
|
||||
{ return cbor_encode_text_string(encoder, string, strlen(string)); }
|
||||
CBOR_API CborError cbor_encode_byte_string(CborEncoder *encoder, const uint8_t *string, size_t length);
|
||||
CBOR_API CborError cbor_encode_floating_point(CborEncoder *encoder, CborType fpType, const void *value);
|
||||
|
||||
CBOR_INLINE_API CborError cbor_encode_boolean(CborEncoder *encoder, bool value)
|
||||
{ return cbor_encode_simple_value(encoder, (int)value - 1 + (CborBooleanType & 0x1f)); }
|
||||
CBOR_INLINE_API CborError cbor_encode_null(CborEncoder *encoder)
|
||||
{ return cbor_encode_simple_value(encoder, CborNullType & 0x1f); }
|
||||
CBOR_INLINE_API CborError cbor_encode_undefined(CborEncoder *encoder)
|
||||
{ return cbor_encode_simple_value(encoder, CborUndefinedType & 0x1f); }
|
||||
|
||||
CBOR_INLINE_API CborError cbor_encode_half_float(CborEncoder *encoder, const void *value)
|
||||
{ return cbor_encode_floating_point(encoder, CborHalfFloatType, value); }
|
||||
CBOR_API CborError cbor_encode_float_as_half_float(CborEncoder *encoder, float value);
|
||||
CBOR_INLINE_API CborError cbor_encode_float(CborEncoder *encoder, float value)
|
||||
{ return cbor_encode_floating_point(encoder, CborFloatType, &value); }
|
||||
CBOR_INLINE_API CborError cbor_encode_double(CborEncoder *encoder, double value)
|
||||
{ return cbor_encode_floating_point(encoder, CborDoubleType, &value); }
|
||||
|
||||
CBOR_API CborError cbor_encoder_create_array(CborEncoder *parentEncoder, CborEncoder *arrayEncoder, size_t length);
|
||||
CBOR_API CborError cbor_encoder_create_map(CborEncoder *parentEncoder, CborEncoder *mapEncoder, size_t length);
|
||||
CBOR_API CborError cbor_encoder_close_container(CborEncoder *parentEncoder, const CborEncoder *containerEncoder);
|
||||
CBOR_API CborError cbor_encoder_close_container_checked(CborEncoder *parentEncoder, const CborEncoder *containerEncoder);
|
||||
|
||||
CBOR_INLINE_API uint8_t *_cbor_encoder_get_buffer_pointer(const CborEncoder *encoder)
|
||||
{
|
||||
return encoder->data.ptr;
|
||||
}
|
||||
|
||||
CBOR_INLINE_API size_t cbor_encoder_get_buffer_size(const CborEncoder *encoder, const uint8_t *buffer)
|
||||
{
|
||||
return (size_t)(encoder->data.ptr - buffer);
|
||||
}
|
||||
|
||||
CBOR_INLINE_API size_t cbor_encoder_get_extra_bytes_needed(const CborEncoder *encoder)
|
||||
{
|
||||
return encoder->end ? 0 : (size_t)encoder->data.bytes_needed;
|
||||
}
|
||||
#endif /* CBOR_NO_ENCODER_API */
|
||||
|
||||
/* Parser API */
|
||||
|
||||
enum CborParserGlobalFlags
|
||||
{
|
||||
CborParserFlag_ExternalSource = 0x01
|
||||
};
|
||||
|
||||
enum CborParserIteratorFlags
|
||||
{
|
||||
/* used for all types, but not during string chunk iteration
|
||||
* (values are static-asserted, don't change) */
|
||||
CborIteratorFlag_IntegerValueIs64Bit = 0x01,
|
||||
CborIteratorFlag_IntegerValueTooLarge = 0x02,
|
||||
|
||||
/* used only for CborIntegerType */
|
||||
CborIteratorFlag_NegativeInteger = 0x04,
|
||||
|
||||
/* used only during string iteration */
|
||||
CborIteratorFlag_BeforeFirstStringChunk = 0x04,
|
||||
CborIteratorFlag_IteratingStringChunks = 0x08,
|
||||
|
||||
/* used for arrays, maps and strings, including during chunk iteration */
|
||||
CborIteratorFlag_UnknownLength = 0x10,
|
||||
|
||||
/* used for maps, but must be kept for all types
|
||||
* (ContainerIsMap value must be CborMapType - CborArrayType) */
|
||||
CborIteratorFlag_ContainerIsMap = 0x20,
|
||||
CborIteratorFlag_NextIsMapKey = 0x40
|
||||
};
|
||||
|
||||
struct CborValue;
|
||||
struct CborParserOperations
|
||||
{
|
||||
bool (*can_read_bytes)(void *token, size_t len);
|
||||
void *(*read_bytes)(void *token, void *dst, size_t offset, size_t len);
|
||||
void (*advance_bytes)(void *token, size_t len);
|
||||
CborError (*transfer_string)(void *token, const void **userptr, size_t offset, size_t len);
|
||||
};
|
||||
|
||||
struct CborParser
|
||||
{
|
||||
union {
|
||||
const uint8_t *end;
|
||||
const struct CborParserOperations *ops;
|
||||
} source;
|
||||
enum CborParserGlobalFlags flags;
|
||||
};
|
||||
typedef struct CborParser CborParser;
|
||||
|
||||
struct CborValue
|
||||
{
|
||||
const CborParser *parser;
|
||||
union {
|
||||
const uint8_t *ptr;
|
||||
void *token;
|
||||
} source;
|
||||
uint32_t remaining;
|
||||
uint16_t extra;
|
||||
uint8_t type;
|
||||
uint8_t flags;
|
||||
};
|
||||
typedef struct CborValue CborValue;
|
||||
|
||||
#ifndef CBOR_NO_PARSER_API
|
||||
CBOR_API CborError cbor_parser_init(const uint8_t *buffer, size_t size, uint32_t flags, CborParser *parser, CborValue *it);
|
||||
CBOR_API CborError cbor_parser_init_reader(const struct CborParserOperations *ops, CborParser *parser, CborValue *it, void *token);
|
||||
|
||||
CBOR_API CborError cbor_value_validate_basic(const CborValue *it);
|
||||
|
||||
CBOR_INLINE_API bool cbor_value_at_end(const CborValue *it)
|
||||
{ return it->remaining == 0; }
|
||||
CBOR_INLINE_API const uint8_t *cbor_value_get_next_byte(const CborValue *it)
|
||||
{ return it->source.ptr; }
|
||||
CBOR_API CborError cbor_value_reparse(CborValue *it);
|
||||
CBOR_API CborError cbor_value_advance_fixed(CborValue *it);
|
||||
CBOR_API CborError cbor_value_advance(CborValue *it);
|
||||
CBOR_INLINE_API bool cbor_value_is_container(const CborValue *it)
|
||||
{ return it->type == CborArrayType || it->type == CborMapType; }
|
||||
CBOR_API CborError cbor_value_enter_container(const CborValue *it, CborValue *recursed);
|
||||
CBOR_API CborError cbor_value_leave_container(CborValue *it, const CborValue *recursed);
|
||||
|
||||
CBOR_PRIVATE_API uint64_t _cbor_value_decode_int64_internal(const CborValue *value);
|
||||
CBOR_INLINE_API uint64_t _cbor_value_extract_int64_helper(const CborValue *value)
|
||||
{
|
||||
return value->flags & CborIteratorFlag_IntegerValueTooLarge ?
|
||||
_cbor_value_decode_int64_internal(value) : value->extra;
|
||||
}
|
||||
|
||||
CBOR_INLINE_API bool cbor_value_is_valid(const CborValue *value)
|
||||
{ return value && value->type != CborInvalidType; }
|
||||
CBOR_INLINE_API CborType cbor_value_get_type(const CborValue *value)
|
||||
{ return (CborType)value->type; }
|
||||
|
||||
/* Null & undefined type */
|
||||
CBOR_INLINE_API bool cbor_value_is_null(const CborValue *value)
|
||||
{ return value->type == CborNullType; }
|
||||
CBOR_INLINE_API bool cbor_value_is_undefined(const CborValue *value)
|
||||
{ return value->type == CborUndefinedType; }
|
||||
|
||||
/* Booleans */
|
||||
CBOR_INLINE_API bool cbor_value_is_boolean(const CborValue *value)
|
||||
{ return value->type == CborBooleanType; }
|
||||
CBOR_INLINE_API CborError cbor_value_get_boolean(const CborValue *value, bool *result)
|
||||
{
|
||||
assert(cbor_value_is_boolean(value));
|
||||
*result = !!value->extra;
|
||||
return CborNoError;
|
||||
}
|
||||
|
||||
/* Simple types */
|
||||
CBOR_INLINE_API bool cbor_value_is_simple_type(const CborValue *value)
|
||||
{ return value->type == CborSimpleType; }
|
||||
CBOR_INLINE_API CborError cbor_value_get_simple_type(const CborValue *value, uint8_t *result)
|
||||
{
|
||||
assert(cbor_value_is_simple_type(value));
|
||||
*result = (uint8_t)value->extra;
|
||||
return CborNoError;
|
||||
}
|
||||
|
||||
/* Integers */
|
||||
CBOR_INLINE_API bool cbor_value_is_integer(const CborValue *value)
|
||||
{ return value->type == CborIntegerType; }
|
||||
CBOR_INLINE_API bool cbor_value_is_unsigned_integer(const CborValue *value)
|
||||
{ return cbor_value_is_integer(value) && (value->flags & CborIteratorFlag_NegativeInteger) == 0; }
|
||||
CBOR_INLINE_API bool cbor_value_is_negative_integer(const CborValue *value)
|
||||
{ return cbor_value_is_integer(value) && (value->flags & CborIteratorFlag_NegativeInteger); }
|
||||
|
||||
CBOR_INLINE_API CborError cbor_value_get_raw_integer(const CborValue *value, uint64_t *result)
|
||||
{
|
||||
assert(cbor_value_is_integer(value));
|
||||
*result = _cbor_value_extract_int64_helper(value);
|
||||
return CborNoError;
|
||||
}
|
||||
|
||||
CBOR_INLINE_API CborError cbor_value_get_uint64(const CborValue *value, uint64_t *result)
|
||||
{
|
||||
assert(cbor_value_is_unsigned_integer(value));
|
||||
*result = _cbor_value_extract_int64_helper(value);
|
||||
return CborNoError;
|
||||
}
|
||||
|
||||
CBOR_INLINE_API CborError cbor_value_get_int64(const CborValue *value, int64_t *result)
|
||||
{
|
||||
assert(cbor_value_is_integer(value));
|
||||
*result = (int64_t) _cbor_value_extract_int64_helper(value);
|
||||
if (value->flags & CborIteratorFlag_NegativeInteger)
|
||||
*result = -*result - 1;
|
||||
return CborNoError;
|
||||
}
|
||||
|
||||
CBOR_INLINE_API CborError cbor_value_get_int(const CborValue *value, int *result)
|
||||
{
|
||||
assert(cbor_value_is_integer(value));
|
||||
*result = (int) _cbor_value_extract_int64_helper(value);
|
||||
if (value->flags & CborIteratorFlag_NegativeInteger)
|
||||
*result = -*result - 1;
|
||||
return CborNoError;
|
||||
}
|
||||
|
||||
CBOR_API CborError cbor_value_get_int64_checked(const CborValue *value, int64_t *result);
|
||||
CBOR_API CborError cbor_value_get_int_checked(const CborValue *value, int *result);
|
||||
|
||||
CBOR_INLINE_API bool cbor_value_is_length_known(const CborValue *value)
|
||||
{ return (value->flags & CborIteratorFlag_UnknownLength) == 0; }
|
||||
|
||||
/* Tags */
|
||||
CBOR_INLINE_API bool cbor_value_is_tag(const CborValue *value)
|
||||
{ return value->type == CborTagType; }
|
||||
CBOR_INLINE_API CborError cbor_value_get_tag(const CborValue *value, CborTag *result)
|
||||
{
|
||||
assert(cbor_value_is_tag(value));
|
||||
*result = _cbor_value_extract_int64_helper(value);
|
||||
return CborNoError;
|
||||
}
|
||||
CBOR_API CborError cbor_value_skip_tag(CborValue *it);
|
||||
|
||||
/* Strings */
|
||||
CBOR_INLINE_API bool cbor_value_is_byte_string(const CborValue *value)
|
||||
{ return value->type == CborByteStringType; }
|
||||
CBOR_INLINE_API bool cbor_value_is_text_string(const CborValue *value)
|
||||
{ return value->type == CborTextStringType; }
|
||||
|
||||
CBOR_INLINE_API CborError cbor_value_get_string_length(const CborValue *value, size_t *length)
|
||||
{
|
||||
uint64_t v;
|
||||
assert(cbor_value_is_byte_string(value) || cbor_value_is_text_string(value));
|
||||
if (!cbor_value_is_length_known(value))
|
||||
return CborErrorUnknownLength;
|
||||
v = _cbor_value_extract_int64_helper(value);
|
||||
*length = (size_t)v;
|
||||
if (*length != v)
|
||||
return CborErrorDataTooLarge;
|
||||
return CborNoError;
|
||||
}
|
||||
|
||||
CBOR_PRIVATE_API CborError _cbor_value_copy_string(const CborValue *value, void *buffer,
|
||||
size_t *buflen, CborValue *next);
|
||||
CBOR_PRIVATE_API CborError _cbor_value_dup_string(const CborValue *value, void **buffer,
|
||||
size_t *buflen, CborValue *next);
|
||||
|
||||
CBOR_API CborError cbor_value_calculate_string_length(const CborValue *value, size_t *length);
|
||||
|
||||
CBOR_INLINE_API CborError cbor_value_copy_text_string(const CborValue *value, char *buffer,
|
||||
size_t *buflen, CborValue *next)
|
||||
{
|
||||
assert(cbor_value_is_text_string(value));
|
||||
return _cbor_value_copy_string(value, buffer, buflen, next);
|
||||
}
|
||||
CBOR_INLINE_API CborError cbor_value_copy_byte_string(const CborValue *value, uint8_t *buffer,
|
||||
size_t *buflen, CborValue *next)
|
||||
{
|
||||
assert(cbor_value_is_byte_string(value));
|
||||
return _cbor_value_copy_string(value, buffer, buflen, next);
|
||||
}
|
||||
|
||||
CBOR_INLINE_API CborError cbor_value_dup_text_string(const CborValue *value, char **buffer,
|
||||
size_t *buflen, CborValue *next)
|
||||
{
|
||||
assert(cbor_value_is_text_string(value));
|
||||
return _cbor_value_dup_string(value, (void **)buffer, buflen, next);
|
||||
}
|
||||
CBOR_INLINE_API CborError cbor_value_dup_byte_string(const CborValue *value, uint8_t **buffer,
|
||||
size_t *buflen, CborValue *next)
|
||||
{
|
||||
assert(cbor_value_is_byte_string(value));
|
||||
return _cbor_value_dup_string(value, (void **)buffer, buflen, next);
|
||||
}
|
||||
|
||||
CBOR_PRIVATE_API CborError _cbor_value_get_string_chunk_size(const CborValue *value, size_t *len);
|
||||
CBOR_INLINE_API CborError cbor_value_get_string_chunk_size(const CborValue *value, size_t *len)
|
||||
{
|
||||
assert(value->flags & CborIteratorFlag_IteratingStringChunks);
|
||||
return _cbor_value_get_string_chunk_size(value, len);
|
||||
}
|
||||
|
||||
CBOR_INLINE_API bool cbor_value_string_iteration_at_end(const CborValue *value)
|
||||
{
|
||||
size_t dummy;
|
||||
return cbor_value_get_string_chunk_size(value, &dummy) == CborErrorNoMoreStringChunks;
|
||||
}
|
||||
|
||||
CBOR_PRIVATE_API CborError _cbor_value_begin_string_iteration(CborValue *value);
|
||||
CBOR_INLINE_API CborError cbor_value_begin_string_iteration(CborValue *value)
|
||||
{
|
||||
assert(cbor_value_is_text_string(value) || cbor_value_is_byte_string(value));
|
||||
assert(!(value->flags & CborIteratorFlag_IteratingStringChunks));
|
||||
return _cbor_value_begin_string_iteration(value);
|
||||
}
|
||||
|
||||
CBOR_PRIVATE_API CborError _cbor_value_finish_string_iteration(CborValue *value);
|
||||
CBOR_INLINE_API CborError cbor_value_finish_string_iteration(CborValue *value)
|
||||
{
|
||||
assert(cbor_value_string_iteration_at_end(value));
|
||||
return _cbor_value_finish_string_iteration(value);
|
||||
}
|
||||
|
||||
CBOR_PRIVATE_API CborError _cbor_value_get_string_chunk(const CborValue *value, const void **bufferptr,
|
||||
size_t *len, CborValue *next);
|
||||
CBOR_INLINE_API CborError cbor_value_get_text_string_chunk(const CborValue *value, const char **bufferptr,
|
||||
size_t *len, CborValue *next)
|
||||
{
|
||||
assert(cbor_value_is_text_string(value));
|
||||
return _cbor_value_get_string_chunk(value, (const void **)bufferptr, len, next);
|
||||
}
|
||||
CBOR_INLINE_API CborError cbor_value_get_byte_string_chunk(const CborValue *value, const uint8_t **bufferptr,
|
||||
size_t *len, CborValue *next)
|
||||
{
|
||||
assert(cbor_value_is_byte_string(value));
|
||||
return _cbor_value_get_string_chunk(value, (const void **)bufferptr, len, next);
|
||||
}
|
||||
|
||||
CBOR_API CborError cbor_value_text_string_equals(const CborValue *value, const char *string, bool *result);
|
||||
|
||||
/* Maps and arrays */
|
||||
CBOR_INLINE_API bool cbor_value_is_array(const CborValue *value)
|
||||
{ return value->type == CborArrayType; }
|
||||
CBOR_INLINE_API bool cbor_value_is_map(const CborValue *value)
|
||||
{ return value->type == CborMapType; }
|
||||
|
||||
CBOR_INLINE_API CborError cbor_value_get_array_length(const CborValue *value, size_t *length)
|
||||
{
|
||||
uint64_t v;
|
||||
assert(cbor_value_is_array(value));
|
||||
if (!cbor_value_is_length_known(value))
|
||||
return CborErrorUnknownLength;
|
||||
v = _cbor_value_extract_int64_helper(value);
|
||||
*length = (size_t)v;
|
||||
if (*length != v)
|
||||
return CborErrorDataTooLarge;
|
||||
return CborNoError;
|
||||
}
|
||||
|
||||
CBOR_INLINE_API CborError cbor_value_get_map_length(const CborValue *value, size_t *length)
|
||||
{
|
||||
uint64_t v;
|
||||
assert(cbor_value_is_map(value));
|
||||
if (!cbor_value_is_length_known(value))
|
||||
return CborErrorUnknownLength;
|
||||
v = _cbor_value_extract_int64_helper(value);
|
||||
*length = (size_t)v;
|
||||
if (*length != v)
|
||||
return CborErrorDataTooLarge;
|
||||
return CborNoError;
|
||||
}
|
||||
|
||||
CBOR_API CborError cbor_value_map_find_value(const CborValue *map, const char *string, CborValue *element);
|
||||
|
||||
/* Floating point */
|
||||
CBOR_INLINE_API bool cbor_value_is_half_float(const CborValue *value)
|
||||
{ return value->type == CborHalfFloatType; }
|
||||
CBOR_API CborError cbor_value_get_half_float_as_float(const CborValue *value, float *result);
|
||||
CBOR_INLINE_API CborError cbor_value_get_half_float(const CborValue *value, void *result)
|
||||
{
|
||||
assert(cbor_value_is_half_float(value));
|
||||
assert((value->flags & CborIteratorFlag_IntegerValueTooLarge) == 0);
|
||||
|
||||
/* size has already been computed */
|
||||
memcpy(result, &value->extra, sizeof(value->extra));
|
||||
return CborNoError;
|
||||
}
|
||||
|
||||
CBOR_INLINE_API bool cbor_value_is_float(const CborValue *value)
|
||||
{ return value->type == CborFloatType; }
|
||||
CBOR_INLINE_API CborError cbor_value_get_float(const CborValue *value, float *result)
|
||||
{
|
||||
uint32_t data;
|
||||
assert(cbor_value_is_float(value));
|
||||
assert(value->flags & CborIteratorFlag_IntegerValueTooLarge);
|
||||
data = (uint32_t)_cbor_value_decode_int64_internal(value);
|
||||
memcpy(result, &data, sizeof(*result));
|
||||
return CborNoError;
|
||||
}
|
||||
|
||||
CBOR_INLINE_API bool cbor_value_is_double(const CborValue *value)
|
||||
{ return value->type == CborDoubleType; }
|
||||
CBOR_INLINE_API CborError cbor_value_get_double(const CborValue *value, double *result)
|
||||
{
|
||||
uint64_t data;
|
||||
assert(cbor_value_is_double(value));
|
||||
assert(value->flags & CborIteratorFlag_IntegerValueTooLarge);
|
||||
data = _cbor_value_decode_int64_internal(value);
|
||||
memcpy(result, &data, sizeof(*result));
|
||||
return CborNoError;
|
||||
}
|
||||
|
||||
/* Validation API */
|
||||
#ifndef CBOR_NO_VALIDATION_API
|
||||
|
||||
enum CborValidationFlags {
|
||||
/* Bit mapping:
|
||||
* bits 0-7 (8 bits): canonical format
|
||||
* bits 8-11 (4 bits): canonical format & strict mode
|
||||
* bits 12-20 (8 bits): strict mode
|
||||
* bits 21-31 (10 bits): other
|
||||
*/
|
||||
|
||||
CborValidateShortestIntegrals = 0x0001,
|
||||
CborValidateShortestFloatingPoint = 0x0002,
|
||||
CborValidateShortestNumbers = CborValidateShortestIntegrals | CborValidateShortestFloatingPoint,
|
||||
CborValidateNoIndeterminateLength = 0x0100,
|
||||
CborValidateMapIsSorted = 0x0200 | CborValidateNoIndeterminateLength,
|
||||
|
||||
CborValidateCanonicalFormat = 0x0fff,
|
||||
|
||||
CborValidateMapKeysAreUnique = 0x1000 | CborValidateMapIsSorted,
|
||||
CborValidateTagUse = 0x2000,
|
||||
CborValidateUtf8 = 0x4000,
|
||||
|
||||
CborValidateStrictMode = 0xfff00,
|
||||
|
||||
CborValidateMapKeysAreString = 0x100000,
|
||||
CborValidateNoUndefined = 0x200000,
|
||||
CborValidateNoTags = 0x400000,
|
||||
CborValidateFiniteFloatingPoint = 0x800000,
|
||||
/* unused = 0x1000000, */
|
||||
/* unused = 0x2000000, */
|
||||
|
||||
CborValidateNoUnknownSimpleTypesSA = 0x4000000,
|
||||
CborValidateNoUnknownSimpleTypes = 0x8000000 | CborValidateNoUnknownSimpleTypesSA,
|
||||
CborValidateNoUnknownTagsSA = 0x10000000,
|
||||
CborValidateNoUnknownTagsSR = 0x20000000 | CborValidateNoUnknownTagsSA,
|
||||
CborValidateNoUnknownTags = 0x40000000 | CborValidateNoUnknownTagsSR,
|
||||
|
||||
CborValidateCompleteData = (int)0x80000000,
|
||||
|
||||
CborValidateStrictest = (int)~0U,
|
||||
CborValidateBasic = 0
|
||||
};
|
||||
|
||||
CBOR_API CborError cbor_value_validate(const CborValue *it, uint32_t flags);
|
||||
#endif /* CBOR_NO_VALIDATION_API */
|
||||
|
||||
/* Human-readable (dump) API */
|
||||
#ifndef CBOR_NO_PRETTY_API
|
||||
|
||||
enum CborPrettyFlags {
|
||||
CborPrettyNumericEncodingIndicators = 0x01,
|
||||
CborPrettyTextualEncodingIndicators = 0,
|
||||
|
||||
CborPrettyIndicateIndeterminateLength = 0x02,
|
||||
CborPrettyIndicateIndetermineLength = CborPrettyIndicateIndeterminateLength, /* deprecated */
|
||||
CborPrettyIndicateOverlongNumbers = 0x04,
|
||||
|
||||
CborPrettyShowStringFragments = 0x100,
|
||||
CborPrettyMergeStringFragments = 0,
|
||||
|
||||
CborPrettyDefaultFlags = CborPrettyIndicateIndeterminateLength
|
||||
};
|
||||
|
||||
typedef CborError (*CborStreamFunction)(void *token, const char *fmt, ...)
|
||||
#ifdef __GNUC__
|
||||
__attribute__((__format__(printf, 2, 3)))
|
||||
#endif
|
||||
;
|
||||
|
||||
CBOR_API CborError cbor_value_to_pretty_stream(CborStreamFunction streamFunction, void *token, CborValue *value, int flags);
|
||||
|
||||
/* The following API requires a hosted C implementation (uses FILE*) */
|
||||
#if !defined(__STDC_HOSTED__) || __STDC_HOSTED__-0 == 1
|
||||
CBOR_API CborError cbor_value_to_pretty_advance_flags(FILE *out, CborValue *value, int flags);
|
||||
CBOR_API CborError cbor_value_to_pretty_advance(FILE *out, CborValue *value);
|
||||
CBOR_INLINE_API CborError cbor_value_to_pretty(FILE *out, const CborValue *value)
|
||||
{
|
||||
CborValue copy = *value;
|
||||
return cbor_value_to_pretty_advance_flags(out, ©, CborPrettyDefaultFlags);
|
||||
}
|
||||
#endif /* __STDC_HOSTED__ check */
|
||||
|
||||
#endif /* CBOR_NO_PRETTY_API */
|
||||
|
||||
#endif /* CBOR_NO_PARSER_API */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* CBOR_H */
|
||||
|
||||
690
frame_serialize/tinycbor/cborencoder.c
Normal file
690
frame_serialize/tinycbor/cborencoder.c
Normal file
@@ -0,0 +1,690 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2021 Intel Corporation
|
||||
**
|
||||
** Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
** of this software and associated documentation files (the "Software"), to deal
|
||||
** in the Software without restriction, including without limitation the rights
|
||||
** to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
** copies of the Software, and to permit persons to whom the Software is
|
||||
** furnished to do so, subject to the following conditions:
|
||||
**
|
||||
** The above copyright notice and this permission notice shall be included in
|
||||
** all copies or substantial portions of the Software.
|
||||
**
|
||||
** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
** OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
** THE SOFTWARE.
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef _BSD_SOURCE
|
||||
#define _BSD_SOURCE 1
|
||||
#endif
|
||||
#ifndef _DEFAULT_SOURCE
|
||||
#define _DEFAULT_SOURCE 1
|
||||
#endif
|
||||
#ifndef __STDC_LIMIT_MACROS
|
||||
# define __STDC_LIMIT_MACROS 1
|
||||
#endif
|
||||
#define __STDC_WANT_IEC_60559_TYPES_EXT__
|
||||
|
||||
#include "cbor.h"
|
||||
#include "cborinternal_p.h"
|
||||
#include "compilersupport_p.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
/**
|
||||
* \defgroup CborEncoding Encoding to CBOR
|
||||
* \brief Group of functions used to encode data to CBOR.
|
||||
*
|
||||
* CborEncoder is used to encode data into a CBOR stream. The outermost
|
||||
* CborEncoder is initialized by calling cbor_encoder_init(), with the buffer
|
||||
* where the CBOR stream will be stored. The outermost CborEncoder is usually
|
||||
* used to encode exactly one item, most often an array or map. It is possible
|
||||
* to encode more than one item, but care must then be taken on the decoder
|
||||
* side to ensure the state is reset after each item was decoded.
|
||||
*
|
||||
* Nested CborEncoder objects are created using cbor_encoder_create_array() and
|
||||
* cbor_encoder_create_map(), later closed with cbor_encoder_close_container()
|
||||
* or cbor_encoder_close_container_checked(). The pairs of creation and closing
|
||||
* must be exactly matched and their parameters are always the same.
|
||||
*
|
||||
* CborEncoder writes directly to the user-supplied buffer, without extra
|
||||
* buffering. CborEncoder does not allocate memory and CborEncoder objects are
|
||||
* usually created on the stack of the encoding functions.
|
||||
*
|
||||
* The example below initializes a CborEncoder object with a buffer and encodes
|
||||
* a single integer.
|
||||
*
|
||||
* \code
|
||||
* uint8_t buf[16];
|
||||
* CborEncoder encoder;
|
||||
* cbor_encoder_init(&encoder, buf, sizeof(buf), 0);
|
||||
* cbor_encode_int(&encoder, some_value);
|
||||
* \endcode
|
||||
*
|
||||
* As explained before, usually the outermost CborEncoder object is used to add
|
||||
* one array or map, which in turn contains multiple elements. The example
|
||||
* below creates a CBOR map with one element: a key "foo" and a boolean value.
|
||||
*
|
||||
* \code
|
||||
* uint8_t buf[16];
|
||||
* CborEncoder encoder, mapEncoder;
|
||||
* cbor_encoder_init(&encoder, buf, sizeof(buf), 0);
|
||||
* cbor_encoder_create_map(&encoder, &mapEncoder, 1);
|
||||
* cbor_encode_text_stringz(&mapEncoder, "foo");
|
||||
* cbor_encode_boolean(&mapEncoder, some_value);
|
||||
* cbor_encoder_close_container(&encoder, &mapEncoder);
|
||||
* \endcode
|
||||
*
|
||||
* <h3 class="groupheader">Error checking and buffer size</h3>
|
||||
*
|
||||
* All functions operating on CborEncoder return a condition of type CborError.
|
||||
* If the encoding was successful, they return CborNoError. Some functions do
|
||||
* extra checking on the input provided and may return some other error
|
||||
* conditions (for example, cbor_encode_simple_value() checks that the type is
|
||||
* of the correct type).
|
||||
*
|
||||
* In addition, all functions check whether the buffer has enough bytes to
|
||||
* encode the item being appended. If that is not possible, they return
|
||||
* CborErrorOutOfMemory.
|
||||
*
|
||||
* It is possible to continue with the encoding of data past the first function
|
||||
* that returns CborErrorOutOfMemory. CborEncoder functions will not overrun
|
||||
* the buffer, but will instead count how many more bytes are needed to
|
||||
* complete the encoding. At the end, you can obtain that count by calling
|
||||
* cbor_encoder_get_extra_bytes_needed().
|
||||
*
|
||||
* \section1 Finalizing the encoding
|
||||
*
|
||||
* Once all items have been appended and the containers have all been properly
|
||||
* closed, the user-supplied buffer will contain the CBOR stream and may be
|
||||
* immediately used. To obtain the size of the buffer, call
|
||||
* cbor_encoder_get_buffer_size() with the original buffer pointer.
|
||||
*
|
||||
* The example below illustrates how one can encode an item with error checking
|
||||
* and then pass on the buffer for network sending.
|
||||
*
|
||||
* \code
|
||||
* uint8_t buf[16];
|
||||
* CborError err;
|
||||
* CborEncoder encoder, mapEncoder;
|
||||
* cbor_encoder_init(&encoder, buf, sizeof(buf), 0);
|
||||
* err = cbor_encoder_create_map(&encoder, &mapEncoder, 1);
|
||||
* if (err)
|
||||
* return err;
|
||||
* err = cbor_encode_text_stringz(&mapEncoder, "foo");
|
||||
* if (err)
|
||||
* return err;
|
||||
* err = cbor_encode_boolean(&mapEncoder, some_value);
|
||||
* if (err)
|
||||
* return err;
|
||||
* err = cbor_encoder_close_container_checked(&encoder, &mapEncoder);
|
||||
* if (err)
|
||||
* return err;
|
||||
*
|
||||
* size_t len = cbor_encoder_get_buffer_size(&encoder, buf);
|
||||
* send_payload(buf, len);
|
||||
* return CborNoError;
|
||||
* \endcode
|
||||
*
|
||||
* Finally, the example below expands on the one above and also
|
||||
* deals with dynamically growing the buffer if the initial allocation wasn't
|
||||
* big enough. Note the two places where the error checking was replaced with
|
||||
* an cbor_assertion, showing where the author assumes no error can occur.
|
||||
*
|
||||
* \code
|
||||
* uint8_t *encode_string_array(const char **strings, int n, size_t *bufsize)
|
||||
* {
|
||||
* CborError err;
|
||||
* CborEncoder encoder, arrayEncoder;
|
||||
* size_t size = 256;
|
||||
* uint8_t *buf = NULL;
|
||||
*
|
||||
* while (1) {
|
||||
* int i;
|
||||
* size_t more_bytes;
|
||||
* uint8_t *nbuf = realloc(buf, size);
|
||||
* if (nbuf == NULL)
|
||||
* goto error;
|
||||
* buf = nbuf;
|
||||
*
|
||||
* cbor_encoder_init(&encoder, buf, size, 0);
|
||||
* err = cbor_encoder_create_array(&encoder, &arrayEncoder, n);
|
||||
* cbor_assert(!err); // can't fail, the buffer is always big enough
|
||||
*
|
||||
* for (i = 0; i < n; ++i) {
|
||||
* err = cbor_encode_text_stringz(&arrayEncoder, strings[i]);
|
||||
* if (err && err != CborErrorOutOfMemory)
|
||||
* goto error;
|
||||
* }
|
||||
*
|
||||
* err = cbor_encoder_close_container_checked(&encoder, &arrayEncoder);
|
||||
* cbor_assert(!err); // shouldn't fail!
|
||||
*
|
||||
* more_bytes = cbor_encoder_get_extra_bytes_needed(encoder);
|
||||
* if (more_size) {
|
||||
* // buffer wasn't big enough, try again
|
||||
* size += more_bytes;
|
||||
* continue;
|
||||
* }
|
||||
*
|
||||
* *bufsize = cbor_encoder_get_buffer_size(encoder, buf);
|
||||
* return buf;
|
||||
* }
|
||||
* error:
|
||||
* free(buf);
|
||||
* return NULL;
|
||||
* }
|
||||
* \endcode
|
||||
*/
|
||||
|
||||
/**
|
||||
* \addtogroup CborEncoding
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* \struct CborEncoder
|
||||
* Structure used to encode to CBOR.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Initializes a CborEncoder structure \a encoder by pointing it to buffer \a
|
||||
* buffer of size \a size. The \a flags field is currently unused and must be
|
||||
* zero.
|
||||
*/
|
||||
void cbor_encoder_init(CborEncoder *encoder, uint8_t *buffer, size_t size, int flags)
|
||||
{
|
||||
encoder->data.ptr = buffer;
|
||||
encoder->end = buffer + size;
|
||||
encoder->remaining = 2;
|
||||
encoder->flags = flags;
|
||||
}
|
||||
|
||||
void cbor_encoder_init_writer(CborEncoder *encoder, CborEncoderWriteFunction writer, void *token)
|
||||
{
|
||||
#ifdef CBOR_ENCODER_WRITE_FUNCTION
|
||||
(void) writer;
|
||||
#else
|
||||
encoder->data.writer = writer;
|
||||
#endif
|
||||
encoder->end = (uint8_t *)token;
|
||||
encoder->remaining = 2;
|
||||
encoder->flags = CborIteratorFlag_WriterFunction;
|
||||
}
|
||||
|
||||
static inline void put16(void *where, uint16_t v)
|
||||
{
|
||||
uint16_t v_be = cbor_htons(v);
|
||||
memcpy(where, &v_be, sizeof(v_be));
|
||||
}
|
||||
|
||||
/* Note: Since this is currently only used in situations where OOM is the only
|
||||
* valid error, we KNOW this to be true. Thus, this function now returns just 'true',
|
||||
* but if in the future, any function starts returning a non-OOM error, this will need
|
||||
* to be changed to the test. At the moment, this is done to prevent more branches
|
||||
* being created in the tinycbor output */
|
||||
static inline bool isOomError(CborError err)
|
||||
{
|
||||
if (CBOR_ENCODER_WRITER_CONTROL < 0)
|
||||
return true;
|
||||
|
||||
/* CborErrorOutOfMemory is the only negative error code, intentionally
|
||||
* so we can write the test like this */
|
||||
return (int)err < 0;
|
||||
}
|
||||
|
||||
static inline void put32(void *where, uint32_t v)
|
||||
{
|
||||
uint32_t v_be = cbor_htonl(v);
|
||||
memcpy(where, &v_be, sizeof(v_be));
|
||||
}
|
||||
|
||||
static inline void put64(void *where, uint64_t v)
|
||||
{
|
||||
uint64_t v_be = cbor_htonll(v);
|
||||
memcpy(where, &v_be, sizeof(v_be));
|
||||
}
|
||||
|
||||
static inline bool would_overflow(CborEncoder *encoder, size_t len)
|
||||
{
|
||||
ptrdiff_t remaining = (ptrdiff_t)encoder->end;
|
||||
remaining -= remaining ? (ptrdiff_t)encoder->data.ptr : encoder->data.bytes_needed;
|
||||
remaining -= (ptrdiff_t)len;
|
||||
return unlikely(remaining < 0);
|
||||
}
|
||||
|
||||
static inline void advance_ptr(CborEncoder *encoder, size_t n)
|
||||
{
|
||||
if (encoder->end)
|
||||
encoder->data.ptr += n;
|
||||
else
|
||||
encoder->data.bytes_needed += n;
|
||||
}
|
||||
|
||||
static inline CborError append_to_buffer(CborEncoder *encoder, const void *data, size_t len,
|
||||
CborEncoderAppendType appendType)
|
||||
{
|
||||
if (CBOR_ENCODER_WRITER_CONTROL >= 0) {
|
||||
if (encoder->flags & CborIteratorFlag_WriterFunction || CBOR_ENCODER_WRITER_CONTROL != 0) {
|
||||
# ifdef CBOR_ENCODER_WRITE_FUNCTION
|
||||
return CBOR_ENCODER_WRITE_FUNCTION(encoder->end, data, len, appendType);
|
||||
# else
|
||||
return encoder->data.writer(encoder->end, data, len, appendType);
|
||||
# endif
|
||||
}
|
||||
}
|
||||
|
||||
#if CBOR_ENCODER_WRITER_CONTROL <= 0
|
||||
if (would_overflow(encoder, len)) {
|
||||
if (encoder->end != NULL) {
|
||||
len -= encoder->end - encoder->data.ptr;
|
||||
encoder->end = NULL;
|
||||
encoder->data.bytes_needed = 0;
|
||||
}
|
||||
|
||||
advance_ptr(encoder, len);
|
||||
return CborErrorOutOfMemory;
|
||||
}
|
||||
|
||||
memcpy(encoder->data.ptr, data, len);
|
||||
encoder->data.ptr += len;
|
||||
#endif
|
||||
return CborNoError;
|
||||
}
|
||||
|
||||
static inline CborError append_byte_to_buffer(CborEncoder *encoder, uint8_t byte)
|
||||
{
|
||||
return append_to_buffer(encoder, &byte, 1, CborEncoderAppendCborData);
|
||||
}
|
||||
|
||||
static inline CborError encode_number_no_update(CborEncoder *encoder, uint64_t ui, uint8_t shiftedMajorType)
|
||||
{
|
||||
/* Little-endian would have been so much more convenient here:
|
||||
* We could just write at the beginning of buf but append_to_buffer
|
||||
* only the necessary bytes.
|
||||
* Since it has to be big endian, do it the other way around:
|
||||
* write from the end. */
|
||||
uint64_t buf[2];
|
||||
uint8_t *const bufend = (uint8_t *)buf + sizeof(buf);
|
||||
uint8_t *bufstart = bufend - 1;
|
||||
put64(buf + 1, ui); /* we probably have a bunch of zeros in the beginning */
|
||||
|
||||
if (ui < Value8Bit) {
|
||||
*bufstart += shiftedMajorType;
|
||||
} else {
|
||||
uint8_t more = 0;
|
||||
if (ui > 0xffU)
|
||||
++more;
|
||||
if (ui > 0xffffU)
|
||||
++more;
|
||||
if (ui > 0xffffffffU)
|
||||
++more;
|
||||
bufstart -= (size_t)1 << more;
|
||||
*bufstart = shiftedMajorType + Value8Bit + more;
|
||||
}
|
||||
|
||||
return append_to_buffer(encoder, bufstart, bufend - bufstart, CborEncoderAppendCborData);
|
||||
}
|
||||
|
||||
static inline void saturated_decrement(CborEncoder *encoder)
|
||||
{
|
||||
if (encoder->remaining)
|
||||
--encoder->remaining;
|
||||
}
|
||||
|
||||
static inline CborError encode_number(CborEncoder *encoder, uint64_t ui, uint8_t shiftedMajorType)
|
||||
{
|
||||
saturated_decrement(encoder);
|
||||
return encode_number_no_update(encoder, ui, shiftedMajorType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends the unsigned 64-bit integer \a value to the CBOR stream provided by
|
||||
* \a encoder.
|
||||
*
|
||||
* \sa cbor_encode_negative_int, cbor_encode_int
|
||||
*/
|
||||
CborError cbor_encode_uint(CborEncoder *encoder, uint64_t value)
|
||||
{
|
||||
return encode_number(encoder, value, UnsignedIntegerType << MajorTypeShift);
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends the negative 64-bit integer whose absolute value is \a
|
||||
* absolute_value to the CBOR stream provided by \a encoder.
|
||||
*
|
||||
* If the value \a absolute_value is zero, this function encodes -2^64.
|
||||
*
|
||||
* \sa cbor_encode_uint, cbor_encode_int
|
||||
*/
|
||||
CborError cbor_encode_negative_int(CborEncoder *encoder, uint64_t absolute_value)
|
||||
{
|
||||
return encode_number(encoder, absolute_value - 1, NegativeIntegerType << MajorTypeShift);
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends the signed 64-bit integer \a value to the CBOR stream provided by
|
||||
* \a encoder.
|
||||
*
|
||||
* \sa cbor_encode_negative_int, cbor_encode_uint
|
||||
*/
|
||||
CborError cbor_encode_int(CborEncoder *encoder, int64_t value)
|
||||
{
|
||||
/* adapted from code in RFC 7049 appendix C (pseudocode) */
|
||||
uint64_t ui = value >> 63; /* extend sign to whole length */
|
||||
uint8_t majorType = ui & 0x20; /* extract major type */
|
||||
ui ^= value; /* complement negatives */
|
||||
return encode_number(encoder, ui, majorType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends the CBOR Simple Type of value \a value to the CBOR stream provided by
|
||||
* \a encoder.
|
||||
*
|
||||
* This function may return error CborErrorIllegalSimpleType if the \a value
|
||||
* variable contains a number that is not a valid simple type.
|
||||
*/
|
||||
CborError cbor_encode_simple_value(CborEncoder *encoder, uint8_t value)
|
||||
{
|
||||
#ifndef CBOR_ENCODER_NO_CHECK_USER
|
||||
/* check if this is a valid simple type */
|
||||
if (value >= HalfPrecisionFloat && value <= Break)
|
||||
return CborErrorIllegalSimpleType;
|
||||
#endif
|
||||
return encode_number(encoder, value, SimpleTypesType << MajorTypeShift);
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends the floating-point value of type \a fpType and pointed to by \a
|
||||
* value to the CBOR stream provided by \a encoder. The value of \a fpType must
|
||||
* be one of CborHalfFloatType, CborFloatType or CborDoubleType, otherwise the
|
||||
* behavior of this function is undefined.
|
||||
*
|
||||
* This function is useful for code that needs to pass through floating point
|
||||
* values but does not wish to have the actual floating-point code.
|
||||
*
|
||||
* \sa cbor_encode_half_float, cbor_encode_float_as_half_float, cbor_encode_float, cbor_encode_double
|
||||
*/
|
||||
CborError cbor_encode_floating_point(CborEncoder *encoder, CborType fpType, const void *value)
|
||||
{
|
||||
unsigned size;
|
||||
uint8_t buf[1 + sizeof(uint64_t)];
|
||||
cbor_assert(fpType == CborHalfFloatType || fpType == CborFloatType || fpType == CborDoubleType);
|
||||
buf[0] = fpType;
|
||||
|
||||
size = 2U << (fpType - CborHalfFloatType);
|
||||
if (size == 8)
|
||||
put64(buf + 1, *(const uint64_t*)value);
|
||||
else if (size == 4)
|
||||
put32(buf + 1, *(const uint32_t*)value);
|
||||
else
|
||||
put16(buf + 1, *(const uint16_t*)value);
|
||||
saturated_decrement(encoder);
|
||||
return append_to_buffer(encoder, buf, size + 1, CborEncoderAppendCborData);
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends the CBOR tag \a tag to the CBOR stream provided by \a encoder.
|
||||
*
|
||||
* \sa CborTag
|
||||
*/
|
||||
CborError cbor_encode_tag(CborEncoder *encoder, CborTag tag)
|
||||
{
|
||||
/* tags don't count towards the number of elements in an array or map */
|
||||
return encode_number_no_update(encoder, tag, TagType << MajorTypeShift);
|
||||
}
|
||||
|
||||
static CborError encode_string(CborEncoder *encoder, size_t length, uint8_t shiftedMajorType, const void *string)
|
||||
{
|
||||
CborError err = encode_number(encoder, length, shiftedMajorType);
|
||||
if (err && !isOomError(err))
|
||||
return err;
|
||||
return append_to_buffer(encoder, string, length, CborEncoderAppendStringData);
|
||||
}
|
||||
|
||||
/**
|
||||
* \fn CborError cbor_encode_text_stringz(CborEncoder *encoder, const char *string)
|
||||
*
|
||||
* Appends the null-terminated text string \a string to the CBOR stream
|
||||
* provided by \a encoder. CBOR requires that \a string be valid UTF-8, but
|
||||
* TinyCBOR makes no verification of correctness. The terminating null is not
|
||||
* included in the stream.
|
||||
*
|
||||
* \sa cbor_encode_text_string, cbor_encode_byte_string
|
||||
*/
|
||||
|
||||
/**
|
||||
* Appends the byte string \a string of length \a length to the CBOR stream
|
||||
* provided by \a encoder. CBOR byte strings are arbitrary raw data.
|
||||
*
|
||||
* \sa cbor_encode_text_stringz, cbor_encode_text_string
|
||||
*/
|
||||
CborError cbor_encode_byte_string(CborEncoder *encoder, const uint8_t *string, size_t length)
|
||||
{
|
||||
return encode_string(encoder, length, ByteStringType << MajorTypeShift, string);
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends the text string \a string of length \a length to the CBOR stream
|
||||
* provided by \a encoder. CBOR requires that \a string be valid UTF-8, but
|
||||
* TinyCBOR makes no verification of correctness.
|
||||
*
|
||||
* \sa CborError cbor_encode_text_stringz, cbor_encode_byte_string
|
||||
*/
|
||||
CborError cbor_encode_text_string(CborEncoder *encoder, const char *string, size_t length)
|
||||
{
|
||||
return encode_string(encoder, length, TextStringType << MajorTypeShift, string);
|
||||
}
|
||||
|
||||
#ifdef __GNUC__
|
||||
__attribute__((noinline))
|
||||
#endif
|
||||
static CborError create_container(CborEncoder *encoder, CborEncoder *container, size_t length, uint8_t shiftedMajorType)
|
||||
{
|
||||
CborError err;
|
||||
container->data.ptr = encoder->data.ptr;
|
||||
container->end = encoder->end;
|
||||
saturated_decrement(encoder);
|
||||
container->remaining = length + 1; /* overflow ok on CborIndefiniteLength */
|
||||
|
||||
cbor_static_assert((int)CborIteratorFlag_ContainerIsMap_ == (int)CborIteratorFlag_ContainerIsMap);
|
||||
cbor_static_assert(((MapType << MajorTypeShift) & CborIteratorFlag_ContainerIsMap) == CborIteratorFlag_ContainerIsMap);
|
||||
cbor_static_assert(((ArrayType << MajorTypeShift) & CborIteratorFlag_ContainerIsMap) == 0);
|
||||
container->flags = shiftedMajorType & CborIteratorFlag_ContainerIsMap;
|
||||
if (CBOR_ENCODER_WRITER_CONTROL == 0)
|
||||
container->flags |= encoder->flags & CborIteratorFlag_WriterFunction;
|
||||
|
||||
if (length == CborIndefiniteLength) {
|
||||
container->flags |= CborIteratorFlag_UnknownLength;
|
||||
err = append_byte_to_buffer(container, shiftedMajorType + IndefiniteLength);
|
||||
} else {
|
||||
if (shiftedMajorType & CborIteratorFlag_ContainerIsMap)
|
||||
container->remaining += length;
|
||||
err = encode_number_no_update(container, length, shiftedMajorType);
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a CBOR array in the CBOR stream provided by \a parentEncoder and
|
||||
* initializes \a arrayEncoder so that items can be added to the array using
|
||||
* the CborEncoder functions. The array must be terminated by calling either
|
||||
* cbor_encoder_close_container() or cbor_encoder_close_container_checked()
|
||||
* with the same \a encoder and \a arrayEncoder parameters.
|
||||
*
|
||||
* The number of items inserted into the array must be exactly \a length items,
|
||||
* otherwise the stream is invalid. If the number of items is not known when
|
||||
* creating the array, the constant \ref CborIndefiniteLength may be passed as
|
||||
* length instead, and an indefinite length array is created.
|
||||
*
|
||||
* \sa cbor_encoder_create_map
|
||||
*/
|
||||
CborError cbor_encoder_create_array(CborEncoder *parentEncoder, CborEncoder *arrayEncoder, size_t length)
|
||||
{
|
||||
return create_container(parentEncoder, arrayEncoder, length, ArrayType << MajorTypeShift);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a CBOR map in the CBOR stream provided by \a parentEncoder and
|
||||
* initializes \a mapEncoder so that items can be added to the map using
|
||||
* the CborEncoder functions. The map must be terminated by calling either
|
||||
* cbor_encoder_close_container() or cbor_encoder_close_container_checked()
|
||||
* with the same \a encoder and \a mapEncoder parameters.
|
||||
*
|
||||
* The number of pair of items inserted into the map must be exactly \a length
|
||||
* items, otherwise the stream is invalid. If the number is not known
|
||||
* when creating the map, the constant \ref CborIndefiniteLength may be passed as
|
||||
* length instead, and an indefinite length map is created.
|
||||
*
|
||||
* \b{Implementation limitation:} TinyCBOR cannot encode more than SIZE_MAX/2
|
||||
* key-value pairs in the stream. If the length \a length is larger than this
|
||||
* value (and is not \ref CborIndefiniteLength), this function returns error
|
||||
* CborErrorDataTooLarge.
|
||||
*
|
||||
* \sa cbor_encoder_create_array
|
||||
*/
|
||||
CborError cbor_encoder_create_map(CborEncoder *parentEncoder, CborEncoder *mapEncoder, size_t length)
|
||||
{
|
||||
if (length != CborIndefiniteLength && length > SIZE_MAX / 2)
|
||||
return CborErrorDataTooLarge;
|
||||
return create_container(parentEncoder, mapEncoder, length, MapType << MajorTypeShift);
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes the CBOR container (array or map) provided by \a containerEncoder and
|
||||
* updates the CBOR stream provided by \a encoder. Both parameters must be the
|
||||
* same as were passed to cbor_encoder_create_array() or
|
||||
* cbor_encoder_create_map().
|
||||
*
|
||||
* Since version 0.5, this function verifies that the number of items (or pairs
|
||||
* of items, in the case of a map) was correct. It is no longer necessary to call
|
||||
* cbor_encoder_close_container_checked() instead.
|
||||
*
|
||||
* \sa cbor_encoder_create_array(), cbor_encoder_create_map()
|
||||
*/
|
||||
CborError cbor_encoder_close_container(CborEncoder *parentEncoder, const CborEncoder *containerEncoder)
|
||||
{
|
||||
// synchronise buffer state with that of the container
|
||||
parentEncoder->end = containerEncoder->end;
|
||||
parentEncoder->data = containerEncoder->data;
|
||||
|
||||
if (containerEncoder->flags & CborIteratorFlag_UnknownLength)
|
||||
return append_byte_to_buffer(parentEncoder, BreakByte);
|
||||
|
||||
if (containerEncoder->remaining != 1)
|
||||
return containerEncoder->remaining == 0 ? CborErrorTooManyItems : CborErrorTooFewItems;
|
||||
|
||||
if (!parentEncoder->end)
|
||||
return CborErrorOutOfMemory; /* keep the state */
|
||||
|
||||
return CborNoError;
|
||||
}
|
||||
|
||||
/**
|
||||
* \fn CborError cbor_encode_boolean(CborEncoder *encoder, bool value)
|
||||
*
|
||||
* Appends the boolean value \a value to the CBOR stream provided by \a encoder.
|
||||
*/
|
||||
|
||||
/**
|
||||
* \fn CborError cbor_encode_null(CborEncoder *encoder)
|
||||
*
|
||||
* Appends the CBOR type representing a null value to the CBOR stream provided
|
||||
* by \a encoder.
|
||||
*
|
||||
* \sa cbor_encode_undefined()
|
||||
*/
|
||||
|
||||
/**
|
||||
* \fn CborError cbor_encode_undefined(CborEncoder *encoder)
|
||||
*
|
||||
* Appends the CBOR type representing an undefined value to the CBOR stream
|
||||
* provided by \a encoder.
|
||||
*
|
||||
* \sa cbor_encode_null()
|
||||
*/
|
||||
|
||||
/**
|
||||
* \fn CborError cbor_encode_half_float(CborEncoder *encoder, const void *value)
|
||||
*
|
||||
* Appends the IEEE 754 half-precision (16-bit) floating point value pointed to
|
||||
* by \a value to the CBOR stream provided by \a encoder.
|
||||
*
|
||||
* \sa cbor_encode_floating_point(), cbor_encode_float(), cbor_encode_double()
|
||||
*/
|
||||
|
||||
/**
|
||||
* \fn CborError cbor_encode_float_as_half_float(CborEncoder *encoder, float value)
|
||||
*
|
||||
* Convert the IEEE 754 single-precision (32-bit) floating point value \a value
|
||||
* to the IEEE 754 half-precision (16-bit) floating point value and append it
|
||||
* to the CBOR stream provided by \a encoder.
|
||||
* The \a value should be in the range of the IEEE 754 half-precision floating point type,
|
||||
* INFINITY, -INFINITY, or NAN, otherwise the behavior of this function is undefined.
|
||||
*
|
||||
* \sa cbor_encode_floating_point(), cbor_encode_float(), cbor_encode_double()
|
||||
*/
|
||||
|
||||
/**
|
||||
* \fn CborError cbor_encode_float(CborEncoder *encoder, float value)
|
||||
*
|
||||
* Appends the IEEE 754 single-precision (32-bit) floating point value \a value
|
||||
* to the CBOR stream provided by \a encoder.
|
||||
*
|
||||
* \sa cbor_encode_floating_point(), cbor_encode_half_float(), cbor_encode_float_as_half_float(), cbor_encode_double()
|
||||
*/
|
||||
|
||||
/**
|
||||
* \fn CborError cbor_encode_double(CborEncoder *encoder, double value)
|
||||
*
|
||||
* Appends the IEEE 754 double-precision (64-bit) floating point value \a value
|
||||
* to the CBOR stream provided by \a encoder.
|
||||
*
|
||||
* \sa cbor_encode_floating_point(), cbor_encode_half_float(), cbor_encode_float_as_half_float(), cbor_encode_float()
|
||||
*/
|
||||
|
||||
/**
|
||||
* \fn size_t cbor_encoder_get_buffer_size(const CborEncoder *encoder, const uint8_t *buffer)
|
||||
*
|
||||
* Returns the total size of the buffer starting at \a buffer after the
|
||||
* encoding finished without errors. The \a encoder and \a buffer arguments
|
||||
* must be the same as supplied to cbor_encoder_init().
|
||||
*
|
||||
* If the encoding process had errors, the return value of this function is
|
||||
* meaningless. If the only errors were CborErrorOutOfMemory, instead use
|
||||
* cbor_encoder_get_extra_bytes_needed() to find out by how much to grow the
|
||||
* buffer before encoding again.
|
||||
*
|
||||
* See \ref CborEncoding for an example of using this function.
|
||||
*
|
||||
* \sa cbor_encoder_init(), cbor_encoder_get_extra_bytes_needed(), CborEncoding
|
||||
*/
|
||||
|
||||
/**
|
||||
* \fn size_t cbor_encoder_get_extra_bytes_needed(const CborEncoder *encoder)
|
||||
*
|
||||
* Returns how many more bytes the original buffer supplied to
|
||||
* cbor_encoder_init() needs to be extended by so that no CborErrorOutOfMemory
|
||||
* condition will happen for the encoding. If the buffer was big enough, this
|
||||
* function returns 0. The \a encoder must be the original argument as passed
|
||||
* to cbor_encoder_init().
|
||||
*
|
||||
* This function is usually called after an encoding sequence ended with one or
|
||||
* more CborErrorOutOfMemory errors, but no other error. If any other error
|
||||
* happened, the return value of this function is meaningless.
|
||||
*
|
||||
* See \ref CborEncoding for an example of using this function.
|
||||
*
|
||||
* \sa cbor_encoder_init(), cbor_encoder_get_buffer_size(), CborEncoding
|
||||
*/
|
||||
|
||||
/** @} */
|
||||
@@ -0,0 +1,58 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2015 Intel Corporation
|
||||
**
|
||||
** Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
** of this software and associated documentation files (the "Software"), to deal
|
||||
** in the Software without restriction, including without limitation the rights
|
||||
** to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
** copies of the Software, and to permit persons to whom the Software is
|
||||
** furnished to do so, subject to the following conditions:
|
||||
**
|
||||
** The above copyright notice and this permission notice shall be included in
|
||||
** all copies or substantial portions of the Software.
|
||||
**
|
||||
** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
** OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
** THE SOFTWARE.
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#define _BSD_SOURCE 1
|
||||
#define _DEFAULT_SOURCE 1
|
||||
#ifndef __STDC_LIMIT_MACROS
|
||||
# define __STDC_LIMIT_MACROS 1
|
||||
#endif
|
||||
#define __STDC_WANT_IEC_60559_TYPES_EXT__
|
||||
|
||||
#include "cbor.h"
|
||||
|
||||
/**
|
||||
* \addtogroup CborEncoding
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
*
|
||||
* Closes the CBOR container (array or map) provided by \a containerEncoder and
|
||||
* updates the CBOR stream provided by \a encoder. Both parameters must be the
|
||||
* same as were passed to cbor_encoder_create_array() or
|
||||
* cbor_encoder_create_map().
|
||||
*
|
||||
* Prior to version 0.5, cbor_encoder_close_container() did not check the
|
||||
* number of items added. Since that version, it does and now
|
||||
* cbor_encoder_close_container_checked() is no longer needed.
|
||||
*
|
||||
* \sa cbor_encoder_create_array(), cbor_encoder_create_map()
|
||||
*/
|
||||
CborError cbor_encoder_close_container_checked(CborEncoder *encoder, const CborEncoder *containerEncoder)
|
||||
{
|
||||
return cbor_encoder_close_container(encoder, containerEncoder);
|
||||
}
|
||||
|
||||
/** @} */
|
||||
43
frame_serialize/tinycbor/cborencoder_float.c
Normal file
43
frame_serialize/tinycbor/cborencoder_float.c
Normal file
@@ -0,0 +1,43 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2019 S.Phirsov
|
||||
**
|
||||
** Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
** of this software and associated documentation files (the "Software"), to deal
|
||||
** in the Software without restriction, including without limitation the rights
|
||||
** to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
** copies of the Software, and to permit persons to whom the Software is
|
||||
** furnished to do so, subject to the following conditions:
|
||||
**
|
||||
** The above copyright notice and this permission notice shall be included in
|
||||
** all copies or substantial portions of the Software.
|
||||
**
|
||||
** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
** OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
** THE SOFTWARE.
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#define _BSD_SOURCE 1
|
||||
#define _DEFAULT_SOURCE 1
|
||||
#ifndef __STDC_LIMIT_MACROS
|
||||
# define __STDC_LIMIT_MACROS 1
|
||||
#endif
|
||||
#define __STDC_WANT_IEC_60559_TYPES_EXT__
|
||||
|
||||
#include "cbor.h"
|
||||
|
||||
#include "cborinternal_p.h"
|
||||
|
||||
#ifndef CBOR_NO_HALF_FLOAT_TYPE
|
||||
CborError cbor_encode_float_as_half_float(CborEncoder *encoder, float value)
|
||||
{
|
||||
uint16_t v = (uint16_t)encode_half(value);
|
||||
|
||||
return cbor_encode_floating_point(encoder, CborHalfFloatType, &v);
|
||||
}
|
||||
#endif
|
||||
188
frame_serialize/tinycbor/cborerrorstrings.c
Normal file
188
frame_serialize/tinycbor/cborerrorstrings.c
Normal file
@@ -0,0 +1,188 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2021 Intel Corporation
|
||||
**
|
||||
** Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
** of this software and associated documentation files (the "Software"), to deal
|
||||
** in the Software without restriction, including without limitation the rights
|
||||
** to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
** copies of the Software, and to permit persons to whom the Software is
|
||||
** furnished to do so, subject to the following conditions:
|
||||
**
|
||||
** The above copyright notice and this permission notice shall be included in
|
||||
** all copies or substantial portions of the Software.
|
||||
**
|
||||
** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
** OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
** THE SOFTWARE.
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#include "cbor.h"
|
||||
|
||||
#ifndef _
|
||||
# define _(msg) msg
|
||||
#endif
|
||||
|
||||
/**
|
||||
* \enum CborError
|
||||
* \ingroup CborGlobals
|
||||
* The CborError enum contains the possible error values used by the CBOR encoder and decoder.
|
||||
*
|
||||
* TinyCBOR functions report success by returning CborNoError, or one error
|
||||
* condition by returning one of the values below. One exception is the
|
||||
* out-of-memory condition (CborErrorOutOfMemory), which the functions for \ref
|
||||
* CborEncoding may report in bit-wise OR with other conditions.
|
||||
*
|
||||
* This technique allows code to determine whether the only error condition was
|
||||
* a lack of buffer space, which may not be a fatal condition if the buffer can
|
||||
* be resized. Additionally, the functions for \ref CborEncoding may continue
|
||||
* to be used even after CborErrorOutOfMemory is returned, and instead they
|
||||
* will simply calculate the extra space needed.
|
||||
*
|
||||
* \value CborNoError No error occurred
|
||||
* \omitvalue CborUnknownError
|
||||
* \value CborErrorUnknownLength Request for the length of an array, map or string whose length is not provided in the CBOR stream
|
||||
* \value CborErrorAdvancePastEOF Not enough data in the stream to decode item (decoding would advance past end of stream)
|
||||
* \value CborErrorIO An I/O error occurred, probably due to an out-of-memory situation
|
||||
* \value CborErrorGarbageAtEnd Bytes exist past the end of the CBOR stream
|
||||
* \value CborErrorUnexpectedEOF End of stream reached unexpectedly
|
||||
* \value CborErrorUnexpectedBreak A CBOR break byte was found where not expected
|
||||
* \value CborErrorUnknownType An unknown type (future extension to CBOR) was found in the stream
|
||||
* \value CborErrorIllegalType An invalid type was found while parsing a chunked CBOR string
|
||||
* \value CborErrorIllegalNumber An illegal initial byte (encoding unspecified additional information) was found
|
||||
* \value CborErrorIllegalSimpleType An illegal encoding of a CBOR Simple Type of value less than 32 was found
|
||||
* \omitvalue CborErrorUnknownSimpleType
|
||||
* \omitvalue CborErrorUnknownTag
|
||||
* \omitvalue CborErrorInappropriateTagForType
|
||||
* \omitvalue CborErrorDuplicateObjectKeys
|
||||
* \value CborErrorInvalidUtf8TextString Illegal UTF-8 encoding found while parsing CBOR Text String
|
||||
* \value CborErrorTooManyItems Too many items were added to CBOR map or array of pre-determined length
|
||||
* \value CborErrorTooFewItems Too few items were added to CBOR map or array of pre-determined length
|
||||
* \value CborErrorDataTooLarge Data item size exceeds TinyCBOR's implementation limits
|
||||
* \value CborErrorNestingTooDeep Data item nesting exceeds TinyCBOR's implementation limits
|
||||
* \omitvalue CborErrorUnsupportedType
|
||||
* \value CborErrorJsonObjectKeyIsAggregate Conversion to JSON failed because the key in a map is a CBOR map or array
|
||||
* \value CborErrorJsonObjectKeyNotString Conversion to JSON failed because the key in a map is not a text string
|
||||
* \value CborErrorOutOfMemory During CBOR encoding, the buffer provided is insufficient for encoding the data item;
|
||||
* in other situations, TinyCBOR failed to allocate memory
|
||||
* \value CborErrorInternalError An internal error occurred in TinyCBOR
|
||||
*/
|
||||
|
||||
/**
|
||||
* \ingroup CborGlobals
|
||||
* Returns the error string corresponding to the CBOR error condition \a error.
|
||||
*/
|
||||
const char *cbor_error_string(CborError error)
|
||||
{
|
||||
switch (error) {
|
||||
case CborNoError:
|
||||
return "";
|
||||
|
||||
case CborUnknownError:
|
||||
return _("unknown error");
|
||||
|
||||
case CborErrorOutOfMemory:
|
||||
return _("out of memory/need more memory");
|
||||
|
||||
case CborErrorUnknownLength:
|
||||
return _("unknown length (attempted to get the length of a map/array/string of indeterminate length");
|
||||
|
||||
case CborErrorAdvancePastEOF:
|
||||
return _("attempted to advance past EOF");
|
||||
|
||||
case CborErrorIO:
|
||||
return _("I/O error");
|
||||
|
||||
case CborErrorGarbageAtEnd:
|
||||
return _("garbage after the end of the content");
|
||||
|
||||
case CborErrorUnexpectedEOF:
|
||||
return _("unexpected end of data");
|
||||
|
||||
case CborErrorUnexpectedBreak:
|
||||
return _("unexpected 'break' byte");
|
||||
|
||||
case CborErrorUnknownType:
|
||||
return _("illegal byte (encodes future extension type)");
|
||||
|
||||
case CborErrorIllegalType:
|
||||
return _("mismatched string type in chunked string");
|
||||
|
||||
case CborErrorIllegalNumber:
|
||||
return _("illegal initial byte (encodes unspecified additional information)");
|
||||
|
||||
case CborErrorIllegalSimpleType:
|
||||
return _("illegal encoding of simple type smaller than 32");
|
||||
|
||||
case CborErrorNoMoreStringChunks:
|
||||
return _("no more byte or text strings available");
|
||||
|
||||
case CborErrorUnknownSimpleType:
|
||||
return _("unknown simple type");
|
||||
|
||||
case CborErrorUnknownTag:
|
||||
return _("unknown tag");
|
||||
|
||||
case CborErrorInappropriateTagForType:
|
||||
return _("inappropriate tag for type");
|
||||
|
||||
case CborErrorDuplicateObjectKeys:
|
||||
return _("duplicate keys in object");
|
||||
|
||||
case CborErrorInvalidUtf8TextString:
|
||||
return _("invalid UTF-8 content in string");
|
||||
|
||||
case CborErrorExcludedType:
|
||||
return _("excluded type found");
|
||||
|
||||
case CborErrorExcludedValue:
|
||||
return _("excluded value found");
|
||||
|
||||
case CborErrorImproperValue:
|
||||
case CborErrorOverlongEncoding:
|
||||
return _("value encoded in non-canonical form");
|
||||
|
||||
case CborErrorMapKeyNotString:
|
||||
case CborErrorJsonObjectKeyNotString:
|
||||
return _("key in map is not a string");
|
||||
|
||||
case CborErrorMapNotSorted:
|
||||
return _("map is not sorted");
|
||||
|
||||
case CborErrorMapKeysNotUnique:
|
||||
return _("map keys are not unique");
|
||||
|
||||
case CborErrorTooManyItems:
|
||||
return _("too many items added to encoder");
|
||||
|
||||
case CborErrorTooFewItems:
|
||||
return _("too few items added to encoder");
|
||||
|
||||
case CborErrorDataTooLarge:
|
||||
return _("internal error: data too large");
|
||||
|
||||
case CborErrorNestingTooDeep:
|
||||
return _("internal error: too many nested containers found in recursive function");
|
||||
|
||||
case CborErrorUnsupportedType:
|
||||
return _("unsupported type");
|
||||
|
||||
case CborErrorUnimplementedValidation:
|
||||
return _("validation not implemented for the current parser state");
|
||||
|
||||
case CborErrorJsonObjectKeyIsAggregate:
|
||||
return _("conversion to JSON failed: key in object is an array or map");
|
||||
|
||||
case CborErrorJsonNotImplemented:
|
||||
return _("conversion to JSON failed: open_memstream unavailable");
|
||||
|
||||
case CborErrorInternalError:
|
||||
return _("internal error");
|
||||
}
|
||||
return cbor_error_string(CborUnknownError);
|
||||
}
|
||||
343
frame_serialize/tinycbor/cborinternal_p.h
Normal file
343
frame_serialize/tinycbor/cborinternal_p.h
Normal file
@@ -0,0 +1,343 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2021 Intel Corporation
|
||||
**
|
||||
** Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
** of this software and associated documentation files (the "Software"), to deal
|
||||
** in the Software without restriction, including without limitation the rights
|
||||
** to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
** copies of the Software, and to permit persons to whom the Software is
|
||||
** furnished to do so, subject to the following conditions:
|
||||
**
|
||||
** The above copyright notice and this permission notice shall be included in
|
||||
** all copies or substantial portions of the Software.
|
||||
**
|
||||
** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
** OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
** THE SOFTWARE.
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef CBORINTERNAL_P_H
|
||||
#define CBORINTERNAL_P_H
|
||||
|
||||
/* Dependent source files (*.c) must define __STDC_WANT_IEC_60559_TYPES_EXT__
|
||||
* before <float.h> is (transitively) first included.
|
||||
*/
|
||||
#if !defined(__STDC_WANT_IEC_60559_TYPES_EXT__)
|
||||
# error __STDC_WANT_IEC_60559_TYPES_EXT__ not defined
|
||||
#endif
|
||||
|
||||
#include "compilersupport_p.h"
|
||||
|
||||
#ifndef CBOR_NO_FLOATING_POINT
|
||||
# include <float.h>
|
||||
# include <math.h>
|
||||
# include <string.h>
|
||||
#else
|
||||
# ifndef CBOR_NO_HALF_FLOAT_TYPE
|
||||
# define CBOR_NO_HALF_FLOAT_TYPE 1
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef CBOR_NO_HALF_FLOAT_TYPE
|
||||
/* Check for FLT16_MANT_DIG using integer comparison. Clang headers incorrectly
|
||||
* define this macro unconditionally when __STDC_WANT_IEC_60559_TYPES_EXT__
|
||||
* is defined (regardless of actual support for _Float16).
|
||||
*/
|
||||
# if FLT16_MANT_DIG > 0 || __FLT16_MANT_DIG__ > 0
|
||||
static inline unsigned short encode_half(float x)
|
||||
{
|
||||
unsigned short h;
|
||||
_Float16 f = (_Float16)x;
|
||||
memcpy(&h, &f, 2);
|
||||
return h;
|
||||
}
|
||||
|
||||
static inline float decode_half(unsigned short x)
|
||||
{
|
||||
_Float16 f;
|
||||
memcpy(&f, &x, 2);
|
||||
return (float)f;
|
||||
}
|
||||
# elif defined(__F16C__) || defined(__AVX2__)
|
||||
# include <immintrin.h>
|
||||
static inline unsigned short encode_half(float val)
|
||||
{
|
||||
__m128i m = _mm_cvtps_ph(_mm_set_ss(val), _MM_FROUND_CUR_DIRECTION);
|
||||
return _mm_extract_epi16(m, 0);
|
||||
}
|
||||
static inline float decode_half(unsigned short half)
|
||||
{
|
||||
__m128i m = _mm_cvtsi32_si128(half);
|
||||
return _mm_cvtss_f32(_mm_cvtph_ps(m));
|
||||
}
|
||||
# else
|
||||
/* software implementation of float-to-fp16 conversions */
|
||||
static inline unsigned short encode_half(double val)
|
||||
{
|
||||
uint64_t v;
|
||||
int sign, exp, mant;
|
||||
memcpy(&v, &val, sizeof(v));
|
||||
sign = v >> 63 << 15;
|
||||
exp = (v >> 52) & 0x7ff;
|
||||
mant = v << 12 >> 12 >> (53-11); /* keep only the 11 most significant bits of the mantissa */
|
||||
exp -= 1023;
|
||||
if (exp == 1024) {
|
||||
/* infinity or NaN */
|
||||
exp = 16;
|
||||
mant >>= 1;
|
||||
} else if (exp >= 16) {
|
||||
/* overflow, as largest number */
|
||||
exp = 15;
|
||||
mant = 1023;
|
||||
} else if (exp >= -14) {
|
||||
/* regular normal */
|
||||
} else if (exp >= -24) {
|
||||
/* subnormal */
|
||||
mant |= 1024;
|
||||
mant >>= -(exp + 14);
|
||||
exp = -15;
|
||||
} else {
|
||||
/* underflow, make zero */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* safe cast here as bit operations above guarantee not to overflow */
|
||||
return (unsigned short)(sign | ((exp + 15) << 10) | mant);
|
||||
}
|
||||
|
||||
/* this function was copied & adapted from RFC 7049 Appendix D */
|
||||
static inline double decode_half(unsigned short half)
|
||||
{
|
||||
int exp = (half >> 10) & 0x1f;
|
||||
int mant = half & 0x3ff;
|
||||
double val;
|
||||
if (exp == 0) val = ldexp(mant, -24);
|
||||
else if (exp != 31) val = ldexp(mant + 1024, exp - 25);
|
||||
else val = mant == 0 ? INFINITY : NAN;
|
||||
return half & 0x8000 ? -val : val;
|
||||
}
|
||||
# endif
|
||||
#endif /* CBOR_NO_HALF_FLOAT_TYPE */
|
||||
|
||||
#ifndef CBOR_INTERNAL_API
|
||||
# define CBOR_INTERNAL_API
|
||||
#endif
|
||||
|
||||
#ifndef CBOR_PARSER_MAX_RECURSIONS
|
||||
# define CBOR_PARSER_MAX_RECURSIONS 1024
|
||||
#endif
|
||||
|
||||
#ifndef CBOR_ENCODER_WRITER_CONTROL
|
||||
# define CBOR_ENCODER_WRITER_CONTROL 0
|
||||
#endif
|
||||
#ifndef CBOR_PARSER_READER_CONTROL
|
||||
# define CBOR_PARSER_READER_CONTROL 0
|
||||
#endif
|
||||
|
||||
/*
|
||||
* CBOR Major types
|
||||
* Encoded in the high 3 bits of the descriptor byte
|
||||
* See http://tools.ietf.org/html/rfc7049#section-2.1
|
||||
*/
|
||||
typedef enum CborMajorTypes {
|
||||
UnsignedIntegerType = 0U,
|
||||
NegativeIntegerType = 1U,
|
||||
ByteStringType = 2U,
|
||||
TextStringType = 3U,
|
||||
ArrayType = 4U,
|
||||
MapType = 5U, /* a.k.a. object */
|
||||
TagType = 6U,
|
||||
SimpleTypesType = 7U
|
||||
} CborMajorTypes;
|
||||
|
||||
/*
|
||||
* CBOR simple and floating point types
|
||||
* Encoded in the low 8 bits of the descriptor byte when the
|
||||
* Major Type is 7.
|
||||
*/
|
||||
typedef enum CborSimpleTypes {
|
||||
FalseValue = 20,
|
||||
TrueValue = 21,
|
||||
NullValue = 22,
|
||||
UndefinedValue = 23,
|
||||
SimpleTypeInNextByte = 24, /* not really a simple type */
|
||||
HalfPrecisionFloat = 25, /* ditto */
|
||||
SinglePrecisionFloat = 26, /* ditto */
|
||||
DoublePrecisionFloat = 27, /* ditto */
|
||||
Break = 31
|
||||
} CborSimpleTypes;
|
||||
|
||||
enum {
|
||||
SmallValueBitLength = 5U,
|
||||
SmallValueMask = (1U << SmallValueBitLength) - 1, /* 31 */
|
||||
Value8Bit = 24U,
|
||||
Value16Bit = 25U,
|
||||
Value32Bit = 26U,
|
||||
Value64Bit = 27U,
|
||||
IndefiniteLength = 31U,
|
||||
|
||||
MajorTypeShift = SmallValueBitLength,
|
||||
MajorTypeMask = (int) (~0U << MajorTypeShift),
|
||||
|
||||
BreakByte = (unsigned)Break | (SimpleTypesType << MajorTypeShift)
|
||||
};
|
||||
|
||||
static inline void copy_current_position(CborValue *dst, const CborValue *src)
|
||||
{
|
||||
/* This "if" is here for pedantry only: the two branches should perform
|
||||
* the same memory operation. */
|
||||
if (src->parser->flags & CborParserFlag_ExternalSource)
|
||||
dst->source.token = src->source.token;
|
||||
else
|
||||
dst->source.ptr = src->source.ptr;
|
||||
}
|
||||
|
||||
static inline bool can_read_bytes(const CborValue *it, size_t n)
|
||||
{
|
||||
if (CBOR_PARSER_READER_CONTROL >= 0) {
|
||||
if (it->parser->flags & CborParserFlag_ExternalSource || CBOR_PARSER_READER_CONTROL != 0) {
|
||||
#ifdef CBOR_PARSER_CAN_READ_BYTES_FUNCTION
|
||||
return CBOR_PARSER_CAN_READ_BYTES_FUNCTION(it->source.token, n);
|
||||
#else
|
||||
return it->parser->source.ops->can_read_bytes(it->source.token, n);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
/* Convert the pointer subtraction to size_t since end >= ptr
|
||||
* (this prevents issues with (ptrdiff_t)n becoming negative).
|
||||
*/
|
||||
return (size_t)(it->parser->source.end - it->source.ptr) >= n;
|
||||
}
|
||||
|
||||
static inline void advance_bytes(CborValue *it, size_t n)
|
||||
{
|
||||
if (CBOR_PARSER_READER_CONTROL >= 0) {
|
||||
if (it->parser->flags & CborParserFlag_ExternalSource || CBOR_PARSER_READER_CONTROL != 0) {
|
||||
#ifdef CBOR_PARSER_ADVANCE_BYTES_FUNCTION
|
||||
CBOR_PARSER_ADVANCE_BYTES_FUNCTION(it->source.token, n);
|
||||
#else
|
||||
it->parser->source.ops->advance_bytes(it->source.token, n);
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
it->source.ptr += n;
|
||||
}
|
||||
|
||||
static inline CborError transfer_string(CborValue *it, const void **ptr, size_t offset, size_t len)
|
||||
{
|
||||
if (CBOR_PARSER_READER_CONTROL >= 0) {
|
||||
if (it->parser->flags & CborParserFlag_ExternalSource || CBOR_PARSER_READER_CONTROL != 0) {
|
||||
#ifdef CBOR_PARSER_TRANSFER_STRING_FUNCTION
|
||||
return CBOR_PARSER_TRANSFER_STRING_FUNCTION(it->source.token, ptr, offset, len);
|
||||
#else
|
||||
return it->parser->source.ops->transfer_string(it->source.token, ptr, offset, len);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
it->source.ptr += offset;
|
||||
if (can_read_bytes(it, len)) {
|
||||
*CONST_CAST(const void **, ptr) = it->source.ptr;
|
||||
it->source.ptr += len;
|
||||
return CborNoError;
|
||||
}
|
||||
return CborErrorUnexpectedEOF;
|
||||
}
|
||||
|
||||
static inline void *read_bytes_unchecked(const CborValue *it, void *dst, size_t offset, size_t n)
|
||||
{
|
||||
if (CBOR_PARSER_READER_CONTROL >= 0) {
|
||||
if (it->parser->flags & CborParserFlag_ExternalSource || CBOR_PARSER_READER_CONTROL != 0) {
|
||||
#ifdef CBOR_PARSER_READ_BYTES_FUNCTION
|
||||
return CBOR_PARSER_READ_BYTES_FUNCTION(it->source.token, dst, offset, n);
|
||||
#else
|
||||
return it->parser->source.ops->read_bytes(it->source.token, dst, offset, n);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
return memcpy(dst, it->source.ptr + offset, n);
|
||||
}
|
||||
|
||||
#ifdef __GNUC__
|
||||
__attribute__((warn_unused_result))
|
||||
#endif
|
||||
static inline void *read_bytes(const CborValue *it, void *dst, size_t offset, size_t n)
|
||||
{
|
||||
if (can_read_bytes(it, offset + n))
|
||||
return read_bytes_unchecked(it, dst, offset, n);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline uint16_t read_uint8(const CborValue *it, size_t offset)
|
||||
{
|
||||
uint8_t result;
|
||||
read_bytes_unchecked(it, &result, offset, sizeof(result));
|
||||
return result;
|
||||
}
|
||||
|
||||
static inline uint16_t read_uint16(const CborValue *it, size_t offset)
|
||||
{
|
||||
uint16_t result;
|
||||
read_bytes_unchecked(it, &result, offset, sizeof(result));
|
||||
return cbor_ntohs(result);
|
||||
}
|
||||
|
||||
static inline uint32_t read_uint32(const CborValue *it, size_t offset)
|
||||
{
|
||||
uint32_t result;
|
||||
read_bytes_unchecked(it, &result, offset, sizeof(result));
|
||||
return cbor_ntohl(result);
|
||||
}
|
||||
|
||||
static inline uint64_t read_uint64(const CborValue *it, size_t offset)
|
||||
{
|
||||
uint64_t result;
|
||||
read_bytes_unchecked(it, &result, offset, sizeof(result));
|
||||
return cbor_ntohll(result);
|
||||
}
|
||||
|
||||
static inline CborError extract_number_checked(const CborValue *it, uint64_t *value, size_t *bytesUsed)
|
||||
{
|
||||
uint8_t descriptor;
|
||||
size_t bytesNeeded = 0;
|
||||
|
||||
/* We've already verified that there's at least one byte to be read */
|
||||
read_bytes_unchecked(it, &descriptor, 0, 1);
|
||||
descriptor &= SmallValueMask;
|
||||
if (descriptor < Value8Bit) {
|
||||
*value = descriptor;
|
||||
} else if (unlikely(descriptor > Value64Bit)) {
|
||||
return CborErrorIllegalNumber;
|
||||
} else {
|
||||
bytesNeeded = (size_t)(1 << (descriptor - Value8Bit));
|
||||
if (!can_read_bytes(it, 1 + bytesNeeded))
|
||||
return CborErrorUnexpectedEOF;
|
||||
if (descriptor <= Value16Bit) {
|
||||
if (descriptor == Value16Bit)
|
||||
*value = read_uint16(it, 1);
|
||||
else
|
||||
*value = read_uint8(it, 1);
|
||||
} else {
|
||||
if (descriptor == Value32Bit)
|
||||
*value = read_uint32(it, 1);
|
||||
else
|
||||
*value = read_uint64(it, 1);
|
||||
}
|
||||
}
|
||||
|
||||
if (bytesUsed)
|
||||
*bytesUsed = bytesNeeded;
|
||||
return CborNoError;
|
||||
}
|
||||
|
||||
#endif /* CBORINTERNAL_P_H */
|
||||
62
frame_serialize/tinycbor/cborjson.h
Normal file
62
frame_serialize/tinycbor/cborjson.h
Normal file
@@ -0,0 +1,62 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2015 Intel Corporation
|
||||
**
|
||||
** Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
** of this software and associated documentation files (the "Software"), to deal
|
||||
** in the Software without restriction, including without limitation the rights
|
||||
** to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
** copies of the Software, and to permit persons to whom the Software is
|
||||
** furnished to do so, subject to the following conditions:
|
||||
**
|
||||
** The above copyright notice and this permission notice shall be included in
|
||||
** all copies or substantial portions of the Software.
|
||||
**
|
||||
** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
** OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
** THE SOFTWARE.
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef CBORJSON_H
|
||||
#define CBORJSON_H
|
||||
|
||||
#include "cbor.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Conversion to JSON */
|
||||
enum CborToJsonFlags
|
||||
{
|
||||
CborConvertAddMetadata = 1,
|
||||
CborConvertTagsToObjects = 2,
|
||||
CborConvertIgnoreTags = 0,
|
||||
|
||||
CborConvertObeyByteStringTags = 0,
|
||||
CborConvertByteStringsToBase64Url = 4,
|
||||
|
||||
CborConvertRequireMapStringKeys = 0,
|
||||
CborConvertStringifyMapKeys = 8,
|
||||
|
||||
CborConvertDefaultFlags = 0
|
||||
};
|
||||
|
||||
CBOR_API CborError cbor_value_to_json_advance(FILE *out, CborValue *value, int flags);
|
||||
CBOR_INLINE_API CborError cbor_value_to_json(FILE *out, const CborValue *value, int flags)
|
||||
{
|
||||
CborValue copy = *value;
|
||||
return cbor_value_to_json_advance(out, ©, flags);
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* CBORJSON_H */
|
||||
|
||||
1530
frame_serialize/tinycbor/cborparser.c
Normal file
1530
frame_serialize/tinycbor/cborparser.c
Normal file
File diff suppressed because it is too large
Load Diff
127
frame_serialize/tinycbor/cborparser_dup_string.c
Normal file
127
frame_serialize/tinycbor/cborparser_dup_string.c
Normal file
@@ -0,0 +1,127 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2016 Intel Corporation
|
||||
**
|
||||
** Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
** of this software and associated documentation files (the "Software"), to deal
|
||||
** in the Software without restriction, including without limitation the rights
|
||||
** to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
** copies of the Software, and to permit persons to whom the Software is
|
||||
** furnished to do so, subject to the following conditions:
|
||||
**
|
||||
** The above copyright notice and this permission notice shall be included in
|
||||
** all copies or substantial portions of the Software.
|
||||
**
|
||||
** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
** OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
** THE SOFTWARE.
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef _BSD_SOURCE
|
||||
#define _BSD_SOURCE 1
|
||||
#endif
|
||||
#ifndef _DEFAULT_SOURCE
|
||||
#define _DEFAULT_SOURCE 1
|
||||
#endif
|
||||
#ifndef __STDC_LIMIT_MACROS
|
||||
# define __STDC_LIMIT_MACROS 1
|
||||
#endif
|
||||
#define __STDC_WANT_IEC_60559_TYPES_EXT__
|
||||
|
||||
#include "cbor.h"
|
||||
#include "compilersupport_p.h"
|
||||
|
||||
#if defined(CBOR_CUSTOM_ALLOC_INCLUDE)
|
||||
# include CBOR_CUSTOM_ALLOC_INCLUDE
|
||||
#else
|
||||
# include <stdlib.h>
|
||||
# define cbor_malloc malloc
|
||||
# define cbor_free free
|
||||
#endif
|
||||
|
||||
/**
|
||||
* \fn CborError cbor_value_dup_text_string(const CborValue *value, char **buffer, size_t *buflen, CborValue *next)
|
||||
*
|
||||
* Allocates memory for the string pointed by \a value and copies it into this
|
||||
* buffer. The pointer to the buffer is stored in \a buffer and the number of
|
||||
* bytes copied is stored in \a buflen (those variables must not be NULL).
|
||||
*
|
||||
* If the iterator \a value does not point to a text string, the behaviour is
|
||||
* undefined, so checking with \ref cbor_value_get_type or \ref
|
||||
* cbor_value_is_text_string is recommended.
|
||||
*
|
||||
* If \c malloc returns a NULL pointer, this function will return error
|
||||
* condition \ref CborErrorOutOfMemory.
|
||||
*
|
||||
* On success, \c{*buffer} will contain a valid pointer that must be freed by
|
||||
* calling \c{free()}. This is the case even for zero-length strings.
|
||||
*
|
||||
* The \a next pointer, if not null, will be updated to point to the next item
|
||||
* after this string. If \a value points to the last item, then \a next will be
|
||||
* invalid.
|
||||
*
|
||||
* This function may not run in constant time (it will run in O(n) time on the
|
||||
* number of chunks). It requires constant memory (O(1)) in addition to the
|
||||
* malloc'ed block.
|
||||
*
|
||||
* \note This function does not perform UTF-8 validation on the incoming text
|
||||
* string.
|
||||
*
|
||||
* \sa cbor_value_get_text_string_chunk(), cbor_value_copy_text_string(), cbor_value_dup_byte_string()
|
||||
*/
|
||||
|
||||
/**
|
||||
* \fn CborError cbor_value_dup_byte_string(const CborValue *value, uint8_t **buffer, size_t *buflen, CborValue *next)
|
||||
*
|
||||
* Allocates memory for the string pointed by \a value and copies it into this
|
||||
* buffer. The pointer to the buffer is stored in \a buffer and the number of
|
||||
* bytes copied is stored in \a buflen (those variables must not be NULL).
|
||||
*
|
||||
* If the iterator \a value does not point to a byte string, the behaviour is
|
||||
* undefined, so checking with \ref cbor_value_get_type or \ref
|
||||
* cbor_value_is_byte_string is recommended.
|
||||
*
|
||||
* If \c malloc returns a NULL pointer, this function will return error
|
||||
* condition \ref CborErrorOutOfMemory.
|
||||
*
|
||||
* On success, \c{*buffer} will contain a valid pointer that must be freed by
|
||||
* calling \c{free()}. This is the case even for zero-length strings.
|
||||
*
|
||||
* The \a next pointer, if not null, will be updated to point to the next item
|
||||
* after this string. If \a value points to the last item, then \a next will be
|
||||
* invalid.
|
||||
*
|
||||
* This function may not run in constant time (it will run in O(n) time on the
|
||||
* number of chunks). It requires constant memory (O(1)) in addition to the
|
||||
* malloc'ed block.
|
||||
*
|
||||
* \sa cbor_value_get_text_string_chunk(), cbor_value_copy_byte_string(), cbor_value_dup_text_string()
|
||||
*/
|
||||
CborError _cbor_value_dup_string(const CborValue *value, void **buffer, size_t *buflen, CborValue *next)
|
||||
{
|
||||
CborError err;
|
||||
cbor_assert(buffer);
|
||||
cbor_assert(buflen);
|
||||
*buflen = SIZE_MAX;
|
||||
err = _cbor_value_copy_string(value, NULL, buflen, NULL);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
++*buflen;
|
||||
*buffer = cbor_malloc(*buflen);
|
||||
if (!*buffer) {
|
||||
/* out of memory */
|
||||
return CborErrorOutOfMemory;
|
||||
}
|
||||
err = _cbor_value_copy_string(value, *buffer, buflen, next);
|
||||
if (err) {
|
||||
cbor_free(*buffer);
|
||||
return err;
|
||||
}
|
||||
return CborNoError;
|
||||
}
|
||||
55
frame_serialize/tinycbor/cborparser_float.c
Normal file
55
frame_serialize/tinycbor/cborparser_float.c
Normal file
@@ -0,0 +1,55 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2019 S.Phirsov
|
||||
**
|
||||
** Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
** of this software and associated documentation files (the "Software"), to deal
|
||||
** in the Software without restriction, including without limitation the rights
|
||||
** to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
** copies of the Software, and to permit persons to whom the Software is
|
||||
** furnished to do so, subject to the following conditions:
|
||||
**
|
||||
** The above copyright notice and this permission notice shall be included in
|
||||
** all copies or substantial portions of the Software.
|
||||
**
|
||||
** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
** OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
** THE SOFTWARE.
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#define _BSD_SOURCE 1
|
||||
#define _DEFAULT_SOURCE 1
|
||||
#ifndef __STDC_LIMIT_MACROS
|
||||
# define __STDC_LIMIT_MACROS 1
|
||||
#endif
|
||||
#define __STDC_WANT_IEC_60559_TYPES_EXT__
|
||||
|
||||
#include "cbor.h"
|
||||
|
||||
#include "cborinternal_p.h"
|
||||
|
||||
#ifndef CBOR_NO_HALF_FLOAT_TYPE
|
||||
/**
|
||||
* Retrieves the CBOR half-precision floating point (16-bit) value that \a
|
||||
* value points to, converts it to the float and store it in \a result.
|
||||
* If the iterator \a value does not point to a half-precision floating
|
||||
* point value, the behavior is undefined, so checking with \ref
|
||||
* cbor_value_get_type or with \ref cbor_value_is_half_float is recommended.
|
||||
* \sa cbor_value_get_type(), cbor_value_is_valid(), cbor_value_is_half_float(), cbor_value_get_half_float(), cbor_value_get_float()
|
||||
*/
|
||||
CborError cbor_value_get_half_float_as_float(const CborValue *value, float *result)
|
||||
{
|
||||
uint16_t v;
|
||||
CborError err = cbor_value_get_half_float(value, &v);
|
||||
cbor_assert(err == CborNoError);
|
||||
|
||||
*result = (float)decode_half((unsigned short)v);
|
||||
|
||||
return CborNoError;
|
||||
}
|
||||
#endif
|
||||
583
frame_serialize/tinycbor/cborpretty.c
Normal file
583
frame_serialize/tinycbor/cborpretty.c
Normal file
@@ -0,0 +1,583 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2021 Intel Corporation
|
||||
**
|
||||
** Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
** of this software and associated documentation files (the "Software"), to deal
|
||||
** in the Software without restriction, including without limitation the rights
|
||||
** to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
** copies of the Software, and to permit persons to whom the Software is
|
||||
** furnished to do so, subject to the following conditions:
|
||||
**
|
||||
** The above copyright notice and this permission notice shall be included in
|
||||
** all copies or substantial portions of the Software.
|
||||
**
|
||||
** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
** OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
** THE SOFTWARE.
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#define _BSD_SOURCE 1
|
||||
#define _DEFAULT_SOURCE 1
|
||||
#ifndef __STDC_LIMIT_MACROS
|
||||
# define __STDC_LIMIT_MACROS 1
|
||||
#endif
|
||||
#define __STDC_WANT_IEC_60559_TYPES_EXT__
|
||||
|
||||
#include "cbor.h"
|
||||
#include "cborinternal_p.h"
|
||||
#include "compilersupport_p.h"
|
||||
#include "utf8_p.h"
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <string.h>
|
||||
|
||||
/**
|
||||
* \defgroup CborPretty Converting CBOR to text
|
||||
* \brief Group of functions used to convert CBOR to text form.
|
||||
*
|
||||
* This group contains two functions that can be used to convert a \ref
|
||||
* CborValue object to a text representation. This module attempts to follow
|
||||
* the recommendations from RFC 7049 section 6 "Diagnostic Notation", though it
|
||||
* has a few differences. They are noted below.
|
||||
*
|
||||
* TinyCBOR does not provide a way to convert from the text representation back
|
||||
* to encoded form. To produce a text form meant to be parsed, CborToJson is
|
||||
* recommended instead.
|
||||
*
|
||||
* Either of the functions in this section will attempt to convert exactly one
|
||||
* CborValue object to text. Those functions may return any error documented
|
||||
* for the functions for CborParsing. In addition, if the C standard library
|
||||
* stream functions return with error, the text conversion will return with
|
||||
* error CborErrorIO.
|
||||
*
|
||||
* These functions also perform UTF-8 validation in CBOR text strings. If they
|
||||
* encounter a sequence of bytes that is not permitted in UTF-8, they will return
|
||||
* CborErrorInvalidUtf8TextString. That includes encoding of surrogate points
|
||||
* in UTF-8.
|
||||
*
|
||||
* \warning The output type produced by these functions is not guaranteed to
|
||||
* remain stable. A future update of TinyCBOR may produce different output for
|
||||
* the same input and parsers may be unable to handle it.
|
||||
*
|
||||
* \sa CborParsing, CborToJson, cbor_parser_init()
|
||||
*/
|
||||
|
||||
/**
|
||||
* \addtogroup CborPretty
|
||||
* @{
|
||||
* <h2 class="groupheader">Text format</h2>
|
||||
*
|
||||
* As described in RFC 7049 section 6 "Diagnostic Notation", the format is
|
||||
* largely borrowed from JSON, but modified to suit CBOR's different data
|
||||
* types. TinyCBOR makes further modifications to distinguish different, but
|
||||
* similar values.
|
||||
*
|
||||
* CBOR values are currently encoded as follows:
|
||||
* \par Integrals (unsigned and negative)
|
||||
* Base-10 (decimal) text representation of the value
|
||||
* \par Byte strings:
|
||||
* <tt>"h'"</tt> followed by the Base16 (hex) representation of the binary data, followed by an ending quote (')
|
||||
* \par Text strings:
|
||||
* C-style escaped string in quotes, with C11/C++11 escaping of Unicode codepoints above U+007F.
|
||||
* \par Tags:
|
||||
* Tag value, with the tagged value in parentheses. No special encoding of the tagged value is performed.
|
||||
* \par Simple types:
|
||||
* <tt>"simple(nn)"</tt> where \c nn is the simple value
|
||||
* \par Null:
|
||||
* \c null
|
||||
* \par Undefined:
|
||||
* \c undefined
|
||||
* \par Booleans:
|
||||
* \c true or \c false
|
||||
* \par Floating point:
|
||||
* If NaN or infinite, the actual words \c NaN or \c infinite.
|
||||
* Otherwise, the decimal representation with as many digits as necessary to ensure no loss of information.
|
||||
* By default, float values are suffixed by "f" and half-float values suffixed by "f16" (doubles have no suffix).
|
||||
* If the CborPrettyNumericEncodingIndicators flag is active, the values instead are encoded following the
|
||||
* Section 6 recommended encoding indicators: float values are suffixed with "_2" and half-float with "_1".
|
||||
* A decimal point is always present.
|
||||
* \par Arrays:
|
||||
* Comma-separated list of elements, enclosed in square brackets ("[" and "]").
|
||||
* \par Maps:
|
||||
* Comma-separated list of key-value pairs, with the key and value separated
|
||||
* by a colon (":"), enclosed in curly braces ("{" and "}").
|
||||
*
|
||||
* The CborPrettyFlags enumerator contains flags to control some aspects of the
|
||||
* encoding:
|
||||
* \par String fragmentation
|
||||
* When the CborPrettyShowStringFragments option is active, text and byte
|
||||
* strings that are transmitted in fragments are shown instead inside
|
||||
* parentheses ("(" and ")") with no preceding number and each fragment is
|
||||
* displayed individually. If a tag precedes the string, then the output
|
||||
* will contain a double set of parentheses. If the option is not active,
|
||||
* the fragments are merged together and the display will not show any
|
||||
* difference from a string transmitted with determinate length.
|
||||
* \par Encoding indicators
|
||||
* Numbers and lengths in CBOR can be encoded in multiple representations.
|
||||
* If the CborPrettyIndicateOverlongNumbers option is active, numbers
|
||||
* and lengths that are transmitted in a longer encoding than necessary
|
||||
* will be indicated, by appending an underscore ("_") to either the
|
||||
* number or the opening bracket or brace, followed by a number
|
||||
* indicating the CBOR additional information: 0 for 1 byte, 1 for 2
|
||||
* bytes, 2 for 4 bytes and 3 for 8 bytes.
|
||||
* If the CborPrettyIndicateIndeterminateLength option is active, maps,
|
||||
* arrays and strings encoded with indeterminate length will be marked by
|
||||
* an underscore after the opening bracket or brace or the string (if not
|
||||
* showing fragments), without a number after it.
|
||||
*/
|
||||
|
||||
/**
|
||||
* \enum CborPrettyFlags
|
||||
* The CborPrettyFlags enum contains flags that control the conversion of CBOR to text format.
|
||||
*
|
||||
* \value CborPrettyNumericEncodingIndicators Use numeric encoding indicators instead of textual for float and half-float.
|
||||
* \value CborPrettyTextualEncodingIndicators Use textual encoding indicators for float ("f") and half-float ("f16").
|
||||
* \value CborPrettyIndicateIndeterminateLength (default) Indicate when a map or array has indeterminate length.
|
||||
* \value CborPrettyIndicateOverlongNumbers Indicate when a number or length was encoded with more bytes than needed.
|
||||
* \value CborPrettyShowStringFragments If the byte or text string is transmitted in chunks, show each individually.
|
||||
* \value CborPrettyMergeStringFragment Merge all chunked byte or text strings and display them in a single entry.
|
||||
* \value CborPrettyDefaultFlags Default conversion flags.
|
||||
*/
|
||||
|
||||
#ifndef CBOR_NO_FLOATING_POINT
|
||||
static inline bool convertToUint64(double v, uint64_t *absolute)
|
||||
{
|
||||
double supremum;
|
||||
v = fabs(v);
|
||||
|
||||
/* C11 standard section 6.3.1.4 "Real floating and integer" says:
|
||||
*
|
||||
* 1 When a finite value of real floating type is converted to an integer
|
||||
* type other than _Bool, the fractional part is discarded (i.e., the
|
||||
* value is truncated toward zero). If the value of the integral part
|
||||
* cannot be represented by the integer type, the behavior is undefined.
|
||||
*
|
||||
* So we must perform a range check that v <= UINT64_MAX, but we can't use
|
||||
* UINT64_MAX + 1.0 because the standard continues:
|
||||
*
|
||||
* 2 When a value of integer type is converted to a real floating type, if
|
||||
* the value being converted can be represented exactly in the new type,
|
||||
* it is unchanged. If the value being converted is in the range of
|
||||
* values that can be represented but cannot be represented exactly, the
|
||||
* result is either the nearest higher or nearest lower representable
|
||||
* value, chosen in an implementation-defined manner.
|
||||
*/
|
||||
supremum = -2.0 * INT64_MIN; /* -2 * (- 2^63) == 2^64 */
|
||||
if (v >= supremum)
|
||||
return false;
|
||||
|
||||
/* Now we can convert, these two conversions cannot be UB */
|
||||
*absolute = v;
|
||||
return *absolute == v;
|
||||
}
|
||||
#endif
|
||||
|
||||
static void printRecursionLimit(CborStreamFunction stream, void *out)
|
||||
{
|
||||
stream(out, "<nesting too deep, recursion stopped>");
|
||||
}
|
||||
|
||||
static CborError hexDump(CborStreamFunction stream, void *out, const void *ptr, size_t n)
|
||||
{
|
||||
const uint8_t *buffer = (const uint8_t *)ptr;
|
||||
CborError err = CborNoError;
|
||||
while (n-- && !err)
|
||||
err = stream(out, "%02" PRIx8, *buffer++);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
/* This function decodes buffer as UTF-8 and prints as escaped UTF-16.
|
||||
* On UTF-8 decoding error, it returns CborErrorInvalidUtf8TextString */
|
||||
static CborError utf8EscapedDump(CborStreamFunction stream, void *out, const void *ptr, size_t n)
|
||||
{
|
||||
const uint8_t *buffer = (const uint8_t *)ptr;
|
||||
const uint8_t * const end = buffer + n;
|
||||
CborError err = CborNoError;
|
||||
|
||||
while (buffer < end && !err) {
|
||||
uint32_t uc = get_utf8(&buffer, end);
|
||||
if (uc == ~0U)
|
||||
return CborErrorInvalidUtf8TextString;
|
||||
|
||||
if (uc < 0x80) {
|
||||
/* single-byte UTF-8 */
|
||||
unsigned char escaped = (unsigned char)uc;
|
||||
if (uc < 0x7f && uc >= 0x20 && uc != '\\' && uc != '"') {
|
||||
err = stream(out, "%c", (char)uc);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* print as an escape sequence */
|
||||
switch (uc) {
|
||||
case '"':
|
||||
case '\\':
|
||||
break;
|
||||
case '\b':
|
||||
escaped = 'b';
|
||||
break;
|
||||
case '\f':
|
||||
escaped = 'f';
|
||||
break;
|
||||
case '\n':
|
||||
escaped = 'n';
|
||||
break;
|
||||
case '\r':
|
||||
escaped = 'r';
|
||||
break;
|
||||
case '\t':
|
||||
escaped = 't';
|
||||
break;
|
||||
default:
|
||||
goto print_utf16;
|
||||
}
|
||||
err = stream(out, "\\%c", escaped);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* now print the sequence */
|
||||
if (uc > 0xffffU) {
|
||||
/* needs surrogate pairs */
|
||||
err = stream(out, "\\u%04" PRIX32 "\\u%04" PRIX32,
|
||||
(uc >> 10) + 0xd7c0, /* high surrogate */
|
||||
(uc % 0x0400) + 0xdc00);
|
||||
} else {
|
||||
print_utf16:
|
||||
/* no surrogate pair needed */
|
||||
err = stream(out, "\\u%04" PRIX32, uc);
|
||||
}
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
static const char *resolve_indicator(const CborValue *it, int flags)
|
||||
{
|
||||
static const char indicators[8][3] = {
|
||||
"_0", "_1", "_2", "_3",
|
||||
"", "", "", /* these are not possible */
|
||||
"_"
|
||||
};
|
||||
const char *no_indicator = indicators[5]; /* empty string */
|
||||
uint8_t additional_information;
|
||||
uint8_t expected_information;
|
||||
uint64_t value;
|
||||
CborError err;
|
||||
|
||||
if (!read_bytes(it, &additional_information, 0, 1))
|
||||
return NULL; /* CborErrorUnexpectedEOF */
|
||||
|
||||
additional_information &= SmallValueMask;
|
||||
if (additional_information < Value8Bit)
|
||||
return no_indicator;
|
||||
|
||||
/* determine whether to show anything */
|
||||
if ((flags & CborPrettyIndicateIndeterminateLength) &&
|
||||
additional_information == IndefiniteLength)
|
||||
return indicators[IndefiniteLength - Value8Bit];
|
||||
if ((flags & CborPrettyIndicateOverlongNumbers) == 0)
|
||||
return no_indicator;
|
||||
|
||||
err = extract_number_checked(it, &value, NULL);
|
||||
if (err)
|
||||
return NULL; /* CborErrorUnexpectedEOF */
|
||||
|
||||
expected_information = Value8Bit - 1;
|
||||
if (value >= Value8Bit)
|
||||
++expected_information;
|
||||
if (value > 0xffU)
|
||||
++expected_information;
|
||||
if (value > 0xffffU)
|
||||
++expected_information;
|
||||
if (value > 0xffffffffU)
|
||||
++expected_information;
|
||||
return expected_information == additional_information ?
|
||||
no_indicator :
|
||||
indicators[additional_information - Value8Bit];
|
||||
}
|
||||
|
||||
static const char *get_indicator(const CborValue *it, int flags)
|
||||
{
|
||||
return resolve_indicator(it, flags);
|
||||
}
|
||||
|
||||
static CborError value_to_pretty(CborStreamFunction stream, void *out, CborValue *it, int flags, int recursionsLeft);
|
||||
static CborError container_to_pretty(CborStreamFunction stream, void *out, CborValue *it, CborType containerType,
|
||||
int flags, int recursionsLeft)
|
||||
{
|
||||
const char *comma = "";
|
||||
CborError err = CborNoError;
|
||||
|
||||
if (!recursionsLeft) {
|
||||
printRecursionLimit(stream, out);
|
||||
while (!cbor_value_at_end(it) && !err) {
|
||||
err = cbor_value_advance(it);
|
||||
}
|
||||
return err; /* do allow the dumping to continue (if the advance was OK) */
|
||||
}
|
||||
|
||||
while (!cbor_value_at_end(it) && !err) {
|
||||
err = stream(out, "%s", comma);
|
||||
comma = ", ";
|
||||
|
||||
if (!err)
|
||||
err = value_to_pretty(stream, out, it, flags, recursionsLeft);
|
||||
|
||||
if (containerType == CborArrayType)
|
||||
continue;
|
||||
|
||||
/* map: that was the key, so get the value */
|
||||
if (!err)
|
||||
err = stream(out, ": ");
|
||||
if (!err)
|
||||
err = value_to_pretty(stream, out, it, flags, recursionsLeft);
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
static CborError value_to_pretty(CborStreamFunction stream, void *out, CborValue *it, int flags, int recursionsLeft)
|
||||
{
|
||||
CborError err = CborNoError;
|
||||
CborType type = cbor_value_get_type(it);
|
||||
switch (type) {
|
||||
case CborArrayType:
|
||||
case CborMapType: {
|
||||
/* recursive type */
|
||||
CborValue recursed;
|
||||
const char *indicator = get_indicator(it, flags);
|
||||
const char *space = *indicator ? " " : indicator;
|
||||
|
||||
err = stream(out, "%c%s%s", type == CborArrayType ? '[' : '{', indicator, space);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = cbor_value_enter_container(it, &recursed);
|
||||
if (err) {
|
||||
copy_current_position(it, &recursed);
|
||||
return err; /* parse error */
|
||||
}
|
||||
err = container_to_pretty(stream, out, &recursed, type, flags, recursionsLeft - 1);
|
||||
if (err) {
|
||||
copy_current_position(it, &recursed);
|
||||
return err; /* parse error */
|
||||
}
|
||||
err = cbor_value_leave_container(it, &recursed);
|
||||
if (err)
|
||||
return err; /* parse error */
|
||||
|
||||
return stream(out, type == CborArrayType ? "]" : "}");
|
||||
}
|
||||
|
||||
case CborIntegerType: {
|
||||
uint64_t val;
|
||||
cbor_value_get_raw_integer(it, &val); /* can't fail */
|
||||
|
||||
if (cbor_value_is_unsigned_integer(it)) {
|
||||
err = stream(out, "%" PRIu64, val);
|
||||
} else {
|
||||
/* CBOR stores the negative number X as -1 - X
|
||||
* (that is, -1 is stored as 0, -2 as 1 and so forth) */
|
||||
if (++val) { /* unsigned overflow may happen */
|
||||
err = stream(out, "-%" PRIu64, val);
|
||||
} else {
|
||||
/* overflown
|
||||
* 0xffff`ffff`ffff`ffff + 1 =
|
||||
* 0x1`0000`0000`0000`0000 = 18446744073709551616 (2^64) */
|
||||
err = stream(out, "-18446744073709551616");
|
||||
}
|
||||
}
|
||||
if (!err)
|
||||
err = stream(out, "%s", get_indicator(it, flags));
|
||||
break;
|
||||
}
|
||||
|
||||
case CborByteStringType:
|
||||
case CborTextStringType: {
|
||||
size_t n = 0;
|
||||
const void *ptr;
|
||||
bool showingFragments = (flags & CborPrettyShowStringFragments) && !cbor_value_is_length_known(it);
|
||||
const char *separator = "";
|
||||
char close = '\'';
|
||||
char open[3] = "h'";
|
||||
const char *indicator = NULL;
|
||||
|
||||
if (type == CborTextStringType) {
|
||||
close = open[0] = '"';
|
||||
open[1] = '\0';
|
||||
}
|
||||
|
||||
if (showingFragments)
|
||||
err = stream(out, "(_ ");
|
||||
else
|
||||
err = stream(out, "%s", open);
|
||||
|
||||
if (!err)
|
||||
err = cbor_value_begin_string_iteration(it);
|
||||
while (!err) {
|
||||
if (showingFragments || indicator == NULL) {
|
||||
/* any iteration, except the second for a non-chunked string */
|
||||
indicator = resolve_indicator(it, flags);
|
||||
}
|
||||
|
||||
err = _cbor_value_get_string_chunk(it, &ptr, &n, it);
|
||||
if (err == CborErrorNoMoreStringChunks) {
|
||||
err = cbor_value_finish_string_iteration(it);
|
||||
break;
|
||||
}
|
||||
|
||||
if (!err && showingFragments)
|
||||
err = stream(out, "%s%s", separator, open);
|
||||
if (!err)
|
||||
err = (type == CborByteStringType ?
|
||||
hexDump(stream, out, ptr, n) :
|
||||
utf8EscapedDump(stream, out, ptr, n));
|
||||
if (!err && showingFragments) {
|
||||
err = stream(out, "%c%s", close, indicator);
|
||||
separator = ", ";
|
||||
}
|
||||
}
|
||||
|
||||
if (!err) {
|
||||
if (showingFragments)
|
||||
err = stream(out, ")");
|
||||
else
|
||||
err = stream(out, "%c%s", close, indicator);
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
case CborTagType: {
|
||||
CborTag tag;
|
||||
cbor_value_get_tag(it, &tag); /* can't fail */
|
||||
err = stream(out, "%" PRIu64 "%s(", tag, get_indicator(it, flags));
|
||||
if (!err)
|
||||
err = cbor_value_advance_fixed(it);
|
||||
if (!err && recursionsLeft)
|
||||
err = value_to_pretty(stream, out, it, flags, recursionsLeft - 1);
|
||||
else if (!err)
|
||||
printRecursionLimit(stream, out);
|
||||
if (!err)
|
||||
err = stream(out, ")");
|
||||
return err;
|
||||
}
|
||||
|
||||
case CborSimpleType: {
|
||||
/* simple types can't fail and can't have overlong encoding */
|
||||
uint8_t simple_type;
|
||||
cbor_value_get_simple_type(it, &simple_type);
|
||||
err = stream(out, "simple(%" PRIu8 ")", simple_type);
|
||||
break;
|
||||
}
|
||||
|
||||
case CborNullType:
|
||||
err = stream(out, "null");
|
||||
break;
|
||||
|
||||
case CborUndefinedType:
|
||||
err = stream(out, "undefined");
|
||||
break;
|
||||
|
||||
case CborBooleanType: {
|
||||
bool val;
|
||||
cbor_value_get_boolean(it, &val); /* can't fail */
|
||||
err = stream(out, val ? "true" : "false");
|
||||
break;
|
||||
}
|
||||
|
||||
#ifndef CBOR_NO_FLOATING_POINT
|
||||
case CborDoubleType: {
|
||||
const char *suffix;
|
||||
double val;
|
||||
int r;
|
||||
uint64_t ival;
|
||||
|
||||
if (false) {
|
||||
float f;
|
||||
case CborFloatType:
|
||||
cbor_value_get_float(it, &f);
|
||||
val = f;
|
||||
suffix = flags & CborPrettyNumericEncodingIndicators ? "_2" : "f";
|
||||
} else if (false) {
|
||||
uint16_t f16;
|
||||
case CborHalfFloatType:
|
||||
#ifndef CBOR_NO_HALF_FLOAT_TYPE
|
||||
cbor_value_get_half_float(it, &f16);
|
||||
val = decode_half(f16);
|
||||
suffix = flags & CborPrettyNumericEncodingIndicators ? "_1" : "f16";
|
||||
#else
|
||||
(void)f16;
|
||||
err = CborErrorUnsupportedType;
|
||||
break;
|
||||
#endif
|
||||
} else {
|
||||
cbor_value_get_double(it, &val);
|
||||
suffix = "";
|
||||
}
|
||||
|
||||
if ((flags & CborPrettyNumericEncodingIndicators) == 0) {
|
||||
r = fpclassify(val);
|
||||
if (r == FP_NAN || r == FP_INFINITE)
|
||||
suffix = "";
|
||||
}
|
||||
|
||||
if (convertToUint64(val, &ival)) {
|
||||
/* this double value fits in a 64-bit integer, so show it as such
|
||||
* (followed by a floating point suffix, to disambiguate) */
|
||||
err = stream(out, "%s%" PRIu64 ".%s", val < 0 ? "-" : "", ival, suffix);
|
||||
} else {
|
||||
/* this number is definitely not a 64-bit integer */
|
||||
err = stream(out, "%." DBL_DECIMAL_DIG_STR "g%s", val, suffix);
|
||||
}
|
||||
break;
|
||||
}
|
||||
#else
|
||||
case CborDoubleType:
|
||||
case CborFloatType:
|
||||
case CborHalfFloatType:
|
||||
err = CborErrorUnsupportedType;
|
||||
break;
|
||||
#endif /* !CBOR_NO_FLOATING_POINT */
|
||||
|
||||
case CborInvalidType:
|
||||
err = stream(out, "invalid");
|
||||
if (err)
|
||||
return err;
|
||||
return CborErrorUnknownType;
|
||||
}
|
||||
|
||||
if (!err)
|
||||
err = cbor_value_advance_fixed(it);
|
||||
return err;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the current CBOR type pointed by \a value to its textual
|
||||
* representation and writes it to the stream by calling the \a streamFunction.
|
||||
* If an error occurs, this function returns an error code similar to
|
||||
* \ref CborParsing.
|
||||
*
|
||||
* The textual representation can be controlled by the \a flags parameter (see
|
||||
* \ref CborPrettyFlags for more information).
|
||||
*
|
||||
* If no error ocurred, this function advances \a value to the next element.
|
||||
* Often, concatenating the text representation of multiple elements can be
|
||||
* done by appending a comma to the output stream in between calls to this
|
||||
* function.
|
||||
*
|
||||
* The \a streamFunction function will be called with the \a token value as the
|
||||
* first parameter and a printf-style format string as the second, with a variable
|
||||
* number of further parameters.
|
||||
*
|
||||
* \sa cbor_value_to_pretty(), cbor_value_to_json_advance()
|
||||
*/
|
||||
CborError cbor_value_to_pretty_stream(CborStreamFunction streamFunction, void *token, CborValue *value, int flags)
|
||||
{
|
||||
return value_to_pretty(streamFunction, token, value, flags, CBOR_PARSER_MAX_RECURSIONS);
|
||||
}
|
||||
|
||||
/** @} */
|
||||
87
frame_serialize/tinycbor/cborpretty_stdio.c
Normal file
87
frame_serialize/tinycbor/cborpretty_stdio.c
Normal file
@@ -0,0 +1,87 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2017 Intel Corporation
|
||||
**
|
||||
** Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
** of this software and associated documentation files (the "Software"), to deal
|
||||
** in the Software without restriction, including without limitation the rights
|
||||
** to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
** copies of the Software, and to permit persons to whom the Software is
|
||||
** furnished to do so, subject to the following conditions:
|
||||
**
|
||||
** The above copyright notice and this permission notice shall be included in
|
||||
** all copies or substantial portions of the Software.
|
||||
**
|
||||
** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
** OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
** THE SOFTWARE.
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#include "cbor.h"
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
|
||||
static CborError cbor_fprintf(void *out, const char *fmt, ...)
|
||||
{
|
||||
int n;
|
||||
|
||||
va_list list;
|
||||
va_start(list, fmt);
|
||||
n = vfprintf((FILE *)out, fmt, list);
|
||||
va_end(list);
|
||||
|
||||
return n < 0 ? CborErrorIO : CborNoError;
|
||||
}
|
||||
|
||||
/**
|
||||
* \fn CborError cbor_value_to_pretty(FILE *out, const CborValue *value)
|
||||
*
|
||||
* Converts the current CBOR type pointed to by \a value to its textual
|
||||
* representation and writes it to the \a out stream. If an error occurs, this
|
||||
* function returns an error code similar to CborParsing.
|
||||
*
|
||||
* \sa cbor_value_to_pretty_advance(), cbor_value_to_json_advance()
|
||||
*/
|
||||
|
||||
/**
|
||||
* Converts the current CBOR type pointed to by \a value to its textual
|
||||
* representation and writes it to the \a out stream. If an error occurs, this
|
||||
* function returns an error code similar to CborParsing.
|
||||
*
|
||||
* If no error ocurred, this function advances \a value to the next element.
|
||||
* Often, concatenating the text representation of multiple elements can be
|
||||
* done by appending a comma to the output stream in between calls to this
|
||||
* function.
|
||||
*
|
||||
* \sa cbor_value_to_pretty(), cbor_value_to_pretty_stream(), cbor_value_to_json_advance()
|
||||
*/
|
||||
CborError cbor_value_to_pretty_advance(FILE *out, CborValue *value)
|
||||
{
|
||||
return cbor_value_to_pretty_stream(cbor_fprintf, out, value, CborPrettyDefaultFlags);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the current CBOR type pointed to by \a value to its textual
|
||||
* representation and writes it to the \a out stream. If an error occurs, this
|
||||
* function returns an error code similar to CborParsing.
|
||||
*
|
||||
* The textual representation can be controlled by the \a flags parameter (see
|
||||
* CborPrettyFlags for more information).
|
||||
*
|
||||
* If no error ocurred, this function advances \a value to the next element.
|
||||
* Often, concatenating the text representation of multiple elements can be
|
||||
* done by appending a comma to the output stream in between calls to this
|
||||
* function.
|
||||
*
|
||||
* \sa cbor_value_to_pretty_stream(), cbor_value_to_pretty(), cbor_value_to_json_advance()
|
||||
*/
|
||||
CborError cbor_value_to_pretty_advance_flags(FILE *out, CborValue *value, int flags)
|
||||
{
|
||||
return cbor_value_to_pretty_stream(cbor_fprintf, out, value, flags);
|
||||
}
|
||||
|
||||
709
frame_serialize/tinycbor/cbortojson.c
Normal file
709
frame_serialize/tinycbor/cbortojson.c
Normal file
@@ -0,0 +1,709 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2021 Intel Corporation
|
||||
**
|
||||
** Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
** of this software and associated documentation files (the "Software"), to deal
|
||||
** in the Software without restriction, including without limitation the rights
|
||||
** to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
** copies of the Software, and to permit persons to whom the Software is
|
||||
** furnished to do so, subject to the following conditions:
|
||||
**
|
||||
** The above copyright notice and this permission notice shall be included in
|
||||
** all copies or substantial portions of the Software.
|
||||
**
|
||||
** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
** OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
** THE SOFTWARE.
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#define _BSD_SOURCE 1
|
||||
#define _DEFAULT_SOURCE 1
|
||||
#define _GNU_SOURCE 1
|
||||
#ifndef __STDC_LIMIT_MACROS
|
||||
# define __STDC_LIMIT_MACROS 1
|
||||
#endif
|
||||
#define __STDC_WANT_IEC_60559_TYPES_EXT__
|
||||
|
||||
#include "cbor.h"
|
||||
#include "cborjson.h"
|
||||
#include "cborinternal_p.h"
|
||||
#include "compilersupport_p.h"
|
||||
#include "cborinternal_p.h"
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
/**
|
||||
* \defgroup CborToJson Converting CBOR to JSON
|
||||
* \brief Group of functions used to convert CBOR to JSON.
|
||||
*
|
||||
* This group contains two functions that can be used to convert a \ref
|
||||
* CborValue object to an equivalent JSON representation. This module attempts
|
||||
* to follow the recommendations from RFC 7049 section 4.1 "Converting from
|
||||
* CBOR to JSON", though it has a few differences. They are noted below.
|
||||
*
|
||||
* These functions produce a "minified" JSON output, with no spacing,
|
||||
* indentation or line breaks. If those are necessary, they need to be applied
|
||||
* in a post-processing phase.
|
||||
*
|
||||
* Note that JSON cannot support all CBOR types with fidelity, so the
|
||||
* conversion is usually lossy. For that reason, TinyCBOR supports adding a set
|
||||
* of metadata JSON values that can be used by a JSON-to-CBOR converter to
|
||||
* restore the original data types.
|
||||
*
|
||||
* The TinyCBOR library does not provide a way to convert from JSON
|
||||
* representation back to encoded form. However, it provides a tool called
|
||||
* \c json2cbor which can be used for that purpose. That tool supports the
|
||||
* metadata format that these functions may produce.
|
||||
*
|
||||
* Either of the functions in this section will attempt to convert exactly one
|
||||
* CborValue object to JSON. Those functions may return any error documented
|
||||
* for the functions for CborParsing. In addition, if the C standard library
|
||||
* stream functions return with error, the text conversion will return with
|
||||
* error CborErrorIO.
|
||||
*
|
||||
* These functions also perform UTF-8 validation in CBOR text strings. If they
|
||||
* encounter a sequence of bytes that is not permitted in UTF-8, they will return
|
||||
* CborErrorInvalidUtf8TextString. That includes encoding of surrogate points
|
||||
* in UTF-8.
|
||||
*
|
||||
* \warning The metadata produced by these functions is not guaranteed to
|
||||
* remain stable. A future update of TinyCBOR may produce different output for
|
||||
* the same input and parsers may be unable to handle it.
|
||||
*
|
||||
* \sa CborParsing, CborPretty, cbor_parser_init()
|
||||
*/
|
||||
|
||||
/**
|
||||
* \addtogroup CborToJson
|
||||
* @{
|
||||
* <h2 class="groupheader">Conversion limitations</h2>
|
||||
*
|
||||
* When converting from CBOR to JSON, there may be information loss. This
|
||||
* section lists the possible scenarios.
|
||||
*
|
||||
* \par Number precision:
|
||||
* ALL JSON numbers, due to its JavaScript heritage, are IEEE 754
|
||||
* double-precision floating point. This means JSON is not capable of
|
||||
* representing all integers numbers outside the range [-(2<sup>53</sup>)+1,
|
||||
* 2<sup>53</sup>-1] and is not capable of representing NaN or infinite. If the
|
||||
* CBOR data contains a number outside the valid range, the conversion will
|
||||
* lose precision. If the input was NaN or infinite, the result of the
|
||||
* conversion will be the JSON null value. In addition, the distinction between
|
||||
* half-, single- and double-precision is lost.
|
||||
*
|
||||
* \par
|
||||
* If enabled, the original value and original type are stored in the metadata.
|
||||
*
|
||||
* \par Non-native types:
|
||||
* CBOR's type system is richer than JSON's, which means some data values
|
||||
* cannot be represented when converted to JSON. The conversion silently turns
|
||||
* them into strings: CBOR simple types become "simple(nn)" where \c nn is the
|
||||
* simple type's value, with the exception of CBOR undefined, which becomes
|
||||
* "undefined", while CBOR byte strings are converted to an Base16, Base64, or
|
||||
* Base64url encoding
|
||||
*
|
||||
* \par
|
||||
* If enabled, the original type is stored in the metadata.
|
||||
*
|
||||
* \par Presence of tags:
|
||||
* JSON has no support for tagged values, so by default tags are dropped when
|
||||
* converting to JSON. However, if the CborConvertObeyByteStringTags option is
|
||||
* active (default), then certain known tags are honored and are used to format
|
||||
* the conversion of the tagged byte string to JSON.
|
||||
*
|
||||
* \par
|
||||
* If the CborConvertTagsToObjects option is active, then the tag and the
|
||||
* tagged value are converted to a JSON object. Otherwise, if enabled, the
|
||||
* last (innermost) tag is stored in the metadata.
|
||||
*
|
||||
* \par Non-string keys in maps:
|
||||
* JSON requires all Object keys to be strings, while CBOR does not. By
|
||||
* default, if a non-string key is found, the conversion fails with error
|
||||
* CborErrorJsonObjectKeyNotString. If the CborConvertStringifyMapKeys option
|
||||
* is active, then the conversion attempts to create a string representation
|
||||
* using CborPretty. Note that the \c json2cbor tool is not able to parse this
|
||||
* back to the original form.
|
||||
*
|
||||
* \par Duplicate keys in maps:
|
||||
* Neither JSON nor CBOR allow duplicated keys, but current TinyCBOR does not
|
||||
* validate that this is the case. If there are duplicated keys in the input,
|
||||
* they will be repeated in the output, which many JSON tools may flag as
|
||||
* invalid. In addition to that, if the CborConvertStringifyMapKeys option is
|
||||
* active, it is possible that a non-string key in a CBOR map will be converted
|
||||
* to a string form that is identical to another key.
|
||||
*
|
||||
* \par
|
||||
* When metadata support is active, the conversion will add extra key-value
|
||||
* pairs to the JSON output so it can store the metadata. It is possible that
|
||||
* the keys for the metadata clash with existing keys in the JSON map.
|
||||
*/
|
||||
|
||||
extern FILE *open_memstream(char **bufptr, size_t *sizeptr);
|
||||
|
||||
enum ConversionStatusFlags {
|
||||
TypeWasNotNative = 0x100, /* anything but strings, boolean, null, arrays and maps */
|
||||
TypeWasTagged = 0x200,
|
||||
NumberPrecisionWasLost = 0x400,
|
||||
NumberWasNaN = 0x800,
|
||||
NumberWasInfinite = 0x1000,
|
||||
NumberWasNegative = 0x2000, /* only used with NumberWasInifite or NumberWasTooBig */
|
||||
|
||||
FinalTypeMask = 0xff
|
||||
};
|
||||
|
||||
typedef struct ConversionStatus {
|
||||
CborTag lastTag;
|
||||
uint64_t originalNumber;
|
||||
int flags;
|
||||
} ConversionStatus;
|
||||
|
||||
static CborError value_to_json(FILE *out, CborValue *it, int flags, CborType type, ConversionStatus *status);
|
||||
|
||||
static CborError dump_bytestring_base16(char **result, CborValue *it)
|
||||
{
|
||||
static const char characters[] = "0123456789abcdef";
|
||||
size_t i;
|
||||
size_t n = 0;
|
||||
uint8_t *buffer;
|
||||
CborError err = cbor_value_calculate_string_length(it, &n);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/* a Base16 (hex) output is twice as big as our buffer */
|
||||
buffer = (uint8_t *)malloc(n * 2 + 1);
|
||||
if (buffer == NULL)
|
||||
/* out of memory */
|
||||
return CborErrorOutOfMemory;
|
||||
|
||||
*result = (char *)buffer;
|
||||
|
||||
/* let cbor_value_copy_byte_string know we have an extra byte for the terminating NUL */
|
||||
++n;
|
||||
err = cbor_value_copy_byte_string(it, buffer + n - 1, &n, it);
|
||||
cbor_assert(err == CborNoError);
|
||||
|
||||
for (i = 0; i < n; ++i) {
|
||||
uint8_t byte = buffer[n + i];
|
||||
buffer[2*i] = characters[byte >> 4];
|
||||
buffer[2*i + 1] = characters[byte & 0xf];
|
||||
}
|
||||
return CborNoError;
|
||||
}
|
||||
|
||||
static CborError generic_dump_base64(char **result, CborValue *it, const char alphabet[65])
|
||||
{
|
||||
size_t n = 0, i;
|
||||
uint8_t *buffer, *out, *in;
|
||||
CborError err = cbor_value_calculate_string_length(it, &n);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/* a Base64 output (untruncated) has 4 bytes for every 3 in the input */
|
||||
size_t len = (n + 5) / 3 * 4;
|
||||
buffer = (uint8_t *)malloc(len + 1);
|
||||
if (buffer == NULL)
|
||||
/* out of memory */
|
||||
return CborErrorOutOfMemory;
|
||||
|
||||
out = buffer;
|
||||
*result = (char *)buffer;
|
||||
|
||||
/* we read our byte string at the tail end of the buffer
|
||||
* so we can do an in-place conversion while iterating forwards */
|
||||
in = buffer + len - n;
|
||||
|
||||
/* let cbor_value_copy_byte_string know we have an extra byte for the terminating NUL */
|
||||
++n;
|
||||
err = cbor_value_copy_byte_string(it, in, &n, it);
|
||||
cbor_assert(err == CborNoError);
|
||||
|
||||
uint_least32_t val = 0;
|
||||
for (i = 0; n - i >= 3; i += 3) {
|
||||
/* read 3 bytes x 8 bits = 24 bits */
|
||||
if (false) {
|
||||
#ifdef __GNUC__
|
||||
} else if (i) {
|
||||
__builtin_memcpy(&val, in + i - 1, sizeof(val));
|
||||
val = cbor_ntohl(val);
|
||||
#endif
|
||||
} else {
|
||||
val = (in[i] << 16) | (in[i + 1] << 8) | in[i + 2];
|
||||
}
|
||||
|
||||
/* write 4 chars x 6 bits = 24 bits */
|
||||
*out++ = alphabet[(val >> 18) & 0x3f];
|
||||
*out++ = alphabet[(val >> 12) & 0x3f];
|
||||
*out++ = alphabet[(val >> 6) & 0x3f];
|
||||
*out++ = alphabet[val & 0x3f];
|
||||
}
|
||||
|
||||
/* maybe 1 or 2 bytes left */
|
||||
if (n - i) {
|
||||
/* we can read in[i + 1] even if it's past the end of the string because
|
||||
* we know (by construction) that it's a NUL byte */
|
||||
#ifdef __GNUC__
|
||||
uint16_t val16;
|
||||
__builtin_memcpy(&val16, in + i, sizeof(val16));
|
||||
val = cbor_ntohs(val16);
|
||||
#else
|
||||
val = (in[i] << 8) | in[i + 1];
|
||||
#endif
|
||||
val <<= 8;
|
||||
|
||||
/* the 65th character in the alphabet is our filler: either '=' or '\0' */
|
||||
out[4] = '\0';
|
||||
out[3] = alphabet[64];
|
||||
if (n - i == 2) {
|
||||
/* write the third char in 3 chars x 6 bits = 18 bits */
|
||||
out[2] = alphabet[(val >> 6) & 0x3f];
|
||||
} else {
|
||||
out[2] = alphabet[64]; /* filler */
|
||||
}
|
||||
out[1] = alphabet[(val >> 12) & 0x3f];
|
||||
out[0] = alphabet[(val >> 18) & 0x3f];
|
||||
} else {
|
||||
out[0] = '\0';
|
||||
}
|
||||
|
||||
return CborNoError;
|
||||
}
|
||||
|
||||
static CborError dump_bytestring_base64(char **result, CborValue *it)
|
||||
{
|
||||
static const char alphabet[] = "ABCDEFGH" "IJKLMNOP" "QRSTUVWX" "YZabcdef"
|
||||
"ghijklmn" "opqrstuv" "wxyz0123" "456789+/" "=";
|
||||
return generic_dump_base64(result, it, alphabet);
|
||||
}
|
||||
|
||||
static CborError dump_bytestring_base64url(char **result, CborValue *it)
|
||||
{
|
||||
static const char alphabet[] = "ABCDEFGH" "IJKLMNOP" "QRSTUVWX" "YZabcdef"
|
||||
"ghijklmn" "opqrstuv" "wxyz0123" "456789-_";
|
||||
return generic_dump_base64(result, it, alphabet);
|
||||
}
|
||||
|
||||
static CborError add_value_metadata(FILE *out, CborType type, const ConversionStatus *status)
|
||||
{
|
||||
int flags = status->flags;
|
||||
if (flags & TypeWasTagged) {
|
||||
/* extract the tagged type, which may be JSON native */
|
||||
type = flags & FinalTypeMask;
|
||||
flags &= ~(FinalTypeMask | TypeWasTagged);
|
||||
|
||||
if (fprintf(out, "\"tag\":\"%" PRIu64 "\"%s", status->lastTag,
|
||||
flags & ~TypeWasTagged ? "," : "") < 0)
|
||||
return CborErrorIO;
|
||||
}
|
||||
|
||||
if (!flags)
|
||||
return CborNoError;
|
||||
|
||||
/* print at least the type */
|
||||
if (fprintf(out, "\"t\":%d", type) < 0)
|
||||
return CborErrorIO;
|
||||
|
||||
if (flags & NumberWasNaN)
|
||||
if (fprintf(out, ",\"v\":\"nan\"") < 0)
|
||||
return CborErrorIO;
|
||||
if (flags & NumberWasInfinite)
|
||||
if (fprintf(out, ",\"v\":\"%sinf\"", flags & NumberWasNegative ? "-" : "") < 0)
|
||||
return CborErrorIO;
|
||||
if (flags & NumberPrecisionWasLost)
|
||||
if (fprintf(out, ",\"v\":\"%c%" PRIx64 "\"", flags & NumberWasNegative ? '-' : '+',
|
||||
status->originalNumber) < 0)
|
||||
return CborErrorIO;
|
||||
if (type == CborSimpleType)
|
||||
if (fprintf(out, ",\"v\":%d", (int)status->originalNumber) < 0)
|
||||
return CborErrorIO;
|
||||
return CborNoError;
|
||||
}
|
||||
|
||||
static CborError find_tagged_type(CborValue *it, CborTag *tag, CborType *type)
|
||||
{
|
||||
CborError err = CborNoError;
|
||||
*type = cbor_value_get_type(it);
|
||||
while (*type == CborTagType) {
|
||||
cbor_value_get_tag(it, tag); /* can't fail */
|
||||
err = cbor_value_advance_fixed(it);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
*type = cbor_value_get_type(it);
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
static CborError tagged_value_to_json(FILE *out, CborValue *it, int flags, ConversionStatus *status)
|
||||
{
|
||||
CborTag tag;
|
||||
CborError err;
|
||||
|
||||
if (flags & CborConvertTagsToObjects) {
|
||||
cbor_value_get_tag(it, &tag); /* can't fail */
|
||||
err = cbor_value_advance_fixed(it);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (fprintf(out, "{\"tag%" PRIu64 "\":", tag) < 0)
|
||||
return CborErrorIO;
|
||||
|
||||
CborType type = cbor_value_get_type(it);
|
||||
err = value_to_json(out, it, flags, type, status);
|
||||
if (err)
|
||||
return err;
|
||||
if (flags & CborConvertAddMetadata && status->flags) {
|
||||
if (fprintf(out, ",\"tag%" PRIu64 "$cbor\":{", tag) < 0 ||
|
||||
add_value_metadata(out, type, status) != CborNoError ||
|
||||
fputc('}', out) < 0)
|
||||
return CborErrorIO;
|
||||
}
|
||||
if (fputc('}', out) < 0)
|
||||
return CborErrorIO;
|
||||
status->flags = TypeWasNotNative | CborTagType;
|
||||
return CborNoError;
|
||||
}
|
||||
|
||||
CborType type;
|
||||
err = find_tagged_type(it, &status->lastTag, &type);
|
||||
if (err)
|
||||
return err;
|
||||
tag = status->lastTag;
|
||||
|
||||
/* special handling of byte strings? */
|
||||
if (type == CborByteStringType && (flags & CborConvertByteStringsToBase64Url) == 0 &&
|
||||
(tag == CborNegativeBignumTag || tag == CborExpectedBase16Tag || tag == CborExpectedBase64Tag)) {
|
||||
char *str;
|
||||
const char *pre = "";
|
||||
|
||||
if (tag == CborNegativeBignumTag) {
|
||||
pre = "~";
|
||||
err = dump_bytestring_base64url(&str, it);
|
||||
} else if (tag == CborExpectedBase64Tag) {
|
||||
err = dump_bytestring_base64(&str, it);
|
||||
} else { /* tag == CborExpectedBase16Tag */
|
||||
err = dump_bytestring_base16(&str, it);
|
||||
}
|
||||
if (err)
|
||||
return err;
|
||||
err = fprintf(out, "\"%s%s\"", pre, str) < 0 ? CborErrorIO : CborNoError;
|
||||
free(str);
|
||||
status->flags = TypeWasNotNative | TypeWasTagged | CborByteStringType;
|
||||
return err;
|
||||
}
|
||||
|
||||
/* no special handling */
|
||||
err = value_to_json(out, it, flags, type, status);
|
||||
status->flags |= TypeWasTagged | type;
|
||||
return err;
|
||||
}
|
||||
|
||||
static CborError stringify_map_key(char **key, CborValue *it, int flags, CborType type)
|
||||
{
|
||||
(void)flags; /* unused */
|
||||
(void)type; /* unused */
|
||||
#ifdef WITHOUT_OPEN_MEMSTREAM
|
||||
(void)key; /* unused */
|
||||
(void)it; /* unused */
|
||||
return CborErrorJsonNotImplemented;
|
||||
#else
|
||||
size_t size;
|
||||
|
||||
FILE *memstream = open_memstream(key, &size);
|
||||
if (memstream == NULL)
|
||||
return CborErrorOutOfMemory; /* could also be EMFILE, but it's unlikely */
|
||||
CborError err = cbor_value_to_pretty_advance(memstream, it);
|
||||
|
||||
if (unlikely(fclose(memstream) < 0 || *key == NULL))
|
||||
return CborErrorInternalError;
|
||||
return err;
|
||||
#endif
|
||||
}
|
||||
|
||||
static CborError array_to_json(FILE *out, CborValue *it, int flags, ConversionStatus *status)
|
||||
{
|
||||
const char *comma = "";
|
||||
while (!cbor_value_at_end(it)) {
|
||||
if (fprintf(out, "%s", comma) < 0)
|
||||
return CborErrorIO;
|
||||
comma = ",";
|
||||
|
||||
CborError err = value_to_json(out, it, flags, cbor_value_get_type(it), status);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
return CborNoError;
|
||||
}
|
||||
|
||||
static CborError map_to_json(FILE *out, CborValue *it, int flags, ConversionStatus *status)
|
||||
{
|
||||
const char *comma = "";
|
||||
CborError err;
|
||||
while (!cbor_value_at_end(it)) {
|
||||
char *key;
|
||||
if (fprintf(out, "%s", comma) < 0)
|
||||
return CborErrorIO;
|
||||
comma = ",";
|
||||
|
||||
CborType keyType = cbor_value_get_type(it);
|
||||
if (likely(keyType == CborTextStringType)) {
|
||||
size_t n = 0;
|
||||
err = cbor_value_dup_text_string(it, &key, &n, it);
|
||||
} else if (flags & CborConvertStringifyMapKeys) {
|
||||
err = stringify_map_key(&key, it, flags, keyType);
|
||||
} else {
|
||||
return CborErrorJsonObjectKeyNotString;
|
||||
}
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/* first, print the key */
|
||||
if (fprintf(out, "\"%s\":", key) < 0) {
|
||||
free(key);
|
||||
return CborErrorIO;
|
||||
}
|
||||
|
||||
/* then, print the value */
|
||||
CborType valueType = cbor_value_get_type(it);
|
||||
err = value_to_json(out, it, flags, valueType, status);
|
||||
|
||||
/* finally, print any metadata we may have */
|
||||
if (flags & CborConvertAddMetadata) {
|
||||
if (!err && keyType != CborTextStringType) {
|
||||
if (fprintf(out, ",\"%s$keycbordump\":true", key) < 0)
|
||||
err = CborErrorIO;
|
||||
}
|
||||
if (!err && status->flags) {
|
||||
if (fprintf(out, ",\"%s$cbor\":{", key) < 0 ||
|
||||
add_value_metadata(out, valueType, status) != CborNoError ||
|
||||
fputc('}', out) < 0)
|
||||
err = CborErrorIO;
|
||||
}
|
||||
}
|
||||
|
||||
free(key);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
return CborNoError;
|
||||
}
|
||||
|
||||
static CborError value_to_json(FILE *out, CborValue *it, int flags, CborType type, ConversionStatus *status)
|
||||
{
|
||||
CborError err;
|
||||
status->flags = 0;
|
||||
|
||||
switch (type) {
|
||||
case CborArrayType:
|
||||
case CborMapType: {
|
||||
/* recursive type */
|
||||
CborValue recursed;
|
||||
err = cbor_value_enter_container(it, &recursed);
|
||||
if (err) {
|
||||
copy_current_position(it, &recursed);
|
||||
return err; /* parse error */
|
||||
}
|
||||
if (fputc(type == CborArrayType ? '[' : '{', out) < 0)
|
||||
return CborErrorIO;
|
||||
|
||||
err = (type == CborArrayType) ?
|
||||
array_to_json(out, &recursed, flags, status) :
|
||||
map_to_json(out, &recursed, flags, status);
|
||||
if (err) {
|
||||
copy_current_position(it, &recursed);
|
||||
return err; /* parse error */
|
||||
}
|
||||
|
||||
if (fputc(type == CborArrayType ? ']' : '}', out) < 0)
|
||||
return CborErrorIO;
|
||||
err = cbor_value_leave_container(it, &recursed);
|
||||
if (err)
|
||||
return err; /* parse error */
|
||||
|
||||
status->flags = 0; /* reset, there are never conversion errors for us */
|
||||
return CborNoError;
|
||||
}
|
||||
|
||||
case CborIntegerType: {
|
||||
double num; /* JS numbers are IEEE double precision */
|
||||
uint64_t val;
|
||||
cbor_value_get_raw_integer(it, &val); /* can't fail */
|
||||
num = (double)val;
|
||||
|
||||
if (cbor_value_is_negative_integer(it)) {
|
||||
num = -num - 1; /* convert to negative */
|
||||
if ((uint64_t)(-num - 1) != val) {
|
||||
status->flags = NumberPrecisionWasLost | NumberWasNegative;
|
||||
status->originalNumber = val;
|
||||
}
|
||||
} else {
|
||||
if ((uint64_t)num != val) {
|
||||
status->flags = NumberPrecisionWasLost;
|
||||
status->originalNumber = val;
|
||||
}
|
||||
}
|
||||
if (fprintf(out, "%.0f", num) < 0) /* this number has no fraction, so no decimal points please */
|
||||
return CborErrorIO;
|
||||
break;
|
||||
}
|
||||
|
||||
case CborByteStringType:
|
||||
case CborTextStringType: {
|
||||
char *str;
|
||||
if (type == CborByteStringType) {
|
||||
err = dump_bytestring_base64url(&str, it);
|
||||
status->flags = TypeWasNotNative;
|
||||
} else {
|
||||
size_t n = 0;
|
||||
err = cbor_value_dup_text_string(it, &str, &n, it);
|
||||
}
|
||||
if (err)
|
||||
return err;
|
||||
err = (fprintf(out, "\"%s\"", str) < 0) ? CborErrorIO : CborNoError;
|
||||
free(str);
|
||||
return err;
|
||||
}
|
||||
|
||||
case CborTagType:
|
||||
return tagged_value_to_json(out, it, flags, status);
|
||||
|
||||
case CborSimpleType: {
|
||||
uint8_t simple_type;
|
||||
cbor_value_get_simple_type(it, &simple_type); /* can't fail */
|
||||
status->flags = TypeWasNotNative;
|
||||
status->originalNumber = simple_type;
|
||||
if (fprintf(out, "\"simple(%" PRIu8 ")\"", simple_type) < 0)
|
||||
return CborErrorIO;
|
||||
break;
|
||||
}
|
||||
|
||||
case CborNullType:
|
||||
if (fprintf(out, "null") < 0)
|
||||
return CborErrorIO;
|
||||
break;
|
||||
|
||||
case CborUndefinedType:
|
||||
status->flags = TypeWasNotNative;
|
||||
if (fprintf(out, "\"undefined\"") < 0)
|
||||
return CborErrorIO;
|
||||
break;
|
||||
|
||||
case CborBooleanType: {
|
||||
bool val;
|
||||
cbor_value_get_boolean(it, &val); /* can't fail */
|
||||
if (fprintf(out, val ? "true" : "false") < 0)
|
||||
return CborErrorIO;
|
||||
break;
|
||||
}
|
||||
|
||||
#ifndef CBOR_NO_FLOATING_POINT
|
||||
case CborDoubleType: {
|
||||
double val;
|
||||
if (false) {
|
||||
float f;
|
||||
case CborFloatType:
|
||||
status->flags = TypeWasNotNative;
|
||||
cbor_value_get_float(it, &f);
|
||||
val = f;
|
||||
} else if (false) {
|
||||
uint16_t f16;
|
||||
case CborHalfFloatType:
|
||||
# ifndef CBOR_NO_HALF_FLOAT_TYPE
|
||||
status->flags = TypeWasNotNative;
|
||||
cbor_value_get_half_float(it, &f16);
|
||||
val = decode_half(f16);
|
||||
# else
|
||||
(void)f16;
|
||||
err = CborErrorUnsupportedType;
|
||||
break;
|
||||
# endif
|
||||
} else {
|
||||
cbor_value_get_double(it, &val);
|
||||
}
|
||||
|
||||
int r = fpclassify(val);
|
||||
if (r == FP_NAN || r == FP_INFINITE) {
|
||||
if (fprintf(out, "null") < 0)
|
||||
return CborErrorIO;
|
||||
status->flags |= r == FP_NAN ? NumberWasNaN :
|
||||
NumberWasInfinite | (val < 0 ? NumberWasNegative : 0);
|
||||
} else {
|
||||
uint64_t ival = (uint64_t)fabs(val);
|
||||
if ((double)ival == fabs(val)) {
|
||||
/* print as integer so we get the full precision */
|
||||
r = fprintf(out, "%s%" PRIu64, val < 0 ? "-" : "", ival);
|
||||
status->flags |= TypeWasNotNative; /* mark this integer number as a double */
|
||||
} else {
|
||||
/* this number is definitely not a 64-bit integer */
|
||||
r = fprintf(out, "%." DBL_DECIMAL_DIG_STR "g", val);
|
||||
}
|
||||
if (r < 0)
|
||||
return CborErrorIO;
|
||||
}
|
||||
break;
|
||||
}
|
||||
#else
|
||||
case CborDoubleType:
|
||||
case CborFloatType:
|
||||
case CborHalfFloatType:
|
||||
err = CborErrorUnsupportedType;
|
||||
break;
|
||||
#endif /* !CBOR_NO_FLOATING_POINT */
|
||||
|
||||
case CborInvalidType:
|
||||
return CborErrorUnknownType;
|
||||
}
|
||||
|
||||
return cbor_value_advance_fixed(it);
|
||||
}
|
||||
|
||||
/**
|
||||
* \enum CborToJsonFlags
|
||||
* The CborToJsonFlags enum contains flags that control the conversion of CBOR to JSON.
|
||||
*
|
||||
* \value CborConvertAddMetadata Adds metadata to facilitate restoration of the original CBOR data.
|
||||
* \value CborConvertTagsToObjects Converts CBOR tags to JSON objects
|
||||
* \value CborConvertIgnoreTags (default) Ignore CBOR tags, except for byte strings
|
||||
* \value CborConvertObeyByteStringTags (default) Honor formatting of CBOR byte strings if so tagged
|
||||
* \value CborConvertByteStringsToBase64Url Force the conversion of all CBOR byte strings to Base64url encoding, despite any tags
|
||||
* \value CborConvertRequireMapStringKeys (default) Require CBOR map keys to be strings, failing the conversion if they are not
|
||||
* \value CborConvertStringifyMapKeys Convert non-string keys in CBOR maps to a string form
|
||||
* \value CborConvertDefaultFlags Default conversion flags.
|
||||
*/
|
||||
|
||||
/**
|
||||
* \fn CborError cbor_value_to_json(FILE *out, const CborValue *value, int flags)
|
||||
*
|
||||
* Converts the current CBOR type pointed to by \a value to JSON and writes that
|
||||
* to the \a out stream. If an error occurs, this function returns an error
|
||||
* code similar to CborParsing. The \a flags parameter indicates one or more of
|
||||
* the flags from CborToJsonFlags that control the conversion.
|
||||
*
|
||||
* \sa cbor_value_to_json_advance(), cbor_value_to_pretty()
|
||||
*/
|
||||
|
||||
/**
|
||||
* Converts the current CBOR type pointed to by \a value to JSON and writes that
|
||||
* to the \a out stream. If an error occurs, this function returns an error
|
||||
* code similar to CborParsing. The \a flags parameter indicates one or more of
|
||||
* the flags from CborToJsonFlags that control the conversion.
|
||||
*
|
||||
* If no error ocurred, this function advances \a value to the next element.
|
||||
*
|
||||
* \sa cbor_value_to_json(), cbor_value_to_pretty_advance()
|
||||
*/
|
||||
CborError cbor_value_to_json_advance(FILE *out, CborValue *value, int flags)
|
||||
{
|
||||
ConversionStatus status;
|
||||
return value_to_json(out, value, flags, cbor_value_get_type(value), &status);
|
||||
}
|
||||
|
||||
/** @} */
|
||||
658
frame_serialize/tinycbor/cborvalidation.c
Normal file
658
frame_serialize/tinycbor/cborvalidation.c
Normal file
@@ -0,0 +1,658 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2021 Intel Corporation
|
||||
**
|
||||
** Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
** of this software and associated documentation files (the "Software"), to deal
|
||||
** in the Software without restriction, including without limitation the rights
|
||||
** to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
** copies of the Software, and to permit persons to whom the Software is
|
||||
** furnished to do so, subject to the following conditions:
|
||||
**
|
||||
** The above copyright notice and this permission notice shall be included in
|
||||
** all copies or substantial portions of the Software.
|
||||
**
|
||||
** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
** OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
** THE SOFTWARE.
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#define _BSD_SOURCE 1
|
||||
#define _DEFAULT_SOURCE 1
|
||||
#ifndef __STDC_LIMIT_MACROS
|
||||
# define __STDC_LIMIT_MACROS 1
|
||||
#endif
|
||||
#define __STDC_WANT_IEC_60559_TYPES_EXT__
|
||||
|
||||
#include "cbor.h"
|
||||
#include "cborinternal_p.h"
|
||||
#include "compilersupport_p.h"
|
||||
#include "utf8_p.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#ifndef CBOR_NO_FLOATING_POINT
|
||||
# include <float.h>
|
||||
# include <math.h>
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef CBOR_PARSER_MAX_RECURSIONS
|
||||
# define CBOR_PARSER_MAX_RECURSIONS 1024
|
||||
#endif
|
||||
|
||||
/**
|
||||
* \addtogroup CborParsing
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* \enum CborValidationFlags
|
||||
* The CborValidationFlags enum contains flags that control the validation of a
|
||||
* CBOR stream.
|
||||
*
|
||||
* \value CborValidateBasic Validates only the syntactic correctedness of the stream.
|
||||
* \value CborValidateCanonical Validates that the stream is in canonical format, according to
|
||||
* RFC 7049 section 3.9.
|
||||
* \value CborValidateStrictMode Performs strict validation, according to RFC 7049 section 3.10.
|
||||
* \value CborValidateStrictest Attempt to perform the strictest validation we know of.
|
||||
*
|
||||
* \value CborValidateShortestIntegrals (Canonical) Validate that integral numbers and lengths are
|
||||
* enconded in their shortest form possible.
|
||||
* \value CborValidateShortestFloatingPoint (Canonical) Validate that floating-point numbers are encoded
|
||||
* in their shortest form possible.
|
||||
* \value CborValidateShortestNumbers (Canonical) Validate both integral and floating-point numbers
|
||||
* are in their shortest form possible.
|
||||
* \value CborValidateNoIndeterminateLength (Canonical) Validate that no string, array or map uses
|
||||
* indeterminate length encoding.
|
||||
* \value CborValidateMapIsSorted (Canonical & Strict mode) Validate that map keys appear in
|
||||
* sorted order.
|
||||
* \value CborValidateMapKeysAreUnique (Strict mode) Validate that map keys are unique.
|
||||
* \value CborValidateTagUse (Strict mode) Validate that known tags are used with the
|
||||
* correct types. This does not validate that the content of
|
||||
* those types is syntactically correct. For example, this
|
||||
* option validates that tag 1 (DateTimeString) is used with
|
||||
* a Text String, but it does not validate that the string is
|
||||
* a valid date/time representation.
|
||||
* \value CborValidateUtf8 (Strict mode) Validate that text strings are appropriately
|
||||
* encoded in UTF-8.
|
||||
* \value CborValidateMapKeysAreString Validate that all map keys are text strings.
|
||||
* \value CborValidateNoUndefined Validate that no elements of type "undefined" are present.
|
||||
* \value CborValidateNoTags Validate that no tags are used.
|
||||
* \value CborValidateFiniteFloatingPoint Validate that all floating point numbers are finite (no NaN or
|
||||
* infinities are allowed).
|
||||
* \value CborValidateCompleteData Validate that the stream is complete and there is no more data
|
||||
* in the buffer.
|
||||
* \value CborValidateNoUnknownSimpleTypesSA Validate that all Standards Action simple types are registered
|
||||
* with IANA.
|
||||
* \value CborValidateNoUnknownSimpleTypes Validate that all simple types used are registered with IANA.
|
||||
* \value CborValidateNoUnknownTagsSA Validate that all Standard Actions tags are registered with IANA.
|
||||
* \value CborValidateNoUnknownTagsSR Validate that all Standard Actions and Specification Required tags
|
||||
* are registered with IANA (see below for limitations).
|
||||
* \value CborValidateNoUnkonwnTags Validate that all tags are registered with IANA
|
||||
* (see below for limitations).
|
||||
*
|
||||
* \par Simple type registry
|
||||
* The CBOR specification requires that registration for use of the first 19
|
||||
* simple types must be done by way of Standards Action. The rest of the simple
|
||||
* types only require a specification. The official list can be obtained from
|
||||
* https://www.iana.org/assignments/cbor-simple-values/cbor-simple-values.xhtml.
|
||||
*
|
||||
* \par
|
||||
* There are no registered simple types recognized by this release of TinyCBOR
|
||||
* (beyond those defined by RFC 7049).
|
||||
*
|
||||
* \par Tag registry
|
||||
* The CBOR specification requires that registration for use of the first 23
|
||||
* tags must be done by way of Standards Action. The next up to tag 255 only
|
||||
* require a specification. Finally, all other tags can be registered on a
|
||||
* first-come-first-serve basis. The official list can be ontained from
|
||||
* https://www.iana.org/assignments/cbor-tags/cbor-tags.xhtml.
|
||||
*
|
||||
* \par
|
||||
* Given the variability of this list, TinyCBOR cannot recognize all tags
|
||||
* registered with IANA. Instead, the implementation only recognizes tags
|
||||
* that are backed by an RFC.
|
||||
*
|
||||
* \par
|
||||
* These are the tags known to the current TinyCBOR release:
|
||||
<table>
|
||||
<tr>
|
||||
<th>Tag</th>
|
||||
<th>Data Item</th>
|
||||
<th>Semantics</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>0</td>
|
||||
<td>UTF-8 text string</td>
|
||||
<td>Standard date/time string</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>1</td>
|
||||
<td>integer</td>
|
||||
<td>Epoch-based date/time</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>2</td>
|
||||
<td>byte string</td>
|
||||
<td>Positive bignum</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>3</td>
|
||||
<td>byte string</td>
|
||||
<td>Negative bignum</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>4</td>
|
||||
<td>array</td>
|
||||
<td>Decimal fraction</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>5</td>
|
||||
<td>array</td>
|
||||
<td>Bigfloat</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>16</td>
|
||||
<td>array</td>
|
||||
<td>COSE Single Recipient Encrypted Data Object (RFC 8152)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>17</td>
|
||||
<td>array</td>
|
||||
<td>COSE Mac w/o Recipients Object (RFC 8152)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>18</td>
|
||||
<td>array</td>
|
||||
<td>COSE Single Signer Data Object (RFC 8162)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>21</td>
|
||||
<td>byte string, array, map</td>
|
||||
<td>Expected conversion to base64url encoding</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>22</td>
|
||||
<td>byte string, array, map</td>
|
||||
<td>Expected conversion to base64 encoding</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>23</td>
|
||||
<td>byte string, array, map</td>
|
||||
<td>Expected conversion to base16 encoding</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>24</td>
|
||||
<td>byte string</td>
|
||||
<td>Encoded CBOR data item</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>32</td>
|
||||
<td>UTF-8 text string</td>
|
||||
<td>URI</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>33</td>
|
||||
<td>UTF-8 text string</td>
|
||||
<td>base64url</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>34</td>
|
||||
<td>UTF-8 text string</td>
|
||||
<td>base64</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>35</td>
|
||||
<td>UTF-8 text string</td>
|
||||
<td>Regular expression</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>36</td>
|
||||
<td>UTF-8 text string</td>
|
||||
<td>MIME message</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>96</td>
|
||||
<td>array</td>
|
||||
<td>COSE Encrypted Data Object (RFC 8152)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>97</td>
|
||||
<td>array</td>
|
||||
<td>COSE MACed Data Object (RFC 8152)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>98</td>
|
||||
<td>array</td>
|
||||
<td>COSE Signed Data Object (RFC 8152)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>55799</td>
|
||||
<td>any</td>
|
||||
<td>Self-describe CBOR</td>
|
||||
</tr>
|
||||
</table>
|
||||
*/
|
||||
|
||||
struct KnownTagData { uint32_t tag; uint32_t types; };
|
||||
static const struct KnownTagData knownTagData[] = {
|
||||
{ 0, (uint32_t)CborTextStringType },
|
||||
{ 1, (uint32_t)(CborIntegerType+1) },
|
||||
{ 2, (uint32_t)CborByteStringType },
|
||||
{ 3, (uint32_t)CborByteStringType },
|
||||
{ 4, (uint32_t)CborArrayType },
|
||||
{ 5, (uint32_t)CborArrayType },
|
||||
{ 16, (uint32_t)CborArrayType },
|
||||
{ 17, (uint32_t)CborArrayType },
|
||||
{ 18, (uint32_t)CborArrayType },
|
||||
{ 21, (uint32_t)CborByteStringType | ((uint32_t)CborArrayType << 8) | ((uint32_t)CborMapType << 16) },
|
||||
{ 22, (uint32_t)CborByteStringType | ((uint32_t)CborArrayType << 8) | ((uint32_t)CborMapType << 16) },
|
||||
{ 23, (uint32_t)CborByteStringType | ((uint32_t)CborArrayType << 8) | ((uint32_t)CborMapType << 16) },
|
||||
{ 24, (uint32_t)CborByteStringType },
|
||||
{ 32, (uint32_t)CborTextStringType },
|
||||
{ 33, (uint32_t)CborTextStringType },
|
||||
{ 34, (uint32_t)CborTextStringType },
|
||||
{ 35, (uint32_t)CborTextStringType },
|
||||
{ 36, (uint32_t)CborTextStringType },
|
||||
{ 96, (uint32_t)CborArrayType },
|
||||
{ 97, (uint32_t)CborArrayType },
|
||||
{ 98, (uint32_t)CborArrayType },
|
||||
{ 55799, 0U }
|
||||
};
|
||||
|
||||
static CborError validate_value(CborValue *it, uint32_t flags, int recursionLeft);
|
||||
|
||||
static inline CborError validate_utf8_string(const void *ptr, size_t n)
|
||||
{
|
||||
const uint8_t *buffer = (const uint8_t *)ptr;
|
||||
const uint8_t * const end = buffer + n;
|
||||
while (buffer < end) {
|
||||
uint32_t uc = get_utf8(&buffer, end);
|
||||
if (uc == ~0U)
|
||||
return CborErrorInvalidUtf8TextString;
|
||||
}
|
||||
return CborNoError;
|
||||
}
|
||||
|
||||
static inline CborError validate_simple_type(uint8_t simple_type, uint32_t flags)
|
||||
{
|
||||
/* At current time, all known simple types are those from RFC 7049,
|
||||
* which are parsed by the parser into different CBOR types.
|
||||
* That means that if we've got here, the type is unknown */
|
||||
if (simple_type < 32)
|
||||
return (flags & CborValidateNoUnknownSimpleTypesSA) ? CborErrorUnknownSimpleType : CborNoError;
|
||||
return (flags & CborValidateNoUnknownSimpleTypes) == CborValidateNoUnknownSimpleTypes ?
|
||||
CborErrorUnknownSimpleType : CborNoError;
|
||||
}
|
||||
|
||||
static inline CborError validate_number(const CborValue *it, CborType type, uint32_t flags)
|
||||
{
|
||||
CborError err = CborNoError;
|
||||
size_t bytesUsed, bytesNeeded;
|
||||
uint64_t value;
|
||||
|
||||
if ((flags & CborValidateShortestIntegrals) == 0)
|
||||
return err;
|
||||
if (type >= CborHalfFloatType && type <= CborDoubleType)
|
||||
return err; /* checked elsewhere */
|
||||
|
||||
err = extract_number_checked(it, &value, &bytesUsed);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
bytesNeeded = 0;
|
||||
if (value >= Value8Bit)
|
||||
++bytesNeeded;
|
||||
if (value > 0xffU)
|
||||
++bytesNeeded;
|
||||
if (value > 0xffffU)
|
||||
bytesNeeded += 2;
|
||||
if (value > 0xffffffffU)
|
||||
bytesNeeded += 4;
|
||||
if (bytesNeeded < bytesUsed)
|
||||
return CborErrorOverlongEncoding;
|
||||
return CborNoError;
|
||||
}
|
||||
|
||||
static inline CborError validate_tag(CborValue *it, CborTag tag, uint32_t flags, int recursionLeft)
|
||||
{
|
||||
CborType type = cbor_value_get_type(it);
|
||||
const size_t knownTagCount = sizeof(knownTagData) / sizeof(knownTagData[0]);
|
||||
const struct KnownTagData *tagData = knownTagData;
|
||||
const struct KnownTagData * const knownTagDataEnd = knownTagData + knownTagCount;
|
||||
|
||||
if (!recursionLeft)
|
||||
return CborErrorNestingTooDeep;
|
||||
if (flags & CborValidateNoTags)
|
||||
return CborErrorExcludedType;
|
||||
|
||||
/* find the tag data, if any */
|
||||
for ( ; tagData != knownTagDataEnd; ++tagData) {
|
||||
if (tagData->tag < tag)
|
||||
continue;
|
||||
if (tagData->tag > tag)
|
||||
tagData = NULL;
|
||||
break;
|
||||
}
|
||||
if (tagData == knownTagDataEnd)
|
||||
tagData = NULL;
|
||||
|
||||
if (flags & CborValidateNoUnknownTags && !tagData) {
|
||||
/* tag not found */
|
||||
if (flags & CborValidateNoUnknownTagsSA && tag < 24)
|
||||
return CborErrorUnknownTag;
|
||||
if ((flags & CborValidateNoUnknownTagsSR) == CborValidateNoUnknownTagsSR && tag < 256)
|
||||
return CborErrorUnknownTag;
|
||||
if ((flags & CborValidateNoUnknownTags) == CborValidateNoUnknownTags)
|
||||
return CborErrorUnknownTag;
|
||||
}
|
||||
|
||||
if (flags & CborValidateTagUse && tagData && tagData->types) {
|
||||
uint32_t allowedTypes = tagData->types;
|
||||
|
||||
/* correct Integer so it's not zero */
|
||||
if (type == CborIntegerType)
|
||||
type = (CborType)(type + 1);
|
||||
|
||||
while (allowedTypes) {
|
||||
if ((uint8_t)(allowedTypes & 0xff) == type)
|
||||
break;
|
||||
allowedTypes >>= 8;
|
||||
}
|
||||
if (!allowedTypes)
|
||||
return CborErrorInappropriateTagForType;
|
||||
}
|
||||
|
||||
return validate_value(it, flags, recursionLeft);
|
||||
}
|
||||
|
||||
#ifndef CBOR_NO_FLOATING_POINT
|
||||
static inline CborError validate_floating_point(CborValue *it, CborType type, uint32_t flags)
|
||||
{
|
||||
CborError err;
|
||||
int r;
|
||||
double val;
|
||||
float valf;
|
||||
uint16_t valf16 = 0x7c01; /* dummy value, an infinity */
|
||||
|
||||
if (type != CborDoubleType) {
|
||||
if (type == CborFloatType) {
|
||||
err = cbor_value_get_float(it, &valf);
|
||||
val = valf;
|
||||
} else {
|
||||
# ifdef CBOR_NO_HALF_FLOAT_TYPE
|
||||
(void)valf16;
|
||||
return CborErrorUnsupportedType;
|
||||
# else
|
||||
err = cbor_value_get_half_float(it, &valf16);
|
||||
val = decode_half(valf16);
|
||||
# endif
|
||||
}
|
||||
} else {
|
||||
err = cbor_value_get_double(it, &val);
|
||||
}
|
||||
cbor_assert(err == CborNoError); /* can't fail */
|
||||
|
||||
r = fpclassify(val);
|
||||
if (r == FP_NAN || r == FP_INFINITE) {
|
||||
if (flags & CborValidateFiniteFloatingPoint)
|
||||
return CborErrorExcludedValue;
|
||||
if (flags & CborValidateShortestFloatingPoint) {
|
||||
if (type == CborDoubleType)
|
||||
return CborErrorOverlongEncoding;
|
||||
# ifndef CBOR_NO_HALF_FLOAT_TYPE
|
||||
if (type == CborFloatType)
|
||||
return CborErrorOverlongEncoding;
|
||||
if (r == FP_NAN && valf16 != 0x7e00)
|
||||
return CborErrorImproperValue;
|
||||
if (r == FP_INFINITE && valf16 != 0x7c00 && valf16 != 0xfc00)
|
||||
return CborErrorImproperValue;
|
||||
# endif
|
||||
}
|
||||
}
|
||||
|
||||
if (flags & CborValidateShortestFloatingPoint && type > CborHalfFloatType) {
|
||||
if (type == CborDoubleType) {
|
||||
valf = (float)val;
|
||||
if ((double)valf == val)
|
||||
return CborErrorOverlongEncoding;
|
||||
}
|
||||
# ifndef CBOR_NO_HALF_FLOAT_TYPE
|
||||
if (type == CborFloatType) {
|
||||
valf16 = encode_half(valf);
|
||||
if (valf == decode_half(valf16))
|
||||
return CborErrorOverlongEncoding;
|
||||
}
|
||||
# endif
|
||||
}
|
||||
|
||||
return CborNoError;
|
||||
}
|
||||
#endif
|
||||
|
||||
static CborError validate_container(CborValue *it, int containerType, uint32_t flags, int recursionLeft)
|
||||
{
|
||||
CborError err;
|
||||
const uint8_t *previous = NULL;
|
||||
const uint8_t *previous_end = NULL;
|
||||
|
||||
if (!recursionLeft)
|
||||
return CborErrorNestingTooDeep;
|
||||
|
||||
while (!cbor_value_at_end(it)) {
|
||||
const uint8_t *current = cbor_value_get_next_byte(it);
|
||||
|
||||
if (containerType == CborMapType) {
|
||||
if (flags & CborValidateMapKeysAreString) {
|
||||
CborType type = cbor_value_get_type(it);
|
||||
if (type == CborTagType) {
|
||||
/* skip the tags */
|
||||
CborValue copy = *it;
|
||||
err = cbor_value_skip_tag(©);
|
||||
if (err)
|
||||
return err;
|
||||
type = cbor_value_get_type(©);
|
||||
}
|
||||
if (type != CborTextStringType)
|
||||
return CborErrorMapKeyNotString;
|
||||
}
|
||||
}
|
||||
|
||||
err = validate_value(it, flags, recursionLeft);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (containerType != CborMapType)
|
||||
continue;
|
||||
|
||||
if (flags & CborValidateMapIsSorted) {
|
||||
if (it->parser->flags & CborParserFlag_ExternalSource)
|
||||
return CborErrorUnimplementedValidation;
|
||||
if (previous) {
|
||||
size_t bytelen1 = (size_t)(previous_end - previous);
|
||||
size_t bytelen2 = (size_t)(cbor_value_get_next_byte(it) - current);
|
||||
int r = memcmp(previous, current, bytelen1 <= bytelen2 ? bytelen1 : bytelen2);
|
||||
|
||||
if (r == 0 && bytelen1 != bytelen2)
|
||||
r = bytelen1 < bytelen2 ? -1 : +1;
|
||||
if (r > 0)
|
||||
return CborErrorMapNotSorted;
|
||||
if (r == 0 && (flags & CborValidateMapKeysAreUnique) == CborValidateMapKeysAreUnique)
|
||||
return CborErrorMapKeysNotUnique;
|
||||
}
|
||||
|
||||
previous = current;
|
||||
previous_end = cbor_value_get_next_byte(it);
|
||||
}
|
||||
|
||||
/* map: that was the key, so get the value */
|
||||
err = validate_value(it, flags, recursionLeft);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
return CborNoError;
|
||||
}
|
||||
|
||||
static CborError validate_value(CborValue *it, uint32_t flags, int recursionLeft)
|
||||
{
|
||||
CborError err;
|
||||
CborType type = cbor_value_get_type(it);
|
||||
|
||||
if (cbor_value_is_length_known(it)) {
|
||||
err = validate_number(it, type, flags);
|
||||
if (err)
|
||||
return err;
|
||||
} else {
|
||||
if (flags & CborValidateNoIndeterminateLength)
|
||||
return CborErrorUnknownLength;
|
||||
}
|
||||
|
||||
switch (type) {
|
||||
case CborArrayType:
|
||||
case CborMapType: {
|
||||
/* recursive type */
|
||||
CborValue recursed;
|
||||
err = cbor_value_enter_container(it, &recursed);
|
||||
if (!err)
|
||||
err = validate_container(&recursed, type, flags, recursionLeft - 1);
|
||||
if (err) {
|
||||
copy_current_position(it, &recursed);
|
||||
return err;
|
||||
}
|
||||
err = cbor_value_leave_container(it, &recursed);
|
||||
if (err)
|
||||
return err;
|
||||
return CborNoError;
|
||||
}
|
||||
|
||||
case CborIntegerType: {
|
||||
uint64_t val;
|
||||
err = cbor_value_get_raw_integer(it, &val);
|
||||
cbor_assert(err == CborNoError); /* can't fail */
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case CborByteStringType:
|
||||
case CborTextStringType: {
|
||||
size_t n = 0;
|
||||
const void *ptr;
|
||||
|
||||
err = cbor_value_begin_string_iteration(it);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
while (1) {
|
||||
CborValue next;
|
||||
err = _cbor_value_get_string_chunk(it, &ptr, &n, &next);
|
||||
if (!err) {
|
||||
err = validate_number(it, type, flags);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
*it = next;
|
||||
if (err == CborErrorNoMoreStringChunks)
|
||||
return cbor_value_finish_string_iteration(it);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (type == CborTextStringType && flags & CborValidateUtf8) {
|
||||
err = validate_utf8_string(ptr, n);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
return CborNoError;
|
||||
}
|
||||
|
||||
case CborTagType: {
|
||||
CborTag tag;
|
||||
err = cbor_value_get_tag(it, &tag);
|
||||
cbor_assert(err == CborNoError); /* can't fail */
|
||||
|
||||
err = cbor_value_advance_fixed(it);
|
||||
if (err)
|
||||
return err;
|
||||
err = validate_tag(it, tag, flags, recursionLeft - 1);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
return CborNoError;
|
||||
}
|
||||
|
||||
case CborSimpleType: {
|
||||
uint8_t simple_type;
|
||||
err = cbor_value_get_simple_type(it, &simple_type);
|
||||
cbor_assert(err == CborNoError); /* can't fail */
|
||||
err = validate_simple_type(simple_type, flags);
|
||||
if (err)
|
||||
return err;
|
||||
break;
|
||||
}
|
||||
|
||||
case CborNullType:
|
||||
case CborBooleanType:
|
||||
break;
|
||||
|
||||
case CborUndefinedType:
|
||||
if (flags & CborValidateNoUndefined)
|
||||
return CborErrorExcludedType;
|
||||
break;
|
||||
|
||||
case CborHalfFloatType:
|
||||
case CborFloatType:
|
||||
case CborDoubleType: {
|
||||
#ifdef CBOR_NO_FLOATING_POINT
|
||||
return CborErrorUnsupportedType;
|
||||
#else
|
||||
err = validate_floating_point(it, type, flags);
|
||||
if (err)
|
||||
return err;
|
||||
break;
|
||||
#endif /* !CBOR_NO_FLOATING_POINT */
|
||||
}
|
||||
|
||||
case CborInvalidType:
|
||||
return CborErrorUnknownType;
|
||||
}
|
||||
|
||||
err = cbor_value_advance_fixed(it);
|
||||
return err;
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs a full validation, controlled by the \a flags options, of the CBOR
|
||||
* stream pointed by \a it and returns the error it found. If no error was
|
||||
* found, it returns CborNoError and the application can iterate over the items
|
||||
* with certainty that no errors will appear during parsing.
|
||||
*
|
||||
* If \a flags is CborValidateBasic, the result should be the same as
|
||||
* cbor_value_validate_basic().
|
||||
*
|
||||
* This function has the same timing and memory requirements as
|
||||
* cbor_value_advance() and cbor_value_validate_basic().
|
||||
*
|
||||
* \sa CborValidationFlags, cbor_value_validate_basic(), cbor_value_advance()
|
||||
*/
|
||||
CborError cbor_value_validate(const CborValue *it, uint32_t flags)
|
||||
{
|
||||
CborValue value = *it;
|
||||
CborError err = validate_value(&value, flags, CBOR_PARSER_MAX_RECURSIONS);
|
||||
if (err)
|
||||
return err;
|
||||
if (flags & CborValidateCompleteData && can_read_bytes(&value, 1))
|
||||
return CborErrorGarbageAtEnd;
|
||||
return CborNoError;
|
||||
}
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
221
frame_serialize/tinycbor/compilersupport_p.h
Normal file
221
frame_serialize/tinycbor/compilersupport_p.h
Normal file
@@ -0,0 +1,221 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2017 Intel Corporation
|
||||
**
|
||||
** Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
** of this software and associated documentation files (the "Software"), to deal
|
||||
** in the Software without restriction, including without limitation the rights
|
||||
** to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
** copies of the Software, and to permit persons to whom the Software is
|
||||
** furnished to do so, subject to the following conditions:
|
||||
**
|
||||
** The above copyright notice and this permission notice shall be included in
|
||||
** all copies or substantial portions of the Software.
|
||||
**
|
||||
** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
** OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
** THE SOFTWARE.
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef COMPILERSUPPORT_H
|
||||
#define COMPILERSUPPORT_H
|
||||
|
||||
#include "cbor.h"
|
||||
|
||||
#ifndef _BSD_SOURCE
|
||||
# define _BSD_SOURCE
|
||||
#endif
|
||||
#ifndef _DEFAULT_SOURCE
|
||||
# define _DEFAULT_SOURCE
|
||||
#endif
|
||||
#ifndef assert
|
||||
# include <assert.h>
|
||||
#endif
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifndef __cplusplus
|
||||
# include <stdbool.h>
|
||||
#endif
|
||||
|
||||
#if __STDC_VERSION__ >= 201112L || (defined(__cplusplus) && __cplusplus >= 201103L) || (defined(__cpp_static_assert) && __cpp_static_assert >= 200410)
|
||||
# define cbor_static_assert(x) static_assert(x, #x)
|
||||
#elif !defined(__cplusplus) && defined(__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__ >= 406) && (__STDC_VERSION__ > 199901L)
|
||||
# define cbor_static_assert(x) _Static_assert(x, #x)
|
||||
#else
|
||||
# define cbor_static_assert(x) ((void)sizeof(char[2*!!(x) - 1]))
|
||||
#endif
|
||||
#if __STDC_VERSION__ >= 199901L || defined(__cplusplus)
|
||||
/* inline is a keyword */
|
||||
#else
|
||||
/* use the definition from cbor.h */
|
||||
# define inline CBOR_INLINE
|
||||
#endif
|
||||
|
||||
#ifdef NDEBUG
|
||||
# define cbor_assert(cond) do { if (!(cond)) unreachable(); } while (0)
|
||||
#else
|
||||
# define cbor_assert(cond) assert(cond)
|
||||
#endif
|
||||
|
||||
#ifndef STRINGIFY
|
||||
#define STRINGIFY(x) STRINGIFY2(x)
|
||||
#endif
|
||||
#define STRINGIFY2(x) #x
|
||||
|
||||
#if !defined(UINT32_MAX) || !defined(INT64_MAX)
|
||||
/* C89? We can define UINT32_MAX portably, but not INT64_MAX */
|
||||
# error "Your system has stdint.h but that doesn't define UINT32_MAX or INT64_MAX"
|
||||
#endif
|
||||
|
||||
#ifndef DBL_DECIMAL_DIG
|
||||
/* DBL_DECIMAL_DIG is C11 */
|
||||
# define DBL_DECIMAL_DIG 17
|
||||
#endif
|
||||
#define DBL_DECIMAL_DIG_STR STRINGIFY(DBL_DECIMAL_DIG)
|
||||
|
||||
#if defined(__GNUC__) && defined(__i386__) && !defined(__iamcu__)
|
||||
# define CBOR_INTERNAL_API_CC __attribute__((regparm(3)))
|
||||
#elif defined(_MSC_VER) && defined(_M_IX86)
|
||||
# define CBOR_INTERNAL_API_CC __fastcall
|
||||
#else
|
||||
# define CBOR_INTERNAL_API_CC
|
||||
#endif
|
||||
|
||||
#ifndef __has_builtin
|
||||
# define __has_builtin(x) 0
|
||||
#endif
|
||||
|
||||
#if (defined(__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__ >= 403)) || \
|
||||
(__has_builtin(__builtin_bswap64) && __has_builtin(__builtin_bswap32))
|
||||
# if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
|
||||
# define cbor_ntohll __builtin_bswap64
|
||||
# define cbor_htonll __builtin_bswap64
|
||||
# define cbor_ntohl __builtin_bswap32
|
||||
# define cbor_htonl __builtin_bswap32
|
||||
# ifdef __INTEL_COMPILER
|
||||
# define cbor_ntohs _bswap16
|
||||
# define cbor_htons _bswap16
|
||||
# elif (__GNUC__ * 100 + __GNUC_MINOR__ >= 608) || __has_builtin(__builtin_bswap16)
|
||||
# define cbor_ntohs __builtin_bswap16
|
||||
# define cbor_htons __builtin_bswap16
|
||||
# else
|
||||
# define cbor_ntohs(x) (((uint16_t)(x) >> 8) | ((uint16_t)(x) << 8))
|
||||
# define cbor_htons cbor_ntohs
|
||||
# endif
|
||||
# else
|
||||
# define cbor_ntohll
|
||||
# define cbor_htonll
|
||||
# define cbor_ntohl
|
||||
# define cbor_htonl
|
||||
# define cbor_ntohs
|
||||
# define cbor_htons
|
||||
# endif
|
||||
#elif defined(__sun)
|
||||
# include <sys/byteorder.h>
|
||||
#elif defined(_MSC_VER)
|
||||
/* MSVC, which implies Windows, which implies little-endian and sizeof(long) == 4 */
|
||||
# include <stdlib.h>
|
||||
# define cbor_ntohll _byteswap_uint64
|
||||
# define cbor_htonll _byteswap_uint64
|
||||
# define cbor_ntohl _byteswap_ulong
|
||||
# define cbor_htonl _byteswap_ulong
|
||||
# define cbor_ntohs _byteswap_ushort
|
||||
# define cbor_htons _byteswap_ushort
|
||||
#elif defined(__ICCARM__)
|
||||
# if __LITTLE_ENDIAN__ == 1
|
||||
# include <intrinsics.h>
|
||||
# define ntohll(x) ((__REV((uint32_t)(x)) * UINT64_C(0x100000000)) + (__REV((x) >> 32)))
|
||||
# define htonll ntohll
|
||||
# define cbor_ntohl __REV
|
||||
# define cbor_htonl __REV
|
||||
# define cbor_ntohs __REVSH
|
||||
# define cbor_htons __REVSH
|
||||
# else
|
||||
# define cbor_ntohll
|
||||
# define cbor_htonll
|
||||
# define cbor_ntohl
|
||||
# define cbor_htonl
|
||||
# define cbor_ntohs
|
||||
# define cbor_htons
|
||||
# endif
|
||||
#endif
|
||||
#ifndef cbor_ntohs
|
||||
# include <arpa/inet.h>
|
||||
# define cbor_ntohs ntohs
|
||||
# define cbor_htons htons
|
||||
#endif
|
||||
#ifndef cbor_ntohl
|
||||
# include <arpa/inet.h>
|
||||
# define cbor_ntohl ntohl
|
||||
# define cbor_htonl htonl
|
||||
#endif
|
||||
#ifndef cbor_ntohll
|
||||
# define cbor_ntohll ntohll
|
||||
# define cbor_htonll htonll
|
||||
/* ntohll isn't usually defined */
|
||||
# ifndef ntohll
|
||||
# if (defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) || \
|
||||
(defined(__BYTE_ORDER) && defined(__BIG_ENDIAN) && __BYTE_ORDER == __BIG_ENDIAN) || \
|
||||
(defined(BYTE_ORDER) && defined(BIG_ENDIAN) && BYTE_ORDER == BIG_ENDIAN) || \
|
||||
(defined(_BIG_ENDIAN) && !defined(_LITTLE_ENDIAN)) || (defined(__BIG_ENDIAN__) && !defined(__LITTLE_ENDIAN__)) || \
|
||||
defined(__ARMEB__) || defined(__MIPSEB__) || defined(__s390__) || defined(__sparc__)
|
||||
# define ntohll
|
||||
# define htonll
|
||||
# elif (defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) || \
|
||||
(defined(__BYTE_ORDER) && defined(__LITTLE_ENDIAN) && __BYTE_ORDER == __LITTLE_ENDIAN) || \
|
||||
(defined(BYTE_ORDER) && defined(LITTLE_ENDIAN) && BYTE_ORDER == LITTLE_ENDIAN) || \
|
||||
defined(_LITTLE_ENDIAN) || defined(__LITTLE_ENDIAN__) || defined(__ARMEL__) || defined(__MIPSEL__) || \
|
||||
defined(__i386) || defined(__i386__) || defined(__x86_64) || defined(__x86_64__) || defined(__amd64)
|
||||
# define ntohll(x) ((cbor_ntohl((uint32_t)(x)) * UINT64_C(0x100000000)) + (cbor_ntohl((x) >> 32)))
|
||||
# define htonll ntohll
|
||||
# else
|
||||
# error "Unable to determine byte order!"
|
||||
# endif
|
||||
# endif
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
# define CONST_CAST(t, v) const_cast<t>(v)
|
||||
#else
|
||||
/* C-style const_cast without triggering a warning with -Wcast-qual */
|
||||
# define CONST_CAST(t, v) (t)(uintptr_t)(v)
|
||||
#endif
|
||||
|
||||
#ifdef __GNUC__
|
||||
#ifndef likely
|
||||
# define likely(x) __builtin_expect(!!(x), 1)
|
||||
#endif
|
||||
#ifndef unlikely
|
||||
# define unlikely(x) __builtin_expect(!!(x), 0)
|
||||
#endif
|
||||
# define unreachable() __builtin_unreachable()
|
||||
#elif defined(_MSC_VER)
|
||||
# define likely(x) (x)
|
||||
# define unlikely(x) (x)
|
||||
# define unreachable() __assume(0)
|
||||
#else
|
||||
# define likely(x) (x)
|
||||
# define unlikely(x) (x)
|
||||
# define unreachable() do {} while (0)
|
||||
#endif
|
||||
|
||||
static inline bool add_check_overflow(size_t v1, size_t v2, size_t *r)
|
||||
{
|
||||
#if ((defined(__GNUC__) && (__GNUC__ >= 5)) && !defined(__INTEL_COMPILER)) || __has_builtin(__builtin_add_overflow)
|
||||
return __builtin_add_overflow(v1, v2, r);
|
||||
#else
|
||||
/* unsigned additions are well-defined */
|
||||
*r = v1 + v2;
|
||||
return v1 > v1 + v2;
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif /* COMPILERSUPPORT_H */
|
||||
114
frame_serialize/tinycbor/open_memstream.c
Normal file
114
frame_serialize/tinycbor/open_memstream.c
Normal file
@@ -0,0 +1,114 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2015 Intel Corporation
|
||||
**
|
||||
** Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
** of this software and associated documentation files (the "Software"), to deal
|
||||
** in the Software without restriction, including without limitation the rights
|
||||
** to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
** copies of the Software, and to permit persons to whom the Software is
|
||||
** furnished to do so, subject to the following conditions:
|
||||
**
|
||||
** The above copyright notice and this permission notice shall be included in
|
||||
** all copies or substantial portions of the Software.
|
||||
**
|
||||
** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
** OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
** THE SOFTWARE.
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#define _BSD_SOURCE 1
|
||||
#define _DEFAULT_SOURCE 1
|
||||
#define _GNU_SOURCE 1
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#if defined(__unix__) || defined(__APPLE__)
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
#ifdef __APPLE__
|
||||
typedef int RetType;
|
||||
typedef int LenType;
|
||||
#elif __linux__
|
||||
typedef ssize_t RetType;
|
||||
typedef size_t LenType;
|
||||
#else
|
||||
# error "Cannot implement open_memstream!"
|
||||
#endif
|
||||
|
||||
#include "compilersupport_p.h"
|
||||
|
||||
struct Buffer
|
||||
{
|
||||
char **ptr;
|
||||
size_t *len;
|
||||
size_t alloc;
|
||||
};
|
||||
|
||||
static RetType write_to_buffer(void *cookie, const char *data, LenType len)
|
||||
{
|
||||
struct Buffer *b = (struct Buffer *)cookie;
|
||||
char *ptr = *b->ptr;
|
||||
size_t newsize;
|
||||
|
||||
errno = EFBIG;
|
||||
if (unlikely(add_check_overflow(*b->len, len, &newsize)))
|
||||
return -1;
|
||||
|
||||
if (newsize >= b->alloc) { // NB! one extra byte is needed to avoid buffer overflow at close_buffer
|
||||
// make room
|
||||
size_t newalloc = newsize + newsize / 2 + 1; // give 50% more room
|
||||
ptr = realloc(ptr, newalloc);
|
||||
if (ptr == NULL)
|
||||
return -1;
|
||||
b->alloc = newalloc;
|
||||
*b->ptr = ptr;
|
||||
}
|
||||
|
||||
memcpy(ptr + *b->len, data, len);
|
||||
*b->len = newsize;
|
||||
return len;
|
||||
}
|
||||
|
||||
static int close_buffer(void *cookie)
|
||||
{
|
||||
struct Buffer *b = (struct Buffer *)cookie;
|
||||
if (*b->ptr)
|
||||
(*b->ptr)[*b->len] = '\0';
|
||||
free(b);
|
||||
return 0;
|
||||
}
|
||||
|
||||
FILE *open_memstream(char **bufptr, size_t *lenptr)
|
||||
{
|
||||
struct Buffer *b = (struct Buffer *)malloc(sizeof(struct Buffer));
|
||||
if (b == NULL)
|
||||
return NULL;
|
||||
b->alloc = 0;
|
||||
b->len = lenptr;
|
||||
b->ptr = bufptr;
|
||||
*bufptr = NULL;
|
||||
*lenptr = 0;
|
||||
|
||||
#ifdef __APPLE__
|
||||
return funopen(b, NULL, write_to_buffer, NULL, close_buffer);
|
||||
#elif __linux__
|
||||
static const cookie_io_functions_t vtable = {
|
||||
NULL,
|
||||
write_to_buffer,
|
||||
NULL,
|
||||
close_buffer
|
||||
};
|
||||
return fopencookie(b, "w", vtable);
|
||||
#endif
|
||||
}
|
||||
|
||||
3
frame_serialize/tinycbor/tinycbor-version.h
Normal file
3
frame_serialize/tinycbor/tinycbor-version.h
Normal file
@@ -0,0 +1,3 @@
|
||||
#define TINYCBOR_VERSION_MAJOR 0
|
||||
#define TINYCBOR_VERSION_MINOR 6
|
||||
#define TINYCBOR_VERSION_PATCH 0
|
||||
104
frame_serialize/tinycbor/utf8_p.h
Normal file
104
frame_serialize/tinycbor/utf8_p.h
Normal file
@@ -0,0 +1,104 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2017 Intel Corporation
|
||||
**
|
||||
** Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
** of this software and associated documentation files (the "Software"), to deal
|
||||
** in the Software without restriction, including without limitation the rights
|
||||
** to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
** copies of the Software, and to permit persons to whom the Software is
|
||||
** furnished to do so, subject to the following conditions:
|
||||
**
|
||||
** The above copyright notice and this permission notice shall be included in
|
||||
** all copies or substantial portions of the Software.
|
||||
**
|
||||
** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
** OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
** THE SOFTWARE.
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef CBOR_UTF8_H
|
||||
#define CBOR_UTF8_H
|
||||
|
||||
#include "compilersupport_p.h"
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
static inline uint32_t get_utf8(const uint8_t **buffer, const uint8_t *end)
|
||||
{
|
||||
int charsNeeded;
|
||||
uint32_t uc, min_uc;
|
||||
uint8_t b;
|
||||
ptrdiff_t n = end - *buffer;
|
||||
if (n == 0)
|
||||
return ~0U;
|
||||
|
||||
uc = *(*buffer)++;
|
||||
if (uc < 0x80) {
|
||||
/* single-byte UTF-8 */
|
||||
return uc;
|
||||
}
|
||||
|
||||
/* multi-byte UTF-8, decode it */
|
||||
if (unlikely(uc <= 0xC1))
|
||||
return ~0U;
|
||||
if (uc < 0xE0) {
|
||||
/* two-byte UTF-8 */
|
||||
charsNeeded = 2;
|
||||
min_uc = 0x80;
|
||||
uc &= 0x1f;
|
||||
} else if (uc < 0xF0) {
|
||||
/* three-byte UTF-8 */
|
||||
charsNeeded = 3;
|
||||
min_uc = 0x800;
|
||||
uc &= 0x0f;
|
||||
} else if (uc < 0xF5) {
|
||||
/* four-byte UTF-8 */
|
||||
charsNeeded = 4;
|
||||
min_uc = 0x10000;
|
||||
uc &= 0x07;
|
||||
} else {
|
||||
return ~0U;
|
||||
}
|
||||
|
||||
if (n < charsNeeded)
|
||||
return ~0U;
|
||||
|
||||
/* first continuation character */
|
||||
b = *(*buffer)++;
|
||||
if ((b & 0xc0) != 0x80)
|
||||
return ~0U;
|
||||
uc <<= 6;
|
||||
uc |= b & 0x3f;
|
||||
|
||||
if (charsNeeded > 2) {
|
||||
/* second continuation character */
|
||||
b = *(*buffer)++;
|
||||
if ((b & 0xc0) != 0x80)
|
||||
return ~0U;
|
||||
uc <<= 6;
|
||||
uc |= b & 0x3f;
|
||||
|
||||
if (charsNeeded > 3) {
|
||||
/* third continuation character */
|
||||
b = *(*buffer)++;
|
||||
if ((b & 0xc0) != 0x80)
|
||||
return ~0U;
|
||||
uc <<= 6;
|
||||
uc |= b & 0x3f;
|
||||
}
|
||||
}
|
||||
|
||||
/* overlong sequence? surrogate pair? out or range? */
|
||||
if (uc < min_uc || uc - 0xd800U < 2048U || uc > 0x10ffff)
|
||||
return ~0U;
|
||||
|
||||
return uc;
|
||||
}
|
||||
|
||||
#endif /* CBOR_UTF8_H */
|
||||
2685
frontend_ui/package-lock.json
generated
2685
frontend_ui/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "jungfrau-frontend",
|
||||
"version": "0.1.0",
|
||||
"license": "GPL-3.0",
|
||||
"name": "jungfraujoch-frontend",
|
||||
"version": "1.0.0",
|
||||
"license": "Proprietary",
|
||||
"private": true,
|
||||
"homepage": "/frontend",
|
||||
"dependencies": {
|
||||
@@ -10,6 +10,7 @@
|
||||
"@mui/icons-material": "^5.10.6",
|
||||
"@mui/material": "^5.10.6",
|
||||
"@mui/x-data-grid": "^5.17.14",
|
||||
"@redocly/cli": "^1.12.2",
|
||||
"@types/jest": "^29.2.4",
|
||||
"@types/node": "^18.11.13",
|
||||
"@types/react": "^18.0.26",
|
||||
@@ -25,9 +26,10 @@
|
||||
"scripts": {
|
||||
"start": "REACT_APP_VERSION=$(git rev-parse --short HEAD) PORT=8000 react-scripts start",
|
||||
"build": "REACT_APP_VERSION=$(git rev-parse --short HEAD) react-scripts build",
|
||||
"redocly": "redocly build-docs ../broker/jfjoch_api.yaml --output=build/openapi.html",
|
||||
"test": "react-scripts test",
|
||||
"eject": "react-scripts eject",
|
||||
"openapi": "openapi --input ../broker/jfjoch_api.yaml --output ./src/openapi"
|
||||
"openapi": "./node_modules/openapi-typescript-codegen/bin/index.js -i ../broker/jfjoch_api.yaml --output ./src/openapi"
|
||||
},
|
||||
"eslintConfig": {
|
||||
"extends": "react-app"
|
||||
|
||||
@@ -145,7 +145,8 @@ class App extends Component<MyProps, MyState> {
|
||||
href="mailto:filip.leonarski@psi.ch">Filip Leonarski</a> <br/>
|
||||
For more information see <a href="https://doi.org/10.1107/S1600577522010268"><i>J. Synchrotron
|
||||
Rad.</i> (2023). <b>30</b>, 227–234</a> <br/>
|
||||
Build: {process.env.REACT_APP_VERSION}</center>
|
||||
Build: {process.env.REACT_APP_VERSION}
|
||||
<a href="/frontend/openapi.html">API reference</a></center>
|
||||
<br/>
|
||||
</ThemeProvider>
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ type MyProps = {};
|
||||
class BkgEstimatePlot extends Component<MyProps> {
|
||||
|
||||
render() {
|
||||
return <Paper style={{textAlign: 'center'}} sx={{height: 450, width: "100%"}}>
|
||||
return <Paper style={{textAlign: 'center'}} sx={{height: 500, width: "100%"}}>
|
||||
<Box sx={{width: "100%", height: 50}}>
|
||||
<br/>
|
||||
<center><strong>Background estimate</strong></center>
|
||||
|
||||
@@ -16,9 +16,7 @@ export enum PlotType {
|
||||
STRONG_PIXELS,
|
||||
ROI_SUM,
|
||||
ROI_MAX_COUNT,
|
||||
RES_ESTIMATION,
|
||||
RECEIVER_FREE_SEND_BUFS,
|
||||
BEAM_CENTER_DRIFT
|
||||
RECEIVER_FREE_SEND_BUFS
|
||||
}
|
||||
|
||||
type MyProps = {
|
||||
@@ -145,13 +143,6 @@ class DataProcessingPlot extends Component<MyProps, MyState> {
|
||||
this.setState({connection_error: true});
|
||||
});
|
||||
break;
|
||||
case PlotType.RES_ESTIMATION:
|
||||
DefaultService.getPlotResolutionEstimateHistogram()
|
||||
.then(data => this.setState({plots: data, connection_error: false}))
|
||||
.catch(error => {
|
||||
this.setState({connection_error: true});
|
||||
});
|
||||
break;
|
||||
case PlotType.RAD_INT_PER_FILE:
|
||||
DefaultService.getPlotRadIntPerFile()
|
||||
.then(data => this.setState({plots: data, connection_error: false}))
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user