init
This commit is contained in:
commit
e4ea13b053
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
/build/
|
3
.idea/.gitignore
generated
vendored
Normal file
3
.idea/.gitignore
generated
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
# Default ignored files
|
||||
/shelf/
|
||||
/workspace.xml
|
29
.idea/CppBuildDebug_CMakeAppBuildConfigurations.xml
generated
Normal file
29
.idea/CppBuildDebug_CMakeAppBuildConfigurations.xml
generated
Normal file
@ -0,0 +1,29 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="CppBuildDebug_CppBuildConfigurations">
|
||||
<option name="cppBuildConfigurations">
|
||||
<list>
|
||||
<CppBuildConfiguration>
|
||||
<option name="buildDirectory" value="build/" />
|
||||
<option name="buildOptions" value="-- -j 9" />
|
||||
<option name="buildType" value="Release" />
|
||||
<option name="cmakeOptions" value="-DCMAKE_BUILD_TYPE=Release -DCMAKE_SKIP_RPATH=TRUE" />
|
||||
<option name="name" value="Debug" />
|
||||
<option name="selected" value="true" />
|
||||
<option name="toolchainName" value="build_conf_928" />
|
||||
<option name="toolchainUuid" value="8bc3bf58-e069-4eca-a9b6-292381c929b6" />
|
||||
</CppBuildConfiguration>
|
||||
<CppBuildConfiguration>
|
||||
<option name="buildDirectory" value="build/" />
|
||||
<option name="buildOptions" value="-- -j 9" />
|
||||
<option name="buildType" value="Release" />
|
||||
<option name="cmakeOptions" value="-DCMAKE_BUILD_TYPE=Release -DCMAKE_SKIP_RPATH=TRUE" />
|
||||
<option name="name" value="Release_ymj" />
|
||||
<option name="toolchainName" value="build_conf_928" />
|
||||
<option name="toolchainUuid" value="8bc3bf58-e069-4eca-a9b6-292381c929b6" />
|
||||
</CppBuildConfiguration>
|
||||
</list>
|
||||
</option>
|
||||
<option name="select" value="Debug" />
|
||||
</component>
|
||||
</project>
|
7
.idea/encodings.xml
generated
Normal file
7
.idea/encodings.xml
generated
Normal file
@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="Encoding">
|
||||
<file url="file://$PROJECT_DIR$/image_framework/plugins/PlguinConfig.cpp" charset="GBK" />
|
||||
<file url="file://$PROJECT_DIR$/image_framework/plugins/PlguinConfig.h" charset="GBK" />
|
||||
</component>
|
||||
</project>
|
9
.idea/image_framework_ymj.iml
generated
Normal file
9
.idea/image_framework_ymj.iml
generated
Normal file
@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="JAVA_MODULE" version="4">
|
||||
<component name="NewModuleRootManager" inherit-compiler-output="true">
|
||||
<exclude-output />
|
||||
<content url="file://$MODULE_DIR$" />
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
</component>
|
||||
</module>
|
8
.idea/modules.xml
generated
Normal file
8
.idea/modules.xml
generated
Normal file
@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectModuleManager">
|
||||
<modules>
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/image_framework_ymj.iml" filepath="$PROJECT_DIR$/.idea/image_framework_ymj.iml" />
|
||||
</modules>
|
||||
</component>
|
||||
</project>
|
6
.idea/vcs.xml
generated
Normal file
6
.idea/vcs.xml
generated
Normal file
@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
||||
</component>
|
||||
</project>
|
139
CMakeLists.txt
Executable file
139
CMakeLists.txt
Executable file
@ -0,0 +1,139 @@
|
||||
cmake_minimum_required(VERSION 3.24)
|
||||
|
||||
include(${CMAKE_SOURCE_DIR}/cmake/cmakebase.cmake)
|
||||
include(${CMAKE_SOURCE_DIR}/cmake/project.cmake)
|
||||
include(${CMAKE_SOURCE_DIR}/cmake/ss928.cmake)
|
||||
|
||||
message(STATUS "========================")
|
||||
message(STATUS ${CMAKE_SYSTEM_NAME})
|
||||
message(STATUS ${CMAKE_SYSTEM_PROCESSOR})
|
||||
message(STATUS "========================")
|
||||
|
||||
set(CMAKE_CXX_STANDARD 14) # 设置使用C++11标准
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON) # 确保编译器遵循C++11标准
|
||||
|
||||
PROJECT(image_framework)
|
||||
|
||||
set(CMAKE_SOURCE_DIR "./")
|
||||
#set(_GLIBCXX_USE_CXX11_ABI 1)
|
||||
|
||||
# 检查Opencv版本
|
||||
find_package(OpenCV 4.10 REQUIRED)
|
||||
if(NOT OpenCV_FOUND)
|
||||
message(FATAL_ERROR "OpenCV > 4.10 not found.")
|
||||
endif()
|
||||
MESSAGE(${OpenCV_VERSION})
|
||||
message(STATUS "OpenCV include dirs: ${OpenCV_INCLUDE_DIRS}")
|
||||
message(STATUS "OpenCV library dirs: ${OpenCV_LIBRARY_DIRS}")
|
||||
message(STATUS "OpenCV libraries: ${OpenCV_LIBRARIES}")
|
||||
|
||||
|
||||
set(OPENGL_opengl_LIBRARY /usr/lib/aarch64-linux-gnu/libOpenGL.so)
|
||||
set(OPENGL_glx_LIBRARY /usr/lib/aarch64-linux-gnu/libGLX.so)
|
||||
set(X11_X11_LIB /usr/lib/aarch64-linux-gnu/libX11.so)
|
||||
find_package(Open3D REQUIRED)
|
||||
if(NOT Open3D_FOUND)
|
||||
message(FATAL_ERROR "Open3D not found.")
|
||||
endif()
|
||||
MESSAGE(${Open3D_VERSION})
|
||||
message(STATUS "Open3D include dirs: ${Open3D_INCLUDE_DIRS}")
|
||||
message(STATUS "Open3D library dirs: ${Open3D_LIBRARY_DIRS}")
|
||||
message(STATUS "Open3D libraries: ${Open3D_LIBRARIES}")
|
||||
|
||||
# 检测操作系统和架构
|
||||
# if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
|
||||
# if(CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64")
|
||||
# set(PLATFORM "linux/x64")
|
||||
# elseif(CMAKE_SYSTEM_PROCESSOR STREQUAL "aarch64")
|
||||
# set(PLATFORM "linux/aarch64")
|
||||
# else()
|
||||
# message(FATAL_ERROR "Unsupported architecture on Linux")
|
||||
# endif()
|
||||
# elseif(CMAKE_SYSTEM_NAME STREQUAL "Windows")
|
||||
# if(CMAKE_SIZEOF_VOID_P EQUAL 8)
|
||||
# set(PLATFORM "windows/x64")
|
||||
# else()
|
||||
# message(FATAL_ERROR "Unsupported architecture on Windows")
|
||||
# endif()
|
||||
# else()
|
||||
# message(FATAL_ERROR "Unsupported operating system")
|
||||
# endif()
|
||||
|
||||
# 输出当前系统和架构
|
||||
message(STATUS "operating system: ${PLATFORM}")
|
||||
|
||||
# 设置输出目录
|
||||
SET(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/output/")
|
||||
|
||||
# 设置头文件目录
|
||||
INCLUDE_DIRECTORIES(
|
||||
"/opt/HuarayTech/MVviewer/include/"
|
||||
/usr/local/include
|
||||
${CMAKE_SOURCE_DIR}/include/
|
||||
${CMAKE_SOURCE_DIR}/include/open3d/
|
||||
${CMAKE_SOURCE_DIR}/include/open3d/3rdparty
|
||||
${CMAKE_SOURCE_DIR}/include/eigen3/
|
||||
${CMAKE_SOURCE_DIR}/include/opencv4.10/
|
||||
${CMAKE_SOURCE_DIR}/include/Livox/
|
||||
${CMAKE_SOURCE_DIR}/image_framework/
|
||||
${CMAKE_SOURCE_DIR}/image_framework/algorithm/
|
||||
${CMAKE_SOURCE_DIR}/image_framework/driver/camera/
|
||||
${CMAKE_SOURCE_DIR}/image_framework/driver/livox/
|
||||
${CMAKE_SOURCE_DIR}/image_framework/plugins/
|
||||
${CMAKE_SOURCE_DIR}/image_framework/thead/
|
||||
${CMAKE_SOURCE_DIR}/image_framework/utils/Ini
|
||||
${CMAKE_SOURCE_DIR}/image_framework/utils/Log
|
||||
)
|
||||
|
||||
# 设置依赖库 .a
|
||||
LINK_DIRECTORIES(
|
||||
/usr/lib/aarch64-linux-gnu
|
||||
)
|
||||
|
||||
# fpermissive
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fpermissive")
|
||||
|
||||
# 设置原文件
|
||||
aux_source_directory(${CMAKE_SOURCE_DIR}/image_framework/ CORE_LIST)
|
||||
aux_source_directory(${CMAKE_SOURCE_DIR}/image_framework/algorithm/ CORE_LIST)
|
||||
aux_source_directory(${CMAKE_SOURCE_DIR}/image_framework/plugins CORE_LIST)
|
||||
aux_source_directory(${CMAKE_SOURCE_DIR}/image_framework/thead CORE_LIST)
|
||||
aux_source_directory(${CMAKE_SOURCE_DIR}/image_framework/driver/camera CORE_LIST)
|
||||
aux_source_directory(${CMAKE_SOURCE_DIR}/image_framework/driver/livox CORE_LIST)
|
||||
aux_source_directory(${CMAKE_SOURCE_DIR}/image_framework/utils/Ini CORE_LIST)
|
||||
aux_source_directory(${CMAKE_SOURCE_DIR}/image_framework/utils/Log CORE_LIST)
|
||||
|
||||
add_executable(${PROJECT_NAME} ${CORE_LIST})
|
||||
set_target_properties(${PROJECT_NAME} PROPERTIES LINK_FLAGS "-Wl,-rpath-link,/usr/lib/aarch64-linux-gnu")
|
||||
target_link_libraries(
|
||||
${PROJECT_NAME}
|
||||
${SYSTEM_LINK_LIB}
|
||||
${OpenCV_LIBS}
|
||||
livox_sdk_static
|
||||
pthread
|
||||
dl
|
||||
libstdc++.so.6
|
||||
Open3D::Open3D
|
||||
libxcb.so.1
|
||||
libXau.so.6
|
||||
libXdmcp.so.6
|
||||
libGLdispatch.so.0
|
||||
libbsd.so
|
||||
libbsd.so.0
|
||||
libbsd.so.0.10.0
|
||||
)
|
||||
|
||||
set(OUTPUT_LIB_DIR ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/lib)
|
||||
add_custom_target(cpfiles ALL DEPENDS ${PROJECT_NAME})
|
||||
|
||||
add_library(DetectDriver MODULE ${CORE_LIST})
|
||||
target_link_libraries(
|
||||
DetectDriver
|
||||
${SYSTEM_LINK_LIB}
|
||||
${OpenCV_LIBS}
|
||||
livox_sdk_static
|
||||
pthread
|
||||
dl
|
||||
)
|
||||
set_property(TARGET DetectDriver PROPERTY POSITION_INDEPENDENT_CODE ON) #添加-fPIC
|
||||
set_target_properties(DetectDriver PROPERTIES LINK_FLAGS "-fPIC")
|
24
cmake/cmakebase.cmake
Executable file
24
cmake/cmakebase.cmake
Executable file
@ -0,0 +1,24 @@
|
||||
# this one is important
|
||||
SET(CMAKE_SYSTEM_NAME Linux)
|
||||
set(CMAKE_SYSTEM_PROCESSOR aarch64 )
|
||||
|
||||
SET(CMAKE_SYSTEM_VERSION 1)
|
||||
|
||||
SET(SYSTEM_LINK_LIB
|
||||
/usr/lib/aarch64-linux-gnu/libpthread.so
|
||||
/usr/lib/aarch64-linux-gnu/librt.so
|
||||
/usr/lib/aarch64-linux-gnu/libdl.so
|
||||
/usr/lib/aarch64-linux-gnu/libm.so
|
||||
)
|
||||
SET(DO_FLAG -DO2)
|
||||
SET(O_FLAG -O2)
|
||||
SET(CMAKE_CXX_FLAGS
|
||||
"${CMAKE_CXX_FLAGS} ${O_FLAG} -std=c++11 -Wno-deprecated-declarations -ffunction-sections -fdata-sections -Werror -Wno-psabi -Wno-pointer-arith -Wno-int-to-pointer-cast"
|
||||
)
|
||||
# SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -lstdc++)
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -lstdc++ -mcpu=cortex-a53 -fno-aggressive-loop-optimizations -ldl -ffunction-sections -fdata-sections -O2 -fstack-protector-strong -fPIC")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fPIE -pie -s -Wall -fsigned-char")
|
||||
|
||||
set(CMAKE_CXX_STANDARD 11)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED TRUE)
|
||||
|
94
cmake/project.cmake
Executable file
94
cmake/project.cmake
Executable file
@ -0,0 +1,94 @@
|
||||
# Project libs
|
||||
|
||||
SET(SOC_LIBS
|
||||
|
||||
# MPI_LIBS
|
||||
libss_mpi.a
|
||||
# ISP_SUPPORT
|
||||
libss_ae.a
|
||||
libss_isp.a
|
||||
libot_isp.a
|
||||
libss_awb.a
|
||||
libss_dehaze.a
|
||||
libss_extend_stats.a
|
||||
libss_drc.a
|
||||
libss_ldci.a
|
||||
libss_crb.a
|
||||
libss_bnr.a
|
||||
libss_calcflicker.a
|
||||
libss_ir_auto.a
|
||||
libss_acs.a
|
||||
libss_acs.a
|
||||
libsns_os08a20.a
|
||||
libsns_os05a10_2l_slave.a
|
||||
libsns_imx347_slave.a
|
||||
libsns_imx485.a
|
||||
libsns_os04a10.a
|
||||
libsns_os08b10.a
|
||||
# ss_hnr
|
||||
|
||||
# AUDIO_LIBA
|
||||
libss_voice_engine.a
|
||||
libss_upvqe.a
|
||||
libss_dnvqe.a
|
||||
libaac_comm.a
|
||||
libaac_enc.a
|
||||
libaac_dec.a
|
||||
libaac_sbr_enc.a
|
||||
libaac_sbr_dec.a
|
||||
|
||||
# memset_s memcpy_s
|
||||
libsecurec.a
|
||||
|
||||
# HDMI lib
|
||||
libss_hdmi.a
|
||||
|
||||
# SVP
|
||||
libss_ive.a
|
||||
libss_md.a
|
||||
libss_mau.a
|
||||
libss_dpu_rect.a
|
||||
libss_dpu_match.a
|
||||
libss_dsp.a
|
||||
libascend_protobuf.a
|
||||
libsvp_acl.a
|
||||
libprotobuf-c.a
|
||||
|
||||
libacl_cblas.so
|
||||
libacl_retr.so
|
||||
libacl_tdt_queue.so
|
||||
libadump.so
|
||||
libaicpu_kernels.so
|
||||
libaicpu_processer.so
|
||||
libaicpu_prof.so
|
||||
libaicpu_scheduler.so
|
||||
libalog.so
|
||||
libascendcl.so
|
||||
libascend_protobuf.so
|
||||
libcce_aicore.so
|
||||
libcpu_kernels_context.so
|
||||
libcpu_kernels.so
|
||||
libc_sec.so
|
||||
libdrv_aicpu.so
|
||||
libdrvdevdrv.so
|
||||
libdrv_dfx.so
|
||||
liberror_manager.so
|
||||
libge_common.so
|
||||
libge_executor.so
|
||||
libgraph.so
|
||||
libmmpa.so
|
||||
libmsprofiler.so
|
||||
libmsprof.so
|
||||
libopt_feature.so
|
||||
libregister.so
|
||||
libruntime.so
|
||||
libslog.so
|
||||
libtsdclient.so
|
||||
|
||||
libss_mcf.so
|
||||
libss_mcf_vi.so
|
||||
libss_pqp.so
|
||||
)
|
||||
|
||||
add_definitions(-DSENSOR0_TYPE=SONY_IMX485_MIPI_8M_30FPS_12BIT)
|
||||
# add_definitions(-DUSE_NCNN_SIMPLEOCV)
|
5
cmake/ss928.cmake
Executable file
5
cmake/ss928.cmake
Executable file
@ -0,0 +1,5 @@
|
||||
SET(PLATFORM ss928)
|
||||
SET(CMAKE_C_COMPILER /home/setups/aarch64-mix210-linux/aarch64-mix210-linux/bin/aarch64-mix210-linux-gcc)
|
||||
SET(CMAKE_CXX_COMPILER /home/setups/aarch64-mix210-linux/aarch64-mix210-linux/bin/aarch64-mix210-linux-g++)
|
||||
SET(CMAKE_STRIP /home/setups/aarch64-mix210-linux/aarch64-mix210-linux/bin/aarch64-mix210-linux-strip)
|
||||
SET(CMAKE_ASM_COMPILER ${CMAKE_C_COMPILER})
|
359
image_framework/Libapi.cpp
Executable file
359
image_framework/Libapi.cpp
Executable file
@ -0,0 +1,359 @@
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <opencv2/opencv.hpp>
|
||||
|
||||
#include "LibapiProcessThread.h"
|
||||
#include "LibapiQueue.h"
|
||||
#include "LibapiQueues.h"
|
||||
#include "Libapi.h"
|
||||
|
||||
#include "IniHelper.h"
|
||||
#include "Yolov5For928.h"
|
||||
|
||||
#include "PlguinConfig.h"
|
||||
#include "MsgBase.h"
|
||||
#include "Libapi2D3D.h"
|
||||
#include "Log.h"
|
||||
#include "CameraHelper.h"
|
||||
|
||||
// 标式系统是否已经启动
|
||||
static bool bSysIsInit = false;
|
||||
|
||||
extern "C" LIBAPI_EXPORT int LIBAPI_CALLMETHOD libapi_init_plugin(int idx, void* pthread)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
// for test
|
||||
static void init1()
|
||||
{
|
||||
int idx = 0;
|
||||
//PlguinEnhance* _plguinEnhance = new PlguinEnhance();
|
||||
//LibapiProcessThread* _thread_plguinEnhance =
|
||||
// new LibapiProcessThread(idx, "_plguinEnhance", (BaseRunnable*)_plguinEnhance);
|
||||
//idx++;
|
||||
|
||||
//PlguinRoi* _plguinRoi = new PlguinRoi();
|
||||
//LibapiProcessThread* _thread_plguinRoi =
|
||||
// new LibapiProcessThread(idx, "_plguinRoi", (BaseRunnable*)_plguinRoi);
|
||||
//idx++;
|
||||
|
||||
//PlguinMotionDetection* _plguinMotionDetection = new PlguinMotionDetection();
|
||||
//LibapiProcessThread* _thread_plguinMotionDetection =
|
||||
// new LibapiProcessThread(idx, "_plguinMotionDetection", (BaseRunnable*)_plguinMotionDetection);
|
||||
//idx++;
|
||||
|
||||
//PlguinTrack* _plguinTrack = new PlguinTrack();
|
||||
//LibapiProcessThread* _thread_plguinTrack =
|
||||
// new LibapiProcessThread(idx, "_plguinTrack", (BaseRunnable*)_plguinTrack);
|
||||
//idx++;
|
||||
|
||||
//PlguinClassification* _plguinClassification = new PlguinClassification();
|
||||
//LibapiProcessThread* _thread_plguinClassification =
|
||||
// new LibapiProcessThread(idx, "_plguinClassification", (BaseRunnable*)_plguinClassification);
|
||||
//idx++;
|
||||
|
||||
//PlguinPostgressing* _plguinPostgressing = new PlguinPostgressing();
|
||||
//LibapiProcessThread* _thread_plguinPostgressing =
|
||||
// new LibapiProcessThread(idx, "_plguinPostgressing", (BaseRunnable*)_plguinPostgressing);
|
||||
//idx++;
|
||||
|
||||
//_thread_plguinEnhance->set_next_thread(_thread_plguinRoi);
|
||||
//_thread_plguinRoi->set_next_thread(_thread_plguinMotionDetection);
|
||||
//_thread_plguinMotionDetection->add_sub_thread(_thread_plguinTrack);
|
||||
//_thread_plguinMotionDetection->add_sub_thread(_thread_plguinClassification);
|
||||
//_thread_plguinMotionDetection->set_next_thread(_thread_plguinPostgressing);
|
||||
|
||||
//_thread_plguinEnhance->start();
|
||||
//_thread_plguinRoi->start();
|
||||
//_thread_plguinMotionDetection->start();
|
||||
//_thread_plguinTrack->start();
|
||||
//_thread_plguinClassification->start();
|
||||
//_thread_plguinPostgressing->start();
|
||||
|
||||
////_thread_plguinEnhance->join();
|
||||
////_thread_plguinRoi->join();
|
||||
////_thread_plguinMotionDetection->join();
|
||||
////_thread_plguinTrack->join();
|
||||
////_thread_plguinClassification->join();
|
||||
////_thread_plguinPostgressing->join();
|
||||
|
||||
////pthread = _thread_plguinEnhance;
|
||||
}
|
||||
|
||||
|
||||
extern "C" LIBAPI_EXPORT int LIBAPI_CALLMETHOD libapi_init_plugin_config(void* config, void* pthread)
|
||||
{
|
||||
return PlguinConfig::getInstance()->plguin_init_plugin_config(config, pthread);
|
||||
}
|
||||
|
||||
extern "C" LIBAPI_EXPORT int LIBAPI_CALLMETHOD libapi_create_MsgBase(char* msg_type, void** pMsg)
|
||||
{
|
||||
if ((*pMsg) != NULL)
|
||||
{
|
||||
std::cout << "pMsg is not null" << std::endl;
|
||||
assert(0);
|
||||
}
|
||||
|
||||
MsgBase* _pMsg = new MsgBase();
|
||||
//memcpy_s(_pMsg->version, sizeof(msg_type), msg_type, sizeof(msg_type));
|
||||
memcpy(_pMsg->version, msg_type, sizeof(msg_type));
|
||||
(*pMsg) = _pMsg;
|
||||
return 0;
|
||||
}
|
||||
|
||||
extern "C" LIBAPI_EXPORT int LIBAPI_CALLMETHOD libapi_delete_MsgBase(void* pMsg)
|
||||
{
|
||||
MsgBase::delete_msg((MsgBase*)pMsg);
|
||||
return 0;
|
||||
}
|
||||
|
||||
extern "C" LIBAPI_EXPORT int LIBAPI_CALLMETHOD libapi_copy_image_to_msg(
|
||||
void* pMsg, int pos, int param_type, void* image_data, int width, int height, int flag)
|
||||
{
|
||||
return MsgBase::copy_image_to_msg(
|
||||
pMsg, pos, param_type, image_data, width, height, flag);
|
||||
}
|
||||
|
||||
extern "C" LIBAPI_EXPORT int LIBAPI_CALLMETHOD libapi_copy(void* tar, void* src, int len)
|
||||
{
|
||||
//memcpy_s(tar, len, src, len);
|
||||
memcpy(tar, src, len);
|
||||
return 0;
|
||||
}
|
||||
|
||||
extern "C" LIBAPI_EXPORT int LIBAPI_CALLMETHOD libapi_bind_queue(int id, char* queue_name, int src_type)
|
||||
{
|
||||
std::string qname(queue_name);
|
||||
LibapiQueue<void*>* queue = Queues::create_queue(id, qname);
|
||||
if (queue == NULL) return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
extern "C" LIBAPI_EXPORT int LIBAPI_CALLMETHOD libapi_ubbind_queue(char* queue_name)
|
||||
{
|
||||
std::string qname(queue_name);
|
||||
LibapiQueue<void*>* queue = Queues::find_queue(qname);
|
||||
if (queue == NULL) return -1;
|
||||
Queues::delete_queue(queue);
|
||||
return 0;
|
||||
}
|
||||
|
||||
extern "C" LIBAPI_EXPORT int LIBAPI_CALLMETHOD libapi_push_to_queue(char* queue_name, void* msg)
|
||||
{
|
||||
((MsgBase*)msg)->add_ref();
|
||||
int ret = Queues::push_to_queue(queue_name, msg);
|
||||
if (ret != 0)
|
||||
{
|
||||
int ref = ((MsgBase*)msg)->sub_ref();
|
||||
if (ref == 0)
|
||||
((MsgBase*)msg)->delete_msg();
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
extern "C" LIBAPI_EXPORT int LIBAPI_CALLMETHOD libapi_pop_from_queue(char* queue_name, void** msg)
|
||||
{
|
||||
std::string qname(queue_name);
|
||||
LibapiQueue<void*>* queue = Queues::find_queue(qname);
|
||||
if (queue == NULL) return -1;
|
||||
queue->pop(*msg);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 初始化
|
||||
extern "C" LIBAPI_EXPORT int LIBAPI_CALLMETHOD LibapiInit(const long id, const char* info, void (*callback)(void*))
|
||||
{
|
||||
int ret = SYS_OK;
|
||||
|
||||
// init config
|
||||
GINIT();
|
||||
|
||||
// init yolo for 928 待优化
|
||||
ret = CYolov5For928::Get()->Init();
|
||||
if (ret != SYS_OK)
|
||||
return SYS_NPU_IS_NOT_INIT;
|
||||
|
||||
//ret = CCameraHelper::Get()->Init();
|
||||
//if (ret != SYS_OK)
|
||||
//{
|
||||
// return SYS_CAMERA_IS_NOT_INIT;
|
||||
//}
|
||||
|
||||
// 初始化CMeasureInfo
|
||||
CMeasureInfo::Init(id, info);
|
||||
|
||||
// 初始化回调函数
|
||||
MsgBase::SetCallBack(callback);
|
||||
|
||||
// init task
|
||||
PlguinConfig::getInstance()->LibapiInitCameraProcessing(nullptr);
|
||||
PlguinConfig::getInstance()->LibapiInitLidarProcessing(nullptr);
|
||||
PlguinConfig::getInstance()->LibapiInitRoiProcessing(nullptr);
|
||||
LibapiThread::delay_second(2);
|
||||
|
||||
// 标识系统已经启动
|
||||
bSysIsInit = true;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
// 启动定位角点
|
||||
extern "C" LIBAPI_EXPORT int LIBAPI_CALLMETHOD LibapiStartDetection()
|
||||
{
|
||||
int ret = SYS_OK;
|
||||
|
||||
if (!bSysIsInit)
|
||||
return SYS_IS_NOT_INIT;
|
||||
|
||||
MsgBase* pMsgCamera = nullptr;
|
||||
MsgBase* pMsgLidar = nullptr;
|
||||
char msg_type[32] = "v1.0";
|
||||
|
||||
libapi_create_MsgBase(msg_type, (void**)&pMsgCamera);
|
||||
libapi_create_MsgBase(msg_type, (void**)&pMsgLidar);
|
||||
pMsgCamera->mMsgType = "StartDetection";
|
||||
pMsgLidar->mMsgType = "StartDetection";
|
||||
|
||||
ret = libapi_push_to_queue((char*)"_t_PluginCameraPro", pMsgCamera);
|
||||
ret = libapi_push_to_queue((char*)"_t_PlguinLidarPro", pMsgLidar);
|
||||
|
||||
// 待优化
|
||||
LibapiThread::delay_second(1);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
extern "C" LIBAPI_EXPORT int LIBAPI_CALLMETHOD LibapiContinuetDetection()
|
||||
{
|
||||
int ret = SYS_OK;
|
||||
|
||||
if (!bSysIsInit)
|
||||
return SYS_IS_NOT_INIT;
|
||||
|
||||
MsgBase::SetWaitInt(MsgBase::iClinetMsg, CLIENT_MSG_CONTINUE);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
// 重新定位角点
|
||||
extern "C" LIBAPI_EXPORT int LIBAPI_CALLMETHOD LibapRestartConnerDetection()
|
||||
{
|
||||
int ret = SYS_OK;
|
||||
|
||||
if (!bSysIsInit)
|
||||
return SYS_IS_NOT_INIT;
|
||||
|
||||
MsgBase::SetWaitInt(MsgBase::iClinetMsg, CLIENT_MSG_RESTART_DETECTION);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
// 终止定位角点
|
||||
extern "C" LIBAPI_EXPORT int LIBAPI_CALLMETHOD LibapStopDetection()
|
||||
{
|
||||
int ret = SYS_OK;
|
||||
|
||||
if (!bSysIsInit)
|
||||
return SYS_IS_NOT_INIT;
|
||||
|
||||
MsgBase::SetWaitInt(MsgBase::iClinetMsg, CLIENT_MSG_STOP_DETECTION);
|
||||
return ret;
|
||||
}
|
||||
|
||||
// 获取结果
|
||||
extern "C" LIBAPI_EXPORT int LIBAPI_CALLMETHOD LibapGetRecord(void* p)
|
||||
{
|
||||
int ret = SYS_OK;
|
||||
|
||||
CallbackInfo* cbInfo = (CallbackInfo*)p;
|
||||
CMeasureInfo* measureInfo = CMeasureInfo::Get();
|
||||
|
||||
if (cbInfo == nullptr || measureInfo == nullptr)
|
||||
assert(0);
|
||||
|
||||
cbInfo->code = 0;
|
||||
//cbInfo->errorInfo = "";
|
||||
cbInfo->bGetData = true;
|
||||
std::vector<std::shared_ptr<CSubRoi>> rois = measureInfo->GetSubRois();
|
||||
cbInfo->roi_size = rois.size();
|
||||
for (int i = 0; i < rois.size(); ++i)
|
||||
{
|
||||
std::shared_ptr<CSubRoi> roi = rois[i];
|
||||
SubRoiData* cb_roi = &cbInfo->subRois[i];
|
||||
|
||||
for (int n = 0; n < (roi.get()->H).total(); ++n)
|
||||
cb_roi->H[n] = (roi.get()->H).at<float>(0, n);
|
||||
for (int n = 0; n < roi.get()->mRoiPoints.size(); ++n)
|
||||
{
|
||||
cv::Point2f p2f = roi.get()->mRoiPoints[n];
|
||||
cb_roi->mRoiPoints[n * 2] = p2f.x;
|
||||
cb_roi->mRoiPoints[n * 2 + 1] = p2f.y;
|
||||
}
|
||||
for (int n = 0; n < roi.get()->mInnerConners.size(); ++n)
|
||||
{
|
||||
cv::Point2f p2f = roi.get()->mInnerConners[n];
|
||||
cb_roi->mInnerConners[n * 2] = p2f.x;
|
||||
cb_roi->mInnerConners[n * 2 + 1] = p2f.y;
|
||||
}
|
||||
for (int n = 0; n < roi.get()->mInnerConners3D.size(); ++n)
|
||||
{
|
||||
cv::Point3f p3f = roi.get()->mInnerConners3D[n];
|
||||
cb_roi->mInnerConners3D[n * 3] = p3f.x;
|
||||
cb_roi->mInnerConners3D[n * 3 + 1] = p3f.y;
|
||||
cb_roi->mInnerConners3D[n * 3 + 2] = p3f.z;
|
||||
}
|
||||
//for (int n = 0; n < roi.get()->mInnerConners3D.size(); ++n)
|
||||
//{
|
||||
//}
|
||||
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
extern "C" LIBAPI_EXPORT int LIBAPI_CALLMETHOD LibapiCameraSendMsgWithImage(
|
||||
void* image_data, int width, int height, int flag, char* type, char* queue_name)
|
||||
{
|
||||
int ret = SYS_OK;
|
||||
MsgBase* _pMsg = new MsgBase();
|
||||
|
||||
_pMsg->mMsgType = type;
|
||||
ret = MsgBase::copy_image_to_msg(_pMsg, PARAM_POS_SRC_IMAGE, 0, image_data, width, height, flag);
|
||||
if (ret != SYS_OK)
|
||||
return ret;
|
||||
|
||||
return libapi_push_to_queue(queue_name, _pMsg);
|
||||
}
|
||||
|
||||
extern "C" LIBAPI_EXPORT int LIBAPI_CALLMETHOD LibapiGetHQImage(
|
||||
void* image_data, int width, int height, int flag, char* type)
|
||||
{
|
||||
int ret = SYS_OK;
|
||||
std::shared_ptr<cv::Mat> ptr = CMeasureInfo::Get()->GetIm();
|
||||
if (ptr != nullptr)
|
||||
{
|
||||
cv::Mat* imPtr = ptr.get();
|
||||
if (imPtr != nullptr && width == imPtr->cols && height == imPtr->rows)
|
||||
{
|
||||
memcpy(image_data, imPtr->data, imPtr->total() * 3);
|
||||
std::cout << "像素数量 : " << imPtr->total() * 3 << std::endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cout << "cv::Mat* imPtr is None" << std::endl;
|
||||
std::cout << imPtr << std::endl;
|
||||
std::cout << width << " : " << imPtr->cols << std::endl;
|
||||
std::cout << height << " : " << imPtr->rows << std::endl;
|
||||
return SYS_ERROR;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cout << "ptr is None width" << std::endl;
|
||||
return SYS_ERROR;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
68
image_framework/Libapi.h
Executable file
68
image_framework/Libapi.h
Executable file
@ -0,0 +1,68 @@
|
||||
/*
|
||||
**************************************************************************************
|
||||
* Filename: Libapi.h
|
||||
* Description: header file
|
||||
*
|
||||
* Version: 1.0
|
||||
* Created:
|
||||
* Author:
|
||||
*
|
||||
* Revision: initial draft;
|
||||
**************************************************************************************
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
/*
|
||||
@desc : macro define
|
||||
*/
|
||||
#ifdef _WIN32
|
||||
#define LIBAPI_CALLMETHOD __cdecl
|
||||
#define LIBAPI_EXPORT __declspec(dllexport)
|
||||
#else
|
||||
#define LIBAPI_CALLMETHOD
|
||||
#define LIBAPI_EXPORT
|
||||
#endif
|
||||
|
||||
#define SYS_BASE 1000
|
||||
#define SYS_OK 0
|
||||
#define SYS_IS_NOT_INIT 1 - SYS_BASE
|
||||
#define SYS_NPU_IS_NOT_INIT 2 - SYS_BASE
|
||||
#define SYS_ERROR 3 - SYS_BASE
|
||||
#define SYS_CAMERA_IS_NOT_INIT 4 - SYS_BASE
|
||||
#define SYS_HAS_NO_IMAGE 5 - SYS_BASE
|
||||
|
||||
|
||||
extern "C" LIBAPI_EXPORT int LIBAPI_CALLMETHOD libapi_init_plugin(int idx, void* pthread);
|
||||
extern "C" LIBAPI_EXPORT int LIBAPI_CALLMETHOD libapi_init_plugin_config(void* config, void* pthread);
|
||||
|
||||
extern "C" LIBAPI_EXPORT int LIBAPI_CALLMETHOD libapi_create_MsgBase(char* msg_type, void** pMsg);
|
||||
extern "C" LIBAPI_EXPORT int LIBAPI_CALLMETHOD libapi_delete_MsgBase(void* pMsg);
|
||||
extern "C" LIBAPI_EXPORT int LIBAPI_CALLMETHOD libapi_copy_image_to_msg(void* pMsg, int pos, int param_type,
|
||||
void* image_data, int width, int height, int flag);
|
||||
|
||||
extern "C" LIBAPI_EXPORT int LIBAPI_CALLMETHOD libapi_copy(void* tar, void* src, int len);
|
||||
|
||||
extern "C" LIBAPI_EXPORT int LIBAPI_CALLMETHOD libapi_bind_queue(int id, char* queue_name, int src_type=0); //0 : c++ , 1 : python
|
||||
extern "C" LIBAPI_EXPORT int LIBAPI_CALLMETHOD libapi_ubbind_queue(char* queue_name);
|
||||
|
||||
extern "C" LIBAPI_EXPORT int LIBAPI_CALLMETHOD libapi_push_to_queue(char* queue_name, void* msg);
|
||||
extern "C" LIBAPI_EXPORT int LIBAPI_CALLMETHOD libapi_pop_from_queue(char* queue_name, void** msg);
|
||||
|
||||
// 初始化
|
||||
extern "C" LIBAPI_EXPORT int LIBAPI_CALLMETHOD LibapiInit(const long id, const char* info, void (*data_callback)(void*));
|
||||
// 启动定位角点
|
||||
extern "C" LIBAPI_EXPORT int LIBAPI_CALLMETHOD LibapiStartDetection();
|
||||
// 继续定位角点
|
||||
extern "C" LIBAPI_EXPORT int LIBAPI_CALLMETHOD LibapiContinuetDetection();
|
||||
// 重新定位角点
|
||||
extern "C" LIBAPI_EXPORT int LIBAPI_CALLMETHOD LibapRestartConnerDetection();
|
||||
// 终止定位角点
|
||||
extern "C" LIBAPI_EXPORT int LIBAPI_CALLMETHOD LibapStopDetection();
|
||||
// 获取结果
|
||||
extern "C" LIBAPI_EXPORT int LIBAPI_CALLMETHOD LibapGetRecord(void* data);
|
||||
// 相机直接输入图像
|
||||
extern "C" LIBAPI_EXPORT int LIBAPI_CALLMETHOD LibapiCameraSendMsgWithImage(
|
||||
void* image_data, int width, int height, int flag, char* type, char* queue_name);
|
||||
// 获取高清图像
|
||||
extern "C" LIBAPI_EXPORT int LIBAPI_CALLMETHOD LibapiGetHQImage(
|
||||
void* image_data, int width, int height, int flag, char* type);
|
3
image_framework/algorithm/LibError.h
Executable file
3
image_framework/algorithm/LibError.h
Executable file
@ -0,0 +1,3 @@
|
||||
#pragma once
|
||||
|
||||
#define SysError int
|
143
image_framework/algorithm/Libapi2D3D.cpp
Executable file
143
image_framework/algorithm/Libapi2D3D.cpp
Executable file
@ -0,0 +1,143 @@
|
||||
#include "Libapi2D3D.h"
|
||||
|
||||
|
||||
CMeasureInfo* CMeasureInfo::m_instance;
|
||||
|
||||
CMeasureInfo* CMeasureInfo::Get()
|
||||
{
|
||||
if (CMeasureInfo::m_instance == nullptr)
|
||||
{
|
||||
assert(0);
|
||||
}
|
||||
return CMeasureInfo::m_instance;
|
||||
}
|
||||
|
||||
CMeasureInfo* CMeasureInfo::Clear()
|
||||
{
|
||||
if (CMeasureInfo::m_instance == nullptr)
|
||||
{
|
||||
assert(0);
|
||||
}
|
||||
CMeasureInfo* measureInfo = CMeasureInfo::m_instance;
|
||||
measureInfo->mId = -1;
|
||||
measureInfo->mInfo = "";
|
||||
measureInfo->mImPtr = nullptr;
|
||||
measureInfo->mIm2D3DPtr = nullptr;
|
||||
for (int i = 0; i < measureInfo->subRois.size(); ++i)
|
||||
{
|
||||
std::shared_ptr<CSubRoi> roi = measureInfo->subRois[i];
|
||||
roi->mId = -1;
|
||||
roi->mInfo = "";
|
||||
roi->mInnerConners.clear();
|
||||
roi->mInnerConners3D.clear();
|
||||
roi->mPparentId = -1;
|
||||
roi->mRoiPoints.clear();
|
||||
roi->mVc2D.clear();
|
||||
roi->mVc3D.clear();
|
||||
roi->vpOffset = { 0.0, 0.0 };
|
||||
}
|
||||
measureInfo->subRois.clear();
|
||||
return CMeasureInfo::m_instance;
|
||||
}
|
||||
|
||||
CMeasureInfo* CMeasureInfo::Init(long id, std::string info)
|
||||
{
|
||||
if (CMeasureInfo::m_instance == nullptr)
|
||||
{
|
||||
CMeasureInfo::m_instance = new CMeasureInfo(id, info);
|
||||
}
|
||||
CMeasureInfo::Clear();
|
||||
CMeasureInfo* measureInfo = CMeasureInfo::m_instance;
|
||||
measureInfo->mId = id;
|
||||
measureInfo->mInfo = info;
|
||||
|
||||
return CMeasureInfo::m_instance;
|
||||
}
|
||||
|
||||
CMeasureInfo::CMeasureInfo()
|
||||
{
|
||||
};
|
||||
|
||||
CMeasureInfo::CMeasureInfo(long id, std::string info)
|
||||
{
|
||||
this->mId = id;
|
||||
this->mInfo = info;
|
||||
}
|
||||
|
||||
CMeasureInfo::~CMeasureInfo()
|
||||
{
|
||||
// 统一在这里删除
|
||||
this->mImPtr = nullptr;
|
||||
};
|
||||
|
||||
long CMeasureInfo::GetID()
|
||||
{
|
||||
return this->mId;
|
||||
}
|
||||
|
||||
std::string CMeasureInfo::GetInfo()
|
||||
{
|
||||
return this->mInfo;
|
||||
}
|
||||
|
||||
std::shared_ptr<cv::Mat> CMeasureInfo::GetIm()
|
||||
{
|
||||
return this->mImPtr;
|
||||
};
|
||||
|
||||
void CMeasureInfo::SetIm(std::shared_ptr<cv::Mat>& imptr)
|
||||
{
|
||||
this->mImPtr = imptr;
|
||||
};
|
||||
|
||||
std::shared_ptr<cv::Mat>& CMeasureInfo::GetIm2D3D()
|
||||
{
|
||||
return this->mIm2D3DPtr;
|
||||
};
|
||||
|
||||
void CMeasureInfo::SetIm2D3D(std::shared_ptr<cv::Mat>& imim2D3Dptr)
|
||||
{
|
||||
this->mIm2D3DPtr = imim2D3Dptr;
|
||||
};
|
||||
|
||||
std::vector<std::shared_ptr<CSubRoi>>& CMeasureInfo::GetSubRois()
|
||||
{
|
||||
return this->subRois;
|
||||
};
|
||||
|
||||
std::vector<std::vector<cv::Point2f>> CMeasureInfo::GetAllRoiConners()
|
||||
{
|
||||
std::vector<std::vector<cv::Point2f>> allConners;
|
||||
std::vector<cv::Point2f> vp2f;
|
||||
for (int i = 0; i < this->subRois.size(); ++i)
|
||||
{
|
||||
CSubRoi* subRoi = this->subRois[i].get();
|
||||
vp2f.clear();
|
||||
for (int j = 0; j < subRoi->mInnerConners.size(); ++j)
|
||||
{
|
||||
vp2f.push_back(subRoi->mInnerConners[j]);
|
||||
|
||||
}
|
||||
allConners.push_back(vp2f);
|
||||
}
|
||||
return allConners;
|
||||
}
|
||||
|
||||
CSubRoi::CSubRoi()
|
||||
{
|
||||
this->mInfo = "";
|
||||
//this->isGood = true;
|
||||
};
|
||||
|
||||
CSubRoi::CSubRoi(long parentId, long id, std::string info)
|
||||
{
|
||||
this->mPparentId = parentId;
|
||||
this->mId = id;
|
||||
this->mInfo = info;
|
||||
this->isGood = true;
|
||||
}
|
||||
|
||||
CSubRoi::~CSubRoi()
|
||||
{
|
||||
|
||||
};
|
114
image_framework/algorithm/Libapi2D3D.h
Executable file
114
image_framework/algorithm/Libapi2D3D.h
Executable file
@ -0,0 +1,114 @@
|
||||
#ifndef LIBAPI_2D3D_H
|
||||
#define LIBAPI_2D3D_H
|
||||
|
||||
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <opencv2/opencv.hpp>
|
||||
#include <chrono>
|
||||
#include <random>
|
||||
|
||||
#define CAL_2D3D_BASE 2000
|
||||
|
||||
#define CAL_OK 0
|
||||
#define CAL_READFILE_FAILED 1 - CAL_2D3D_BASE
|
||||
#define CAL_WRITEFILE_FAILED 2 - CAL_2D3D_BASE
|
||||
#define CAL_NONE_PTR 3 - CAL_2D3D_BASE
|
||||
#define CAL_PRAMA_EMPUTY 4 - CAL_2D3D_BASE
|
||||
#define CAL_READIM_FAILED 5 - CAL_2D3D_BASE
|
||||
#define CAL_NPU_LOAD_DATASET_FAILED 6 - CAL_2D3D_BASE
|
||||
#define CAL_NPU_MODEL_EXE_FAILED 7 - CAL_2D3D_BASE
|
||||
#define CAL_NPU_GET_RESULT_FAILED 8 - CAL_2D3D_BASE
|
||||
#define CAL_NPU_UNLOAD_DATASET_FAILED 9 - CAL_2D3D_BASE
|
||||
#define CAL_YOLO_DETECT_NO_ROI 10 - CAL_2D3D_BASE
|
||||
#define CAL_ROIS_PUSH_TREAD_FAILED 11 - CAL_2D3D_BASE
|
||||
#define CAL_H_FAILED 12 - CAL_2D3D_BASE
|
||||
#define CAL_3D_COONERS_FAILED 13 - CAL_2D3D_BASE
|
||||
#define CAL_INNER_COONERS_ISNOT_4 14 - CAL_2D3D_BASE
|
||||
#define CAL_3D_PROJECT_POINTS_IS_0 15 - CAL_2D3D_BASE
|
||||
#define CAL_3D_CLOUD_POINTS_IS_0 16 - CAL_2D3D_BASE
|
||||
#define CAL_HAS_NO_GOOD_CONNER 17 - CAL_2D3D_BASE
|
||||
#define CAL_2D_ROI_DETECTIION_IS_0 18 - CAL_2D3D_BASE
|
||||
#define CAL_2D_CAP_IMAGE_FAILED 19 - CAL_2D3D_BASE
|
||||
|
||||
|
||||
class CalUtils
|
||||
{
|
||||
public:
|
||||
static int LibapiGenRandomId(long& id)
|
||||
{
|
||||
auto now = std::chrono::system_clock::now();
|
||||
auto duration = now.time_since_epoch();
|
||||
auto seconds = std::chrono::duration_cast<std::chrono::seconds>(duration).count();
|
||||
id = std::hash<long>{}(static_cast<long>(seconds));
|
||||
|
||||
return CAL_OK;
|
||||
};
|
||||
};
|
||||
|
||||
class CSubRoi;
|
||||
class CMeasureInfo // 设计为单例模式
|
||||
{
|
||||
public:
|
||||
static CMeasureInfo* Get();
|
||||
static CMeasureInfo* Clear();
|
||||
static CMeasureInfo* Init(long id, std::string info);
|
||||
public:
|
||||
CMeasureInfo();
|
||||
CMeasureInfo(long id, std::string info);
|
||||
~CMeasureInfo();
|
||||
long GetID();
|
||||
std::string GetInfo();
|
||||
std::shared_ptr<cv::Mat> GetIm();
|
||||
void SetIm(std::shared_ptr<cv::Mat>& imptr);
|
||||
std::shared_ptr<cv::Mat>& GetIm2D3D();
|
||||
void SetIm2D3D(std::shared_ptr<cv::Mat>& imim2D3Dptr);
|
||||
std::vector<std::shared_ptr<CSubRoi>>& GetSubRois();
|
||||
std::vector<std::vector<cv::Point2f>> GetAllRoiConners();
|
||||
private:
|
||||
static CMeasureInfo* m_instance;
|
||||
private:
|
||||
|
||||
private:
|
||||
// 该区域ID
|
||||
long mId;
|
||||
// 该区域信息
|
||||
std::string mInfo;
|
||||
// 该区域的图像指针
|
||||
std::shared_ptr<cv::Mat> mImPtr;
|
||||
// 该区域的图像指针
|
||||
std::shared_ptr<cv::Mat> mIm2D3DPtr;
|
||||
// 该区域的子图像指针
|
||||
std::vector<std::shared_ptr<CSubRoi>> subRois;
|
||||
|
||||
};
|
||||
|
||||
class CSubRoi
|
||||
{
|
||||
public:
|
||||
CSubRoi();
|
||||
CSubRoi(long parentId, long id, std::string info);
|
||||
~CSubRoi();
|
||||
public:
|
||||
// 该区域父图像的ID
|
||||
long mPparentId;
|
||||
// 该区域ID
|
||||
long mId;
|
||||
bool isGood;
|
||||
// 该区域信息
|
||||
std::string mInfo;
|
||||
// 区域与原图的偏移量
|
||||
cv::Point2f vpOffset;
|
||||
// 该区域的坐标(ROI的4个坐标点) * 4
|
||||
std::vector<cv::Point2f> mRoiPoints;
|
||||
// 该区域的角点的2D信息 * 4
|
||||
std::vector<cv::Point2f> mInnerConners;
|
||||
// 该区域的角点的3D信息 * 4
|
||||
std::vector<cv::Point3f> mInnerConners3D;
|
||||
// for test cal * 10000+
|
||||
std::vector<cv::Point2f> mVc2D;
|
||||
std::vector<cv::Point3f> mVc3D;
|
||||
cv::Mat H;
|
||||
};
|
||||
|
||||
#endif
|
891
image_framework/algorithm/Libapi2d.cpp
Executable file
891
image_framework/algorithm/Libapi2d.cpp
Executable file
@ -0,0 +1,891 @@
|
||||
|
||||
#include "Libapi2d.h"
|
||||
#include "Libapi3d.h"
|
||||
#include "IniHelper.h"
|
||||
#include "Yolov5For928.h"
|
||||
#include "Log.h"
|
||||
#include "CameraHelper.h"
|
||||
|
||||
#include <vector>
|
||||
#include <cmath>
|
||||
#include <algorithm>
|
||||
#include <atomic>
|
||||
|
||||
static std::atomic_flag atomic_lock = ATOMIC_FLAG_INIT;
|
||||
|
||||
static cv::Mat Sobel(cv::Mat& mat, double alpha, double beta)
|
||||
{
|
||||
cv::Mat tmpImage;
|
||||
cv::Mat tmpImageX;
|
||||
cv::Mat tmpImageY;
|
||||
|
||||
if (mat.type() != CV_8UC1)
|
||||
cvtColor(mat, tmpImage, cv::COLOR_BGR2GRAY);
|
||||
else
|
||||
tmpImage = mat;
|
||||
|
||||
cv::Sobel(tmpImage, tmpImageX, CV_64F, 1, 0, 1);
|
||||
cv::Sobel(tmpImage, tmpImageY, CV_64F, 0, 1, 1);
|
||||
|
||||
cv::convertScaleAbs(tmpImageX, tmpImageX);
|
||||
cv::convertScaleAbs(tmpImageY, tmpImageY);
|
||||
|
||||
cv::bitwise_or(tmpImageX, tmpImageY, tmpImage);
|
||||
//cv::addWeighted(tmpImageX, alpha, tmpImageY, beta, 0, tmpImage);
|
||||
return tmpImage;
|
||||
}
|
||||
|
||||
|
||||
static cv::Mat CopyToEx(cv::Mat& src, cv::Mat& mask, cv::Mat& tar, int x_offset, int y_offset)
|
||||
{
|
||||
cv::Mat dst;
|
||||
tar.copyTo(dst);
|
||||
cv::Rect roi_rect = cv::Rect(x_offset, y_offset, src.cols, src.rows);
|
||||
src.copyTo(dst(roi_rect), mask);
|
||||
return dst;
|
||||
}
|
||||
|
||||
|
||||
static cv::Rect OutSquare(const std::vector<cv::Point>& vp)
|
||||
{
|
||||
int x1 = 9999;
|
||||
int y1 = 9999;
|
||||
int x2 = 0;
|
||||
int y2 = 0;
|
||||
for (int i = 0; i < vp.size(); i++)
|
||||
{
|
||||
if (vp[i].x < x1)
|
||||
x1 = vp[i].x;
|
||||
if (vp[i].x > x2)
|
||||
x2 = vp[i].x;
|
||||
if (vp[i].y < y1)
|
||||
y1 = vp[i].y;
|
||||
if (vp[i].y > y2)
|
||||
y2 = vp[i].y;
|
||||
}
|
||||
|
||||
return cv::Rect(x1, y1, x2 - x1, y2 - y1);
|
||||
}
|
||||
|
||||
|
||||
static std::vector<cv::Point> Offset(const std::vector<cv::Point>& vp, int x, int y)
|
||||
{
|
||||
std::vector<cv::Point> vpTar;
|
||||
|
||||
for (int i = 0; i < vp.size(); i++)
|
||||
{
|
||||
cv::Point p(vp[i].x + x, vp[i].y + y);
|
||||
vpTar.push_back(p);
|
||||
}
|
||||
|
||||
return vpTar;
|
||||
}
|
||||
|
||||
|
||||
static cv::Mat GetRoi(cv::Mat& mat, const std::vector<cv::Point>& vp)
|
||||
{
|
||||
cv::Mat dst;
|
||||
cv::Rect rt = OutSquare(vp);
|
||||
cv::Mat src = mat(rt);
|
||||
cv::Mat roi = cv::Mat::zeros(src.size(), CV_8U);
|
||||
|
||||
std::vector<std::vector<cv::Point>> contour;
|
||||
std::vector<cv::Point> vpOffset = Offset(vp, -rt.x, -rt.y);
|
||||
//contour.push_back(vpOffset);
|
||||
//cv::drawContours(roi, contour, 0, cv::Scalar::all(255), -1);
|
||||
src.copyTo(dst, roi);
|
||||
|
||||
return dst;
|
||||
}
|
||||
|
||||
|
||||
static std::vector<std::vector<float>> SortLines(std::vector<std::vector<float>>& lines4)
|
||||
{
|
||||
float Ax = 1, Bx = 0, Cx = 0;
|
||||
float Ay = 0, By = 1, Cy = 0;
|
||||
float min_dx = 10000, max_dx = 0, min_dy = 10000, max_dy = 0;
|
||||
float min_dx_idx = -1, max_dx_idx = -1, min_dy_idx = -1, max_dy_idx = -1;
|
||||
float cx = 0.0, cy = 0.0;
|
||||
float dx = 0.0, dy = 0.0;
|
||||
|
||||
std::vector<std::vector<float>> sort_lines4(4); // 上、右、下、左四条线
|
||||
for (int i = 0; i < sort_lines4.size(); ++i) {
|
||||
sort_lines4[i].resize(6); // x1, y1, x2, y2, theta, r
|
||||
}
|
||||
|
||||
for (int i = 0; i < lines4.size(); ++i)
|
||||
{
|
||||
cx = (lines4[i][2] + lines4[i][0]) / 2, cy = (lines4[i][3] + lines4[i][1]) / 2;
|
||||
dx = abs(Ay * cx + By * cy + Cy) / sqrt(pow(Ay, 2) + pow(By, 2));
|
||||
dy = abs(Ax * cx + Bx * cy + Cx) / sqrt(pow(Ax, 2) + pow(Bx, 2));
|
||||
if (dx < min_dx)
|
||||
{
|
||||
min_dx = dx;
|
||||
min_dx_idx = i;
|
||||
}
|
||||
if (dx > max_dx)
|
||||
{
|
||||
max_dx = dx;
|
||||
max_dx_idx = i;
|
||||
}
|
||||
if (dy < min_dy)
|
||||
{
|
||||
min_dy = dy;
|
||||
min_dy_idx = i;
|
||||
}
|
||||
if (dy > max_dy)
|
||||
{
|
||||
max_dy = dy;
|
||||
max_dy_idx = i;
|
||||
}
|
||||
}
|
||||
sort_lines4[0] = lines4[min_dx_idx];
|
||||
sort_lines4[1] = lines4[max_dy_idx];
|
||||
sort_lines4[2] = lines4[max_dx_idx];
|
||||
sort_lines4[3] = lines4[min_dy_idx];
|
||||
return sort_lines4;
|
||||
}
|
||||
|
||||
|
||||
static std::vector<std::vector<float>> GetIntersections(cv::Mat& im, std::vector<std::vector<float>>& sort_lines4)
|
||||
{
|
||||
float x1, y1, x2, y2;
|
||||
float x1_next, y1_next, x2_next, y2_next;
|
||||
float m, m_next;
|
||||
float A, B, C, A_next, B_next, C_next;
|
||||
float x_p, y_p;
|
||||
|
||||
std::vector<std::vector<float>> sort_conners4(4);
|
||||
|
||||
for (int i = 0; i < sort_conners4.size(); ++i) {
|
||||
sort_conners4[i].resize(2); // x1, y1, x2, y2, theta, r
|
||||
}
|
||||
|
||||
for (int i = 0; i < 4; ++i)
|
||||
{
|
||||
std::vector<float> line = sort_lines4[i];
|
||||
x1 = line[0], y1 = line[1], x2 = line[2], y2 = line[3];
|
||||
std::vector<float> line_next = sort_lines4[(i + 1) % 4];
|
||||
x1_next = line_next[0], y1_next = line_next[1], x2_next = line_next[2], y2_next = line_next[3];
|
||||
|
||||
// 检查是否为垂直线
|
||||
if (x2 == x1)
|
||||
x2 += 0.001f;
|
||||
m = (y2 - y1) / (x2 - x1);
|
||||
A = m, B = -1, C = y1 - m * x1;
|
||||
|
||||
if (x2_next == x1_next)
|
||||
x2_next += 0.001f;
|
||||
m_next = (y2_next - y1_next) / (x2_next - x1_next);
|
||||
A_next = m_next, B_next = -1, C_next = y1_next - m_next * x1_next;
|
||||
|
||||
// 检查是否平行(理论上不会)
|
||||
if (A * B_next == A_next * B)
|
||||
continue;
|
||||
|
||||
// 计算交点
|
||||
x_p = (B_next * C - B * C_next) / (A_next * B - A * B_next);
|
||||
y_p = (A * x_p + C) / -B;
|
||||
|
||||
// 确保交点在图像范围内
|
||||
if (0 <= int(x_p) && int(x_p) <= im.cols && 0 <= int(y_p) && int(y_p) < im.rows)
|
||||
sort_conners4[(i + 1) % 4] = { x_p, y_p };
|
||||
}
|
||||
|
||||
return sort_conners4;
|
||||
}
|
||||
|
||||
|
||||
static int GetSortConnersAndEdgess(
|
||||
cv::Mat& src,
|
||||
std::vector<std::vector<float>>& sort_lines4,
|
||||
std::vector<std::vector<float>>& sort_conners4,
|
||||
int thresh_hold = 80,
|
||||
int minLineLength = 400)
|
||||
{
|
||||
int ret = CAL_OK;
|
||||
|
||||
if (G(conners_detect_fake) == "true")
|
||||
{
|
||||
sort_conners4.push_back({ 465,436 });
|
||||
sort_conners4.push_back({ 615, 260 });
|
||||
sort_conners4.push_back({ 783, 405 });
|
||||
sort_conners4.push_back({ 630, 581 });
|
||||
for (int i = 0; i < sort_conners4.size(); ++i)
|
||||
sort_conners4[i] = {
|
||||
float(sort_conners4[i][0] * 9344 / 934 / 1.5),
|
||||
float(sort_conners4[i][1] * 7000 / 700 / 1.5) };
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::chrono::high_resolution_clock::time_point m_start = std::chrono::high_resolution_clock::now();
|
||||
|
||||
cv::Mat gray;
|
||||
cv::cvtColor(src, gray, cv::COLOR_BGR2GRAY);
|
||||
cv::GaussianBlur(gray, gray, cv::Size(5, 5), 0, 0);
|
||||
gray = Sobel(gray, 0.0, 0.0);
|
||||
cv::Mat mask;
|
||||
cv::threshold(gray, mask, 5, 255, cv::THRESH_BINARY);
|
||||
|
||||
float PI = 3.1415926f;
|
||||
std::vector<cv::Vec4f> lines;
|
||||
cv::HoughLinesP(mask, lines, 1, PI / 180, thresh_hold, minLineLength, G(edge_max_line_gap));
|
||||
|
||||
float x1, y1, x2, y2, theta, r, m;
|
||||
float A, B, C;
|
||||
bool bRepeat = false;
|
||||
float cx, cy, d, r_max;
|
||||
std::vector<std::vector<float>> _line4; // 上、右、下、左四条线
|
||||
//for (int i = 0; i < _line4.size(); ++i) {
|
||||
// _line4[i].resize(6); // x1, y1, x2, y2, theta, r
|
||||
//}
|
||||
for (int l = 0; l < lines.size(); ++l)
|
||||
{
|
||||
cv::Vec4f _line = lines[l];
|
||||
x1 = _line[0];
|
||||
y1 = _line[1];
|
||||
x2 = _line[2];
|
||||
y2 = _line[3];
|
||||
|
||||
// 计算极坐标
|
||||
if (x1 == x2)
|
||||
x2 += 0.001f;
|
||||
theta = atan((y2 - y1) / (x2 - x1)) * (180 / PI);
|
||||
r = sqrt(pow((y2 - y1), 2) + pow((x2 - x1), 2));
|
||||
|
||||
// 计算直线的斜率(如果 1 ≠ 2),待优化
|
||||
m = (y2 - y1) / (x2 - x1);
|
||||
A = m;
|
||||
B = -1;
|
||||
C = y1 - m * x1;
|
||||
|
||||
// 查找符合条件的直线边缘
|
||||
bRepeat = false;
|
||||
for (int i = 0; i < _line4.size(); ++i)
|
||||
{
|
||||
if (abs(abs(theta) - abs(_line4[i][4])) < G(edge_min_angle_th)) // 33°
|
||||
{
|
||||
cx = (_line4[i][2] + _line4[i][0]) / 2;
|
||||
cy = (_line4[i][3] + _line4[i][1]) / 2;
|
||||
|
||||
// 中点到目标线的垂线小于系数,选择 r 较长的作为边缘
|
||||
d = abs(A * cx + B * cy + C) / sqrt(pow(A, 2) + pow(B, 2));
|
||||
r_max = _line4[i][5] > r ? _line4[i][5] : r;
|
||||
if (d < r_max / 3)
|
||||
{
|
||||
bRepeat = true;
|
||||
if (r > _line4[i][5])
|
||||
{
|
||||
std::vector<float> v;
|
||||
v.resize(6);
|
||||
v = { x1, y1, x2, y2, theta, r };
|
||||
_line4[i] = v;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!bRepeat)
|
||||
{
|
||||
std::vector<float> v;
|
||||
v.resize(6);
|
||||
v = { x1, y1, x2, y2, theta, r };
|
||||
_line4.push_back(v);
|
||||
}
|
||||
}
|
||||
|
||||
Loger(LEVEL_INFOR, "_line4.size() < 4 is %d", _line4.size());
|
||||
if (_line4.size() < 4)
|
||||
{
|
||||
return CAL_INNER_COONERS_ISNOT_4;
|
||||
}
|
||||
|
||||
|
||||
sort_lines4 = SortLines(_line4);
|
||||
if (sort_lines4.size() != 4)
|
||||
assert(0);
|
||||
sort_conners4 = GetIntersections(src, sort_lines4);
|
||||
if (sort_conners4.size() != 4)
|
||||
assert(0);
|
||||
|
||||
std::chrono::high_resolution_clock::time_point m_end = std::chrono::high_resolution_clock::now();
|
||||
std::chrono::duration<double> elapsex = m_end - m_start;
|
||||
std::cout << "Cal3D static GetSortConnersAndEdgess time is : " << elapsex.count() << std::endl;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static std::vector<std::vector<float>> UpdateConners(std::vector<std::vector<float>>& sort_conners4)
|
||||
{
|
||||
std::vector<std::vector<float>> sort_conners4_new(4);
|
||||
|
||||
return sort_conners4_new;
|
||||
}
|
||||
|
||||
static void delay_second(double second)
|
||||
{
|
||||
clock_t start_time;
|
||||
start_time = clock();
|
||||
for (; (clock() - start_time) < second * CLOCKS_PER_SEC;);
|
||||
}
|
||||
|
||||
|
||||
//广角摄像机和高清相机图像映射
|
||||
int Cal2D::LibapiGet2D2DMapRect(cv::Mat& dst_im, bool fake, std::string fakeFilePath)
|
||||
{
|
||||
int ret = CAL_OK;
|
||||
|
||||
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
//读取广角相机图像
|
||||
int Cal2D::LibapiCapLQImage(cv::Mat& dst_im)
|
||||
{
|
||||
int ret = CAL_OK;
|
||||
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
//采集高清图像
|
||||
static int camera_idxx = 0;
|
||||
int Cal2D::LibapiCapHQImage(CMeasureInfo* measureInfoPtr, std::shared_ptr<cv::Mat>& dst_im)
|
||||
{
|
||||
int ret = CAL_OK;
|
||||
if (G(camera_cap_fake) == "true")
|
||||
{
|
||||
if (G(fake_image_fpath) == "")
|
||||
assert(0);
|
||||
else
|
||||
{
|
||||
// 读取fake文件,获取点云数据
|
||||
ret = LibapiReadHQImage(G(fake_image_fpath), *dst_im);
|
||||
if (ret != CAL_OK)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
if (dst_im->empty())
|
||||
{
|
||||
return CAL_READFILE_FAILED;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
while (atomic_lock.test_and_set(std::memory_order_acquire)) {}
|
||||
if (camera_idxx == 0)
|
||||
{
|
||||
//等待初始化
|
||||
ret = CCameraHelper::Get()->Init();
|
||||
Loger(LEVEL_INFOR, "CCameraHelper::Get()->Init() ret is %d", ret);
|
||||
ret = CCameraHelper::Get()->Start(G(export_time) * 10000);
|
||||
Loger(LEVEL_INFOR, "CCameraHelper::Get()->Start() ret is %d", ret);
|
||||
camera_idxx = 1;
|
||||
}
|
||||
// cap camera
|
||||
/*CCameraHelper::Get()->Start();*/
|
||||
int times = 3;
|
||||
while (true)
|
||||
{
|
||||
void* pData = (void*)(dst_im.get()->data);
|
||||
int w, h;
|
||||
ret = CCameraHelper::Get()->Cap((void**) & pData, w, h, 5000);
|
||||
Loger(LEVEL_INFOR, "Capture Image times : %d", 3 - times +1);
|
||||
if (ret == 0)
|
||||
{
|
||||
Loger(LEVEL_INFOR, "Capture Image sucess!");
|
||||
break;
|
||||
}
|
||||
delay_second(1.5);
|
||||
times--;
|
||||
if (times == 0)
|
||||
{
|
||||
Loger(LEVEL_INFOR, "Capture Image faild!");
|
||||
//CCameraHelper::Get()->Stop();
|
||||
//CCameraHelper::Get()->Init();
|
||||
//CCameraHelper::Get()->Start();
|
||||
return CAL_2D_CAP_IMAGE_FAILED;
|
||||
}
|
||||
}
|
||||
atomic_lock.clear(std::memory_order_release);
|
||||
//CCameraHelper::Get()->Stop();
|
||||
}
|
||||
measureInfoPtr->SetIm(dst_im);
|
||||
return ret;
|
||||
}
|
||||
|
||||
//从文件读取高清图像
|
||||
int Cal2D::LibapiReadHQImage(const std::string plyPath, cv::Mat& dst_im)
|
||||
{
|
||||
int ret = CAL_OK;
|
||||
|
||||
dst_im = cv::imread(plyPath, cv::IMREAD_UNCHANGED);
|
||||
|
||||
if (dst_im.empty())
|
||||
{
|
||||
Loger(LEVEL_INFOR, "dst_im.empty() dst_im : %s", plyPath.c_str());
|
||||
return CAL_PRAMA_EMPUTY;
|
||||
//assert(0);
|
||||
}
|
||||
|
||||
Loger(LEVEL_INFOR, "Image read success: %s", plyPath.c_str());
|
||||
return ret;
|
||||
}
|
||||
|
||||
//保存高清图像
|
||||
int Cal2D::LibapiCopyHQImage(cv::Mat& src_im, cv::Mat& dst_im)
|
||||
{
|
||||
int ret = CAL_OK;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
//图像去畸变
|
||||
int Cal2D::LibapiUndistort(cv::Mat& src_im, cv::Mat& dst_im)
|
||||
{
|
||||
int ret = CAL_OK;
|
||||
|
||||
cv::Mat cameraMatrix = (cv::Mat_<double>(3, 3) << G(fx), 0, G(cx), 0, G(fy), G(cy), 0, 0, 1);
|
||||
cv::Mat distCoeffs = (cv::Mat_<double>(1, 5) << G(k1), G(k2), G(p1), G(p2), G(k3));
|
||||
cv::undistort(src_im, dst_im, cameraMatrix, distCoeffs);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
//持续采集广角图像(PYTHON)
|
||||
//AI识别广角图像中的预埋件,返回其ROI坐标
|
||||
//待优化
|
||||
static int idxx = 0;
|
||||
int Cal2D::LibapiDetectObj(CMeasureInfo* measureInfo)
|
||||
{
|
||||
int ret = CAL_OK;
|
||||
|
||||
if (G(npu_fake) == "true")
|
||||
{
|
||||
std::shared_ptr<CSubRoi> subRoi1Ptr = std::make_shared<CSubRoi>();
|
||||
// 待修改
|
||||
subRoi1Ptr->mRoiPoints.push_back({ 465,436 });
|
||||
subRoi1Ptr->mRoiPoints.push_back({ 615, 260 });
|
||||
subRoi1Ptr->mRoiPoints.push_back({ 783, 405 });
|
||||
subRoi1Ptr->mRoiPoints.push_back({ 630, 581 });
|
||||
for (int i = 0; i < subRoi1Ptr->mInnerConners.size(); ++i)
|
||||
subRoi1Ptr->mInnerConners[i] = {
|
||||
float(subRoi1Ptr->mInnerConners[i].x * 9344 / 934 / 1.5),
|
||||
float(subRoi1Ptr->mInnerConners[i].y * 7000 / 700 / 1.5) };
|
||||
std::shared_ptr<CSubRoi> subRoi2Ptr = std::make_shared<CSubRoi>();
|
||||
subRoi2Ptr->mRoiPoints.push_back({ 465,436 });
|
||||
subRoi2Ptr->mRoiPoints.push_back({ 615, 260 });
|
||||
subRoi2Ptr->mRoiPoints.push_back({ 783, 405 });
|
||||
subRoi2Ptr->mRoiPoints.push_back({ 630, 581 });
|
||||
for (int i = 0; i < subRoi2Ptr->mInnerConners.size(); ++i)
|
||||
subRoi2Ptr->mInnerConners[i] = {
|
||||
float(subRoi2Ptr->mInnerConners[i].x * 9344 / 934 / 1.5),
|
||||
float(subRoi2Ptr->mInnerConners[i].y * 7000 / 700 / 1.5) };
|
||||
std::shared_ptr<CSubRoi> subRoi3Ptr = std::make_shared<CSubRoi>();
|
||||
subRoi3Ptr->mRoiPoints.push_back({ 465,436 });
|
||||
subRoi3Ptr->mRoiPoints.push_back({ 615, 260 });
|
||||
subRoi3Ptr->mRoiPoints.push_back({ 783, 405 });
|
||||
subRoi3Ptr->mRoiPoints.push_back({ 630, 581 });
|
||||
for (int i = 0; i < subRoi3Ptr->mInnerConners.size(); ++i)
|
||||
subRoi3Ptr->mInnerConners[i] = {
|
||||
float(subRoi3Ptr->mInnerConners[i].x * 9344 / 934 / 1.5),
|
||||
float(subRoi3Ptr->mInnerConners[i].y * 7000 / 700 / 1.5) };
|
||||
|
||||
measureInfo->GetSubRois().push_back(subRoi1Ptr);
|
||||
measureInfo->GetSubRois().push_back(subRoi2Ptr);
|
||||
measureInfo->GetSubRois().push_back(subRoi3Ptr);
|
||||
}
|
||||
else
|
||||
{
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
if (idxx == 0)
|
||||
{
|
||||
// 待优化
|
||||
// init sig
|
||||
ret = CYolov5For928::Get()->pfucLibapiSvpNpuHandleSig();
|
||||
if (ret != RST_OK)
|
||||
{
|
||||
assert(0);
|
||||
return ret;
|
||||
}
|
||||
// init acl
|
||||
ret = CYolov5For928::Get()->pfucLibapiSvpNpuAclPrepareInit();
|
||||
if (ret != RST_OK)
|
||||
{
|
||||
assert(0);
|
||||
return ret;
|
||||
}
|
||||
|
||||
// init model
|
||||
const char* om_model_path = G(yolo_modol_path).c_str();
|
||||
ret = CYolov5For928::Get()->pfucLibApiSvpNpuLoadModel(om_model_path, 0, false);
|
||||
if (ret != RST_OK)
|
||||
{
|
||||
assert(0);
|
||||
return ret;
|
||||
}
|
||||
idxx = 1;
|
||||
}
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
cv::Mat* hq_im = measureInfo->GetIm().get();
|
||||
// run yolo model to detect
|
||||
ret = CYolov5For928::Get()->pfucLibApiSvpNpuLoadDataset(0, (void*)hq_im->data, hq_im->total() * hq_im->channels(),
|
||||
hq_im->size().width , hq_im->size().height , CV_8UC3);
|
||||
if (ret != CAL_OK)
|
||||
{
|
||||
Loger(LEVEL_INFOR, " CYolov5For928::Get()->pfucLibApiSvpNpuLoadDataset() has error %d" , ret);
|
||||
Loger(LEVEL_INFOR, " w: %d h : %d ch : %d", hq_im->size().width, hq_im->size().height, hq_im->channels());
|
||||
return CAL_NPU_LOAD_DATASET_FAILED;
|
||||
}
|
||||
Loger(LEVEL_INFOR, " CYolov5For928::Get()->pfucLibApiSvpNpuLoadDataset() success");
|
||||
ret = CYolov5For928::Get()->pfucLibApiSvpNpuModelExecute(0);
|
||||
if (ret != CAL_OK)
|
||||
{
|
||||
CYolov5For928::Get()->pfucLibApiSvpNpuUnloadDataset();
|
||||
Loger(LEVEL_INFOR, " CYolov5For928::Get()->pfucLibApiSvpNpuModelExecute() has error %d", ret);
|
||||
return CAL_NPU_MODEL_EXE_FAILED;
|
||||
}
|
||||
Loger(LEVEL_INFOR, " CYolov5For928::Get()->pfucLibApiSvpNpuModelExecute() success");
|
||||
RetrunObject objs;
|
||||
ret = CYolov5For928::Get()->pfucLibApiSvpNpuGetModelExecuteResult(0, &objs);
|
||||
if (ret != CAL_OK)
|
||||
{
|
||||
CYolov5For928::Get()->pfucLibApiSvpNpuUnloadDataset();
|
||||
Loger(LEVEL_INFOR, " CYolov5For928::Get()->pfucLibApiSvpNpuGetModelExecuteResult() has error %d", ret);
|
||||
return CAL_NPU_GET_RESULT_FAILED;
|
||||
}
|
||||
Loger(LEVEL_INFOR, "pfucLibApiSvpNpuGetModelExecuteResult objs.count = %d", objs.count);
|
||||
if (objs.count == 0)
|
||||
{
|
||||
Loger(LEVEL_INFOR, " pfucLibApiSvpNpuGetModelExecuteResult() objs.count == 0");
|
||||
}
|
||||
else if (objs.count > 128)
|
||||
{
|
||||
Loger(LEVEL_INFOR, " pfucLibApiSvpNpuGetModelExecuteResult() objs.count > 128");
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < objs.count; ++i)
|
||||
{
|
||||
std::cout << " label: " << G(yolo_label) << " - " << objs.objects[i].label
|
||||
<< " prob: " << G(yolo_prob) << " - " << objs.objects[i].prob << std::endl;
|
||||
if (objs.objects[i].label == (int)G(yolo_label) && objs.objects[i].prob > (float)G(yolo_prob))
|
||||
{
|
||||
std::shared_ptr<CSubRoi> subRoi1Ptr = std::make_shared<CSubRoi>();
|
||||
//subRoi1Ptr->mRoiPoints.push_back({ (float)(objs.objects[i].x - 20), (float)(objs.objects[i].y + G(roi_y_offset) - 20) });
|
||||
//subRoi1Ptr->mRoiPoints.push_back({ (float)(objs.objects[i].x + 20 + (float)objs.objects[i].width), (float)(objs.objects[i].y + G(roi_y_offset) - 20) });
|
||||
//subRoi1Ptr->mRoiPoints.push_back({ (float)(objs.objects[i].x + 20 + (float)objs.objects[i].width), (float)(objs.objects[i].y + objs.objects[i].height + G(roi_y_offset) + 20) });
|
||||
//subRoi1Ptr->mRoiPoints.push_back({ (float)(objs.objects[i].x - 20), (float)(objs.objects[i].y + objs.objects[i].height + G(roi_y_offset) + 20) });
|
||||
subRoi1Ptr->mRoiPoints.push_back({ (float)(objs.objects[i].x - 2), (float)(objs.objects[i].y + G(roi_y_offset) - 2) });
|
||||
subRoi1Ptr->mRoiPoints.push_back({ (float)(objs.objects[i].x + 2 + (float)objs.objects[i].width), (float)(objs.objects[i].y + G(roi_y_offset) - 2) });
|
||||
subRoi1Ptr->mRoiPoints.push_back({ (float)(objs.objects[i].x + 2 + (float)objs.objects[i].width), (float)(objs.objects[i].y + objs.objects[i].height + G(roi_y_offset) + 2) });
|
||||
subRoi1Ptr->mRoiPoints.push_back({ (float)(objs.objects[i].x - 2), (float)(objs.objects[i].y + objs.objects[i].height + G(roi_y_offset) + 2) });
|
||||
|
||||
for (int j = 0; j < 4; ++j)
|
||||
{
|
||||
if (subRoi1Ptr->mRoiPoints[j].x < 0)
|
||||
subRoi1Ptr->mRoiPoints[j].x = 0;
|
||||
if (subRoi1Ptr->mRoiPoints[j].x > hq_im->cols)
|
||||
subRoi1Ptr->mRoiPoints[j].x = hq_im->cols;
|
||||
if (subRoi1Ptr->mRoiPoints[j].y < 0)
|
||||
subRoi1Ptr->mRoiPoints[j].y = 0;
|
||||
if (subRoi1Ptr->mRoiPoints[j].y > hq_im->rows)
|
||||
subRoi1Ptr->mRoiPoints[j].y = hq_im->rows;
|
||||
}
|
||||
measureInfo->GetSubRois().push_back(subRoi1Ptr);
|
||||
|
||||
if (measureInfo->GetSubRois().size() == 16)
|
||||
{
|
||||
Loger(LEVEL_INFOR, "[ERROR] pfucLibApiSvpNpuGetModelExecuteResult() objs.count > 16");
|
||||
}
|
||||
else
|
||||
{
|
||||
Loger(LEVEL_INFOR, "measureInfo->GetSubRois().size() is %d", measureInfo->GetSubRois().size());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
ret = CYolov5For928::Get()->pfucLibApiSvpNpuUnloadDataset();
|
||||
if (ret != CAL_OK)
|
||||
{
|
||||
Loger(LEVEL_INFOR, " CYolov5For928::Get()->pfucLibApiSvpNpuUnloadDataset() has error %d", ret);
|
||||
return CAL_NPU_UNLOAD_DATASET_FAILED;
|
||||
}
|
||||
|
||||
// 待优化
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//ret = CYolov5For928::Get()->pfucLibApiSvpNpuUnLoadModel(0);
|
||||
//ret = CYolov5For928::Get()->pfucLibApiSvpNpuAclPrepareExit();
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
Loger(LEVEL_INFOR, "LibApiSvpNpuModelExecute success");
|
||||
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
//通过一组ROI坐标获取ROI图像(弃用)
|
||||
//id: parentId
|
||||
int Cal2D::LibapiGetSubImFromRois(cv::Mat& im, const int& id, const std::string& info,
|
||||
std::vector<cv::Rect2f> rois, std::vector<CSubRoi>& subMat, bool fake)
|
||||
{
|
||||
if (im.empty() || rois.size() == 0)
|
||||
{
|
||||
Loger(LEVEL_INFOR, "im.empty() || rois.size() == 0");
|
||||
return CAL_2D_ROI_DETECTIION_IS_0;
|
||||
//assert(0);
|
||||
}
|
||||
|
||||
int ret = CAL_OK;
|
||||
|
||||
for (int i = 0; i < rois.size(); i++)
|
||||
{
|
||||
CSubRoi mat;
|
||||
//mat
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
//在单个预埋件图像中计算区域内预埋件边缘和角点
|
||||
int Cal2D::LibapiGetEdegsAndConners(cv::Mat& src,
|
||||
std::vector<std::vector<float>>& sort_lines4,
|
||||
std::vector<std::vector<float>>& sort_conners4)
|
||||
{
|
||||
return GetSortConnersAndEdgess(
|
||||
src,
|
||||
sort_lines4,
|
||||
sort_conners4,
|
||||
80,
|
||||
G(edge_min_line_len));
|
||||
}
|
||||
|
||||
// 挑选出的内在区域(亚像素检测算法)
|
||||
int Cal2D::LibapiSelectInnerRegion(CSubRoi& subMat)
|
||||
{
|
||||
int ret = CAL_OK;
|
||||
if (subMat.mRoiPoints.size() != 4)
|
||||
assert(0);
|
||||
|
||||
if (subMat.mRoiPoints.size() != 4)
|
||||
assert(0);
|
||||
return ret;
|
||||
}
|
||||
|
||||
// 挑选出2D-3D点对用于计算单应矩阵H
|
||||
int Cal2D::LibapiSelect2DTo3DPoints(CMeasureInfo& measureInfo, CSubRoi& subRoi,
|
||||
std::vector<cv::Point2f>& vec2D, std::vector<cv::Point3f>& vec3D)
|
||||
{
|
||||
// 该函数弃用
|
||||
assert(0);
|
||||
if (measureInfo.GetIm()->empty() || subRoi.mInnerConners.size() != 4)
|
||||
assert(0);
|
||||
|
||||
int ret = CAL_OK;
|
||||
|
||||
std::chrono::high_resolution_clock::time_point m_start = std::chrono::high_resolution_clock::now();
|
||||
// 待修改,在roi中遍历
|
||||
float* hptr;
|
||||
cv::Mat *im_2D3D = measureInfo.GetIm().get();
|
||||
int ch = im_2D3D->channels();
|
||||
for (int h = 0; h < im_2D3D->rows; ++h)
|
||||
{
|
||||
hptr = (float*)im_2D3D->ptr<float>(h);
|
||||
for (int w = 0; w < im_2D3D->cols; ++w)
|
||||
{
|
||||
// 待优化
|
||||
if (hptr[w * ch + 2] >= 3.5)
|
||||
{
|
||||
cv::Point2f p2 = { (float)w, (float)h };
|
||||
if (cv::pointPolygonTest(subRoi.mInnerConners, p2, false))
|
||||
{
|
||||
cv::Point3f v3 = { hptr[w * ch], hptr[w * ch + 1], hptr[w * ch + 2] };
|
||||
vec2D.push_back(p2);
|
||||
vec3D.push_back(v3);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (vec2D.size() < 2000)
|
||||
assert(0);
|
||||
|
||||
std::cout << vec2D.size() << std::endl;
|
||||
std::cout << vec3D.size() << std::endl;
|
||||
std::chrono::high_resolution_clock::time_point m_end = std::chrono::high_resolution_clock::now();
|
||||
std::chrono::duration<double> elapsex = m_end - m_start;
|
||||
std::cout << "Cal2D::LibapiSelect2DTo3DPoints time is : " << elapsex.count() << std::endl;
|
||||
return ret;
|
||||
}
|
||||
|
||||
// 计算单应矩阵
|
||||
int Cal2D::LibapiCalH(const std::vector<cv::Point2f>& vec2D, const std::vector<cv::Point3f>& vec3D, cv::Mat& H)
|
||||
{
|
||||
if (vec2D.size() == 0 || vec3D.size() == 0)
|
||||
{
|
||||
Loger(LEVEL_INFOR, "vec2D.size() == 0 || vec3D.size() == 0");
|
||||
return CAL_PRAMA_EMPUTY;
|
||||
//assert(0);
|
||||
}
|
||||
|
||||
int ret = CAL_OK;
|
||||
|
||||
std::chrono::high_resolution_clock::time_point m_start = std::chrono::high_resolution_clock::now();
|
||||
|
||||
float ransacReprojThreshold = 5.0;
|
||||
std::vector<cv::Point3f> vp3;
|
||||
for (int i = 0; i < vec2D.size(); ++i)
|
||||
{
|
||||
cv::Point3f p3 = { vec2D[i].x, vec2D[i].y, 1 };
|
||||
vp3.push_back(p3);
|
||||
}
|
||||
|
||||
H = cv::findHomography(vec3D, vp3, cv::RANSAC, ransacReprojThreshold);
|
||||
std::cout << H << std::endl;
|
||||
std::chrono::high_resolution_clock::time_point m_end = std::chrono::high_resolution_clock::now();
|
||||
std::chrono::duration<double> elapsex = m_end - m_start;
|
||||
std::cout << "Cal2D::LibapiCalH time is : " << elapsex.count() << std::endl;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
// 计算预埋件角点和中心位置
|
||||
int Cal2D::LibapiCalScale(const CSubRoi& subConner, int H)
|
||||
{
|
||||
int ret = CAL_OK;
|
||||
|
||||
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static CMeasureInfo* fake_create2D3D()
|
||||
{
|
||||
int ret = CAL_OK;
|
||||
|
||||
utility::SetVerbosityLevel(utility::VerbosityLevel::Debug);
|
||||
|
||||
auto cloud_ptr = std::make_shared<geometry::PointCloud>();
|
||||
auto cloud_ptr_by_dist = std::make_shared<geometry::PointCloud>();
|
||||
auto cloud_ptr_by_correct = std::make_shared<geometry::PointCloud>();
|
||||
|
||||
ret = Cal3D::LibapiCapCloudPoints(cloud_ptr);
|
||||
if (ret != CAL_OK) assert(0);
|
||||
|
||||
ret = Cal3D::LibapiRotAndTrans(cloud_ptr);
|
||||
|
||||
ret = Cal3D::LibapiFilterCloudPointsByDist(cloud_ptr, cloud_ptr_by_dist,
|
||||
G(dminx), G(dmaxx), G(dminy), G(dmaxy), G(dminz), G(dmaxz));
|
||||
if (ret != CAL_OK) assert(0);
|
||||
if (cloud_ptr_by_dist->IsEmpty()) assert(0);
|
||||
|
||||
ret = Cal3D::LibapiCorrectCloudPoint(cloud_ptr_by_dist, cloud_ptr_by_correct, 0);
|
||||
|
||||
std::vector<cv::Point3d> vec_point_3d;
|
||||
ret = Cal3D::LibapiCloudPointToVec(cloud_ptr_by_correct, vec_point_3d);
|
||||
|
||||
cv::Mat cameraMatrix = (cv::Mat_<double>(3, 3) << G(fx), 0, G(cx), 0, G(fy), G(cy), 0, 0, 1);
|
||||
std::vector<cv::Point2d> vec_point_2d;
|
||||
//cv::Mat test_src_im = cv::imread("output.png");
|
||||
cv::Mat test_src_im;
|
||||
|
||||
//cv::Mat test_src_im;
|
||||
std::shared_ptr<cv::Mat> im_2D3D = std::make_shared<cv::Mat>(cv::Size(G(w), G(h)), CV_32FC3);
|
||||
im_2D3D->setTo(cv::Scalar(0, 0, 0)); // 设置为全黑背景
|
||||
ret = Cal3D::LibapiCloudPointsPorject(vec_point_3d, cameraMatrix, vec_point_2d, im_2D3D.get(), false, test_src_im);
|
||||
|
||||
// for test
|
||||
ret = Cal3D::LibapiCloudPointProjectTest(*im_2D3D);
|
||||
//cv::FileStorage file("d:\\im_2D3D.yml", cv::FileStorage::WRITE);
|
||||
//std::string tag = "im_2D3D";
|
||||
//file << tag << *im_2D3D;
|
||||
//file.release();
|
||||
|
||||
// 创建CMeasureInfo数据结构
|
||||
long id;
|
||||
ret = CalUtils::LibapiGenRandomId(id);
|
||||
std::string info = "abc";
|
||||
|
||||
//std::shared_ptr<CMeasureInfo> measureInfoPtr = std::make_shared<CMeasureInfo>(id, info, im_2D3D);
|
||||
CMeasureInfo* measureInfoPtr = CMeasureInfo::Init(id, info);
|
||||
measureInfoPtr->SetIm2D3D(im_2D3D);
|
||||
|
||||
return measureInfoPtr;
|
||||
}
|
||||
|
||||
//int main()
|
||||
//{
|
||||
// G(fx);
|
||||
// int ret = CAL_OK;
|
||||
//
|
||||
// std::shared_ptr<cv::Mat> hqImPtr = std::make_shared<cv::Mat>();
|
||||
//
|
||||
// *hqImPtr = cv::imread("./caowei/fe57022fa2c58888.jpg");
|
||||
//
|
||||
// std::vector<std::vector<float>> sort_lines4;
|
||||
// std::vector<std::vector<float>> sort_conners4;
|
||||
//
|
||||
// cv::Mat hq_im_cp = hqImPtr->clone();
|
||||
// GetSortConnersAndEdgess(
|
||||
// hq_im_cp,
|
||||
// sort_lines4,
|
||||
// sort_conners4,
|
||||
// 80,
|
||||
// 100);
|
||||
//
|
||||
// float x1, y1, x2, y2;
|
||||
// float x_p, y_p;
|
||||
//
|
||||
// for (int i = 0; i < 4; ++i)
|
||||
// {
|
||||
// std::vector<float> line = sort_lines4[i];
|
||||
// x1 = line[0], y1 = line[1], x2 = line[2], y2 = line[3];
|
||||
// std::vector<float> conners = sort_conners4[i];
|
||||
// x_p = conners[0], y_p = conners[1];
|
||||
//
|
||||
// cv::circle(*hqImPtr, cv::Point(int(x_p), int(y_p)), 2, cv::Scalar(0, 0, 255), -1);
|
||||
// cv::line(*hqImPtr, cv::Point(int(x1), int(y1)), cv::Point(int(x2), int(y2)), cv::Scalar(0,255, 0), 1);
|
||||
// }
|
||||
//
|
||||
// cv::imshow("im_edge", *hqImPtr);
|
||||
// cv::waitKey(0);
|
||||
//
|
||||
// // 拍摄照片
|
||||
// CMeasureInfo* measureInfoPtr = CMeasureInfo::Init(1, "");
|
||||
// ret = Cal2D::LibapiCapHQImage(measureInfoPtr, hqImPtr);
|
||||
// if (ret != CAL_OK || hqImPtr->empty())
|
||||
// assert(0);
|
||||
//
|
||||
//
|
||||
// // AI识别划分ROI
|
||||
// //std::vector<cv::Rect2f> rois;
|
||||
// //ret = Cal2D::LibapiDetectObj(hq_im, rois, true);
|
||||
// //if (ret != CAL_OK || rois.size()==0)
|
||||
// // assert(0);
|
||||
// measureInfoPtr = fake_create2D3D();
|
||||
// std::shared_ptr<CSubRoi> subRoi = std::make_shared<CSubRoi>();
|
||||
// measureInfoPtr->GetSubRois().push_back(subRoi);
|
||||
//
|
||||
// subRoi->mInnerConners.push_back({ 465,436 });
|
||||
// subRoi->mInnerConners.push_back( { 615, 260 } );
|
||||
// subRoi->mInnerConners.push_back({ 783, 405 } );
|
||||
// subRoi->mInnerConners.push_back( { 630, 581 } );
|
||||
// for (int i = 0; i < subRoi->mInnerConners.size(); ++i)
|
||||
// subRoi->mInnerConners[i] = {
|
||||
// float(subRoi->mInnerConners[i].x * 9344 / 934 / 1.5),
|
||||
// float(subRoi->mInnerConners[i].y * 7000 / 700 / 1.5)};
|
||||
// std::vector<cv::Point2f> vec2D;
|
||||
// std::vector<cv::Point3f> vec3D;
|
||||
//
|
||||
// //ret = Cal2D::LibapiSelect2DTo3DPoints(*measureInfoPtr, *subRoi, vec2D, vec3D);
|
||||
//
|
||||
// cv::Mat H;
|
||||
// //ret = Cal2D::LibapiCalH(vec2D, vec3D, H);
|
||||
//
|
||||
// // 开多线程分发ROI进行识别
|
||||
//
|
||||
//
|
||||
// return 0;
|
||||
//}
|
56
image_framework/algorithm/Libapi2d.h
Executable file
56
image_framework/algorithm/Libapi2d.h
Executable file
@ -0,0 +1,56 @@
|
||||
#ifndef LIBAPI_2D_H
|
||||
#define LIBAPI_2D_H
|
||||
|
||||
#include "Libapi2D3D.h"
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <opencv2/opencv.hpp>
|
||||
|
||||
class Cal2D
|
||||
{
|
||||
public:
|
||||
//广角摄像机和高清相机图像映射
|
||||
static int LibapiGet2D2DMapRect(cv::Mat& dst_im, bool fake = true, std::string fakeFilePath = "");
|
||||
|
||||
//读取广角相机图像
|
||||
static int LibapiCapLQImage(cv::Mat& dst_im);
|
||||
|
||||
//读取高清图像
|
||||
static int LibapiCapHQImage(CMeasureInfo* measureInfoPtr, std::shared_ptr<cv::Mat>& dst_im);
|
||||
|
||||
//从文件读取高清图像
|
||||
static int LibapiReadHQImage(const std::string plyPath, cv::Mat& dst_im);
|
||||
|
||||
//保存高清图像
|
||||
static int LibapiCopyHQImage(cv::Mat& src_im, cv::Mat& dst_im);
|
||||
|
||||
//图像去畸变
|
||||
static int LibapiUndistort(cv::Mat& src_im, cv::Mat& dst_im);
|
||||
|
||||
//持续采集广角图像(PYTHON)
|
||||
//AI识别广角图像中的预埋件,返回其ROI坐标
|
||||
static int LibapiDetectObj(CMeasureInfo* CMeasureInfo);
|
||||
|
||||
//通过一组ROI坐标获取ROI图像
|
||||
static int LibapiGetSubImFromRois(cv::Mat& im, const int& id, const std::string& info,
|
||||
std::vector<cv::Rect2f> rois, std::vector<CSubRoi>&subMat, bool fake);
|
||||
|
||||
//在单个预埋件图像中计算区域内预埋件边缘和角点
|
||||
static int LibapiGetEdegsAndConners(cv::Mat& src,
|
||||
std::vector<std::vector<float>>& sort_lines4,
|
||||
std::vector<std::vector<float>>& sort_conners4);
|
||||
|
||||
// 挑选出的内在区域
|
||||
static int LibapiSelectInnerRegion(CSubRoi& subMat);
|
||||
|
||||
// 挑选出2D-3D点对用于计算单应矩阵H
|
||||
static int LibapiSelect2DTo3DPoints(CMeasureInfo& CMeasureInfo, CSubRoi& im,
|
||||
std::vector<cv::Point2f>& vec2D, std::vector<cv::Point3f>& vec3D);
|
||||
|
||||
// 计算单应矩阵
|
||||
static int LibapiCalH(const std::vector<cv::Point2f>& vec2D, const std::vector<cv::Point3f>& vec3D, cv::Mat& H);
|
||||
|
||||
// 计算预埋件角点和中心位置
|
||||
static int LibapiCalScale(const CSubRoi& subConner, int H);
|
||||
};
|
||||
#endif
|
762
image_framework/algorithm/Libapi3d.cpp
Executable file
762
image_framework/algorithm/Libapi3d.cpp
Executable file
@ -0,0 +1,762 @@
|
||||
#include "Libapi3d.h"
|
||||
#include "IniHelper.h"
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <cmath>
|
||||
#include <chrono>
|
||||
#include "Log.h"
|
||||
#include "LidarHelper.h"
|
||||
#include "Log.h"
|
||||
#include "LidarHelper.h"
|
||||
|
||||
|
||||
static void delay_second(double second)
|
||||
{
|
||||
clock_t start_time;
|
||||
start_time = clock();
|
||||
for (; (clock() - start_time) < second * CLOCKS_PER_SEC;);
|
||||
}
|
||||
|
||||
#ifndef _WIN32
|
||||
static bool bCouldIsRecv = false;
|
||||
static bool bCouldIsGet = false;
|
||||
static uint32_t need_points_size = 30 * 10000;
|
||||
static float points_data[40 * 10000 * 4];
|
||||
//static uint32_t cur_point_num = 0;
|
||||
static std::atomic<uint32_t> cur_point_num(0);
|
||||
static void GetLidarData(uint8_t handle, LivoxEthPacket* data, uint32_t data_num, void* client_data)
|
||||
{
|
||||
if (data) {
|
||||
/** Parsing the timestamp and the point cloud data. */ uint64_t cur_timestamp = *((uint64_t*)(data->timestamp));
|
||||
if (data->data_type == kCartesian) {
|
||||
LivoxRawPoint* p_point_data = (LivoxRawPoint*)data->data;
|
||||
}
|
||||
else if (data->data_type == kSpherical) {
|
||||
LivoxSpherPoint* p_point_data = (LivoxSpherPoint*)data->data;
|
||||
}
|
||||
else if (data->data_type == kExtendCartesian) {
|
||||
LivoxExtendRawPoint* p_point_data = (LivoxExtendRawPoint*)data->data;
|
||||
#ifdef _WIN32
|
||||
LivoxExtendRawPoint point_array[10 * 10000];
|
||||
#else
|
||||
LivoxExtendRawPoint point_array[data_num];
|
||||
#endif
|
||||
//uint32_t* converted_data = (uint32_t*)malloc(data_num * 4 * sizeof(uint32_t));
|
||||
if (!bCouldIsRecv)
|
||||
{
|
||||
uint32_t _cur_point_num = cur_point_num++;
|
||||
//cur_point_num += data_num;
|
||||
_cur_point_num = _cur_point_num * data_num;
|
||||
need_points_size = G(cloud_need_points_size);
|
||||
uint32_t _offset = _cur_point_num * 4;
|
||||
|
||||
for (uint32_t i = 0; i < data_num; ++i)
|
||||
{
|
||||
_offset = _offset + i * 4;
|
||||
points_data[_offset] = p_point_data[i].x / 1000.0;
|
||||
points_data[_offset + 1] = p_point_data[i].y / 1000.0;
|
||||
points_data[_offset + 2] = p_point_data[i].z / 1000.0;
|
||||
points_data[_offset + 3] = (uint32_t)(p_point_data[i].reflectivity << 8 | p_point_data[i].tag);
|
||||
}
|
||||
|
||||
uint32_t _cur_count = _cur_point_num + data_num;
|
||||
if ((_cur_count % 100000) <= 100)
|
||||
std::cout << _cur_count << " need data size : " << need_points_size << std::endl;
|
||||
if (_cur_count < need_points_size)
|
||||
return;
|
||||
else
|
||||
bCouldIsRecv = true;
|
||||
}
|
||||
else
|
||||
return;
|
||||
|
||||
// 等待点云拷贝结束
|
||||
//__p_point_data = p_point_data;
|
||||
//__data_num = data_num;
|
||||
while (true)
|
||||
{
|
||||
if (!bCouldIsGet)
|
||||
{
|
||||
delay_second(0.01);
|
||||
continue;
|
||||
}
|
||||
cur_point_num = 0;
|
||||
uint32_t* p = (uint32_t*)points_data;
|
||||
memset(p , 0, need_points_size * 4);
|
||||
bCouldIsGet = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (data->data_type == kExtendSpherical) {
|
||||
LivoxExtendSpherPoint* p_point_data = (LivoxExtendSpherPoint*)data->data;
|
||||
}
|
||||
else if (data->data_type == kDualExtendCartesian) {
|
||||
LivoxDualExtendRawPoint* p_point_data = (LivoxDualExtendRawPoint*)data->data;
|
||||
}
|
||||
else if (data->data_type == kDualExtendSpherical) {
|
||||
LivoxDualExtendSpherPoint* p_point_data = (LivoxDualExtendSpherPoint*)data->data;
|
||||
}
|
||||
else if (data->data_type == kImu) {
|
||||
LivoxImuPoint* p_point_data = (LivoxImuPoint*)data->data;
|
||||
}
|
||||
else if (data->data_type == kTripleExtendCartesian) {
|
||||
LivoxTripleExtendRawPoint* p_point_data = (LivoxTripleExtendRawPoint*)data->data;
|
||||
}
|
||||
else if (data->data_type == kTripleExtendSpherical) {
|
||||
LivoxTripleExtendSpherPoint* p_point_data = (LivoxTripleExtendSpherPoint*)data->data;
|
||||
}
|
||||
// printf("data_type %d\n", data->data_type);
|
||||
}
|
||||
}
|
||||
#else
|
||||
/** Extend cartesian coordinate format. */
|
||||
typedef struct {
|
||||
int32_t x; /**< X axis, Unit:mm */
|
||||
int32_t y; /**< Y axis, Unit:mm */
|
||||
int32_t z; /**< Z axis, Unit:mm */
|
||||
uint8_t reflectivity; /**< Reflectivity */
|
||||
uint8_t tag; /**< Tag */
|
||||
} LivoxExtendRawPoint;
|
||||
typedef struct {
|
||||
uint8_t version; /**< Packet protocol version. */
|
||||
uint8_t slot; /**< Slot number used for connecting LiDAR. */
|
||||
uint8_t id; /**< LiDAR id. */
|
||||
uint8_t rsvd; /**< Reserved. */
|
||||
uint32_t err_code; /**< Device error status indicator information. */
|
||||
uint8_t timestamp_type; /**< Timestamp type. */
|
||||
/** Point cloud coordinate format, refer to \ref PointDataType . */
|
||||
uint8_t data_type;
|
||||
uint8_t timestamp[8]; /**< Nanosecond or UTC format timestamp. */
|
||||
uint8_t data[1]; /**< Point cloud data. */
|
||||
} LivoxEthPacket;
|
||||
static bool bCouldIsRecv = false;
|
||||
static bool bCouldIsGet = false;
|
||||
static uint32_t need_points_size = 30 * 10000;
|
||||
static float points_data[40 * 10000];
|
||||
//static uint32_t cur_data_num = 0;
|
||||
static std::atomic<uint32_t> cur_point_num(0);
|
||||
typedef void (*FuncGetLidarData)(uint8_t handle, LivoxEthPacket* data, uint32_t data_num, void* client_data);
|
||||
FuncGetLidarData GetLidarData;
|
||||
#endif // !_WIN32
|
||||
|
||||
|
||||
// 采集点云数据
|
||||
static int lidar_indxx = 0;
|
||||
int Cal3D::LibapiCapCloudPoints(std::shared_ptr<geometry::PointCloud>& cloud_ptr)
|
||||
{
|
||||
int ret = CAL_OK;
|
||||
|
||||
if (G(lidar_cap_fake) == "true")
|
||||
{
|
||||
if (G(fake_lidar_fpath) == "")
|
||||
assert(0);
|
||||
else
|
||||
{
|
||||
// 读取fake文件,获取点云数据
|
||||
ret = LibapiReadCloudPointsPly(G(fake_lidar_fpath), cloud_ptr);
|
||||
if (ret != CAL_OK)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
if (cloud_ptr == nullptr)
|
||||
{
|
||||
return CAL_NONE_PTR;
|
||||
}
|
||||
if (cloud_ptr.get()->points_.size() == 0)
|
||||
{
|
||||
return CAL_3D_CLOUD_POINTS_IS_0;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// cloud_ptr = cap demo ...
|
||||
if (lidar_indxx == 0)
|
||||
{
|
||||
Loger(LEVEL_INFOR, "CLidarHelper::Get()->Init start");
|
||||
ret = CLidarHelper::Get()->Init((void*)GetLidarData);
|
||||
Loger(LEVEL_INFOR, "CLidarHelper::Get()->Init end");
|
||||
if (ret != CAL_OK)
|
||||
{
|
||||
Loger(LEVEL_INFOR, "CLidarHelper::Get()->Init() %d", ret);
|
||||
return ret;
|
||||
}
|
||||
lidar_indxx = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
Loger(LEVEL_INFOR, "CLidarHelper::Get()->Start start");
|
||||
ret = CLidarHelper::Get()->Start();
|
||||
Loger(LEVEL_INFOR, "CLidarHelper::Get()->Start end");
|
||||
if (ret != CAL_OK)
|
||||
{
|
||||
Loger(LEVEL_INFOR, "CLidarHelper::Get()->Start() %d", ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
// 写入点云对象
|
||||
Loger(LEVEL_INFOR, "cloud_ptr.get()->points_. get data start");
|
||||
geometry::PointCloud* pCloud = cloud_ptr.get();
|
||||
// int size = cloud_ptr.get()->points_.size() + __data_num ;
|
||||
// cloud_ptr.get()->points_.resize(size * 3 * sizeof(float));
|
||||
// wait数据
|
||||
while (true)
|
||||
{
|
||||
if (!bCouldIsRecv)
|
||||
{
|
||||
delay_second(0.05);
|
||||
continue;
|
||||
}
|
||||
delay_second(0.01);
|
||||
break;
|
||||
}
|
||||
pCloud->points_.resize(need_points_size);
|
||||
for (uint32_t i = 0; i < need_points_size; ++i) {
|
||||
pCloud->points_[i][0] = points_data[i * 4];
|
||||
pCloud->points_[i][1] = points_data[i * 4 + 1];
|
||||
pCloud->points_[i][2] = points_data[i * 4 + 2];
|
||||
//pCloud->points_.push_back({ (float)point[0], (float)point[1], (float)point[2] });
|
||||
}
|
||||
if (G(save_cload) == "true")
|
||||
{
|
||||
io::WritePointCloud("output.ply", *pCloud);
|
||||
}
|
||||
|
||||
bCouldIsGet = true;
|
||||
delay_second(0.01);
|
||||
bCouldIsRecv = false; //开始接收数据
|
||||
|
||||
Loger(LEVEL_INFOR, "cloud_ptr.get()->points_. get data end, data size is %d", pCloud->points_.size());
|
||||
|
||||
Loger(LEVEL_INFOR, "CLidarHelper::Get()->Stop start");
|
||||
ret = CLidarHelper::Get()->Stop();
|
||||
if (ret != CAL_OK)
|
||||
{
|
||||
Loger(LEVEL_INFOR, "CLidarHelper::Get()->Stop() %d", ret);
|
||||
return ret;
|
||||
}
|
||||
Loger(LEVEL_INFOR, "CLidarHelper::Get()->Stop end");
|
||||
}
|
||||
|
||||
return CAL_OK;
|
||||
}
|
||||
|
||||
// 读取点云数据
|
||||
int Cal3D::LibapiReadCloudPointsPly(const std::string plyPath, std::shared_ptr<geometry::PointCloud>& cloud_ptr)
|
||||
{
|
||||
int ret = CAL_OK;
|
||||
|
||||
cloud_ptr = io::CreatePointCloudFromFile(plyPath);
|
||||
|
||||
/*if (!io::ReadPointCloud(plyPath, *cloud_ptr))*/
|
||||
if (cloud_ptr == nullptr)
|
||||
{
|
||||
Loger(LEVEL_INFOR, "Cal3D::LibapiReadCloudPointsPly Failed to read %s", plyPath.c_str());
|
||||
return CAL_READFILE_FAILED;
|
||||
}
|
||||
|
||||
if (cloud_ptr->IsEmpty())
|
||||
{
|
||||
Loger(LEVEL_INFOR, "cloud_ptr->IsEmpty() cloud_ptr : %s", plyPath.c_str());
|
||||
return CAL_PRAMA_EMPUTY;
|
||||
assert(0);
|
||||
}
|
||||
|
||||
Loger(LEVEL_INFOR, "cloud_ptr read success: %s", plyPath.c_str());
|
||||
return ret;
|
||||
}
|
||||
|
||||
// 保存点云数据
|
||||
int Cal3D::LibapiSaveCloudPointsPly(std::string savaPath, std::shared_ptr<geometry::PointCloud>& cloud_ptr)
|
||||
{
|
||||
if (cloud_ptr->IsEmpty())
|
||||
assert(0);
|
||||
|
||||
int ret = CAL_OK;
|
||||
|
||||
if (!io::WritePointCloud(savaPath, *cloud_ptr))
|
||||
{
|
||||
return CAL_WRITEFILE_FAILED;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
// 点云数据筛选
|
||||
// 按照 point[0],point[1],point[2] = x, y, z
|
||||
int Cal3D::LibapiFilterCloudPointsByDist(std::shared_ptr<geometry::PointCloud>& src_cloud_ptr,
|
||||
std::shared_ptr<geometry::PointCloud>& dst_cloud_ptr, float minusx, float x, float minusy, float y, float minusz, float z)
|
||||
{
|
||||
if (src_cloud_ptr->IsEmpty())
|
||||
assert(0);
|
||||
|
||||
int ret = CAL_OK;
|
||||
|
||||
std::chrono::high_resolution_clock::time_point m_start = std::chrono::high_resolution_clock::now();
|
||||
|
||||
// 遍历点云中的每个点
|
||||
for (int i = 0; i < src_cloud_ptr->points_.size(); ++i) {
|
||||
Eigen::Vector3d point_3d = src_cloud_ptr->points_[i];
|
||||
if (minusx < point_3d.x() && point_3d.x() < x
|
||||
&& minusy < point_3d.y() && point_3d.y() < y
|
||||
&& point_3d.z() < z)
|
||||
{
|
||||
Eigen::Vector3d dst_point_3d = Eigen::Vector3d(point_3d.x(), point_3d.y(), point_3d.z());
|
||||
dst_cloud_ptr->points_.push_back(dst_point_3d);
|
||||
}
|
||||
}
|
||||
|
||||
if (dst_cloud_ptr->IsEmpty())
|
||||
assert(0);
|
||||
|
||||
std::chrono::high_resolution_clock::time_point m_end = std::chrono::high_resolution_clock::now();
|
||||
std::chrono::duration<double> elapsex = m_end - m_start;
|
||||
std::cout << "Cal3D::LibapiFilterCloudPointsByDist time is : " << elapsex.count() << std::endl;
|
||||
return ret;
|
||||
}
|
||||
|
||||
// 点云修正
|
||||
int Cal3D::LibapiCorrectCloudPoint(std::shared_ptr<geometry::PointCloud>& src_cloud_ptr,
|
||||
std::shared_ptr<geometry::PointCloud>& dst_cloud_ptr, int node)
|
||||
{
|
||||
if (src_cloud_ptr->IsEmpty())
|
||||
assert(0);
|
||||
|
||||
std::chrono::high_resolution_clock::time_point m_start = std::chrono::high_resolution_clock::now();
|
||||
|
||||
int ret = CAL_OK;
|
||||
|
||||
float kk = G(kk);
|
||||
float r;
|
||||
for (int i = 0; i < src_cloud_ptr->points_.size(); ++i)
|
||||
{
|
||||
Eigen::Vector3d point_3d = src_cloud_ptr->points_[i];
|
||||
//r = sqrt(pow(point_3d[0], 2) + pow(point_3d[1], 2) + pow(point_3d[2], 2));
|
||||
//point_3d[0] = point_3d[0] + point_3d[0] / r * kk;
|
||||
//point_3d[1] = point_3d[1] + point_3d[1] / r * kk;
|
||||
//point_3d[2] = point_3d[2] + point_3d[2] / r * kk;
|
||||
point_3d[2] -= kk;
|
||||
dst_cloud_ptr->points_.push_back(point_3d);
|
||||
}
|
||||
|
||||
if (dst_cloud_ptr->IsEmpty())
|
||||
assert(0);
|
||||
|
||||
std::chrono::high_resolution_clock::time_point m_end = std::chrono::high_resolution_clock::now();
|
||||
std::chrono::duration<double> elapsex = m_end - m_start;
|
||||
std::cout << "Cal3D::LibapiCorrectCloudPoint time is : " << elapsex.count() << std::endl;
|
||||
return ret;
|
||||
}
|
||||
|
||||
// 点云转数组
|
||||
int Cal3D::LibapiCloudPointToVec(std::shared_ptr<geometry::PointCloud>& src_cloud_ptr,
|
||||
std::vector<cv::Point3d>& dst_3d)
|
||||
{
|
||||
if (src_cloud_ptr->IsEmpty())
|
||||
{
|
||||
Loger(LEVEL_INFOR, "src_cloud_ptr->IsEmpty()");
|
||||
return CAL_PRAMA_EMPUTY;
|
||||
//assert(0);
|
||||
}
|
||||
|
||||
std::chrono::high_resolution_clock::time_point m_start = std::chrono::high_resolution_clock::now();
|
||||
|
||||
int ret = CAL_OK;
|
||||
|
||||
for (int i = 0; i < src_cloud_ptr->points_.size(); ++i)
|
||||
{
|
||||
Eigen::Vector3d point_3d = src_cloud_ptr->points_[i];
|
||||
dst_3d.push_back(cv::Point3d(point_3d[0], point_3d[1], point_3d[2]));
|
||||
}
|
||||
|
||||
std::chrono::high_resolution_clock::time_point m_end = std::chrono::high_resolution_clock::now();
|
||||
std::chrono::duration<double> elapsex = m_end - m_start;
|
||||
std::cout << "Cal3D::LibapiCloudPointToVec time is : " << elapsex.count() << std::endl;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
// 点云数据矩阵变换
|
||||
int Cal3D::LibapiRotAndTrans(std::shared_ptr<geometry::PointCloud>& cloud_ptr)
|
||||
{
|
||||
std::chrono::high_resolution_clock::time_point m_start = std::chrono::high_resolution_clock::now();
|
||||
|
||||
int ret = CAL_OK;
|
||||
|
||||
//float y = 1.91032;
|
||||
//float p = -1.5938;
|
||||
//float r = -0.321605;
|
||||
|
||||
Eigen::Matrix3d Rz = cloud_ptr->GetRotationMatrixFromXYZ({ 0, 0, G(y) });
|
||||
Eigen::Matrix3d Ry = cloud_ptr->GetRotationMatrixFromXYZ({ 0, G(p), 0 });
|
||||
Eigen::Matrix3d Rx = cloud_ptr->GetRotationMatrixFromXYZ({ G(r), 0, 0 });
|
||||
|
||||
cloud_ptr->Rotate(Rx, { 1, 0, 0 });
|
||||
cloud_ptr->Rotate(Ry, { 0, 1, 0 });
|
||||
cloud_ptr->Rotate(Rz, { 0, 0, 1 });
|
||||
|
||||
Eigen::Vector3d T_vector = Eigen::Vector3d({ G(tx), G(ty), G(tz) });
|
||||
|
||||
cloud_ptr->Translate(T_vector);
|
||||
|
||||
std::chrono::high_resolution_clock::time_point m_end = std::chrono::high_resolution_clock::now();
|
||||
std::chrono::duration<double> elapsex = m_end - m_start;
|
||||
std::cout << "Cal3D::LibapiRotAndTrans time is : " << elapsex.count() << std::endl;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
// 点云数据投影
|
||||
// im 必须是去畸变图像 undistort image
|
||||
int Cal3D::LibapiCloudPointsPorject(std::vector<cv::Point3d>& src_points3D,
|
||||
cv::Mat& cameraMatrix, std::vector<cv::Point2d>& dst_points2D, cv::Mat* im_2D3D, bool doTest, cv::Mat& test_src_im)
|
||||
{
|
||||
if (src_points3D.size() == 0 || cameraMatrix.empty())
|
||||
assert(0);
|
||||
|
||||
if (doTest && test_src_im.empty()) assert(0);
|
||||
|
||||
std::chrono::high_resolution_clock::time_point m_start = std::chrono::high_resolution_clock::now();
|
||||
|
||||
int ret = CAL_OK;
|
||||
|
||||
cv::Mat rvec, tvec;
|
||||
rvec.create(1, 3, cv::DataType<float>::type);
|
||||
rvec.at<float>(0) = 0.0;
|
||||
rvec.at<float>(1) = 0.0;
|
||||
rvec.at<float>(2) = 0.0;
|
||||
tvec.create(3, 1, cv::DataType<float>::type);
|
||||
tvec.at<float>(0) = 0.0;
|
||||
tvec.at<float>(1) = 0.0;
|
||||
tvec.at<float>(2) = 0.0;
|
||||
cv::Mat distCoeffs = (cv::Mat_<double>(1, 5) << 0.0, 0.0, 0.0, 0.0, 0.0);
|
||||
|
||||
// 投影点
|
||||
cv::projectPoints(src_points3D, rvec, tvec, cameraMatrix, distCoeffs, dst_points2D);
|
||||
|
||||
if (dst_points2D.size() == 0)
|
||||
assert(0);
|
||||
|
||||
cv::Mat test_im = cv::Mat::zeros(im_2D3D->size(), im_2D3D->type());
|
||||
int ch = im_2D3D->channels();;
|
||||
float* im_2D3D_row_ptr;
|
||||
uchar* test_im_row_ptr;
|
||||
for (int i = 0; i < dst_points2D.size(); ++i)
|
||||
{
|
||||
if (0 <= dst_points2D[i].x && dst_points2D[i].x < im_2D3D->cols && 0 <= dst_points2D[i].y && dst_points2D[i].y < im_2D3D->rows)
|
||||
{
|
||||
im_2D3D_row_ptr = (float*)im_2D3D->ptr<float>(int(dst_points2D[i].y));
|
||||
im_2D3D_row_ptr[(int)dst_points2D[i].x * ch] = src_points3D[i].x;
|
||||
im_2D3D_row_ptr[(int)dst_points2D[i].x * ch + 1] = src_points3D[i].y;
|
||||
im_2D3D_row_ptr[(int)dst_points2D[i].x * ch + 2] = src_points3D[i].z;
|
||||
|
||||
//std::cout << im_2D3D_row_ptr[(int)dst_points2D[i].x * ch] << std::endl;
|
||||
//std::cout << im_2D3D_row_ptr[(int)dst_points2D[i].x * ch+1] << std::endl;
|
||||
//std::cout << im_2D3D_row_ptr[(int)dst_points2D[i].x * ch+2] << std::endl;
|
||||
|
||||
if (doTest)
|
||||
{
|
||||
test_im_row_ptr = (uchar*)test_im.ptr<uchar>(int(dst_points2D[i].y));
|
||||
test_im_row_ptr[(int)dst_points2D[i].x * ch] = 255;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// for test
|
||||
if (doTest)
|
||||
{
|
||||
cv::Mat image_test_red = cv::Mat::zeros(test_src_im.size(), test_src_im.type());
|
||||
cv::Mat image_test_mask;
|
||||
image_test_red.setTo(cv::Scalar(0, 0, 255));
|
||||
cv::cvtColor(test_im, test_im, cv::COLOR_RGB2GRAY);
|
||||
cv::threshold(test_im, image_test_mask, 1, 255, cv::THRESH_BINARY);
|
||||
cv::Mat kernel = getStructuringElement(cv::MORPH_RECT, cv::Size(9, 9), cv::Point(-1, -1));
|
||||
cv::dilate(image_test_mask, image_test_mask, kernel);
|
||||
cv::bitwise_and(image_test_red, test_src_im, test_src_im, image_test_mask);
|
||||
#ifdef WIN32
|
||||
cv::resize(test_src_im, test_src_im, cv::Size(int(934), int(700)));
|
||||
cv::imshow("test_src_im", test_src_im);
|
||||
cv::waitKey(0);
|
||||
#endif
|
||||
}
|
||||
|
||||
std::chrono::high_resolution_clock::time_point m_end = std::chrono::high_resolution_clock::now();
|
||||
std::chrono::duration<double> elapsex = m_end - m_start;
|
||||
std::cout << "Cal3D::LibapiCloudPointsPorject time is : " << elapsex.count() << std::endl;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int Cal3D::LibapiCloudPointsPorject(
|
||||
std::vector<cv::Point3d>& src_points3D,
|
||||
cv::Mat& cameraMatrix,
|
||||
std::vector <std::vector<cv::Point2f>>& vecConners,
|
||||
cv::Mat* im2D3D,
|
||||
std::vector<std::vector<cv::Point2f>>& vecInConners2D,
|
||||
std::vector<std::vector<cv::Point3f>>& vecInConners3D)
|
||||
{
|
||||
if (src_points3D.size() == 0 || cameraMatrix.empty())
|
||||
{
|
||||
Loger(LEVEL_INFOR, "src_points3D.size() == 0 || cameraMatrix.empty()");
|
||||
return CAL_PRAMA_EMPUTY;
|
||||
//assert(0);
|
||||
}
|
||||
|
||||
|
||||
std::chrono::high_resolution_clock::time_point m_start = std::chrono::high_resolution_clock::now();
|
||||
|
||||
int ret = CAL_OK;
|
||||
|
||||
cv::Mat rvec, tvec;
|
||||
rvec.create(1, 3, cv::DataType<float>::type);
|
||||
rvec.at<float>(0) = 0.0;
|
||||
rvec.at<float>(1) = 0.0;
|
||||
rvec.at<float>(2) = 0.0;
|
||||
tvec.create(3, 1, cv::DataType<float>::type);
|
||||
tvec.at<float>(0) = 0.0;
|
||||
tvec.at<float>(1) = 0.0;
|
||||
tvec.at<float>(2) = 0.0;
|
||||
cv::Mat distCoeffs = (cv::Mat_<double>(1, 5) << 0.0, 0.0, 0.0, 0.0, 0.0);
|
||||
|
||||
// 投影点
|
||||
std::vector<cv::Point2d> dstPoints2D;
|
||||
cv::projectPoints(src_points3D, rvec, tvec, cameraMatrix, distCoeffs, dstPoints2D);
|
||||
|
||||
if (dstPoints2D.empty())
|
||||
{
|
||||
Loger(LEVEL_INFOR, "dstPoints2D.empty()");
|
||||
return CAL_3D_PROJECT_POINTS_IS_0;
|
||||
//assert(0);
|
||||
}
|
||||
|
||||
int ch = 3;
|
||||
float* im2D3DRowPtr;
|
||||
cv::Point2f p2d;
|
||||
std::vector<int> counts(vecConners.size());
|
||||
for (int r = 0; r < vecConners.size(); ++r)
|
||||
counts[r] = 0;
|
||||
for (int i = 0; i < dstPoints2D.size(); ++i)
|
||||
{
|
||||
if (0 <= dstPoints2D[i].x && dstPoints2D[i].x < im2D3D->cols && 0 <= dstPoints2D[i].y && dstPoints2D[i].y < im2D3D->rows)
|
||||
{
|
||||
im2D3DRowPtr = (float*)im2D3D->ptr<float>(int(dstPoints2D[i].y));
|
||||
im2D3DRowPtr[(int)dstPoints2D[i].x * ch] = src_points3D[i].x;
|
||||
im2D3DRowPtr[(int)dstPoints2D[i].x * ch + 1] = src_points3D[i].y;
|
||||
im2D3DRowPtr[(int)dstPoints2D[i].x * ch + 2] = src_points3D[i].z;
|
||||
p2d.x = dstPoints2D[i].x;
|
||||
p2d.y = dstPoints2D[i].y;
|
||||
|
||||
for (int r = 0; r < vecConners.size(); ++r)
|
||||
{
|
||||
// 在ROI检测中,未正常检测到4个角点
|
||||
if (vecConners[r].size() != 4)
|
||||
continue;
|
||||
|
||||
// 待优化
|
||||
// 收缩4个角点
|
||||
std::vector<cv::Point2f> vecConnersTemp;
|
||||
vecConnersTemp.push_back({ vecConners[r][0].x + 100.0f,vecConners[r][0].y + 100.0f });
|
||||
vecConnersTemp.push_back({ vecConners[r][1].x - 100.0f,vecConners[r][1].y + 100.0f });
|
||||
vecConnersTemp.push_back({ vecConners[r][2].x - 100.0f,vecConners[r][2].y - 100.0f });
|
||||
vecConnersTemp.push_back({ vecConners[r][3].x + 100.0f,vecConners[r][3].y - 100.0f });
|
||||
|
||||
// 返回正值:点在多边形内部
|
||||
// 返回零:点在多边形上
|
||||
// 返回负值:点在多边形外部
|
||||
if (cv::pointPolygonTest(vecConnersTemp, p2d, false) >= 0)
|
||||
{
|
||||
counts[r]++;
|
||||
if ((counts[r] % 5) == 0)
|
||||
{
|
||||
cv::Point3f p3d = { (float)src_points3D[i].x, (float)src_points3D[i].y, (float)src_points3D[i].z };
|
||||
vecInConners3D[r].push_back(p3d);
|
||||
vecInConners2D[r].push_back(p2d);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
//int main() {
|
||||
// // 假设 img 是一个 CV_32FC3 类型的图像
|
||||
// cv::Mat img = cv::Mat::ones(480, 640, CV_32FC3) * 0.0001; // 示例数据,值很小
|
||||
//
|
||||
// // 获取最小值和最大值
|
||||
// double minVal, maxVal;
|
||||
// cv::minMaxLoc(img.reshape(1), &minVal, &maxVal); // 将图像展平到单通道以获得总体 min/max
|
||||
//
|
||||
// // 如果 minVal 和 maxVal 接近,可以直接设置一个范围(例如 0 到 1)
|
||||
// if (maxVal - minVal < 1e-6) {
|
||||
// maxVal = minVal + 1.0;
|
||||
// }
|
||||
//
|
||||
// // 手动进行归一化,将图像值扩展到 0 到 255 的范围
|
||||
// cv::Mat img_normalized;
|
||||
// img.convertTo(img_normalized, CV_32FC3, 1.0 / (maxVal - minVal), -minVal / (maxVal - minVal));
|
||||
// img_normalized.convertTo(img_normalized, CV_8UC3, 255.0); // 转换为 8 位图像
|
||||
//
|
||||
// // 显示图像
|
||||
// cv::imshow("Image", img_normalized);
|
||||
// cv::waitKey(0);
|
||||
//
|
||||
// return 0;
|
||||
//}
|
||||
// 用于测试点云数据投影产生的2D3D数据
|
||||
int Cal3D::LibapiCloudPointProjectTest(cv::Mat& im_2D3D)
|
||||
{
|
||||
int ret = CAL_OK;
|
||||
|
||||
#ifdef WIN32
|
||||
cv::Mat tmp;
|
||||
im_2D3D.convertTo(tmp, CV_8UC3, 255.0);
|
||||
cv::resize(tmp, tmp, cv::Size(int(934), int(700)));
|
||||
tmp = tmp * 1000;
|
||||
cv::imshow("im_2D3D", tmp);
|
||||
cv::waitKey(0);
|
||||
#endif
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
// 点云数据转换为2D3D点对数据
|
||||
int Cal3D::LibapiCloudPointsToCMeasureInfo(cv::Mat& im_2D3D, CMeasureInfo& CMeasureInfo)
|
||||
{
|
||||
if (im_2D3D.empty())
|
||||
assert(0);
|
||||
|
||||
int ret = CAL_OK;
|
||||
|
||||
//CMeasureInfo.im = &im_2D3D;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static Eigen::Matrix3f cvMatToEigenMap(const cv::Mat& mat)
|
||||
{
|
||||
//if (mat.type() != CV_32FC1) {
|
||||
// throw std::invalid_argument("输入矩阵必须是 CV_32FC1 类型");
|
||||
//}
|
||||
Eigen::Matrix3f eigenMat(mat.rows, mat.cols);
|
||||
|
||||
// 将数据逐元素拷贝到 Eigen 矩阵
|
||||
for (int i = 0; i < mat.rows; ++i) {
|
||||
for (int j = 0; j < mat.cols; ++j) {
|
||||
eigenMat(i, j) = mat.at<double>(i, j);
|
||||
}
|
||||
}
|
||||
|
||||
return eigenMat;
|
||||
}
|
||||
|
||||
// 通过H,计算2D坐标的3D坐标
|
||||
int Cal3D::LibapiCalConner3D(const std::vector<cv::Point2f>& vec2D_2, cv::Mat& H,
|
||||
std::vector<cv::Point3f> vec3d_n, std::vector<cv::Point3f>& vec3D_4)
|
||||
{
|
||||
int ret = CAL_OK;
|
||||
|
||||
open3d::geometry::PointCloud _3pts_cloud = open3d::geometry::PointCloud();
|
||||
for (const auto& point : vec3d_n) {
|
||||
_3pts_cloud.points_.push_back(Eigen::Vector3d(point.x, point.y, point.z));
|
||||
}
|
||||
//distance_threshold=0.01, ransac_n=3, num_iterations=500
|
||||
float A, B, C, D;
|
||||
std::vector<size_t> inliers;
|
||||
std::tuple<Eigen::Vector4d, std::vector<size_t>> result = _3pts_cloud.SegmentPlane(0.01, 3, 500);
|
||||
Eigen::Vector4d abcd = std::get<0>(result);
|
||||
A = abcd[0], B = abcd[1], C = abcd[2], D = abcd[3];
|
||||
inliers = std::get<1>(result);
|
||||
|
||||
float x, y, t;
|
||||
Eigen::Matrix3f H_inv = cvMatToEigenMap(H).inverse();
|
||||
Eigen::Matrix3f xy1;
|
||||
Eigen::MatrixXf pts3d;
|
||||
cv::Point3f p3d(3);
|
||||
cv::Point3f p3d_next(3);
|
||||
for (int i = 0; i < 4; ++i)
|
||||
{
|
||||
cv::Point2f p2d = vec2D_2[i];
|
||||
x = p2d.x, y = p2d.y;
|
||||
xy1(0) = x, xy1(1) = y, xy1(2) = 1;
|
||||
pts3d = H_inv * xy1.conjugate();
|
||||
pts3d(0) = pts3d(0) / pts3d(2);
|
||||
pts3d(1) = pts3d(1) / pts3d(2);
|
||||
pts3d(2) = pts3d(2) / pts3d(2);
|
||||
t = -D / (A * pts3d(0) + B * pts3d(1) + C * pts3d(2));
|
||||
pts3d(0) = t * pts3d(0);
|
||||
pts3d(1) = t * pts3d(1);
|
||||
pts3d(2) = t * pts3d(2);
|
||||
p3d.x = pts3d(0);
|
||||
p3d.y = pts3d(1);
|
||||
p3d.z = pts3d(2);
|
||||
vec3D_4.push_back(p3d);
|
||||
}
|
||||
|
||||
for (int i = 0; i < 4; ++i)
|
||||
{
|
||||
p3d = vec3D_4[i];
|
||||
p3d_next = vec3D_4[(i + 1) % 4];
|
||||
float edges = sqrt(pow((p3d.x - p3d_next.x), 2)
|
||||
+ pow((p3d.y - p3d_next.y), 2)
|
||||
+ pow((p3d.z - p3d_next.z), 2));
|
||||
std::cout << edges << std::endl;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
//
|
||||
//int main()
|
||||
//{
|
||||
// int ret = CAL_OK;
|
||||
//
|
||||
// utility::SetVerbosityLevel(utility::VerbosityLevel::Debug);
|
||||
//
|
||||
// auto cloud_ptr = std::make_shared<geometry::PointCloud>();
|
||||
// auto cloud_ptr_by_dist = std::make_shared<geometry::PointCloud>();
|
||||
// auto cloud_ptr_by_correct = std::make_shared<geometry::PointCloud>();
|
||||
//
|
||||
// ret = Cal3D::LibapiCapCloudPoints(cloud_ptr);
|
||||
// if (ret != CAL_OK) assert(0);
|
||||
//
|
||||
// ret = Cal3D::LibapiRotAndTrans(cloud_ptr);
|
||||
//
|
||||
// ret = Cal3D::LibapiFilterCloudPointsByDist(cloud_ptr, cloud_ptr_by_dist,
|
||||
// G(dminx), G(dmaxx), G(dminy), G(dmaxy), G(dminz), G(dmaxz));
|
||||
// if (ret != CAL_OK) assert(0);
|
||||
// if (cloud_ptr_by_dist->IsEmpty()) assert(0);
|
||||
//
|
||||
// ret = Cal3D::LibapiCorrectCloudPoint(cloud_ptr_by_dist, cloud_ptr_by_correct, 0);
|
||||
//
|
||||
// std::vector<cv::Point3d> vec_point_3d;
|
||||
// ret = Cal3D::LibapiCloudPointToVec(cloud_ptr_by_correct, vec_point_3d);
|
||||
//
|
||||
// cv::Mat cameraMatrix = (cv::Mat_<double>(3, 3) << G(fx), 0, G(cx), 0, G(fy), G(cy), 0, 0, 1);
|
||||
// std::vector<cv::Point2d> vec_point_2d;
|
||||
// //cv::Mat test_src_im = cv::imread("output.png");
|
||||
// cv::Mat test_src_im;
|
||||
//
|
||||
// //cv::Mat test_src_im;
|
||||
// cv::Mat* im_2D3D = new cv::Mat(cv::Size(G(w), G(h)), CV_32FC3);
|
||||
// im_2D3D->setTo(cv::Scalar(0, 0, 0)); // 设置为全黑背景
|
||||
// ret = Cal3D::LibapiCloudPointsPorject(vec_point_3d, cameraMatrix, vec_point_2d, im_2D3D, false, test_src_im);
|
||||
//
|
||||
// // for test
|
||||
// //ret = Cal3D::LibapiCloudPointProjectTest(*im_2D3D);
|
||||
// //cv::FileStorage file("d:\\im_2D3D.yml", cv::FileStorage::WRITE);
|
||||
// //std::string tag = "im_2D3D";
|
||||
// //file << tag << *im_2D3D;
|
||||
// //file.release();
|
||||
//
|
||||
// // 创建CMeasureInfo数据结构
|
||||
// long id;
|
||||
// ret = CalUtils::LibapiGenRandomId(id);
|
||||
// std::string info = "abc";
|
||||
// CMeasureInfo* CMeasureInfo_ptr = new CMeasureInfo(id, info, im_2D3D);
|
||||
//
|
||||
// visualization::DrawGeometries({ cloud_ptr_by_correct }, "TestFileFormat", 1920, 1080);
|
||||
//
|
||||
// return 0;
|
||||
//}
|
64
image_framework/algorithm/Libapi3d.h
Executable file
64
image_framework/algorithm/Libapi3d.h
Executable file
@ -0,0 +1,64 @@
|
||||
#ifndef LIBAPI_3D_H
|
||||
#define LIBAPI_3D_H
|
||||
|
||||
#include "Libapi2D3D.h"
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <opencv2/opencv.hpp>
|
||||
#include "open3d/Open3D.h"
|
||||
|
||||
using namespace open3d;
|
||||
|
||||
class Cal3D
|
||||
{
|
||||
public:
|
||||
|
||||
// 采集点云数据
|
||||
static int LibapiCapCloudPoints(std::shared_ptr<geometry::PointCloud>& cloud_ptr);
|
||||
|
||||
// 读取点云数据
|
||||
static int LibapiReadCloudPointsPly(const std::string plyPath, std::shared_ptr<geometry::PointCloud>& cloud_ptr);
|
||||
|
||||
// 保存点云数据
|
||||
static int LibapiSaveCloudPointsPly(std::string savaPath, std::shared_ptr<geometry::PointCloud>& cloud_ptr);
|
||||
|
||||
// 点云数据筛选
|
||||
static int LibapiFilterCloudPointsByDist(std::shared_ptr<geometry::PointCloud>& src_cloud_ptr,
|
||||
std::shared_ptr<geometry::PointCloud>& dst_cloud_ptr, float minusx, float x, float minusy, float y, float minusz, float z);
|
||||
|
||||
// 点云修正
|
||||
static int LibapiCorrectCloudPoint(std::shared_ptr<geometry::PointCloud>& src_cloud_ptr,
|
||||
std::shared_ptr<geometry::PointCloud>& dst_cloud_ptr, int node);
|
||||
|
||||
// 点云转数组
|
||||
static int LibapiCloudPointToVec(std::shared_ptr<geometry::PointCloud>& src_cloud_ptr,
|
||||
std::vector<cv::Point3d>& dst_3d);
|
||||
|
||||
// 点云数据转换
|
||||
static int LibapiRotAndTrans(std::shared_ptr<geometry::PointCloud>& cloud_ptr);
|
||||
|
||||
// 点云数据投影
|
||||
static int LibapiCloudPointsPorject(std::vector<cv::Point3d>& src_points3D,
|
||||
cv::Mat& cameraMatrix, std::vector<cv::Point2d>& dst_points2D, cv::Mat* im_2D3D, bool doTest, cv::Mat& src_im);
|
||||
|
||||
// 点云数据投影,按照预埋件区域ROI进行筛选
|
||||
static int LibapiCloudPointsPorject(
|
||||
std::vector<cv::Point3d>& src_points3D,
|
||||
cv::Mat& cameraMatrix,
|
||||
std::vector <std::vector<cv::Point2f>>& vecConners,
|
||||
cv::Mat* im2D3D,
|
||||
std::vector<std::vector<cv::Point2f>>& vecInConners2D,
|
||||
std::vector<std::vector<cv::Point3f>>& vecInConners3D);
|
||||
|
||||
// 用于测试点云数据投影产生的2D3D数据
|
||||
static int LibapiCloudPointProjectTest(cv::Mat& im_2D3D);
|
||||
|
||||
// 点云数据转换为2D3D点对数据
|
||||
static int LibapiCloudPointsToCMeasureInfo(cv::Mat& im_2D3D, CMeasureInfo& CMeasureInfo);
|
||||
|
||||
// 通过H,计算2D坐标的3D坐标
|
||||
static int LibapiCalConner3D(const std::vector<cv::Point2f>& vec2D_2, cv::Mat& H,
|
||||
std::vector<cv::Point3f> vec3d_n, std::vector<cv::Point3f>& vec3D_4);
|
||||
};
|
||||
|
||||
#endif
|
448
image_framework/algorithm/LibapiEdgesSubPix.cpp
Executable file
448
image_framework/algorithm/LibapiEdgesSubPix.cpp
Executable file
@ -0,0 +1,448 @@
|
||||
#include "LibapiEdgesSubPix.h"
|
||||
#include <cmath>
|
||||
#include <opencv2/opencv.hpp>
|
||||
using namespace cv;
|
||||
using namespace std;
|
||||
|
||||
|
||||
const double scale = 128.0; // sum of half Canny filter is 128
|
||||
|
||||
static void getCannyKernel(OutputArray _d, double alpha)
|
||||
{
|
||||
int r = cvRound(alpha * 3);
|
||||
int ksize = 2 * r + 1;
|
||||
|
||||
_d.create(ksize, 1, CV_16S, -1, true);
|
||||
|
||||
Mat k = _d.getMat();
|
||||
|
||||
vector<float> kerF(ksize, 0.0f);
|
||||
kerF[r] = 0.0f;
|
||||
double a2 = alpha * alpha;
|
||||
float sum = 0.0f;
|
||||
for (int x = 1; x <= r; ++x)
|
||||
{
|
||||
float v = (float)(-x * std::exp(-x * x / (2 * a2)));
|
||||
sum += v;
|
||||
kerF[r + x] = v;
|
||||
kerF[r - x] = -v;
|
||||
}
|
||||
float scale = 128 / sum;
|
||||
for (int i = 0; i < ksize; ++i)
|
||||
{
|
||||
kerF[i] *= scale;
|
||||
}
|
||||
Mat temp(ksize, 1, CV_32F, &kerF[0]);
|
||||
temp.convertTo(k, CV_16S);
|
||||
}
|
||||
|
||||
// non-maximum supression and hysteresis
|
||||
static void postCannyFilter(const Mat &src, Mat &dx, Mat &dy, int low, int high, Mat &dst)
|
||||
{
|
||||
ptrdiff_t mapstep = src.cols + 2;
|
||||
AutoBuffer<uchar> buffer((src.cols + 2)*(src.rows + 2) + mapstep * 3 * sizeof(int));
|
||||
|
||||
// L2Gradient comparison with square
|
||||
high = high * high;
|
||||
low = low * low;
|
||||
|
||||
int* mag_buf[3];
|
||||
mag_buf[0] = (int*)(uchar*)buffer;
|
||||
mag_buf[1] = mag_buf[0] + mapstep;
|
||||
mag_buf[2] = mag_buf[1] + mapstep;
|
||||
memset(mag_buf[0], 0, mapstep*sizeof(int));
|
||||
|
||||
uchar* map = (uchar*)(mag_buf[2] + mapstep);
|
||||
memset(map, 1, mapstep);
|
||||
memset(map + mapstep*(src.rows + 1), 1, mapstep);
|
||||
|
||||
int maxsize = std::max(1 << 10, src.cols * src.rows / 10);
|
||||
std::vector<uchar*> stack(maxsize);
|
||||
uchar **stack_top = &stack[0];
|
||||
uchar **stack_bottom = &stack[0];
|
||||
|
||||
/* sector numbers
|
||||
(Top-Left Origin)
|
||||
|
||||
1 2 3
|
||||
* * *
|
||||
* * *
|
||||
0*******0
|
||||
* * *
|
||||
* * *
|
||||
3 2 1
|
||||
*/
|
||||
|
||||
#define CANNY_PUSH(d) *(d) = uchar(2), *stack_top++ = (d)
|
||||
#define CANNY_POP(d) (d) = *--stack_top
|
||||
|
||||
#if CV_SSE2
|
||||
bool haveSSE2 = checkHardwareSupport(CV_CPU_SSE2);
|
||||
#endif
|
||||
|
||||
// calculate magnitude and angle of gradient, perform non-maxima suppression.
|
||||
// fill the map with one of the following values:
|
||||
// 0 - the pixel might belong to an edge
|
||||
// 1 - the pixel can not belong to an edge
|
||||
// 2 - the pixel does belong to an edge
|
||||
for (int i = 0; i <= src.rows; i++)
|
||||
{
|
||||
int* _norm = mag_buf[(i > 0) + 1] + 1;
|
||||
if (i < src.rows)
|
||||
{
|
||||
short* _dx = dx.ptr<short>(i);
|
||||
short* _dy = dy.ptr<short>(i);
|
||||
|
||||
int j = 0, width = src.cols;
|
||||
#if CV_SSE2
|
||||
if (haveSSE2)
|
||||
{
|
||||
for (; j <= width - 8; j += 8)
|
||||
{
|
||||
__m128i v_dx = _mm_loadu_si128((const __m128i *)(_dx + j));
|
||||
__m128i v_dy = _mm_loadu_si128((const __m128i *)(_dy + j));
|
||||
|
||||
__m128i v_dx_ml = _mm_mullo_epi16(v_dx, v_dx), v_dx_mh = _mm_mulhi_epi16(v_dx, v_dx);
|
||||
__m128i v_dy_ml = _mm_mullo_epi16(v_dy, v_dy), v_dy_mh = _mm_mulhi_epi16(v_dy, v_dy);
|
||||
|
||||
__m128i v_norm = _mm_add_epi32(_mm_unpacklo_epi16(v_dx_ml, v_dx_mh), _mm_unpacklo_epi16(v_dy_ml, v_dy_mh));
|
||||
_mm_storeu_si128((__m128i *)(_norm + j), v_norm);
|
||||
|
||||
v_norm = _mm_add_epi32(_mm_unpackhi_epi16(v_dx_ml, v_dx_mh), _mm_unpackhi_epi16(v_dy_ml, v_dy_mh));
|
||||
_mm_storeu_si128((__m128i *)(_norm + j + 4), v_norm);
|
||||
}
|
||||
}
|
||||
#elif CV_NEON
|
||||
for (; j <= width - 8; j += 8)
|
||||
{
|
||||
int16x8_t v_dx = vld1q_s16(_dx + j), v_dy = vld1q_s16(_dy + j);
|
||||
int16x4_t v_dxp = vget_low_s16(v_dx), v_dyp = vget_low_s16(v_dy);
|
||||
int32x4_t v_dst = vmlal_s16(vmull_s16(v_dxp, v_dxp), v_dyp, v_dyp);
|
||||
vst1q_s32(_norm + j, v_dst);
|
||||
|
||||
v_dxp = vget_high_s16(v_dx), v_dyp = vget_high_s16(v_dy);
|
||||
v_dst = vmlal_s16(vmull_s16(v_dxp, v_dxp), v_dyp, v_dyp);
|
||||
vst1q_s32(_norm + j + 4, v_dst);
|
||||
}
|
||||
#endif
|
||||
for (; j < width; ++j)
|
||||
_norm[j] = int(_dx[j])*_dx[j] + int(_dy[j])*_dy[j];
|
||||
|
||||
_norm[-1] = _norm[src.cols] = 0;
|
||||
}
|
||||
else
|
||||
memset(_norm - 1, 0, /* cn* */mapstep*sizeof(int));
|
||||
|
||||
// at the very beginning we do not have a complete ring
|
||||
// buffer of 3 magnitude rows for non-maxima suppression
|
||||
if (i == 0)
|
||||
continue;
|
||||
|
||||
uchar* _map = map + mapstep*i + 1;
|
||||
_map[-1] = _map[src.cols] = 1;
|
||||
|
||||
int* _mag = mag_buf[1] + 1; // take the central row
|
||||
ptrdiff_t magstep1 = mag_buf[2] - mag_buf[1];
|
||||
ptrdiff_t magstep2 = mag_buf[0] - mag_buf[1];
|
||||
|
||||
const short* _x = dx.ptr<short>(i - 1);
|
||||
const short* _y = dy.ptr<short>(i - 1);
|
||||
|
||||
if ((stack_top - stack_bottom) + src.cols > maxsize)
|
||||
{
|
||||
int sz = (int)(stack_top - stack_bottom);
|
||||
maxsize = std::max(maxsize * 3 / 2, sz + src.cols);
|
||||
stack.resize(maxsize);
|
||||
stack_bottom = &stack[0];
|
||||
stack_top = stack_bottom + sz;
|
||||
}
|
||||
|
||||
int prev_flag = 0;
|
||||
for (int j = 0; j < src.cols; j++)
|
||||
{
|
||||
#define CANNY_SHIFT 15
|
||||
const int TG22 = (int)(0.4142135623730950488016887242097*(1 << CANNY_SHIFT) + 0.5);
|
||||
|
||||
int m = _mag[j];
|
||||
|
||||
if (m > low)
|
||||
{
|
||||
int xs = _x[j];
|
||||
int ys = _y[j];
|
||||
int x = std::abs(xs);
|
||||
int y = std::abs(ys) << CANNY_SHIFT;
|
||||
|
||||
int tg22x = x * TG22;
|
||||
|
||||
if (y < tg22x)
|
||||
{
|
||||
if (m > _mag[j - 1] && m >= _mag[j + 1]) goto __ocv_canny_push;
|
||||
}
|
||||
else
|
||||
{
|
||||
int tg67x = tg22x + (x << (CANNY_SHIFT + 1));
|
||||
if (y > tg67x)
|
||||
{
|
||||
if (m > _mag[j + magstep2] && m >= _mag[j + magstep1]) goto __ocv_canny_push;
|
||||
}
|
||||
else
|
||||
{
|
||||
int s = (xs ^ ys) < 0 ? -1 : 1;
|
||||
if (m > _mag[j + magstep2 - s] && m > _mag[j + magstep1 + s]) goto __ocv_canny_push;
|
||||
}
|
||||
}
|
||||
}
|
||||
prev_flag = 0;
|
||||
_map[j] = uchar(1);
|
||||
continue;
|
||||
__ocv_canny_push:
|
||||
if (!prev_flag && m > high && _map[j - mapstep] != 2)
|
||||
{
|
||||
CANNY_PUSH(_map + j);
|
||||
prev_flag = 1;
|
||||
}
|
||||
else
|
||||
_map[j] = 0;
|
||||
}
|
||||
|
||||
// scroll the ring buffer
|
||||
_mag = mag_buf[0];
|
||||
mag_buf[0] = mag_buf[1];
|
||||
mag_buf[1] = mag_buf[2];
|
||||
mag_buf[2] = _mag;
|
||||
}
|
||||
|
||||
// now track the edges (hysteresis thresholding)
|
||||
while (stack_top > stack_bottom)
|
||||
{
|
||||
uchar* m;
|
||||
if ((stack_top - stack_bottom) + 8 > maxsize)
|
||||
{
|
||||
int sz = (int)(stack_top - stack_bottom);
|
||||
maxsize = maxsize * 3 / 2;
|
||||
stack.resize(maxsize);
|
||||
stack_bottom = &stack[0];
|
||||
stack_top = stack_bottom + sz;
|
||||
}
|
||||
|
||||
CANNY_POP(m);
|
||||
|
||||
if (!m[-1]) CANNY_PUSH(m - 1);
|
||||
if (!m[1]) CANNY_PUSH(m + 1);
|
||||
if (!m[-mapstep - 1]) CANNY_PUSH(m - mapstep - 1);
|
||||
if (!m[-mapstep]) CANNY_PUSH(m - mapstep);
|
||||
if (!m[-mapstep + 1]) CANNY_PUSH(m - mapstep + 1);
|
||||
if (!m[mapstep - 1]) CANNY_PUSH(m + mapstep - 1);
|
||||
if (!m[mapstep]) CANNY_PUSH(m + mapstep);
|
||||
if (!m[mapstep + 1]) CANNY_PUSH(m + mapstep + 1);
|
||||
}
|
||||
|
||||
// the final pass, form the final image
|
||||
const uchar* pmap = map + mapstep + 1;
|
||||
uchar* pdst = dst.ptr();
|
||||
for (int i = 0; i < src.rows; i++, pmap += mapstep, pdst += dst.step)
|
||||
{
|
||||
for (int j = 0; j < src.cols; j++)
|
||||
pdst[j] = (uchar)-(pmap[j] >> 1);
|
||||
}
|
||||
}
|
||||
|
||||
static inline double getAmplitude(Mat &dx, Mat &dy, int i, int j)
|
||||
{
|
||||
Point2d mag(dx.at<short>(i, j), dy.at<short>(i, j));
|
||||
return norm(mag);
|
||||
}
|
||||
|
||||
static inline void getMagNeighbourhood(Mat &dx, Mat &dy, Point &p, int w, int h, vector<double> &mag)
|
||||
{
|
||||
int top = p.y - 1 >= 0 ? p.y - 1 : p.y;
|
||||
int down = p.y + 1 < h ? p.y + 1 : p.y;
|
||||
int left = p.x - 1 >= 0 ? p.x - 1 : p.x;
|
||||
int right = p.x + 1 < w ? p.x + 1 : p.x;
|
||||
|
||||
mag[0] = getAmplitude(dx, dy, top, left);
|
||||
mag[1] = getAmplitude(dx, dy, top, p.x);
|
||||
mag[2] = getAmplitude(dx, dy, top, right);
|
||||
mag[3] = getAmplitude(dx, dy, p.y, left);
|
||||
mag[4] = getAmplitude(dx, dy, p.y, p.x);
|
||||
mag[5] = getAmplitude(dx, dy, p.y, right);
|
||||
mag[6] = getAmplitude(dx, dy, down, left);
|
||||
mag[7] = getAmplitude(dx, dy, down, p.x);
|
||||
mag[8] = getAmplitude(dx, dy, down, right);
|
||||
}
|
||||
|
||||
static inline void get2ndFacetModelIn3x3(vector<double> &mag, vector<double> &a)
|
||||
{
|
||||
a[0] = (-mag[0] + 2.0 * mag[1] - mag[2] + 2.0 * mag[3] + 5.0 * mag[4] + 2.0 * mag[5] - mag[6] + 2.0 * mag[7] - mag[8]) / 9.0;
|
||||
a[1] = (-mag[0] + mag[2] - mag[3] + mag[5] - mag[6] + mag[8]) / 6.0;
|
||||
a[2] = (mag[6] + mag[7] + mag[8] - mag[0] - mag[1] - mag[2]) / 6.0;
|
||||
a[3] = (mag[0] - 2.0 * mag[1] + mag[2] + mag[3] - 2.0 * mag[4] + mag[5] + mag[6] - 2.0 * mag[7] + mag[8]) / 6.0;
|
||||
a[4] = (-mag[0] + mag[2] + mag[6] - mag[8]) / 4.0;
|
||||
a[5] = (mag[0] + mag[1] + mag[2] - 2.0 * (mag[3] + mag[4] + mag[5]) + mag[6] + mag[7] + mag[8]) / 6.0;
|
||||
}
|
||||
/*
|
||||
Compute the eigenvalues and eigenvectors of the Hessian matrix given by
|
||||
dfdrr, dfdrc, and dfdcc, and sort them in descending order according to
|
||||
their absolute values.
|
||||
*/
|
||||
static inline void eigenvals(vector<double> &a, double eigval[2], double eigvec[2][2])
|
||||
{
|
||||
// derivatives
|
||||
// fx = a[1], fy = a[2]
|
||||
// fxy = a[4]
|
||||
// fxx = 2 * a[3]
|
||||
// fyy = 2 * a[5]
|
||||
double dfdrc = a[4];
|
||||
double dfdcc = a[3] * 2.0;
|
||||
double dfdrr = a[5] * 2.0;
|
||||
double theta, t, c, s, e1, e2, n1, n2; /* , phi; */
|
||||
|
||||
/* Compute the eigenvalues and eigenvectors of the Hessian matrix. */
|
||||
if (dfdrc != 0.0) {
|
||||
theta = 0.5*(dfdcc - dfdrr) / dfdrc;
|
||||
t = 1.0 / (fabs(theta) + sqrt(theta*theta + 1.0));
|
||||
if (theta < 0.0) t = -t;
|
||||
c = 1.0 / sqrt(t*t + 1.0);
|
||||
s = t*c;
|
||||
e1 = dfdrr - t*dfdrc;
|
||||
e2 = dfdcc + t*dfdrc;
|
||||
}
|
||||
else {
|
||||
c = 1.0;
|
||||
s = 0.0;
|
||||
e1 = dfdrr;
|
||||
e2 = dfdcc;
|
||||
}
|
||||
n1 = c;
|
||||
n2 = -s;
|
||||
|
||||
/* If the absolute value of an eigenvalue is larger than the other, put that
|
||||
eigenvalue into first position. If both are of equal absolute value, put
|
||||
the negative one first. */
|
||||
if (fabs(e1) > fabs(e2)) {
|
||||
eigval[0] = e1;
|
||||
eigval[1] = e2;
|
||||
eigvec[0][0] = n1;
|
||||
eigvec[0][1] = n2;
|
||||
eigvec[1][0] = -n2;
|
||||
eigvec[1][1] = n1;
|
||||
}
|
||||
else if (fabs(e1) < fabs(e2)) {
|
||||
eigval[0] = e2;
|
||||
eigval[1] = e1;
|
||||
eigvec[0][0] = -n2;
|
||||
eigvec[0][1] = n1;
|
||||
eigvec[1][0] = n1;
|
||||
eigvec[1][1] = n2;
|
||||
}
|
||||
else {
|
||||
if (e1 < e2) {
|
||||
eigval[0] = e1;
|
||||
eigval[1] = e2;
|
||||
eigvec[0][0] = n1;
|
||||
eigvec[0][1] = n2;
|
||||
eigvec[1][0] = -n2;
|
||||
eigvec[1][1] = n1;
|
||||
}
|
||||
else {
|
||||
eigval[0] = e2;
|
||||
eigval[1] = e1;
|
||||
eigvec[0][0] = -n2;
|
||||
eigvec[0][1] = n1;
|
||||
eigvec[1][0] = n1;
|
||||
eigvec[1][1] = n2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static inline double vector2angle(double x, double y)
|
||||
{
|
||||
double a = std::atan2(y, x);
|
||||
return a >= 0.0 ? a : a + CV_2PI;
|
||||
}
|
||||
|
||||
void extractSubPixPoints(Mat &dx, Mat &dy, vector<vector<Point> > &contoursInPixel, vector<Contour> &contours)
|
||||
{
|
||||
int w = dx.cols;
|
||||
int h = dx.rows;
|
||||
contours.resize(contoursInPixel.size());
|
||||
for (size_t i = 0; i < contoursInPixel.size(); ++i)
|
||||
{
|
||||
vector<Point> &icontour = contoursInPixel[i];
|
||||
Contour &contour = contours[i];
|
||||
contour.points.resize(icontour.size());
|
||||
contour.response.resize(icontour.size());
|
||||
contour.direction.resize(icontour.size());
|
||||
#if defined(_OPENMP) && defined(NDEBUG)
|
||||
#pragma omp parallel for
|
||||
#endif
|
||||
for (int j = 0; j < (int)icontour.size(); ++j)
|
||||
{
|
||||
vector<double> magNeighbour(9);
|
||||
getMagNeighbourhood(dx, dy, icontour[j], w, h, magNeighbour);
|
||||
vector<double> a(9);
|
||||
get2ndFacetModelIn3x3(magNeighbour, a);
|
||||
|
||||
// Hessian eigen vector
|
||||
double eigvec[2][2], eigval[2];
|
||||
eigenvals(a, eigval, eigvec);
|
||||
double t = 0.0;
|
||||
double ny = eigvec[0][0];
|
||||
double nx = eigvec[0][1];
|
||||
if (eigval[0] < 0.0)
|
||||
{
|
||||
double rx = a[1], ry = a[2], rxy = a[4], rxx = a[3] * 2.0, ryy = a[5] * 2.0;
|
||||
t = -(rx * nx + ry * ny) / (rxx * nx * nx + 2.0 * rxy * nx * ny + ryy * ny * ny);
|
||||
}
|
||||
double px = nx * t;
|
||||
double py = ny * t;
|
||||
float x = (float)icontour[j].x;
|
||||
float y = (float)icontour[j].y;
|
||||
if (fabs(px) <= 0.5 && fabs(py) <= 0.5)
|
||||
{
|
||||
x += (float)px;
|
||||
y += (float)py;
|
||||
}
|
||||
contour.points[j] = Point2f(x, y);
|
||||
contour.response[j] = (float)(a[0] / scale);
|
||||
contour.direction[j] = (float)vector2angle(ny, nx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
// INTERFACE FUNCTION
|
||||
//---------------------------------------------------------------------
|
||||
void EdgesSubPix(Mat &gray, double alpha, int low, int high,
|
||||
vector<Contour> &contours, OutputArray hierarchy, int mode)
|
||||
{
|
||||
Mat blur;
|
||||
GaussianBlur(gray, blur, Size(0, 0), alpha, alpha);
|
||||
|
||||
Mat d;
|
||||
getCannyKernel(d, alpha);
|
||||
Mat one = Mat::ones(Size(1, 1), CV_16S);
|
||||
Mat dx, dy;
|
||||
sepFilter2D(blur, dx, CV_16S, d, one);
|
||||
sepFilter2D(blur, dy, CV_16S, one, d);
|
||||
|
||||
// non-maximum supression & hysteresis threshold
|
||||
Mat edge = Mat::zeros(gray.size(), CV_8UC1);
|
||||
int lowThresh = cvRound(scale * low);
|
||||
int highThresh = cvRound(scale * high);
|
||||
postCannyFilter(gray, dx, dy, lowThresh, highThresh, edge);
|
||||
|
||||
// contours in pixel precision
|
||||
vector<vector<Point> > contoursInPixel;
|
||||
findContours(edge, contoursInPixel, hierarchy, mode, CHAIN_APPROX_NONE);
|
||||
|
||||
// subpixel position extraction with steger's method and facet model 2nd polynominal in 3x3 neighbourhood
|
||||
extractSubPixPoints(dx, dy, contoursInPixel, contours);
|
||||
|
||||
}
|
||||
|
||||
void EdgesSubPix(Mat &gray, double alpha, int low, int high, vector<Contour> &contours)
|
||||
{
|
||||
vector<Vec4i> hierarchy;
|
||||
EdgesSubPix(gray, alpha, low, high, contours, hierarchy, RETR_LIST);
|
||||
}
|
20
image_framework/algorithm/LibapiEdgesSubPix.h
Executable file
20
image_framework/algorithm/LibapiEdgesSubPix.h
Executable file
@ -0,0 +1,20 @@
|
||||
#ifndef __EDGES_SUBPIX_H__
|
||||
#define __EDGES_SUBPIX_H__
|
||||
#include <opencv2/opencv.hpp>
|
||||
#include <vector>
|
||||
|
||||
struct Contour
|
||||
{
|
||||
std::vector<cv::Point2f> points;
|
||||
std::vector<float> direction;
|
||||
std::vector<float> response;
|
||||
};
|
||||
// only 8-bit
|
||||
CV_EXPORTS void EdgesSubPix(cv::Mat &gray, double alpha, int low, int high,
|
||||
std::vector<Contour> &contours, cv::OutputArray hierarchy,
|
||||
int mode);
|
||||
|
||||
CV_EXPORTS void EdgesSubPix(cv::Mat &gray, double alpha, int low, int high,
|
||||
std::vector<Contour> &contours);
|
||||
|
||||
#endif // __EDGES_SUBPIX_H__
|
83
image_framework/algorithm/Yolov5For928.cpp
Executable file
83
image_framework/algorithm/Yolov5For928.cpp
Executable file
@ -0,0 +1,83 @@
|
||||
#include "Yolov5For928.h"
|
||||
#include "Log.h"
|
||||
#include "IniHelper.h"
|
||||
#include <iostream>
|
||||
#ifndef _WIN32
|
||||
#include <dlfcn.h> // Linux for so
|
||||
#endif
|
||||
#include <cassert>
|
||||
|
||||
CYolov5For928* CYolov5For928::m_instance;
|
||||
|
||||
CYolov5For928* CYolov5For928::Get()
|
||||
{
|
||||
if (CYolov5For928::m_instance == nullptr) {
|
||||
CYolov5For928::m_instance = new CYolov5For928();
|
||||
}
|
||||
return CYolov5For928::m_instance;
|
||||
|
||||
}
|
||||
|
||||
CYolov5For928::CYolov5For928()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
CYolov5For928::~CYolov5For928()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
int CYolov5For928::Init()
|
||||
{
|
||||
int ret = RST_OK;
|
||||
|
||||
#ifndef _WIN32
|
||||
const char* libPath = "./libss928driver.so";
|
||||
void* handle = dlopen(libPath, RTLD_LAZY);
|
||||
if (!handle) {
|
||||
// Linux
|
||||
std::cerr << "无法加载动态库: " << dlerror() << std::endl;
|
||||
return INIT_ERROR;
|
||||
}
|
||||
|
||||
pfucLibapiSvpNpuHandleSig = (pFucLibapiSvpNpuHandleSig)dlsym(handle, "LibapiSvpNpuHandleSig");
|
||||
pfucLibapiSvpNpuAclPrepareInit = (pFucLibapiSvpNpuAclPrepareInit)dlsym(handle, "LibapiSvpNpuAclPrepareInit");
|
||||
pfucLibApiSvpNpuAclPrepareExit = (pFucLibApiSvpNpuAclPrepareExit)dlsym(handle, "LibApiSvpNpuAclPrepareExit");
|
||||
pfucLibApiSvpNpuLoadModel = (pFucLibApiSvpNpuLoadModel)dlsym(handle, "LibApiSvpNpuLoadModel");
|
||||
pfucLibApiSvpNpuUnLoadModel = (pFucLibApiSvpNpuUnLoadModel)dlsym(handle, "LibApiSvpNpuUnLoadModel");
|
||||
pfucLibApiSvpNpuLoadDataset = (pFucLibApiSvpNpuLoadDataset)dlsym(handle, "LibApiSvpNpuLoadDataset");
|
||||
pfucLibApiSvpNpuUnloadDataset = (pFucLibApiSvpNpuUnloadDataset)dlsym(handle, "LibApiSvpNpuUnloadDataset");
|
||||
pfucLibApiSvpNpuModelExecute = (pFucLibApiSvpNpuModelExecute)dlsym(handle, "LibApiSvpNpuModelExecute");
|
||||
pfucLibApiSvpNpuGetModelExecuteResult = (pFucLibApiSvpNpuGetModelExecuteResult)dlsym(handle, "LibApiSvpNpuGetModelExecuteResult");
|
||||
|
||||
|
||||
//// init sig
|
||||
//ret = pfucLibapiSvpNpuHandleSig();
|
||||
//if (ret != RST_OK)
|
||||
//{
|
||||
// assert(0);
|
||||
// return ret;
|
||||
//}
|
||||
//// init acl
|
||||
//ret = pfucLibapiSvpNpuAclPrepareInit();
|
||||
//if (ret != RST_OK)
|
||||
//{
|
||||
// assert(0);
|
||||
// return ret;
|
||||
//}
|
||||
//
|
||||
//// init model
|
||||
//const char* om_model_path = G(yolo_modol_path).c_str();
|
||||
//ret = pfucLibApiSvpNpuLoadModel(om_model_path, 0, false);
|
||||
//if (ret != RST_OK)
|
||||
//{
|
||||
// assert(0);
|
||||
// return ret;
|
||||
//}
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
return RST_OK;
|
||||
}
|
54
image_framework/algorithm/Yolov5For928.h
Executable file
54
image_framework/algorithm/Yolov5For928.h
Executable file
@ -0,0 +1,54 @@
|
||||
#ifndef _YOLOV5_FOR_928_H
|
||||
#define _YOLOV5_FOR_928_H
|
||||
|
||||
#define YOLO_BASE 3000
|
||||
#define RST_OK 0
|
||||
#define INIT_ERROR YOLO_BASE - 1
|
||||
|
||||
typedef int (*pFucLibapiSvpNpuHandleSig)();
|
||||
typedef int (*pFucLibapiSvpNpuAclPrepareInit)();
|
||||
typedef int (*pFucLibApiSvpNpuAclPrepareExit)();
|
||||
typedef int (*pFucLibApiSvpNpuLoadModel)(const char* om_model_path, int model_index, bool is_cached);
|
||||
typedef int (*pFucLibApiSvpNpuUnLoadModel)(int model_index);
|
||||
typedef int (*pFucLibApiSvpNpuLoadDataset)(int model_index, void* src, int data_len, int imgin_w, int imgin_h, int flag);
|
||||
typedef int (*pFucLibApiSvpNpuUnloadDataset)();
|
||||
typedef int (*pFucLibApiSvpNpuModelExecute)(int model_index);
|
||||
typedef int (*pFucLibApiSvpNpuGetModelExecuteResult)(int model_index, void* retrunObject);
|
||||
|
||||
struct TarObject {
|
||||
int x;
|
||||
int y;
|
||||
int width;
|
||||
int height;
|
||||
int label;
|
||||
float prob;
|
||||
char text[256];
|
||||
};
|
||||
|
||||
struct RetrunObject {
|
||||
int count;
|
||||
TarObject objects[128];
|
||||
};
|
||||
|
||||
class CYolov5For928
|
||||
{
|
||||
public:
|
||||
static CYolov5For928* Get();
|
||||
public:
|
||||
static CYolov5For928* m_instance;
|
||||
CYolov5For928();
|
||||
~CYolov5For928();
|
||||
int Init();
|
||||
public:
|
||||
pFucLibapiSvpNpuHandleSig pfucLibapiSvpNpuHandleSig = nullptr;
|
||||
pFucLibapiSvpNpuAclPrepareInit pfucLibapiSvpNpuAclPrepareInit = nullptr;
|
||||
pFucLibApiSvpNpuAclPrepareExit pfucLibApiSvpNpuAclPrepareExit = nullptr;
|
||||
pFucLibApiSvpNpuLoadModel pfucLibApiSvpNpuLoadModel = nullptr;
|
||||
pFucLibApiSvpNpuUnLoadModel pfucLibApiSvpNpuUnLoadModel = nullptr;
|
||||
pFucLibApiSvpNpuLoadDataset pfucLibApiSvpNpuLoadDataset = nullptr;
|
||||
pFucLibApiSvpNpuUnloadDataset pfucLibApiSvpNpuUnloadDataset = nullptr;
|
||||
pFucLibApiSvpNpuModelExecute pfucLibApiSvpNpuModelExecute = nullptr;
|
||||
pFucLibApiSvpNpuGetModelExecuteResult pfucLibApiSvpNpuGetModelExecuteResult = nullptr;
|
||||
};
|
||||
|
||||
#endif
|
76
image_framework/driver/camera/CameraHelper.cpp
Executable file
76
image_framework/driver/camera/CameraHelper.cpp
Executable file
@ -0,0 +1,76 @@
|
||||
#include "CameraHelper.h"
|
||||
#include "IniHelper.h"
|
||||
#include <cassert>
|
||||
#ifndef _WIN32
|
||||
#include <dlfcn.h> // Linux for so
|
||||
#endif
|
||||
#include <iostream>
|
||||
|
||||
CCameraHelper* CCameraHelper::m_instance;
|
||||
|
||||
CCameraHelper* CCameraHelper::Get()
|
||||
{
|
||||
if (CCameraHelper::m_instance == nullptr) {
|
||||
CCameraHelper::m_instance = new CCameraHelper();
|
||||
// 待优化
|
||||
}
|
||||
return CCameraHelper::m_instance;
|
||||
}
|
||||
|
||||
CCameraHelper::CCameraHelper()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
CCameraHelper::~CCameraHelper()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
int CCameraHelper::Init()
|
||||
{
|
||||
#ifndef _WIN32
|
||||
const char* libPath = "./libCameraDriver.so";
|
||||
void* handle = dlopen(libPath, RTLD_LAZY);
|
||||
if (!handle) {
|
||||
// Linux
|
||||
std::cerr << "无法加载动态库: " << dlerror() << std::endl;
|
||||
return CAMERA_DLL_INIT_ERROR;
|
||||
}
|
||||
pfuccamera_init = (PFuccamera_init)dlsym(handle, "camera_init");
|
||||
pfuccamera_start = (PFuccamera_start)dlsym(handle, "camera_start");
|
||||
pfuccamera_stop = (PFuccamera_stop)dlsym(handle, "camera_stop");
|
||||
pfuccamera_cap = (PFuccamera_cap)dlsym(handle, "camera_cap");
|
||||
if (G(camera_cap_fake) == "true")
|
||||
return 0;
|
||||
else
|
||||
{
|
||||
this->pfuccamera_init();
|
||||
//this->pfuccamera_start(12 * 10000);
|
||||
return 0;
|
||||
//return this->pfuccamera_init();
|
||||
}
|
||||
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
int CCameraHelper::Start(int epx_time)
|
||||
{
|
||||
return this->pfuccamera_start(epx_time);
|
||||
}
|
||||
|
||||
int CCameraHelper::Stop()
|
||||
{
|
||||
return this->pfuccamera_stop();
|
||||
}
|
||||
|
||||
int CCameraHelper::Cap(void** data, int& w, int& h, int timeout)
|
||||
{
|
||||
return this->pfuccamera_cap(data, w, h, timeout);
|
||||
}
|
||||
|
||||
#ifndef _WIN32
|
||||
|
||||
#endif
|
||||
|
36
image_framework/driver/camera/CameraHelper.h
Executable file
36
image_framework/driver/camera/CameraHelper.h
Executable file
@ -0,0 +1,36 @@
|
||||
#ifndef CAMERA_HELPER_H
|
||||
#define CAMERA_HELPER_H
|
||||
|
||||
|
||||
typedef int (*PFuccamera_init)();
|
||||
typedef int (*PFuccamera_start)(int epx_time);
|
||||
typedef int (*PFuccamera_stop)();
|
||||
typedef int (*PFuccamera_cap)(void** data, int& w, int& h, int time_out);
|
||||
|
||||
#define CAMERA_BASE 4000
|
||||
#define CAMERA_DLL_INIT_ERROR 1 - CAMERA_BASE
|
||||
|
||||
class CCameraHelper
|
||||
{
|
||||
public:
|
||||
static CCameraHelper* Get();
|
||||
static CCameraHelper* m_instance;
|
||||
public:
|
||||
CCameraHelper();
|
||||
~CCameraHelper();
|
||||
public:
|
||||
PFuccamera_init pfuccamera_init = nullptr;
|
||||
PFuccamera_start pfuccamera_start = nullptr;
|
||||
PFuccamera_stop pfuccamera_stop = nullptr;
|
||||
PFuccamera_cap pfuccamera_cap = nullptr;
|
||||
public:
|
||||
int Init();
|
||||
int Start(int epx_time = 12 * 10000);
|
||||
int Stop();
|
||||
int Cap(void**, int& w, int& h, int timeout);
|
||||
int GetState() { return 0; };
|
||||
};
|
||||
|
||||
|
||||
|
||||
#endif
|
341
image_framework/driver/livox/LidarHelper.cpp
Executable file
341
image_framework/driver/livox/LidarHelper.cpp
Executable file
@ -0,0 +1,341 @@
|
||||
#ifndef _WIN32
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#ifndef _WIN32
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#include <string.h>
|
||||
|
||||
#include "LidarHelper.h"
|
||||
|
||||
CLidarHelper* CLidarHelper::m_instance;
|
||||
extern "C" {
|
||||
|
||||
/** 回调函数声明 */
|
||||
static void OnLidarErrorStatusCallback(livox_status status, uint8_t handle, ErrorMessage* message);
|
||||
static void GetLidarData(uint8_t handle, LivoxEthPacket* data, uint32_t data_num, void* client_data);
|
||||
static void OnSampleCallback(livox_status status, uint8_t handle, uint8_t response, void* data);
|
||||
static void OnCommonCommandCallback(livox_status status, uint8_t handle, uint8_t response, void* data);
|
||||
static void OnStopSampleCallback(livox_status status, uint8_t handle, uint8_t response, void* data);
|
||||
static void OnDeviceInfoChange(const DeviceInfo* info, DeviceEvent type);
|
||||
static void OnDeviceBroadcast(const BroadcastDeviceInfo* info);
|
||||
|
||||
/** 用于Python的回调函数指针 */
|
||||
//static void (*python_data_callback)(uint8_t, uint32_t*, uint32_t) = NULL;
|
||||
//static void (*python_error_callback)(livox_status, uint8_t, ErrorMessage*) = NULL;
|
||||
//static void (*python_device_change_callback)(const DeviceInfo*, DeviceEvent) = NULL;
|
||||
//static void (*python_device_broadcast_callback)(const BroadcastDeviceInfo*) = NULL;
|
||||
//static void (*python_common_command_callback)(livox_status, uint8_t, uint8_t) = NULL;
|
||||
|
||||
|
||||
|
||||
typedef enum {
|
||||
kDeviceStateDisconnect = 0,
|
||||
kDeviceStateConnect = 1,
|
||||
kDeviceStateSampling = 2,
|
||||
} DeviceState;
|
||||
|
||||
typedef struct {
|
||||
uint8_t handle;
|
||||
DeviceState device_state;
|
||||
DeviceInfo info;
|
||||
} DeviceItem;
|
||||
|
||||
static DeviceItem devices[kMaxLidarCount];
|
||||
static int lidar_count = 0;
|
||||
static FuncGetLidarData pfuncGetLidarData = nullptr;
|
||||
|
||||
static bool init_sdk() {
|
||||
printf("Livox SDK initializing.\n");
|
||||
if (!Init()) {
|
||||
return false;
|
||||
}
|
||||
printf("Livox SDK has been initialized.\n");
|
||||
LivoxSdkVersion _sdkversion;
|
||||
GetLivoxSdkVersion(&_sdkversion);
|
||||
printf("Livox SDK version %d.%d.%d .\n", _sdkversion.major, _sdkversion.minor, _sdkversion.patch);
|
||||
|
||||
memset(devices, 0, sizeof(devices));
|
||||
return true;
|
||||
}
|
||||
|
||||
/** 启动设备扫描 */
|
||||
static bool start_discovery() {
|
||||
SetBroadcastCallback(OnDeviceBroadcast);
|
||||
SetDeviceStateUpdateCallback(OnDeviceInfoChange);
|
||||
|
||||
if (!Start()) {
|
||||
printf("Failed to start device discovery.\n");
|
||||
Uninit();
|
||||
return false;
|
||||
}
|
||||
printf("Started device discovery.\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
/** 停止SDK并清理 */
|
||||
static void stop_sdk() {
|
||||
printf("Stopping Livox SDK.\n");
|
||||
for (int i = 0; i < kMaxLidarCount; ++i) {
|
||||
if (devices[i].device_state == kDeviceStateSampling) {
|
||||
LidarStopSampling(devices[i].handle, OnStopSampleCallback, NULL);
|
||||
}
|
||||
}
|
||||
Uninit();
|
||||
}
|
||||
|
||||
static int connect(const char* broadcast_code) {
|
||||
uint8_t handle = 0;
|
||||
livox_status result = AddLidarToConnect(broadcast_code, &handle);
|
||||
if (result == kStatusSuccess) {
|
||||
/** Set the point cloud data for a specific Livox LiDAR. */
|
||||
SetDataCallback(handle, pfuncGetLidarData, NULL);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static int start_sampling(uint8_t handle) {
|
||||
livox_status result = LidarStartSampling(handle, OnSampleCallback, NULL);
|
||||
devices[handle].device_state = kDeviceStateSampling;
|
||||
return result;
|
||||
}
|
||||
|
||||
static int stop_sampling(uint8_t handle) {
|
||||
livox_status result = LidarStopSampling(handle, OnSampleCallback, NULL);
|
||||
devices[handle].device_state = kDeviceStateSampling;
|
||||
return result;
|
||||
}
|
||||
|
||||
static int set_mode(LidarMode mode) {
|
||||
return LidarSetMode(devices[0].handle, mode, OnCommonCommandCallback, NULL);
|
||||
}
|
||||
|
||||
/** 回调函数的定义 */
|
||||
static void OnLidarErrorStatusCallback(livox_status status, uint8_t handle, ErrorMessage* message) {
|
||||
//if (python_error_callback) {
|
||||
// python_error_callback(status, handle, message);
|
||||
//}
|
||||
}
|
||||
|
||||
static void OnCommonCommandCallback(livox_status status, uint8_t handle, uint8_t response, void* data) {
|
||||
//if (python_common_command_callback) {
|
||||
// python_common_command_callback(status, handle, response);
|
||||
//}
|
||||
}
|
||||
|
||||
static void GetLidarData(uint8_t handle, LivoxEthPacket* data, uint32_t data_num, void* client_data) {
|
||||
if (data) {
|
||||
/** Parsing the timestamp and the point cloud data. */
|
||||
uint64_t cur_timestamp = *((uint64_t*)(data->timestamp));
|
||||
if (data->data_type == kCartesian) {
|
||||
LivoxRawPoint* p_point_data = (LivoxRawPoint*)data->data;
|
||||
}
|
||||
else if (data->data_type == kSpherical) {
|
||||
LivoxSpherPoint* p_point_data = (LivoxSpherPoint*)data->data;
|
||||
}
|
||||
else if (data->data_type == kExtendCartesian) {
|
||||
LivoxExtendRawPoint* p_point_data = (LivoxExtendRawPoint*)data->data;
|
||||
#ifdef _WIN32
|
||||
LivoxExtendRawPoint point_array[10*10000];
|
||||
#else
|
||||
LivoxExtendRawPoint point_array[data_num];
|
||||
#endif
|
||||
uint32_t* converted_data = (uint32_t*)malloc(data_num * 4 * sizeof(uint32_t));
|
||||
for (uint32_t i = 0; i < data_num; ++i) {
|
||||
LivoxExtendRawPoint* point = &p_point_data[i];
|
||||
// 将结构体的 x, y, z 放入 uint32_t 数组中
|
||||
converted_data[i * 4] = point->x;
|
||||
converted_data[i * 4 + 1] = point->y;
|
||||
converted_data[i * 4 + 2] = point->z;
|
||||
// 将 reflectivity 和 tag 合并成一个 uint32_t(高16位和低16位)
|
||||
converted_data[i * 4 + 3] = (uint32_t)(point->reflectivity << 8 | point->tag);
|
||||
}
|
||||
//// 调用 Python 回调函数
|
||||
//if (python_data_callback) {
|
||||
// python_data_callback(handle, converted_data, data_num);
|
||||
//}
|
||||
}
|
||||
else if (data->data_type == kExtendSpherical) {
|
||||
LivoxExtendSpherPoint* p_point_data = (LivoxExtendSpherPoint*)data->data;
|
||||
}
|
||||
else if (data->data_type == kDualExtendCartesian) {
|
||||
LivoxDualExtendRawPoint* p_point_data = (LivoxDualExtendRawPoint*)data->data;
|
||||
}
|
||||
else if (data->data_type == kDualExtendSpherical) {
|
||||
LivoxDualExtendSpherPoint* p_point_data = (LivoxDualExtendSpherPoint*)data->data;
|
||||
}
|
||||
else if (data->data_type == kImu) {
|
||||
LivoxImuPoint* p_point_data = (LivoxImuPoint*)data->data;
|
||||
}
|
||||
else if (data->data_type == kTripleExtendCartesian) {
|
||||
LivoxTripleExtendRawPoint* p_point_data = (LivoxTripleExtendRawPoint*)data->data;
|
||||
}
|
||||
else if (data->data_type == kTripleExtendSpherical) {
|
||||
LivoxTripleExtendSpherPoint* p_point_data = (LivoxTripleExtendSpherPoint*)data->data;
|
||||
}
|
||||
// printf("data_type %d\n", data->data_type);
|
||||
}
|
||||
}
|
||||
|
||||
static void OnSampleCallback(livox_status status, uint8_t handle, uint8_t response, void* data) {
|
||||
if (status == kStatusSuccess && response != 0) {
|
||||
devices[handle].device_state = kDeviceStateConnect;
|
||||
}
|
||||
else if (status == kStatusTimeout) {
|
||||
devices[handle].device_state = kDeviceStateConnect;
|
||||
}
|
||||
}
|
||||
|
||||
static void OnStopSampleCallback(livox_status status, uint8_t handle, uint8_t response, void* data) {
|
||||
// 停止采样时的回调处理
|
||||
}
|
||||
|
||||
/** Query the firmware version of Livox LiDAR. */
|
||||
static void OnDeviceInformation(livox_status status, uint8_t handle, DeviceInformationResponse* ack, void* data) {
|
||||
if (status != kStatusSuccess) {
|
||||
printf("Device Query Informations Failed %d\n", status);
|
||||
}
|
||||
if (ack) {
|
||||
printf("firm ver: %d.%d.%d.%d\n",
|
||||
ack->firmware_version[0],
|
||||
ack->firmware_version[1],
|
||||
ack->firmware_version[2],
|
||||
ack->firmware_version[3]);
|
||||
}
|
||||
}
|
||||
|
||||
static void LidarConnect(const DeviceInfo* info) {
|
||||
uint8_t handle = info->handle;
|
||||
QueryDeviceInformation(handle, OnDeviceInformation, NULL);
|
||||
if (devices[handle].device_state == kDeviceStateDisconnect) {
|
||||
devices[handle].device_state = kDeviceStateConnect;
|
||||
devices[handle].info = *info;
|
||||
}
|
||||
}
|
||||
|
||||
static void LidarDisConnect(const DeviceInfo* info) {
|
||||
uint8_t handle = info->handle;
|
||||
devices[handle].device_state = kDeviceStateDisconnect;
|
||||
}
|
||||
|
||||
static void LidarStateChange(const DeviceInfo* info) {
|
||||
uint8_t handle = info->handle;
|
||||
devices[handle].info = *info;
|
||||
}
|
||||
|
||||
static void OnDeviceInfoChange(const DeviceInfo* info, DeviceEvent type) {
|
||||
if (info == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
uint8_t handle = info->handle;
|
||||
if (handle >= kMaxLidarCount) {
|
||||
return;
|
||||
}
|
||||
if (type == kEventConnect) {
|
||||
LidarConnect(info);
|
||||
printf("[WARNING] Lidar sn: [%s] Connect!!!\n", info->broadcast_code);
|
||||
}
|
||||
else if (type == kEventDisconnect) {
|
||||
LidarDisConnect(info);
|
||||
printf("[WARNING] Lidar sn: [%s] Disconnect!!!\n", info->broadcast_code);
|
||||
}
|
||||
else if (type == kEventStateChange) {
|
||||
LidarStateChange(info);
|
||||
printf("[WARNING] Lidar sn: [%s] StateChange!!!\n", info->broadcast_code);
|
||||
}
|
||||
printf("Device Working State %d\n", devices[handle].info.state);
|
||||
if (devices[handle].device_state == kDeviceStateConnect) {
|
||||
if (devices[handle].info.state == kLidarStateInit) {
|
||||
printf("Device State Change Progress %u\n", devices[handle].info.status.progress);
|
||||
}
|
||||
else {
|
||||
printf("Device State Error Code 0X%08x\n", devices[handle].info.status.status_code.error_code);
|
||||
}
|
||||
printf("Device feature %d\n", devices[handle].info.feature);
|
||||
SetErrorMessageCallback(handle, OnLidarErrorStatusCallback);
|
||||
if (devices[handle].info.state == kLidarStateNormal) {
|
||||
LidarStartSampling(handle, OnSampleCallback, NULL);
|
||||
devices[handle].device_state = kDeviceStateSampling;
|
||||
}
|
||||
}
|
||||
//if (python_device_change_callback) {
|
||||
// python_device_change_callback(info, type);
|
||||
//}
|
||||
}
|
||||
|
||||
static void OnDeviceBroadcast(const BroadcastDeviceInfo* info) {
|
||||
//if (python_device_broadcast_callback) {
|
||||
// python_device_broadcast_callback(info);
|
||||
//}
|
||||
printf("connect to device %d \n", info->broadcast_code);
|
||||
connect(info->broadcast_code);
|
||||
}
|
||||
|
||||
CLidarHelper* CLidarHelper::Get()
|
||||
{
|
||||
if (CLidarHelper::m_instance == nullptr) {
|
||||
CLidarHelper::m_instance = new CLidarHelper();
|
||||
// 待优化
|
||||
}
|
||||
return CLidarHelper::m_instance;
|
||||
}
|
||||
|
||||
CLidarHelper::CLidarHelper()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
CLidarHelper::~CLidarHelper()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
int CLidarHelper::Init(void* pfunGetdate)
|
||||
{
|
||||
pfuncGetLidarData = (FuncGetLidarData)pfunGetdate;
|
||||
|
||||
bool succ = init_sdk();
|
||||
if (!succ)
|
||||
return LIDAR_INIT_SDK_FAILED;
|
||||
succ = start_discovery();
|
||||
if (!succ)
|
||||
return LIDAR_START_DISCOVERY_FAILD;
|
||||
|
||||
return LIDAR_OK;
|
||||
}
|
||||
|
||||
int CLidarHelper::Start(int epx_time)
|
||||
{
|
||||
int ret = start_sampling(0);
|
||||
if (ret != 0)
|
||||
{
|
||||
printf("start_sampling error is %d \n", ret);
|
||||
return LIDAR_START_SAMPLING_FAILD;
|
||||
}
|
||||
|
||||
return LIDAR_OK;
|
||||
}
|
||||
|
||||
int CLidarHelper::Stop()
|
||||
{
|
||||
int ret = stop_sampling(0);
|
||||
if (ret != 0)
|
||||
{
|
||||
printf("stop_sampling error is %d \n", ret);
|
||||
return LIDAR_STOP_SAMPLING_FAILD;
|
||||
}
|
||||
return LIDAR_OK;
|
||||
}
|
||||
|
||||
int CLidarHelper::Cap()
|
||||
{
|
||||
return LIDAR_OK;
|
||||
}
|
||||
|
||||
} // extern "C"
|
||||
#else
|
||||
#include "LidarHelper.h"
|
||||
CLidarHelper* CLidarHelper::m_instance;
|
||||
#endif //_WIN32
|
||||
|
75
image_framework/driver/livox/LidarHelper.h
Executable file
75
image_framework/driver/livox/LidarHelper.h
Executable file
@ -0,0 +1,75 @@
|
||||
#ifndef CAMERA_HELPER_H
|
||||
#define CAMERA_HELPER_H
|
||||
|
||||
#ifndef _WIN32
|
||||
#include "livox_sdk.h"
|
||||
|
||||
extern "C" {
|
||||
|
||||
typedef void (*FuncGetLidarData)(uint8_t handle, LivoxEthPacket* data, uint32_t data_num, void* client_data);
|
||||
|
||||
//#ifndef _WIN32
|
||||
//typedef int (*PFuccamera_init)();
|
||||
//typedef int (*PFuccamera_start)(int epx_time);
|
||||
//typedef int (*PFuccamera_stop)();
|
||||
//typedef int (*PFuccamera_cap)(void** data, int& w, int& h, int time_out);
|
||||
|
||||
#define LIDAR_BASE 5000
|
||||
#define LIDAR_OK 0
|
||||
#define LIDAR_INIT_SDK_FAILED 1 - LIDAR_BASE
|
||||
#define LIDAR_DLL_INIT_ERROR 2 - LIDAR_BASE
|
||||
#define LIDAR_START_DISCOVERY_FAILD 3- LIDAR_BASE
|
||||
#define LIDAR_START_SAMPLING_FAILD 5- LIDAR_BASE
|
||||
#define LIDAR_STOP_SAMPLING_FAILD 6- LIDAR_BASE
|
||||
|
||||
|
||||
class CLidarHelper
|
||||
{
|
||||
public:
|
||||
static CLidarHelper* Get();
|
||||
static CLidarHelper* m_instance;
|
||||
public:
|
||||
CLidarHelper();
|
||||
~CLidarHelper();
|
||||
public:
|
||||
//PFuccamera_init pfuccamera_init = nullptr;
|
||||
//PFuccamera_start pFuccamera_start = nullptr;
|
||||
//PFuccamera_stop pFuccamera_stop = nullptr;
|
||||
//PFuccamera_cap pfuccamera_cap = nullptr;
|
||||
public:
|
||||
int Init(void* pfunGetdate);
|
||||
int Start(int epx_time = 12 * 10000);
|
||||
int Stop();
|
||||
int Cap();
|
||||
int GetState() { return 0; };
|
||||
};
|
||||
} // extern "C" {
|
||||
#else
|
||||
class CLidarHelper
|
||||
{
|
||||
public:
|
||||
static CLidarHelper* Get() {
|
||||
if (CLidarHelper::m_instance == nullptr) {
|
||||
CLidarHelper::m_instance = new CLidarHelper();
|
||||
// 待优化
|
||||
}
|
||||
return CLidarHelper::m_instance;
|
||||
};
|
||||
static CLidarHelper* m_instance;
|
||||
public:
|
||||
CLidarHelper() {};
|
||||
~CLidarHelper() {};
|
||||
public:
|
||||
//PFuccamera_init pfuccamera_init = nullptr;
|
||||
//PFuccamera_start pFuccamera_start = nullptr;
|
||||
//PFuccamera_stop pFuccamera_stop = nullptr;
|
||||
//PFuccamera_cap pfuccamera_cap = nullptr;
|
||||
public:
|
||||
int Init(void* pfunGetdate) { return 0; };
|
||||
int Start(int epx_time = 12 * 10000) { return 0; };
|
||||
int Stop() { return 0; };
|
||||
int Cap() { return 0; };
|
||||
int GetState() { return 0; };
|
||||
};
|
||||
#endif
|
||||
#endif
|
4
image_framework/driver/livox/README.MD
Executable file
4
image_framework/driver/livox/README.MD
Executable file
@ -0,0 +1,4 @@
|
||||
找到 CMakeLists.txt 中编译静态库的地方,确保添加 -fPIC 标志。可以通过以下方式添加:
|
||||
```cmake
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC")
|
||||
```
|
7
image_framework/driver/livox/build.sh
Executable file
7
image_framework/driver/livox/build.sh
Executable file
@ -0,0 +1,7 @@
|
||||
#!/usr/bin/env bash
|
||||
rm -rf build
|
||||
mkdir build
|
||||
cd build
|
||||
cmake ..
|
||||
make
|
||||
cp liblivox_sdk_wrapper.so ../
|
212
image_framework/driver/livox/sdk_test.py
Executable file
212
image_framework/driver/livox/sdk_test.py
Executable file
@ -0,0 +1,212 @@
|
||||
import ctypes
|
||||
from ctypes import *
|
||||
|
||||
# 加载C++库
|
||||
livox_sdk = ctypes.CDLL('./liblivox_sdk_wrapper.so')
|
||||
|
||||
# 预定义的常量
|
||||
kBroadcastCodeSize = 16 # 广播码长度
|
||||
# 定义枚举类型
|
||||
class DeviceType(c_int):
|
||||
kDeviceTypeHub = 0
|
||||
kDeviceTypeLidarMid40 = 1
|
||||
kDeviceTypeLidarTele = 2
|
||||
kDeviceTypeLidarHorizon = 3
|
||||
kDeviceTypeLidarMid70 = 6
|
||||
kDeviceTypeLidarAvia = 7
|
||||
|
||||
class LidarState(c_int):
|
||||
kLidarStateInit = 0
|
||||
kLidarStateNormal = 1
|
||||
kLidarStatePowerSaving = 2
|
||||
kLidarStateStandBy = 3
|
||||
kLidarStateError = 4
|
||||
kLidarStateUnknown = 5
|
||||
|
||||
class LidarMode(c_int):
|
||||
kLidarModeNormal = 1
|
||||
kLidarModePowerSaving = 2
|
||||
kLidarModeStandby = 3
|
||||
|
||||
class LidarFeature(c_int):
|
||||
kLidarFeatureNone = 0
|
||||
kLidarFeatureRainFog = 1
|
||||
|
||||
class LidarIpMode(c_int):
|
||||
kLidarDynamicIpMode = 0
|
||||
kLidarStaticIpMode = 1
|
||||
|
||||
class LidarScanPattern(c_int):
|
||||
kNoneRepetitiveScanPattern = 0
|
||||
kRepetitiveScanPattern = 1
|
||||
|
||||
class LivoxStatus(c_int):
|
||||
kStatusSendFailed = -9
|
||||
kStatusHandlerImplNotExist = -8
|
||||
kStatusInvalidHandle = -7
|
||||
kStatusChannelNotExist = -6
|
||||
kStatusNotEnoughMemory = -5
|
||||
kStatusTimeout = -4
|
||||
kStatusNotSupported = -3
|
||||
kStatusNotConnected = -2
|
||||
kStatusFailure = -1
|
||||
kStatusSuccess = 0
|
||||
|
||||
# 定义结构体和联合体
|
||||
class LidarErrorCode(Structure):
|
||||
_fields_ = [
|
||||
("temp_status", c_uint32, 2),
|
||||
("volt_status", c_uint32, 2),
|
||||
("motor_status", c_uint32, 2),
|
||||
("dirty_warn", c_uint32, 2),
|
||||
("firmware_err", c_uint32, 1),
|
||||
("pps_status", c_uint32, 1),
|
||||
("device_status", c_uint32, 1),
|
||||
("fan_status", c_uint32, 1),
|
||||
("self_heating", c_uint32, 1),
|
||||
("ptp_status", c_uint32, 1),
|
||||
("time_sync_status", c_uint32, 3),
|
||||
("rsvd", c_uint32, 13),
|
||||
("system_status", c_uint32, 2),
|
||||
]
|
||||
|
||||
class HubErrorCode(Structure):
|
||||
_fields_ = [
|
||||
("sync_status", c_uint32, 2),
|
||||
("temp_status", c_uint32, 2),
|
||||
("lidar_status", c_uint32, 1),
|
||||
("lidar_link_status", c_uint32, 1),
|
||||
("firmware_err", c_uint32, 1),
|
||||
("rsvd", c_uint32, 23),
|
||||
("system_status", c_uint32, 2),
|
||||
]
|
||||
|
||||
class ErrorMessage(Union):
|
||||
_fields_ = [
|
||||
("error_code", c_uint32),
|
||||
("lidar_error_code", LidarErrorCode),
|
||||
("hub_error_code", HubErrorCode)
|
||||
]
|
||||
|
||||
class StatusUnion(Union):
|
||||
_fields_ = [
|
||||
("error_code", c_uint32), # 假设这个字段为示例
|
||||
("lidar_error_code", LidarErrorCode),
|
||||
("hub_error_code", HubErrorCode)
|
||||
]
|
||||
|
||||
# 定义 DeviceInfo 结构体
|
||||
class DeviceInfo(Structure):
|
||||
_fields_ = [
|
||||
("broadcast_code", c_char * kBroadcastCodeSize), # 广播码,最大15个字符,带终止符
|
||||
("handle", c_uint8), # 设备句柄
|
||||
("slot", c_uint8), # 插槽编号
|
||||
("id", c_uint8), # LiDAR id
|
||||
("type", DeviceType), # 设备类型
|
||||
("data_port", c_uint16), # 点云数据UDP端口
|
||||
("cmd_port", c_uint16), # 控制命令UDP端口
|
||||
("sensor_port", c_uint16), # IMU数据UDP端口
|
||||
("ip", c_char * 16), # IP地址
|
||||
("state", LidarState), # LiDAR状态
|
||||
("feature", LidarFeature), # LiDAR特性
|
||||
("status", StatusUnion), # LiDAR工作状态
|
||||
("firmware_version", c_uint8 * 4) # 固件版本
|
||||
]
|
||||
|
||||
# 定义 BroadcastDeviceInfo 结构体
|
||||
class BroadcastDeviceInfo(Structure):
|
||||
_fields_ = [
|
||||
("broadcast_code", c_char * kBroadcastCodeSize), # 广播码,最多15个字符,带终止符
|
||||
("dev_type", c_uint8), # 设备类型,参考 DeviceType
|
||||
("reserved", c_uint16), # 保留字段
|
||||
("ip", c_char * 16) # 设备 IP 地址
|
||||
]
|
||||
|
||||
# 定义 LivoxEthPacket 结构体
|
||||
class LivoxEthPacket(Structure):
|
||||
_fields_ = [
|
||||
("version", c_uint8), # Packet protocol version.
|
||||
("slot", c_uint8), # Slot number used for connecting LiDAR.
|
||||
("id", c_uint8), # LiDAR id.
|
||||
("rsvd", c_uint8), # Reserved.
|
||||
("err_code", c_uint32), # Device error status indicator information.
|
||||
("timestamp_type", c_uint8), # Timestamp type.
|
||||
("data_type", c_uint8), # Point cloud coordinate format.
|
||||
("timestamp", c_uint8 * 8), # Nanosecond or UTC format timestamp.
|
||||
("data", c_uint8 * 1) # Point cloud data (can be extended as needed).
|
||||
]
|
||||
|
||||
# 定义 LivoxExtendRawPoint 结构体
|
||||
class LivoxExtendRawPoint(Structure):
|
||||
_fields_ = [
|
||||
('x', c_int32), # X axis, Unit: mm
|
||||
('y', c_int32), # Y axis, Unit: mm
|
||||
('z', c_int32), # Z axis, Unit: mm
|
||||
('reflectivity', c_uint8), # Reflectivity
|
||||
('tag', c_uint8) # Tag
|
||||
]
|
||||
|
||||
# 回调函数类型定义
|
||||
DataCallbackType = CFUNCTYPE(None, c_uint8, POINTER(LivoxEthPacket), c_uint32)
|
||||
ErrorCallbackType = CFUNCTYPE(None, c_uint8, c_uint8, POINTER(ErrorMessage))
|
||||
DeviceChangeCallbackType = CFUNCTYPE(None, POINTER(DeviceInfo), c_uint8)
|
||||
DeviceBroadcastCallbackType = CFUNCTYPE(None, POINTER(BroadcastDeviceInfo))
|
||||
|
||||
|
||||
point_size = sizeof(LivoxExtendRawPoint)
|
||||
|
||||
# 数据回调函数
|
||||
@DataCallbackType
|
||||
def data_callback(handle, packet, data_num):
|
||||
# print(f"Received data from handle {handle}, data num: {data_num}")
|
||||
# 1. 计算数据的总字节数
|
||||
total_data_size = data_num * point_size
|
||||
# 2. 将 packet.data 转换为指向 LivoxExtendRawPoint 数组的指针
|
||||
point_data_array_type = LivoxExtendRawPoint * data_num # 定义类型
|
||||
point_data_pointer = cast(packet.data, POINTER(point_data_array_type)) # 将data转换为LivoxExtendRawPoint指针
|
||||
# 3. 获取具体的点云数据
|
||||
point_data_array = point_data_pointer.contents # 访问数组内容
|
||||
# 4. 遍历每个 LivoxExtendRawPoint 并打印数据
|
||||
for i in range(data_num):
|
||||
point = point_data_array[i]
|
||||
print(f"Point {i}: X={point.x}, Y={point.y}, Z={point.z}, Reflectivity={point.reflectivity}, Tag={point.tag}")
|
||||
|
||||
# 错误回调函数
|
||||
@ErrorCallbackType
|
||||
def error_callback(status, handle, error_message):
|
||||
print(f"Error from handle {handle}, status: {status}")
|
||||
|
||||
# 设备状态变化回调函数
|
||||
@DeviceChangeCallbackType
|
||||
def device_change_callback(info, event_type):
|
||||
print(f"Device {bytes(info.contents.broadcast_code).decode('utf-8')} changed state, event type: {event_type}")
|
||||
|
||||
# 设备广播回调函数
|
||||
@DeviceBroadcastCallbackType
|
||||
def device_broadcast_callback(info):
|
||||
print(f"New device broadcast received: {bytes(info.contents.broadcast_code).decode('utf-8')}")
|
||||
|
||||
# 注册回调函数
|
||||
livox_sdk.register_data_callback(data_callback)
|
||||
livox_sdk.register_error_callback(error_callback)
|
||||
livox_sdk.register_device_change_callback(device_change_callback)
|
||||
livox_sdk.register_device_broadcast_callback(device_broadcast_callback)
|
||||
|
||||
# 调用初始化和开始发现设备的函数
|
||||
if livox_sdk.init_sdk():
|
||||
print("Livox SDK initialized.")
|
||||
else:
|
||||
print("Failed to initialize Livox SDK.")
|
||||
|
||||
if livox_sdk.start_discovery():
|
||||
print("Started discovering Livox devices.")
|
||||
else:
|
||||
print("Failed to discover devices.")
|
||||
|
||||
# 等待数据回调
|
||||
try:
|
||||
while True:
|
||||
pass
|
||||
except KeyboardInterrupt:
|
||||
livox_sdk.stop_sdk()
|
||||
print("SDK stopped.")
|
160
image_framework/plugins/MsgBase.cpp
Executable file
160
image_framework/plugins/MsgBase.cpp
Executable file
@ -0,0 +1,160 @@
|
||||
#include "MsgBase.h"
|
||||
#include "LibapiThread.h"
|
||||
#include "Libapi2D3D.h"
|
||||
|
||||
// for test
|
||||
MsgBase* MsgBase::msg_ptr1 = nullptr;
|
||||
|
||||
FuncCallback MsgBase::pCallback = nullptr;
|
||||
|
||||
bool MsgBase::bAllRoisConnersCheckIsEnd = false;
|
||||
bool MsgBase::bCloudProjectIsOk = false;
|
||||
int MsgBase::iCameraToLidarMsg = CLIENT_MSG_NONE; // 2D第一阶段处理结束0:无回复 1:继续执行 2:重新检测 3:停止检测
|
||||
int MsgBase::iClinetMsg = CLIENT_MSG_NONE; // 客户端确认:0:无回复 1:继续执行 2:重新检测 3:停止检测
|
||||
|
||||
static std::mutex s_mutex;
|
||||
|
||||
void MsgBase::SetMsgPtr1(MsgBase* msg)
|
||||
{
|
||||
MsgBase::msg_ptr1 = msg;
|
||||
};
|
||||
|
||||
MsgBase* MsgBase::GetMsgPtr1()
|
||||
{
|
||||
return MsgBase::msg_ptr1;
|
||||
};
|
||||
void MsgBase::SetCallBack(FuncCallback f)
|
||||
{
|
||||
MsgBase::pCallback = f;
|
||||
}
|
||||
|
||||
void MsgBase::Callback(void* data)
|
||||
{
|
||||
if (MsgBase::pCallback != nullptr)
|
||||
MsgBase::pCallback(data);
|
||||
else assert(0);
|
||||
}
|
||||
|
||||
void MsgBase::Callback(int code, std::string errorInfo)
|
||||
{
|
||||
CallbackInfo cbInfo;
|
||||
cbInfo.code = code;
|
||||
memset(cbInfo.errorInfo, 0, sizeof(cbInfo.errorInfo));
|
||||
memcpy(cbInfo.errorInfo, errorInfo.c_str(), errorInfo.size());
|
||||
cbInfo.bGetData = false;
|
||||
if (MsgBase::pCallback != nullptr)
|
||||
MsgBase::pCallback(&cbInfo);
|
||||
//else assert(0);
|
||||
}
|
||||
|
||||
void MsgBase::CallbackWithData(int code, std::string errorInfo)
|
||||
{
|
||||
CallbackInfo cbInfo;
|
||||
cbInfo.code = code;
|
||||
memset(cbInfo.errorInfo, 0, sizeof(cbInfo.errorInfo));
|
||||
memcpy(cbInfo.errorInfo, errorInfo.c_str(), errorInfo.size());
|
||||
cbInfo.bGetData = true;
|
||||
CMeasureInfo* measureInfo = CMeasureInfo::Get();
|
||||
|
||||
std::vector<std::shared_ptr<CSubRoi>> rois = measureInfo->GetSubRois();
|
||||
cbInfo.roi_size = rois.size();
|
||||
std::cout << "=====================" << rois.size() << std::endl;
|
||||
for (int i = 0; i < rois.size(); ++i)
|
||||
{
|
||||
std::shared_ptr<CSubRoi> roi = rois[i];
|
||||
SubRoiData* cb_roi = &cbInfo.subRois[i];
|
||||
|
||||
for (int n = 0; n < (roi.get()->H).total(); ++n)
|
||||
cb_roi->H[n] = (roi.get()->H).at<float>(0, n);
|
||||
for (int n = 0; n < roi.get()->mRoiPoints.size(); ++n)
|
||||
{
|
||||
cv::Point2f p2f = roi.get()->mRoiPoints[n];
|
||||
cb_roi->mRoiPoints[n * 2] = p2f.x;
|
||||
cb_roi->mRoiPoints[n * 2 + 1] = p2f.y;
|
||||
}
|
||||
for (int n = 0; n < roi.get()->mInnerConners.size(); ++n)
|
||||
{
|
||||
cv::Point2f p2f = roi.get()->mInnerConners[n];
|
||||
cb_roi->mInnerConners[n * 2] = p2f.x;
|
||||
cb_roi->mInnerConners[n * 2 + 1] = p2f.y;
|
||||
}
|
||||
for (int n = 0; n < roi.get()->mInnerConners3D.size(); ++n)
|
||||
{
|
||||
cv::Point3f p3f = roi.get()->mInnerConners3D[n];
|
||||
cb_roi->mInnerConners3D[n * 3] = p3f.x;
|
||||
cb_roi->mInnerConners3D[n * 3 + 1] = p3f.y;
|
||||
cb_roi->mInnerConners3D[n * 3 + 2] = p3f.z;
|
||||
}
|
||||
//for (int n = 0; n < roi.get()->mInnerConners3D.size(); ++n)
|
||||
//{
|
||||
//}
|
||||
|
||||
}
|
||||
|
||||
if (MsgBase::pCallback != nullptr)
|
||||
MsgBase::pCallback(&cbInfo);
|
||||
}
|
||||
|
||||
void MsgBase::WaitBool(bool& b)
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
LibapiThread::delay_second(0.05);
|
||||
if (b)
|
||||
{
|
||||
b = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MsgBase::SetWaitBool(bool& b)
|
||||
{
|
||||
b = true;
|
||||
}
|
||||
|
||||
int MsgBase::WaitInt(int& val)
|
||||
{
|
||||
int rst = 0;
|
||||
while (true)
|
||||
{
|
||||
LibapiThread::delay_second(0.05);
|
||||
std::unique_lock<std::mutex> lock(s_mutex);
|
||||
if (val != 0)
|
||||
{
|
||||
rst = val;
|
||||
val = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return rst;
|
||||
}
|
||||
|
||||
void MsgBase::SetWaitInt(int& it, int val)
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(s_mutex);
|
||||
it = val;
|
||||
}
|
||||
|
||||
// 待优化
|
||||
std::string MsgBase::GetCodeInfo(int code)
|
||||
{
|
||||
if (code == CAL_OK) return "success";
|
||||
|
||||
else if (code == TO_CLIENT_NOTIFY_CAMERA_CAP_START) return "开始采集数据";
|
||||
else if (code == TO_CLIENT_NOTIFY_CAMERA_CAP_END) return "采集数据已完成";
|
||||
|
||||
else if (code == TO_CLIENT_NOTIFY_DETECTION_START) return "开始识别预埋件";
|
||||
else if (code == TO_CLIENT_NOTIFY_DETECTION_END) return "识别预埋件已完成";
|
||||
|
||||
else if (code == TO_CLIENT_NOTIFY_CONNER2D_START) return "开始检测角点";
|
||||
else if (code == TO_CLIENT_NOTIFY_CONNER2D_END) return "检测角点已完成";
|
||||
|
||||
else if (code == TO_CLIENT_NOTIFY_CONNER3D_START) return "开始计算角点3D数据";
|
||||
else if (code == TO_CLIENT_NOTIFY_CONNER3D_END) return "角点3D数据计算已完成";
|
||||
|
||||
else if (code == TO_CLIENT_NOTIFY_MEASURE_START) return "开始计算预埋件数据";
|
||||
else if (code == TO_CLIENT_NOTIFY_MEASURE_END) return "计算预埋件数据已完成";
|
||||
|
||||
else return "未定义事件";
|
||||
}
|
112
image_framework/plugins/MsgBase.h
Executable file
112
image_framework/plugins/MsgBase.h
Executable file
@ -0,0 +1,112 @@
|
||||
#ifndef MSG1_H
|
||||
#define MSG1_H
|
||||
|
||||
#include <string>
|
||||
#include <opencv2/opencv.hpp>
|
||||
#include "LibapiMsg.h"
|
||||
|
||||
#define PARAM_POS_SRC_IMAGE 0
|
||||
#define PARAM_POS_ROI_IMAGE 1
|
||||
#define PARAM_POS_ENHANCE_IMAGE 2
|
||||
#define PARAM_POS_LIDAR_DATA 4
|
||||
#define PARAM_POS_LIDAR_2D3D 5
|
||||
#define PARAM_POS_CMeasureInfo 6
|
||||
#define PARAM_POS_MOTION_DETECTION_DATA 33
|
||||
|
||||
// 客户端到主任务的消息定义
|
||||
#define CLIENT_MSG_NONE 0
|
||||
#define CLIENT_MSG_CONTINUE 1
|
||||
#define CLIENT_MSG_RESTART_DETECTION 2
|
||||
#define CLIENT_MSG_STOP_DETECTION 3
|
||||
|
||||
// 发送到客户端得消息定义
|
||||
#define TO_CLIENT_NOTIFY_BASE 1000
|
||||
#define TO_CLIENT_NOTIFY_CAMERA_CAP_START 1 + TO_CLIENT_NOTIFY_BASE
|
||||
#define TO_CLIENT_NOTIFY_CAMERA_CAP_END 2 + TO_CLIENT_NOTIFY_BASE
|
||||
#define TO_CLIENT_NOTIFY_LIDAR_CAP_START 3 + TO_CLIENT_NOTIFY_BASE
|
||||
#define TO_CLIENT_NOTIFY_LIDAR_CAP_END 4 + TO_CLIENT_NOTIFY_BASE
|
||||
#define TO_CLIENT_NOTIFY_DETECTION_START 5 + TO_CLIENT_NOTIFY_BASE
|
||||
#define TO_CLIENT_NOTIFY_DETECTION_END 6 + TO_CLIENT_NOTIFY_BASE
|
||||
#define TO_CLIENT_NOTIFY_CONNER2D_START 7 + TO_CLIENT_NOTIFY_BASE
|
||||
#define TO_CLIENT_NOTIFY_CONNER2D_END 8 + TO_CLIENT_NOTIFY_BASE
|
||||
#define TO_CLIENT_NOTIFY_CONNER3D_START 9 + TO_CLIENT_NOTIFY_BASE
|
||||
#define TO_CLIENT_NOTIFY_CONNER3D_END 10 + TO_CLIENT_NOTIFY_BASE
|
||||
#define TO_CLIENT_NOTIFY_MEASURE_START 11 + TO_CLIENT_NOTIFY_BASE
|
||||
#define TO_CLIENT_NOTIFY_MEASURE_END 12 + TO_CLIENT_NOTIFY_BASE
|
||||
|
||||
#define DoCallback(ret) \
|
||||
MsgBase::Callback(ret, MsgBase::GetCodeInfo(ret));\
|
||||
|
||||
#define DoCallbackWithData(ret) \
|
||||
MsgBase::CallbackWithData(ret, MsgBase::GetCodeInfo(ret));\
|
||||
|
||||
typedef void (*FuncCallback)(void* returnMeasureInfo);
|
||||
struct MsgBase : public LibapiMsg
|
||||
{
|
||||
public:
|
||||
// for test
|
||||
static MsgBase* msg_ptr1;
|
||||
public:
|
||||
static bool bAllRoisConnersCheckIsEnd; // 所有的ROI边缘检测,角点检测结束
|
||||
static bool bCloudProjectIsOk; // 3D投影结束
|
||||
static int iCameraToLidarMsg; // 2D第一阶段处理结束0:无回复 1:继续执行 2:重新检测 3:停止检测
|
||||
static int iClinetMsg; // 客户端确认:0:无回复 1:继续执行 2:重新检测 3:停止检测
|
||||
private:
|
||||
static FuncCallback pCallback;
|
||||
public:
|
||||
std::string mLog;
|
||||
int mRoiCounts;
|
||||
int mRoiIndex;
|
||||
std::string mMsgType;
|
||||
|
||||
public:
|
||||
// for test
|
||||
static void SetMsgPtr1(MsgBase* msg);
|
||||
static MsgBase* GetMsgPtr1();
|
||||
public:
|
||||
static void SetCallBack(FuncCallback f);
|
||||
static void Callback(void* data);
|
||||
static void Callback(int code, std::string errorInfo);
|
||||
static void CallbackWithData(int code, std::string errorInfo);
|
||||
static void WaitBool(bool& b);
|
||||
static void SetWaitBool(bool& b);
|
||||
static int WaitInt(int& val);
|
||||
static void SetWaitInt(int& it, int val);
|
||||
static std::string GetCodeInfo(int code);
|
||||
};
|
||||
|
||||
// 给回调函数使用
|
||||
typedef struct tagSubRoi
|
||||
{
|
||||
public:
|
||||
long mPparentId;
|
||||
long mId;
|
||||
char mInfo[256];
|
||||
bool isGood;
|
||||
float vpOffset[2];
|
||||
float mRoiPoints[4 * 2];
|
||||
float mInnerConners[4 * 2];
|
||||
float mInnerConners3D[4 * 3];
|
||||
float edges[4];
|
||||
float center[2];
|
||||
int cloud_size;
|
||||
float* mVc2D;
|
||||
float* mVc3D;
|
||||
float H[9];
|
||||
}SubRoiData;
|
||||
|
||||
typedef struct tagCallbakInfo
|
||||
{
|
||||
public:
|
||||
int code; // 0:返回数据;1-99999 返回消息
|
||||
char errorInfo[256];
|
||||
bool bGetData;
|
||||
long mId;
|
||||
char mInfo[256];
|
||||
char mImPath[256];
|
||||
char mIm2D3DPtr[256];
|
||||
int roi_size;
|
||||
SubRoiData subRois[16];
|
||||
}CallbackInfo;
|
||||
|
||||
#endif
|
67
image_framework/plugins/PlguinConfig.cpp
Executable file
67
image_framework/plugins/PlguinConfig.cpp
Executable file
@ -0,0 +1,67 @@
|
||||
|
||||
#include "PlguinConfig.h"
|
||||
#include "LibapiProcessThread.h"
|
||||
#include "LibapiQueue.h"
|
||||
#include "LibapiQueues.h"
|
||||
|
||||
#include "PluginCameraProcessing.h"
|
||||
#include "PluginLidarProcessing.h"
|
||||
#include "PlguinRoi.h"
|
||||
#include "PlguinPostgressing.h"
|
||||
|
||||
PlguinConfig* PlguinConfig::m_instance;
|
||||
|
||||
PlguinConfig* PlguinConfig::getInstance()
|
||||
{
|
||||
if (PlguinConfig::m_instance == nullptr) {
|
||||
PlguinConfig::m_instance = new PlguinConfig();
|
||||
}
|
||||
return PlguinConfig::m_instance;
|
||||
}
|
||||
|
||||
PlguinConfig::PlguinConfig()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
PlguinConfig::~PlguinConfig()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
// for test
|
||||
int PlguinConfig::plguin_init_plugin_config(void* config, void* pthread)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 初始化高清相机处理流程
|
||||
int PlguinConfig::LibapiInitCameraProcessing(void* config)
|
||||
{
|
||||
SharedThread _t_PluginCamera = ProThread::create_and_start<PluginCameraProcessing>("_t_PluginCameraPro");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 初始化激光雷达处理流程
|
||||
int PlguinConfig::LibapiInitLidarProcessing(void* config)
|
||||
{
|
||||
SharedThread _t_PlguinEnhance = ProThread::create_and_start<PluginLidarProcessing>("_t_PlguinLidarPro");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 初始化ROI计算处理流程
|
||||
int PlguinConfig::LibapiInitRoiProcessing(void* config)
|
||||
{
|
||||
SharedThread _t_PluginRoiStart = ProThread::create_and_start<PlguinRoi>("_t_PluginRoiStart");
|
||||
SharedThread _t_PluginRoi1 = ProThread::create_and_start<PlguinRoi>("_t_PluginRoi1");
|
||||
SharedThread _t_PluginRoi2 = ProThread::create_and_start<PlguinRoi>("_t_PluginRoi2");
|
||||
SharedThread _t_PluginRoi3 = ProThread::create_and_start<PlguinRoi>("_t_PluginRoi3");
|
||||
SharedThread _t_PluginRoi4 = ProThread::create_and_start<PlguinRoi>("_t_PluginRoi4");
|
||||
|
||||
_t_PluginRoiStart->set_next_thread(_t_PluginRoi1.get());
|
||||
_t_PluginRoiStart->set_next_thread(_t_PluginRoi2.get());
|
||||
_t_PluginRoiStart->set_next_thread(_t_PluginRoi3.get());
|
||||
_t_PluginRoiStart->set_next_thread(_t_PluginRoi4.get());
|
||||
|
||||
return 0;
|
||||
}
|
36
image_framework/plugins/PlguinConfig.h
Executable file
36
image_framework/plugins/PlguinConfig.h
Executable file
@ -0,0 +1,36 @@
|
||||
#ifndef PLUGIN_CONFIG_H
|
||||
#define PLUGIN_CONFIG_H
|
||||
|
||||
#include<vector>
|
||||
|
||||
class PlguinConfig
|
||||
{
|
||||
public:
|
||||
static PlguinConfig* getInstance();
|
||||
private:
|
||||
static PlguinConfig* m_instance;
|
||||
PlguinConfig();
|
||||
~PlguinConfig();
|
||||
private:
|
||||
std::vector<int> m_configs;
|
||||
|
||||
public:
|
||||
// 初始化高清相机处理流程
|
||||
int plguin_init_plugin_config(void* config, void* pthread);
|
||||
|
||||
// 初始化高清相机处理流程
|
||||
int LibapiInitCameraProcessing(void* config);
|
||||
|
||||
// 初始化激光雷达处理流程
|
||||
int LibapiInitLidarProcessing(void* config);
|
||||
|
||||
// 初始化ROI计算处理流程
|
||||
int LibapiInitRoiProcessing(void* config);
|
||||
|
||||
// 查询config的首任务名称
|
||||
//std::string plguin_find_config(int config_id);
|
||||
// 删除所有config
|
||||
};
|
||||
|
||||
|
||||
#endif
|
34
image_framework/plugins/PlguinPostgressing.cpp
Executable file
34
image_framework/plugins/PlguinPostgressing.cpp
Executable file
@ -0,0 +1,34 @@
|
||||
#include "PlguinPostgressing.h"
|
||||
#include "MsgBase.h"
|
||||
#include "Libapi.h"
|
||||
|
||||
#include <opencv2/opencv.hpp>
|
||||
#include <string>
|
||||
|
||||
PlguinPostgressing::PlguinPostgressing()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
PlguinPostgressing::~PlguinPostgressing()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void PlguinPostgressing::onMouse(int event, int x, int y, int, void*) {
|
||||
if (event == cv::EVENT_LBUTTONDOWN) {
|
||||
std::cout << "Mouse click at: " << x << ", " << y << std::endl;
|
||||
}
|
||||
};
|
||||
|
||||
int PlguinPostgressing::OnProcess(LibapiThread* pThisThread, void* pMsg)
|
||||
{
|
||||
MACRO_START_TIME(pThisThread->get_name());
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void PlguinPostgressing::OnEndProcess(LibapiThread* pThisThread, void* pMsg)
|
||||
{
|
||||
MACRO_RECORD_RUN_TIME(pThisThread->get_name());
|
||||
}
|
16
image_framework/plugins/PlguinPostgressing.h
Executable file
16
image_framework/plugins/PlguinPostgressing.h
Executable file
@ -0,0 +1,16 @@
|
||||
#ifndef PLGUIN_POSTGRESSING_H
|
||||
#define PLGUIN_POSTGRESSING_H
|
||||
|
||||
#include "LibapiThread.h"
|
||||
|
||||
class PlguinPostgressing : BaseRunnable
|
||||
{
|
||||
public:
|
||||
PlguinPostgressing();
|
||||
virtual ~PlguinPostgressing();
|
||||
static void onMouse(int event, int x, int y, int, void*);
|
||||
int OnProcess(LibapiThread* pThisThread, void* pMsg);
|
||||
void OnEndProcess(LibapiThread* pThisThread, void* pMsg);
|
||||
};
|
||||
|
||||
#endif
|
147
image_framework/plugins/PlguinRoi.cpp
Executable file
147
image_framework/plugins/PlguinRoi.cpp
Executable file
@ -0,0 +1,147 @@
|
||||
#include "PlguinRoi.h"
|
||||
#include "MsgBase.h"
|
||||
#include "Libapi2d.h"
|
||||
#include "Libapi2D3D.h"
|
||||
#include "Log.h"
|
||||
|
||||
#include <opencv2/opencv.hpp>
|
||||
#include <string>
|
||||
|
||||
static std::mutex mtx;
|
||||
static int rois_count = 0;
|
||||
|
||||
static cv::Rect OutSquare(const std::vector<cv::Point2f>& vp)
|
||||
{
|
||||
int x1 = 9999;
|
||||
int y1 = 9999;
|
||||
int x2 = 0;
|
||||
int y2 = 0;
|
||||
for (int i = 0; i < vp.size(); i++)
|
||||
{
|
||||
if (vp[i].x < x1)
|
||||
x1 = vp[i].x;
|
||||
if (vp[i].x > x2)
|
||||
x2 = vp[i].x;
|
||||
if (vp[i].y < y1)
|
||||
y1 = vp[i].y;
|
||||
if (vp[i].y > y2)
|
||||
y2 = vp[i].y;
|
||||
}
|
||||
|
||||
return cv::Rect(x1, y1, x2 - x1, y2 - y1);
|
||||
}
|
||||
|
||||
static std::vector<cv::Point2f> Offset(const std::vector<cv::Point2f>& vp, int x, int y)
|
||||
{
|
||||
std::vector<cv::Point2f> vpTar;
|
||||
|
||||
for (int i = 0; i < vp.size(); i++)
|
||||
{
|
||||
cv::Point2f p(vp[i].x + x, vp[i].y + y);
|
||||
vpTar.push_back(p);
|
||||
}
|
||||
|
||||
return vpTar;
|
||||
}
|
||||
|
||||
static cv::Mat GetRoi(cv::Mat& mat, const std::vector<cv::Point2f>& vp, cv::Point2f& vpOffset)
|
||||
{
|
||||
//cv::Mat dst;
|
||||
cv::Rect rt = OutSquare(vp);
|
||||
cv::Mat dst = mat(rt);
|
||||
//cv::Mat roi = cv::Mat::zeros(src.size(), CV_8U);
|
||||
|
||||
//std::vector<std::vector<cv::Point2f>> contour;
|
||||
vpOffset = {(float) rt.x, (float)rt.y};
|
||||
//contour.push_back(vpOffset);
|
||||
//cv::drawContours(roi, contour, 0, cv::Scalar::all(255), -1);
|
||||
//src.copyTo(dst, roi);
|
||||
|
||||
return dst;
|
||||
}
|
||||
|
||||
PlguinRoi::PlguinRoi()
|
||||
{
|
||||
|
||||
};
|
||||
|
||||
PlguinRoi::~PlguinRoi()
|
||||
{
|
||||
|
||||
};
|
||||
|
||||
int PlguinRoi::OnProcess(LibapiThread* pThisThread, void* pMsg)
|
||||
{
|
||||
int ret = CAL_OK;
|
||||
MsgBase* pMsgRoi = (MsgBase*)pMsg;
|
||||
|
||||
if (pMsgRoi->mMsgType == "roi_start")
|
||||
{
|
||||
pMsgRoi->mMsgType = "roi_process";
|
||||
return CAL_OK;
|
||||
}
|
||||
|
||||
if (pMsgRoi->mMsgType != "roi_process")
|
||||
return CAL_OK;
|
||||
|
||||
int roiIndx = pMsgRoi->mRoiIndex;
|
||||
CMeasureInfo* measureInfo = CMeasureInfo::Get();
|
||||
std::shared_ptr<CSubRoi> subRoiPtr = measureInfo->GetSubRois()[roiIndx];
|
||||
// roiMat:roi mat
|
||||
// vpOffset: 在原图中的偏移量
|
||||
cv::Mat roiMat = GetRoi(*measureInfo->GetIm(), subRoiPtr->mRoiPoints, subRoiPtr->vpOffset);
|
||||
// 待优化
|
||||
cv::imwrite(std::to_string(pMsgRoi->mRoiIndex)+"_roi_image.png", roiMat);
|
||||
|
||||
// 处理高精度角点
|
||||
std::vector<std::vector<float>> sort_lines4;
|
||||
std::vector<std::vector<float>> sort_conners4;
|
||||
ret = Cal2D::LibapiGetEdegsAndConners(roiMat, sort_lines4, sort_conners4);
|
||||
if (ret != CAL_OK)
|
||||
{
|
||||
subRoiPtr->isGood = false;
|
||||
Loger(LEVEL_INFOR, "subRoiPtr->isGood = false; mId is %d : ", subRoiPtr->mId);
|
||||
// 保存图片
|
||||
//DoCallback(ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
for (int i = 0; i < 4; ++i)
|
||||
{
|
||||
std::cout << sort_conners4[i][0] << ", " << sort_conners4[i][1] << std::endl;
|
||||
|
||||
cv::Point2f p = { sort_conners4[i][0] + subRoiPtr->vpOffset.x,
|
||||
sort_conners4[i][1] + subRoiPtr->vpOffset.y };
|
||||
subRoiPtr->mInnerConners.push_back(p);
|
||||
|
||||
std::cout << p.x << ", " << p.y << std::endl;
|
||||
}
|
||||
|
||||
|
||||
|
||||
return CAL_OK;
|
||||
}
|
||||
|
||||
|
||||
void PlguinRoi::OnEndProcess(LibapiThread* pThisThread, void* pMsg)
|
||||
{
|
||||
MACRO_RECORD_RUN_TIME(pThisThread->get_name());
|
||||
|
||||
MsgBase* pMsgRoi = (MsgBase*)pMsg;
|
||||
|
||||
if (pThisThread->get_name() == "_t_PluginRoiStart")
|
||||
return;
|
||||
|
||||
if (pMsgRoi->mMsgType == "roi_process")
|
||||
{
|
||||
std::lock_guard<std::mutex> guard(mtx);
|
||||
rois_count++;
|
||||
if (rois_count == pMsgRoi->mRoiCounts)
|
||||
{
|
||||
// 在 PluginCameraProcessing 中会等待该信号
|
||||
MsgBase::SetWaitBool(MsgBase::bAllRoisConnersCheckIsEnd);
|
||||
std::cout << "MsgBase::bAllRoisConnersCheckIsEnd is ok" << std::endl;
|
||||
rois_count = 0;
|
||||
}
|
||||
}
|
||||
}
|
20
image_framework/plugins/PlguinRoi.h
Executable file
20
image_framework/plugins/PlguinRoi.h
Executable file
@ -0,0 +1,20 @@
|
||||
#ifndef PLGUIN_ROI_H
|
||||
#define PLGUIN_ROI_H
|
||||
|
||||
#include "LibapiThread.h"
|
||||
#include <opencv2/opencv.hpp>
|
||||
|
||||
class PlguinRoi : BaseRunnable
|
||||
{
|
||||
private:
|
||||
cv::Mat mDonut;
|
||||
cv::Mat mDonut1;
|
||||
int idx = 0;
|
||||
public:
|
||||
PlguinRoi();
|
||||
virtual ~PlguinRoi();
|
||||
int OnProcess(LibapiThread* pThisThread, void* pMsg);
|
||||
void OnEndProcess(LibapiThread* pThisThread, void* pMsg);
|
||||
};
|
||||
|
||||
#endif
|
331
image_framework/plugins/PluginCameraProcessing.cpp
Executable file
331
image_framework/plugins/PluginCameraProcessing.cpp
Executable file
@ -0,0 +1,331 @@
|
||||
#include "PluginCameraProcessing.h"
|
||||
#include "MsgBase.h"
|
||||
#include "Libapi3d.h"
|
||||
#include "Libapi2d.h"
|
||||
#include "Libapi.h"
|
||||
#include "Log.h"
|
||||
#include "IniHelper.h"
|
||||
|
||||
|
||||
static int CapHqImage(CMeasureInfo* measureInfoPtr)
|
||||
{
|
||||
int ret = CAL_OK;
|
||||
|
||||
std::shared_ptr<cv::Mat> hqImPtr = std::make_shared<cv::Mat>();
|
||||
hqImPtr.get()->create(7000, 9344, CV_8UC3);
|
||||
|
||||
ret = Cal2D::LibapiCapHQImage(measureInfoPtr, hqImPtr);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int DetectObjs(CMeasureInfo* measureInfoPtr)
|
||||
{
|
||||
int ret = CAL_OK;
|
||||
|
||||
// 通过 yolo 检测 预埋件的位置,输出rois(n * roiPoints * 4)
|
||||
ret = Cal2D::LibapiDetectObj(measureInfoPtr);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int CalConners2D(CMeasureInfo* measureInfoPtr)
|
||||
{
|
||||
int ret = CAL_OK;
|
||||
|
||||
// 分发线程ROI检测任务(内角点粗略定位->内角点精确定位,每个任务: 1 * innerConners2D * 4s)
|
||||
int roi_size = measureInfoPtr->GetSubRois().size();
|
||||
if (roi_size == 0)
|
||||
{
|
||||
Loger(LEVEL_INFOR, "roi_size = measureInfoPtr->GetSubRois().size() == 0");
|
||||
return CAL_YOLO_DETECT_NO_ROI;
|
||||
//assert(0);
|
||||
}
|
||||
|
||||
int roi_index = 0;
|
||||
|
||||
// 初始化所有SubRoi
|
||||
for (int i = 0; i < roi_size; ++i)
|
||||
{
|
||||
std::shared_ptr<CSubRoi> subRoiPtr = measureInfoPtr->GetSubRois()[i];
|
||||
subRoiPtr->mPparentId = measureInfoPtr->GetID();
|
||||
long id = -1;
|
||||
CalUtils::LibapiGenRandomId(id);
|
||||
subRoiPtr->mId = id;
|
||||
subRoiPtr->mInfo = measureInfoPtr->GetInfo();
|
||||
subRoiPtr->isGood = true;
|
||||
}
|
||||
|
||||
while (true)
|
||||
{
|
||||
MsgBase* pMsgRoi = nullptr;
|
||||
char msg_type[32] = "v0.1";
|
||||
libapi_create_MsgBase(msg_type, (void**)&pMsgRoi);
|
||||
pMsgRoi->mRoiCounts = roi_size;
|
||||
pMsgRoi->mRoiIndex = roi_index;
|
||||
pMsgRoi->mMsgType = "roi_start";
|
||||
|
||||
ret = libapi_push_to_queue((char*)"_t_PluginRoiStart", pMsgRoi);
|
||||
if (ret != CAL_OK)
|
||||
{
|
||||
Loger(LEVEL_INFOR, "libapi_push_to_queue((char*)\"_t_PluginRoiStart\", pMsgRoi) error");
|
||||
return CAL_ROIS_PUSH_TREAD_FAILED;
|
||||
//assert(0);
|
||||
}
|
||||
|
||||
// 待优化
|
||||
++roi_index;
|
||||
if (roi_size == roi_index || roi_size >= 16)
|
||||
break;
|
||||
}
|
||||
|
||||
// 等待所有ROI任务结束
|
||||
MsgBase::WaitBool(MsgBase::bAllRoisConnersCheckIsEnd);
|
||||
Loger(LEVEL_INFOR, "MsgBase::WaitBool(MsgBase::bAllRoisConnersCheckIsEnd)");
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int CalConners3D(CMeasureInfo* measureInfoPtr)
|
||||
{
|
||||
int ret = CAL_OK;
|
||||
|
||||
int roi_size = measureInfoPtr->GetSubRois().size();
|
||||
|
||||
// 分发线程计算H矩阵并计算各个subMat的 innerConners3D 数据
|
||||
for (int i = 0; i < roi_size; ++i)
|
||||
{
|
||||
CSubRoi* subRoi = measureInfoPtr->GetSubRois()[i].get();
|
||||
cv::Mat H;
|
||||
|
||||
if (!subRoi->isGood)
|
||||
continue;
|
||||
|
||||
ret = Cal2D::LibapiCalH(subRoi->mVc2D, subRoi->mVc3D, H);
|
||||
if (ret != CAL_OK)
|
||||
{
|
||||
subRoi->isGood = false;
|
||||
ret = CAL_OK;
|
||||
continue;
|
||||
//return CAL_H_FAILED;
|
||||
//assert(0);
|
||||
}
|
||||
|
||||
ret = Cal3D::LibapiCalConner3D(subRoi->mInnerConners, H, subRoi->mVc3D, subRoi->mInnerConners3D);
|
||||
if (ret != CAL_OK)
|
||||
{
|
||||
return CAL_3D_COONERS_FAILED;
|
||||
//assert(0);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int CalData(CMeasureInfo* measureInfoPtr)
|
||||
{
|
||||
int ret = CAL_OK;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int InitLog()
|
||||
{
|
||||
int ret = CAL_OK;
|
||||
// 初始化log
|
||||
std::string infoLogPath = "ERROR";
|
||||
Log::getInstance().init(LEVEL_INFOR, infoLogPath.c_str());
|
||||
Loger(LEVEL_INFOR, IniHelper::Get()->GetRecord().c_str());
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool hasGoodConners(CMeasureInfo* measureInfoPtr)
|
||||
{
|
||||
for (int i = 0; i < measureInfoPtr->GetSubRois().size(); ++i)
|
||||
if (measureInfoPtr->GetSubRois()[i].get()->isGood)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
static int pythonProcessing(CMeasureInfo* measureInfoPtr)
|
||||
{
|
||||
int ret = CAL_OK;
|
||||
|
||||
DoCallback(TO_CLIENT_NOTIFY_DETECTION_START);
|
||||
ret = DetectObjs(measureInfoPtr);
|
||||
if (ret != CAL_OK)
|
||||
{
|
||||
Loger(LEVEL_INFOR, "[ERROR] DetectObjs is error!");
|
||||
DoCallback(ret);
|
||||
CMeasureInfo::Clear();
|
||||
return ret;
|
||||
//assert(0);
|
||||
}
|
||||
DoCallbackWithData(TO_CLIENT_NOTIFY_DETECTION_END);
|
||||
Loger(LEVEL_INFOR, "DetectObjs is success!");
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
PluginCameraProcessing::PluginCameraProcessing() {
|
||||
|
||||
|
||||
};
|
||||
|
||||
PluginCameraProcessing::~PluginCameraProcessing()
|
||||
{
|
||||
|
||||
};
|
||||
|
||||
int PluginCameraProcessing::OnProcess(LibapiThread* pThisThread, void* pMsg)
|
||||
{
|
||||
int ret = CAL_OK;
|
||||
|
||||
MsgBase* pCameraMsg = (MsgBase*)pMsg;
|
||||
CMeasureInfo* measureInfoPtr = CMeasureInfo::Init(1, "test");
|
||||
bool bCircle = true;
|
||||
|
||||
// 处理广角图片
|
||||
if (pCameraMsg->mMsgType == "PythonProcessing")
|
||||
{
|
||||
Param p = pCameraMsg->params[PARAM_POS_SRC_IMAGE];
|
||||
std::shared_ptr<cv::Mat> im = std::make_shared<cv::Mat>();
|
||||
im->create(p.height, p.width, CV_8UC3);
|
||||
memcpy(im.get()->data, (char*)p.spData.get(), p.height * p.width * 3);
|
||||
Loger(LEVEL_INFOR, " cap image size is w: %d, h: %d", p.height, p.width);
|
||||
measureInfoPtr->SetIm(im);
|
||||
Loger(LEVEL_INFOR, "get image");
|
||||
return pythonProcessing(measureInfoPtr);
|
||||
}
|
||||
|
||||
InitLog();
|
||||
|
||||
while (bCircle)
|
||||
{
|
||||
std::chrono::high_resolution_clock::time_point m_start = std::chrono::high_resolution_clock::now();
|
||||
DoCallback(TO_CLIENT_NOTIFY_CAMERA_CAP_START);
|
||||
ret = CapHqImage(measureInfoPtr);
|
||||
if (ret != CAL_OK)
|
||||
{
|
||||
Loger(LEVEL_INFOR, "[ERROR] CapHqImage is error!");
|
||||
MsgBase::SetWaitInt(MsgBase::iCameraToLidarMsg, CLIENT_MSG_STOP_DETECTION);
|
||||
DoCallback(ret);
|
||||
CMeasureInfo::Clear();
|
||||
return ret;
|
||||
//assert(0);
|
||||
}
|
||||
DoCallback(TO_CLIENT_NOTIFY_CAMERA_CAP_END);
|
||||
Loger(LEVEL_INFOR, "CapHqImage is success!");
|
||||
|
||||
|
||||
DoCallback(TO_CLIENT_NOTIFY_DETECTION_START);
|
||||
ret = DetectObjs(measureInfoPtr);
|
||||
if (ret != CAL_OK)
|
||||
{
|
||||
Loger(LEVEL_INFOR, "[ERROR] DetectObjs is error!");
|
||||
MsgBase::SetWaitInt(MsgBase::iCameraToLidarMsg, CLIENT_MSG_STOP_DETECTION);
|
||||
DoCallback(ret);
|
||||
CMeasureInfo::Clear();
|
||||
return ret;
|
||||
//assert(0);
|
||||
}
|
||||
DoCallbackWithData(TO_CLIENT_NOTIFY_DETECTION_END);
|
||||
Loger(LEVEL_INFOR, "DetectObjs is success!");
|
||||
|
||||
|
||||
DoCallback(TO_CLIENT_NOTIFY_CONNER2D_START);
|
||||
ret = CalConners2D(measureInfoPtr);
|
||||
if (ret != CAL_OK)
|
||||
{
|
||||
Loger(LEVEL_INFOR, "[ERROR] CalConners2D is error!");
|
||||
MsgBase::SetWaitInt(MsgBase::iCameraToLidarMsg, CLIENT_MSG_STOP_DETECTION);
|
||||
DoCallback(ret);
|
||||
CMeasureInfo::Clear();
|
||||
return ret;
|
||||
//assert(0);
|
||||
}
|
||||
if (!hasGoodConners(measureInfoPtr))
|
||||
{
|
||||
MsgBase::SetWaitInt(MsgBase::iCameraToLidarMsg, CLIENT_MSG_STOP_DETECTION);
|
||||
DoCallback(CAL_HAS_NO_GOOD_CONNER);
|
||||
CMeasureInfo::Clear();
|
||||
Loger(LEVEL_INFOR, "[ERROR] CalConners2D has no good conner !");
|
||||
return ret;
|
||||
//assert(0);
|
||||
}
|
||||
Loger(LEVEL_INFOR, "CalConners2D is success!");
|
||||
DoCallbackWithData(TO_CLIENT_NOTIFY_CONNER2D_END);
|
||||
|
||||
// send msg to client
|
||||
// wait client nake sure
|
||||
int msg_rst = MsgBase::WaitInt(MsgBase::iClinetMsg);
|
||||
switch (msg_rst)
|
||||
{
|
||||
case CLIENT_MSG_NONE:
|
||||
assert(0);
|
||||
case CLIENT_MSG_CONTINUE:
|
||||
MsgBase::SetWaitInt(MsgBase::iCameraToLidarMsg, CLIENT_MSG_CONTINUE);
|
||||
bCircle = false;
|
||||
break;
|
||||
case CLIENT_MSG_RESTART_DETECTION:
|
||||
MsgBase::SetWaitInt(MsgBase::iCameraToLidarMsg, CLIENT_MSG_RESTART_DETECTION);
|
||||
CMeasureInfo::Clear();
|
||||
continue;
|
||||
case CLIENT_MSG_STOP_DETECTION:
|
||||
MsgBase::SetWaitInt(MsgBase::iCameraToLidarMsg, CLIENT_MSG_STOP_DETECTION);
|
||||
CMeasureInfo::Clear();
|
||||
return ret;
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
DoCallback(TO_CLIENT_NOTIFY_CONNER3D_START);
|
||||
|
||||
// 等待点云处理完成
|
||||
MsgBase::WaitBool(MsgBase::bCloudProjectIsOk);
|
||||
if (measureInfoPtr->GetIm2D3D() == nullptr)
|
||||
{
|
||||
DoCallback(CAL_PRAMA_EMPUTY);
|
||||
CMeasureInfo::Clear();
|
||||
return CAL_PRAMA_EMPUTY;
|
||||
}
|
||||
|
||||
ret = CalConners3D(measureInfoPtr);
|
||||
if (ret != CAL_OK)
|
||||
{
|
||||
DoCallback(ret);
|
||||
CMeasureInfo::Clear();
|
||||
Loger(LEVEL_INFOR, "[ERROR] CalConners3D is error!");
|
||||
return ret;
|
||||
//assert(0);
|
||||
}
|
||||
DoCallback(TO_CLIENT_NOTIFY_CONNER3D_END);
|
||||
Loger(LEVEL_INFOR, "CalConners3D is success!");
|
||||
|
||||
DoCallback(TO_CLIENT_NOTIFY_MEASURE_START);
|
||||
ret = CalData(measureInfoPtr);
|
||||
if (ret != CAL_OK)
|
||||
{
|
||||
DoCallback(ret);
|
||||
CMeasureInfo::Clear();
|
||||
Loger(LEVEL_INFOR, "[ERROR] CalData is error!");
|
||||
return ret;
|
||||
//assert(0);
|
||||
}
|
||||
Loger(LEVEL_INFOR, "CalData is success!");
|
||||
DoCallbackWithData(TO_CLIENT_NOTIFY_MEASURE_END);
|
||||
|
||||
// 清楚当此所有信息
|
||||
CMeasureInfo::Clear();
|
||||
|
||||
std::chrono::high_resolution_clock::time_point m_end = std::chrono::high_resolution_clock::now();
|
||||
std::chrono::duration<double> elapsex = m_end - m_start;
|
||||
std::cout << "PluginCameraProcessing::OnProcess time is : " << elapsex.count() << std::endl;
|
||||
};
|
||||
|
||||
Log::getInstance().quit();
|
||||
return ret;
|
||||
}
|
||||
|
||||
void PluginCameraProcessing::OnEndProcess(LibapiThread* pThisThread, void* pMsg)
|
||||
{
|
||||
MACRO_RECORD_RUN_TIME(pThisThread->get_name());
|
||||
//std::cout << " PluginCameraProcessing is end! " << std::endl;
|
||||
}
|
20
image_framework/plugins/PluginCameraProcessing.h
Executable file
20
image_framework/plugins/PluginCameraProcessing.h
Executable file
@ -0,0 +1,20 @@
|
||||
#ifndef PLGUIN_CAMERA_PROCESSING_H
|
||||
#define PLGUIN_CAMERA_PROCESSING_H
|
||||
|
||||
#include "LibapiThread.h"
|
||||
#include <opencv2/opencv.hpp>
|
||||
|
||||
class PluginCameraProcessing : BaseRunnable
|
||||
{
|
||||
private:
|
||||
cv::Mat mDonut;
|
||||
cv::Mat mDonut1;
|
||||
int idx = 0;
|
||||
public:
|
||||
PluginCameraProcessing();
|
||||
virtual ~PluginCameraProcessing();
|
||||
int OnProcess(LibapiThread* pThisThread, void* pMsg);
|
||||
void OnEndProcess(LibapiThread* pThisThread, void* pMsg);
|
||||
};
|
||||
|
||||
#endif
|
180
image_framework/plugins/PluginLidarProcessing.cpp
Executable file
180
image_framework/plugins/PluginLidarProcessing.cpp
Executable file
@ -0,0 +1,180 @@
|
||||
#include "PluginLidarProcessing.h"
|
||||
#include "MsgBase.h"
|
||||
#include "Libapi3d.h"
|
||||
#include "IniHelper.h"
|
||||
#include "Log.h"
|
||||
|
||||
|
||||
PluginLidarProcessing::PluginLidarProcessing() {
|
||||
|
||||
|
||||
};
|
||||
|
||||
PluginLidarProcessing::~PluginLidarProcessing()
|
||||
{
|
||||
|
||||
};
|
||||
|
||||
static int CapCloudPointsAndPretreatment(
|
||||
std::shared_ptr<geometry::PointCloud>& cloud_ptr,
|
||||
std::shared_ptr<geometry::PointCloud>& cloud_ptr_by_dist,
|
||||
std::shared_ptr<geometry::PointCloud>& cloud_ptr_by_correct)
|
||||
{
|
||||
int ret = CAL_OK;
|
||||
|
||||
ret = Cal3D::LibapiCapCloudPoints(cloud_ptr);
|
||||
if (ret != CAL_OK)
|
||||
{
|
||||
return ret;
|
||||
//assert(0);
|
||||
}
|
||||
|
||||
ret = Cal3D::LibapiRotAndTrans(cloud_ptr);
|
||||
if (ret != CAL_OK)
|
||||
{
|
||||
return ret;
|
||||
//assert(0);
|
||||
}
|
||||
|
||||
ret = Cal3D::LibapiFilterCloudPointsByDist(cloud_ptr, cloud_ptr_by_dist, -2.5, 2.5, -2.5, 2.5, 0, 3.8);
|
||||
if (ret != CAL_OK)
|
||||
{
|
||||
return ret;
|
||||
//assert(0);
|
||||
}
|
||||
|
||||
if (cloud_ptr_by_dist->IsEmpty())
|
||||
{
|
||||
return ret;
|
||||
//assert(0);
|
||||
}
|
||||
|
||||
ret = Cal3D::LibapiCorrectCloudPoint(cloud_ptr_by_dist, cloud_ptr_by_correct, 0);
|
||||
if (ret != CAL_OK)
|
||||
{
|
||||
return ret;
|
||||
//assert(0);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int PluginLidarProcessing::OnProcess(LibapiThread* pThisThread, void* pMsg)
|
||||
{
|
||||
int ret = 0;
|
||||
bool bCircle = true;
|
||||
|
||||
//utility::SetVerbosityLevel(utility::VerbosityLevel::Debug);
|
||||
while(bCircle)
|
||||
{
|
||||
auto cloud_ptr = std::make_shared<geometry::PointCloud>();
|
||||
auto cloud_ptr_by_dist = std::make_shared<geometry::PointCloud>();
|
||||
auto cloud_ptr_by_correct = std::make_shared<geometry::PointCloud>();
|
||||
|
||||
ret = CapCloudPointsAndPretreatment(cloud_ptr, cloud_ptr_by_dist, cloud_ptr_by_correct);
|
||||
if (ret != CAL_OK)
|
||||
{
|
||||
Loger(LEVEL_INFOR, "[ERROR] CapCloudPointsAndPretreatment is error!");
|
||||
DoCallback(ret);
|
||||
}
|
||||
Loger(LEVEL_INFOR, "CapCloudPointsAndPretreatment is success!");
|
||||
|
||||
std::vector<cv::Point3d> vec_point_3d;
|
||||
ret = Cal3D::LibapiCloudPointToVec(cloud_ptr_by_correct, vec_point_3d);
|
||||
if (ret != CAL_OK)
|
||||
{
|
||||
Loger(LEVEL_INFOR, "[ERROR] LibapiCloudPointToVec is error!");
|
||||
DoCallback(ret);
|
||||
}
|
||||
Loger(LEVEL_INFOR, "LibapiCloudPointToVec is success!");
|
||||
|
||||
// 等待相机线程发来的消息
|
||||
int msg_rst = MsgBase::WaitInt(MsgBase::iCameraToLidarMsg);
|
||||
switch (msg_rst)
|
||||
{
|
||||
case CLIENT_MSG_NONE:
|
||||
assert(0);
|
||||
case CLIENT_MSG_CONTINUE:
|
||||
bCircle = false;
|
||||
break;
|
||||
case CLIENT_MSG_RESTART_DETECTION:
|
||||
continue;
|
||||
case CLIENT_MSG_STOP_DETECTION:
|
||||
return ret;
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
|
||||
if (cloud_ptr.get()->IsEmpty())
|
||||
{
|
||||
DoCallback(CAL_PRAMA_EMPUTY);
|
||||
MsgBase::SetWaitBool(MsgBase::bCloudProjectIsOk);
|
||||
Loger(LEVEL_INFOR, "[ERROR] cloud_ptr.get()->IsEmpty()");
|
||||
return CAL_PRAMA_EMPUTY;
|
||||
}
|
||||
|
||||
cv::Mat cameraMatrix = (cv::Mat_<double>(3, 3) << G(fx), 0, G(cx), 0, G(fy), G(cy), 0, 0, 1);
|
||||
std::vector<cv::Point2d> vec_point_2d;
|
||||
//cv::Mat test_src_im = cv::imread("output.png");
|
||||
cv::Mat test_src_im;
|
||||
|
||||
//生成点云2D-3D数据
|
||||
std::shared_ptr<cv::Mat> im_2D3D = std::make_shared<cv::Mat>(cv::Size(9344, 7000), CV_32FC3);
|
||||
im_2D3D->setTo(cv::Scalar(0, 0, 0)); // 设置为全黑背景
|
||||
//ret = Cal3D::LibapiCloudPointsPorject(vec_point_3d, cameraMatrix, vec_point_2d, im_2D3D.get(), false, test_src_im);
|
||||
CMeasureInfo* measureInfo = CMeasureInfo::Get();
|
||||
int roiSize = measureInfo->GetSubRois().size();
|
||||
std::vector<std::vector<cv::Point2f>> vecInConners2D(roiSize);
|
||||
std::vector<std::vector<cv::Point3f>> vecInConners3D(roiSize);
|
||||
|
||||
std::vector <std::vector<cv::Point2f>> vecConners = measureInfo->GetAllRoiConners();
|
||||
|
||||
ret = Cal3D::LibapiCloudPointsPorject(vec_point_3d, cameraMatrix, vecConners, im_2D3D.get(), vecInConners2D, vecInConners3D);
|
||||
if (ret != CAL_OK)
|
||||
{
|
||||
DoCallback(ret);
|
||||
std::shared_ptr<cv::Mat> empty = nullptr;
|
||||
measureInfo->SetIm2D3D(empty);
|
||||
MsgBase::SetWaitBool(MsgBase::bCloudProjectIsOk);
|
||||
Loger(LEVEL_INFOR, "[ERROR] LibapiCloudPointsPorject is error");
|
||||
return ret;
|
||||
//assert(0);
|
||||
}
|
||||
Loger(LEVEL_INFOR, "LibapiCloudPointsPorject is success!");
|
||||
measureInfo->SetIm2D3D(im_2D3D);
|
||||
|
||||
std::vector<std::shared_ptr<CSubRoi>> rois = measureInfo->GetSubRois();
|
||||
for (int i = 0; i < rois.size(); ++i)
|
||||
{
|
||||
CSubRoi* roi = rois[i].get();
|
||||
roi->mVc2D.resize(vecInConners3D[i].size());
|
||||
roi->mVc3D.resize(vecInConners3D[i].size());
|
||||
std::copy_n(vecInConners3D[i].begin(), vecInConners3D[i].size(), roi->mVc3D.begin());
|
||||
std::copy_n(vecInConners2D[i].begin(), vecInConners2D[i].size(), roi->mVc2D.begin());
|
||||
}
|
||||
|
||||
MsgBase::SetWaitBool(MsgBase::bCloudProjectIsOk);
|
||||
|
||||
// 查看点云的投影(用于测试)
|
||||
//ret = Cal3D::LibapiCloudPointProjectTest(*im_2D3D);
|
||||
|
||||
// 创建CMeasureInfo数据结构
|
||||
//long id;
|
||||
//ret = CalUtils::LibapiGenRandomId(id);
|
||||
//std::string info = "abc";
|
||||
//CMeasureInfo* measureInfoPtr = CMeasureInfo::Init(id, info);
|
||||
//measureInfoPtr->SetIm2D3D(im_2D3D);
|
||||
//MsgBase::set_spointer_to_msg<CMeasureInfo>((LibapiMsg*)pCameraMsg, PARAM_POS_LIDAR_2D3D, CMeasureInfo_ptr);
|
||||
|
||||
//visualization::DrawGeometries({ cloud_ptr_by_correct }, "TestFileFormat", 1920, 1080);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void PluginLidarProcessing::OnEndProcess(LibapiThread* pThisThread, void* pMsg)
|
||||
{
|
||||
MACRO_RECORD_RUN_TIME(pThisThread->get_name());
|
||||
|
||||
std::cout << " PluginLidarProcessing is end! " << std::endl;
|
||||
}
|
20
image_framework/plugins/PluginLidarProcessing.h
Executable file
20
image_framework/plugins/PluginLidarProcessing.h
Executable file
@ -0,0 +1,20 @@
|
||||
#ifndef PLGUIN_LIDAR_PROCESSING_H
|
||||
#define PLGUIN_LIDAR_PROCESSING_H
|
||||
|
||||
#include "LibapiThread.h"
|
||||
#include <opencv2/opencv.hpp>
|
||||
|
||||
class PluginLidarProcessing : BaseRunnable
|
||||
{
|
||||
private:
|
||||
cv::Mat mDonut;
|
||||
cv::Mat mDonut1;
|
||||
int idx = 0;
|
||||
public:
|
||||
PluginLidarProcessing();
|
||||
virtual ~PluginLidarProcessing();
|
||||
int OnProcess(LibapiThread* pThisThread, void* pMsg);
|
||||
void OnEndProcess(LibapiThread* pThisThread, void* pMsg);
|
||||
};
|
||||
|
||||
#endif
|
239
image_framework/thead/LibapiMsg.h
Executable file
239
image_framework/thead/LibapiMsg.h
Executable file
@ -0,0 +1,239 @@
|
||||
#ifndef MSG_H
|
||||
#define MSG_H
|
||||
|
||||
#include <opencv2/opencv.hpp>
|
||||
|
||||
#define MAX_STRING_LENGTH 128
|
||||
//最多64个参数
|
||||
#define MAX_PARAMS_LENGTH 64
|
||||
|
||||
// msg1
|
||||
enum ParmaType
|
||||
{
|
||||
PARMATYPE_INPUT_IMAGE = 0,
|
||||
PARMATYPE_OPTION,
|
||||
PARMATYPE_OUTPUT_DATA,
|
||||
PARMATYPE_TEMP_DATA,
|
||||
};
|
||||
|
||||
enum DataType
|
||||
{
|
||||
DATATYPE_NONE = 0,
|
||||
DATATYPE_INT,
|
||||
DATATYPE_INT_ARRAY,
|
||||
DATATYPE_CHAR,
|
||||
DATATYPE_CHAR_ARRAY,
|
||||
DATATYPE_FLOAT,
|
||||
DATATYPE_FLOAT_ARRAY,
|
||||
DATATYPE_BOOL,
|
||||
DATATYPE_BOOL_ARRAY,
|
||||
DATATYPE_ENUM,
|
||||
};
|
||||
|
||||
struct Param
|
||||
{
|
||||
public:
|
||||
char name[32] = "";
|
||||
//void* data = 0;
|
||||
long data_len = 0;
|
||||
int width = 0;
|
||||
int height = 0;
|
||||
int flag = 0;
|
||||
int run_times = 0;
|
||||
bool need_delete = false;
|
||||
long used_time = 0;
|
||||
void (*delete_msg_func_ptr)(Param*) = 0;
|
||||
std::shared_ptr<char> spData;
|
||||
ParmaType param_type = PARMATYPE_OPTION;
|
||||
DataType data_type = DATATYPE_NONE;
|
||||
};
|
||||
// msg1
|
||||
|
||||
|
||||
template<class T>
|
||||
struct LibapiDeleter
|
||||
{
|
||||
inline void operator()(void* pData)
|
||||
{
|
||||
delete static_cast<T*>(pData);
|
||||
}
|
||||
};
|
||||
|
||||
template<class T>
|
||||
struct LibapiDeleter<T[]>
|
||||
{
|
||||
inline void operator()(void* pData)
|
||||
{
|
||||
delete[] static_cast<T*>(pData);
|
||||
}
|
||||
};
|
||||
|
||||
struct LibapiMsg
|
||||
{
|
||||
// msg1
|
||||
public:
|
||||
char creator_type[32] = "";
|
||||
int creator_id = 0;
|
||||
char version[32] = "";
|
||||
long used_time = 0;
|
||||
int cmd_id = 0;
|
||||
Param params[MAX_PARAMS_LENGTH];
|
||||
|
||||
public:
|
||||
|
||||
virtual void set_used_time(long time)
|
||||
{
|
||||
this->used_time = time;
|
||||
}
|
||||
|
||||
virtual void delete_msg()
|
||||
{
|
||||
LibapiMsg::delete_msg(this);
|
||||
}
|
||||
|
||||
static void delete_msg(LibapiMsg* pMsg)
|
||||
{
|
||||
if (pMsg == NULL)
|
||||
{
|
||||
std::cout << "pMsg is null" << std::endl;
|
||||
assert(0);
|
||||
}
|
||||
|
||||
LibapiMsg* _pMsg = (LibapiMsg*)pMsg;
|
||||
for (int i = 0; i < MAX_PARAMS_LENGTH; i++)
|
||||
{
|
||||
Param* _param = &_pMsg->params[i];
|
||||
if (_param->need_delete)
|
||||
{
|
||||
_param->need_delete = false;
|
||||
_param->spData = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
delete pMsg;
|
||||
pMsg = NULL;
|
||||
}
|
||||
|
||||
static int copy_image_to_msg(void* pMsg, int pos, int param_type,
|
||||
void* image_data, int width, int height, int flag)
|
||||
{
|
||||
if (pMsg == NULL)
|
||||
{
|
||||
std::cout << "pMsg == NULL" << std::endl;
|
||||
assert(0);
|
||||
}
|
||||
|
||||
if (pos > MAX_PARAMS_LENGTH)
|
||||
{
|
||||
std::cout << "pos > MAX_PARAMS_LENGTH" << std::endl;
|
||||
assert(0);
|
||||
}
|
||||
|
||||
LibapiMsg* _pMsg = (LibapiMsg*)pMsg;
|
||||
Param* _param = &_pMsg->params[pos];
|
||||
int image_data_len = width * height * flag;
|
||||
|
||||
if (_param->spData != NULL)
|
||||
{
|
||||
std::cout << "_param->spData != NULL" << std::endl;
|
||||
assert(0);
|
||||
|
||||
}
|
||||
|
||||
char* pCharData = new char[image_data_len];
|
||||
std::shared_ptr<char> spCharData(reinterpret_cast<char*>(pCharData), LibapiDeleter<char[]>());
|
||||
memcpy(pCharData, image_data, image_data_len);
|
||||
memcpy(_param->name, "IMAGE", sizeof("IMAGE"));
|
||||
_param->spData = spCharData;
|
||||
_param->width = width;
|
||||
_param->height = height;
|
||||
_param->flag = flag;
|
||||
_param->need_delete = true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static cv::Mat get_image_from_msg(void* pMsg, int pos)
|
||||
{
|
||||
LibapiMsg* _pMsg = (LibapiMsg*)pMsg;
|
||||
|
||||
return cv::Mat(
|
||||
_pMsg->params[pos].height,
|
||||
_pMsg->params[pos].width,
|
||||
CV_8UC3,
|
||||
_pMsg->params[pos].spData.get());
|
||||
}
|
||||
|
||||
template<class T>
|
||||
static int set_spointer_to_msg(LibapiMsg* pMsg, int pos, void* p)
|
||||
{
|
||||
if (p != nullptr)
|
||||
{
|
||||
std::shared_ptr<char> spMatData(reinterpret_cast<char*>(p), LibapiDeleter<T>());
|
||||
pMsg->params[pos].spData = spMatData;
|
||||
pMsg->params[pos].need_delete = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
pMsg->params[pos].spData = nullptr;
|
||||
pMsg->params[pos].need_delete = false;
|
||||
}
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
static T* get_spointer_from_msg(LibapiMsg* pMsg, int pos)
|
||||
{
|
||||
if (pMsg->params[pos].spData == nullptr)
|
||||
return NULL;
|
||||
|
||||
return (T*)pMsg->params[pos].spData.get();
|
||||
}
|
||||
|
||||
// msg1
|
||||
public:
|
||||
//virtual void set_used_time(long time) = 0;
|
||||
//virtual void delete_msg() = 0;
|
||||
int add_ref()
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(m_ref_mutex);
|
||||
this->mRef++;
|
||||
return mRef;
|
||||
};
|
||||
|
||||
int sub_ref()
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(m_ref_mutex);
|
||||
this->mRef--;
|
||||
return this->mRef;
|
||||
};
|
||||
|
||||
int get_ref()
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(m_ref_mutex);
|
||||
return this->mRef;
|
||||
};
|
||||
|
||||
bool select_one_process(bool need)
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(m_ref_mutex_process);
|
||||
this->mNeedOneProcess = need;
|
||||
return need;
|
||||
}
|
||||
|
||||
bool is_one_process(bool need = true)
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(m_ref_mutex_process);
|
||||
return this->mNeedOneProcess;
|
||||
}
|
||||
|
||||
private:
|
||||
int mRef = 0;
|
||||
std::mutex m_ref_mutex;
|
||||
std::mutex m_ref_mutex_process;
|
||||
bool mNeedOneProcess = false;
|
||||
};
|
||||
|
||||
#endif
|
858
image_framework/thead/LibapiNanoTime.h
Executable file
858
image_framework/thead/LibapiNanoTime.h
Executable file
@ -0,0 +1,858 @@
|
||||
#ifndef _include_guard_nanotime_
|
||||
#define _include_guard_nanotime_
|
||||
|
||||
/*
|
||||
* You can choose this license, if possible in your jurisdiction:
|
||||
*
|
||||
* Unlicense
|
||||
*
|
||||
* This is free and unencumbered software released into the public domain.
|
||||
*
|
||||
* Anyone is free to copy, modify, publish, use, compile, sell, or distribute
|
||||
* this software, either in source code form or as a compiled binary, for any
|
||||
* purpose, commercial or non-commercial, and by any means.
|
||||
*
|
||||
* In jurisdictions that recognize copyright laws, the author or authors of
|
||||
* this software dedicate any and all copyright interest in the software to the
|
||||
* public domain. We make this dedication for the benefit of the public at
|
||||
* large and to the detriment of our heirs and successors. We intend this
|
||||
* dedication to be an overt act of relinquishment in perpetuity of all present
|
||||
* and future rights to this software under copyright law.
|
||||
*
|
||||
* 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 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.
|
||||
*
|
||||
* For more information, please refer to <http://unlicense.org/>
|
||||
*
|
||||
*
|
||||
* Alternative license choice, if works can't be directly submitted to the
|
||||
* public domain in your jurisdiction:
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (C) 2022 Brandon McGriff <nightmareci@gmail.com>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#if (_MSC_VER < 1600)
|
||||
#error "Current Visual Studio version is not at least Visual Studio 2010, the nanotime library requires at least 2010."
|
||||
#endif
|
||||
#elif defined(__cplusplus)
|
||||
#if (__cplusplus < 201103L)
|
||||
#error "Current C++ standard is not at least C++11, the nanotime library requires at least C++11."
|
||||
#endif
|
||||
#elif defined(__STDC_VERSION__)
|
||||
#if (__STDC_VERSION__ < 199901L)
|
||||
#error "Current C standard is not at least C99, the nanotime library requires at least C99."
|
||||
#endif
|
||||
#else
|
||||
#error "Current C or C++ standard is unknown, the nanotime library requires stdint.h and stdbool.h to be available (C99 or higher, C++11 or higher, Visual Studio 2010 or higher)."
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Implementor's note: This library directly uses Win32 APIs both for MSVC and
|
||||
* MinGW GCC, as they work for both, and produce better behavior in MinGW
|
||||
* builds. Detection of them is accomplished via checking if _WIN32 is defined,
|
||||
* as it's defined in both MSVC and MinGW GCC. Though it's convenient to have
|
||||
* UNIX-like APIs on Windows provided by MinGW, they just aren't as good as
|
||||
* directly using Win32 APIs on Windows.
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <assert.h>
|
||||
|
||||
#define NANOTIME_NSEC_PER_SEC UINT64_C(1000000000)
|
||||
|
||||
#ifndef NANOTIME_ONLY_STEP
|
||||
|
||||
/*
|
||||
* Returns the current time since some unspecified epoch. With the exception of
|
||||
* the standard C11 implementation and non-Apple/Mach kernel POSIX
|
||||
* implementation when neither CLOCK_MONOTONIC_RAW nor CLOCK_MONOTONIC are
|
||||
* available, the time values monotonically increase, so they're not equivalent
|
||||
* to calendar time (i.e., no leap seconds are accounted for, etc.). Calendar
|
||||
* time has to be used as a last resort sometimes, as monotonic time isn't
|
||||
* always available.
|
||||
*/
|
||||
uint64_t nanotime_now();
|
||||
|
||||
/*
|
||||
* Returns the maximum possible timestamp value. Use of this value is required
|
||||
* to properly handle overflow of timestamp values, such as when calculating the
|
||||
* interval between a time value before overflow and the next time value after
|
||||
* overflow.
|
||||
*/
|
||||
uint64_t nanotime_now_max();
|
||||
|
||||
/*
|
||||
* Sleeps the current thread for the requested count of nanoseconds. The slept
|
||||
* duration may be less than, equal to, or greater than the time requested.
|
||||
*/
|
||||
void nanotime_sleep(uint64_t nsec_count);
|
||||
|
||||
/*
|
||||
* Yield the CPU/core that called nanotime_yield to the operating system for a
|
||||
* small time slice.
|
||||
*/
|
||||
void nanotime_yield();
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Calculates the time interval between two nanosecond time values, correctly
|
||||
* handling the case when the end time value overflows past max. You should
|
||||
* probably use this function when calculating time intervals, as not all
|
||||
* platforms' maximum timestamp value is UINT64_MAX, which is required for the
|
||||
* trivial "end - start" formula for interval calculation to work as expected.
|
||||
*/
|
||||
uint64_t nanotime_interval(const uint64_t start, const uint64_t end, const uint64_t max);
|
||||
|
||||
typedef struct nanotime_step_data {
|
||||
uint64_t sleep_duration;
|
||||
uint64_t now_max;
|
||||
uint64_t (* now)();
|
||||
void (* sleep)(uint64_t nsec_count);
|
||||
|
||||
uint64_t zero_sleep_duration;
|
||||
uint64_t accumulator;
|
||||
uint64_t sleep_point;
|
||||
} nanotime_step_data;
|
||||
|
||||
/*
|
||||
* Initializes the nanotime precise fixed timestep object. Call immediately
|
||||
* before entering the loop using the stepper object.
|
||||
*/
|
||||
void nanotime_step_init(
|
||||
nanotime_step_data* const stepper,
|
||||
const uint64_t sleep_duration,
|
||||
const uint64_t now_max,
|
||||
uint64_t (* const now)(),
|
||||
void (* const sleep)(uint64_t nsec_count)
|
||||
);
|
||||
|
||||
/*
|
||||
* Does one step of sleeping for a fixed timestep logic update cycle. It makes
|
||||
* a best-attempt at a precise delay per iteration, but might skip a cycle of
|
||||
* sleeping if skipping sleeps is required to catch up to the correct
|
||||
* wall-clock time. Returns true if a sleep up to the latest target sleep end
|
||||
* time occurred, otherwise returns false in the case of a sleep step skip.
|
||||
*/
|
||||
bool nanotime_step(nanotime_step_data* const stepper);
|
||||
|
||||
#if !defined(NANOTIME_ONLY_STEP) && defined(NANOTIME_IMPLEMENTATION)
|
||||
|
||||
/*
|
||||
* Non-portable, platform-specific implementations are first. If none of them
|
||||
* match the current platform, the standard C/C++ versions are used as a last
|
||||
* resort.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Checking _WIN32 must be above the UNIX-like implementations, so MinGW is
|
||||
* guaranteed to use it.
|
||||
*/
|
||||
#ifdef _WIN32
|
||||
|
||||
#ifndef WIN32_LEAN_AND_MEAN
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#endif
|
||||
#ifndef NOMINMAX
|
||||
#define NOMINMAX
|
||||
#endif
|
||||
#include <Windows.h>
|
||||
|
||||
#ifndef NANOTIME_NOW_IMPLEMENTED
|
||||
uint64_t nanotime_now() {
|
||||
static uint64_t scale = UINT64_C(0);
|
||||
static bool multiply;
|
||||
if (scale == 0u) {
|
||||
LARGE_INTEGER frequency;
|
||||
QueryPerformanceFrequency(&frequency);
|
||||
if (frequency.QuadPart < NANOTIME_NSEC_PER_SEC) {
|
||||
scale = NANOTIME_NSEC_PER_SEC / frequency.QuadPart;
|
||||
multiply = true;
|
||||
}
|
||||
else {
|
||||
scale = frequency.QuadPart / NANOTIME_NSEC_PER_SEC;
|
||||
multiply = false;
|
||||
}
|
||||
}
|
||||
LARGE_INTEGER performanceCount;
|
||||
QueryPerformanceCounter(&performanceCount);
|
||||
if (multiply) {
|
||||
return performanceCount.QuadPart * scale;
|
||||
}
|
||||
else {
|
||||
return performanceCount.QuadPart / scale;
|
||||
}
|
||||
}
|
||||
#define NANOTIME_NOW_IMPLEMENTED
|
||||
#endif
|
||||
|
||||
#ifndef NANOTIME_NOW_MAX_IMPLEMENTED
|
||||
uint64_t nanotime_now_max() {
|
||||
static uint64_t now_max;
|
||||
if (now_max == UINT64_C(0)) {
|
||||
LARGE_INTEGER frequency;
|
||||
QueryPerformanceFrequency(&frequency);
|
||||
if (frequency.QuadPart < NANOTIME_NSEC_PER_SEC) {
|
||||
now_max = UINT64_MAX * (NANOTIME_NSEC_PER_SEC / frequency.QuadPart);
|
||||
}
|
||||
else {
|
||||
now_max = UINT64_MAX / (frequency.QuadPart / NANOTIME_NSEC_PER_SEC);
|
||||
}
|
||||
}
|
||||
return now_max;
|
||||
}
|
||||
#define NANOTIME_NOW_MAX_IMPLEMENTED
|
||||
#endif
|
||||
|
||||
#ifndef NANOTIME_SLEEP_IMPLEMENTED
|
||||
void nanotime_sleep(uint64_t nsec_count) {
|
||||
LARGE_INTEGER dueTime;
|
||||
|
||||
if (nsec_count < UINT64_C(100)) {
|
||||
/*
|
||||
* Allows the OS to schedule another process for a single time
|
||||
* slice. Better than a delay of 0, which immediately returns
|
||||
* with no actual non-CPU-hogging delay. The time-slice-yield
|
||||
* behavior is specified in Microsoft's Windows documentation.
|
||||
*/
|
||||
SleepEx(0UL, FALSE);
|
||||
}
|
||||
else {
|
||||
HANDLE timer = NULL;
|
||||
if (
|
||||
#ifdef CREATE_WAITABLE_TIMER_HIGH_RESOLUTION
|
||||
/*
|
||||
* Requesting a high resolution timer can make quite the
|
||||
* difference, so always request high resolution if available. It's
|
||||
* available in Windows 10 1803 and above. This arrangement of
|
||||
* building it if the build system supports it will allow the
|
||||
* executable to use high resolution if available on a user's
|
||||
* system, but revert to low resolution if the user's system
|
||||
* doesn't support high resolution.
|
||||
*/
|
||||
(timer = CreateWaitableTimerEx(NULL, NULL, CREATE_WAITABLE_TIMER_HIGH_RESOLUTION, TIMER_ALL_ACCESS)) == NULL &&
|
||||
#endif
|
||||
(timer = CreateWaitableTimer(NULL, TRUE, NULL)) == NULL
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
dueTime.QuadPart = -(LONGLONG)(nsec_count / UINT64_C(100));
|
||||
|
||||
SetWaitableTimer(timer, &dueTime, 0L, NULL, NULL, FALSE);
|
||||
WaitForSingleObject(timer, INFINITE);
|
||||
|
||||
CloseHandle(timer);
|
||||
}
|
||||
}
|
||||
#define NANOTIME_SLEEP_IMPLEMENTED
|
||||
#endif
|
||||
|
||||
#ifndef NANOTIME_YIELD_IMPLEMENTED
|
||||
#ifndef WIN32_LEAN_AND_MEAN
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#endif
|
||||
#ifndef NOMINMAX
|
||||
#define NOMINMAX
|
||||
#endif
|
||||
#include <Windows.h>
|
||||
void nanotime_yield() {
|
||||
YieldProcessor();
|
||||
}
|
||||
#define NANOTIME_YIELD_IMPLEMENTED
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
* To avoid using standard UNIX APIs on UNIX-like platforms, the
|
||||
* platform-specific implementations must be first. That way, the
|
||||
* lower-overhead kernel APIs can be used, that aren't UNIX-like.
|
||||
*/
|
||||
|
||||
#ifndef NANOTIME_NOW_IMPLEMENTED
|
||||
#if defined(__APPLE__) || defined(__MACH__)
|
||||
/*
|
||||
* The current platform is some Apple operating system, or at least uses some
|
||||
* Mach kernel. The POSIX implementation below using clock_gettime works on at
|
||||
* least Apple platforms, though this version using Mach functions has lower
|
||||
* overhead.
|
||||
*/
|
||||
#include <mach/mach_time.h>
|
||||
uint64_t nanotime_now() {
|
||||
static mach_timebase_info_data_t info = { 0 };
|
||||
if (info.denom == UINT32_C(0)) {
|
||||
const kern_return_t status = mach_timebase_info(&info);
|
||||
assert(status == KERN_SUCCESS);
|
||||
if (status != KERN_SUCCESS) {
|
||||
return UINT64_C(0);
|
||||
}
|
||||
}
|
||||
return (mach_absolute_time() * info.numer) / info.denom;
|
||||
}
|
||||
#define NANOTIME_NOW_IMPLEMENTED
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef NANOTIME_NOW_MAX_IMPLEMENTED
|
||||
#if defined(__APPLE__) || defined(__MACH__)
|
||||
#include <mach/mach_time.h>
|
||||
uint64_t nanotime_now_max() {
|
||||
static uint64_t now_max = UINT64_C(0);
|
||||
if (now_max == UINT64_C(0)) {
|
||||
mach_timebase_info_data_t info;
|
||||
const kern_return_t status = mach_timebase_info(&info);
|
||||
assert(status == KERN_SUCCESS);
|
||||
if (status != KERN_SUCCESS) {
|
||||
return UINT64_C(0);
|
||||
}
|
||||
else {
|
||||
now_max = UINT64_MAX / info.denom;
|
||||
}
|
||||
}
|
||||
return now_max;
|
||||
}
|
||||
#define NANOTIME_NOW_MAX_IMPLEMENTED
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef NANOTIME_NOW_IMPLEMENTED
|
||||
#if defined(__unix__) && defined(_POSIX_VERSION) && (_POSIX_VERSION >= 199309L) && !defined(NANOTIME_NOW_IMPLEMENTED)
|
||||
/*
|
||||
* Current platform is some version of POSIX, that might have clock_gettime.
|
||||
*/
|
||||
#include <unistd.h>
|
||||
#include <time.h>
|
||||
#include <errno.h>
|
||||
uint64_t nanotime_now() {
|
||||
struct timespec now;
|
||||
const int status = clock_gettime(
|
||||
#if defined(CLOCK_MONOTONIC_RAW)
|
||||
/*
|
||||
* Monotonic raw is more precise, but not always available. For
|
||||
* the sorts of applications this code is intended for, mainly
|
||||
* soft real time applications such as game programming, the
|
||||
* subtle inconsistencies of it vs. monotonic aren't an issue.
|
||||
*/
|
||||
CLOCK_MONOTONIC_RAW
|
||||
#elif defined(CLOCK_MONOTONIC)
|
||||
/*
|
||||
* Monotonic is quite good, and widely available, but not as
|
||||
* precise as monotonic raw, so it's only used if required.
|
||||
*/
|
||||
CLOCK_MONOTONIC
|
||||
#else
|
||||
/*
|
||||
* Realtime isn't fully correct, as it's calendar time, but is
|
||||
* even more widely available than monotonic. Monotonic is only
|
||||
* unavailable on very old platforms though, so old they're
|
||||
* likely unused now (as of last editing this, 2023).
|
||||
*/
|
||||
CLOCK_REALTIME
|
||||
#endif
|
||||
, &now);
|
||||
assert(status == 0 || (status == -1 && errno != EOVERFLOW));
|
||||
if (status == 0 || (status == -1 && errno != EOVERFLOW)) {
|
||||
return (uint64_t)now.tv_sec * NANOTIME_NSEC_PER_SEC + (uint64_t)now.tv_nsec;
|
||||
}
|
||||
else {
|
||||
return UINT64_C(0);
|
||||
}
|
||||
}
|
||||
#define NANOTIME_NOW_IMPLEMENTED
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef NANOTIME_SLEEP_IMPLEMENTED
|
||||
#if defined(__unix__) || (defined(__APPLE__) && defined(__MACH__)) || defined(__MINGW32__) || defined(__MINGW64__)
|
||||
#include <unistd.h>
|
||||
#include <time.h>
|
||||
#include <errno.h>
|
||||
void nanotime_sleep(uint64_t nsec_count) {
|
||||
const struct timespec req = {
|
||||
.tv_sec = (time_t)(nsec_count / NANOTIME_NSEC_PER_SEC),
|
||||
.tv_nsec = (long)(nsec_count % NANOTIME_NSEC_PER_SEC)
|
||||
};
|
||||
#ifndef NDEBUG
|
||||
const int status =
|
||||
#endif
|
||||
nanosleep(&req, NULL);
|
||||
assert(status == 0 || (status == -1 && errno != EINVAL));
|
||||
}
|
||||
#define NANOTIME_SLEEP_IMPLEMENTED
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef NANOTIME_YIELD_IMPLEMENTED
|
||||
#if (defined(__unix__) || defined(__APPLE__)) && defined(_POSIX_VERSION) && (_POSIX_VERSION >= 200112L)
|
||||
#include <sched.h>
|
||||
void nanotime_yield() {
|
||||
(void)sched_yield();
|
||||
}
|
||||
#define NANOTIME_YIELD_IMPLEMENTED
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef NANOTIME_NOW_IMPLEMENTED
|
||||
#if defined(__vita__)
|
||||
#include <psp2/kernel/processmgr.h>
|
||||
uint64_t nanotime_now() {
|
||||
return sceKernelGetProcessTimeWide() * UINT64_C(1000);
|
||||
}
|
||||
#define NANOTIME_NOW_IMPLEMENTED
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef NANOTIME_SLEEP_IMPLEMENTED
|
||||
#if defined(__vita__)
|
||||
#include <psp2/kernel/processmgr.h>
|
||||
void nanotime_sleep(uint64_t nsec_count) {
|
||||
sceKernelDelayThreadCB(nsec_count / UINT64_C(1000));
|
||||
}
|
||||
#define NANOTIME_SLEEP_IMPLEMENTED
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef NANOTIME_SLEEP_IMPLEMENTED
|
||||
#ifdef __EMSCRIPTEN__
|
||||
#include <emscripten.h>
|
||||
/*
|
||||
* NOTE: You *must* have asyncify enabled in the Emscripten build (pass
|
||||
* -sASYNCIFY to the compiler/linker) or sleeping won't work.
|
||||
*/
|
||||
void nanotime_sleep(uint64_t nsec_count) {
|
||||
emscripten_sleep(nsec_count / UINT64_C(1000000));
|
||||
}
|
||||
#define NANOTIME_SLEEP_IMPLEMENTED
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef NANOTIME_NOW_IMPLEMENTED
|
||||
#ifdef __EMSCRIPTEN__
|
||||
#include <emscripten.h>
|
||||
uint64_t nanotime_now() {
|
||||
const double now = emscripten_get_now();
|
||||
return (uint64_t)now * UINT64_C(1000000);
|
||||
}
|
||||
#define NANOTIME_NOW_IMPLEMENTED
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef NANOTIME_SLEEP_IMPLEMENTED
|
||||
#ifdef __SWITCH__
|
||||
#include <switch.h>
|
||||
void nanotime_sleep(uint64_t nsec_count) {
|
||||
if (nsec_count > INT64_MAX) {
|
||||
svcSleepThread(INT64_MAX);
|
||||
}
|
||||
else {
|
||||
svcSleepThread((s64)nsec_count);
|
||||
}
|
||||
}
|
||||
#define NANOTIME_SLEEP_IMPLEMENTED
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef NANOTIME_NOW_IMPLEMENTED
|
||||
#ifdef __SWITCH__
|
||||
#include <switch.h>
|
||||
uint64_t nanotime_now() {
|
||||
return armTicksToNs(armGetSystemTick());
|
||||
}
|
||||
#define NANOTIME_NOW_IMPLEMENTED
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef NANOTIME_YIELD_IMPLEMENTED
|
||||
#if defined(__SWITCH__)
|
||||
#include <switch.h>
|
||||
void nanotime_yield() {
|
||||
svcSleepThread(YieldType_ToAnyThread);
|
||||
}
|
||||
#define NANOTIME_YIELD_IMPLEMENTED
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef NANOTIME_NOW_IMPLEMENTED
|
||||
#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L)
|
||||
#include <time.h>
|
||||
uint64_t nanotime_now() {
|
||||
struct timespec now;
|
||||
const int status = timespec_get(&now, TIME_UTC);
|
||||
assert(status == TIME_UTC);
|
||||
if (status == TIME_UTC) {
|
||||
return (uint64_t)now.tv_sec * NANOTIME_NSEC_PER_SEC + (uint64_t)now.tv_nsec;
|
||||
}
|
||||
else {
|
||||
return UINT64_C(0);
|
||||
}
|
||||
}
|
||||
#define NANOTIME_NOW_IMPLEMENTED
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef NANOTIME_SLEEP_IMPLEMENTED
|
||||
#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L) && !defined(__STDC_NO_THREADS__)
|
||||
#include <threads.h>
|
||||
void nanotime_sleep(uint64_t nsec_count) {
|
||||
const struct timespec req = {
|
||||
.tv_sec = (time_t)(nsec_count / NANOTIME_NSEC_PER_SEC),
|
||||
.tv_nsec = (long)(nsec_count % NANOTIME_NSEC_PER_SEC)
|
||||
};
|
||||
const int status = thrd_sleep(&req, NULL);
|
||||
assert(status == 0 || status == -1);
|
||||
}
|
||||
#define NANOTIME_SLEEP_IMPLEMENTED
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef NANOTIME_YIELD_IMPLEMENTED
|
||||
#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L) && !defined(__STDC_NO_THREADS__)
|
||||
#include <threads.h>
|
||||
void nanotime_yield() {
|
||||
thrd_yield();
|
||||
}
|
||||
#define NANOTIME_YIELD_IMPLEMENTED
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* C++ implementations follow here, but defined with C linkage.
|
||||
*/
|
||||
|
||||
#ifndef NANOTIME_NOW_IMPLEMENTED
|
||||
#ifdef __cplusplus
|
||||
#include <cstdint>
|
||||
#include <chrono>
|
||||
extern "C" uint64_t nanotime_now() {
|
||||
return static_cast<uint64_t>(
|
||||
std::chrono::time_point_cast<std::chrono::nanoseconds>(
|
||||
std::chrono::steady_clock::now()
|
||||
).time_since_epoch().count()
|
||||
);
|
||||
}
|
||||
#define NANOTIME_NOW_IMPLEMENTED
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef NANOTIME_SLEEP_IMPLEMENTED
|
||||
#ifdef __cplusplus
|
||||
#include <cstdint>
|
||||
#include <thread>
|
||||
#include <exception>
|
||||
extern "C" void nanotime_sleep(uint64_t nsec_count) {
|
||||
try {
|
||||
std::this_thread::sleep_for(std::chrono::nanoseconds(nsec_count));
|
||||
}
|
||||
catch (std::exception e) {
|
||||
}
|
||||
}
|
||||
#define NANOTIME_SLEEP_IMPLEMENTED
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef NANOTIME_YIELD_IMPLEMENTED
|
||||
#ifdef __cplusplus
|
||||
#include <thread>
|
||||
extern "C" void nanotime_yield() {
|
||||
std::this_thread::yield();
|
||||
}
|
||||
#define NANOTIME_YIELD_IMPLEMENTED
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef NANOTIME_NOW_IMPLEMENTED
|
||||
#error "Failed to implement nanotime_now (try using C11 with C11 threads support or C++11)."
|
||||
#endif
|
||||
|
||||
#ifndef NANOTIME_SLEEP_IMPLEMENTED
|
||||
#error "Failed to implement nanotime_sleep (try using C11 with C11 threads support or C++11)."
|
||||
#endif
|
||||
|
||||
#ifndef NANOTIME_YIELD_IMPLEMENTED
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
/*
|
||||
* As a last resort, make a zero-duration sleep request to implement yield.
|
||||
* Such sleep requests often have the desired yielding behavior on many
|
||||
* platforms.
|
||||
*/
|
||||
void nanotime_yield() {
|
||||
nanotime_sleep(0u);
|
||||
}
|
||||
#define NANOTIME_YIELD_IMPLEMENTED
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#ifndef NANOTIME_NOW_MAX_IMPLEMENTED
|
||||
/*
|
||||
* Might not be correct on some platforms, but it's the best we can do as a last
|
||||
* resort.
|
||||
*/
|
||||
uint64_t nanotime_now_max() {
|
||||
return UINT64_MAX;
|
||||
}
|
||||
#define NANOTIME_NOW_MAX_IMPLEMENTED
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef NANOTIME_IMPLEMENTATION
|
||||
|
||||
uint64_t nanotime_interval(const uint64_t start, const uint64_t end, const uint64_t max) {
|
||||
assert(max > UINT64_C(0));
|
||||
assert(start <= max);
|
||||
assert(end <= max);
|
||||
|
||||
if (end >= start) {
|
||||
return end - start;
|
||||
}
|
||||
else {
|
||||
return end + (max - start) + UINT64_C(1);
|
||||
}
|
||||
}
|
||||
|
||||
void nanotime_step_init(
|
||||
nanotime_step_data* const stepper,
|
||||
const uint64_t sleep_duration,
|
||||
const uint64_t now_max,
|
||||
uint64_t (* const now)(),
|
||||
void (* const sleep)(uint64_t nsec_count)
|
||||
) {
|
||||
assert(stepper != NULL);
|
||||
assert(sleep_duration > UINT64_C(0));
|
||||
assert(now_max > UINT64_C(0));
|
||||
assert(now != NULL);
|
||||
assert(sleep != NULL);
|
||||
|
||||
stepper->sleep_duration = sleep_duration;
|
||||
stepper->now_max = now_max;
|
||||
stepper->now = now;
|
||||
stepper->sleep = sleep;
|
||||
|
||||
const uint64_t start = now();
|
||||
sleep(UINT64_C(0));
|
||||
stepper->zero_sleep_duration = nanotime_interval(start, now(), now_max);
|
||||
stepper->accumulator = UINT64_C(0);
|
||||
|
||||
/*
|
||||
* This should be last here, so the sleep point is close to what it
|
||||
* should be.
|
||||
*/
|
||||
stepper->sleep_point = now();
|
||||
}
|
||||
|
||||
bool nanotime_step(nanotime_step_data* const stepper) {
|
||||
assert(stepper != NULL);
|
||||
|
||||
const uint64_t start_point = stepper->now();
|
||||
|
||||
if (nanotime_interval(stepper->sleep_point, start_point, stepper->now_max) >= stepper->sleep_duration + NANOTIME_NSEC_PER_SEC / UINT64_C(10)) {
|
||||
stepper->sleep_point = start_point;
|
||||
stepper->accumulator = UINT64_C(0);
|
||||
}
|
||||
|
||||
bool slept;
|
||||
if (stepper->accumulator < stepper->sleep_duration) {
|
||||
const uint64_t total_sleep_duration = stepper->sleep_duration - stepper->accumulator;
|
||||
uint64_t current_sleep_duration = total_sleep_duration;
|
||||
const uint64_t shift = UINT64_C(4);
|
||||
|
||||
/*
|
||||
* The algorithm implemented here takes the assumption that a
|
||||
* sequence of repeated sleep requests of the same requested
|
||||
* duration end up being approximately of equal actual sleep
|
||||
* duration, even if they're all well above the requested
|
||||
* duration. In practice, such an assumption proves out to be
|
||||
* true on various platforms.
|
||||
*/
|
||||
|
||||
/*
|
||||
* A big initial sleep lowers power usage on any platform, as
|
||||
* more small sleep requests use more power than fewer bigger,
|
||||
* equivalent sleep requests. In practice, operating systems
|
||||
* "actually sleep" when 1ms or more is requested, and 1ms is
|
||||
* the minimum request duration you can make on some platforms
|
||||
* (like older versions of Windows). Additionally, power usage
|
||||
* is nice and low when doing the number of 1ms sleeps that's
|
||||
* (hopefully) short of the target duration.
|
||||
*
|
||||
* But, the loop here maintains a maximum of the actual slept
|
||||
* durations, breaking out when the time remaining is greater
|
||||
* than or equal to the maximum found. By breaking out on the
|
||||
* maximum found rather than just 1ms-or-less remaining,
|
||||
* sleeping beyond the target deadline is reduced.
|
||||
*/
|
||||
{
|
||||
uint64_t max = NANOTIME_NSEC_PER_SEC / UINT64_C(1000);
|
||||
uint64_t start = stepper->now();
|
||||
while (nanotime_interval(stepper->sleep_point, start, stepper->now_max) + max < total_sleep_duration) {
|
||||
stepper->sleep(NANOTIME_NSEC_PER_SEC / UINT64_C(1000));
|
||||
const uint64_t next = stepper->now();
|
||||
const uint64_t current_interval = nanotime_interval(start, next, stepper->now_max);
|
||||
if (current_interval > max) {
|
||||
max = current_interval;
|
||||
}
|
||||
start = next;
|
||||
}
|
||||
const uint64_t initial_duration = nanotime_interval(start_point, stepper->now(), stepper->now_max);
|
||||
if (initial_duration < current_sleep_duration) {
|
||||
current_sleep_duration -= initial_duration;
|
||||
}
|
||||
else {
|
||||
goto step_end;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* This has the flavor of Zeno's dichotomous paradox of motion,
|
||||
* as it successively divides the time remaining to sleep, but
|
||||
* attempts to stop short of the deadline to hopefully be able
|
||||
* to precisely sleep up to the deadline below this loop. The
|
||||
* divisor is larger than two though, as it produces better
|
||||
* behavior, and seems to work fine in testing on real
|
||||
* hardware. The same method of keeping track of the max
|
||||
* duration per loop of same sleep request durations above is
|
||||
* used here. The overshoot possible in the loop below this one
|
||||
* won't overshoot much, or in the best case won't overshoot,
|
||||
* so the busyloop can finish up the sleep precisely.
|
||||
*/
|
||||
current_sleep_duration >>= shift;
|
||||
for (
|
||||
uint64_t max = stepper->zero_sleep_duration;
|
||||
nanotime_interval(stepper->sleep_point, stepper->now(), stepper->now_max) + max < total_sleep_duration && current_sleep_duration > UINT64_C(0);
|
||||
current_sleep_duration >>= shift
|
||||
) {
|
||||
max = stepper->zero_sleep_duration;
|
||||
uint64_t start;
|
||||
while (max < stepper->sleep_duration && nanotime_interval(stepper->sleep_point, start = stepper->now(), stepper->now_max) + max < total_sleep_duration) {
|
||||
stepper->sleep(current_sleep_duration);
|
||||
uint64_t slept_duration;
|
||||
if ((slept_duration = nanotime_interval(start, stepper->now(), stepper->now_max)) > max) {
|
||||
max = slept_duration;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (nanotime_interval(stepper->sleep_point, stepper->now(), stepper->now_max) >= total_sleep_duration) {
|
||||
goto step_end;
|
||||
}
|
||||
|
||||
{
|
||||
/*
|
||||
* After (hopefully) stopping short of the deadline by
|
||||
* a small amount, do small sleeps here to get closer
|
||||
* to the deadline, but again attempting to stop short
|
||||
* by an even smaller amount. It's best to do larger
|
||||
* sleeps as done in the above loops, to reduce
|
||||
* CPU/power usage, as each sleep iteration has a
|
||||
* more-or-less fixed overhead of CPU/power usage.
|
||||
*
|
||||
* In testing on an M1 Mac mini running macOS, power
|
||||
* usage is lower using zero-duration sleeps vs.
|
||||
* nanotime_yield(), with no loss of timing precision.
|
||||
* The same might be true for other hardwares/operating
|
||||
* systems.
|
||||
*/
|
||||
uint64_t max = stepper->zero_sleep_duration;
|
||||
uint64_t start;
|
||||
while (nanotime_interval(stepper->sleep_point, start = stepper->now(), stepper->now_max) + max < total_sleep_duration) {
|
||||
stepper->sleep(UINT64_C(0));
|
||||
if ((stepper->zero_sleep_duration = nanotime_interval(start, stepper->now(), stepper->now_max)) > max) {
|
||||
max = stepper->zero_sleep_duration;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
step_end:
|
||||
{
|
||||
/*
|
||||
* Finally, do a busyloop to precisely sleep up to the
|
||||
* deadline. The code above this loop attempts to
|
||||
* reduce the remaining time to sleep to a minimum via
|
||||
* process-yielding sleeps, so the amount of time spent
|
||||
* spinning here is hopefully quite low.
|
||||
*
|
||||
* In testing on an M1 Mac mini running macOS,
|
||||
* busylooping here produces the absolute greatest
|
||||
* precision possible on the hardware, down to the
|
||||
* sub-10ns-off-per-update range for longish stretches
|
||||
* during 60 Hz updates, but in the
|
||||
* hundreds-to-thousands of nanoseconds off when using
|
||||
* nanotime_yield() or zero-duration sleeps. And,
|
||||
* because the sleeping algorithm above does such a
|
||||
* good job of stopping very close to the deadline,
|
||||
* busylooping here has basically negligible difference
|
||||
* in power usage vs. yields/zero-duration sleeps.
|
||||
*/
|
||||
uint64_t current_time;
|
||||
uint64_t accumulated;
|
||||
while ((accumulated = nanotime_interval(stepper->sleep_point, current_time = stepper->now(), stepper->now_max)) < total_sleep_duration);
|
||||
|
||||
stepper->accumulator += accumulated;
|
||||
stepper->sleep_point = current_time;
|
||||
slept = true;
|
||||
}
|
||||
}
|
||||
else {
|
||||
slept = false;
|
||||
}
|
||||
stepper->accumulator -= stepper->sleep_duration;
|
||||
return slept;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _include_guard_nanotime_ */
|
192
image_framework/thead/LibapiProcessThread.cpp
Executable file
192
image_framework/thead/LibapiProcessThread.cpp
Executable file
@ -0,0 +1,192 @@
|
||||
#include <iostream>
|
||||
#include <chrono>
|
||||
#include <mutex>
|
||||
#include <cassert>
|
||||
#include <typeinfo>
|
||||
#include <iostream>
|
||||
//#include <spdlog/async.h>
|
||||
#include "LibapiProcessThread.h"
|
||||
#include "LibapiMsg.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
LibapiProcessThread::LibapiProcessThread(int id, std::string name, BaseRunnable* runnable):
|
||||
LibapiThread(id, name, runnable)
|
||||
{
|
||||
}
|
||||
|
||||
LibapiProcessThread::~LibapiProcessThread()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void LibapiProcessThread::set_parent_thread(LibapiProcessThread* pParentThread)
|
||||
{
|
||||
pParentThread->add_sub_thread(this);
|
||||
this->m_parent = pParentThread;
|
||||
}
|
||||
|
||||
void LibapiProcessThread::add_sub_thread(LibapiProcessThread* pSubThread)
|
||||
{
|
||||
for (auto it = m_sub_threads.begin(); it < m_sub_threads.end(); it++)
|
||||
{
|
||||
if ((*it)->m_id == pSubThread->get_id() || (*it)->m_name == pSubThread->get_name())
|
||||
{
|
||||
//spdlog::info(this->get_name() + " 添加重名子线程 " + pSubThread->get_name());
|
||||
std::cout << this->get_name() << " 添加重名子线程 " << pSubThread->get_name() << std::endl;
|
||||
assert(0);
|
||||
}
|
||||
}
|
||||
if (pSubThread->m_parent != nullptr)
|
||||
{
|
||||
//spdlog::info(this->get_name() + " pSubThread->m_parent != nullptr " + pSubThread->get_name());
|
||||
std::cout << this->get_name() << " pSubThread->m_parent != nullptr " << pSubThread->get_name() << std::endl;
|
||||
assert(0);
|
||||
}
|
||||
|
||||
this->m_sub_threads.emplace_back(pSubThread);
|
||||
Signal sig = { pSubThread->get_id(), false };
|
||||
this->m_sub_thread_signal.emplace_back(sig);
|
||||
pSubThread->m_parent = this;
|
||||
}
|
||||
|
||||
void LibapiProcessThread::set_next_thread(LibapiProcessThread* pNextThread)
|
||||
{
|
||||
m_next_threads.emplace_back(pNextThread);
|
||||
//m_next_thread = pNextThread;
|
||||
}
|
||||
|
||||
void LibapiProcessThread::reset_sub_thread_signal(std::vector<Signal>& sub_thread_signal)
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(m_sig_mutex);
|
||||
|
||||
for (auto it = sub_thread_signal.begin(); it < sub_thread_signal.end(); it++)
|
||||
{
|
||||
(*it).end = false;
|
||||
}
|
||||
}
|
||||
|
||||
void LibapiProcessThread::update_sub_thread_signal(LibapiProcessThread* pThread)
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(m_sig_mutex);
|
||||
|
||||
for (auto it = m_sub_thread_signal.begin(); it < m_sub_thread_signal.end(); it++)
|
||||
{
|
||||
if ((*it).id == pThread->get_id())
|
||||
{
|
||||
(*it).end = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool LibapiProcessThread::check_all_sub_complete()
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(m_sig_mutex);
|
||||
|
||||
for (auto it = m_sub_thread_signal.begin(); it < m_sub_thread_signal.end(); it++)
|
||||
{
|
||||
if ((*it).end == false)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// override function
|
||||
void LibapiProcessThread::run()
|
||||
{
|
||||
int ret = 0;
|
||||
while (!m_stopFlag)
|
||||
{
|
||||
if (m_pauseFlag)
|
||||
{
|
||||
unique_lock<mutex> locker(m_mutex);
|
||||
while (m_pauseFlag)
|
||||
{
|
||||
m_condition.wait(locker);
|
||||
}
|
||||
locker.unlock();
|
||||
}
|
||||
|
||||
void* pMsg = NULL;
|
||||
m_queue->pop(pMsg);
|
||||
|
||||
if (m_prunnable != NULL && pMsg != NULL)
|
||||
{
|
||||
m_prunnable->get_start_time();
|
||||
ret = m_prunnable->OnProcess(this, pMsg);
|
||||
//处理完,如果pMsg为null,则不再处理了
|
||||
if (ret == -1) continue;
|
||||
}
|
||||
|
||||
reset_sub_thread_signal(m_sub_thread_signal);
|
||||
if (m_sub_threads.size() > 0)
|
||||
{
|
||||
bool succ = false;
|
||||
for (auto it = m_sub_threads.begin(); it < m_sub_threads.end(); it++)
|
||||
{
|
||||
LibapiThread* subThread = (LibapiThread*)(*it);
|
||||
((LibapiMsg*)pMsg)->add_ref();
|
||||
succ = subThread->push(pMsg);
|
||||
// 如果push成功,加引用
|
||||
if (!succ)
|
||||
{
|
||||
((LibapiMsg*)pMsg)->sub_ref();
|
||||
update_sub_thread_signal((LibapiProcessThread*)subThread);
|
||||
}
|
||||
}
|
||||
|
||||
if (!check_all_sub_complete())
|
||||
{
|
||||
unique_lock<mutex> locker(m_mutex);
|
||||
while (!check_all_sub_complete())
|
||||
{
|
||||
m_condition.wait(locker);
|
||||
// LibapiThread::delay_second(0.001);
|
||||
}
|
||||
locker.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
if (m_prunnable != NULL && pMsg != NULL)
|
||||
{
|
||||
m_prunnable->OnEndProcess(this, pMsg);
|
||||
}
|
||||
|
||||
int next_thread_size = m_next_threads.size();
|
||||
if (next_thread_size == 1)
|
||||
{
|
||||
((LibapiMsg*)pMsg)->add_ref();
|
||||
int succ = m_next_threads[0]->push(pMsg);
|
||||
if (!succ)
|
||||
((LibapiMsg*)pMsg)->sub_ref();
|
||||
}
|
||||
else if (next_thread_size > 1)
|
||||
{
|
||||
((LibapiMsg*)pMsg)->add_ref();
|
||||
int succ = m_next_threads[m_cur_index % next_thread_size]->push(pMsg);
|
||||
// 如果push不成功,减引用
|
||||
if (!succ)
|
||||
((LibapiMsg*)pMsg)->sub_ref();
|
||||
m_cur_index++;
|
||||
if (m_cur_index == next_thread_size) m_cur_index = 0;
|
||||
}
|
||||
|
||||
if (m_parent != NULL)
|
||||
{
|
||||
m_parent->update_sub_thread_signal(this);
|
||||
m_parent->notify();
|
||||
}
|
||||
|
||||
// 消息处理完成,减引用
|
||||
int ref = ((LibapiMsg*)pMsg)->sub_ref();
|
||||
if (ref==0) ((LibapiMsg*)pMsg)->delete_msg();
|
||||
}
|
||||
|
||||
m_pauseFlag = false;
|
||||
m_stopFlag = false;
|
||||
|
||||
//spdlog::info("exit thread:%d", get_id());
|
||||
}
|
93
image_framework/thead/LibapiProcessThread.h
Executable file
93
image_framework/thead/LibapiProcessThread.h
Executable file
@ -0,0 +1,93 @@
|
||||
#ifndef LIBAPI_PROCESS_THREAD_H
|
||||
#define LIBAPI_PROCESS_THREAD_H
|
||||
|
||||
#include <thread>
|
||||
#include <atomic>
|
||||
#include <mutex>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include <condition_variable>
|
||||
#include "LibapiThread.h"
|
||||
#include "LibapiQueue.h"
|
||||
#include "LibapiQueues.h"
|
||||
|
||||
struct Signal
|
||||
{
|
||||
int id;
|
||||
bool end = false;
|
||||
};
|
||||
|
||||
class LibapiProcessThread;
|
||||
typedef LibapiProcessThread ProThread;
|
||||
typedef std::shared_ptr<LibapiProcessThread> SharedThread;
|
||||
|
||||
// 全局线程管理
|
||||
static std::vector<SharedThread> shared_threads;
|
||||
static std::mutex g_mutex;
|
||||
|
||||
class LibapiProcessThread : public LibapiThread
|
||||
{
|
||||
public:
|
||||
static std::vector<SharedThread>* get_shared_threads()
|
||||
{
|
||||
return &shared_threads;
|
||||
};
|
||||
|
||||
template<class T>
|
||||
static std::shared_ptr<LibapiProcessThread> create(std::string thread_name = "")
|
||||
{
|
||||
std::unique_lock<std::mutex> locker(g_mutex);
|
||||
|
||||
T* plugin = new T();
|
||||
|
||||
std::string type_name;
|
||||
if (thread_name == "") type_name = typeid(plugin).name();
|
||||
else type_name = thread_name;
|
||||
|
||||
SharedThread ptr = std::make_shared<LibapiProcessThread>(-1, type_name,(IRunnable*)plugin);
|
||||
shared_threads.push_back(ptr);
|
||||
return ptr;
|
||||
};
|
||||
|
||||
template<class T>
|
||||
static std::shared_ptr<LibapiProcessThread> create_and_start(std::string thread_name = "")
|
||||
{
|
||||
std::unique_lock<std::mutex> locker(g_mutex);
|
||||
|
||||
T* plugin = new T();
|
||||
|
||||
std::string type_name;
|
||||
if (thread_name == "") type_name = typeid(plugin).name();
|
||||
else type_name = thread_name;
|
||||
|
||||
SharedThread ptr = std::make_shared<LibapiProcessThread>(-1, type_name, (BaseRunnable*)plugin);
|
||||
ptr->start();
|
||||
shared_threads.push_back(ptr);
|
||||
return ptr;
|
||||
};
|
||||
|
||||
public:
|
||||
LibapiProcessThread(int id, std::string name, BaseRunnable* runnable);
|
||||
virtual ~LibapiProcessThread();
|
||||
void set_parent_thread(LibapiProcessThread* pThread);
|
||||
void add_sub_thread(LibapiProcessThread* pParentThread);
|
||||
void set_next_thread(LibapiProcessThread* pSubThread);
|
||||
void update_sub_thread_signal(LibapiProcessThread* pThread);
|
||||
void run(); // override function
|
||||
|
||||
private:
|
||||
void reset_sub_thread_signal(std::vector<Signal>& sub_thread_signal);
|
||||
bool check_all_sub_complete();
|
||||
|
||||
private:
|
||||
LibapiProcessThread* m_parent = NULL;
|
||||
std::vector<LibapiProcessThread*> m_sub_threads;
|
||||
std::vector<Signal> m_sub_thread_signal;
|
||||
//LibapiProcessThread* m_next_thread = NULL;
|
||||
std::vector<LibapiProcessThread*> m_next_threads;
|
||||
int m_cur_index = 0;
|
||||
std::mutex m_sig_mutex;
|
||||
};
|
||||
|
||||
#endif // LIBAPITHREAD_H
|
350
image_framework/thead/LibapiQueue.h
Executable file
350
image_framework/thead/LibapiQueue.h
Executable file
@ -0,0 +1,350 @@
|
||||
/*
|
||||
* LibapiQueue.hpp
|
||||
* Copyright (C) 2019 Alfredo Pons Menargues <apons@linucleus.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
* See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef SAFEQUEUE_HPP_
|
||||
#define SAFEQUEUE_HPP_
|
||||
|
||||
#include <queue>
|
||||
#include <list>
|
||||
#include <mutex>
|
||||
#include <thread>
|
||||
#include <cstdint>
|
||||
#include <condition_variable>
|
||||
//#include "spdlog/spdlog.h"
|
||||
|
||||
|
||||
/** A thread-safe asynchronous queue */
|
||||
template <class T, class Container = std::list<T>>
|
||||
class LibapiQueue
|
||||
{
|
||||
typedef typename Container::value_type value_type;
|
||||
typedef typename Container::size_type size_type;
|
||||
typedef Container container_type;
|
||||
|
||||
public:
|
||||
/*! Create safe queue. */
|
||||
LibapiQueue() = default;
|
||||
|
||||
LibapiQueue(int id, std::string name)
|
||||
{
|
||||
m_id = id;
|
||||
m_name = name;
|
||||
// 测试使用,默认两张图
|
||||
m_max_num_items = 32;
|
||||
}
|
||||
|
||||
LibapiQueue (LibapiQueue&& sq)
|
||||
{
|
||||
m_queue = std::move (sq.m_queue);
|
||||
}
|
||||
|
||||
LibapiQueue (const LibapiQueue& sq)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock (sq.m_mutex);
|
||||
m_queue = sq.m_queue;
|
||||
}
|
||||
|
||||
|
||||
/*! Destroy safe queue. */
|
||||
~LibapiQueue()
|
||||
{
|
||||
std::lock_guard<std::mutex> lock (m_mutex);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the maximum number of items in the queue. Defaults is 0: No limit
|
||||
* \param[in] item An item.
|
||||
*/
|
||||
void set_max_num_items (unsigned int max_num_items)
|
||||
{
|
||||
m_max_num_items = max_num_items;
|
||||
}
|
||||
|
||||
/**
|
||||
* Pushes the item into the queue.
|
||||
* \param[in] item An item.
|
||||
* \return true if an item was pushed into the queue
|
||||
*/
|
||||
bool push (const value_type& item)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock (m_mutex);
|
||||
|
||||
if (m_max_num_items > 0 && m_queue.size() > m_max_num_items)
|
||||
return false;
|
||||
|
||||
m_queue.push (item);
|
||||
m_condition.notify_all();
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Pushes the item into the queue.
|
||||
* \param[in] item An item.
|
||||
* \return true if an item was pushed into the queue
|
||||
*/
|
||||
bool push (const value_type&& item)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock (m_mutex);
|
||||
|
||||
if (m_max_num_items > 0 && m_queue.size() > m_max_num_items)
|
||||
return false;
|
||||
|
||||
m_queue.push (item);
|
||||
m_condition.notify_one();
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Pops item from the queue. If queue is empty, this function blocks until item becomes available.
|
||||
* \param[out] item The item.
|
||||
*/
|
||||
void pop (value_type& item)
|
||||
{
|
||||
std::unique_lock<std::mutex> lock (m_mutex);
|
||||
while (m_queue.empty())
|
||||
{
|
||||
m_condition.wait (lock, [this]() // Lambda funct
|
||||
{
|
||||
return !m_queue.empty();
|
||||
});
|
||||
}
|
||||
|
||||
item = m_queue.front();
|
||||
m_queue.pop();
|
||||
}
|
||||
|
||||
/**
|
||||
* Pops item from the queue using the contained type's move assignment operator, if it has one..
|
||||
* This method is identical to the pop() method if that type has no move assignment operator.
|
||||
* If queue is empty, this function blocks until item becomes available.
|
||||
* \param[out] item The item.
|
||||
*/
|
||||
void move_pop (value_type& item)
|
||||
{
|
||||
std::unique_lock<std::mutex> lock (m_mutex);
|
||||
while (m_queue.empty())
|
||||
{
|
||||
m_condition.wait(lock, [this]() // Lambda funct
|
||||
{
|
||||
return !m_queue.empty();
|
||||
});
|
||||
}
|
||||
|
||||
item = std::move (m_queue.front());
|
||||
m_queue.pop();
|
||||
}
|
||||
|
||||
/**
|
||||
* Tries to pop item from the queue.
|
||||
* \param[out] item The item.
|
||||
* \return False is returned if no item is available.
|
||||
*/
|
||||
bool try_pop (value_type& item)
|
||||
{
|
||||
std::unique_lock<std::mutex> lock (m_mutex);
|
||||
|
||||
if (m_queue.empty())
|
||||
return false;
|
||||
|
||||
item = m_queue.front();
|
||||
m_queue.pop();
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tries to pop item from the queue using the contained type's move assignment operator, if it has one..
|
||||
* This method is identical to the try_pop() method if that type has no move assignment operator.
|
||||
* \param[out] item The item.
|
||||
* \return False is returned if no item is available.
|
||||
*/
|
||||
bool try_move_pop (value_type& item)
|
||||
{
|
||||
std::unique_lock<std::mutex> lock (m_mutex);
|
||||
|
||||
if (m_queue.empty())
|
||||
return false;
|
||||
|
||||
item = std::move (m_queue.front());
|
||||
m_queue.pop();
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Pops item from the queue. If the queue is empty, blocks for timeout microseconds, or until item becomes available.
|
||||
* \param[out] t An item.
|
||||
* \param[in] timeout The number of microseconds to wait.
|
||||
* \return true if get an item from the queue, false if no item is received before the timeout.
|
||||
*/
|
||||
bool timeout_pop (value_type& item, std::uint64_t timeout)
|
||||
{
|
||||
std::unique_lock<std::mutex> lock (m_mutex);
|
||||
|
||||
if (m_queue.empty())
|
||||
{
|
||||
if (timeout == 0)
|
||||
return false;
|
||||
|
||||
if (m_condition.wait_for (lock, std::chrono::microseconds (timeout)) == std::cv_status::timeout)
|
||||
return false;
|
||||
}
|
||||
|
||||
item = m_queue.front();
|
||||
m_queue.pop();
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Pops item from the queue using the contained type's move assignment operator, if it has one..
|
||||
* If the queue is empty, blocks for timeout microseconds, or until item becomes available.
|
||||
* This method is identical to the try_pop() method if that type has no move assignment operator.
|
||||
* \param[out] t An item.
|
||||
* \param[in] timeout The number of microseconds to wait.
|
||||
* \return true if get an item from the queue, false if no item is received before the timeout.
|
||||
*/
|
||||
bool timeout_move_pop (value_type& item, std::uint64_t timeout)
|
||||
{
|
||||
std::unique_lock<std::mutex> lock (m_mutex);
|
||||
|
||||
if (m_queue.empty())
|
||||
{
|
||||
if (timeout == 0)
|
||||
return false;
|
||||
|
||||
if (m_condition.wait_for (lock, std::chrono::microseconds (timeout)) == std::cv_status::timeout)
|
||||
return false;
|
||||
}
|
||||
|
||||
item = std::move (m_queue.front());
|
||||
m_queue.pop();
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the number of items in the queue.
|
||||
* \return Number of items in the queue.
|
||||
*/
|
||||
size_type size() const
|
||||
{
|
||||
std::lock_guard<std::mutex> lock (m_mutex);
|
||||
return m_queue.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the queue is empty.
|
||||
* \return true if queue is empty.
|
||||
*/
|
||||
bool empty() const
|
||||
{
|
||||
std::lock_guard<std::mutex> lock (m_mutex);
|
||||
return m_queue.empty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Swaps the contents.
|
||||
* \param[out] sq The LibapiQueue to swap with 'this'.
|
||||
*/
|
||||
void swap (LibapiQueue& sq)
|
||||
{
|
||||
if (this != &sq)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock1 (m_mutex);
|
||||
std::lock_guard<std::mutex> lock2 (sq.m_mutex);
|
||||
m_queue.swap (sq.m_queue);
|
||||
|
||||
if (!m_queue.empty())
|
||||
m_condition.notify_all();
|
||||
|
||||
if (!sq.m_queue.empty())
|
||||
sq.m_condition.notify_all();
|
||||
}
|
||||
}
|
||||
|
||||
/*! The copy assignment operator */
|
||||
LibapiQueue& operator= (const LibapiQueue& sq)
|
||||
{
|
||||
if (this != &sq)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock1 (m_mutex);
|
||||
std::lock_guard<std::mutex> lock2 (sq.m_mutex);
|
||||
std::queue<T, Container> temp {sq.m_queue};
|
||||
m_queue.swap (temp);
|
||||
|
||||
if (!m_queue.empty())
|
||||
m_condition.notify_all();
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
/*! The move assignment operator */
|
||||
LibapiQueue& operator= (LibapiQueue && sq)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock (m_mutex);
|
||||
m_queue = std::move (sq.m_queue);
|
||||
|
||||
if (!m_queue.empty()) m_condition.notify_all();
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
void set_id(int id)
|
||||
{
|
||||
m_id = id;
|
||||
}
|
||||
|
||||
int get_id()
|
||||
{
|
||||
return m_id;
|
||||
}
|
||||
|
||||
void set_name(std::string name)
|
||||
{
|
||||
m_name = name;
|
||||
}
|
||||
|
||||
std::string get_name()
|
||||
{
|
||||
return m_name;
|
||||
}
|
||||
|
||||
private:
|
||||
int m_id;
|
||||
std::string m_name;
|
||||
std::queue<T, Container> m_queue;
|
||||
mutable std::mutex m_mutex;
|
||||
std::condition_variable m_condition;
|
||||
unsigned int m_max_num_items = 32;
|
||||
};
|
||||
|
||||
/*! Swaps the contents of two LibapiQueue objects. */
|
||||
template <class T, class Container>
|
||||
void swap(LibapiQueue<T, Container>& q1, LibapiQueue<T, Container>& q2)
|
||||
{
|
||||
q1.swap(q2);
|
||||
}
|
||||
#endif /* SAFEQUEUE_HPP_ */
|
||||
|
||||
// #include <LibapiQueue.hpp>
|
||||
|
||||
// int main()
|
||||
// {
|
||||
// LibapiQueue <int> my_queue;
|
||||
|
||||
// my_queue.push(1);
|
||||
|
||||
// return 0;
|
||||
// }
|
104
image_framework/thead/LibapiQueues.cpp
Executable file
104
image_framework/thead/LibapiQueues.cpp
Executable file
@ -0,0 +1,104 @@
|
||||
#include "LibapiQueues.h"
|
||||
#include <cassert>
|
||||
#include <iostream>
|
||||
|
||||
|
||||
static std::vector<LibapiQueue<void*>*> _queues;
|
||||
|
||||
void Queues::add_to_queue_list(LibapiQueue<void*>* queue)
|
||||
{
|
||||
for (auto it=_queues.begin(); it!=_queues.end(); it++)
|
||||
{
|
||||
|
||||
LibapiQueue<void*>* sq = (LibapiQueue<void*>*)(*it);
|
||||
if (sq->get_id() == queue->get_id() || sq->get_name() == queue->get_name())
|
||||
{
|
||||
assert(0);
|
||||
}
|
||||
}
|
||||
_queues.push_back(queue);
|
||||
}
|
||||
|
||||
void Queues::remove_from_queue_list(int& id)
|
||||
{
|
||||
for (auto it = _queues.begin(); it != _queues.end(); it++)
|
||||
{
|
||||
LibapiQueue<void*>* sq = (LibapiQueue<void*>*)(*it);
|
||||
if (sq->get_id() == id)
|
||||
{
|
||||
_queues.erase(it);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
LibapiQueue<void*>* Queues::find_queue(int& id)
|
||||
{
|
||||
for (auto it = _queues.begin(); it != _queues.end(); it++)
|
||||
{
|
||||
LibapiQueue<void*>* sq = (LibapiQueue<void*>*)(*it);
|
||||
if (sq->get_id() == id) return sq;
|
||||
}
|
||||
return NULL;
|
||||
//auto it = std::find_if(LibapiQueue::get_queues().begin(), LibapiQueue::get_queues().end(), [&](const LibapiQueue* sq)
|
||||
// return sq->get_id() == id);
|
||||
//if (it != LibapiQueue::get_queues().end()) return (LibapiQueue*)it;
|
||||
//else return NULL;
|
||||
}
|
||||
|
||||
LibapiQueue<void*>* Queues::find_queue(std::string& name)
|
||||
{
|
||||
for (auto it = _queues.begin(); it != _queues.end(); it++)
|
||||
{
|
||||
LibapiQueue<void*>* sq = (LibapiQueue<void*>*)(*it);
|
||||
if (sq->get_name() == name) return sq;
|
||||
}
|
||||
return NULL;
|
||||
//auto it = std::find_if(LibapiQueue::get_queues().begin(), LibapiQueue::get_queues().end(), [&](const LibapiQueue* sq)
|
||||
// return sq - get_name() == name);
|
||||
//if (it != LibapiQueue::get_queues().end()) return (LibapiQueue*)it;
|
||||
//else return NULL;
|
||||
}
|
||||
|
||||
std::vector<LibapiQueue<void*>*> Queues::get_queues()
|
||||
{
|
||||
return _queues;
|
||||
}
|
||||
|
||||
LibapiQueue<void*>* Queues::create_queue(int& id, std::string& name)
|
||||
{
|
||||
LibapiQueue<void*>* sq = new LibapiQueue<void*>(id, name);
|
||||
add_to_queue_list(sq);
|
||||
return sq;
|
||||
}
|
||||
|
||||
void Queues::delete_queue(LibapiQueue<void*>* queue)
|
||||
{
|
||||
if (queue != NULL)
|
||||
{
|
||||
int id = queue->get_id();
|
||||
remove_from_queue_list(id);
|
||||
delete queue;
|
||||
queue = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void Queues::clear()
|
||||
{
|
||||
for (auto it = _queues.begin(); it != _queues.end(); it++)
|
||||
if ((*it) != NULL)
|
||||
delete (*it);
|
||||
_queues.clear();
|
||||
}
|
||||
|
||||
int Queues::push_to_queue(char* queue_name, void* msg)
|
||||
{
|
||||
std::string qname(queue_name);
|
||||
LibapiQueue<void*>* queue = find_queue(qname);
|
||||
if (queue == NULL) return -1;
|
||||
bool ret = queue->push(msg);
|
||||
if (ret)
|
||||
return 0;
|
||||
else
|
||||
return -1;
|
||||
}
|
31
image_framework/thead/LibapiQueues.h
Executable file
31
image_framework/thead/LibapiQueues.h
Executable file
@ -0,0 +1,31 @@
|
||||
#ifndef LIBAPIQUEUE_HPP_
|
||||
#define LIBAPIQUEUE_HPP_
|
||||
|
||||
#include "LibapiQueue.h"
|
||||
|
||||
class Queues
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
static void add_to_queue_list(LibapiQueue<void*>* queue);
|
||||
|
||||
static void remove_from_queue_list(int& id);
|
||||
|
||||
static LibapiQueue<void*>* find_queue(int& id);
|
||||
|
||||
static LibapiQueue<void*>* find_queue(std::string& name);
|
||||
|
||||
static std::vector<LibapiQueue<void*>*> get_queues();
|
||||
|
||||
static LibapiQueue<void*>* create_queue(int& id, std::string& name);
|
||||
|
||||
static void delete_queue(LibapiQueue<void*>* queue);
|
||||
|
||||
static void clear();
|
||||
|
||||
static int push_to_queue(char* queue_name, void* msg);
|
||||
|
||||
};
|
||||
|
||||
#endif /* LIBAPIQUEUE_HPP_ */
|
207
image_framework/thead/LibapiThread.cpp
Executable file
207
image_framework/thead/LibapiThread.cpp
Executable file
@ -0,0 +1,207 @@
|
||||
#include <iostream>
|
||||
#include <time.h>
|
||||
#include <stdio.h>
|
||||
#include <chrono>
|
||||
#include "LibapiThread.h"
|
||||
#include "LibapiQueue.h"
|
||||
#include "LibapiQueues.h"
|
||||
#include <iostream>
|
||||
|
||||
using namespace std;
|
||||
|
||||
static int id_max = -1;
|
||||
|
||||
LibapiThread::LibapiThread(int id, std::string name, BaseRunnable* runnable)
|
||||
: m_pthread(nullptr),
|
||||
m_pauseFlag(false),
|
||||
m_stopFlag(false),
|
||||
m_state(Stoped),
|
||||
m_id(id),
|
||||
m_name(name),
|
||||
m_prunnable(runnable)
|
||||
{
|
||||
if (m_id == -1)
|
||||
{
|
||||
m_id = id_max + 1;
|
||||
id_max++;
|
||||
}
|
||||
m_queue = Queues::create_queue(m_id, m_name);
|
||||
}
|
||||
|
||||
LibapiThread::~LibapiThread()
|
||||
{
|
||||
Queues::delete_queue(this->m_queue);
|
||||
stop();
|
||||
}
|
||||
|
||||
LibapiThread::State LibapiThread::state() const
|
||||
{
|
||||
return m_state;
|
||||
}
|
||||
|
||||
void LibapiThread::start()
|
||||
{
|
||||
if (m_pthread == nullptr)
|
||||
{
|
||||
std::cout << this->get_name() << " thread start! " << std::endl;
|
||||
//spdlog::info(this->get_name() + "thread start!");
|
||||
|
||||
m_pthread = new thread(&LibapiThread::run, this);
|
||||
m_pauseFlag = false;
|
||||
m_stopFlag = false;
|
||||
m_state = Running;
|
||||
}
|
||||
}
|
||||
|
||||
void LibapiThread::stop()
|
||||
{
|
||||
if (m_pthread != nullptr)
|
||||
{
|
||||
m_pauseFlag = false;
|
||||
m_stopFlag = true;
|
||||
m_condition.notify_one(); // Notify one waiting thread, if there is one.
|
||||
m_pthread->join(); // wait for thread finished
|
||||
delete m_pthread;
|
||||
m_pthread = nullptr;
|
||||
m_state = Stoped;
|
||||
}
|
||||
}
|
||||
|
||||
void LibapiThread::join()
|
||||
{
|
||||
if (m_pthread != nullptr)
|
||||
{
|
||||
m_pthread->join(); // wait for thread finished
|
||||
}
|
||||
}
|
||||
|
||||
void LibapiThread::pause()
|
||||
{
|
||||
if (m_pthread != nullptr)
|
||||
{
|
||||
m_pauseFlag = true;
|
||||
m_state = Paused;
|
||||
}
|
||||
}
|
||||
|
||||
void LibapiThread::resume()
|
||||
{
|
||||
if (m_pthread != nullptr)
|
||||
{
|
||||
m_pauseFlag = false;
|
||||
m_condition.notify_all();
|
||||
m_state = Running;
|
||||
}
|
||||
}
|
||||
|
||||
bool LibapiThread::push(void* pMsg)
|
||||
{
|
||||
return m_queue->push(pMsg);
|
||||
}
|
||||
|
||||
void* LibapiThread::pop()
|
||||
{
|
||||
std::cout<<"LibapiThread::pop()"<<std::endl;
|
||||
void* p = NULL;
|
||||
m_queue->pop(p);
|
||||
return p;
|
||||
}
|
||||
|
||||
void LibapiThread::notify()
|
||||
{
|
||||
m_condition.notify_one();
|
||||
}
|
||||
|
||||
void LibapiThread::run()
|
||||
{
|
||||
//cout << "enter thread:" << this_thread::get_id() << endl;
|
||||
cout << "enter thread:" << get_id() << endl;
|
||||
//spdlog::info("enter thread:%d", get_id());
|
||||
|
||||
while (!m_stopFlag)
|
||||
{
|
||||
if (/*!m_queue->empty() && */m_prunnable!=NULL)
|
||||
{
|
||||
void* pMsg = NULL;
|
||||
m_queue->pop(pMsg);
|
||||
m_prunnable->OnProcess(this, pMsg);
|
||||
}
|
||||
|
||||
if (m_pauseFlag)
|
||||
{
|
||||
unique_lock<mutex> locker(m_mutex);
|
||||
while (m_pauseFlag)
|
||||
{
|
||||
m_condition.wait(locker); // Unlock m_mutex and wait to be notified
|
||||
}
|
||||
locker.unlock();
|
||||
}
|
||||
}
|
||||
m_pauseFlag = false;
|
||||
m_stopFlag = false;
|
||||
|
||||
//cout << "exit thread:" << this_thread::get_id() << endl;
|
||||
cout << "exit thread:" << get_id() << endl;
|
||||
//spdlog::info("exit thread:%d", get_id());
|
||||
}
|
||||
|
||||
int LibapiThread::get_id()
|
||||
{
|
||||
return this->m_id;
|
||||
}
|
||||
|
||||
void LibapiThread::set_id(int& id)
|
||||
{
|
||||
this->m_id = id;
|
||||
}
|
||||
|
||||
std::string LibapiThread::get_name()
|
||||
{
|
||||
return this->m_name;
|
||||
}
|
||||
|
||||
void LibapiThread::set_name(std::string& name)
|
||||
{
|
||||
this->m_name = name;
|
||||
}
|
||||
|
||||
// 阻塞式的SLEEP
|
||||
void LibapiThread::delay_microseconds(int microseconds)
|
||||
{
|
||||
#ifndef _WIN32
|
||||
struct timespec req, rem;
|
||||
req.tv_sec = microseconds / 1000000L;
|
||||
req.tv_nsec = (microseconds % 1000000L) * 1000L;
|
||||
|
||||
while ((nanosleep(&req, &rem) == -1) && (errno == EINTR)) {
|
||||
req.tv_sec = rem.tv_sec;
|
||||
req.tv_nsec = rem.tv_nsec;
|
||||
}
|
||||
#endif
|
||||
|
||||
auto start = std::chrono::system_clock::now();
|
||||
while (true)
|
||||
{
|
||||
auto duration =
|
||||
std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now() - start).count();
|
||||
if (duration > microseconds)
|
||||
{
|
||||
//LOGGING_ERROR("timeout occurred,timeout %d ms", timeout_ms);
|
||||
break;
|
||||
}
|
||||
//std::this_thread::sleep_for(std::chrono::nanoseconds(1000));
|
||||
}
|
||||
}
|
||||
|
||||
// 消耗cpu资源,定时器很准,最高精度1ms
|
||||
void LibapiThread::delay_second(double second)
|
||||
{
|
||||
clock_t start_time;
|
||||
start_time = clock();
|
||||
for (; (clock() - start_time) < second * CLOCKS_PER_SEC;);
|
||||
}
|
||||
|
||||
LibapiQueue<void*>* LibapiThread::get_queue()
|
||||
{
|
||||
return m_queue;
|
||||
}
|
141
image_framework/thead/LibapiThread.h
Executable file
141
image_framework/thead/LibapiThread.h
Executable file
@ -0,0 +1,141 @@
|
||||
#ifndef LIBAPITHREAD_H
|
||||
#define LIBAPITHREAD_H
|
||||
|
||||
|
||||
#include <thread>
|
||||
#include <atomic>
|
||||
#include <mutex>
|
||||
#include <chrono>
|
||||
#include <condition_variable>
|
||||
//#include <spdlog/async.h>
|
||||
#include "LibapiQueue.h"
|
||||
#include "LibapiMsg.h"
|
||||
|
||||
#define MACRO_FRAMES_RATE_DEFINE(x) \
|
||||
static int count##x = 0; \
|
||||
static int count_last##x = 0;\
|
||||
auto start##x = std::chrono::high_resolution_clock::now();\
|
||||
|
||||
//#define MACRO_FRAMES_RATE_DEFINE_END(x, log)\
|
||||
// count##x++;\
|
||||
// auto finish##x = std::chrono::high_resolution_clock::now();\
|
||||
// std::chrono::duration<double> elapsed##x = finish##x - start##x;\
|
||||
// if (elapsed##x.count() > 1.0)\
|
||||
// {\
|
||||
// start##x = std::chrono::high_resolution_clock::now();\
|
||||
// spdlog::info(log##" : frames per second is {}", count##x);\
|
||||
// count##x = 0;\
|
||||
// }\
|
||||
|
||||
#define MACRO_FRAMES_RATE_DEFINE_END(x, log)\
|
||||
count##x++;\
|
||||
auto finish##x = std::chrono::high_resolution_clock::now();\
|
||||
std::chrono::duration<double> elapsed##x = finish##x - start##x;\
|
||||
if (elapsed##x.count() > 1.0)\
|
||||
{\
|
||||
start##x = std::chrono::high_resolution_clock::now();\
|
||||
count##x = 0;\
|
||||
}\
|
||||
|
||||
#define MACRO_START_TIME(thread_name)\
|
||||
m_start = std::chrono::high_resolution_clock::now();\
|
||||
|
||||
|
||||
#define MACRO_RECORD_RUN_TIME(thread_name)\
|
||||
m_end = std::chrono::high_resolution_clock::now();\
|
||||
m_elapsed = m_end - m_start;\
|
||||
//spdlog::info(pThisThread->get_name() + ":Elapsed Time:{} ms\n", m_elapsed.count());\
|
||||
|
||||
class LibapiThread;
|
||||
class IRunnable
|
||||
{
|
||||
public:
|
||||
virtual int OnProcess(LibapiThread* pthread, void* pMsg) = 0;
|
||||
virtual void OnEndProcess(LibapiThread* pthread, void* pMsg) = 0;
|
||||
virtual void OnDeleteMsg(LibapiThread* pthread, void* pMsg) = 0;
|
||||
};
|
||||
|
||||
|
||||
class BaseRunnable : IRunnable
|
||||
{
|
||||
public:
|
||||
std::chrono::high_resolution_clock::time_point m_start;
|
||||
std::chrono::high_resolution_clock::time_point m_end;
|
||||
std::chrono::duration<double, std::milli> m_elapsed;
|
||||
public:
|
||||
virtual int OnProcess(LibapiThread* pthread, void* pMsg) { return 0; };
|
||||
virtual void OnEndProcess(LibapiThread* pthread, void* pMsg) {};
|
||||
virtual void OnDeleteMsg(LibapiThread* pthread, void* pMsg) {};
|
||||
public:
|
||||
void get_start_time()
|
||||
{
|
||||
m_start = std::chrono::high_resolution_clock::now();
|
||||
}
|
||||
|
||||
long get_used_time()
|
||||
{
|
||||
m_end = std::chrono::high_resolution_clock::now();
|
||||
std::chrono::duration<double> elapsex = m_end - m_start;
|
||||
long seconds = static_cast<long>(elapsex.count());
|
||||
|
||||
return seconds;
|
||||
}
|
||||
};
|
||||
|
||||
class IDeleteMsgCallBack
|
||||
{
|
||||
public:
|
||||
virtual void delete_msg(void* pMsg) = 0;
|
||||
};
|
||||
|
||||
class LibapiThread
|
||||
{
|
||||
public:
|
||||
static void delay_microseconds(int microseconds);
|
||||
static void delay_second(double second);
|
||||
|
||||
public:
|
||||
LibapiThread(int id, std::string name, BaseRunnable* runnable);
|
||||
virtual ~LibapiThread();
|
||||
|
||||
enum State
|
||||
{
|
||||
Stoped, ///<停止状态,包括从未启动过和启动后被停止
|
||||
Running, ///<运行状态
|
||||
Paused ///<暂停状态
|
||||
};
|
||||
|
||||
State state() const;
|
||||
void start();
|
||||
void stop();
|
||||
void join();
|
||||
void pause();
|
||||
void resume();
|
||||
bool push(void* pMsg); //push到本线程
|
||||
//void push_to(int queue_id, void* pMsg); //从本线程push到其他线程
|
||||
void* pop();
|
||||
void notify();
|
||||
int get_id();
|
||||
void set_id(int& id);
|
||||
std::string get_name();
|
||||
void set_name(std::string& name);
|
||||
LibapiQueue<void*>* get_queue();
|
||||
|
||||
protected:
|
||||
virtual void run();
|
||||
|
||||
protected:
|
||||
int m_id;
|
||||
std::string m_name;
|
||||
std::thread* m_pthread;
|
||||
BaseRunnable* m_prunnable;
|
||||
std::mutex m_mutex;
|
||||
std::mutex m_msg_mutex;
|
||||
std::condition_variable m_condition;
|
||||
std::atomic_bool m_pauseFlag; ///<暂停标识
|
||||
std::atomic_bool m_stopFlag; ///<停止标识
|
||||
State m_state;
|
||||
LibapiQueue<void*>* m_queue;
|
||||
};
|
||||
|
||||
#endif // LIBAPITHREAD_H
|
132
image_framework/thead/LibapiThread.h.bak
Executable file
132
image_framework/thead/LibapiThread.h.bak
Executable file
@ -0,0 +1,132 @@
|
||||
#ifndef LIBAPITHREAD_H
|
||||
#define LIBAPITHREAD_H
|
||||
|
||||
|
||||
#include <thread>
|
||||
#include <atomic>
|
||||
#include <mutex>
|
||||
#include <chrono>
|
||||
#include <condition_variable>
|
||||
#include <spdlog/async.h>
|
||||
#include "LibapiQueue.h"
|
||||
#include "LibapiMsg.h"
|
||||
|
||||
#define MACRO_FRAMES_RATE_DEFINE(x) \
|
||||
static int count##x = 0; \
|
||||
static int count_last##x = 0;\
|
||||
auto start##x = std::chrono::high_resolution_clock::now();\
|
||||
|
||||
#define MACRO_FRAMES_RATE_DEFINE_END(x, log)\
|
||||
count##x++;\
|
||||
auto finish##x = std::chrono::high_resolution_clock::now();\
|
||||
std::chrono::duration<double> elapsed##x = finish##x - start##x;\
|
||||
if (elapsed##x.count() > 1.0)\
|
||||
{\
|
||||
start##x = std::chrono::high_resolution_clock::now();\
|
||||
spdlog::info(log##" : frames per second is {}", count##x);\
|
||||
count##x = 0;\
|
||||
}\
|
||||
|
||||
#define MACRO_START_TIME(thread_name)\
|
||||
auto start = std::chrono::high_resolution_clock::now();\
|
||||
|
||||
|
||||
#define MACRO_RECORD_RUN_TIME(thread_name)\
|
||||
auto end = std::chrono::high_resolution_clock::now();\
|
||||
// m_elapsed = end - m_start;\
|
||||
// spdlog::info(pThisThread->get_name() + ":Elapsed Time:{} ms\n", m_elapsed.count());\
|
||||
|
||||
class LibapiThread;
|
||||
class IRunnable
|
||||
{
|
||||
public:
|
||||
virtual int OnProcess(LibapiThread* pthread, void* pMsg) = 0;
|
||||
virtual void OnEndProcess(LibapiThread* pthread, void* pMsg) = 0;
|
||||
virtual void OnDeleteMsg(LibapiThread* pthread, void* pMsg) = 0;
|
||||
};
|
||||
|
||||
|
||||
class BaseRunnable : IRunnable
|
||||
{
|
||||
public:
|
||||
std::chrono::steady_clock::time_point m_start;
|
||||
// std::chrono::steady_clock::time_point m_end;
|
||||
std::chrono::duration<double, std::milli> m_elapsed;
|
||||
public:
|
||||
virtual int OnProcess(LibapiThread* pthread, void* pMsg) { return 0; };
|
||||
virtual void OnEndProcess(LibapiThread* pthread, void* pMsg) {};
|
||||
virtual void OnDeleteMsg(LibapiThread* pthread, void* pMsg) {};
|
||||
public:
|
||||
void get_start_time()
|
||||
{
|
||||
auto start = std::chrono::high_resolution_clock::now();
|
||||
// m_start = start;
|
||||
}
|
||||
|
||||
// long get_used_time()
|
||||
// {
|
||||
// m_end = std::chrono::high_resolution_clock::now();
|
||||
// std::chrono::duration<double> elapsex = m_end - m_start;
|
||||
// long seconds = static_cast<long>(elapsex.count());
|
||||
|
||||
// return seconds;
|
||||
// }
|
||||
};
|
||||
|
||||
class IDeleteMsgCallBack
|
||||
{
|
||||
public:
|
||||
virtual void delete_msg(void* pMsg) = 0;
|
||||
};
|
||||
|
||||
class LibapiThread
|
||||
{
|
||||
public:
|
||||
static void delay_microseconds(int microseconds);
|
||||
static void delay_second(double second);
|
||||
|
||||
public:
|
||||
LibapiThread(int id, std::string name, BaseRunnable* runnable);
|
||||
virtual ~LibapiThread();
|
||||
|
||||
enum State
|
||||
{
|
||||
Stoped, ///<停止状态,包括从未启动过和启动后被停止
|
||||
Running, ///<运行状态
|
||||
Paused ///<暂停状态
|
||||
};
|
||||
|
||||
State state() const;
|
||||
void start();
|
||||
void stop();
|
||||
void join();
|
||||
void pause();
|
||||
void resume();
|
||||
bool push(void* pMsg); //push到本线程
|
||||
//void push_to(int queue_id, void* pMsg); //从本线程push到其他线程
|
||||
void* pop();
|
||||
void notify();
|
||||
int get_id();
|
||||
void set_id(int& id);
|
||||
std::string get_name();
|
||||
void set_name(std::string& name);
|
||||
LibapiQueue<void*>* get_queue();
|
||||
|
||||
protected:
|
||||
virtual void run();
|
||||
|
||||
protected:
|
||||
int m_id;
|
||||
std::string m_name;
|
||||
std::thread* m_pthread;
|
||||
BaseRunnable* m_prunnable;
|
||||
std::mutex m_mutex;
|
||||
std::mutex m_msg_mutex;
|
||||
std::condition_variable m_condition;
|
||||
std::atomic_bool m_pauseFlag; ///<暂停标识
|
||||
std::atomic_bool m_stopFlag; ///<停止标识
|
||||
State m_state;
|
||||
LibapiQueue<void*>* m_queue;
|
||||
};
|
||||
|
||||
#endif // LIBAPITHREAD_H
|
112
image_framework/thead/LibapiThreadPool.h
Executable file
112
image_framework/thead/LibapiThreadPool.h
Executable file
@ -0,0 +1,112 @@
|
||||
#ifndef THREAD_POOL_H
|
||||
#define THREAD_POOL_H
|
||||
|
||||
#include <vector>
|
||||
#include <queue>
|
||||
#include <memory>
|
||||
#include <thread>
|
||||
#include <mutex>
|
||||
#include <condition_variable>
|
||||
#include <future>
|
||||
#include <functional>
|
||||
#include <stdexcept>
|
||||
|
||||
class ThreadPool {
|
||||
public:
|
||||
explicit ThreadPool(size_t);
|
||||
template<class F, class... Args>//可变参数模版
|
||||
//值得注意的是这里F&&表示universal reference而不是右值引用
|
||||
//如果存在推断类型如template或auto那么&&即表示universal reference,具体是左值引用还是右值引用由初始化决定
|
||||
auto enqueue(F&& f, Args&&... args)//f是函数名,args是参数
|
||||
->std::future<decltype(f(args...))>;//尾置返回类型,返回 函数f返回值类型的future
|
||||
~ThreadPool();
|
||||
private:
|
||||
// need to keep track of threads so we can join them
|
||||
std::vector< std::thread > workers;
|
||||
// the task queue
|
||||
std::queue< std::function<void()> > tasks;//std::function通用的函数封装,要求一个返回值类型为void的无参函数
|
||||
|
||||
// synchronization
|
||||
std::mutex queue_mutex;//锁,负责保护任务队列和stop
|
||||
std::condition_variable condition;//条件变量
|
||||
bool stop;
|
||||
};
|
||||
|
||||
// the constructor just launches some amount of workers
|
||||
inline ThreadPool::ThreadPool(size_t threads)//构造时设定线程数量
|
||||
: stop(false)
|
||||
{
|
||||
for(size_t i = 0;i<threads;++i)
|
||||
workers.emplace_back(//push_back的优化版本
|
||||
[this]//lambda表达式捕获this指针
|
||||
{
|
||||
for(;;)//比while(1)更优
|
||||
{
|
||||
std::function<void()> task;
|
||||
{//{}内相当于新的作用域
|
||||
std::unique_lock<std::mutex> lock(this->queue_mutex);
|
||||
//在等待任务队列中出现任务的过程中解锁queue_mutex
|
||||
//由notify_one或notify_all唤醒
|
||||
//线程池初始化后将有threads个线程在此处等待,每个线程执行完分配到的任务将执行循环,再取任务执行或等待任务加入队列
|
||||
/* 我们需要知道这么做的目的是,std::thread本身仅能绑定一个函数,而我们需要仅用threads个线程去帮我们执行m个任务,
|
||||
* 而不是每执行一个任务创建一个线程,如果这样我们将创建m个线程,而创建线程是需要开销的,这引起了不必要的浪费,线程池就是为此而生的
|
||||
* 通过这种方式,每个std::thread仍然是只绑定了一个函数,但是这一个函数会执行我们想要的多个任务
|
||||
*/
|
||||
this->condition.wait(lock,
|
||||
[this]{ return this->stop || !this->tasks.empty(); });
|
||||
if(this->stop && this->tasks.empty())//stop=true,仍需执行任务队列中剩余任务
|
||||
return;
|
||||
task = std::move(this->tasks.front());//std::move避免拷贝
|
||||
this->tasks.pop();
|
||||
}
|
||||
|
||||
task();//执行任务
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
// add new work item to the pool
|
||||
template<class F, class... Args>
|
||||
auto ThreadPool::enqueue(F&& f, Args&&... args)
|
||||
-> std::future<decltype(f(args...))>
|
||||
{
|
||||
using return_type = decltype(f(args...));
|
||||
|
||||
//基本类型是std::shared_ptr,指向类型是std::packaged_task,类型是返回值类型为return_type的无参函数
|
||||
auto task = std::make_shared< std::packaged_task<return_type()> >(
|
||||
/* 现在该说说为什么std::packaged_task的类型是一个返回值为return_type的无参数函数了
|
||||
* 返回值是return_type这没有问题,至于参数消失的原因是因为:std::bind
|
||||
* 在这里它创建了一个无参数(参数均被指定)版本的函数f
|
||||
*/
|
||||
//std::forward配合universal reference使用,完美转发,实际效果是如果是右值引用那么还是右值引用,如果是左值引用那么还是左值引用
|
||||
std::bind(std::forward<F>(f), std::forward<Args>(args)...)
|
||||
);
|
||||
|
||||
std::future<return_type> res = task->get_future();//任务函数实际执行后的返回值
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(queue_mutex);
|
||||
|
||||
// don't allow enqueueing after stopping the pool
|
||||
if(stop)
|
||||
throw std::runtime_error("enqueue on stopped ThreadPool");
|
||||
|
||||
tasks.emplace([task](){ (*task)(); });//往tasks队列压入一个无参无返回值的函数,函数体内调用task(不要忘记task是shared_ptr类型)
|
||||
}
|
||||
//任务压入队列,唤醒等待的线程
|
||||
condition.notify_one();
|
||||
return res;
|
||||
}
|
||||
|
||||
// the destructor joins all threads
|
||||
inline ThreadPool::~ThreadPool()
|
||||
{
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(queue_mutex);
|
||||
stop = true;
|
||||
}
|
||||
condition.notify_all();//唤醒所有等待的进程
|
||||
for(std::thread &worker: workers)
|
||||
worker.join();//等待所有线程结束
|
||||
}
|
||||
|
||||
#endif
|
130
image_framework/thead/TestMain.cpp
Executable file
130
image_framework/thead/TestMain.cpp
Executable file
@ -0,0 +1,130 @@
|
||||
#include "LibapiProcessThread.h"
|
||||
#include "LibapiQueue.h"
|
||||
#include "LibapiQueues.h"
|
||||
#include "MsgBase.h"
|
||||
#include <memory>
|
||||
#include <chrono>
|
||||
#include <opencv2/opencv.hpp>
|
||||
#include <iostream>
|
||||
#include <locale>
|
||||
#include <codecvt>
|
||||
#include <string>
|
||||
#include <fstream>
|
||||
#include "PlguinConfig.h"
|
||||
|
||||
#include "Libapi.h"
|
||||
#include "IniHelper.h"
|
||||
#include "Log.h"
|
||||
#include "Yolov5For928.h"
|
||||
|
||||
// for ext
|
||||
int main()
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
// init config
|
||||
GINIT();
|
||||
|
||||
// init yolo for 928
|
||||
ret = CYolov5For928::Get()->Init();
|
||||
if (ret != 0) return ret;
|
||||
|
||||
// init task
|
||||
PlguinConfig::getInstance()->LibapiInitCameraProcessing(nullptr);
|
||||
PlguinConfig::getInstance()->LibapiInitLidarProcessing(nullptr);
|
||||
PlguinConfig::getInstance()->LibapiInitRoiProcessing(nullptr);
|
||||
LibapiThread::delay_second(2);
|
||||
|
||||
MsgBase* pMsgCamera = nullptr;
|
||||
MsgBase* pMsgLidar = nullptr;
|
||||
char msg_type[32] = "MsgBase";
|
||||
|
||||
while (true)
|
||||
{
|
||||
char msg_type[32] = "MsgBase";
|
||||
pMsgCamera = nullptr;
|
||||
pMsgLidar = nullptr;
|
||||
libapi_create_MsgBase(msg_type, (void**)&pMsgCamera);
|
||||
libapi_create_MsgBase(msg_type, (void**)&pMsgLidar);
|
||||
ret = libapi_push_to_queue((char*)"_t_PluginCameraPro", pMsgCamera);
|
||||
ret = libapi_push_to_queue((char*)"_t_PlguinLidarPro", pMsgLidar);
|
||||
LibapiThread::delay_second(2);
|
||||
LibapiThread::delay_second(5);
|
||||
|
||||
//#define CLIENT_MSG_CONTINUE 1
|
||||
//#define CLIENT_MSG_RESTART_DETECTION 2
|
||||
//#define CLIENT_MSG_STOP_DETECTION 3
|
||||
MsgBase::SetWaitInt(MsgBase::iClinetMsg, CLIENT_MSG_CONTINUE);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// for dll
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#endif // _WIN32
|
||||
|
||||
typedef int (*DLLLibapiInit)(int, char*, void*);
|
||||
typedef int (*DLLLLibapiStartDetection)();
|
||||
typedef int (*DLLLibapiContinuetDetection)();
|
||||
typedef int (*DLLLibapRestartConnerDetection)();
|
||||
typedef int (*DLLLibapStopDetectiont)();
|
||||
static const char* dllName = "./image_framework.dll";
|
||||
|
||||
//static const char* DLLLibapiInit_name = "LibapiInit";
|
||||
//static const char* DLLLLibapiStartDetection_name = "LibapiStartDetection";
|
||||
//static const char* DLLLibapiContinuetDetection_name = "LibapiContinuetDetection";
|
||||
//static const char* DLLLibapRestartConnerDetection_name = "LibapRestartConnerDetection";
|
||||
//static const char* DLLLibapStopDetectiont_name = "LibapStopDetectiont";
|
||||
|
||||
//static wchar_t* char2wchar(const char* c)
|
||||
//{
|
||||
// int bufferSize = MultiByteToWideChar(CP_UTF8, 0, c, -1, NULL, 0);
|
||||
// wchar_t* wideString = new wchar_t[bufferSize];
|
||||
// MultiByteToWideChar(CP_UTF8, 0, c, -1, wideString, bufferSize);
|
||||
// return wideString;
|
||||
//}
|
||||
//int main()
|
||||
//{
|
||||
// wchar_t* ws = char2wchar(dllName);
|
||||
//
|
||||
// HINSTANCE hinst = LoadLibrary(ws);
|
||||
// if (hinst == NULL)
|
||||
// {
|
||||
// DWORD error = GetLastError();
|
||||
// if (error == ERROR_MOD_NOT_FOUND)
|
||||
// {
|
||||
// // 处理DLL找不到的情况
|
||||
// std::cout << "DLL找不到的情况" << std::endl;
|
||||
// return 0;
|
||||
// }
|
||||
// else if (error == ERROR_PROC_NOT_FOUND)
|
||||
// {
|
||||
// // 处理DLL中的特定函数找不到的情况
|
||||
// std::cout << "DLL中的特定函数找不到的情况" << std::endl;
|
||||
// return 0;
|
||||
// }
|
||||
// // 其他错误处理...
|
||||
// }
|
||||
// DLLLibapiInit funcDLLLibapiInit =
|
||||
// (DLLLibapiInit)GetProcAddress(hinst, "LibapiInit");
|
||||
// DLLLLibapiStartDetection funcDLLLLibapiStartDetection =
|
||||
// (DLLLLibapiStartDetection)GetProcAddress(hinst, "LibapiStartDetection");
|
||||
// DLLLibapiContinuetDetection funcDLLLibapiContinuetDetection =
|
||||
// (DLLLibapiContinuetDetection)GetProcAddress(hinst, "LibapiContinuetDetection");
|
||||
// DLLLibapRestartConnerDetection funcDLLLibapRestartConnerDetection =
|
||||
// (DLLLibapRestartConnerDetection)GetProcAddress(hinst, "LibapRestartConnerDetection");
|
||||
// DLLLibapStopDetectiont funcDLLLibapStopDetectiont =
|
||||
// (DLLLibapStopDetectiont)GetProcAddress(hinst, "LibapStopDetection");
|
||||
//
|
||||
// char c[256] = "1111";
|
||||
// funcDLLLibapiInit(1, c, nullptr);
|
||||
// while (true)
|
||||
// {
|
||||
// funcDLLLLibapiStartDetection();
|
||||
//
|
||||
// LibapiThread::delay_second(10);
|
||||
//
|
||||
// funcDLLLibapiContinuetDetection();
|
||||
// }
|
||||
//}
|
135
image_framework/utils/Ini/IniHelper.cpp
Executable file
135
image_framework/utils/Ini/IniHelper.cpp
Executable file
@ -0,0 +1,135 @@
|
||||
#include "IniParser.h"
|
||||
#include "IniHelper.h"
|
||||
#include <iostream>
|
||||
|
||||
IniHelper* IniHelper::m_instance;
|
||||
|
||||
#ifdef _WIN32
|
||||
static xini_file_t xini_file("./config.ini");
|
||||
#else
|
||||
static xini_file_t xini_file("./config.ini");
|
||||
#endif
|
||||
|
||||
IniHelper* IniHelper::Get()
|
||||
{
|
||||
if (IniHelper::m_instance == nullptr) {
|
||||
IniHelper::m_instance = new IniHelper();
|
||||
|
||||
// 2D section
|
||||
G(w) = IniHelper::Get()->GetInt("2D", "w");
|
||||
G(h) = IniHelper::Get()->GetFloat("2D", "h");
|
||||
|
||||
G(fx) = IniHelper::Get()->GetFloat("2D", "fx");
|
||||
G(fy) = IniHelper::Get()->GetFloat("2D", "fy");
|
||||
G(cx) = IniHelper::Get()->GetFloat("2D", "cx");
|
||||
G(cy) = IniHelper::Get()->GetFloat("2D", "cy");
|
||||
G(k1) = IniHelper::Get()->GetFloat("2D", "k1");
|
||||
G(k2) = IniHelper::Get()->GetFloat("2D", "k2");
|
||||
G(p1) = IniHelper::Get()->GetFloat("2D", "p1");
|
||||
G(p2) = IniHelper::Get()->GetFloat("2D", "p2");
|
||||
G(k3) = IniHelper::Get()->GetFloat("2D", "k3");
|
||||
|
||||
G(yolo_label) = IniHelper::Get()->GetInt("2D", "yolo_label");
|
||||
G(yolo_prob) = IniHelper::Get()->GetFloat("2D", "yolo_prob");
|
||||
G(yolo_modol_path) = IniHelper::Get()->GetStr("2D", "yolo_modol_path");
|
||||
G(save_image) = IniHelper::Get()->GetStr("2D", "save_image");
|
||||
G(roi_y_offset) = IniHelper::Get()->GetInt("2D", "roi_y_offset");
|
||||
|
||||
G(edge_min_line_len) = IniHelper::Get()->GetInt("2D", "edge_min_line_len");
|
||||
G(edge_max_line_gap) = IniHelper::Get()->GetInt("2D", "edge_max_line_gap");
|
||||
G(edge_min_angle_th) = IniHelper::Get()->GetInt("2D", "edge_min_angle_th");
|
||||
|
||||
G(kk) = IniHelper::Get()->GetFloat("2D", "kk");
|
||||
|
||||
|
||||
// 3D section
|
||||
G(r) = IniHelper::Get()->GetFloat("3D", "r");
|
||||
G(p) = IniHelper::Get()->GetFloat("3D", "p");
|
||||
G(y) = IniHelper::Get()->GetFloat("3D", "y");
|
||||
|
||||
G(tx) = IniHelper::Get()->GetFloat("3D", "tx");
|
||||
G(ty) = IniHelper::Get()->GetFloat("3D", "ty");
|
||||
G(tz) = IniHelper::Get()->GetFloat("3D", "tz");
|
||||
|
||||
G(dminx) = IniHelper::Get()->GetFloat("3D", "dminx");
|
||||
G(dmaxx) = IniHelper::Get()->GetFloat("3D", "dmaxx");
|
||||
G(dminy) = IniHelper::Get()->GetFloat("3D", "dminy");
|
||||
G(dmaxy) = IniHelper::Get()->GetFloat("3D", "dmaxy");
|
||||
G(dminz) = IniHelper::Get()->GetFloat("3D", "dminz");
|
||||
G(dmaxz) = IniHelper::Get()->GetFloat("3D", "dmaxz");
|
||||
G(cloud_need_points_size) = IniHelper::Get()->GetInt("3D", "cloud_need_points_size");
|
||||
G(save_cload) = IniHelper::Get()->GetStr("3D", "save_cload");
|
||||
|
||||
|
||||
G(fake) = IniHelper::Get()->GetStr("sys", "fake");
|
||||
G(camera_cap_fake) = IniHelper::Get()->GetStr("sys", "camera_cap_fake");
|
||||
G(lidar_cap_fake) = IniHelper::Get()->GetStr("sys", "lidar_cap_fake");
|
||||
G(npu_fake) = IniHelper::Get()->GetStr("sys", "npu_fake");
|
||||
G(conners_detect_fake) = IniHelper::Get()->GetStr("sys", "conners_detect_fake");
|
||||
G(fake_image_fpath) = IniHelper::Get()->GetStr("sys", "fake_image_fpath");
|
||||
G(fake_lidar_fpath) = IniHelper::Get()->GetStr("sys", "fake_lidar_fpath");
|
||||
G(export_time) = IniHelper::Get()->GetInt("sys", "export_time");
|
||||
}
|
||||
|
||||
return IniHelper::m_instance;
|
||||
}
|
||||
|
||||
static std::string floatToString(float value) {
|
||||
std::ostringstream oss;
|
||||
oss << value;
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
static std::string intToString(int value) {
|
||||
std::ostringstream oss;
|
||||
oss << value;
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
IniHelper::IniHelper()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
IniHelper::~IniHelper()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
std::string IniHelper::GetStr(std::string section, std::string item)
|
||||
{
|
||||
std::string val = (const char*)xini_file[section][item];
|
||||
//std::cout << item << ": " << val << std::endl;
|
||||
this->mRecord += item;
|
||||
this->mRecord += ": ";
|
||||
this->mRecord += val;
|
||||
this->mRecord += "\n";
|
||||
return val;
|
||||
}
|
||||
|
||||
float IniHelper::GetFloat(std::string section, std::string item)
|
||||
{
|
||||
float val = xini_file[section][item];
|
||||
//std::cout << item << ": " << val << std::endl;
|
||||
this->mRecord += item;
|
||||
this->mRecord += ": ";
|
||||
this->mRecord += floatToString(val);
|
||||
this->mRecord += "\n";
|
||||
return val;
|
||||
}
|
||||
|
||||
int IniHelper::GetInt(std::string section, std::string item)
|
||||
{
|
||||
int val = xini_file[section][item];
|
||||
//std::cout << item << ": " << val << std::endl;
|
||||
this->mRecord += item;
|
||||
this->mRecord += ": ";
|
||||
this->mRecord += intToString(val);
|
||||
this->mRecord += "\n";
|
||||
return val;
|
||||
}
|
||||
|
||||
std::string IniHelper::GetRecord()
|
||||
{
|
||||
return this->mRecord;
|
||||
}
|
74
image_framework/utils/Ini/IniHelper.h
Executable file
74
image_framework/utils/Ini/IniHelper.h
Executable file
@ -0,0 +1,74 @@
|
||||
#ifndef INI_HELPER_H
|
||||
#define INI_HELPER_H
|
||||
|
||||
#include <string>
|
||||
|
||||
#define G(x) IniHelper::Get()->x
|
||||
#define GINIT() IniHelper::Get()->w
|
||||
|
||||
class IniHelper
|
||||
{
|
||||
public:
|
||||
static IniHelper* Get();
|
||||
public:
|
||||
static IniHelper* m_instance;
|
||||
IniHelper();
|
||||
~IniHelper();
|
||||
|
||||
public:
|
||||
std::string GetStr(std::string section, std::string item);
|
||||
float GetFloat(std::string section, std::string item);
|
||||
int GetInt(std::string section, std::string item);
|
||||
std::string GetRecord();
|
||||
|
||||
private:
|
||||
std::string mRecord;
|
||||
|
||||
public:
|
||||
int w;
|
||||
int h;
|
||||
float fx;
|
||||
float fy;
|
||||
float cx;
|
||||
float cy;
|
||||
float k1;
|
||||
float k2;
|
||||
float p1;
|
||||
float p2;
|
||||
float k3;
|
||||
int yolo_label;
|
||||
float yolo_prob;
|
||||
std::string yolo_modol_path;
|
||||
std::string save_image;
|
||||
int roi_y_offset;
|
||||
int edge_min_line_len;
|
||||
int edge_max_line_gap;
|
||||
int edge_min_angle_th;
|
||||
float kk;
|
||||
|
||||
float r;
|
||||
float p;
|
||||
float y;
|
||||
float tx;
|
||||
float ty;
|
||||
float tz;
|
||||
float dminx;
|
||||
float dmaxx;
|
||||
float dminy;
|
||||
float dmaxy;
|
||||
float dminz;
|
||||
float dmaxz;
|
||||
int cloud_need_points_size;
|
||||
std::string save_cload;
|
||||
|
||||
std::string fake;
|
||||
std::string camera_cap_fake;
|
||||
std::string lidar_cap_fake;
|
||||
std::string npu_fake;
|
||||
std::string conners_detect_fake;
|
||||
std::string fake_image_fpath;
|
||||
std::string fake_lidar_fpath;
|
||||
int export_time;
|
||||
};
|
||||
|
||||
#endif
|
2165
image_framework/utils/Ini/IniParser.h
Executable file
2165
image_framework/utils/Ini/IniParser.h
Executable file
File diff suppressed because it is too large
Load Diff
249
image_framework/utils/Log/Log.cpp
Executable file
249
image_framework/utils/Log/Log.cpp
Executable file
@ -0,0 +1,249 @@
|
||||
#include "Log.h"
|
||||
#include <cstdarg>
|
||||
#include <cstring>
|
||||
#include <chrono>
|
||||
#include <ctime>
|
||||
#include <cstdio>
|
||||
#include <sstream>
|
||||
using namespace std;
|
||||
using namespace std::chrono;
|
||||
#define LOG_BUF_SIZE 20480
|
||||
#define TIME_BUF_SIZE 64
|
||||
Log Log::m_log;
|
||||
int Log::m_counter = 0;
|
||||
|
||||
|
||||
Log::Log()
|
||||
:LogTask(),
|
||||
m_bExit(false),
|
||||
m_fLog(nullptr),
|
||||
m_logLevel(LEVEL_NORMAL)
|
||||
{
|
||||
}
|
||||
|
||||
Log::~Log()
|
||||
{
|
||||
// wait data write end
|
||||
while (!m_logQue.empty())
|
||||
{
|
||||
milliseconds drua(10);
|
||||
this_thread::sleep_for(drua);
|
||||
}
|
||||
if (m_fLog)
|
||||
{
|
||||
fclose(m_fLog);
|
||||
m_fLog = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
std::string Log::getSysTime()
|
||||
{
|
||||
time_t tt = system_clock::to_time_t(system_clock::now());
|
||||
char timeBuf[TIME_BUF_SIZE];
|
||||
memset(timeBuf, 0, sizeof(timeBuf));
|
||||
struct tm* pTime = localtime(&tt);
|
||||
sprintf(timeBuf, "%4d/%02d/%02d %02d:%02d:%02d", pTime->tm_year + 1900, pTime->tm_mon + 1,
|
||||
pTime->tm_mday, pTime->tm_hour, pTime->tm_min, pTime->tm_sec);
|
||||
return string(timeBuf);
|
||||
}
|
||||
|
||||
Log& Log::getInstance()
|
||||
{
|
||||
return m_log;
|
||||
}
|
||||
|
||||
void Log::init(int level, const char* pLogModuleName)
|
||||
{
|
||||
std::unique_lock <std::mutex> lck(m_mutex);
|
||||
m_logLevel = level;
|
||||
// 每次init都重新打开一个log文件
|
||||
if (m_fLog != nullptr)
|
||||
{
|
||||
fclose(m_fLog);
|
||||
m_fLog = nullptr;
|
||||
}
|
||||
if (m_fLog == nullptr && m_logLevel > 0)
|
||||
{
|
||||
time_t tt = system_clock::to_time_t(system_clock::now());
|
||||
char timeBuf[TIME_BUF_SIZE];
|
||||
memset(timeBuf, 0, sizeof(timeBuf));
|
||||
struct tm* pTime = localtime(&tt);
|
||||
sprintf(timeBuf, "%4d-%02d-%02d %02d-%02d-%02d", pTime->tm_year + 1900, pTime->tm_mon + 1,
|
||||
pTime->tm_mday, pTime->tm_hour, pTime->tm_min, pTime->tm_sec);
|
||||
|
||||
string strpath = "./log/log_";
|
||||
if (pLogModuleName)
|
||||
{
|
||||
strpath += pLogModuleName;
|
||||
strpath += "_";
|
||||
}
|
||||
strpath += timeBuf;
|
||||
strpath += ".txt";
|
||||
m_fLog = fopen(strpath.c_str(), "a+");
|
||||
// 开启写入文件线程
|
||||
m_log.log_write_thread();
|
||||
}
|
||||
}
|
||||
|
||||
void Log::log(int level, const char* file, const char* func, int lineNo, const char* cFormat, ...)
|
||||
{
|
||||
if (level <= LEVEL_NORMAL || level > LEVEL_DEBUG)
|
||||
return;
|
||||
va_list args;
|
||||
ostringstream oss;
|
||||
//oss << file << ' : ' << lineNo << ' : ' << func << "() \n";
|
||||
oss << lineNo << " : " << func << "() ==> " << cFormat << "\n";
|
||||
va_start(args, cFormat);
|
||||
push_log(level, const_cast<char*>(oss.str().c_str()), args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
void Log::log2(int level, const char* cFormat, ...)
|
||||
{
|
||||
if (level <= LEVEL_NORMAL || level > LEVEL_DEBUG)
|
||||
return;
|
||||
va_list args;
|
||||
va_start(args, cFormat);
|
||||
push_log(level, (char*)cFormat, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
void Log::debugBin(const char* szInfo, uint8_t* szData, uint32_t nDataLen)
|
||||
{
|
||||
// 不输出debug信息
|
||||
if (m_logLevel < LEVEL_DEBUG)
|
||||
return;
|
||||
char szBuf[LOG_BUF_SIZE];
|
||||
hex2Str(szBuf, sizeof(szBuf), szData, nDataLen);
|
||||
log2(LEVEL_DEBUG, "%s %s", szInfo, szBuf);
|
||||
}
|
||||
|
||||
void Log::debugStr(const char* szInfo, const char* cFormat, ...)
|
||||
{
|
||||
if (m_logLevel < LEVEL_DEBUG)
|
||||
return;
|
||||
va_list args;
|
||||
va_start(args, cFormat);
|
||||
char logbuf[LOG_BUF_SIZE];
|
||||
memset(logbuf, 0, sizeof(logbuf));
|
||||
string&& sysTime = getSysTime();
|
||||
sprintf(logbuf, "%s [DEBUG] %s", sysTime.c_str(), szInfo);
|
||||
size_t lens = strlen(logbuf);
|
||||
vsnprintf(logbuf + lens, LOG_BUF_SIZE - 1 - lens, cFormat, args);// last bit'\0'
|
||||
va_end(args);
|
||||
|
||||
string LogString(logbuf);
|
||||
push_logstr(LogString);
|
||||
|
||||
}
|
||||
|
||||
void Log::info(const char* szInfo, const char* cFormat, ...)
|
||||
{
|
||||
if (m_logLevel < LEVEL_INFOR)
|
||||
return;
|
||||
va_list args;
|
||||
va_start(args, cFormat);
|
||||
char logbuf[LOG_BUF_SIZE];
|
||||
memset(logbuf, 0, sizeof(logbuf));
|
||||
string&& sysTime = getSysTime();
|
||||
sprintf(logbuf, "%s %s", sysTime.c_str(), szInfo);
|
||||
size_t lens = strlen(logbuf);
|
||||
vsnprintf(logbuf + lens, LOG_BUF_SIZE - 1 - lens, cFormat, args);// last bit'\0'
|
||||
va_end(args);
|
||||
|
||||
string LogString(logbuf);
|
||||
push_logstr(LogString);
|
||||
}
|
||||
|
||||
void Log::hex2Str(char* outBuf, uint32_t nbufLen, uint8_t* szData, uint32_t nDataLen)
|
||||
{
|
||||
memset(outBuf, 0, nbufLen);
|
||||
uint32_t i = 0, j = 0;
|
||||
for (; i < nDataLen && j < nbufLen - 4; ++i)
|
||||
{
|
||||
|
||||
if (i % 24 == 0)
|
||||
{
|
||||
sprintf(outBuf + j, "%s", "\n");
|
||||
j += 1;
|
||||
}
|
||||
sprintf(outBuf + j, "%02X ", szData[i]);
|
||||
j += 3;
|
||||
}
|
||||
sprintf(outBuf + j, "%s", "\n");
|
||||
}
|
||||
|
||||
void Log::push_log(int level, char* cFormat, va_list vlist)
|
||||
{
|
||||
if (level <= m_logLevel)
|
||||
{
|
||||
char levelstr[20];
|
||||
switch (level)
|
||||
{
|
||||
case LEVEL_DEBUG:
|
||||
strcpy(levelstr, "DEBUG");
|
||||
break;
|
||||
case LEVEL_ERROR:
|
||||
strcpy(levelstr, "ERROR");
|
||||
break;
|
||||
case LEVEL_INFOR:
|
||||
default:
|
||||
strcpy(levelstr, "INFOR");
|
||||
break;
|
||||
}
|
||||
char logbuf[LOG_BUF_SIZE];
|
||||
memset(logbuf, 0, sizeof(logbuf));
|
||||
string&& sysTime = getSysTime();
|
||||
sprintf(logbuf, "%s [%s] ", sysTime.c_str(), levelstr);
|
||||
int lens = strlen(logbuf);
|
||||
vsnprintf(logbuf + lens, LOG_BUF_SIZE - 1 - lens, cFormat, vlist);// last bit'\0'
|
||||
|
||||
string LogString(logbuf);
|
||||
push_logstr(LogString);
|
||||
}
|
||||
}
|
||||
|
||||
void Log::push_logstr(std::string& strLog)
|
||||
{
|
||||
std::unique_lock <std::mutex> lck(m_mutex);
|
||||
m_logQue.push(strLog);
|
||||
m_cv.notify_all();
|
||||
}
|
||||
|
||||
void Log::quit()
|
||||
{
|
||||
std::unique_lock <std::mutex> lck(m_mutex);
|
||||
m_bExit = true;
|
||||
m_cv.notify_all();
|
||||
}
|
||||
|
||||
std::string Log::pop_log()
|
||||
{
|
||||
std::string LogString;
|
||||
std::unique_lock <std::mutex> lck(m_mutex);
|
||||
if (m_logQue.empty())
|
||||
{
|
||||
m_cv.wait(lck);
|
||||
}
|
||||
if (!m_logQue.empty())
|
||||
{
|
||||
LogString = m_logQue.front();
|
||||
m_logQue.pop();
|
||||
}
|
||||
return LogString;
|
||||
}
|
||||
|
||||
void Log::run()
|
||||
{
|
||||
|
||||
while (!m_bExit)
|
||||
{
|
||||
std::string LogString = pop_log();
|
||||
if (m_fLog && !LogString.empty())
|
||||
{
|
||||
fprintf(m_fLog, "%s", LogString.c_str());
|
||||
fflush(m_fLog);
|
||||
}
|
||||
fprintf(stderr, "%s", LogString.c_str());
|
||||
}
|
||||
}
|
60
image_framework/utils/Log/Log.h
Executable file
60
image_framework/utils/Log/Log.h
Executable file
@ -0,0 +1,60 @@
|
||||
#ifndef _LOG_H
|
||||
#define _LOG_H
|
||||
#include "LogTask.h"
|
||||
#include <queue>
|
||||
#include <string>
|
||||
#include <mutex>
|
||||
#include <condition_variable>
|
||||
#define LEVEL_NORMAL 0
|
||||
#define LEVEL_ERROR 1
|
||||
#define LEVEL_INFOR 2
|
||||
#define LEVEL_DEBUG 3
|
||||
|
||||
|
||||
class Log :
|
||||
public LogTask
|
||||
{
|
||||
public:
|
||||
static Log& getInstance();
|
||||
// 初始化日志打印, 不调用,不记录日子信息,
|
||||
// level 日志等级,pLogModuleName: 日志模块名称
|
||||
void init(int level, const char* pLogModuleName = nullptr);
|
||||
void log(int level, const char* file, const char* func, int lineNo, const char* cFormat, ...);
|
||||
void debugBin(const char* szInfo, uint8_t* szData = nullptr, uint32_t nDataLen = 0);
|
||||
void debugStr(const char* szInfo, const char *cFormat, ...);
|
||||
void info(const char* szInfo, const char *cFormat, ...);
|
||||
void quit();
|
||||
protected:
|
||||
void hex2Str(char* outBuf, uint32_t nbufLen, uint8_t* szData, uint32_t nDataLen);
|
||||
void log2(int level,const char* cFormat, ...);
|
||||
void push_log(int level, char* cFormat, va_list vlist);
|
||||
void push_logstr(std::string& strLog);
|
||||
|
||||
virtual void run() override;
|
||||
private:
|
||||
std::string pop_log();
|
||||
Log();
|
||||
Log(const Log&) = delete;
|
||||
Log(const Log&&) = delete;
|
||||
Log& operator=(const Log&) = delete;
|
||||
Log& operator=(const Log&&) = delete;
|
||||
std::string getSysTime();
|
||||
virtual ~Log();
|
||||
|
||||
bool m_bExit;
|
||||
FILE* m_fLog;
|
||||
static Log m_log;
|
||||
static int m_counter;
|
||||
int m_logLevel;
|
||||
std::queue<std::string> m_logQue;
|
||||
std::mutex m_mutex;
|
||||
std::condition_variable m_cv;
|
||||
};
|
||||
#define Loger(level,cFormat,...) Log::getInstance().log(level, __FILE__, /*__PRETTY_FUNCTION__*/__FUNCTION__, __LINE__, cFormat, ##__VA_ARGS__);
|
||||
#define LogDebugBin(szInfo, szData, nDataLen) Log::getInstance().debugBin(szInfo, szData, nDataLen);
|
||||
#define LogDebugStr(szInfo, cFormat, ...) Log::getInstance().debugStr(szInfo, cFormat, ##__VA_ARGS__);
|
||||
#define LogInfoStr(szInfo, cFormat, ...) Log::getInstance().info(szInfo, cFormat, ##__VA_ARGS__);
|
||||
#define LogFunctionBegin() Loger(LEVEL_INFOR, "%s", "\tbegin!!!!")
|
||||
#define LogFunctionEnd() Loger(LEVEL_INFOR, "%s", "\tend!!!!")
|
||||
|
||||
#endif // _LOG_H
|
22
image_framework/utils/Log/LogTask.cpp
Executable file
22
image_framework/utils/Log/LogTask.cpp
Executable file
@ -0,0 +1,22 @@
|
||||
#include "LogTask.h"
|
||||
|
||||
LogTask::LogTask()
|
||||
:m_pThread(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
LogTask::~LogTask()
|
||||
{
|
||||
}
|
||||
|
||||
void LogTask::log_write_thread()
|
||||
{
|
||||
m_pThread = new std::thread(start, this);
|
||||
m_pThread->detach();
|
||||
}
|
||||
|
||||
void LogTask::start(LogTask* pLog)
|
||||
{
|
||||
pLog->run();
|
||||
}
|
22
image_framework/utils/Log/LogTask.h
Executable file
22
image_framework/utils/Log/LogTask.h
Executable file
@ -0,0 +1,22 @@
|
||||
#ifndef _LOGINTERFACE_H
|
||||
#define _LOGINTERFACE_H
|
||||
|
||||
#include <thread>
|
||||
|
||||
class LogTask
|
||||
{
|
||||
protected:
|
||||
void log_write_thread();
|
||||
static void start(LogTask* plog);
|
||||
virtual void run() = 0;
|
||||
LogTask();
|
||||
LogTask(const LogTask&) = delete;
|
||||
LogTask(const LogTask&&) = delete;
|
||||
LogTask& operator=(const LogTask&) = delete;
|
||||
LogTask& operator=(const LogTask&&) = delete;
|
||||
virtual ~LogTask();
|
||||
private:
|
||||
std::thread* m_pThread;
|
||||
};
|
||||
|
||||
#endif // _LOGINTERFACE_H
|
72
include/Livox/comm/comm_port.h
Executable file
72
include/Livox/comm/comm_port.h
Executable file
@ -0,0 +1,72 @@
|
||||
//
|
||||
// The MIT License (MIT)
|
||||
//
|
||||
// Copyright (c) 2019 Livox. All rights reserved.
|
||||
//
|
||||
// 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 COMM_COMM_PORT_H_
|
||||
#define COMM_COMM_PORT_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include "protocol.h"
|
||||
|
||||
namespace livox {
|
||||
const uint32_t kCacheSize = 8192;
|
||||
const uint32_t kMoveCacheLimit = 1536;
|
||||
|
||||
typedef struct {
|
||||
uint8_t buf[kCacheSize];
|
||||
uint32_t rd_idx;
|
||||
uint32_t wr_idx;
|
||||
uint32_t size;
|
||||
} PortCache;
|
||||
|
||||
class CommPort {
|
||||
public:
|
||||
CommPort();
|
||||
|
||||
~CommPort();
|
||||
|
||||
int32_t Pack(uint8_t *o_buf, uint32_t o_buf_size, uint32_t *o_len, const CommPacket &i_packet);
|
||||
|
||||
int32_t ParseCommStream(CommPacket *o_pack);
|
||||
|
||||
uint8_t *FetchCacheFreeSpace(uint32_t *o_len);
|
||||
|
||||
int32_t UpdateCacheWrIdx(uint32_t used_size);
|
||||
|
||||
uint16_t GetAndUpdateSeqNum();
|
||||
|
||||
private:
|
||||
uint32_t GetCacheTailSize();
|
||||
|
||||
uint32_t GetValidDataSize();
|
||||
|
||||
void UpdateCache(void);
|
||||
|
||||
PortCache cache_;
|
||||
Protocol *protocol_;
|
||||
uint32_t parse_step_;
|
||||
uint16_t seq_num_;
|
||||
};
|
||||
|
||||
} // namespace livox
|
||||
#endif // COMM_COMM_PORT_H_
|
82
include/Livox/comm/protocol.h
Executable file
82
include/Livox/comm/protocol.h
Executable file
@ -0,0 +1,82 @@
|
||||
//
|
||||
// The MIT License (MIT)
|
||||
//
|
||||
// Copyright (c) 2019 Livox. All rights reserved.
|
||||
//
|
||||
// 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 COMM_PROTOCOL_H_
|
||||
#define COMM_PROTOCOL_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
namespace livox {
|
||||
typedef struct CommPacket CommPacket;
|
||||
|
||||
typedef int (*RequestPackCb)(CommPacket *packet);
|
||||
|
||||
typedef enum { kRequestPack, kAckPack, kMsgPack } PacketType;
|
||||
|
||||
typedef enum { kLidarSdk, kRsvd1, kProtocolUndef } ProtocolType;
|
||||
|
||||
typedef enum { kNoNeed, kNeedAck, kDelayAck } NeedAckType;
|
||||
|
||||
typedef enum { kParseSuccess, kParseFail } ParseResult;
|
||||
|
||||
typedef struct CommPacket {
|
||||
uint8_t packet_type;
|
||||
uint8_t protocol;
|
||||
uint8_t protocol_version;
|
||||
uint8_t cmd_set;
|
||||
uint32_t cmd_code;
|
||||
uint32_t sender;
|
||||
uint32_t sub_sender;
|
||||
uint32_t receiver;
|
||||
uint32_t sub_receiver;
|
||||
uint32_t seq_num;
|
||||
uint8_t *data;
|
||||
uint16_t data_len;
|
||||
uint32_t padding;
|
||||
// RequestPackCb *ack_request_cb;
|
||||
// uint32_t retry_times;
|
||||
// uint32_t timeout;
|
||||
} CommPacket;
|
||||
|
||||
class Protocol {
|
||||
public:
|
||||
virtual ~Protocol(){};
|
||||
|
||||
virtual int32_t ParsePacket(uint8_t *i_buf, uint32_t i_len, CommPacket *o_packet) = 0;
|
||||
|
||||
virtual int32_t Pack(uint8_t *o_buf, uint32_t o_buf_size, uint32_t *o_len, const CommPacket &i_packet) = 0;
|
||||
|
||||
virtual uint32_t GetPreambleLen() = 0;
|
||||
|
||||
virtual uint32_t GetPacketWrapperLen() = 0;
|
||||
|
||||
virtual uint32_t GetPacketLen(uint8_t *buf) = 0;
|
||||
|
||||
virtual int32_t CheckPreamble(uint8_t *buf) = 0;
|
||||
|
||||
virtual int32_t CheckPacket(uint8_t *buf) = 0;
|
||||
};
|
||||
|
||||
} // namespace livox
|
||||
#endif // COMM_PROTOCOL_H_
|
49
include/Livox/config.h
Executable file
49
include/Livox/config.h
Executable file
@ -0,0 +1,49 @@
|
||||
//
|
||||
// The MIT License (MIT)
|
||||
//
|
||||
// Copyright (c) 2019 Livox. All rights reserved.
|
||||
//
|
||||
// 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 CONFIG_H_
|
||||
#define CONFIG_H_
|
||||
|
||||
#if defined(__linux__)
|
||||
#include <sys/epoll.h>
|
||||
#include <sys/time.h>
|
||||
#include <unistd.h>
|
||||
#define HAVE_EPOLL 1
|
||||
#elif defined(_WIN32)
|
||||
#include <winsock2.h>
|
||||
#define HAVE_SELECT 1
|
||||
#elif defined(__APPLE__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined (__NetBSD__)
|
||||
#include <sys/event.h>
|
||||
#include <sys/types.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#define HAVE_KQUEUE 1
|
||||
#else
|
||||
#include <sys/poll.h>
|
||||
#define HAVE_POLL 1
|
||||
#endif
|
||||
|
||||
#endif // CONFIG_H_
|
||||
|
||||
|
855
include/Livox/livox_def.h
Executable file
855
include/Livox/livox_def.h
Executable file
@ -0,0 +1,855 @@
|
||||
//
|
||||
// The MIT License (MIT)
|
||||
//
|
||||
// Copyright (c) 2019 Livox. All rights reserved.
|
||||
//
|
||||
// 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 LIVOX_DEF_H_
|
||||
#define LIVOX_DEF_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#define kMaxLidarCount 32
|
||||
|
||||
/** Device type. */
|
||||
typedef enum {
|
||||
kDeviceTypeHub = 0, /**< Livox Hub. */
|
||||
kDeviceTypeLidarMid40 = 1, /**< Mid-40. */
|
||||
kDeviceTypeLidarTele = 2, /**< Tele. */
|
||||
kDeviceTypeLidarHorizon = 3, /**< Horizon. */
|
||||
kDeviceTypeLidarMid70 = 6, /**< Livox Mid-70. */
|
||||
kDeviceTypeLidarAvia = 7 /**< Avia. */
|
||||
} DeviceType;
|
||||
|
||||
/** Lidar state. */
|
||||
typedef enum {
|
||||
kLidarStateInit = 0, /**< Initialization state. */
|
||||
kLidarStateNormal = 1, /**< Normal work state. */
|
||||
kLidarStatePowerSaving = 2, /**< Power-saving state. */
|
||||
kLidarStateStandBy = 3, /**< Standby state. */
|
||||
kLidarStateError = 4, /**< Error state. */
|
||||
kLidarStateUnknown = 5 /**< Unknown state. */
|
||||
} LidarState;
|
||||
|
||||
/** Lidar mode. */
|
||||
typedef enum {
|
||||
kLidarModeNormal = 1, /**< Normal mode. */
|
||||
kLidarModePowerSaving = 2, /**< Power-saving mode. */
|
||||
kLidarModeStandby = 3 /**< Standby mode. */
|
||||
} LidarMode;
|
||||
|
||||
/** Lidar feature. */
|
||||
typedef enum {
|
||||
kLidarFeatureNone = 0, /**< No feature. */
|
||||
kLidarFeatureRainFog = 1 /**< Rain and fog feature. */
|
||||
} LidarFeature;
|
||||
|
||||
/** Lidar IP mode. */
|
||||
typedef enum {
|
||||
kLidarDynamicIpMode = 0, /**< Dynamic IP. */
|
||||
kLidarStaticIpMode = 1 /**< Static IP. */
|
||||
} LidarIpMode;
|
||||
|
||||
/** Lidar Scan Pattern. */
|
||||
typedef enum {
|
||||
kNoneRepetitiveScanPattern = 0, /**< None Repetitive Scan Pattern. */
|
||||
kRepetitiveScanPattern = 1, /**< Repetitive Scan Pattern. */
|
||||
} LidarScanPattern;
|
||||
|
||||
/** Function return value definition. */
|
||||
typedef enum {
|
||||
kStatusSendFailed = -9, /**< Command send failed. */
|
||||
kStatusHandlerImplNotExist = -8, /**< Handler implementation not exist. */
|
||||
kStatusInvalidHandle = -7, /**< Device handle invalid. */
|
||||
kStatusChannelNotExist = -6, /**< Command channel not exist. */
|
||||
kStatusNotEnoughMemory = -5, /**< No enough memory. */
|
||||
kStatusTimeout = -4, /**< Operation timeouts. */
|
||||
kStatusNotSupported = -3, /**< Operation is not supported on this device. */
|
||||
kStatusNotConnected = -2, /**< Requested device is not connected. */
|
||||
kStatusFailure = -1, /**< Failure. */
|
||||
kStatusSuccess = 0 /**< Success. */
|
||||
} LivoxStatus;
|
||||
|
||||
/** Fuction return value defination, refer to \ref LivoxStatus. */
|
||||
typedef int32_t livox_status;
|
||||
|
||||
/** Device update type, indicating the change of device connection or working state. */
|
||||
typedef enum {
|
||||
kEventConnect = 0, /**< Device is connected. */
|
||||
kEventDisconnect = 1, /**< Device is removed. */
|
||||
kEventStateChange = 2, /**< Device working state changes or an error occurs. */
|
||||
kEventHubConnectionChange = 3 /**< Hub is connected or LiDAR unit(s) is/are removed. */
|
||||
} DeviceEvent;
|
||||
|
||||
/** Timestamp sync mode define. */
|
||||
typedef enum {
|
||||
kTimestampTypeNoSync = 0, /**< No sync signal mode. */
|
||||
kTimestampTypePtp = 1, /**< 1588v2.0 PTP sync mode. */
|
||||
kTimestampTypeRsvd = 2, /**< Reserved use. */
|
||||
kTimestampTypePpsGps = 3, /**< pps+gps sync mode. */
|
||||
kTimestampTypePps = 4, /**< pps only sync mode. */
|
||||
kTimestampTypeUnknown = 5 /**< Unknown mode. */
|
||||
} TimestampType;
|
||||
|
||||
/** Point data type. */
|
||||
typedef enum {
|
||||
kCartesian, /**< Cartesian coordinate point cloud. */
|
||||
kSpherical, /**< Spherical coordinate point cloud. */
|
||||
kExtendCartesian, /**< Extend cartesian coordinate point cloud. */
|
||||
kExtendSpherical, /**< Extend spherical coordinate point cloud. */
|
||||
kDualExtendCartesian, /**< Dual extend cartesian coordinate point cloud. */
|
||||
kDualExtendSpherical, /**< Dual extend spherical coordinate point cloud. */
|
||||
kImu, /**< IMU data. */
|
||||
kTripleExtendCartesian, /**< Triple extend cartesian coordinate point cloud. */
|
||||
kTripleExtendSpherical, /**< Triple extend spherical coordinate point cloud. */
|
||||
kMaxPointDataType /**< Max Point Data Type. */
|
||||
} PointDataType;
|
||||
|
||||
/** Point cloud return mode. */
|
||||
typedef enum {
|
||||
kFirstReturn, /**< First single return mode . */
|
||||
kStrongestReturn, /**< Strongest single return mode. */
|
||||
kDualReturn, /**< Dual return mode. */
|
||||
kTripleReturn, /**< Triple return mode. */
|
||||
} PointCloudReturnMode;
|
||||
|
||||
/** IMU push frequency. */
|
||||
typedef enum {
|
||||
kImuFreq0Hz, /**< IMU push closed. */
|
||||
kImuFreq200Hz, /**< IMU push frequency 200Hz. */
|
||||
} ImuFreq;
|
||||
|
||||
#pragma pack(1)
|
||||
|
||||
#define LIVOX_SDK_MAJOR_VERSION 2
|
||||
#define LIVOX_SDK_MINOR_VERSION 3
|
||||
#define LIVOX_SDK_PATCH_VERSION 0
|
||||
|
||||
#define kBroadcastCodeSize 16
|
||||
|
||||
/** The numeric version information struct. */
|
||||
typedef struct {
|
||||
int major; /**< major number */
|
||||
int minor; /**< minor number */
|
||||
int patch; /**< patch number */
|
||||
} LivoxSdkVersion;
|
||||
|
||||
/** Cartesian coordinate format. */
|
||||
typedef struct {
|
||||
int32_t x; /**< X axis, Unit:mm */
|
||||
int32_t y; /**< Y axis, Unit:mm */
|
||||
int32_t z; /**< Z axis, Unit:mm */
|
||||
uint8_t reflectivity; /**< Reflectivity */
|
||||
} LivoxRawPoint;
|
||||
|
||||
/** Spherical coordinate format. */
|
||||
typedef struct {
|
||||
uint32_t depth; /**< Depth, Unit: mm */
|
||||
uint16_t theta; /**< Zenith angle[0, 18000], Unit: 0.01 degree */
|
||||
uint16_t phi; /**< Azimuth[0, 36000], Unit: 0.01 degree */
|
||||
uint8_t reflectivity; /**< Reflectivity */
|
||||
} LivoxSpherPoint;
|
||||
|
||||
/** Standard point cloud format */
|
||||
typedef struct {
|
||||
float x; /**< X axis, Unit:m */
|
||||
float y; /**< Y axis, Unit:m */
|
||||
float z; /**< Z axis, Unit:m */
|
||||
uint8_t reflectivity; /**< Reflectivity */
|
||||
} LivoxPoint;
|
||||
|
||||
/** Extend cartesian coordinate format. */
|
||||
typedef struct {
|
||||
int32_t x; /**< X axis, Unit:mm */
|
||||
int32_t y; /**< Y axis, Unit:mm */
|
||||
int32_t z; /**< Z axis, Unit:mm */
|
||||
uint8_t reflectivity; /**< Reflectivity */
|
||||
uint8_t tag; /**< Tag */
|
||||
} LivoxExtendRawPoint;
|
||||
|
||||
/** Extend spherical coordinate format. */
|
||||
typedef struct {
|
||||
uint32_t depth; /**< Depth, Unit: mm */
|
||||
uint16_t theta; /**< Zenith angle[0, 18000], Unit: 0.01 degree */
|
||||
uint16_t phi; /**< Azimuth[0, 36000], Unit: 0.01 degree */
|
||||
uint8_t reflectivity; /**< Reflectivity */
|
||||
uint8_t tag; /**< Tag */
|
||||
} LivoxExtendSpherPoint;
|
||||
|
||||
/** Dual extend cartesian coordinate format. */
|
||||
typedef struct {
|
||||
int32_t x1; /**< X axis, Unit:mm */
|
||||
int32_t y1; /**< Y axis, Unit:mm */
|
||||
int32_t z1; /**< Z axis, Unit:mm */
|
||||
uint8_t reflectivity1; /**< Reflectivity */
|
||||
uint8_t tag1; /**< Tag */
|
||||
int32_t x2; /**< X axis, Unit:mm */
|
||||
int32_t y2; /**< Y axis, Unit:mm */
|
||||
int32_t z2; /**< Z axis, Unit:mm */
|
||||
uint8_t reflectivity2; /**< Reflectivity */
|
||||
uint8_t tag2; /**< Tag */
|
||||
} LivoxDualExtendRawPoint;
|
||||
|
||||
/** Dual extend spherical coordinate format. */
|
||||
typedef struct {
|
||||
uint16_t theta; /**< Zenith angle[0, 18000], Unit: 0.01 degree */
|
||||
uint16_t phi; /**< Azimuth[0, 36000], Unit: 0.01 degree */
|
||||
uint32_t depth1; /**< Depth, Unit: mm */
|
||||
uint8_t reflectivity1; /**< Reflectivity */
|
||||
uint8_t tag1; /**< Tag */
|
||||
uint32_t depth2; /**< Depth, Unit: mm */
|
||||
uint8_t reflectivity2; /**< Reflectivity */
|
||||
uint8_t tag2; /**< Tag */
|
||||
} LivoxDualExtendSpherPoint;
|
||||
|
||||
/** Triple extend cartesian coordinate format. */
|
||||
typedef struct {
|
||||
int32_t x1; /**< X axis, Unit:mm */
|
||||
int32_t y1; /**< Y axis, Unit:mm */
|
||||
int32_t z1; /**< Z axis, Unit:mm */
|
||||
uint8_t reflectivity1; /**< Reflectivity */
|
||||
uint8_t tag1; /**< Tag */
|
||||
int32_t x2; /**< X axis, Unit:mm */
|
||||
int32_t y2; /**< Y axis, Unit:mm */
|
||||
int32_t z2; /**< Z axis, Unit:mm */
|
||||
uint8_t reflectivity2; /**< Reflectivity */
|
||||
uint8_t tag2; /**< Tag */
|
||||
int32_t x3; /**< X axis, Unit:mm */
|
||||
int32_t y3; /**< Y axis, Unit:mm */
|
||||
int32_t z3; /**< Z axis, Unit:mm */
|
||||
uint8_t reflectivity3; /**< Reflectivity */
|
||||
uint8_t tag3; /**< Tag */
|
||||
} LivoxTripleExtendRawPoint;
|
||||
|
||||
/** Triple extend spherical coordinate format. */
|
||||
typedef struct {
|
||||
uint16_t theta; /**< Zenith angle[0, 18000], Unit: 0.01 degree */
|
||||
uint16_t phi; /**< Azimuth[0, 36000], Unit: 0.01 degree */
|
||||
uint32_t depth1; /**< Depth, Unit: mm */
|
||||
uint8_t reflectivity1; /**< Reflectivity */
|
||||
uint8_t tag1; /**< Tag */
|
||||
uint32_t depth2; /**< Depth, Unit: mm */
|
||||
uint8_t reflectivity2; /**< Reflectivity */
|
||||
uint8_t tag2; /**< Tag */
|
||||
uint32_t depth3; /**< Depth, Unit: mm */
|
||||
uint8_t reflectivity3; /**< Reflectivity */
|
||||
uint8_t tag3; /**< Tag */
|
||||
} LivoxTripleExtendSpherPoint;
|
||||
|
||||
/** IMU data format. */
|
||||
typedef struct {
|
||||
float gyro_x; /**< Gyroscope X axis, Unit:rad/s */
|
||||
float gyro_y; /**< Gyroscope Y axis, Unit:rad/s */
|
||||
float gyro_z; /**< Gyroscope Z axis, Unit:rad/s */
|
||||
float acc_x; /**< Accelerometer X axis, Unit:g */
|
||||
float acc_y; /**< Accelerometer Y axis, Unit:g */
|
||||
float acc_z; /**< Accelerometer Z axis, Unit:g */
|
||||
} LivoxImuPoint;
|
||||
|
||||
/** LiDAR error code. */
|
||||
typedef struct {
|
||||
uint32_t temp_status : 2; /**< 0: Temperature in Normal State. 1: High or Low. 2: Extremely High or Extremely Low. */
|
||||
uint32_t volt_status : 2; /**< 0: Voltage in Normal State. 1: High. 2: Extremely High. */
|
||||
uint32_t motor_status : 2; /**< 0: Motor in Normal State. 1: Motor in Warning State. 2:Motor in Error State, Unable to Work. */
|
||||
uint32_t dirty_warn : 2; /**< 0: Not Dirty or Blocked. 1: Dirty or Blocked. */
|
||||
uint32_t firmware_err : 1; /**< 0: Firmware is OK. 1: Firmware is Abnormal, Need to be Upgraded. */
|
||||
uint32_t pps_status : 1; /**< 0: No PPS Signal. 1: PPS Signal is OK. */
|
||||
uint32_t device_status : 1; /**< 0: Normal. 1: Warning for Approaching the End of Service Life. */
|
||||
uint32_t fan_status : 1; /**< 0: Fan in Normal State. 1: Fan in Warning State. */
|
||||
uint32_t self_heating : 1; /**< 0: Normal. 1: Low Temperature Self Heating On. */
|
||||
uint32_t ptp_status : 1; /**< 0: No 1588 Signal. 1: 1588 Signal is OK. */
|
||||
/** 0: System dose not start time synchronization.
|
||||
* 1: Using PTP 1588 synchronization.
|
||||
* 2: Using GPS synchronization.
|
||||
* 3: Using PPS synchronization.
|
||||
* 4: System time synchronization is abnormal.(The highest priority synchronization signal is abnormal)
|
||||
*/
|
||||
uint32_t time_sync_status : 3;
|
||||
uint32_t rsvd : 13; /**< Reserved. */
|
||||
uint32_t system_status : 2; /**< 0: Normal. 1: Warning. 2: Error. */
|
||||
} LidarErrorCode;
|
||||
|
||||
/** Hub error code. */
|
||||
typedef struct {
|
||||
/** 0: No synchronization signal.
|
||||
* 1: 1588 synchronization.
|
||||
* 2: GPS synchronization.
|
||||
* 3: System time synchronization is abnormal.(The highest priority synchronization signal is abnormal)
|
||||
*/
|
||||
uint32_t sync_status : 2;
|
||||
uint32_t temp_status : 2; /**< 0: Temperature in Normal State. 1: High or Low. 2: Extremely High or Extremely Low. */
|
||||
uint32_t lidar_status : 1; /**< 0: LiDAR State is Normal. 1: LiDAR State is Abnormal. */
|
||||
uint32_t lidar_link_status : 1; /**< 0: LiDAR Connection is Normal. 1: LiDAR Connection is Abnormal. */
|
||||
uint32_t firmware_err : 1; /**< 0: LiDAR Firmware is OK. 1: LiDAR Firmware is Abnormal, Need to be Upgraded. */
|
||||
uint32_t rsvd : 23; /**< Reserved. */
|
||||
uint32_t system_status : 2; /**< 0: Normal. 1: Warning. 2: Error. */
|
||||
} HubErrorCode;
|
||||
|
||||
/**
|
||||
* Device error message.
|
||||
*/
|
||||
typedef union {
|
||||
uint32_t error_code; /**< Error code. */
|
||||
LidarErrorCode lidar_error_code; /**< Lidar error code. */
|
||||
HubErrorCode hub_error_code; /**< Hub error code. */
|
||||
} ErrorMessage;
|
||||
|
||||
/** Point cloud packet. */
|
||||
typedef struct {
|
||||
uint8_t version; /**< Packet protocol version. */
|
||||
uint8_t slot; /**< Slot number used for connecting LiDAR. */
|
||||
uint8_t id; /**< LiDAR id. */
|
||||
uint8_t rsvd; /**< Reserved. */
|
||||
uint32_t err_code; /**< Device error status indicator information. */
|
||||
uint8_t timestamp_type; /**< Timestamp type. */
|
||||
/** Point cloud coordinate format, refer to \ref PointDataType . */
|
||||
uint8_t data_type;
|
||||
uint8_t timestamp[8]; /**< Nanosecond or UTC format timestamp. */
|
||||
uint8_t data[1]; /**< Point cloud data. */
|
||||
} LivoxEthPacket;
|
||||
|
||||
/** Information of LiDAR work state. */
|
||||
typedef union {
|
||||
uint32_t progress; /**< LiDAR work state switching progress. */
|
||||
ErrorMessage status_code; /**< LiDAR work state status code. */
|
||||
} StatusUnion;
|
||||
|
||||
/** Information of the connected LiDAR or hub. */
|
||||
typedef struct {
|
||||
char broadcast_code[kBroadcastCodeSize]; /**< Device broadcast code, null-terminated string, 15 characters at most. */
|
||||
uint8_t handle; /**< Device handle. */
|
||||
uint8_t slot; /**< Slot number used for connecting LiDAR. */
|
||||
uint8_t id; /**< LiDAR id. */
|
||||
uint8_t type; /**< Device type, refer to \ref DeviceType. */
|
||||
uint16_t data_port; /**< Point cloud data UDP port. */
|
||||
uint16_t cmd_port; /**< Control command UDP port. */
|
||||
uint16_t sensor_port; /**< IMU data UDP port. */
|
||||
char ip[16]; /**< IP address. */
|
||||
LidarState state; /**< LiDAR state. */
|
||||
LidarFeature feature; /**< LiDAR feature. */
|
||||
StatusUnion status; /**< LiDAR work state status. */
|
||||
uint8_t firmware_version[4]; /**< Firmware version. */
|
||||
} DeviceInfo;
|
||||
|
||||
/** The information of broadcast device. */
|
||||
typedef struct {
|
||||
char broadcast_code[kBroadcastCodeSize]; /**< Device broadcast code, null-terminated string, 15 characters at most. */
|
||||
uint8_t dev_type; /**< Device type, refer to \ref DeviceType. */
|
||||
uint16_t reserved; /**< Reserved. */
|
||||
char ip[16]; /**< Device ip. */
|
||||
} BroadcastDeviceInfo;
|
||||
|
||||
/** The information of LiDAR units that are connected to the Livox Hub. */
|
||||
typedef struct {
|
||||
char broadcast_code[kBroadcastCodeSize]; /**< Device broadcast code, null-terminated string, 15 characters at most. */
|
||||
uint8_t dev_type; /**< Device type, refer to \ref DeviceType. */
|
||||
uint8_t version[4]; /**< Firmware version. */
|
||||
uint8_t slot; /**< Slot number used for connecting LiDAR units. */
|
||||
uint8_t id; /**< Device id. */
|
||||
} ConnectedLidarInfo;
|
||||
|
||||
/** LiDAR mode configuration information. */
|
||||
typedef struct {
|
||||
char broadcast_code[kBroadcastCodeSize]; /**< Device broadcast code, null-terminated string, 15 characters at most. */
|
||||
uint8_t state; /**< LiDAR state, refer to \ref LidarMode. */
|
||||
} LidarModeRequestItem;
|
||||
|
||||
typedef struct {
|
||||
uint8_t ret_code; /**< Return code. */
|
||||
char broadcast_code[kBroadcastCodeSize]; /**< Device broadcast code. */
|
||||
} ReturnCode;
|
||||
|
||||
typedef struct {
|
||||
char broadcast_code[kBroadcastCodeSize]; /**< Device broadcast code. */
|
||||
} DeviceBroadcastCode;
|
||||
|
||||
typedef struct {
|
||||
char broadcast_code[kBroadcastCodeSize]; /**< Device broadcast code. */
|
||||
uint8_t feature; /**< Close or open the rain and fog feature. */
|
||||
} RainFogSuppressRequestItem;
|
||||
|
||||
typedef struct {
|
||||
char broadcast_code[kBroadcastCodeSize]; /**< Device broadcast code. */
|
||||
uint8_t state; /**< Fan state: 1 for turn on fan, 0 for turn off fan. */
|
||||
} FanControlRequestItem;
|
||||
|
||||
typedef struct {
|
||||
char broadcast_code[kBroadcastCodeSize]; /**< Device broadcast code. */
|
||||
} GetFanStateRequestItem;
|
||||
|
||||
typedef struct {
|
||||
uint8_t ret_code; /**< Return code. */
|
||||
char broadcast_code[kBroadcastCodeSize]; /**< Device broadcast code. */
|
||||
uint8_t state; /**< Fan state: 1 for fan is on, 0 for fan is off. */
|
||||
} GetFanStateResponseItem;
|
||||
|
||||
typedef struct {
|
||||
char broadcast_code[kBroadcastCodeSize]; /**< Device broadcast code. */
|
||||
uint8_t mode; /**< Point cloud return mode, refer to \ref PointCloudReturnMode. */
|
||||
} SetPointCloudReturnModeRequestItem;
|
||||
|
||||
typedef struct {
|
||||
char broadcast_code[kBroadcastCodeSize]; /**< Device broadcast code. */
|
||||
} GetPointCloudReturnModeRequestItem;
|
||||
|
||||
typedef struct {
|
||||
uint8_t ret_code; /**< Return code. */
|
||||
char broadcast_code[kBroadcastCodeSize]; /**< Device broadcast code. */
|
||||
uint8_t mode; /**< Point cloud return mode, refer to \ref PointCloudReturnMode. */
|
||||
} GetPointCloudReturnModeResponseItem;
|
||||
|
||||
typedef struct {
|
||||
char broadcast_code[kBroadcastCodeSize]; /**< Device broadcast code. */
|
||||
uint8_t freq; /**< IMU push frequency, refer to \ref ImuFreq. */
|
||||
} SetImuPushFrequencyRequestItem;
|
||||
|
||||
|
||||
typedef struct {
|
||||
char broadcast_code[kBroadcastCodeSize]; /**< Device broadcast code. */
|
||||
} GetImuPushFrequencyRequestItem;
|
||||
|
||||
typedef struct {
|
||||
uint8_t ret_code; /**< Return code. */
|
||||
char broadcast_code[kBroadcastCodeSize]; /**< Device broadcast code. */
|
||||
uint8_t freq; /**< IMU push frequency, refer to \ref ImuFreq. */
|
||||
} GetImuPushFrequencyResponseItem;
|
||||
|
||||
/** LiDAR configuration information. */
|
||||
typedef struct {
|
||||
char broadcast_code[kBroadcastCodeSize]; /**< Device broadcast code. */
|
||||
float roll; /**< Roll angle, unit: degree. */
|
||||
float pitch; /**< Pitch angle, unit: degree. */
|
||||
float yaw; /**< Yaw angle, unit: degree. */
|
||||
int32_t x; /**< X translation, unit: mm. */
|
||||
int32_t y; /**< Y translation, unit: mm. */
|
||||
int32_t z; /**< Z translation, unit: mm. */
|
||||
} ExtrinsicParameterRequestItem;
|
||||
|
||||
/** LiDAR extrinsic parameters. */
|
||||
typedef struct {
|
||||
uint8_t ret_code; /**< Return code. */
|
||||
char broadcast_code[kBroadcastCodeSize]; /**< Broadcast code. */
|
||||
float roll; /**< Roll angle, unit: degree. */
|
||||
float pitch; /**< Pitch angle, unit: degree. */
|
||||
float yaw; /**< Yaw angle, unit: degree. */
|
||||
int32_t x; /**< X translation, unit: mm. */
|
||||
int32_t y; /**< Y translation, unit: mm. */
|
||||
int32_t z; /**< Z translation, unit: mm. */
|
||||
} ExtrinsicParameterResponseItem;
|
||||
|
||||
typedef struct {
|
||||
char broadcast_code[kBroadcastCodeSize]; /**< Broadcast code. */
|
||||
uint8_t state; /**< LiDAR state. */
|
||||
uint8_t feature; /**< LiDAR feature. */
|
||||
StatusUnion error_union; /**< LiDAR work state. */
|
||||
} LidarStateItem;
|
||||
|
||||
/**
|
||||
* The request body for the command of handshake.
|
||||
*/
|
||||
typedef struct {
|
||||
uint32_t ip_addr; /**< IP address of the device. */
|
||||
uint16_t data_port; /**< UDP port of the data connection. */
|
||||
uint16_t cmd_port; /**< UDP port of the command connection. */
|
||||
uint16_t sensor_port; /**< UDP port of the sensor connection. */
|
||||
} HandshakeRequest;
|
||||
|
||||
/**
|
||||
* The response body of querying device information.
|
||||
*/
|
||||
typedef struct {
|
||||
uint8_t ret_code; /**< Return code. */
|
||||
uint8_t firmware_version[4]; /**< Firmware version. */
|
||||
} DeviceInformationResponse;
|
||||
|
||||
/**
|
||||
* The request body of the command for setting device's IP mode.
|
||||
*/
|
||||
typedef struct {
|
||||
uint8_t ip_mode; /**< IP address mode: 0 for dynamic IP address, 1 for static IP address. */
|
||||
uint32_t ip_addr; /**< IP address. */
|
||||
} SetDeviceIPModeRequest;
|
||||
|
||||
/**
|
||||
* The response body of getting device's IP mode.
|
||||
*/
|
||||
typedef struct {
|
||||
uint8_t ret_code; /**< Return code. */
|
||||
uint8_t ip_mode; /**< IP address mode: 0 for dynamic IP address, 1 for static IP address. */
|
||||
uint32_t ip_addr; /**< IP address. */
|
||||
uint32_t net_mask; /**< Subnet mask. */
|
||||
uint32_t gw_addr; /**< Gateway address. */
|
||||
} GetDeviceIpModeResponse;
|
||||
|
||||
/**
|
||||
* The request body of the command for setting static device's IP mode.
|
||||
*/
|
||||
typedef struct {
|
||||
uint32_t ip_addr; /**< IP address. */
|
||||
uint32_t net_mask; /**< Subnet mask. */
|
||||
uint32_t gw_addr; /**< Gateway address. */
|
||||
} SetStaticDeviceIpModeRequest;
|
||||
|
||||
/**
|
||||
* The body of heartbeat response.
|
||||
*/
|
||||
typedef struct {
|
||||
uint8_t ret_code; /**< Return code. */
|
||||
uint8_t state; /**< Working state. */
|
||||
uint8_t feature; /**< LiDAR feature. */
|
||||
StatusUnion error_union; /**< LiDAR work state. */
|
||||
} HeartbeatResponse;
|
||||
|
||||
/**
|
||||
* The error code of Getting/Setting Device's Parameters.
|
||||
*/
|
||||
typedef enum {
|
||||
kKeyNoError = 0, /**< No Error. */
|
||||
kKeyNotSupported = 1, /**< The key is not supported. */
|
||||
kKeyExecFailed = 2, /**< Execution failed. */
|
||||
kKeyNotSupportedWritingState = 3, /**< The key cannot be written. */
|
||||
kKeyValueError = 4, /**< Wrong value. */
|
||||
kKeyValueLengthError = 5, /**< Wrong value length. */
|
||||
kKeyNoEnoughMemory = 6, /**< Reading parameter length limit. */
|
||||
kKeyLengthError = 7, /**< The number of parameters does not match. */
|
||||
} KeyErrorCode;
|
||||
|
||||
/**
|
||||
* The response body of setting device's parameter.
|
||||
*/
|
||||
typedef struct {
|
||||
uint8_t ret_code; /**< Return code. */
|
||||
uint16_t error_param_key; /**< Error Key. */
|
||||
uint8_t error_code; /**< Error code, refer to \ref KeyErrorCode. */
|
||||
} DeviceParameterResponse;
|
||||
|
||||
/**
|
||||
* Keys of device's parameters.
|
||||
*/
|
||||
typedef enum {
|
||||
kKeyDefault = 0, /**< Default key name. */
|
||||
kKeyHighSensetivity = 1, /**< Key to get/set LiDAR' Sensetivity. */
|
||||
kKeyScanPattern = 2, /**< Key to get/set LiDAR' ScanPattern. */
|
||||
kKeySlotNum = 3, /**< Key to get/set LiDAR' Slot number. */
|
||||
} DeviceParamKeyName;
|
||||
|
||||
/**
|
||||
* Key and value of device's parameters.
|
||||
*/
|
||||
typedef struct {
|
||||
uint16_t key; /*< Key, refer to \ref DeviceParamKeyName. */
|
||||
uint16_t length; /*< Length of value */
|
||||
uint8_t value[1]; /*< Value */
|
||||
} KeyValueParam;
|
||||
|
||||
/**
|
||||
* The response body of getting device's parameter.
|
||||
*/
|
||||
typedef struct {
|
||||
DeviceParameterResponse rsp; /*< Return code. */
|
||||
KeyValueParam kv; /*< Key and value of device's parameters. */
|
||||
} GetDeviceParameterResponse;
|
||||
|
||||
/**
|
||||
* The request body for the command of getting device's parameters.
|
||||
*/
|
||||
typedef struct {
|
||||
uint8_t param_num; /*< Number of key. */
|
||||
uint16_t key[1]; /*< Key, refer to \ref DeviceParamKeyName. */
|
||||
} GetDeviceParameterRequest;
|
||||
|
||||
/**
|
||||
* The request body for the command of resetting device's parameters.
|
||||
*/
|
||||
typedef struct {
|
||||
uint8_t flag; /*< 0: for resetting all keys, 1: for resetting part of keys. */
|
||||
uint8_t key_num; /*< number of keys to reset. */
|
||||
uint16_t key[1]; /*< Keys to reset, refer to \ref DeviceParamKeyName. */
|
||||
} ResetDeviceParameterRequest;
|
||||
|
||||
/**
|
||||
* The request body for the command of setting Livox LiDAR's parameters.
|
||||
*/
|
||||
typedef struct {
|
||||
float roll; /**< Roll angle, unit: degree. */
|
||||
float pitch; /**< Pitch angle, unit: degree. */
|
||||
float yaw; /**< Yaw angle, unit: degree. */
|
||||
int32_t x; /**< X translation, unit: mm. */
|
||||
int32_t y; /**< Y translation, unit: mm. */
|
||||
int32_t z; /**< Z translation, unit: mm. */
|
||||
} LidarSetExtrinsicParameterRequest;
|
||||
|
||||
/**
|
||||
* The response body of getting Livox LiDAR's parameters.
|
||||
*/
|
||||
typedef struct {
|
||||
uint8_t ret_code;
|
||||
float roll; /**< Roll angle, unit: degree. */
|
||||
float pitch; /**< Pitch angle, unit: degree. */
|
||||
float yaw; /**< Yaw angle, unit: degree. */
|
||||
int32_t x; /**< X translation, unit: mm. */
|
||||
int32_t y; /**< Y translation, unit: mm. */
|
||||
int32_t z; /**< Z translation, unit: mm. */
|
||||
} LidarGetExtrinsicParameterResponse;
|
||||
|
||||
/**
|
||||
* The response body of getting the Livox LiDAR's fan state.
|
||||
*/
|
||||
typedef struct {
|
||||
uint8_t ret_code; /**< Return code. */
|
||||
uint8_t state; /**< Fan state: 1 for fan is on, 0 for fan is off. */
|
||||
} LidarGetFanStateResponse;
|
||||
|
||||
/**
|
||||
* The response body of getting the Livox LiDAR's point cloud return mode.
|
||||
*/
|
||||
typedef struct {
|
||||
uint8_t ret_code; /**< Return code. */
|
||||
uint8_t mode; /**< Point cloud return mode, refer to \ref PointCloudReturnMode. */
|
||||
} LidarGetPointCloudReturnModeResponse;
|
||||
|
||||
|
||||
/**
|
||||
* The response body of getting the Livox LiDAR's IMU push frequency.
|
||||
*/
|
||||
typedef struct {
|
||||
uint8_t ret_code; /**< Return code. */
|
||||
uint8_t freq; /**< IMU push frequency, refer to \ref ImuFreq. */
|
||||
} LidarGetImuPushFrequencyResponse;
|
||||
|
||||
/**
|
||||
* The response body of setting the Livox LiDAR's Sync time.
|
||||
*/
|
||||
typedef struct {
|
||||
uint8_t year;
|
||||
uint8_t month;
|
||||
uint8_t day;
|
||||
uint8_t hour;
|
||||
uint32_t microsecond;
|
||||
} LidarSetUtcSyncTimeRequest;
|
||||
|
||||
/**
|
||||
* The response body of querying the information of LiDAR units connected to the Livox Hub.
|
||||
*/
|
||||
typedef struct {
|
||||
uint8_t ret_code; /**< Return code. */
|
||||
uint8_t count; /**< Count of device_info_list. */
|
||||
ConnectedLidarInfo device_info_list[1]; /**< Connected lidars information list. */
|
||||
} HubQueryLidarInformationResponse;
|
||||
|
||||
/**
|
||||
* The request body of setting Livox Hub's working mode.
|
||||
*/
|
||||
typedef struct {
|
||||
uint8_t count; /**< Count of config_list. */
|
||||
LidarModeRequestItem config_list[1]; /**< LiDAR mode configuration list. */
|
||||
} HubSetModeRequest;
|
||||
|
||||
/**
|
||||
* The response of setting Livox Hub's working mode.
|
||||
*/
|
||||
typedef struct {
|
||||
uint8_t ret_code; /**< Return code. */
|
||||
uint8_t count; /**< Count of ret_state_list. */
|
||||
ReturnCode ret_state_list[1]; /**< Return status list. */
|
||||
} HubSetModeResponse;
|
||||
|
||||
/**
|
||||
* The request body of toggling the power supply of the slot.
|
||||
*/
|
||||
typedef struct {
|
||||
uint8_t slot; /**< Slot of the hub. */
|
||||
uint8_t state; /**< Status of toggling the power supply. */
|
||||
} HubControlSlotPowerRequest;
|
||||
|
||||
/**
|
||||
* The request body of setting the Livox Hub's parameters.
|
||||
*/
|
||||
typedef struct {
|
||||
uint8_t count; /**< Count of cfg_param_list. */
|
||||
ExtrinsicParameterRequestItem parameter_list[1]; /**< Extrinsic parameter configuration list. */
|
||||
} HubSetExtrinsicParameterRequest;
|
||||
|
||||
/**
|
||||
* The response body of setting the Livox Hub's parameters.
|
||||
*/
|
||||
typedef struct {
|
||||
uint8_t ret_code; /**< Return code. */
|
||||
uint8_t count; /**< Count of ret_code_list. */
|
||||
ReturnCode ret_code_list[1]; /**< Return code list. */
|
||||
} HubSetExtrinsicParameterResponse;
|
||||
|
||||
/**
|
||||
* The request body of getting the Livox Hub's parameters.
|
||||
*/
|
||||
typedef struct {
|
||||
uint8_t count; /**< Count of code_list. */
|
||||
DeviceBroadcastCode code_list[1]; /**< Broadcast code list. */
|
||||
} HubGetExtrinsicParameterRequest;
|
||||
|
||||
/**
|
||||
* The response body of getting the Livox Hub's parameters.
|
||||
*/
|
||||
typedef struct {
|
||||
uint8_t ret_code; /**< Return code. */
|
||||
uint8_t count; /**< Count of code_list. */
|
||||
ExtrinsicParameterResponseItem parameter_list[1]; /**< Extrinsic parameter list. */
|
||||
} HubGetExtrinsicParameterResponse;
|
||||
|
||||
/**
|
||||
* The response body of getting sub LiDAR's state conneted to Hub.
|
||||
*/
|
||||
typedef struct {
|
||||
uint8_t ret_code; /**< Return code. */
|
||||
uint8_t count; /**< Count of state_list. */
|
||||
LidarStateItem state_list[1]; /**< LiDAR units state list. */
|
||||
} HubQueryLidarStatusResponse;
|
||||
|
||||
/**
|
||||
* The request body of toggling the Livox Hub's rain and fog mode.
|
||||
*/
|
||||
typedef struct {
|
||||
uint8_t count; /**< Count of lidar_cfg_list. */
|
||||
RainFogSuppressRequestItem lidar_cfg_list[1]; /**< Rain fog suppress configuration list. */
|
||||
} HubRainFogSuppressRequest;
|
||||
|
||||
/**
|
||||
* The response body of toggling the Livox Hub's rain and fog mode.
|
||||
*/
|
||||
typedef struct {
|
||||
uint8_t ret_code; /**< Return code. */
|
||||
uint8_t count; /**< Count of ret_state_list. */
|
||||
ReturnCode ret_state_list[1]; /**< Return state list */
|
||||
} HubRainFogSuppressResponse;
|
||||
|
||||
/**
|
||||
* The response body of getting Hub slots' power state.
|
||||
*/
|
||||
typedef struct {
|
||||
uint8_t ret_code; /**< Return code. */
|
||||
uint16_t slot_power_state; /**< Slot power status. */
|
||||
} HubQuerySlotPowerStatusResponse;
|
||||
|
||||
/**
|
||||
* The request body of controlling the sub LiDAR's fan state conneted to Hub.
|
||||
*/
|
||||
typedef struct {
|
||||
uint8_t count; /**< Count of lidar_cfg_list. */
|
||||
FanControlRequestItem lidar_cfg_list[1]; /**< Fan control configuration list. */
|
||||
} HubFanControlRequest;
|
||||
|
||||
/**
|
||||
* The response body of controlling the sub LiDAR's fan state conneted to Hub.
|
||||
*/
|
||||
typedef struct {
|
||||
uint8_t ret_code; /**< Return code. */
|
||||
uint8_t count; /**< Count of return_list. */
|
||||
ReturnCode return_list[1]; /**< Return list */
|
||||
} HubFanControlResponse;
|
||||
|
||||
/**
|
||||
* The request body of getting the sub LiDAR's fan state conneted to Hub.
|
||||
*/
|
||||
typedef struct {
|
||||
uint8_t count; /**< Count of lidar_cfg_list. */
|
||||
GetFanStateRequestItem lidar_cfg_list[1]; /**< Get Fan state list. */
|
||||
} HubGetFanStateRequest;
|
||||
|
||||
/**
|
||||
* The response body of getting the sub LiDAR's fan state conneted to Hub.
|
||||
*/
|
||||
typedef struct {
|
||||
uint8_t ret_code; /**< Return code. */
|
||||
uint8_t count; /**< Count of return_list. */
|
||||
GetFanStateResponseItem return_list[1]; /**< Fan state list. */
|
||||
} HubGetFanStateResponse;
|
||||
|
||||
/**
|
||||
* The request body of setting point cloud return mode of sub LiDAR conneted to Hub.
|
||||
*/
|
||||
typedef struct {
|
||||
uint8_t count; /**< Count of lidar_cfg_list. */
|
||||
SetPointCloudReturnModeRequestItem lidar_cfg_list[1]; /**< Point cloud return mode configuration list. */
|
||||
} HubSetPointCloudReturnModeRequest;
|
||||
|
||||
/**
|
||||
* The response body of setting point cloud return mode of sub LiDAR conneted to Hub.
|
||||
*/
|
||||
typedef struct {
|
||||
uint8_t ret_code; /**< Return code. */
|
||||
uint8_t count; /**< Count of return_list. */
|
||||
ReturnCode return_list[1]; /**< Return list. */
|
||||
} HubSetPointCloudReturnModeResponse;
|
||||
|
||||
/**
|
||||
* The request body of getting sub LiDAR's point cloud return mode conneted to Hub.
|
||||
*/
|
||||
typedef struct {
|
||||
uint8_t count; /**< Count of lidar_cfg_list. */
|
||||
GetPointCloudReturnModeRequestItem lidar_cfg_list[1]; /**< Get point cloud return mode list. */
|
||||
} HubGetPointCloudReturnModeRequest;
|
||||
|
||||
/**
|
||||
* The response body of getting sub LiDAR's point cloud return mode conneted to Hub.
|
||||
*/
|
||||
typedef struct {
|
||||
uint8_t ret_code; /**< Return code. */
|
||||
uint8_t count; /**< Count of return_list. */
|
||||
GetPointCloudReturnModeResponseItem return_list[1]; /**< Point cloud return mode list. */
|
||||
} HubGetPointCloudReturnModeResponse;
|
||||
|
||||
/**
|
||||
* The request body of setting IMU push frequency of sub LiDAR conneted to Hub.
|
||||
*/
|
||||
typedef struct {
|
||||
uint8_t count; /**< Count of lidar_cfg_list. */
|
||||
SetImuPushFrequencyRequestItem lidar_cfg_list[1]; /**< IMU push frequency configuration list. */
|
||||
} HubSetImuPushFrequencyRequest;
|
||||
|
||||
/**
|
||||
* The response body of setting IMU push frequency of sub LiDAR conneted to Hub.
|
||||
*/
|
||||
typedef struct {
|
||||
uint8_t ret_code; /**< Return code. */
|
||||
uint8_t count; /**< Count of return_list. */
|
||||
ReturnCode return_list[1]; /**< Return list. */
|
||||
} HubSetImuPushFrequencyResponse;
|
||||
|
||||
/**
|
||||
* The request body of getting sub LiDAR's IMU push frequency conneted to Hub.
|
||||
*/
|
||||
typedef struct {
|
||||
uint8_t count; /**< Count of lidar_cfg_list. */
|
||||
GetImuPushFrequencyRequestItem lidar_cfg_list[1]; /**< Get IMU push frequency list. */
|
||||
} HubGetImuPushFrequencyRequest;
|
||||
|
||||
/**
|
||||
* The response body of getting sub LiDAR's IMU push frequency conneted to Hub.
|
||||
*/
|
||||
typedef struct {
|
||||
uint8_t ret_code; /**< Return code. */
|
||||
uint8_t count; /**< Count of return_list. */
|
||||
GetImuPushFrequencyResponseItem return_list[1]; /**< IMU push frequency list. */
|
||||
} HubGetImuPushFrequencyResponse;
|
||||
|
||||
#pragma pack()
|
||||
|
||||
#endif // LIVOX_DEF_H_
|
999
include/Livox/livox_sdk.h
Executable file
999
include/Livox/livox_sdk.h
Executable file
@ -0,0 +1,999 @@
|
||||
//
|
||||
// The MIT License (MIT)
|
||||
//
|
||||
// Copyright (c) 2019 Livox. All rights reserved.
|
||||
//
|
||||
// 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 LIVOX_SDK_H_
|
||||
#define LIVOX_SDK_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include "livox_def.h"
|
||||
|
||||
/**
|
||||
* Return SDK's version information in a numeric form.
|
||||
* @param version Pointer to a version structure for returning the version information.
|
||||
*/
|
||||
void GetLivoxSdkVersion(LivoxSdkVersion *version);
|
||||
|
||||
/**
|
||||
* Disable console log output.
|
||||
*/
|
||||
void DisableConsoleLogger();
|
||||
|
||||
/**
|
||||
* Initialize the SDK.
|
||||
* @return true if successfully initialized, otherwise false.
|
||||
*/
|
||||
bool Init();
|
||||
|
||||
/**
|
||||
* Start the device scanning routine which runs on a separate thread.
|
||||
* @return true if successfully started, otherwise false.
|
||||
*/
|
||||
bool Start();
|
||||
|
||||
/**
|
||||
* Uninitialize the SDK.
|
||||
*/
|
||||
void Uninit();
|
||||
|
||||
/**
|
||||
* Save the log file.
|
||||
*/
|
||||
void SaveLoggerFile();
|
||||
|
||||
/**
|
||||
* @c SetBroadcastCallback response callback function.
|
||||
* @param info information of the broadcast device, becomes invalid after the function returns.
|
||||
*/
|
||||
typedef void (*DeviceBroadcastCallback)(const BroadcastDeviceInfo *info);
|
||||
|
||||
/**
|
||||
* Set the callback of listening device broadcast message. When broadcast message is received from Livox Hub/LiDAR, cb
|
||||
* is called.
|
||||
* @param cb callback for device broadcast.
|
||||
*/
|
||||
void SetBroadcastCallback(DeviceBroadcastCallback cb);
|
||||
|
||||
/**
|
||||
* @c SetDeviceStateUpdateCallback response callback function.
|
||||
* @param device information of the connected device.
|
||||
* @param type the update type that indicates connection/disconnection of the device or change of working state.
|
||||
*/
|
||||
typedef void (*DeviceStateUpdateCallback)(const DeviceInfo *device, DeviceEvent type);
|
||||
|
||||
/**
|
||||
* @brief Add a callback for device connection or working state changing event.
|
||||
* @note Livox SDK supports two hardware connection modes. 1: Directly connecting to the LiDAR device; 2. Connecting to
|
||||
* the LiDAR device(s) via the Livox Hub. In the first mode, connection/disconnection of every LiDAR unit is reported by
|
||||
* this callback. In the second mode, only connection/disconnection of the Livox Hub is reported by this callback. If
|
||||
* you want to get information of the LiDAR unit(s) connected to hub, see \ref HubQueryLidarInformation.
|
||||
* @note 3 conditions can trigger this callback:
|
||||
* 1. Connection and disconnection of device.
|
||||
* 2. A change of device working state.
|
||||
* 3. An error occurs.
|
||||
* @param cb callback for device connection/disconnection.
|
||||
*/
|
||||
void SetDeviceStateUpdateCallback(DeviceStateUpdateCallback cb);
|
||||
|
||||
/**
|
||||
* Add a broadcast code to the connecting list and only devices with broadcast code in this list will be connected. The
|
||||
* broadcast code is unique for every device.
|
||||
* @param broadcast_code device's broadcast code.
|
||||
* @param handle device handle. For Livox Hub, the handle is always 31; for LiDAR units connected to the Livox Hub,
|
||||
* the corresponding handle is (slot-1)*3+id-1.
|
||||
* @return kStatusSuccess on successful return, see \ref LivoxStatus for other error code.
|
||||
*/
|
||||
livox_status AddHubToConnect(const char *broadcast_code, uint8_t *handle);
|
||||
|
||||
/**
|
||||
* Add a broadcast code to the connecting list and only devices with broadcast code in this list will be connected. The
|
||||
* broadcast code is unique for every device.
|
||||
* @param broadcast_code device's broadcast code.
|
||||
* @param handle device handle. The handle is the same as the order calling AddLidarToConnect starting from 0.
|
||||
* @return kStatusSuccess on successful return, see \ref LivoxStatus for other error code.
|
||||
*/
|
||||
livox_status AddLidarToConnect(const char *broadcast_code, uint8_t *handle);
|
||||
|
||||
/**
|
||||
* Get all connected devices' information.
|
||||
* @param devices list of connected devices' information.
|
||||
* @param size number of devices connected.
|
||||
* @return kStatusSuccess on successful return, see \ref LivoxStatus for other error code.
|
||||
*/
|
||||
livox_status GetConnectedDevices(DeviceInfo *devices, uint8_t *size);
|
||||
|
||||
/**
|
||||
* Function type of callback that queries device's information.
|
||||
* @param status kStatusSuccess on successful return, kStatusTimeout on timeout, see \ref LivoxStatus for other
|
||||
* error code.
|
||||
* @param handle device handle.
|
||||
* @param response response from the device.
|
||||
* @param client_data user data associated with the command.
|
||||
*/
|
||||
typedef void (*DeviceInformationCallback)(livox_status status,
|
||||
uint8_t handle,
|
||||
DeviceInformationResponse *response,
|
||||
void *client_data);
|
||||
|
||||
/**
|
||||
* Command to query device's information.
|
||||
* @param handle device handle.
|
||||
* @param cb callback for the command.
|
||||
* @param client_data user data associated with the command.
|
||||
* @return kStatusSuccess on successful return, see \ref LivoxStatus for other error code.
|
||||
*/
|
||||
livox_status QueryDeviceInformation(uint8_t handle, DeviceInformationCallback cb, void *client_data);
|
||||
|
||||
/**
|
||||
* Callback function for receiving point cloud data.
|
||||
* @param handle device handle.
|
||||
* @param data device's data.
|
||||
* @param data_num number of points in data.
|
||||
* @param client_data user data associated with the command.
|
||||
*/
|
||||
typedef void (*DataCallback)(uint8_t handle, LivoxEthPacket *data, uint32_t data_num, void *client_data);
|
||||
|
||||
/**
|
||||
* Set the callback to receive point cloud data. Only one callback is supported for a specific device. Set the point
|
||||
* cloud data callback before beginning sampling.
|
||||
* @param handle device handle.
|
||||
* @param cb callback to receive point cloud data.
|
||||
* @note 1: Don't do any blocking operations in callback function, it will affects further data's receiving;
|
||||
* 2: For different device handle, callback to receive point cloud data will run on its own thread. If you bind
|
||||
* different handle to same callback function, please make sure that operations in callback function are thread-safe;
|
||||
* 3: callback function's data pointer will be invalid after callback fuction returns. It's recommended to
|
||||
* copy all data_num of point cloud every time callback is triggered.
|
||||
* @param client_data user data associated with the command.
|
||||
*/
|
||||
void SetDataCallback(uint8_t handle, DataCallback cb, void *client_data);
|
||||
|
||||
/**
|
||||
* Function type of callback with 1 byte of response.
|
||||
* @param status kStatusSuccess on successful return, kStatusTimeout on timeout, see \ref LivoxStatus for other
|
||||
* error code.
|
||||
* @param handle device handle.
|
||||
* @param response response from the device.
|
||||
* @param client_data user data associated with the command.
|
||||
*/
|
||||
typedef void (*CommonCommandCallback)(livox_status status, uint8_t handle, uint8_t response, void *client_data);
|
||||
|
||||
/**
|
||||
* Start hub sampling.
|
||||
* @param cb callback for the command.
|
||||
* @param client_data user data associated with the command.
|
||||
* @return kStatusSuccess on successful return, see \ref LivoxStatus for other error code.
|
||||
*/
|
||||
livox_status HubStartSampling(CommonCommandCallback cb, void *client_data);
|
||||
|
||||
/**
|
||||
* Stop the Livox Hub's sampling.
|
||||
* @param cb callback for the command.
|
||||
* @param client_data user data associated with the command.
|
||||
* @return kStatusSuccess on successful return, see \ref LivoxStatus for other error code.
|
||||
*/
|
||||
livox_status HubStopSampling(CommonCommandCallback cb, void *client_data);
|
||||
|
||||
/**
|
||||
* Get the LiDAR unit handle used in the Livox Hub data callback function from slot and id.
|
||||
* @param slot Livox Hub's slot.
|
||||
* @param id Livox Hub's id.
|
||||
* @return LiDAR unit handle.
|
||||
*/
|
||||
uint8_t HubGetLidarHandle(uint8_t slot, uint8_t id);
|
||||
|
||||
/**
|
||||
* Disconnect divice.
|
||||
* @param handle device handle.
|
||||
* @param cb callback for the command.
|
||||
* @param client_data user data associated with the command.
|
||||
* @return kStatusSuccess on successful return, see \ref LivoxStatus for other error code.
|
||||
*/
|
||||
livox_status DisconnectDevice(uint8_t handle, CommonCommandCallback cb, void *client_data);
|
||||
|
||||
/**
|
||||
* Change point cloud coordinate system to cartesian coordinate.
|
||||
* @param handle device handle.
|
||||
* @param cb callback for the command.
|
||||
* @param client_data user data associated with the command.
|
||||
* @return kStatusSuccess on successful return, see \ref LivoxStatus for other error code.
|
||||
*/
|
||||
livox_status SetCartesianCoordinate(uint8_t handle, CommonCommandCallback cb, void *client_data);
|
||||
|
||||
/**
|
||||
* Change point cloud coordinate system to spherical coordinate.
|
||||
* @param handle device handle.
|
||||
* @param cb callback for the command.
|
||||
* @param client_data user data associated with the command.
|
||||
* @return kStatusSuccess on successful return, see \ref LivoxStatus for other error code.
|
||||
*/
|
||||
livox_status SetSphericalCoordinate(uint8_t handle, CommonCommandCallback cb, void *client_data);
|
||||
|
||||
/**
|
||||
* Callback of the error status message.
|
||||
* kStatusSuccess on successful return, see \ref LivoxStatus for other
|
||||
* @param handle device handle.
|
||||
* @param response response from the device.
|
||||
*/
|
||||
typedef void (*ErrorMessageCallback)(livox_status status, uint8_t handle, ErrorMessage *message);
|
||||
|
||||
/**
|
||||
* Add error status callback for the device.
|
||||
* error code.
|
||||
* @param handle device handle.
|
||||
* @param cb callback for the command.
|
||||
* @return kStatusSuccess on successful return, see \ref LivoxStatus for other error code.
|
||||
*/
|
||||
livox_status SetErrorMessageCallback(uint8_t handle, ErrorMessageCallback cb);
|
||||
|
||||
/**
|
||||
* Set device's IP mode.
|
||||
* @note \ref SetStaticDynamicIP only supports setting Hub or Mid40/100's IP mode.
|
||||
* If you want to set Horizon or Tele's IP mode, see \ref SetStaticIp and \ref SetDynamicIp.
|
||||
* @param handle device handle.
|
||||
* @param req request sent to device.
|
||||
* @param cb callback for the command.
|
||||
* @param client_data user data associated with the command.
|
||||
* @return kStatusSuccess on successful return, see \ref LivoxStatus for other error code.
|
||||
*/
|
||||
livox_status SetStaticDynamicIP(uint8_t handle,
|
||||
SetDeviceIPModeRequest *req,
|
||||
CommonCommandCallback cb,
|
||||
void *client_data);
|
||||
/**
|
||||
* Set device's static IP mode.
|
||||
* @note Mid40/100 is not supported to set subnet mask and gateway address.
|
||||
* \ref SetStaticDeviceIpModeRequest's setting: net_mask and gw_addr will not take effect on Mid40/100.
|
||||
* @param handle device handle.
|
||||
* @param req request sent to device.
|
||||
* @param cb callback for the command.
|
||||
* @param client_data user data associated with the command.
|
||||
* @return kStatusSuccess on successful return, see \ref LivoxStatus for other error code.
|
||||
*/
|
||||
livox_status SetStaticIp(uint8_t handle,
|
||||
SetStaticDeviceIpModeRequest *req,
|
||||
CommonCommandCallback cb,
|
||||
void *client_data);
|
||||
|
||||
/**
|
||||
* Set device's dynamic IP mode.
|
||||
* @param handle device handle.
|
||||
* @param cb callback for the command.
|
||||
* @param client_data user data associated with the command.
|
||||
* @return kStatusSuccess on successful return, see \ref LivoxStatus for other error code.
|
||||
*/
|
||||
livox_status SetDynamicIp(uint8_t handle,
|
||||
CommonCommandCallback cb,
|
||||
void *client_data);
|
||||
/**
|
||||
* Callback function that gets device's IP information.
|
||||
* @param status kStatusSuccess on successful return, kStatusTimeout on timeout, see \ref LivoxStatus for other
|
||||
* error code.
|
||||
* @param handle device handle.
|
||||
* @param response response from the device.
|
||||
* @param client_data user data associated with the command.
|
||||
*/
|
||||
typedef void (*GetDeviceIpInformationCallback)(livox_status status,
|
||||
uint8_t handle,
|
||||
GetDeviceIpModeResponse *response,
|
||||
void *client_data);
|
||||
|
||||
/**
|
||||
* Get device's IP mode.
|
||||
* @param handle device handle.
|
||||
* @param cb callback for the command.
|
||||
* @param client_data user data associated with the command.
|
||||
* @return kStatusSuccess on successful return, see \ref LivoxStatus for other error code.
|
||||
*/
|
||||
livox_status GetDeviceIpInformation(uint8_t handle, GetDeviceIpInformationCallback cb, void *client_data);
|
||||
|
||||
/**
|
||||
* Reboot device.
|
||||
* @note \ref RebootDevice is not supported for Mid40/100 firmware version < 03.07.0000.
|
||||
* @param handle device handle.
|
||||
* @param timeout reboot device after [timeout] ms.
|
||||
* @param cb callback for the command.
|
||||
* @param client_data user data associated with the command.
|
||||
* @return kStatusSuccess on successful return, see \ref LivoxStatus for other error code.
|
||||
*/
|
||||
livox_status RebootDevice(uint8_t handle, uint16_t timeout, CommonCommandCallback cb, void * client_data);
|
||||
|
||||
/**
|
||||
* @c SetDeviceParameters' response callback function.
|
||||
* @param status kStatusSuccess on successful return, kStatusTimeout on timeout, see \ref LivoxStatus for other
|
||||
* error code.
|
||||
* @param handle device handle.
|
||||
* @param response response from the device.
|
||||
* @param client_data user data associated with the command.
|
||||
*/
|
||||
typedef void (*SetDeviceParametersCallback)(livox_status status,
|
||||
uint8_t handle,
|
||||
DeviceParameterResponse *response,
|
||||
void *client_data);
|
||||
|
||||
/**
|
||||
* LiDAR Enable HighSensitivity.
|
||||
* @note \ref LidarEnableHighSensitivity only support for Tele/Avia.
|
||||
* @param handle device handle.
|
||||
* @param cb callback for the command.
|
||||
* @param client_data user data associated with the command.
|
||||
* @return kStatusSuccess on successful return, see \ref LivoxStatus for other error code.
|
||||
*/
|
||||
livox_status LidarEnableHighSensitivity(uint8_t handle, SetDeviceParametersCallback cb, void *client_data);
|
||||
|
||||
/**
|
||||
* LiDAR Disable HighSensitivity.
|
||||
* @note \ref LidarDisableHighSensitivity only support for Tele/Avia.
|
||||
* @param handle device handle.
|
||||
* @param cb callback for the command.
|
||||
* @param client_data user data associated with the command.
|
||||
* @return kStatusSuccess on successful return, see \ref LivoxStatus for other error code.
|
||||
*/
|
||||
livox_status LidarDisableHighSensitivity(uint8_t handle, SetDeviceParametersCallback cb, void *client_data);
|
||||
|
||||
/**
|
||||
* @c GetDeviceParameters' response callback function.
|
||||
* @param status kStatusSuccess on successful return, kStatusTimeout on timeout, see \ref LivoxStatus for other
|
||||
* error code.
|
||||
* @param handle device handle.
|
||||
* @param response response from the device.
|
||||
* @param client_data user data associated with the command.
|
||||
*/
|
||||
typedef void (*GetDeviceParametersCallback)(livox_status status,
|
||||
uint8_t handle,
|
||||
GetDeviceParameterResponse *response,
|
||||
void *client_data);
|
||||
|
||||
/**
|
||||
* LiDAR Get HighSensitivity State.
|
||||
* @note \ref LidarGetHighSensitivityState only support for Tele/Avia.
|
||||
* @param handle device handle.
|
||||
* @param cb callback for the command.
|
||||
* @param client_data user data associated with the command.
|
||||
* @return kStatusSuccess on successful return, see \ref LivoxStatus for other error code.
|
||||
*/
|
||||
livox_status LidarGetHighSensitivityState(uint8_t handle, GetDeviceParametersCallback cb, void *client_data);
|
||||
|
||||
/**
|
||||
* LiDAR Set Scan Pattern.
|
||||
* @note \ref LidarSetScanPattern only support for Avia.
|
||||
* @param handle device handle.
|
||||
* @param pattern scan pattern of LiDAR, see \ref LidarScanPattern for detail.
|
||||
* @param cb callback for the command.
|
||||
* @param client_data user data associated with the command.
|
||||
* @return kStatusSuccess on successful return, see \ref LivoxStatus for other error code.
|
||||
*/
|
||||
livox_status LidarSetScanPattern(uint8_t handle, LidarScanPattern pattern, SetDeviceParametersCallback cb, void *client_data);
|
||||
|
||||
/**
|
||||
* LiDAR Get Scan Pattern.
|
||||
* @note \ref LidarGetScanPattern only support for Avia.
|
||||
* @param handle device handle.
|
||||
* @param cb callback for the command.
|
||||
* @param client_data user data associated with the command.
|
||||
* @return kStatusSuccess on successful return, see \ref LivoxStatus for other error code.
|
||||
*/
|
||||
livox_status LidarGetScanPattern(uint8_t handle, GetDeviceParametersCallback cb, void *client_data);
|
||||
|
||||
/**
|
||||
* LiDAR Set Slot Number.
|
||||
* @note \ref LidarSetSlotNum only support for Mid70/Avia.
|
||||
* @param handle device handle.
|
||||
* @param slot slot number of LiDAR, range from 1 to 9.
|
||||
* @param cb callback for the command.
|
||||
* @param client_data user data associated with the command.
|
||||
* @return kStatusSuccess on successful return, see \ref LivoxStatus for other error code.
|
||||
*/
|
||||
livox_status LidarSetSlotNum(uint8_t handle, uint8_t slot, SetDeviceParametersCallback cb, void *client_data);
|
||||
|
||||
/**
|
||||
* LiDAR Get Slot Number.
|
||||
* @note \ref LidarGetSlotNum only support for Mid70/Avia.
|
||||
* @param handle device handle.
|
||||
* @param cb callback for the command.
|
||||
* @param client_data user data associated with the command.
|
||||
* @return kStatusSuccess on successful return, see \ref LivoxStatus for other error code.
|
||||
*/
|
||||
livox_status LidarGetSlotNum(uint8_t handle, GetDeviceParametersCallback cb, void *client_data);
|
||||
|
||||
/**
|
||||
* @c DeviceResetParameters' response callback function.
|
||||
* @param status kStatusSuccess on successful return, kStatusTimeout on timeout, see \ref LivoxStatus for other
|
||||
* error code.
|
||||
* @param handle device handle.
|
||||
* @param response response from the device.
|
||||
* @param client_data user data associated with the command.
|
||||
*/
|
||||
typedef void (*DeviceResetParametersCallback)(livox_status status,
|
||||
uint8_t handle,
|
||||
DeviceParameterResponse *response,
|
||||
void *client_data);
|
||||
|
||||
/**
|
||||
* Reset LiDAR/Hub's All Parameters, see \ref DeviceParamKeyName for all parameters.
|
||||
* @param handle device handle.
|
||||
* @param cb callback for the command.
|
||||
* @param client_data user data associated with the command.
|
||||
* @return kStatusSuccess on successful return, see \ref LivoxStatus for other error code.
|
||||
*/
|
||||
livox_status DeviceResetAllParameters(uint8_t handle, DeviceResetParametersCallback cb, void *client_data);
|
||||
|
||||
/**
|
||||
* Reset LiDAR/Hub's Parameters, see \ref DeviceParamKeyName for all parameters.
|
||||
* @param handle device handle.
|
||||
* @param keys keys to reset, see \ref DeviceParamKeyName for all parameters.
|
||||
* @param num num of keys to reset.
|
||||
* @param cb callback for the command.
|
||||
* @param client_data user data associated with the command.
|
||||
* @return kStatusSuccess on successful return, see \ref LivoxStatus for other error code.
|
||||
*/
|
||||
livox_status DeviceResetParameters(uint8_t handle, DeviceParamKeyName * keys, uint8_t num, DeviceResetParametersCallback cb, void *client_data);
|
||||
|
||||
|
||||
/**
|
||||
* @c HubQueryLidarInformation response callback function.
|
||||
* @param status kStatusSuccess on successful return, kStatusTimeout on timeout, see \ref LivoxStatus for other
|
||||
* error code.
|
||||
* @param handle device handle.
|
||||
* @param response response from the device.
|
||||
* @param client_data user data associated with the command.
|
||||
*/
|
||||
typedef void (*HubQueryLidarInformationCallback)(livox_status status,
|
||||
uint8_t handle,
|
||||
HubQueryLidarInformationResponse *response,
|
||||
void *client_data);
|
||||
|
||||
/**
|
||||
* Query the information of LiDARs connected to the hub.
|
||||
* @param cb callback for the command.
|
||||
* @param client_data user data associated with the command.
|
||||
* @return kStatusSuccess on successful return, see \ref LivoxStatus for other error code.
|
||||
*/
|
||||
livox_status HubQueryLidarInformation(HubQueryLidarInformationCallback cb, void *client_data);
|
||||
|
||||
/**
|
||||
* @c HubSetMode response callback function.
|
||||
* @param status kStatusSuccess on successful return, kStatusTimeout on timeout, see \ref LivoxStatus for other
|
||||
* error code.
|
||||
* @param handle device handle.
|
||||
* @param response response from the device.
|
||||
* @param client_data user data associated with the command.
|
||||
*/
|
||||
typedef void (*HubSetModeCallback)(livox_status status, uint8_t handle, HubSetModeResponse *response, void *client_data);
|
||||
|
||||
/**
|
||||
* Set the mode of LiDAR unit connected to the Livox Hub.
|
||||
* @param req mode configuration of LiDAR units.
|
||||
* @param length length of req.
|
||||
* @param cb callback for the command.
|
||||
* @param client_data user data associated with the command.
|
||||
* @return kStatusSuccess on successful return, see \ref LivoxStatus for other error code.
|
||||
*/
|
||||
livox_status HubSetMode(HubSetModeRequest *req, uint16_t length, HubSetModeCallback cb, void *client_data);
|
||||
|
||||
/**
|
||||
* @c HubQueryLidarStatus response callback function.
|
||||
* @param status kStatusSuccess on successful return, kStatusTimeout on timeout, see \ref LivoxStatus for other
|
||||
* error code.
|
||||
* @param handle device handle.
|
||||
* @param response response from the device.
|
||||
* @param client_data user data associated with the command.
|
||||
*/
|
||||
typedef void (*HubQueryLidarStatusCallback)(livox_status status, uint8_t handle, HubQueryLidarStatusResponse *response, void *client_data);
|
||||
|
||||
/**
|
||||
* Get the state of LiDAR units connected to the Livox Hub.
|
||||
* @param cb callback for the command.
|
||||
* @param client_data user data associated with the command.
|
||||
* @return kStatusSuccess on successful return, see \ref LivoxStatus for other error code.
|
||||
*/
|
||||
livox_status HubQueryLidarStatus(HubQueryLidarStatusCallback cb, void *client_data);
|
||||
|
||||
/**
|
||||
* Toggle the power supply of designated slots.
|
||||
* @param req request whether to enable or disable the power of designated slots.
|
||||
* @param cb callback for the command.
|
||||
* @param client_data user data associated with the command.
|
||||
* @return kStatusSuccess on successful return, see \ref LivoxStatus for other error code.
|
||||
*/
|
||||
livox_status HubControlSlotPower(HubControlSlotPowerRequest *req, CommonCommandCallback cb, void *client_data);
|
||||
|
||||
/**
|
||||
* @c HubSetExtrinsicParameter response callback function.
|
||||
* @param status kStatusSuccess on successful return, kStatusTimeout on timeout, see \ref LivoxStatus for other
|
||||
* error code.
|
||||
* @param handle device handle.
|
||||
* @param response response from the device.
|
||||
* @param client_data user data associated with the command.
|
||||
*/
|
||||
typedef void (*HubSetExtrinsicParameterCallback)(livox_status status,
|
||||
uint8_t handle,
|
||||
HubSetExtrinsicParameterResponse *response,
|
||||
void *client_data);
|
||||
|
||||
/**
|
||||
* Set extrinsic parameters of LiDAR units connected to the Livox Hub.
|
||||
* @param req the parameters to write.
|
||||
* @param length the request's length.
|
||||
* @param cb callback for the command.
|
||||
* @param client_data user data associated with the command.
|
||||
* @return kStatusSuccess on successful return, see \ref LivoxStatus for other error code.
|
||||
*/
|
||||
livox_status HubSetExtrinsicParameter(HubSetExtrinsicParameterRequest *req,
|
||||
uint16_t length,
|
||||
HubSetExtrinsicParameterCallback cb,
|
||||
void *client_data);
|
||||
|
||||
/**
|
||||
* @c HubGetExtrinsicParameter response callback function.
|
||||
* @param status kStatusSuccess on successful return, kStatusTimeout on timeout, see \ref LivoxStatus for other
|
||||
* error code.
|
||||
* @param handle device handle.
|
||||
* @param response response from the device.
|
||||
* @param client_data user data associated with the command.
|
||||
*/
|
||||
typedef void (*HubGetExtrinsicParameterCallback)(livox_status status,
|
||||
uint8_t handle,
|
||||
HubGetExtrinsicParameterResponse *response,
|
||||
void *client_data);
|
||||
|
||||
/**
|
||||
* Get extrinsic parameters of LiDAR units connected to the Livox Hub.
|
||||
* @param cb callback for the command.
|
||||
* @param client_data user data associated with the command.
|
||||
* @return kStatusSuccess on successful return, see \ref LivoxStatus for other error code.
|
||||
*/
|
||||
livox_status HubGetExtrinsicParameter(HubGetExtrinsicParameterCallback cb, void *client_data);
|
||||
|
||||
/**
|
||||
* Turn on or off the calculation of extrinsic parameters.
|
||||
* @param enable the request whether enable or disable calculating the extrinsic parameters.
|
||||
* @param cb callback for the command.
|
||||
* @param client_data user data associated with the command.
|
||||
* @return kStatusSuccess on successful return, see \ref LivoxStatus for other error code.
|
||||
*/
|
||||
livox_status HubExtrinsicParameterCalculation(bool enable, CommonCommandCallback cb, void *client_data);
|
||||
|
||||
/**
|
||||
* @c HubRainFogSuppress response callback function.
|
||||
* @param status kStatusSuccess on successful return, kStatusTimeout on timeout, see \ref LivoxStatus for other
|
||||
* error code.
|
||||
* @param handle device handle.
|
||||
* @param response response from the device.
|
||||
* @param client_data user data associated with the command.
|
||||
*/
|
||||
typedef void (*HubRainFogSuppressCallback)(livox_status status,
|
||||
uint8_t handle,
|
||||
HubRainFogSuppressResponse *response,
|
||||
void *client_data);
|
||||
|
||||
/**
|
||||
* Toggling the rain and fog mode for lidars connected to the hub.
|
||||
* @param req the request whether open or close the rain and fog mode.
|
||||
* @param length the request's length.
|
||||
* @param cb callback for the command.
|
||||
* @param client_data user data associated with the command.
|
||||
* @return kStatusSuccess on successful return, see \ref LivoxStatus for other error code.
|
||||
*/
|
||||
livox_status HubRainFogSuppress(HubRainFogSuppressRequest *req,
|
||||
uint16_t length,
|
||||
HubRainFogSuppressCallback cb,
|
||||
void *client_data);
|
||||
|
||||
/**
|
||||
* @c HubQuerySlotPowerStatus response callback function.
|
||||
* @param status kStatusSuccess on successful return, kStatusTimeout on timeout, see \ref LivoxStatus for other
|
||||
* error code.
|
||||
* @param handle device handle.
|
||||
* @param response response from the device.
|
||||
* @param client_data user data associated with the command.
|
||||
*/
|
||||
typedef void(*HubQuerySlotPowerStatusCallback)(livox_status status, uint8_t handle, HubQuerySlotPowerStatusResponse *response, void *client_data);
|
||||
|
||||
/**
|
||||
* Get the power supply state of each hub slot.
|
||||
* @param cb callback for the command.
|
||||
* @param client_data user data associated with the command.
|
||||
* @return kStatusSuccess on successful return, see \ref LivoxStatus for other error code.
|
||||
*/
|
||||
livox_status HubQuerySlotPowerStatus(HubQuerySlotPowerStatusCallback cb, void *client_data);
|
||||
|
||||
/**
|
||||
* @c HubFanControl response callback function.
|
||||
* @param status kStatusSuccess on successful return, kStatusTimeout on timeout, see \ref LivoxStatus for other
|
||||
* error code.
|
||||
* @param handle device handle.
|
||||
* @param response response from the device.
|
||||
* @param client_data user data associated with the command.
|
||||
*/
|
||||
typedef void (*HubFanControlCallback)(livox_status status,
|
||||
uint8_t handle,
|
||||
HubFanControlResponse *response,
|
||||
void *client_data);
|
||||
|
||||
/**
|
||||
* Turn on or off the fan of LiDAR unit connected to the Livox Hub.
|
||||
* @param req Fan control of LiDAR units.
|
||||
* @param length length of req.
|
||||
* @param cb callback for the command.
|
||||
* @param client_data user data associated with the command.
|
||||
* @return kStatusSuccess on successful return, see \ref LivoxStatus for other error code.
|
||||
*/
|
||||
livox_status HubFanControl(HubFanControlRequest *req, uint16_t length, HubFanControlCallback cb, void *client_data);
|
||||
|
||||
/**
|
||||
* @c HubGetFanControl response callback function.
|
||||
* @param status kStatusSuccess on successful return, kStatusTimeout on timeout, see \ref LivoxStatus for other
|
||||
* error code.
|
||||
* @param handle device handle.
|
||||
* @param response response from the device.
|
||||
* @param client_data user data associated with the command.
|
||||
*/
|
||||
typedef void (*HubGetFanStateCallback)(livox_status status,
|
||||
uint8_t handle,
|
||||
HubGetFanStateResponse *response,
|
||||
void *client_data);
|
||||
|
||||
/**
|
||||
* Get fan state of LiDAR unit connected to the Livox Hub.
|
||||
* @param req Get fan state of LiDAR units.
|
||||
* @param length length of req.
|
||||
* @param cb callback for the command.
|
||||
* @param client_data user data associated with the command.
|
||||
* @return kStatusSuccess on successful return, see \ref LivoxStatus for other error code.
|
||||
*/
|
||||
livox_status HubGetFanState(HubGetFanStateRequest *req,
|
||||
uint16_t length,
|
||||
HubGetFanStateCallback cb,
|
||||
void *client_data);
|
||||
|
||||
/**
|
||||
* @c HubSetPointCloudReturnMode response callback function.
|
||||
* @param status kStatusSuccess on successful return, kStatusTimeout on timeout, see \ref LivoxStatus for other
|
||||
* error code.
|
||||
* @param handle device handle.
|
||||
* @param response response from the device.
|
||||
* @param client_data user data associated with the command.
|
||||
*/
|
||||
typedef void (*HubSetPointCloudReturnModeCallback)(livox_status status,
|
||||
uint8_t handle,
|
||||
HubSetPointCloudReturnModeResponse *response,
|
||||
void *client_data);
|
||||
|
||||
/**
|
||||
* Set point cloud return mode of LiDAR units connected to the Livox Hub.
|
||||
* @param req set point cloud return mode of LiDAR units.
|
||||
* @param length the request's length.
|
||||
* @param cb callback for the command.
|
||||
* @param client_data user data associated with the command.
|
||||
* @return kStatusSuccess on successful return, see \ref LivoxStatus for other error code.
|
||||
*/
|
||||
livox_status HubSetPointCloudReturnMode(HubSetPointCloudReturnModeRequest *req,
|
||||
uint16_t length,
|
||||
HubSetPointCloudReturnModeCallback cb,
|
||||
void *client_data);
|
||||
|
||||
/**
|
||||
* @c HubGetPointCloudReturnMode response callback function.
|
||||
* @param status kStatusSuccess on successful return, kStatusTimeout on timeout, see \ref LivoxStatus for other
|
||||
* error code.
|
||||
* @param handle device handle.
|
||||
* @param response response from the device.
|
||||
* @param client_data user data associated with the command.
|
||||
*/
|
||||
typedef void (*HubGetPointCloudReturnModeCallback)(livox_status status,
|
||||
uint8_t handle,
|
||||
HubGetPointCloudReturnModeResponse *response,
|
||||
void *client_data);
|
||||
|
||||
/**
|
||||
* Get point cloud return mode of LiDAR unit connected to the Livox Hub.
|
||||
* @param req Get point cloud return mode of LiDAR units.
|
||||
* @param length length of req.
|
||||
* @param cb callback for the command.
|
||||
* @param client_data user data associated with the command.
|
||||
* @return kStatusSuccess on successful return, see \ref LivoxStatus for other error code.
|
||||
*/
|
||||
livox_status HubGetPointCloudReturnMode(HubGetPointCloudReturnModeRequest *req,
|
||||
uint16_t length,
|
||||
HubGetPointCloudReturnModeCallback cb,
|
||||
void *client_data);
|
||||
|
||||
/**
|
||||
* @c HubSetImuPushFrequency response callback function.
|
||||
* @param status kStatusSuccess on successful return, kStatusTimeout on timeout, see \ref LivoxStatus for other
|
||||
* error code.
|
||||
* @param handle device handle.
|
||||
* @param response response from the device.
|
||||
* @param client_data user data associated with the command.
|
||||
*/
|
||||
typedef void (*HubSetImuPushFrequencyCallback)(livox_status status,
|
||||
uint8_t handle,
|
||||
HubSetImuPushFrequencyResponse *response,
|
||||
void *client_data);
|
||||
|
||||
/**
|
||||
* Set IMU push frequency of LiDAR units connected to the Livox Hub.
|
||||
* @param req set IMU push frequency of LiDAR units.
|
||||
* @param length the request's length.
|
||||
* @param cb callback for the command.
|
||||
* @param client_data user data associated with the command.
|
||||
* @return kStatusSuccess on successful return, see \ref LivoxStatus for other error code.
|
||||
*/
|
||||
livox_status HubSetImuPushFrequency(HubSetImuPushFrequencyRequest *req,
|
||||
uint16_t length,
|
||||
HubSetImuPushFrequencyCallback cb,
|
||||
void *client_data);
|
||||
|
||||
/**
|
||||
* @c HubGetImuPushFrequency response callback function.
|
||||
* @param status kStatusSuccess on successful return, kStatusTimeout on timeout, see \ref LivoxStatus for other
|
||||
* error code.
|
||||
* @param handle device handle.
|
||||
* @param response response from the device.
|
||||
* @param client_data user data associated with the command.
|
||||
*/
|
||||
typedef void (*HubGetImuPushFrequencyCallback)(livox_status status,
|
||||
uint8_t handle,
|
||||
HubGetImuPushFrequencyResponse *response,
|
||||
void *client_data);
|
||||
|
||||
/**
|
||||
* Get IMU push frequency of LiDAR units connected to the Livox Hub.
|
||||
* @param req get IMU push frequency of LiDAR units.
|
||||
* @param length the request's length.
|
||||
* @param cb callback for the command.
|
||||
* @param client_data user data associated with the command.
|
||||
* @return kStatusSuccess on successful return, see \ref LivoxStatus for other error code.
|
||||
*/
|
||||
livox_status HubGetImuPushFrequency(HubGetImuPushFrequencyRequest *req,
|
||||
uint16_t length,
|
||||
HubGetImuPushFrequencyCallback cb,
|
||||
void *client_data);
|
||||
|
||||
/**
|
||||
* Start LiDAR sampling.
|
||||
* @param handle device handle.
|
||||
* @param cb callback for the command.
|
||||
* @param client_data user data associated with the command.
|
||||
* @return kStatusSuccess on successful return, see \ref LivoxStatus for other error code.
|
||||
*/
|
||||
livox_status LidarStartSampling(uint8_t handle, CommonCommandCallback cb, void *client_data);
|
||||
|
||||
/**
|
||||
* Stop LiDAR sampling.
|
||||
* @param handle device handle.
|
||||
* @param cb callback for the command.
|
||||
* @param client_data user data associated with the command.
|
||||
* @return kStatusSuccess on successful return, see \ref LivoxStatus for other error code.
|
||||
*/
|
||||
livox_status LidarStopSampling(uint8_t handle, CommonCommandCallback cb, void *client_data);
|
||||
|
||||
/**
|
||||
* Set LiDAR mode.
|
||||
* @note Successful callback function status only means LiDAR successfully starting the changing process of mode.
|
||||
* You need to observe the actually change of mode in DeviceStateUpdateCallback function.
|
||||
* @param handle device handle.
|
||||
* @param mode the mode to change.
|
||||
* @param cb callback for the command.
|
||||
* @param client_data user data associated with the command.
|
||||
* @return kStatusSuccess on successful return, see \ref LivoxStatus for other error code.
|
||||
*/
|
||||
livox_status LidarSetMode(uint8_t handle, LidarMode mode, CommonCommandCallback cb, void *client_data);
|
||||
|
||||
/**
|
||||
* Set LiDAR extrinsic parameters.
|
||||
* @param handle device handle.
|
||||
* @param req the parameters to write.
|
||||
* @param cb callback for the command.
|
||||
* @param client_data user data associated with the command.
|
||||
* @return kStatusSuccess on successful return, see \ref LivoxStatus for other error code.
|
||||
*/
|
||||
livox_status LidarSetExtrinsicParameter(uint8_t handle,
|
||||
LidarSetExtrinsicParameterRequest *req,
|
||||
CommonCommandCallback cb,
|
||||
void *client_data);
|
||||
|
||||
/**
|
||||
* @c LidarGetExtrinsicParameter response callback function.
|
||||
* @param status kStatusSuccess on successful return, kStatusTimeout on timeout, see \ref LivoxStatus for other
|
||||
* error code.
|
||||
* @param handle device handle.
|
||||
* @param response response from the device.
|
||||
* @param client_data user data associated with the command.
|
||||
*/
|
||||
typedef void (*LidarGetExtrinsicParameterCallback)(livox_status status,
|
||||
uint8_t handle,
|
||||
LidarGetExtrinsicParameterResponse *response,
|
||||
void *client_data);
|
||||
|
||||
/**
|
||||
* Get LiDAR extrinsic parameters.
|
||||
* @param handle device handle.
|
||||
* @param cb callback for the command.
|
||||
* @param client_data user data associated with the command.
|
||||
* @return kStatusSuccess on successful return, see \ref LivoxStatus for other error code.
|
||||
*/
|
||||
livox_status LidarGetExtrinsicParameter(uint8_t handle, LidarGetExtrinsicParameterCallback cb, void *client_data);
|
||||
|
||||
/**
|
||||
* Enable and disable the rain/fog suppression.
|
||||
* @note \ref LidarRainFogSuppress only support for Mid40/100.
|
||||
* @param handle device handle.
|
||||
* @param enable enable and disable the rain/fog suppression.
|
||||
* @param cb callback for the command.
|
||||
* @param client_data user data associated with the command.
|
||||
* @return kStatusSuccess on successful return, see \ref LivoxStatus for other error code.
|
||||
*/
|
||||
livox_status LidarRainFogSuppress(uint8_t handle, bool enable, CommonCommandCallback cb, void *client_data);
|
||||
|
||||
/**
|
||||
* Turn off the fan.
|
||||
* @note \ref LidarTurnOffFan is not supported for Mid40/100.
|
||||
* @param handle device handle.
|
||||
* @param cb callback for the command.
|
||||
* @param client_data user data associated with the command.
|
||||
* @return kStatusSuccess on successful return, see \ref LivoxStatus for other error code.
|
||||
*/
|
||||
livox_status LidarTurnOffFan(uint8_t handle, CommonCommandCallback cb, void *client_data);
|
||||
|
||||
/**
|
||||
* Turn on the fan.
|
||||
* @note \ref LidarTurnOnFan is not supported for Mid40/100.
|
||||
* @param handle device handle.
|
||||
* @param cb callback for the command.
|
||||
* @param client_data user data associated with the command.
|
||||
* @return kStatusSuccess on successful return, see \ref LivoxStatus for other error code.
|
||||
*/
|
||||
livox_status LidarTurnOnFan(uint8_t handle, CommonCommandCallback cb, void *client_data);
|
||||
|
||||
/**
|
||||
* @c LidarGetFanState response callback function.
|
||||
* @param status kStatusSuccess on successful return, kStatusTimeout on timeout, see \ref LivoxStatus for other
|
||||
* error code.
|
||||
* @param handle device handle.
|
||||
* @param response response from the device.
|
||||
* @param client_data user data associated with the command.
|
||||
*/
|
||||
typedef void (*LidarGetFanStateCallback)(livox_status status,
|
||||
uint8_t handle,
|
||||
LidarGetFanStateResponse *response,
|
||||
void *client_data);
|
||||
|
||||
/**
|
||||
* Get state of the fan.
|
||||
* @note \ref LidarGetFanState is not supported for Mid40/100.
|
||||
* @param handle device handle.
|
||||
* @param cb callback for the command.
|
||||
* @param client_data user data associated with the command.
|
||||
* @return kStatusSuccess on successful return, see \ref LivoxStatus for other error code.
|
||||
*/
|
||||
livox_status LidarGetFanState(uint8_t handle, LidarGetFanStateCallback cb, void * client_data) ;
|
||||
|
||||
/**
|
||||
* Set point cloud return mode.
|
||||
* @note \ref LidarSetPointCloudReturnMode is not supported for Mid40/100.
|
||||
* @param handle device handle.
|
||||
* @param mode point cloud return mode.
|
||||
* @param cb callback for the command.
|
||||
* @param client_data user data associated with the command.
|
||||
* @return kStatusSuccess on successful return, see \ref LivoxStatus for other error code.
|
||||
*/
|
||||
livox_status LidarSetPointCloudReturnMode(uint8_t handle, PointCloudReturnMode mode, CommonCommandCallback cb, void * client_data);
|
||||
|
||||
/**
|
||||
* @c LidaGetPointCloudReturnMode response callback function.
|
||||
* @param status kStatusSuccess on successful return, kStatusTimeout on timeout, see \ref LivoxStatus for other
|
||||
* error code.
|
||||
* @param handle device handle.
|
||||
* @param response response from the device.
|
||||
* @param client_data user data associated with the command.
|
||||
*/
|
||||
typedef void (*LidarGetPointCloudReturnModeCallback)(livox_status status,
|
||||
uint8_t handle,
|
||||
LidarGetPointCloudReturnModeResponse *response,
|
||||
void *client_data);
|
||||
|
||||
/**
|
||||
* Get point cloud return mode.
|
||||
* @note \ref LidarGetPointCloudReturnMode is not supported for Mid40/100.
|
||||
* @param handle device handle.
|
||||
* @param cb callback for the command.
|
||||
* @param client_data user data associated with the command.
|
||||
* @return kStatusSuccess on successful return, see \ref LivoxStatus for other error code.
|
||||
*/
|
||||
livox_status LidarGetPointCloudReturnMode(uint8_t handle, LidarGetPointCloudReturnModeCallback cb, void * client_data);
|
||||
|
||||
/**
|
||||
* Set IMU push frequency.
|
||||
* @note \ref LidarSetImuPushFrequency is not supported for Mid40/100.
|
||||
* @param handle device handle.
|
||||
* @param freq IMU push frequency.
|
||||
* @param cb callback for the command.
|
||||
* @param client_data user data associated with the command.
|
||||
* @return kStatusSuccess on successful return, see \ref LivoxStatus for other error code.
|
||||
*/
|
||||
livox_status LidarSetImuPushFrequency(uint8_t handle, ImuFreq freq, CommonCommandCallback cb, void * client_data);
|
||||
|
||||
/**
|
||||
* @c LidaGetImuPushFrequency response callback function.
|
||||
* @param status kStatusSuccess on successful return, kStatusTimeout on timeout, see \ref LivoxStatus for other
|
||||
* error code.
|
||||
* @param handle device handle.
|
||||
* @param response response from the device.
|
||||
* @param client_data user data associated with the command.
|
||||
*/
|
||||
typedef void (*LidarGetImuPushFrequencyCallback)(livox_status status,
|
||||
uint8_t handle,
|
||||
LidarGetImuPushFrequencyResponse *response,
|
||||
void *client_data);
|
||||
|
||||
/**
|
||||
* Get IMU push frequency.
|
||||
* @note \ref LidarGetImuPushFrequency is not supported for Mid40/100.
|
||||
* @param handle device handle.
|
||||
* @param cb callback for the command.
|
||||
* @param client_data user data associated with the command.
|
||||
* @return kStatusSuccess on successful return, see \ref LivoxStatus for other error code.
|
||||
*/
|
||||
livox_status LidarGetImuPushFrequency(uint8_t handle, LidarGetImuPushFrequencyCallback cb, void * client_data);
|
||||
|
||||
/**
|
||||
* Set GPRMC formate synchronization time.
|
||||
* @note \ref LidarSetRmcSyncTime is not supported for Mid40/100 firmware version < 03.07.0000.
|
||||
* @param handle device handle.
|
||||
* @param rmc GPRMC/GNRMC format data.
|
||||
* @param rmc_length lenth of gprmc.
|
||||
* @param cb callback for the command.
|
||||
* @param client_data user data associated with the command.
|
||||
* @return kStatusSuccess on successful return, see \ref LivoxStatus for other error code.
|
||||
*/
|
||||
livox_status LidarSetRmcSyncTime(uint8_t handle,
|
||||
const char* rmc,
|
||||
uint16_t rmc_length,
|
||||
CommonCommandCallback cb,
|
||||
void *client_data);
|
||||
|
||||
/**
|
||||
* Set UTC formate synchronization time.
|
||||
* @note \ref LidarSetUtcSyncTime is not supported for Mid40/100 firmware version < 03.07.0000.
|
||||
* @param handle device handle.
|
||||
* @param req UTC format data.
|
||||
* @param cb callback for the command.
|
||||
* @param client_data user data associated with the command.
|
||||
* @return kStatusSuccess on successful return, see \ref LivoxStatus for other error code.
|
||||
*/
|
||||
livox_status LidarSetUtcSyncTime(uint8_t handle,
|
||||
LidarSetUtcSyncTimeRequest* req,
|
||||
CommonCommandCallback cb,
|
||||
void *client_data);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // LIVOX_SDK_H_
|
79
include/Livox/third_party/FastCRC/FastCRC.h
vendored
Executable file
79
include/Livox/third_party/FastCRC/FastCRC.h
vendored
Executable file
@ -0,0 +1,79 @@
|
||||
/* FastCRC library code is placed under the MIT license
|
||||
* Copyright (c) 2014,2015 Frank Bosing
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
|
||||
// Teensy 3.0, Teensy 3.1:
|
||||
// See K20P64M72SF1RM.pdf (Kinetis), Pages 638 - 641 for documentation of CRC Device
|
||||
// See KINETIS_4N30D.pdf for Errata (Errata ID 2776)
|
||||
//
|
||||
// So, ALL HW-calculations are done as 32 bit.
|
||||
//
|
||||
//
|
||||
//
|
||||
// Thanks to:
|
||||
// - Catalogue of parametrised CRC algorithms, CRC RevEng
|
||||
// http://reveng.sourceforge.net/crc-catalogue/
|
||||
//
|
||||
// - Danjel McGougan (CRC-Table-Generator)
|
||||
//
|
||||
|
||||
//
|
||||
// modify from FastCRC library @ 2018/11/20
|
||||
//
|
||||
|
||||
#ifndef FASTCRC_FASTCRC_H_
|
||||
#define FASTCRC_FASTCRC_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
|
||||
// ================= 16-BIT CRC ===================
|
||||
|
||||
class FastCRC16 {
|
||||
public:
|
||||
FastCRC16(uint16_t seed);
|
||||
|
||||
// change function name from mcrf4xx_upd to mcrf4xx
|
||||
uint16_t mcrf4xx_calc(const uint8_t *data,const uint16_t datalen); // Equivalent to _crc_ccitt_update() in crc16.h from avr_libc
|
||||
|
||||
private:
|
||||
uint16_t seed_;
|
||||
|
||||
};
|
||||
|
||||
// ================= 32-BIT CRC ===================
|
||||
|
||||
class FastCRC32 {
|
||||
public:
|
||||
FastCRC32(uint32_t seed);
|
||||
|
||||
// change function name from crc32_upd to crc32
|
||||
uint32_t crc32_calc(const uint8_t *data, uint16_t len); // Call for subsequent calculations with previous seed
|
||||
|
||||
private:
|
||||
uint32_t seed_;
|
||||
};
|
||||
|
||||
#endif // FASTCRC_FASTCRC_H_
|
||||
|
823
include/Livox/third_party/cmdline/cmdline.h
vendored
Executable file
823
include/Livox/third_party/cmdline/cmdline.h
vendored
Executable file
@ -0,0 +1,823 @@
|
||||
/*
|
||||
Copyright (c) 2009, Hideyuki Tanaka
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the <organization> nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY <copyright holder> ''AS IS'' AND ANY
|
||||
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL <copyright holder> BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <stdexcept>
|
||||
#include <typeinfo>
|
||||
#include <cstring>
|
||||
#include <algorithm>
|
||||
#if defined(_MSC_VER)
|
||||
#include <windows.h>
|
||||
#include <dbghelp.h>
|
||||
#undef max
|
||||
#pragma comment(lib, "dbghelp.lib")
|
||||
#elif defined(__clang__) || defined(__GNUC__)
|
||||
#include <cxxabi.h>
|
||||
#endif
|
||||
#include <cstdlib>
|
||||
|
||||
namespace cmdline{
|
||||
|
||||
namespace detail{
|
||||
|
||||
template <typename Target, typename Source, bool Same>
|
||||
class lexical_cast_t{
|
||||
public:
|
||||
static Target cast(const Source &arg){
|
||||
Target ret;
|
||||
std::stringstream ss;
|
||||
if (!(ss<<arg && ss>>ret && ss.eof()))
|
||||
throw std::bad_cast();
|
||||
|
||||
return ret;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Target, typename Source>
|
||||
class lexical_cast_t<Target, Source, true>{
|
||||
public:
|
||||
static Target cast(const Source &arg){
|
||||
return arg;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Source>
|
||||
class lexical_cast_t<std::string, Source, false>{
|
||||
public:
|
||||
static std::string cast(const Source &arg){
|
||||
std::ostringstream ss;
|
||||
ss<<arg;
|
||||
return ss.str();
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Target>
|
||||
class lexical_cast_t<Target, std::string, false>{
|
||||
public:
|
||||
static Target cast(const std::string &arg){
|
||||
Target ret;
|
||||
std::istringstream ss(arg);
|
||||
if (!(ss>>ret && ss.eof()))
|
||||
throw std::bad_cast();
|
||||
return ret;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T1, typename T2>
|
||||
struct is_same {
|
||||
static const bool value = false;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct is_same<T, T>{
|
||||
static const bool value = true;
|
||||
};
|
||||
|
||||
template<typename Target, typename Source>
|
||||
Target lexical_cast(const Source &arg)
|
||||
{
|
||||
return lexical_cast_t<Target, Source, detail::is_same<Target, Source>::value>::cast(arg);
|
||||
}
|
||||
|
||||
static inline std::string demangle(const std::string &name)
|
||||
{
|
||||
#if defined(_MSC_VER)
|
||||
TCHAR ret[256];
|
||||
std::memset(ret, 0, 256);
|
||||
::UnDecorateSymbolName(name.c_str(), ret, 256, 0);
|
||||
return ret;
|
||||
#else
|
||||
int status=0;
|
||||
char *p=abi::__cxa_demangle(name.c_str(), 0, 0, &status);
|
||||
std::string ret(p);
|
||||
free(p);
|
||||
return ret;
|
||||
#endif
|
||||
}
|
||||
|
||||
template <class T>
|
||||
std::string readable_typename()
|
||||
{
|
||||
return demangle(typeid(T).name());
|
||||
}
|
||||
|
||||
template <class T>
|
||||
std::string default_value(T def)
|
||||
{
|
||||
return detail::lexical_cast<std::string>(def);
|
||||
}
|
||||
|
||||
template <>
|
||||
inline std::string readable_typename<std::string>()
|
||||
{
|
||||
return "string";
|
||||
}
|
||||
|
||||
} // detail
|
||||
|
||||
//-----
|
||||
|
||||
class cmdline_error : public std::exception {
|
||||
public:
|
||||
cmdline_error(const std::string &msg): msg(msg){}
|
||||
~cmdline_error() throw() {}
|
||||
const char *what() const throw() { return msg.c_str(); }
|
||||
private:
|
||||
std::string msg;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct default_reader{
|
||||
T operator()(const std::string &str){
|
||||
return detail::lexical_cast<T>(str);
|
||||
}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct range_reader{
|
||||
range_reader(const T &low, const T &high): low(low), high(high) {}
|
||||
T operator()(const std::string &s) const {
|
||||
T ret=default_reader<T>()(s);
|
||||
if (!(ret>=low && ret<=high)) throw cmdline::cmdline_error("range_error");
|
||||
return ret;
|
||||
}
|
||||
private:
|
||||
T low, high;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
range_reader<T> range(const T &low, const T &high)
|
||||
{
|
||||
return range_reader<T>(low, high);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
struct oneof_reader{
|
||||
T operator()(const std::string &s){
|
||||
T ret=default_reader<T>()(s);
|
||||
if (std::find(alt.begin(), alt.end(), ret)==alt.end())
|
||||
throw cmdline_error("");
|
||||
return ret;
|
||||
}
|
||||
void add(const T &v){ alt.push_back(v); }
|
||||
private:
|
||||
std::vector<T> alt;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
oneof_reader<T> oneof(T a1)
|
||||
{
|
||||
oneof_reader<T> ret;
|
||||
ret.add(a1);
|
||||
return ret;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
oneof_reader<T> oneof(T a1, T a2)
|
||||
{
|
||||
oneof_reader<T> ret;
|
||||
ret.add(a1);
|
||||
ret.add(a2);
|
||||
return ret;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
oneof_reader<T> oneof(T a1, T a2, T a3)
|
||||
{
|
||||
oneof_reader<T> ret;
|
||||
ret.add(a1);
|
||||
ret.add(a2);
|
||||
ret.add(a3);
|
||||
return ret;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
oneof_reader<T> oneof(T a1, T a2, T a3, T a4)
|
||||
{
|
||||
oneof_reader<T> ret;
|
||||
ret.add(a1);
|
||||
ret.add(a2);
|
||||
ret.add(a3);
|
||||
ret.add(a4);
|
||||
return ret;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
oneof_reader<T> oneof(T a1, T a2, T a3, T a4, T a5)
|
||||
{
|
||||
oneof_reader<T> ret;
|
||||
ret.add(a1);
|
||||
ret.add(a2);
|
||||
ret.add(a3);
|
||||
ret.add(a4);
|
||||
ret.add(a5);
|
||||
return ret;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
oneof_reader<T> oneof(T a1, T a2, T a3, T a4, T a5, T a6)
|
||||
{
|
||||
oneof_reader<T> ret;
|
||||
ret.add(a1);
|
||||
ret.add(a2);
|
||||
ret.add(a3);
|
||||
ret.add(a4);
|
||||
ret.add(a5);
|
||||
ret.add(a6);
|
||||
return ret;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
oneof_reader<T> oneof(T a1, T a2, T a3, T a4, T a5, T a6, T a7)
|
||||
{
|
||||
oneof_reader<T> ret;
|
||||
ret.add(a1);
|
||||
ret.add(a2);
|
||||
ret.add(a3);
|
||||
ret.add(a4);
|
||||
ret.add(a5);
|
||||
ret.add(a6);
|
||||
ret.add(a7);
|
||||
return ret;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
oneof_reader<T> oneof(T a1, T a2, T a3, T a4, T a5, T a6, T a7, T a8)
|
||||
{
|
||||
oneof_reader<T> ret;
|
||||
ret.add(a1);
|
||||
ret.add(a2);
|
||||
ret.add(a3);
|
||||
ret.add(a4);
|
||||
ret.add(a5);
|
||||
ret.add(a6);
|
||||
ret.add(a7);
|
||||
ret.add(a8);
|
||||
return ret;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
oneof_reader<T> oneof(T a1, T a2, T a3, T a4, T a5, T a6, T a7, T a8, T a9)
|
||||
{
|
||||
oneof_reader<T> ret;
|
||||
ret.add(a1);
|
||||
ret.add(a2);
|
||||
ret.add(a3);
|
||||
ret.add(a4);
|
||||
ret.add(a5);
|
||||
ret.add(a6);
|
||||
ret.add(a7);
|
||||
ret.add(a8);
|
||||
ret.add(a9);
|
||||
return ret;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
oneof_reader<T> oneof(T a1, T a2, T a3, T a4, T a5, T a6, T a7, T a8, T a9, T a10)
|
||||
{
|
||||
oneof_reader<T> ret;
|
||||
ret.add(a1);
|
||||
ret.add(a2);
|
||||
ret.add(a3);
|
||||
ret.add(a4);
|
||||
ret.add(a5);
|
||||
ret.add(a6);
|
||||
ret.add(a7);
|
||||
ret.add(a8);
|
||||
ret.add(a9);
|
||||
ret.add(a10);
|
||||
return ret;
|
||||
}
|
||||
|
||||
//-----
|
||||
|
||||
class parser{
|
||||
public:
|
||||
parser(){
|
||||
}
|
||||
~parser(){
|
||||
for (std::map<std::string, option_base*>::iterator p=options.begin();
|
||||
p!=options.end(); p++)
|
||||
delete p->second;
|
||||
}
|
||||
|
||||
void add(const std::string &name,
|
||||
char short_name=0,
|
||||
const std::string &desc=""){
|
||||
if (options.count(name)) throw cmdline_error("multiple definition: "+name);
|
||||
options[name]=new option_without_value(name, short_name, desc);
|
||||
ordered.push_back(options[name]);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void add(const std::string &name,
|
||||
char short_name=0,
|
||||
const std::string &desc="",
|
||||
bool need=true,
|
||||
const T def=T()){
|
||||
add(name, short_name, desc, need, def, default_reader<T>());
|
||||
}
|
||||
|
||||
template <class T, class F>
|
||||
void add(const std::string &name,
|
||||
char short_name=0,
|
||||
const std::string &desc="",
|
||||
bool need=true,
|
||||
const T def=T(),
|
||||
F reader=F()){
|
||||
if (options.count(name)) throw cmdline_error("multiple definition: "+name);
|
||||
options[name]=new option_with_value_with_reader<T, F>(name, short_name, need, def, desc, reader);
|
||||
ordered.push_back(options[name]);
|
||||
}
|
||||
|
||||
void footer(const std::string &f){
|
||||
ftr=f;
|
||||
}
|
||||
|
||||
void set_program_name(const std::string &name){
|
||||
prog_name=name;
|
||||
}
|
||||
|
||||
bool exist(const std::string &name) const {
|
||||
if (options.count(name)==0) throw cmdline_error("there is no flag: --"+name);
|
||||
return options.find(name)->second->has_set();
|
||||
}
|
||||
|
||||
template <class T>
|
||||
const T &get(const std::string &name) const {
|
||||
if (options.count(name)==0) throw cmdline_error("there is no flag: --"+name);
|
||||
const option_with_value<T> *p=dynamic_cast<const option_with_value<T>*>(options.find(name)->second);
|
||||
if (p==NULL) throw cmdline_error("type mismatch flag '"+name+"'");
|
||||
return p->get();
|
||||
}
|
||||
|
||||
const std::vector<std::string> &rest() const {
|
||||
return others;
|
||||
}
|
||||
|
||||
bool parse(const std::string &arg){
|
||||
std::vector<std::string> args;
|
||||
|
||||
std::string buf;
|
||||
bool in_quote=false;
|
||||
for (std::string::size_type i=0; i<arg.length(); i++){
|
||||
if (arg[i]=='\"'){
|
||||
in_quote=!in_quote;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (arg[i]==' ' && !in_quote){
|
||||
args.push_back(buf);
|
||||
buf="";
|
||||
continue;
|
||||
}
|
||||
|
||||
if (arg[i]=='\\'){
|
||||
i++;
|
||||
if (i>=arg.length()){
|
||||
errors.push_back("unexpected occurrence of '\\' at end of string");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
buf+=arg[i];
|
||||
}
|
||||
|
||||
if (in_quote){
|
||||
errors.push_back("quote is not closed");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (buf.length()>0)
|
||||
args.push_back(buf);
|
||||
|
||||
for (size_t i=0; i<args.size(); i++)
|
||||
std::cout<<"\""<<args[i]<<"\""<<std::endl;
|
||||
|
||||
return parse(args);
|
||||
}
|
||||
|
||||
bool parse(const std::vector<std::string> &args){
|
||||
int argc=static_cast<int>(args.size());
|
||||
std::vector<const char*> argv(argc);
|
||||
|
||||
for (int i=0; i<argc; i++)
|
||||
argv[i]=args[i].c_str();
|
||||
|
||||
return parse(argc, &argv[0]);
|
||||
}
|
||||
|
||||
bool parse(int argc, const char * const argv[]){
|
||||
errors.clear();
|
||||
others.clear();
|
||||
|
||||
if (argc<1){
|
||||
errors.push_back("argument number must be longer than 0");
|
||||
return false;
|
||||
}
|
||||
if (prog_name=="")
|
||||
prog_name=argv[0];
|
||||
|
||||
std::map<char, std::string> lookup;
|
||||
for (std::map<std::string, option_base*>::iterator p=options.begin();
|
||||
p!=options.end(); p++){
|
||||
if (p->first.length()==0) continue;
|
||||
char initial=p->second->short_name();
|
||||
if (initial){
|
||||
if (lookup.count(initial)>0){
|
||||
lookup[initial]="";
|
||||
errors.push_back(std::string("short option '")+initial+"' is ambiguous");
|
||||
return false;
|
||||
}
|
||||
else lookup[initial]=p->first;
|
||||
}
|
||||
}
|
||||
|
||||
for (int i=1; i<argc; i++){
|
||||
if (strncmp(argv[i], "--", 2)==0){
|
||||
const char *p=strchr(argv[i]+2, '=');
|
||||
if (p){
|
||||
std::string name(argv[i]+2, p);
|
||||
std::string val(p+1);
|
||||
set_option(name, val);
|
||||
}
|
||||
else{
|
||||
std::string name(argv[i]+2);
|
||||
if (options.count(name)==0){
|
||||
errors.push_back("undefined option: --"+name);
|
||||
continue;
|
||||
}
|
||||
if (options[name]->has_value()){
|
||||
if (i+1>=argc){
|
||||
errors.push_back("option needs value: --"+name);
|
||||
continue;
|
||||
}
|
||||
else{
|
||||
i++;
|
||||
set_option(name, argv[i]);
|
||||
}
|
||||
}
|
||||
else{
|
||||
set_option(name);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (strncmp(argv[i], "-", 1)==0){
|
||||
if (!argv[i][1]) continue;
|
||||
char last=argv[i][1];
|
||||
for (int j=2; argv[i][j]; j++){
|
||||
last=argv[i][j];
|
||||
if (lookup.count(argv[i][j-1])==0){
|
||||
errors.push_back(std::string("undefined short option: -")+argv[i][j-1]);
|
||||
continue;
|
||||
}
|
||||
if (lookup[argv[i][j-1]]==""){
|
||||
errors.push_back(std::string("ambiguous short option: -")+argv[i][j-1]);
|
||||
continue;
|
||||
}
|
||||
set_option(lookup[argv[i][j-1]]);
|
||||
}
|
||||
|
||||
if (lookup.count(last)==0){
|
||||
errors.push_back(std::string("undefined short option: -")+last);
|
||||
continue;
|
||||
}
|
||||
if (lookup[last]==""){
|
||||
errors.push_back(std::string("ambiguous short option: -")+last);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (i+1<argc && options[lookup[last]]->has_value()){
|
||||
set_option(lookup[last], argv[i+1]);
|
||||
i++;
|
||||
}
|
||||
else{
|
||||
set_option(lookup[last]);
|
||||
}
|
||||
}
|
||||
else{
|
||||
others.push_back(argv[i]);
|
||||
}
|
||||
}
|
||||
|
||||
for (std::map<std::string, option_base*>::iterator p=options.begin();
|
||||
p!=options.end(); p++)
|
||||
if (!p->second->valid())
|
||||
errors.push_back("need option: --"+std::string(p->first));
|
||||
|
||||
return errors.size()==0;
|
||||
}
|
||||
|
||||
void parse_check(const std::string &arg){
|
||||
if (!options.count("help"))
|
||||
add("help", '?', "print this message");
|
||||
check(0, parse(arg));
|
||||
}
|
||||
|
||||
void parse_check(const std::vector<std::string> &args){
|
||||
if (!options.count("help"))
|
||||
add("help", '?', "print this message");
|
||||
check(args.size(), parse(args));
|
||||
}
|
||||
|
||||
void parse_check(int argc, char *argv[]){
|
||||
if (!options.count("help"))
|
||||
add("help", '?', "print this message");
|
||||
check(argc, parse(argc, argv));
|
||||
}
|
||||
|
||||
std::string error() const{
|
||||
return errors.size()>0?errors[0]:"";
|
||||
}
|
||||
|
||||
std::string error_full() const{
|
||||
std::ostringstream oss;
|
||||
for (size_t i=0; i<errors.size(); i++)
|
||||
oss<<errors[i]<<std::endl;
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
std::string usage() const {
|
||||
std::ostringstream oss;
|
||||
oss<<"usage: "<<prog_name<<" ";
|
||||
for (size_t i=0; i<ordered.size(); i++){
|
||||
if (ordered[i]->must())
|
||||
oss<<ordered[i]->short_description()<<" ";
|
||||
}
|
||||
|
||||
oss<<"[options] ... "<<ftr<<std::endl;
|
||||
oss<<"options:"<<std::endl;
|
||||
|
||||
size_t max_width=0;
|
||||
for (size_t i=0; i<ordered.size(); i++){
|
||||
max_width=std::max(max_width, ordered[i]->name().length());
|
||||
}
|
||||
for (size_t i=0; i<ordered.size(); i++){
|
||||
if (ordered[i]->short_name()){
|
||||
oss<<" -"<<ordered[i]->short_name()<<", ";
|
||||
}
|
||||
else{
|
||||
oss<<" ";
|
||||
}
|
||||
|
||||
oss<<"--"<<ordered[i]->name();
|
||||
for (size_t j=ordered[i]->name().length(); j<max_width+4; j++)
|
||||
oss<<' ';
|
||||
oss<<ordered[i]->description()<<std::endl;
|
||||
}
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
void check(int argc, bool ok){
|
||||
if ((argc==1 && !ok) || exist("help")){
|
||||
std::cerr<<usage();
|
||||
exit(0);
|
||||
}
|
||||
|
||||
if (!ok){
|
||||
std::cerr<<error()<<std::endl<<usage();
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
void set_option(const std::string &name){
|
||||
if (options.count(name)==0){
|
||||
errors.push_back("undefined option: --"+name);
|
||||
return;
|
||||
}
|
||||
if (!options[name]->set()){
|
||||
errors.push_back("option needs value: --"+name);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void set_option(const std::string &name, const std::string &value){
|
||||
if (options.count(name)==0){
|
||||
errors.push_back("undefined option: --"+name);
|
||||
return;
|
||||
}
|
||||
if (!options[name]->set(value)){
|
||||
errors.push_back("option value is invalid: --"+name+"="+value);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
class option_base{
|
||||
public:
|
||||
virtual ~option_base(){}
|
||||
|
||||
virtual bool has_value() const=0;
|
||||
virtual bool set()=0;
|
||||
virtual bool set(const std::string &value)=0;
|
||||
virtual bool has_set() const=0;
|
||||
virtual bool valid() const=0;
|
||||
virtual bool must() const=0;
|
||||
|
||||
virtual const std::string &name() const=0;
|
||||
virtual char short_name() const=0;
|
||||
virtual const std::string &description() const=0;
|
||||
virtual std::string short_description() const=0;
|
||||
};
|
||||
|
||||
class option_without_value : public option_base {
|
||||
public:
|
||||
option_without_value(const std::string &name,
|
||||
char short_name,
|
||||
const std::string &desc)
|
||||
:nam(name), snam(short_name), desc(desc), has(false){
|
||||
}
|
||||
~option_without_value(){}
|
||||
|
||||
bool has_value() const { return false; }
|
||||
|
||||
bool set(){
|
||||
has=true;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool set(const std::string &){
|
||||
return false;
|
||||
}
|
||||
|
||||
bool has_set() const {
|
||||
return has;
|
||||
}
|
||||
|
||||
bool valid() const{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool must() const{
|
||||
return false;
|
||||
}
|
||||
|
||||
const std::string &name() const{
|
||||
return nam;
|
||||
}
|
||||
|
||||
char short_name() const{
|
||||
return snam;
|
||||
}
|
||||
|
||||
const std::string &description() const {
|
||||
return desc;
|
||||
}
|
||||
|
||||
std::string short_description() const{
|
||||
return "--"+nam;
|
||||
}
|
||||
|
||||
private:
|
||||
std::string nam;
|
||||
char snam;
|
||||
std::string desc;
|
||||
bool has;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
class option_with_value : public option_base {
|
||||
public:
|
||||
option_with_value(const std::string &name,
|
||||
char short_name,
|
||||
bool need,
|
||||
const T &def,
|
||||
const std::string &desc)
|
||||
: nam(name), snam(short_name), need(need), has(false)
|
||||
, def(def), actual(def) {
|
||||
this->desc=full_description(desc);
|
||||
}
|
||||
~option_with_value(){}
|
||||
|
||||
const T &get() const {
|
||||
return actual;
|
||||
}
|
||||
|
||||
bool has_value() const { return true; }
|
||||
|
||||
bool set(){
|
||||
return false;
|
||||
}
|
||||
|
||||
bool set(const std::string &value){
|
||||
try{
|
||||
actual=read(value);
|
||||
has=true;
|
||||
}
|
||||
catch(const std::exception &){
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool has_set() const{
|
||||
return has;
|
||||
}
|
||||
|
||||
bool valid() const{
|
||||
if (need && !has) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool must() const{
|
||||
return need;
|
||||
}
|
||||
|
||||
const std::string &name() const{
|
||||
return nam;
|
||||
}
|
||||
|
||||
char short_name() const{
|
||||
return snam;
|
||||
}
|
||||
|
||||
const std::string &description() const {
|
||||
return desc;
|
||||
}
|
||||
|
||||
std::string short_description() const{
|
||||
return "--"+nam+"="+detail::readable_typename<T>();
|
||||
}
|
||||
|
||||
protected:
|
||||
std::string full_description(const std::string &desc){
|
||||
return
|
||||
desc+" ("+detail::readable_typename<T>()+
|
||||
(need?"":" [="+detail::default_value<T>(def)+"]")
|
||||
+")";
|
||||
}
|
||||
|
||||
virtual T read(const std::string &s)=0;
|
||||
|
||||
std::string nam;
|
||||
char snam;
|
||||
bool need;
|
||||
std::string desc;
|
||||
|
||||
bool has;
|
||||
T def;
|
||||
T actual;
|
||||
};
|
||||
|
||||
template <class T, class F>
|
||||
class option_with_value_with_reader : public option_with_value<T> {
|
||||
public:
|
||||
option_with_value_with_reader(const std::string &name,
|
||||
char short_name,
|
||||
bool need,
|
||||
const T def,
|
||||
const std::string &desc,
|
||||
F reader)
|
||||
: option_with_value<T>(name, short_name, need, def, desc), reader(reader){
|
||||
}
|
||||
|
||||
private:
|
||||
T read(const std::string &s){
|
||||
return reader(s);
|
||||
}
|
||||
|
||||
F reader;
|
||||
};
|
||||
|
||||
std::map<std::string, option_base*> options;
|
||||
std::vector<option_base*> ordered;
|
||||
std::string ftr;
|
||||
|
||||
std::string prog_name;
|
||||
std::vector<std::string> others;
|
||||
|
||||
std::vector<std::string> errors;
|
||||
};
|
||||
|
||||
} // cmdline
|
87
include/Livox/third_party/spdlog/spdlog/async.h
vendored
Executable file
87
include/Livox/third_party/spdlog/spdlog/async.h
vendored
Executable file
@ -0,0 +1,87 @@
|
||||
|
||||
//
|
||||
// Copyright(c) 2018 Gabi Melman.
|
||||
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
//
|
||||
// Async logging using global thread pool
|
||||
// All loggers created here share same global thread pool.
|
||||
// Each log message is pushed to a queue along withe a shared pointer to the
|
||||
// logger.
|
||||
// If a logger deleted while having pending messages in the queue, it's actual
|
||||
// destruction will defer
|
||||
// until all its messages are processed by the thread pool.
|
||||
// This is because each message in the queue holds a shared_ptr to the
|
||||
// originating logger.
|
||||
|
||||
#include "spdlog/async_logger.h"
|
||||
#include "spdlog/details/registry.h"
|
||||
#include "spdlog/details/thread_pool.h"
|
||||
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
|
||||
namespace spdlog {
|
||||
|
||||
namespace details {
|
||||
static const size_t default_async_q_size = 8192;
|
||||
}
|
||||
|
||||
// async logger factory - creates async loggers backed with thread pool.
|
||||
// if a global thread pool doesn't already exist, create it with default queue
|
||||
// size of 8192 items and single thread.
|
||||
template<async_overflow_policy OverflowPolicy = async_overflow_policy::block>
|
||||
struct async_factory_impl
|
||||
{
|
||||
template<typename Sink, typename... SinkArgs>
|
||||
static std::shared_ptr<async_logger> create(std::string logger_name, SinkArgs &&... args)
|
||||
{
|
||||
auto ®istry_inst = details::registry::instance();
|
||||
|
||||
// create global thread pool if not already exists..
|
||||
std::lock_guard<std::recursive_mutex> tp_lock(registry_inst.tp_mutex());
|
||||
auto tp = registry_inst.get_tp();
|
||||
if (tp == nullptr)
|
||||
{
|
||||
tp = std::make_shared<details::thread_pool>(details::default_async_q_size, 1);
|
||||
registry_inst.set_tp(tp);
|
||||
}
|
||||
|
||||
auto sink = std::make_shared<Sink>(std::forward<SinkArgs>(args)...);
|
||||
auto new_logger = std::make_shared<async_logger>(std::move(logger_name), std::move(sink), std::move(tp), OverflowPolicy);
|
||||
registry_inst.initialize_logger(new_logger);
|
||||
return new_logger;
|
||||
}
|
||||
};
|
||||
|
||||
using async_factory = async_factory_impl<async_overflow_policy::block>;
|
||||
using async_factory_nonblock = async_factory_impl<async_overflow_policy::overrun_oldest>;
|
||||
|
||||
template<typename Sink, typename... SinkArgs>
|
||||
inline std::shared_ptr<spdlog::logger> create_async(std::string logger_name, SinkArgs &&... sink_args)
|
||||
{
|
||||
return async_factory::create<Sink>(std::move(logger_name), std::forward<SinkArgs>(sink_args)...);
|
||||
}
|
||||
|
||||
template<typename Sink, typename... SinkArgs>
|
||||
inline std::shared_ptr<spdlog::logger> create_async_nb(std::string logger_name, SinkArgs &&... sink_args)
|
||||
{
|
||||
return async_factory_nonblock::create<Sink>(std::move(logger_name), std::forward<SinkArgs>(sink_args)...);
|
||||
}
|
||||
|
||||
// set global thread pool.
|
||||
inline void init_thread_pool(size_t q_size, size_t thread_count)
|
||||
{
|
||||
auto tp = std::make_shared<details::thread_pool>(q_size, thread_count);
|
||||
details::registry::instance().set_tp(std::move(tp));
|
||||
}
|
||||
|
||||
// get the global thread pool.
|
||||
inline std::shared_ptr<spdlog::details::thread_pool> thread_pool()
|
||||
{
|
||||
return details::registry::instance().get_tp();
|
||||
}
|
||||
} // namespace spdlog
|
73
include/Livox/third_party/spdlog/spdlog/async_logger.h
vendored
Executable file
73
include/Livox/third_party/spdlog/spdlog/async_logger.h
vendored
Executable file
@ -0,0 +1,73 @@
|
||||
//
|
||||
// Copyright(c) 2015 Gabi Melman.
|
||||
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
// Very fast asynchronous logger (millions of logs per second on an average
|
||||
// desktop)
|
||||
// Uses pre allocated lockfree queue for maximum throughput even under large
|
||||
// number of threads.
|
||||
// Creates a single back thread to pop messages from the queue and log them.
|
||||
//
|
||||
// Upon each log write the logger:
|
||||
// 1. Checks if its log level is enough to log the message
|
||||
// 2. Push a new copy of the message to a queue (or block the caller until
|
||||
// space is available in the queue)
|
||||
// 3. will throw spdlog_ex upon log exceptions
|
||||
// Upon destruction, logs all remaining messages in the queue before
|
||||
// destructing..
|
||||
|
||||
#include "spdlog/common.h"
|
||||
#include "spdlog/logger.h"
|
||||
|
||||
#include <chrono>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
namespace spdlog {
|
||||
|
||||
// Async overflow policy - block by default.
|
||||
enum class async_overflow_policy
|
||||
{
|
||||
block, // Block until message can be enqueued
|
||||
overrun_oldest // Discard oldest message in the queue if full when trying to
|
||||
// add new item.
|
||||
};
|
||||
|
||||
namespace details {
|
||||
class thread_pool;
|
||||
}
|
||||
|
||||
class async_logger final : public std::enable_shared_from_this<async_logger>, public logger
|
||||
{
|
||||
friend class details::thread_pool;
|
||||
|
||||
public:
|
||||
template<typename It>
|
||||
async_logger(std::string logger_name, It begin, It end, std::weak_ptr<details::thread_pool> tp,
|
||||
async_overflow_policy overflow_policy = async_overflow_policy::block);
|
||||
|
||||
async_logger(std::string logger_name, sinks_init_list sinks_list, std::weak_ptr<details::thread_pool> tp,
|
||||
async_overflow_policy overflow_policy = async_overflow_policy::block);
|
||||
|
||||
async_logger(std::string logger_name, sink_ptr single_sink, std::weak_ptr<details::thread_pool> tp,
|
||||
async_overflow_policy overflow_policy = async_overflow_policy::block);
|
||||
|
||||
std::shared_ptr<logger> clone(std::string new_name) override;
|
||||
|
||||
protected:
|
||||
void sink_it_(details::log_msg &msg) override;
|
||||
void flush_() override;
|
||||
|
||||
void backend_log_(const details::log_msg &incoming_log_msg);
|
||||
void backend_flush_();
|
||||
|
||||
private:
|
||||
std::weak_ptr<details::thread_pool> thread_pool_;
|
||||
async_overflow_policy overflow_policy_;
|
||||
};
|
||||
} // namespace spdlog
|
||||
|
||||
#include "details/async_logger_impl.h"
|
246
include/Livox/third_party/spdlog/spdlog/common.h
vendored
Executable file
246
include/Livox/third_party/spdlog/spdlog/common.h
vendored
Executable file
@ -0,0 +1,246 @@
|
||||
//
|
||||
// Copyright(c) 2015 Gabi Melman.
|
||||
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "spdlog/tweakme.h"
|
||||
|
||||
#include <atomic>
|
||||
#include <chrono>
|
||||
#include <functional>
|
||||
#include <initializer_list>
|
||||
#include <memory>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <cstring>
|
||||
#include <type_traits>
|
||||
#include <unordered_map>
|
||||
|
||||
#if defined(SPDLOG_WCHAR_FILENAMES) || defined(SPDLOG_WCHAR_TO_UTF8_SUPPORT)
|
||||
#include <codecvt>
|
||||
#include <locale>
|
||||
#endif
|
||||
|
||||
#include "spdlog/details/null_mutex.h"
|
||||
|
||||
#include "spdlog/fmt/fmt.h"
|
||||
|
||||
// visual studio upto 2013 does not support noexcept nor constexpr
|
||||
#if defined(_MSC_VER) && (_MSC_VER < 1900)
|
||||
#define SPDLOG_NOEXCEPT throw()
|
||||
#define SPDLOG_CONSTEXPR
|
||||
#else
|
||||
#define SPDLOG_NOEXCEPT noexcept
|
||||
#define SPDLOG_CONSTEXPR constexpr
|
||||
#endif
|
||||
|
||||
#if defined(__GNUC__) || defined(__clang__)
|
||||
#define SPDLOG_DEPRECATED __attribute__((deprecated))
|
||||
#elif defined(_MSC_VER)
|
||||
#define SPDLOG_DEPRECATED __declspec(deprecated)
|
||||
#else
|
||||
#define SPDLOG_DEPRECATED
|
||||
#endif
|
||||
|
||||
// disable thread local on msvc 2013
|
||||
#ifndef SPDLOG_NO_TLS
|
||||
#if (defined(_MSC_VER) && (_MSC_VER < 1900)) || defined(__cplusplus_winrt)
|
||||
#define SPDLOG_NO_TLS 1
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Get the basename of __FILE__ (at compile time if possible)
|
||||
#if FMT_HAS_FEATURE(__builtin_strrchr)
|
||||
#define SPDLOG_STRRCHR(str, sep) __builtin_strrchr(str, sep)
|
||||
#else
|
||||
#define SPDLOG_STRRCHR(str, sep) strrchr(str, sep)
|
||||
#endif //__builtin_strrchr not defined
|
||||
|
||||
#ifdef _WIN32
|
||||
#define SPDLOG_FILE_BASENAME(file) SPDLOG_STRRCHR("\\" file, '\\') + 1
|
||||
#else
|
||||
#define SPDLOG_FILE_BASENAME(file) SPDLOG_STRRCHR("/" file, '/') + 1
|
||||
#endif
|
||||
|
||||
#ifndef SPDLOG_FUNCTION
|
||||
#define SPDLOG_FUNCTION __FUNCTION__
|
||||
#endif
|
||||
|
||||
namespace spdlog {
|
||||
|
||||
class formatter;
|
||||
|
||||
namespace sinks {
|
||||
class sink;
|
||||
}
|
||||
|
||||
using log_clock = std::chrono::system_clock;
|
||||
using sink_ptr = std::shared_ptr<sinks::sink>;
|
||||
using sinks_init_list = std::initializer_list<sink_ptr>;
|
||||
using log_err_handler = std::function<void(const std::string &err_msg)>;
|
||||
|
||||
// string_view type - either std::string_view or fmt::string_view (pre c++17)
|
||||
#if defined(FMT_USE_STD_STRING_VIEW)
|
||||
using string_view_t = std::string_view;
|
||||
#else
|
||||
using string_view_t = fmt::string_view;
|
||||
#endif
|
||||
|
||||
#if defined(SPDLOG_NO_ATOMIC_LEVELS)
|
||||
using level_t = details::null_atomic_int;
|
||||
#else
|
||||
using level_t = std::atomic<int>;
|
||||
#endif
|
||||
|
||||
#define SPDLOG_LEVEL_TRACE 0
|
||||
#define SPDLOG_LEVEL_DEBUG 1
|
||||
#define SPDLOG_LEVEL_INFO 2
|
||||
#define SPDLOG_LEVEL_WARN 3
|
||||
#define SPDLOG_LEVEL_ERROR 4
|
||||
#define SPDLOG_LEVEL_CRITICAL 5
|
||||
#define SPDLOG_LEVEL_OFF 6
|
||||
|
||||
#if !defined(SPDLOG_ACTIVE_LEVEL)
|
||||
#define SPDLOG_ACTIVE_LEVEL SPDLOG_LEVEL_INFO
|
||||
#endif
|
||||
|
||||
// Log level enum
|
||||
namespace level {
|
||||
enum level_enum
|
||||
{
|
||||
trace = SPDLOG_LEVEL_TRACE,
|
||||
debug = SPDLOG_LEVEL_DEBUG,
|
||||
info = SPDLOG_LEVEL_INFO,
|
||||
warn = SPDLOG_LEVEL_WARN,
|
||||
err = SPDLOG_LEVEL_ERROR,
|
||||
critical = SPDLOG_LEVEL_CRITICAL,
|
||||
off = SPDLOG_LEVEL_OFF,
|
||||
};
|
||||
|
||||
#if !defined(SPDLOG_LEVEL_NAMES)
|
||||
#define SPDLOG_LEVEL_NAMES \
|
||||
{ \
|
||||
"trace", "debug", "info", "warning", "error", "critical", "off" \
|
||||
}
|
||||
#endif
|
||||
static string_view_t level_string_views[] SPDLOG_LEVEL_NAMES;
|
||||
|
||||
#if !defined(SPDLOG_SHORT_LEVEL_NAMES)
|
||||
#define SPDLOG_SHORT_LEVEL_NAMES {"T", "D", "I", "W", "E", "C", "O"}
|
||||
#endif
|
||||
static const char *short_level_names[] SPDLOG_SHORT_LEVEL_NAMES;
|
||||
|
||||
inline string_view_t &to_string_view(spdlog::level::level_enum l) SPDLOG_NOEXCEPT
|
||||
{
|
||||
return level_string_views[l];
|
||||
}
|
||||
|
||||
inline const char *to_short_c_str(spdlog::level::level_enum l) SPDLOG_NOEXCEPT
|
||||
{
|
||||
return short_level_names[l];
|
||||
}
|
||||
|
||||
inline spdlog::level::level_enum from_str(const std::string &name) SPDLOG_NOEXCEPT
|
||||
{
|
||||
int level = 0;
|
||||
for (const auto &level_str : level_string_views)
|
||||
{
|
||||
if (level_str == name)
|
||||
{
|
||||
return static_cast<level::level_enum>(level);
|
||||
}
|
||||
level++;
|
||||
}
|
||||
return level::off;
|
||||
}
|
||||
|
||||
using level_hasher = std::hash<int>;
|
||||
} // namespace level
|
||||
|
||||
//
|
||||
// Pattern time - specific time getting to use for pattern_formatter.
|
||||
// local time by default
|
||||
//
|
||||
enum class pattern_time_type
|
||||
{
|
||||
local, // log localtime
|
||||
utc // log utc
|
||||
};
|
||||
|
||||
//
|
||||
// Log exception
|
||||
//
|
||||
class spdlog_ex : public std::exception
|
||||
{
|
||||
public:
|
||||
explicit spdlog_ex(std::string msg)
|
||||
: msg_(std::move(msg))
|
||||
{
|
||||
}
|
||||
|
||||
spdlog_ex(const std::string &msg, int last_errno)
|
||||
{
|
||||
fmt::memory_buffer outbuf;
|
||||
fmt::format_system_error(outbuf, last_errno, msg);
|
||||
msg_ = fmt::to_string(outbuf);
|
||||
}
|
||||
|
||||
const char *what() const SPDLOG_NOEXCEPT override
|
||||
{
|
||||
return msg_.c_str();
|
||||
}
|
||||
|
||||
private:
|
||||
std::string msg_;
|
||||
};
|
||||
|
||||
//
|
||||
// wchar support for windows file names (SPDLOG_WCHAR_FILENAMES must be defined)
|
||||
//
|
||||
#if defined(_WIN32) && defined(SPDLOG_WCHAR_FILENAMES)
|
||||
using filename_t = std::wstring;
|
||||
#else
|
||||
using filename_t = std::string;
|
||||
#endif
|
||||
|
||||
struct source_loc
|
||||
{
|
||||
SPDLOG_CONSTEXPR source_loc()
|
||||
: filename{""}
|
||||
, line{0}
|
||||
, funcname{""}
|
||||
{
|
||||
}
|
||||
SPDLOG_CONSTEXPR source_loc(const char *filename_in, int line_in, const char *funcname_in)
|
||||
: filename{filename_in}
|
||||
, line{static_cast<uint32_t>(line_in)}
|
||||
, funcname{funcname_in}
|
||||
{
|
||||
}
|
||||
|
||||
SPDLOG_CONSTEXPR bool empty() const SPDLOG_NOEXCEPT
|
||||
{
|
||||
return line == 0;
|
||||
}
|
||||
const char *filename;
|
||||
uint32_t line;
|
||||
const char *funcname;
|
||||
};
|
||||
|
||||
namespace details {
|
||||
// make_unique support for pre c++14
|
||||
|
||||
#if __cplusplus >= 201402L // C++14 and beyond
|
||||
using std::make_unique;
|
||||
#else
|
||||
template<typename T, typename... Args>
|
||||
std::unique_ptr<T> make_unique(Args &&... args)
|
||||
{
|
||||
static_assert(!std::is_array<T>::value, "arrays not supported");
|
||||
return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
|
||||
}
|
||||
#endif
|
||||
} // namespace details
|
||||
} // namespace spdlog
|
110
include/Livox/third_party/spdlog/spdlog/details/async_logger_impl.h
vendored
Executable file
110
include/Livox/third_party/spdlog/spdlog/details/async_logger_impl.h
vendored
Executable file
@ -0,0 +1,110 @@
|
||||
//
|
||||
// Copyright(c) 2015 Gabi Melman.
|
||||
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
// async logger implementation
|
||||
// uses a thread pool to perform the actual logging
|
||||
|
||||
#include "spdlog/details/thread_pool.h"
|
||||
|
||||
#include <chrono>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
template<typename It>
|
||||
inline spdlog::async_logger::async_logger(
|
||||
std::string logger_name, It begin, It end, std::weak_ptr<details::thread_pool> tp, async_overflow_policy overflow_policy)
|
||||
: logger(std::move(logger_name), begin, end)
|
||||
, thread_pool_(std::move(tp))
|
||||
, overflow_policy_(overflow_policy)
|
||||
{
|
||||
}
|
||||
|
||||
inline spdlog::async_logger::async_logger(
|
||||
std::string logger_name, sinks_init_list sinks_list, std::weak_ptr<details::thread_pool> tp, async_overflow_policy overflow_policy)
|
||||
: async_logger(std::move(logger_name), sinks_list.begin(), sinks_list.end(), std::move(tp), overflow_policy)
|
||||
{
|
||||
}
|
||||
|
||||
inline spdlog::async_logger::async_logger(
|
||||
std::string logger_name, sink_ptr single_sink, std::weak_ptr<details::thread_pool> tp, async_overflow_policy overflow_policy)
|
||||
: async_logger(std::move(logger_name), {std::move(single_sink)}, std::move(tp), overflow_policy)
|
||||
{
|
||||
}
|
||||
|
||||
// send the log message to the thread pool
|
||||
inline void spdlog::async_logger::sink_it_(details::log_msg &msg)
|
||||
{
|
||||
#if defined(SPDLOG_ENABLE_MESSAGE_COUNTER)
|
||||
incr_msg_counter_(msg);
|
||||
#endif
|
||||
if (auto pool_ptr = thread_pool_.lock())
|
||||
{
|
||||
pool_ptr->post_log(shared_from_this(), msg, overflow_policy_);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw spdlog_ex("async log: thread pool doesn't exist anymore");
|
||||
}
|
||||
}
|
||||
|
||||
// send flush request to the thread pool
|
||||
inline void spdlog::async_logger::flush_()
|
||||
{
|
||||
if (auto pool_ptr = thread_pool_.lock())
|
||||
{
|
||||
pool_ptr->post_flush(shared_from_this(), overflow_policy_);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw spdlog_ex("async flush: thread pool doesn't exist anymore");
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// backend functions - called from the thread pool to do the actual job
|
||||
//
|
||||
inline void spdlog::async_logger::backend_log_(const details::log_msg &incoming_log_msg)
|
||||
{
|
||||
try
|
||||
{
|
||||
for (auto &s : sinks_)
|
||||
{
|
||||
if (s->should_log(incoming_log_msg.level))
|
||||
{
|
||||
s->log(incoming_log_msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
SPDLOG_CATCH_AND_HANDLE
|
||||
|
||||
if (should_flush_(incoming_log_msg))
|
||||
{
|
||||
backend_flush_();
|
||||
}
|
||||
}
|
||||
|
||||
inline void spdlog::async_logger::backend_flush_()
|
||||
{
|
||||
try
|
||||
{
|
||||
for (auto &sink : sinks_)
|
||||
{
|
||||
sink->flush();
|
||||
}
|
||||
}
|
||||
SPDLOG_CATCH_AND_HANDLE
|
||||
}
|
||||
|
||||
inline std::shared_ptr<spdlog::logger> spdlog::async_logger::clone(std::string new_name)
|
||||
{
|
||||
auto cloned = std::make_shared<spdlog::async_logger>(std::move(new_name), sinks_.begin(), sinks_.end(), thread_pool_, overflow_policy_);
|
||||
|
||||
cloned->set_level(this->level());
|
||||
cloned->flush_on(this->flush_level());
|
||||
cloned->set_error_handler(this->error_handler());
|
||||
return std::move(cloned);
|
||||
}
|
72
include/Livox/third_party/spdlog/spdlog/details/circular_q.h
vendored
Executable file
72
include/Livox/third_party/spdlog/spdlog/details/circular_q.h
vendored
Executable file
@ -0,0 +1,72 @@
|
||||
//
|
||||
// Copyright(c) 2018 Gabi Melman.
|
||||
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
||||
//
|
||||
|
||||
// cirucal q view of std::vector.
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace spdlog {
|
||||
namespace details {
|
||||
template<typename T>
|
||||
class circular_q
|
||||
{
|
||||
public:
|
||||
using item_type = T;
|
||||
|
||||
explicit circular_q(size_t max_items)
|
||||
: max_items_(max_items + 1) // one item is reserved as marker for full q
|
||||
, v_(max_items_)
|
||||
{
|
||||
}
|
||||
|
||||
// push back, overrun (oldest) item if no room left
|
||||
void push_back(T &&item)
|
||||
{
|
||||
v_[tail_] = std::move(item);
|
||||
tail_ = (tail_ + 1) % max_items_;
|
||||
|
||||
if (tail_ == head_) // overrun last item if full
|
||||
{
|
||||
head_ = (head_ + 1) % max_items_;
|
||||
++overrun_counter_;
|
||||
}
|
||||
}
|
||||
|
||||
// Pop item from front.
|
||||
// If there are no elements in the container, the behavior is undefined.
|
||||
void pop_front(T &popped_item)
|
||||
{
|
||||
popped_item = std::move(v_[head_]);
|
||||
head_ = (head_ + 1) % max_items_;
|
||||
}
|
||||
|
||||
bool empty()
|
||||
{
|
||||
return tail_ == head_;
|
||||
}
|
||||
|
||||
bool full()
|
||||
{
|
||||
// head is ahead of the tail by 1
|
||||
return ((tail_ + 1) % max_items_) == head_;
|
||||
}
|
||||
|
||||
size_t overrun_counter() const
|
||||
{
|
||||
return overrun_counter_;
|
||||
}
|
||||
|
||||
private:
|
||||
size_t max_items_;
|
||||
typename std::vector<T>::size_type head_ = 0;
|
||||
typename std::vector<T>::size_type tail_ = 0;
|
||||
|
||||
std::vector<T> v_;
|
||||
|
||||
size_t overrun_counter_ = 0;
|
||||
};
|
||||
} // namespace details
|
||||
} // namespace spdlog
|
74
include/Livox/third_party/spdlog/spdlog/details/console_globals.h
vendored
Executable file
74
include/Livox/third_party/spdlog/spdlog/details/console_globals.h
vendored
Executable file
@ -0,0 +1,74 @@
|
||||
#pragma once
|
||||
//
|
||||
// Copyright(c) 2018 Gabi Melman.
|
||||
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
||||
//
|
||||
|
||||
#include "spdlog/details/null_mutex.h"
|
||||
#include <cstdio>
|
||||
#include <mutex>
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
#ifndef NOMINMAX
|
||||
#define NOMINMAX // prevent windows redefining min/max
|
||||
#endif
|
||||
|
||||
#ifndef WIN32_LEAN_AND_MEAN
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#endif
|
||||
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
namespace spdlog {
|
||||
namespace details {
|
||||
struct console_stdout
|
||||
{
|
||||
static std::FILE *stream()
|
||||
{
|
||||
return stdout;
|
||||
}
|
||||
#ifdef _WIN32
|
||||
static HANDLE handle()
|
||||
{
|
||||
return ::GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
struct console_stderr
|
||||
{
|
||||
static std::FILE *stream()
|
||||
{
|
||||
return stderr;
|
||||
}
|
||||
#ifdef _WIN32
|
||||
static HANDLE handle()
|
||||
{
|
||||
return ::GetStdHandle(STD_ERROR_HANDLE);
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
struct console_mutex
|
||||
{
|
||||
using mutex_t = std::mutex;
|
||||
static mutex_t &mutex()
|
||||
{
|
||||
static mutex_t s_mutex;
|
||||
return s_mutex;
|
||||
}
|
||||
};
|
||||
|
||||
struct console_nullmutex
|
||||
{
|
||||
using mutex_t = null_mutex;
|
||||
static mutex_t &mutex()
|
||||
{
|
||||
static mutex_t s_mutex;
|
||||
return s_mutex;
|
||||
}
|
||||
};
|
||||
} // namespace details
|
||||
} // namespace spdlog
|
152
include/Livox/third_party/spdlog/spdlog/details/file_helper.h
vendored
Executable file
152
include/Livox/third_party/spdlog/spdlog/details/file_helper.h
vendored
Executable file
@ -0,0 +1,152 @@
|
||||
//
|
||||
// Copyright(c) 2015 Gabi Melman.
|
||||
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
// Helper class for file sinks.
|
||||
// When failing to open a file, retry several times(5) with a delay interval(10 ms).
|
||||
// Throw spdlog_ex exception on errors.
|
||||
|
||||
#include "spdlog/details/log_msg.h"
|
||||
#include "spdlog/details/os.h"
|
||||
|
||||
#include <cerrno>
|
||||
#include <chrono>
|
||||
#include <cstdio>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
#include <tuple>
|
||||
|
||||
namespace spdlog {
|
||||
namespace details {
|
||||
|
||||
class file_helper
|
||||
{
|
||||
|
||||
public:
|
||||
const int open_tries = 5;
|
||||
const int open_interval = 10;
|
||||
|
||||
explicit file_helper() = default;
|
||||
|
||||
file_helper(const file_helper &) = delete;
|
||||
file_helper &operator=(const file_helper &) = delete;
|
||||
|
||||
~file_helper()
|
||||
{
|
||||
close();
|
||||
}
|
||||
|
||||
void open(const filename_t &fname, bool truncate = false)
|
||||
{
|
||||
close();
|
||||
auto *mode = truncate ? SPDLOG_FILENAME_T("wb") : SPDLOG_FILENAME_T("ab");
|
||||
_filename = fname;
|
||||
for (int tries = 0; tries < open_tries; ++tries)
|
||||
{
|
||||
if (!os::fopen_s(&fd_, fname, mode))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
details::os::sleep_for_millis(open_interval);
|
||||
}
|
||||
|
||||
throw spdlog_ex("Failed opening file " + os::filename_to_str(_filename) + " for writing", errno);
|
||||
}
|
||||
|
||||
void reopen(bool truncate)
|
||||
{
|
||||
if (_filename.empty())
|
||||
{
|
||||
throw spdlog_ex("Failed re opening file - was not opened before");
|
||||
}
|
||||
open(_filename, truncate);
|
||||
}
|
||||
|
||||
void flush()
|
||||
{
|
||||
std::fflush(fd_);
|
||||
}
|
||||
|
||||
void close()
|
||||
{
|
||||
if (fd_ != nullptr)
|
||||
{
|
||||
std::fclose(fd_);
|
||||
fd_ = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void write(const fmt::memory_buffer &buf)
|
||||
{
|
||||
size_t msg_size = buf.size();
|
||||
auto data = buf.data();
|
||||
if (std::fwrite(data, 1, msg_size, fd_) != msg_size)
|
||||
{
|
||||
throw spdlog_ex("Failed writing to file " + os::filename_to_str(_filename), errno);
|
||||
}
|
||||
}
|
||||
|
||||
size_t size() const
|
||||
{
|
||||
if (fd_ == nullptr)
|
||||
{
|
||||
throw spdlog_ex("Cannot use size() on closed file " + os::filename_to_str(_filename));
|
||||
}
|
||||
return os::filesize(fd_);
|
||||
}
|
||||
|
||||
const filename_t &filename() const
|
||||
{
|
||||
return _filename;
|
||||
}
|
||||
|
||||
static bool file_exists(const filename_t &fname)
|
||||
{
|
||||
return os::file_exists(fname);
|
||||
}
|
||||
|
||||
//
|
||||
// return file path and its extension:
|
||||
//
|
||||
// "mylog.txt" => ("mylog", ".txt")
|
||||
// "mylog" => ("mylog", "")
|
||||
// "mylog." => ("mylog.", "")
|
||||
// "/dir1/dir2/mylog.txt" => ("/dir1/dir2/mylog", ".txt")
|
||||
//
|
||||
// the starting dot in filenames is ignored (hidden files):
|
||||
//
|
||||
// ".mylog" => (".mylog". "")
|
||||
// "my_folder/.mylog" => ("my_folder/.mylog", "")
|
||||
// "my_folder/.mylog.txt" => ("my_folder/.mylog", ".txt")
|
||||
static std::tuple<filename_t, filename_t> split_by_extension(const spdlog::filename_t &fname)
|
||||
{
|
||||
auto ext_index = fname.rfind('.');
|
||||
|
||||
// no valid extension found - return whole path and empty string as
|
||||
// extension
|
||||
if (ext_index == filename_t::npos || ext_index == 0 || ext_index == fname.size() - 1)
|
||||
{
|
||||
return std::make_tuple(fname, spdlog::filename_t());
|
||||
}
|
||||
|
||||
// treat casese like "/etc/rc.d/somelogfile or "/abc/.hiddenfile"
|
||||
auto folder_index = fname.rfind(details::os::folder_sep);
|
||||
if (folder_index != filename_t::npos && folder_index >= ext_index - 1)
|
||||
{
|
||||
return std::make_tuple(fname, spdlog::filename_t());
|
||||
}
|
||||
|
||||
// finally - return a valid base and extension tuple
|
||||
return std::make_tuple(fname.substr(0, ext_index), fname.substr(ext_index));
|
||||
}
|
||||
|
||||
private:
|
||||
std::FILE *fd_{nullptr};
|
||||
filename_t _filename;
|
||||
};
|
||||
} // namespace details
|
||||
} // namespace spdlog
|
122
include/Livox/third_party/spdlog/spdlog/details/fmt_helper.h
vendored
Executable file
122
include/Livox/third_party/spdlog/spdlog/details/fmt_helper.h
vendored
Executable file
@ -0,0 +1,122 @@
|
||||
//
|
||||
// Created by gabi on 6/15/18.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <chrono>
|
||||
#include <type_traits>
|
||||
#include "spdlog/fmt/fmt.h"
|
||||
|
||||
// Some fmt helpers to efficiently format and pad ints and strings
|
||||
namespace spdlog {
|
||||
namespace details {
|
||||
namespace fmt_helper {
|
||||
|
||||
template<size_t Buffer_Size>
|
||||
inline spdlog::string_view_t to_string_view(const fmt::basic_memory_buffer<char, Buffer_Size> &buf) SPDLOG_NOEXCEPT
|
||||
{
|
||||
return spdlog::string_view_t(buf.data(), buf.size());
|
||||
}
|
||||
|
||||
template<size_t Buffer_Size1, size_t Buffer_Size2>
|
||||
inline void append_buf(const fmt::basic_memory_buffer<char, Buffer_Size1> &buf, fmt::basic_memory_buffer<char, Buffer_Size2> &dest)
|
||||
{
|
||||
auto *buf_ptr = buf.data();
|
||||
dest.append(buf_ptr, buf_ptr + buf.size());
|
||||
}
|
||||
|
||||
template<size_t Buffer_Size>
|
||||
inline void append_string_view(spdlog::string_view_t view, fmt::basic_memory_buffer<char, Buffer_Size> &dest)
|
||||
{
|
||||
auto *buf_ptr = view.data();
|
||||
if (buf_ptr != nullptr)
|
||||
{
|
||||
dest.append(buf_ptr, buf_ptr + view.size());
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T, size_t Buffer_Size>
|
||||
inline void append_int(T n, fmt::basic_memory_buffer<char, Buffer_Size> &dest)
|
||||
{
|
||||
fmt::format_int i(n);
|
||||
dest.append(i.data(), i.data() + i.size());
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline unsigned count_digits(T n)
|
||||
{
|
||||
using count_type = typename std::conditional<(sizeof(T) > sizeof(uint32_t)), uint64_t, uint32_t>::type;
|
||||
return static_cast<unsigned>(fmt::internal::count_digits(static_cast<count_type>(n)));
|
||||
}
|
||||
|
||||
template<size_t Buffer_Size>
|
||||
inline void pad2(int n, fmt::basic_memory_buffer<char, Buffer_Size> &dest)
|
||||
{
|
||||
if (n > 99)
|
||||
{
|
||||
append_int(n, dest);
|
||||
}
|
||||
else if (n > 9) // 10-99
|
||||
{
|
||||
dest.push_back(static_cast<char>('0' + n / 10));
|
||||
dest.push_back(static_cast<char>('0' + n % 10));
|
||||
}
|
||||
else if (n >= 0) // 0-9
|
||||
{
|
||||
dest.push_back('0');
|
||||
dest.push_back(static_cast<char>('0' + n));
|
||||
}
|
||||
else // negatives (unlikely, but just in case, let fmt deal with it)
|
||||
{
|
||||
fmt::format_to(dest, "{:02}", n);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T, size_t Buffer_Size>
|
||||
inline void pad_uint(T n, unsigned int width, fmt::basic_memory_buffer<char, Buffer_Size> &dest)
|
||||
{
|
||||
static_assert(std::is_unsigned<T>::value, "pad_uint must get unsigned T");
|
||||
auto digits = count_digits(n);
|
||||
if (width > digits)
|
||||
{
|
||||
const char *zeroes = "0000000000000000000";
|
||||
dest.append(zeroes, zeroes + width - digits);
|
||||
}
|
||||
append_int(n, dest);
|
||||
}
|
||||
|
||||
template<typename T, size_t Buffer_Size>
|
||||
inline void pad3(T n, fmt::basic_memory_buffer<char, Buffer_Size> &dest)
|
||||
{
|
||||
pad_uint(n, 3, dest);
|
||||
}
|
||||
|
||||
template<typename T, size_t Buffer_Size>
|
||||
inline void pad6(T n, fmt::basic_memory_buffer<char, Buffer_Size> &dest)
|
||||
{
|
||||
pad_uint(n, 6, dest);
|
||||
}
|
||||
|
||||
template<typename T, size_t Buffer_Size>
|
||||
inline void pad9(T n, fmt::basic_memory_buffer<char, Buffer_Size> &dest)
|
||||
{
|
||||
pad_uint(n, 9, dest);
|
||||
}
|
||||
|
||||
// return fraction of a second of the given time_point.
|
||||
// e.g.
|
||||
// fraction<std::milliseconds>(tp) -> will return the millis part of the second
|
||||
template<typename ToDuration>
|
||||
inline ToDuration time_fraction(const log_clock::time_point &tp)
|
||||
{
|
||||
using std::chrono::duration_cast;
|
||||
using std::chrono::seconds;
|
||||
auto duration = tp.time_since_epoch();
|
||||
auto secs = duration_cast<seconds>(duration);
|
||||
return duration_cast<ToDuration>(duration) - duration_cast<ToDuration>(secs);
|
||||
}
|
||||
|
||||
} // namespace fmt_helper
|
||||
} // namespace details
|
||||
} // namespace spdlog
|
55
include/Livox/third_party/spdlog/spdlog/details/log_msg.h
vendored
Executable file
55
include/Livox/third_party/spdlog/spdlog/details/log_msg.h
vendored
Executable file
@ -0,0 +1,55 @@
|
||||
//
|
||||
// Copyright(c) 2015 Gabi Melman.
|
||||
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "spdlog/common.h"
|
||||
#include "spdlog/details/os.h"
|
||||
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
namespace spdlog {
|
||||
namespace details {
|
||||
struct log_msg
|
||||
{
|
||||
|
||||
log_msg(source_loc loc, const std::string *loggers_name, level::level_enum lvl, string_view_t view)
|
||||
: logger_name(loggers_name)
|
||||
, level(lvl)
|
||||
#ifndef SPDLOG_NO_DATETIME
|
||||
, time(os::now())
|
||||
#endif
|
||||
|
||||
#ifndef SPDLOG_NO_THREAD_ID
|
||||
, thread_id(os::thread_id())
|
||||
#endif
|
||||
, source(loc)
|
||||
, payload(view)
|
||||
{
|
||||
}
|
||||
|
||||
log_msg(const std::string *loggers_name, level::level_enum lvl, string_view_t view)
|
||||
: log_msg(source_loc{}, loggers_name, lvl, view)
|
||||
{
|
||||
}
|
||||
|
||||
log_msg(const log_msg &other) = default;
|
||||
|
||||
const std::string *logger_name{nullptr};
|
||||
level::level_enum level{level::off};
|
||||
log_clock::time_point time;
|
||||
size_t thread_id{0};
|
||||
size_t msg_id{0};
|
||||
|
||||
// wrapping the formatted text with color (updated by pattern_formatter).
|
||||
mutable size_t color_range_start{0};
|
||||
mutable size_t color_range_end{0};
|
||||
|
||||
source_loc source;
|
||||
const string_view_t payload;
|
||||
};
|
||||
} // namespace details
|
||||
} // namespace spdlog
|
435
include/Livox/third_party/spdlog/spdlog/details/logger_impl.h
vendored
Executable file
435
include/Livox/third_party/spdlog/spdlog/details/logger_impl.h
vendored
Executable file
@ -0,0 +1,435 @@
|
||||
//
|
||||
// Copyright(c) 2015 Gabi Melman.
|
||||
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "spdlog/details/fmt_helper.h"
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#define SPDLOG_CATCH_AND_HANDLE \
|
||||
catch (const std::exception &ex) \
|
||||
{ \
|
||||
err_handler_(ex.what()); \
|
||||
} \
|
||||
catch (...) \
|
||||
{ \
|
||||
err_handler_("Unknown exception in logger"); \
|
||||
}
|
||||
|
||||
// create logger with given name, sinks and the default pattern formatter
|
||||
// all other ctors will call this one
|
||||
template<typename It>
|
||||
inline spdlog::logger::logger(std::string logger_name, It begin, It end)
|
||||
: name_(std::move(logger_name))
|
||||
, sinks_(begin, end)
|
||||
{
|
||||
}
|
||||
|
||||
// ctor with sinks as init list
|
||||
inline spdlog::logger::logger(std::string logger_name, sinks_init_list sinks_list)
|
||||
: logger(std::move(logger_name), sinks_list.begin(), sinks_list.end())
|
||||
{
|
||||
}
|
||||
|
||||
// ctor with single sink
|
||||
inline spdlog::logger::logger(std::string logger_name, spdlog::sink_ptr single_sink)
|
||||
: logger(std::move(logger_name), {std::move(single_sink)})
|
||||
{
|
||||
}
|
||||
|
||||
inline spdlog::logger::~logger() = default;
|
||||
|
||||
inline void spdlog::logger::set_formatter(std::unique_ptr<spdlog::formatter> f)
|
||||
{
|
||||
for (auto &sink : sinks_)
|
||||
{
|
||||
sink->set_formatter(f->clone());
|
||||
}
|
||||
}
|
||||
|
||||
inline void spdlog::logger::set_pattern(std::string pattern, pattern_time_type time_type)
|
||||
{
|
||||
auto new_formatter = details::make_unique<spdlog::pattern_formatter>(std::move(pattern), time_type);
|
||||
set_formatter(std::move(new_formatter));
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
inline void spdlog::logger::log(source_loc source, level::level_enum lvl, const char *fmt, const Args &... args)
|
||||
{
|
||||
if (!should_log(lvl))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
using details::fmt_helper::to_string_view;
|
||||
fmt::memory_buffer buf;
|
||||
fmt::format_to(buf, fmt, args...);
|
||||
details::log_msg log_msg(source, &name_, lvl, to_string_view(buf));
|
||||
sink_it_(log_msg);
|
||||
}
|
||||
SPDLOG_CATCH_AND_HANDLE
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
inline void spdlog::logger::log(level::level_enum lvl, const char *fmt, const Args &... args)
|
||||
{
|
||||
log(source_loc{}, lvl, fmt, args...);
|
||||
}
|
||||
|
||||
inline void spdlog::logger::log(source_loc source, level::level_enum lvl, const char *msg)
|
||||
{
|
||||
if (!should_log(lvl))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
details::log_msg log_msg(source, &name_, lvl, spdlog::string_view_t(msg));
|
||||
sink_it_(log_msg);
|
||||
}
|
||||
SPDLOG_CATCH_AND_HANDLE
|
||||
}
|
||||
|
||||
inline void spdlog::logger::log(level::level_enum lvl, const char *msg)
|
||||
{
|
||||
log(source_loc{}, lvl, msg);
|
||||
}
|
||||
|
||||
template<class T>
|
||||
inline void spdlog::logger::log(level::level_enum lvl, const T &msg)
|
||||
{
|
||||
log(source_loc{}, lvl, msg);
|
||||
}
|
||||
|
||||
template<class T, typename std::enable_if<std::is_convertible<T, spdlog::string_view_t>::value, T>::type *>
|
||||
inline void spdlog::logger::log(source_loc source, level::level_enum lvl, const T &msg)
|
||||
{
|
||||
if (!should_log(lvl))
|
||||
{
|
||||
return;
|
||||
}
|
||||
try
|
||||
{
|
||||
details::log_msg log_msg(source, &name_, lvl, msg);
|
||||
sink_it_(log_msg);
|
||||
}
|
||||
SPDLOG_CATCH_AND_HANDLE
|
||||
}
|
||||
|
||||
template<class T, typename std::enable_if<!std::is_convertible<T, spdlog::string_view_t>::value, T>::type *>
|
||||
inline void spdlog::logger::log(source_loc source, level::level_enum lvl, const T &msg)
|
||||
{
|
||||
if (!should_log(lvl))
|
||||
{
|
||||
return;
|
||||
}
|
||||
try
|
||||
{
|
||||
using details::fmt_helper::to_string_view;
|
||||
fmt::memory_buffer buf;
|
||||
fmt::format_to(buf, "{}", msg);
|
||||
details::log_msg log_msg(source, &name_, lvl, to_string_view(buf));
|
||||
sink_it_(log_msg);
|
||||
}
|
||||
SPDLOG_CATCH_AND_HANDLE
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
inline void spdlog::logger::trace(const char *fmt, const Args &... args)
|
||||
{
|
||||
log(level::trace, fmt, args...);
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
inline void spdlog::logger::debug(const char *fmt, const Args &... args)
|
||||
{
|
||||
log(level::debug, fmt, args...);
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
inline void spdlog::logger::info(const char *fmt, const Args &... args)
|
||||
{
|
||||
log(level::info, fmt, args...);
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
inline void spdlog::logger::warn(const char *fmt, const Args &... args)
|
||||
{
|
||||
log(level::warn, fmt, args...);
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
inline void spdlog::logger::error(const char *fmt, const Args &... args)
|
||||
{
|
||||
log(level::err, fmt, args...);
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
inline void spdlog::logger::critical(const char *fmt, const Args &... args)
|
||||
{
|
||||
log(level::critical, fmt, args...);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline void spdlog::logger::trace(const T &msg)
|
||||
{
|
||||
log(level::trace, msg);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline void spdlog::logger::debug(const T &msg)
|
||||
{
|
||||
log(level::debug, msg);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline void spdlog::logger::info(const T &msg)
|
||||
{
|
||||
log(level::info, msg);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline void spdlog::logger::warn(const T &msg)
|
||||
{
|
||||
log(level::warn, msg);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline void spdlog::logger::error(const T &msg)
|
||||
{
|
||||
log(level::err, msg);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline void spdlog::logger::critical(const T &msg)
|
||||
{
|
||||
log(level::critical, msg);
|
||||
}
|
||||
|
||||
#ifdef SPDLOG_WCHAR_TO_UTF8_SUPPORT
|
||||
|
||||
inline void wbuf_to_utf8buf(const fmt::wmemory_buffer &wbuf, fmt::memory_buffer &target)
|
||||
{
|
||||
int wbuf_size = static_cast<int>(wbuf.size());
|
||||
if (wbuf_size == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
auto result_size = ::WideCharToMultiByte(CP_UTF8, 0, wbuf.data(), wbuf_size, NULL, 0, NULL, NULL);
|
||||
|
||||
if (result_size > 0)
|
||||
{
|
||||
target.resize(result_size);
|
||||
::WideCharToMultiByte(CP_UTF8, 0, wbuf.data(), wbuf_size, &target.data()[0], result_size, NULL, NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw spdlog::spdlog_ex(fmt::format("WideCharToMultiByte failed. Last error: {}", ::GetLastError()));
|
||||
}
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
inline void spdlog::logger::log(source_loc source, level::level_enum lvl, const wchar_t *fmt, const Args &... args)
|
||||
{
|
||||
if (!should_log(lvl))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
// format to wmemory_buffer and convert to utf8
|
||||
using details::fmt_helper::to_string_view;
|
||||
fmt::wmemory_buffer wbuf;
|
||||
fmt::format_to(wbuf, fmt, args...);
|
||||
fmt::memory_buffer buf;
|
||||
wbuf_to_utf8buf(wbuf, buf);
|
||||
details::log_msg log_msg(source, &name_, lvl, to_string_view(buf));
|
||||
sink_it_(log_msg);
|
||||
}
|
||||
SPDLOG_CATCH_AND_HANDLE
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
inline void spdlog::logger::log(level::level_enum lvl, const wchar_t *fmt, const Args &... args)
|
||||
{
|
||||
log(source_loc{}, lvl, fmt, args...);
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
inline void spdlog::logger::trace(const wchar_t *fmt, const Args &... args)
|
||||
{
|
||||
log(level::trace, fmt, args...);
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
inline void spdlog::logger::debug(const wchar_t *fmt, const Args &... args)
|
||||
{
|
||||
log(level::debug, fmt, args...);
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
inline void spdlog::logger::info(const wchar_t *fmt, const Args &... args)
|
||||
{
|
||||
log(level::info, fmt, args...);
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
inline void spdlog::logger::warn(const wchar_t *fmt, const Args &... args)
|
||||
{
|
||||
log(level::warn, fmt, args...);
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
inline void spdlog::logger::error(const wchar_t *fmt, const Args &... args)
|
||||
{
|
||||
log(level::err, fmt, args...);
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
inline void spdlog::logger::critical(const wchar_t *fmt, const Args &... args)
|
||||
{
|
||||
log(level::critical, fmt, args...);
|
||||
}
|
||||
|
||||
#endif // SPDLOG_WCHAR_TO_UTF8_SUPPORT
|
||||
|
||||
//
|
||||
// name and level
|
||||
//
|
||||
inline const std::string &spdlog::logger::name() const
|
||||
{
|
||||
return name_;
|
||||
}
|
||||
|
||||
inline void spdlog::logger::set_level(spdlog::level::level_enum log_level)
|
||||
{
|
||||
level_.store(log_level);
|
||||
}
|
||||
|
||||
inline void spdlog::logger::set_error_handler(spdlog::log_err_handler err_handler)
|
||||
{
|
||||
err_handler_ = std::move(err_handler);
|
||||
}
|
||||
|
||||
inline spdlog::log_err_handler spdlog::logger::error_handler() const
|
||||
{
|
||||
return err_handler_;
|
||||
}
|
||||
|
||||
inline void spdlog::logger::flush()
|
||||
{
|
||||
try
|
||||
{
|
||||
flush_();
|
||||
}
|
||||
SPDLOG_CATCH_AND_HANDLE
|
||||
}
|
||||
|
||||
inline void spdlog::logger::flush_on(level::level_enum log_level)
|
||||
{
|
||||
flush_level_.store(log_level);
|
||||
}
|
||||
|
||||
inline spdlog::level::level_enum spdlog::logger::flush_level() const
|
||||
{
|
||||
return static_cast<spdlog::level::level_enum>(flush_level_.load(std::memory_order_relaxed));
|
||||
}
|
||||
|
||||
inline bool spdlog::logger::should_flush_(const details::log_msg &msg)
|
||||
{
|
||||
auto flush_level = flush_level_.load(std::memory_order_relaxed);
|
||||
return (msg.level >= flush_level) && (msg.level != level::off);
|
||||
}
|
||||
|
||||
inline spdlog::level::level_enum spdlog::logger::default_level()
|
||||
{
|
||||
return static_cast<spdlog::level::level_enum>(SPDLOG_ACTIVE_LEVEL);
|
||||
}
|
||||
|
||||
inline spdlog::level::level_enum spdlog::logger::level() const
|
||||
{
|
||||
return static_cast<spdlog::level::level_enum>(level_.load(std::memory_order_relaxed));
|
||||
}
|
||||
|
||||
inline bool spdlog::logger::should_log(spdlog::level::level_enum msg_level) const
|
||||
{
|
||||
return msg_level >= level_.load(std::memory_order_relaxed);
|
||||
}
|
||||
|
||||
//
|
||||
// protected virtual called at end of each user log call (if enabled) by the
|
||||
// line_logger
|
||||
//
|
||||
inline void spdlog::logger::sink_it_(details::log_msg &msg)
|
||||
{
|
||||
#if defined(SPDLOG_ENABLE_MESSAGE_COUNTER)
|
||||
incr_msg_counter_(msg);
|
||||
#endif
|
||||
for (auto &sink : sinks_)
|
||||
{
|
||||
if (sink->should_log(msg.level))
|
||||
{
|
||||
sink->log(msg);
|
||||
}
|
||||
}
|
||||
|
||||
if (should_flush_(msg))
|
||||
{
|
||||
flush_();
|
||||
}
|
||||
}
|
||||
|
||||
inline void spdlog::logger::flush_()
|
||||
{
|
||||
for (auto &sink : sinks_)
|
||||
{
|
||||
sink->flush();
|
||||
}
|
||||
}
|
||||
|
||||
inline void spdlog::logger::default_err_handler_(const std::string &msg)
|
||||
{
|
||||
auto now = time(nullptr);
|
||||
if (now - last_err_time_ < 60)
|
||||
{
|
||||
return;
|
||||
}
|
||||
last_err_time_ = now;
|
||||
auto tm_time = details::os::localtime(now);
|
||||
char date_buf[100];
|
||||
std::strftime(date_buf, sizeof(date_buf), "%Y-%m-%d %H:%M:%S", &tm_time);
|
||||
fmt::print(stderr, "[*** LOG ERROR ***] [{}] [{}] {}\n", date_buf, name(), msg);
|
||||
}
|
||||
|
||||
inline void spdlog::logger::incr_msg_counter_(details::log_msg &msg)
|
||||
{
|
||||
msg.msg_id = msg_counter_.fetch_add(1, std::memory_order_relaxed);
|
||||
}
|
||||
|
||||
inline const std::vector<spdlog::sink_ptr> &spdlog::logger::sinks() const
|
||||
{
|
||||
return sinks_;
|
||||
}
|
||||
|
||||
inline std::vector<spdlog::sink_ptr> &spdlog::logger::sinks()
|
||||
{
|
||||
return sinks_;
|
||||
}
|
||||
|
||||
inline std::shared_ptr<spdlog::logger> spdlog::logger::clone(std::string logger_name)
|
||||
{
|
||||
auto cloned = std::make_shared<spdlog::logger>(std::move(logger_name), sinks_.begin(), sinks_.end());
|
||||
cloned->set_level(this->level());
|
||||
cloned->flush_on(this->flush_level());
|
||||
cloned->set_error_handler(this->error_handler());
|
||||
return cloned;
|
||||
}
|
121
include/Livox/third_party/spdlog/spdlog/details/mpmc_blocking_q.h
vendored
Executable file
121
include/Livox/third_party/spdlog/spdlog/details/mpmc_blocking_q.h
vendored
Executable file
@ -0,0 +1,121 @@
|
||||
#pragma once
|
||||
|
||||
//
|
||||
// Copyright(c) 2018 Gabi Melman.
|
||||
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
||||
//
|
||||
|
||||
// multi producer-multi consumer blocking queue.
|
||||
// enqueue(..) - will block until room found to put the new message.
|
||||
// enqueue_nowait(..) - will return immediately with false if no room left in
|
||||
// the queue.
|
||||
// dequeue_for(..) - will block until the queue is not empty or timeout have
|
||||
// passed.
|
||||
|
||||
#include "spdlog/details/circular_q.h"
|
||||
|
||||
#include <condition_variable>
|
||||
#include <mutex>
|
||||
|
||||
namespace spdlog {
|
||||
namespace details {
|
||||
|
||||
template<typename T>
|
||||
class mpmc_blocking_queue
|
||||
{
|
||||
public:
|
||||
using item_type = T;
|
||||
explicit mpmc_blocking_queue(size_t max_items)
|
||||
: q_(max_items)
|
||||
{
|
||||
}
|
||||
|
||||
#ifndef __MINGW32__
|
||||
// try to enqueue and block if no room left
|
||||
void enqueue(T &&item)
|
||||
{
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(queue_mutex_);
|
||||
pop_cv_.wait(lock, [this] { return !this->q_.full(); });
|
||||
q_.push_back(std::move(item));
|
||||
}
|
||||
push_cv_.notify_one();
|
||||
}
|
||||
|
||||
// enqueue immediately. overrun oldest message in the queue if no room left.
|
||||
void enqueue_nowait(T &&item)
|
||||
{
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(queue_mutex_);
|
||||
q_.push_back(std::move(item));
|
||||
}
|
||||
push_cv_.notify_one();
|
||||
}
|
||||
|
||||
// try to dequeue item. if no item found. wait upto timeout and try again
|
||||
// Return true, if succeeded dequeue item, false otherwise
|
||||
bool dequeue_for(T &popped_item, std::chrono::milliseconds wait_duration)
|
||||
{
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(queue_mutex_);
|
||||
if (!push_cv_.wait_for(lock, wait_duration, [this] { return !this->q_.empty(); }))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
q_.pop_front(popped_item);
|
||||
}
|
||||
pop_cv_.notify_one();
|
||||
return true;
|
||||
}
|
||||
|
||||
#else
|
||||
// apparently mingw deadlocks if the mutex is released before cv.notify_one(),
|
||||
// so release the mutex at the very end each function.
|
||||
|
||||
// try to enqueue and block if no room left
|
||||
void enqueue(T &&item)
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(queue_mutex_);
|
||||
pop_cv_.wait(lock, [this] { return !this->q_.full(); });
|
||||
q_.push_back(std::move(item));
|
||||
push_cv_.notify_one();
|
||||
}
|
||||
|
||||
// enqueue immediately. overrun oldest message in the queue if no room left.
|
||||
void enqueue_nowait(T &&item)
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(queue_mutex_);
|
||||
q_.push_back(std::move(item));
|
||||
push_cv_.notify_one();
|
||||
}
|
||||
|
||||
// try to dequeue item. if no item found. wait upto timeout and try again
|
||||
// Return true, if succeeded dequeue item, false otherwise
|
||||
bool dequeue_for(T &popped_item, std::chrono::milliseconds wait_duration)
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(queue_mutex_);
|
||||
if (!push_cv_.wait_for(lock, wait_duration, [this] { return !this->q_.empty(); }))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
q_.pop_front(popped_item);
|
||||
pop_cv_.notify_one();
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
size_t overrun_counter()
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(queue_mutex_);
|
||||
return q_.overrun_counter();
|
||||
}
|
||||
|
||||
private:
|
||||
std::mutex queue_mutex_;
|
||||
std::condition_variable push_cv_;
|
||||
std::condition_variable pop_cv_;
|
||||
spdlog::details::circular_q<T> q_;
|
||||
};
|
||||
} // namespace details
|
||||
} // namespace spdlog
|
45
include/Livox/third_party/spdlog/spdlog/details/null_mutex.h
vendored
Executable file
45
include/Livox/third_party/spdlog/spdlog/details/null_mutex.h
vendored
Executable file
@ -0,0 +1,45 @@
|
||||
//
|
||||
// Copyright(c) 2015 Gabi Melman.
|
||||
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <atomic>
|
||||
// null, no cost dummy "mutex" and dummy "atomic" int
|
||||
|
||||
namespace spdlog {
|
||||
namespace details {
|
||||
struct null_mutex
|
||||
{
|
||||
void lock() {}
|
||||
void unlock() {}
|
||||
bool try_lock()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
struct null_atomic_int
|
||||
{
|
||||
int value;
|
||||
null_atomic_int() = default;
|
||||
|
||||
explicit null_atomic_int(int val)
|
||||
: value(val)
|
||||
{
|
||||
}
|
||||
|
||||
int load(std::memory_order) const
|
||||
{
|
||||
return value;
|
||||
}
|
||||
|
||||
void store(int val)
|
||||
{
|
||||
value = val;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace details
|
||||
} // namespace spdlog
|
421
include/Livox/third_party/spdlog/spdlog/details/os.h
vendored
Executable file
421
include/Livox/third_party/spdlog/spdlog/details/os.h
vendored
Executable file
@ -0,0 +1,421 @@
|
||||
//
|
||||
// Copyright(c) 2015 Gabi Melman.
|
||||
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
||||
//
|
||||
#pragma once
|
||||
|
||||
#include "../common.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <chrono>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <ctime>
|
||||
#include <functional>
|
||||
#include <string>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <thread>
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
#ifndef NOMINMAX
|
||||
#define NOMINMAX // prevent windows redefining min/max
|
||||
#endif
|
||||
|
||||
#ifndef WIN32_LEAN_AND_MEAN
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#endif
|
||||
#include <io.h> // _get_osfhandle and _isatty support
|
||||
#include <process.h> // _get_pid support
|
||||
#include <windows.h>
|
||||
|
||||
#ifdef __MINGW32__
|
||||
#include <share.h>
|
||||
#endif
|
||||
|
||||
#else // unix
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#ifdef __linux__
|
||||
#include <sys/syscall.h> //Use gettid() syscall under linux to get thread id
|
||||
|
||||
#elif __FreeBSD__
|
||||
#include <sys/thr.h> //Use thr_self() syscall under FreeBSD to get thread id
|
||||
#endif
|
||||
|
||||
#endif // unix
|
||||
|
||||
#ifndef __has_feature // Clang - feature checking macros.
|
||||
#define __has_feature(x) 0 // Compatibility with non-clang compilers.
|
||||
#endif
|
||||
|
||||
namespace spdlog {
|
||||
namespace details {
|
||||
namespace os {
|
||||
|
||||
inline spdlog::log_clock::time_point now() SPDLOG_NOEXCEPT
|
||||
{
|
||||
|
||||
#if defined __linux__ && defined SPDLOG_CLOCK_COARSE
|
||||
timespec ts;
|
||||
::clock_gettime(CLOCK_REALTIME_COARSE, &ts);
|
||||
return std::chrono::time_point<log_clock, typename log_clock::duration>(
|
||||
std::chrono::duration_cast<typename log_clock::duration>(std::chrono::seconds(ts.tv_sec) + std::chrono::nanoseconds(ts.tv_nsec)));
|
||||
|
||||
#else
|
||||
return log_clock::now();
|
||||
#endif
|
||||
}
|
||||
inline std::tm localtime(const std::time_t &time_tt) SPDLOG_NOEXCEPT
|
||||
{
|
||||
|
||||
#ifdef _WIN32
|
||||
std::tm tm;
|
||||
localtime_s(&tm, &time_tt);
|
||||
#else
|
||||
std::tm tm;
|
||||
localtime_r(&time_tt, &tm);
|
||||
#endif
|
||||
return tm;
|
||||
}
|
||||
|
||||
inline std::tm localtime() SPDLOG_NOEXCEPT
|
||||
{
|
||||
std::time_t now_t = time(nullptr);
|
||||
return localtime(now_t);
|
||||
}
|
||||
|
||||
inline std::tm gmtime(const std::time_t &time_tt) SPDLOG_NOEXCEPT
|
||||
{
|
||||
|
||||
#ifdef _WIN32
|
||||
std::tm tm;
|
||||
gmtime_s(&tm, &time_tt);
|
||||
#else
|
||||
std::tm tm;
|
||||
gmtime_r(&time_tt, &tm);
|
||||
#endif
|
||||
return tm;
|
||||
}
|
||||
|
||||
inline std::tm gmtime() SPDLOG_NOEXCEPT
|
||||
{
|
||||
std::time_t now_t = time(nullptr);
|
||||
return gmtime(now_t);
|
||||
}
|
||||
|
||||
// eol definition
|
||||
#if !defined(SPDLOG_EOL)
|
||||
#ifdef _WIN32
|
||||
#define SPDLOG_EOL "\r\n"
|
||||
#else
|
||||
#define SPDLOG_EOL "\n"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
SPDLOG_CONSTEXPR static const char *default_eol = SPDLOG_EOL;
|
||||
|
||||
// folder separator
|
||||
#ifdef _WIN32
|
||||
SPDLOG_CONSTEXPR static const char folder_sep = '\\';
|
||||
#else
|
||||
SPDLOG_CONSTEXPR static const char folder_sep = '/';
|
||||
#endif
|
||||
|
||||
inline void prevent_child_fd(FILE *f)
|
||||
{
|
||||
|
||||
#ifdef _WIN32
|
||||
#if !defined(__cplusplus_winrt)
|
||||
auto file_handle = (HANDLE)_get_osfhandle(_fileno(f));
|
||||
if (!::SetHandleInformation(file_handle, HANDLE_FLAG_INHERIT, 0))
|
||||
throw spdlog_ex("SetHandleInformation failed", errno);
|
||||
#endif
|
||||
#else
|
||||
auto fd = fileno(f);
|
||||
if (fcntl(fd, F_SETFD, FD_CLOEXEC) == -1)
|
||||
{
|
||||
throw spdlog_ex("fcntl with FD_CLOEXEC failed", errno);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// fopen_s on non windows for writing
|
||||
inline bool fopen_s(FILE **fp, const filename_t &filename, const filename_t &mode)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
#ifdef SPDLOG_WCHAR_FILENAMES
|
||||
*fp = _wfsopen((filename.c_str()), mode.c_str(), _SH_DENYNO);
|
||||
#else
|
||||
*fp = _fsopen((filename.c_str()), mode.c_str(), _SH_DENYNO);
|
||||
#endif
|
||||
#else // unix
|
||||
*fp = fopen((filename.c_str()), mode.c_str());
|
||||
#endif
|
||||
|
||||
#ifdef SPDLOG_PREVENT_CHILD_FD
|
||||
if (*fp != nullptr)
|
||||
{
|
||||
prevent_child_fd(*fp);
|
||||
}
|
||||
#endif
|
||||
return *fp == nullptr;
|
||||
}
|
||||
|
||||
inline int remove(const filename_t &filename) SPDLOG_NOEXCEPT
|
||||
{
|
||||
#if defined(_WIN32) && defined(SPDLOG_WCHAR_FILENAMES)
|
||||
return _wremove(filename.c_str());
|
||||
#else
|
||||
return std::remove(filename.c_str());
|
||||
#endif
|
||||
}
|
||||
|
||||
inline int rename(const filename_t &filename1, const filename_t &filename2) SPDLOG_NOEXCEPT
|
||||
{
|
||||
#if defined(_WIN32) && defined(SPDLOG_WCHAR_FILENAMES)
|
||||
return _wrename(filename1.c_str(), filename2.c_str());
|
||||
#else
|
||||
return std::rename(filename1.c_str(), filename2.c_str());
|
||||
#endif
|
||||
}
|
||||
|
||||
// Return if file exists
|
||||
inline bool file_exists(const filename_t &filename) SPDLOG_NOEXCEPT
|
||||
{
|
||||
#ifdef _WIN32
|
||||
#ifdef SPDLOG_WCHAR_FILENAMES
|
||||
auto attribs = GetFileAttributesW(filename.c_str());
|
||||
#else
|
||||
auto attribs = GetFileAttributesA(filename.c_str());
|
||||
#endif
|
||||
return (attribs != INVALID_FILE_ATTRIBUTES && !(attribs & FILE_ATTRIBUTE_DIRECTORY));
|
||||
#else // common linux/unix all have the stat system call
|
||||
struct stat buffer;
|
||||
return (stat(filename.c_str(), &buffer) == 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
// Return file size according to open FILE* object
|
||||
inline size_t filesize(FILE *f)
|
||||
{
|
||||
if (f == nullptr)
|
||||
{
|
||||
throw spdlog_ex("Failed getting file size. fd is null");
|
||||
}
|
||||
#if defined(_WIN32) && !defined(__CYGWIN__)
|
||||
int fd = _fileno(f);
|
||||
#if _WIN64 // 64 bits
|
||||
__int64 ret = _filelengthi64(fd);
|
||||
if (ret >= 0)
|
||||
{
|
||||
return static_cast<size_t>(ret);
|
||||
}
|
||||
|
||||
#else // windows 32 bits
|
||||
long ret = _filelength(fd);
|
||||
if (ret >= 0)
|
||||
{
|
||||
return static_cast<size_t>(ret);
|
||||
}
|
||||
#endif
|
||||
|
||||
#else // unix
|
||||
int fd = fileno(f);
|
||||
// 64 bits(but not in osx or cygwin, where fstat64 is deprecated)
|
||||
#if !defined(__FreeBSD__) && !defined(__APPLE__) && (defined(__x86_64__) || defined(__ppc64__)) && !defined(__CYGWIN__)
|
||||
struct stat64 st;
|
||||
if (fstat64(fd, &st) == 0)
|
||||
{
|
||||
return static_cast<size_t>(st.st_size);
|
||||
}
|
||||
#else // unix 32 bits or cygwin
|
||||
struct stat st;
|
||||
|
||||
if (fstat(fd, &st) == 0)
|
||||
{
|
||||
return static_cast<size_t>(st.st_size);
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
throw spdlog_ex("Failed getting file size from fd", errno);
|
||||
}
|
||||
|
||||
// Return utc offset in minutes or throw spdlog_ex on failure
|
||||
inline int utc_minutes_offset(const std::tm &tm = details::os::localtime())
|
||||
{
|
||||
|
||||
#ifdef _WIN32
|
||||
#if _WIN32_WINNT < _WIN32_WINNT_WS08
|
||||
TIME_ZONE_INFORMATION tzinfo;
|
||||
auto rv = GetTimeZoneInformation(&tzinfo);
|
||||
#else
|
||||
DYNAMIC_TIME_ZONE_INFORMATION tzinfo;
|
||||
auto rv = GetDynamicTimeZoneInformation(&tzinfo);
|
||||
#endif
|
||||
if (rv == TIME_ZONE_ID_INVALID)
|
||||
throw spdlog::spdlog_ex("Failed getting timezone info. ", errno);
|
||||
|
||||
int offset = -tzinfo.Bias;
|
||||
if (tm.tm_isdst)
|
||||
{
|
||||
offset -= tzinfo.DaylightBias;
|
||||
}
|
||||
else
|
||||
{
|
||||
offset -= tzinfo.StandardBias;
|
||||
}
|
||||
return offset;
|
||||
#else
|
||||
|
||||
#if defined(sun) || defined(__sun) || defined(_AIX)
|
||||
// 'tm_gmtoff' field is BSD extension and it's missing on SunOS/Solaris
|
||||
struct helper
|
||||
{
|
||||
static long int calculate_gmt_offset(const std::tm &localtm = details::os::localtime(), const std::tm &gmtm = details::os::gmtime())
|
||||
{
|
||||
int local_year = localtm.tm_year + (1900 - 1);
|
||||
int gmt_year = gmtm.tm_year + (1900 - 1);
|
||||
|
||||
long int days = (
|
||||
// difference in day of year
|
||||
localtm.tm_yday -
|
||||
gmtm.tm_yday
|
||||
|
||||
// + intervening leap days
|
||||
+ ((local_year >> 2) - (gmt_year >> 2)) - (local_year / 100 - gmt_year / 100) +
|
||||
((local_year / 100 >> 2) - (gmt_year / 100 >> 2))
|
||||
|
||||
// + difference in years * 365 */
|
||||
+ (long int)(local_year - gmt_year) * 365);
|
||||
|
||||
long int hours = (24 * days) + (localtm.tm_hour - gmtm.tm_hour);
|
||||
long int mins = (60 * hours) + (localtm.tm_min - gmtm.tm_min);
|
||||
long int secs = (60 * mins) + (localtm.tm_sec - gmtm.tm_sec);
|
||||
|
||||
return secs;
|
||||
}
|
||||
};
|
||||
|
||||
auto offset_seconds = helper::calculate_gmt_offset(tm);
|
||||
#else
|
||||
auto offset_seconds = tm.tm_gmtoff;
|
||||
#endif
|
||||
|
||||
return static_cast<int>(offset_seconds / 60);
|
||||
#endif
|
||||
}
|
||||
|
||||
// Return current thread id as size_t
|
||||
// It exists because the std::this_thread::get_id() is much slower(especially
|
||||
// under VS 2013)
|
||||
inline size_t _thread_id() SPDLOG_NOEXCEPT
|
||||
{
|
||||
#ifdef _WIN32
|
||||
return static_cast<size_t>(::GetCurrentThreadId());
|
||||
#elif __linux__
|
||||
#if defined(__ANDROID__) && defined(__ANDROID_API__) && (__ANDROID_API__ < 21)
|
||||
#define SYS_gettid __NR_gettid
|
||||
#endif
|
||||
return static_cast<size_t>(syscall(SYS_gettid));
|
||||
#elif __FreeBSD__
|
||||
long tid;
|
||||
thr_self(&tid);
|
||||
return static_cast<size_t>(tid);
|
||||
#elif __APPLE__
|
||||
uint64_t tid;
|
||||
pthread_threadid_np(nullptr, &tid);
|
||||
return static_cast<size_t>(tid);
|
||||
#else // Default to standard C++11 (other Unix)
|
||||
return static_cast<size_t>(std::hash<std::thread::id>()(std::this_thread::get_id()));
|
||||
#endif
|
||||
}
|
||||
|
||||
// Return current thread id as size_t (from thread local storage)
|
||||
inline size_t thread_id() SPDLOG_NOEXCEPT
|
||||
{
|
||||
#if defined(SPDLOG_NO_TLS)
|
||||
return _thread_id();
|
||||
#else // cache thread id in tls
|
||||
static thread_local const size_t tid = _thread_id();
|
||||
return tid;
|
||||
#endif
|
||||
}
|
||||
|
||||
// This is avoid msvc issue in sleep_for that happens if the clock changes.
|
||||
// See https://github.com/gabime/spdlog/issues/609
|
||||
inline void sleep_for_millis(int milliseconds) SPDLOG_NOEXCEPT
|
||||
{
|
||||
#if defined(_WIN32)
|
||||
::Sleep(milliseconds);
|
||||
#else
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(milliseconds));
|
||||
#endif
|
||||
}
|
||||
|
||||
// wchar support for windows file names (SPDLOG_WCHAR_FILENAMES must be defined)
|
||||
#if defined(_WIN32) && defined(SPDLOG_WCHAR_FILENAMES)
|
||||
#define SPDLOG_FILENAME_T(s) L##s
|
||||
inline std::string filename_to_str(const filename_t &filename)
|
||||
{
|
||||
std::wstring_convert<std::codecvt_utf8<wchar_t>, wchar_t> c;
|
||||
return c.to_bytes(filename);
|
||||
}
|
||||
#else
|
||||
#define SPDLOG_FILENAME_T(s) s
|
||||
inline std::string filename_to_str(const filename_t &filename)
|
||||
{
|
||||
return filename;
|
||||
}
|
||||
#endif
|
||||
|
||||
inline int pid()
|
||||
{
|
||||
|
||||
#ifdef _WIN32
|
||||
return static_cast<int>(::GetCurrentProcessId());
|
||||
#else
|
||||
return static_cast<int>(::getpid());
|
||||
#endif
|
||||
}
|
||||
|
||||
// Determine if the terminal supports colors
|
||||
// Source: https://github.com/agauniyal/rang/
|
||||
inline bool is_color_terminal() SPDLOG_NOEXCEPT
|
||||
{
|
||||
#ifdef _WIN32
|
||||
return true;
|
||||
#else
|
||||
static constexpr const char *Terms[] = {
|
||||
"ansi", "color", "console", "cygwin", "gnome", "konsole", "kterm", "linux", "msys", "putty", "rxvt", "screen", "vt100", "xterm"};
|
||||
|
||||
const char *env_p = std::getenv("TERM");
|
||||
if (env_p == nullptr)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
static const bool result =
|
||||
std::any_of(std::begin(Terms), std::end(Terms), [&](const char *term) { return std::strstr(env_p, term) != nullptr; });
|
||||
return result;
|
||||
#endif
|
||||
}
|
||||
|
||||
// Detrmine if the terminal attached
|
||||
// Source: https://github.com/agauniyal/rang/
|
||||
inline bool in_terminal(FILE *file) SPDLOG_NOEXCEPT
|
||||
{
|
||||
|
||||
#ifdef _WIN32
|
||||
return _isatty(_fileno(file)) != 0;
|
||||
#else
|
||||
return isatty(fileno(file)) != 0;
|
||||
#endif
|
||||
}
|
||||
} // namespace os
|
||||
} // namespace details
|
||||
} // namespace spdlog
|
1336
include/Livox/third_party/spdlog/spdlog/details/pattern_formatter.h
vendored
Executable file
1336
include/Livox/third_party/spdlog/spdlog/details/pattern_formatter.h
vendored
Executable file
File diff suppressed because it is too large
Load Diff
71
include/Livox/third_party/spdlog/spdlog/details/periodic_worker.h
vendored
Executable file
71
include/Livox/third_party/spdlog/spdlog/details/periodic_worker.h
vendored
Executable file
@ -0,0 +1,71 @@
|
||||
|
||||
//
|
||||
// Copyright(c) 2018 Gabi Melman.
|
||||
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
// periodic worker thread - periodically executes the given callback function.
|
||||
//
|
||||
// RAII over the owned thread:
|
||||
// creates the thread on construction.
|
||||
// stops and joins the thread on destruction (if the thread is executing a callback, wait for it to finish first).
|
||||
|
||||
#include <chrono>
|
||||
#include <condition_variable>
|
||||
#include <functional>
|
||||
#include <mutex>
|
||||
#include <thread>
|
||||
namespace spdlog {
|
||||
namespace details {
|
||||
|
||||
class periodic_worker
|
||||
{
|
||||
public:
|
||||
periodic_worker(const std::function<void()> &callback_fun, std::chrono::seconds interval)
|
||||
{
|
||||
active_ = (interval > std::chrono::seconds::zero());
|
||||
if (!active_)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
worker_thread_ = std::thread([this, callback_fun, interval]() {
|
||||
for (;;)
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(this->mutex_);
|
||||
if (this->cv_.wait_for(lock, interval, [this] { return !this->active_; }))
|
||||
{
|
||||
return; // active_ == false, so exit this thread
|
||||
}
|
||||
callback_fun();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
periodic_worker(const periodic_worker &) = delete;
|
||||
periodic_worker &operator=(const periodic_worker &) = delete;
|
||||
|
||||
// stop the worker thread and join it
|
||||
~periodic_worker()
|
||||
{
|
||||
if (worker_thread_.joinable())
|
||||
{
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
active_ = false;
|
||||
}
|
||||
cv_.notify_one();
|
||||
worker_thread_.join();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
bool active_;
|
||||
std::thread worker_thread_;
|
||||
std::mutex mutex_;
|
||||
std::condition_variable cv_;
|
||||
};
|
||||
} // namespace details
|
||||
} // namespace spdlog
|
285
include/Livox/third_party/spdlog/spdlog/details/registry.h
vendored
Executable file
285
include/Livox/third_party/spdlog/spdlog/details/registry.h
vendored
Executable file
@ -0,0 +1,285 @@
|
||||
//
|
||||
// Copyright(c) 2015 Gabi Melman.
|
||||
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
// Loggers registy of unique name->logger pointer
|
||||
// An attempt to create a logger with an already existing name will be ignored
|
||||
// If user requests a non existing logger, nullptr will be returned
|
||||
// This class is thread safe
|
||||
|
||||
#include "spdlog/common.h"
|
||||
#include "spdlog/details/periodic_worker.h"
|
||||
#include "spdlog/logger.h"
|
||||
|
||||
#ifndef SPDLOG_DISABLE_DEFAULT_LOGGER
|
||||
// support for the default stdout color logger
|
||||
#ifdef _WIN32
|
||||
#include "spdlog/sinks/wincolor_sink.h"
|
||||
#else
|
||||
#include "spdlog/sinks/ansicolor_sink.h"
|
||||
#endif
|
||||
#endif // SPDLOG_DISABLE_DEFAULT_LOGGER
|
||||
|
||||
#include <chrono>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
|
||||
namespace spdlog {
|
||||
namespace details {
|
||||
class thread_pool;
|
||||
|
||||
class registry
|
||||
{
|
||||
public:
|
||||
registry(const registry &) = delete;
|
||||
registry &operator=(const registry &) = delete;
|
||||
|
||||
void register_logger(std::shared_ptr<logger> new_logger)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(logger_map_mutex_);
|
||||
register_logger_(std::move(new_logger));
|
||||
}
|
||||
|
||||
void initialize_logger(std::shared_ptr<logger> new_logger)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(logger_map_mutex_);
|
||||
new_logger->set_formatter(formatter_->clone());
|
||||
|
||||
if (err_handler_)
|
||||
{
|
||||
new_logger->set_error_handler(err_handler_);
|
||||
}
|
||||
|
||||
new_logger->set_level(level_);
|
||||
new_logger->flush_on(flush_level_);
|
||||
|
||||
if (automatic_registration_)
|
||||
{
|
||||
register_logger_(std::move(new_logger));
|
||||
}
|
||||
}
|
||||
|
||||
std::shared_ptr<logger> get(const std::string &logger_name)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(logger_map_mutex_);
|
||||
auto found = loggers_.find(logger_name);
|
||||
return found == loggers_.end() ? nullptr : found->second;
|
||||
}
|
||||
|
||||
std::shared_ptr<logger> default_logger()
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(logger_map_mutex_);
|
||||
return default_logger_;
|
||||
}
|
||||
|
||||
// Return raw ptr to the default logger.
|
||||
// To be used directly by the spdlog default api (e.g. spdlog::info)
|
||||
// This make the default API faster, but cannot be used concurrently with set_default_logger().
|
||||
// e.g do not call set_default_logger() from one thread while calling spdlog::info() from another.
|
||||
logger *get_default_raw()
|
||||
{
|
||||
return default_logger_.get();
|
||||
}
|
||||
|
||||
// set default logger.
|
||||
// default logger is stored in default_logger_ (for faster retrieval) and in the loggers_ map.
|
||||
void set_default_logger(std::shared_ptr<logger> new_default_logger)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(logger_map_mutex_);
|
||||
// remove previous default logger from the map
|
||||
if (default_logger_ != nullptr)
|
||||
{
|
||||
loggers_.erase(default_logger_->name());
|
||||
}
|
||||
if (new_default_logger != nullptr)
|
||||
{
|
||||
loggers_[new_default_logger->name()] = new_default_logger;
|
||||
}
|
||||
default_logger_ = std::move(new_default_logger);
|
||||
}
|
||||
|
||||
void set_tp(std::shared_ptr<thread_pool> tp)
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> lock(tp_mutex_);
|
||||
tp_ = std::move(tp);
|
||||
}
|
||||
|
||||
std::shared_ptr<thread_pool> get_tp()
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> lock(tp_mutex_);
|
||||
return tp_;
|
||||
}
|
||||
|
||||
// Set global formatter. Each sink in each logger will get a clone of this object
|
||||
void set_formatter(std::unique_ptr<formatter> formatter)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(logger_map_mutex_);
|
||||
formatter_ = std::move(formatter);
|
||||
for (auto &l : loggers_)
|
||||
{
|
||||
l.second->set_formatter(formatter_->clone());
|
||||
}
|
||||
}
|
||||
|
||||
void set_level(level::level_enum log_level)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(logger_map_mutex_);
|
||||
for (auto &l : loggers_)
|
||||
{
|
||||
l.second->set_level(log_level);
|
||||
}
|
||||
level_ = log_level;
|
||||
}
|
||||
|
||||
void flush_on(level::level_enum log_level)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(logger_map_mutex_);
|
||||
for (auto &l : loggers_)
|
||||
{
|
||||
l.second->flush_on(log_level);
|
||||
}
|
||||
flush_level_ = log_level;
|
||||
}
|
||||
|
||||
void flush_every(std::chrono::seconds interval)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(flusher_mutex_);
|
||||
std::function<void()> clbk = std::bind(®istry::flush_all, this);
|
||||
periodic_flusher_ = details::make_unique<periodic_worker>(clbk, interval);
|
||||
}
|
||||
|
||||
void set_error_handler(log_err_handler handler)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(logger_map_mutex_);
|
||||
for (auto &l : loggers_)
|
||||
{
|
||||
l.second->set_error_handler(handler);
|
||||
}
|
||||
err_handler_ = handler;
|
||||
}
|
||||
|
||||
void apply_all(const std::function<void(const std::shared_ptr<logger>)> &fun)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(logger_map_mutex_);
|
||||
for (auto &l : loggers_)
|
||||
{
|
||||
fun(l.second);
|
||||
}
|
||||
}
|
||||
|
||||
void flush_all()
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(logger_map_mutex_);
|
||||
for (auto &l : loggers_)
|
||||
{
|
||||
l.second->flush();
|
||||
}
|
||||
}
|
||||
|
||||
void drop(const std::string &logger_name)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(logger_map_mutex_);
|
||||
loggers_.erase(logger_name);
|
||||
if (default_logger_ && default_logger_->name() == logger_name)
|
||||
{
|
||||
default_logger_.reset();
|
||||
}
|
||||
}
|
||||
|
||||
void drop_all()
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(logger_map_mutex_);
|
||||
loggers_.clear();
|
||||
default_logger_.reset();
|
||||
}
|
||||
|
||||
// clean all resources and threads started by the registry
|
||||
void shutdown()
|
||||
{
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(flusher_mutex_);
|
||||
periodic_flusher_.reset();
|
||||
}
|
||||
|
||||
drop_all();
|
||||
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> lock(tp_mutex_);
|
||||
tp_.reset();
|
||||
}
|
||||
}
|
||||
|
||||
std::recursive_mutex &tp_mutex()
|
||||
{
|
||||
return tp_mutex_;
|
||||
}
|
||||
|
||||
void set_automatic_registration(bool automatic_regsistration)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(logger_map_mutex_);
|
||||
automatic_registration_ = automatic_regsistration;
|
||||
}
|
||||
|
||||
static registry &instance()
|
||||
{
|
||||
static registry s_instance;
|
||||
return s_instance;
|
||||
}
|
||||
|
||||
private:
|
||||
registry()
|
||||
: formatter_(new pattern_formatter())
|
||||
{
|
||||
|
||||
#ifndef SPDLOG_DISABLE_DEFAULT_LOGGER
|
||||
// create default logger (ansicolor_stdout_sink_mt or wincolor_stdout_sink_mt in windows).
|
||||
#ifdef _WIN32
|
||||
auto color_sink = std::make_shared<sinks::wincolor_stdout_sink_mt>();
|
||||
#else
|
||||
auto color_sink = std::make_shared<sinks::ansicolor_stdout_sink_mt>();
|
||||
#endif
|
||||
|
||||
const char *default_logger_name = "";
|
||||
default_logger_ = std::make_shared<spdlog::logger>(default_logger_name, std::move(color_sink));
|
||||
loggers_[default_logger_name] = default_logger_;
|
||||
|
||||
#endif // SPDLOG_DISABLE_DEFAULT_LOGGER
|
||||
}
|
||||
|
||||
~registry() = default;
|
||||
|
||||
void throw_if_exists_(const std::string &logger_name)
|
||||
{
|
||||
if (loggers_.find(logger_name) != loggers_.end())
|
||||
{
|
||||
throw spdlog_ex("logger with name '" + logger_name + "' already exists");
|
||||
}
|
||||
}
|
||||
|
||||
void register_logger_(std::shared_ptr<logger> new_logger)
|
||||
{
|
||||
auto logger_name = new_logger->name();
|
||||
throw_if_exists_(logger_name);
|
||||
loggers_[logger_name] = std::move(new_logger);
|
||||
}
|
||||
|
||||
std::mutex logger_map_mutex_, flusher_mutex_;
|
||||
std::recursive_mutex tp_mutex_;
|
||||
std::unordered_map<std::string, std::shared_ptr<logger>> loggers_;
|
||||
std::unique_ptr<formatter> formatter_;
|
||||
level::level_enum level_ = spdlog::logger::default_level();
|
||||
level::level_enum flush_level_ = level::off;
|
||||
log_err_handler err_handler_;
|
||||
std::shared_ptr<thread_pool> tp_;
|
||||
std::unique_ptr<periodic_worker> periodic_flusher_;
|
||||
std::shared_ptr<logger> default_logger_;
|
||||
bool automatic_registration_ = true;
|
||||
};
|
||||
|
||||
} // namespace details
|
||||
} // namespace spdlog
|
238
include/Livox/third_party/spdlog/spdlog/details/thread_pool.h
vendored
Executable file
238
include/Livox/third_party/spdlog/spdlog/details/thread_pool.h
vendored
Executable file
@ -0,0 +1,238 @@
|
||||
#pragma once
|
||||
|
||||
#include "spdlog/details/fmt_helper.h"
|
||||
#include "spdlog/details/log_msg.h"
|
||||
#include "spdlog/details/mpmc_blocking_q.h"
|
||||
#include "spdlog/details/os.h"
|
||||
|
||||
#include <chrono>
|
||||
#include <memory>
|
||||
#include <thread>
|
||||
#include <vector>
|
||||
|
||||
namespace spdlog {
|
||||
namespace details {
|
||||
|
||||
using async_logger_ptr = std::shared_ptr<spdlog::async_logger>;
|
||||
|
||||
enum class async_msg_type
|
||||
{
|
||||
log,
|
||||
flush,
|
||||
terminate
|
||||
};
|
||||
|
||||
// Async msg to move to/from the queue
|
||||
// Movable only. should never be copied
|
||||
struct async_msg
|
||||
{
|
||||
async_msg_type msg_type;
|
||||
level::level_enum level;
|
||||
log_clock::time_point time;
|
||||
size_t thread_id;
|
||||
fmt::basic_memory_buffer<char, 176> raw;
|
||||
|
||||
size_t msg_id;
|
||||
source_loc source;
|
||||
async_logger_ptr worker_ptr;
|
||||
|
||||
async_msg() = default;
|
||||
~async_msg() = default;
|
||||
|
||||
// should only be moved in or out of the queue..
|
||||
async_msg(const async_msg &) = delete;
|
||||
|
||||
// support for vs2013 move
|
||||
#if defined(_MSC_VER) && _MSC_VER <= 1800
|
||||
async_msg(async_msg &&other) SPDLOG_NOEXCEPT : msg_type(other.msg_type),
|
||||
level(other.level),
|
||||
time(other.time),
|
||||
thread_id(other.thread_id),
|
||||
raw(move(other.raw)),
|
||||
msg_id(other.msg_id),
|
||||
source(other.source),
|
||||
worker_ptr(std::move(other.worker_ptr))
|
||||
{
|
||||
}
|
||||
|
||||
async_msg &operator=(async_msg &&other) SPDLOG_NOEXCEPT
|
||||
{
|
||||
msg_type = other.msg_type;
|
||||
level = other.level;
|
||||
time = other.time;
|
||||
thread_id = other.thread_id;
|
||||
raw = std::move(other.raw);
|
||||
msg_id = other.msg_id;
|
||||
source = other.source;
|
||||
worker_ptr = std::move(other.worker_ptr);
|
||||
return *this;
|
||||
}
|
||||
#else // (_MSC_VER) && _MSC_VER <= 1800
|
||||
async_msg(async_msg &&) = default;
|
||||
async_msg &operator=(async_msg &&) = default;
|
||||
#endif
|
||||
|
||||
// construct from log_msg with given type
|
||||
async_msg(async_logger_ptr &&worker, async_msg_type the_type, details::log_msg &m)
|
||||
: msg_type(the_type)
|
||||
, level(m.level)
|
||||
, time(m.time)
|
||||
, thread_id(m.thread_id)
|
||||
, msg_id(m.msg_id)
|
||||
, source(m.source)
|
||||
, worker_ptr(std::move(worker))
|
||||
{
|
||||
fmt_helper::append_string_view(m.payload, raw);
|
||||
}
|
||||
|
||||
async_msg(async_logger_ptr &&worker, async_msg_type the_type)
|
||||
: msg_type(the_type)
|
||||
, level(level::off)
|
||||
, time()
|
||||
, thread_id(0)
|
||||
, msg_id(0)
|
||||
, source()
|
||||
, worker_ptr(std::move(worker))
|
||||
{
|
||||
}
|
||||
|
||||
explicit async_msg(async_msg_type the_type)
|
||||
: async_msg(nullptr, the_type)
|
||||
{
|
||||
}
|
||||
|
||||
// copy into log_msg
|
||||
log_msg to_log_msg()
|
||||
{
|
||||
log_msg msg(&worker_ptr->name(), level, string_view_t(raw.data(), raw.size()));
|
||||
msg.time = time;
|
||||
msg.thread_id = thread_id;
|
||||
msg.msg_id = msg_id;
|
||||
msg.source = source;
|
||||
msg.color_range_start = 0;
|
||||
msg.color_range_end = 0;
|
||||
return msg;
|
||||
}
|
||||
};
|
||||
|
||||
class thread_pool
|
||||
{
|
||||
public:
|
||||
using item_type = async_msg;
|
||||
using q_type = details::mpmc_blocking_queue<item_type>;
|
||||
|
||||
thread_pool(size_t q_max_items, size_t threads_n)
|
||||
: q_(q_max_items)
|
||||
{
|
||||
// std::cout << "thread_pool() q_size_bytes: " << q_size_bytes <<
|
||||
// "\tthreads_n: " << threads_n << std::endl;
|
||||
if (threads_n == 0 || threads_n > 1000)
|
||||
{
|
||||
throw spdlog_ex("spdlog::thread_pool(): invalid threads_n param (valid "
|
||||
"range is 1-1000)");
|
||||
}
|
||||
for (size_t i = 0; i < threads_n; i++)
|
||||
{
|
||||
threads_.emplace_back(&thread_pool::worker_loop_, this);
|
||||
}
|
||||
}
|
||||
|
||||
// message all threads to terminate gracefully join them
|
||||
~thread_pool()
|
||||
{
|
||||
try
|
||||
{
|
||||
for (size_t i = 0; i < threads_.size(); i++)
|
||||
{
|
||||
post_async_msg_(async_msg(async_msg_type::terminate), async_overflow_policy::block);
|
||||
}
|
||||
|
||||
for (auto &t : threads_)
|
||||
{
|
||||
t.join();
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
thread_pool(const thread_pool &) = delete;
|
||||
thread_pool &operator=(thread_pool &&) = delete;
|
||||
|
||||
void post_log(async_logger_ptr &&worker_ptr, details::log_msg &msg, async_overflow_policy overflow_policy)
|
||||
{
|
||||
async_msg async_m(std::move(worker_ptr), async_msg_type::log, msg);
|
||||
post_async_msg_(std::move(async_m), overflow_policy);
|
||||
}
|
||||
|
||||
void post_flush(async_logger_ptr &&worker_ptr, async_overflow_policy overflow_policy)
|
||||
{
|
||||
post_async_msg_(async_msg(std::move(worker_ptr), async_msg_type::flush), overflow_policy);
|
||||
}
|
||||
|
||||
size_t overrun_counter()
|
||||
{
|
||||
return q_.overrun_counter();
|
||||
}
|
||||
|
||||
private:
|
||||
q_type q_;
|
||||
|
||||
std::vector<std::thread> threads_;
|
||||
|
||||
void post_async_msg_(async_msg &&new_msg, async_overflow_policy overflow_policy)
|
||||
{
|
||||
if (overflow_policy == async_overflow_policy::block)
|
||||
{
|
||||
q_.enqueue(std::move(new_msg));
|
||||
}
|
||||
else
|
||||
{
|
||||
q_.enqueue_nowait(std::move(new_msg));
|
||||
}
|
||||
}
|
||||
|
||||
void worker_loop_()
|
||||
{
|
||||
while (process_next_msg_()) {};
|
||||
}
|
||||
|
||||
// process next message in the queue
|
||||
// return true if this thread should still be active (while no terminate msg
|
||||
// was received)
|
||||
bool process_next_msg_()
|
||||
{
|
||||
async_msg incoming_async_msg;
|
||||
bool dequeued = q_.dequeue_for(incoming_async_msg, std::chrono::seconds(10));
|
||||
if (!dequeued)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
switch (incoming_async_msg.msg_type)
|
||||
{
|
||||
case async_msg_type::log:
|
||||
{
|
||||
auto msg = incoming_async_msg.to_log_msg();
|
||||
incoming_async_msg.worker_ptr->backend_log_(msg);
|
||||
return true;
|
||||
}
|
||||
case async_msg_type::flush:
|
||||
{
|
||||
incoming_async_msg.worker_ptr->backend_flush_();
|
||||
return true;
|
||||
}
|
||||
|
||||
case async_msg_type::terminate:
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
assert(false && "Unexpected async_msg_type");
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace details
|
||||
} // namespace spdlog
|
172
include/Livox/third_party/spdlog/spdlog/fmt/bin_to_hex.h
vendored
Executable file
172
include/Livox/third_party/spdlog/spdlog/fmt/bin_to_hex.h
vendored
Executable file
@ -0,0 +1,172 @@
|
||||
//
|
||||
// Copyright(c) 2015 Gabi Melman.
|
||||
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
//
|
||||
// Support for logging binary data as hex
|
||||
// format flags:
|
||||
// {:X} - print in uppercase.
|
||||
// {:s} - don't separate each byte with space.
|
||||
// {:p} - don't print the position on each line start.
|
||||
// {:n} - don't split the output to lines.
|
||||
|
||||
//
|
||||
// Examples:
|
||||
//
|
||||
// std::vector<char> v(200, 0x0b);
|
||||
// logger->info("Some buffer {}", spdlog::to_hex(v));
|
||||
// char buf[128];
|
||||
// logger->info("Some buffer {:X}", spdlog::to_hex(std::begin(buf), std::end(buf)));
|
||||
|
||||
namespace spdlog {
|
||||
namespace details {
|
||||
|
||||
template<typename It>
|
||||
class bytes_range
|
||||
{
|
||||
public:
|
||||
bytes_range(It range_begin, It range_end)
|
||||
: begin_(range_begin)
|
||||
, end_(range_end)
|
||||
{
|
||||
}
|
||||
|
||||
It begin() const
|
||||
{
|
||||
return begin_;
|
||||
}
|
||||
It end() const
|
||||
{
|
||||
return end_;
|
||||
}
|
||||
|
||||
private:
|
||||
It begin_, end_;
|
||||
};
|
||||
} // namespace details
|
||||
|
||||
// create a bytes_range that wraps the given container
|
||||
template<typename Container>
|
||||
inline details::bytes_range<typename Container::const_iterator> to_hex(const Container &container)
|
||||
{
|
||||
static_assert(sizeof(typename Container::value_type) == 1, "sizeof(Container::value_type) != 1");
|
||||
using Iter = typename Container::const_iterator;
|
||||
return details::bytes_range<Iter>(std::begin(container), std::end(container));
|
||||
}
|
||||
|
||||
// create bytes_range from ranges
|
||||
template<typename It>
|
||||
inline details::bytes_range<It> to_hex(const It range_begin, const It range_end)
|
||||
{
|
||||
return details::bytes_range<It>(range_begin, range_end);
|
||||
}
|
||||
|
||||
} // namespace spdlog
|
||||
|
||||
namespace fmt {
|
||||
|
||||
template<typename T>
|
||||
struct formatter<spdlog::details::bytes_range<T>>
|
||||
{
|
||||
const std::size_t line_size = 100;
|
||||
const char delimiter = ' ';
|
||||
|
||||
bool put_newlines = true;
|
||||
bool put_delimiters = true;
|
||||
bool use_uppercase = false;
|
||||
bool put_positions = true; // position on start of each line
|
||||
|
||||
// parse the format string flags
|
||||
template<typename ParseContext>
|
||||
auto parse(ParseContext &ctx) -> decltype(ctx.begin())
|
||||
{
|
||||
auto it = ctx.begin();
|
||||
while (*it && *it != '}')
|
||||
{
|
||||
switch (*it)
|
||||
{
|
||||
case 'X':
|
||||
use_uppercase = true;
|
||||
break;
|
||||
case 's':
|
||||
put_delimiters = false;
|
||||
break;
|
||||
case 'p':
|
||||
put_positions = false;
|
||||
break;
|
||||
case 'n':
|
||||
put_newlines = false;
|
||||
break;
|
||||
}
|
||||
|
||||
++it;
|
||||
}
|
||||
return it;
|
||||
}
|
||||
|
||||
// format the given bytes range as hex
|
||||
template<typename FormatContext, typename Container>
|
||||
auto format(const spdlog::details::bytes_range<Container> &the_range, FormatContext &ctx) -> decltype(ctx.out())
|
||||
{
|
||||
SPDLOG_CONSTEXPR const char *hex_upper = "0123456789ABCDEF";
|
||||
SPDLOG_CONSTEXPR const char *hex_lower = "0123456789abcdef";
|
||||
const char *hex_chars = use_uppercase ? hex_upper : hex_lower;
|
||||
|
||||
std::size_t pos = 0;
|
||||
std::size_t column = line_size;
|
||||
auto inserter = ctx.begin();
|
||||
|
||||
for (auto &item : the_range)
|
||||
{
|
||||
auto ch = static_cast<unsigned char>(item);
|
||||
pos++;
|
||||
|
||||
if (put_newlines && column >= line_size)
|
||||
{
|
||||
column = put_newline(inserter, pos);
|
||||
|
||||
// put first byte without delimiter in front of it
|
||||
*inserter++ = hex_chars[(ch >> 4) & 0x0f];
|
||||
*inserter++ = hex_chars[ch & 0x0f];
|
||||
column += 2;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (put_delimiters)
|
||||
{
|
||||
*inserter++ = delimiter;
|
||||
++column;
|
||||
}
|
||||
|
||||
*inserter++ = hex_chars[(ch >> 4) & 0x0f];
|
||||
*inserter++ = hex_chars[ch & 0x0f];
|
||||
column += 2;
|
||||
}
|
||||
return inserter;
|
||||
}
|
||||
|
||||
// put newline(and position header)
|
||||
// return the next column
|
||||
template<typename It>
|
||||
std::size_t put_newline(It inserter, std::size_t pos)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
*inserter++ = '\r';
|
||||
#endif
|
||||
*inserter++ = '\n';
|
||||
|
||||
if (put_positions)
|
||||
{
|
||||
fmt::format_to(inserter, "{:<04X}: ", pos - 1);
|
||||
return 7;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
};
|
||||
} // namespace fmt
|
23
include/Livox/third_party/spdlog/spdlog/fmt/bundled/LICENSE.rst
vendored
Executable file
23
include/Livox/third_party/spdlog/spdlog/fmt/bundled/LICENSE.rst
vendored
Executable file
@ -0,0 +1,23 @@
|
||||
Copyright (c) 2012 - 2016, Victor Zverovich
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
452
include/Livox/third_party/spdlog/spdlog/fmt/bundled/chrono.h
vendored
Executable file
452
include/Livox/third_party/spdlog/spdlog/fmt/bundled/chrono.h
vendored
Executable file
@ -0,0 +1,452 @@
|
||||
// Formatting library for C++ - chrono support
|
||||
//
|
||||
// Copyright (c) 2012 - present, Victor Zverovich
|
||||
// All rights reserved.
|
||||
//
|
||||
// For the license information refer to format.h.
|
||||
|
||||
#ifndef FMT_CHRONO_H_
|
||||
#define FMT_CHRONO_H_
|
||||
|
||||
#include "format.h"
|
||||
#include "locale.h"
|
||||
|
||||
#include <chrono>
|
||||
#include <ctime>
|
||||
#include <locale>
|
||||
#include <sstream>
|
||||
|
||||
FMT_BEGIN_NAMESPACE
|
||||
|
||||
namespace internal{
|
||||
|
||||
enum class numeric_system {
|
||||
standard,
|
||||
// Alternative numeric system, e.g. 十二 instead of 12 in ja_JP locale.
|
||||
alternative
|
||||
};
|
||||
|
||||
// Parses a put_time-like format string and invokes handler actions.
|
||||
template <typename Char, typename Handler>
|
||||
FMT_CONSTEXPR const Char *parse_chrono_format(
|
||||
const Char *begin, const Char *end, Handler &&handler) {
|
||||
auto ptr = begin;
|
||||
while (ptr != end) {
|
||||
auto c = *ptr;
|
||||
if (c == '}') break;
|
||||
if (c != '%') {
|
||||
++ptr;
|
||||
continue;
|
||||
}
|
||||
if (begin != ptr)
|
||||
handler.on_text(begin, ptr);
|
||||
++ptr; // consume '%'
|
||||
if (ptr == end)
|
||||
throw format_error("invalid format");
|
||||
c = *ptr++;
|
||||
switch (c) {
|
||||
case '%':
|
||||
handler.on_text(ptr - 1, ptr);
|
||||
break;
|
||||
case 'n': {
|
||||
const char newline[] = "\n";
|
||||
handler.on_text(newline, newline + 1);
|
||||
break;
|
||||
}
|
||||
case 't': {
|
||||
const char tab[] = "\t";
|
||||
handler.on_text(tab, tab + 1);
|
||||
break;
|
||||
}
|
||||
// Day of the week:
|
||||
case 'a':
|
||||
handler.on_abbr_weekday();
|
||||
break;
|
||||
case 'A':
|
||||
handler.on_full_weekday();
|
||||
break;
|
||||
case 'w':
|
||||
handler.on_dec0_weekday(numeric_system::standard);
|
||||
break;
|
||||
case 'u':
|
||||
handler.on_dec1_weekday(numeric_system::standard);
|
||||
break;
|
||||
// Month:
|
||||
case 'b':
|
||||
handler.on_abbr_month();
|
||||
break;
|
||||
case 'B':
|
||||
handler.on_full_month();
|
||||
break;
|
||||
// Hour, minute, second:
|
||||
case 'H':
|
||||
handler.on_24_hour(numeric_system::standard);
|
||||
break;
|
||||
case 'I':
|
||||
handler.on_12_hour(numeric_system::standard);
|
||||
break;
|
||||
case 'M':
|
||||
handler.on_minute(numeric_system::standard);
|
||||
break;
|
||||
case 'S':
|
||||
handler.on_second(numeric_system::standard);
|
||||
break;
|
||||
// Other:
|
||||
case 'c':
|
||||
handler.on_datetime(numeric_system::standard);
|
||||
break;
|
||||
case 'x':
|
||||
handler.on_loc_date(numeric_system::standard);
|
||||
break;
|
||||
case 'X':
|
||||
handler.on_loc_time(numeric_system::standard);
|
||||
break;
|
||||
case 'D':
|
||||
handler.on_us_date();
|
||||
break;
|
||||
case 'F':
|
||||
handler.on_iso_date();
|
||||
break;
|
||||
case 'r':
|
||||
handler.on_12_hour_time();
|
||||
break;
|
||||
case 'R':
|
||||
handler.on_24_hour_time();
|
||||
break;
|
||||
case 'T':
|
||||
handler.on_iso_time();
|
||||
break;
|
||||
case 'p':
|
||||
handler.on_am_pm();
|
||||
break;
|
||||
case 'z':
|
||||
handler.on_utc_offset();
|
||||
break;
|
||||
case 'Z':
|
||||
handler.on_tz_name();
|
||||
break;
|
||||
// Alternative representation:
|
||||
case 'E': {
|
||||
if (ptr == end)
|
||||
throw format_error("invalid format");
|
||||
c = *ptr++;
|
||||
switch (c) {
|
||||
case 'c':
|
||||
handler.on_datetime(numeric_system::alternative);
|
||||
break;
|
||||
case 'x':
|
||||
handler.on_loc_date(numeric_system::alternative);
|
||||
break;
|
||||
case 'X':
|
||||
handler.on_loc_time(numeric_system::alternative);
|
||||
break;
|
||||
default:
|
||||
throw format_error("invalid format");
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 'O':
|
||||
if (ptr == end)
|
||||
throw format_error("invalid format");
|
||||
c = *ptr++;
|
||||
switch (c) {
|
||||
case 'w':
|
||||
handler.on_dec0_weekday(numeric_system::alternative);
|
||||
break;
|
||||
case 'u':
|
||||
handler.on_dec1_weekday(numeric_system::alternative);
|
||||
break;
|
||||
case 'H':
|
||||
handler.on_24_hour(numeric_system::alternative);
|
||||
break;
|
||||
case 'I':
|
||||
handler.on_12_hour(numeric_system::alternative);
|
||||
break;
|
||||
case 'M':
|
||||
handler.on_minute(numeric_system::alternative);
|
||||
break;
|
||||
case 'S':
|
||||
handler.on_second(numeric_system::alternative);
|
||||
break;
|
||||
default:
|
||||
throw format_error("invalid format");
|
||||
}
|
||||
break;
|
||||
default:
|
||||
throw format_error("invalid format");
|
||||
}
|
||||
begin = ptr;
|
||||
}
|
||||
if (begin != ptr)
|
||||
handler.on_text(begin, ptr);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
struct chrono_format_checker {
|
||||
void report_no_date() { throw format_error("no date"); }
|
||||
|
||||
template <typename Char>
|
||||
void on_text(const Char *, const Char *) {}
|
||||
void on_abbr_weekday() { report_no_date(); }
|
||||
void on_full_weekday() { report_no_date(); }
|
||||
void on_dec0_weekday(numeric_system) { report_no_date(); }
|
||||
void on_dec1_weekday(numeric_system) { report_no_date(); }
|
||||
void on_abbr_month() { report_no_date(); }
|
||||
void on_full_month() { report_no_date(); }
|
||||
void on_24_hour(numeric_system) {}
|
||||
void on_12_hour(numeric_system) {}
|
||||
void on_minute(numeric_system) {}
|
||||
void on_second(numeric_system) {}
|
||||
void on_datetime(numeric_system) { report_no_date(); }
|
||||
void on_loc_date(numeric_system) { report_no_date(); }
|
||||
void on_loc_time(numeric_system) { report_no_date(); }
|
||||
void on_us_date() { report_no_date(); }
|
||||
void on_iso_date() { report_no_date(); }
|
||||
void on_12_hour_time() {}
|
||||
void on_24_hour_time() {}
|
||||
void on_iso_time() {}
|
||||
void on_am_pm() {}
|
||||
void on_utc_offset() { report_no_date(); }
|
||||
void on_tz_name() { report_no_date(); }
|
||||
};
|
||||
|
||||
template <typename Int>
|
||||
inline int to_int(Int value) {
|
||||
FMT_ASSERT(value >= (std::numeric_limits<int>::min)() &&
|
||||
value <= (std::numeric_limits<int>::max)(), "invalid value");
|
||||
return static_cast<int>(value);
|
||||
}
|
||||
|
||||
template <typename FormatContext, typename OutputIt>
|
||||
struct chrono_formatter {
|
||||
FormatContext &context;
|
||||
OutputIt out;
|
||||
std::chrono::seconds s;
|
||||
std::chrono::milliseconds ms;
|
||||
|
||||
typedef typename FormatContext::char_type char_type;
|
||||
|
||||
explicit chrono_formatter(FormatContext &ctx, OutputIt o)
|
||||
: context(ctx), out(o) {}
|
||||
|
||||
int hour() const { return to_int((s.count() / 3600) % 24); }
|
||||
|
||||
int hour12() const {
|
||||
auto hour = to_int((s.count() / 3600) % 12);
|
||||
return hour > 0 ? hour : 12;
|
||||
}
|
||||
|
||||
int minute() const { return to_int((s.count() / 60) % 60); }
|
||||
int second() const { return to_int(s.count() % 60); }
|
||||
|
||||
std::tm time() const {
|
||||
auto time = std::tm();
|
||||
time.tm_hour = hour();
|
||||
time.tm_min = minute();
|
||||
time.tm_sec = second();
|
||||
return time;
|
||||
}
|
||||
|
||||
void write(int value, int width) {
|
||||
typedef typename int_traits<int>::main_type main_type;
|
||||
main_type n = to_unsigned(value);
|
||||
int num_digits = internal::count_digits(n);
|
||||
if (width > num_digits)
|
||||
out = std::fill_n(out, width - num_digits, '0');
|
||||
out = format_decimal<char_type>(out, n, num_digits);
|
||||
}
|
||||
|
||||
void format_localized(const tm &time, const char *format) {
|
||||
auto locale = context.locale().template get<std::locale>();
|
||||
auto &facet = std::use_facet<std::time_put<char_type>>(locale);
|
||||
std::basic_ostringstream<char_type> os;
|
||||
os.imbue(locale);
|
||||
facet.put(os, os, ' ', &time, format, format + std::strlen(format));
|
||||
auto str = os.str();
|
||||
std::copy(str.begin(), str.end(), out);
|
||||
}
|
||||
|
||||
void on_text(const char_type *begin, const char_type *end) {
|
||||
std::copy(begin, end, out);
|
||||
}
|
||||
|
||||
// These are not implemented because durations don't have date information.
|
||||
void on_abbr_weekday() {}
|
||||
void on_full_weekday() {}
|
||||
void on_dec0_weekday(numeric_system) {}
|
||||
void on_dec1_weekday(numeric_system) {}
|
||||
void on_abbr_month() {}
|
||||
void on_full_month() {}
|
||||
void on_datetime(numeric_system) {}
|
||||
void on_loc_date(numeric_system) {}
|
||||
void on_loc_time(numeric_system) {}
|
||||
void on_us_date() {}
|
||||
void on_iso_date() {}
|
||||
void on_utc_offset() {}
|
||||
void on_tz_name() {}
|
||||
|
||||
void on_24_hour(numeric_system ns) {
|
||||
if (ns == numeric_system::standard)
|
||||
return write(hour(), 2);
|
||||
auto time = tm();
|
||||
time.tm_hour = hour();
|
||||
format_localized(time, "%OH");
|
||||
}
|
||||
|
||||
void on_12_hour(numeric_system ns) {
|
||||
if (ns == numeric_system::standard)
|
||||
return write(hour12(), 2);
|
||||
auto time = tm();
|
||||
time.tm_hour = hour();
|
||||
format_localized(time, "%OI");
|
||||
}
|
||||
|
||||
void on_minute(numeric_system ns) {
|
||||
if (ns == numeric_system::standard)
|
||||
return write(minute(), 2);
|
||||
auto time = tm();
|
||||
time.tm_min = minute();
|
||||
format_localized(time, "%OM");
|
||||
}
|
||||
|
||||
void on_second(numeric_system ns) {
|
||||
if (ns == numeric_system::standard) {
|
||||
write(second(), 2);
|
||||
if (ms != std::chrono::milliseconds(0)) {
|
||||
*out++ = '.';
|
||||
write(to_int(ms.count()), 3);
|
||||
}
|
||||
return;
|
||||
}
|
||||
auto time = tm();
|
||||
time.tm_sec = second();
|
||||
format_localized(time, "%OS");
|
||||
}
|
||||
|
||||
void on_12_hour_time() { format_localized(time(), "%r"); }
|
||||
|
||||
void on_24_hour_time() {
|
||||
write(hour(), 2);
|
||||
*out++ = ':';
|
||||
write(minute(), 2);
|
||||
}
|
||||
|
||||
void on_iso_time() {
|
||||
on_24_hour_time();
|
||||
*out++ = ':';
|
||||
write(second(), 2);
|
||||
}
|
||||
|
||||
void on_am_pm() { format_localized(time(), "%p"); }
|
||||
};
|
||||
} // namespace internal
|
||||
|
||||
template <typename Period> FMT_CONSTEXPR const char *get_units() {
|
||||
return FMT_NULL;
|
||||
}
|
||||
template <> FMT_CONSTEXPR const char *get_units<std::atto>() { return "as"; }
|
||||
template <> FMT_CONSTEXPR const char *get_units<std::femto>() { return "fs"; }
|
||||
template <> FMT_CONSTEXPR const char *get_units<std::pico>() { return "ps"; }
|
||||
template <> FMT_CONSTEXPR const char *get_units<std::nano>() { return "ns"; }
|
||||
template <> FMT_CONSTEXPR const char *get_units<std::micro>() { return "µs"; }
|
||||
template <> FMT_CONSTEXPR const char *get_units<std::milli>() { return "ms"; }
|
||||
template <> FMT_CONSTEXPR const char *get_units<std::centi>() { return "cs"; }
|
||||
template <> FMT_CONSTEXPR const char *get_units<std::deci>() { return "ds"; }
|
||||
template <> FMT_CONSTEXPR const char *get_units<std::ratio<1>>() { return "s"; }
|
||||
template <> FMT_CONSTEXPR const char *get_units<std::deca>() { return "das"; }
|
||||
template <> FMT_CONSTEXPR const char *get_units<std::hecto>() { return "hs"; }
|
||||
template <> FMT_CONSTEXPR const char *get_units<std::kilo>() { return "ks"; }
|
||||
template <> FMT_CONSTEXPR const char *get_units<std::mega>() { return "Ms"; }
|
||||
template <> FMT_CONSTEXPR const char *get_units<std::giga>() { return "Gs"; }
|
||||
template <> FMT_CONSTEXPR const char *get_units<std::tera>() { return "Ts"; }
|
||||
template <> FMT_CONSTEXPR const char *get_units<std::peta>() { return "Ps"; }
|
||||
template <> FMT_CONSTEXPR const char *get_units<std::exa>() { return "Es"; }
|
||||
template <> FMT_CONSTEXPR const char *get_units<std::ratio<60>>() {
|
||||
return "m";
|
||||
}
|
||||
template <> FMT_CONSTEXPR const char *get_units<std::ratio<3600>>() {
|
||||
return "h";
|
||||
}
|
||||
|
||||
template <typename Rep, typename Period, typename Char>
|
||||
struct formatter<std::chrono::duration<Rep, Period>, Char> {
|
||||
private:
|
||||
align_spec spec;
|
||||
internal::arg_ref<Char> width_ref;
|
||||
mutable basic_string_view<Char> format_str;
|
||||
typedef std::chrono::duration<Rep, Period> duration;
|
||||
|
||||
struct spec_handler {
|
||||
formatter &f;
|
||||
basic_parse_context<Char> &context;
|
||||
|
||||
typedef internal::arg_ref<Char> arg_ref_type;
|
||||
|
||||
template <typename Id>
|
||||
FMT_CONSTEXPR arg_ref_type make_arg_ref(Id arg_id) {
|
||||
context.check_arg_id(arg_id);
|
||||
return arg_ref_type(arg_id);
|
||||
}
|
||||
|
||||
FMT_CONSTEXPR arg_ref_type make_arg_ref(internal::auto_id) {
|
||||
return arg_ref_type(context.next_arg_id());
|
||||
}
|
||||
|
||||
void on_error(const char *msg) { throw format_error(msg); }
|
||||
void on_fill(Char fill) { f.spec.fill_ = fill; }
|
||||
void on_align(alignment align) { f.spec.align_ = align; }
|
||||
void on_width(unsigned width) { f.spec.width_ = width; }
|
||||
|
||||
template <typename Id>
|
||||
void on_dynamic_width(Id arg_id) {
|
||||
f.width_ref = make_arg_ref(arg_id);
|
||||
}
|
||||
};
|
||||
|
||||
public:
|
||||
formatter() : spec() {}
|
||||
|
||||
FMT_CONSTEXPR auto parse(basic_parse_context<Char> &ctx)
|
||||
-> decltype(ctx.begin()) {
|
||||
auto begin = ctx.begin(), end = ctx.end();
|
||||
if (begin == end) return begin;
|
||||
spec_handler handler{*this, ctx};
|
||||
begin = internal::parse_align(begin, end, handler);
|
||||
if (begin == end) return begin;
|
||||
begin = internal::parse_width(begin, end, handler);
|
||||
end = parse_chrono_format(begin, end, internal::chrono_format_checker());
|
||||
format_str = basic_string_view<Char>(&*begin, internal::to_unsigned(end - begin));
|
||||
return end;
|
||||
}
|
||||
|
||||
template <typename FormatContext>
|
||||
auto format(const duration &d, FormatContext &ctx)
|
||||
-> decltype(ctx.out()) {
|
||||
auto begin = format_str.begin(), end = format_str.end();
|
||||
memory_buffer buf;
|
||||
typedef output_range<decltype(ctx.out()), Char> range;
|
||||
basic_writer<range> w(range(ctx.out()));
|
||||
if (begin == end || *begin == '}') {
|
||||
if (const char *unit = get_units<Period>())
|
||||
format_to(buf, "{}{}", d.count(), unit);
|
||||
else if (Period::den == 1)
|
||||
format_to(buf, "{}[{}]s", d.count(), Period::num);
|
||||
else
|
||||
format_to(buf, "{}[{}/{}]s", d.count(), Period::num, Period::den);
|
||||
internal::handle_dynamic_spec<internal::width_checker>(
|
||||
spec.width_, width_ref, ctx);
|
||||
} else {
|
||||
auto out = std::back_inserter(buf);
|
||||
internal::chrono_formatter<FormatContext, decltype(out)> f(ctx, out);
|
||||
f.s = std::chrono::duration_cast<std::chrono::seconds>(d);
|
||||
f.ms = std::chrono::duration_cast<std::chrono::milliseconds>(d - f.s);
|
||||
parse_chrono_format(begin, end, f);
|
||||
}
|
||||
w.write(buf.data(), buf.size(), spec);
|
||||
return w.out();
|
||||
}
|
||||
};
|
||||
|
||||
FMT_END_NAMESPACE
|
||||
|
||||
#endif // FMT_CHRONO_H_
|
577
include/Livox/third_party/spdlog/spdlog/fmt/bundled/color.h
vendored
Executable file
577
include/Livox/third_party/spdlog/spdlog/fmt/bundled/color.h
vendored
Executable file
@ -0,0 +1,577 @@
|
||||
// Formatting library for C++ - color support
|
||||
//
|
||||
// Copyright (c) 2018 - present, Victor Zverovich and fmt contributors
|
||||
// All rights reserved.
|
||||
//
|
||||
// For the license information refer to format.h.
|
||||
|
||||
#ifndef FMT_COLOR_H_
|
||||
#define FMT_COLOR_H_
|
||||
|
||||
#include "format.h"
|
||||
|
||||
FMT_BEGIN_NAMESPACE
|
||||
|
||||
#ifdef FMT_DEPRECATED_COLORS
|
||||
|
||||
// color and (v)print_colored are deprecated.
|
||||
enum color { black, red, green, yellow, blue, magenta, cyan, white };
|
||||
FMT_API void vprint_colored(color c, string_view format, format_args args);
|
||||
FMT_API void vprint_colored(color c, wstring_view format, wformat_args args);
|
||||
template <typename... Args>
|
||||
inline void print_colored(color c, string_view format_str,
|
||||
const Args & ... args) {
|
||||
vprint_colored(c, format_str, make_format_args(args...));
|
||||
}
|
||||
template <typename... Args>
|
||||
inline void print_colored(color c, wstring_view format_str,
|
||||
const Args & ... args) {
|
||||
vprint_colored(c, format_str, make_format_args<wformat_context>(args...));
|
||||
}
|
||||
|
||||
inline void vprint_colored(color c, string_view format, format_args args) {
|
||||
char escape[] = "\x1b[30m";
|
||||
escape[3] = static_cast<char>('0' + c);
|
||||
std::fputs(escape, stdout);
|
||||
vprint(format, args);
|
||||
std::fputs(internal::data::RESET_COLOR, stdout);
|
||||
}
|
||||
|
||||
inline void vprint_colored(color c, wstring_view format, wformat_args args) {
|
||||
wchar_t escape[] = L"\x1b[30m";
|
||||
escape[3] = static_cast<wchar_t>('0' + c);
|
||||
std::fputws(escape, stdout);
|
||||
vprint(format, args);
|
||||
std::fputws(internal::data::WRESET_COLOR, stdout);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
enum class color : uint32_t {
|
||||
alice_blue = 0xF0F8FF, // rgb(240,248,255)
|
||||
antique_white = 0xFAEBD7, // rgb(250,235,215)
|
||||
aqua = 0x00FFFF, // rgb(0,255,255)
|
||||
aquamarine = 0x7FFFD4, // rgb(127,255,212)
|
||||
azure = 0xF0FFFF, // rgb(240,255,255)
|
||||
beige = 0xF5F5DC, // rgb(245,245,220)
|
||||
bisque = 0xFFE4C4, // rgb(255,228,196)
|
||||
black = 0x000000, // rgb(0,0,0)
|
||||
blanched_almond = 0xFFEBCD, // rgb(255,235,205)
|
||||
blue = 0x0000FF, // rgb(0,0,255)
|
||||
blue_violet = 0x8A2BE2, // rgb(138,43,226)
|
||||
brown = 0xA52A2A, // rgb(165,42,42)
|
||||
burly_wood = 0xDEB887, // rgb(222,184,135)
|
||||
cadet_blue = 0x5F9EA0, // rgb(95,158,160)
|
||||
chartreuse = 0x7FFF00, // rgb(127,255,0)
|
||||
chocolate = 0xD2691E, // rgb(210,105,30)
|
||||
coral = 0xFF7F50, // rgb(255,127,80)
|
||||
cornflower_blue = 0x6495ED, // rgb(100,149,237)
|
||||
cornsilk = 0xFFF8DC, // rgb(255,248,220)
|
||||
crimson = 0xDC143C, // rgb(220,20,60)
|
||||
cyan = 0x00FFFF, // rgb(0,255,255)
|
||||
dark_blue = 0x00008B, // rgb(0,0,139)
|
||||
dark_cyan = 0x008B8B, // rgb(0,139,139)
|
||||
dark_golden_rod = 0xB8860B, // rgb(184,134,11)
|
||||
dark_gray = 0xA9A9A9, // rgb(169,169,169)
|
||||
dark_green = 0x006400, // rgb(0,100,0)
|
||||
dark_khaki = 0xBDB76B, // rgb(189,183,107)
|
||||
dark_magenta = 0x8B008B, // rgb(139,0,139)
|
||||
dark_olive_green = 0x556B2F, // rgb(85,107,47)
|
||||
dark_orange = 0xFF8C00, // rgb(255,140,0)
|
||||
dark_orchid = 0x9932CC, // rgb(153,50,204)
|
||||
dark_red = 0x8B0000, // rgb(139,0,0)
|
||||
dark_salmon = 0xE9967A, // rgb(233,150,122)
|
||||
dark_sea_green = 0x8FBC8F, // rgb(143,188,143)
|
||||
dark_slate_blue = 0x483D8B, // rgb(72,61,139)
|
||||
dark_slate_gray = 0x2F4F4F, // rgb(47,79,79)
|
||||
dark_turquoise = 0x00CED1, // rgb(0,206,209)
|
||||
dark_violet = 0x9400D3, // rgb(148,0,211)
|
||||
deep_pink = 0xFF1493, // rgb(255,20,147)
|
||||
deep_sky_blue = 0x00BFFF, // rgb(0,191,255)
|
||||
dim_gray = 0x696969, // rgb(105,105,105)
|
||||
dodger_blue = 0x1E90FF, // rgb(30,144,255)
|
||||
fire_brick = 0xB22222, // rgb(178,34,34)
|
||||
floral_white = 0xFFFAF0, // rgb(255,250,240)
|
||||
forest_green = 0x228B22, // rgb(34,139,34)
|
||||
fuchsia = 0xFF00FF, // rgb(255,0,255)
|
||||
gainsboro = 0xDCDCDC, // rgb(220,220,220)
|
||||
ghost_white = 0xF8F8FF, // rgb(248,248,255)
|
||||
gold = 0xFFD700, // rgb(255,215,0)
|
||||
golden_rod = 0xDAA520, // rgb(218,165,32)
|
||||
gray = 0x808080, // rgb(128,128,128)
|
||||
green = 0x008000, // rgb(0,128,0)
|
||||
green_yellow = 0xADFF2F, // rgb(173,255,47)
|
||||
honey_dew = 0xF0FFF0, // rgb(240,255,240)
|
||||
hot_pink = 0xFF69B4, // rgb(255,105,180)
|
||||
indian_red = 0xCD5C5C, // rgb(205,92,92)
|
||||
indigo = 0x4B0082, // rgb(75,0,130)
|
||||
ivory = 0xFFFFF0, // rgb(255,255,240)
|
||||
khaki = 0xF0E68C, // rgb(240,230,140)
|
||||
lavender = 0xE6E6FA, // rgb(230,230,250)
|
||||
lavender_blush = 0xFFF0F5, // rgb(255,240,245)
|
||||
lawn_green = 0x7CFC00, // rgb(124,252,0)
|
||||
lemon_chiffon = 0xFFFACD, // rgb(255,250,205)
|
||||
light_blue = 0xADD8E6, // rgb(173,216,230)
|
||||
light_coral = 0xF08080, // rgb(240,128,128)
|
||||
light_cyan = 0xE0FFFF, // rgb(224,255,255)
|
||||
light_golden_rod_yellow = 0xFAFAD2, // rgb(250,250,210)
|
||||
light_gray = 0xD3D3D3, // rgb(211,211,211)
|
||||
light_green = 0x90EE90, // rgb(144,238,144)
|
||||
light_pink = 0xFFB6C1, // rgb(255,182,193)
|
||||
light_salmon = 0xFFA07A, // rgb(255,160,122)
|
||||
light_sea_green = 0x20B2AA, // rgb(32,178,170)
|
||||
light_sky_blue = 0x87CEFA, // rgb(135,206,250)
|
||||
light_slate_gray = 0x778899, // rgb(119,136,153)
|
||||
light_steel_blue = 0xB0C4DE, // rgb(176,196,222)
|
||||
light_yellow = 0xFFFFE0, // rgb(255,255,224)
|
||||
lime = 0x00FF00, // rgb(0,255,0)
|
||||
lime_green = 0x32CD32, // rgb(50,205,50)
|
||||
linen = 0xFAF0E6, // rgb(250,240,230)
|
||||
magenta = 0xFF00FF, // rgb(255,0,255)
|
||||
maroon = 0x800000, // rgb(128,0,0)
|
||||
medium_aquamarine = 0x66CDAA, // rgb(102,205,170)
|
||||
medium_blue = 0x0000CD, // rgb(0,0,205)
|
||||
medium_orchid = 0xBA55D3, // rgb(186,85,211)
|
||||
medium_purple = 0x9370DB, // rgb(147,112,219)
|
||||
medium_sea_green = 0x3CB371, // rgb(60,179,113)
|
||||
medium_slate_blue = 0x7B68EE, // rgb(123,104,238)
|
||||
medium_spring_green = 0x00FA9A, // rgb(0,250,154)
|
||||
medium_turquoise = 0x48D1CC, // rgb(72,209,204)
|
||||
medium_violet_red = 0xC71585, // rgb(199,21,133)
|
||||
midnight_blue = 0x191970, // rgb(25,25,112)
|
||||
mint_cream = 0xF5FFFA, // rgb(245,255,250)
|
||||
misty_rose = 0xFFE4E1, // rgb(255,228,225)
|
||||
moccasin = 0xFFE4B5, // rgb(255,228,181)
|
||||
navajo_white = 0xFFDEAD, // rgb(255,222,173)
|
||||
navy = 0x000080, // rgb(0,0,128)
|
||||
old_lace = 0xFDF5E6, // rgb(253,245,230)
|
||||
olive = 0x808000, // rgb(128,128,0)
|
||||
olive_drab = 0x6B8E23, // rgb(107,142,35)
|
||||
orange = 0xFFA500, // rgb(255,165,0)
|
||||
orange_red = 0xFF4500, // rgb(255,69,0)
|
||||
orchid = 0xDA70D6, // rgb(218,112,214)
|
||||
pale_golden_rod = 0xEEE8AA, // rgb(238,232,170)
|
||||
pale_green = 0x98FB98, // rgb(152,251,152)
|
||||
pale_turquoise = 0xAFEEEE, // rgb(175,238,238)
|
||||
pale_violet_red = 0xDB7093, // rgb(219,112,147)
|
||||
papaya_whip = 0xFFEFD5, // rgb(255,239,213)
|
||||
peach_puff = 0xFFDAB9, // rgb(255,218,185)
|
||||
peru = 0xCD853F, // rgb(205,133,63)
|
||||
pink = 0xFFC0CB, // rgb(255,192,203)
|
||||
plum = 0xDDA0DD, // rgb(221,160,221)
|
||||
powder_blue = 0xB0E0E6, // rgb(176,224,230)
|
||||
purple = 0x800080, // rgb(128,0,128)
|
||||
rebecca_purple = 0x663399, // rgb(102,51,153)
|
||||
red = 0xFF0000, // rgb(255,0,0)
|
||||
rosy_brown = 0xBC8F8F, // rgb(188,143,143)
|
||||
royal_blue = 0x4169E1, // rgb(65,105,225)
|
||||
saddle_brown = 0x8B4513, // rgb(139,69,19)
|
||||
salmon = 0xFA8072, // rgb(250,128,114)
|
||||
sandy_brown = 0xF4A460, // rgb(244,164,96)
|
||||
sea_green = 0x2E8B57, // rgb(46,139,87)
|
||||
sea_shell = 0xFFF5EE, // rgb(255,245,238)
|
||||
sienna = 0xA0522D, // rgb(160,82,45)
|
||||
silver = 0xC0C0C0, // rgb(192,192,192)
|
||||
sky_blue = 0x87CEEB, // rgb(135,206,235)
|
||||
slate_blue = 0x6A5ACD, // rgb(106,90,205)
|
||||
slate_gray = 0x708090, // rgb(112,128,144)
|
||||
snow = 0xFFFAFA, // rgb(255,250,250)
|
||||
spring_green = 0x00FF7F, // rgb(0,255,127)
|
||||
steel_blue = 0x4682B4, // rgb(70,130,180)
|
||||
tan = 0xD2B48C, // rgb(210,180,140)
|
||||
teal = 0x008080, // rgb(0,128,128)
|
||||
thistle = 0xD8BFD8, // rgb(216,191,216)
|
||||
tomato = 0xFF6347, // rgb(255,99,71)
|
||||
turquoise = 0x40E0D0, // rgb(64,224,208)
|
||||
violet = 0xEE82EE, // rgb(238,130,238)
|
||||
wheat = 0xF5DEB3, // rgb(245,222,179)
|
||||
white = 0xFFFFFF, // rgb(255,255,255)
|
||||
white_smoke = 0xF5F5F5, // rgb(245,245,245)
|
||||
yellow = 0xFFFF00, // rgb(255,255,0)
|
||||
yellow_green = 0x9ACD32 // rgb(154,205,50)
|
||||
}; // enum class color
|
||||
|
||||
enum class terminal_color : uint8_t {
|
||||
black = 30,
|
||||
red,
|
||||
green,
|
||||
yellow,
|
||||
blue,
|
||||
magenta,
|
||||
cyan,
|
||||
white,
|
||||
bright_black = 90,
|
||||
bright_red,
|
||||
bright_green,
|
||||
bright_yellow,
|
||||
bright_blue,
|
||||
bright_magenta,
|
||||
bright_cyan,
|
||||
bright_white
|
||||
}; // enum class terminal_color
|
||||
|
||||
enum class emphasis : uint8_t {
|
||||
bold = 1,
|
||||
italic = 1 << 1,
|
||||
underline = 1 << 2,
|
||||
strikethrough = 1 << 3
|
||||
}; // enum class emphasis
|
||||
|
||||
// rgb is a struct for red, green and blue colors.
|
||||
// We use rgb as name because some editors will show it as color direct in the
|
||||
// editor.
|
||||
struct rgb {
|
||||
FMT_CONSTEXPR_DECL rgb() : r(0), g(0), b(0) {}
|
||||
FMT_CONSTEXPR_DECL rgb(uint8_t r_, uint8_t g_, uint8_t b_)
|
||||
: r(r_), g(g_), b(b_) {}
|
||||
FMT_CONSTEXPR_DECL rgb(uint32_t hex)
|
||||
: r((hex >> 16) & 0xFF), g((hex >> 8) & 0xFF), b((hex) & 0xFF) {}
|
||||
FMT_CONSTEXPR_DECL rgb(color hex)
|
||||
: r((uint32_t(hex) >> 16) & 0xFF), g((uint32_t(hex) >> 8) & 0xFF),
|
||||
b(uint32_t(hex) & 0xFF) {}
|
||||
uint8_t r;
|
||||
uint8_t g;
|
||||
uint8_t b;
|
||||
};
|
||||
|
||||
namespace internal {
|
||||
|
||||
// color is a struct of either a rgb color or a terminal color.
|
||||
struct color_type {
|
||||
FMT_CONSTEXPR color_type() FMT_NOEXCEPT
|
||||
: is_rgb(), value{} {}
|
||||
FMT_CONSTEXPR color_type(color rgb_color) FMT_NOEXCEPT
|
||||
: is_rgb(true), value{} {
|
||||
value.rgb_color = static_cast<uint32_t>(rgb_color);
|
||||
}
|
||||
FMT_CONSTEXPR color_type(rgb rgb_color) FMT_NOEXCEPT
|
||||
: is_rgb(true), value{} {
|
||||
value.rgb_color = (static_cast<uint32_t>(rgb_color.r) << 16)
|
||||
| (static_cast<uint32_t>(rgb_color.g) << 8) | rgb_color.b;
|
||||
}
|
||||
FMT_CONSTEXPR color_type(terminal_color term_color) FMT_NOEXCEPT
|
||||
: is_rgb(), value{} {
|
||||
value.term_color = static_cast<uint8_t>(term_color);
|
||||
}
|
||||
bool is_rgb;
|
||||
union color_union {
|
||||
uint8_t term_color;
|
||||
uint32_t rgb_color;
|
||||
} value;
|
||||
};
|
||||
} // namespace internal
|
||||
|
||||
// Experimental text formatting support.
|
||||
class text_style {
|
||||
public:
|
||||
FMT_CONSTEXPR text_style(emphasis em = emphasis()) FMT_NOEXCEPT
|
||||
: set_foreground_color(), set_background_color(), ems(em) {}
|
||||
|
||||
FMT_CONSTEXPR text_style &operator|=(const text_style &rhs) {
|
||||
if (!set_foreground_color) {
|
||||
set_foreground_color = rhs.set_foreground_color;
|
||||
foreground_color = rhs.foreground_color;
|
||||
} else if (rhs.set_foreground_color) {
|
||||
if (!foreground_color.is_rgb || !rhs.foreground_color.is_rgb)
|
||||
throw format_error("can't OR a terminal color");
|
||||
foreground_color.value.rgb_color |= rhs.foreground_color.value.rgb_color;
|
||||
}
|
||||
|
||||
if (!set_background_color) {
|
||||
set_background_color = rhs.set_background_color;
|
||||
background_color = rhs.background_color;
|
||||
} else if (rhs.set_background_color) {
|
||||
if (!background_color.is_rgb || !rhs.background_color.is_rgb)
|
||||
throw format_error("can't OR a terminal color");
|
||||
background_color.value.rgb_color |= rhs.background_color.value.rgb_color;
|
||||
}
|
||||
|
||||
ems = static_cast<emphasis>(static_cast<uint8_t>(ems) |
|
||||
static_cast<uint8_t>(rhs.ems));
|
||||
return *this;
|
||||
}
|
||||
|
||||
friend FMT_CONSTEXPR
|
||||
text_style operator|(text_style lhs, const text_style &rhs) {
|
||||
return lhs |= rhs;
|
||||
}
|
||||
|
||||
FMT_CONSTEXPR text_style &operator&=(const text_style &rhs) {
|
||||
if (!set_foreground_color) {
|
||||
set_foreground_color = rhs.set_foreground_color;
|
||||
foreground_color = rhs.foreground_color;
|
||||
} else if (rhs.set_foreground_color) {
|
||||
if (!foreground_color.is_rgb || !rhs.foreground_color.is_rgb)
|
||||
throw format_error("can't AND a terminal color");
|
||||
foreground_color.value.rgb_color &= rhs.foreground_color.value.rgb_color;
|
||||
}
|
||||
|
||||
if (!set_background_color) {
|
||||
set_background_color = rhs.set_background_color;
|
||||
background_color = rhs.background_color;
|
||||
} else if (rhs.set_background_color) {
|
||||
if (!background_color.is_rgb || !rhs.background_color.is_rgb)
|
||||
throw format_error("can't AND a terminal color");
|
||||
background_color.value.rgb_color &= rhs.background_color.value.rgb_color;
|
||||
}
|
||||
|
||||
ems = static_cast<emphasis>(static_cast<uint8_t>(ems) &
|
||||
static_cast<uint8_t>(rhs.ems));
|
||||
return *this;
|
||||
}
|
||||
|
||||
friend FMT_CONSTEXPR
|
||||
text_style operator&(text_style lhs, const text_style &rhs) {
|
||||
return lhs &= rhs;
|
||||
}
|
||||
|
||||
FMT_CONSTEXPR bool has_foreground() const FMT_NOEXCEPT {
|
||||
return set_foreground_color;
|
||||
}
|
||||
FMT_CONSTEXPR bool has_background() const FMT_NOEXCEPT {
|
||||
return set_background_color;
|
||||
}
|
||||
FMT_CONSTEXPR bool has_emphasis() const FMT_NOEXCEPT {
|
||||
return static_cast<uint8_t>(ems) != 0;
|
||||
}
|
||||
FMT_CONSTEXPR internal::color_type get_foreground() const FMT_NOEXCEPT {
|
||||
assert(has_foreground() && "no foreground specified for this style");
|
||||
return foreground_color;
|
||||
}
|
||||
FMT_CONSTEXPR internal::color_type get_background() const FMT_NOEXCEPT {
|
||||
assert(has_background() && "no background specified for this style");
|
||||
return background_color;
|
||||
}
|
||||
FMT_CONSTEXPR emphasis get_emphasis() const FMT_NOEXCEPT {
|
||||
assert(has_emphasis() && "no emphasis specified for this style");
|
||||
return ems;
|
||||
}
|
||||
|
||||
private:
|
||||
FMT_CONSTEXPR text_style(bool is_foreground,
|
||||
internal::color_type text_color) FMT_NOEXCEPT
|
||||
: set_foreground_color(),
|
||||
set_background_color(),
|
||||
ems() {
|
||||
if (is_foreground) {
|
||||
foreground_color = text_color;
|
||||
set_foreground_color = true;
|
||||
} else {
|
||||
background_color = text_color;
|
||||
set_background_color = true;
|
||||
}
|
||||
}
|
||||
|
||||
friend FMT_CONSTEXPR_DECL text_style fg(internal::color_type foreground)
|
||||
FMT_NOEXCEPT;
|
||||
friend FMT_CONSTEXPR_DECL text_style bg(internal::color_type background)
|
||||
FMT_NOEXCEPT;
|
||||
|
||||
internal::color_type foreground_color;
|
||||
internal::color_type background_color;
|
||||
bool set_foreground_color;
|
||||
bool set_background_color;
|
||||
emphasis ems;
|
||||
};
|
||||
|
||||
FMT_CONSTEXPR text_style fg(internal::color_type foreground) FMT_NOEXCEPT {
|
||||
return text_style(/*is_foreground=*/true, foreground);
|
||||
}
|
||||
|
||||
FMT_CONSTEXPR text_style bg(internal::color_type background) FMT_NOEXCEPT {
|
||||
return text_style(/*is_foreground=*/false, background);
|
||||
}
|
||||
|
||||
FMT_CONSTEXPR text_style operator|(emphasis lhs, emphasis rhs) FMT_NOEXCEPT {
|
||||
return text_style(lhs) | rhs;
|
||||
}
|
||||
|
||||
namespace internal {
|
||||
|
||||
template <typename Char>
|
||||
struct ansi_color_escape {
|
||||
FMT_CONSTEXPR ansi_color_escape(internal::color_type text_color,
|
||||
const char * esc) FMT_NOEXCEPT {
|
||||
// If we have a terminal color, we need to output another escape code
|
||||
// sequence.
|
||||
if (!text_color.is_rgb) {
|
||||
bool is_background = esc == internal::data::BACKGROUND_COLOR;
|
||||
uint32_t value = text_color.value.term_color;
|
||||
// Background ASCII codes are the same as the foreground ones but with
|
||||
// 10 more.
|
||||
if (is_background)
|
||||
value += 10u;
|
||||
|
||||
std::size_t index = 0;
|
||||
buffer[index++] = static_cast<Char>('\x1b');
|
||||
buffer[index++] = static_cast<Char>('[');
|
||||
|
||||
if (value >= 100u) {
|
||||
buffer[index++] = static_cast<Char>('1');
|
||||
value %= 100u;
|
||||
}
|
||||
buffer[index++] = static_cast<Char>('0' + value / 10u);
|
||||
buffer[index++] = static_cast<Char>('0' + value % 10u);
|
||||
|
||||
buffer[index++] = static_cast<Char>('m');
|
||||
buffer[index++] = static_cast<Char>('\0');
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 0; i < 7; i++) {
|
||||
buffer[i] = static_cast<Char>(esc[i]);
|
||||
}
|
||||
rgb color(text_color.value.rgb_color);
|
||||
to_esc(color.r, buffer + 7, ';');
|
||||
to_esc(color.g, buffer + 11, ';');
|
||||
to_esc(color.b, buffer + 15, 'm');
|
||||
buffer[19] = static_cast<Char>(0);
|
||||
}
|
||||
FMT_CONSTEXPR ansi_color_escape(emphasis em) FMT_NOEXCEPT {
|
||||
uint8_t em_codes[4] = {};
|
||||
uint8_t em_bits = static_cast<uint8_t>(em);
|
||||
if (em_bits & static_cast<uint8_t>(emphasis::bold))
|
||||
em_codes[0] = 1;
|
||||
if (em_bits & static_cast<uint8_t>(emphasis::italic))
|
||||
em_codes[1] = 3;
|
||||
if (em_bits & static_cast<uint8_t>(emphasis::underline))
|
||||
em_codes[2] = 4;
|
||||
if (em_bits & static_cast<uint8_t>(emphasis::strikethrough))
|
||||
em_codes[3] = 9;
|
||||
|
||||
std::size_t index = 0;
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
if (!em_codes[i])
|
||||
continue;
|
||||
buffer[index++] = static_cast<Char>('\x1b');
|
||||
buffer[index++] = static_cast<Char>('[');
|
||||
buffer[index++] = static_cast<Char>('0' + em_codes[i]);
|
||||
buffer[index++] = static_cast<Char>('m');
|
||||
}
|
||||
buffer[index++] = static_cast<Char>(0);
|
||||
}
|
||||
FMT_CONSTEXPR operator const Char *() const FMT_NOEXCEPT { return buffer; }
|
||||
|
||||
private:
|
||||
Char buffer[7u + 3u * 4u + 1u];
|
||||
|
||||
static FMT_CONSTEXPR void to_esc(uint8_t c, Char *out,
|
||||
char delimiter) FMT_NOEXCEPT {
|
||||
out[0] = static_cast<Char>('0' + c / 100);
|
||||
out[1] = static_cast<Char>('0' + c / 10 % 10);
|
||||
out[2] = static_cast<Char>('0' + c % 10);
|
||||
out[3] = static_cast<Char>(delimiter);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Char>
|
||||
FMT_CONSTEXPR ansi_color_escape<Char>
|
||||
make_foreground_color(internal::color_type foreground) FMT_NOEXCEPT {
|
||||
return ansi_color_escape<Char>(foreground, internal::data::FOREGROUND_COLOR);
|
||||
}
|
||||
|
||||
template <typename Char>
|
||||
FMT_CONSTEXPR ansi_color_escape<Char>
|
||||
make_background_color(internal::color_type background) FMT_NOEXCEPT {
|
||||
return ansi_color_escape<Char>(background, internal::data::BACKGROUND_COLOR);
|
||||
}
|
||||
|
||||
template <typename Char>
|
||||
FMT_CONSTEXPR ansi_color_escape<Char>
|
||||
make_emphasis(emphasis em) FMT_NOEXCEPT {
|
||||
return ansi_color_escape<Char>(em);
|
||||
}
|
||||
|
||||
template <typename Char>
|
||||
inline void fputs(const Char *chars, FILE *stream) FMT_NOEXCEPT {
|
||||
std::fputs(chars, stream);
|
||||
}
|
||||
|
||||
template <>
|
||||
inline void fputs<wchar_t>(const wchar_t *chars, FILE *stream) FMT_NOEXCEPT {
|
||||
std::fputws(chars, stream);
|
||||
}
|
||||
|
||||
template <typename Char>
|
||||
inline void reset_color(FILE *stream) FMT_NOEXCEPT {
|
||||
fputs(internal::data::RESET_COLOR, stream);
|
||||
}
|
||||
|
||||
template <>
|
||||
inline void reset_color<wchar_t>(FILE *stream) FMT_NOEXCEPT {
|
||||
fputs(internal::data::WRESET_COLOR, stream);
|
||||
}
|
||||
|
||||
// The following specialiazation disables using std::FILE as a character type,
|
||||
// which is needed because or else
|
||||
// fmt::print(stderr, fmt::emphasis::bold, "");
|
||||
// would take stderr (a std::FILE *) as the format string.
|
||||
template <>
|
||||
struct is_string<std::FILE *> : std::false_type {};
|
||||
template <>
|
||||
struct is_string<const std::FILE *> : std::false_type {};
|
||||
} // namespace internal
|
||||
|
||||
template <
|
||||
typename S, typename Char = typename internal::char_t<S>::type>
|
||||
void vprint(std::FILE *f, const text_style &ts, const S &format,
|
||||
basic_format_args<typename buffer_context<Char>::type> args) {
|
||||
bool has_style = false;
|
||||
if (ts.has_emphasis()) {
|
||||
has_style = true;
|
||||
internal::fputs<Char>(
|
||||
internal::make_emphasis<Char>(ts.get_emphasis()), f);
|
||||
}
|
||||
if (ts.has_foreground()) {
|
||||
has_style = true;
|
||||
internal::fputs<Char>(
|
||||
internal::make_foreground_color<Char>(ts.get_foreground()), f);
|
||||
}
|
||||
if (ts.has_background()) {
|
||||
has_style = true;
|
||||
internal::fputs<Char>(
|
||||
internal::make_background_color<Char>(ts.get_background()), f);
|
||||
}
|
||||
vprint(f, format, args);
|
||||
if (has_style) {
|
||||
internal::reset_color<Char>(f);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Formats a string and prints it to the specified file stream using ANSI
|
||||
escape sequences to specify text formatting.
|
||||
Example:
|
||||
fmt::print(fmt::emphasis::bold | fg(fmt::color::red),
|
||||
"Elapsed time: {0:.2f} seconds", 1.23);
|
||||
*/
|
||||
template <typename String, typename... Args>
|
||||
typename std::enable_if<internal::is_string<String>::value>::type print(
|
||||
std::FILE *f, const text_style &ts, const String &format_str,
|
||||
const Args &... args) {
|
||||
internal::check_format_string<Args...>(format_str);
|
||||
typedef typename internal::char_t<String>::type char_t;
|
||||
typedef typename buffer_context<char_t>::type context_t;
|
||||
format_arg_store<context_t, Args...> as{args...};
|
||||
vprint(f, ts, format_str, basic_format_args<context_t>(as));
|
||||
}
|
||||
|
||||
/**
|
||||
Formats a string and prints it to stdout using ANSI escape sequences to
|
||||
specify text formatting.
|
||||
Example:
|
||||
fmt::print(fmt::emphasis::bold | fg(fmt::color::red),
|
||||
"Elapsed time: {0:.2f} seconds", 1.23);
|
||||
*/
|
||||
template <typename String, typename... Args>
|
||||
typename std::enable_if<internal::is_string<String>::value>::type print(
|
||||
const text_style &ts, const String &format_str,
|
||||
const Args &... args) {
|
||||
return print(stdout, ts, format_str, args...);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
FMT_END_NAMESPACE
|
||||
|
||||
#endif // FMT_COLOR_H_
|
1502
include/Livox/third_party/spdlog/spdlog/fmt/bundled/core.h
vendored
Executable file
1502
include/Livox/third_party/spdlog/spdlog/fmt/bundled/core.h
vendored
Executable file
File diff suppressed because it is too large
Load Diff
972
include/Livox/third_party/spdlog/spdlog/fmt/bundled/format-inl.h
vendored
Executable file
972
include/Livox/third_party/spdlog/spdlog/fmt/bundled/format-inl.h
vendored
Executable file
@ -0,0 +1,972 @@
|
||||
// Formatting library for C++
|
||||
//
|
||||
// Copyright (c) 2012 - 2016, Victor Zverovich
|
||||
// All rights reserved.
|
||||
//
|
||||
// For the license information refer to format.h.
|
||||
|
||||
#ifndef FMT_FORMAT_INL_H_
|
||||
#define FMT_FORMAT_INL_H_
|
||||
|
||||
#include "format.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include <cctype>
|
||||
#include <cerrno>
|
||||
#include <climits>
|
||||
#include <cmath>
|
||||
#include <cstdarg>
|
||||
#include <cstddef> // for std::ptrdiff_t
|
||||
#include <cstring> // for std::memmove
|
||||
#if !defined(FMT_STATIC_THOUSANDS_SEPARATOR)
|
||||
# include <locale>
|
||||
#endif
|
||||
|
||||
#if FMT_USE_WINDOWS_H
|
||||
# if !defined(FMT_HEADER_ONLY) && !defined(WIN32_LEAN_AND_MEAN)
|
||||
# define WIN32_LEAN_AND_MEAN
|
||||
# endif
|
||||
# if defined(NOMINMAX) || defined(FMT_WIN_MINMAX)
|
||||
# include <windows.h>
|
||||
# else
|
||||
# define NOMINMAX
|
||||
# include <windows.h>
|
||||
# undef NOMINMAX
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if FMT_EXCEPTIONS
|
||||
# define FMT_TRY try
|
||||
# define FMT_CATCH(x) catch (x)
|
||||
#else
|
||||
# define FMT_TRY if (true)
|
||||
# define FMT_CATCH(x) if (false)
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
# pragma warning(push)
|
||||
# pragma warning(disable: 4127) // conditional expression is constant
|
||||
# pragma warning(disable: 4702) // unreachable code
|
||||
// Disable deprecation warning for strerror. The latter is not called but
|
||||
// MSVC fails to detect it.
|
||||
# pragma warning(disable: 4996)
|
||||
#endif
|
||||
|
||||
// Dummy implementations of strerror_r and strerror_s called if corresponding
|
||||
// system functions are not available.
|
||||
inline fmt::internal::null<> strerror_r(int, char *, ...) {
|
||||
return fmt::internal::null<>();
|
||||
}
|
||||
inline fmt::internal::null<> strerror_s(char *, std::size_t, ...) {
|
||||
return fmt::internal::null<>();
|
||||
}
|
||||
|
||||
FMT_BEGIN_NAMESPACE
|
||||
|
||||
namespace {
|
||||
|
||||
#ifndef _MSC_VER
|
||||
# define FMT_SNPRINTF snprintf
|
||||
#else // _MSC_VER
|
||||
inline int fmt_snprintf(char *buffer, size_t size, const char *format, ...) {
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
int result = vsnprintf_s(buffer, size, _TRUNCATE, format, args);
|
||||
va_end(args);
|
||||
return result;
|
||||
}
|
||||
# define FMT_SNPRINTF fmt_snprintf
|
||||
#endif // _MSC_VER
|
||||
|
||||
#if defined(_WIN32) && defined(__MINGW32__) && !defined(__NO_ISOCEXT)
|
||||
# define FMT_SWPRINTF snwprintf
|
||||
#else
|
||||
# define FMT_SWPRINTF swprintf
|
||||
#endif // defined(_WIN32) && defined(__MINGW32__) && !defined(__NO_ISOCEXT)
|
||||
|
||||
typedef void (*FormatFunc)(internal::buffer &, int, string_view);
|
||||
|
||||
// Portable thread-safe version of strerror.
|
||||
// Sets buffer to point to a string describing the error code.
|
||||
// This can be either a pointer to a string stored in buffer,
|
||||
// or a pointer to some static immutable string.
|
||||
// Returns one of the following values:
|
||||
// 0 - success
|
||||
// ERANGE - buffer is not large enough to store the error message
|
||||
// other - failure
|
||||
// Buffer should be at least of size 1.
|
||||
int safe_strerror(
|
||||
int error_code, char *&buffer, std::size_t buffer_size) FMT_NOEXCEPT {
|
||||
FMT_ASSERT(buffer != FMT_NULL && buffer_size != 0, "invalid buffer");
|
||||
|
||||
class dispatcher {
|
||||
private:
|
||||
int error_code_;
|
||||
char *&buffer_;
|
||||
std::size_t buffer_size_;
|
||||
|
||||
// A noop assignment operator to avoid bogus warnings.
|
||||
void operator=(const dispatcher &) {}
|
||||
|
||||
// Handle the result of XSI-compliant version of strerror_r.
|
||||
int handle(int result) {
|
||||
// glibc versions before 2.13 return result in errno.
|
||||
return result == -1 ? errno : result;
|
||||
}
|
||||
|
||||
// Handle the result of GNU-specific version of strerror_r.
|
||||
int handle(char *message) {
|
||||
// If the buffer is full then the message is probably truncated.
|
||||
if (message == buffer_ && strlen(buffer_) == buffer_size_ - 1)
|
||||
return ERANGE;
|
||||
buffer_ = message;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Handle the case when strerror_r is not available.
|
||||
int handle(internal::null<>) {
|
||||
return fallback(strerror_s(buffer_, buffer_size_, error_code_));
|
||||
}
|
||||
|
||||
// Fallback to strerror_s when strerror_r is not available.
|
||||
int fallback(int result) {
|
||||
// If the buffer is full then the message is probably truncated.
|
||||
return result == 0 && strlen(buffer_) == buffer_size_ - 1 ?
|
||||
ERANGE : result;
|
||||
}
|
||||
|
||||
#if !FMT_MSC_VER
|
||||
// Fallback to strerror if strerror_r and strerror_s are not available.
|
||||
int fallback(internal::null<>) {
|
||||
errno = 0;
|
||||
buffer_ = strerror(error_code_);
|
||||
return errno;
|
||||
}
|
||||
#endif
|
||||
|
||||
public:
|
||||
dispatcher(int err_code, char *&buf, std::size_t buf_size)
|
||||
: error_code_(err_code), buffer_(buf), buffer_size_(buf_size) {}
|
||||
|
||||
int run() {
|
||||
return handle(strerror_r(error_code_, buffer_, buffer_size_));
|
||||
}
|
||||
};
|
||||
return dispatcher(error_code, buffer, buffer_size).run();
|
||||
}
|
||||
|
||||
void format_error_code(internal::buffer &out, int error_code,
|
||||
string_view message) FMT_NOEXCEPT {
|
||||
// Report error code making sure that the output fits into
|
||||
// inline_buffer_size to avoid dynamic memory allocation and potential
|
||||
// bad_alloc.
|
||||
out.resize(0);
|
||||
static const char SEP[] = ": ";
|
||||
static const char ERROR_STR[] = "error ";
|
||||
// Subtract 2 to account for terminating null characters in SEP and ERROR_STR.
|
||||
std::size_t error_code_size = sizeof(SEP) + sizeof(ERROR_STR) - 2;
|
||||
typedef internal::int_traits<int>::main_type main_type;
|
||||
main_type abs_value = static_cast<main_type>(error_code);
|
||||
if (internal::is_negative(error_code)) {
|
||||
abs_value = 0 - abs_value;
|
||||
++error_code_size;
|
||||
}
|
||||
error_code_size += internal::to_unsigned(internal::count_digits(abs_value));
|
||||
writer w(out);
|
||||
if (message.size() <= inline_buffer_size - error_code_size) {
|
||||
w.write(message);
|
||||
w.write(SEP);
|
||||
}
|
||||
w.write(ERROR_STR);
|
||||
w.write(error_code);
|
||||
assert(out.size() <= inline_buffer_size);
|
||||
}
|
||||
|
||||
void report_error(FormatFunc func, int error_code,
|
||||
string_view message) FMT_NOEXCEPT {
|
||||
memory_buffer full_message;
|
||||
func(full_message, error_code, message);
|
||||
// Use Writer::data instead of Writer::c_str to avoid potential memory
|
||||
// allocation.
|
||||
std::fwrite(full_message.data(), full_message.size(), 1, stderr);
|
||||
std::fputc('\n', stderr);
|
||||
}
|
||||
} // namespace
|
||||
|
||||
FMT_FUNC size_t internal::count_code_points(basic_string_view<char8_t> s) {
|
||||
const char8_t *data = s.data();
|
||||
size_t num_code_points = 0;
|
||||
for (size_t i = 0, size = s.size(); i != size; ++i) {
|
||||
if ((data[i] & 0xc0) != 0x80)
|
||||
++num_code_points;
|
||||
}
|
||||
return num_code_points;
|
||||
}
|
||||
|
||||
#if !defined(FMT_STATIC_THOUSANDS_SEPARATOR)
|
||||
namespace internal {
|
||||
|
||||
template <typename Locale>
|
||||
locale_ref::locale_ref(const Locale &loc) : locale_(&loc) {
|
||||
static_assert(std::is_same<Locale, std::locale>::value, "");
|
||||
}
|
||||
|
||||
template <typename Locale>
|
||||
Locale locale_ref::get() const {
|
||||
static_assert(std::is_same<Locale, std::locale>::value, "");
|
||||
return locale_ ? *static_cast<const std::locale*>(locale_) : std::locale();
|
||||
}
|
||||
|
||||
template <typename Char>
|
||||
FMT_FUNC Char thousands_sep_impl(locale_ref loc) {
|
||||
return std::use_facet<std::numpunct<Char> >(
|
||||
loc.get<std::locale>()).thousands_sep();
|
||||
}
|
||||
}
|
||||
#else
|
||||
template <typename Char>
|
||||
FMT_FUNC Char internal::thousands_sep_impl(locale_ref) {
|
||||
return FMT_STATIC_THOUSANDS_SEPARATOR;
|
||||
}
|
||||
#endif
|
||||
|
||||
FMT_FUNC void system_error::init(
|
||||
int err_code, string_view format_str, format_args args) {
|
||||
error_code_ = err_code;
|
||||
memory_buffer buffer;
|
||||
format_system_error(buffer, err_code, vformat(format_str, args));
|
||||
std::runtime_error &base = *this;
|
||||
base = std::runtime_error(to_string(buffer));
|
||||
}
|
||||
|
||||
namespace internal {
|
||||
template <typename T>
|
||||
int char_traits<char>::format_float(
|
||||
char *buf, std::size_t size, const char *format, int precision, T value) {
|
||||
return precision < 0 ?
|
||||
FMT_SNPRINTF(buf, size, format, value) :
|
||||
FMT_SNPRINTF(buf, size, format, precision, value);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
int char_traits<wchar_t>::format_float(
|
||||
wchar_t *buf, std::size_t size, const wchar_t *format, int precision,
|
||||
T value) {
|
||||
return precision < 0 ?
|
||||
FMT_SWPRINTF(buf, size, format, value) :
|
||||
FMT_SWPRINTF(buf, size, format, precision, value);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
const char basic_data<T>::DIGITS[] =
|
||||
"0001020304050607080910111213141516171819"
|
||||
"2021222324252627282930313233343536373839"
|
||||
"4041424344454647484950515253545556575859"
|
||||
"6061626364656667686970717273747576777879"
|
||||
"8081828384858687888990919293949596979899";
|
||||
|
||||
#define FMT_POWERS_OF_10(factor) \
|
||||
factor * 10, \
|
||||
factor * 100, \
|
||||
factor * 1000, \
|
||||
factor * 10000, \
|
||||
factor * 100000, \
|
||||
factor * 1000000, \
|
||||
factor * 10000000, \
|
||||
factor * 100000000, \
|
||||
factor * 1000000000
|
||||
|
||||
template <typename T>
|
||||
const uint32_t basic_data<T>::POWERS_OF_10_32[] = {
|
||||
1, FMT_POWERS_OF_10(1)
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
const uint32_t basic_data<T>::ZERO_OR_POWERS_OF_10_32[] = {
|
||||
0, FMT_POWERS_OF_10(1)
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
const uint64_t basic_data<T>::ZERO_OR_POWERS_OF_10_64[] = {
|
||||
0,
|
||||
FMT_POWERS_OF_10(1),
|
||||
FMT_POWERS_OF_10(1000000000ull),
|
||||
10000000000000000000ull
|
||||
};
|
||||
|
||||
// Normalized 64-bit significands of pow(10, k), for k = -348, -340, ..., 340.
|
||||
// These are generated by support/compute-powers.py.
|
||||
template <typename T>
|
||||
const uint64_t basic_data<T>::POW10_SIGNIFICANDS[] = {
|
||||
0xfa8fd5a0081c0288, 0xbaaee17fa23ebf76, 0x8b16fb203055ac76,
|
||||
0xcf42894a5dce35ea, 0x9a6bb0aa55653b2d, 0xe61acf033d1a45df,
|
||||
0xab70fe17c79ac6ca, 0xff77b1fcbebcdc4f, 0xbe5691ef416bd60c,
|
||||
0x8dd01fad907ffc3c, 0xd3515c2831559a83, 0x9d71ac8fada6c9b5,
|
||||
0xea9c227723ee8bcb, 0xaecc49914078536d, 0x823c12795db6ce57,
|
||||
0xc21094364dfb5637, 0x9096ea6f3848984f, 0xd77485cb25823ac7,
|
||||
0xa086cfcd97bf97f4, 0xef340a98172aace5, 0xb23867fb2a35b28e,
|
||||
0x84c8d4dfd2c63f3b, 0xc5dd44271ad3cdba, 0x936b9fcebb25c996,
|
||||
0xdbac6c247d62a584, 0xa3ab66580d5fdaf6, 0xf3e2f893dec3f126,
|
||||
0xb5b5ada8aaff80b8, 0x87625f056c7c4a8b, 0xc9bcff6034c13053,
|
||||
0x964e858c91ba2655, 0xdff9772470297ebd, 0xa6dfbd9fb8e5b88f,
|
||||
0xf8a95fcf88747d94, 0xb94470938fa89bcf, 0x8a08f0f8bf0f156b,
|
||||
0xcdb02555653131b6, 0x993fe2c6d07b7fac, 0xe45c10c42a2b3b06,
|
||||
0xaa242499697392d3, 0xfd87b5f28300ca0e, 0xbce5086492111aeb,
|
||||
0x8cbccc096f5088cc, 0xd1b71758e219652c, 0x9c40000000000000,
|
||||
0xe8d4a51000000000, 0xad78ebc5ac620000, 0x813f3978f8940984,
|
||||
0xc097ce7bc90715b3, 0x8f7e32ce7bea5c70, 0xd5d238a4abe98068,
|
||||
0x9f4f2726179a2245, 0xed63a231d4c4fb27, 0xb0de65388cc8ada8,
|
||||
0x83c7088e1aab65db, 0xc45d1df942711d9a, 0x924d692ca61be758,
|
||||
0xda01ee641a708dea, 0xa26da3999aef774a, 0xf209787bb47d6b85,
|
||||
0xb454e4a179dd1877, 0x865b86925b9bc5c2, 0xc83553c5c8965d3d,
|
||||
0x952ab45cfa97a0b3, 0xde469fbd99a05fe3, 0xa59bc234db398c25,
|
||||
0xf6c69a72a3989f5c, 0xb7dcbf5354e9bece, 0x88fcf317f22241e2,
|
||||
0xcc20ce9bd35c78a5, 0x98165af37b2153df, 0xe2a0b5dc971f303a,
|
||||
0xa8d9d1535ce3b396, 0xfb9b7cd9a4a7443c, 0xbb764c4ca7a44410,
|
||||
0x8bab8eefb6409c1a, 0xd01fef10a657842c, 0x9b10a4e5e9913129,
|
||||
0xe7109bfba19c0c9d, 0xac2820d9623bf429, 0x80444b5e7aa7cf85,
|
||||
0xbf21e44003acdd2d, 0x8e679c2f5e44ff8f, 0xd433179d9c8cb841,
|
||||
0x9e19db92b4e31ba9, 0xeb96bf6ebadf77d9, 0xaf87023b9bf0ee6b,
|
||||
};
|
||||
|
||||
// Binary exponents of pow(10, k), for k = -348, -340, ..., 340, corresponding
|
||||
// to significands above.
|
||||
template <typename T>
|
||||
const int16_t basic_data<T>::POW10_EXPONENTS[] = {
|
||||
-1220, -1193, -1166, -1140, -1113, -1087, -1060, -1034, -1007, -980, -954,
|
||||
-927, -901, -874, -847, -821, -794, -768, -741, -715, -688, -661,
|
||||
-635, -608, -582, -555, -529, -502, -475, -449, -422, -396, -369,
|
||||
-343, -316, -289, -263, -236, -210, -183, -157, -130, -103, -77,
|
||||
-50, -24, 3, 30, 56, 83, 109, 136, 162, 189, 216,
|
||||
242, 269, 295, 322, 348, 375, 402, 428, 455, 481, 508,
|
||||
534, 561, 588, 614, 641, 667, 694, 720, 747, 774, 800,
|
||||
827, 853, 880, 907, 933, 960, 986, 1013, 1039, 1066
|
||||
};
|
||||
|
||||
template <typename T> const char basic_data<T>::FOREGROUND_COLOR[] = "\x1b[38;2;";
|
||||
template <typename T> const char basic_data<T>::BACKGROUND_COLOR[] = "\x1b[48;2;";
|
||||
template <typename T> const char basic_data<T>::RESET_COLOR[] = "\x1b[0m";
|
||||
template <typename T> const wchar_t basic_data<T>::WRESET_COLOR[] = L"\x1b[0m";
|
||||
|
||||
// A handmade floating-point number f * pow(2, e).
|
||||
class fp {
|
||||
private:
|
||||
typedef uint64_t significand_type;
|
||||
|
||||
// All sizes are in bits.
|
||||
static FMT_CONSTEXPR_DECL const int char_size =
|
||||
std::numeric_limits<unsigned char>::digits;
|
||||
// Subtract 1 to account for an implicit most significant bit in the
|
||||
// normalized form.
|
||||
static FMT_CONSTEXPR_DECL const int double_significand_size =
|
||||
std::numeric_limits<double>::digits - 1;
|
||||
static FMT_CONSTEXPR_DECL const uint64_t implicit_bit =
|
||||
1ull << double_significand_size;
|
||||
|
||||
public:
|
||||
significand_type f;
|
||||
int e;
|
||||
|
||||
static FMT_CONSTEXPR_DECL const int significand_size =
|
||||
sizeof(significand_type) * char_size;
|
||||
|
||||
fp(): f(0), e(0) {}
|
||||
fp(uint64_t f_val, int e_val): f(f_val), e(e_val) {}
|
||||
|
||||
// Constructs fp from an IEEE754 double. It is a template to prevent compile
|
||||
// errors on platforms where double is not IEEE754.
|
||||
template <typename Double>
|
||||
explicit fp(Double d) {
|
||||
// Assume double is in the format [sign][exponent][significand].
|
||||
typedef std::numeric_limits<Double> limits;
|
||||
const int double_size = static_cast<int>(sizeof(Double) * char_size);
|
||||
const int exponent_size =
|
||||
double_size - double_significand_size - 1; // -1 for sign
|
||||
const uint64_t significand_mask = implicit_bit - 1;
|
||||
const uint64_t exponent_mask = (~0ull >> 1) & ~significand_mask;
|
||||
const int exponent_bias = (1 << exponent_size) - limits::max_exponent - 1;
|
||||
auto u = bit_cast<uint64_t>(d);
|
||||
auto biased_e = (u & exponent_mask) >> double_significand_size;
|
||||
f = u & significand_mask;
|
||||
if (biased_e != 0)
|
||||
f += implicit_bit;
|
||||
else
|
||||
biased_e = 1; // Subnormals use biased exponent 1 (min exponent).
|
||||
e = static_cast<int>(biased_e - exponent_bias - double_significand_size);
|
||||
}
|
||||
|
||||
// Normalizes the value converted from double and multiplied by (1 << SHIFT).
|
||||
template <int SHIFT = 0>
|
||||
void normalize() {
|
||||
// Handle subnormals.
|
||||
auto shifted_implicit_bit = implicit_bit << SHIFT;
|
||||
while ((f & shifted_implicit_bit) == 0) {
|
||||
f <<= 1;
|
||||
--e;
|
||||
}
|
||||
// Subtract 1 to account for hidden bit.
|
||||
auto offset = significand_size - double_significand_size - SHIFT - 1;
|
||||
f <<= offset;
|
||||
e -= offset;
|
||||
}
|
||||
|
||||
// Compute lower and upper boundaries (m^- and m^+ in the Grisu paper), where
|
||||
// a boundary is a value half way between the number and its predecessor
|
||||
// (lower) or successor (upper). The upper boundary is normalized and lower
|
||||
// has the same exponent but may be not normalized.
|
||||
void compute_boundaries(fp &lower, fp &upper) const {
|
||||
lower = f == implicit_bit ?
|
||||
fp((f << 2) - 1, e - 2) : fp((f << 1) - 1, e - 1);
|
||||
upper = fp((f << 1) + 1, e - 1);
|
||||
upper.normalize<1>(); // 1 is to account for the exponent shift above.
|
||||
lower.f <<= lower.e - upper.e;
|
||||
lower.e = upper.e;
|
||||
}
|
||||
};
|
||||
|
||||
// Returns an fp number representing x - y. Result may not be normalized.
|
||||
inline fp operator-(fp x, fp y) {
|
||||
FMT_ASSERT(x.f >= y.f && x.e == y.e, "invalid operands");
|
||||
return fp(x.f - y.f, x.e);
|
||||
}
|
||||
|
||||
// Computes an fp number r with r.f = x.f * y.f / pow(2, 64) rounded to nearest
|
||||
// with half-up tie breaking, r.e = x.e + y.e + 64. Result may not be normalized.
|
||||
FMT_API fp operator*(fp x, fp y);
|
||||
|
||||
// Returns cached power (of 10) c_k = c_k.f * pow(2, c_k.e) such that its
|
||||
// (binary) exponent satisfies min_exponent <= c_k.e <= min_exponent + 3.
|
||||
FMT_API fp get_cached_power(int min_exponent, int &pow10_exponent);
|
||||
|
||||
FMT_FUNC fp operator*(fp x, fp y) {
|
||||
// Multiply 32-bit parts of significands.
|
||||
uint64_t mask = (1ULL << 32) - 1;
|
||||
uint64_t a = x.f >> 32, b = x.f & mask;
|
||||
uint64_t c = y.f >> 32, d = y.f & mask;
|
||||
uint64_t ac = a * c, bc = b * c, ad = a * d, bd = b * d;
|
||||
// Compute mid 64-bit of result and round.
|
||||
uint64_t mid = (bd >> 32) + (ad & mask) + (bc & mask) + (1U << 31);
|
||||
return fp(ac + (ad >> 32) + (bc >> 32) + (mid >> 32), x.e + y.e + 64);
|
||||
}
|
||||
|
||||
FMT_FUNC fp get_cached_power(int min_exponent, int &pow10_exponent) {
|
||||
const double one_over_log2_10 = 0.30102999566398114; // 1 / log2(10)
|
||||
int index = static_cast<int>(std::ceil(
|
||||
(min_exponent + fp::significand_size - 1) * one_over_log2_10));
|
||||
// Decimal exponent of the first (smallest) cached power of 10.
|
||||
const int first_dec_exp = -348;
|
||||
// Difference between 2 consecutive decimal exponents in cached powers of 10.
|
||||
const int dec_exp_step = 8;
|
||||
index = (index - first_dec_exp - 1) / dec_exp_step + 1;
|
||||
pow10_exponent = first_dec_exp + index * dec_exp_step;
|
||||
return fp(data::POW10_SIGNIFICANDS[index], data::POW10_EXPONENTS[index]);
|
||||
}
|
||||
|
||||
FMT_FUNC bool grisu2_round(
|
||||
char *buf, int &size, int max_digits, uint64_t delta,
|
||||
uint64_t remainder, uint64_t exp, uint64_t diff, int &exp10) {
|
||||
while (remainder < diff && delta - remainder >= exp &&
|
||||
(remainder + exp < diff || diff - remainder > remainder + exp - diff)) {
|
||||
--buf[size - 1];
|
||||
remainder += exp;
|
||||
}
|
||||
if (size > max_digits) {
|
||||
--size;
|
||||
++exp10;
|
||||
if (buf[size] >= '5')
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Generates output using Grisu2 digit-gen algorithm.
|
||||
FMT_FUNC bool grisu2_gen_digits(
|
||||
char *buf, int &size, uint32_t hi, uint64_t lo, int &exp,
|
||||
uint64_t delta, const fp &one, const fp &diff, int max_digits) {
|
||||
// Generate digits for the most significant part (hi).
|
||||
while (exp > 0) {
|
||||
uint32_t digit = 0;
|
||||
// This optimization by miloyip reduces the number of integer divisions by
|
||||
// one per iteration.
|
||||
switch (exp) {
|
||||
case 10: digit = hi / 1000000000; hi %= 1000000000; break;
|
||||
case 9: digit = hi / 100000000; hi %= 100000000; break;
|
||||
case 8: digit = hi / 10000000; hi %= 10000000; break;
|
||||
case 7: digit = hi / 1000000; hi %= 1000000; break;
|
||||
case 6: digit = hi / 100000; hi %= 100000; break;
|
||||
case 5: digit = hi / 10000; hi %= 10000; break;
|
||||
case 4: digit = hi / 1000; hi %= 1000; break;
|
||||
case 3: digit = hi / 100; hi %= 100; break;
|
||||
case 2: digit = hi / 10; hi %= 10; break;
|
||||
case 1: digit = hi; hi = 0; break;
|
||||
default:
|
||||
FMT_ASSERT(false, "invalid number of digits");
|
||||
}
|
||||
if (digit != 0 || size != 0)
|
||||
buf[size++] = static_cast<char>('0' + digit);
|
||||
--exp;
|
||||
uint64_t remainder = (static_cast<uint64_t>(hi) << -one.e) + lo;
|
||||
if (remainder <= delta || size > max_digits) {
|
||||
return grisu2_round(
|
||||
buf, size, max_digits, delta, remainder,
|
||||
static_cast<uint64_t>(data::POWERS_OF_10_32[exp]) << -one.e,
|
||||
diff.f, exp);
|
||||
}
|
||||
}
|
||||
// Generate digits for the least significant part (lo).
|
||||
for (;;) {
|
||||
lo *= 10;
|
||||
delta *= 10;
|
||||
char digit = static_cast<char>(lo >> -one.e);
|
||||
if (digit != 0 || size != 0)
|
||||
buf[size++] = static_cast<char>('0' + digit);
|
||||
lo &= one.f - 1;
|
||||
--exp;
|
||||
if (lo < delta || size > max_digits) {
|
||||
return grisu2_round(buf, size, max_digits, delta, lo, one.f,
|
||||
diff.f * data::POWERS_OF_10_32[-exp], exp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if FMT_CLANG_VERSION
|
||||
# define FMT_FALLTHROUGH [[clang::fallthrough]];
|
||||
#elif FMT_GCC_VERSION >= 700
|
||||
# define FMT_FALLTHROUGH [[gnu::fallthrough]];
|
||||
#else
|
||||
# define FMT_FALLTHROUGH
|
||||
#endif
|
||||
|
||||
struct gen_digits_params {
|
||||
int num_digits;
|
||||
bool fixed;
|
||||
bool upper;
|
||||
bool trailing_zeros;
|
||||
};
|
||||
|
||||
struct prettify_handler {
|
||||
char *data;
|
||||
ptrdiff_t size;
|
||||
buffer &buf;
|
||||
|
||||
explicit prettify_handler(buffer &b, ptrdiff_t n)
|
||||
: data(b.data()), size(n), buf(b) {}
|
||||
~prettify_handler() {
|
||||
assert(buf.size() >= to_unsigned(size));
|
||||
buf.resize(to_unsigned(size));
|
||||
}
|
||||
|
||||
template <typename F>
|
||||
void insert(ptrdiff_t pos, ptrdiff_t n, F f) {
|
||||
std::memmove(data + pos + n, data + pos, to_unsigned(size - pos));
|
||||
f(data + pos);
|
||||
size += n;
|
||||
}
|
||||
|
||||
void insert(ptrdiff_t pos, char c) {
|
||||
std::memmove(data + pos + 1, data + pos, to_unsigned(size - pos));
|
||||
data[pos] = c;
|
||||
++size;
|
||||
}
|
||||
|
||||
void append(ptrdiff_t n, char c) {
|
||||
std::uninitialized_fill_n(data + size, n, c);
|
||||
size += n;
|
||||
}
|
||||
|
||||
void append(char c) { data[size++] = c; }
|
||||
|
||||
void remove_trailing(char c) {
|
||||
while (data[size - 1] == c) --size;
|
||||
}
|
||||
};
|
||||
|
||||
// Writes the exponent exp in the form "[+-]d{2,3}" to buffer.
|
||||
template <typename Handler>
|
||||
FMT_FUNC void write_exponent(int exp, Handler &&h) {
|
||||
FMT_ASSERT(-1000 < exp && exp < 1000, "exponent out of range");
|
||||
if (exp < 0) {
|
||||
h.append('-');
|
||||
exp = -exp;
|
||||
} else {
|
||||
h.append('+');
|
||||
}
|
||||
if (exp >= 100) {
|
||||
h.append(static_cast<char>('0' + exp / 100));
|
||||
exp %= 100;
|
||||
const char *d = data::DIGITS + exp * 2;
|
||||
h.append(d[0]);
|
||||
h.append(d[1]);
|
||||
} else {
|
||||
const char *d = data::DIGITS + exp * 2;
|
||||
h.append(d[0]);
|
||||
h.append(d[1]);
|
||||
}
|
||||
}
|
||||
|
||||
struct fill {
|
||||
size_t n;
|
||||
void operator()(char *buf) const {
|
||||
buf[0] = '0';
|
||||
buf[1] = '.';
|
||||
std::uninitialized_fill_n(buf + 2, n, '0');
|
||||
}
|
||||
};
|
||||
|
||||
// The number is given as v = f * pow(10, exp), where f has size digits.
|
||||
template <typename Handler>
|
||||
FMT_FUNC void grisu2_prettify(const gen_digits_params ¶ms,
|
||||
int size, int exp, Handler &&handler) {
|
||||
if (!params.fixed) {
|
||||
// Insert a decimal point after the first digit and add an exponent.
|
||||
handler.insert(1, '.');
|
||||
exp += size - 1;
|
||||
if (size < params.num_digits)
|
||||
handler.append(params.num_digits - size, '0');
|
||||
handler.append(params.upper ? 'E' : 'e');
|
||||
write_exponent(exp, handler);
|
||||
return;
|
||||
}
|
||||
// pow(10, full_exp - 1) <= v <= pow(10, full_exp).
|
||||
int full_exp = size + exp;
|
||||
const int exp_threshold = 21;
|
||||
if (size <= full_exp && full_exp <= exp_threshold) {
|
||||
// 1234e7 -> 12340000000[.0+]
|
||||
handler.append(full_exp - size, '0');
|
||||
int num_zeros = params.num_digits - full_exp;
|
||||
if (num_zeros > 0 && params.trailing_zeros) {
|
||||
handler.append('.');
|
||||
handler.append(num_zeros, '0');
|
||||
}
|
||||
} else if (full_exp > 0) {
|
||||
// 1234e-2 -> 12.34[0+]
|
||||
handler.insert(full_exp, '.');
|
||||
if (!params.trailing_zeros) {
|
||||
// Remove trailing zeros.
|
||||
handler.remove_trailing('0');
|
||||
} else if (params.num_digits > size) {
|
||||
// Add trailing zeros.
|
||||
ptrdiff_t num_zeros = params.num_digits - size;
|
||||
handler.append(num_zeros, '0');
|
||||
}
|
||||
} else {
|
||||
// 1234e-6 -> 0.001234
|
||||
handler.insert(0, 2 - full_exp, fill{to_unsigned(-full_exp)});
|
||||
}
|
||||
}
|
||||
|
||||
struct char_counter {
|
||||
ptrdiff_t size;
|
||||
|
||||
template <typename F>
|
||||
void insert(ptrdiff_t, ptrdiff_t n, F) { size += n; }
|
||||
void insert(ptrdiff_t, char) { ++size; }
|
||||
void append(ptrdiff_t n, char) { size += n; }
|
||||
void append(char) { ++size; }
|
||||
void remove_trailing(char) {}
|
||||
};
|
||||
|
||||
// Converts format specifiers into parameters for digit generation and computes
|
||||
// output buffer size for a number in the range [pow(10, exp - 1), pow(10, exp)
|
||||
// or 0 if exp == 1.
|
||||
FMT_FUNC gen_digits_params process_specs(const core_format_specs &specs,
|
||||
int exp, buffer &buf) {
|
||||
auto params = gen_digits_params();
|
||||
int num_digits = specs.precision >= 0 ? specs.precision : 6;
|
||||
switch (specs.type) {
|
||||
case 'G':
|
||||
params.upper = true;
|
||||
FMT_FALLTHROUGH
|
||||
case '\0': case 'g':
|
||||
params.trailing_zeros = (specs.flags & HASH_FLAG) != 0;
|
||||
if (-4 <= exp && exp < num_digits + 1) {
|
||||
params.fixed = true;
|
||||
if (!specs.type && params.trailing_zeros && exp >= 0)
|
||||
num_digits = exp + 1;
|
||||
}
|
||||
break;
|
||||
case 'F':
|
||||
params.upper = true;
|
||||
FMT_FALLTHROUGH
|
||||
case 'f': {
|
||||
params.fixed = true;
|
||||
params.trailing_zeros = true;
|
||||
int adjusted_min_digits = num_digits + exp;
|
||||
if (adjusted_min_digits > 0)
|
||||
num_digits = adjusted_min_digits;
|
||||
break;
|
||||
}
|
||||
case 'E':
|
||||
params.upper = true;
|
||||
FMT_FALLTHROUGH
|
||||
case 'e':
|
||||
++num_digits;
|
||||
break;
|
||||
}
|
||||
params.num_digits = num_digits;
|
||||
char_counter counter{num_digits};
|
||||
grisu2_prettify(params, params.num_digits, exp - num_digits, counter);
|
||||
buf.resize(to_unsigned(counter.size));
|
||||
return params;
|
||||
}
|
||||
|
||||
template <typename Double>
|
||||
FMT_FUNC typename std::enable_if<sizeof(Double) == sizeof(uint64_t), bool>::type
|
||||
grisu2_format(Double value, buffer &buf, core_format_specs specs) {
|
||||
FMT_ASSERT(value >= 0, "value is negative");
|
||||
if (value == 0) {
|
||||
gen_digits_params params = process_specs(specs, 1, buf);
|
||||
const size_t size = 1;
|
||||
buf[0] = '0';
|
||||
grisu2_prettify(params, size, 0, prettify_handler(buf, size));
|
||||
return true;
|
||||
}
|
||||
|
||||
fp fp_value(value);
|
||||
fp lower, upper; // w^- and w^+ in the Grisu paper.
|
||||
fp_value.compute_boundaries(lower, upper);
|
||||
|
||||
// Find a cached power of 10 close to 1 / upper and use it to scale upper.
|
||||
const int min_exp = -60; // alpha in Grisu.
|
||||
int cached_exp = 0; // K in Grisu.
|
||||
auto cached_pow = get_cached_power( // \tilde{c}_{-k} in Grisu.
|
||||
min_exp - (upper.e + fp::significand_size), cached_exp);
|
||||
cached_exp = -cached_exp;
|
||||
upper = upper * cached_pow; // \tilde{M}^+ in Grisu.
|
||||
--upper.f; // \tilde{M}^+ - 1 ulp -> M^+_{\downarrow}.
|
||||
fp one(1ull << -upper.e, upper.e);
|
||||
// hi (p1 in Grisu) contains the most significant digits of scaled_upper.
|
||||
// hi = floor(upper / one).
|
||||
uint32_t hi = static_cast<uint32_t>(upper.f >> -one.e);
|
||||
int exp = count_digits(hi); // kappa in Grisu.
|
||||
gen_digits_params params = process_specs(specs, cached_exp + exp, buf);
|
||||
fp_value.normalize();
|
||||
fp scaled_value = fp_value * cached_pow;
|
||||
lower = lower * cached_pow; // \tilde{M}^- in Grisu.
|
||||
++lower.f; // \tilde{M}^- + 1 ulp -> M^-_{\uparrow}.
|
||||
uint64_t delta = upper.f - lower.f;
|
||||
fp diff = upper - scaled_value; // wp_w in Grisu.
|
||||
// lo (p2 in Grisu) contains the least significants digits of scaled_upper.
|
||||
// lo = supper % one.
|
||||
uint64_t lo = upper.f & (one.f - 1);
|
||||
int size = 0;
|
||||
if (!grisu2_gen_digits(buf.data(), size, hi, lo, exp, delta, one, diff,
|
||||
params.num_digits)) {
|
||||
buf.clear();
|
||||
return false;
|
||||
}
|
||||
grisu2_prettify(params, size, cached_exp + exp, prettify_handler(buf, size));
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename Double>
|
||||
void sprintf_format(Double value, internal::buffer &buf,
|
||||
core_format_specs spec) {
|
||||
// Buffer capacity must be non-zero, otherwise MSVC's vsnprintf_s will fail.
|
||||
FMT_ASSERT(buf.capacity() != 0, "empty buffer");
|
||||
|
||||
// Build format string.
|
||||
enum { MAX_FORMAT_SIZE = 10}; // longest format: %#-*.*Lg
|
||||
char format[MAX_FORMAT_SIZE];
|
||||
char *format_ptr = format;
|
||||
*format_ptr++ = '%';
|
||||
if (spec.has(HASH_FLAG))
|
||||
*format_ptr++ = '#';
|
||||
if (spec.precision >= 0) {
|
||||
*format_ptr++ = '.';
|
||||
*format_ptr++ = '*';
|
||||
}
|
||||
if (std::is_same<Double, long double>::value)
|
||||
*format_ptr++ = 'L';
|
||||
*format_ptr++ = spec.type;
|
||||
*format_ptr = '\0';
|
||||
|
||||
// Format using snprintf.
|
||||
char *start = FMT_NULL;
|
||||
for (;;) {
|
||||
std::size_t buffer_size = buf.capacity();
|
||||
start = &buf[0];
|
||||
int result = internal::char_traits<char>::format_float(
|
||||
start, buffer_size, format, spec.precision, value);
|
||||
if (result >= 0) {
|
||||
unsigned n = internal::to_unsigned(result);
|
||||
if (n < buf.capacity()) {
|
||||
buf.resize(n);
|
||||
break; // The buffer is large enough - continue with formatting.
|
||||
}
|
||||
buf.reserve(n + 1);
|
||||
} else {
|
||||
// If result is negative we ask to increase the capacity by at least 1,
|
||||
// but as std::vector, the buffer grows exponentially.
|
||||
buf.reserve(buf.capacity() + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
} // namespace internal
|
||||
|
||||
#if FMT_USE_WINDOWS_H
|
||||
|
||||
FMT_FUNC internal::utf8_to_utf16::utf8_to_utf16(string_view s) {
|
||||
static const char ERROR_MSG[] = "cannot convert string from UTF-8 to UTF-16";
|
||||
if (s.size() > INT_MAX)
|
||||
FMT_THROW(windows_error(ERROR_INVALID_PARAMETER, ERROR_MSG));
|
||||
int s_size = static_cast<int>(s.size());
|
||||
if (s_size == 0) {
|
||||
// MultiByteToWideChar does not support zero length, handle separately.
|
||||
buffer_.resize(1);
|
||||
buffer_[0] = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
int length = MultiByteToWideChar(
|
||||
CP_UTF8, MB_ERR_INVALID_CHARS, s.data(), s_size, FMT_NULL, 0);
|
||||
if (length == 0)
|
||||
FMT_THROW(windows_error(GetLastError(), ERROR_MSG));
|
||||
buffer_.resize(length + 1);
|
||||
length = MultiByteToWideChar(
|
||||
CP_UTF8, MB_ERR_INVALID_CHARS, s.data(), s_size, &buffer_[0], length);
|
||||
if (length == 0)
|
||||
FMT_THROW(windows_error(GetLastError(), ERROR_MSG));
|
||||
buffer_[length] = 0;
|
||||
}
|
||||
|
||||
FMT_FUNC internal::utf16_to_utf8::utf16_to_utf8(wstring_view s) {
|
||||
if (int error_code = convert(s)) {
|
||||
FMT_THROW(windows_error(error_code,
|
||||
"cannot convert string from UTF-16 to UTF-8"));
|
||||
}
|
||||
}
|
||||
|
||||
FMT_FUNC int internal::utf16_to_utf8::convert(wstring_view s) {
|
||||
if (s.size() > INT_MAX)
|
||||
return ERROR_INVALID_PARAMETER;
|
||||
int s_size = static_cast<int>(s.size());
|
||||
if (s_size == 0) {
|
||||
// WideCharToMultiByte does not support zero length, handle separately.
|
||||
buffer_.resize(1);
|
||||
buffer_[0] = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int length = WideCharToMultiByte(
|
||||
CP_UTF8, 0, s.data(), s_size, FMT_NULL, 0, FMT_NULL, FMT_NULL);
|
||||
if (length == 0)
|
||||
return GetLastError();
|
||||
buffer_.resize(length + 1);
|
||||
length = WideCharToMultiByte(
|
||||
CP_UTF8, 0, s.data(), s_size, &buffer_[0], length, FMT_NULL, FMT_NULL);
|
||||
if (length == 0)
|
||||
return GetLastError();
|
||||
buffer_[length] = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
FMT_FUNC void windows_error::init(
|
||||
int err_code, string_view format_str, format_args args) {
|
||||
error_code_ = err_code;
|
||||
memory_buffer buffer;
|
||||
internal::format_windows_error(buffer, err_code, vformat(format_str, args));
|
||||
std::runtime_error &base = *this;
|
||||
base = std::runtime_error(to_string(buffer));
|
||||
}
|
||||
|
||||
FMT_FUNC void internal::format_windows_error(
|
||||
internal::buffer &out, int error_code, string_view message) FMT_NOEXCEPT {
|
||||
FMT_TRY {
|
||||
wmemory_buffer buf;
|
||||
buf.resize(inline_buffer_size);
|
||||
for (;;) {
|
||||
wchar_t *system_message = &buf[0];
|
||||
int result = FormatMessageW(
|
||||
FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
|
||||
FMT_NULL, error_code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
|
||||
system_message, static_cast<uint32_t>(buf.size()), FMT_NULL);
|
||||
if (result != 0) {
|
||||
utf16_to_utf8 utf8_message;
|
||||
if (utf8_message.convert(system_message) == ERROR_SUCCESS) {
|
||||
writer w(out);
|
||||
w.write(message);
|
||||
w.write(": ");
|
||||
w.write(utf8_message);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
|
||||
break; // Can't get error message, report error code instead.
|
||||
buf.resize(buf.size() * 2);
|
||||
}
|
||||
} FMT_CATCH(...) {}
|
||||
format_error_code(out, error_code, message);
|
||||
}
|
||||
|
||||
#endif // FMT_USE_WINDOWS_H
|
||||
|
||||
FMT_FUNC void format_system_error(
|
||||
internal::buffer &out, int error_code, string_view message) FMT_NOEXCEPT {
|
||||
FMT_TRY {
|
||||
memory_buffer buf;
|
||||
buf.resize(inline_buffer_size);
|
||||
for (;;) {
|
||||
char *system_message = &buf[0];
|
||||
int result = safe_strerror(error_code, system_message, buf.size());
|
||||
if (result == 0) {
|
||||
writer w(out);
|
||||
w.write(message);
|
||||
w.write(": ");
|
||||
w.write(system_message);
|
||||
return;
|
||||
}
|
||||
if (result != ERANGE)
|
||||
break; // Can't get error message, report error code instead.
|
||||
buf.resize(buf.size() * 2);
|
||||
}
|
||||
} FMT_CATCH(...) {}
|
||||
format_error_code(out, error_code, message);
|
||||
}
|
||||
|
||||
FMT_FUNC void internal::error_handler::on_error(const char *message) {
|
||||
FMT_THROW(format_error(message));
|
||||
}
|
||||
|
||||
FMT_FUNC void report_system_error(
|
||||
int error_code, fmt::string_view message) FMT_NOEXCEPT {
|
||||
report_error(format_system_error, error_code, message);
|
||||
}
|
||||
|
||||
#if FMT_USE_WINDOWS_H
|
||||
FMT_FUNC void report_windows_error(
|
||||
int error_code, fmt::string_view message) FMT_NOEXCEPT {
|
||||
report_error(internal::format_windows_error, error_code, message);
|
||||
}
|
||||
#endif
|
||||
|
||||
FMT_FUNC void vprint(std::FILE *f, string_view format_str, format_args args) {
|
||||
memory_buffer buffer;
|
||||
internal::vformat_to(buffer, format_str,
|
||||
basic_format_args<buffer_context<char>::type>(args));
|
||||
std::fwrite(buffer.data(), 1, buffer.size(), f);
|
||||
}
|
||||
|
||||
FMT_FUNC void vprint(std::FILE *f, wstring_view format_str, wformat_args args) {
|
||||
wmemory_buffer buffer;
|
||||
internal::vformat_to(buffer, format_str, args);
|
||||
std::fwrite(buffer.data(), sizeof(wchar_t), buffer.size(), f);
|
||||
}
|
||||
|
||||
FMT_FUNC void vprint(string_view format_str, format_args args) {
|
||||
vprint(stdout, format_str, args);
|
||||
}
|
||||
|
||||
FMT_FUNC void vprint(wstring_view format_str, wformat_args args) {
|
||||
vprint(stdout, format_str, args);
|
||||
}
|
||||
|
||||
FMT_END_NAMESPACE
|
||||
|
||||
#ifdef _MSC_VER
|
||||
# pragma warning(pop)
|
||||
#endif
|
||||
|
||||
#endif // FMT_FORMAT_INL_H_
|
3555
include/Livox/third_party/spdlog/spdlog/fmt/bundled/format.h
vendored
Executable file
3555
include/Livox/third_party/spdlog/spdlog/fmt/bundled/format.h
vendored
Executable file
File diff suppressed because it is too large
Load Diff
77
include/Livox/third_party/spdlog/spdlog/fmt/bundled/locale.h
vendored
Executable file
77
include/Livox/third_party/spdlog/spdlog/fmt/bundled/locale.h
vendored
Executable file
@ -0,0 +1,77 @@
|
||||
// Formatting library for C++ - std::locale support
|
||||
//
|
||||
// Copyright (c) 2012 - present, Victor Zverovich
|
||||
// All rights reserved.
|
||||
//
|
||||
// For the license information refer to format.h.
|
||||
|
||||
#ifndef FMT_LOCALE_H_
|
||||
#define FMT_LOCALE_H_
|
||||
|
||||
#include "format.h"
|
||||
#include <locale>
|
||||
|
||||
FMT_BEGIN_NAMESPACE
|
||||
|
||||
namespace internal {
|
||||
template <typename Char>
|
||||
typename buffer_context<Char>::type::iterator vformat_to(
|
||||
const std::locale &loc, basic_buffer<Char> &buf,
|
||||
basic_string_view<Char> format_str,
|
||||
basic_format_args<typename buffer_context<Char>::type> args) {
|
||||
typedef back_insert_range<basic_buffer<Char> > range;
|
||||
return vformat_to<arg_formatter<range>>(
|
||||
buf, to_string_view(format_str), args, internal::locale_ref(loc));
|
||||
}
|
||||
|
||||
template <typename Char>
|
||||
std::basic_string<Char> vformat(
|
||||
const std::locale &loc, basic_string_view<Char> format_str,
|
||||
basic_format_args<typename buffer_context<Char>::type> args) {
|
||||
basic_memory_buffer<Char> buffer;
|
||||
internal::vformat_to(loc, buffer, format_str, args);
|
||||
return fmt::to_string(buffer);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename S, typename Char = FMT_CHAR(S)>
|
||||
inline std::basic_string<Char> vformat(
|
||||
const std::locale &loc, const S &format_str,
|
||||
basic_format_args<typename buffer_context<Char>::type> args) {
|
||||
return internal::vformat(loc, to_string_view(format_str), args);
|
||||
}
|
||||
|
||||
template <typename S, typename... Args>
|
||||
inline std::basic_string<FMT_CHAR(S)> format(
|
||||
const std::locale &loc, const S &format_str, const Args &... args) {
|
||||
return internal::vformat(
|
||||
loc, to_string_view(format_str),
|
||||
*internal::checked_args<S, Args...>(format_str, args...));
|
||||
}
|
||||
|
||||
template <typename String, typename OutputIt, typename... Args>
|
||||
inline typename std::enable_if<internal::is_output_iterator<OutputIt>::value,
|
||||
OutputIt>::type
|
||||
vformat_to(OutputIt out, const std::locale &loc, const String &format_str,
|
||||
typename format_args_t<OutputIt, FMT_CHAR(String)>::type args) {
|
||||
typedef output_range<OutputIt, FMT_CHAR(String)> range;
|
||||
return vformat_to<arg_formatter<range>>(
|
||||
range(out), to_string_view(format_str), args, internal::locale_ref(loc));
|
||||
}
|
||||
|
||||
template <typename OutputIt, typename S, typename... Args>
|
||||
inline typename std::enable_if<
|
||||
internal::is_string<S>::value &&
|
||||
internal::is_output_iterator<OutputIt>::value, OutputIt>::type
|
||||
format_to(OutputIt out, const std::locale &loc, const S &format_str,
|
||||
const Args &... args) {
|
||||
internal::check_format_string<Args...>(format_str);
|
||||
typedef typename format_context_t<OutputIt, FMT_CHAR(S)>::type context;
|
||||
format_arg_store<context, Args...> as{args...};
|
||||
return vformat_to(out, loc, to_string_view(format_str),
|
||||
basic_format_args<context>(as));
|
||||
}
|
||||
|
||||
FMT_END_NAMESPACE
|
||||
|
||||
#endif // FMT_LOCALE_H_
|
153
include/Livox/third_party/spdlog/spdlog/fmt/bundled/ostream.h
vendored
Executable file
153
include/Livox/third_party/spdlog/spdlog/fmt/bundled/ostream.h
vendored
Executable file
@ -0,0 +1,153 @@
|
||||
// Formatting library for C++ - std::ostream support
|
||||
//
|
||||
// Copyright (c) 2012 - present, Victor Zverovich
|
||||
// All rights reserved.
|
||||
//
|
||||
// For the license information refer to format.h.
|
||||
|
||||
#ifndef FMT_OSTREAM_H_
|
||||
#define FMT_OSTREAM_H_
|
||||
|
||||
#include "format.h"
|
||||
#include <ostream>
|
||||
|
||||
FMT_BEGIN_NAMESPACE
|
||||
namespace internal {
|
||||
|
||||
template <class Char>
|
||||
class formatbuf : public std::basic_streambuf<Char> {
|
||||
private:
|
||||
typedef typename std::basic_streambuf<Char>::int_type int_type;
|
||||
typedef typename std::basic_streambuf<Char>::traits_type traits_type;
|
||||
|
||||
basic_buffer<Char> &buffer_;
|
||||
|
||||
public:
|
||||
formatbuf(basic_buffer<Char> &buffer) : buffer_(buffer) {}
|
||||
|
||||
protected:
|
||||
// The put-area is actually always empty. This makes the implementation
|
||||
// simpler and has the advantage that the streambuf and the buffer are always
|
||||
// in sync and sputc never writes into uninitialized memory. The obvious
|
||||
// disadvantage is that each call to sputc always results in a (virtual) call
|
||||
// to overflow. There is no disadvantage here for sputn since this always
|
||||
// results in a call to xsputn.
|
||||
|
||||
int_type overflow(int_type ch = traits_type::eof()) FMT_OVERRIDE {
|
||||
if (!traits_type::eq_int_type(ch, traits_type::eof()))
|
||||
buffer_.push_back(static_cast<Char>(ch));
|
||||
return ch;
|
||||
}
|
||||
|
||||
std::streamsize xsputn(const Char *s, std::streamsize count) FMT_OVERRIDE {
|
||||
buffer_.append(s, s + count);
|
||||
return count;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Char>
|
||||
struct test_stream : std::basic_ostream<Char> {
|
||||
private:
|
||||
struct null;
|
||||
// Hide all operator<< from std::basic_ostream<Char>.
|
||||
void operator<<(null);
|
||||
};
|
||||
|
||||
// Checks if T has a user-defined operator<< (e.g. not a member of std::ostream).
|
||||
template <typename T, typename Char>
|
||||
class is_streamable {
|
||||
private:
|
||||
template <typename U>
|
||||
static decltype(
|
||||
internal::declval<test_stream<Char>&>()
|
||||
<< internal::declval<U>(), std::true_type()) test(int);
|
||||
|
||||
template <typename>
|
||||
static std::false_type test(...);
|
||||
|
||||
typedef decltype(test<T>(0)) result;
|
||||
|
||||
public:
|
||||
static const bool value = result::value;
|
||||
};
|
||||
|
||||
// Write the content of buf to os.
|
||||
template <typename Char>
|
||||
void write(std::basic_ostream<Char> &os, basic_buffer<Char> &buf) {
|
||||
const Char *data = buf.data();
|
||||
typedef std::make_unsigned<std::streamsize>::type UnsignedStreamSize;
|
||||
UnsignedStreamSize size = buf.size();
|
||||
UnsignedStreamSize max_size =
|
||||
internal::to_unsigned((std::numeric_limits<std::streamsize>::max)());
|
||||
do {
|
||||
UnsignedStreamSize n = size <= max_size ? size : max_size;
|
||||
os.write(data, static_cast<std::streamsize>(n));
|
||||
data += n;
|
||||
size -= n;
|
||||
} while (size != 0);
|
||||
}
|
||||
|
||||
template <typename Char, typename T>
|
||||
void format_value(basic_buffer<Char> &buffer, const T &value) {
|
||||
internal::formatbuf<Char> format_buf(buffer);
|
||||
std::basic_ostream<Char> output(&format_buf);
|
||||
output.exceptions(std::ios_base::failbit | std::ios_base::badbit);
|
||||
output << value;
|
||||
buffer.resize(buffer.size());
|
||||
}
|
||||
} // namespace internal
|
||||
|
||||
// Disable conversion to int if T has an overloaded operator<< which is a free
|
||||
// function (not a member of std::ostream).
|
||||
template <typename T, typename Char>
|
||||
struct convert_to_int<T, Char, void> {
|
||||
static const bool value =
|
||||
convert_to_int<T, Char, int>::value &&
|
||||
!internal::is_streamable<T, Char>::value;
|
||||
};
|
||||
|
||||
// Formats an object of type T that has an overloaded ostream operator<<.
|
||||
template <typename T, typename Char>
|
||||
struct formatter<T, Char,
|
||||
typename std::enable_if<
|
||||
internal::is_streamable<T, Char>::value &&
|
||||
!internal::format_type<
|
||||
typename buffer_context<Char>::type, T>::value>::type>
|
||||
: formatter<basic_string_view<Char>, Char> {
|
||||
|
||||
template <typename Context>
|
||||
auto format(const T &value, Context &ctx) -> decltype(ctx.out()) {
|
||||
basic_memory_buffer<Char> buffer;
|
||||
internal::format_value(buffer, value);
|
||||
basic_string_view<Char> str(buffer.data(), buffer.size());
|
||||
return formatter<basic_string_view<Char>, Char>::format(str, ctx);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Char>
|
||||
inline void vprint(std::basic_ostream<Char> &os,
|
||||
basic_string_view<Char> format_str,
|
||||
basic_format_args<typename buffer_context<Char>::type> args) {
|
||||
basic_memory_buffer<Char> buffer;
|
||||
internal::vformat_to(buffer, format_str, args);
|
||||
internal::write(os, buffer);
|
||||
}
|
||||
/**
|
||||
\rst
|
||||
Prints formatted data to the stream *os*.
|
||||
|
||||
**Example**::
|
||||
|
||||
fmt::print(cerr, "Don't {}!", "panic");
|
||||
\endrst
|
||||
*/
|
||||
template <typename S, typename... Args>
|
||||
inline typename std::enable_if<internal::is_string<S>::value>::type
|
||||
print(std::basic_ostream<FMT_CHAR(S)> &os, const S &format_str,
|
||||
const Args & ... args) {
|
||||
internal::checked_args<S, Args...> ca(format_str, args...);
|
||||
vprint(os, to_string_view(format_str), *ca);
|
||||
}
|
||||
FMT_END_NAMESPACE
|
||||
|
||||
#endif // FMT_OSTREAM_H_
|
324
include/Livox/third_party/spdlog/spdlog/fmt/bundled/posix.h
vendored
Executable file
324
include/Livox/third_party/spdlog/spdlog/fmt/bundled/posix.h
vendored
Executable file
@ -0,0 +1,324 @@
|
||||
// A C++ interface to POSIX functions.
|
||||
//
|
||||
// Copyright (c) 2012 - 2016, Victor Zverovich
|
||||
// All rights reserved.
|
||||
//
|
||||
// For the license information refer to format.h.
|
||||
|
||||
#ifndef FMT_POSIX_H_
|
||||
#define FMT_POSIX_H_
|
||||
|
||||
#if defined(__MINGW32__) || defined(__CYGWIN__)
|
||||
// Workaround MinGW bug https://sourceforge.net/p/mingw/bugs/2024/.
|
||||
# undef __STRICT_ANSI__
|
||||
#endif
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h> // for O_RDONLY
|
||||
#include <locale.h> // for locale_t
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h> // for strtod_l
|
||||
|
||||
#include <cstddef>
|
||||
|
||||
#if defined __APPLE__ || defined(__FreeBSD__)
|
||||
# include <xlocale.h> // for LC_NUMERIC_MASK on OS X
|
||||
#endif
|
||||
|
||||
#include "format.h"
|
||||
|
||||
#ifndef FMT_POSIX
|
||||
# if defined(_WIN32) && !defined(__MINGW32__)
|
||||
// Fix warnings about deprecated symbols.
|
||||
# define FMT_POSIX(call) _##call
|
||||
# else
|
||||
# define FMT_POSIX(call) call
|
||||
# endif
|
||||
#endif
|
||||
|
||||
// Calls to system functions are wrapped in FMT_SYSTEM for testability.
|
||||
#ifdef FMT_SYSTEM
|
||||
# define FMT_POSIX_CALL(call) FMT_SYSTEM(call)
|
||||
#else
|
||||
# define FMT_SYSTEM(call) call
|
||||
# ifdef _WIN32
|
||||
// Fix warnings about deprecated symbols.
|
||||
# define FMT_POSIX_CALL(call) ::_##call
|
||||
# else
|
||||
# define FMT_POSIX_CALL(call) ::call
|
||||
# endif
|
||||
#endif
|
||||
|
||||
// Retries the expression while it evaluates to error_result and errno
|
||||
// equals to EINTR.
|
||||
#ifndef _WIN32
|
||||
# define FMT_RETRY_VAL(result, expression, error_result) \
|
||||
do { \
|
||||
result = (expression); \
|
||||
} while (result == error_result && errno == EINTR)
|
||||
#else
|
||||
# define FMT_RETRY_VAL(result, expression, error_result) result = (expression)
|
||||
#endif
|
||||
|
||||
#define FMT_RETRY(result, expression) FMT_RETRY_VAL(result, expression, -1)
|
||||
|
||||
FMT_BEGIN_NAMESPACE
|
||||
|
||||
/**
|
||||
\rst
|
||||
A reference to a null-terminated string. It can be constructed from a C
|
||||
string or ``std::string``.
|
||||
|
||||
You can use one of the following typedefs for common character types:
|
||||
|
||||
+---------------+-----------------------------+
|
||||
| Type | Definition |
|
||||
+===============+=============================+
|
||||
| cstring_view | basic_cstring_view<char> |
|
||||
+---------------+-----------------------------+
|
||||
| wcstring_view | basic_cstring_view<wchar_t> |
|
||||
+---------------+-----------------------------+
|
||||
|
||||
This class is most useful as a parameter type to allow passing
|
||||
different types of strings to a function, for example::
|
||||
|
||||
template <typename... Args>
|
||||
std::string format(cstring_view format_str, const Args & ... args);
|
||||
|
||||
format("{}", 42);
|
||||
format(std::string("{}"), 42);
|
||||
\endrst
|
||||
*/
|
||||
template <typename Char>
|
||||
class basic_cstring_view {
|
||||
private:
|
||||
const Char *data_;
|
||||
|
||||
public:
|
||||
/** Constructs a string reference object from a C string. */
|
||||
basic_cstring_view(const Char *s) : data_(s) {}
|
||||
|
||||
/**
|
||||
\rst
|
||||
Constructs a string reference from an ``std::string`` object.
|
||||
\endrst
|
||||
*/
|
||||
basic_cstring_view(const std::basic_string<Char> &s) : data_(s.c_str()) {}
|
||||
|
||||
/** Returns the pointer to a C string. */
|
||||
const Char *c_str() const { return data_; }
|
||||
};
|
||||
|
||||
typedef basic_cstring_view<char> cstring_view;
|
||||
typedef basic_cstring_view<wchar_t> wcstring_view;
|
||||
|
||||
// An error code.
|
||||
class error_code {
|
||||
private:
|
||||
int value_;
|
||||
|
||||
public:
|
||||
explicit error_code(int value = 0) FMT_NOEXCEPT : value_(value) {}
|
||||
|
||||
int get() const FMT_NOEXCEPT { return value_; }
|
||||
};
|
||||
|
||||
// A buffered file.
|
||||
class buffered_file {
|
||||
private:
|
||||
FILE *file_;
|
||||
|
||||
friend class file;
|
||||
|
||||
explicit buffered_file(FILE *f) : file_(f) {}
|
||||
|
||||
public:
|
||||
// Constructs a buffered_file object which doesn't represent any file.
|
||||
buffered_file() FMT_NOEXCEPT : file_(FMT_NULL) {}
|
||||
|
||||
// Destroys the object closing the file it represents if any.
|
||||
FMT_API ~buffered_file() FMT_NOEXCEPT;
|
||||
|
||||
private:
|
||||
buffered_file(const buffered_file &) = delete;
|
||||
void operator=(const buffered_file &) = delete;
|
||||
|
||||
|
||||
public:
|
||||
buffered_file(buffered_file &&other) FMT_NOEXCEPT : file_(other.file_) {
|
||||
other.file_ = FMT_NULL;
|
||||
}
|
||||
|
||||
buffered_file& operator=(buffered_file &&other) {
|
||||
close();
|
||||
file_ = other.file_;
|
||||
other.file_ = FMT_NULL;
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Opens a file.
|
||||
FMT_API buffered_file(cstring_view filename, cstring_view mode);
|
||||
|
||||
// Closes the file.
|
||||
FMT_API void close();
|
||||
|
||||
// Returns the pointer to a FILE object representing this file.
|
||||
FILE *get() const FMT_NOEXCEPT { return file_; }
|
||||
|
||||
// We place parentheses around fileno to workaround a bug in some versions
|
||||
// of MinGW that define fileno as a macro.
|
||||
FMT_API int (fileno)() const;
|
||||
|
||||
void vprint(string_view format_str, format_args args) {
|
||||
fmt::vprint(file_, format_str, args);
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
inline void print(string_view format_str, const Args & ... args) {
|
||||
vprint(format_str, make_format_args(args...));
|
||||
}
|
||||
};
|
||||
|
||||
// A file. Closed file is represented by a file object with descriptor -1.
|
||||
// Methods that are not declared with FMT_NOEXCEPT may throw
|
||||
// fmt::system_error in case of failure. Note that some errors such as
|
||||
// closing the file multiple times will cause a crash on Windows rather
|
||||
// than an exception. You can get standard behavior by overriding the
|
||||
// invalid parameter handler with _set_invalid_parameter_handler.
|
||||
class file {
|
||||
private:
|
||||
int fd_; // File descriptor.
|
||||
|
||||
// Constructs a file object with a given descriptor.
|
||||
explicit file(int fd) : fd_(fd) {}
|
||||
|
||||
public:
|
||||
// Possible values for the oflag argument to the constructor.
|
||||
enum {
|
||||
RDONLY = FMT_POSIX(O_RDONLY), // Open for reading only.
|
||||
WRONLY = FMT_POSIX(O_WRONLY), // Open for writing only.
|
||||
RDWR = FMT_POSIX(O_RDWR) // Open for reading and writing.
|
||||
};
|
||||
|
||||
// Constructs a file object which doesn't represent any file.
|
||||
file() FMT_NOEXCEPT : fd_(-1) {}
|
||||
|
||||
// Opens a file and constructs a file object representing this file.
|
||||
FMT_API file(cstring_view path, int oflag);
|
||||
|
||||
private:
|
||||
file(const file &) = delete;
|
||||
void operator=(const file &) = delete;
|
||||
|
||||
public:
|
||||
file(file &&other) FMT_NOEXCEPT : fd_(other.fd_) {
|
||||
other.fd_ = -1;
|
||||
}
|
||||
|
||||
file& operator=(file &&other) {
|
||||
close();
|
||||
fd_ = other.fd_;
|
||||
other.fd_ = -1;
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Destroys the object closing the file it represents if any.
|
||||
FMT_API ~file() FMT_NOEXCEPT;
|
||||
|
||||
// Returns the file descriptor.
|
||||
int descriptor() const FMT_NOEXCEPT { return fd_; }
|
||||
|
||||
// Closes the file.
|
||||
FMT_API void close();
|
||||
|
||||
// Returns the file size. The size has signed type for consistency with
|
||||
// stat::st_size.
|
||||
FMT_API long long size() const;
|
||||
|
||||
// Attempts to read count bytes from the file into the specified buffer.
|
||||
FMT_API std::size_t read(void *buffer, std::size_t count);
|
||||
|
||||
// Attempts to write count bytes from the specified buffer to the file.
|
||||
FMT_API std::size_t write(const void *buffer, std::size_t count);
|
||||
|
||||
// Duplicates a file descriptor with the dup function and returns
|
||||
// the duplicate as a file object.
|
||||
FMT_API static file dup(int fd);
|
||||
|
||||
// Makes fd be the copy of this file descriptor, closing fd first if
|
||||
// necessary.
|
||||
FMT_API void dup2(int fd);
|
||||
|
||||
// Makes fd be the copy of this file descriptor, closing fd first if
|
||||
// necessary.
|
||||
FMT_API void dup2(int fd, error_code &ec) FMT_NOEXCEPT;
|
||||
|
||||
// Creates a pipe setting up read_end and write_end file objects for reading
|
||||
// and writing respectively.
|
||||
FMT_API static void pipe(file &read_end, file &write_end);
|
||||
|
||||
// Creates a buffered_file object associated with this file and detaches
|
||||
// this file object from the file.
|
||||
FMT_API buffered_file fdopen(const char *mode);
|
||||
};
|
||||
|
||||
// Returns the memory page size.
|
||||
long getpagesize();
|
||||
|
||||
#if (defined(LC_NUMERIC_MASK) || defined(_MSC_VER)) && \
|
||||
!defined(__ANDROID__) && !defined(__CYGWIN__) && !defined(__OpenBSD__) && \
|
||||
!defined(__NEWLIB_H__)
|
||||
# define FMT_LOCALE
|
||||
#endif
|
||||
|
||||
#ifdef FMT_LOCALE
|
||||
// A "C" numeric locale.
|
||||
class Locale {
|
||||
private:
|
||||
# ifdef _MSC_VER
|
||||
typedef _locale_t locale_t;
|
||||
|
||||
enum { LC_NUMERIC_MASK = LC_NUMERIC };
|
||||
|
||||
static locale_t newlocale(int category_mask, const char *locale, locale_t) {
|
||||
return _create_locale(category_mask, locale);
|
||||
}
|
||||
|
||||
static void freelocale(locale_t locale) {
|
||||
_free_locale(locale);
|
||||
}
|
||||
|
||||
static double strtod_l(const char *nptr, char **endptr, _locale_t locale) {
|
||||
return _strtod_l(nptr, endptr, locale);
|
||||
}
|
||||
# endif
|
||||
|
||||
locale_t locale_;
|
||||
|
||||
Locale(const Locale &) = delete;
|
||||
void operator=(const Locale &) = delete;
|
||||
|
||||
public:
|
||||
typedef locale_t Type;
|
||||
|
||||
Locale() : locale_(newlocale(LC_NUMERIC_MASK, "C", FMT_NULL)) {
|
||||
if (!locale_)
|
||||
FMT_THROW(system_error(errno, "cannot create locale"));
|
||||
}
|
||||
~Locale() { freelocale(locale_); }
|
||||
|
||||
Type get() const { return locale_; }
|
||||
|
||||
// Converts string to floating-point number and advances str past the end
|
||||
// of the parsed input.
|
||||
double strtod(const char *&str) const {
|
||||
char *end = FMT_NULL;
|
||||
double result = strtod_l(str, &end, locale_);
|
||||
str = end;
|
||||
return result;
|
||||
}
|
||||
};
|
||||
#endif // FMT_LOCALE
|
||||
FMT_END_NAMESPACE
|
||||
|
||||
#endif // FMT_POSIX_H_
|
855
include/Livox/third_party/spdlog/spdlog/fmt/bundled/printf.h
vendored
Executable file
855
include/Livox/third_party/spdlog/spdlog/fmt/bundled/printf.h
vendored
Executable file
@ -0,0 +1,855 @@
|
||||
// Formatting library for C++
|
||||
//
|
||||
// Copyright (c) 2012 - 2016, Victor Zverovich
|
||||
// All rights reserved.
|
||||
//
|
||||
// For the license information refer to format.h.
|
||||
|
||||
#ifndef FMT_PRINTF_H_
|
||||
#define FMT_PRINTF_H_
|
||||
|
||||
#include <algorithm> // std::fill_n
|
||||
#include <limits> // std::numeric_limits
|
||||
|
||||
#include "ostream.h"
|
||||
|
||||
FMT_BEGIN_NAMESPACE
|
||||
namespace internal {
|
||||
|
||||
// An iterator that produces a null terminator on *end. This simplifies parsing
|
||||
// and allows comparing the performance of processing a null-terminated string
|
||||
// vs string_view.
|
||||
template <typename Char>
|
||||
class null_terminating_iterator {
|
||||
public:
|
||||
typedef std::ptrdiff_t difference_type;
|
||||
typedef Char value_type;
|
||||
typedef const Char* pointer;
|
||||
typedef const Char& reference;
|
||||
typedef std::random_access_iterator_tag iterator_category;
|
||||
|
||||
null_terminating_iterator() : ptr_(0), end_(0) {}
|
||||
|
||||
FMT_CONSTEXPR null_terminating_iterator(const Char *ptr, const Char *end)
|
||||
: ptr_(ptr), end_(end) {}
|
||||
|
||||
template <typename Range>
|
||||
FMT_CONSTEXPR explicit null_terminating_iterator(const Range &r)
|
||||
: ptr_(r.begin()), end_(r.end()) {}
|
||||
|
||||
FMT_CONSTEXPR null_terminating_iterator &operator=(const Char *ptr) {
|
||||
assert(ptr <= end_);
|
||||
ptr_ = ptr;
|
||||
return *this;
|
||||
}
|
||||
|
||||
FMT_CONSTEXPR Char operator*() const {
|
||||
return ptr_ != end_ ? *ptr_ : Char();
|
||||
}
|
||||
|
||||
FMT_CONSTEXPR null_terminating_iterator operator++() {
|
||||
++ptr_;
|
||||
return *this;
|
||||
}
|
||||
|
||||
FMT_CONSTEXPR null_terminating_iterator operator++(int) {
|
||||
null_terminating_iterator result(*this);
|
||||
++ptr_;
|
||||
return result;
|
||||
}
|
||||
|
||||
FMT_CONSTEXPR null_terminating_iterator operator--() {
|
||||
--ptr_;
|
||||
return *this;
|
||||
}
|
||||
|
||||
FMT_CONSTEXPR null_terminating_iterator operator+(difference_type n) {
|
||||
return null_terminating_iterator(ptr_ + n, end_);
|
||||
}
|
||||
|
||||
FMT_CONSTEXPR null_terminating_iterator operator-(difference_type n) {
|
||||
return null_terminating_iterator(ptr_ - n, end_);
|
||||
}
|
||||
|
||||
FMT_CONSTEXPR null_terminating_iterator operator+=(difference_type n) {
|
||||
ptr_ += n;
|
||||
return *this;
|
||||
}
|
||||
|
||||
FMT_CONSTEXPR difference_type operator-(
|
||||
null_terminating_iterator other) const {
|
||||
return ptr_ - other.ptr_;
|
||||
}
|
||||
|
||||
FMT_CONSTEXPR bool operator!=(null_terminating_iterator other) const {
|
||||
return ptr_ != other.ptr_;
|
||||
}
|
||||
|
||||
bool operator>=(null_terminating_iterator other) const {
|
||||
return ptr_ >= other.ptr_;
|
||||
}
|
||||
|
||||
// This should be a friend specialization pointer_from<Char> but the latter
|
||||
// doesn't compile by gcc 5.1 due to a compiler bug.
|
||||
template <typename CharT>
|
||||
friend FMT_CONSTEXPR_DECL const CharT *pointer_from(
|
||||
null_terminating_iterator<CharT> it);
|
||||
|
||||
private:
|
||||
const Char *ptr_;
|
||||
const Char *end_;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
FMT_CONSTEXPR const T *pointer_from(const T *p) { return p; }
|
||||
|
||||
template <typename Char>
|
||||
FMT_CONSTEXPR const Char *pointer_from(null_terminating_iterator<Char> it) {
|
||||
return it.ptr_;
|
||||
}
|
||||
|
||||
// DEPRECATED: Parses the input as an unsigned integer. This function assumes
|
||||
// that the first character is a digit and presence of a non-digit character at
|
||||
// the end.
|
||||
// it: an iterator pointing to the beginning of the input range.
|
||||
template <typename Iterator, typename ErrorHandler>
|
||||
FMT_CONSTEXPR unsigned parse_nonnegative_int(Iterator &it, ErrorHandler &&eh) {
|
||||
assert('0' <= *it && *it <= '9');
|
||||
if (*it == '0') {
|
||||
++it;
|
||||
return 0;
|
||||
}
|
||||
unsigned value = 0;
|
||||
// Convert to unsigned to prevent a warning.
|
||||
unsigned max_int = (std::numeric_limits<int>::max)();
|
||||
unsigned big = max_int / 10;
|
||||
do {
|
||||
// Check for overflow.
|
||||
if (value > big) {
|
||||
value = max_int + 1;
|
||||
break;
|
||||
}
|
||||
value = value * 10 + unsigned(*it - '0');
|
||||
// Workaround for MSVC "setup_exception stack overflow" error:
|
||||
auto next = it;
|
||||
++next;
|
||||
it = next;
|
||||
} while ('0' <= *it && *it <= '9');
|
||||
if (value > max_int)
|
||||
eh.on_error("number is too big");
|
||||
return value;
|
||||
}
|
||||
|
||||
// Checks if a value fits in int - used to avoid warnings about comparing
|
||||
// signed and unsigned integers.
|
||||
template <bool IsSigned>
|
||||
struct int_checker {
|
||||
template <typename T>
|
||||
static bool fits_in_int(T value) {
|
||||
unsigned max = std::numeric_limits<int>::max();
|
||||
return value <= max;
|
||||
}
|
||||
static bool fits_in_int(bool) { return true; }
|
||||
};
|
||||
|
||||
template <>
|
||||
struct int_checker<true> {
|
||||
template <typename T>
|
||||
static bool fits_in_int(T value) {
|
||||
return value >= std::numeric_limits<int>::min() &&
|
||||
value <= std::numeric_limits<int>::max();
|
||||
}
|
||||
static bool fits_in_int(int) { return true; }
|
||||
};
|
||||
|
||||
class printf_precision_handler: public function<int> {
|
||||
public:
|
||||
template <typename T>
|
||||
typename std::enable_if<std::is_integral<T>::value, int>::type
|
||||
operator()(T value) {
|
||||
if (!int_checker<std::numeric_limits<T>::is_signed>::fits_in_int(value))
|
||||
FMT_THROW(format_error("number is too big"));
|
||||
return static_cast<int>(value);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
typename std::enable_if<!std::is_integral<T>::value, int>::type operator()(T) {
|
||||
FMT_THROW(format_error("precision is not integer"));
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
// An argument visitor that returns true iff arg is a zero integer.
|
||||
class is_zero_int: public function<bool> {
|
||||
public:
|
||||
template <typename T>
|
||||
typename std::enable_if<std::is_integral<T>::value, bool>::type
|
||||
operator()(T value) { return value == 0; }
|
||||
|
||||
template <typename T>
|
||||
typename std::enable_if<!std::is_integral<T>::value, bool>::type
|
||||
operator()(T) { return false; }
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct make_unsigned_or_bool : std::make_unsigned<T> {};
|
||||
|
||||
template <>
|
||||
struct make_unsigned_or_bool<bool> {
|
||||
typedef bool type;
|
||||
};
|
||||
|
||||
template <typename T, typename Context>
|
||||
class arg_converter: public function<void> {
|
||||
private:
|
||||
typedef typename Context::char_type Char;
|
||||
|
||||
basic_format_arg<Context> &arg_;
|
||||
typename Context::char_type type_;
|
||||
|
||||
public:
|
||||
arg_converter(basic_format_arg<Context> &arg, Char type)
|
||||
: arg_(arg), type_(type) {}
|
||||
|
||||
void operator()(bool value) {
|
||||
if (type_ != 's')
|
||||
operator()<bool>(value);
|
||||
}
|
||||
|
||||
template <typename U>
|
||||
typename std::enable_if<std::is_integral<U>::value>::type
|
||||
operator()(U value) {
|
||||
bool is_signed = type_ == 'd' || type_ == 'i';
|
||||
typedef typename std::conditional<
|
||||
std::is_same<T, void>::value, U, T>::type TargetType;
|
||||
if (const_check(sizeof(TargetType) <= sizeof(int))) {
|
||||
// Extra casts are used to silence warnings.
|
||||
if (is_signed) {
|
||||
arg_ = internal::make_arg<Context>(
|
||||
static_cast<int>(static_cast<TargetType>(value)));
|
||||
} else {
|
||||
typedef typename make_unsigned_or_bool<TargetType>::type Unsigned;
|
||||
arg_ = internal::make_arg<Context>(
|
||||
static_cast<unsigned>(static_cast<Unsigned>(value)));
|
||||
}
|
||||
} else {
|
||||
if (is_signed) {
|
||||
// glibc's printf doesn't sign extend arguments of smaller types:
|
||||
// std::printf("%lld", -42); // prints "4294967254"
|
||||
// but we don't have to do the same because it's a UB.
|
||||
arg_ = internal::make_arg<Context>(static_cast<long long>(value));
|
||||
} else {
|
||||
arg_ = internal::make_arg<Context>(
|
||||
static_cast<typename make_unsigned_or_bool<U>::type>(value));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename U>
|
||||
typename std::enable_if<!std::is_integral<U>::value>::type operator()(U) {
|
||||
// No coversion needed for non-integral types.
|
||||
}
|
||||
};
|
||||
|
||||
// Converts an integer argument to T for printf, if T is an integral type.
|
||||
// If T is void, the argument is converted to corresponding signed or unsigned
|
||||
// type depending on the type specifier: 'd' and 'i' - signed, other -
|
||||
// unsigned).
|
||||
template <typename T, typename Context, typename Char>
|
||||
void convert_arg(basic_format_arg<Context> &arg, Char type) {
|
||||
visit_format_arg(arg_converter<T, Context>(arg, type), arg);
|
||||
}
|
||||
|
||||
// Converts an integer argument to char for printf.
|
||||
template <typename Context>
|
||||
class char_converter: public function<void> {
|
||||
private:
|
||||
basic_format_arg<Context> &arg_;
|
||||
|
||||
public:
|
||||
explicit char_converter(basic_format_arg<Context> &arg) : arg_(arg) {}
|
||||
|
||||
template <typename T>
|
||||
typename std::enable_if<std::is_integral<T>::value>::type
|
||||
operator()(T value) {
|
||||
typedef typename Context::char_type Char;
|
||||
arg_ = internal::make_arg<Context>(static_cast<Char>(value));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
typename std::enable_if<!std::is_integral<T>::value>::type operator()(T) {
|
||||
// No coversion needed for non-integral types.
|
||||
}
|
||||
};
|
||||
|
||||
// Checks if an argument is a valid printf width specifier and sets
|
||||
// left alignment if it is negative.
|
||||
template <typename Char>
|
||||
class printf_width_handler: public function<unsigned> {
|
||||
private:
|
||||
typedef basic_format_specs<Char> format_specs;
|
||||
|
||||
format_specs &spec_;
|
||||
|
||||
public:
|
||||
explicit printf_width_handler(format_specs &spec) : spec_(spec) {}
|
||||
|
||||
template <typename T>
|
||||
typename std::enable_if<std::is_integral<T>::value, unsigned>::type
|
||||
operator()(T value) {
|
||||
typedef typename internal::int_traits<T>::main_type UnsignedType;
|
||||
UnsignedType width = static_cast<UnsignedType>(value);
|
||||
if (internal::is_negative(value)) {
|
||||
spec_.align_ = ALIGN_LEFT;
|
||||
width = 0 - width;
|
||||
}
|
||||
unsigned int_max = std::numeric_limits<int>::max();
|
||||
if (width > int_max)
|
||||
FMT_THROW(format_error("number is too big"));
|
||||
return static_cast<unsigned>(width);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
typename std::enable_if<!std::is_integral<T>::value, unsigned>::type
|
||||
operator()(T) {
|
||||
FMT_THROW(format_error("width is not integer"));
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Char, typename Context>
|
||||
void printf(basic_buffer<Char> &buf, basic_string_view<Char> format,
|
||||
basic_format_args<Context> args) {
|
||||
Context(std::back_inserter(buf), format, args).format();
|
||||
}
|
||||
} // namespace internal
|
||||
|
||||
using internal::printf; // For printing into memory_buffer.
|
||||
|
||||
template <typename Range>
|
||||
class printf_arg_formatter;
|
||||
|
||||
template <
|
||||
typename OutputIt, typename Char,
|
||||
typename ArgFormatter =
|
||||
printf_arg_formatter<back_insert_range<internal::basic_buffer<Char>>>>
|
||||
class basic_printf_context;
|
||||
|
||||
/**
|
||||
\rst
|
||||
The ``printf`` argument formatter.
|
||||
\endrst
|
||||
*/
|
||||
template <typename Range>
|
||||
class printf_arg_formatter:
|
||||
public internal::function<
|
||||
typename internal::arg_formatter_base<Range>::iterator>,
|
||||
public internal::arg_formatter_base<Range> {
|
||||
private:
|
||||
typedef typename Range::value_type char_type;
|
||||
typedef decltype(internal::declval<Range>().begin()) iterator;
|
||||
typedef internal::arg_formatter_base<Range> base;
|
||||
typedef basic_printf_context<iterator, char_type> context_type;
|
||||
|
||||
context_type &context_;
|
||||
|
||||
void write_null_pointer(char) {
|
||||
this->spec()->type = 0;
|
||||
this->write("(nil)");
|
||||
}
|
||||
|
||||
void write_null_pointer(wchar_t) {
|
||||
this->spec()->type = 0;
|
||||
this->write(L"(nil)");
|
||||
}
|
||||
|
||||
public:
|
||||
typedef typename base::format_specs format_specs;
|
||||
|
||||
/**
|
||||
\rst
|
||||
Constructs an argument formatter object.
|
||||
*buffer* is a reference to the output buffer and *spec* contains format
|
||||
specifier information for standard argument types.
|
||||
\endrst
|
||||
*/
|
||||
printf_arg_formatter(internal::basic_buffer<char_type> &buffer,
|
||||
format_specs &spec, context_type &ctx)
|
||||
: base(back_insert_range<internal::basic_buffer<char_type>>(buffer), &spec,
|
||||
ctx.locale()),
|
||||
context_(ctx) {}
|
||||
|
||||
template <typename T>
|
||||
typename std::enable_if<std::is_integral<T>::value, iterator>::type
|
||||
operator()(T value) {
|
||||
// MSVC2013 fails to compile separate overloads for bool and char_type so
|
||||
// use std::is_same instead.
|
||||
if (std::is_same<T, bool>::value) {
|
||||
format_specs &fmt_spec = *this->spec();
|
||||
if (fmt_spec.type != 's')
|
||||
return base::operator()(value ? 1 : 0);
|
||||
fmt_spec.type = 0;
|
||||
this->write(value != 0);
|
||||
} else if (std::is_same<T, char_type>::value) {
|
||||
format_specs &fmt_spec = *this->spec();
|
||||
if (fmt_spec.type && fmt_spec.type != 'c')
|
||||
return (*this)(static_cast<int>(value));
|
||||
fmt_spec.flags = 0;
|
||||
fmt_spec.align_ = ALIGN_RIGHT;
|
||||
return base::operator()(value);
|
||||
} else {
|
||||
return base::operator()(value);
|
||||
}
|
||||
return this->out();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
typename std::enable_if<std::is_floating_point<T>::value, iterator>::type
|
||||
operator()(T value) {
|
||||
return base::operator()(value);
|
||||
}
|
||||
|
||||
/** Formats a null-terminated C string. */
|
||||
iterator operator()(const char *value) {
|
||||
if (value)
|
||||
base::operator()(value);
|
||||
else if (this->spec()->type == 'p')
|
||||
write_null_pointer(char_type());
|
||||
else
|
||||
this->write("(null)");
|
||||
return this->out();
|
||||
}
|
||||
|
||||
/** Formats a null-terminated wide C string. */
|
||||
iterator operator()(const wchar_t *value) {
|
||||
if (value)
|
||||
base::operator()(value);
|
||||
else if (this->spec()->type == 'p')
|
||||
write_null_pointer(char_type());
|
||||
else
|
||||
this->write(L"(null)");
|
||||
return this->out();
|
||||
}
|
||||
|
||||
iterator operator()(basic_string_view<char_type> value) {
|
||||
return base::operator()(value);
|
||||
}
|
||||
|
||||
iterator operator()(monostate value) {
|
||||
return base::operator()(value);
|
||||
}
|
||||
|
||||
/** Formats a pointer. */
|
||||
iterator operator()(const void *value) {
|
||||
if (value)
|
||||
return base::operator()(value);
|
||||
this->spec()->type = 0;
|
||||
write_null_pointer(char_type());
|
||||
return this->out();
|
||||
}
|
||||
|
||||
/** Formats an argument of a custom (user-defined) type. */
|
||||
iterator operator()(typename basic_format_arg<context_type>::handle handle) {
|
||||
handle.format(context_);
|
||||
return this->out();
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct printf_formatter {
|
||||
template <typename ParseContext>
|
||||
auto parse(ParseContext &ctx) -> decltype(ctx.begin()) { return ctx.begin(); }
|
||||
|
||||
template <typename FormatContext>
|
||||
auto format(const T &value, FormatContext &ctx) -> decltype(ctx.out()) {
|
||||
internal::format_value(internal::get_container(ctx.out()), value);
|
||||
return ctx.out();
|
||||
}
|
||||
};
|
||||
|
||||
/** This template formats data and writes the output to a writer. */
|
||||
template <typename OutputIt, typename Char, typename ArgFormatter>
|
||||
class basic_printf_context :
|
||||
// Inherit publicly as a workaround for the icc bug
|
||||
// https://software.intel.com/en-us/forums/intel-c-compiler/topic/783476.
|
||||
public internal::context_base<
|
||||
OutputIt, basic_printf_context<OutputIt, Char, ArgFormatter>, Char> {
|
||||
public:
|
||||
/** The character type for the output. */
|
||||
typedef Char char_type;
|
||||
|
||||
template <typename T>
|
||||
struct formatter_type { typedef printf_formatter<T> type; };
|
||||
|
||||
private:
|
||||
typedef internal::context_base<OutputIt, basic_printf_context, Char> base;
|
||||
typedef typename base::format_arg format_arg;
|
||||
typedef basic_format_specs<char_type> format_specs;
|
||||
typedef internal::null_terminating_iterator<char_type> iterator;
|
||||
|
||||
void parse_flags(format_specs &spec, iterator &it);
|
||||
|
||||
// Returns the argument with specified index or, if arg_index is equal
|
||||
// to the maximum unsigned value, the next argument.
|
||||
format_arg get_arg(
|
||||
iterator it,
|
||||
unsigned arg_index = (std::numeric_limits<unsigned>::max)());
|
||||
|
||||
// Parses argument index, flags and width and returns the argument index.
|
||||
unsigned parse_header(iterator &it, format_specs &spec);
|
||||
|
||||
public:
|
||||
/**
|
||||
\rst
|
||||
Constructs a ``printf_context`` object. References to the arguments and
|
||||
the writer are stored in the context object so make sure they have
|
||||
appropriate lifetimes.
|
||||
\endrst
|
||||
*/
|
||||
basic_printf_context(OutputIt out, basic_string_view<char_type> format_str,
|
||||
basic_format_args<basic_printf_context> args)
|
||||
: base(out, format_str, args) {}
|
||||
|
||||
using base::parse_context;
|
||||
using base::out;
|
||||
using base::advance_to;
|
||||
|
||||
/** Formats stored arguments and writes the output to the range. */
|
||||
void format();
|
||||
};
|
||||
|
||||
template <typename OutputIt, typename Char, typename AF>
|
||||
void basic_printf_context<OutputIt, Char, AF>::parse_flags(
|
||||
format_specs &spec, iterator &it) {
|
||||
for (;;) {
|
||||
switch (*it++) {
|
||||
case '-':
|
||||
spec.align_ = ALIGN_LEFT;
|
||||
break;
|
||||
case '+':
|
||||
spec.flags |= SIGN_FLAG | PLUS_FLAG;
|
||||
break;
|
||||
case '0':
|
||||
spec.fill_ = '0';
|
||||
break;
|
||||
case ' ':
|
||||
spec.flags |= SIGN_FLAG;
|
||||
break;
|
||||
case '#':
|
||||
spec.flags |= HASH_FLAG;
|
||||
break;
|
||||
default:
|
||||
--it;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename OutputIt, typename Char, typename AF>
|
||||
typename basic_printf_context<OutputIt, Char, AF>::format_arg
|
||||
basic_printf_context<OutputIt, Char, AF>::get_arg(
|
||||
iterator it, unsigned arg_index) {
|
||||
(void)it;
|
||||
if (arg_index == std::numeric_limits<unsigned>::max())
|
||||
return this->do_get_arg(this->parse_context().next_arg_id());
|
||||
return base::get_arg(arg_index - 1);
|
||||
}
|
||||
|
||||
template <typename OutputIt, typename Char, typename AF>
|
||||
unsigned basic_printf_context<OutputIt, Char, AF>::parse_header(
|
||||
iterator &it, format_specs &spec) {
|
||||
unsigned arg_index = std::numeric_limits<unsigned>::max();
|
||||
char_type c = *it;
|
||||
if (c >= '0' && c <= '9') {
|
||||
// Parse an argument index (if followed by '$') or a width possibly
|
||||
// preceded with '0' flag(s).
|
||||
internal::error_handler eh;
|
||||
unsigned value = parse_nonnegative_int(it, eh);
|
||||
if (*it == '$') { // value is an argument index
|
||||
++it;
|
||||
arg_index = value;
|
||||
} else {
|
||||
if (c == '0')
|
||||
spec.fill_ = '0';
|
||||
if (value != 0) {
|
||||
// Nonzero value means that we parsed width and don't need to
|
||||
// parse it or flags again, so return now.
|
||||
spec.width_ = value;
|
||||
return arg_index;
|
||||
}
|
||||
}
|
||||
}
|
||||
parse_flags(spec, it);
|
||||
// Parse width.
|
||||
if (*it >= '0' && *it <= '9') {
|
||||
internal::error_handler eh;
|
||||
spec.width_ = parse_nonnegative_int(it, eh);
|
||||
} else if (*it == '*') {
|
||||
++it;
|
||||
spec.width_ = visit_format_arg(
|
||||
internal::printf_width_handler<char_type>(spec), get_arg(it));
|
||||
}
|
||||
return arg_index;
|
||||
}
|
||||
|
||||
template <typename OutputIt, typename Char, typename AF>
|
||||
void basic_printf_context<OutputIt, Char, AF>::format() {
|
||||
auto &buffer = internal::get_container(this->out());
|
||||
auto start = iterator(this->parse_context());
|
||||
auto it = start;
|
||||
using internal::pointer_from;
|
||||
while (*it) {
|
||||
char_type c = *it++;
|
||||
if (c != '%') continue;
|
||||
if (*it == c) {
|
||||
buffer.append(pointer_from(start), pointer_from(it));
|
||||
start = ++it;
|
||||
continue;
|
||||
}
|
||||
buffer.append(pointer_from(start), pointer_from(it) - 1);
|
||||
|
||||
format_specs spec;
|
||||
spec.align_ = ALIGN_RIGHT;
|
||||
|
||||
// Parse argument index, flags and width.
|
||||
unsigned arg_index = parse_header(it, spec);
|
||||
|
||||
// Parse precision.
|
||||
if (*it == '.') {
|
||||
++it;
|
||||
if ('0' <= *it && *it <= '9') {
|
||||
internal::error_handler eh;
|
||||
spec.precision = static_cast<int>(parse_nonnegative_int(it, eh));
|
||||
} else if (*it == '*') {
|
||||
++it;
|
||||
spec.precision =
|
||||
visit_format_arg(internal::printf_precision_handler(), get_arg(it));
|
||||
} else {
|
||||
spec.precision = 0;
|
||||
}
|
||||
}
|
||||
|
||||
format_arg arg = get_arg(it, arg_index);
|
||||
if (spec.has(HASH_FLAG) && visit_format_arg(internal::is_zero_int(), arg))
|
||||
spec.flags = static_cast<uint_least8_t>(spec.flags & (~internal::to_unsigned<int>(HASH_FLAG)));
|
||||
if (spec.fill_ == '0') {
|
||||
if (arg.is_arithmetic())
|
||||
spec.align_ = ALIGN_NUMERIC;
|
||||
else
|
||||
spec.fill_ = ' '; // Ignore '0' flag for non-numeric types.
|
||||
}
|
||||
|
||||
// Parse length and convert the argument to the required type.
|
||||
using internal::convert_arg;
|
||||
switch (*it++) {
|
||||
case 'h':
|
||||
if (*it == 'h')
|
||||
convert_arg<signed char>(arg, *++it);
|
||||
else
|
||||
convert_arg<short>(arg, *it);
|
||||
break;
|
||||
case 'l':
|
||||
if (*it == 'l')
|
||||
convert_arg<long long>(arg, *++it);
|
||||
else
|
||||
convert_arg<long>(arg, *it);
|
||||
break;
|
||||
case 'j':
|
||||
convert_arg<intmax_t>(arg, *it);
|
||||
break;
|
||||
case 'z':
|
||||
convert_arg<std::size_t>(arg, *it);
|
||||
break;
|
||||
case 't':
|
||||
convert_arg<std::ptrdiff_t>(arg, *it);
|
||||
break;
|
||||
case 'L':
|
||||
// printf produces garbage when 'L' is omitted for long double, no
|
||||
// need to do the same.
|
||||
break;
|
||||
default:
|
||||
--it;
|
||||
convert_arg<void>(arg, *it);
|
||||
}
|
||||
|
||||
// Parse type.
|
||||
if (!*it)
|
||||
FMT_THROW(format_error("invalid format string"));
|
||||
spec.type = static_cast<char>(*it++);
|
||||
if (arg.is_integral()) {
|
||||
// Normalize type.
|
||||
switch (spec.type) {
|
||||
case 'i': case 'u':
|
||||
spec.type = 'd';
|
||||
break;
|
||||
case 'c':
|
||||
// TODO: handle wchar_t better?
|
||||
visit_format_arg(
|
||||
internal::char_converter<basic_printf_context>(arg), arg);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
start = it;
|
||||
|
||||
// Format argument.
|
||||
visit_format_arg(AF(buffer, spec, *this), arg);
|
||||
}
|
||||
buffer.append(pointer_from(start), pointer_from(it));
|
||||
}
|
||||
|
||||
template <typename Buffer>
|
||||
struct basic_printf_context_t {
|
||||
typedef basic_printf_context<
|
||||
std::back_insert_iterator<Buffer>, typename Buffer::value_type> type;
|
||||
};
|
||||
|
||||
typedef basic_printf_context_t<internal::buffer>::type printf_context;
|
||||
typedef basic_printf_context_t<internal::wbuffer>::type wprintf_context;
|
||||
|
||||
typedef basic_format_args<printf_context> printf_args;
|
||||
typedef basic_format_args<wprintf_context> wprintf_args;
|
||||
|
||||
/**
|
||||
\rst
|
||||
Constructs an `~fmt::format_arg_store` object that contains references to
|
||||
arguments and can be implicitly converted to `~fmt::printf_args`.
|
||||
\endrst
|
||||
*/
|
||||
template<typename... Args>
|
||||
inline format_arg_store<printf_context, Args...>
|
||||
make_printf_args(const Args &... args) { return {args...}; }
|
||||
|
||||
/**
|
||||
\rst
|
||||
Constructs an `~fmt::format_arg_store` object that contains references to
|
||||
arguments and can be implicitly converted to `~fmt::wprintf_args`.
|
||||
\endrst
|
||||
*/
|
||||
template<typename... Args>
|
||||
inline format_arg_store<wprintf_context, Args...>
|
||||
make_wprintf_args(const Args &... args) { return {args...}; }
|
||||
|
||||
template <typename S, typename Char = FMT_CHAR(S)>
|
||||
inline std::basic_string<Char>
|
||||
vsprintf(const S &format,
|
||||
basic_format_args<typename basic_printf_context_t<
|
||||
internal::basic_buffer<Char>>::type> args) {
|
||||
basic_memory_buffer<Char> buffer;
|
||||
printf(buffer, to_string_view(format), args);
|
||||
return to_string(buffer);
|
||||
}
|
||||
|
||||
/**
|
||||
\rst
|
||||
Formats arguments and returns the result as a string.
|
||||
|
||||
**Example**::
|
||||
|
||||
std::string message = fmt::sprintf("The answer is %d", 42);
|
||||
\endrst
|
||||
*/
|
||||
template <typename S, typename... Args>
|
||||
inline FMT_ENABLE_IF_T(
|
||||
internal::is_string<S>::value, std::basic_string<FMT_CHAR(S)>)
|
||||
sprintf(const S &format, const Args & ... args) {
|
||||
internal::check_format_string<Args...>(format);
|
||||
typedef internal::basic_buffer<FMT_CHAR(S)> buffer;
|
||||
typedef typename basic_printf_context_t<buffer>::type context;
|
||||
format_arg_store<context, Args...> as{ args... };
|
||||
return vsprintf(to_string_view(format),
|
||||
basic_format_args<context>(as));
|
||||
}
|
||||
|
||||
template <typename S, typename Char = FMT_CHAR(S)>
|
||||
inline int vfprintf(std::FILE *f, const S &format,
|
||||
basic_format_args<typename basic_printf_context_t<
|
||||
internal::basic_buffer<Char>>::type> args) {
|
||||
basic_memory_buffer<Char> buffer;
|
||||
printf(buffer, to_string_view(format), args);
|
||||
std::size_t size = buffer.size();
|
||||
return std::fwrite(
|
||||
buffer.data(), sizeof(Char), size, f) < size ? -1 : static_cast<int>(size);
|
||||
}
|
||||
|
||||
/**
|
||||
\rst
|
||||
Prints formatted data to the file *f*.
|
||||
|
||||
**Example**::
|
||||
|
||||
fmt::fprintf(stderr, "Don't %s!", "panic");
|
||||
\endrst
|
||||
*/
|
||||
template <typename S, typename... Args>
|
||||
inline FMT_ENABLE_IF_T(internal::is_string<S>::value, int)
|
||||
fprintf(std::FILE *f, const S &format, const Args & ... args) {
|
||||
internal::check_format_string<Args...>(format);
|
||||
typedef internal::basic_buffer<FMT_CHAR(S)> buffer;
|
||||
typedef typename basic_printf_context_t<buffer>::type context;
|
||||
format_arg_store<context, Args...> as{ args... };
|
||||
return vfprintf(f, to_string_view(format),
|
||||
basic_format_args<context>(as));
|
||||
}
|
||||
|
||||
template <typename S, typename Char = FMT_CHAR(S)>
|
||||
inline int vprintf(const S &format,
|
||||
basic_format_args<typename basic_printf_context_t<
|
||||
internal::basic_buffer<Char>>::type> args) {
|
||||
return vfprintf(stdout, to_string_view(format), args);
|
||||
}
|
||||
|
||||
/**
|
||||
\rst
|
||||
Prints formatted data to ``stdout``.
|
||||
|
||||
**Example**::
|
||||
|
||||
fmt::printf("Elapsed time: %.2f seconds", 1.23);
|
||||
\endrst
|
||||
*/
|
||||
template <typename S, typename... Args>
|
||||
inline FMT_ENABLE_IF_T(internal::is_string<S>::value, int)
|
||||
printf(const S &format_str, const Args & ... args) {
|
||||
internal::check_format_string<Args...>(format_str);
|
||||
typedef internal::basic_buffer<FMT_CHAR(S)> buffer;
|
||||
typedef typename basic_printf_context_t<buffer>::type context;
|
||||
format_arg_store<context, Args...> as{ args... };
|
||||
return vprintf(to_string_view(format_str),
|
||||
basic_format_args<context>(as));
|
||||
}
|
||||
|
||||
template <typename S, typename Char = FMT_CHAR(S)>
|
||||
inline int vfprintf(std::basic_ostream<Char> &os,
|
||||
const S &format,
|
||||
basic_format_args<typename basic_printf_context_t<
|
||||
internal::basic_buffer<Char>>::type> args) {
|
||||
basic_memory_buffer<Char> buffer;
|
||||
printf(buffer, to_string_view(format), args);
|
||||
internal::write(os, buffer);
|
||||
return static_cast<int>(buffer.size());
|
||||
}
|
||||
|
||||
/**
|
||||
\rst
|
||||
Prints formatted data to the stream *os*.
|
||||
|
||||
**Example**::
|
||||
|
||||
fmt::fprintf(cerr, "Don't %s!", "panic");
|
||||
\endrst
|
||||
*/
|
||||
template <typename S, typename... Args>
|
||||
inline FMT_ENABLE_IF_T(internal::is_string<S>::value, int)
|
||||
fprintf(std::basic_ostream<FMT_CHAR(S)> &os,
|
||||
const S &format_str, const Args & ... args) {
|
||||
internal::check_format_string<Args...>(format_str);
|
||||
typedef internal::basic_buffer<FMT_CHAR(S)> buffer;
|
||||
typedef typename basic_printf_context_t<buffer>::type context;
|
||||
format_arg_store<context, Args...> as{ args... };
|
||||
return vfprintf(os, to_string_view(format_str),
|
||||
basic_format_args<context>(as));
|
||||
}
|
||||
FMT_END_NAMESPACE
|
||||
|
||||
#endif // FMT_PRINTF_H_
|
308
include/Livox/third_party/spdlog/spdlog/fmt/bundled/ranges.h
vendored
Executable file
308
include/Livox/third_party/spdlog/spdlog/fmt/bundled/ranges.h
vendored
Executable file
@ -0,0 +1,308 @@
|
||||
// Formatting library for C++ - the core API
|
||||
//
|
||||
// Copyright (c) 2012 - present, Victor Zverovich
|
||||
// All rights reserved.
|
||||
//
|
||||
// For the license information refer to format.h.
|
||||
//
|
||||
// Copyright (c) 2018 - present, Remotion (Igor Schulz)
|
||||
// All Rights Reserved
|
||||
// {fmt} support for ranges, containers and types tuple interface.
|
||||
|
||||
#ifndef FMT_RANGES_H_
|
||||
#define FMT_RANGES_H_
|
||||
|
||||
#include "format.h"
|
||||
#include <type_traits>
|
||||
|
||||
// output only up to N items from the range.
|
||||
#ifndef FMT_RANGE_OUTPUT_LENGTH_LIMIT
|
||||
# define FMT_RANGE_OUTPUT_LENGTH_LIMIT 256
|
||||
#endif
|
||||
|
||||
FMT_BEGIN_NAMESPACE
|
||||
|
||||
template <typename Char>
|
||||
struct formatting_base {
|
||||
template <typename ParseContext>
|
||||
FMT_CONSTEXPR auto parse(ParseContext &ctx) -> decltype(ctx.begin()) {
|
||||
return ctx.begin();
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Char, typename Enable = void>
|
||||
struct formatting_range : formatting_base<Char> {
|
||||
static FMT_CONSTEXPR_DECL const std::size_t range_length_limit =
|
||||
FMT_RANGE_OUTPUT_LENGTH_LIMIT; // output only up to N items from the range.
|
||||
Char prefix;
|
||||
Char delimiter;
|
||||
Char postfix;
|
||||
formatting_range() : prefix('{'), delimiter(','), postfix('}') {}
|
||||
static FMT_CONSTEXPR_DECL const bool add_delimiter_spaces = true;
|
||||
static FMT_CONSTEXPR_DECL const bool add_prepostfix_space = false;
|
||||
};
|
||||
|
||||
template <typename Char, typename Enable = void>
|
||||
struct formatting_tuple : formatting_base<Char> {
|
||||
Char prefix;
|
||||
Char delimiter;
|
||||
Char postfix;
|
||||
formatting_tuple() : prefix('('), delimiter(','), postfix(')') {}
|
||||
static FMT_CONSTEXPR_DECL const bool add_delimiter_spaces = true;
|
||||
static FMT_CONSTEXPR_DECL const bool add_prepostfix_space = false;
|
||||
};
|
||||
|
||||
namespace internal {
|
||||
|
||||
template <typename RangeT, typename OutputIterator>
|
||||
void copy(const RangeT &range, OutputIterator out) {
|
||||
for (auto it = range.begin(), end = range.end(); it != end; ++it)
|
||||
*out++ = *it;
|
||||
}
|
||||
|
||||
template <typename OutputIterator>
|
||||
void copy(const char *str, OutputIterator out) {
|
||||
const char *p_curr = str;
|
||||
while (*p_curr) {
|
||||
*out++ = *p_curr++;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename OutputIterator>
|
||||
void copy(char ch, OutputIterator out) {
|
||||
*out++ = ch;
|
||||
}
|
||||
|
||||
/// Return true value if T has std::string interface, like std::string_view.
|
||||
template <typename T>
|
||||
class is_like_std_string {
|
||||
template <typename U>
|
||||
static auto check(U *p) ->
|
||||
decltype(p->find('a'), p->length(), p->data(), int());
|
||||
template <typename>
|
||||
static void check(...);
|
||||
|
||||
public:
|
||||
static FMT_CONSTEXPR_DECL const bool value =
|
||||
!std::is_void<decltype(check<T>(FMT_NULL))>::value;
|
||||
};
|
||||
|
||||
template <typename Char>
|
||||
struct is_like_std_string<fmt::basic_string_view<Char>> : std::true_type {};
|
||||
|
||||
template <typename... Ts>
|
||||
struct conditional_helper {};
|
||||
|
||||
template <typename T, typename _ = void>
|
||||
struct is_range_ : std::false_type {};
|
||||
|
||||
#if !FMT_MSC_VER || FMT_MSC_VER > 1800
|
||||
template <typename T>
|
||||
struct is_range_<T, typename std::conditional<
|
||||
false,
|
||||
conditional_helper<decltype(internal::declval<T>().begin()),
|
||||
decltype(internal::declval<T>().end())>,
|
||||
void>::type> : std::true_type {};
|
||||
#endif
|
||||
|
||||
/// tuple_size and tuple_element check.
|
||||
template <typename T>
|
||||
class is_tuple_like_ {
|
||||
template <typename U>
|
||||
static auto check(U *p) ->
|
||||
decltype(std::tuple_size<U>::value,
|
||||
internal::declval<typename std::tuple_element<0, U>::type>(), int());
|
||||
template <typename>
|
||||
static void check(...);
|
||||
|
||||
public:
|
||||
static FMT_CONSTEXPR_DECL const bool value =
|
||||
!std::is_void<decltype(check<T>(FMT_NULL))>::value;
|
||||
};
|
||||
|
||||
// Check for integer_sequence
|
||||
#if defined(__cpp_lib_integer_sequence) || FMT_MSC_VER >= 1900
|
||||
template <typename T, T... N>
|
||||
using integer_sequence = std::integer_sequence<T, N...>;
|
||||
template <std::size_t... N>
|
||||
using index_sequence = std::index_sequence<N...>;
|
||||
template <std::size_t N>
|
||||
using make_index_sequence = std::make_index_sequence<N>;
|
||||
#else
|
||||
template <typename T, T... N>
|
||||
struct integer_sequence {
|
||||
typedef T value_type;
|
||||
|
||||
static FMT_CONSTEXPR std::size_t size() {
|
||||
return sizeof...(N);
|
||||
}
|
||||
};
|
||||
|
||||
template <std::size_t... N>
|
||||
using index_sequence = integer_sequence<std::size_t, N...>;
|
||||
|
||||
template <typename T, std::size_t N, T... Ns>
|
||||
struct make_integer_sequence : make_integer_sequence<T, N - 1, N - 1, Ns...> {};
|
||||
template <typename T, T... Ns>
|
||||
struct make_integer_sequence<T, 0, Ns...> : integer_sequence<T, Ns...> {};
|
||||
|
||||
template <std::size_t N>
|
||||
using make_index_sequence = make_integer_sequence<std::size_t, N>;
|
||||
#endif
|
||||
|
||||
template <class Tuple, class F, size_t... Is>
|
||||
void for_each(index_sequence<Is...>, Tuple &&tup, F &&f) FMT_NOEXCEPT {
|
||||
using std::get;
|
||||
// using free function get<I>(T) now.
|
||||
const int _[] = {0, ((void)f(get<Is>(tup)), 0)...};
|
||||
(void)_; // blocks warnings
|
||||
}
|
||||
|
||||
template <class T>
|
||||
FMT_CONSTEXPR make_index_sequence<std::tuple_size<T>::value>
|
||||
get_indexes(T const &) { return {}; }
|
||||
|
||||
template <class Tuple, class F>
|
||||
void for_each(Tuple &&tup, F &&f) {
|
||||
const auto indexes = get_indexes(tup);
|
||||
for_each(indexes, std::forward<Tuple>(tup), std::forward<F>(f));
|
||||
}
|
||||
|
||||
template<typename Arg>
|
||||
FMT_CONSTEXPR const char* format_str_quoted(bool add_space, const Arg&,
|
||||
typename std::enable_if<
|
||||
!is_like_std_string<typename std::decay<Arg>::type>::value>::type* = nullptr) {
|
||||
return add_space ? " {}" : "{}";
|
||||
}
|
||||
|
||||
template<typename Arg>
|
||||
FMT_CONSTEXPR const char* format_str_quoted(bool add_space, const Arg&,
|
||||
typename std::enable_if<
|
||||
is_like_std_string<typename std::decay<Arg>::type>::value>::type* = nullptr) {
|
||||
return add_space ? " \"{}\"" : "\"{}\"";
|
||||
}
|
||||
|
||||
FMT_CONSTEXPR const char* format_str_quoted(bool add_space, const char*) {
|
||||
return add_space ? " \"{}\"" : "\"{}\"";
|
||||
}
|
||||
FMT_CONSTEXPR const wchar_t* format_str_quoted(bool add_space, const wchar_t*) {
|
||||
return add_space ? L" \"{}\"" : L"\"{}\"";
|
||||
}
|
||||
|
||||
FMT_CONSTEXPR const char* format_str_quoted(bool add_space, const char) {
|
||||
return add_space ? " '{}'" : "'{}'";
|
||||
}
|
||||
FMT_CONSTEXPR const wchar_t* format_str_quoted(bool add_space, const wchar_t) {
|
||||
return add_space ? L" '{}'" : L"'{}'";
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
|
||||
template <typename T>
|
||||
struct is_tuple_like {
|
||||
static FMT_CONSTEXPR_DECL const bool value =
|
||||
internal::is_tuple_like_<T>::value && !internal::is_range_<T>::value;
|
||||
};
|
||||
|
||||
template <typename TupleT, typename Char>
|
||||
struct formatter<TupleT, Char,
|
||||
typename std::enable_if<fmt::is_tuple_like<TupleT>::value>::type> {
|
||||
private:
|
||||
// C++11 generic lambda for format()
|
||||
template <typename FormatContext>
|
||||
struct format_each {
|
||||
template <typename T>
|
||||
void operator()(const T& v) {
|
||||
if (i > 0) {
|
||||
if (formatting.add_prepostfix_space) {
|
||||
*out++ = ' ';
|
||||
}
|
||||
internal::copy(formatting.delimiter, out);
|
||||
}
|
||||
format_to(out,
|
||||
internal::format_str_quoted(
|
||||
(formatting.add_delimiter_spaces && i > 0), v),
|
||||
v);
|
||||
++i;
|
||||
}
|
||||
|
||||
formatting_tuple<Char>& formatting;
|
||||
std::size_t& i;
|
||||
typename std::add_lvalue_reference<decltype(std::declval<FormatContext>().out())>::type out;
|
||||
};
|
||||
|
||||
public:
|
||||
formatting_tuple<Char> formatting;
|
||||
|
||||
template <typename ParseContext>
|
||||
FMT_CONSTEXPR auto parse(ParseContext &ctx) -> decltype(ctx.begin()) {
|
||||
return formatting.parse(ctx);
|
||||
}
|
||||
|
||||
template <typename FormatContext = format_context>
|
||||
auto format(const TupleT &values, FormatContext &ctx) -> decltype(ctx.out()) {
|
||||
auto out = ctx.out();
|
||||
std::size_t i = 0;
|
||||
internal::copy(formatting.prefix, out);
|
||||
|
||||
internal::for_each(values, format_each<FormatContext>{formatting, i, out});
|
||||
if (formatting.add_prepostfix_space) {
|
||||
*out++ = ' ';
|
||||
}
|
||||
internal::copy(formatting.postfix, out);
|
||||
|
||||
return ctx.out();
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct is_range {
|
||||
static FMT_CONSTEXPR_DECL const bool value =
|
||||
internal::is_range_<T>::value && !internal::is_like_std_string<T>::value;
|
||||
};
|
||||
|
||||
template <typename RangeT, typename Char>
|
||||
struct formatter<RangeT, Char,
|
||||
typename std::enable_if<fmt::is_range<RangeT>::value>::type> {
|
||||
|
||||
formatting_range<Char> formatting;
|
||||
|
||||
template <typename ParseContext>
|
||||
FMT_CONSTEXPR auto parse(ParseContext &ctx) -> decltype(ctx.begin()) {
|
||||
return formatting.parse(ctx);
|
||||
}
|
||||
|
||||
template <typename FormatContext>
|
||||
typename FormatContext::iterator format(
|
||||
const RangeT &values, FormatContext &ctx) {
|
||||
auto out = ctx.out();
|
||||
internal::copy(formatting.prefix, out);
|
||||
std::size_t i = 0;
|
||||
for (auto it = values.begin(), end = values.end(); it != end; ++it) {
|
||||
if (i > 0) {
|
||||
if (formatting.add_prepostfix_space) {
|
||||
*out++ = ' ';
|
||||
}
|
||||
internal::copy(formatting.delimiter, out);
|
||||
}
|
||||
format_to(out,
|
||||
internal::format_str_quoted(
|
||||
(formatting.add_delimiter_spaces && i > 0), *it),
|
||||
*it);
|
||||
if (++i > formatting.range_length_limit) {
|
||||
format_to(out, " ... <other elements>");
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (formatting.add_prepostfix_space) {
|
||||
*out++ = ' ';
|
||||
}
|
||||
internal::copy(formatting.postfix, out);
|
||||
return ctx.out();
|
||||
}
|
||||
};
|
||||
|
||||
FMT_END_NAMESPACE
|
||||
|
||||
#endif // FMT_RANGES_H_
|
||||
|
160
include/Livox/third_party/spdlog/spdlog/fmt/bundled/time.h
vendored
Executable file
160
include/Livox/third_party/spdlog/spdlog/fmt/bundled/time.h
vendored
Executable file
@ -0,0 +1,160 @@
|
||||
// Formatting library for C++ - time formatting
|
||||
//
|
||||
// Copyright (c) 2012 - present, Victor Zverovich
|
||||
// All rights reserved.
|
||||
//
|
||||
// For the license information refer to format.h.
|
||||
|
||||
#ifndef FMT_TIME_H_
|
||||
#define FMT_TIME_H_
|
||||
|
||||
#include "format.h"
|
||||
#include <ctime>
|
||||
#include <locale>
|
||||
|
||||
FMT_BEGIN_NAMESPACE
|
||||
|
||||
// Prevents expansion of a preceding token as a function-style macro.
|
||||
// Usage: f FMT_NOMACRO()
|
||||
#define FMT_NOMACRO
|
||||
|
||||
namespace internal{
|
||||
inline null<> localtime_r FMT_NOMACRO(...) { return null<>(); }
|
||||
inline null<> localtime_s(...) { return null<>(); }
|
||||
inline null<> gmtime_r(...) { return null<>(); }
|
||||
inline null<> gmtime_s(...) { return null<>(); }
|
||||
} // namespace internal
|
||||
|
||||
// Thread-safe replacement for std::localtime
|
||||
inline std::tm localtime(std::time_t time) {
|
||||
struct dispatcher {
|
||||
std::time_t time_;
|
||||
std::tm tm_;
|
||||
|
||||
dispatcher(std::time_t t): time_(t) {}
|
||||
|
||||
bool run() {
|
||||
using namespace fmt::internal;
|
||||
return handle(localtime_r(&time_, &tm_));
|
||||
}
|
||||
|
||||
bool handle(std::tm *tm) { return tm != FMT_NULL; }
|
||||
|
||||
bool handle(internal::null<>) {
|
||||
using namespace fmt::internal;
|
||||
return fallback(localtime_s(&tm_, &time_));
|
||||
}
|
||||
|
||||
bool fallback(int res) { return res == 0; }
|
||||
|
||||
#if !FMT_MSC_VER
|
||||
bool fallback(internal::null<>) {
|
||||
using namespace fmt::internal;
|
||||
std::tm *tm = std::localtime(&time_);
|
||||
if (tm) tm_ = *tm;
|
||||
return tm != FMT_NULL;
|
||||
}
|
||||
#endif
|
||||
};
|
||||
dispatcher lt(time);
|
||||
// Too big time values may be unsupported.
|
||||
if (!lt.run())
|
||||
FMT_THROW(format_error("time_t value out of range"));
|
||||
return lt.tm_;
|
||||
}
|
||||
|
||||
// Thread-safe replacement for std::gmtime
|
||||
inline std::tm gmtime(std::time_t time) {
|
||||
struct dispatcher {
|
||||
std::time_t time_;
|
||||
std::tm tm_;
|
||||
|
||||
dispatcher(std::time_t t): time_(t) {}
|
||||
|
||||
bool run() {
|
||||
using namespace fmt::internal;
|
||||
return handle(gmtime_r(&time_, &tm_));
|
||||
}
|
||||
|
||||
bool handle(std::tm *tm) { return tm != FMT_NULL; }
|
||||
|
||||
bool handle(internal::null<>) {
|
||||
using namespace fmt::internal;
|
||||
return fallback(gmtime_s(&tm_, &time_));
|
||||
}
|
||||
|
||||
bool fallback(int res) { return res == 0; }
|
||||
|
||||
#if !FMT_MSC_VER
|
||||
bool fallback(internal::null<>) {
|
||||
std::tm *tm = std::gmtime(&time_);
|
||||
if (tm) tm_ = *tm;
|
||||
return tm != FMT_NULL;
|
||||
}
|
||||
#endif
|
||||
};
|
||||
dispatcher gt(time);
|
||||
// Too big time values may be unsupported.
|
||||
if (!gt.run())
|
||||
FMT_THROW(format_error("time_t value out of range"));
|
||||
return gt.tm_;
|
||||
}
|
||||
|
||||
namespace internal {
|
||||
inline std::size_t strftime(char *str, std::size_t count, const char *format,
|
||||
const std::tm *time) {
|
||||
return std::strftime(str, count, format, time);
|
||||
}
|
||||
|
||||
inline std::size_t strftime(wchar_t *str, std::size_t count,
|
||||
const wchar_t *format, const std::tm *time) {
|
||||
return std::wcsftime(str, count, format, time);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Char>
|
||||
struct formatter<std::tm, Char> {
|
||||
template <typename ParseContext>
|
||||
auto parse(ParseContext &ctx) -> decltype(ctx.begin()) {
|
||||
auto it = ctx.begin();
|
||||
if (it != ctx.end() && *it == ':')
|
||||
++it;
|
||||
auto end = it;
|
||||
while (end != ctx.end() && *end != '}')
|
||||
++end;
|
||||
tm_format.reserve(internal::to_unsigned(end - it + 1));
|
||||
tm_format.append(it, end);
|
||||
tm_format.push_back('\0');
|
||||
return end;
|
||||
}
|
||||
|
||||
template <typename FormatContext>
|
||||
auto format(const std::tm &tm, FormatContext &ctx) -> decltype(ctx.out()) {
|
||||
basic_memory_buffer<Char> buf;
|
||||
std::size_t start = buf.size();
|
||||
for (;;) {
|
||||
std::size_t size = buf.capacity() - start;
|
||||
std::size_t count =
|
||||
internal::strftime(&buf[start], size, &tm_format[0], &tm);
|
||||
if (count != 0) {
|
||||
buf.resize(start + count);
|
||||
break;
|
||||
}
|
||||
if (size >= tm_format.size() * 256) {
|
||||
// If the buffer is 256 times larger than the format string, assume
|
||||
// that `strftime` gives an empty result. There doesn't seem to be a
|
||||
// better way to distinguish the two cases:
|
||||
// https://github.com/fmtlib/fmt/issues/367
|
||||
break;
|
||||
}
|
||||
const std::size_t MIN_GROWTH = 10;
|
||||
buf.reserve(buf.capacity() + (size > MIN_GROWTH ? size : MIN_GROWTH));
|
||||
}
|
||||
return std::copy(buf.begin(), buf.end(), ctx.out());
|
||||
}
|
||||
|
||||
basic_memory_buffer<Char> tm_format;
|
||||
};
|
||||
FMT_END_NAMESPACE
|
||||
|
||||
#endif // FMT_TIME_H_
|
25
include/Livox/third_party/spdlog/spdlog/fmt/fmt.h
vendored
Executable file
25
include/Livox/third_party/spdlog/spdlog/fmt/fmt.h
vendored
Executable file
@ -0,0 +1,25 @@
|
||||
//
|
||||
// Copyright(c) 2016-2018 Gabi Melman.
|
||||
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
//
|
||||
// Include a bundled header-only copy of fmtlib or an external one.
|
||||
// By default spdlog include its own copy.
|
||||
//
|
||||
|
||||
#if !defined(SPDLOG_FMT_EXTERNAL)
|
||||
#ifndef FMT_HEADER_ONLY
|
||||
#define FMT_HEADER_ONLY
|
||||
#endif
|
||||
#ifndef FMT_USE_WINDOWS_H
|
||||
#define FMT_USE_WINDOWS_H 0
|
||||
#endif
|
||||
#include "bundled/core.h"
|
||||
#include "bundled/format.h"
|
||||
#else // external fmtlib
|
||||
#include <fmt/core.h>
|
||||
#include <fmt/format.h>
|
||||
#endif
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user