diff --git a/components/ext_dev/include/maix_imu.hpp b/components/ext_dev/include/maix_imu.hpp new file mode 100644 index 00000000..24db8f92 --- /dev/null +++ b/components/ext_dev/include/maix_imu.hpp @@ -0,0 +1,139 @@ +/** + * @author iawak9lkm + * @copyright Sipeed Ltd 2024- + * @license Apache 2.0 + * @update 2024.8.6: Add framework, create this file. + */ + +#pragma once +#include "maix_basic.hpp" + +#include +#include + +namespace maix::ext_dev::imu { + +/** + * @brief imu mode + * @maixpy maix.ext_dev.imu.Mode + */ +enum Mode { + ACC_ONLY = 0, + GYRO_ONLY, + DUAL +}; + +/** + * @brief imu acc scale + * @maixpy maix.ext_dev.imu.AccScale + */ +enum AccScale { + ACC_SCALE_2G = 0, + ACC_SCALE_4G, + ACC_SCALE_8G, + ACC_SCALE_16G +}; + +/** + * @brief imu acc output data rate + * @maixpy maix.ext_dev.imu.AccOdr + */ +enum AccOdr { + ACC_ODR_8000, // Accelerometer ODR set to 8000 Hz. + ACC_ODR_4000, // Accelerometer ODR set to 4000 Hz. + ACC_ODR_2000, // Accelerometer ODR set to 2000 Hz. + ACC_ODR_1000, // Accelerometer ODR set to 1000 Hz. + ACC_ODR_500, // Accelerometer ODR set to 500 Hz. + ACC_ODR_250, // Accelerometer ODR set to 250 Hz. + ACC_ODR_125, // Accelerometer ODR set to 125 Hz. + ACC_ODR_62_5, // Accelerometer ODR set to 62.5 Hz. + ACC_ODR_31_25, // Accelerometer ODR set to 31.25 Hz. + ACC_ODR_128 = 12, // Accelerometer ODR set to 128 Hz. + ACC_ODR_21, // Accelerometer ODR set to 21 Hz. + ACC_ODR_11, // Accelerometer ODR set to 11 Hz. + ACC_ODR_3, // Accelerometer ODR set to 3 Hz. +}; + +/** + * @brief imu gyro scale + * @maixpy maix.ext_dev.imu.GyroScale + */ +enum GyroScale { + GYRO_SCALE_16DPS = 0, // Gyroscope scale set to ±16 degrees per second. + GYRO_SCALE_32DPS, // Gyroscope scale set to ±32 degrees per second. + GYRO_SCALE_64DPS, // Gyroscope scale set to ±64 degrees per second. + GYRO_SCALE_128DPS, // Gyroscope scale set to ±128 degrees per second. + GYRO_SCALE_256DPS, // Gyroscope scale set to ±256 degrees per second. + GYRO_SCALE_512DPS, // Gyroscope scale set to ±512 degrees per second. + GYRO_SCALE_1024DPS, // Gyroscope scale set to ±1024 degrees per second. + GYRO_SCALE_2048DPS, // Gyroscope scale set to ±2048 degrees per second. +}; + +/** + * @brief imu gyro output data rate + * @maixpy maix.ext_dev.imu.GyroOdr + */ +enum GyroOdr { + GYRO_ODR_8000, // Gyroscope ODR set to 8000 Hz. + GYRO_ODR_4000, // Gyroscope ODR set to 4000 Hz. + GYRO_ODR_2000, // Gyroscope ODR set to 2000 Hz. + GYRO_ODR_1000, // Gyroscope ODR set to 1000 Hz. + GYRO_ODR_500, // Gyroscope ODR set to 500 Hz. + GYRO_ODR_250, // Gyroscope ODR set to 250 Hz. + GYRO_ODR_125, // Gyroscope ODR set to 125 Hz. + GYRO_ODR_62_5, // Gyroscope ODR set to 62.5 Hz. + GYRO_ODR_31_25, // Gyroscope ODR set to 31.25 Hz. +}; + +/** + * QMI8656 driver class + * @maixpy maix.ext_dev.imu.IMU + */ +class IMU { +public: + /** + * @brief Construct a new IMU object, will open IMU + * + * @param driver driver name, only support "qmi8656" + * @param i2c_bus i2c bus number. Automatically selects the on-board imu when -1 is passed in. + * @param addr IMU i2c addr. + * @param freq IMU freq + * @param mode IMU Mode: ACC_ONLY/GYRO_ONLY/DUAL + * @param acc_scale acc scale, see @imu::AccScale + * @param acc_odr acc output data rate, see @imu::AccOdr + * @param gyro_scale gyro scale, see @imu::GyroScale + * @param gyro_odr gyro output data rate, see @imu::GyroOdr + * @param block block or non-block, defalut is true + * + * @maixpy maix.ext_dev.imu.IMU.__init__ + */ + IMU(std::string driver, int i2c_bus=-1, int addr=0x6B, int freq=400000, + maix::ext_dev::imu::Mode mode=maix::ext_dev::imu::Mode::DUAL, + maix::ext_dev::imu::AccScale acc_scale=maix::ext_dev::imu::AccScale::ACC_SCALE_2G, + maix::ext_dev::imu::AccOdr acc_odr=maix::ext_dev::imu::AccOdr::ACC_ODR_8000, + maix::ext_dev::imu::GyroScale gyro_scale=maix::ext_dev::imu::GyroScale::GYRO_SCALE_16DPS, + maix::ext_dev::imu::GyroOdr gyro_odr=maix::ext_dev::imu::GyroOdr::GYRO_ODR_8000, + bool block=true); + ~IMU(); + + IMU(const IMU&) = delete; + IMU& operator=(const IMU&) = delete; + IMU(IMU&&) = delete; + IMU& operator=(IMU&&) = delete; + + /** + * @brief Read data from IMU. + * + * @return list type. If only one of the outputs is initialized, only [x,y,z] of that output will be returned. + * If all outputs are initialized, [acc_x, acc_y, acc_z, gyro_x, gyro_y, gyro_z] is returned. + * + * @maixpy maix.ext_dev.imu.IMU.read + */ + std::vector read(); +private: + void* _param; + std::string _driver; +}; + + +} \ No newline at end of file diff --git a/components/ext_dev/include/maix_qmi8658.hpp b/components/ext_dev/include/maix_qmi8658.hpp index 402164f1..1d4c242f 100644 --- a/components/ext_dev/include/maix_qmi8658.hpp +++ b/components/ext_dev/include/maix_qmi8658.hpp @@ -7,83 +7,12 @@ #pragma once #include "maix_basic.hpp" +#include "maix_imu.hpp" #include #include namespace maix::ext_dev::qmi8658 { -/** - * @brief qmi8658 mode - * @maixpy maix.ext_dev.qmi8658.Mode - */ -enum Mode { - ACC_ONLY = 0, - GYRO_ONLY, - DUAL -}; - -/** - * @brief qmi8658 acc scale - * @maixpy maix.ext_dev.qmi8658.AccScale - */ -enum AccScale { - ACC_SCALE_2G = 0, - ACC_SCALE_4G, - ACC_SCALE_8G, - ACC_SCALE_16G -}; - -/** - * @brief qmi8658 acc output data rate - * @maixpy maix.ext_dev.qmi8658.AccOdr - */ -enum AccOdr { - ACC_ODR_8000, // Accelerometer ODR set to 8000 Hz. - ACC_ODR_4000, // Accelerometer ODR set to 4000 Hz. - ACC_ODR_2000, // Accelerometer ODR set to 2000 Hz. - ACC_ODR_1000, // Accelerometer ODR set to 1000 Hz. - ACC_ODR_500, // Accelerometer ODR set to 500 Hz. - ACC_ODR_250, // Accelerometer ODR set to 250 Hz. - ACC_ODR_125, // Accelerometer ODR set to 125 Hz. - ACC_ODR_62_5, // Accelerometer ODR set to 62.5 Hz. - ACC_ODR_31_25, // Accelerometer ODR set to 31.25 Hz. - ACC_ODR_128 = 12, // Accelerometer ODR set to 128 Hz. - ACC_ODR_21, // Accelerometer ODR set to 21 Hz. - ACC_ODR_11, // Accelerometer ODR set to 11 Hz. - ACC_ODR_3, // Accelerometer ODR set to 3 Hz. -}; - -/** - * @brief qmi8658 gyro scale - * @maixpy maix.ext_dev.qmi8658.GyroScale - */ -enum GyroScale { - GYRO_SCALE_16DPS = 0, // Gyroscope scale set to ±16 degrees per second. - GYRO_SCALE_32DPS, // Gyroscope scale set to ±32 degrees per second. - GYRO_SCALE_64DPS, // Gyroscope scale set to ±64 degrees per second. - GYRO_SCALE_128DPS, // Gyroscope scale set to ±128 degrees per second. - GYRO_SCALE_256DPS, // Gyroscope scale set to ±256 degrees per second. - GYRO_SCALE_512DPS, // Gyroscope scale set to ±512 degrees per second. - GYRO_SCALE_1024DPS, // Gyroscope scale set to ±1024 degrees per second. - GYRO_SCALE_2048DPS, // Gyroscope scale set to ±2048 degrees per second. -}; - -/** - * @brief qmi8658 gyro output data rate - * @maixpy maix.ext_dev.qmi8658.GyroOdr - */ -enum GyroOdr { - GYRO_ODR_8000, // Gyroscope ODR set to 8000 Hz. - GYRO_ODR_4000, // Gyroscope ODR set to 4000 Hz. - GYRO_ODR_2000, // Gyroscope ODR set to 2000 Hz. - GYRO_ODR_1000, // Gyroscope ODR set to 1000 Hz. - GYRO_ODR_500, // Gyroscope ODR set to 500 Hz. - GYRO_ODR_250, // Gyroscope ODR set to 250 Hz. - GYRO_ODR_125, // Gyroscope ODR set to 125 Hz. - GYRO_ODR_62_5, // Gyroscope ODR set to 62.5 Hz. - GYRO_ODR_31_25, // Gyroscope ODR set to 31.25 Hz. -}; - /** * QMI8656 driver class * @maixpy maix.ext_dev.qmi8658.QMI8658 @@ -106,11 +35,11 @@ class QMI8658 { * @maixpy maix.ext_dev.qmi8658.QMI8658.__init__ */ QMI8658(int i2c_bus=-1, int addr=0x6B, int freq=400000, - maix::ext_dev::qmi8658::Mode mode=maix::ext_dev::qmi8658::Mode::DUAL, - maix::ext_dev::qmi8658::AccScale acc_scale=maix::ext_dev::qmi8658::AccScale::ACC_SCALE_2G, - maix::ext_dev::qmi8658::AccOdr acc_odr=maix::ext_dev::qmi8658::AccOdr::ACC_ODR_8000, - maix::ext_dev::qmi8658::GyroScale gyro_scale=maix::ext_dev::qmi8658::GyroScale::GYRO_SCALE_16DPS, - maix::ext_dev::qmi8658::GyroOdr gyro_odr=maix::ext_dev::qmi8658::GyroOdr::GYRO_ODR_8000, + maix::ext_dev::imu::Mode mode=maix::ext_dev::imu::Mode::DUAL, + maix::ext_dev::imu::AccScale acc_scale=maix::ext_dev::imu::AccScale::ACC_SCALE_2G, + maix::ext_dev::imu::AccOdr acc_odr=maix::ext_dev::imu::AccOdr::ACC_ODR_8000, + maix::ext_dev::imu::GyroScale gyro_scale=maix::ext_dev::imu::GyroScale::GYRO_SCALE_16DPS, + maix::ext_dev::imu::GyroOdr gyro_odr=maix::ext_dev::imu::GyroOdr::GYRO_ODR_8000, bool block=true); ~QMI8658(); @@ -130,7 +59,7 @@ class QMI8658 { std::vector read(); private: void* _data; - Mode _mode; + imu::Mode _mode; std::atomic_bool reset_finished{false}; std::future> open_future; bool open_fut_need_get{false}; diff --git a/components/ext_dev/src/maix_imu.cpp b/components/ext_dev/src/maix_imu.cpp new file mode 100644 index 00000000..cbbac92e --- /dev/null +++ b/components/ext_dev/src/maix_imu.cpp @@ -0,0 +1,51 @@ + +#include "maix_basic.hpp" +#include "maix_imu.hpp" +#include "maix_qmi8658.hpp" + + +namespace maix::ext_dev::imu { + +typedef struct { + union { + maix::ext_dev::qmi8658::QMI8658 *qmi8658; + } driver; +} imu_param_t; + +IMU::IMU(std::string driver, int i2c_bus, int addr, int freq, imu::Mode mode, imu::AccScale acc_scale, + imu::AccOdr acc_odr, imu::GyroScale gyro_scale, imu::GyroOdr gyro_odr, bool block) +{ + err::check_bool_raise(driver == "qmi8658", "Only support qmi8658 now"); + imu_param_t *param = (imu_param_t *)malloc(sizeof(imu_param_t)); + err::check_null_raise(param, "Failed to malloc param"); + + + param->driver.qmi8658 = new maix::ext_dev::qmi8658::QMI8658(i2c_bus, addr, freq, mode, acc_scale, acc_odr, gyro_scale, gyro_odr, block); + _param = (void *)param; + _driver = driver; +} + +IMU::~IMU() +{ + if (_param) { + imu_param_t *param = (imu_param_t *)_param; + if (_driver == "qmi8658") { + delete param->driver.qmi8658; + param->driver.qmi8658 = NULL; + } + free(_param); + _param = NULL; + } +} + +std::vector IMU::read() +{ + std::vector out; + imu_param_t *param = (imu_param_t *)_param; + if (_driver == "qmi8658") { + out = param->driver.qmi8658->read(); + } + return out; +} + +} \ No newline at end of file diff --git a/components/ext_dev/src/qmi8658/maix_qmi8658.cpp b/components/ext_dev/src/qmi8658/maix_qmi8658.cpp index 8256a8e4..6c96e421 100644 --- a/components/ext_dev/src/qmi8658/maix_qmi8658.cpp +++ b/components/ext_dev/src/qmi8658/maix_qmi8658.cpp @@ -81,20 +81,20 @@ void Qmi8658c::maix_qmi_deinit_i2c_bus(int bus) namespace maix::ext_dev::qmi8658 { -static std::vector make_read_result(const Mode& m, const priv::qmi_data_t& data) +static std::vector make_read_result(const imu::Mode& m, const priv::qmi_data_t& data) { - if (m == Mode::DUAL) + if (m == imu::Mode::DUAL) return {data.acc_xyz.x, data.acc_xyz.y, data.acc_xyz.z, data.gyro_xyz.x, data.gyro_xyz.y, data.gyro_xyz.z, data.temperature}; - if (m == Mode::ACC_ONLY) + if (m == imu::Mode::ACC_ONLY) return {data.acc_xyz.x, data.acc_xyz.y, data.acc_xyz.z, data.temperature}; - if (m == Mode::GYRO_ONLY) + if (m == imu::Mode::GYRO_ONLY) return {data.gyro_xyz.x, data.gyro_xyz.y, data.gyro_xyz.z, data.temperature}; log::error("[%s] Unknown Mode, return empty", priv::TAG); return {}; } -QMI8658::QMI8658(int i2c_bus, int addr, int freq, qmi8658::Mode mode, qmi8658::AccScale acc_scale, - qmi8658::AccOdr acc_odr, qmi8658::GyroScale gyro_scale, qmi8658::GyroOdr gyro_odr, bool block) +QMI8658::QMI8658(int i2c_bus, int addr, int freq, imu::Mode mode, imu::AccScale acc_scale, + imu::AccOdr acc_odr, imu::GyroScale gyro_scale, imu::GyroOdr gyro_odr, bool block) { auto qmi8658c = new priv::Qmi8658c(i2c_bus, (uint8_t)addr, freq); this->_data = (void*)qmi8658c; diff --git a/components/vision/include/maix_video.hpp b/components/vision/include/maix_video.hpp index 43666c92..2b8fe7d4 100644 --- a/components/vision/include/maix_video.hpp +++ b/components/vision/include/maix_video.hpp @@ -1295,9 +1295,9 @@ namespace maix::video * if you bind a audio, audio will be recorded, * if you bind a IMU, IMU data will be logged. * @return error code - * @maixpy maix.video.VideoRecorder.record + * @maixpy maix.video.VideoRecorder.record_start */ - err::Err record(); + err::Err record_start(); /** * @brief Take a snapshot @@ -1309,9 +1309,9 @@ namespace maix::video /** * @brief Stop recording and save the video * @return error code - * @maixpy maix.video.VideoRecorder.finish + * @maixpy maix.video.VideoRecorder.record_finish */ - err::Err finish(); + err::Err record_finish(); /** * @brief Draw a rect on the video diff --git a/components/vision/port/linux/maix_video_linux.cpp b/components/vision/port/linux/maix_video_linux.cpp index 2c3badbc..03b721df 100644 --- a/components/vision/port/linux/maix_video_linux.cpp +++ b/components/vision/port/linux/maix_video_linux.cpp @@ -265,7 +265,7 @@ namespace maix::video return 0; } - err::Err VideoRecorder::record() + err::Err VideoRecorder::record_start() { return err::ERR_NOT_IMPL; } @@ -275,7 +275,7 @@ namespace maix::video return NULL; } - err::Err VideoRecorder::finish() + err::Err VideoRecorder::record_finish() { return err::ERR_NOT_IMPL; } diff --git a/components/vision/port/maixcam/maix_video_mmf.cpp b/components/vision/port/maixcam/maix_video_mmf.cpp index 60e7b964..27cf5ef0 100644 --- a/components/vision/port/maixcam/maix_video_mmf.cpp +++ b/components/vision/port/maixcam/maix_video_mmf.cpp @@ -3573,7 +3573,7 @@ namespace maix::video err::Err VideoRecorder::reset() { - finish(); + record_finish(); lock(); video_recoder_param_t *param = (video_recoder_param_t *)_param; @@ -3793,7 +3793,7 @@ namespace maix::video return param->seek_ms; } - err::Err VideoRecorder::record() + err::Err VideoRecorder::record_start() { auto resolution = this->get_resolution(); @@ -3988,7 +3988,7 @@ namespace maix::video return new_image; } - err::Err VideoRecorder::finish() + err::Err VideoRecorder::record_finish() { lock(); video_recoder_param_t *param = (video_recoder_param_t *)_param; diff --git a/examples/maix_imu/.gitignore b/examples/maix_imu/.gitignore new file mode 100644 index 00000000..6c93fbbf --- /dev/null +++ b/examples/maix_imu/.gitignore @@ -0,0 +1,7 @@ +build +dist +.config.mk +.flash.conf.json +data +/CMakeLists.txt +__pycache__ diff --git a/examples/maix_imu/README.md b/examples/maix_imu/README.md new file mode 100644 index 00000000..ceacb760 --- /dev/null +++ b/examples/maix_imu/README.md @@ -0,0 +1,9 @@ +maix_qmi8658 Project based on MaixCDK +==== + + + + + +This is a project based on MaixCDK, build method please visit [MaixCDK](https://github.com/sipeed/MaixCDK) + diff --git a/examples/maix_imu/app.yaml b/examples/maix_imu/app.yaml new file mode 100644 index 00000000..12a19fc0 --- /dev/null +++ b/examples/maix_imu/app.yaml @@ -0,0 +1,10 @@ +id: maix_imu +name: maix_imu +name[zh]: +version: 1.0.0 +#icon: assets/hello.png +author: +desc: +desc[zh]: +files: + # assets: assets diff --git a/examples/maix_imu/main/CMakeLists.txt b/examples/maix_imu/main/CMakeLists.txt new file mode 100644 index 00000000..4be5a698 --- /dev/null +++ b/examples/maix_imu/main/CMakeLists.txt @@ -0,0 +1,73 @@ +############### Add include ################### +list(APPEND ADD_INCLUDE "include" + ) +list(APPEND ADD_PRIVATE_INCLUDE "") +############################################### + +############ Add source files ################# +# list(APPEND ADD_SRCS "src/main.c" +# "src/test.c" +# ) +append_srcs_dir(ADD_SRCS "src") # append source file in src dir to var ADD_SRCS +# list(REMOVE_ITEM COMPONENT_SRCS "src/test2.c") +# FILE(GLOB_RECURSE EXTRA_SRC "src/*.c") +# FILE(GLOB EXTRA_SRC "src/*.c") +# list(APPEND ADD_SRCS ${EXTRA_SRC}) +# aux_source_directory(src ADD_SRCS) # collect all source file in src dir, will set var ADD_SRCS +# append_srcs_dir(ADD_SRCS "src") # append source file in src dir to var ADD_SRCS +# list(REMOVE_ITEM COMPONENT_SRCS "src/test.c") +# set(ADD_ASM_SRCS "src/asm.S") +# list(APPEND ADD_SRCS ${ADD_ASM_SRCS}) +# SET_PROPERTY(SOURCE ${ADD_ASM_SRCS} PROPERTY LANGUAGE C) # set .S ASM file as C language +# SET_SOURCE_FILES_PROPERTIES(${ADD_ASM_SRCS} PROPERTIES COMPILE_FLAGS "-x assembler-with-cpp -D BBBBB") +############################################### + +###### Add required/dependent components ###### +list(APPEND ADD_REQUIREMENTS basic ext_dev) +############################################### + +###### Add link search path for requirements/libs ###### +# list(APPEND ADD_LINK_SEARCH_PATH "${CONFIG_TOOLCHAIN_PATH}/lib") +# list(APPEND ADD_REQUIREMENTS pthread m) # add system libs, pthread and math lib for example here +# set (OpenCV_DIR opencv/lib/cmake/opencv4) +# find_package(OpenCV REQUIRED) +############################################### + +############ Add static libs ################## +# list(APPEND ADD_STATIC_LIB "lib/libtest.a") +############################################### + +#### Add compile option for this component #### +#### Just for this component, won't affect other +#### modules, including component that depend +#### on this component +# list(APPEND ADD_DEFINITIONS_PRIVATE -DAAAAA=1) + +#### Add compile option for this component +#### and components depend on this component +# list(APPEND ADD_DEFINITIONS -DAAAAA222=1 +# -DAAAAA333=1) +############################################### + +############ Add static libs ################## +#### Update parent's variables like CMAKE_C_LINK_FLAGS +# set(CMAKE_C_LINK_FLAGS "${CMAKE_C_LINK_FLAGS} -Wl,--start-group libmaix/libtest.a -ltest2 -Wl,--end-group" PARENT_SCOPE) +############################################### + +######### Add files need to download ######### +# list(APPEND ADD_FILE_DOWNLOADS "{ +# 'url': 'https://*****/abcde.tar.xz', +# 'urls': [], # backup urls, if url failed, will try urls +# 'sites': [], # download site, user can manually download file and put it into dl_path +# 'sha256sum': '', +# 'filename': 'abcde.tar.xz', +# 'path': 'toolchains/xxxxx', +# }" +# ) +# +# then extracted file in ${DL_EXTRACTED_PATH}/toolchains/xxxxx, +# you can directly use then, for example use it in add_custom_command +############################################## + +# register component, DYNAMIC or SHARED flags will make component compiled to dynamic(shared) lib +register_component() diff --git a/components/ext_dev/include/maix_imu.h b/examples/maix_imu/main/Kconfig similarity index 100% rename from components/ext_dev/include/maix_imu.h rename to examples/maix_imu/main/Kconfig diff --git a/examples/maix_imu/main/include/main.h b/examples/maix_imu/main/include/main.h new file mode 100644 index 00000000..45dcbb04 --- /dev/null +++ b/examples/maix_imu/main/include/main.h @@ -0,0 +1,3 @@ +#pragma once + + diff --git a/examples/maix_imu/main/src/main.cpp b/examples/maix_imu/main/src/main.cpp new file mode 100644 index 00000000..ecd0466c --- /dev/null +++ b/examples/maix_imu/main/src/main.cpp @@ -0,0 +1,43 @@ + +#include "maix_basic.hpp" +#include "main.h" +#include "maix_imu.hpp" + +using namespace maix; + +int _main(int argc, char* argv[]) +{ + ext_dev::imu::IMU imu("qmi8658"); + + maix::time::sleep(3); + + while (!app::need_exit()) { + auto res = imu.read(); + printf("\n"); + log::info("------------------------"); + printf("acc x: %f\t", res[0]); + printf("acc y: %f\t", res[1]); + printf("acc z: %f\n", res[2]); + printf("gyro x: %f\t", res[3]); + printf("gyro y: %f\t", res[4]); + printf("gyro z: %f\n", res[5]); + printf("temp: %f\n", res[6]); + log::info("------------------------\n"); + time::sleep_ms(500); + } + + return 0; +} + +int main(int argc, char* argv[]) +{ + // Catch signal and process + sys::register_default_signal_handle(); + + // Use CATCH_EXCEPTION_RUN_RETURN to catch exception, + // if we don't catch exception, when program throw exception, the objects will not be destructed. + // So we catch exception here to let resources be released(call objects' destructor) before exit. + CATCH_EXCEPTION_RUN_RETURN(_main, -1, argc, argv); +} + +