commit 78578a1bed55f843b9ccbcc72f8a662eaf32d755 Author: lgv Date: Wed Aug 5 16:42:59 2026 +0800 first commit diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..ab1f416 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,10 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Ignored default folder with query files +/queries/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml +# Editor-based HTTP Client requests +/httpRequests/ diff --git a/.idea/cmvr-head-client.iml b/.idea/cmvr-head-client.iml new file mode 100644 index 0000000..24a1527 --- /dev/null +++ b/.idea/cmvr-head-client.iml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/inspectionProfiles/profiles_settings.xml b/.idea/inspectionProfiles/profiles_settings.xml new file mode 100644 index 0000000..105ce2d --- /dev/null +++ b/.idea/inspectionProfiles/profiles_settings.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..f7e64e8 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,7 @@ + + + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..31cab54 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/__init__.py b/__init__.py new file mode 100644 index 0000000..d623662 --- /dev/null +++ b/__init__.py @@ -0,0 +1,6 @@ +# +# Generated by erpcgen 1.14.0 on Tue Apr 28 12:25:45 2026. +# +# AUTOGENERATED - DO NOT EDIT +# + diff --git a/__pycache__/main.cpython-310.pyc b/__pycache__/main.cpython-310.pyc new file mode 100644 index 0000000..cc51453 Binary files /dev/null and b/__pycache__/main.cpython-310.pyc differ diff --git a/__pycache__/s_curve.cpython-310.pyc b/__pycache__/s_curve.cpython-310.pyc new file mode 100644 index 0000000..83bd94b Binary files /dev/null and b/__pycache__/s_curve.cpython-310.pyc differ diff --git a/__pycache__/s_curve.cpython-311.pyc b/__pycache__/s_curve.cpython-311.pyc new file mode 100644 index 0000000..afd6f25 Binary files /dev/null and b/__pycache__/s_curve.cpython-311.pyc differ diff --git a/config/__pycache__/yaml_to_json.cpython-310.pyc b/config/__pycache__/yaml_to_json.cpython-310.pyc new file mode 100644 index 0000000..1f97ff4 Binary files /dev/null and b/config/__pycache__/yaml_to_json.cpython-310.pyc differ diff --git a/config/servo_config.json b/config/servo_config.json new file mode 100644 index 0000000..b8c47b6 --- /dev/null +++ b/config/servo_config.json @@ -0,0 +1,90 @@ +{ + "version": 1, + "servo_count": 4, + "servos": [ + { + "id": "eye_l_up", + "limit_min_angle_rad": -0.8, + "limit_max_angle_rad": 0, + "home_angle_rad": 0, + "driver": { + "period_ns": 20000000, + "min_pulse_ns": 500000, + "max_pulse_ns": 2500000, + "min_angle_rad": -1.5707963, + "max_angle_rad": 1.5707963, + "pwm_dev_name": "pwm1", + "pwm_channel": 1 + }, + "control": { + "max_velocity_rad": 20, + "max_acceleration_rad": 1000.0, + "max_jerk_rad": 500.0, + "position_gain": 4.5 + } + }, + { + "id": "eye_l_lower", + "limit_min_angle_rad": -1, + "limit_max_angle_rad": -0.2, + "home_angle_rad": -1, + "driver": { + "period_ns": 20000000, + "min_pulse_ns": 500000, + "max_pulse_ns": 2500000, + "min_angle_rad": -1.5707963, + "max_angle_rad": 1.5707963, + "pwm_dev_name": "pwm1", + "pwm_channel": 2 + }, + "control": { + "max_velocity_rad": 20, + "max_acceleration_rad": 1000.0, + "max_jerk_rad": 500.0, + "position_gain": 4.5 + } + }, + { + "id": "eye_l_v", + "limit_min_angle_rad": -0.85, + "limit_max_angle_rad": 0.85, + "home_angle_rad": 0, + "driver": { + "period_ns": 20000000, + "min_pulse_ns": 500000, + "max_pulse_ns": 2500000, + "min_angle_rad": -1.5707963, + "max_angle_rad": 1.5707963, + "pwm_dev_name": "pwm1", + "pwm_channel": 3 + }, + "control": { + "max_velocity_rad": 20, + "max_acceleration_rad": 1000.0, + "max_jerk_rad": 500.0, + "position_gain": 4.5 + } + }, + { + "id": "eye_l_h", + "limit_min_angle_rad": -0.65, + "limit_max_angle_rad": 0.7, + "home_angle_rad": 0, + "driver": { + "period_ns": 20000000, + "min_pulse_ns": 500000, + "max_pulse_ns": 2500000, + "min_angle_rad": -1.5707963, + "max_angle_rad": 1.5707963, + "pwm_dev_name": "pwm1", + "pwm_channel": 4 + }, + "control": { + "max_velocity_rad": 20, + "max_acceleration_rad": 1000.0, + "max_jerk_rad": 500.0, + "position_gain": 4.5 + } + } + ] +} diff --git a/config/servo_config.yaml b/config/servo_config.yaml new file mode 100644 index 0000000..3034ccb --- /dev/null +++ b/config/servo_config.yaml @@ -0,0 +1,60 @@ +version: 1 +servo_count: 4 + +default_driver: &default_driver + period_ns: 20000000 + min_pulse_ns: 500000 + max_pulse_ns: 2500000 + min_angle_rad: -1.5707963 + max_angle_rad: 1.5707963 + +default_control: &default_control + max_velocity_rad: 20 + max_acceleration_rad: 1000.0 + max_jerk_rad: 500.0 + position_gain: 4.5 + +servos: + - id: eye_l_up + limit_min_angle_rad: -0.8 + limit_max_angle_rad: 0 + home_angle_rad: 0 + driver: + <<: *default_driver + pwm_dev_name: pwm1 + pwm_channel: 1 + control: + <<: *default_control + + - id: eye_l_lower + limit_min_angle_rad: -1 + limit_max_angle_rad: -0.2 + home_angle_rad: -1 + driver: + <<: *default_driver + pwm_dev_name: pwm1 + pwm_channel: 2 + control: + <<: *default_control + + - id: eye_l_v + limit_min_angle_rad: -0.85 + limit_max_angle_rad: 0.85 + home_angle_rad: 0 + driver: + <<: *default_driver + pwm_dev_name: pwm1 + pwm_channel: 3 + control: + <<: *default_control + + - id: eye_l_h + limit_min_angle_rad: -0.65 + limit_max_angle_rad: 0.7 + home_angle_rad: 0 + driver: + <<: *default_driver + pwm_dev_name: pwm1 + pwm_channel: 4 + control: + <<: *default_control \ No newline at end of file diff --git a/config/yaml_to_json.py b/config/yaml_to_json.py new file mode 100644 index 0000000..642e87f --- /dev/null +++ b/config/yaml_to_json.py @@ -0,0 +1,57 @@ +import argparse +import json +from pathlib import Path + + +SCRIPT_DIR = Path(__file__).resolve().parent +DEFAULT_INPUT_FILE = SCRIPT_DIR / "servo_config.yaml" +DEFAULT_OUTPUT_FILE = SCRIPT_DIR / "servo_config.json" + + +def parse_args(): + parser = argparse.ArgumentParser(description="Convert a servo YAML config to JSON.") + parser.add_argument("input", nargs="?", type=Path, default=DEFAULT_INPUT_FILE) + parser.add_argument("output", nargs="?", type=Path, default=DEFAULT_OUTPUT_FILE) + return parser.parse_args() + + +def convert_yaml_to_json(input_file, output_file): + try: + import yaml + except ModuleNotFoundError as exc: + raise RuntimeError( + "PyYAML is required. Install it with: python -m pip install PyYAML" + ) from exc + + input_file = Path(input_file).resolve() + output_file = Path(output_file).resolve() + + with input_file.open("r", encoding="utf-8") as stream: + data = yaml.safe_load(stream) + + if not isinstance(data, dict): + raise ValueError("Servo config root must be a YAML mapping.") + + # These helper nodes only exist to support YAML anchors and merge keys. + data.pop("default_driver", None) + data.pop("default_control", None) + + output_file.parent.mkdir(parents=True, exist_ok=True) + with output_file.open("w", encoding="utf-8") as stream: + json.dump(data, stream, indent=2, ensure_ascii=False) + stream.write("\n") + + return output_file + + +def main(): + args = parse_args() + try: + output_file = convert_yaml_to_json(args.input, args.output) + except Exception as exc: + raise SystemExit(f"YAML conversion failed: {exc}") from exc + print(f"Generated {output_file}") + + +if __name__ == "__main__": + main() diff --git a/cpp/common/curve/CMakeLists.txt b/cpp/common/curve/CMakeLists.txt new file mode 100644 index 0000000..83109b7 --- /dev/null +++ b/cpp/common/curve/CMakeLists.txt @@ -0,0 +1,32 @@ +cmake_minimum_required(VERSION 3.20) + +project(cmvr_scurve LANGUAGES CXX) + +find_package(Python REQUIRED COMPONENTS Interpreter Development.Module) + +execute_process( + COMMAND "${Python_EXECUTABLE}" -m pybind11 --cmakedir + OUTPUT_VARIABLE pybind11_DIR + OUTPUT_STRIP_TRAILING_WHITESPACE +) + +find_package(pybind11 CONFIG REQUIRED) + +pybind11_add_module(_s_curve_native + src/s_curve.cpp + src/s_curve_pybind.cpp + ../../planner/s_curve_planner/src/s_curve_velocity_planner.cpp + ../../planner/s_curve_planner/src/s_curve_position_planner.cpp +) + +target_compile_features(_s_curve_native PUBLIC cxx_std_17) + +target_include_directories(_s_curve_native + PUBLIC + ${CMAKE_CURRENT_SOURCE_DIR}/../.. + ${CMAKE_CURRENT_SOURCE_DIR}/include +) + +set_target_properties(_s_curve_native PROPERTIES + OUTPUT_NAME "_s_curve_native" +) diff --git a/cpp/common/curve/README.md b/cpp/common/curve/README.md new file mode 100644 index 0000000..16baac0 --- /dev/null +++ b/cpp/common/curve/README.md @@ -0,0 +1,26 @@ +# SCurve Python Bridge + +This folder now exposes the C++ `SCurve` class as a native Python extension built with `pybind11`. + +## Build + +From the repository root: + +```powershell +powershell -ExecutionPolicy Bypass -File .\cpp\common\curve\build_python.ps1 -PythonExecutable "C:\Users\Administrator\miniconda3\envs\cmvr-head-client\python.exe" +``` + +Expected output: + +- `cpp/common/curve/build/_s_curve_native*.pyd` + +## Python usage + +```python +from s_curve import SCurve + +curve = SCurve(max_velocity=3.0, max_acceleration=10.0, max_jerk=50.0) +curve.setConstraints(4.0, 12.0, 80.0) +profile = curve.calculateProfile(0.0, 30.0, 0.0, 0.0) +samples = curve.sampleTrajectory(profile, 0.01) +``` diff --git a/cpp/common/curve/build/.ninja_deps b/cpp/common/curve/build/.ninja_deps new file mode 100644 index 0000000..74eeefc Binary files /dev/null and b/cpp/common/curve/build/.ninja_deps differ diff --git a/cpp/common/curve/build/.ninja_log b/cpp/common/curve/build/.ninja_log new file mode 100644 index 0000000..1a2b3a8 --- /dev/null +++ b/cpp/common/curve/build/.ninja_log @@ -0,0 +1,12 @@ +# ninja log v5 +1 1048 7986139309146135 _s_curve_native.cp310-win_amd64.pyd 673782cfb92e82ed +294 378 7985314121237372 cmvr_scurve.dll f5a2deae4722be51 +3 192 7985314119482111 CMakeFiles/cmvr_scurve.dir/src/s_curve_c_api.cpp.obj c45d67ef9cd340bf +1 192 7985325638396114 CMakeFiles/_s_curve_native.dir/src/s_curve.cpp.obj c1eacea52f4088b1 +1 294 7985314120489746 CMakeFiles/cmvr_scurve.dir/src/s_curve.cpp.obj feab6347a1d9fd9 +2 140 7986137855321581 CMakeFiles/_s_curve_native.dir/D_/cmvr/0-worksapce/cmvr-head-client/cpp/planner/s_curve_planner/src/s_curve_position_planner.cpp.obj e63e15a214de1054 +294 378 7985314121237372 cmvr_scurve.lib f5a2deae4722be51 +3 1750 7986133195476363 CMakeFiles/_s_curve_native.dir/src/s_curve_pybind.cpp.obj e94b80eb42378794 +1 164 7986135846813044 CMakeFiles/_s_curve_native.dir/D_/cmvr/0-worksapce/cmvr-head-client/cpp/planner/s_curve_planner/src/s_curve_velocity_planner.cpp.obj f46dab0fc0756a6a +1 137 7986140057393930 CMakeFiles/_s_curve_native.dir/D_/cmvr/0-worksapce/cmvr-head-client/cpp/planner/s_curve_planner/src/s_curve_position_planner.cpp.obj e63e15a214de1054 +137 1174 7986140067522517 _s_curve_native.cp310-win_amd64.pyd 673782cfb92e82ed diff --git a/cpp/common/curve/build/CMakeCache.txt b/cpp/common/curve/build/CMakeCache.txt new file mode 100644 index 0000000..c0d191e --- /dev/null +++ b/cpp/common/curve/build/CMakeCache.txt @@ -0,0 +1,352 @@ +# This is the CMakeCache file. +# For build in directory: d:/cmvr/0-worksapce/cmvr-head-client/cpp/common/curve/build +# It was generated by CMake: C:/Program Files/STM32/STM32CubeCLT_1.20.0/CMake/bin/cmake.exe +# You can edit this file to change values found and used by cmake. +# If you do not want to change any of the values, simply exit the editor. +# If you do want to change a value, simply edit, save, and exit the editor. +# The syntax for the file is as follows: +# KEY:TYPE=VALUE +# KEY is the name of a variable in the cache. +# TYPE is a hint to GUIs for the type of VALUE, DO NOT EDIT TYPE!. +# VALUE is the current value for the KEY. + +######################## +# EXTERNAL cache entries +######################## + +//Path to a program. +CMAKE_AR:FILEPATH=C:/Program Files/Microsoft Visual Studio/18/Community/VC/Tools/MSVC/14.50.35717/bin/Hostx64/x64/lib.exe + +//Choose the type of build, options are: None Debug Release RelWithDebInfo +// MinSizeRel ... +CMAKE_BUILD_TYPE:STRING=Release + +//CXX compiler +CMAKE_CXX_COMPILER:FILEPATH=C:/Program Files/Microsoft Visual Studio/18/Community/VC/Tools/MSVC/14.50.35717/bin/Hostx64/x64/cl.exe + +//Flags used by the CXX compiler during all build types. +CMAKE_CXX_FLAGS:STRING=/DWIN32 /D_WINDOWS /EHsc + +//Flags used by the CXX compiler during DEBUG builds. +CMAKE_CXX_FLAGS_DEBUG:STRING=/Zi /Ob0 /Od /RTC1 + +//Flags used by the CXX compiler during MINSIZEREL builds. +CMAKE_CXX_FLAGS_MINSIZEREL:STRING=/O1 /Ob1 /DNDEBUG + +//Flags used by the CXX compiler during RELEASE builds. +CMAKE_CXX_FLAGS_RELEASE:STRING=/O2 /Ob2 /DNDEBUG + +//Flags used by the CXX compiler during RELWITHDEBINFO builds. +CMAKE_CXX_FLAGS_RELWITHDEBINFO:STRING=/Zi /O2 /Ob1 /DNDEBUG + +//Libraries linked by default with all C++ applications. +CMAKE_CXX_STANDARD_LIBRARIES:STRING=kernel32.lib user32.lib gdi32.lib winspool.lib shell32.lib ole32.lib oleaut32.lib uuid.lib comdlg32.lib advapi32.lib + +//Flags used by the linker during all build types. +CMAKE_EXE_LINKER_FLAGS:STRING=/machine:x64 + +//Flags used by the linker during DEBUG builds. +CMAKE_EXE_LINKER_FLAGS_DEBUG:STRING=/debug /INCREMENTAL + +//Flags used by the linker during MINSIZEREL builds. +CMAKE_EXE_LINKER_FLAGS_MINSIZEREL:STRING=/INCREMENTAL:NO + +//Flags used by the linker during RELEASE builds. +CMAKE_EXE_LINKER_FLAGS_RELEASE:STRING=/INCREMENTAL:NO + +//Flags used by the linker during RELWITHDEBINFO builds. +CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO:STRING=/debug /INCREMENTAL + +//Enable/Disable output of compile commands during generation. +CMAKE_EXPORT_COMPILE_COMMANDS:BOOL= + +//Value Computed by CMake. +CMAKE_FIND_PACKAGE_REDIRECTS_DIR:STATIC=D:/cmvr/0-worksapce/cmvr-head-client/cpp/common/curve/build/CMakeFiles/pkgRedirects + +//Install path prefix, prepended onto install directories. +CMAKE_INSTALL_PREFIX:PATH=C:/Program Files (x86)/cmvr_scurve + +//Path to a program. +CMAKE_LINKER:FILEPATH=C:/Program Files/Microsoft Visual Studio/18/Community/VC/Tools/MSVC/14.50.35717/bin/Hostx64/x64/link.exe + +//make program +CMAKE_MAKE_PROGRAM:FILEPATH=C:/PROGRA~1/STM32/STM32C~1.0/Ninja/bin/ninja.exe + +//Flags used by the linker during the creation of modules during +// all build types. +CMAKE_MODULE_LINKER_FLAGS:STRING=/machine:x64 + +//Flags used by the linker during the creation of modules during +// DEBUG builds. +CMAKE_MODULE_LINKER_FLAGS_DEBUG:STRING=/debug /INCREMENTAL + +//Flags used by the linker during the creation of modules during +// MINSIZEREL builds. +CMAKE_MODULE_LINKER_FLAGS_MINSIZEREL:STRING=/INCREMENTAL:NO + +//Flags used by the linker during the creation of modules during +// RELEASE builds. +CMAKE_MODULE_LINKER_FLAGS_RELEASE:STRING=/INCREMENTAL:NO + +//Flags used by the linker during the creation of modules during +// RELWITHDEBINFO builds. +CMAKE_MODULE_LINKER_FLAGS_RELWITHDEBINFO:STRING=/debug /INCREMENTAL + +//Path to a program. +CMAKE_MT:FILEPATH=C:/Program Files (x86)/Windows Kits/10/bin/10.0.26100.0/x64/mt.exe + +//Value Computed by CMake +CMAKE_PROJECT_DESCRIPTION:STATIC= + +//Value Computed by CMake +CMAKE_PROJECT_HOMEPAGE_URL:STATIC= + +//Value Computed by CMake +CMAKE_PROJECT_NAME:STATIC=cmvr_scurve + +//RC compiler +CMAKE_RC_COMPILER:FILEPATH=C:/Program Files (x86)/Windows Kits/10/bin/10.0.26100.0/x64/rc.exe + +//Flags for Windows Resource Compiler during all build types. +CMAKE_RC_FLAGS:STRING=-DWIN32 + +//Flags for Windows Resource Compiler during DEBUG builds. +CMAKE_RC_FLAGS_DEBUG:STRING=-D_DEBUG + +//Flags for Windows Resource Compiler during MINSIZEREL builds. +CMAKE_RC_FLAGS_MINSIZEREL:STRING= + +//Flags for Windows Resource Compiler during RELEASE builds. +CMAKE_RC_FLAGS_RELEASE:STRING= + +//Flags for Windows Resource Compiler during RELWITHDEBINFO builds. +CMAKE_RC_FLAGS_RELWITHDEBINFO:STRING= + +//Flags used by the linker during the creation of shared libraries +// during all build types. +CMAKE_SHARED_LINKER_FLAGS:STRING=/machine:x64 + +//Flags used by the linker during the creation of shared libraries +// during DEBUG builds. +CMAKE_SHARED_LINKER_FLAGS_DEBUG:STRING=/debug /INCREMENTAL + +//Flags used by the linker during the creation of shared libraries +// during MINSIZEREL builds. +CMAKE_SHARED_LINKER_FLAGS_MINSIZEREL:STRING=/INCREMENTAL:NO + +//Flags used by the linker during the creation of shared libraries +// during RELEASE builds. +CMAKE_SHARED_LINKER_FLAGS_RELEASE:STRING=/INCREMENTAL:NO + +//Flags used by the linker during the creation of shared libraries +// during RELWITHDEBINFO builds. +CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO:STRING=/debug /INCREMENTAL + +//If set, runtime paths are not added when installing shared libraries, +// but are added when building. +CMAKE_SKIP_INSTALL_RPATH:BOOL=NO + +//If set, runtime paths are not added when using shared libraries. +CMAKE_SKIP_RPATH:BOOL=NO + +//Flags used by the linker during the creation of static libraries +// during all build types. +CMAKE_STATIC_LINKER_FLAGS:STRING=/machine:x64 + +//Flags used by the linker during the creation of static libraries +// during DEBUG builds. +CMAKE_STATIC_LINKER_FLAGS_DEBUG:STRING= + +//Flags used by the linker during the creation of static libraries +// during MINSIZEREL builds. +CMAKE_STATIC_LINKER_FLAGS_MINSIZEREL:STRING= + +//Flags used by the linker during the creation of static libraries +// during RELEASE builds. +CMAKE_STATIC_LINKER_FLAGS_RELEASE:STRING= + +//Flags used by the linker during the creation of static libraries +// during RELWITHDEBINFO builds. +CMAKE_STATIC_LINKER_FLAGS_RELWITHDEBINFO:STRING= + +//If this value is on, makefiles will be generated without the +// .SILENT directive, and all commands will be echoed to the console +// during the make. This is useful for debugging only. With Visual +// Studio IDE projects all commands are done without /nologo. +CMAKE_VERBOSE_MAKEFILE:BOOL=FALSE + +//No help, variable specified on the command line. +Python_EXECUTABLE:UNINITIALIZED=C:\Users\Administrator\miniconda3\envs\cmvr-head-client\python.exe + +//Value Computed by CMake +cmvr_scurve_BINARY_DIR:STATIC=D:/cmvr/0-worksapce/cmvr-head-client/cpp/common/curve/build + +//Value Computed by CMake +cmvr_scurve_IS_TOP_LEVEL:STATIC=ON + +//Value Computed by CMake +cmvr_scurve_SOURCE_DIR:STATIC=D:/cmvr/0-worksapce/cmvr-head-client/cpp/common/curve + + +######################## +# INTERNAL cache entries +######################## + +//ADVANCED property for variable: CMAKE_AR +CMAKE_AR-ADVANCED:INTERNAL=1 +//This is the directory where this CMakeCache.txt was created +CMAKE_CACHEFILE_DIR:INTERNAL=d:/cmvr/0-worksapce/cmvr-head-client/cpp/common/curve/build +//Major version of cmake used to create the current loaded cache +CMAKE_CACHE_MAJOR_VERSION:INTERNAL=3 +//Minor version of cmake used to create the current loaded cache +CMAKE_CACHE_MINOR_VERSION:INTERNAL=28 +//Patch version of cmake used to create the current loaded cache +CMAKE_CACHE_PATCH_VERSION:INTERNAL=1 +//Path to CMake executable. +CMAKE_COMMAND:INTERNAL=C:/Program Files/STM32/STM32CubeCLT_1.20.0/CMake/bin/cmake.exe +//Path to cpack program executable. +CMAKE_CPACK_COMMAND:INTERNAL=C:/Program Files/STM32/STM32CubeCLT_1.20.0/CMake/bin/cpack.exe +//Path to ctest program executable. +CMAKE_CTEST_COMMAND:INTERNAL=C:/Program Files/STM32/STM32CubeCLT_1.20.0/CMake/bin/ctest.exe +//ADVANCED property for variable: CMAKE_CXX_COMPILER +CMAKE_CXX_COMPILER-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_CXX_FLAGS +CMAKE_CXX_FLAGS-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_CXX_FLAGS_DEBUG +CMAKE_CXX_FLAGS_DEBUG-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_CXX_FLAGS_MINSIZEREL +CMAKE_CXX_FLAGS_MINSIZEREL-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_CXX_FLAGS_RELEASE +CMAKE_CXX_FLAGS_RELEASE-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_CXX_FLAGS_RELWITHDEBINFO +CMAKE_CXX_FLAGS_RELWITHDEBINFO-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_CXX_STANDARD_LIBRARIES +CMAKE_CXX_STANDARD_LIBRARIES-ADVANCED:INTERNAL=1 +//Path to cache edit program executable. +CMAKE_EDIT_COMMAND:INTERNAL=C:/Program Files/STM32/STM32CubeCLT_1.20.0/CMake/bin/cmake-gui.exe +//Executable file format +CMAKE_EXECUTABLE_FORMAT:INTERNAL=Unknown +//ADVANCED property for variable: CMAKE_EXE_LINKER_FLAGS +CMAKE_EXE_LINKER_FLAGS-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_EXE_LINKER_FLAGS_DEBUG +CMAKE_EXE_LINKER_FLAGS_DEBUG-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_EXE_LINKER_FLAGS_MINSIZEREL +CMAKE_EXE_LINKER_FLAGS_MINSIZEREL-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_EXE_LINKER_FLAGS_RELEASE +CMAKE_EXE_LINKER_FLAGS_RELEASE-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO +CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_EXPORT_COMPILE_COMMANDS +CMAKE_EXPORT_COMPILE_COMMANDS-ADVANCED:INTERNAL=1 +//Name of external makefile project generator. +CMAKE_EXTRA_GENERATOR:INTERNAL= +//Name of generator. +CMAKE_GENERATOR:INTERNAL=Ninja +//Generator instance identifier. +CMAKE_GENERATOR_INSTANCE:INTERNAL= +//Name of generator platform. +CMAKE_GENERATOR_PLATFORM:INTERNAL= +//Name of generator toolset. +CMAKE_GENERATOR_TOOLSET:INTERNAL= +//Source directory with the top level CMakeLists.txt file for this +// project +CMAKE_HOME_DIRECTORY:INTERNAL=D:/cmvr/0-worksapce/cmvr-head-client/cpp/common/curve +//ADVANCED property for variable: CMAKE_LINKER +CMAKE_LINKER-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_MAKE_PROGRAM +CMAKE_MAKE_PROGRAM-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_MODULE_LINKER_FLAGS +CMAKE_MODULE_LINKER_FLAGS-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_MODULE_LINKER_FLAGS_DEBUG +CMAKE_MODULE_LINKER_FLAGS_DEBUG-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_MODULE_LINKER_FLAGS_MINSIZEREL +CMAKE_MODULE_LINKER_FLAGS_MINSIZEREL-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_MODULE_LINKER_FLAGS_RELEASE +CMAKE_MODULE_LINKER_FLAGS_RELEASE-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_MODULE_LINKER_FLAGS_RELWITHDEBINFO +CMAKE_MODULE_LINKER_FLAGS_RELWITHDEBINFO-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_MT +CMAKE_MT-ADVANCED:INTERNAL=1 +//number of local generators +CMAKE_NUMBER_OF_MAKEFILES:INTERNAL=1 +//Platform information initialized +CMAKE_PLATFORM_INFO_INITIALIZED:INTERNAL=1 +//noop for ranlib +CMAKE_RANLIB:INTERNAL=: +//ADVANCED property for variable: CMAKE_RC_COMPILER +CMAKE_RC_COMPILER-ADVANCED:INTERNAL=1 +CMAKE_RC_COMPILER_WORKS:INTERNAL=1 +//ADVANCED property for variable: CMAKE_RC_FLAGS +CMAKE_RC_FLAGS-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_RC_FLAGS_DEBUG +CMAKE_RC_FLAGS_DEBUG-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_RC_FLAGS_MINSIZEREL +CMAKE_RC_FLAGS_MINSIZEREL-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_RC_FLAGS_RELEASE +CMAKE_RC_FLAGS_RELEASE-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_RC_FLAGS_RELWITHDEBINFO +CMAKE_RC_FLAGS_RELWITHDEBINFO-ADVANCED:INTERNAL=1 +//Path to CMake installation. +CMAKE_ROOT:INTERNAL=C:/Program Files/STM32/STM32CubeCLT_1.20.0/CMake/share/cmake-3.28 +//ADVANCED property for variable: CMAKE_SHARED_LINKER_FLAGS +CMAKE_SHARED_LINKER_FLAGS-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_SHARED_LINKER_FLAGS_DEBUG +CMAKE_SHARED_LINKER_FLAGS_DEBUG-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_SHARED_LINKER_FLAGS_MINSIZEREL +CMAKE_SHARED_LINKER_FLAGS_MINSIZEREL-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_SHARED_LINKER_FLAGS_RELEASE +CMAKE_SHARED_LINKER_FLAGS_RELEASE-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO +CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_SKIP_INSTALL_RPATH +CMAKE_SKIP_INSTALL_RPATH-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_SKIP_RPATH +CMAKE_SKIP_RPATH-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_STATIC_LINKER_FLAGS +CMAKE_STATIC_LINKER_FLAGS-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_STATIC_LINKER_FLAGS_DEBUG +CMAKE_STATIC_LINKER_FLAGS_DEBUG-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_STATIC_LINKER_FLAGS_MINSIZEREL +CMAKE_STATIC_LINKER_FLAGS_MINSIZEREL-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_STATIC_LINKER_FLAGS_RELEASE +CMAKE_STATIC_LINKER_FLAGS_RELEASE-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_STATIC_LINKER_FLAGS_RELWITHDEBINFO +CMAKE_STATIC_LINKER_FLAGS_RELWITHDEBINFO-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_VERBOSE_MAKEFILE +CMAKE_VERBOSE_MAKEFILE-ADVANCED:INTERNAL=1 +//Details about finding Python +FIND_PACKAGE_MESSAGE_DETAILS_Python:INTERNAL=[C:\Users\Administrator\miniconda3\envs\cmvr-head-client\python.exe][C:/Users/Administrator/miniconda3/envs/cmvr-head-client/libs/python310.lib][C:/Users/Administrator/miniconda3/envs/cmvr-head-client/include][cfound components: Interpreter Development.Module ][v3.10.20()] +//Test HAS_MSVC_GL_LTCG +HAS_MSVC_GL_LTCG:INTERNAL=1 +//Python executable during the last CMake run +PYBIND11_PYTHON_EXECUTABLE_LAST:INTERNAL=C:\Users\Administrator\miniconda3\envs\cmvr-head-client\python.exe +//Python debug status +PYTHON_IS_DEBUG:INTERNAL=0 +PYTHON_MODULE_DEBUG_POSTFIX:INTERNAL= +PYTHON_MODULE_EXTENSION:INTERNAL=.cp310-win_amd64.pyd +_PYBIND11_CROSSCOMPILING:INTERNAL=OFF +_Python:INTERNAL=Python +//Compiler reason failure +_Python_Compiler_REASON_FAILURE:INTERNAL= +_Python_DEVELOPMENT_MODULE_SIGNATURE:INTERNAL=3a22dc2b94a46256ea8dac49ac5f6ebc +//Development reason failure +_Python_Development_REASON_FAILURE:INTERNAL= +_Python_EXECUTABLE:INTERNAL=C:\Users\Administrator\miniconda3\envs\cmvr-head-client\python.exe +//Path to a file. +_Python_INCLUDE_DIR:INTERNAL=C:/Users/Administrator/miniconda3/envs/cmvr-head-client/include +//Python Properties +_Python_INTERPRETER_PROPERTIES:INTERNAL=Python;3;10;20;64;;cp310-win_amd64;;C:\Users\Administrator\miniconda3\envs\cmvr-head-client\Lib;C:\Users\Administrator\miniconda3\envs\cmvr-head-client\Lib;C:\Users\Administrator\miniconda3\envs\cmvr-head-client\Lib\site-packages;C:\Users\Administrator\miniconda3\envs\cmvr-head-client\Lib\site-packages +_Python_INTERPRETER_SIGNATURE:INTERNAL=0a9f8137d2a58419f97d1d2f7ec6526f +//Interpreter reason failure +_Python_Interpreter_REASON_FAILURE:INTERNAL= +//Path to a library. +_Python_LIBRARY_DEBUG:INTERNAL=_Python_LIBRARY_DEBUG-NOTFOUND +//Path to a library. +_Python_LIBRARY_RELEASE:INTERNAL=C:/Users/Administrator/miniconda3/envs/cmvr-head-client/libs/python310.lib +//NumPy reason failure +_Python_NumPy_REASON_FAILURE:INTERNAL= +//Path to a library. +_Python_RUNTIME_LIBRARY_RELEASE:INTERNAL=C:/Users/Administrator/miniconda3/envs/cmvr-head-client/python310.dll +//Directories where pybind11 and possibly Python headers are located +pybind11_INCLUDE_DIRS:INTERNAL=C:/Users/Administrator/miniconda3/envs/cmvr-head-client/Lib/site-packages/pybind11/include;C:/Users/Administrator/miniconda3/envs/cmvr-head-client/include + diff --git a/cpp/common/curve/build/CMakeFiles/3.28.1/CMakeCXXCompiler.cmake b/cpp/common/curve/build/CMakeFiles/3.28.1/CMakeCXXCompiler.cmake new file mode 100644 index 0000000..9653339 --- /dev/null +++ b/cpp/common/curve/build/CMakeFiles/3.28.1/CMakeCXXCompiler.cmake @@ -0,0 +1,85 @@ +set(CMAKE_CXX_COMPILER "C:/Program Files/Microsoft Visual Studio/18/Community/VC/Tools/MSVC/14.50.35717/bin/Hostx64/x64/cl.exe") +set(CMAKE_CXX_COMPILER_ARG1 "") +set(CMAKE_CXX_COMPILER_ID "MSVC") +set(CMAKE_CXX_COMPILER_VERSION "19.50.35722.0") +set(CMAKE_CXX_COMPILER_VERSION_INTERNAL "") +set(CMAKE_CXX_COMPILER_WRAPPER "") +set(CMAKE_CXX_STANDARD_COMPUTED_DEFAULT "14") +set(CMAKE_CXX_EXTENSIONS_COMPUTED_DEFAULT "OFF") +set(CMAKE_CXX_COMPILE_FEATURES "cxx_std_98;cxx_template_template_parameters;cxx_std_11;cxx_alias_templates;cxx_alignas;cxx_alignof;cxx_attributes;cxx_auto_type;cxx_constexpr;cxx_decltype;cxx_decltype_incomplete_return_types;cxx_default_function_template_args;cxx_defaulted_functions;cxx_defaulted_move_initializers;cxx_delegating_constructors;cxx_deleted_functions;cxx_enum_forward_declarations;cxx_explicit_conversions;cxx_extended_friend_declarations;cxx_extern_templates;cxx_final;cxx_func_identifier;cxx_generalized_initializers;cxx_inheriting_constructors;cxx_inline_namespaces;cxx_lambdas;cxx_local_type_template_args;cxx_long_long_type;cxx_noexcept;cxx_nonstatic_member_init;cxx_nullptr;cxx_override;cxx_range_for;cxx_raw_string_literals;cxx_reference_qualified_functions;cxx_right_angle_brackets;cxx_rvalue_references;cxx_sizeof_member;cxx_static_assert;cxx_strong_enums;cxx_thread_local;cxx_trailing_return_types;cxx_unicode_literals;cxx_uniform_initialization;cxx_unrestricted_unions;cxx_user_literals;cxx_variadic_macros;cxx_variadic_templates;cxx_std_14;cxx_aggregate_default_initializers;cxx_attribute_deprecated;cxx_binary_literals;cxx_contextual_conversions;cxx_decltype_auto;cxx_digit_separators;cxx_generic_lambdas;cxx_lambda_init_captures;cxx_relaxed_constexpr;cxx_return_type_deduction;cxx_variable_templates;cxx_std_17;cxx_std_20;cxx_std_23") +set(CMAKE_CXX98_COMPILE_FEATURES "cxx_std_98;cxx_template_template_parameters") +set(CMAKE_CXX11_COMPILE_FEATURES "cxx_std_11;cxx_alias_templates;cxx_alignas;cxx_alignof;cxx_attributes;cxx_auto_type;cxx_constexpr;cxx_decltype;cxx_decltype_incomplete_return_types;cxx_default_function_template_args;cxx_defaulted_functions;cxx_defaulted_move_initializers;cxx_delegating_constructors;cxx_deleted_functions;cxx_enum_forward_declarations;cxx_explicit_conversions;cxx_extended_friend_declarations;cxx_extern_templates;cxx_final;cxx_func_identifier;cxx_generalized_initializers;cxx_inheriting_constructors;cxx_inline_namespaces;cxx_lambdas;cxx_local_type_template_args;cxx_long_long_type;cxx_noexcept;cxx_nonstatic_member_init;cxx_nullptr;cxx_override;cxx_range_for;cxx_raw_string_literals;cxx_reference_qualified_functions;cxx_right_angle_brackets;cxx_rvalue_references;cxx_sizeof_member;cxx_static_assert;cxx_strong_enums;cxx_thread_local;cxx_trailing_return_types;cxx_unicode_literals;cxx_uniform_initialization;cxx_unrestricted_unions;cxx_user_literals;cxx_variadic_macros;cxx_variadic_templates") +set(CMAKE_CXX14_COMPILE_FEATURES "cxx_std_14;cxx_aggregate_default_initializers;cxx_attribute_deprecated;cxx_binary_literals;cxx_contextual_conversions;cxx_decltype_auto;cxx_digit_separators;cxx_generic_lambdas;cxx_lambda_init_captures;cxx_relaxed_constexpr;cxx_return_type_deduction;cxx_variable_templates") +set(CMAKE_CXX17_COMPILE_FEATURES "cxx_std_17") +set(CMAKE_CXX20_COMPILE_FEATURES "cxx_std_20") +set(CMAKE_CXX23_COMPILE_FEATURES "cxx_std_23") + +set(CMAKE_CXX_PLATFORM_ID "Windows") +set(CMAKE_CXX_SIMULATE_ID "") +set(CMAKE_CXX_COMPILER_FRONTEND_VARIANT "MSVC") +set(CMAKE_CXX_SIMULATE_VERSION "") +set(CMAKE_CXX_COMPILER_ARCHITECTURE_ID x64) + +set(MSVC_CXX_ARCHITECTURE_ID x64) + +set(CMAKE_AR "C:/Program Files/Microsoft Visual Studio/18/Community/VC/Tools/MSVC/14.50.35717/bin/Hostx64/x64/lib.exe") +set(CMAKE_CXX_COMPILER_AR "") +set(CMAKE_RANLIB ":") +set(CMAKE_CXX_COMPILER_RANLIB "") +set(CMAKE_LINKER "C:/Program Files/Microsoft Visual Studio/18/Community/VC/Tools/MSVC/14.50.35717/bin/Hostx64/x64/link.exe") +set(CMAKE_MT "C:/Program Files (x86)/Windows Kits/10/bin/10.0.26100.0/x64/mt.exe") +set(CMAKE_TAPI "") +set(CMAKE_COMPILER_IS_GNUCXX ) +set(CMAKE_CXX_COMPILER_LOADED 1) +set(CMAKE_CXX_COMPILER_WORKS TRUE) +set(CMAKE_CXX_ABI_COMPILED TRUE) + +set(CMAKE_CXX_COMPILER_ENV_VAR "CXX") + +set(CMAKE_CXX_COMPILER_ID_RUN 1) +set(CMAKE_CXX_SOURCE_FILE_EXTENSIONS C;M;c++;cc;cpp;cxx;m;mm;mpp;CPP;ixx;cppm;ccm;cxxm;c++m) +set(CMAKE_CXX_IGNORE_EXTENSIONS inl;h;hpp;HPP;H;o;O;obj;OBJ;def;DEF;rc;RC) + +foreach (lang C OBJC OBJCXX) + if (CMAKE_${lang}_COMPILER_ID_RUN) + foreach(extension IN LISTS CMAKE_${lang}_SOURCE_FILE_EXTENSIONS) + list(REMOVE_ITEM CMAKE_CXX_SOURCE_FILE_EXTENSIONS ${extension}) + endforeach() + endif() +endforeach() + +set(CMAKE_CXX_LINKER_PREFERENCE 30) +set(CMAKE_CXX_LINKER_PREFERENCE_PROPAGATES 1) +set(CMAKE_CXX_LINKER_DEPFILE_SUPPORTED ) + +# Save compiler ABI information. +set(CMAKE_CXX_SIZEOF_DATA_PTR "8") +set(CMAKE_CXX_COMPILER_ABI "") +set(CMAKE_CXX_BYTE_ORDER "LITTLE_ENDIAN") +set(CMAKE_CXX_LIBRARY_ARCHITECTURE "") + +if(CMAKE_CXX_SIZEOF_DATA_PTR) + set(CMAKE_SIZEOF_VOID_P "${CMAKE_CXX_SIZEOF_DATA_PTR}") +endif() + +if(CMAKE_CXX_COMPILER_ABI) + set(CMAKE_INTERNAL_PLATFORM_ABI "${CMAKE_CXX_COMPILER_ABI}") +endif() + +if(CMAKE_CXX_LIBRARY_ARCHITECTURE) + set(CMAKE_LIBRARY_ARCHITECTURE "") +endif() + +set(CMAKE_CXX_CL_SHOWINCLUDES_PREFIX "注意: 包含文件: ") +if(CMAKE_CXX_CL_SHOWINCLUDES_PREFIX) + set(CMAKE_CL_SHOWINCLUDES_PREFIX "${CMAKE_CXX_CL_SHOWINCLUDES_PREFIX}") +endif() + + + + + +set(CMAKE_CXX_IMPLICIT_INCLUDE_DIRECTORIES "") +set(CMAKE_CXX_IMPLICIT_LINK_LIBRARIES "") +set(CMAKE_CXX_IMPLICIT_LINK_DIRECTORIES "") +set(CMAKE_CXX_IMPLICIT_LINK_FRAMEWORK_DIRECTORIES "") diff --git a/cpp/common/curve/build/CMakeFiles/3.28.1/CMakeDetermineCompilerABI_CXX.bin b/cpp/common/curve/build/CMakeFiles/3.28.1/CMakeDetermineCompilerABI_CXX.bin new file mode 100644 index 0000000..4cd9710 Binary files /dev/null and b/cpp/common/curve/build/CMakeFiles/3.28.1/CMakeDetermineCompilerABI_CXX.bin differ diff --git a/cpp/common/curve/build/CMakeFiles/3.28.1/CMakeRCCompiler.cmake b/cpp/common/curve/build/CMakeFiles/3.28.1/CMakeRCCompiler.cmake new file mode 100644 index 0000000..04ac4ca --- /dev/null +++ b/cpp/common/curve/build/CMakeFiles/3.28.1/CMakeRCCompiler.cmake @@ -0,0 +1,6 @@ +set(CMAKE_RC_COMPILER "C:/Program Files (x86)/Windows Kits/10/bin/10.0.26100.0/x64/rc.exe") +set(CMAKE_RC_COMPILER_ARG1 "") +set(CMAKE_RC_COMPILER_LOADED 1) +set(CMAKE_RC_SOURCE_FILE_EXTENSIONS rc;RC) +set(CMAKE_RC_OUTPUT_EXTENSION .res) +set(CMAKE_RC_COMPILER_ENV_VAR "RC") diff --git a/cpp/common/curve/build/CMakeFiles/3.28.1/CMakeSystem.cmake b/cpp/common/curve/build/CMakeFiles/3.28.1/CMakeSystem.cmake new file mode 100644 index 0000000..000cf69 --- /dev/null +++ b/cpp/common/curve/build/CMakeFiles/3.28.1/CMakeSystem.cmake @@ -0,0 +1,15 @@ +set(CMAKE_HOST_SYSTEM "Windows-10.0.26100") +set(CMAKE_HOST_SYSTEM_NAME "Windows") +set(CMAKE_HOST_SYSTEM_VERSION "10.0.26100") +set(CMAKE_HOST_SYSTEM_PROCESSOR "AMD64") + + + +set(CMAKE_SYSTEM "Windows-10.0.26100") +set(CMAKE_SYSTEM_NAME "Windows") +set(CMAKE_SYSTEM_VERSION "10.0.26100") +set(CMAKE_SYSTEM_PROCESSOR "AMD64") + +set(CMAKE_CROSSCOMPILING "FALSE") + +set(CMAKE_SYSTEM_LOADED 1) diff --git a/cpp/common/curve/build/CMakeFiles/3.28.1/CompilerIdCXX/CMakeCXXCompilerId.cpp b/cpp/common/curve/build/CMakeFiles/3.28.1/CompilerIdCXX/CMakeCXXCompilerId.cpp new file mode 100644 index 0000000..9c9c90e --- /dev/null +++ b/cpp/common/curve/build/CMakeFiles/3.28.1/CompilerIdCXX/CMakeCXXCompilerId.cpp @@ -0,0 +1,869 @@ +/* This source file must have a .cpp extension so that all C++ compilers + recognize the extension without flags. Borland does not know .cxx for + example. */ +#ifndef __cplusplus +# error "A C compiler has been selected for C++." +#endif + +#if !defined(__has_include) +/* If the compiler does not have __has_include, pretend the answer is + always no. */ +# define __has_include(x) 0 +#endif + + +/* Version number components: V=Version, R=Revision, P=Patch + Version date components: YYYY=Year, MM=Month, DD=Day */ + +#if defined(__COMO__) +# define COMPILER_ID "Comeau" + /* __COMO_VERSION__ = VRR */ +# define COMPILER_VERSION_MAJOR DEC(__COMO_VERSION__ / 100) +# define COMPILER_VERSION_MINOR DEC(__COMO_VERSION__ % 100) + +#elif defined(__INTEL_COMPILER) || defined(__ICC) +# define COMPILER_ID "Intel" +# if defined(_MSC_VER) +# define SIMULATE_ID "MSVC" +# endif +# if defined(__GNUC__) +# define SIMULATE_ID "GNU" +# endif + /* __INTEL_COMPILER = VRP prior to 2021, and then VVVV for 2021 and later, + except that a few beta releases use the old format with V=2021. */ +# if __INTEL_COMPILER < 2021 || __INTEL_COMPILER == 202110 || __INTEL_COMPILER == 202111 +# define COMPILER_VERSION_MAJOR DEC(__INTEL_COMPILER/100) +# define COMPILER_VERSION_MINOR DEC(__INTEL_COMPILER/10 % 10) +# if defined(__INTEL_COMPILER_UPDATE) +# define COMPILER_VERSION_PATCH DEC(__INTEL_COMPILER_UPDATE) +# else +# define COMPILER_VERSION_PATCH DEC(__INTEL_COMPILER % 10) +# endif +# else +# define COMPILER_VERSION_MAJOR DEC(__INTEL_COMPILER) +# define COMPILER_VERSION_MINOR DEC(__INTEL_COMPILER_UPDATE) + /* The third version component from --version is an update index, + but no macro is provided for it. */ +# define COMPILER_VERSION_PATCH DEC(0) +# endif +# if defined(__INTEL_COMPILER_BUILD_DATE) + /* __INTEL_COMPILER_BUILD_DATE = YYYYMMDD */ +# define COMPILER_VERSION_TWEAK DEC(__INTEL_COMPILER_BUILD_DATE) +# endif +# if defined(_MSC_VER) + /* _MSC_VER = VVRR */ +# define SIMULATE_VERSION_MAJOR DEC(_MSC_VER / 100) +# define SIMULATE_VERSION_MINOR DEC(_MSC_VER % 100) +# endif +# if defined(__GNUC__) +# define SIMULATE_VERSION_MAJOR DEC(__GNUC__) +# elif defined(__GNUG__) +# define SIMULATE_VERSION_MAJOR DEC(__GNUG__) +# endif +# if defined(__GNUC_MINOR__) +# define SIMULATE_VERSION_MINOR DEC(__GNUC_MINOR__) +# endif +# if defined(__GNUC_PATCHLEVEL__) +# define SIMULATE_VERSION_PATCH DEC(__GNUC_PATCHLEVEL__) +# endif + +#elif (defined(__clang__) && defined(__INTEL_CLANG_COMPILER)) || defined(__INTEL_LLVM_COMPILER) +# define COMPILER_ID "IntelLLVM" +#if defined(_MSC_VER) +# define SIMULATE_ID "MSVC" +#endif +#if defined(__GNUC__) +# define SIMULATE_ID "GNU" +#endif +/* __INTEL_LLVM_COMPILER = VVVVRP prior to 2021.2.0, VVVVRRPP for 2021.2.0 and + * later. Look for 6 digit vs. 8 digit version number to decide encoding. + * VVVV is no smaller than the current year when a version is released. + */ +#if __INTEL_LLVM_COMPILER < 1000000L +# define COMPILER_VERSION_MAJOR DEC(__INTEL_LLVM_COMPILER/100) +# define COMPILER_VERSION_MINOR DEC(__INTEL_LLVM_COMPILER/10 % 10) +# define COMPILER_VERSION_PATCH DEC(__INTEL_LLVM_COMPILER % 10) +#else +# define COMPILER_VERSION_MAJOR DEC(__INTEL_LLVM_COMPILER/10000) +# define COMPILER_VERSION_MINOR DEC(__INTEL_LLVM_COMPILER/100 % 100) +# define COMPILER_VERSION_PATCH DEC(__INTEL_LLVM_COMPILER % 100) +#endif +#if defined(_MSC_VER) + /* _MSC_VER = VVRR */ +# define SIMULATE_VERSION_MAJOR DEC(_MSC_VER / 100) +# define SIMULATE_VERSION_MINOR DEC(_MSC_VER % 100) +#endif +#if defined(__GNUC__) +# define SIMULATE_VERSION_MAJOR DEC(__GNUC__) +#elif defined(__GNUG__) +# define SIMULATE_VERSION_MAJOR DEC(__GNUG__) +#endif +#if defined(__GNUC_MINOR__) +# define SIMULATE_VERSION_MINOR DEC(__GNUC_MINOR__) +#endif +#if defined(__GNUC_PATCHLEVEL__) +# define SIMULATE_VERSION_PATCH DEC(__GNUC_PATCHLEVEL__) +#endif + +#elif defined(__PATHCC__) +# define COMPILER_ID "PathScale" +# define COMPILER_VERSION_MAJOR DEC(__PATHCC__) +# define COMPILER_VERSION_MINOR DEC(__PATHCC_MINOR__) +# if defined(__PATHCC_PATCHLEVEL__) +# define COMPILER_VERSION_PATCH DEC(__PATHCC_PATCHLEVEL__) +# endif + +#elif defined(__BORLANDC__) && defined(__CODEGEARC_VERSION__) +# define COMPILER_ID "Embarcadero" +# define COMPILER_VERSION_MAJOR HEX(__CODEGEARC_VERSION__>>24 & 0x00FF) +# define COMPILER_VERSION_MINOR HEX(__CODEGEARC_VERSION__>>16 & 0x00FF) +# define COMPILER_VERSION_PATCH DEC(__CODEGEARC_VERSION__ & 0xFFFF) + +#elif defined(__BORLANDC__) +# define COMPILER_ID "Borland" + /* __BORLANDC__ = 0xVRR */ +# define COMPILER_VERSION_MAJOR HEX(__BORLANDC__>>8) +# define COMPILER_VERSION_MINOR HEX(__BORLANDC__ & 0xFF) + +#elif defined(__WATCOMC__) && __WATCOMC__ < 1200 +# define COMPILER_ID "Watcom" + /* __WATCOMC__ = VVRR */ +# define COMPILER_VERSION_MAJOR DEC(__WATCOMC__ / 100) +# define COMPILER_VERSION_MINOR DEC((__WATCOMC__ / 10) % 10) +# if (__WATCOMC__ % 10) > 0 +# define COMPILER_VERSION_PATCH DEC(__WATCOMC__ % 10) +# endif + +#elif defined(__WATCOMC__) +# define COMPILER_ID "OpenWatcom" + /* __WATCOMC__ = VVRP + 1100 */ +# define COMPILER_VERSION_MAJOR DEC((__WATCOMC__ - 1100) / 100) +# define COMPILER_VERSION_MINOR DEC((__WATCOMC__ / 10) % 10) +# if (__WATCOMC__ % 10) > 0 +# define COMPILER_VERSION_PATCH DEC(__WATCOMC__ % 10) +# endif + +#elif defined(__SUNPRO_CC) +# define COMPILER_ID "SunPro" +# if __SUNPRO_CC >= 0x5100 + /* __SUNPRO_CC = 0xVRRP */ +# define COMPILER_VERSION_MAJOR HEX(__SUNPRO_CC>>12) +# define COMPILER_VERSION_MINOR HEX(__SUNPRO_CC>>4 & 0xFF) +# define COMPILER_VERSION_PATCH HEX(__SUNPRO_CC & 0xF) +# else + /* __SUNPRO_CC = 0xVRP */ +# define COMPILER_VERSION_MAJOR HEX(__SUNPRO_CC>>8) +# define COMPILER_VERSION_MINOR HEX(__SUNPRO_CC>>4 & 0xF) +# define COMPILER_VERSION_PATCH HEX(__SUNPRO_CC & 0xF) +# endif + +#elif defined(__HP_aCC) +# define COMPILER_ID "HP" + /* __HP_aCC = VVRRPP */ +# define COMPILER_VERSION_MAJOR DEC(__HP_aCC/10000) +# define COMPILER_VERSION_MINOR DEC(__HP_aCC/100 % 100) +# define COMPILER_VERSION_PATCH DEC(__HP_aCC % 100) + +#elif defined(__DECCXX) +# define COMPILER_ID "Compaq" + /* __DECCXX_VER = VVRRTPPPP */ +# define COMPILER_VERSION_MAJOR DEC(__DECCXX_VER/10000000) +# define COMPILER_VERSION_MINOR DEC(__DECCXX_VER/100000 % 100) +# define COMPILER_VERSION_PATCH DEC(__DECCXX_VER % 10000) + +#elif defined(__IBMCPP__) && defined(__COMPILER_VER__) +# define COMPILER_ID "zOS" + /* __IBMCPP__ = VRP */ +# define COMPILER_VERSION_MAJOR DEC(__IBMCPP__/100) +# define COMPILER_VERSION_MINOR DEC(__IBMCPP__/10 % 10) +# define COMPILER_VERSION_PATCH DEC(__IBMCPP__ % 10) + +#elif defined(__open_xl__) && defined(__clang__) +# define COMPILER_ID "IBMClang" +# define COMPILER_VERSION_MAJOR DEC(__open_xl_version__) +# define COMPILER_VERSION_MINOR DEC(__open_xl_release__) +# define COMPILER_VERSION_PATCH DEC(__open_xl_modification__) +# define COMPILER_VERSION_TWEAK DEC(__open_xl_ptf_fix_level__) + + +#elif defined(__ibmxl__) && defined(__clang__) +# define COMPILER_ID "XLClang" +# define COMPILER_VERSION_MAJOR DEC(__ibmxl_version__) +# define COMPILER_VERSION_MINOR DEC(__ibmxl_release__) +# define COMPILER_VERSION_PATCH DEC(__ibmxl_modification__) +# define COMPILER_VERSION_TWEAK DEC(__ibmxl_ptf_fix_level__) + + +#elif defined(__IBMCPP__) && !defined(__COMPILER_VER__) && __IBMCPP__ >= 800 +# define COMPILER_ID "XL" + /* __IBMCPP__ = VRP */ +# define COMPILER_VERSION_MAJOR DEC(__IBMCPP__/100) +# define COMPILER_VERSION_MINOR DEC(__IBMCPP__/10 % 10) +# define COMPILER_VERSION_PATCH DEC(__IBMCPP__ % 10) + +#elif defined(__IBMCPP__) && !defined(__COMPILER_VER__) && __IBMCPP__ < 800 +# define COMPILER_ID "VisualAge" + /* __IBMCPP__ = VRP */ +# define COMPILER_VERSION_MAJOR DEC(__IBMCPP__/100) +# define COMPILER_VERSION_MINOR DEC(__IBMCPP__/10 % 10) +# define COMPILER_VERSION_PATCH DEC(__IBMCPP__ % 10) + +#elif defined(__NVCOMPILER) +# define COMPILER_ID "NVHPC" +# define COMPILER_VERSION_MAJOR DEC(__NVCOMPILER_MAJOR__) +# define COMPILER_VERSION_MINOR DEC(__NVCOMPILER_MINOR__) +# if defined(__NVCOMPILER_PATCHLEVEL__) +# define COMPILER_VERSION_PATCH DEC(__NVCOMPILER_PATCHLEVEL__) +# endif + +#elif defined(__PGI) +# define COMPILER_ID "PGI" +# define COMPILER_VERSION_MAJOR DEC(__PGIC__) +# define COMPILER_VERSION_MINOR DEC(__PGIC_MINOR__) +# if defined(__PGIC_PATCHLEVEL__) +# define COMPILER_VERSION_PATCH DEC(__PGIC_PATCHLEVEL__) +# endif + +#elif defined(__clang__) && defined(__cray__) +# define COMPILER_ID "CrayClang" +# define COMPILER_VERSION_MAJOR DEC(__cray_major__) +# define COMPILER_VERSION_MINOR DEC(__cray_minor__) +# define COMPILER_VERSION_PATCH DEC(__cray_patchlevel__) +# define COMPILER_VERSION_INTERNAL_STR __clang_version__ + + +#elif defined(_CRAYC) +# define COMPILER_ID "Cray" +# define COMPILER_VERSION_MAJOR DEC(_RELEASE_MAJOR) +# define COMPILER_VERSION_MINOR DEC(_RELEASE_MINOR) + +#elif defined(__TI_COMPILER_VERSION__) +# define COMPILER_ID "TI" + /* __TI_COMPILER_VERSION__ = VVVRRRPPP */ +# define COMPILER_VERSION_MAJOR DEC(__TI_COMPILER_VERSION__/1000000) +# define COMPILER_VERSION_MINOR DEC(__TI_COMPILER_VERSION__/1000 % 1000) +# define COMPILER_VERSION_PATCH DEC(__TI_COMPILER_VERSION__ % 1000) + +#elif defined(__CLANG_FUJITSU) +# define COMPILER_ID "FujitsuClang" +# define COMPILER_VERSION_MAJOR DEC(__FCC_major__) +# define COMPILER_VERSION_MINOR DEC(__FCC_minor__) +# define COMPILER_VERSION_PATCH DEC(__FCC_patchlevel__) +# define COMPILER_VERSION_INTERNAL_STR __clang_version__ + + +#elif defined(__FUJITSU) +# define COMPILER_ID "Fujitsu" +# if defined(__FCC_version__) +# define COMPILER_VERSION __FCC_version__ +# elif defined(__FCC_major__) +# define COMPILER_VERSION_MAJOR DEC(__FCC_major__) +# define COMPILER_VERSION_MINOR DEC(__FCC_minor__) +# define COMPILER_VERSION_PATCH DEC(__FCC_patchlevel__) +# endif +# if defined(__fcc_version) +# define COMPILER_VERSION_INTERNAL DEC(__fcc_version) +# elif defined(__FCC_VERSION) +# define COMPILER_VERSION_INTERNAL DEC(__FCC_VERSION) +# endif + + +#elif defined(__ghs__) +# define COMPILER_ID "GHS" +/* __GHS_VERSION_NUMBER = VVVVRP */ +# ifdef __GHS_VERSION_NUMBER +# define COMPILER_VERSION_MAJOR DEC(__GHS_VERSION_NUMBER / 100) +# define COMPILER_VERSION_MINOR DEC(__GHS_VERSION_NUMBER / 10 % 10) +# define COMPILER_VERSION_PATCH DEC(__GHS_VERSION_NUMBER % 10) +# endif + +#elif defined(__TASKING__) +# define COMPILER_ID "Tasking" + # define COMPILER_VERSION_MAJOR DEC(__VERSION__/1000) + # define COMPILER_VERSION_MINOR DEC(__VERSION__ % 100) +# define COMPILER_VERSION_INTERNAL DEC(__VERSION__) + +#elif defined(__ORANGEC__) +# define COMPILER_ID "OrangeC" +# define COMPILER_VERSION_MAJOR DEC(__ORANGEC_MAJOR__) +# define COMPILER_VERSION_MINOR DEC(__ORANGEC_MINOR__) +# define COMPILER_VERSION_PATCH DEC(__ORANGEC_PATCHLEVEL__) + +#elif defined(__SCO_VERSION__) +# define COMPILER_ID "SCO" + +#elif defined(__ARMCC_VERSION) && !defined(__clang__) +# define COMPILER_ID "ARMCC" +#if __ARMCC_VERSION >= 1000000 + /* __ARMCC_VERSION = VRRPPPP */ + # define COMPILER_VERSION_MAJOR DEC(__ARMCC_VERSION/1000000) + # define COMPILER_VERSION_MINOR DEC(__ARMCC_VERSION/10000 % 100) + # define COMPILER_VERSION_PATCH DEC(__ARMCC_VERSION % 10000) +#else + /* __ARMCC_VERSION = VRPPPP */ + # define COMPILER_VERSION_MAJOR DEC(__ARMCC_VERSION/100000) + # define COMPILER_VERSION_MINOR DEC(__ARMCC_VERSION/10000 % 10) + # define COMPILER_VERSION_PATCH DEC(__ARMCC_VERSION % 10000) +#endif + + +#elif defined(__clang__) && defined(__apple_build_version__) +# define COMPILER_ID "AppleClang" +# if defined(_MSC_VER) +# define SIMULATE_ID "MSVC" +# endif +# define COMPILER_VERSION_MAJOR DEC(__clang_major__) +# define COMPILER_VERSION_MINOR DEC(__clang_minor__) +# define COMPILER_VERSION_PATCH DEC(__clang_patchlevel__) +# if defined(_MSC_VER) + /* _MSC_VER = VVRR */ +# define SIMULATE_VERSION_MAJOR DEC(_MSC_VER / 100) +# define SIMULATE_VERSION_MINOR DEC(_MSC_VER % 100) +# endif +# define COMPILER_VERSION_TWEAK DEC(__apple_build_version__) + +#elif defined(__clang__) && defined(__ARMCOMPILER_VERSION) +# define COMPILER_ID "ARMClang" + # define COMPILER_VERSION_MAJOR DEC(__ARMCOMPILER_VERSION/1000000) + # define COMPILER_VERSION_MINOR DEC(__ARMCOMPILER_VERSION/10000 % 100) + # define COMPILER_VERSION_PATCH DEC(__ARMCOMPILER_VERSION/100 % 100) +# define COMPILER_VERSION_INTERNAL DEC(__ARMCOMPILER_VERSION) + +#elif defined(__clang__) +# define COMPILER_ID "Clang" +# if defined(_MSC_VER) +# define SIMULATE_ID "MSVC" +# endif +# define COMPILER_VERSION_MAJOR DEC(__clang_major__) +# define COMPILER_VERSION_MINOR DEC(__clang_minor__) +# define COMPILER_VERSION_PATCH DEC(__clang_patchlevel__) +# if defined(_MSC_VER) + /* _MSC_VER = VVRR */ +# define SIMULATE_VERSION_MAJOR DEC(_MSC_VER / 100) +# define SIMULATE_VERSION_MINOR DEC(_MSC_VER % 100) +# endif + +#elif defined(__LCC__) && (defined(__GNUC__) || defined(__GNUG__) || defined(__MCST__)) +# define COMPILER_ID "LCC" +# define COMPILER_VERSION_MAJOR DEC(__LCC__ / 100) +# define COMPILER_VERSION_MINOR DEC(__LCC__ % 100) +# if defined(__LCC_MINOR__) +# define COMPILER_VERSION_PATCH DEC(__LCC_MINOR__) +# endif +# if defined(__GNUC__) && defined(__GNUC_MINOR__) +# define SIMULATE_ID "GNU" +# define SIMULATE_VERSION_MAJOR DEC(__GNUC__) +# define SIMULATE_VERSION_MINOR DEC(__GNUC_MINOR__) +# if defined(__GNUC_PATCHLEVEL__) +# define SIMULATE_VERSION_PATCH DEC(__GNUC_PATCHLEVEL__) +# endif +# endif + +#elif defined(__GNUC__) || defined(__GNUG__) +# define COMPILER_ID "GNU" +# if defined(__GNUC__) +# define COMPILER_VERSION_MAJOR DEC(__GNUC__) +# else +# define COMPILER_VERSION_MAJOR DEC(__GNUG__) +# endif +# if defined(__GNUC_MINOR__) +# define COMPILER_VERSION_MINOR DEC(__GNUC_MINOR__) +# endif +# if defined(__GNUC_PATCHLEVEL__) +# define COMPILER_VERSION_PATCH DEC(__GNUC_PATCHLEVEL__) +# endif + +#elif defined(_MSC_VER) +# define COMPILER_ID "MSVC" + /* _MSC_VER = VVRR */ +# define COMPILER_VERSION_MAJOR DEC(_MSC_VER / 100) +# define COMPILER_VERSION_MINOR DEC(_MSC_VER % 100) +# if defined(_MSC_FULL_VER) +# if _MSC_VER >= 1400 + /* _MSC_FULL_VER = VVRRPPPPP */ +# define COMPILER_VERSION_PATCH DEC(_MSC_FULL_VER % 100000) +# else + /* _MSC_FULL_VER = VVRRPPPP */ +# define COMPILER_VERSION_PATCH DEC(_MSC_FULL_VER % 10000) +# endif +# endif +# if defined(_MSC_BUILD) +# define COMPILER_VERSION_TWEAK DEC(_MSC_BUILD) +# endif + +#elif defined(_ADI_COMPILER) +# define COMPILER_ID "ADSP" +#if defined(__VERSIONNUM__) + /* __VERSIONNUM__ = 0xVVRRPPTT */ +# define COMPILER_VERSION_MAJOR DEC(__VERSIONNUM__ >> 24 & 0xFF) +# define COMPILER_VERSION_MINOR DEC(__VERSIONNUM__ >> 16 & 0xFF) +# define COMPILER_VERSION_PATCH DEC(__VERSIONNUM__ >> 8 & 0xFF) +# define COMPILER_VERSION_TWEAK DEC(__VERSIONNUM__ & 0xFF) +#endif + +#elif defined(__IAR_SYSTEMS_ICC__) || defined(__IAR_SYSTEMS_ICC) +# define COMPILER_ID "IAR" +# if defined(__VER__) && defined(__ICCARM__) +# define COMPILER_VERSION_MAJOR DEC((__VER__) / 1000000) +# define COMPILER_VERSION_MINOR DEC(((__VER__) / 1000) % 1000) +# define COMPILER_VERSION_PATCH DEC((__VER__) % 1000) +# define COMPILER_VERSION_INTERNAL DEC(__IAR_SYSTEMS_ICC__) +# elif defined(__VER__) && (defined(__ICCAVR__) || defined(__ICCRX__) || defined(__ICCRH850__) || defined(__ICCRL78__) || defined(__ICC430__) || defined(__ICCRISCV__) || defined(__ICCV850__) || defined(__ICC8051__) || defined(__ICCSTM8__)) +# define COMPILER_VERSION_MAJOR DEC((__VER__) / 100) +# define COMPILER_VERSION_MINOR DEC((__VER__) - (((__VER__) / 100)*100)) +# define COMPILER_VERSION_PATCH DEC(__SUBVERSION__) +# define COMPILER_VERSION_INTERNAL DEC(__IAR_SYSTEMS_ICC__) +# endif + + +/* These compilers are either not known or too old to define an + identification macro. Try to identify the platform and guess that + it is the native compiler. */ +#elif defined(__hpux) || defined(__hpua) +# define COMPILER_ID "HP" + +#else /* unknown compiler */ +# define COMPILER_ID "" +#endif + +/* Construct the string literal in pieces to prevent the source from + getting matched. Store it in a pointer rather than an array + because some compilers will just produce instructions to fill the + array rather than assigning a pointer to a static array. */ +char const* info_compiler = "INFO" ":" "compiler[" COMPILER_ID "]"; +#ifdef SIMULATE_ID +char const* info_simulate = "INFO" ":" "simulate[" SIMULATE_ID "]"; +#endif + +#ifdef __QNXNTO__ +char const* qnxnto = "INFO" ":" "qnxnto[]"; +#endif + +#if defined(__CRAYXT_COMPUTE_LINUX_TARGET) +char const *info_cray = "INFO" ":" "compiler_wrapper[CrayPrgEnv]"; +#endif + +#define STRINGIFY_HELPER(X) #X +#define STRINGIFY(X) STRINGIFY_HELPER(X) + +/* Identify known platforms by name. */ +#if defined(__linux) || defined(__linux__) || defined(linux) +# define PLATFORM_ID "Linux" + +#elif defined(__MSYS__) +# define PLATFORM_ID "MSYS" + +#elif defined(__CYGWIN__) +# define PLATFORM_ID "Cygwin" + +#elif defined(__MINGW32__) +# define PLATFORM_ID "MinGW" + +#elif defined(__APPLE__) +# define PLATFORM_ID "Darwin" + +#elif defined(_WIN32) || defined(__WIN32__) || defined(WIN32) +# define PLATFORM_ID "Windows" + +#elif defined(__FreeBSD__) || defined(__FreeBSD) +# define PLATFORM_ID "FreeBSD" + +#elif defined(__NetBSD__) || defined(__NetBSD) +# define PLATFORM_ID "NetBSD" + +#elif defined(__OpenBSD__) || defined(__OPENBSD) +# define PLATFORM_ID "OpenBSD" + +#elif defined(__sun) || defined(sun) +# define PLATFORM_ID "SunOS" + +#elif defined(_AIX) || defined(__AIX) || defined(__AIX__) || defined(__aix) || defined(__aix__) +# define PLATFORM_ID "AIX" + +#elif defined(__hpux) || defined(__hpux__) +# define PLATFORM_ID "HP-UX" + +#elif defined(__HAIKU__) +# define PLATFORM_ID "Haiku" + +#elif defined(__BeOS) || defined(__BEOS__) || defined(_BEOS) +# define PLATFORM_ID "BeOS" + +#elif defined(__QNX__) || defined(__QNXNTO__) +# define PLATFORM_ID "QNX" + +#elif defined(__tru64) || defined(_tru64) || defined(__TRU64__) +# define PLATFORM_ID "Tru64" + +#elif defined(__riscos) || defined(__riscos__) +# define PLATFORM_ID "RISCos" + +#elif defined(__sinix) || defined(__sinix__) || defined(__SINIX__) +# define PLATFORM_ID "SINIX" + +#elif defined(__UNIX_SV__) +# define PLATFORM_ID "UNIX_SV" + +#elif defined(__bsdos__) +# define PLATFORM_ID "BSDOS" + +#elif defined(_MPRAS) || defined(MPRAS) +# define PLATFORM_ID "MP-RAS" + +#elif defined(__osf) || defined(__osf__) +# define PLATFORM_ID "OSF1" + +#elif defined(_SCO_SV) || defined(SCO_SV) || defined(sco_sv) +# define PLATFORM_ID "SCO_SV" + +#elif defined(__ultrix) || defined(__ultrix__) || defined(_ULTRIX) +# define PLATFORM_ID "ULTRIX" + +#elif defined(__XENIX__) || defined(_XENIX) || defined(XENIX) +# define PLATFORM_ID "Xenix" + +#elif defined(__WATCOMC__) +# if defined(__LINUX__) +# define PLATFORM_ID "Linux" + +# elif defined(__DOS__) +# define PLATFORM_ID "DOS" + +# elif defined(__OS2__) +# define PLATFORM_ID "OS2" + +# elif defined(__WINDOWS__) +# define PLATFORM_ID "Windows3x" + +# elif defined(__VXWORKS__) +# define PLATFORM_ID "VxWorks" + +# else /* unknown platform */ +# define PLATFORM_ID +# endif + +#elif defined(__INTEGRITY) +# if defined(INT_178B) +# define PLATFORM_ID "Integrity178" + +# else /* regular Integrity */ +# define PLATFORM_ID "Integrity" +# endif + +# elif defined(_ADI_COMPILER) +# define PLATFORM_ID "ADSP" + +#else /* unknown platform */ +# define PLATFORM_ID + +#endif + +/* For windows compilers MSVC and Intel we can determine + the architecture of the compiler being used. This is because + the compilers do not have flags that can change the architecture, + but rather depend on which compiler is being used +*/ +#if defined(_WIN32) && defined(_MSC_VER) +# if defined(_M_IA64) +# define ARCHITECTURE_ID "IA64" + +# elif defined(_M_ARM64EC) +# define ARCHITECTURE_ID "ARM64EC" + +# elif defined(_M_X64) || defined(_M_AMD64) +# define ARCHITECTURE_ID "x64" + +# elif defined(_M_IX86) +# define ARCHITECTURE_ID "X86" + +# elif defined(_M_ARM64) +# define ARCHITECTURE_ID "ARM64" + +# elif defined(_M_ARM) +# if _M_ARM == 4 +# define ARCHITECTURE_ID "ARMV4I" +# elif _M_ARM == 5 +# define ARCHITECTURE_ID "ARMV5I" +# else +# define ARCHITECTURE_ID "ARMV" STRINGIFY(_M_ARM) +# endif + +# elif defined(_M_MIPS) +# define ARCHITECTURE_ID "MIPS" + +# elif defined(_M_SH) +# define ARCHITECTURE_ID "SHx" + +# else /* unknown architecture */ +# define ARCHITECTURE_ID "" +# endif + +#elif defined(__WATCOMC__) +# if defined(_M_I86) +# define ARCHITECTURE_ID "I86" + +# elif defined(_M_IX86) +# define ARCHITECTURE_ID "X86" + +# else /* unknown architecture */ +# define ARCHITECTURE_ID "" +# endif + +#elif defined(__IAR_SYSTEMS_ICC__) || defined(__IAR_SYSTEMS_ICC) +# if defined(__ICCARM__) +# define ARCHITECTURE_ID "ARM" + +# elif defined(__ICCRX__) +# define ARCHITECTURE_ID "RX" + +# elif defined(__ICCRH850__) +# define ARCHITECTURE_ID "RH850" + +# elif defined(__ICCRL78__) +# define ARCHITECTURE_ID "RL78" + +# elif defined(__ICCRISCV__) +# define ARCHITECTURE_ID "RISCV" + +# elif defined(__ICCAVR__) +# define ARCHITECTURE_ID "AVR" + +# elif defined(__ICC430__) +# define ARCHITECTURE_ID "MSP430" + +# elif defined(__ICCV850__) +# define ARCHITECTURE_ID "V850" + +# elif defined(__ICC8051__) +# define ARCHITECTURE_ID "8051" + +# elif defined(__ICCSTM8__) +# define ARCHITECTURE_ID "STM8" + +# else /* unknown architecture */ +# define ARCHITECTURE_ID "" +# endif + +#elif defined(__ghs__) +# if defined(__PPC64__) +# define ARCHITECTURE_ID "PPC64" + +# elif defined(__ppc__) +# define ARCHITECTURE_ID "PPC" + +# elif defined(__ARM__) +# define ARCHITECTURE_ID "ARM" + +# elif defined(__x86_64__) +# define ARCHITECTURE_ID "x64" + +# elif defined(__i386__) +# define ARCHITECTURE_ID "X86" + +# else /* unknown architecture */ +# define ARCHITECTURE_ID "" +# endif + +#elif defined(__TI_COMPILER_VERSION__) +# if defined(__TI_ARM__) +# define ARCHITECTURE_ID "ARM" + +# elif defined(__MSP430__) +# define ARCHITECTURE_ID "MSP430" + +# elif defined(__TMS320C28XX__) +# define ARCHITECTURE_ID "TMS320C28x" + +# elif defined(__TMS320C6X__) || defined(_TMS320C6X) +# define ARCHITECTURE_ID "TMS320C6x" + +# else /* unknown architecture */ +# define ARCHITECTURE_ID "" +# endif + +# elif defined(__ADSPSHARC__) +# define ARCHITECTURE_ID "SHARC" + +# elif defined(__ADSPBLACKFIN__) +# define ARCHITECTURE_ID "Blackfin" + +#elif defined(__TASKING__) + +# if defined(__CTC__) || defined(__CPTC__) +# define ARCHITECTURE_ID "TriCore" + +# elif defined(__CMCS__) +# define ARCHITECTURE_ID "MCS" + +# elif defined(__CARM__) +# define ARCHITECTURE_ID "ARM" + +# elif defined(__CARC__) +# define ARCHITECTURE_ID "ARC" + +# elif defined(__C51__) +# define ARCHITECTURE_ID "8051" + +# elif defined(__CPCP__) +# define ARCHITECTURE_ID "PCP" + +# else +# define ARCHITECTURE_ID "" +# endif + +#else +# define ARCHITECTURE_ID +#endif + +/* Convert integer to decimal digit literals. */ +#define DEC(n) \ + ('0' + (((n) / 10000000)%10)), \ + ('0' + (((n) / 1000000)%10)), \ + ('0' + (((n) / 100000)%10)), \ + ('0' + (((n) / 10000)%10)), \ + ('0' + (((n) / 1000)%10)), \ + ('0' + (((n) / 100)%10)), \ + ('0' + (((n) / 10)%10)), \ + ('0' + ((n) % 10)) + +/* Convert integer to hex digit literals. */ +#define HEX(n) \ + ('0' + ((n)>>28 & 0xF)), \ + ('0' + ((n)>>24 & 0xF)), \ + ('0' + ((n)>>20 & 0xF)), \ + ('0' + ((n)>>16 & 0xF)), \ + ('0' + ((n)>>12 & 0xF)), \ + ('0' + ((n)>>8 & 0xF)), \ + ('0' + ((n)>>4 & 0xF)), \ + ('0' + ((n) & 0xF)) + +/* Construct a string literal encoding the version number. */ +#ifdef COMPILER_VERSION +char const* info_version = "INFO" ":" "compiler_version[" COMPILER_VERSION "]"; + +/* Construct a string literal encoding the version number components. */ +#elif defined(COMPILER_VERSION_MAJOR) +char const info_version[] = { + 'I', 'N', 'F', 'O', ':', + 'c','o','m','p','i','l','e','r','_','v','e','r','s','i','o','n','[', + COMPILER_VERSION_MAJOR, +# ifdef COMPILER_VERSION_MINOR + '.', COMPILER_VERSION_MINOR, +# ifdef COMPILER_VERSION_PATCH + '.', COMPILER_VERSION_PATCH, +# ifdef COMPILER_VERSION_TWEAK + '.', COMPILER_VERSION_TWEAK, +# endif +# endif +# endif + ']','\0'}; +#endif + +/* Construct a string literal encoding the internal version number. */ +#ifdef COMPILER_VERSION_INTERNAL +char const info_version_internal[] = { + 'I', 'N', 'F', 'O', ':', + 'c','o','m','p','i','l','e','r','_','v','e','r','s','i','o','n','_', + 'i','n','t','e','r','n','a','l','[', + COMPILER_VERSION_INTERNAL,']','\0'}; +#elif defined(COMPILER_VERSION_INTERNAL_STR) +char const* info_version_internal = "INFO" ":" "compiler_version_internal[" COMPILER_VERSION_INTERNAL_STR "]"; +#endif + +/* Construct a string literal encoding the version number components. */ +#ifdef SIMULATE_VERSION_MAJOR +char const info_simulate_version[] = { + 'I', 'N', 'F', 'O', ':', + 's','i','m','u','l','a','t','e','_','v','e','r','s','i','o','n','[', + SIMULATE_VERSION_MAJOR, +# ifdef SIMULATE_VERSION_MINOR + '.', SIMULATE_VERSION_MINOR, +# ifdef SIMULATE_VERSION_PATCH + '.', SIMULATE_VERSION_PATCH, +# ifdef SIMULATE_VERSION_TWEAK + '.', SIMULATE_VERSION_TWEAK, +# endif +# endif +# endif + ']','\0'}; +#endif + +/* Construct the string literal in pieces to prevent the source from + getting matched. Store it in a pointer rather than an array + because some compilers will just produce instructions to fill the + array rather than assigning a pointer to a static array. */ +char const* info_platform = "INFO" ":" "platform[" PLATFORM_ID "]"; +char const* info_arch = "INFO" ":" "arch[" ARCHITECTURE_ID "]"; + + + +#if defined(__INTEL_COMPILER) && defined(_MSVC_LANG) && _MSVC_LANG < 201403L +# if defined(__INTEL_CXX11_MODE__) +# if defined(__cpp_aggregate_nsdmi) +# define CXX_STD 201402L +# else +# define CXX_STD 201103L +# endif +# else +# define CXX_STD 199711L +# endif +#elif defined(_MSC_VER) && defined(_MSVC_LANG) +# define CXX_STD _MSVC_LANG +#else +# define CXX_STD __cplusplus +#endif + +const char* info_language_standard_default = "INFO" ":" "standard_default[" +#if CXX_STD > 202002L + "23" +#elif CXX_STD > 201703L + "20" +#elif CXX_STD >= 201703L + "17" +#elif CXX_STD >= 201402L + "14" +#elif CXX_STD >= 201103L + "11" +#else + "98" +#endif +"]"; + +const char* info_language_extensions_default = "INFO" ":" "extensions_default[" +#if (defined(__clang__) || defined(__GNUC__) || defined(__xlC__) || \ + defined(__TI_COMPILER_VERSION__)) && \ + !defined(__STRICT_ANSI__) + "ON" +#else + "OFF" +#endif +"]"; + +/*--------------------------------------------------------------------------*/ + +int main(int argc, char* argv[]) +{ + int require = 0; + require += info_compiler[argc]; + require += info_platform[argc]; + require += info_arch[argc]; +#ifdef COMPILER_VERSION_MAJOR + require += info_version[argc]; +#endif +#ifdef COMPILER_VERSION_INTERNAL + require += info_version_internal[argc]; +#endif +#ifdef SIMULATE_ID + require += info_simulate[argc]; +#endif +#ifdef SIMULATE_VERSION_MAJOR + require += info_simulate_version[argc]; +#endif +#if defined(__CRAYXT_COMPUTE_LINUX_TARGET) + require += info_cray[argc]; +#endif + require += info_language_standard_default[argc]; + require += info_language_extensions_default[argc]; + (void)argv; + return require; +} diff --git a/cpp/common/curve/build/CMakeFiles/3.28.1/CompilerIdCXX/CMakeCXXCompilerId.exe b/cpp/common/curve/build/CMakeFiles/3.28.1/CompilerIdCXX/CMakeCXXCompilerId.exe new file mode 100644 index 0000000..c359278 Binary files /dev/null and b/cpp/common/curve/build/CMakeFiles/3.28.1/CompilerIdCXX/CMakeCXXCompilerId.exe differ diff --git a/cpp/common/curve/build/CMakeFiles/3.28.1/CompilerIdCXX/CMakeCXXCompilerId.obj b/cpp/common/curve/build/CMakeFiles/3.28.1/CompilerIdCXX/CMakeCXXCompilerId.obj new file mode 100644 index 0000000..52ef8fd Binary files /dev/null and b/cpp/common/curve/build/CMakeFiles/3.28.1/CompilerIdCXX/CMakeCXXCompilerId.obj differ diff --git a/cpp/common/curve/build/CMakeFiles/CMakeConfigureLog.yaml b/cpp/common/curve/build/CMakeFiles/CMakeConfigureLog.yaml new file mode 100644 index 0000000..a4182c8 --- /dev/null +++ b/cpp/common/curve/build/CMakeFiles/CMakeConfigureLog.yaml @@ -0,0 +1,118 @@ + +--- +events: + - + kind: "message-v1" + backtrace: + - "C:/Program Files/STM32/STM32CubeCLT_1.20.0/CMake/share/cmake-3.28/Modules/CMakeDetermineSystem.cmake:233 (message)" + - "CMakeLists.txt:3 (project)" + message: | + The system is: Windows - 10.0.26100 - AMD64 + - + kind: "message-v1" + backtrace: + - "C:/Program Files/STM32/STM32CubeCLT_1.20.0/CMake/share/cmake-3.28/Modules/CMakeDetermineCompilerId.cmake:17 (message)" + - "C:/Program Files/STM32/STM32CubeCLT_1.20.0/CMake/share/cmake-3.28/Modules/CMakeDetermineCompilerId.cmake:64 (__determine_compiler_id_test)" + - "C:/Program Files/STM32/STM32CubeCLT_1.20.0/CMake/share/cmake-3.28/Modules/CMakeDetermineCXXCompiler.cmake:126 (CMAKE_DETERMINE_COMPILER_ID)" + - "CMakeLists.txt:3 (project)" + message: | + Compiling the CXX compiler identification source file "CMakeCXXCompilerId.cpp" succeeded. + Compiler: C:/Program Files/Microsoft Visual Studio/18/Community/VC/Tools/MSVC/14.50.35717/bin/Hostx64/x64/cl.exe + Build flags: + Id flags: + + The output was: + 0 + 用于 x64 的 Microsoft (R) C/C++ 优化编译器 19.50.35722 版 + 版权所有(C) Microsoft Corporation。保留所有权利。 + + CMakeCXXCompilerId.cpp + Microsoft (R) Incremental Linker Version 14.50.35722.0 + Copyright (C) Microsoft Corporation. All rights reserved. + + /out:CMakeCXXCompilerId.exe + CMakeCXXCompilerId.obj + + + Compilation of the CXX compiler identification source "CMakeCXXCompilerId.cpp" produced "CMakeCXXCompilerId.exe" + + Compilation of the CXX compiler identification source "CMakeCXXCompilerId.cpp" produced "CMakeCXXCompilerId.obj" + + The CXX compiler identification is MSVC, found in: + D:/cmvr/0-worksapce/cmvr-head-client/cpp/common/curve/build/CMakeFiles/3.28.1/CompilerIdCXX/CMakeCXXCompilerId.exe + + - + kind: "message-v1" + backtrace: + - "C:/Program Files/STM32/STM32CubeCLT_1.20.0/CMake/share/cmake-3.28/Modules/CMakeDetermineCompilerId.cmake:1182 (message)" + - "C:/Program Files/STM32/STM32CubeCLT_1.20.0/CMake/share/cmake-3.28/Modules/CMakeDetermineCompilerId.cmake:247 (CMAKE_DETERMINE_MSVC_SHOWINCLUDES_PREFIX)" + - "C:/Program Files/STM32/STM32CubeCLT_1.20.0/CMake/share/cmake-3.28/Modules/CMakeDetermineCXXCompiler.cmake:126 (CMAKE_DETERMINE_COMPILER_ID)" + - "CMakeLists.txt:3 (project)" + message: | + Detecting CXX compiler /showIncludes prefix: + main.c + 注意: 包含文件: D:\\cmvr\\0-worksapce\\cmvr-head-client\\cpp\\common\\curve\\build\\CMakeFiles\\ShowIncludes\\foo.h + + Found prefix "注意: 包含文件: " + - + kind: "try_compile-v1" + backtrace: + - "C:/Program Files/STM32/STM32CubeCLT_1.20.0/CMake/share/cmake-3.28/Modules/CMakeDetermineCompilerABI.cmake:57 (try_compile)" + - "C:/Program Files/STM32/STM32CubeCLT_1.20.0/CMake/share/cmake-3.28/Modules/CMakeTestCXXCompiler.cmake:26 (CMAKE_DETERMINE_COMPILER_ABI)" + - "CMakeLists.txt:3 (project)" + checks: + - "Detecting CXX compiler ABI info" + directories: + source: "D:/cmvr/0-worksapce/cmvr-head-client/cpp/common/curve/build/CMakeFiles/CMakeScratch/TryCompile-pxs2x3" + binary: "D:/cmvr/0-worksapce/cmvr-head-client/cpp/common/curve/build/CMakeFiles/CMakeScratch/TryCompile-pxs2x3" + cmakeVariables: + CMAKE_CXX_FLAGS: "/DWIN32 /D_WINDOWS /EHsc" + CMAKE_CXX_FLAGS_DEBUG: "/Zi /Ob0 /Od /RTC1" + CMAKE_EXE_LINKER_FLAGS: "/machine:x64" + buildResult: + variable: "CMAKE_CXX_ABI_COMPILED" + cached: true + stdout: | + Change Dir: 'D:/cmvr/0-worksapce/cmvr-head-client/cpp/common/curve/build/CMakeFiles/CMakeScratch/TryCompile-pxs2x3' + + Run Build Command(s): C:/PROGRA~1/STM32/STM32C~1.0/Ninja/bin/ninja.exe -v cmTC_04a14 + [1/2] C:\\PROGRA~1\\MIB055~1\\18\\COMMUN~1\\VC\\Tools\\MSVC\\1450~1.357\\bin\\Hostx64\\x64\\cl.exe /nologo /TP /DWIN32 /D_WINDOWS /EHsc /Zi /Ob0 /Od /RTC1 -MDd /showIncludes /FoCMakeFiles\\cmTC_04a14.dir\\CMakeCXXCompilerABI.cpp.obj /FdCMakeFiles\\cmTC_04a14.dir\\ /FS -c "C:\\Program Files\\STM32\\STM32CubeCLT_1.20.0\\CMake\\share\\cmake-3.28\\Modules\\CMakeCXXCompilerABI.cpp" + [2/2] C:\\windows\\system32\\cmd.exe /C "cd . && "C:\\Program Files\\STM32\\STM32CubeCLT_1.20.0\\CMake\\bin\\cmake.exe" -E vs_link_exe --intdir=CMakeFiles\\cmTC_04a14.dir --rc=C:\\PROGRA~2\\WINDOW~4\\10\\bin\\100261~1.0\\x64\\rc.exe --mt=C:\\PROGRA~2\\WINDOW~4\\10\\bin\\100261~1.0\\x64\\mt.exe --manifests -- C:\\PROGRA~1\\MIB055~1\\18\\COMMUN~1\\VC\\Tools\\MSVC\\1450~1.357\\bin\\Hostx64\\x64\\link.exe /nologo CMakeFiles\\cmTC_04a14.dir\\CMakeCXXCompilerABI.cpp.obj /out:cmTC_04a14.exe /implib:cmTC_04a14.lib /pdb:cmTC_04a14.pdb /version:0.0 /machine:x64 /debug /INCREMENTAL /subsystem:console kernel32.lib user32.lib gdi32.lib winspool.lib shell32.lib ole32.lib oleaut32.lib uuid.lib comdlg32.lib advapi32.lib && cd ." + + exitCode: 0 +... + +--- +events: + - + kind: "try_compile-v1" + backtrace: + - "C:/Program Files/STM32/STM32CubeCLT_1.20.0/CMake/share/cmake-3.28/Modules/Internal/CheckSourceCompiles.cmake:101 (try_compile)" + - "C:/Program Files/STM32/STM32CubeCLT_1.20.0/CMake/share/cmake-3.28/Modules/Internal/CheckCompilerFlag.cmake:18 (cmake_check_source_compiles)" + - "C:/Program Files/STM32/STM32CubeCLT_1.20.0/CMake/share/cmake-3.28/Modules/CheckCXXCompilerFlag.cmake:34 (cmake_check_compiler_flag)" + - "C:/Users/Administrator/miniconda3/envs/cmvr-head-client/Lib/site-packages/pybind11/share/cmake/pybind11/pybind11Common.cmake:332 (check_cxx_compiler_flag)" + - "C:/Users/Administrator/miniconda3/envs/cmvr-head-client/Lib/site-packages/pybind11/share/cmake/pybind11/pybind11Common.cmake:404 (_pybind11_return_if_cxx_and_linker_flags_work)" + - "C:/Users/Administrator/miniconda3/envs/cmvr-head-client/Lib/site-packages/pybind11/share/cmake/pybind11/pybind11Common.cmake:438 (_pybind11_generate_lto)" + - "C:/Users/Administrator/miniconda3/envs/cmvr-head-client/Lib/site-packages/pybind11/share/cmake/pybind11/pybind11Config.cmake:257 (include)" + - "CMakeLists.txt:13 (find_package)" + checks: + - "Performing Test HAS_MSVC_GL_LTCG" + directories: + source: "D:/cmvr/0-worksapce/cmvr-head-client/cpp/common/curve/build/CMakeFiles/CMakeScratch/TryCompile-n8t4hj" + binary: "D:/cmvr/0-worksapce/cmvr-head-client/cpp/common/curve/build/CMakeFiles/CMakeScratch/TryCompile-n8t4hj" + cmakeVariables: + CMAKE_CXX_FLAGS: "/DWIN32 /D_WINDOWS /EHsc" + CMAKE_CXX_FLAGS_DEBUG: "/Zi /Ob0 /Od /RTC1" + CMAKE_EXE_LINKER_FLAGS: "/machine:x64" + buildResult: + variable: "HAS_MSVC_GL_LTCG" + cached: true + stdout: | + Change Dir: 'D:/cmvr/0-worksapce/cmvr-head-client/cpp/common/curve/build/CMakeFiles/CMakeScratch/TryCompile-n8t4hj' + + Run Build Command(s): C:/PROGRA~1/STM32/STM32C~1.0/Ninja/bin/ninja.exe -v cmTC_1814a + [1/2] C:\\PROGRA~1\\MIB055~1\\18\\COMMUN~1\\VC\\Tools\\MSVC\\1450~1.357\\bin\\Hostx64\\x64\\cl.exe /nologo /TP -DHAS_MSVC_GL_LTCG /DWIN32 /D_WINDOWS /EHsc /Zi /Ob0 /Od /RTC1 -MDd /GL /showIncludes /FoCMakeFiles\\cmTC_1814a.dir\\src.cxx.obj /FdCMakeFiles\\cmTC_1814a.dir\\ /FS -c D:\\cmvr\\0-worksapce\\cmvr-head-client\\cpp\\common\\curve\\build\\CMakeFiles\\CMakeScratch\\TryCompile-n8t4hj\\src.cxx + [2/2] C:\\windows\\system32\\cmd.exe /C "cd . && "C:\\Program Files\\STM32\\STM32CubeCLT_1.20.0\\CMake\\bin\\cmake.exe" -E vs_link_exe --intdir=CMakeFiles\\cmTC_1814a.dir --rc=C:\\PROGRA~2\\WINDOW~4\\10\\bin\\100261~1.0\\x64\\rc.exe --mt=C:\\PROGRA~2\\WINDOW~4\\10\\bin\\100261~1.0\\x64\\mt.exe --manifests -- C:\\PROGRA~1\\MIB055~1\\18\\COMMUN~1\\VC\\Tools\\MSVC\\1450~1.357\\bin\\Hostx64\\x64\\link.exe /nologo CMakeFiles\\cmTC_1814a.dir\\src.cxx.obj /out:cmTC_1814a.exe /implib:cmTC_1814a.lib /pdb:cmTC_1814a.pdb /version:0.0 /machine:x64 /debug /INCREMENTAL /subsystem:console -LTCG kernel32.lib user32.lib gdi32.lib winspool.lib shell32.lib ole32.lib oleaut32.lib uuid.lib comdlg32.lib advapi32.lib && cd ." + + exitCode: 0 +... diff --git a/cpp/common/curve/build/CMakeFiles/ShowIncludes/foo.h b/cpp/common/curve/build/CMakeFiles/ShowIncludes/foo.h new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/cpp/common/curve/build/CMakeFiles/ShowIncludes/foo.h @@ -0,0 +1 @@ + diff --git a/cpp/common/curve/build/CMakeFiles/ShowIncludes/main.c b/cpp/common/curve/build/CMakeFiles/ShowIncludes/main.c new file mode 100644 index 0000000..cd3cbc1 --- /dev/null +++ b/cpp/common/curve/build/CMakeFiles/ShowIncludes/main.c @@ -0,0 +1,2 @@ +#include "foo.h" +int main(){} diff --git a/cpp/common/curve/build/CMakeFiles/ShowIncludes/main.obj b/cpp/common/curve/build/CMakeFiles/ShowIncludes/main.obj new file mode 100644 index 0000000..8190791 Binary files /dev/null and b/cpp/common/curve/build/CMakeFiles/ShowIncludes/main.obj differ diff --git a/cpp/common/curve/build/CMakeFiles/TargetDirectories.txt b/cpp/common/curve/build/CMakeFiles/TargetDirectories.txt new file mode 100644 index 0000000..5b2506d --- /dev/null +++ b/cpp/common/curve/build/CMakeFiles/TargetDirectories.txt @@ -0,0 +1,3 @@ +D:/cmvr/0-worksapce/cmvr-head-client/cpp/common/curve/build/CMakeFiles/_s_curve_native.dir +D:/cmvr/0-worksapce/cmvr-head-client/cpp/common/curve/build/CMakeFiles/edit_cache.dir +D:/cmvr/0-worksapce/cmvr-head-client/cpp/common/curve/build/CMakeFiles/rebuild_cache.dir diff --git a/cpp/common/curve/build/CMakeFiles/_s_curve_native.dir/D_/cmvr/0-worksapce/cmvr-head-client/cpp/planner/s_curve_planner/src/s_curve_position_planner.cpp.obj b/cpp/common/curve/build/CMakeFiles/_s_curve_native.dir/D_/cmvr/0-worksapce/cmvr-head-client/cpp/planner/s_curve_planner/src/s_curve_position_planner.cpp.obj new file mode 100644 index 0000000..2bf6850 Binary files /dev/null and b/cpp/common/curve/build/CMakeFiles/_s_curve_native.dir/D_/cmvr/0-worksapce/cmvr-head-client/cpp/planner/s_curve_planner/src/s_curve_position_planner.cpp.obj differ diff --git a/cpp/common/curve/build/CMakeFiles/_s_curve_native.dir/D_/cmvr/0-worksapce/cmvr-head-client/cpp/planner/s_curve_planner/src/s_curve_velocity_planner.cpp.obj b/cpp/common/curve/build/CMakeFiles/_s_curve_native.dir/D_/cmvr/0-worksapce/cmvr-head-client/cpp/planner/s_curve_planner/src/s_curve_velocity_planner.cpp.obj new file mode 100644 index 0000000..2ea8384 Binary files /dev/null and b/cpp/common/curve/build/CMakeFiles/_s_curve_native.dir/D_/cmvr/0-worksapce/cmvr-head-client/cpp/planner/s_curve_planner/src/s_curve_velocity_planner.cpp.obj differ diff --git a/cpp/common/curve/build/CMakeFiles/_s_curve_native.dir/src/s_curve.cpp.obj b/cpp/common/curve/build/CMakeFiles/_s_curve_native.dir/src/s_curve.cpp.obj new file mode 100644 index 0000000..523d70a Binary files /dev/null and b/cpp/common/curve/build/CMakeFiles/_s_curve_native.dir/src/s_curve.cpp.obj differ diff --git a/cpp/common/curve/build/CMakeFiles/_s_curve_native.dir/src/s_curve_pybind.cpp.obj b/cpp/common/curve/build/CMakeFiles/_s_curve_native.dir/src/s_curve_pybind.cpp.obj new file mode 100644 index 0000000..30d8b67 Binary files /dev/null and b/cpp/common/curve/build/CMakeFiles/_s_curve_native.dir/src/s_curve_pybind.cpp.obj differ diff --git a/cpp/common/curve/build/CMakeFiles/cmake.check_cache b/cpp/common/curve/build/CMakeFiles/cmake.check_cache new file mode 100644 index 0000000..3dccd73 --- /dev/null +++ b/cpp/common/curve/build/CMakeFiles/cmake.check_cache @@ -0,0 +1 @@ +# This file is generated by cmake for dependency checking of the CMakeCache.txt file diff --git a/cpp/common/curve/build/CMakeFiles/cmvr_scurve.dir/src/s_curve.cpp.obj b/cpp/common/curve/build/CMakeFiles/cmvr_scurve.dir/src/s_curve.cpp.obj new file mode 100644 index 0000000..3a79d8a Binary files /dev/null and b/cpp/common/curve/build/CMakeFiles/cmvr_scurve.dir/src/s_curve.cpp.obj differ diff --git a/cpp/common/curve/build/CMakeFiles/cmvr_scurve.dir/src/s_curve_c_api.cpp.obj b/cpp/common/curve/build/CMakeFiles/cmvr_scurve.dir/src/s_curve_c_api.cpp.obj new file mode 100644 index 0000000..58fa279 Binary files /dev/null and b/cpp/common/curve/build/CMakeFiles/cmvr_scurve.dir/src/s_curve_c_api.cpp.obj differ diff --git a/cpp/common/curve/build/CMakeFiles/rules.ninja b/cpp/common/curve/build/CMakeFiles/rules.ninja new file mode 100644 index 0000000..b66dbc4 --- /dev/null +++ b/cpp/common/curve/build/CMakeFiles/rules.ninja @@ -0,0 +1,69 @@ +# CMAKE generated file: DO NOT EDIT! +# Generated by "Ninja" Generator, CMake Version 3.28 + +# This file contains all the rules used to get the outputs files +# built from the input files. +# It is included in the main 'build.ninja'. + +# ============================================================================= +# Project: cmvr_scurve +# Configurations: Release +# ============================================================================= +# ============================================================================= + +############################################# +# localized /showIncludes string + +msvc_deps_prefix = ע: ļ: + + +############################################# +# Rule for compiling CXX files. + +rule CXX_COMPILER___s_curve_native_unscanned_Release + deps = msvc + command = ${LAUNCHER}${CODE_CHECK}C:\PROGRA~1\MIB055~1\18\COMMUN~1\VC\Tools\MSVC\1450~1.357\bin\Hostx64\x64\cl.exe /nologo /TP $DEFINES $INCLUDES $FLAGS /showIncludes /Fo$out /Fd$TARGET_COMPILE_PDB /FS -c $in + description = Building CXX object $out + + +############################################# +# Rule for linking CXX shared module. + +rule CXX_MODULE_LIBRARY_LINKER___s_curve_native_Release + command = C:\windows\system32\cmd.exe /C "$PRE_LINK && "C:\Program Files\STM32\STM32CubeCLT_1.20.0\CMake\bin\cmake.exe" -E vs_link_dll --intdir=$OBJECT_DIR --rc=C:\PROGRA~2\WINDOW~4\10\bin\100261~1.0\x64\rc.exe --mt=C:\PROGRA~2\WINDOW~4\10\bin\100261~1.0\x64\mt.exe --manifests $MANIFESTS -- C:\PROGRA~1\MIB055~1\18\COMMUN~1\VC\Tools\MSVC\1450~1.357\bin\Hostx64\x64\link.exe /nologo $in /out:$TARGET_FILE /implib:$TARGET_IMPLIB /pdb:$TARGET_PDB /dll /version:0.0 $LINK_FLAGS $LINK_PATH $LINK_LIBRARIES && $POST_BUILD" + description = Linking CXX shared module $TARGET_FILE + restat = $RESTAT + + +############################################# +# Rule for running custom commands. + +rule CUSTOM_COMMAND + command = $COMMAND + description = $DESC + + +############################################# +# Rule for re-running cmake. + +rule RERUN_CMAKE + command = "C:\Program Files\STM32\STM32CubeCLT_1.20.0\CMake\bin\cmake.exe" --regenerate-during-build -SD:\cmvr\0-worksapce\cmvr-head-client\cpp\common\curve -BD:\cmvr\0-worksapce\cmvr-head-client\cpp\common\curve\build + description = Re-running CMake... + generator = 1 + + +############################################# +# Rule for cleaning all built files. + +rule CLEAN + command = C:\PROGRA~1\STM32\STM32C~1.0\Ninja\bin\ninja.exe $FILE_ARG -t clean $TARGETS + description = Cleaning all built files... + + +############################################# +# Rule for printing all primary targets available. + +rule HELP + command = C:\PROGRA~1\STM32\STM32C~1.0\Ninja\bin\ninja.exe -t targets + description = All primary targets available: + diff --git a/cpp/common/curve/build/_s_curve_native.cp310-win_amd64.pyd b/cpp/common/curve/build/_s_curve_native.cp310-win_amd64.pyd new file mode 100644 index 0000000..7094047 Binary files /dev/null and b/cpp/common/curve/build/_s_curve_native.cp310-win_amd64.pyd differ diff --git a/cpp/common/curve/build/_s_curve_native.exp b/cpp/common/curve/build/_s_curve_native.exp new file mode 100644 index 0000000..1da2e96 Binary files /dev/null and b/cpp/common/curve/build/_s_curve_native.exp differ diff --git a/cpp/common/curve/build/_s_curve_native.lib b/cpp/common/curve/build/_s_curve_native.lib new file mode 100644 index 0000000..17ece0d Binary files /dev/null and b/cpp/common/curve/build/_s_curve_native.lib differ diff --git a/cpp/common/curve/build/build.ninja b/cpp/common/curve/build/build.ninja new file mode 100644 index 0000000..ed54b25 --- /dev/null +++ b/cpp/common/curve/build/build.ninja @@ -0,0 +1,179 @@ +# CMAKE generated file: DO NOT EDIT! +# Generated by "Ninja" Generator, CMake Version 3.28 + +# This file contains all the build statements describing the +# compilation DAG. + +# ============================================================================= +# Write statements declared in CMakeLists.txt: +# +# Which is the root file. +# ============================================================================= + +# ============================================================================= +# Project: cmvr_scurve +# Configurations: Release +# ============================================================================= + +############################################# +# Minimal version of Ninja required by this file + +ninja_required_version = 1.5 + + +############################################# +# Set configuration variable for custom commands. + +CONFIGURATION = Release +# ============================================================================= +# Include auxiliary files. + + +############################################# +# Include rules file. + +include CMakeFiles\rules.ninja + +# ============================================================================= + +############################################# +# Logical path to working directory; prefix for absolute paths. + +cmake_ninja_workdir = D$:\cmvr\0-worksapce\cmvr-head-client\cpp\common\curve\build\ +# ============================================================================= +# Object build statements for MODULE_LIBRARY target _s_curve_native + + +############################################# +# Order-only phony target for _s_curve_native + +build cmake_object_order_depends_target__s_curve_native: phony || CMakeFiles\_s_curve_native.dir + +build CMakeFiles\_s_curve_native.dir\src\s_curve.cpp.obj: CXX_COMPILER___s_curve_native_unscanned_Release D$:\cmvr\0-worksapce\cmvr-head-client\cpp\common\curve\src\s_curve.cpp || cmake_object_order_depends_target__s_curve_native + DEFINES = -D_s_curve_native_EXPORTS + FLAGS = /DWIN32 /D_WINDOWS /EHsc /O2 /Ob2 /DNDEBUG -std:c++17 -MD /GL /bigobj /MP + INCLUDES = -ID:\cmvr\0-worksapce\cmvr-head-client\cpp\common\curve\..\.. -ID:\cmvr\0-worksapce\cmvr-head-client\cpp\common\curve\include -external:IC:\Users\Administrator\miniconda3\envs\cmvr-head-client\include -external:IC:\Users\Administrator\miniconda3\envs\cmvr-head-client\Lib\site-packages\pybind11\include -external:W0 + OBJECT_DIR = CMakeFiles\_s_curve_native.dir + OBJECT_FILE_DIR = CMakeFiles\_s_curve_native.dir\src + TARGET_COMPILE_PDB = CMakeFiles\_s_curve_native.dir\ + TARGET_PDB = _s_curve_native.pdb + +build CMakeFiles\_s_curve_native.dir\src\s_curve_pybind.cpp.obj: CXX_COMPILER___s_curve_native_unscanned_Release D$:\cmvr\0-worksapce\cmvr-head-client\cpp\common\curve\src\s_curve_pybind.cpp || cmake_object_order_depends_target__s_curve_native + DEFINES = -D_s_curve_native_EXPORTS + FLAGS = /DWIN32 /D_WINDOWS /EHsc /O2 /Ob2 /DNDEBUG -std:c++17 -MD /GL /bigobj /MP + INCLUDES = -ID:\cmvr\0-worksapce\cmvr-head-client\cpp\common\curve\..\.. -ID:\cmvr\0-worksapce\cmvr-head-client\cpp\common\curve\include -external:IC:\Users\Administrator\miniconda3\envs\cmvr-head-client\include -external:IC:\Users\Administrator\miniconda3\envs\cmvr-head-client\Lib\site-packages\pybind11\include -external:W0 + OBJECT_DIR = CMakeFiles\_s_curve_native.dir + OBJECT_FILE_DIR = CMakeFiles\_s_curve_native.dir\src + TARGET_COMPILE_PDB = CMakeFiles\_s_curve_native.dir\ + TARGET_PDB = _s_curve_native.pdb + +build CMakeFiles\_s_curve_native.dir\D_\cmvr\0-worksapce\cmvr-head-client\cpp\planner\s_curve_planner\src\s_curve_velocity_planner.cpp.obj: CXX_COMPILER___s_curve_native_unscanned_Release D$:\cmvr\0-worksapce\cmvr-head-client\cpp\planner\s_curve_planner\src\s_curve_velocity_planner.cpp || cmake_object_order_depends_target__s_curve_native + DEFINES = -D_s_curve_native_EXPORTS + FLAGS = /DWIN32 /D_WINDOWS /EHsc /O2 /Ob2 /DNDEBUG -std:c++17 -MD /GL /bigobj /MP + INCLUDES = -ID:\cmvr\0-worksapce\cmvr-head-client\cpp\common\curve\..\.. -ID:\cmvr\0-worksapce\cmvr-head-client\cpp\common\curve\include -external:IC:\Users\Administrator\miniconda3\envs\cmvr-head-client\include -external:IC:\Users\Administrator\miniconda3\envs\cmvr-head-client\Lib\site-packages\pybind11\include -external:W0 + OBJECT_DIR = CMakeFiles\_s_curve_native.dir + OBJECT_FILE_DIR = CMakeFiles\_s_curve_native.dir\D_\cmvr\0-worksapce\cmvr-head-client\cpp\planner\s_curve_planner\src + TARGET_COMPILE_PDB = CMakeFiles\_s_curve_native.dir\ + TARGET_PDB = _s_curve_native.pdb + +build CMakeFiles\_s_curve_native.dir\D_\cmvr\0-worksapce\cmvr-head-client\cpp\planner\s_curve_planner\src\s_curve_position_planner.cpp.obj: CXX_COMPILER___s_curve_native_unscanned_Release D$:\cmvr\0-worksapce\cmvr-head-client\cpp\planner\s_curve_planner\src\s_curve_position_planner.cpp || cmake_object_order_depends_target__s_curve_native + DEFINES = -D_s_curve_native_EXPORTS + FLAGS = /DWIN32 /D_WINDOWS /EHsc /O2 /Ob2 /DNDEBUG -std:c++17 -MD /GL /bigobj /MP + INCLUDES = -ID:\cmvr\0-worksapce\cmvr-head-client\cpp\common\curve\..\.. -ID:\cmvr\0-worksapce\cmvr-head-client\cpp\common\curve\include -external:IC:\Users\Administrator\miniconda3\envs\cmvr-head-client\include -external:IC:\Users\Administrator\miniconda3\envs\cmvr-head-client\Lib\site-packages\pybind11\include -external:W0 + OBJECT_DIR = CMakeFiles\_s_curve_native.dir + OBJECT_FILE_DIR = CMakeFiles\_s_curve_native.dir\D_\cmvr\0-worksapce\cmvr-head-client\cpp\planner\s_curve_planner\src + TARGET_COMPILE_PDB = CMakeFiles\_s_curve_native.dir\ + TARGET_PDB = _s_curve_native.pdb + + +# ============================================================================= +# Link build statements for MODULE_LIBRARY target _s_curve_native + + +############################################# +# Link the shared module _s_curve_native.cp310-win_amd64.pyd + +build _s_curve_native.cp310-win_amd64.pyd: CXX_MODULE_LIBRARY_LINKER___s_curve_native_Release CMakeFiles\_s_curve_native.dir\src\s_curve.cpp.obj CMakeFiles\_s_curve_native.dir\src\s_curve_pybind.cpp.obj CMakeFiles\_s_curve_native.dir\D_\cmvr\0-worksapce\cmvr-head-client\cpp\planner\s_curve_planner\src\s_curve_velocity_planner.cpp.obj CMakeFiles\_s_curve_native.dir\D_\cmvr\0-worksapce\cmvr-head-client\cpp\planner\s_curve_planner\src\s_curve_position_planner.cpp.obj | C$:\Users\Administrator\miniconda3\envs\cmvr-head-client\libs\python310.lib + LANGUAGE_COMPILE_FLAGS = /DWIN32 /D_WINDOWS /EHsc /O2 /Ob2 /DNDEBUG -MD + LINK_FLAGS = /machine:x64 /INCREMENTAL:NO -LTCG + LINK_LIBRARIES = C:\Users\Administrator\miniconda3\envs\cmvr-head-client\libs\python310.lib kernel32.lib user32.lib gdi32.lib winspool.lib shell32.lib ole32.lib oleaut32.lib uuid.lib comdlg32.lib advapi32.lib + OBJECT_DIR = CMakeFiles\_s_curve_native.dir + POST_BUILD = cd . + PRE_LINK = cd . + TARGET_COMPILE_PDB = CMakeFiles\_s_curve_native.dir\ + TARGET_FILE = _s_curve_native.cp310-win_amd64.pyd + TARGET_IMPLIB = _s_curve_native.lib + TARGET_PDB = _s_curve_native.pdb + + +############################################# +# Utility command for edit_cache + +build CMakeFiles\edit_cache.util: CUSTOM_COMMAND + COMMAND = C:\windows\system32\cmd.exe /C "cd /D D:\cmvr\0-worksapce\cmvr-head-client\cpp\common\curve\build && "C:\Program Files\STM32\STM32CubeCLT_1.20.0\CMake\bin\cmake-gui.exe" -SD:\cmvr\0-worksapce\cmvr-head-client\cpp\common\curve -BD:\cmvr\0-worksapce\cmvr-head-client\cpp\common\curve\build" + DESC = Running CMake cache editor... + pool = console + restat = 1 + +build edit_cache: phony CMakeFiles\edit_cache.util + + +############################################# +# Utility command for rebuild_cache + +build CMakeFiles\rebuild_cache.util: CUSTOM_COMMAND + COMMAND = C:\windows\system32\cmd.exe /C "cd /D D:\cmvr\0-worksapce\cmvr-head-client\cpp\common\curve\build && "C:\Program Files\STM32\STM32CubeCLT_1.20.0\CMake\bin\cmake.exe" --regenerate-during-build -SD:\cmvr\0-worksapce\cmvr-head-client\cpp\common\curve -BD:\cmvr\0-worksapce\cmvr-head-client\cpp\common\curve\build" + DESC = Running CMake to regenerate build system... + pool = console + restat = 1 + +build rebuild_cache: phony CMakeFiles\rebuild_cache.util + +# ============================================================================= +# Target aliases. + +build _s_curve_native: phony _s_curve_native.cp310-win_amd64.pyd + +# ============================================================================= +# Folder targets. + +# ============================================================================= + +############################################# +# Folder: D:/cmvr/0-worksapce/cmvr-head-client/cpp/common/curve/build + +build all: phony _s_curve_native.cp310-win_amd64.pyd + +# ============================================================================= +# Built-in targets + + +############################################# +# Re-run CMake if any of its inputs changed. + +build build.ninja: RERUN_CMAKE | C$:\Program$ Files\STM32\STM32CubeCLT_1.20.0\CMake\share\cmake-3.28\Modules\CMakeCXXInformation.cmake C$:\Program$ Files\STM32\STM32CubeCLT_1.20.0\CMake\share\cmake-3.28\Modules\CMakeCheckCompilerFlagCommonPatterns.cmake C$:\Program$ Files\STM32\STM32CubeCLT_1.20.0\CMake\share\cmake-3.28\Modules\CMakeCommonLanguageInclude.cmake C$:\Program$ Files\STM32\STM32CubeCLT_1.20.0\CMake\share\cmake-3.28\Modules\CMakeGenericSystem.cmake C$:\Program$ Files\STM32\STM32CubeCLT_1.20.0\CMake\share\cmake-3.28\Modules\CMakeInitializeConfigs.cmake C$:\Program$ Files\STM32\STM32CubeCLT_1.20.0\CMake\share\cmake-3.28\Modules\CMakeLanguageInformation.cmake C$:\Program$ Files\STM32\STM32CubeCLT_1.20.0\CMake\share\cmake-3.28\Modules\CMakeRCInformation.cmake C$:\Program$ Files\STM32\STM32CubeCLT_1.20.0\CMake\share\cmake-3.28\Modules\CMakeSystemSpecificInformation.cmake C$:\Program$ Files\STM32\STM32CubeCLT_1.20.0\CMake\share\cmake-3.28\Modules\CMakeSystemSpecificInitialize.cmake C$:\Program$ Files\STM32\STM32CubeCLT_1.20.0\CMake\share\cmake-3.28\Modules\CheckCXXCompilerFlag.cmake C$:\Program$ Files\STM32\STM32CubeCLT_1.20.0\CMake\share\cmake-3.28\Modules\CheckCXXSourceCompiles.cmake C$:\Program$ Files\STM32\STM32CubeCLT_1.20.0\CMake\share\cmake-3.28\Modules\Compiler\CMakeCommonCompilerMacros.cmake C$:\Program$ Files\STM32\STM32CubeCLT_1.20.0\CMake\share\cmake-3.28\Modules\Compiler\MSVC-CXX.cmake C$:\Program$ Files\STM32\STM32CubeCLT_1.20.0\CMake\share\cmake-3.28\Modules\Compiler\MSVC.cmake C$:\Program$ Files\STM32\STM32CubeCLT_1.20.0\CMake\share\cmake-3.28\Modules\FindPackageHandleStandardArgs.cmake C$:\Program$ Files\STM32\STM32CubeCLT_1.20.0\CMake\share\cmake-3.28\Modules\FindPackageMessage.cmake C$:\Program$ Files\STM32\STM32CubeCLT_1.20.0\CMake\share\cmake-3.28\Modules\FindPython.cmake C$:\Program$ Files\STM32\STM32CubeCLT_1.20.0\CMake\share\cmake-3.28\Modules\FindPython\Support.cmake C$:\Program$ Files\STM32\STM32CubeCLT_1.20.0\CMake\share\cmake-3.28\Modules\Internal\CheckCompilerFlag.cmake C$:\Program$ Files\STM32\STM32CubeCLT_1.20.0\CMake\share\cmake-3.28\Modules\Internal\CheckFlagCommonConfig.cmake C$:\Program$ Files\STM32\STM32CubeCLT_1.20.0\CMake\share\cmake-3.28\Modules\Internal\CheckSourceCompiles.cmake C$:\Program$ Files\STM32\STM32CubeCLT_1.20.0\CMake\share\cmake-3.28\Modules\Platform\Windows-Initialize.cmake C$:\Program$ Files\STM32\STM32CubeCLT_1.20.0\CMake\share\cmake-3.28\Modules\Platform\Windows-MSVC-CXX.cmake C$:\Program$ Files\STM32\STM32CubeCLT_1.20.0\CMake\share\cmake-3.28\Modules\Platform\Windows-MSVC.cmake C$:\Program$ Files\STM32\STM32CubeCLT_1.20.0\CMake\share\cmake-3.28\Modules\Platform\Windows.cmake C$:\Program$ Files\STM32\STM32CubeCLT_1.20.0\CMake\share\cmake-3.28\Modules\Platform\WindowsPaths.cmake C$:\Users\Administrator\miniconda3\envs\cmvr-head-client\Lib\site-packages\pybind11\share\cmake\pybind11\pybind11Common.cmake C$:\Users\Administrator\miniconda3\envs\cmvr-head-client\Lib\site-packages\pybind11\share\cmake\pybind11\pybind11Config.cmake C$:\Users\Administrator\miniconda3\envs\cmvr-head-client\Lib\site-packages\pybind11\share\cmake\pybind11\pybind11ConfigVersion.cmake C$:\Users\Administrator\miniconda3\envs\cmvr-head-client\Lib\site-packages\pybind11\share\cmake\pybind11\pybind11NewTools.cmake C$:\Users\Administrator\miniconda3\envs\cmvr-head-client\Lib\site-packages\pybind11\share\cmake\pybind11\pybind11Targets.cmake CMakeCache.txt CMakeFiles\3.28.1\CMakeCXXCompiler.cmake CMakeFiles\3.28.1\CMakeRCCompiler.cmake CMakeFiles\3.28.1\CMakeSystem.cmake D$:\cmvr\0-worksapce\cmvr-head-client\cpp\common\curve\CMakeLists.txt + pool = console + + +############################################# +# A missing CMake input file is not an error. + +build C$:\Program$ Files\STM32\STM32CubeCLT_1.20.0\CMake\share\cmake-3.28\Modules\CMakeCXXInformation.cmake C$:\Program$ Files\STM32\STM32CubeCLT_1.20.0\CMake\share\cmake-3.28\Modules\CMakeCheckCompilerFlagCommonPatterns.cmake C$:\Program$ Files\STM32\STM32CubeCLT_1.20.0\CMake\share\cmake-3.28\Modules\CMakeCommonLanguageInclude.cmake C$:\Program$ Files\STM32\STM32CubeCLT_1.20.0\CMake\share\cmake-3.28\Modules\CMakeGenericSystem.cmake C$:\Program$ Files\STM32\STM32CubeCLT_1.20.0\CMake\share\cmake-3.28\Modules\CMakeInitializeConfigs.cmake C$:\Program$ Files\STM32\STM32CubeCLT_1.20.0\CMake\share\cmake-3.28\Modules\CMakeLanguageInformation.cmake C$:\Program$ Files\STM32\STM32CubeCLT_1.20.0\CMake\share\cmake-3.28\Modules\CMakeRCInformation.cmake C$:\Program$ Files\STM32\STM32CubeCLT_1.20.0\CMake\share\cmake-3.28\Modules\CMakeSystemSpecificInformation.cmake C$:\Program$ Files\STM32\STM32CubeCLT_1.20.0\CMake\share\cmake-3.28\Modules\CMakeSystemSpecificInitialize.cmake C$:\Program$ Files\STM32\STM32CubeCLT_1.20.0\CMake\share\cmake-3.28\Modules\CheckCXXCompilerFlag.cmake C$:\Program$ Files\STM32\STM32CubeCLT_1.20.0\CMake\share\cmake-3.28\Modules\CheckCXXSourceCompiles.cmake C$:\Program$ Files\STM32\STM32CubeCLT_1.20.0\CMake\share\cmake-3.28\Modules\Compiler\CMakeCommonCompilerMacros.cmake C$:\Program$ Files\STM32\STM32CubeCLT_1.20.0\CMake\share\cmake-3.28\Modules\Compiler\MSVC-CXX.cmake C$:\Program$ Files\STM32\STM32CubeCLT_1.20.0\CMake\share\cmake-3.28\Modules\Compiler\MSVC.cmake C$:\Program$ Files\STM32\STM32CubeCLT_1.20.0\CMake\share\cmake-3.28\Modules\FindPackageHandleStandardArgs.cmake C$:\Program$ Files\STM32\STM32CubeCLT_1.20.0\CMake\share\cmake-3.28\Modules\FindPackageMessage.cmake C$:\Program$ Files\STM32\STM32CubeCLT_1.20.0\CMake\share\cmake-3.28\Modules\FindPython.cmake C$:\Program$ Files\STM32\STM32CubeCLT_1.20.0\CMake\share\cmake-3.28\Modules\FindPython\Support.cmake C$:\Program$ Files\STM32\STM32CubeCLT_1.20.0\CMake\share\cmake-3.28\Modules\Internal\CheckCompilerFlag.cmake C$:\Program$ Files\STM32\STM32CubeCLT_1.20.0\CMake\share\cmake-3.28\Modules\Internal\CheckFlagCommonConfig.cmake C$:\Program$ Files\STM32\STM32CubeCLT_1.20.0\CMake\share\cmake-3.28\Modules\Internal\CheckSourceCompiles.cmake C$:\Program$ Files\STM32\STM32CubeCLT_1.20.0\CMake\share\cmake-3.28\Modules\Platform\Windows-Initialize.cmake C$:\Program$ Files\STM32\STM32CubeCLT_1.20.0\CMake\share\cmake-3.28\Modules\Platform\Windows-MSVC-CXX.cmake C$:\Program$ Files\STM32\STM32CubeCLT_1.20.0\CMake\share\cmake-3.28\Modules\Platform\Windows-MSVC.cmake C$:\Program$ Files\STM32\STM32CubeCLT_1.20.0\CMake\share\cmake-3.28\Modules\Platform\Windows.cmake C$:\Program$ Files\STM32\STM32CubeCLT_1.20.0\CMake\share\cmake-3.28\Modules\Platform\WindowsPaths.cmake C$:\Users\Administrator\miniconda3\envs\cmvr-head-client\Lib\site-packages\pybind11\share\cmake\pybind11\pybind11Common.cmake C$:\Users\Administrator\miniconda3\envs\cmvr-head-client\Lib\site-packages\pybind11\share\cmake\pybind11\pybind11Config.cmake C$:\Users\Administrator\miniconda3\envs\cmvr-head-client\Lib\site-packages\pybind11\share\cmake\pybind11\pybind11ConfigVersion.cmake C$:\Users\Administrator\miniconda3\envs\cmvr-head-client\Lib\site-packages\pybind11\share\cmake\pybind11\pybind11NewTools.cmake C$:\Users\Administrator\miniconda3\envs\cmvr-head-client\Lib\site-packages\pybind11\share\cmake\pybind11\pybind11Targets.cmake CMakeCache.txt CMakeFiles\3.28.1\CMakeCXXCompiler.cmake CMakeFiles\3.28.1\CMakeRCCompiler.cmake CMakeFiles\3.28.1\CMakeSystem.cmake D$:\cmvr\0-worksapce\cmvr-head-client\cpp\common\curve\CMakeLists.txt: phony + + +############################################# +# Clean all the built files. + +build clean: CLEAN + + +############################################# +# Print all primary targets available. + +build help: HELP + + +############################################# +# Make the all target the default. + +default all diff --git a/cpp/common/curve/build/cmake_install.cmake b/cpp/common/curve/build/cmake_install.cmake new file mode 100644 index 0000000..db77ade --- /dev/null +++ b/cpp/common/curve/build/cmake_install.cmake @@ -0,0 +1,44 @@ +# Install script for directory: D:/cmvr/0-worksapce/cmvr-head-client/cpp/common/curve + +# Set the install prefix +if(NOT DEFINED CMAKE_INSTALL_PREFIX) + set(CMAKE_INSTALL_PREFIX "C:/Program Files (x86)/cmvr_scurve") +endif() +string(REGEX REPLACE "/$" "" CMAKE_INSTALL_PREFIX "${CMAKE_INSTALL_PREFIX}") + +# Set the install configuration name. +if(NOT DEFINED CMAKE_INSTALL_CONFIG_NAME) + if(BUILD_TYPE) + string(REGEX REPLACE "^[^A-Za-z0-9_]+" "" + CMAKE_INSTALL_CONFIG_NAME "${BUILD_TYPE}") + else() + set(CMAKE_INSTALL_CONFIG_NAME "Release") + endif() + message(STATUS "Install configuration: \"${CMAKE_INSTALL_CONFIG_NAME}\"") +endif() + +# Set the component getting installed. +if(NOT CMAKE_INSTALL_COMPONENT) + if(COMPONENT) + message(STATUS "Install component: \"${COMPONENT}\"") + set(CMAKE_INSTALL_COMPONENT "${COMPONENT}") + else() + set(CMAKE_INSTALL_COMPONENT) + endif() +endif() + +# Is this installation the result of a crosscompile? +if(NOT DEFINED CMAKE_CROSSCOMPILING) + set(CMAKE_CROSSCOMPILING "FALSE") +endif() + +if(CMAKE_INSTALL_COMPONENT) + set(CMAKE_INSTALL_MANIFEST "install_manifest_${CMAKE_INSTALL_COMPONENT}.txt") +else() + set(CMAKE_INSTALL_MANIFEST "install_manifest.txt") +endif() + +string(REPLACE ";" "\n" CMAKE_INSTALL_MANIFEST_CONTENT + "${CMAKE_INSTALL_MANIFEST_FILES}") +file(WRITE "D:/cmvr/0-worksapce/cmvr-head-client/cpp/common/curve/build/${CMAKE_INSTALL_MANIFEST}" + "${CMAKE_INSTALL_MANIFEST_CONTENT}") diff --git a/cpp/common/curve/build/cmvr_scurve.dll b/cpp/common/curve/build/cmvr_scurve.dll new file mode 100644 index 0000000..f9dea4b Binary files /dev/null and b/cpp/common/curve/build/cmvr_scurve.dll differ diff --git a/cpp/common/curve/build/cmvr_scurve.exp b/cpp/common/curve/build/cmvr_scurve.exp new file mode 100644 index 0000000..1830951 Binary files /dev/null and b/cpp/common/curve/build/cmvr_scurve.exp differ diff --git a/cpp/common/curve/build/cmvr_scurve.lib b/cpp/common/curve/build/cmvr_scurve.lib new file mode 100644 index 0000000..ffbe99e Binary files /dev/null and b/cpp/common/curve/build/cmvr_scurve.lib differ diff --git a/cpp/common/curve/build_python.ps1 b/cpp/common/curve/build_python.ps1 new file mode 100644 index 0000000..f10998f --- /dev/null +++ b/cpp/common/curve/build_python.ps1 @@ -0,0 +1,35 @@ +param( + [string]$PythonExecutable = "C:\Users\Administrator\miniconda3\envs\cmvr-head-client\python.exe" +) + +$ErrorActionPreference = "Stop" + +$repoRoot = Resolve-Path (Join-Path $PSScriptRoot "..\\..\\..") +$sourceDir = Join-Path $repoRoot "cpp\\common\\curve" +$buildDir = Join-Path $sourceDir "build" +$vsDevCmd = "C:\\Program Files\\Microsoft Visual Studio\\18\\Community\\Common7\\Tools\\VsDevCmd.bat" + +if (-not (Test-Path $vsDevCmd)) { + throw "VsDevCmd.bat not found at $vsDevCmd" +} + +if (-not (Test-Path $PythonExecutable)) { + throw "Python executable not found at $PythonExecutable" +} + +New-Item -ItemType Directory -Force -Path $buildDir | Out-Null + +$configure = "call `"$vsDevCmd`" -arch=x64 && cmake -S `"$sourceDir`" -B `"$buildDir`" -G Ninja -DCMAKE_BUILD_TYPE=Release -DPython_EXECUTABLE=`"$PythonExecutable`"" +cmd /c $configure +if ($LASTEXITCODE -ne 0) { + throw "CMake configure failed." +} + +$build = "call `"$vsDevCmd`" -arch=x64 && cmake --build `"$buildDir`" --config Release" +cmd /c $build +if ($LASTEXITCODE -ne 0) { + throw "CMake build failed." +} + +Write-Host "Built Python module:" +Get-ChildItem $buildDir -Filter "_s_curve_native*.pyd" -Recurse | Select-Object FullName diff --git a/cpp/common/curve/include/s_curve.h b/cpp/common/curve/include/s_curve.h new file mode 100644 index 0000000..3c8a980 --- /dev/null +++ b/cpp/common/curve/include/s_curve.h @@ -0,0 +1,167 @@ +// +// Created by lgv on 2026/3/2. +// +/** + * @file s_curve.h + * @brief 严格点到点位置 S 曲线轨迹生成器 + * + * 实现标准 7 段式位置 S 曲线速度剖面: + * 1. 加加速度上升段(加速度逐渐增大) + * 2. 匀加速段 + * 3. 加加速度下降段(加速度逐渐降到 0) + * 4. 匀速巡航段 + * 5. 加加速度下降段(减速度逐渐增大) + * 6. 匀减速段 + * 7. 加加速度上升段(减速度逐渐降到 0) + * + * 本类只负责严格点到点 profile 规划与采样,不负责实时目标跟踪。 + */ + +#pragma once + +#include +#include +#include + + +namespace cmvr +{ + +/** + * @brief 单次点到点运动的 S 曲线剖面参数 + */ +struct SCurveProfile +{ + // 7 个阶段的持续时间 + double t1; // 加加速度上升时间(加速阶段) + double t2; // 匀加速时间 + double t3; // 加加速度下降时间(加速阶段结束) + double t4; // 匀速时间(巡航) + double t5; // 加加速度下降时间(减速阶段) + double t6; // 匀减速时间 + double t7; // 加加速度上升时间(减速阶段结束) + + double total_time; + + // 运动约束 + double j_max; // 最大加加速度 (rad/s³) + double a_max; // 最大加速度 (rad/s²) + double v_max; // 最大速度 (rad/s) + + // 运动参数 + double distance; // 运动总距离 + double direction; // +1 或 -1 + double v_cruise; // 实际达到的巡航速度 + double a_limit; // 实际达到的加速度上限 + + // 初始条件 + double p0; // 初始位置 + double v0; // 初始速度 + double a0; // 初始加速度 + double vf; // 终止速度 + + SCurveProfile() + : t1(0), t2(0), t3(0), t4(0), t5(0), t6(0), t7(0) + , total_time(0) + , j_max(50.0), a_max(10.0), v_max(3.0) + , distance(0), direction(1.0), v_cruise(0), a_limit(0) + , p0(0), v0(0), a0(0), vf(0) + {} +}; + +/** + * @brief 严格点到点位置 S 曲线规划器 + */ +class SCurve +{ +public: + /** + * @brief 构造函数(带运动约束) + * @param max_velocity 最大速度 (rad/s) + * @param max_acceleration 最大加速度 (rad/s²) + * @param max_jerk 最大加加速度 (rad/s³) + */ + SCurve(double max_velocity = 3.0, + double max_acceleration = 10.0, + double max_jerk = 50.0); + + /** + * @brief 设置运动约束 + */ + void setConstraints(double max_velocity, double max_acceleration, double max_jerk); + + /** + * @brief 获取当前运动约束 + */ + void getConstraints(double& max_velocity, double& max_acceleration, double& max_jerk) const; + + /** + * @brief 计算点到点运动的完整 S 曲线剖面 + * @param start_position 起始位置 + * @param end_position 终止位置 + * @param start_velocity 起始速度(默认 0) + * @param end_velocity 终止速度(默认 0) + * @return 计算得到的剖面参数 + */ + SCurveProfile calculateProfile(double start_position, double end_position, + double start_velocity = 0.0, double end_velocity = 0.0); + + /** + * @brief 给定剖面下,获取时刻 t 的位置 + * @param profile S 曲线剖面 + * @param t 从起点开始的时间 + * @return 时刻 t 的位置 + */ + double getPositionAtTime(const SCurveProfile& profile, double t) const; + + /** + * @brief 给定剖面下,获取时刻 t 的速度 + * @param profile S 曲线剖面 + * @param t 从起点开始的时间 + * @return 时刻 t 的速度 + */ + double getVelocityAtTime(const SCurveProfile& profile, double t) const; + + /** + * @brief 给定剖面下,获取时刻 t 的加速度 + * @param profile S 曲线剖面 + * @param t 从起点开始的时间 + * @return 时刻 t 的加速度 + */ + double getAccelerationAtTime(const SCurveProfile& profile, double t) const; + + /** + * @brief 给定剖面下,获取时刻 t 的加加速度 + * @param profile S 曲线剖面 + * @param t 从起点开始的时间 + * @return 时刻 t 的加加速度 + */ + double getJerkAtTime(const SCurveProfile& profile, double t) const; + + /** + * @brief 按固定时间间隔生成轨迹点 + * @param profile S 曲线剖面 + * @param dt 轨迹点时间间隔 + * @param positions 输出:每个时间点的位置 + * @param velocities 输出:每个时间点的速度 + * @param accelerations 输出:每个时间点的加速度 + */ + void generateTrajectory(const SCurveProfile& profile, double dt, + std::vector& positions, + std::vector& velocities, + std::vector& accelerations) const; + +private: + double max_velocity_; + double max_acceleration_; + double max_jerk_; + + static constexpr double EPSILON = 1e-9; + static constexpr double VELOCITY_THRESHOLD = 1e-6; + + double computeSegmentJerk(const SCurveProfile& profile, double t) const; + void calculateShortProfile(SCurveProfile& profile) const; + void calculateLongProfile(SCurveProfile& profile) const; +}; + +} // namespace cmvr diff --git a/cpp/common/curve/src/s_curve.cpp b/cpp/common/curve/src/s_curve.cpp new file mode 100644 index 0000000..e5025cc --- /dev/null +++ b/cpp/common/curve/src/s_curve.cpp @@ -0,0 +1,542 @@ +// +// Created by lgv on 2026/3/2. +// + + +/** + * @file s_curve_generator.cpp + * @brief S 曲线轨迹生成器实现 + */ + +#include "common/curve/include/s_curve.h" +#include +#include +#include + +namespace cmvr +{ +SCurve::SCurve(double max_velocity, double max_acceleration, double max_jerk) + : max_velocity_(std::abs(max_velocity)) + , max_acceleration_(std::abs(max_acceleration)) + , max_jerk_(std::abs(max_jerk)) +{} + +void SCurve::setConstraints(double max_velocity, double max_acceleration, double max_jerk) +{ + max_velocity_ = std::abs(max_velocity); + max_acceleration_ = std::abs(max_acceleration); + max_jerk_ = std::abs(max_jerk); +} + +void SCurve::getConstraints(double& max_velocity, double& max_acceleration, double& max_jerk) const +{ + max_velocity = max_velocity_; + max_acceleration = max_acceleration_; + max_jerk = max_jerk_; +} + +SCurveProfile SCurve::calculateProfile(double start_position, double end_position, + double start_velocity, double end_velocity) +{ + SCurveProfile profile; + profile.j_max = max_jerk_; + profile.a_max = max_acceleration_; + profile.v_max = max_velocity_; + profile.p0 = start_position; + profile.v0 = start_velocity; + profile.a0 = 0.0; // Assume starting from zero acceleration + profile.vf = end_velocity; + + double displacement = end_position - start_position; + profile.distance = std::abs(displacement); + profile.direction = (displacement >= 0) ? 1.0 : -1.0; + + if (profile.distance < EPSILON) { + // 无需运动 + profile.total_time = 0.0; + return profile; + } + + const double start_speed = profile.direction * start_velocity; + const double end_speed = profile.direction * end_velocity; + if (start_speed < -VELOCITY_THRESHOLD || end_speed < -VELOCITY_THRESHOLD) { + profile.total_time = 0.0; + return profile; + } + + if (std::abs(start_speed) > VELOCITY_THRESHOLD || + std::abs(end_speed) > VELOCITY_THRESHOLD) { + auto calc_transition = [&](double v_from, double v_to, + double& t_j, double& t_a, + double& duration, double& distance) { + t_j = 0.0; + t_a = 0.0; + duration = 0.0; + distance = 0.0; + + const double dv = std::abs(v_to - v_from); + if (dv <= 1e-12 || profile.a_max <= 1e-12 || profile.j_max <= 1e-12) { + return; + } + + const double dv_switch = profile.a_max * profile.a_max / profile.j_max; + if (dv < dv_switch) { + t_j = std::sqrt(dv / profile.j_max); + t_a = 0.0; + } else { + t_j = profile.a_max / profile.j_max; + t_a = dv / profile.a_max - t_j; + } + + duration = 2.0 * t_j + t_a; + distance = 0.5 * (v_from + v_to) * duration; + }; + + const double v_cap = std::max({profile.v_max, start_speed, end_speed}); + const double v_peak_min = std::max(start_speed, end_speed); + + double acc_tj = 0.0, acc_ta = 0.0, acc_duration = 0.0, acc_distance = 0.0; + double dec_tj = 0.0, dec_ta = 0.0, dec_duration = 0.0, dec_distance = 0.0; + calc_transition(start_speed, v_peak_min, + acc_tj, acc_ta, acc_duration, acc_distance); + calc_transition(v_peak_min, end_speed, + dec_tj, dec_ta, dec_duration, dec_distance); + const double d_min = acc_distance + dec_distance; + if (profile.distance + EPSILON < d_min) { + profile.total_time = 0.0; + return profile; + } + + calc_transition(start_speed, v_cap, + acc_tj, acc_ta, acc_duration, acc_distance); + calc_transition(v_cap, end_speed, + dec_tj, dec_ta, dec_duration, dec_distance); + const double d_cap = acc_distance + dec_distance; + + double v_peak = v_cap; + double t4 = 0.0; + + if (profile.distance > d_cap + EPSILON) { + t4 = (profile.distance - d_cap) / std::max(v_peak, EPSILON); + } else { + double lo = v_peak_min; + double hi = v_cap; + for (int iter = 0; iter < 80; ++iter) { + const double mid = 0.5 * (lo + hi); + double mid_acc_tj = 0.0, mid_acc_ta = 0.0, mid_acc_duration = 0.0, mid_acc_distance = 0.0; + double mid_dec_tj = 0.0, mid_dec_ta = 0.0, mid_dec_duration = 0.0, mid_dec_distance = 0.0; + calc_transition(start_speed, mid, + mid_acc_tj, mid_acc_ta, mid_acc_duration, mid_acc_distance); + calc_transition(mid, end_speed, + mid_dec_tj, mid_dec_ta, mid_dec_duration, mid_dec_distance); + const double d_mid = mid_acc_distance + mid_dec_distance; + if (d_mid < profile.distance) { + lo = mid; + } else { + hi = mid; + } + } + v_peak = hi; + calc_transition(start_speed, v_peak, + acc_tj, acc_ta, acc_duration, acc_distance); + calc_transition(v_peak, end_speed, + dec_tj, dec_ta, dec_duration, dec_distance); + } + + profile.t1 = acc_tj; + profile.t2 = acc_ta; + profile.t3 = acc_tj; + profile.t4 = t4; + profile.t5 = dec_tj; + profile.t6 = dec_ta; + profile.t7 = dec_tj; + profile.v_cruise = v_peak; + profile.a_limit = std::max(profile.j_max * profile.t1, profile.j_max * profile.t5); + profile.total_time = profile.t1 + profile.t2 + profile.t3 + profile.t4 + + profile.t5 + profile.t6 + profile.t7; + return profile; + } + + const double j = profile.j_max; + const double a = profile.a_max; + const double v = profile.v_max; + const double t_j_a = a / j; + + if (v < a * t_j_a) { + const double t_j_v = std::sqrt(v / j); + const double s_min = 2.0 * j * t_j_v * t_j_v * t_j_v; + if (profile.distance > s_min + EPSILON) { + calculateLongProfile(profile); + } else { + calculateShortProfile(profile); + } + } else { + const double t_a_v = v / a - t_j_a; + const double s_half_v = + a * (t_j_a * t_j_a + 1.5 * t_j_a * t_a_v + 0.5 * t_a_v * t_a_v); + const double s_min = 2.0 * s_half_v; + if (profile.distance > s_min + EPSILON) { + calculateLongProfile(profile); + } else { + calculateShortProfile(profile); + } + } + + return profile; +} + +void SCurve::calculateShortProfile(SCurveProfile& profile) const +{ + // 短距离:无巡航段(t4 = 0),与 moveL_SCurveLocal 中的 SCurveProfile1D 保持一致。 + const double j = profile.j_max; + const double a = profile.a_max; + const double v = profile.v_max; + const double d = profile.distance; + const double t_j_a = a / j; + + if (v < a * t_j_a) { + // 达不到 a_max:极短距离时只有 4 个 jerk 段。 + const double t1 = std::cbrt(d / (2.0 * j)); + profile.t1 = t1; + profile.t2 = 0.0; + profile.t3 = t1; + profile.t4 = 0.0; + profile.t5 = t1; + profile.t6 = 0.0; + profile.t7 = t1; + profile.v_cruise = j * t1 * t1; + profile.a_limit = j * t1; + } else { + // 能达到 a_max,但达不到 v_max:求无巡航的匀加速持续时间。 + const double D = t_j_a * t_j_a + 4.0 * (d / a); + double t2 = (-3.0 * t_j_a + std::sqrt(std::max(0.0, D))) * 0.5; + + if (t2 < 0.0) { + const double t1 = std::cbrt(d / (2.0 * j)); + profile.t1 = t1; + profile.t2 = 0.0; + profile.t3 = t1; + profile.t4 = 0.0; + profile.t5 = t1; + profile.t6 = 0.0; + profile.t7 = t1; + profile.v_cruise = j * t1 * t1; + profile.a_limit = j * t1; + } else { + profile.t1 = t_j_a; + profile.t2 = t2; + profile.t3 = t_j_a; + profile.t4 = 0.0; + profile.t5 = t_j_a; + profile.t6 = t2; + profile.t7 = t_j_a; + profile.v_cruise = a * (t2 + t_j_a); + profile.a_limit = a; + } + } + + profile.total_time = profile.t1 + profile.t2 + profile.t3 + profile.t4 + + profile.t5 + profile.t6 + profile.t7; +} + +void SCurve::calculateLongProfile(SCurveProfile& profile) const +{ + // 含巡航段的完整 7 段式 S 曲线;与 SCurveProfile1D 的 full-profile 公式一致。 + const double j = profile.j_max; + const double a = profile.a_max; + const double v = profile.v_max; + const double d = profile.distance; + const double t_j_a = a / j; + + if (v < a * t_j_a) { + // 达不到 a_max,但可以达到 v_max 并进入巡航。 + const double t_j_v = std::sqrt(v / j); + const double s_min = 2.0 * j * t_j_v * t_j_v * t_j_v; + profile.t1 = t_j_v; + profile.t2 = 0.0; + profile.t3 = t_j_v; + profile.t4 = std::max(0.0, (d - s_min) / v); + profile.t5 = t_j_v; + profile.t6 = 0.0; + profile.t7 = t_j_v; + profile.v_cruise = v; + profile.a_limit = j * t_j_v; + } else { + // 能达到 a_max 和 v_max。 + const double t_a = v / a - t_j_a; + const double s_half = + a * (t_j_a * t_j_a + 1.5 * t_j_a * t_a + 0.5 * t_a * t_a); + const double s_min = 2.0 * s_half; + + profile.t1 = t_j_a; + profile.t2 = t_a; + profile.t3 = t_j_a; + profile.t4 = std::max(0.0, (d - s_min) / v); + profile.t5 = t_j_a; + profile.t6 = t_a; + profile.t7 = t_j_a; + profile.v_cruise = v; + profile.a_limit = a; + } + + profile.total_time = profile.t1 + profile.t2 + profile.t3 + profile.t4 + + profile.t5 + profile.t6 + profile.t7; +} + +double SCurve::computeSegmentJerk(const SCurveProfile& profile, double t) const +{ + double j = profile.j_max * profile.direction; + + // 判断所处阶段 + double t_end1 = profile.t1; + double t_end2 = t_end1 + profile.t2; + double t_end3 = t_end2 + profile.t3; + double t_end4 = t_end3 + profile.t4; + double t_end5 = t_end4 + profile.t5; + double t_end6 = t_end5 + profile.t6; + // double t_end7 = t_end6 + profile.t7; // = total_time + + if (t < t_end1) { + return j; // 段 1:正加加速度(加速) + } else if (t < t_end2) { + return 0.0; // 段 2:加加速度为 0(匀加速) + } else if (t < t_end3) { + return -j; // 段 3:负加加速度(减小加速度) + } else if (t < t_end4) { + return 0.0; // 段 4:加加速度为 0(巡航) + } else if (t < t_end5) { + return -j; // 段 5:负加加速度(开始减速) + } else if (t < t_end6) { + return 0.0; // 段 6:加加速度为 0(匀减速) + } else { + return j; // 段 7:正加加速度(减速结束) + } +} + +double SCurve::getPositionAtTime(const SCurveProfile& profile, double t) const +{ + if (t <= 0) return profile.p0; + if (t >= profile.total_time) return profile.p0 + profile.distance * profile.direction; + + double j = profile.j_max * profile.direction; + double p = profile.p0; + double v = profile.v0; + double a = profile.a0; + + // 时间边界 + double t_end1 = profile.t1; + double t_end2 = t_end1 + profile.t2; + double t_end3 = t_end2 + profile.t3; + double t_end4 = t_end3 + profile.t4; + double t_end5 = t_end4 + profile.t5; + double t_end6 = t_end5 + profile.t6; + + // 依次处理各阶段 + auto processSegment = [&](double dt, double jerk) { + p += v * dt + 0.5 * a * dt * dt + (1.0/6.0) * jerk * dt * dt * dt; + v += a * dt + 0.5 * jerk * dt * dt; + a += jerk * dt; + }; + + // 段 1 + if (t <= t_end1) { + processSegment(t, j); + return p; + } + processSegment(profile.t1, j); + + // 段 2 + if (t <= t_end2) { + processSegment(t - t_end1, 0.0); + return p; + } + processSegment(profile.t2, 0.0); + + // 段 3 + if (t <= t_end3) { + processSegment(t - t_end2, -j); + return p; + } + processSegment(profile.t3, -j); + + // 段 4(巡航) + if (t <= t_end4) { + processSegment(t - t_end3, 0.0); + return p; + } + processSegment(profile.t4, 0.0); + + // 段 5 + if (t <= t_end5) { + processSegment(t - t_end4, -j); + return p; + } + processSegment(profile.t5, -j); + + // 段 6 + if (t <= t_end6) { + processSegment(t - t_end5, 0.0); + return p; + } + processSegment(profile.t6, 0.0); + + // 段 7 + processSegment(t - t_end6, j); + return p; +} + +double SCurve::getVelocityAtTime(const SCurveProfile& profile, double t) const +{ + if (t <= 0) return profile.v0; + if (t >= profile.total_time) return profile.vf; + + double j = profile.j_max * profile.direction; + double v = profile.v0; + double a = profile.a0; + + // 时间边界 + double t_end1 = profile.t1; + double t_end2 = t_end1 + profile.t2; + double t_end3 = t_end2 + profile.t3; + double t_end4 = t_end3 + profile.t4; + double t_end5 = t_end4 + profile.t5; + double t_end6 = t_end5 + profile.t6; + + auto processSegment = [&](double dt, double jerk) { + v += a * dt + 0.5 * jerk * dt * dt; + a += jerk * dt; + }; + + if (t <= t_end1) { + v += a * t + 0.5 * j * t * t; + return v; + } + processSegment(profile.t1, j); + + if (t <= t_end2) { + v += a * (t - t_end1); + return v; + } + processSegment(profile.t2, 0.0); + + if (t <= t_end3) { + double dt = t - t_end2; + v += a * dt + 0.5 * (-j) * dt * dt; + return v; + } + processSegment(profile.t3, -j); + + if (t <= t_end4) { + v += a * (t - t_end3); + return v; + } + processSegment(profile.t4, 0.0); + + if (t <= t_end5) { + double dt = t - t_end4; + v += a * dt + 0.5 * (-j) * dt * dt; + return v; + } + processSegment(profile.t5, -j); + + if (t <= t_end6) { + v += a * (t - t_end5); + return v; + } + processSegment(profile.t6, 0.0); + + double dt = t - t_end6; + v += a * dt + 0.5 * j * dt * dt; + return v; +} + +double SCurve::getAccelerationAtTime(const SCurveProfile& profile, double t) const +{ + if (t <= 0 || t >= profile.total_time) return 0.0; + + double j = profile.j_max * profile.direction; + double a = profile.a0; + + // 时间边界 + double t_end1 = profile.t1; + double t_end2 = t_end1 + profile.t2; + double t_end3 = t_end2 + profile.t3; + double t_end4 = t_end3 + profile.t4; + double t_end5 = t_end4 + profile.t5; + double t_end6 = t_end5 + profile.t6; + + if (t <= t_end1) { + return a + j * t; + } + a += j * profile.t1; + + if (t <= t_end2) { + return a; + } + + if (t <= t_end3) { + return a + (-j) * (t - t_end2); + } + a += (-j) * profile.t3; + + if (t <= t_end4) { + return a; // Should be ~0 + } + + if (t <= t_end5) { + return a + (-j) * (t - t_end4); + } + a += (-j) * profile.t5; + + if (t <= t_end6) { + return a; + } + + return a + j * (t - t_end6); +} + +double SCurve::getJerkAtTime(const SCurveProfile& profile, double t) const +{ + if (t <= 0.0 || t >= profile.total_time) { + return 0.0; + } + return computeSegmentJerk(profile, t); +} + +void SCurve::generateTrajectory(const SCurveProfile& profile, double dt, + std::vector& positions, + std::vector& velocities, + std::vector& accelerations) const +{ + positions.clear(); + velocities.clear(); + accelerations.clear(); + + if (profile.total_time <= 0 || dt <= 0) { + positions.push_back(profile.p0); + velocities.push_back(profile.v0); + accelerations.push_back(profile.a0); + return; + } + + int num_points = static_cast(std::ceil(profile.total_time / dt)) + 1; + positions.reserve(num_points); + velocities.reserve(num_points); + accelerations.reserve(num_points); + + for (double t = 0; t <= profile.total_time; t += dt) { + positions.push_back(getPositionAtTime(profile, t)); + velocities.push_back(getVelocityAtTime(profile, t)); + accelerations.push_back(getAccelerationAtTime(profile, t)); + } + + // 确保包含最终点 + if (positions.empty() || + std::abs(positions.back() - (profile.p0 + profile.distance * profile.direction)) > EPSILON) { + positions.push_back(profile.p0 + profile.distance * profile.direction); + velocities.push_back(profile.vf); + accelerations.push_back(0.0); + } +} + +} diff --git a/cpp/common/curve/src/s_curve_pybind.cpp b/cpp/common/curve/src/s_curve_pybind.cpp new file mode 100644 index 0000000..d45cb52 --- /dev/null +++ b/cpp/common/curve/src/s_curve_pybind.cpp @@ -0,0 +1,171 @@ +#include "common/curve/include/s_curve.h" +#include "planner/s_curve_planner/include/s_curve_position_planner.h" + +#include +#include +#include + +#include +#include + +namespace py = pybind11; + +namespace { + +py::dict sample_trajectory(const cmvr::SCurve& curve, const cmvr::SCurveProfile& profile, double dt) +{ + if (dt <= 0.0) { + throw std::invalid_argument("dt must be > 0"); + } + + std::vector times; + std::vector positions; + std::vector velocities; + std::vector accelerations; + std::vector jerks; + + if (profile.total_time <= 0.0) { + times.push_back(0.0); + positions.push_back(profile.p0); + velocities.push_back(profile.v0); + accelerations.push_back(profile.a0); + jerks.push_back(0.0); + } else { + for (double t = 0.0; t <= profile.total_time + 1e-12; t += dt) { + const double sample_time = std::min(t, profile.total_time); + times.push_back(sample_time); + positions.push_back(curve.getPositionAtTime(profile, sample_time)); + velocities.push_back(curve.getVelocityAtTime(profile, sample_time)); + accelerations.push_back(curve.getAccelerationAtTime(profile, sample_time)); + jerks.push_back(curve.getJerkAtTime(profile, sample_time)); + } + + if (std::abs(times.back() - profile.total_time) > 1e-9) { + times.push_back(profile.total_time); + positions.push_back(curve.getPositionAtTime(profile, profile.total_time)); + velocities.push_back(curve.getVelocityAtTime(profile, profile.total_time)); + accelerations.push_back(curve.getAccelerationAtTime(profile, profile.total_time)); + jerks.push_back(curve.getJerkAtTime(profile, profile.total_time)); + } + } + + py::dict result; + result["times"] = times; + result["positions"] = positions; + result["velocities"] = velocities; + result["accelerations"] = accelerations; + result["jerks"] = jerks; + return result; +} + +} // namespace + +PYBIND11_MODULE(_s_curve_native, m) +{ + m.doc() = "pybind11 bindings for cmvr::SCurve"; + + py::class_(m, "SCurveProfile") + .def(py::init<>()) + .def_readwrite("t1", &cmvr::SCurveProfile::t1) + .def_readwrite("t2", &cmvr::SCurveProfile::t2) + .def_readwrite("t3", &cmvr::SCurveProfile::t3) + .def_readwrite("t4", &cmvr::SCurveProfile::t4) + .def_readwrite("t5", &cmvr::SCurveProfile::t5) + .def_readwrite("t6", &cmvr::SCurveProfile::t6) + .def_readwrite("t7", &cmvr::SCurveProfile::t7) + .def_readwrite("total_time", &cmvr::SCurveProfile::total_time) + .def_readwrite("j_max", &cmvr::SCurveProfile::j_max) + .def_readwrite("a_max", &cmvr::SCurveProfile::a_max) + .def_readwrite("v_max", &cmvr::SCurveProfile::v_max) + .def_readwrite("distance", &cmvr::SCurveProfile::distance) + .def_readwrite("direction", &cmvr::SCurveProfile::direction) + .def_readwrite("v_cruise", &cmvr::SCurveProfile::v_cruise) + .def_readwrite("a_limit", &cmvr::SCurveProfile::a_limit) + .def_readwrite("p0", &cmvr::SCurveProfile::p0) + .def_readwrite("v0", &cmvr::SCurveProfile::v0) + .def_readwrite("a0", &cmvr::SCurveProfile::a0) + .def_readwrite("vf", &cmvr::SCurveProfile::vf); + + py::class_(m, "SCurve") + .def(py::init(), + py::arg("max_velocity") = 3.0, + py::arg("max_acceleration") = 10.0, + py::arg("max_jerk") = 50.0) + .def("setConstraints", &cmvr::SCurve::setConstraints, + py::arg("max_velocity"), + py::arg("max_acceleration"), + py::arg("max_jerk")) + .def("getConstraints", [](const cmvr::SCurve& self) { + double max_velocity = 0.0; + double max_acceleration = 0.0; + double max_jerk = 0.0; + self.getConstraints(max_velocity, max_acceleration, max_jerk); + return py::make_tuple(max_velocity, max_acceleration, max_jerk); + }) + .def("calculateProfile", &cmvr::SCurve::calculateProfile, + py::arg("start_position"), + py::arg("end_position"), + py::arg("start_velocity") = 0.0, + py::arg("end_velocity") = 0.0) + .def("getPositionAtTime", &cmvr::SCurve::getPositionAtTime, + py::arg("profile"), + py::arg("t")) + .def("getVelocityAtTime", &cmvr::SCurve::getVelocityAtTime, + py::arg("profile"), + py::arg("t")) + .def("getAccelerationAtTime", &cmvr::SCurve::getAccelerationAtTime, + py::arg("profile"), + py::arg("t")) + .def("getJerkAtTime", &cmvr::SCurve::getJerkAtTime, + py::arg("profile"), + py::arg("t")) + .def("sampleTrajectory", &sample_trajectory, + py::arg("profile"), + py::arg("dt")); + + py::class_(m, "SCurvePositionPlannerState") + .def(py::init<>()) + .def_readwrite("position", &cmvr::SCurvePositionPlannerState::position) + .def_readwrite("velocity", &cmvr::SCurvePositionPlannerState::velocity) + .def_readwrite("acceleration", &cmvr::SCurvePositionPlannerState::acceleration) + .def_readwrite("jerk", &cmvr::SCurvePositionPlannerState::jerk) + .def_readwrite("target_position", &cmvr::SCurvePositionPlannerState::target_position) + .def_readwrite("is_moving", &cmvr::SCurvePositionPlannerState::is_moving); + + py::class_(m, "SCurvePositionPlanner1D") + .def(py::init(), + py::arg("max_velocity") = 3.0, + py::arg("max_acceleration") = 10.0, + py::arg("max_jerk") = 50.0) + .def("setConstraints", &cmvr::SCurvePositionPlanner1D::setConstraints, + py::arg("max_velocity"), + py::arg("max_acceleration"), + py::arg("max_jerk")) + .def("getConstraints", [](const cmvr::SCurvePositionPlanner1D& self) { + double max_velocity = 0.0; + double max_acceleration = 0.0; + double max_jerk = 0.0; + self.getConstraints(max_velocity, max_acceleration, max_jerk); + return py::make_tuple(max_velocity, max_acceleration, max_jerk); + }) + .def("setPositionGain", &cmvr::SCurvePositionPlanner1D::setPositionGain, + py::arg("position_gain")) + .def("getPositionGain", &cmvr::SCurvePositionPlanner1D::getPositionGain) + .def("initialize", &cmvr::SCurvePositionPlanner1D::initialize, + py::arg("position"), + py::arg("velocity") = 0.0, + py::arg("acceleration") = 0.0) + .def("reset", &cmvr::SCurvePositionPlanner1D::reset) + .def("setTarget", &cmvr::SCurvePositionPlanner1D::setTarget, + py::arg("target_position")) + .def("update", &cmvr::SCurvePositionPlanner1D::update, + py::arg("dt")) + .def("getState", &cmvr::SCurvePositionPlanner1D::getState, + py::return_value_policy::reference_internal) + .def("getPosition", &cmvr::SCurvePositionPlanner1D::getPosition) + .def("getVelocity", &cmvr::SCurvePositionPlanner1D::getVelocity) + .def("getAcceleration", &cmvr::SCurvePositionPlanner1D::getAcceleration) + .def("getJerk", &cmvr::SCurvePositionPlanner1D::getJerk) + .def("getTargetPosition", &cmvr::SCurvePositionPlanner1D::getTargetPosition) + .def("isMoving", &cmvr::SCurvePositionPlanner1D::isMoving); +} diff --git a/cpp/planner/s_curve_planner/include/s_curve_position_planner.h b/cpp/planner/s_curve_planner/include/s_curve_position_planner.h new file mode 100644 index 0000000..551abaa --- /dev/null +++ b/cpp/planner/s_curve_planner/include/s_curve_position_planner.h @@ -0,0 +1,100 @@ +// +// Created by lgv on 2026/3/10. +// + +#pragma once + +#include "s_curve_velocity_planner.h" + +#include +#include + +namespace cmvr +{ + +struct SCurvePositionPlannerState +{ + double position; + double velocity; + double acceleration; + double jerk; + double target_position; + bool is_moving; + + SCurvePositionPlannerState() + : position(0.0) + , velocity(0.0) + , acceleration(0.0) + , jerk(0.0) + , target_position(0.0) + , is_moving(false) + {} +}; + +/** + * @brief 单轴位置跟踪规划器 + * + * 结构: + * - 外环:position_error -> desired_velocity + * - 内环:SCurveVelocityPlanner1D 负责 jerk-limited 速度规划 + * + * 这个类用于高频变化目标的位置跟踪,不承担严格点到点 profile 语义。 + */ +class SCurvePositionPlanner1D +{ +public: + SCurvePositionPlanner1D(double max_velocity = 3.0, + double max_acceleration = 10.0, + double max_jerk = 50.0); + + void setConstraints(double max_velocity, double max_acceleration, double max_jerk); + void getConstraints(double& max_velocity, double& max_acceleration, double& max_jerk) const; + + void setPositionGain(double position_gain); + double getPositionGain() const { return position_gain_; } + + void initialize(double position, double velocity = 0.0, double acceleration = 0.0); + void reset(); + + void setTarget(double target_position); + double update(double dt); + + const SCurvePositionPlannerState& getState() const { return state_; } + double getPosition() const { return state_.position; } + double getVelocity() const { return state_.velocity; } + double getAcceleration() const { return state_.acceleration; } + double getJerk() const { return state_.jerk; } + double getTargetPosition() const { return state_.target_position; } + bool isMoving() const { return state_.is_moving; } + +private: + double max_velocity_; + double max_acceleration_; + double max_jerk_; + + SCurvePositionPlannerState state_; + SCurveVelocityPlanner1D velocity_planner_; + double position_gain_; + + static constexpr double EPSILON = 1e-9; + static constexpr double VELOCITY_THRESHOLD = 1e-6; + static constexpr double ACCELERATION_THRESHOLD = 1e-6; + static constexpr double POSITION_THRESHOLD = 1e-7; + + double computeDesiredVelocity(double position_error) const; + double computePlannerStoppingDistance(double velocity, double acceleration) const; + + static double clamp(double value, double min_val, double max_val) + { + return std::max(min_val, std::min(max_val, value)); + } + + static double sign(double value) + { + if (value > EPSILON) return 1.0; + if (value < -EPSILON) return -1.0; + return 0.0; + } +}; + +} // namespace cmvr diff --git a/cpp/planner/s_curve_planner/include/s_curve_velocity_planner.h b/cpp/planner/s_curve_planner/include/s_curve_velocity_planner.h new file mode 100644 index 0000000..f9e5977 --- /dev/null +++ b/cpp/planner/s_curve_planner/include/s_curve_velocity_planner.h @@ -0,0 +1,240 @@ +// +// Created by lgv on 2026/3/9. +// + +#pragma once + +#include +#include +#include + +namespace cmvr +{ + +/** + * @brief 单次速度切换的 S 曲线剖面参数 + * + * 本类表示从任意 (v0, a0) 连续规划到 (vf, 0) 的 3 段 jerk-limited profile: + * + * seg1: jerk = j1, duration = t1 + * seg2: jerk = j2, duration = t2 (当前实现 j2 = 0) + * seg3: jerk = j3, duration = t3 + * + * 其中 j1/j3 为 ±j_max,j2 为 0。 + */ +struct SCurveVelocityProfile +{ + double t1; + double t2; + double t3; + + double total_time; + + double j1; + double j2; + double j3; + + double v0; + double a0; + double vf; + + bool valid; + + SCurveVelocityProfile() + : t1(0.0), t2(0.0), t3(0.0) + , total_time(0.0) + , j1(0.0), j2(0.0), j3(0.0) + , v0(0.0), a0(0.0), vf(0.0) + , valid(false) + {} +}; + +/** + * @brief S 曲线速度规划器状态 + */ +struct SCurveVelocityPlannerState +{ + double velocity; + double acceleration; + double jerk; + + double target_velocity; + + double elapsed_time; + bool has_active_profile; + bool is_moving; + + SCurveVelocityPlannerState() + : velocity(0.0) + , acceleration(0.0) + , jerk(0.0) + , target_velocity(0.0) + , elapsed_time(0.0) + , has_active_profile(false) + , is_moving(false) + {} +}; + +/** + * @brief 单轴速度型 S 曲线规划器 + * + * 语义: + * - setTargetVelocity(v): 设置新目标并重规划 + * - update(dt): 只采样当前 active profile + * - overwriteState(v,a): 仅覆盖当前状态并清掉旧 profile + * - synchronizeAndReplan(v,a): 用测量状态同步,并按当前目标重规划 + * + * 数学目标: + * - 从任意 (v0, a0) 连续规划到 (vf, 0) + * - 满足 |v| <= v_max, |a| <= a_max, |j| <= j_max + */ +class SCurveVelocityPlanner1D +{ +public: + SCurveVelocityPlanner1D(double max_velocity = 1.0, + double max_acceleration = 1.0, + double max_jerk = 5.0); + + void setConstraints(double max_velocity, double max_acceleration, double max_jerk); + void getConstraints(double& max_velocity, double& max_acceleration, double& max_jerk) const; + + /** + * @brief 设置目标变化阈值 + * + * 目标变化量小于该阈值时,不触发重规划。 + */ + void setTargetReplanThreshold(double threshold); + + /** + * @brief 设置同步反馈时的重规划阈值 + * + * 测量速度与当前 profile 采样状态的偏差小于该阈值时, + * synchronizeAndReplan() 只对齐当前状态,不打断现有 profile。 + */ + void setSynchronizeReplanThreshold(double threshold); + + void initialize(double velocity = 0.0, double acceleration = 0.0); + void reset(); + + /** + * @brief 仅覆盖当前状态,并清掉旧 profile + * + * 注意: + * - 这个接口不会自动重规划 + * - 用于初始化、调试、或显式中断旧轨迹 + */ + void overwriteState(double velocity, + double acceleration = 0.0, + bool keep_target_velocity = true); + + /** + * @brief 用测量状态同步,并按当前目标重新规划 + * + * 这是闭环场景真正该用的接口。 + */ + void synchronizeAndReplan(double velocity, + double acceleration = 0.0); + + /** + * @brief 设置目标速度,并立即重规划 + */ + void setTargetVelocity(double target_velocity); + + /** + * @brief 平滑停下 + */ + void stop() { setTargetVelocity(0.0); } + + /** + * @brief 更新一步(只采样) + * @param dt 时间步长 + * @return 当前采样后的速度 + */ + double update(double dt); + + /** + * @brief 计算单次速度切换剖面 + */ + SCurveVelocityProfile calculateProfile(double start_velocity, + double end_velocity, + double start_acceleration = 0.0) const; + + /** + * @brief 给定剖面下,获取时刻 t 的速度 + */ + double getVelocityAtTime(const SCurveVelocityProfile& profile, double t) const; + + /** + * @brief 给定剖面下,获取时刻 t 的加速度 + */ + double getAccelerationAtTime(const SCurveVelocityProfile& profile, double t) const; + + /** + * @brief 给定剖面下,获取时刻 t 的 jerk + */ + double getJerkAtTime(const SCurveVelocityProfile& profile, double t) const; + + /** + * @brief 按固定时间间隔生成轨迹点 + */ + void generateTrajectory(const SCurveVelocityProfile& profile, double dt, + std::vector& velocities, + std::vector& accelerations, + std::vector& jerks) const; + + const SCurveVelocityPlannerState& getState() const { return state_; } + const SCurveVelocityProfile& getActiveProfile() const { return active_profile_; } + + double getVelocity() const { return state_.velocity; } + double getAcceleration() const { return state_.acceleration; } + double getJerk() const { return state_.jerk; } + double getTargetVelocity() const { return state_.target_velocity; } + bool hasActiveProfile() const { return state_.has_active_profile; } + bool isMoving() const { return state_.is_moving; } + +private: + double max_velocity_; + double max_acceleration_; + double max_jerk_; + + double target_replan_threshold_; + double synchronize_replan_threshold_; + + SCurveVelocityPlannerState state_; + SCurveVelocityProfile active_profile_; + + static constexpr double EPSILON = 1e-9; + static constexpr double VELOCITY_THRESHOLD = 1e-6; + static constexpr double ACCELERATION_THRESHOLD = 1e-6; + static constexpr double DEFAULT_TARGET_REPLAN_THRESHOLD = 1e-9; + static constexpr double DEFAULT_SYNCHRONIZE_REPLAN_THRESHOLD = 5e-2; + +private: + void updateIsMovingFlag(); + + /** + * @brief 判断 profile 是否满足速度上限 + */ + bool isVelocityLimitSatisfied(const SCurveVelocityProfile& profile) const; + + /** + * @brief 计算完整剖面终点状态 + */ + void integrateWholeProfile(const SCurveVelocityProfile& profile, + double& v_end, + double& a_end) const; + + static double clamp(double value, double min_val, double max_val) + { + return std::max(min_val, std::min(max_val, value)); + } + + static double sign(double value) + { + if (value > EPSILON) return 1.0; + if (value < -EPSILON) return -1.0; + return 0.0; + } +}; + +} // namespace cmvr diff --git a/cpp/planner/s_curve_planner/src/s_curve_position_planner.cpp b/cpp/planner/s_curve_planner/src/s_curve_position_planner.cpp new file mode 100644 index 0000000..70b5e82 --- /dev/null +++ b/cpp/planner/s_curve_planner/src/s_curve_position_planner.cpp @@ -0,0 +1,193 @@ +// +// Created by lgv on 2026/3/10. +// + +#include "planner/s_curve_planner/include/s_curve_position_planner.h" + +#include +#include + +namespace cmvr +{ + +SCurvePositionPlanner1D::SCurvePositionPlanner1D(double max_velocity, + double max_acceleration, + double max_jerk) + : max_velocity_(std::abs(max_velocity)) + , max_acceleration_(std::abs(max_acceleration)) + , max_jerk_(std::abs(max_jerk)) + , velocity_planner_(max_velocity_, max_acceleration_, max_jerk_) + , position_gain_(1.0) +{ + velocity_planner_.setTargetReplanThreshold(std::max(1e-3, 0.02 * max_velocity_)); + reset(); +} + +void SCurvePositionPlanner1D::setConstraints(double max_velocity, + double max_acceleration, + double max_jerk) +{ + max_velocity_ = std::abs(max_velocity); + max_acceleration_ = std::abs(max_acceleration); + max_jerk_ = std::abs(max_jerk); + velocity_planner_.setConstraints(max_velocity_, max_acceleration_, max_jerk_); + velocity_planner_.setTargetReplanThreshold(std::max(1e-3, 0.02 * max_velocity_)); +} + +void SCurvePositionPlanner1D::getConstraints(double& max_velocity, + double& max_acceleration, + double& max_jerk) const +{ + max_velocity = max_velocity_; + max_acceleration = max_acceleration_; + max_jerk = max_jerk_; +} + +void SCurvePositionPlanner1D::setPositionGain(double position_gain) +{ + position_gain_ = std::max(0.0, position_gain); +} + +void SCurvePositionPlanner1D::initialize(double position, double velocity, double acceleration) +{ + state_.position = position; + velocity_planner_.initialize(velocity, acceleration); + state_.velocity = velocity_planner_.getVelocity(); + state_.acceleration = velocity_planner_.getAcceleration(); + state_.jerk = 0.0; + state_.target_position = position; + state_.is_moving = false; +} + +void SCurvePositionPlanner1D::reset() +{ + state_ = SCurvePositionPlannerState(); + velocity_planner_.reset(); +} + +void SCurvePositionPlanner1D::setTarget(double target_position) +{ + state_.target_position = target_position; +} + +double SCurvePositionPlanner1D::update(double dt) +{ + if (dt <= 0.0 || dt > 0.1) { + return state_.position; + } + + const double position_error = state_.target_position - state_.position; + if (std::abs(position_error) < POSITION_THRESHOLD && + std::abs(velocity_planner_.getVelocity()) < VELOCITY_THRESHOLD && + std::abs(velocity_planner_.getAcceleration()) < ACCELERATION_THRESHOLD) { + velocity_planner_.overwriteState(0.0, 0.0, false); + state_.position = state_.target_position; + state_.velocity = 0.0; + state_.acceleration = 0.0; + state_.jerk = 0.0; + state_.is_moving = false; + return state_.position; + } + + velocity_planner_.setTargetVelocity(computeDesiredVelocity(position_error)); + + const double old_velocity = velocity_planner_.getVelocity(); + const double new_velocity = velocity_planner_.update(dt); + + state_.velocity = new_velocity; + state_.acceleration = velocity_planner_.getAcceleration(); + state_.jerk = velocity_planner_.getJerk(); + state_.position += 0.5 * (old_velocity + new_velocity) * dt; + + const double updated_error = state_.target_position - state_.position; + if (std::abs(updated_error) < POSITION_THRESHOLD && + std::abs(state_.velocity) < VELOCITY_THRESHOLD && + std::abs(state_.acceleration) < ACCELERATION_THRESHOLD) { + velocity_planner_.overwriteState(0.0, 0.0, false); + state_.position = state_.target_position; + state_.velocity = 0.0; + state_.acceleration = 0.0; + state_.jerk = 0.0; + state_.is_moving = false; + return state_.position; + } + + state_.is_moving = velocity_planner_.isMoving() || + std::abs(updated_error) > POSITION_THRESHOLD; + return state_.position; +} + +double SCurvePositionPlanner1D::computeDesiredVelocity(double position_error) const +{ + if (std::abs(position_error) <= POSITION_THRESHOLD) { + return 0.0; + } + + const double proportional_velocity = + clamp(position_gain_ * position_error, -max_velocity_, max_velocity_); + + return proportional_velocity; + const double current_velocity = velocity_planner_.getVelocity(); + const double current_acceleration = velocity_planner_.getAcceleration(); + const double stopping_distance = + computePlannerStoppingDistance(current_velocity, current_acceleration); + + if (std::abs(current_velocity) > VELOCITY_THRESHOLD && + sign(current_velocity) != sign(position_error)) { + return 0.0; + } + + if (std::abs(current_velocity) > VELOCITY_THRESHOLD && + sign(current_velocity) == sign(position_error) && + std::abs(position_error) <= std::abs(stopping_distance) * 1.05) { + return 0.0; + } + + double low = 0.0; + double high = max_velocity_; + for (int i = 0; i < 40; ++i) { + const double mid = 0.5 * (low + high); + const double distance = + std::abs(computePlannerStoppingDistance(sign(position_error) * mid, 0.0)); + if (distance <= std::abs(position_error)) { + low = mid; + } else { + high = mid; + } + } + + return sign(position_error) * + std::min(std::abs(proportional_velocity), low); +} + +double SCurvePositionPlanner1D::computePlannerStoppingDistance(double velocity, + double acceleration) const +{ + if (std::abs(velocity) <= VELOCITY_THRESHOLD && + std::abs(acceleration) <= ACCELERATION_THRESHOLD) { + return 0.0; + } + + const auto profile = velocity_planner_.calculateProfile(velocity, 0.0, acceleration); + if (!profile.valid || profile.total_time <= EPSILON) { + return 0.0; + } + + const int steps = std::max(16, static_cast(std::ceil(profile.total_time / 0.002))); + const double dt = profile.total_time / static_cast(steps); + + double distance = 0.0; + double previous_time = 0.0; + double previous_velocity = velocity_planner_.getVelocityAtTime(profile, 0.0); + for (int i = 1; i <= steps; ++i) { + const double t = (i == steps) ? profile.total_time : i * dt; + const double current_velocity = velocity_planner_.getVelocityAtTime(profile, t); + distance += 0.5 * (previous_velocity + current_velocity) * (t - previous_time); + previous_time = t; + previous_velocity = current_velocity; + } + + return distance; +} + +} // namespace cmvr diff --git a/cpp/planner/s_curve_planner/src/s_curve_velocity_planner.cpp b/cpp/planner/s_curve_planner/src/s_curve_velocity_planner.cpp new file mode 100644 index 0000000..8861109 --- /dev/null +++ b/cpp/planner/s_curve_planner/src/s_curve_velocity_planner.cpp @@ -0,0 +1,549 @@ +// +// Created by lgv on 2026/3/9. +// + +#include "../include/s_curve_velocity_planner.h" + +#include +#include + +namespace cmvr +{ + +SCurveVelocityPlanner1D::SCurveVelocityPlanner1D(double max_velocity, + double max_acceleration, + double max_jerk) + : max_velocity_(std::abs(max_velocity)) + , max_acceleration_(std::abs(max_acceleration)) + , max_jerk_(std::abs(max_jerk)) + , target_replan_threshold_(DEFAULT_TARGET_REPLAN_THRESHOLD) + , synchronize_replan_threshold_(DEFAULT_SYNCHRONIZE_REPLAN_THRESHOLD) +{ + reset(); +} + +void SCurveVelocityPlanner1D::setConstraints(double max_velocity, + double max_acceleration, + double max_jerk) +{ + max_velocity_ = std::abs(max_velocity); + max_acceleration_ = std::abs(max_acceleration); + max_jerk_ = std::abs(max_jerk); + + state_.velocity = clamp(state_.velocity, -max_velocity_, max_velocity_); + state_.acceleration = clamp(state_.acceleration, -max_acceleration_, max_acceleration_); + state_.target_velocity = clamp(state_.target_velocity, -max_velocity_, max_velocity_); + + if (state_.has_active_profile) { + active_profile_ = calculateProfile(state_.velocity, + state_.target_velocity, + state_.acceleration); + state_.elapsed_time = 0.0; + state_.has_active_profile = active_profile_.valid && active_profile_.total_time > EPSILON; + } + + updateIsMovingFlag(); +} + +void SCurveVelocityPlanner1D::getConstraints(double& max_velocity, + double& max_acceleration, + double& max_jerk) const +{ + max_velocity = max_velocity_; + max_acceleration = max_acceleration_; + max_jerk = max_jerk_; +} + +void SCurveVelocityPlanner1D::setTargetReplanThreshold(double threshold) +{ + target_replan_threshold_ = std::max(0.0, threshold); +} + +void SCurveVelocityPlanner1D::setSynchronizeReplanThreshold(double threshold) +{ + synchronize_replan_threshold_ = std::max(0.0, threshold); +} + +void SCurveVelocityPlanner1D::initialize(double velocity, double acceleration) +{ + state_ = SCurveVelocityPlannerState(); + state_.velocity = clamp(velocity, -max_velocity_, max_velocity_); + state_.acceleration = clamp(acceleration, -max_acceleration_, max_acceleration_); + state_.jerk = 0.0; + state_.target_velocity = state_.velocity; + state_.elapsed_time = 0.0; + state_.has_active_profile = false; + + active_profile_ = SCurveVelocityProfile(); + active_profile_.v0 = state_.velocity; + active_profile_.a0 = state_.acceleration; + active_profile_.vf = state_.velocity; + active_profile_.valid = false; + + updateIsMovingFlag(); +} + +void SCurveVelocityPlanner1D::reset() +{ + state_ = SCurveVelocityPlannerState(); + active_profile_ = SCurveVelocityProfile(); +} + +void SCurveVelocityPlanner1D::overwriteState(double velocity, + double acceleration, + bool keep_target_velocity) +{ + state_.velocity = clamp(velocity, -max_velocity_, max_velocity_); + state_.acceleration = clamp(acceleration, -max_acceleration_, max_acceleration_); + state_.jerk = 0.0; + state_.elapsed_time = 0.0; + state_.has_active_profile = false; + + if (!keep_target_velocity) { + state_.target_velocity = state_.velocity; + } else { + state_.target_velocity = clamp(state_.target_velocity, -max_velocity_, max_velocity_); + } + + active_profile_ = SCurveVelocityProfile(); + active_profile_.v0 = state_.velocity; + active_profile_.a0 = state_.acceleration; + active_profile_.vf = state_.target_velocity; + active_profile_.valid = false; + + updateIsMovingFlag(); +} + +void SCurveVelocityPlanner1D::synchronizeAndReplan(double velocity, + double acceleration) +{ + const double measured_velocity = clamp(velocity, -max_velocity_, max_velocity_); + const double measured_acceleration = + clamp(acceleration, -max_acceleration_, max_acceleration_); + + if (!state_.has_active_profile && + std::abs(measured_velocity - state_.target_velocity) <= VELOCITY_THRESHOLD) { + state_.velocity = state_.target_velocity; + state_.acceleration = 0.0; + state_.jerk = 0.0; + updateIsMovingFlag(); + return; + } + + // If the measured state is still close to the active profile sample, keep + // following that profile instead of restarting the plan every cycle. + if (state_.has_active_profile && + std::abs(measured_velocity - state_.velocity) <= synchronize_replan_threshold_) { + state_.velocity = measured_velocity; + state_.acceleration = measured_acceleration; + state_.jerk = getJerkAtTime(active_profile_, state_.elapsed_time); + updateIsMovingFlag(); + return; + } + + state_.velocity = measured_velocity; + state_.acceleration = measured_acceleration; + state_.jerk = 0.0; + + active_profile_ = calculateProfile(state_.velocity, + state_.target_velocity, + state_.acceleration); + + state_.elapsed_time = 0.0; + state_.has_active_profile = active_profile_.total_time > EPSILON; + + updateIsMovingFlag(); +} + +void SCurveVelocityPlanner1D::setTargetVelocity(double target_velocity) +{ + const double new_target = clamp(target_velocity, -max_velocity_, max_velocity_); + + const bool same_target = + std::abs(new_target - state_.target_velocity) <= target_replan_threshold_; + + if (same_target && + state_.has_active_profile) { + return; + } + + if (same_target && + !state_.has_active_profile && + std::abs(state_.velocity - new_target) <= VELOCITY_THRESHOLD && + std::abs(state_.acceleration) <= ACCELERATION_THRESHOLD) { + return; + } + + state_.target_velocity = new_target; + + active_profile_ = calculateProfile(state_.velocity, + state_.target_velocity, + state_.acceleration); + + state_.elapsed_time = 0.0; + state_.has_active_profile = active_profile_.valid && active_profile_.total_time > EPSILON; + + updateIsMovingFlag(); +} + +double SCurveVelocityPlanner1D::getVelocityAtTime(const SCurveVelocityProfile& profile, double t) const +{ + if (!profile.valid) { + return profile.v0; + } + + if (t <= 0.0) { + return profile.v0; + } + if (t >= profile.total_time) { + return profile.vf; + } + + double v = profile.v0; + double a = profile.a0; + + auto process_segment = [&](double dt, double jerk) { + v += a * dt + 0.5 * jerk * dt * dt; + a += jerk * dt; + }; + + if (t <= profile.t1) { + process_segment(t, profile.j1); + return v; + } + process_segment(profile.t1, profile.j1); + + const double t_after_1 = t - profile.t1; + if (t_after_1 <= profile.t2) { + process_segment(t_after_1, profile.j2); + return v; + } + process_segment(profile.t2, profile.j2); + + const double t_after_2 = t_after_1 - profile.t2; + process_segment(t_after_2, profile.j3); + return v; +} + +double SCurveVelocityPlanner1D::getAccelerationAtTime(const SCurveVelocityProfile& profile, double t) const +{ + if (!profile.valid) { + return profile.a0; + } + + if (t <= 0.0) { + return profile.a0; + } + if (t >= profile.total_time) { + return 0.0; + } + + double a = profile.a0; + + auto process_segment = [&](double dt, double jerk) { + a += jerk * dt; + }; + + if (t <= profile.t1) { + process_segment(t, profile.j1); + return a; + } + process_segment(profile.t1, profile.j1); + + const double t_after_1 = t - profile.t1; + if (t_after_1 <= profile.t2) { + process_segment(t_after_1, profile.j2); + return a; + } + process_segment(profile.t2, profile.j2); + + const double t_after_2 = t_after_1 - profile.t2; + process_segment(t_after_2, profile.j3); + return a; +} + +double SCurveVelocityPlanner1D::getJerkAtTime(const SCurveVelocityProfile& profile, double t) const +{ + if (!profile.valid) { + return 0.0; + } + + if (t <= 0.0 || t >= profile.total_time) { + return 0.0; + } + + if (t <= profile.t1) { + return profile.j1; + } + if (t <= profile.t1 + profile.t2) { + return profile.j2; + } + return profile.j3; +} + +void SCurveVelocityPlanner1D::integrateWholeProfile(const SCurveVelocityProfile& profile, + double& v_end, + double& a_end) const +{ + double v = profile.v0; + double a = profile.a0; + + auto process_segment = [&](double dt, double jerk) { + v += a * dt + 0.5 * jerk * dt * dt; + a += jerk * dt; + }; + + process_segment(profile.t1, profile.j1); + process_segment(profile.t2, profile.j2); + process_segment(profile.t3, profile.j3); + + v_end = v; + a_end = a; +} + +bool SCurveVelocityPlanner1D::isVelocityLimitSatisfied(const SCurveVelocityProfile& profile) const +{ + if (!profile.valid) { + return true; + } + + std::vector check_times; + check_times.reserve(8); + + check_times.push_back(0.0); + check_times.push_back(profile.t1); + check_times.push_back(profile.t1 + profile.t2); + check_times.push_back(profile.total_time); + + // If acceleration crosses zero inside segment 1, velocity may reach an + // extremum within the segment and needs to be checked explicitly. + if (std::abs(profile.j1) > EPSILON && profile.t1 > EPSILON) { + const double tz = -profile.a0 / profile.j1; + if (tz > EPSILON && tz < profile.t1 - EPSILON) { + check_times.push_back(tz); + } + } + + for (double t : check_times) { + const double v = getVelocityAtTime(profile, t); + if (std::abs(v) > max_velocity_ + 1e-7) { + return false; + } + } + + return true; +} + +SCurveVelocityProfile SCurveVelocityPlanner1D::calculateProfile(double start_velocity, + double end_velocity, + double start_acceleration) const +{ + SCurveVelocityProfile best; + best.v0 = clamp(start_velocity, -max_velocity_, max_velocity_); + best.a0 = clamp(start_acceleration, -max_acceleration_, max_acceleration_); + best.vf = clamp(end_velocity, -max_velocity_, max_velocity_); + + if (max_jerk_ <= EPSILON || max_acceleration_ <= EPSILON) { + return best; + } + + const double v0 = best.v0; + const double a0 = best.a0; + const double vf = best.vf; + + // Work in a signed frame where the requested delta velocity is non-negative. + double s = sign(vf - v0); + if (std::abs(vf - v0) <= VELOCITY_THRESHOLD) { + s = 1.0; + } + + const double dv = s * (vf - v0); + const double a0s = s * a0; + const double j = max_jerk_; + const double amax = max_acceleration_; + + auto normalize_nonnegative = [](double x) { + return (x < 0.0 && x > -1e-10) ? 0.0 : x; + }; + + auto try_candidate = [&](double t1, double t2, double t3, + double j1s, double j2s, double j3s) { + t1 = normalize_nonnegative(t1); + t2 = normalize_nonnegative(t2); + t3 = normalize_nonnegative(t3); + + if (t1 < 0.0 || t2 < 0.0 || t3 < 0.0) { + return; + } + + SCurveVelocityProfile cand; + cand.t1 = t1; + cand.t2 = t2; + cand.t3 = t3; + cand.total_time = t1 + t2 + t3; + + cand.j1 = s * j1s; + cand.j2 = s * j2s; + cand.j3 = s * j3s; + + cand.v0 = v0; + cand.a0 = a0; + cand.vf = vf; + cand.valid = true; + + double vend = 0.0; + double aend = 0.0; + integrateWholeProfile(cand, vend, aend); + + if (std::abs(vend - vf) > 1e-5) { + return; + } + if (std::abs(aend) > 1e-5) { + return; + } + if (!isVelocityLimitSatisfied(cand)) { + return; + } + + if (!best.valid || cand.total_time < best.total_time) { + best = cand; + } + }; + + { + const double A2 = 0.5 * (2.0 * j * dv + a0s * a0s); + if (A2 >= -1e-10) { + const double A = std::sqrt(std::max(0.0, A2)); + if (A <= amax + 1e-10 && A >= a0s - 1e-10) { + const double t1 = (A - a0s) / j; + const double t2 = 0.0; + const double t3 = A / j; + try_candidate(t1, t2, t3, +j, 0.0, -j); + } + } + } + + { + const double A = amax; + if (A > EPSILON && A >= a0s - 1e-10) { + const double base = (2.0 * A * A - a0s * a0s) / (2.0 * j); + const double t1 = (A - a0s) / j; + const double t2 = (dv - base) / A; + const double t3 = A / j; + try_candidate(t1, t2, t3, +j, 0.0, -j); + } + } + + { + const double B2 = 0.5 * (a0s * a0s - 2.0 * j * dv); + if (B2 >= -1e-10) { + const double B = std::sqrt(std::max(0.0, B2)); + if (B <= amax + 1e-10 && B >= -a0s - 1e-10) { + const double t1 = (a0s + B) / j; + const double t2 = 0.0; + const double t3 = B / j; + try_candidate(t1, t2, t3, -j, 0.0, +j); + } + } + } + + { + const double B = amax; + if (B > EPSILON && B >= -a0s - 1e-10) { + const double base = (a0s * a0s - 2.0 * B * B) / (2.0 * j); + const double t1 = (a0s + B) / j; + const double t2 = (base - dv) / B; + const double t3 = B / j; + try_candidate(t1, t2, t3, -j, 0.0, +j); + } + } + + if (!best.valid && + std::abs(vf - v0) <= VELOCITY_THRESHOLD && + std::abs(a0) <= ACCELERATION_THRESHOLD) { + best.valid = false; + best.total_time = 0.0; + best.v0 = v0; + best.a0 = a0; + best.vf = vf; + } + + return best; +} + +void SCurveVelocityPlanner1D::generateTrajectory(const SCurveVelocityProfile& profile, double dt, + std::vector& velocities, + std::vector& accelerations, + std::vector& jerks) const +{ + velocities.clear(); + accelerations.clear(); + jerks.clear(); + + if (!profile.valid || profile.total_time <= 0.0 || dt <= 0.0) { + velocities.push_back(profile.v0); + accelerations.push_back(profile.a0); + jerks.push_back(0.0); + return; + } + + const int num_points = static_cast(std::ceil(profile.total_time / dt)) + 1; + velocities.reserve(num_points); + accelerations.reserve(num_points); + jerks.reserve(num_points); + + for (double t = 0.0; t <= profile.total_time; t += dt) { + velocities.push_back(getVelocityAtTime(profile, t)); + accelerations.push_back(getAccelerationAtTime(profile, t)); + jerks.push_back(getJerkAtTime(profile, t)); + } + + if (velocities.empty() || std::abs(velocities.back() - profile.vf) > VELOCITY_THRESHOLD) { + velocities.push_back(profile.vf); + accelerations.push_back(0.0); + jerks.push_back(0.0); + } +} + +double SCurveVelocityPlanner1D::update(double dt) +{ + if (dt <= 0.0) { + return state_.velocity; + } + + if (!state_.has_active_profile || !active_profile_.valid) { + state_.jerk = 0.0; + updateIsMovingFlag(); + return state_.velocity; + } + + state_.elapsed_time += dt; + + if (state_.elapsed_time >= active_profile_.total_time) { + state_.elapsed_time = active_profile_.total_time; + state_.velocity = active_profile_.vf; + state_.acceleration = 0.0; + state_.jerk = 0.0; + state_.has_active_profile = false; + updateIsMovingFlag(); + return state_.velocity; + } + + state_.velocity = getVelocityAtTime(active_profile_, state_.elapsed_time); + state_.acceleration = getAccelerationAtTime(active_profile_, state_.elapsed_time); + state_.jerk = getJerkAtTime(active_profile_, state_.elapsed_time); + + updateIsMovingFlag(); + return state_.velocity; +} + +void SCurveVelocityPlanner1D::updateIsMovingFlag() +{ + state_.is_moving = + state_.has_active_profile || + std::abs(state_.velocity) > VELOCITY_THRESHOLD || + std::abs(state_.target_velocity) > VELOCITY_THRESHOLD || + std::abs(state_.acceleration) > ACCELERATION_THRESHOLD; +} + +} // namespace cmvr diff --git a/file_service.erpc b/file_service.erpc new file mode 100644 index 0000000..49731ae --- /dev/null +++ b/file_service.erpc @@ -0,0 +1,11 @@ +// file_service.erpc +program file_service + +@id(2) +interface file_service +{ + fileWriteBegin(string path, uint32 total_size) -> int32 + fileWriteChunk(binary data) -> int32 + fileWriteEnd() -> int32 + fileWriteAbort() -> int32 +} diff --git a/file_service/__init__.py b/file_service/__init__.py new file mode 100644 index 0000000..83fca68 --- /dev/null +++ b/file_service/__init__.py @@ -0,0 +1,19 @@ +# +# Generated by erpcgen 1.14.0 on Tue Apr 28 12:25:45 2026. +# +# AUTOGENERATED - DO NOT EDIT +# + +try: + from erpc import erpc_version + version = erpc_version.ERPC_VERSION +except ImportError: + version = "unknown" +if version != "1.14.0": + raise ValueError("The generated shim code version (1.14.0) is different to the rest of eRPC code (%s). \ +Install newer version by running \"python setup.py install\" in folder erpc/erpc_python/." % repr(version)) + +from . import common +from . import client +from . import server +from . import interface diff --git a/file_service/__pycache__/__init__.cpython-310.pyc b/file_service/__pycache__/__init__.cpython-310.pyc new file mode 100644 index 0000000..a2c5904 Binary files /dev/null and b/file_service/__pycache__/__init__.cpython-310.pyc differ diff --git a/file_service/__pycache__/client.cpython-310.pyc b/file_service/__pycache__/client.cpython-310.pyc new file mode 100644 index 0000000..d1af51b Binary files /dev/null and b/file_service/__pycache__/client.cpython-310.pyc differ diff --git a/file_service/__pycache__/common.cpython-310.pyc b/file_service/__pycache__/common.cpython-310.pyc new file mode 100644 index 0000000..0d573b5 Binary files /dev/null and b/file_service/__pycache__/common.cpython-310.pyc differ diff --git a/file_service/__pycache__/interface.cpython-310.pyc b/file_service/__pycache__/interface.cpython-310.pyc new file mode 100644 index 0000000..fac27fd Binary files /dev/null and b/file_service/__pycache__/interface.cpython-310.pyc differ diff --git a/file_service/__pycache__/server.cpython-310.pyc b/file_service/__pycache__/server.cpython-310.pyc new file mode 100644 index 0000000..11cca28 Binary files /dev/null and b/file_service/__pycache__/server.cpython-310.pyc differ diff --git a/file_service/client.py b/file_service/client.py new file mode 100644 index 0000000..14a3780 --- /dev/null +++ b/file_service/client.py @@ -0,0 +1,85 @@ +# +# Generated by erpcgen 1.14.0 on Tue Apr 28 12:25:45 2026. +# +# AUTOGENERATED - DO NOT EDIT +# + +import erpc +from . import common, interface + +# Client for file_service +class file_serviceClient(interface.Ifile_service): + def __init__(self, manager): + super(file_serviceClient, self).__init__() + self._clientManager = manager + + def fileWriteBegin(self, path, total_size): + # Build remote function invocation message. + request = self._clientManager.create_request() + codec = request.codec + codec.start_write_message(erpc.codec.MessageInfo( + type=erpc.codec.MessageType.kInvocationMessage, + service=self.SERVICE_ID, + request=self.FILEWRITEBEGIN_ID, + sequence=request.sequence)) + if path is None: + raise ValueError("path is None") + codec.write_string(path) + if total_size is None: + raise ValueError("total_size is None") + codec.write_uint32(total_size) + + # Send request and process reply. + self._clientManager.perform_request(request) + _result = codec.read_int32() + return _result + + def fileWriteChunk(self, data): + # Build remote function invocation message. + request = self._clientManager.create_request() + codec = request.codec + codec.start_write_message(erpc.codec.MessageInfo( + type=erpc.codec.MessageType.kInvocationMessage, + service=self.SERVICE_ID, + request=self.FILEWRITECHUNK_ID, + sequence=request.sequence)) + if data is None: + raise ValueError("data is None") + codec.write_binary(data) + + # Send request and process reply. + self._clientManager.perform_request(request) + _result = codec.read_int32() + return _result + + def fileWriteEnd(self): + # Build remote function invocation message. + request = self._clientManager.create_request() + codec = request.codec + codec.start_write_message(erpc.codec.MessageInfo( + type=erpc.codec.MessageType.kInvocationMessage, + service=self.SERVICE_ID, + request=self.FILEWRITEEND_ID, + sequence=request.sequence)) + + # Send request and process reply. + self._clientManager.perform_request(request) + _result = codec.read_int32() + return _result + + def fileWriteAbort(self): + # Build remote function invocation message. + request = self._clientManager.create_request() + codec = request.codec + codec.start_write_message(erpc.codec.MessageInfo( + type=erpc.codec.MessageType.kInvocationMessage, + service=self.SERVICE_ID, + request=self.FILEWRITEABORT_ID, + sequence=request.sequence)) + + # Send request and process reply. + self._clientManager.perform_request(request) + _result = codec.read_int32() + return _result + + diff --git a/file_service/common.py b/file_service/common.py new file mode 100644 index 0000000..792db11 --- /dev/null +++ b/file_service/common.py @@ -0,0 +1,7 @@ +# +# Generated by erpcgen 1.14.0 on Tue Apr 28 12:25:45 2026. +# +# AUTOGENERATED - DO NOT EDIT +# + + diff --git a/file_service/interface.py b/file_service/interface.py new file mode 100644 index 0000000..ebad64f --- /dev/null +++ b/file_service/interface.py @@ -0,0 +1,27 @@ +# +# Generated by erpcgen 1.14.0 on Tue Apr 28 12:25:45 2026. +# +# AUTOGENERATED - DO NOT EDIT +# + +# Abstract base class for file_service +class Ifile_service(object): + SERVICE_ID = 2 + FILEWRITEBEGIN_ID = 1 + FILEWRITECHUNK_ID = 2 + FILEWRITEEND_ID = 3 + FILEWRITEABORT_ID = 4 + + def fileWriteBegin(self, path, total_size): + raise NotImplementedError() + + def fileWriteChunk(self, data): + raise NotImplementedError() + + def fileWriteEnd(self): + raise NotImplementedError() + + def fileWriteAbort(self): + raise NotImplementedError() + + diff --git a/file_service/server.py b/file_service/server.py new file mode 100644 index 0000000..c97ccfc --- /dev/null +++ b/file_service/server.py @@ -0,0 +1,93 @@ +# +# Generated by erpcgen 1.14.0 on Tue Apr 28 12:25:45 2026. +# +# AUTOGENERATED - DO NOT EDIT +# + +import erpc +from . import common, interface + +# Client for file_service +class file_serviceService(erpc.server.Service): + def __init__(self, handler): + super(file_serviceService, self).__init__(interface.Ifile_service.SERVICE_ID) + self._handler = handler + self._methods = { + interface.Ifile_service.FILEWRITEBEGIN_ID: self._handle_fileWriteBegin, + interface.Ifile_service.FILEWRITECHUNK_ID: self._handle_fileWriteChunk, + interface.Ifile_service.FILEWRITEEND_ID: self._handle_fileWriteEnd, + interface.Ifile_service.FILEWRITEABORT_ID: self._handle_fileWriteAbort, + } + + def _handle_fileWriteBegin(self, sequence, codec): + # Read incoming parameters. + path = codec.read_string() + total_size = codec.read_uint32() + + # Invoke user implementation of remote function. + _result = self._handler.fileWriteBegin(path, total_size) + + # Prepare codec for reply message. + codec.reset() + + # Construct reply message. + codec.start_write_message(erpc.codec.MessageInfo( + type=erpc.codec.MessageType.kReplyMessage, + service=interface.Ifile_service.SERVICE_ID, + request=interface.Ifile_service.FILEWRITEBEGIN_ID, + sequence=sequence)) + codec.write_int32(_result) + + def _handle_fileWriteChunk(self, sequence, codec): + # Read incoming parameters. + data = codec.read_binary() + + # Invoke user implementation of remote function. + _result = self._handler.fileWriteChunk(data) + + # Prepare codec for reply message. + codec.reset() + + # Construct reply message. + codec.start_write_message(erpc.codec.MessageInfo( + type=erpc.codec.MessageType.kReplyMessage, + service=interface.Ifile_service.SERVICE_ID, + request=interface.Ifile_service.FILEWRITECHUNK_ID, + sequence=sequence)) + codec.write_int32(_result) + + def _handle_fileWriteEnd(self, sequence, codec): + # Read incoming parameters. + + # Invoke user implementation of remote function. + _result = self._handler.fileWriteEnd() + + # Prepare codec for reply message. + codec.reset() + + # Construct reply message. + codec.start_write_message(erpc.codec.MessageInfo( + type=erpc.codec.MessageType.kReplyMessage, + service=interface.Ifile_service.SERVICE_ID, + request=interface.Ifile_service.FILEWRITEEND_ID, + sequence=sequence)) + codec.write_int32(_result) + + def _handle_fileWriteAbort(self, sequence, codec): + # Read incoming parameters. + + # Invoke user implementation of remote function. + _result = self._handler.fileWriteAbort() + + # Prepare codec for reply message. + codec.reset() + + # Construct reply message. + codec.start_write_message(erpc.codec.MessageInfo( + type=erpc.codec.MessageType.kReplyMessage, + service=interface.Ifile_service.SERVICE_ID, + request=interface.Ifile_service.FILEWRITEABORT_ID, + sequence=sequence)) + codec.write_int32(_result) + + diff --git a/generated/c_file_service_client.cpp b/generated/c_file_service_client.cpp new file mode 100644 index 0000000..1867f63 --- /dev/null +++ b/generated/c_file_service_client.cpp @@ -0,0 +1,77 @@ +/* + * Generated by erpcgen 1.14.0 on Tue Apr 28 12:16:37 2026. + * + * AUTOGENERATED - DO NOT EDIT + */ + + +#include "c_file_service_client.h" +#include "file_service_client.hpp" +#include "erpc_manually_constructed.hpp" + +using namespace erpc; +using namespace std; +using namespace erpcShim; + + +#if ERPC_ALLOCATION_POLICY == ERPC_ALLOCATION_POLICY_DYNAMIC +file_service_client *s_file_service_client = nullptr; +#else +ERPC_MANUALLY_CONSTRUCTED_STATIC(file_service_client, s_file_service_client); +#endif + +int32_t fileWriteBegin(const char * path, uint32_t total_size) +{ + int32_t result; + result = s_file_service_client->fileWriteBegin(path, total_size); + + return result; +} + +int32_t fileWriteChunk(const binary_t * data) +{ + int32_t result; + result = s_file_service_client->fileWriteChunk(data); + + return result; +} + +int32_t fileWriteEnd(void) +{ + int32_t result; + result = s_file_service_client->fileWriteEnd(); + + return result; +} + +int32_t fileWriteAbort(void) +{ + int32_t result; + result = s_file_service_client->fileWriteAbort(); + + return result; +} + +void initfile_service_client(erpc_client_t client) +{ +#if ERPC_ALLOCATION_POLICY == ERPC_ALLOCATION_POLICY_DYNAMIC + erpc_assert(s_file_service_client == nullptr); + s_file_service_client = new file_service_client(reinterpret_cast(client)); +#else + erpc_assert(!s_file_service_client.isUsed()); + s_file_service_client.construct(reinterpret_cast(client)); +#endif +} + +void deinitfile_service_client(void) +{ +#if ERPC_ALLOCATION_POLICY == ERPC_ALLOCATION_POLICY_DYNAMIC + if (s_file_service_client != nullptr) + { + delete s_file_service_client; + s_file_service_client = nullptr; + } +#else + s_file_service_client.destroy(); +#endif +} diff --git a/generated/c_file_service_client.h b/generated/c_file_service_client.h new file mode 100644 index 0000000..c05aade --- /dev/null +++ b/generated/c_file_service_client.h @@ -0,0 +1,54 @@ +/* + * Generated by erpcgen 1.14.0 on Tue Apr 28 12:16:37 2026. + * + * AUTOGENERATED - DO NOT EDIT + */ + + +#if !defined(_c_file_service_client_h_) +#define _c_file_service_client_h_ + +#include "file_service_common.h" +#include "erpc_client_manager.h" + +#if defined(__cplusplus) +extern "C" +{ +#endif + +#if !defined(ERPC_FUNCTIONS_DEFINITIONS) +#define ERPC_FUNCTIONS_DEFINITIONS + + +/*! @brief file_service identifiers */ +enum _file_service_ids +{ + kfile_service_service_id = 2, + kfile_service_fileWriteBegin_id = 1, + kfile_service_fileWriteChunk_id = 2, + kfile_service_fileWriteEnd_id = 3, + kfile_service_fileWriteAbort_id = 4, +}; + +//! @name file_service +//@{ +int32_t fileWriteBegin(const char * path, uint32_t total_size); + +int32_t fileWriteChunk(const binary_t * data); + +int32_t fileWriteEnd(void); + +int32_t fileWriteAbort(void); +//@} + +#endif // ERPC_FUNCTIONS_DEFINITIONS + +void initfile_service_client(erpc_client_t client); + +void deinitfile_service_client(void); + +#if defined(__cplusplus) +} +#endif + +#endif // _c_file_service_client_h_ diff --git a/generated/c_file_service_server.cpp b/generated/c_file_service_server.cpp new file mode 100644 index 0000000..839a974 --- /dev/null +++ b/generated/c_file_service_server.cpp @@ -0,0 +1,97 @@ +/* + * Generated by erpcgen 1.14.0 on Tue Apr 28 12:16:37 2026. + * + * AUTOGENERATED - DO NOT EDIT + */ + + +#include +#include "c_file_service_server.h" +#include "file_service_server.hpp" +#include "erpc_manually_constructed.hpp" + +using namespace erpc; +using namespace std; +using namespace erpcShim; + + +class file_service_server: public file_service_interface +{ + public: + virtual ~file_service_server() {}; + + + int32_t fileWriteBegin(const char * path, uint32_t total_size) + { + int32_t result; + result = ::fileWriteBegin(path, total_size); + + return result; + } + + int32_t fileWriteChunk(const binary_t * data) + { + int32_t result; + result = ::fileWriteChunk(data); + + return result; + } + + int32_t fileWriteEnd(void) + { + int32_t result; + result = ::fileWriteEnd(); + + return result; + } + + int32_t fileWriteAbort(void) + { + int32_t result; + result = ::fileWriteAbort(); + + return result; + } +}; + +ERPC_MANUALLY_CONSTRUCTED_STATIC(file_service_service, s_file_service_service); +ERPC_MANUALLY_CONSTRUCTED_STATIC(file_service_server, s_file_service_server); + +erpc_service_t create_file_service_service(void) +{ + erpc_service_t service; + +#if ERPC_ALLOCATION_POLICY == ERPC_ALLOCATION_POLICY_DYNAMIC + service = new (nothrow) file_service_service(new (nothrow)file_service_server()); +#else + if (s_file_service_service.isUsed()) + { + service = NULL; + } + else + { + s_file_service_server.construct(); + s_file_service_service.construct(s_file_service_server.get()); + service = s_file_service_service.get(); + } +#endif + + return service; +} + +void destroy_file_service_service(erpc_service_t service) +{ +#if ERPC_ALLOCATION_POLICY == ERPC_ALLOCATION_POLICY_DYNAMIC + if (service) + { + delete (file_service_server *)(((file_service_service *)service)->getHandler()); + delete (file_service_service *)service; + } +#else + (void)service; + erpc_assert(service == s_file_service_service.get()); + s_file_service_service.destroy(); + s_file_service_server.destroy(); +#endif +} + diff --git a/generated/c_file_service_server.h b/generated/c_file_service_server.h new file mode 100644 index 0000000..ae7e34e --- /dev/null +++ b/generated/c_file_service_server.h @@ -0,0 +1,59 @@ +/* + * Generated by erpcgen 1.14.0 on Tue Apr 28 12:16:37 2026. + * + * AUTOGENERATED - DO NOT EDIT + */ + + +#if !defined(_c_file_service_server_h_) +#define _c_file_service_server_h_ + +#include "file_service_common.h" + +#if defined(__cplusplus) +extern "C" +{ +#endif + +typedef void * erpc_service_t; + +#if !defined(ERPC_FUNCTIONS_DEFINITIONS) +#define ERPC_FUNCTIONS_DEFINITIONS + + +/*! @brief file_service identifiers */ +enum _file_service_ids +{ + kfile_service_service_id = 2, + kfile_service_fileWriteBegin_id = 1, + kfile_service_fileWriteChunk_id = 2, + kfile_service_fileWriteEnd_id = 3, + kfile_service_fileWriteAbort_id = 4, +}; + +//! @name file_service +//@{ +int32_t fileWriteBegin(const char * path, uint32_t total_size); + +int32_t fileWriteChunk(const binary_t * data); + +int32_t fileWriteEnd(void); + +int32_t fileWriteAbort(void); +//@} + + +#endif // ERPC_FUNCTIONS_DEFINITIONS + +/*! @brief Return file_service_service service object. */ +erpc_service_t create_file_service_service(void); + +/*! @brief Destroy file_service_service service object. */ +void destroy_file_service_service(erpc_service_t service); + + +#if defined(__cplusplus) +} +#endif + +#endif // _c_file_service_server_h_ diff --git a/generated/c_servo_service_client.cpp b/generated/c_servo_service_client.cpp new file mode 100644 index 0000000..03036f1 --- /dev/null +++ b/generated/c_servo_service_client.cpp @@ -0,0 +1,93 @@ +/* + * Generated by erpcgen 1.14.0 on Tue Apr 28 12:16:31 2026. + * + * AUTOGENERATED - DO NOT EDIT + */ + + +#include "c_servo_service_client.h" +#include "servo_service_client.hpp" +#include "erpc_manually_constructed.hpp" + +using namespace erpc; +using namespace std; +using namespace erpcShim; + + +#if ERPC_ALLOCATION_POLICY == ERPC_ALLOCATION_POLICY_DYNAMIC +servo_service_client *s_servo_service_client = nullptr; +#else +ERPC_MANUALLY_CONSTRUCTED_STATIC(servo_service_client, s_servo_service_client); +#endif + +bool setConstraints(const char * id, float max_velocity_rad, float max_acceleration_rad, float max_jerk_rad) +{ + bool result; + result = s_servo_service_client->setConstraints(id, max_velocity_rad, max_acceleration_rad, max_jerk_rad); + + return result; +} + +bool setPositionGain(const char * id, float position_gain) +{ + bool result; + result = s_servo_service_client->setPositionGain(id, position_gain); + + return result; +} + +bool setMode(RpcMotionMode mode) +{ + bool result; + result = s_servo_service_client->setMode(mode); + + return result; +} + +bool setUpdatePeriodMs(uint32_t ms) +{ + bool result; + result = s_servo_service_client->setUpdatePeriodMs(ms); + + return result; +} + +int32_t move(const list_ServoCmd_1_t * cmds) +{ + int32_t result; + result = s_servo_service_client->move(cmds); + + return result; +} + +int32_t moveJ(const list_float_1_t * angles_rad) +{ + int32_t result; + result = s_servo_service_client->moveJ(angles_rad); + + return result; +} + +void initservo_service_client(erpc_client_t client) +{ +#if ERPC_ALLOCATION_POLICY == ERPC_ALLOCATION_POLICY_DYNAMIC + erpc_assert(s_servo_service_client == nullptr); + s_servo_service_client = new servo_service_client(reinterpret_cast(client)); +#else + erpc_assert(!s_servo_service_client.isUsed()); + s_servo_service_client.construct(reinterpret_cast(client)); +#endif +} + +void deinitservo_service_client(void) +{ +#if ERPC_ALLOCATION_POLICY == ERPC_ALLOCATION_POLICY_DYNAMIC + if (s_servo_service_client != nullptr) + { + delete s_servo_service_client; + s_servo_service_client = nullptr; + } +#else + s_servo_service_client.destroy(); +#endif +} diff --git a/generated/c_servo_service_client.h b/generated/c_servo_service_client.h new file mode 100644 index 0000000..1dfa6ad --- /dev/null +++ b/generated/c_servo_service_client.h @@ -0,0 +1,60 @@ +/* + * Generated by erpcgen 1.14.0 on Tue Apr 28 12:16:31 2026. + * + * AUTOGENERATED - DO NOT EDIT + */ + + +#if !defined(_c_servo_service_client_h_) +#define _c_servo_service_client_h_ + +#include "servo_service_common.h" +#include "erpc_client_manager.h" + +#if defined(__cplusplus) +extern "C" +{ +#endif + +#if !defined(ERPC_FUNCTIONS_DEFINITIONS) +#define ERPC_FUNCTIONS_DEFINITIONS + + +/*! @brief servo_service identifiers */ +enum _servo_service_ids +{ + kservo_service_service_id = 1, + kservo_service_setConstraints_id = 1, + kservo_service_setPositionGain_id = 2, + kservo_service_setMode_id = 3, + kservo_service_setUpdatePeriodMs_id = 4, + kservo_service_move_id = 5, + kservo_service_moveJ_id = 6, +}; + +//! @name servo_service +//@{ +bool setConstraints(const char * id, float max_velocity_rad, float max_acceleration_rad, float max_jerk_rad); + +bool setPositionGain(const char * id, float position_gain); + +bool setMode(RpcMotionMode mode); + +bool setUpdatePeriodMs(uint32_t ms); + +int32_t move(const list_ServoCmd_1_t * cmds); + +int32_t moveJ(const list_float_1_t * angles_rad); +//@} + +#endif // ERPC_FUNCTIONS_DEFINITIONS + +void initservo_service_client(erpc_client_t client); + +void deinitservo_service_client(void); + +#if defined(__cplusplus) +} +#endif + +#endif // _c_servo_service_client_h_ diff --git a/generated/c_servo_service_server.cpp b/generated/c_servo_service_server.cpp new file mode 100644 index 0000000..99a6b28 --- /dev/null +++ b/generated/c_servo_service_server.cpp @@ -0,0 +1,113 @@ +/* + * Generated by erpcgen 1.14.0 on Tue Apr 28 12:16:31 2026. + * + * AUTOGENERATED - DO NOT EDIT + */ + + +#include +#include "c_servo_service_server.h" +#include "servo_service_server.hpp" +#include "erpc_manually_constructed.hpp" + +using namespace erpc; +using namespace std; +using namespace erpcShim; + + +class servo_service_server: public servo_service_interface +{ + public: + virtual ~servo_service_server() {}; + + + bool setConstraints(const char * id, float max_velocity_rad, float max_acceleration_rad, float max_jerk_rad) + { + bool result; + result = ::setConstraints(id, max_velocity_rad, max_acceleration_rad, max_jerk_rad); + + return result; + } + + bool setPositionGain(const char * id, float position_gain) + { + bool result; + result = ::setPositionGain(id, position_gain); + + return result; + } + + bool setMode(RpcMotionMode mode) + { + bool result; + result = ::setMode(mode); + + return result; + } + + bool setUpdatePeriodMs(uint32_t ms) + { + bool result; + result = ::setUpdatePeriodMs(ms); + + return result; + } + + int32_t move(const list_ServoCmd_1_t * cmds) + { + int32_t result; + result = ::move(cmds); + + return result; + } + + int32_t moveJ(const list_float_1_t * angles_rad) + { + int32_t result; + result = ::moveJ(angles_rad); + + return result; + } +}; + +ERPC_MANUALLY_CONSTRUCTED_STATIC(servo_service_service, s_servo_service_service); +ERPC_MANUALLY_CONSTRUCTED_STATIC(servo_service_server, s_servo_service_server); + +erpc_service_t create_servo_service_service(void) +{ + erpc_service_t service; + +#if ERPC_ALLOCATION_POLICY == ERPC_ALLOCATION_POLICY_DYNAMIC + service = new (nothrow) servo_service_service(new (nothrow)servo_service_server()); +#else + if (s_servo_service_service.isUsed()) + { + service = NULL; + } + else + { + s_servo_service_server.construct(); + s_servo_service_service.construct(s_servo_service_server.get()); + service = s_servo_service_service.get(); + } +#endif + + return service; +} + +void destroy_servo_service_service(erpc_service_t service) +{ +#if ERPC_ALLOCATION_POLICY == ERPC_ALLOCATION_POLICY_DYNAMIC + if (service) + { + delete (servo_service_server *)(((servo_service_service *)service)->getHandler()); + delete (servo_service_service *)service; + } +#else + (void)service; + erpc_assert(service == s_servo_service_service.get()); + s_servo_service_service.destroy(); + s_servo_service_server.destroy(); +#endif +} + diff --git a/generated/c_servo_service_server.h b/generated/c_servo_service_server.h new file mode 100644 index 0000000..2def2f4 --- /dev/null +++ b/generated/c_servo_service_server.h @@ -0,0 +1,65 @@ +/* + * Generated by erpcgen 1.14.0 on Tue Apr 28 12:16:31 2026. + * + * AUTOGENERATED - DO NOT EDIT + */ + + +#if !defined(_c_servo_service_server_h_) +#define _c_servo_service_server_h_ + +#include "servo_service_common.h" + +#if defined(__cplusplus) +extern "C" +{ +#endif + +typedef void * erpc_service_t; + +#if !defined(ERPC_FUNCTIONS_DEFINITIONS) +#define ERPC_FUNCTIONS_DEFINITIONS + + +/*! @brief servo_service identifiers */ +enum _servo_service_ids +{ + kservo_service_service_id = 1, + kservo_service_setConstraints_id = 1, + kservo_service_setPositionGain_id = 2, + kservo_service_setMode_id = 3, + kservo_service_setUpdatePeriodMs_id = 4, + kservo_service_move_id = 5, + kservo_service_moveJ_id = 6, +}; + +//! @name servo_service +//@{ +bool setConstraints(const char * id, float max_velocity_rad, float max_acceleration_rad, float max_jerk_rad); + +bool setPositionGain(const char * id, float position_gain); + +bool setMode(RpcMotionMode mode); + +bool setUpdatePeriodMs(uint32_t ms); + +int32_t move(const list_ServoCmd_1_t * cmds); + +int32_t moveJ(const list_float_1_t * angles_rad); +//@} + + +#endif // ERPC_FUNCTIONS_DEFINITIONS + +/*! @brief Return servo_service_service service object. */ +erpc_service_t create_servo_service_service(void); + +/*! @brief Destroy servo_service_service service object. */ +void destroy_servo_service_service(erpc_service_t service); + + +#if defined(__cplusplus) +} +#endif + +#endif // _c_servo_service_server_h_ diff --git a/generated/file_service_client.cpp b/generated/file_service_client.cpp new file mode 100644 index 0000000..19ca4d4 --- /dev/null +++ b/generated/file_service_client.cpp @@ -0,0 +1,302 @@ +/* + * Generated by erpcgen 1.14.0 on Tue Apr 28 12:16:37 2026. + * + * AUTOGENERATED - DO NOT EDIT + */ + + +#if ERPC_ALLOCATION_POLICY == ERPC_ALLOCATION_POLICY_DYNAMIC +#include "erpc_port.h" +#endif +#include "erpc_codec.hpp" +#include "file_service_client.hpp" +#include "erpc_manually_constructed.hpp" + +#if 11400 != ERPC_VERSION_NUMBER +#error "The generated shim code version is different to the rest of eRPC code." +#endif + +using namespace erpc; +using namespace std; +using namespace erpcShim; + +//! @brief Function to write struct binary_t +static void write_binary_t_struct(erpc::Codec * codec, const binary_t * data); + + +// Write struct binary_t function implementation +static void write_binary_t_struct(erpc::Codec * codec, const binary_t * data) +{ + if(NULL == data) + { + return; + } + + codec->writeBinary(data->dataLength, data->data); +} + + + + +file_service_client::file_service_client(ClientManager *manager) +:m_clientManager(manager) +{ +} + +file_service_client::~file_service_client() +{ +} + +// file_service interface fileWriteBegin function client shim. +int32_t file_service_client::fileWriteBegin(const char * path, uint32_t total_size) +{ + erpc_status_t err = kErpcStatus_Success; + + int32_t result; + +#if ERPC_PRE_POST_ACTION + pre_post_action_cb preCB = m_clientManager->getPreCB(); + if (preCB) + { + preCB(); + } +#endif + + // Get a new request. + RequestContext request = m_clientManager->createRequest(false); + + // Encode the request. + Codec * codec = request.getCodec(); + + if (codec == NULL) + { + err = kErpcStatus_MemoryError; + } + else + { + codec->startWriteMessage(message_type_t::kInvocationMessage, m_serviceId, m_fileWriteBeginId, request.getSequence()); + + { + uint32_t path_len = strlen((const char*)path); + + codec->writeString(path_len, (const char*)path); + } + + codec->write(total_size); + + // Send message to server + // Codec status is checked inside this function. + m_clientManager->performRequest(request); + + codec->read(result); + + err = codec->getStatus(); + } + + // Dispose of the request. + m_clientManager->releaseRequest(request); + + // Invoke error handler callback function + m_clientManager->callErrorHandler(err, m_fileWriteBeginId); + +#if ERPC_PRE_POST_ACTION + pre_post_action_cb postCB = m_clientManager->getPostCB(); + if (postCB) + { + postCB(); + } +#endif + + + if (err != kErpcStatus_Success) + { + result = -1; + } + + return result; +} + +// file_service interface fileWriteChunk function client shim. +int32_t file_service_client::fileWriteChunk(const binary_t * data) +{ + erpc_status_t err = kErpcStatus_Success; + + int32_t result; + +#if ERPC_PRE_POST_ACTION + pre_post_action_cb preCB = m_clientManager->getPreCB(); + if (preCB) + { + preCB(); + } +#endif + + // Get a new request. + RequestContext request = m_clientManager->createRequest(false); + + // Encode the request. + Codec * codec = request.getCodec(); + + if (codec == NULL) + { + err = kErpcStatus_MemoryError; + } + else + { + codec->startWriteMessage(message_type_t::kInvocationMessage, m_serviceId, m_fileWriteChunkId, request.getSequence()); + + write_binary_t_struct(codec, data); + + // Send message to server + // Codec status is checked inside this function. + m_clientManager->performRequest(request); + + codec->read(result); + + err = codec->getStatus(); + } + + // Dispose of the request. + m_clientManager->releaseRequest(request); + + // Invoke error handler callback function + m_clientManager->callErrorHandler(err, m_fileWriteChunkId); + +#if ERPC_PRE_POST_ACTION + pre_post_action_cb postCB = m_clientManager->getPostCB(); + if (postCB) + { + postCB(); + } +#endif + + + if (err != kErpcStatus_Success) + { + result = -1; + } + + return result; +} + +// file_service interface fileWriteEnd function client shim. +int32_t file_service_client::fileWriteEnd(void) +{ + erpc_status_t err = kErpcStatus_Success; + + int32_t result; + +#if ERPC_PRE_POST_ACTION + pre_post_action_cb preCB = m_clientManager->getPreCB(); + if (preCB) + { + preCB(); + } +#endif + + // Get a new request. + RequestContext request = m_clientManager->createRequest(false); + + // Encode the request. + Codec * codec = request.getCodec(); + + if (codec == NULL) + { + err = kErpcStatus_MemoryError; + } + else + { + codec->startWriteMessage(message_type_t::kInvocationMessage, m_serviceId, m_fileWriteEndId, request.getSequence()); + + // Send message to server + // Codec status is checked inside this function. + m_clientManager->performRequest(request); + + codec->read(result); + + err = codec->getStatus(); + } + + // Dispose of the request. + m_clientManager->releaseRequest(request); + + // Invoke error handler callback function + m_clientManager->callErrorHandler(err, m_fileWriteEndId); + +#if ERPC_PRE_POST_ACTION + pre_post_action_cb postCB = m_clientManager->getPostCB(); + if (postCB) + { + postCB(); + } +#endif + + + if (err != kErpcStatus_Success) + { + result = -1; + } + + return result; +} + +// file_service interface fileWriteAbort function client shim. +int32_t file_service_client::fileWriteAbort(void) +{ + erpc_status_t err = kErpcStatus_Success; + + int32_t result; + +#if ERPC_PRE_POST_ACTION + pre_post_action_cb preCB = m_clientManager->getPreCB(); + if (preCB) + { + preCB(); + } +#endif + + // Get a new request. + RequestContext request = m_clientManager->createRequest(false); + + // Encode the request. + Codec * codec = request.getCodec(); + + if (codec == NULL) + { + err = kErpcStatus_MemoryError; + } + else + { + codec->startWriteMessage(message_type_t::kInvocationMessage, m_serviceId, m_fileWriteAbortId, request.getSequence()); + + // Send message to server + // Codec status is checked inside this function. + m_clientManager->performRequest(request); + + codec->read(result); + + err = codec->getStatus(); + } + + // Dispose of the request. + m_clientManager->releaseRequest(request); + + // Invoke error handler callback function + m_clientManager->callErrorHandler(err, m_fileWriteAbortId); + +#if ERPC_PRE_POST_ACTION + pre_post_action_cb postCB = m_clientManager->getPostCB(); + if (postCB) + { + postCB(); + } +#endif + + + if (err != kErpcStatus_Success) + { + result = -1; + } + + return result; +} diff --git a/generated/file_service_client.hpp b/generated/file_service_client.hpp new file mode 100644 index 0000000..b62cc73 --- /dev/null +++ b/generated/file_service_client.hpp @@ -0,0 +1,40 @@ +/* + * Generated by erpcgen 1.14.0 on Tue Apr 28 12:16:37 2026. + * + * AUTOGENERATED - DO NOT EDIT + */ + + +#if !defined(_file_service_client_hpp_) +#define _file_service_client_hpp_ + +#include "file_service_interface.hpp" + +#include "erpc_client_manager.h" + +namespace erpcShim +{ + +class file_service_client: public file_service_interface +{ + public: + file_service_client(erpc::ClientManager *manager); + + virtual ~file_service_client(); + + virtual int32_t fileWriteBegin(const char * path, uint32_t total_size); + + virtual int32_t fileWriteChunk(const binary_t * data); + + virtual int32_t fileWriteEnd(void); + + virtual int32_t fileWriteAbort(void); + + protected: + erpc::ClientManager *m_clientManager; +}; + +} // erpcShim + + +#endif // _file_service_client_hpp_ diff --git a/generated/file_service_common.h b/generated/file_service_common.h new file mode 100644 index 0000000..3a89eb7 --- /dev/null +++ b/generated/file_service_common.h @@ -0,0 +1,47 @@ +/* + * Generated by erpcgen 1.14.0 on Tue Apr 28 12:16:37 2026. + * + * AUTOGENERATED - DO NOT EDIT + */ + + +#if !defined(_file_service_common_h_) +#define _file_service_common_h_ + + +#if defined(__cplusplus) +extern "C" +{ +#endif +#include +#include +#include + +#include "erpc_version.h" + +#if 11400 != ERPC_VERSION_NUMBER +#error "The generated shim code version is different to the rest of eRPC code." +#endif + + +#if !defined(ERPC_TYPE_DEFINITIONS_FILE_SERVICE) +#define ERPC_TYPE_DEFINITIONS_FILE_SERVICE + +// Aliases data types declarations +typedef struct binary_t binary_t; + +// Structures/unions data types declarations +struct binary_t +{ + uint8_t * data; + uint32_t dataLength; +}; + + +#endif // ERPC_TYPE_DEFINITIONS_FILE_SERVICE + +#if defined(__cplusplus) +} +#endif + +#endif // _file_service_common_h_ diff --git a/generated/file_service_common.hpp b/generated/file_service_common.hpp new file mode 100644 index 0000000..f78a270 --- /dev/null +++ b/generated/file_service_common.hpp @@ -0,0 +1,39 @@ +/* + * Generated by erpcgen 1.14.0 on Tue Apr 28 12:16:37 2026. + * + * AUTOGENERATED - DO NOT EDIT + */ + + +#if !defined(_file_service_common_hpp_) +#define _file_service_common_hpp_ + + +#include +#include + +#include "erpc_version.h" + +#if 11400 != ERPC_VERSION_NUMBER +#error "The generated shim code version is different to the rest of eRPC code." +#endif + + +#if !defined(ERPC_TYPE_DEFINITIONS_FILE_SERVICE) +#define ERPC_TYPE_DEFINITIONS_FILE_SERVICE + +// Aliases data types declarations +typedef struct binary_t binary_t; + +// Structures/unions data types declarations +struct binary_t +{ + uint8_t * data; + uint32_t dataLength; +}; + + +#endif // ERPC_TYPE_DEFINITIONS_FILE_SERVICE + + +#endif // _file_service_common_hpp_ diff --git a/generated/file_service_interface.cpp b/generated/file_service_interface.cpp new file mode 100644 index 0000000..94388bd --- /dev/null +++ b/generated/file_service_interface.cpp @@ -0,0 +1,20 @@ +/* + * Generated by erpcgen 1.14.0 on Tue Apr 28 12:16:37 2026. + * + * AUTOGENERATED - DO NOT EDIT + */ + + +#include "file_service_interface.hpp" + +#if 11400 != ERPC_VERSION_NUMBER +#error "The generated shim code version is different to the rest of eRPC code." +#endif + + +using namespace std; +using namespace erpcShim; + +file_service_interface::~file_service_interface(void) +{ +} diff --git a/generated/file_service_interface.hpp b/generated/file_service_interface.hpp new file mode 100644 index 0000000..2920f2a --- /dev/null +++ b/generated/file_service_interface.hpp @@ -0,0 +1,41 @@ +/* + * Generated by erpcgen 1.14.0 on Tue Apr 28 12:16:37 2026. + * + * AUTOGENERATED - DO NOT EDIT + */ + + +#if !defined(_file_service_interface_hpp_) +#define _file_service_interface_hpp_ + +#include "file_service_common.hpp" + +namespace erpcShim +{ + + +// Abstract base class for file_service +class file_service_interface +{ + public: + static const uint8_t m_serviceId = 2; + static const uint8_t m_fileWriteBeginId = 1; + static const uint8_t m_fileWriteChunkId = 2; + static const uint8_t m_fileWriteEndId = 3; + static const uint8_t m_fileWriteAbortId = 4; + + virtual ~file_service_interface(void); + + virtual int32_t fileWriteBegin(const char * path, uint32_t total_size) = 0; + + virtual int32_t fileWriteChunk(const binary_t * data) = 0; + + virtual int32_t fileWriteEnd(void) = 0; + + virtual int32_t fileWriteAbort(void) = 0; +private: +}; +} // erpcShim + + +#endif // _file_service_interface_hpp_ diff --git a/generated/file_service_server.cpp b/generated/file_service_server.cpp new file mode 100644 index 0000000..6e960a9 --- /dev/null +++ b/generated/file_service_server.cpp @@ -0,0 +1,327 @@ +/* + * Generated by erpcgen 1.14.0 on Tue Apr 28 12:16:37 2026. + * + * AUTOGENERATED - DO NOT EDIT + */ + + +#include "file_service_server.hpp" +#if ERPC_ALLOCATION_POLICY == ERPC_ALLOCATION_POLICY_DYNAMIC +#include +#include "erpc_port.h" +#endif +#include "erpc_manually_constructed.hpp" + +#if 11400 != ERPC_VERSION_NUMBER +#error "The generated shim code version is different to the rest of eRPC code." +#endif + +using namespace erpc; +using namespace std; +using namespace erpcShim; + +#if ERPC_NESTED_CALLS_DETECTION +extern bool nestingDetection; +#endif + + +//! @brief Function to read struct binary_t +static void read_binary_t_struct(erpc::Codec * codec, binary_t * data); + + +// Read struct binary_t function implementation +static void read_binary_t_struct(erpc::Codec * codec, binary_t * data) +{ + if(NULL == data) + { + return; + } + + uint8_t * data_local; + codec->readBinary(data->dataLength, &data_local); + if (data->dataLength > 0) + { + data->data = (uint8_t *) erpc_malloc(data->dataLength * sizeof(uint8_t)); + if (data->data == NULL) + { + codec->updateStatus(kErpcStatus_MemoryError); + } + else + { + memcpy(data->data, data_local, data->dataLength); + } + } + else + { + data->data = NULL; + } +} + + +//! @brief Function to free space allocated inside struct binary_t +static void free_binary_t_struct(binary_t * data); + + +// Free space allocated inside struct binary_t function implementation +static void free_binary_t_struct(binary_t * data) +{ + erpc_free(data->data); +} + + + +file_service_service::file_service_service(file_service_interface *_file_service_interface) + : erpc::Service(file_service_interface::m_serviceId) + , m_handler(_file_service_interface) +{ +} + +file_service_service::~file_service_service() +{ +} + +// return service interface handler. +file_service_interface* file_service_service::getHandler(void) +{ + return m_handler; +} + +// Call the correct server shim based on method unique ID. +erpc_status_t file_service_service::handleInvocation(uint32_t methodId, uint32_t sequence, Codec * codec, MessageBufferFactory *messageFactory, Transport * transport) +{ + erpc_status_t erpcStatus; + switch (methodId) + { + case file_service_interface::m_fileWriteBeginId: + { + erpcStatus = fileWriteBegin_shim(codec, messageFactory, transport, sequence); + break; + } + + case file_service_interface::m_fileWriteChunkId: + { + erpcStatus = fileWriteChunk_shim(codec, messageFactory, transport, sequence); + break; + } + + case file_service_interface::m_fileWriteEndId: + { + erpcStatus = fileWriteEnd_shim(codec, messageFactory, transport, sequence); + break; + } + + case file_service_interface::m_fileWriteAbortId: + { + erpcStatus = fileWriteAbort_shim(codec, messageFactory, transport, sequence); + break; + } + + default: + { + erpcStatus = kErpcStatus_InvalidArgument; + break; + } + } + + return erpcStatus; +} + +// Server shim for fileWriteBegin of file_service interface. +erpc_status_t file_service_service::fileWriteBegin_shim(Codec * codec, MessageBufferFactory *messageFactory, Transport * transport, uint32_t sequence) +{ + erpc_status_t err = kErpcStatus_Success; + + char * path = NULL; + uint32_t total_size; + int32_t result; + + // startReadMessage() was already called before this shim was invoked. + + { + uint32_t path_len; + char * path_local; + codec->readString(path_len, &path_local); + path = (char*) erpc_malloc((path_len + 1) * sizeof(char)); + if ((path == NULL) || (path_local == NULL)) + { + codec->updateStatus(kErpcStatus_MemoryError); + } + else + { + memcpy(path, path_local, path_len); + (path)[path_len] = 0; + } + } + + codec->read(total_size); + + err = codec->getStatus(); + if (err == kErpcStatus_Success) + { + // Invoke the actual served function. +#if ERPC_NESTED_CALLS_DETECTION + nestingDetection = true; +#endif + result = m_handler->fileWriteBegin(path, total_size); +#if ERPC_NESTED_CALLS_DETECTION + nestingDetection = false; +#endif + + // preparing MessageBuffer for serializing data + err = messageFactory->prepareServerBufferForSend(codec->getBufferRef(), transport->reserveHeaderSize()); + } + + if (err == kErpcStatus_Success) + { + // preparing codec for serializing data + codec->reset(transport->reserveHeaderSize()); + + // Build response message. + codec->startWriteMessage(message_type_t::kReplyMessage, file_service_interface::m_serviceId, file_service_interface::m_fileWriteBeginId, sequence); + + codec->write(result); + + err = codec->getStatus(); + } + + erpc_free(path); + + return err; +} + +// Server shim for fileWriteChunk of file_service interface. +erpc_status_t file_service_service::fileWriteChunk_shim(Codec * codec, MessageBufferFactory *messageFactory, Transport * transport, uint32_t sequence) +{ + erpc_status_t err = kErpcStatus_Success; + + binary_t *data = NULL; + data = (binary_t *) erpc_malloc(sizeof(binary_t)); + if (data == NULL) + { + codec->updateStatus(kErpcStatus_MemoryError); + } + int32_t result; + + // startReadMessage() was already called before this shim was invoked. + + read_binary_t_struct(codec, data); + + err = codec->getStatus(); + if (err == kErpcStatus_Success) + { + // Invoke the actual served function. +#if ERPC_NESTED_CALLS_DETECTION + nestingDetection = true; +#endif + result = m_handler->fileWriteChunk(data); +#if ERPC_NESTED_CALLS_DETECTION + nestingDetection = false; +#endif + + // preparing MessageBuffer for serializing data + err = messageFactory->prepareServerBufferForSend(codec->getBufferRef(), transport->reserveHeaderSize()); + } + + if (err == kErpcStatus_Success) + { + // preparing codec for serializing data + codec->reset(transport->reserveHeaderSize()); + + // Build response message. + codec->startWriteMessage(message_type_t::kReplyMessage, file_service_interface::m_serviceId, file_service_interface::m_fileWriteChunkId, sequence); + + codec->write(result); + + err = codec->getStatus(); + } + + if (data) + { + free_binary_t_struct(data); + } + erpc_free(data); + + return err; +} + +// Server shim for fileWriteEnd of file_service interface. +erpc_status_t file_service_service::fileWriteEnd_shim(Codec * codec, MessageBufferFactory *messageFactory, Transport * transport, uint32_t sequence) +{ + erpc_status_t err = kErpcStatus_Success; + + int32_t result; + + // startReadMessage() was already called before this shim was invoked. + + err = codec->getStatus(); + if (err == kErpcStatus_Success) + { + // Invoke the actual served function. +#if ERPC_NESTED_CALLS_DETECTION + nestingDetection = true; +#endif + result = m_handler->fileWriteEnd(); +#if ERPC_NESTED_CALLS_DETECTION + nestingDetection = false; +#endif + + // preparing MessageBuffer for serializing data + err = messageFactory->prepareServerBufferForSend(codec->getBufferRef(), transport->reserveHeaderSize()); + } + + if (err == kErpcStatus_Success) + { + // preparing codec for serializing data + codec->reset(transport->reserveHeaderSize()); + + // Build response message. + codec->startWriteMessage(message_type_t::kReplyMessage, file_service_interface::m_serviceId, file_service_interface::m_fileWriteEndId, sequence); + + codec->write(result); + + err = codec->getStatus(); + } + + return err; +} + +// Server shim for fileWriteAbort of file_service interface. +erpc_status_t file_service_service::fileWriteAbort_shim(Codec * codec, MessageBufferFactory *messageFactory, Transport * transport, uint32_t sequence) +{ + erpc_status_t err = kErpcStatus_Success; + + int32_t result; + + // startReadMessage() was already called before this shim was invoked. + + err = codec->getStatus(); + if (err == kErpcStatus_Success) + { + // Invoke the actual served function. +#if ERPC_NESTED_CALLS_DETECTION + nestingDetection = true; +#endif + result = m_handler->fileWriteAbort(); +#if ERPC_NESTED_CALLS_DETECTION + nestingDetection = false; +#endif + + // preparing MessageBuffer for serializing data + err = messageFactory->prepareServerBufferForSend(codec->getBufferRef(), transport->reserveHeaderSize()); + } + + if (err == kErpcStatus_Success) + { + // preparing codec for serializing data + codec->reset(transport->reserveHeaderSize()); + + // Build response message. + codec->startWriteMessage(message_type_t::kReplyMessage, file_service_interface::m_serviceId, file_service_interface::m_fileWriteAbortId, sequence); + + codec->write(result); + + err = codec->getStatus(); + } + + return err; +} diff --git a/generated/file_service_server.hpp b/generated/file_service_server.hpp new file mode 100644 index 0000000..b850a59 --- /dev/null +++ b/generated/file_service_server.hpp @@ -0,0 +1,58 @@ +/* + * Generated by erpcgen 1.14.0 on Tue Apr 28 12:16:37 2026. + * + * AUTOGENERATED - DO NOT EDIT + */ + + +#if !defined(_file_service_server_hpp_) +#define _file_service_server_hpp_ + +#include "file_service_interface.hpp" + +#include "erpc_server.hpp" +#include "erpc_codec.hpp" + +#if 11400 != ERPC_VERSION_NUMBER +#error "The generated shim code version is different to the rest of eRPC code." +#endif + + +namespace erpcShim +{ + +/*! + * @brief Service subclass for file_service. + */ +class file_service_service : public erpc::Service +{ +public: + file_service_service(file_service_interface *_file_service_interface); + + virtual ~file_service_service(); + + /*! @brief return service interface handler. */ + file_service_interface* getHandler(void); + + /*! @brief Call the correct server shim based on method unique ID. */ + virtual erpc_status_t handleInvocation(uint32_t methodId, uint32_t sequence, erpc::Codec * codec, erpc::MessageBufferFactory *messageFactory, erpc::Transport * transport); + +private: + file_service_interface *m_handler; + /*! @brief Server shim for fileWriteBegin of file_service interface. */ + erpc_status_t fileWriteBegin_shim(erpc::Codec * codec, erpc::MessageBufferFactory *messageFactory, erpc::Transport * transport, uint32_t sequence); + + /*! @brief Server shim for fileWriteChunk of file_service interface. */ + erpc_status_t fileWriteChunk_shim(erpc::Codec * codec, erpc::MessageBufferFactory *messageFactory, erpc::Transport * transport, uint32_t sequence); + + /*! @brief Server shim for fileWriteEnd of file_service interface. */ + erpc_status_t fileWriteEnd_shim(erpc::Codec * codec, erpc::MessageBufferFactory *messageFactory, erpc::Transport * transport, uint32_t sequence); + + /*! @brief Server shim for fileWriteAbort of file_service interface. */ + erpc_status_t fileWriteAbort_shim(erpc::Codec * codec, erpc::MessageBufferFactory *messageFactory, erpc::Transport * transport, uint32_t sequence); +}; + +} // erpcShim + + +#endif // _file_service_server_hpp_ diff --git a/generated/servo_service_client.cpp b/generated/servo_service_client.cpp new file mode 100644 index 0000000..3035d71 --- /dev/null +++ b/generated/servo_service_client.cpp @@ -0,0 +1,484 @@ +/* + * Generated by erpcgen 1.14.0 on Tue Apr 28 12:16:31 2026. + * + * AUTOGENERATED - DO NOT EDIT + */ + + +#if ERPC_ALLOCATION_POLICY == ERPC_ALLOCATION_POLICY_DYNAMIC +#include "erpc_port.h" +#endif +#include "erpc_codec.hpp" +#include "servo_service_client.hpp" +#include "erpc_manually_constructed.hpp" + +#if 11400 != ERPC_VERSION_NUMBER +#error "The generated shim code version is different to the rest of eRPC code." +#endif + +using namespace erpc; +using namespace std; +using namespace erpcShim; + +//! @brief Function to write struct ServoCmd +static void write_ServoCmd_struct(erpc::Codec * codec, const ServoCmd * data); + +//! @brief Function to write struct list_ServoCmd_1_t +static void write_list_ServoCmd_1_t_struct(erpc::Codec * codec, const list_ServoCmd_1_t * data); + +//! @brief Function to write struct list_float_1_t +static void write_list_float_1_t_struct(erpc::Codec * codec, const list_float_1_t * data); + + +// Write struct ServoCmd function implementation +static void write_ServoCmd_struct(erpc::Codec * codec, const ServoCmd * data) +{ + if(NULL == data) + { + return; + } + + { + uint32_t id_len = strlen((const char*)data->id); + + codec->writeString(id_len, (const char*)data->id); + } + + codec->write(data->angle_rad); +} + +// Write struct list_ServoCmd_1_t function implementation +static void write_list_ServoCmd_1_t_struct(erpc::Codec * codec, const list_ServoCmd_1_t * data) +{ + if(NULL == data) + { + return; + } + + codec->startWriteList(data->elementsCount); + for (uint32_t listCount = 0U; listCount < data->elementsCount; ++listCount) + { + write_ServoCmd_struct(codec, &(data->elements[listCount])); + } +} + +// Write struct list_float_1_t function implementation +static void write_list_float_1_t_struct(erpc::Codec * codec, const list_float_1_t * data) +{ + if(NULL == data) + { + return; + } + + codec->startWriteList(data->elementsCount); + for (uint32_t listCount = 0U; listCount < data->elementsCount; ++listCount) + { + codec->write(data->elements[listCount]); + } +} + + + + +servo_service_client::servo_service_client(ClientManager *manager) +:m_clientManager(manager) +{ +} + +servo_service_client::~servo_service_client() +{ +} + +// servo_service interface setConstraints function client shim. +bool servo_service_client::setConstraints(const char * id, float max_velocity_rad, float max_acceleration_rad, float max_jerk_rad) +{ + erpc_status_t err = kErpcStatus_Success; + + bool result; + +#if ERPC_PRE_POST_ACTION + pre_post_action_cb preCB = m_clientManager->getPreCB(); + if (preCB) + { + preCB(); + } +#endif + + // Get a new request. + RequestContext request = m_clientManager->createRequest(false); + + // Encode the request. + Codec * codec = request.getCodec(); + + if (codec == NULL) + { + err = kErpcStatus_MemoryError; + } + else + { + codec->startWriteMessage(message_type_t::kInvocationMessage, m_serviceId, m_setConstraintsId, request.getSequence()); + + { + uint32_t id_len = strlen((const char*)id); + + codec->writeString(id_len, (const char*)id); + } + + codec->write(max_velocity_rad); + + codec->write(max_acceleration_rad); + + codec->write(max_jerk_rad); + + // Send message to server + // Codec status is checked inside this function. + m_clientManager->performRequest(request); + + codec->read(result); + + err = codec->getStatus(); + } + + // Dispose of the request. + m_clientManager->releaseRequest(request); + + // Invoke error handler callback function + m_clientManager->callErrorHandler(err, m_setConstraintsId); + +#if ERPC_PRE_POST_ACTION + pre_post_action_cb postCB = m_clientManager->getPostCB(); + if (postCB) + { + postCB(); + } +#endif + + + if (err != kErpcStatus_Success) + { + result = false; + } + + return result; +} + +// servo_service interface setPositionGain function client shim. +bool servo_service_client::setPositionGain(const char * id, float position_gain) +{ + erpc_status_t err = kErpcStatus_Success; + + bool result; + +#if ERPC_PRE_POST_ACTION + pre_post_action_cb preCB = m_clientManager->getPreCB(); + if (preCB) + { + preCB(); + } +#endif + + // Get a new request. + RequestContext request = m_clientManager->createRequest(false); + + // Encode the request. + Codec * codec = request.getCodec(); + + if (codec == NULL) + { + err = kErpcStatus_MemoryError; + } + else + { + codec->startWriteMessage(message_type_t::kInvocationMessage, m_serviceId, m_setPositionGainId, request.getSequence()); + + { + uint32_t id_len = strlen((const char*)id); + + codec->writeString(id_len, (const char*)id); + } + + codec->write(position_gain); + + // Send message to server + // Codec status is checked inside this function. + m_clientManager->performRequest(request); + + codec->read(result); + + err = codec->getStatus(); + } + + // Dispose of the request. + m_clientManager->releaseRequest(request); + + // Invoke error handler callback function + m_clientManager->callErrorHandler(err, m_setPositionGainId); + +#if ERPC_PRE_POST_ACTION + pre_post_action_cb postCB = m_clientManager->getPostCB(); + if (postCB) + { + postCB(); + } +#endif + + + if (err != kErpcStatus_Success) + { + result = false; + } + + return result; +} + +// servo_service interface setMode function client shim. +bool servo_service_client::setMode(RpcMotionMode mode) +{ + erpc_status_t err = kErpcStatus_Success; + + bool result; + +#if ERPC_PRE_POST_ACTION + pre_post_action_cb preCB = m_clientManager->getPreCB(); + if (preCB) + { + preCB(); + } +#endif + + // Get a new request. + RequestContext request = m_clientManager->createRequest(false); + + // Encode the request. + Codec * codec = request.getCodec(); + + if (codec == NULL) + { + err = kErpcStatus_MemoryError; + } + else + { + codec->startWriteMessage(message_type_t::kInvocationMessage, m_serviceId, m_setModeId, request.getSequence()); + + codec->write(static_cast(mode)); + + // Send message to server + // Codec status is checked inside this function. + m_clientManager->performRequest(request); + + codec->read(result); + + err = codec->getStatus(); + } + + // Dispose of the request. + m_clientManager->releaseRequest(request); + + // Invoke error handler callback function + m_clientManager->callErrorHandler(err, m_setModeId); + +#if ERPC_PRE_POST_ACTION + pre_post_action_cb postCB = m_clientManager->getPostCB(); + if (postCB) + { + postCB(); + } +#endif + + + if (err != kErpcStatus_Success) + { + result = false; + } + + return result; +} + +// servo_service interface setUpdatePeriodMs function client shim. +bool servo_service_client::setUpdatePeriodMs(uint32_t ms) +{ + erpc_status_t err = kErpcStatus_Success; + + bool result; + +#if ERPC_PRE_POST_ACTION + pre_post_action_cb preCB = m_clientManager->getPreCB(); + if (preCB) + { + preCB(); + } +#endif + + // Get a new request. + RequestContext request = m_clientManager->createRequest(false); + + // Encode the request. + Codec * codec = request.getCodec(); + + if (codec == NULL) + { + err = kErpcStatus_MemoryError; + } + else + { + codec->startWriteMessage(message_type_t::kInvocationMessage, m_serviceId, m_setUpdatePeriodMsId, request.getSequence()); + + codec->write(ms); + + // Send message to server + // Codec status is checked inside this function. + m_clientManager->performRequest(request); + + codec->read(result); + + err = codec->getStatus(); + } + + // Dispose of the request. + m_clientManager->releaseRequest(request); + + // Invoke error handler callback function + m_clientManager->callErrorHandler(err, m_setUpdatePeriodMsId); + +#if ERPC_PRE_POST_ACTION + pre_post_action_cb postCB = m_clientManager->getPostCB(); + if (postCB) + { + postCB(); + } +#endif + + + if (err != kErpcStatus_Success) + { + result = false; + } + + return result; +} + +// servo_service interface move function client shim. +int32_t servo_service_client::move(const list_ServoCmd_1_t * cmds) +{ + erpc_status_t err = kErpcStatus_Success; + + int32_t result; + +#if ERPC_PRE_POST_ACTION + pre_post_action_cb preCB = m_clientManager->getPreCB(); + if (preCB) + { + preCB(); + } +#endif + + // Get a new request. + RequestContext request = m_clientManager->createRequest(false); + + // Encode the request. + Codec * codec = request.getCodec(); + + if (codec == NULL) + { + err = kErpcStatus_MemoryError; + } + else + { + codec->startWriteMessage(message_type_t::kInvocationMessage, m_serviceId, m_moveId, request.getSequence()); + + write_list_ServoCmd_1_t_struct(codec, cmds); + + // Send message to server + // Codec status is checked inside this function. + m_clientManager->performRequest(request); + + codec->read(result); + + err = codec->getStatus(); + } + + // Dispose of the request. + m_clientManager->releaseRequest(request); + + // Invoke error handler callback function + m_clientManager->callErrorHandler(err, m_moveId); + +#if ERPC_PRE_POST_ACTION + pre_post_action_cb postCB = m_clientManager->getPostCB(); + if (postCB) + { + postCB(); + } +#endif + + + if (err != kErpcStatus_Success) + { + result = -1; + } + + return result; +} + +// servo_service interface moveJ function client shim. +int32_t servo_service_client::moveJ(const list_float_1_t * angles_rad) +{ + erpc_status_t err = kErpcStatus_Success; + + int32_t result; + +#if ERPC_PRE_POST_ACTION + pre_post_action_cb preCB = m_clientManager->getPreCB(); + if (preCB) + { + preCB(); + } +#endif + + // Get a new request. + RequestContext request = m_clientManager->createRequest(false); + + // Encode the request. + Codec * codec = request.getCodec(); + + if (codec == NULL) + { + err = kErpcStatus_MemoryError; + } + else + { + codec->startWriteMessage(message_type_t::kInvocationMessage, m_serviceId, m_moveJId, request.getSequence()); + + write_list_float_1_t_struct(codec, angles_rad); + + // Send message to server + // Codec status is checked inside this function. + m_clientManager->performRequest(request); + + codec->read(result); + + err = codec->getStatus(); + } + + // Dispose of the request. + m_clientManager->releaseRequest(request); + + // Invoke error handler callback function + m_clientManager->callErrorHandler(err, m_moveJId); + +#if ERPC_PRE_POST_ACTION + pre_post_action_cb postCB = m_clientManager->getPostCB(); + if (postCB) + { + postCB(); + } +#endif + + + if (err != kErpcStatus_Success) + { + result = -1; + } + + return result; +} diff --git a/generated/servo_service_client.hpp b/generated/servo_service_client.hpp new file mode 100644 index 0000000..a6ab06d --- /dev/null +++ b/generated/servo_service_client.hpp @@ -0,0 +1,44 @@ +/* + * Generated by erpcgen 1.14.0 on Tue Apr 28 12:16:31 2026. + * + * AUTOGENERATED - DO NOT EDIT + */ + + +#if !defined(_servo_service_client_hpp_) +#define _servo_service_client_hpp_ + +#include "servo_service_interface.hpp" + +#include "erpc_client_manager.h" + +namespace erpcShim +{ + +class servo_service_client: public servo_service_interface +{ + public: + servo_service_client(erpc::ClientManager *manager); + + virtual ~servo_service_client(); + + virtual bool setConstraints(const char * id, float max_velocity_rad, float max_acceleration_rad, float max_jerk_rad); + + virtual bool setPositionGain(const char * id, float position_gain); + + virtual bool setMode(RpcMotionMode mode); + + virtual bool setUpdatePeriodMs(uint32_t ms); + + virtual int32_t move(const list_ServoCmd_1_t * cmds); + + virtual int32_t moveJ(const list_float_1_t * angles_rad); + + protected: + erpc::ClientManager *m_clientManager; +}; + +} // erpcShim + + +#endif // _servo_service_client_hpp_ diff --git a/generated/servo_service_common.h b/generated/servo_service_common.h new file mode 100644 index 0000000..3b264a5 --- /dev/null +++ b/generated/servo_service_common.h @@ -0,0 +1,69 @@ +/* + * Generated by erpcgen 1.14.0 on Tue Apr 28 12:16:31 2026. + * + * AUTOGENERATED - DO NOT EDIT + */ + + +#if !defined(_servo_service_common_h_) +#define _servo_service_common_h_ + + +#if defined(__cplusplus) +extern "C" +{ +#endif +#include +#include +#include + +#include "erpc_version.h" + +#if 11400 != ERPC_VERSION_NUMBER +#error "The generated shim code version is different to the rest of eRPC code." +#endif + + +#if !defined(ERPC_TYPE_DEFINITIONS_SERVO_SERVICE) +#define ERPC_TYPE_DEFINITIONS_SERVO_SERVICE + +// Enumerators data types declarations +typedef enum RpcMotionMode +{ + RpcMotionModeImmediate = 0, + RpcMotionModeSCurve = 1, + RpcMotionModeFollow = 2 +} RpcMotionMode; + +// Aliases data types declarations +typedef struct list_float_1_t list_float_1_t; +typedef struct ServoCmd ServoCmd; +typedef struct list_ServoCmd_1_t list_ServoCmd_1_t; + +// Structures/unions data types declarations +struct list_float_1_t +{ + float * elements; + uint32_t elementsCount; +}; + +struct ServoCmd +{ + char * id; + float angle_rad; +}; + +struct list_ServoCmd_1_t +{ + ServoCmd * elements; + uint32_t elementsCount; +}; + + +#endif // ERPC_TYPE_DEFINITIONS_SERVO_SERVICE + +#if defined(__cplusplus) +} +#endif + +#endif // _servo_service_common_h_ diff --git a/generated/servo_service_common.hpp b/generated/servo_service_common.hpp new file mode 100644 index 0000000..4f3e131 --- /dev/null +++ b/generated/servo_service_common.hpp @@ -0,0 +1,61 @@ +/* + * Generated by erpcgen 1.14.0 on Tue Apr 28 12:16:31 2026. + * + * AUTOGENERATED - DO NOT EDIT + */ + + +#if !defined(_servo_service_common_hpp_) +#define _servo_service_common_hpp_ + + +#include +#include + +#include "erpc_version.h" + +#if 11400 != ERPC_VERSION_NUMBER +#error "The generated shim code version is different to the rest of eRPC code." +#endif + + +#if !defined(ERPC_TYPE_DEFINITIONS_SERVO_SERVICE) +#define ERPC_TYPE_DEFINITIONS_SERVO_SERVICE + +// Enumerators data types declarations +typedef enum RpcMotionMode +{ + RpcMotionModeImmediate = 0, + RpcMotionModeSCurve = 1, + RpcMotionModeFollow = 2 +} RpcMotionMode; + +// Aliases data types declarations +typedef struct list_float_1_t list_float_1_t; +typedef struct ServoCmd ServoCmd; +typedef struct list_ServoCmd_1_t list_ServoCmd_1_t; + +// Structures/unions data types declarations +struct list_float_1_t +{ + float * elements; + uint32_t elementsCount; +}; + +struct ServoCmd +{ + char * id; + float angle_rad; +}; + +struct list_ServoCmd_1_t +{ + ServoCmd * elements; + uint32_t elementsCount; +}; + + +#endif // ERPC_TYPE_DEFINITIONS_SERVO_SERVICE + + +#endif // _servo_service_common_hpp_ diff --git a/generated/servo_service_interface.cpp b/generated/servo_service_interface.cpp new file mode 100644 index 0000000..ffac068 --- /dev/null +++ b/generated/servo_service_interface.cpp @@ -0,0 +1,20 @@ +/* + * Generated by erpcgen 1.14.0 on Tue Apr 28 12:16:31 2026. + * + * AUTOGENERATED - DO NOT EDIT + */ + + +#include "servo_service_interface.hpp" + +#if 11400 != ERPC_VERSION_NUMBER +#error "The generated shim code version is different to the rest of eRPC code." +#endif + + +using namespace std; +using namespace erpcShim; + +servo_service_interface::~servo_service_interface(void) +{ +} diff --git a/generated/servo_service_interface.hpp b/generated/servo_service_interface.hpp new file mode 100644 index 0000000..d09d643 --- /dev/null +++ b/generated/servo_service_interface.hpp @@ -0,0 +1,47 @@ +/* + * Generated by erpcgen 1.14.0 on Tue Apr 28 12:16:31 2026. + * + * AUTOGENERATED - DO NOT EDIT + */ + + +#if !defined(_servo_service_interface_hpp_) +#define _servo_service_interface_hpp_ + +#include "servo_service_common.hpp" + +namespace erpcShim +{ + + +// Abstract base class for servo_service +class servo_service_interface +{ + public: + static const uint8_t m_serviceId = 1; + static const uint8_t m_setConstraintsId = 1; + static const uint8_t m_setPositionGainId = 2; + static const uint8_t m_setModeId = 3; + static const uint8_t m_setUpdatePeriodMsId = 4; + static const uint8_t m_moveId = 5; + static const uint8_t m_moveJId = 6; + + virtual ~servo_service_interface(void); + + virtual bool setConstraints(const char * id, float max_velocity_rad, float max_acceleration_rad, float max_jerk_rad) = 0; + + virtual bool setPositionGain(const char * id, float position_gain) = 0; + + virtual bool setMode(RpcMotionMode mode) = 0; + + virtual bool setUpdatePeriodMs(uint32_t ms) = 0; + + virtual int32_t move(const list_ServoCmd_1_t * cmds) = 0; + + virtual int32_t moveJ(const list_float_1_t * angles_rad) = 0; +private: +}; +} // erpcShim + + +#endif // _servo_service_interface_hpp_ diff --git a/generated/servo_service_server.cpp b/generated/servo_service_server.cpp new file mode 100644 index 0000000..7a1e076 --- /dev/null +++ b/generated/servo_service_server.cpp @@ -0,0 +1,539 @@ +/* + * Generated by erpcgen 1.14.0 on Tue Apr 28 12:16:31 2026. + * + * AUTOGENERATED - DO NOT EDIT + */ + + +#include "servo_service_server.hpp" +#if ERPC_ALLOCATION_POLICY == ERPC_ALLOCATION_POLICY_DYNAMIC +#include +#include "erpc_port.h" +#endif +#include "erpc_manually_constructed.hpp" + +#if 11400 != ERPC_VERSION_NUMBER +#error "The generated shim code version is different to the rest of eRPC code." +#endif + +using namespace erpc; +using namespace std; +using namespace erpcShim; + +#if ERPC_NESTED_CALLS_DETECTION +extern bool nestingDetection; +#endif + + +//! @brief Function to read struct ServoCmd +static void read_ServoCmd_struct(erpc::Codec * codec, ServoCmd * data); + +//! @brief Function to read struct list_ServoCmd_1_t +static void read_list_ServoCmd_1_t_struct(erpc::Codec * codec, list_ServoCmd_1_t * data); + +//! @brief Function to read struct list_float_1_t +static void read_list_float_1_t_struct(erpc::Codec * codec, list_float_1_t * data); + + +// Read struct ServoCmd function implementation +static void read_ServoCmd_struct(erpc::Codec * codec, ServoCmd * data) +{ + if(NULL == data) + { + return; + } + + { + uint32_t id_len; + char * id_local; + codec->readString(id_len, &id_local); + data->id = (char*) erpc_malloc((id_len + 1) * sizeof(char)); + if ((data->id == NULL) || (id_local == NULL)) + { + codec->updateStatus(kErpcStatus_MemoryError); + } + else + { + memcpy(data->id, id_local, id_len); + (data->id)[id_len] = 0; + } + } + + codec->read(data->angle_rad); +} + +// Read struct list_ServoCmd_1_t function implementation +static void read_list_ServoCmd_1_t_struct(erpc::Codec * codec, list_ServoCmd_1_t * data) +{ + if(NULL == data) + { + return; + } + + codec->startReadList(data->elementsCount); + data->elements = (ServoCmd *) erpc_malloc(data->elementsCount * sizeof(ServoCmd)); + if ((data->elements == NULL) && (data->elementsCount > 0)) + { + codec->updateStatus(kErpcStatus_MemoryError); + } + for (uint32_t listCount = 0U; listCount < data->elementsCount; ++listCount) + { + read_ServoCmd_struct(codec, &(data->elements[listCount])); + } +} + +// Read struct list_float_1_t function implementation +static void read_list_float_1_t_struct(erpc::Codec * codec, list_float_1_t * data) +{ + if(NULL == data) + { + return; + } + + codec->startReadList(data->elementsCount); + data->elements = (float *) erpc_malloc(data->elementsCount * sizeof(float)); + if ((data->elements == NULL) && (data->elementsCount > 0)) + { + codec->updateStatus(kErpcStatus_MemoryError); + } + for (uint32_t listCount = 0U; listCount < data->elementsCount; ++listCount) + { + codec->read(data->elements[listCount]); + } +} + + +//! @brief Function to free space allocated inside struct ServoCmd +static void free_ServoCmd_struct(ServoCmd * data); + +//! @brief Function to free space allocated inside struct list_ServoCmd_1_t +static void free_list_ServoCmd_1_t_struct(list_ServoCmd_1_t * data); + +//! @brief Function to free space allocated inside struct list_float_1_t +static void free_list_float_1_t_struct(list_float_1_t * data); + + +// Free space allocated inside struct ServoCmd function implementation +static void free_ServoCmd_struct(ServoCmd * data) +{ + erpc_free(data->id); +} + +// Free space allocated inside struct list_ServoCmd_1_t function implementation +static void free_list_ServoCmd_1_t_struct(list_ServoCmd_1_t * data) +{ + for (uint32_t listCount = 0; listCount < data->elementsCount; ++listCount) + { + free_ServoCmd_struct(&data->elements[listCount]); + } + + erpc_free(data->elements); +} + +// Free space allocated inside struct list_float_1_t function implementation +static void free_list_float_1_t_struct(list_float_1_t * data) +{ + erpc_free(data->elements); +} + + + +servo_service_service::servo_service_service(servo_service_interface *_servo_service_interface) + : erpc::Service(servo_service_interface::m_serviceId) + , m_handler(_servo_service_interface) +{ +} + +servo_service_service::~servo_service_service() +{ +} + +// return service interface handler. +servo_service_interface* servo_service_service::getHandler(void) +{ + return m_handler; +} + +// Call the correct server shim based on method unique ID. +erpc_status_t servo_service_service::handleInvocation(uint32_t methodId, uint32_t sequence, Codec * codec, MessageBufferFactory *messageFactory, Transport * transport) +{ + erpc_status_t erpcStatus; + switch (methodId) + { + case servo_service_interface::m_setConstraintsId: + { + erpcStatus = setConstraints_shim(codec, messageFactory, transport, sequence); + break; + } + + case servo_service_interface::m_setPositionGainId: + { + erpcStatus = setPositionGain_shim(codec, messageFactory, transport, sequence); + break; + } + + case servo_service_interface::m_setModeId: + { + erpcStatus = setMode_shim(codec, messageFactory, transport, sequence); + break; + } + + case servo_service_interface::m_setUpdatePeriodMsId: + { + erpcStatus = setUpdatePeriodMs_shim(codec, messageFactory, transport, sequence); + break; + } + + case servo_service_interface::m_moveId: + { + erpcStatus = move_shim(codec, messageFactory, transport, sequence); + break; + } + + case servo_service_interface::m_moveJId: + { + erpcStatus = moveJ_shim(codec, messageFactory, transport, sequence); + break; + } + + default: + { + erpcStatus = kErpcStatus_InvalidArgument; + break; + } + } + + return erpcStatus; +} + +// Server shim for setConstraints of servo_service interface. +erpc_status_t servo_service_service::setConstraints_shim(Codec * codec, MessageBufferFactory *messageFactory, Transport * transport, uint32_t sequence) +{ + erpc_status_t err = kErpcStatus_Success; + + char * id = NULL; + float max_velocity_rad; + float max_acceleration_rad; + float max_jerk_rad; + bool result; + + // startReadMessage() was already called before this shim was invoked. + + { + uint32_t id_len; + char * id_local; + codec->readString(id_len, &id_local); + id = (char*) erpc_malloc((id_len + 1) * sizeof(char)); + if ((id == NULL) || (id_local == NULL)) + { + codec->updateStatus(kErpcStatus_MemoryError); + } + else + { + memcpy(id, id_local, id_len); + (id)[id_len] = 0; + } + } + + codec->read(max_velocity_rad); + + codec->read(max_acceleration_rad); + + codec->read(max_jerk_rad); + + err = codec->getStatus(); + if (err == kErpcStatus_Success) + { + // Invoke the actual served function. +#if ERPC_NESTED_CALLS_DETECTION + nestingDetection = true; +#endif + result = m_handler->setConstraints(id, max_velocity_rad, max_acceleration_rad, max_jerk_rad); +#if ERPC_NESTED_CALLS_DETECTION + nestingDetection = false; +#endif + + // preparing MessageBuffer for serializing data + err = messageFactory->prepareServerBufferForSend(codec->getBufferRef(), transport->reserveHeaderSize()); + } + + if (err == kErpcStatus_Success) + { + // preparing codec for serializing data + codec->reset(transport->reserveHeaderSize()); + + // Build response message. + codec->startWriteMessage(message_type_t::kReplyMessage, servo_service_interface::m_serviceId, servo_service_interface::m_setConstraintsId, sequence); + + codec->write(result); + + err = codec->getStatus(); + } + + erpc_free(id); + + return err; +} + +// Server shim for setPositionGain of servo_service interface. +erpc_status_t servo_service_service::setPositionGain_shim(Codec * codec, MessageBufferFactory *messageFactory, Transport * transport, uint32_t sequence) +{ + erpc_status_t err = kErpcStatus_Success; + + char * id = NULL; + float position_gain; + bool result; + + // startReadMessage() was already called before this shim was invoked. + + { + uint32_t id_len; + char * id_local; + codec->readString(id_len, &id_local); + id = (char*) erpc_malloc((id_len + 1) * sizeof(char)); + if ((id == NULL) || (id_local == NULL)) + { + codec->updateStatus(kErpcStatus_MemoryError); + } + else + { + memcpy(id, id_local, id_len); + (id)[id_len] = 0; + } + } + + codec->read(position_gain); + + err = codec->getStatus(); + if (err == kErpcStatus_Success) + { + // Invoke the actual served function. +#if ERPC_NESTED_CALLS_DETECTION + nestingDetection = true; +#endif + result = m_handler->setPositionGain(id, position_gain); +#if ERPC_NESTED_CALLS_DETECTION + nestingDetection = false; +#endif + + // preparing MessageBuffer for serializing data + err = messageFactory->prepareServerBufferForSend(codec->getBufferRef(), transport->reserveHeaderSize()); + } + + if (err == kErpcStatus_Success) + { + // preparing codec for serializing data + codec->reset(transport->reserveHeaderSize()); + + // Build response message. + codec->startWriteMessage(message_type_t::kReplyMessage, servo_service_interface::m_serviceId, servo_service_interface::m_setPositionGainId, sequence); + + codec->write(result); + + err = codec->getStatus(); + } + + erpc_free(id); + + return err; +} + +// Server shim for setMode of servo_service interface. +erpc_status_t servo_service_service::setMode_shim(Codec * codec, MessageBufferFactory *messageFactory, Transport * transport, uint32_t sequence) +{ + erpc_status_t err = kErpcStatus_Success; + + RpcMotionMode mode; + int32_t _tmp_local_i32; + bool result; + + // startReadMessage() was already called before this shim was invoked. + + codec->read(_tmp_local_i32); + mode = static_cast(_tmp_local_i32); + + err = codec->getStatus(); + if (err == kErpcStatus_Success) + { + // Invoke the actual served function. +#if ERPC_NESTED_CALLS_DETECTION + nestingDetection = true; +#endif + result = m_handler->setMode(mode); +#if ERPC_NESTED_CALLS_DETECTION + nestingDetection = false; +#endif + + // preparing MessageBuffer for serializing data + err = messageFactory->prepareServerBufferForSend(codec->getBufferRef(), transport->reserveHeaderSize()); + } + + if (err == kErpcStatus_Success) + { + // preparing codec for serializing data + codec->reset(transport->reserveHeaderSize()); + + // Build response message. + codec->startWriteMessage(message_type_t::kReplyMessage, servo_service_interface::m_serviceId, servo_service_interface::m_setModeId, sequence); + + codec->write(result); + + err = codec->getStatus(); + } + + return err; +} + +// Server shim for setUpdatePeriodMs of servo_service interface. +erpc_status_t servo_service_service::setUpdatePeriodMs_shim(Codec * codec, MessageBufferFactory *messageFactory, Transport * transport, uint32_t sequence) +{ + erpc_status_t err = kErpcStatus_Success; + + uint32_t ms; + bool result; + + // startReadMessage() was already called before this shim was invoked. + + codec->read(ms); + + err = codec->getStatus(); + if (err == kErpcStatus_Success) + { + // Invoke the actual served function. +#if ERPC_NESTED_CALLS_DETECTION + nestingDetection = true; +#endif + result = m_handler->setUpdatePeriodMs(ms); +#if ERPC_NESTED_CALLS_DETECTION + nestingDetection = false; +#endif + + // preparing MessageBuffer for serializing data + err = messageFactory->prepareServerBufferForSend(codec->getBufferRef(), transport->reserveHeaderSize()); + } + + if (err == kErpcStatus_Success) + { + // preparing codec for serializing data + codec->reset(transport->reserveHeaderSize()); + + // Build response message. + codec->startWriteMessage(message_type_t::kReplyMessage, servo_service_interface::m_serviceId, servo_service_interface::m_setUpdatePeriodMsId, sequence); + + codec->write(result); + + err = codec->getStatus(); + } + + return err; +} + +// Server shim for move of servo_service interface. +erpc_status_t servo_service_service::move_shim(Codec * codec, MessageBufferFactory *messageFactory, Transport * transport, uint32_t sequence) +{ + erpc_status_t err = kErpcStatus_Success; + + list_ServoCmd_1_t *cmds = NULL; + cmds = (list_ServoCmd_1_t *) erpc_malloc(sizeof(list_ServoCmd_1_t)); + if (cmds == NULL) + { + codec->updateStatus(kErpcStatus_MemoryError); + } + int32_t result; + + // startReadMessage() was already called before this shim was invoked. + + read_list_ServoCmd_1_t_struct(codec, cmds); + + err = codec->getStatus(); + if (err == kErpcStatus_Success) + { + // Invoke the actual served function. +#if ERPC_NESTED_CALLS_DETECTION + nestingDetection = true; +#endif + result = m_handler->move(cmds); +#if ERPC_NESTED_CALLS_DETECTION + nestingDetection = false; +#endif + + // preparing MessageBuffer for serializing data + err = messageFactory->prepareServerBufferForSend(codec->getBufferRef(), transport->reserveHeaderSize()); + } + + if (err == kErpcStatus_Success) + { + // preparing codec for serializing data + codec->reset(transport->reserveHeaderSize()); + + // Build response message. + codec->startWriteMessage(message_type_t::kReplyMessage, servo_service_interface::m_serviceId, servo_service_interface::m_moveId, sequence); + + codec->write(result); + + err = codec->getStatus(); + } + + if (cmds) + { + free_list_ServoCmd_1_t_struct(cmds); + } + erpc_free(cmds); + + return err; +} + +// Server shim for moveJ of servo_service interface. +erpc_status_t servo_service_service::moveJ_shim(Codec * codec, MessageBufferFactory *messageFactory, Transport * transport, uint32_t sequence) +{ + erpc_status_t err = kErpcStatus_Success; + + list_float_1_t *angles_rad = NULL; + angles_rad = (list_float_1_t *) erpc_malloc(sizeof(list_float_1_t)); + if (angles_rad == NULL) + { + codec->updateStatus(kErpcStatus_MemoryError); + } + int32_t result; + + // startReadMessage() was already called before this shim was invoked. + + read_list_float_1_t_struct(codec, angles_rad); + + err = codec->getStatus(); + if (err == kErpcStatus_Success) + { + // Invoke the actual served function. +#if ERPC_NESTED_CALLS_DETECTION + nestingDetection = true; +#endif + result = m_handler->moveJ(angles_rad); +#if ERPC_NESTED_CALLS_DETECTION + nestingDetection = false; +#endif + + // preparing MessageBuffer for serializing data + err = messageFactory->prepareServerBufferForSend(codec->getBufferRef(), transport->reserveHeaderSize()); + } + + if (err == kErpcStatus_Success) + { + // preparing codec for serializing data + codec->reset(transport->reserveHeaderSize()); + + // Build response message. + codec->startWriteMessage(message_type_t::kReplyMessage, servo_service_interface::m_serviceId, servo_service_interface::m_moveJId, sequence); + + codec->write(result); + + err = codec->getStatus(); + } + + if (angles_rad) + { + free_list_float_1_t_struct(angles_rad); + } + erpc_free(angles_rad); + + return err; +} diff --git a/generated/servo_service_server.hpp b/generated/servo_service_server.hpp new file mode 100644 index 0000000..61faa47 --- /dev/null +++ b/generated/servo_service_server.hpp @@ -0,0 +1,64 @@ +/* + * Generated by erpcgen 1.14.0 on Tue Apr 28 12:16:31 2026. + * + * AUTOGENERATED - DO NOT EDIT + */ + + +#if !defined(_servo_service_server_hpp_) +#define _servo_service_server_hpp_ + +#include "servo_service_interface.hpp" + +#include "erpc_server.hpp" +#include "erpc_codec.hpp" + +#if 11400 != ERPC_VERSION_NUMBER +#error "The generated shim code version is different to the rest of eRPC code." +#endif + + +namespace erpcShim +{ + +/*! + * @brief Service subclass for servo_service. + */ +class servo_service_service : public erpc::Service +{ +public: + servo_service_service(servo_service_interface *_servo_service_interface); + + virtual ~servo_service_service(); + + /*! @brief return service interface handler. */ + servo_service_interface* getHandler(void); + + /*! @brief Call the correct server shim based on method unique ID. */ + virtual erpc_status_t handleInvocation(uint32_t methodId, uint32_t sequence, erpc::Codec * codec, erpc::MessageBufferFactory *messageFactory, erpc::Transport * transport); + +private: + servo_service_interface *m_handler; + /*! @brief Server shim for setConstraints of servo_service interface. */ + erpc_status_t setConstraints_shim(erpc::Codec * codec, erpc::MessageBufferFactory *messageFactory, erpc::Transport * transport, uint32_t sequence); + + /*! @brief Server shim for setPositionGain of servo_service interface. */ + erpc_status_t setPositionGain_shim(erpc::Codec * codec, erpc::MessageBufferFactory *messageFactory, erpc::Transport * transport, uint32_t sequence); + + /*! @brief Server shim for setMode of servo_service interface. */ + erpc_status_t setMode_shim(erpc::Codec * codec, erpc::MessageBufferFactory *messageFactory, erpc::Transport * transport, uint32_t sequence); + + /*! @brief Server shim for setUpdatePeriodMs of servo_service interface. */ + erpc_status_t setUpdatePeriodMs_shim(erpc::Codec * codec, erpc::MessageBufferFactory *messageFactory, erpc::Transport * transport, uint32_t sequence); + + /*! @brief Server shim for move of servo_service interface. */ + erpc_status_t move_shim(erpc::Codec * codec, erpc::MessageBufferFactory *messageFactory, erpc::Transport * transport, uint32_t sequence); + + /*! @brief Server shim for moveJ of servo_service interface. */ + erpc_status_t moveJ_shim(erpc::Codec * codec, erpc::MessageBufferFactory *messageFactory, erpc::Transport * transport, uint32_t sequence); +}; + +} // erpcShim + + +#endif // _servo_service_server_hpp_ diff --git a/main.py b/main.py new file mode 100644 index 0000000..6dd3b81 --- /dev/null +++ b/main.py @@ -0,0 +1,41 @@ +import statistics +import time + +import erpc + +from servo_service import client + + +PORT = "COM8" +BAUD = 115200 +N = 180 +JOINT_COUNT = 48 + + +def main(): + xport = erpc.transport.SerialTransport(PORT, BAUD) + client_mgr = erpc.client.ClientManager(xport, erpc.basic_codec.BasicCodec) + api = client.servo_serviceClient(client_mgr) + + angles = [0.0] * JOINT_COUNT + + while True: + costs_ms = [] + + for _ in range(N): + t0 = time.perf_counter() + api.moveJ(angles) + t1 = time.perf_counter() + costs_ms.append((t1 - t0) * 1000.0) + + print(f"N={N}") + print(f"avg = {statistics.mean(costs_ms):.3f} ms") + print(f"min = {min(costs_ms):.3f} ms") + print(f"max = {max(costs_ms):.3f} ms") + if N >= 2: + print(f"p50 = {statistics.median(costs_ms):.3f} ms") + print(f"p95 ~= {sorted(costs_ms)[int(0.95 * (N - 1))]:.3f} ms") + + +if __name__ == "__main__": + main() diff --git a/run_ui.ps1 b/run_ui.ps1 new file mode 100644 index 0000000..eb7da4e --- /dev/null +++ b/run_ui.ps1 @@ -0,0 +1,35 @@ +param( + [string]$PythonExecutable = "C:\Users\Administrator\miniconda3\envs\cmvr-head-client\python.exe", + [switch]$SkipBuild +) + +$ErrorActionPreference = "Stop" + +$repoRoot = Split-Path -Parent $MyInvocation.MyCommand.Path +$buildScript = Join-Path $repoRoot "cpp\common\curve\build_python.ps1" +$uiScript = Join-Path $repoRoot "ui\face_servo_control.py" + +if (-not (Test-Path $PythonExecutable)) { + throw "Python executable not found at $PythonExecutable" +} + +if (-not (Test-Path $uiScript)) { + throw "UI script not found at $uiScript" +} + +if (-not $SkipBuild) { + if (-not (Test-Path $buildScript)) { + throw "Build script not found at $buildScript" + } + + Write-Host "[1/2] Rebuilding _s_curve_native..." + powershell -ExecutionPolicy Bypass -File $buildScript -PythonExecutable $PythonExecutable + if ($LASTEXITCODE -ne 0) { + throw "Native module rebuild failed." + } +} else { + Write-Host "[1/2] Skipping native rebuild." +} + +Write-Host "[2/2] Launching UI..." +& $PythonExecutable $uiScript diff --git a/s_curve.py b/s_curve.py new file mode 100644 index 0000000..ed494a6 --- /dev/null +++ b/s_curve.py @@ -0,0 +1,246 @@ +import importlib.util +from pathlib import Path +import sys + + +REPO_ROOT = Path(__file__).resolve().parent + + +class SCurveError(RuntimeError): + pass + + +def _default_module_candidates(): + search_roots = [ + REPO_ROOT / "cpp" / "common" / "curve" / "build", + REPO_ROOT / "cpp" / "common" / "curve" / "build" / "Release", + ] + patterns = [ + "_s_curve_native*.pyd", + "_s_curve_native*.so", + ] + candidates = [] + for root in search_roots: + if not root.exists(): + continue + for pattern in patterns: + candidates.extend(sorted(root.glob(pattern))) + return candidates + + +def _resolve_module_path(module_path=None): + if module_path: + path = Path(module_path) + if path.exists(): + return path + raise FileNotFoundError(f"SCurve native module not found: {path}") + + for candidate in _default_module_candidates(): + if candidate.exists(): + return candidate + + candidate_text = "\n".join(str(path) for path in _default_module_candidates()) + raise FileNotFoundError( + "SCurve native module not found. Build it first with:\n" + "powershell -ExecutionPolicy Bypass -File .\\cpp\\common\\curve\\build_python.ps1 " + "-PythonExecutable 'C:\\Users\\Administrator\\miniconda3\\envs\\cmvr-head-client\\python.exe'\n" + f"Expected one of:\n{candidate_text}" + ) + + +class SCurve: + def __init__(self, max_velocity=3.0, max_acceleration=10.0, max_jerk=50.0, module_path=None, dll_path=None): + resolved_path = _resolve_module_path(module_path or dll_path) + try: + self._module = self._load_native_module(resolved_path) + self._native = self._module.SCurve(max_velocity, max_acceleration, max_jerk) + except Exception as exc: + raise SCurveError(f"Failed to create pybind11 SCurve instance: {exc}") from exc + + @staticmethod + def _load_native_module(module_path): + module_name = "_s_curve_native" + if module_name in sys.modules: + return sys.modules[module_name] + spec = importlib.util.spec_from_file_location(module_name, module_path) + if spec is None or spec.loader is None: + raise ImportError(f"Unable to load module from {module_path}") + module = importlib.util.module_from_spec(spec) + sys.modules[module_name] = module + spec.loader.exec_module(module) + return module + + @staticmethod + def _wrap_native_call(action, fn, *args, **kwargs): + try: + return fn(*args, **kwargs) + except Exception as exc: + raise SCurveError(f"{action} failed: {exc}") from exc + + def setConstraints(self, max_velocity, max_acceleration, max_jerk): + return self._wrap_native_call( + "setConstraints", + self._native.setConstraints, + max_velocity, + max_acceleration, + max_jerk, + ) + + def getConstraints(self): + return self._wrap_native_call( + "getConstraints", + self._native.getConstraints, + ) + + def calculateProfile(self, start_position, end_position, start_velocity=0.0, end_velocity=0.0): + return self._wrap_native_call( + "calculateProfile", + self._native.calculateProfile, + start_position, + end_position, + start_velocity, + end_velocity, + ) + + def getPositionAtTime(self, profile, t): + return self._wrap_native_call("getPositionAtTime", self._native.getPositionAtTime, profile, t) + + def getVelocityAtTime(self, profile, t): + return self._wrap_native_call("getVelocityAtTime", self._native.getVelocityAtTime, profile, t) + + def getAccelerationAtTime(self, profile, t): + return self._wrap_native_call( + "getAccelerationAtTime", + self._native.getAccelerationAtTime, + profile, + t, + ) + + def getJerkAtTime(self, profile, t): + return self._wrap_native_call("getJerkAtTime", self._native.getJerkAtTime, profile, t) + + def sampleTrajectory(self, profile, dt): + return self._wrap_native_call( + "sampleTrajectory", + self._native.sampleTrajectory, + profile, + dt, + ) + + +class SCurvePositionPlanner1D: + def __init__(self, max_velocity=3.0, max_acceleration=10.0, max_jerk=50.0, module_path=None, dll_path=None): + resolved_path = _resolve_module_path(module_path or dll_path) + try: + self._module = SCurve._load_native_module(resolved_path) + self._native = self._module.SCurvePositionPlanner1D( + max_velocity, + max_acceleration, + max_jerk, + ) + except Exception as exc: + raise SCurveError(f"Failed to create pybind11 SCurvePositionPlanner1D instance: {exc}") from exc + + def setConstraints(self, max_velocity, max_acceleration, max_jerk): + return SCurve._wrap_native_call( + "setConstraints", + self._native.setConstraints, + max_velocity, + max_acceleration, + max_jerk, + ) + + def getConstraints(self): + return SCurve._wrap_native_call("getConstraints", self._native.getConstraints) + + def setPositionGain(self, position_gain): + return SCurve._wrap_native_call("setPositionGain", self._native.setPositionGain, position_gain) + + def getPositionGain(self): + return SCurve._wrap_native_call("getPositionGain", self._native.getPositionGain) + + def initialize(self, position, velocity=0.0, acceleration=0.0): + return SCurve._wrap_native_call( + "initialize", + self._native.initialize, + position, + velocity, + acceleration, + ) + + def reset(self): + return SCurve._wrap_native_call("reset", self._native.reset) + + def setTarget(self, target_position): + return SCurve._wrap_native_call("setTarget", self._native.setTarget, target_position) + + def update(self, dt): + return SCurve._wrap_native_call("update", self._native.update, dt) + + def getState(self): + return SCurve._wrap_native_call("getState", self._native.getState) + + def sampleTrajectory( + self, + target_position, + dt, + duration, + initial_position=0.0, + initial_velocity=0.0, + initial_acceleration=0.0, + position_gain=None, + ): + if dt <= 0: + raise ValueError("dt must be > 0") + if duration < 0: + raise ValueError("duration must be >= 0") + + self.initialize(initial_position, initial_velocity, initial_acceleration) + if position_gain is not None: + self.setPositionGain(position_gain) + self.setTarget(target_position) + + times = [0.0] + state = self.getState() + positions = [state.position] + velocities = [state.velocity] + accelerations = [state.acceleration] + jerks = [state.jerk] + targets = [state.target_position] + moving = [state.is_moving] + + t = 0.0 + while t + dt <= duration + 1e-12: + t = round(t + dt, 12) + self.update(dt) + state = self.getState() + times.append(t) + positions.append(state.position) + velocities.append(state.velocity) + accelerations.append(state.acceleration) + jerks.append(state.jerk) + targets.append(state.target_position) + moving.append(state.is_moving) + + if abs(times[-1] - duration) > 1e-9: + final_dt = duration - times[-1] + if final_dt > 1e-12: + self.update(final_dt) + state = self.getState() + times.append(duration) + positions.append(state.position) + velocities.append(state.velocity) + accelerations.append(state.acceleration) + jerks.append(state.jerk) + targets.append(state.target_position) + moving.append(state.is_moving) + + return { + "times": times, + "positions": positions, + "velocities": velocities, + "accelerations": accelerations, + "jerks": jerks, + "targets": targets, + "moving": moving, + } diff --git a/servo_service.erpc b/servo_service.erpc new file mode 100644 index 0000000..2e1cc54 --- /dev/null +++ b/servo_service.erpc @@ -0,0 +1,34 @@ +// servo_service.erpc +// Generator examples: +// .\erpcgen.exe -o .\generated\ -g c .\servo_service.erpc +// .\erpcgen.exe -g py .\servo_service.erpc +// 注意:interface 客户端和服务端erpc里面的函数顺序一定要一样 + +program servo_service + +enum RpcMotionMode { + RpcMotionModeImmediate = 0, + RpcMotionModeSCurve = 1, + RpcMotionModeFollow = 2 +} +struct ServoCmd { + string id + float angle_rad +} +interface servo_service +{ + setConstraints(string id, + float max_velocity_rad, + float max_acceleration_rad, + float max_jerk_rad) -> bool + setPositionGain(string id, + float position_gain) -> bool + + setMode(RpcMotionMode mode)->bool + setUpdatePeriodMs(uint32 ms) -> bool + move(list cmds) -> int32 + + moveJ(list angles_rad) -> int32 + + +} diff --git a/servo_service/__init__.py b/servo_service/__init__.py new file mode 100644 index 0000000..b43ad03 --- /dev/null +++ b/servo_service/__init__.py @@ -0,0 +1,19 @@ +# +# Generated by erpcgen 1.14.0 on Tue Apr 28 12:25:26 2026. +# +# AUTOGENERATED - DO NOT EDIT +# + +try: + from erpc import erpc_version + version = erpc_version.ERPC_VERSION +except ImportError: + version = "unknown" +if version != "1.14.0": + raise ValueError("The generated shim code version (1.14.0) is different to the rest of eRPC code (%s). \ +Install newer version by running \"python setup.py install\" in folder erpc/erpc_python/." % repr(version)) + +from . import common +from . import client +from . import server +from . import interface diff --git a/servo_service/__pycache__/__init__.cpython-310.pyc b/servo_service/__pycache__/__init__.cpython-310.pyc new file mode 100644 index 0000000..c7e7871 Binary files /dev/null and b/servo_service/__pycache__/__init__.cpython-310.pyc differ diff --git a/servo_service/__pycache__/client.cpython-310.pyc b/servo_service/__pycache__/client.cpython-310.pyc new file mode 100644 index 0000000..21061aa Binary files /dev/null and b/servo_service/__pycache__/client.cpython-310.pyc differ diff --git a/servo_service/__pycache__/common.cpython-310.pyc b/servo_service/__pycache__/common.cpython-310.pyc new file mode 100644 index 0000000..faa26af Binary files /dev/null and b/servo_service/__pycache__/common.cpython-310.pyc differ diff --git a/servo_service/__pycache__/interface.cpython-310.pyc b/servo_service/__pycache__/interface.cpython-310.pyc new file mode 100644 index 0000000..3c812cb Binary files /dev/null and b/servo_service/__pycache__/interface.cpython-310.pyc differ diff --git a/servo_service/__pycache__/server.cpython-310.pyc b/servo_service/__pycache__/server.cpython-310.pyc new file mode 100644 index 0000000..b054b1e Binary files /dev/null and b/servo_service/__pycache__/server.cpython-310.pyc differ diff --git a/servo_service/client.py b/servo_service/client.py new file mode 100644 index 0000000..c6b50ad --- /dev/null +++ b/servo_service/client.py @@ -0,0 +1,142 @@ +# +# Generated by erpcgen 1.14.0 on Tue Apr 28 12:25:26 2026. +# +# AUTOGENERATED - DO NOT EDIT +# + +import erpc +from . import common, interface + +# Client for servo_service +class servo_serviceClient(interface.Iservo_service): + def __init__(self, manager): + super(servo_serviceClient, self).__init__() + self._clientManager = manager + + def setConstraints(self, id, max_velocity_rad, max_acceleration_rad, max_jerk_rad): + # Build remote function invocation message. + request = self._clientManager.create_request() + codec = request.codec + codec.start_write_message(erpc.codec.MessageInfo( + type=erpc.codec.MessageType.kInvocationMessage, + service=self.SERVICE_ID, + request=self.SETCONSTRAINTS_ID, + sequence=request.sequence)) + if id is None: + raise ValueError("id is None") + codec.write_string(id) + if max_velocity_rad is None: + raise ValueError("max_velocity_rad is None") + codec.write_float(max_velocity_rad) + if max_acceleration_rad is None: + raise ValueError("max_acceleration_rad is None") + codec.write_float(max_acceleration_rad) + if max_jerk_rad is None: + raise ValueError("max_jerk_rad is None") + codec.write_float(max_jerk_rad) + + # Send request and process reply. + self._clientManager.perform_request(request) + _result = codec.read_bool() + return _result + + def setPositionGain(self, id, position_gain): + # Build remote function invocation message. + request = self._clientManager.create_request() + codec = request.codec + codec.start_write_message(erpc.codec.MessageInfo( + type=erpc.codec.MessageType.kInvocationMessage, + service=self.SERVICE_ID, + request=self.SETPOSITIONGAIN_ID, + sequence=request.sequence)) + if id is None: + raise ValueError("id is None") + codec.write_string(id) + if position_gain is None: + raise ValueError("position_gain is None") + codec.write_float(position_gain) + + # Send request and process reply. + self._clientManager.perform_request(request) + _result = codec.read_bool() + return _result + + def setMode(self, mode): + # Build remote function invocation message. + request = self._clientManager.create_request() + codec = request.codec + codec.start_write_message(erpc.codec.MessageInfo( + type=erpc.codec.MessageType.kInvocationMessage, + service=self.SERVICE_ID, + request=self.SETMODE_ID, + sequence=request.sequence)) + if mode is None: + raise ValueError("mode is None") + codec.write_int32(mode) + + # Send request and process reply. + self._clientManager.perform_request(request) + _result = codec.read_bool() + return _result + + def setUpdatePeriodMs(self, ms): + # Build remote function invocation message. + request = self._clientManager.create_request() + codec = request.codec + codec.start_write_message(erpc.codec.MessageInfo( + type=erpc.codec.MessageType.kInvocationMessage, + service=self.SERVICE_ID, + request=self.SETUPDATEPERIODMS_ID, + sequence=request.sequence)) + if ms is None: + raise ValueError("ms is None") + codec.write_uint32(ms) + + # Send request and process reply. + self._clientManager.perform_request(request) + _result = codec.read_bool() + return _result + + def move(self, cmds): + # Build remote function invocation message. + request = self._clientManager.create_request() + codec = request.codec + codec.start_write_message(erpc.codec.MessageInfo( + type=erpc.codec.MessageType.kInvocationMessage, + service=self.SERVICE_ID, + request=self.MOVE_ID, + sequence=request.sequence)) + if cmds is None: + raise ValueError("cmds is None") + codec.start_write_list(len(cmds)) + for _i0 in cmds: + _i0._write(codec) + + + # Send request and process reply. + self._clientManager.perform_request(request) + _result = codec.read_int32() + return _result + + def moveJ(self, angles_rad): + # Build remote function invocation message. + request = self._clientManager.create_request() + codec = request.codec + codec.start_write_message(erpc.codec.MessageInfo( + type=erpc.codec.MessageType.kInvocationMessage, + service=self.SERVICE_ID, + request=self.MOVEJ_ID, + sequence=request.sequence)) + if angles_rad is None: + raise ValueError("angles_rad is None") + codec.start_write_list(len(angles_rad)) + for _i0 in angles_rad: + codec.write_float(_i0) + + + # Send request and process reply. + self._clientManager.perform_request(request) + _result = codec.read_int32() + return _result + + diff --git a/servo_service/common.py b/servo_service/common.py new file mode 100644 index 0000000..5e22c53 --- /dev/null +++ b/servo_service/common.py @@ -0,0 +1,39 @@ +# +# Generated by erpcgen 1.14.0 on Tue Apr 28 12:25:26 2026. +# +# AUTOGENERATED - DO NOT EDIT +# + + +# Enumerators data types declarations +class RpcMotionMode: + RpcMotionModeImmediate = 0 + RpcMotionModeSCurve = 1 + RpcMotionModeFollow = 2 + + +# Structures data types declarations +class ServoCmd(object): + def __init__(self, id=None, angle_rad=None): + self.id = id # string + self.angle_rad = angle_rad # float + + def _read(self, codec): + self.id = codec.read_string() + self.angle_rad = codec.read_float() + return self + + def _write(self, codec): + if self.id is None: + raise ValueError("id is None") + codec.write_string(self.id) + if self.angle_rad is None: + raise ValueError("angle_rad is None") + codec.write_float(self.angle_rad) + + def __str__(self): + return "<%s@%x id=%s angle_rad=%s>" % (self.__class__.__name__, id(self), self.id, self.angle_rad) + + def __repr__(self): + return self.__str__() + diff --git a/servo_service/interface.py b/servo_service/interface.py new file mode 100644 index 0000000..f6a71f3 --- /dev/null +++ b/servo_service/interface.py @@ -0,0 +1,35 @@ +# +# Generated by erpcgen 1.14.0 on Tue Apr 28 12:25:26 2026. +# +# AUTOGENERATED - DO NOT EDIT +# + +# Abstract base class for servo_service +class Iservo_service(object): + SERVICE_ID = 1 + SETCONSTRAINTS_ID = 1 + SETPOSITIONGAIN_ID = 2 + SETMODE_ID = 3 + SETUPDATEPERIODMS_ID = 4 + MOVE_ID = 5 + MOVEJ_ID = 6 + + def setConstraints(self, id, max_velocity_rad, max_acceleration_rad, max_jerk_rad): + raise NotImplementedError() + + def setPositionGain(self, id, position_gain): + raise NotImplementedError() + + def setMode(self, mode): + raise NotImplementedError() + + def setUpdatePeriodMs(self, ms): + raise NotImplementedError() + + def move(self, cmds): + raise NotImplementedError() + + def moveJ(self, angles_rad): + raise NotImplementedError() + + diff --git a/servo_service/server.py b/servo_service/server.py new file mode 100644 index 0000000..78f584b --- /dev/null +++ b/servo_service/server.py @@ -0,0 +1,146 @@ +# +# Generated by erpcgen 1.14.0 on Tue Apr 28 12:25:26 2026. +# +# AUTOGENERATED - DO NOT EDIT +# + +import erpc +from . import common, interface + +# Client for servo_service +class servo_serviceService(erpc.server.Service): + def __init__(self, handler): + super(servo_serviceService, self).__init__(interface.Iservo_service.SERVICE_ID) + self._handler = handler + self._methods = { + interface.Iservo_service.SETCONSTRAINTS_ID: self._handle_setConstraints, + interface.Iservo_service.SETPOSITIONGAIN_ID: self._handle_setPositionGain, + interface.Iservo_service.SETMODE_ID: self._handle_setMode, + interface.Iservo_service.SETUPDATEPERIODMS_ID: self._handle_setUpdatePeriodMs, + interface.Iservo_service.MOVE_ID: self._handle_move, + interface.Iservo_service.MOVEJ_ID: self._handle_moveJ, + } + + def _handle_setConstraints(self, sequence, codec): + # Read incoming parameters. + id = codec.read_string() + max_velocity_rad = codec.read_float() + max_acceleration_rad = codec.read_float() + max_jerk_rad = codec.read_float() + + # Invoke user implementation of remote function. + _result = self._handler.setConstraints(id, max_velocity_rad, max_acceleration_rad, max_jerk_rad) + + # Prepare codec for reply message. + codec.reset() + + # Construct reply message. + codec.start_write_message(erpc.codec.MessageInfo( + type=erpc.codec.MessageType.kReplyMessage, + service=interface.Iservo_service.SERVICE_ID, + request=interface.Iservo_service.SETCONSTRAINTS_ID, + sequence=sequence)) + codec.write_bool(_result) + + def _handle_setPositionGain(self, sequence, codec): + # Read incoming parameters. + id = codec.read_string() + position_gain = codec.read_float() + + # Invoke user implementation of remote function. + _result = self._handler.setPositionGain(id, position_gain) + + # Prepare codec for reply message. + codec.reset() + + # Construct reply message. + codec.start_write_message(erpc.codec.MessageInfo( + type=erpc.codec.MessageType.kReplyMessage, + service=interface.Iservo_service.SERVICE_ID, + request=interface.Iservo_service.SETPOSITIONGAIN_ID, + sequence=sequence)) + codec.write_bool(_result) + + def _handle_setMode(self, sequence, codec): + # Read incoming parameters. + mode = codec.read_int32() + + # Invoke user implementation of remote function. + _result = self._handler.setMode(mode) + + # Prepare codec for reply message. + codec.reset() + + # Construct reply message. + codec.start_write_message(erpc.codec.MessageInfo( + type=erpc.codec.MessageType.kReplyMessage, + service=interface.Iservo_service.SERVICE_ID, + request=interface.Iservo_service.SETMODE_ID, + sequence=sequence)) + codec.write_bool(_result) + + def _handle_setUpdatePeriodMs(self, sequence, codec): + # Read incoming parameters. + ms = codec.read_uint32() + + # Invoke user implementation of remote function. + _result = self._handler.setUpdatePeriodMs(ms) + + # Prepare codec for reply message. + codec.reset() + + # Construct reply message. + codec.start_write_message(erpc.codec.MessageInfo( + type=erpc.codec.MessageType.kReplyMessage, + service=interface.Iservo_service.SERVICE_ID, + request=interface.Iservo_service.SETUPDATEPERIODMS_ID, + sequence=sequence)) + codec.write_bool(_result) + + def _handle_move(self, sequence, codec): + # Read incoming parameters. + _n0 = codec.start_read_list() + cmds = [] + for _i0 in range(_n0): + _v0 = common.ServoCmd()._read(codec) + cmds.append(_v0) + + + # Invoke user implementation of remote function. + _result = self._handler.move(cmds) + + # Prepare codec for reply message. + codec.reset() + + # Construct reply message. + codec.start_write_message(erpc.codec.MessageInfo( + type=erpc.codec.MessageType.kReplyMessage, + service=interface.Iservo_service.SERVICE_ID, + request=interface.Iservo_service.MOVE_ID, + sequence=sequence)) + codec.write_int32(_result) + + def _handle_moveJ(self, sequence, codec): + # Read incoming parameters. + _n0 = codec.start_read_list() + angles_rad = [] + for _i0 in range(_n0): + _v0 = codec.read_float() + angles_rad.append(_v0) + + + # Invoke user implementation of remote function. + _result = self._handler.moveJ(angles_rad) + + # Prepare codec for reply message. + codec.reset() + + # Construct reply message. + codec.start_write_message(erpc.codec.MessageInfo( + type=erpc.codec.MessageType.kReplyMessage, + service=interface.Iservo_service.SERVICE_ID, + request=interface.Iservo_service.MOVEJ_ID, + sequence=sequence)) + codec.write_int32(_result) + + diff --git a/test.py b/test.py new file mode 100644 index 0000000..21a4c64 --- /dev/null +++ b/test.py @@ -0,0 +1,118 @@ +import argparse +import statistics +import time + +import erpc + +from servo_service import client + + +DEFAULT_PORT = "COM8" +DEFAULT_BAUD = 115200 +DEFAULT_ITERATIONS = 100 +DEFAULT_JOINT_COUNT = 26 +DEFAULT_WARMUP = 5 + + +def positive_int(value): + parsed = int(value) + if parsed <= 0: + raise argparse.ArgumentTypeError("value must be > 0") + return parsed + + +def non_negative_float(value): + parsed = float(value) + if parsed < 0: + raise argparse.ArgumentTypeError("value must be >= 0") + return parsed + + +def percentile(values, ratio): + if not values: + raise ValueError("values must not be empty") + ordered = sorted(values) + index = int(ratio * (len(ordered) - 1)) + return ordered[index] + + +def measure_movej_latency(api, angles, iterations, warmup): + for index in range(warmup): + result = api.moveJ(angles) + # if result != 0: + # raise RuntimeError(f"Warmup moveJ failed at iteration {index}: {result}") + + costs_ms = [] + for index in range(iterations): + t0 = time.perf_counter() + result = api.moveJ(angles) + elapsed_ms = (time.perf_counter() - t0) * 1000.0 + # if result != 0: + # raise RuntimeError(f"moveJ failed at iteration {index}: {result}") + costs_ms.append(elapsed_ms) + return costs_ms + + +def print_summary(costs_ms): + print(f"count = {len(costs_ms)}") + print(f"avg = {statistics.mean(costs_ms):.3f} ms") + print(f"min = {min(costs_ms):.3f} ms") + print(f"max = {max(costs_ms):.3f} ms") + print(f"p50 = {statistics.median(costs_ms):.3f} ms") + print(f"p95 = {percentile(costs_ms, 0.95):.3f} ms") + + +def build_parser(): + parser = argparse.ArgumentParser(description="Measure moveJ RPC latency.") + parser.add_argument("--port", default=DEFAULT_PORT, help=f"Serial port, default: {DEFAULT_PORT}") + parser.add_argument("--baud", type=positive_int, default=DEFAULT_BAUD, help=f"Serial baud, default: {DEFAULT_BAUD}") + parser.add_argument( + "--iterations", + type=positive_int, + default=DEFAULT_ITERATIONS, + help=f"Measured moveJ calls, default: {DEFAULT_ITERATIONS}", + ) + parser.add_argument( + "--warmup", + type=positive_int, + default=DEFAULT_WARMUP, + help=f"Warmup moveJ calls before measuring, default: {DEFAULT_WARMUP}", + ) + parser.add_argument( + "--joint-count", + type=positive_int, + default=DEFAULT_JOINT_COUNT, + help=f"Length of angles_rad list, default: {DEFAULT_JOINT_COUNT}", + ) + parser.add_argument( + "--angle-rad", + type=non_negative_float, + default=0.0, + help="Angle value written into every joint slot, default: 0.0", + ) + return parser + + +def main(): + args = build_parser().parse_args() + angles = [args.angle_rad] * args.joint_count + + transport = erpc.transport.SerialTransport(args.port, args.baud) + try: + client_mgr = erpc.client.ClientManager(transport, erpc.basic_codec.BasicCodec) + api = client.servo_serviceClient(client_mgr) + print(f"port = {args.port}") + print(f"baud = {args.baud}") + print(f"iterations = {args.iterations}") + print(f"warmup = {args.warmup}") + print(f"joint_count = {args.joint_count}") + print(f"angle_rad = {args.angle_rad}") + costs_ms = measure_movej_latency(api, angles, args.iterations, args.warmup) + print_summary(costs_ms) + finally: + if hasattr(transport, "close"): + transport.close() + + +if __name__ == "__main__": + main() diff --git a/ui/README.md b/ui/README.md new file mode 100644 index 0000000..27094b5 --- /dev/null +++ b/ui/README.md @@ -0,0 +1,36 @@ +# Face Servo UI + +Run the desktop UI from the repository root: + +```powershell +powershell -ExecutionPolicy Bypass -File .\run_ui.ps1 +``` + +If you only changed Python/UI code and want to skip rebuilding `_s_curve_native`: + +```powershell +powershell -ExecutionPolicy Bypass -File .\run_ui.ps1 -SkipBuild +``` + +If you need to override the Python path: + +```powershell +powershell -ExecutionPolicy Bypass -File .\run_ui.ps1 -PythonExecutable "C:\Users\Administrator\miniconda3\envs\cmvr-head-client\python.exe" +``` + +Current UI scope includes: + +- `servo_service` eRPC control +- single-servo / moveJ controls +- `SCurve` preview +- `SCurvePositionPlanner1D` preview + +Default serial settings are `COM8` and `115200`. + +The servo config uploader defaults to `config/servo_config.yaml`. It runs +`config/yaml_to_json.py` and uploads the generated JSON to +`config/servo_config.json` on the device. The converter requires PyYAML: + +```powershell +python -m pip install PyYAML +``` diff --git a/ui/__pycache__/face_servo_control.cpython-310.pyc b/ui/__pycache__/face_servo_control.cpython-310.pyc new file mode 100644 index 0000000..577d0db Binary files /dev/null and b/ui/__pycache__/face_servo_control.cpython-310.pyc differ diff --git a/ui/__pycache__/face_servo_control.cpython-311.pyc b/ui/__pycache__/face_servo_control.cpython-311.pyc new file mode 100644 index 0000000..eb1ccf5 Binary files /dev/null and b/ui/__pycache__/face_servo_control.cpython-311.pyc differ diff --git a/ui/face_servo_control.py b/ui/face_servo_control.py new file mode 100644 index 0000000..611651d --- /dev/null +++ b/ui/face_servo_control.py @@ -0,0 +1,2342 @@ +import json +import queue +import subprocess +import sys +import threading +import time +import traceback +import math +from pathlib import Path +import tkinter as tk +from tkinter import filedialog, messagebox, ttk + +import erpc + + +REPO_ROOT = Path(__file__).resolve().parents[1] +if str(REPO_ROOT) not in sys.path: + sys.path.insert(0, str(REPO_ROOT)) + +from file_service import client as file_service_client +from servo_service import client as servo_service_client +from servo_service import common as servo_service_common +from s_curve import SCurve, SCurveError, SCurvePositionPlanner1D + +SERVO_CHANNEL_COUNT = 48 +DEFAULT_FILE_CHUNK_SIZE = 4096 +CONFIG_DIR = REPO_ROOT / "config" +SERVO_CONFIG_YAML_PATH = CONFIG_DIR / "servo_config.yaml" +SERVO_CONFIG_PATH = CONFIG_DIR / "servo_config.json" +YAML_TO_JSON_SCRIPT = CONFIG_DIR / "yaml_to_json.py" +DEFAULT_REMOTE_SERVO_CONFIG_PATH = "config/servo_config.json" +BLINK_TRANSITION_MS = 90 +BLINK_STEP_MS = 15 +EYE_CONTROL_SPECS = ( + {"title": "Left Upper Lid", "short": "Upper Lid", "default_id": "eye_l_up", "blink": True}, + {"title": "Left Lower Lid", "short": "Lower Lid", "default_id": "eye_l_lower", "blink": True}, + {"title": "Right Upper Lid", "short": "Upper Lid", "default_id": "eye_r_up", "blink": True}, + {"title": "Right Lower Lid", "short": "Lower Lid", "default_id": "eye_r_lower", "blink": True}, + {"title": "Eyes Horizontal", "short": "Horizontal", "default_id": "", "blink": False}, + {"title": "Eyes Vertical", "short": "Vertical", "default_id": "", "blink": False}, +) + + +class FaceServoRpcClient: + def __init__(self): + self._transport = None + self._manager = None + self._servo_client = None + self._file_client = None + + @property + def is_connected(self): + return self._servo_client is not None and self._file_client is not None + + def connect(self, port, baud): + self.close() + self._transport = erpc.transport.SerialTransport(port, baud) + self._manager = erpc.client.ClientManager( + self._transport, + erpc.basic_codec.BasicCodec, + ) + self._servo_client = servo_service_client.servo_serviceClient(self._manager) + self._file_client = file_service_client.file_serviceClient(self._manager) + + def close(self): + transport = self._transport + self._servo_client = None + self._file_client = None + self._manager = None + self._transport = None + if transport and hasattr(transport, "close"): + transport.close() + + def move(self, items): + self._require_servo_client() + cmds = [ + servo_service_common.ServoCmd(id=servo_id, angle_rad=float(angle_rad)) + for servo_id, angle_rad in items + ] + return self._servo_client.move(cmds) + + def move_j(self, angles_rad): + self._require_servo_client() + return self._servo_client.moveJ([float(value) for value in angles_rad]) + + def set_constraints(self, servo_id, max_velocity_rad, max_acceleration_rad, max_jerk_rad): + self._require_servo_client() + return self._servo_client.setConstraints( + servo_id, + float(max_velocity_rad), + float(max_acceleration_rad), + float(max_jerk_rad), + ) + + def set_position_gain(self, servo_id, position_gain): + self._require_servo_client() + return self._servo_client.setPositionGain( + servo_id, + float(position_gain), + ) + + def set_mode(self, mode): + self._require_servo_client() + return self._servo_client.setMode(int(mode)) + + def set_update_period_ms(self, ms): + self._require_servo_client() + return self._servo_client.setUpdatePeriodMs(int(ms)) + + def file_write_begin(self, path, total_size): + self._require_file_client() + return self._file_client.fileWriteBegin(path, int(total_size)) + + def file_write_chunk(self, data): + self._require_file_client() + return self._file_client.fileWriteChunk(data) + + def file_write_end(self): + self._require_file_client() + return self._file_client.fileWriteEnd() + + def file_write_abort(self): + self._require_file_client() + return self._file_client.fileWriteAbort() + + def upload_file(self, local_path, remote_path, chunk_size, progress=None, cancelled=None): + self._require_file_client() + file_path = Path(local_path) + if not file_path.is_file(): + raise FileNotFoundError(f"Local file not found: {file_path}") + if not remote_path: + raise ValueError("Remote path is required.") + if chunk_size <= 0: + raise ValueError("Chunk size must be > 0.") + + total_size = file_path.stat().st_size + if total_size > 0xFFFFFFFF: + raise ValueError("File is too large for uint32 total_size.") + + if callable(cancelled) and cancelled(): + raise InterruptedError("Upload aborted before start.") + + begin_result = self.file_write_begin(remote_path, total_size) + if begin_result != 0: + raise RuntimeError(f"fileWriteBegin failed: {begin_result}") + + bytes_sent = 0 + chunk_count = 0 + try: + with file_path.open("rb") as stream: + while True: + if callable(cancelled) and cancelled(): + raise InterruptedError("Upload aborted by user.") + + chunk = stream.read(chunk_size) + if not chunk: + break + + result = self.file_write_chunk(chunk) + if result != 0: + raise RuntimeError( + f"fileWriteChunk failed at offset {bytes_sent}: {result}" + ) + + bytes_sent += len(chunk) + chunk_count += 1 + if callable(progress): + progress(bytes_sent, total_size) + + end_result = self.file_write_end() + if end_result != 0: + raise RuntimeError(f"fileWriteEnd failed: {end_result}") + except Exception: + try: + self.file_write_abort() + except Exception: + pass + raise + + return { + "local_path": str(file_path), + "remote_path": remote_path, + "total_size": total_size, + "bytes_sent": bytes_sent, + "chunk_count": chunk_count, + } + + def _require_servo_client(self): + if not self._servo_client: + raise RuntimeError("Not connected. Configure serial and click Connect first.") + + def _require_file_client(self): + if not self._file_client: + raise RuntimeError("Not connected. Configure serial and click Connect first.") + + +class FaceServoControlApp: + def __init__(self, root): + self.root = root + self.root.title("Face Servo Console") + self.root.geometry("1380x880") + self.root.minsize(1180, 760) + self.root.protocol("WM_DELETE_WINDOW", self.on_close) + + self.rpc = FaceServoRpcClient() + self.events = queue.Queue() + self.servo_configs, self.servo_config_error = self._load_servo_configs() + self.servo_id_options = list(self.servo_configs.keys()) + default_servo_id = self._get_preferred_servo_id() + + self.status_var = tk.StringVar(value="Disconnected") + self.port_var = tk.StringVar(value="COM8") + self.baud_var = tk.StringVar(value="115200") + self.single_id_var = tk.StringVar(value=default_servo_id) + self.single_angle_var = tk.DoubleVar(value=0.0) + self.single_live_drag_var = tk.BooleanVar(value=True) + self.single_live_rate_hz_var = tk.StringVar(value="50") + self.rpc_mode_var = tk.StringVar(value="immediate") + self.update_period_ms_var = tk.StringVar(value="10") + self.file_local_path_var = tk.StringVar(value=str(SERVO_CONFIG_YAML_PATH)) + self.file_remote_path_var = tk.StringVar(value=DEFAULT_REMOTE_SERVO_CONFIG_PATH) + self.file_chunk_size_var = tk.StringVar(value=str(DEFAULT_FILE_CHUNK_SIZE)) + self.file_status_var = tk.StringVar(value="Config upload idle") + self.file_progress_var = tk.StringVar(value=f"Ready: {SERVO_CONFIG_YAML_PATH.name}") + self.file_progress_percent_var = tk.DoubleVar(value=0.0) + self.fill_angle_var = tk.DoubleVar(value=0.0) + self.blink_hold_ms_var = tk.StringVar(value="120") + self.last_result_var = tk.StringVar(value="Result: idle") + self.constraint_servo_id_var = tk.StringVar(value=default_servo_id) + self.scurve_max_velocity_var = tk.StringVar(value="3.0") + self.scurve_max_acceleration_var = tk.StringVar(value="10.0") + self.scurve_max_jerk_var = tk.StringVar(value="50.0") + self.scurve_start_position_var = tk.StringVar(value="0.0") + self.scurve_end_position_var = tk.StringVar(value="30.0") + self.scurve_start_velocity_var = tk.StringVar(value="0.0") + self.scurve_end_velocity_var = tk.StringVar(value="0.0") + self.scurve_sample_dt_var = tk.StringVar(value="0.01") + self.scurve_status_var = tk.StringVar(value="SCurve idle") + self.scurve_summary_var = tk.StringVar(value="No SCurve plan yet.") + self.scurve_segments_var = tk.StringVar(value="Segments: -") + self.follow_servo_id_var = tk.StringVar(value=default_servo_id) + self.position_planner_max_velocity_var = tk.StringVar(value="3.0") + self.position_planner_max_acceleration_var = tk.StringVar(value="10.0") + self.position_planner_max_jerk_var = tk.StringVar(value="50.0") + self.position_planner_gain_var = tk.StringVar(value="1.0") + self.position_planner_initial_position_var = tk.StringVar(value="0.0") + self.position_planner_initial_velocity_var = tk.StringVar(value="0.0") + self.position_planner_initial_acceleration_var = tk.StringVar(value="0.0") + self.position_planner_target_position_var = tk.StringVar(value="30.0") + self.position_planner_sample_dt_var = tk.StringVar(value="0.01") + self.position_planner_duration_var = tk.StringVar(value="3.0") + self.position_planner_status_var = tk.StringVar(value="Follow planner idle") + self.position_planner_summary_var = tk.StringVar(value="No follow plan yet.") + self.position_planner_target_var = tk.StringVar(value="Target: -") + + self.eye_controls = [ + { + **spec, + "id_var": tk.StringVar(value=spec["default_id"]), + "angle_var": tk.DoubleVar(value=0.0), + } + for spec in EYE_CONTROL_SPECS + ] + self.scurve = None + self.position_planner = None + self._single_live_job = None + self._single_live_pending = False + self._file_upload_cancel = threading.Event() + self._file_upload_active = False + self._blink_active = False + self._blink_loop_job = None + self._preview_update_job = None + self.notebook = None + self.single_angle_scale = None + self.tab_frames = {} + self.scurve_canvases = {} + self.scurve_plot_series = { + "position": None, + "velocity": None, + "acceleration": None, + "jerk": None, + } + self.position_planner_canvases = {} + self.position_planner_plot_series = { + "position": None, + "velocity": None, + "acceleration": None, + "jerk": None, + } + self.colors = { + "app_bg": "#eef4f7", + "panel_bg": "#ffffff", + "panel_edge": "#d5e2ea", + "hero_text": "#163243", + "body_text": "#315164", + "muted_text": "#6f8796", + "input_bg": "#f7fbfd", + "input_text": "#173446", + "accent": "#32b3a4", + "accent_active": "#54c6b8", + "accent_text": "#ffffff", + "ghost": "#e6f1f5", + "ghost_active": "#d7e8ef", + "ghost_text": "#21475b", + "status": "#22906d", + "notebook_tab": "#ddebf1", + "notebook_tab_active": "#cfe3eb", + "notebook_tab_selected": "#32b3a4", + "log_bg": "#f4fafc", + "log_text": "#224054", + "plot_bg": "#f6fbfd", + "plot_grid": "#d7e6ee", + "plot_axis": "#a9c0cc", + } + + self._build_style() + self._build_layout() + self._initialize_servo_config_ui() + self._poll_events() + + def _build_style(self): + c = self.colors + self.root.configure(bg=c["app_bg"]) + style = ttk.Style() + style.theme_use("clam") + style.configure( + ".", + background=c["app_bg"], + foreground=c["body_text"], + fieldbackground=c["input_bg"], + bordercolor=c["panel_edge"], + lightcolor=c["panel_edge"], + darkcolor=c["panel_edge"], + ) + style.configure("TFrame", background=c["app_bg"]) + style.configure("Panel.TFrame", background=c["panel_bg"], relief="flat") + style.configure( + "TLabel", + background=c["app_bg"], + foreground=c["body_text"], + font=("Segoe UI", 10), + ) + style.configure( + "Header.TLabel", + background=c["app_bg"], + foreground=c["hero_text"], + font=("Bahnschrift SemiBold", 22), + ) + style.configure( + "Subhead.TLabel", + background=c["panel_bg"], + foreground=c["hero_text"], + font=("Bahnschrift SemiBold", 12), + ) + style.configure( + "Muted.TLabel", + background=c["panel_bg"], + foreground=c["muted_text"], + font=("Segoe UI", 9), + ) + style.configure( + "TEntry", + padding=7, + foreground=c["input_text"], + fieldbackground=c["input_bg"], + insertcolor=c["input_text"], + ) + style.configure( + "Accent.TButton", + background=c["accent"], + foreground=c["accent_text"], + padding=(14, 8), + borderwidth=0, + font=("Bahnschrift SemiBold", 10), + ) + style.map( + "Accent.TButton", + background=[("active", c["accent_active"]), ("disabled", "#b5c6cf")], + foreground=[("disabled", "#f6fbfd")], + ) + style.configure( + "Ghost.TButton", + background=c["ghost"], + foreground=c["ghost_text"], + padding=(14, 8), + borderwidth=0, + font=("Segoe UI Semibold", 10), + ) + style.map("Ghost.TButton", background=[("active", c["ghost_active"])]) + style.configure( + "Status.TLabel", + background=c["panel_bg"], + foreground=c["status"], + font=("Segoe UI Semibold", 10), + ) + style.configure( + "File.Horizontal.TProgressbar", + background=c["accent"], + troughcolor=c["ghost"], + bordercolor=c["panel_edge"], + lightcolor=c["accent"], + darkcolor=c["accent"], + thickness=12, + ) + style.configure("TNotebook", background=c["app_bg"], borderwidth=0, tabmargins=(0, 0, 0, 0)) + style.configure( + "TNotebook.Tab", + background=c["notebook_tab"], + foreground=c["ghost_text"], + padding=(16, 8), + font=("Segoe UI Semibold", 10), + ) + style.map( + "TNotebook.Tab", + background=[("selected", c["notebook_tab_selected"]), ("active", c["notebook_tab_active"])], + foreground=[("selected", c["accent_text"])], + ) + + def _build_layout(self): + shell = ttk.Frame(self.root, padding=18) + shell.pack(fill="both", expand=True) + shell.columnconfigure(0, weight=1) + shell.rowconfigure(1, weight=1) + + hero = ttk.Frame(shell) + hero.grid(row=0, column=0, sticky="ew", pady=(0, 14)) + hero.columnconfigure(0, weight=1) + + ttk.Label(hero, text="Face Servo Console", style="Header.TLabel").grid( + row=0, column=0, sticky="w" + ) + ttk.Label( + hero, + text="eRPC serial controller for servo_service and file_service", + style="TLabel", + ).grid(row=1, column=0, sticky="w", pady=(4, 0)) + + main = ttk.Frame(shell) + main.grid(row=1, column=0, sticky="nsew") + main.columnconfigure(0, weight=0) + main.columnconfigure(1, weight=1) + main.rowconfigure(0, weight=1) + + left = ttk.Frame(main, style="Panel.TFrame", padding=16) + left.grid(row=0, column=0, sticky="nsw", padx=(0, 14)) + right = ttk.Frame(main, style="Panel.TFrame", padding=16) + right.grid(row=0, column=1, sticky="nsew") + right.columnconfigure(0, weight=1) + right.rowconfigure(0, weight=1) + + self._build_connection_panel(left) + self._build_motion_panel(left) + self._build_single_panel(left) + self._build_file_panel(left) + self._build_log_panel(left) + notebook = ttk.Notebook(right) + notebook.grid(row=0, column=0, sticky="nsew") + self.notebook = notebook + + servo_tab = ttk.Frame(notebook, style="Panel.TFrame", padding=16) + servo_tab.columnconfigure(0, weight=1) + servo_tab.rowconfigure(1, weight=1) + notebook.add(servo_tab, text="Servo Matrix") + + scurve_tab = ttk.Frame(notebook, style="Panel.TFrame", padding=16) + scurve_tab.columnconfigure(0, weight=1) + scurve_tab.rowconfigure(1, weight=1) + notebook.add(scurve_tab, text="SCurve Planner") + + position_planner_tab = ttk.Frame(notebook, style="Panel.TFrame", padding=16) + position_planner_tab.columnconfigure(0, weight=1) + position_planner_tab.rowconfigure(1, weight=1) + notebook.add(position_planner_tab, text="Follow Planner") + self.tab_frames = { + "servo": servo_tab, + "scurve": scurve_tab, + "follow": position_planner_tab, + } + + self._build_all_angles_panel(servo_tab) + self._build_scurve_panel(scurve_tab) + self._build_position_planner_panel(position_planner_tab) + + def _build_connection_panel(self, parent): + panel = ttk.Frame(parent, style="Panel.TFrame") + panel.pack(fill="x") + panel.columnconfigure(1, weight=1) + + ttk.Label(panel, text="Connection", style="Subhead.TLabel").grid( + row=0, column=0, columnspan=2, sticky="w" + ) + ttk.Label(panel, text="Serial link to the board", style="Muted.TLabel").grid( + row=1, column=0, columnspan=2, sticky="w", pady=(0, 14) + ) + + ttk.Label(panel, text="Port").grid(row=2, column=0, sticky="w", pady=4) + ttk.Entry(panel, textvariable=self.port_var, width=18).grid( + row=2, column=1, sticky="ew", pady=4 + ) + + ttk.Label(panel, text="Baud").grid(row=3, column=0, sticky="w", pady=4) + ttk.Entry(panel, textvariable=self.baud_var, width=18).grid( + row=3, column=1, sticky="ew", pady=4 + ) + + button_row = ttk.Frame(panel, style="Panel.TFrame") + button_row.grid(row=4, column=0, columnspan=2, sticky="ew", pady=(10, 8)) + button_row.columnconfigure(0, weight=1) + button_row.columnconfigure(1, weight=1) + + ttk.Button( + button_row, + text="Connect", + style="Accent.TButton", + command=self.connect_clicked, + ).grid(row=0, column=0, sticky="ew", padx=(0, 6)) + ttk.Button( + button_row, + text="Disconnect", + style="Ghost.TButton", + command=self.disconnect_clicked, + ).grid(row=0, column=1, sticky="ew", padx=(6, 0)) + + ttk.Label(panel, textvariable=self.status_var, style="Status.TLabel").grid( + row=5, column=0, columnspan=2, sticky="w" + ) + ttk.Label(panel, textvariable=self.last_result_var, style="Muted.TLabel").grid( + row=6, column=0, columnspan=2, sticky="w", pady=(4, 0) + ) + + def _build_motion_panel(self, parent): + panel = ttk.Frame(parent, style="Panel.TFrame") + panel.pack(fill="x", pady=(22, 0)) + panel.columnconfigure(1, weight=1) + + ttk.Label(panel, text="Motion Settings", style="Subhead.TLabel").grid( + row=0, column=0, columnspan=2, sticky="w" + ) + ttk.Label(panel, text="Global setMode() and setUpdatePeriodMs()", style="Muted.TLabel").grid( + row=1, column=0, columnspan=2, sticky="w", pady=(0, 14) + ) + + ttk.Label(panel, text="Mode").grid(row=2, column=0, sticky="w", pady=4) + mode_row = ttk.Frame(panel, style="Panel.TFrame") + mode_row.grid(row=2, column=1, sticky="w", pady=4) + ttk.Radiobutton( + mode_row, + text="Immediate", + value="immediate", + variable=self.rpc_mode_var, + command=self._on_motion_mode_changed, + ).grid(row=0, column=0, sticky="w") + ttk.Radiobutton( + mode_row, + text="SCurve", + value="scurve", + variable=self.rpc_mode_var, + command=self._on_motion_mode_changed, + ).grid(row=0, column=1, sticky="w", padx=(12, 0)) + ttk.Radiobutton( + mode_row, + text="Follow", + value="follow", + variable=self.rpc_mode_var, + command=self._on_motion_mode_changed, + ).grid(row=0, column=2, sticky="w", padx=(12, 0)) + + ttk.Label(panel, text="Period ms").grid(row=3, column=0, sticky="w", pady=4) + ttk.Entry(panel, textvariable=self.update_period_ms_var).grid( + row=3, column=1, sticky="ew", pady=4 + ) + + button_row = ttk.Frame(panel, style="Panel.TFrame") + button_row.grid(row=4, column=0, columnspan=2, sticky="ew", pady=(12, 0)) + button_row.columnconfigure(0, weight=1) + button_row.columnconfigure(1, weight=1) + ttk.Button( + button_row, + text="Apply Settings", + style="Accent.TButton", + command=self.send_motion_settings_clicked, + ).grid(row=0, column=0, sticky="ew", padx=(0, 6)) + ttk.Button( + button_row, + text="Send Mode Only", + style="Ghost.TButton", + command=self.send_mode_clicked, + ).grid(row=0, column=1, sticky="ew", padx=(6, 0)) + + def _build_single_panel(self, parent): + panel = ttk.Frame(parent, style="Panel.TFrame") + panel.pack(fill="x", pady=(22, 0)) + panel.columnconfigure(1, weight=1) + + ttk.Label(panel, text="Single Servo", style="Subhead.TLabel").grid( + row=0, column=0, columnspan=2, sticky="w" + ) + ttk.Label(panel, text="Call move([ServoCmd(id, angle_rad)])", style="Muted.TLabel").grid( + row=1, column=0, columnspan=2, sticky="w", pady=(0, 14) + ) + + ttk.Label(panel, text="Servo ID").grid(row=2, column=0, sticky="w", pady=4) + single_id_entry = ttk.Combobox( + panel, + textvariable=self.single_id_var, + values=self.servo_id_options, + state="normal", + ) + single_id_entry.grid(row=2, column=1, sticky="ew", pady=4) + single_id_entry.bind("<>", self._on_single_servo_id_changed) + single_id_entry.bind("", self._on_single_servo_id_changed) + single_id_entry.bind("", self._on_single_servo_id_changed) + + ttk.Label(panel, text="Angle").grid(row=3, column=0, sticky="w", pady=4) + angle_row = ttk.Frame(panel, style="Panel.TFrame") + angle_row.grid(row=3, column=1, sticky="ew", pady=4) + angle_row.columnconfigure(0, weight=1) + self.single_angle_scale = ttk.Scale( + angle_row, + variable=self.single_angle_var, + from_=-math.pi, + to=math.pi, + orient="horizontal", + command=self._on_single_scale_changed, + ) + self.single_angle_scale.grid(row=0, column=0, sticky="ew", padx=(0, 10)) + single_angle_entry = ttk.Entry(angle_row, textvariable=self.single_angle_var, width=8) + single_angle_entry.grid(row=0, column=1, sticky="e") + single_angle_entry.bind("", self._send_single_from_event) + self.single_angle_scale.bind("", self._on_single_scale_released) + + command_row = ttk.Frame(panel, style="Panel.TFrame") + command_row.grid(row=4, column=0, columnspan=2, sticky="ew", pady=(10, 0)) + command_row.columnconfigure(0, weight=1) + command_row.columnconfigure(1, weight=0) + command_row.columnconfigure(2, weight=0) + ttk.Checkbutton( + command_row, + text="Live drag send", + variable=self.single_live_drag_var, + command=self._on_single_live_drag_toggled, + ).grid(row=0, column=0, sticky="e") + ttk.Entry(command_row, textvariable=self.single_live_rate_hz_var, width=6).grid( + row=0, column=1, sticky="e", padx=(10, 6) + ) + ttk.Label(command_row, text="Hz", style="Muted.TLabel").grid(row=0, column=2, sticky="e") + + ttk.Label(panel, text="Angle unit: rad", style="Muted.TLabel").grid( + row=5, column=0, columnspan=2, sticky="w", pady=(8, 0) + ) + + single_button_row = ttk.Frame(panel, style="Panel.TFrame") + single_button_row.grid(row=6, column=0, columnspan=2, sticky="ew", pady=(12, 0)) + single_button_row.columnconfigure(0, weight=1) + ttk.Button( + single_button_row, + text="Send move", + style="Accent.TButton", + command=self.send_single_clicked, + ).grid(row=0, column=0, sticky="ew") + + def _build_log_panel(self, parent): + panel = ttk.Frame(parent, style="Panel.TFrame") + panel.pack(fill="both", expand=True, pady=(22, 0)) + panel.columnconfigure(0, weight=1) + panel.rowconfigure(1, weight=1) + + ttk.Label(panel, text="Activity", style="Subhead.TLabel").grid( + row=0, column=0, sticky="w" + ) + self.log_widget = tk.Text( + panel, + height=12, + bg=self.colors["log_bg"], + fg=self.colors["log_text"], + insertbackground=self.colors["log_text"], + relief="flat", + bd=0, + wrap="word", + font=("Consolas", 10), + ) + self.log_widget.grid(row=1, column=0, sticky="nsew", pady=(10, 0)) + self.log_widget.insert("end", "Console ready.\n") + self.log_widget.configure(state="disabled") + + def _build_file_panel(self, parent): + panel = ttk.Frame(parent, style="Panel.TFrame") + panel.pack(fill="x", pady=(22, 0)) + panel.columnconfigure(1, weight=1) + + ttk.Label(panel, text="Servo Config Upload", style="Subhead.TLabel").grid( + row=0, column=0, columnspan=2, sticky="w" + ) + ttk.Label( + panel, + text="Convert the local YAML config to JSON, then upload it with file_service.", + style="Muted.TLabel", + ).grid(row=1, column=0, columnspan=2, sticky="w", pady=(0, 14)) + + ttk.Label(panel, text="Local YAML").grid(row=2, column=0, sticky="w", pady=4) + local_row = ttk.Frame(panel, style="Panel.TFrame") + local_row.grid(row=2, column=1, sticky="ew", pady=4) + local_row.columnconfigure(0, weight=1) + local_entry = ttk.Entry(local_row, textvariable=self.file_local_path_var) + local_entry.grid(row=0, column=0, sticky="ew", padx=(0, 8)) + local_entry.bind("", self._send_file_from_event) + ttk.Button( + local_row, + text="Browse", + style="Ghost.TButton", + command=self.browse_file_clicked, + ).grid(row=0, column=1, sticky="e") + + ttk.Label(panel, text="Remote path").grid(row=3, column=0, sticky="w", pady=4) + remote_entry = ttk.Entry(panel, textvariable=self.file_remote_path_var) + remote_entry.grid(row=3, column=1, sticky="ew", pady=4) + remote_entry.bind("", self._send_file_from_event) + + ttk.Label(panel, text="Chunk bytes").grid(row=4, column=0, sticky="w", pady=4) + chunk_entry = ttk.Entry(panel, textvariable=self.file_chunk_size_var) + chunk_entry.grid(row=4, column=1, sticky="ew", pady=4) + chunk_entry.bind("", self._send_file_from_event) + + button_row = ttk.Frame(panel, style="Panel.TFrame") + button_row.grid(row=5, column=0, columnspan=2, sticky="ew", pady=(12, 0)) + button_row.columnconfigure(0, weight=1) + button_row.columnconfigure(1, weight=1) + ttk.Button( + button_row, + text="Upload Config", + style="Accent.TButton", + command=self.send_file_clicked, + ).grid(row=0, column=0, sticky="ew", padx=(0, 6)) + ttk.Button( + button_row, + text="Abort Upload", + style="Ghost.TButton", + command=self.abort_file_clicked, + ).grid(row=0, column=1, sticky="ew", padx=(6, 0)) + + ttk.Label(panel, textvariable=self.file_status_var, style="Status.TLabel").grid( + row=6, column=0, columnspan=2, sticky="w", pady=(8, 0) + ) + ttk.Progressbar( + panel, + style="File.Horizontal.TProgressbar", + mode="determinate", + maximum=100.0, + variable=self.file_progress_percent_var, + ).grid(row=7, column=0, columnspan=2, sticky="ew", pady=(8, 0)) + ttk.Label(panel, textvariable=self.file_progress_var, style="Muted.TLabel").grid( + row=8, column=0, columnspan=2, sticky="w", pady=(4, 0) + ) + + def _build_all_angles_panel(self, parent): + header = ttk.Frame(parent, style="Panel.TFrame") + header.grid(row=0, column=0, sticky="ew") + header.columnconfigure(0, weight=1) + + ttk.Label(header, text="Eye Servo Layout", style="Subhead.TLabel").grid( + row=0, column=0, sticky="w" + ) + ttk.Label( + header, + text=( + f"{len(EYE_CONTROL_SPECS)} eye controls with configurable string servo IDs; " + f"send uses move([ServoCmd(id, angle_rad)]). IDs must match firmware names exactly." + ), + style="Muted.TLabel", + ).grid(row=1, column=0, sticky="w", pady=(0, 14)) + + controls = ttk.Frame(header, style="Panel.TFrame") + controls.grid(row=0, column=1, rowspan=2, sticky="e") + controls.columnconfigure(0, weight=1) + ttk.Entry(controls, textvariable=self.fill_angle_var, width=10).grid( + row=0, column=0, sticky="e", padx=(0, 8) + ) + ttk.Button( + controls, + text="Fill Visible", + style="Ghost.TButton", + command=self.fill_all_clicked, + ).grid(row=0, column=1, sticky="e", padx=(0, 8)) + ttk.Button( + controls, + text="Zero Visible", + style="Ghost.TButton", + command=self.zero_all_clicked, + ).grid(row=0, column=2, sticky="e", padx=(0, 8)) + ttk.Button( + controls, + text="Send move", + style="Accent.TButton", + command=self.send_all_clicked, + ).grid(row=0, column=3, sticky="e") + ttk.Label(controls, text="Blink wait (ms)", style="Muted.TLabel").grid( + row=1, column=0, sticky="e", padx=(0, 8), pady=(10, 0) + ) + blink_hold_entry = ttk.Entry(controls, textvariable=self.blink_hold_ms_var, width=10) + blink_hold_entry.grid(row=1, column=1, sticky="e", padx=(0, 8), pady=(10, 0)) + blink_hold_entry.bind("", self._blink_from_event) + ttk.Button( + controls, + text="Start Blink", + style="Ghost.TButton", + command=self.blink_clicked, + ).grid(row=1, column=2, sticky="e", padx=(0, 8), pady=(10, 0)) + ttk.Button( + controls, + text="Stop Blink", + style="Ghost.TButton", + command=self.stop_blink_clicked, + ).grid(row=1, column=3, sticky="e", pady=(10, 0)) + + body = ttk.Frame(parent, style="Panel.TFrame") + body.grid(row=1, column=0, sticky="nsew", pady=(8, 0)) + body.columnconfigure(0, weight=1) + body.columnconfigure(1, weight=0) + body.columnconfigure(2, weight=1) + body.rowconfigure(1, weight=1) + + ( + left_upper, + left_lower, + right_upper, + right_lower, + gaze_horizontal, + gaze_vertical, + ) = self.eye_controls + + self._build_eye_slider_card(body, left_upper).grid( + row=0, column=0, sticky="ew", padx=(0, 10), pady=(0, 10) + ) + self._build_vertical_gaze_card(body, gaze_vertical).grid( + row=0, column=1, rowspan=3, sticky="ns", padx=8, pady=(0, 10) + ) + self._build_eye_slider_card(body, right_upper).grid( + row=0, column=2, sticky="ew", padx=(10, 0), pady=(0, 10) + ) + + self._build_eye_preview_card(body, "Left Eye").grid( + row=1, column=0, sticky="n", padx=(0, 10), pady=(0, 10) + ) + self._build_eye_preview_card(body, "Right Eye").grid( + row=1, column=2, sticky="n", padx=(10, 0), pady=(0, 10) + ) + + self._build_eye_slider_card(body, left_lower).grid( + row=2, column=0, sticky="ew", padx=(0, 10), pady=(0, 10) + ) + self._build_eye_slider_card(body, right_lower).grid( + row=2, column=2, sticky="ew", padx=(10, 0), pady=(0, 10) + ) + + self._build_horizontal_gaze_card(body, gaze_horizontal).grid( + row=3, column=0, columnspan=3, sticky="ew", pady=(6, 0) + ) + + def _build_eye_slider_card(self, parent, control): + card = ttk.Frame(parent, style="Panel.TFrame", padding=12) + card.columnconfigure(0, weight=1) + meta = ttk.Frame(card, style="Panel.TFrame") + meta.grid(row=0, column=0, sticky="ew", pady=(0, 8)) + meta.columnconfigure(0, weight=1) + + ttk.Label(meta, text=control["title"], style="Subhead.TLabel").grid( + row=0, column=0, sticky="w" + ) + ttk.Label(meta, text="ID", style="Muted.TLabel").grid( + row=0, column=1, sticky="e", padx=(12, 6) + ) + id_combo = ttk.Combobox( + meta, + textvariable=control["id_var"], + values=self.servo_id_options, + state="normal", + width=16, + ) + id_combo.grid(row=0, column=2, sticky="e") + id_combo.bind("<>", lambda event, item=control: self._on_eye_control_id_changed(item, event)) + id_combo.bind("", lambda event, item=control: self._on_eye_control_id_changed(item, event)) + id_combo.bind("", lambda event, item=control: self._on_eye_control_id_changed(item, event)) + ttk.Label(card, text="Servo angle (rad)", style="Muted.TLabel").grid( + row=1, column=0, sticky="w", pady=(0, 8) + ) + control["scale"] = ttk.Scale( + card, + variable=control["angle_var"], + from_=-math.pi, + to=math.pi, + orient="horizontal", + ) + control["scale"].grid(row=2, column=0, sticky="ew") + ttk.Entry(card, textvariable=control["angle_var"], width=10).grid( + row=3, column=0, sticky="ew", pady=(8, 0) + ) + return card + + def _build_vertical_gaze_card(self, parent, control): + card = ttk.Frame(parent, style="Panel.TFrame", padding=12) + card.columnconfigure(0, weight=1) + meta = ttk.Frame(card, style="Panel.TFrame") + meta.grid(row=0, column=0, sticky="ew") + meta.columnconfigure(0, weight=1) + + ttk.Label(meta, text=control["title"], style="Subhead.TLabel").grid( + row=0, column=0, sticky="w" + ) + ttk.Label(meta, text="ID", style="Muted.TLabel").grid( + row=0, column=1, sticky="e", padx=(12, 6) + ) + id_combo = ttk.Combobox( + meta, + textvariable=control["id_var"], + values=self.servo_id_options, + state="normal", + width=16, + ) + id_combo.grid(row=0, column=2, sticky="e") + id_combo.bind("<>", lambda event, item=control: self._on_eye_control_id_changed(item, event)) + id_combo.bind("", lambda event, item=control: self._on_eye_control_id_changed(item, event)) + id_combo.bind("", lambda event, item=control: self._on_eye_control_id_changed(item, event)) + ttk.Label(card, text="Both eyes", style="Muted.TLabel").grid( + row=1, column=0, sticky="w", pady=(2, 10) + ) + ttk.Label(card, text="Up", style="Muted.TLabel").grid( + row=2, column=0, sticky="n", pady=(0, 6) + ) + control["scale"] = ttk.Scale( + card, + variable=control["angle_var"], + from_=math.pi, + to=-math.pi, + orient="vertical", + length=220, + ) + control["scale"].grid(row=3, column=0, sticky="ns") + ttk.Label(card, text="Down", style="Muted.TLabel").grid( + row=4, column=0, sticky="s", pady=(6, 0) + ) + ttk.Entry(card, textvariable=control["angle_var"], width=10).grid( + row=5, column=0, sticky="ew", pady=(10, 0) + ) + return card + + def _build_horizontal_gaze_card(self, parent, control): + card = ttk.Frame(parent, style="Panel.TFrame", padding=12) + card.columnconfigure(1, weight=1) + meta = ttk.Frame(card, style="Panel.TFrame") + meta.grid(row=0, column=0, columnspan=3, sticky="ew") + meta.columnconfigure(0, weight=1) + + ttk.Label(meta, text=control["title"], style="Subhead.TLabel").grid( + row=0, column=0, sticky="w" + ) + ttk.Label(meta, text="ID", style="Muted.TLabel").grid( + row=0, column=1, sticky="e", padx=(12, 6) + ) + id_combo = ttk.Combobox( + meta, + textvariable=control["id_var"], + values=self.servo_id_options, + state="normal", + width=16, + ) + id_combo.grid(row=0, column=2, sticky="e") + id_combo.bind("<>", lambda event, item=control: self._on_eye_control_id_changed(item, event)) + id_combo.bind("", lambda event, item=control: self._on_eye_control_id_changed(item, event)) + id_combo.bind("", lambda event, item=control: self._on_eye_control_id_changed(item, event)) + ttk.Label(card, text="Both eyes", style="Muted.TLabel").grid( + row=1, column=0, columnspan=3, sticky="w", pady=(2, 8) + ) + ttk.Label(card, text="Left", style="Muted.TLabel").grid( + row=2, column=0, sticky="w", padx=(0, 8) + ) + control["scale"] = ttk.Scale( + card, + variable=control["angle_var"], + from_=-math.pi, + to=math.pi, + orient="horizontal", + ) + control["scale"].grid(row=2, column=1, sticky="ew") + ttk.Label(card, text="Right", style="Muted.TLabel").grid( + row=2, column=2, sticky="e", padx=(8, 0) + ) + ttk.Entry(card, textvariable=control["angle_var"], width=10).grid( + row=3, column=0, columnspan=3, sticky="e", pady=(10, 0) + ) + return card + + def _build_eye_preview_card(self, parent, title): + card = ttk.Frame(parent, style="Panel.TFrame", padding=12) + card.columnconfigure(0, weight=1) + ttk.Label(card, text=title, style="Subhead.TLabel").grid( + row=0, column=0 + ) + + canvas = tk.Canvas( + card, + width=260, + height=170, + bg=self.colors["input_bg"], + highlightthickness=1, + highlightbackground=self.colors["panel_edge"], + bd=0, + ) + canvas.grid(row=1, column=0, pady=(10, 0)) + canvas.create_oval(24, 28, 236, 144, fill="#f3f8fb", outline="#aebfca", width=2) + canvas.create_arc(24, 18, 236, 128, start=0, extent=180, style="arc", outline="#2b3440", width=12) + canvas.create_arc(24, 44, 236, 154, start=180, extent=180, style="arc", outline="#2b3440", width=12) + canvas.create_oval(78, 46, 182, 150, fill="#4169a8", outline="#1a2a44", width=2) + canvas.create_oval(104, 72, 156, 124, fill="#2e4f86", outline="#16253c", width=1) + canvas.create_oval(119, 87, 141, 109, fill="#dfe8f1", outline="#16253c", width=1) + return card + + def _build_scurve_panel(self, parent): + header = ttk.Frame(parent, style="Panel.TFrame") + header.grid(row=0, column=0, sticky="ew") + header.columnconfigure(0, weight=1) + + ttk.Label(header, text="SCurve Planner", style="Subhead.TLabel").grid( + row=0, column=0, sticky="w" + ) + ttk.Label( + header, + text="Configure local SCurve planning and device setConstraints(id, v, a, j).", + style="Muted.TLabel", + ).grid(row=1, column=0, sticky="w", pady=(0, 14)) + + controls = ttk.Frame(header, style="Panel.TFrame") + controls.grid(row=2, column=0, sticky="ew") + for col in range(4): + controls.columnconfigure(col, weight=1) + + entries = [ + ("Servo ID", self.constraint_servo_id_var), + ("Max velocity", self.scurve_max_velocity_var), + ("Max accel", self.scurve_max_acceleration_var), + ("Max jerk", self.scurve_max_jerk_var), + ("Sample dt", self.scurve_sample_dt_var), + ("Start pos", self.scurve_start_position_var), + ("End pos", self.scurve_end_position_var), + ("Start vel", self.scurve_start_velocity_var), + ("End vel", self.scurve_end_velocity_var), + ] + for index, (label_text, variable) in enumerate(entries): + row = (index // 4) * 2 + col = index % 4 + ttk.Label(controls, text=label_text).grid(row=row, column=col, sticky="w", padx=6, pady=(0, 4)) + if label_text == "Servo ID": + entry = ttk.Combobox( + controls, + textvariable=variable, + values=self.servo_id_options, + state="normal", + ) + entry.bind("<>", self._on_constraint_servo_id_changed) + entry.bind("", self._on_constraint_servo_id_changed) + entry.bind("", self._on_constraint_servo_id_changed) + else: + entry = ttk.Entry(controls, textvariable=variable) + entry.bind("", self._plan_scurve_from_event) + entry.grid(row=row + 1, column=col, sticky="ew", padx=6, pady=(0, 10)) + + button_row = ttk.Frame(header, style="Panel.TFrame") + button_row.grid(row=3, column=0, sticky="ew", pady=(4, 0)) + button_row.columnconfigure(0, weight=0) + button_row.columnconfigure(1, weight=0) + button_row.columnconfigure(2, weight=1) + + ttk.Button( + button_row, + text="Plan Curve", + style="Accent.TButton", + command=self.plan_scurve_clicked, + ).grid(row=0, column=0, sticky="w") + ttk.Button( + button_row, + text="Send Constraints", + style="Ghost.TButton", + command=self.send_scurve_constraints_clicked, + ).grid(row=0, column=1, sticky="w", padx=(10, 0)) + ttk.Label(button_row, textvariable=self.scurve_status_var, style="Status.TLabel").grid( + row=0, column=2, sticky="w", padx=(14, 0) + ) + + ttk.Label(header, textvariable=self.scurve_summary_var, style="Muted.TLabel").grid( + row=4, column=0, sticky="w", pady=(10, 0) + ) + ttk.Label(header, textvariable=self.scurve_segments_var, style="Muted.TLabel").grid( + row=5, column=0, sticky="w", pady=(4, 0) + ) + + plot_area = ttk.Frame(parent, style="Panel.TFrame") + plot_area.grid(row=1, column=0, sticky="nsew", pady=(16, 0)) + plot_area.columnconfigure(0, weight=1) + plot_area.rowconfigure(0, weight=1) + plot_area.rowconfigure(1, weight=1) + plot_area.rowconfigure(2, weight=1) + plot_area.rowconfigure(3, weight=1) + + plot_specs = [ + ("position", "Position", "#7ce0a0"), + ("velocity", "Velocity", "#65c7ff"), + ("acceleration", "Acceleration", "#ffd166"), + ("jerk", "Jerk", "#ff8c7e"), + ] + for row_index, (key, title, color) in enumerate(plot_specs): + card = ttk.Frame(plot_area, style="Panel.TFrame", padding=10) + card.grid(row=row_index, column=0, sticky="nsew", pady=(0, 10) if row_index < len(plot_specs) - 1 else 0) + card.columnconfigure(0, weight=1) + card.rowconfigure(1, weight=1) + + ttk.Label(card, text=title, style="Subhead.TLabel").grid(row=0, column=0, sticky="w") + ttk.Label(card, text="Time on X axis", style="Muted.TLabel").grid( + row=0, column=1, sticky="e" + ) + canvas = tk.Canvas( + card, + height=180, + bg=self.colors["plot_bg"], + highlightthickness=0, + bd=0, + ) + canvas.grid(row=1, column=0, columnspan=2, sticky="nsew", pady=(10, 0)) + canvas.bind("", lambda _event, metric=key: self._redraw_curve_plot(metric)) + self.scurve_canvases[key] = canvas + self.scurve_plot_series[key] = { + "title": title, + "color": color, + "times": [], + "values": [], + } + + def _build_position_planner_panel(self, parent): + header = ttk.Frame(parent, style="Panel.TFrame") + header.grid(row=0, column=0, sticky="ew") + header.columnconfigure(0, weight=1) + + ttk.Label(header, text="Follow Planner", style="Subhead.TLabel").grid( + row=0, column=0, sticky="w" + ) + ttk.Label( + header, + text="Preview SCurvePositionPlanner1D follow behavior and optionally send follow constraints and gain.", + style="Muted.TLabel", + ).grid(row=1, column=0, sticky="w", pady=(0, 14)) + + controls = ttk.Frame(header, style="Panel.TFrame") + controls.grid(row=2, column=0, sticky="ew") + for col in range(5): + controls.columnconfigure(col, weight=1) + + entries = [ + ("Servo ID", self.follow_servo_id_var), + ("Max velocity", self.position_planner_max_velocity_var), + ("Max accel", self.position_planner_max_acceleration_var), + ("Max jerk", self.position_planner_max_jerk_var), + ("Pos gain", self.position_planner_gain_var), + ("Initial pos", self.position_planner_initial_position_var), + ("Initial vel", self.position_planner_initial_velocity_var), + ("Initial accel", self.position_planner_initial_acceleration_var), + ("Target pos", self.position_planner_target_position_var), + ("Sample dt", self.position_planner_sample_dt_var), + ("Duration", self.position_planner_duration_var), + ] + for index, (label_text, variable) in enumerate(entries): + row = (index // 5) * 2 + col = index % 5 + ttk.Label(controls, text=label_text).grid(row=row, column=col, sticky="w", padx=6, pady=(0, 4)) + if label_text == "Servo ID": + entry = ttk.Combobox( + controls, + textvariable=variable, + values=self.servo_id_options, + state="normal", + ) + entry.bind("<>", self._on_follow_servo_id_changed) + entry.bind("", self._on_follow_servo_id_changed) + entry.bind("", self._on_follow_servo_id_changed) + else: + entry = ttk.Entry(controls, textvariable=variable) + entry.bind("", self._plan_position_planner_from_event) + entry.grid(row=row + 1, column=col, sticky="ew", padx=6, pady=(0, 10)) + + button_row = ttk.Frame(header, style="Panel.TFrame") + button_row.grid(row=3, column=0, sticky="ew", pady=(4, 0)) + button_row.columnconfigure(0, weight=0) + button_row.columnconfigure(1, weight=0) + button_row.columnconfigure(2, weight=0) + button_row.columnconfigure(3, weight=1) + + ttk.Button( + button_row, + text="Plan Follow Curve", + style="Accent.TButton", + command=self.plan_position_planner_clicked, + ).grid(row=0, column=0, sticky="w") + ttk.Button( + button_row, + text="Send Constraints", + style="Ghost.TButton", + command=self.send_follow_constraints_clicked, + ).grid(row=0, column=1, sticky="w", padx=(10, 0)) + ttk.Button( + button_row, + text="Send Gain", + style="Ghost.TButton", + command=self.send_follow_position_gain_clicked, + ).grid(row=0, column=2, sticky="w", padx=(10, 0)) + ttk.Label(button_row, textvariable=self.position_planner_status_var, style="Status.TLabel").grid( + row=0, column=3, sticky="w", padx=(14, 0) + ) + + ttk.Label(header, textvariable=self.position_planner_summary_var, style="Muted.TLabel").grid( + row=4, column=0, sticky="w", pady=(10, 0) + ) + ttk.Label(header, textvariable=self.position_planner_target_var, style="Muted.TLabel").grid( + row=5, column=0, sticky="w", pady=(4, 0) + ) + + plot_area = ttk.Frame(parent, style="Panel.TFrame") + plot_area.grid(row=1, column=0, sticky="nsew", pady=(16, 0)) + plot_area.columnconfigure(0, weight=1) + plot_area.rowconfigure(0, weight=1) + plot_area.rowconfigure(1, weight=1) + plot_area.rowconfigure(2, weight=1) + plot_area.rowconfigure(3, weight=1) + + plot_specs = [ + ("position", "Position", "#6abf69"), + ("velocity", "Velocity", "#4da3ff"), + ("acceleration", "Acceleration", "#f2b43c"), + ("jerk", "Jerk", "#ef6c73"), + ] + for row_index, (key, title, color) in enumerate(plot_specs): + card = ttk.Frame(plot_area, style="Panel.TFrame", padding=10) + card.grid(row=row_index, column=0, sticky="nsew", pady=(0, 10) if row_index < len(plot_specs) - 1 else 0) + card.columnconfigure(0, weight=1) + card.rowconfigure(1, weight=1) + + ttk.Label(card, text=title, style="Subhead.TLabel").grid(row=0, column=0, sticky="w") + ttk.Label(card, text="Time on X axis", style="Muted.TLabel").grid( + row=0, column=1, sticky="e" + ) + canvas = tk.Canvas( + card, + height=180, + bg=self.colors["plot_bg"], + highlightthickness=0, + bd=0, + ) + canvas.grid(row=1, column=0, columnspan=2, sticky="nsew", pady=(10, 0)) + canvas.bind("", lambda _event, metric=key: self._redraw_position_planner_plot(metric)) + self.position_planner_canvases[key] = canvas + self.position_planner_plot_series[key] = { + "title": title, + "color": color, + "times": [], + "values": [], + } + + def _load_servo_configs(self): + try: + raw = json.loads(SERVO_CONFIG_PATH.read_text(encoding="utf-8")) + except Exception as exc: + return {}, str(exc) + + configs = {} + for item in raw.get("servos", []): + servo_id = str(item.get("id", "")).strip() + if servo_id: + configs[servo_id] = item + return configs, None + + def _get_preferred_servo_id(self): + if "eye_l_up" in self.servo_configs: + return "eye_l_up" + if self.servo_id_options: + return self.servo_id_options[0] + return "" + + def _initialize_servo_config_ui(self): + self._apply_single_servo_config(use_home=True) + self._sync_planner_inputs_from_single() + self._apply_constraint_servo_config() + self._apply_follow_servo_config() + for control in self.eye_controls: + self._apply_eye_control_config(control, use_home=self._should_use_home_for_eye_control(control)) + + if self.servo_config_error: + self._append_log(f"Servo config load failed: {self.servo_config_error}") + return + self._append_log( + f"Loaded {len(self.servo_configs)} servo configs from {SERVO_CONFIG_PATH}" + ) + + def _get_servo_config(self, servo_id): + if not servo_id: + return None + return self.servo_configs.get(servo_id.strip()) + + def _get_servo_limits(self, servo_config): + if not servo_config: + return -math.pi, math.pi + min_angle = float(servo_config.get("limit_min_angle_rad", -math.pi)) + max_angle = float(servo_config.get("limit_max_angle_rad", math.pi)) + if min_angle > max_angle: + min_angle, max_angle = max_angle, min_angle + return min_angle, max_angle + + def _apply_scale_limits(self, scale, variable, min_angle, max_angle, *, vertical=False, home_angle=None, use_home=False): + if scale is not None: + if vertical: + scale.configure(from_=max_angle, to=min_angle) + else: + scale.configure(from_=min_angle, to=max_angle) + + value = float(variable.get()) + if use_home and home_angle is not None: + value = float(home_angle) + value = max(min_angle, min(max_angle, value)) + variable.set(value) + + def _apply_single_servo_config(self, use_home=False): + servo_config = self._get_servo_config(self.single_id_var.get().strip()) + min_angle, max_angle = self._get_servo_limits(servo_config) + home_angle = servo_config.get("home_angle_rad") if servo_config else None + self._apply_scale_limits( + self.single_angle_scale, + self.single_angle_var, + min_angle, + max_angle, + home_angle=home_angle, + use_home=use_home, + ) + + def _apply_constraint_servo_config(self): + servo_config = self._get_servo_config(self.constraint_servo_id_var.get().strip()) + control = servo_config.get("control", {}) if servo_config else {} + if not control: + return + self.scurve_max_velocity_var.set(str(control.get("max_velocity_rad", self.scurve_max_velocity_var.get()))) + self.scurve_max_acceleration_var.set(str(control.get("max_acceleration_rad", self.scurve_max_acceleration_var.get()))) + self.scurve_max_jerk_var.set(str(control.get("max_jerk_rad", self.scurve_max_jerk_var.get()))) + + def _apply_follow_servo_config(self): + servo_config = self._get_servo_config(self.follow_servo_id_var.get().strip()) + control = servo_config.get("control", {}) if servo_config else {} + if not control: + return + self.position_planner_max_velocity_var.set( + str(control.get("max_velocity_rad", self.position_planner_max_velocity_var.get())) + ) + self.position_planner_max_acceleration_var.set( + str(control.get("max_acceleration_rad", self.position_planner_max_acceleration_var.get())) + ) + self.position_planner_max_jerk_var.set( + str(control.get("max_jerk_rad", self.position_planner_max_jerk_var.get())) + ) + self.position_planner_gain_var.set( + str(control.get("position_gain", self.position_planner_gain_var.get())) + ) + + def _apply_eye_control_config(self, control, use_home=False): + servo_config = self._get_servo_config(control["id_var"].get().strip()) + min_angle, max_angle = self._get_servo_limits(servo_config) + home_angle = servo_config.get("home_angle_rad") if servo_config else None + self._apply_scale_limits( + control.get("scale"), + control["angle_var"], + min_angle, + max_angle, + vertical=(control["title"] == "Eyes Vertical"), + home_angle=home_angle, + use_home=use_home, + ) + + def _should_use_home_for_eye_control(self, control): + return not bool(control.get("blink")) + + def _on_single_servo_id_changed(self, _event=None): + self._apply_single_servo_config(use_home=True) + self._sync_planner_inputs_from_single() + self._apply_constraint_servo_config() + self._apply_follow_servo_config() + self._schedule_mode_preview_update(delay_ms=0) + + def _on_constraint_servo_id_changed(self, _event=None): + self._apply_constraint_servo_config() + + def _on_follow_servo_id_changed(self, _event=None): + self._apply_follow_servo_config() + + def _on_eye_control_id_changed(self, control, _event=None): + self._apply_eye_control_config(control, use_home=self._should_use_home_for_eye_control(control)) + + def connect_clicked(self): + port = self.port_var.get().strip() + baud_text = self.baud_var.get().strip() + if not port: + messagebox.showerror("Missing port", "Please enter a serial port such as COM8.") + return + try: + baud = int(baud_text) + except ValueError: + messagebox.showerror("Invalid baud", f"Baud must be an integer, got: {baud_text}") + return + + self.status_var.set("Connecting...") + self._run_rpc( + f"Connect {port} @ {baud}", + lambda: self.rpc.connect(port, baud), + on_success=lambda _: self.status_var.set(f"Connected to {port} @ {baud}"), + ) + + def disconnect_clicked(self): + self.rpc.close() + self.status_var.set("Disconnected") + self.last_result_var.set("Result: disconnected") + self._append_log("Disconnected from serial transport.") + + def send_mode_clicked(self): + mode_name = self.rpc_mode_var.get() + mode_value = self._get_motion_mode_value(mode_name) + self._run_rpc( + f"setMode({self._get_motion_mode_label(mode_name)})", + lambda: self.rpc.set_mode(mode_value), + ) + + def send_motion_settings_clicked(self): + try: + period_ms = self._parse_int(self.update_period_ms_var, "Period ms") + if period_ms < 0: + raise ValueError("Period ms must be >= 0.") + except ValueError as exc: + messagebox.showerror("Motion settings", str(exc)) + return + + mode_name = self.rpc_mode_var.get() + mode_value = self._get_motion_mode_value(mode_name) + + def action(): + mode_result = self.rpc.set_mode(mode_value) + period_result = self.rpc.set_update_period_ms(period_ms) + return {"mode": mode_result, "period": period_result} + + self._run_rpc( + f"setMode({self._get_motion_mode_label(mode_name)}) + setUpdatePeriodMs({period_ms})", + action, + ) + + def send_single_clicked(self): + servo_id = self.single_id_var.get().strip() + if not servo_id: + messagebox.showerror("Missing ID", "Servo ID is required.") + return + angle_rad = self.single_angle_var.get() + label, action = self._build_single_command(servo_id, angle_rad) + self._run_rpc(label, action) + + def browse_file_clicked(self): + file_path = filedialog.askopenfilename( + title="Select servo YAML config", + initialdir=str(SERVO_CONFIG_YAML_PATH.parent), + filetypes=(("YAML files", "*.yaml *.yml"), ("All files", "*.*")), + ) + if not file_path: + return + + self.file_local_path_var.set(file_path) + if not self.file_remote_path_var.get().strip(): + self.file_remote_path_var.set(DEFAULT_REMOTE_SERVO_CONFIG_PATH) + try: + size = Path(file_path).stat().st_size + except OSError: + self.file_progress_percent_var.set(0.0) + self.file_progress_var.set(f"Selected: {file_path}") + else: + self.file_progress_percent_var.set(0.0) + self.file_progress_var.set(f"Selected {size} bytes from {Path(file_path).name}") + + def send_file_clicked(self): + local_path = self.file_local_path_var.get().strip() + remote_path = self.file_remote_path_var.get().strip() + + if not local_path: + messagebox.showerror("File upload", "Local file is required.") + return + if not remote_path: + messagebox.showerror("File upload", "Remote path is required.") + return + + try: + yaml_path = Path(local_path).expanduser().resolve() + if yaml_path.suffix.lower() not in {".yaml", ".yml"}: + raise ValueError("Local config must be a .yaml or .yml file.") + if not yaml_path.is_file(): + raise FileNotFoundError(f"Local YAML config not found: {yaml_path}") + chunk_size = self._parse_int(self.file_chunk_size_var, "Chunk bytes") + if chunk_size <= 0: + raise ValueError("Chunk bytes must be > 0.") + yaml_size = yaml_path.stat().st_size + except (OSError, ValueError) as exc: + messagebox.showerror("File upload", str(exc)) + return + + if self._file_upload_active: + messagebox.showerror("File upload", "Another upload is already running.") + return + + self._file_upload_cancel.clear() + self._file_upload_active = True + self.file_status_var.set("Converting YAML...") + self.file_progress_percent_var.set(0.0) + self.file_progress_var.set("Waiting for YAML conversion.") + + label = ( + f"convert+fileWrite {yaml_path.name} -> {remote_path} " + f"(chunk={chunk_size}, yaml_size={yaml_size})" + ) + + def progress(bytes_sent, total_size): + self.events.put(("file_progress", bytes_sent, total_size)) + + def action(): + json_path = self._convert_yaml_config(yaml_path) + if self._file_upload_cancel.is_set(): + raise InterruptedError("Upload aborted after YAML conversion.") + self.events.put(("file_conversion_complete", str(json_path), json_path.stat().st_size)) + result = self.rpc.upload_file( + json_path, + remote_path, + chunk_size, + progress=progress, + cancelled=self._file_upload_cancel.is_set, + ) + result["source_yaml"] = str(yaml_path) + return result + + def on_success(result): + self._file_upload_active = False + self.file_status_var.set("Upload complete") + self.file_progress_percent_var.set(100.0) + self.file_progress_var.set( + f"{result['bytes_sent']} / {result['total_size']} bytes in {result['chunk_count']} chunks" + ) + + def on_error(exc): + self._file_upload_active = False + if isinstance(exc, InterruptedError): + self.file_status_var.set("Upload aborted") + self.file_progress_var.set("Upload aborted before completion.") + return + self.file_status_var.set("Upload failed") + + self._run_rpc(label, action, on_success=on_success, on_error=on_error) + + @staticmethod + def _convert_yaml_config(yaml_path): + if not YAML_TO_JSON_SCRIPT.is_file(): + raise FileNotFoundError(f"YAML converter not found: {YAML_TO_JSON_SCRIPT}") + + json_path = Path(yaml_path).with_suffix(".json") + completed = subprocess.run( + [sys.executable, str(YAML_TO_JSON_SCRIPT), str(yaml_path), str(json_path)], + cwd=str(YAML_TO_JSON_SCRIPT.parent), + capture_output=True, + text=True, + check=False, + ) + if completed.returncode != 0: + detail = completed.stderr.strip() or completed.stdout.strip() + raise RuntimeError(detail or "YAML conversion failed without an error message.") + if not json_path.is_file(): + raise FileNotFoundError(f"Converted JSON was not created: {json_path}") + return json_path + + def abort_file_clicked(self): + if self._file_upload_active: + self._file_upload_cancel.set() + self.file_status_var.set("Aborting upload...") + self._append_log("Abort requested for current upload.") + return + + self._run_rpc( + "fileWriteAbort()", + lambda: self.rpc.file_write_abort(), + on_success=lambda _result: self.file_status_var.set("Abort sent"), + ) + + def _send_file_from_event(self, _event): + self.send_file_clicked() + + def _send_single_from_event(self, _event): + self.send_single_clicked() + + def _blink_from_event(self, _event): + self.blink_clicked() + + def _on_single_scale_changed(self, _value): + self._schedule_mode_preview_update() + if not self.single_live_drag_var.get(): + return + + servo_id = self.single_id_var.get().strip() + if not servo_id or not self.rpc.is_connected: + return + + self._single_live_pending = True + if self._single_live_job is None: + self._schedule_single_live_send() + + def _on_single_scale_released(self, _event): + self._schedule_mode_preview_update(delay_ms=0) + if self.single_live_drag_var.get(): + if self._single_live_pending and self._single_live_job is None: + self._schedule_single_live_send() + return + self.send_single_clicked() + + def _on_single_live_drag_toggled(self): + if not self.single_live_drag_var.get(): + self._cancel_single_live_send() + self._single_live_pending = False + return + if self._single_live_pending and self._single_live_job is None: + self._schedule_single_live_send() + + def _on_motion_mode_changed(self): + self._select_mode_tab(self.rpc_mode_var.get()) + self._schedule_mode_preview_update(delay_ms=0) + + def _select_mode_tab(self, mode_name): + if not self.notebook: + return + if mode_name == "scurve": + self.notebook.select(self.tab_frames["scurve"]) + elif mode_name == "follow": + self.notebook.select(self.tab_frames["follow"]) + + def _schedule_mode_preview_update(self, delay_ms=50): + if self._preview_update_job is not None: + self.root.after_cancel(self._preview_update_job) + self._preview_update_job = self.root.after(delay_ms, self._update_mode_preview) + + def _update_mode_preview(self): + self._preview_update_job = None + self._sync_planner_inputs_from_single() + + mode_name = self.rpc_mode_var.get() + if mode_name == "scurve": + self._plan_scurve(show_errors=False) + elif mode_name == "follow": + self._plan_position_planner(show_errors=False) + + def _sync_planner_inputs_from_single(self): + servo_id = self.single_id_var.get().strip() + if servo_id: + self.constraint_servo_id_var.set(servo_id) + self.follow_servo_id_var.set(servo_id) + self._apply_constraint_servo_config() + self._apply_follow_servo_config() + + angle_rad = self.single_angle_var.get() + angle_text = f"{angle_rad:.4f}" + self.scurve_end_position_var.set(angle_text) + self.position_planner_target_position_var.set(angle_text) + + def fill_all_clicked(self): + value = self.fill_angle_var.get() + for control in self.eye_controls: + control["angle_var"].set(value) + self._append_log( + f"Filled {len(EYE_CONTROL_SPECS)} visible eye servos with {value:.4f} rad." + ) + + def zero_all_clicked(self): + for control in self.eye_controls: + control["angle_var"].set(0.0) + self._append_log("Visible eye servos set to 0.0000 rad locally.") + + def send_all_clicked(self): + if not self.rpc.is_connected: + messagebox.showerror("Eye Servo Layout", "Not connected. Configure serial and click Connect first.") + return + try: + items = self._build_eye_move_items() + except ValueError as exc: + messagebox.showerror("Eye Servo Layout", str(exc)) + return + label = "move([" + ", ".join(f"{servo_id}: {angle_rad:.4f}" for servo_id, angle_rad in items) + "])" + self.status_var.set("Sending eye move...") + self._run_rpc( + label, + lambda: self.rpc.move(items), + on_success=lambda _result: self.status_var.set("Eye move sent"), + ) + + def blink_clicked(self): + if self._blink_active: + messagebox.showinfo("Blink", "Blink is already in progress.") + return + if not self.rpc.is_connected: + messagebox.showerror("Blink", "Not connected. Configure serial and click Connect first.") + return + + self._blink_active = True + self.status_var.set("Blinking...") + self._start_blink_cycle() + + def stop_blink_clicked(self): + if not self._blink_active: + return + + had_pending_cycle = self._blink_loop_job is not None + if self._blink_loop_job is not None: + self.root.after_cancel(self._blink_loop_job) + self._blink_loop_job = None + + self._blink_active = False + self.status_var.set("Blink stopped" if had_pending_cycle else "Stopping blink...") + + def send_scurve_constraints_clicked(self): + try: + servo_id = self.constraint_servo_id_var.get().strip() + max_velocity = self._parse_float(self.scurve_max_velocity_var, "Max velocity") + max_acceleration = self._parse_float(self.scurve_max_acceleration_var, "Max accel") + max_jerk = self._parse_float(self.scurve_max_jerk_var, "Max jerk") + except ValueError as exc: + messagebox.showerror("SCurve constraints", str(exc)) + return + if not servo_id: + messagebox.showerror("SCurve constraints", "Servo ID is required.") + return + self._run_rpc( + f"setConstraints({servo_id}, {max_velocity:.4f}, {max_acceleration:.4f}, {max_jerk:.4f})", + lambda: self.rpc.set_constraints(servo_id, max_velocity, max_acceleration, max_jerk), + on_success=lambda _result: self.scurve_status_var.set("SCurve constraints sent"), + ) + + def plan_scurve_clicked(self): + self._plan_scurve(show_errors=True) + + def _plan_scurve(self, show_errors): + try: + max_velocity = self._parse_float(self.scurve_max_velocity_var, "Max velocity") + max_acceleration = self._parse_float(self.scurve_max_acceleration_var, "Max accel") + max_jerk = self._parse_float(self.scurve_max_jerk_var, "Max jerk") + start_position = self._parse_float(self.scurve_start_position_var, "Start pos") + end_position = self._parse_float(self.scurve_end_position_var, "End pos") + start_velocity = self._parse_float(self.scurve_start_velocity_var, "Start vel") + end_velocity = self._parse_float(self.scurve_end_velocity_var, "End vel") + sample_dt = self._parse_float(self.scurve_sample_dt_var, "Sample dt") + if sample_dt <= 0: + raise ValueError("Sample dt must be > 0.") + planner = self._ensure_scurve() + planner.setConstraints(max_velocity, max_acceleration, max_jerk) + profile = planner.calculateProfile( + start_position, + end_position, + start_velocity, + end_velocity, + ) + estimated_points = max(1, int(profile.total_time / sample_dt) + 1) + if estimated_points > 20000: + raise ValueError( + f"Sample dt is too small for this move. It would create about {estimated_points} points." + ) + samples = planner.sampleTrajectory(profile, sample_dt) + except (ValueError, FileNotFoundError, OSError, SCurveError) as exc: + self.scurve_status_var.set("SCurve error") + self.scurve_summary_var.set(str(exc)) + self.scurve_segments_var.set("Segments: -") + self._clear_curve_plots() + if show_errors: + messagebox.showerror("SCurve planner", str(exc)) + return + + self.scurve_status_var.set("SCurve ready") + self.scurve_summary_var.set( + f"distance={profile.distance:.4f} | total={profile.total_time:.4f}s | " + f"v_cruise={profile.v_cruise:.4f} | a_limit={profile.a_limit:.4f} | " + f"samples={len(samples['times'])}" + ) + self.scurve_segments_var.set( + "Segments: " + f"t1={profile.t1:.4f}, t2={profile.t2:.4f}, t3={profile.t3:.4f}, " + f"t4={profile.t4:.4f}, t5={profile.t5:.4f}, t6={profile.t6:.4f}, t7={profile.t7:.4f}" + ) + self.scurve_plot_series["position"] = { + "title": "Position", + "color": "#7ce0a0", + "times": samples["times"], + "values": samples["positions"], + } + self.scurve_plot_series["velocity"] = { + "title": "Velocity", + "color": "#65c7ff", + "times": samples["times"], + "values": samples["velocities"], + } + self.scurve_plot_series["acceleration"] = { + "title": "Acceleration", + "color": "#ffd166", + "times": samples["times"], + "values": samples["accelerations"], + } + self.scurve_plot_series["jerk"] = { + "title": "Jerk", + "color": "#ff8c7e", + "times": samples["times"], + "values": samples["jerks"], + } + self._redraw_all_curve_plots() + self._append_log( + f"SCurve planned: total={profile.total_time:.4f}s, samples={len(samples['times'])}, " + f"constraints=({max_velocity:.3f}, {max_acceleration:.3f}, {max_jerk:.3f})" + ) + + def _plan_scurve_from_event(self, _event): + self.plan_scurve_clicked() + + def send_follow_constraints_clicked(self): + try: + servo_id = self.follow_servo_id_var.get().strip() + max_velocity = self._parse_float(self.position_planner_max_velocity_var, "Max velocity") + max_acceleration = self._parse_float(self.position_planner_max_acceleration_var, "Max accel") + max_jerk = self._parse_float(self.position_planner_max_jerk_var, "Max jerk") + except ValueError as exc: + messagebox.showerror("Follow planner constraints", str(exc)) + return + if not servo_id: + messagebox.showerror("Follow planner constraints", "Servo ID is required.") + return + + self._run_rpc( + f"setConstraints({servo_id}, {max_velocity:.4f}, {max_acceleration:.4f}, {max_jerk:.4f})", + lambda: self.rpc.set_constraints(servo_id, max_velocity, max_acceleration, max_jerk), + on_success=lambda _result: self.position_planner_status_var.set("Follow constraints sent"), + ) + + def send_follow_position_gain_clicked(self): + try: + servo_id = self.follow_servo_id_var.get().strip() + position_gain = self._parse_float(self.position_planner_gain_var, "Pos gain") + except ValueError as exc: + messagebox.showerror("Follow planner gain", str(exc)) + return + if not servo_id: + messagebox.showerror("Follow planner gain", "Servo ID is required.") + return + + self._run_rpc( + f"setPositionGain({servo_id}, {position_gain:.4f})", + lambda: self.rpc.set_position_gain(servo_id, position_gain), + on_success=lambda _result: self.position_planner_status_var.set("Follow gain sent"), + ) + + def plan_position_planner_clicked(self): + self._plan_position_planner(show_errors=True) + + def _plan_position_planner(self, show_errors): + try: + max_velocity = self._parse_float(self.position_planner_max_velocity_var, "Max velocity") + max_acceleration = self._parse_float(self.position_planner_max_acceleration_var, "Max accel") + max_jerk = self._parse_float(self.position_planner_max_jerk_var, "Max jerk") + position_gain = self._parse_float(self.position_planner_gain_var, "Pos gain") + initial_position = self._parse_float(self.position_planner_initial_position_var, "Initial pos") + initial_velocity = self._parse_float(self.position_planner_initial_velocity_var, "Initial vel") + initial_acceleration = self._parse_float(self.position_planner_initial_acceleration_var, "Initial accel") + target_position = self._parse_float(self.position_planner_target_position_var, "Target pos") + sample_dt = self._parse_float(self.position_planner_sample_dt_var, "Sample dt") + duration = self._parse_float(self.position_planner_duration_var, "Duration") + if sample_dt <= 0: + raise ValueError("Sample dt must be > 0.") + if duration < 0: + raise ValueError("Duration must be >= 0.") + planner = self._ensure_position_planner() + planner.setConstraints(max_velocity, max_acceleration, max_jerk) + planner.setPositionGain(position_gain) + samples = planner.sampleTrajectory( + target_position=target_position, + dt=sample_dt, + duration=duration, + initial_position=initial_position, + initial_velocity=initial_velocity, + initial_acceleration=initial_acceleration, + position_gain=position_gain, + ) + except (ValueError, FileNotFoundError, OSError, SCurveError) as exc: + self.position_planner_status_var.set("Follow planner error") + self.position_planner_summary_var.set(str(exc)) + self.position_planner_target_var.set("Target: -") + self._clear_position_planner_plots() + if show_errors: + messagebox.showerror("Follow planner", str(exc)) + return + + final_position = samples["positions"][-1] + final_velocity = samples["velocities"][-1] + final_acceleration = samples["accelerations"][-1] + self.position_planner_status_var.set("Follow planner ready") + self.position_planner_summary_var.set( + f"duration={duration:.4f}s | samples={len(samples['times'])} | " + f"final_pos={final_position:.4f} | final_vel={final_velocity:.4f} | final_acc={final_acceleration:.4f}" + ) + self.position_planner_target_var.set( + f"Target: {target_position:.4f} | initial={initial_position:.4f} | gain={position_gain:.4f}" + ) + self.position_planner_plot_series["position"] = { + "title": "Position", + "color": "#6abf69", + "times": samples["times"], + "values": samples["positions"], + } + self.position_planner_plot_series["velocity"] = { + "title": "Velocity", + "color": "#4da3ff", + "times": samples["times"], + "values": samples["velocities"], + } + self.position_planner_plot_series["acceleration"] = { + "title": "Acceleration", + "color": "#f2b43c", + "times": samples["times"], + "values": samples["accelerations"], + } + self.position_planner_plot_series["jerk"] = { + "title": "Jerk", + "color": "#ef6c73", + "times": samples["times"], + "values": samples["jerks"], + } + self._redraw_all_position_planner_plots() + self._append_log( + f"Follow planner: target={target_position:.4f}, duration={duration:.4f}s, " + f"samples={len(samples['times'])}, constraints=({max_velocity:.3f}, {max_acceleration:.3f}, {max_jerk:.3f})" + ) + + def _plan_position_planner_from_event(self, _event): + self.plan_position_planner_clicked() + + def _ensure_scurve(self): + if self.scurve is None: + self.scurve = SCurve() + return self.scurve + + def _ensure_position_planner(self): + if self.position_planner is None: + self.position_planner = SCurvePositionPlanner1D() + return self.position_planner + + def _parse_float(self, variable, label): + try: + return float(variable.get().strip()) + except ValueError as exc: + raise ValueError(f"{label} must be a valid number.") from exc + + def _parse_int(self, variable, label): + try: + return int(variable.get().strip()) + except ValueError as exc: + raise ValueError(f"{label} must be a valid integer.") from exc + + def _build_eye_move_items(self): + items = [] + used_ids = set() + + for control in self.eye_controls: + servo_id = control["id_var"].get().strip() + if not servo_id: + raise ValueError(f"{control['title']} ID is required.") + if servo_id in used_ids: + raise ValueError(f"Duplicate eye control ID: {servo_id}.") + used_ids.add(servo_id) + items.append((servo_id, float(control["angle_var"].get()))) + + return items + + def _build_blink_move_items(self): + close_items = [] + open_items = [] + used_ids = set() + has_motion = False + + for control in self.eye_controls: + if not control.get("blink"): + continue + + servo_id = control["id_var"].get().strip() + if not servo_id: + raise ValueError(f"{control['title']} ID is required for blink.") + if servo_id in used_ids: + raise ValueError(f"Duplicate blink servo ID: {servo_id}.") + + servo_config = self._get_servo_config(servo_id) + if not servo_config: + raise ValueError(f"Blink servo config not found for ID: {servo_id}.") + if "home_angle_rad" not in servo_config: + raise ValueError(f"Blink servo {servo_id} is missing home_angle_rad.") + + used_ids.add(servo_id) + min_angle, max_angle = self._get_servo_limits(servo_config) + close_angle = max(min_angle, min(max_angle, float(servo_config["home_angle_rad"]))) + open_angle = max(min_angle, min(max_angle, float(control["angle_var"].get()))) + if abs(open_angle - close_angle) > 1e-6: + has_motion = True + close_items.append((servo_id, close_angle)) + open_items.append((servo_id, open_angle)) + + if not close_items: + raise ValueError("No blink-enabled eye servos are configured.") + if not has_motion: + raise ValueError("Blink open angles match home_angle_rad. Adjust the eyelid sliders to an open-eye position first.") + + return close_items, open_items + + def _build_blink_transition_frames(self, start_items, end_items): + if len(start_items) != len(end_items): + raise ValueError("Blink frame build failed: item count mismatch.") + + steps = max(1, int(math.ceil(BLINK_TRANSITION_MS / BLINK_STEP_MS))) + frames = [] + for step_index in range(1, steps + 1): + ratio = step_index / steps + frame = [] + for (start_id, start_angle), (end_id, end_angle) in zip(start_items, end_items): + if start_id != end_id: + raise ValueError("Blink frame build failed: servo order mismatch.") + angle = start_angle + (end_angle - start_angle) * ratio + frame.append((start_id, angle)) + frames.append(frame) + return frames + + def _start_blink_cycle(self): + if not self._blink_active: + return + + try: + hold_ms = self._parse_int(self.blink_hold_ms_var, "Blink delay ms") + if hold_ms < 0: + raise ValueError("Blink delay ms must be >= 0.") + close_items, open_items = self._build_blink_move_items() + except ValueError as exc: + self._blink_active = False + self.status_var.set("Blink failed") + messagebox.showerror("Blink", str(exc)) + return + + self._blink_loop_job = None + self._run_rpc( + f"blink(delay={hold_ms} ms)", + lambda: self._run_blink_sequence(close_items, open_items, hold_ms), + on_success=lambda result, delay_ms=hold_ms: self._on_blink_success(result, delay_ms), + on_error=self._on_blink_error, + ) + + def _schedule_blink_cycle(self, delay_ms): + if not self._blink_active: + return + if self._blink_loop_job is not None: + self.root.after_cancel(self._blink_loop_job) + self._blink_loop_job = self.root.after(delay_ms, self._start_blink_cycle) + + def _run_blink_sequence(self, close_items, open_items, hold_ms): + close_frames = self._build_blink_transition_frames(open_items, close_items) + open_frames = self._build_blink_transition_frames(close_items, open_items) + step_sleep_s = BLINK_STEP_MS / 1000.0 + + close_result = 0 + for frame in close_frames: + close_result = self.rpc.move(frame) + if step_sleep_s > 0: + time.sleep(step_sleep_s) + if hold_ms > 0: + time.sleep(hold_ms / 1000.0) + open_result = 0 + for frame in open_frames: + open_result = self.rpc.move(frame) + if step_sleep_s > 0: + time.sleep(step_sleep_s) + return { + "close_result": close_result, + "open_result": open_result, + "hold_ms": hold_ms, + } + + def _on_blink_success(self, _result, delay_ms): + if not self._blink_active: + self.status_var.set("Blink stopped") + return + self.status_var.set("Blinking...") + self._schedule_blink_cycle(delay_ms) + + def _on_blink_error(self, exc): + self._blink_active = False + if self._blink_loop_job is not None: + self.root.after_cancel(self._blink_loop_job) + self._blink_loop_job = None + self.status_var.set("Blink failed") + messagebox.showerror("Blink", str(exc)) + + def _get_single_live_interval_ms(self): + try: + rate_hz = float(self.single_live_rate_hz_var.get().strip()) + except ValueError: + rate_hz = 50.0 + if rate_hz <= 0: + rate_hz = 50.0 + return max(1, int(round(1000.0 / rate_hz))) + + def _schedule_single_live_send(self): + interval_ms = self._get_single_live_interval_ms() + self._single_live_job = self.root.after(interval_ms, self._flush_single_live_send) + + def _flush_single_live_send(self): + self._single_live_job = None + if not self.single_live_drag_var.get() or not self._single_live_pending: + return + + servo_id = self.single_id_var.get().strip() + if not servo_id or not self.rpc.is_connected: + self._single_live_pending = False + return + + angle_rad = self.single_angle_var.get() + label, action = self._build_single_command(servo_id, angle_rad) + self._single_live_pending = False + self._run_rpc(label, action, log_request=False) + + if self.single_live_drag_var.get() and self._single_live_pending: + self._schedule_single_live_send() + + def _cancel_single_live_send(self): + if self._single_live_job is not None: + self.root.after_cancel(self._single_live_job) + self._single_live_job = None + + def _get_motion_mode_value(self, mode_name): + if mode_name == "follow": + return servo_service_common.RpcMotionMode.RpcMotionModeFollow + if mode_name == "scurve": + return servo_service_common.RpcMotionMode.RpcMotionModeSCurve + return servo_service_common.RpcMotionMode.RpcMotionModeImmediate + + def _get_motion_mode_label(self, mode_name): + if mode_name == "follow": + return "Follow" + if mode_name == "scurve": + return "SCurve" + return "Immediate" + + def _build_single_command(self, servo_id, angle_rad): + return ( + f"move([{servo_id}: {angle_rad:.4f} rad])", + lambda: self.rpc.move([(servo_id, angle_rad)]), + ) + + def _clear_curve_plots(self): + for key, series in self.scurve_plot_series.items(): + series["times"] = [] + series["values"] = [] + self._redraw_curve_plot(key) + + def _clear_position_planner_plots(self): + for key, series in self.position_planner_plot_series.items(): + series["times"] = [] + series["values"] = [] + self._redraw_position_planner_plot(key) + + def _redraw_all_curve_plots(self): + for key in self.scurve_canvases: + self._redraw_curve_plot(key) + + def _redraw_all_position_planner_plots(self): + for key in self.position_planner_canvases: + self._redraw_position_planner_plot(key) + + def _redraw_curve_plot(self, key): + canvas = self.scurve_canvases.get(key) + series = self.scurve_plot_series.get(key) + self._render_plot_series(canvas, series) + + def _redraw_position_planner_plot(self, key): + canvas = self.position_planner_canvases.get(key) + series = self.position_planner_plot_series.get(key) + self._render_plot_series(canvas, series) + + def _render_plot_series(self, canvas, series): + if not canvas or not series: + return + + canvas.delete("all") + width = max(canvas.winfo_width(), 10) + height = max(canvas.winfo_height(), 10) + if width < 80 or height < 80: + return + + if not series["times"] or not series["values"]: + canvas.create_text( + width / 2, + height / 2, + text="Plan curve to preview.", + fill=self.colors["muted_text"], + font=("Segoe UI", 11), + ) + return + + left = 60 + top = 16 + right = width - 18 + bottom = height - 30 + plot_width = max(1, right - left) + plot_height = max(1, bottom - top) + times = series["times"] + values = series["values"] + min_time = times[0] + max_time = times[-1] if times[-1] > times[0] else times[0] + 1.0 + min_value = min(values) + max_value = max(values) + if abs(max_value - min_value) < 1e-9: + padding = max(1.0, abs(max_value) * 0.1 + 1.0) + min_value -= padding + max_value += padding + else: + padding = (max_value - min_value) * 0.1 + min_value -= padding + max_value += padding + + for step in range(6): + x = left + plot_width * step / 5 + y = top + plot_height * step / 5 + canvas.create_line(x, top, x, bottom, fill=self.colors["plot_grid"], width=1) + canvas.create_line(left, y, right, y, fill=self.colors["plot_grid"], width=1) + + if min_value < 0 < max_value: + zero_y = top + (max_value / (max_value - min_value)) * plot_height + canvas.create_line(left, zero_y, right, zero_y, fill=self.colors["plot_axis"], width=1) + + canvas.create_rectangle(left, top, right, bottom, outline=self.colors["plot_axis"], width=1) + + points = [] + value_span = max_value - min_value + time_span = max_time - min_time + for t_value, y_value in zip(times, values): + x = left + ((t_value - min_time) / time_span) * plot_width + y = bottom - ((y_value - min_value) / value_span) * plot_height + points.extend((x, y)) + + if len(points) >= 4: + canvas.create_line(*points, fill=series["color"], width=2) + + canvas.create_text(left, top - 8, anchor="sw", text=series["title"], fill=self.colors["hero_text"], font=("Segoe UI Semibold", 10)) + canvas.create_text(left - 8, top, anchor="ne", text=f"{max_value:.4f}", fill=self.colors["muted_text"], font=("Consolas", 9)) + canvas.create_text(left - 8, bottom, anchor="ne", text=f"{min_value:.4f}", fill=self.colors["muted_text"], font=("Consolas", 9)) + canvas.create_text(left, bottom + 8, anchor="nw", text=f"{min_time:.4f}s", fill=self.colors["muted_text"], font=("Consolas", 9)) + canvas.create_text(right, bottom + 8, anchor="ne", text=f"{max_time:.4f}s", fill=self.colors["muted_text"], font=("Consolas", 9)) + + def _run_rpc(self, label, action, on_success=None, on_error=None, log_request=True): + if log_request: + self._append_log(f"> {label}") + + def worker(): + started_at = time.perf_counter() + try: + result = action() + except Exception as exc: + elapsed_ms = (time.perf_counter() - started_at) * 1000.0 + self.events.put(("error", label, exc, traceback.format_exc(), elapsed_ms, on_error)) + else: + elapsed_ms = (time.perf_counter() - started_at) * 1000.0 + self.events.put(("success", label, result, on_success, elapsed_ms)) + + threading.Thread(target=worker, daemon=True).start() + + def _poll_events(self): + while True: + try: + event = self.events.get_nowait() + except queue.Empty: + break + self._handle_event(event) + self.root.after(120, self._poll_events) + + def _handle_event(self, event): + kind = event[0] + if kind == "file_conversion_complete": + _, json_path, total_size = event + self.file_status_var.set("Uploading JSON...") + self.file_progress_var.set(f"Converted {Path(json_path).name}: {total_size} bytes") + self._append_log(f"Converted YAML to {json_path} ({total_size} bytes)") + return + + if kind == "file_progress": + _, bytes_sent, total_size = event + percent = (bytes_sent / total_size * 100.0) if total_size else 100.0 + self.file_progress_percent_var.set(percent) + self.file_status_var.set( + f"Uploading... {bytes_sent}/{total_size} bytes" + ) + self.file_progress_var.set( + f"{bytes_sent} / {total_size} bytes ({percent:.1f}%)" + ) + return + + if kind == "success": + _, label, result, on_success, elapsed_ms = event + self.last_result_var.set(f"Result: {result} ({elapsed_ms:.3f} ms)") + self._append_log(f"< {label} -> {result} [{elapsed_ms:.3f} ms]") + if callable(on_success): + on_success(result) + return + + _, label, exc, trace_text, elapsed_ms, on_error = event + self.status_var.set("Error") + self.last_result_var.set(f"Result: error ({exc}) [{elapsed_ms:.3f} ms]") + self._append_log(f"! {label} failed: {exc} [{elapsed_ms:.3f} ms]") + self._append_log(trace_text.strip()) + if callable(on_error): + on_error(exc) + + def _append_log(self, text): + self.log_widget.configure(state="normal") + self.log_widget.insert("end", text + "\n") + self.log_widget.see("end") + self.log_widget.configure(state="disabled") + + def on_close(self): + self.rpc.close() + self.root.destroy() + + +def main(): + root = tk.Tk() + app = FaceServoControlApp(root) + root.mainloop() + + +if __name__ == "__main__": + main()