Compare commits
75 Commits
b871b9dd46
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9ad5bfb09b | ||
| 40d36545f3 | |||
| 3dbd68b21c | |||
|
|
617bcec1a1 | ||
|
|
28352f6c64 | ||
|
|
0ee87ccbf9 | ||
| f2aad0807d | |||
|
|
de097d6db2 | ||
| be69df5068 | |||
| 5d498d47f8 | |||
|
|
5e9e8897f0 | ||
|
|
f72d0bc3f0 | ||
| d42fa37a04 | |||
| ba03832ce6 | |||
| 3bd12bcf6d | |||
|
|
6199af6392 | ||
| 4401616d44 | |||
| 2f10fa2796 | |||
| 8aa58b727b | |||
| d9cb52f755 | |||
| 09a234ddc9 | |||
| 76cebec136 | |||
| e0b3ef225d | |||
| 32ed709222 | |||
| f8162779d6 | |||
| e6004a6c8a | |||
| 099c6056d7 | |||
| 18e6a99267 | |||
| 889d4ff3b2 | |||
| 53245002c5 | |||
| d11222a07f | |||
| 0ffee8eceb | |||
| de98ead539 | |||
|
|
2f80bcc78b | ||
|
|
408d23c376 | ||
|
|
b98063b229 | ||
|
|
00c7641d50 | ||
|
|
af5d852db9 | ||
| 1a8e1bbed0 | |||
| 578339fd8b | |||
| 775dedd835 | |||
| 1841664b63 | |||
| 5cfa67d6a1 | |||
| 8dd5e4751c | |||
| b1c5b64879 | |||
| c5299d06bb | |||
| 5202f8dc84 | |||
| ec7b7d8506 | |||
| cc57643315 | |||
| dce1c62419 | |||
| d1a31fc52c | |||
| 7049317539 | |||
|
|
c174021c40 | ||
|
|
7b110fb7ff | ||
|
|
dff70225ef | ||
|
|
452bd1c3e4 | ||
| 26011e7630 | |||
|
|
82f1477edd | ||
|
|
66e5f37c74 | ||
| 6ffc8e3582 | |||
| accbeff765 | |||
|
|
affaf176e5 | ||
| 700ed63169 | |||
|
|
9fbfb0d0b3 | ||
|
|
7cc2c5e2a3 | ||
| 4e08d985c9 | |||
| 652fbd0890 | |||
| b1df84a87f | |||
|
|
5df3dcf596 | ||
|
|
07cf211b3d | ||
| 86bb53d358 | |||
|
|
97b908838c | ||
| 6352865610 | |||
| 593a914d8d | |||
| 5b4456d6ef |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1,2 +1,3 @@
|
||||
CMakeLists.txt.user
|
||||
build
|
||||
.qtcreator
|
||||
|
||||
746
.qtcreator/CMakeLists.txt.user.25c9513
Normal file
746
.qtcreator/CMakeLists.txt.user.25c9513
Normal file
@@ -0,0 +1,746 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE QtCreatorProject>
|
||||
<!-- Written by QtCreator 18.0.1, 2026-02-10T08:36:52. -->
|
||||
<qtcreator>
|
||||
<data>
|
||||
<variable>EnvironmentId</variable>
|
||||
<value type="QByteArray">{25c95133-c398-49ba-8aa0-e9daf4073ad0}</value>
|
||||
</data>
|
||||
<data>
|
||||
<variable>ProjectExplorer.Project.ActiveTarget</variable>
|
||||
<value type="qlonglong">0</value>
|
||||
</data>
|
||||
<data>
|
||||
<variable>ProjectExplorer.Project.EditorSettings</variable>
|
||||
<valuemap type="QVariantMap">
|
||||
<value type="bool" key="EditorConfiguration.AutoDetect">true</value>
|
||||
<value type="bool" key="EditorConfiguration.AutoIndent">true</value>
|
||||
<value type="bool" key="EditorConfiguration.CamelCaseNavigation">true</value>
|
||||
<valuemap type="QVariantMap" key="EditorConfiguration.CodeStyle.0">
|
||||
<value type="QString" key="language">Cpp</value>
|
||||
<valuemap type="QVariantMap" key="value">
|
||||
<value type="QByteArray" key="CurrentPreferences">CppGlobal</value>
|
||||
</valuemap>
|
||||
</valuemap>
|
||||
<valuemap type="QVariantMap" key="EditorConfiguration.CodeStyle.1">
|
||||
<value type="QString" key="language">QmlJS</value>
|
||||
<valuemap type="QVariantMap" key="value">
|
||||
<value type="QByteArray" key="CurrentPreferences">QmlJSGlobal</value>
|
||||
</valuemap>
|
||||
</valuemap>
|
||||
<value type="qlonglong" key="EditorConfiguration.CodeStyle.Count">2</value>
|
||||
<value type="QByteArray" key="EditorConfiguration.Codec">UTF-8</value>
|
||||
<value type="bool" key="EditorConfiguration.ConstrainTooltips">false</value>
|
||||
<value type="int" key="EditorConfiguration.IndentSize">4</value>
|
||||
<value type="bool" key="EditorConfiguration.KeyboardTooltips">false</value>
|
||||
<value type="int" key="EditorConfiguration.LineEndingBehavior">0</value>
|
||||
<value type="int" key="EditorConfiguration.MarginColumn">80</value>
|
||||
<value type="bool" key="EditorConfiguration.MouseHiding">true</value>
|
||||
<value type="bool" key="EditorConfiguration.MouseNavigation">true</value>
|
||||
<value type="int" key="EditorConfiguration.PaddingMode">1</value>
|
||||
<value type="int" key="EditorConfiguration.PreferAfterWhitespaceComments">0</value>
|
||||
<value type="bool" key="EditorConfiguration.PreferSingleLineComments">false</value>
|
||||
<value type="bool" key="EditorConfiguration.ScrollWheelZooming">true</value>
|
||||
<value type="bool" key="EditorConfiguration.ShowMargin">false</value>
|
||||
<value type="int" key="EditorConfiguration.SmartBackspaceBehavior">2</value>
|
||||
<value type="bool" key="EditorConfiguration.SmartSelectionChanging">true</value>
|
||||
<value type="bool" key="EditorConfiguration.SpacesForTabs">true</value>
|
||||
<value type="int" key="EditorConfiguration.TabKeyBehavior">0</value>
|
||||
<value type="int" key="EditorConfiguration.TabSize">8</value>
|
||||
<value type="bool" key="EditorConfiguration.UseGlobal">true</value>
|
||||
<value type="bool" key="EditorConfiguration.UseIndenter">false</value>
|
||||
<value type="int" key="EditorConfiguration.Utf8BomBehavior">1</value>
|
||||
<value type="bool" key="EditorConfiguration.addFinalNewLine">true</value>
|
||||
<value type="bool" key="EditorConfiguration.cleanIndentation">true</value>
|
||||
<value type="bool" key="EditorConfiguration.cleanWhitespace">true</value>
|
||||
<value type="QString" key="EditorConfiguration.ignoreFileTypes">*.md, *.MD, Makefile</value>
|
||||
<value type="bool" key="EditorConfiguration.inEntireDocument">false</value>
|
||||
<value type="bool" key="EditorConfiguration.skipTrailingWhitespace">true</value>
|
||||
<value type="bool" key="EditorConfiguration.tintMarginArea">true</value>
|
||||
</valuemap>
|
||||
</data>
|
||||
<data>
|
||||
<variable>ProjectExplorer.Project.PluginSettings</variable>
|
||||
<valuemap type="QVariantMap">
|
||||
<valuemap type="QVariantMap" key="AutoTest.ActiveFrameworks">
|
||||
<value type="bool" key="AutoTest.Framework.Boost">true</value>
|
||||
<value type="bool" key="AutoTest.Framework.CTest">false</value>
|
||||
<value type="bool" key="AutoTest.Framework.Catch">true</value>
|
||||
<value type="bool" key="AutoTest.Framework.GTest">true</value>
|
||||
<value type="bool" key="AutoTest.Framework.QtQuickTest">true</value>
|
||||
<value type="bool" key="AutoTest.Framework.QtTest">true</value>
|
||||
</valuemap>
|
||||
<value type="bool" key="AutoTest.ApplyFilter">false</value>
|
||||
<valuemap type="QVariantMap" key="AutoTest.CheckStates"/>
|
||||
<valuelist type="QVariantList" key="AutoTest.PathFilters"/>
|
||||
<value type="int" key="AutoTest.RunAfterBuild">0</value>
|
||||
<value type="bool" key="AutoTest.UseGlobal">true</value>
|
||||
<valuemap type="QVariantMap" key="ClangTools">
|
||||
<value type="bool" key="ClangTools.AnalyzeOpenFiles">true</value>
|
||||
<value type="bool" key="ClangTools.BuildBeforeAnalysis">true</value>
|
||||
<value type="QString" key="ClangTools.DiagnosticConfig">Builtin.DefaultTidyAndClazy</value>
|
||||
<value type="int" key="ClangTools.ParallelJobs">4</value>
|
||||
<value type="bool" key="ClangTools.PreferConfigFile">true</value>
|
||||
<valuelist type="QVariantList" key="ClangTools.SelectedDirs"/>
|
||||
<valuelist type="QVariantList" key="ClangTools.SelectedFiles"/>
|
||||
<valuelist type="QVariantList" key="ClangTools.SuppressedDiagnostics"/>
|
||||
<value type="bool" key="ClangTools.UseGlobalSettings">true</value>
|
||||
</valuemap>
|
||||
<valuemap type="QVariantMap" key="ClangdSettings">
|
||||
<value type="bool" key="blockIndexing">true</value>
|
||||
<value type="bool" key="useGlobalSettings">true</value>
|
||||
</valuemap>
|
||||
<value type="int" key="RcSync">0</value>
|
||||
</valuemap>
|
||||
</data>
|
||||
<data>
|
||||
<variable>ProjectExplorer.Project.Target.0</variable>
|
||||
<valuemap type="QVariantMap">
|
||||
<value type="QString" key="DeviceType">Desktop</value>
|
||||
<value type="bool" key="HasPerBcDcs">true</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Desktop</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Desktop</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">{0a48682c-1ff4-4142-9b6d-ae2f5a4dfc82}</value>
|
||||
<value type="qlonglong" key="ProjectExplorer.Target.ActiveBuildConfiguration">0</value>
|
||||
<value type="qlonglong" key="ProjectExplorer.Target.ActiveDeployConfiguration">0</value>
|
||||
<value type="qlonglong" key="ProjectExplorer.Target.ActiveRunConfiguration">1</value>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.Target.BuildConfiguration.0">
|
||||
<value type="QString" key="CMake.Build.Type">Debug</value>
|
||||
<value type="int" key="CMake.Configure.BaseEnvironment">2</value>
|
||||
<value type="bool" key="CMake.Configure.ClearSystemEnvironment">false</value>
|
||||
<valuelist type="QVariantList" key="CMake.Configure.UserEnvironmentChanges"/>
|
||||
<value type="QString" key="CMake.Initial.Parameters">-DCMAKE_COLOR_DIAGNOSTICS:BOOL=ON
|
||||
-DCMAKE_C_COMPILER:STRING=%{Compiler:Executable:C}
|
||||
-DCMAKE_GENERATOR:STRING=Unix Makefiles
|
||||
-DCMAKE_PROJECT_INCLUDE_BEFORE:FILEPATH=%{BuildConfig:BuildDirectory:NativeFilePath}/.qtc/package-manager/auto-setup.cmake
|
||||
-DCMAKE_CXX_COMPILER:STRING=%{Compiler:Executable:Cxx}
|
||||
-DCMAKE_BUILD_TYPE:STRING=Debug</value>
|
||||
<value type="QString" key="ProjectExplorer.BuildConfiguration.BuildDirectory">/home/timur/PROGRAMS/C++/mcc/build/Desktop-Debug</value>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
|
||||
<value type="QString" key="CMakeProjectManager.MakeStep.BuildPreset"></value>
|
||||
<valuelist type="QVariantList" key="CMakeProjectManager.MakeStep.BuildTargets">
|
||||
<value type="QString">all</value>
|
||||
</valuelist>
|
||||
<value type="bool" key="CMakeProjectManager.MakeStep.ClearSystemEnvironment">false</value>
|
||||
<valuelist type="QVariantList" key="CMakeProjectManager.MakeStep.UserEnvironmentChanges"/>
|
||||
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Собрать</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">CMakeProjectManager.MakeStep</value>
|
||||
</valuemap>
|
||||
<value type="qlonglong" key="ProjectExplorer.BuildStepList.StepsCount">1</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Сборка</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Сборка</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Build</value>
|
||||
</valuemap>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.1">
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
|
||||
<value type="QString" key="CMakeProjectManager.MakeStep.BuildPreset"></value>
|
||||
<valuelist type="QVariantList" key="CMakeProjectManager.MakeStep.BuildTargets">
|
||||
<value type="QString">clean</value>
|
||||
</valuelist>
|
||||
<value type="bool" key="CMakeProjectManager.MakeStep.ClearSystemEnvironment">false</value>
|
||||
<valuelist type="QVariantList" key="CMakeProjectManager.MakeStep.UserEnvironmentChanges"/>
|
||||
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Собрать</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">CMakeProjectManager.MakeStep</value>
|
||||
</valuemap>
|
||||
<value type="qlonglong" key="ProjectExplorer.BuildStepList.StepsCount">1</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Очистка</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Очистка</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Clean</value>
|
||||
</valuemap>
|
||||
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">2</value>
|
||||
<value type="bool" key="ProjectExplorer.BuildConfiguration.ClearSystemEnvironment">false</value>
|
||||
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.CustomParsers"/>
|
||||
<value type="bool" key="ProjectExplorer.BuildConfiguration.ParseStandardOutput">false</value>
|
||||
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.UserEnvironmentChanges"/>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Отладка</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">CMakeProjectManager.CMakeBuildConfiguration</value>
|
||||
<value type="qlonglong" key="ProjectExplorer.Target.ActiveDeployConfiguration">0</value>
|
||||
<value type="qlonglong" key="ProjectExplorer.Target.ActiveRunConfiguration">1</value>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.Target.DeployConfiguration.0">
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
|
||||
<value type="qlonglong" key="ProjectExplorer.BuildStepList.StepsCount">0</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Развёртывание</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Развёртывание</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Deploy</value>
|
||||
</valuemap>
|
||||
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">1</value>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.DeployConfiguration.CustomData"/>
|
||||
<value type="bool" key="ProjectExplorer.DeployConfiguration.CustomDataEnabled">false</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.DefaultDeployConfiguration</value>
|
||||
</valuemap>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.Target.DeployConfiguration.1">
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
|
||||
<value type="QString" key="CMakeProjectManager.MakeStep.BuildPreset"></value>
|
||||
<valuelist type="QVariantList" key="CMakeProjectManager.MakeStep.BuildTargets">
|
||||
<value type="QString"></value>
|
||||
</valuelist>
|
||||
<value type="bool" key="CMakeProjectManager.MakeStep.ClearSystemEnvironment">false</value>
|
||||
<valuelist type="QVariantList" key="CMakeProjectManager.MakeStep.UserEnvironmentChanges"/>
|
||||
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Собрать</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ApplicationManagerPlugin.Deploy.CMakePackageStep</value>
|
||||
</valuemap>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.1">
|
||||
<value type="QString" key="ApplicationManagerPlugin.Deploy.InstallPackageStep.Arguments">install-package --acknowledge</value>
|
||||
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Install Application Manager package</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ApplicationManagerPlugin.Deploy.InstallPackageStep</value>
|
||||
<valuelist type="QVariantList" key="ProjectExplorer.RunConfiguration.LastDeployedFiles"/>
|
||||
<valuelist type="QVariantList" key="ProjectExplorer.RunConfiguration.LastDeployedHosts"/>
|
||||
<valuelist type="QVariantList" key="ProjectExplorer.RunConfiguration.LastDeployedRemotePaths"/>
|
||||
<valuelist type="QVariantList" key="ProjectExplorer.RunConfiguration.LastDeployedSysroots"/>
|
||||
<valuelist type="QVariantList" key="RemoteLinux.LastDeployedLocalTimes"/>
|
||||
<valuelist type="QVariantList" key="RemoteLinux.LastDeployedRemoteTimes"/>
|
||||
</valuemap>
|
||||
<value type="qlonglong" key="ProjectExplorer.BuildStepList.StepsCount">2</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Развёртывание</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Развёртывание</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Deploy</value>
|
||||
</valuemap>
|
||||
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">1</value>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.DeployConfiguration.CustomData"/>
|
||||
<value type="bool" key="ProjectExplorer.DeployConfiguration.CustomDataEnabled">false</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ApplicationManagerPlugin.Deploy.Configuration</value>
|
||||
</valuemap>
|
||||
<value type="qlonglong" key="ProjectExplorer.Target.DeployConfigurationCount">2</value>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.Target.PluginSettings">
|
||||
<value type="bool" key="AndroidBuildTargetDirSupport">false</value>
|
||||
<valuelist type="QVariantList" key="ApplicationmanagerPackageTargets"/>
|
||||
<value type="bool" key="UseAndroidBuildTargetDir">false</value>
|
||||
</valuemap>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.Target.RunConfiguration.0">
|
||||
<value type="bool" key="Analyzer.Perf.Settings.UseGlobalSettings">true</value>
|
||||
<value type="bool" key="Analyzer.QmlProfiler.Settings.UseGlobalSettings">true</value>
|
||||
<value type="int" key="Analyzer.Valgrind.Callgrind.CostFormat">0</value>
|
||||
<value type="bool" key="Analyzer.Valgrind.Settings.UseGlobalSettings">true</value>
|
||||
<value type="QString" key="Analyzer.Valgrind.ValgrindExecutable">/usr/bin/valgrind</value>
|
||||
<valuelist type="QVariantList" key="CustomOutputParsers"/>
|
||||
<value type="int" key="PE.EnvironmentAspect.Base">2</value>
|
||||
<valuelist type="QVariantList" key="PE.EnvironmentAspect.Changes"/>
|
||||
<value type="bool" key="PE.EnvironmentAspect.PrintOnRun">false</value>
|
||||
<value type="QString" key="PerfRecordArgsId">-e cpu-cycles --call-graph dwarf,4096 -F 250</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">CMakeProjectManager.CMakeRunConfiguration.</value>
|
||||
<value type="QString" key="ProjectExplorer.RunConfiguration.BuildKey">mcc_telemetry_test</value>
|
||||
<value type="bool" key="ProjectExplorer.RunConfiguration.Customized">false</value>
|
||||
<value type="QString" key="ProjectExplorer.RunConfiguration.UniqueId"></value>
|
||||
<value type="bool" key="RunConfiguration.UseCppDebuggerAuto">true</value>
|
||||
<value type="bool" key="RunConfiguration.UseLibrarySearchPath">true</value>
|
||||
<value type="bool" key="RunConfiguration.UseQmlDebuggerAuto">true</value>
|
||||
<value type="QString" key="RunConfiguration.WorkingDirectory.default">%{RunConfig:Executable:Path}</value>
|
||||
</valuemap>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.Target.RunConfiguration.1">
|
||||
<value type="bool" key="Analyzer.Perf.Settings.UseGlobalSettings">true</value>
|
||||
<value type="bool" key="Analyzer.QmlProfiler.Settings.UseGlobalSettings">true</value>
|
||||
<value type="int" key="Analyzer.Valgrind.Callgrind.CostFormat">0</value>
|
||||
<value type="bool" key="Analyzer.Valgrind.Settings.UseGlobalSettings">true</value>
|
||||
<value type="QString" key="Analyzer.Valgrind.ValgrindExecutable">/usr/bin/valgrind</value>
|
||||
<valuelist type="QVariantList" key="CustomOutputParsers"/>
|
||||
<value type="int" key="PE.EnvironmentAspect.Base">2</value>
|
||||
<valuelist type="QVariantList" key="PE.EnvironmentAspect.Changes"/>
|
||||
<value type="bool" key="PE.EnvironmentAspect.PrintOnRun">false</value>
|
||||
<value type="QString" key="PerfRecordArgsId">-e cpu-cycles --call-graph dwarf,4096 -F 250</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">CMakeProjectManager.CMakeRunConfiguration.</value>
|
||||
<value type="QString" key="ProjectExplorer.RunConfiguration.BuildKey">mcc_coord_test</value>
|
||||
<value type="bool" key="ProjectExplorer.RunConfiguration.Customized">false</value>
|
||||
<value type="QString" key="ProjectExplorer.RunConfiguration.UniqueId"></value>
|
||||
<value type="bool" key="RunConfiguration.UseCppDebuggerAuto">true</value>
|
||||
<value type="bool" key="RunConfiguration.UseLibrarySearchPath">true</value>
|
||||
<value type="bool" key="RunConfiguration.UseQmlDebuggerAuto">true</value>
|
||||
<value type="QString" key="RunConfiguration.WorkingDirectory.default">%{RunConfig:Executable:Path}</value>
|
||||
</valuemap>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.Target.RunConfiguration.2">
|
||||
<value type="bool" key="Analyzer.Perf.Settings.UseGlobalSettings">true</value>
|
||||
<value type="bool" key="Analyzer.QmlProfiler.Settings.UseGlobalSettings">true</value>
|
||||
<value type="int" key="Analyzer.Valgrind.Callgrind.CostFormat">0</value>
|
||||
<value type="bool" key="Analyzer.Valgrind.Settings.UseGlobalSettings">true</value>
|
||||
<value type="QString" key="Analyzer.Valgrind.ValgrindExecutable">/usr/bin/valgrind</value>
|
||||
<valuelist type="QVariantList" key="CustomOutputParsers"/>
|
||||
<value type="int" key="PE.EnvironmentAspect.Base">2</value>
|
||||
<valuelist type="QVariantList" key="PE.EnvironmentAspect.Changes"/>
|
||||
<value type="bool" key="PE.EnvironmentAspect.PrintOnRun">false</value>
|
||||
<value type="QString" key="PerfRecordArgsId">-e cpu-cycles --call-graph dwarf,4096 -F 250</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">CMakeProjectManager.CMakeRunConfiguration.</value>
|
||||
<value type="QString" key="ProjectExplorer.RunConfiguration.BuildKey">mcc_pzone_test</value>
|
||||
<value type="bool" key="ProjectExplorer.RunConfiguration.Customized">false</value>
|
||||
<value type="QString" key="ProjectExplorer.RunConfiguration.UniqueId"></value>
|
||||
<value type="bool" key="RunConfiguration.UseCppDebuggerAuto">true</value>
|
||||
<value type="bool" key="RunConfiguration.UseLibrarySearchPath">true</value>
|
||||
<value type="bool" key="RunConfiguration.UseQmlDebuggerAuto">true</value>
|
||||
<value type="QString" key="RunConfiguration.WorkingDirectory.default">%{RunConfig:Executable:Path}</value>
|
||||
</valuemap>
|
||||
<value type="qlonglong" key="ProjectExplorer.Target.RunConfigurationCount">3</value>
|
||||
</valuemap>
|
||||
<value type="qlonglong" key="ProjectExplorer.Target.BuildConfigurationCount">1</value>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.Target.DeployConfiguration.0">
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
|
||||
<value type="qlonglong" key="ProjectExplorer.BuildStepList.StepsCount">0</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Развёртывание</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Развёртывание</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Deploy</value>
|
||||
</valuemap>
|
||||
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">1</value>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.DeployConfiguration.CustomData"/>
|
||||
<value type="bool" key="ProjectExplorer.DeployConfiguration.CustomDataEnabled">false</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.DefaultDeployConfiguration</value>
|
||||
</valuemap>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.Target.DeployConfiguration.1">
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
|
||||
<value type="QString" key="CMakeProjectManager.MakeStep.BuildPreset"></value>
|
||||
<valuelist type="QVariantList" key="CMakeProjectManager.MakeStep.BuildTargets">
|
||||
<value type="QString"></value>
|
||||
</valuelist>
|
||||
<value type="bool" key="CMakeProjectManager.MakeStep.ClearSystemEnvironment">false</value>
|
||||
<valuelist type="QVariantList" key="CMakeProjectManager.MakeStep.UserEnvironmentChanges"/>
|
||||
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Собрать</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ApplicationManagerPlugin.Deploy.CMakePackageStep</value>
|
||||
</valuemap>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.1">
|
||||
<value type="QString" key="ApplicationManagerPlugin.Deploy.InstallPackageStep.Arguments">install-package --acknowledge</value>
|
||||
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Install Application Manager package</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ApplicationManagerPlugin.Deploy.InstallPackageStep</value>
|
||||
<valuelist type="QVariantList" key="ProjectExplorer.RunConfiguration.LastDeployedFiles"/>
|
||||
<valuelist type="QVariantList" key="ProjectExplorer.RunConfiguration.LastDeployedHosts"/>
|
||||
<valuelist type="QVariantList" key="ProjectExplorer.RunConfiguration.LastDeployedRemotePaths"/>
|
||||
<valuelist type="QVariantList" key="ProjectExplorer.RunConfiguration.LastDeployedSysroots"/>
|
||||
<valuelist type="QVariantList" key="RemoteLinux.LastDeployedLocalTimes"/>
|
||||
<valuelist type="QVariantList" key="RemoteLinux.LastDeployedRemoteTimes"/>
|
||||
</valuemap>
|
||||
<value type="qlonglong" key="ProjectExplorer.BuildStepList.StepsCount">2</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Развёртывание</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Развёртывание</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Deploy</value>
|
||||
</valuemap>
|
||||
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">1</value>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.DeployConfiguration.CustomData"/>
|
||||
<value type="bool" key="ProjectExplorer.DeployConfiguration.CustomDataEnabled">false</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ApplicationManagerPlugin.Deploy.Configuration</value>
|
||||
</valuemap>
|
||||
<value type="qlonglong" key="ProjectExplorer.Target.DeployConfigurationCount">2</value>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.Target.RunConfiguration.0">
|
||||
<value type="bool" key="Analyzer.Perf.Settings.UseGlobalSettings">true</value>
|
||||
<value type="bool" key="Analyzer.QmlProfiler.Settings.UseGlobalSettings">true</value>
|
||||
<value type="int" key="Analyzer.Valgrind.Callgrind.CostFormat">0</value>
|
||||
<value type="bool" key="Analyzer.Valgrind.Settings.UseGlobalSettings">true</value>
|
||||
<value type="QString" key="Analyzer.Valgrind.ValgrindExecutable">/usr/bin/valgrind</value>
|
||||
<valuelist type="QVariantList" key="CustomOutputParsers"/>
|
||||
<value type="int" key="PE.EnvironmentAspect.Base">2</value>
|
||||
<valuelist type="QVariantList" key="PE.EnvironmentAspect.Changes"/>
|
||||
<value type="bool" key="PE.EnvironmentAspect.PrintOnRun">false</value>
|
||||
<value type="QString" key="PerfRecordArgsId">-e cpu-cycles --call-graph dwarf,4096 -F 250</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">CMakeProjectManager.CMakeRunConfiguration.</value>
|
||||
<value type="QString" key="ProjectExplorer.RunConfiguration.BuildKey">mcc_telemetry_test</value>
|
||||
<value type="bool" key="ProjectExplorer.RunConfiguration.Customized">false</value>
|
||||
<value type="QString" key="ProjectExplorer.RunConfiguration.UniqueId"></value>
|
||||
<value type="bool" key="RunConfiguration.UseCppDebuggerAuto">true</value>
|
||||
<value type="bool" key="RunConfiguration.UseLibrarySearchPath">true</value>
|
||||
<value type="bool" key="RunConfiguration.UseQmlDebuggerAuto">true</value>
|
||||
<value type="QString" key="RunConfiguration.WorkingDirectory.default">%{RunConfig:Executable:Path}</value>
|
||||
</valuemap>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.Target.RunConfiguration.1">
|
||||
<value type="bool" key="Analyzer.Perf.Settings.UseGlobalSettings">true</value>
|
||||
<value type="bool" key="Analyzer.QmlProfiler.Settings.UseGlobalSettings">true</value>
|
||||
<value type="int" key="Analyzer.Valgrind.Callgrind.CostFormat">0</value>
|
||||
<value type="bool" key="Analyzer.Valgrind.Settings.UseGlobalSettings">true</value>
|
||||
<value type="QString" key="Analyzer.Valgrind.ValgrindExecutable">/usr/bin/valgrind</value>
|
||||
<valuelist type="QVariantList" key="CustomOutputParsers"/>
|
||||
<value type="int" key="PE.EnvironmentAspect.Base">2</value>
|
||||
<valuelist type="QVariantList" key="PE.EnvironmentAspect.Changes"/>
|
||||
<value type="bool" key="PE.EnvironmentAspect.PrintOnRun">false</value>
|
||||
<value type="QString" key="PerfRecordArgsId">-e cpu-cycles --call-graph dwarf,4096 -F 250</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">CMakeProjectManager.CMakeRunConfiguration.</value>
|
||||
<value type="QString" key="ProjectExplorer.RunConfiguration.BuildKey">mcc_coord_test</value>
|
||||
<value type="bool" key="ProjectExplorer.RunConfiguration.Customized">false</value>
|
||||
<value type="QString" key="ProjectExplorer.RunConfiguration.UniqueId"></value>
|
||||
<value type="bool" key="RunConfiguration.UseCppDebuggerAuto">true</value>
|
||||
<value type="bool" key="RunConfiguration.UseLibrarySearchPath">true</value>
|
||||
<value type="bool" key="RunConfiguration.UseQmlDebuggerAuto">true</value>
|
||||
<value type="QString" key="RunConfiguration.WorkingDirectory.default">%{RunConfig:Executable:Path}</value>
|
||||
</valuemap>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.Target.RunConfiguration.2">
|
||||
<value type="bool" key="Analyzer.Perf.Settings.UseGlobalSettings">true</value>
|
||||
<value type="bool" key="Analyzer.QmlProfiler.Settings.UseGlobalSettings">true</value>
|
||||
<value type="int" key="Analyzer.Valgrind.Callgrind.CostFormat">0</value>
|
||||
<value type="bool" key="Analyzer.Valgrind.Settings.UseGlobalSettings">true</value>
|
||||
<value type="QString" key="Analyzer.Valgrind.ValgrindExecutable">/usr/bin/valgrind</value>
|
||||
<valuelist type="QVariantList" key="CustomOutputParsers"/>
|
||||
<value type="int" key="PE.EnvironmentAspect.Base">2</value>
|
||||
<valuelist type="QVariantList" key="PE.EnvironmentAspect.Changes"/>
|
||||
<value type="bool" key="PE.EnvironmentAspect.PrintOnRun">false</value>
|
||||
<value type="QString" key="PerfRecordArgsId">-e cpu-cycles --call-graph dwarf,4096 -F 250</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">CMakeProjectManager.CMakeRunConfiguration.</value>
|
||||
<value type="QString" key="ProjectExplorer.RunConfiguration.BuildKey">mcc_pzone_test</value>
|
||||
<value type="bool" key="ProjectExplorer.RunConfiguration.Customized">false</value>
|
||||
<value type="QString" key="ProjectExplorer.RunConfiguration.UniqueId"></value>
|
||||
<value type="bool" key="RunConfiguration.UseCppDebuggerAuto">true</value>
|
||||
<value type="bool" key="RunConfiguration.UseLibrarySearchPath">true</value>
|
||||
<value type="bool" key="RunConfiguration.UseQmlDebuggerAuto">true</value>
|
||||
<value type="QString" key="RunConfiguration.WorkingDirectory.default">%{RunConfig:Executable:Path}</value>
|
||||
</valuemap>
|
||||
<value type="qlonglong" key="ProjectExplorer.Target.RunConfigurationCount">3</value>
|
||||
</valuemap>
|
||||
</data>
|
||||
<data>
|
||||
<variable>ProjectExplorer.Project.Target.1</variable>
|
||||
<valuemap type="QVariantMap">
|
||||
<value type="QString" key="DeviceType">Desktop</value>
|
||||
<value type="bool" key="HasPerBcDcs">true</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Clang</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Clang</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">{609869bc-d303-4485-8b34-3f43a08cec9e}</value>
|
||||
<value type="qlonglong" key="ProjectExplorer.Target.ActiveBuildConfiguration">0</value>
|
||||
<value type="qlonglong" key="ProjectExplorer.Target.ActiveDeployConfiguration">0</value>
|
||||
<value type="qlonglong" key="ProjectExplorer.Target.ActiveRunConfiguration">3</value>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.Target.BuildConfiguration.0">
|
||||
<value type="QString" key="CMake.Build.Type">Debug</value>
|
||||
<value type="int" key="CMake.Configure.BaseEnvironment">2</value>
|
||||
<value type="bool" key="CMake.Configure.ClearSystemEnvironment">false</value>
|
||||
<valuelist type="QVariantList" key="CMake.Configure.UserEnvironmentChanges"/>
|
||||
<value type="QString" key="CMake.Initial.Parameters">-DCMAKE_COLOR_DIAGNOSTICS:BOOL=ON
|
||||
-DCMAKE_C_COMPILER:STRING=%{Compiler:Executable:C}
|
||||
-DCMAKE_GENERATOR:STRING=Ninja
|
||||
-DCMAKE_PROJECT_INCLUDE_BEFORE:FILEPATH=%{BuildConfig:BuildDirectory:NativeFilePath}/.qtc/package-manager/auto-setup.cmake
|
||||
-DCMAKE_PREFIX_PATH:STRING=%{Qt:QT_INSTALL_PREFIX}
|
||||
-DQT_QMAKE_EXECUTABLE:STRING=%{Qt:qmakeExecutable}
|
||||
-DCMAKE_CXX_COMPILER:STRING=%{Compiler:Executable:Cxx}
|
||||
-DCMAKE_BUILD_TYPE:STRING=Debug</value>
|
||||
<value type="QString" key="ProjectExplorer.BuildConfiguration.BuildDirectory">/home/timur/PROGRAMS/C++/mcc/build/Clang-Debug</value>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
|
||||
<value type="QString" key="CMakeProjectManager.MakeStep.BuildPreset"></value>
|
||||
<valuelist type="QVariantList" key="CMakeProjectManager.MakeStep.BuildTargets">
|
||||
<value type="QString">all</value>
|
||||
</valuelist>
|
||||
<value type="bool" key="CMakeProjectManager.MakeStep.ClearSystemEnvironment">false</value>
|
||||
<valuelist type="QVariantList" key="CMakeProjectManager.MakeStep.UserEnvironmentChanges"/>
|
||||
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Собрать</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">CMakeProjectManager.MakeStep</value>
|
||||
</valuemap>
|
||||
<value type="qlonglong" key="ProjectExplorer.BuildStepList.StepsCount">1</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Сборка</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Сборка</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Build</value>
|
||||
</valuemap>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.1">
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
|
||||
<value type="QString" key="CMakeProjectManager.MakeStep.BuildPreset"></value>
|
||||
<valuelist type="QVariantList" key="CMakeProjectManager.MakeStep.BuildTargets">
|
||||
<value type="QString">clean</value>
|
||||
</valuelist>
|
||||
<value type="bool" key="CMakeProjectManager.MakeStep.ClearSystemEnvironment">false</value>
|
||||
<valuelist type="QVariantList" key="CMakeProjectManager.MakeStep.UserEnvironmentChanges"/>
|
||||
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Собрать</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">CMakeProjectManager.MakeStep</value>
|
||||
</valuemap>
|
||||
<value type="qlonglong" key="ProjectExplorer.BuildStepList.StepsCount">1</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Очистка</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Очистка</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Clean</value>
|
||||
</valuemap>
|
||||
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">2</value>
|
||||
<value type="bool" key="ProjectExplorer.BuildConfiguration.ClearSystemEnvironment">false</value>
|
||||
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.CustomParsers"/>
|
||||
<value type="bool" key="ProjectExplorer.BuildConfiguration.ParseStandardOutput">false</value>
|
||||
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.UserEnvironmentChanges"/>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Отладка</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">CMakeProjectManager.CMakeBuildConfiguration</value>
|
||||
<value type="qlonglong" key="ProjectExplorer.Target.ActiveDeployConfiguration">0</value>
|
||||
<value type="qlonglong" key="ProjectExplorer.Target.ActiveRunConfiguration">3</value>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.Target.DeployConfiguration.0">
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
|
||||
<value type="qlonglong" key="ProjectExplorer.BuildStepList.StepsCount">0</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Развёртывание</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Развёртывание</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Deploy</value>
|
||||
</valuemap>
|
||||
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">1</value>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.DeployConfiguration.CustomData"/>
|
||||
<value type="bool" key="ProjectExplorer.DeployConfiguration.CustomDataEnabled">false</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.DefaultDeployConfiguration</value>
|
||||
</valuemap>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.Target.DeployConfiguration.1">
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
|
||||
<value type="QString" key="CMakeProjectManager.MakeStep.BuildPreset"></value>
|
||||
<valuelist type="QVariantList" key="CMakeProjectManager.MakeStep.BuildTargets">
|
||||
<value type="QString"></value>
|
||||
</valuelist>
|
||||
<value type="bool" key="CMakeProjectManager.MakeStep.ClearSystemEnvironment">false</value>
|
||||
<valuelist type="QVariantList" key="CMakeProjectManager.MakeStep.UserEnvironmentChanges"/>
|
||||
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Собрать</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ApplicationManagerPlugin.Deploy.CMakePackageStep</value>
|
||||
</valuemap>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.1">
|
||||
<value type="QString" key="ApplicationManagerPlugin.Deploy.InstallPackageStep.Arguments">install-package --acknowledge</value>
|
||||
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Install Application Manager package</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ApplicationManagerPlugin.Deploy.InstallPackageStep</value>
|
||||
<valuelist type="QVariantList" key="ProjectExplorer.RunConfiguration.LastDeployedFiles"/>
|
||||
<valuelist type="QVariantList" key="ProjectExplorer.RunConfiguration.LastDeployedHosts"/>
|
||||
<valuelist type="QVariantList" key="ProjectExplorer.RunConfiguration.LastDeployedRemotePaths"/>
|
||||
<valuelist type="QVariantList" key="ProjectExplorer.RunConfiguration.LastDeployedSysroots"/>
|
||||
<valuelist type="QVariantList" key="RemoteLinux.LastDeployedLocalTimes"/>
|
||||
<valuelist type="QVariantList" key="RemoteLinux.LastDeployedRemoteTimes"/>
|
||||
</valuemap>
|
||||
<value type="qlonglong" key="ProjectExplorer.BuildStepList.StepsCount">2</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Развёртывание</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Развёртывание</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Deploy</value>
|
||||
</valuemap>
|
||||
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">1</value>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.DeployConfiguration.CustomData"/>
|
||||
<value type="bool" key="ProjectExplorer.DeployConfiguration.CustomDataEnabled">false</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ApplicationManagerPlugin.Deploy.Configuration</value>
|
||||
</valuemap>
|
||||
<value type="qlonglong" key="ProjectExplorer.Target.DeployConfigurationCount">2</value>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.Target.PluginSettings">
|
||||
<value type="bool" key="AndroidBuildTargetDirSupport">false</value>
|
||||
<valuelist type="QVariantList" key="ApplicationmanagerPackageTargets"/>
|
||||
<value type="bool" key="UseAndroidBuildTargetDir">false</value>
|
||||
</valuemap>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.Target.RunConfiguration.0">
|
||||
<value type="bool" key="Analyzer.Perf.Settings.UseGlobalSettings">true</value>
|
||||
<value type="bool" key="Analyzer.QmlProfiler.Settings.UseGlobalSettings">true</value>
|
||||
<value type="int" key="Analyzer.Valgrind.Callgrind.CostFormat">0</value>
|
||||
<value type="bool" key="Analyzer.Valgrind.Settings.UseGlobalSettings">true</value>
|
||||
<value type="QString" key="Analyzer.Valgrind.ValgrindExecutable">/usr/bin/valgrind</value>
|
||||
<valuelist type="QVariantList" key="CustomOutputParsers"/>
|
||||
<value type="int" key="PE.EnvironmentAspect.Base">2</value>
|
||||
<valuelist type="QVariantList" key="PE.EnvironmentAspect.Changes"/>
|
||||
<value type="bool" key="PE.EnvironmentAspect.PrintOnRun">false</value>
|
||||
<value type="QString" key="PerfRecordArgsId">-e cpu-cycles --call-graph dwarf,4096 -F 250</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">CMakeProjectManager.CMakeRunConfiguration.</value>
|
||||
<value type="QString" key="ProjectExplorer.RunConfiguration.BuildKey">exe</value>
|
||||
<value type="bool" key="ProjectExplorer.RunConfiguration.Customized">false</value>
|
||||
<value type="QString" key="ProjectExplorer.RunConfiguration.UniqueId"></value>
|
||||
<value type="bool" key="RunConfiguration.UseCppDebuggerAuto">true</value>
|
||||
<value type="bool" key="RunConfiguration.UseLibrarySearchPath">true</value>
|
||||
<value type="bool" key="RunConfiguration.UseQmlDebuggerAuto">true</value>
|
||||
<value type="QString" key="RunConfiguration.WorkingDirectory.default">%{RunConfig:Executable:Path}</value>
|
||||
</valuemap>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.Target.RunConfiguration.1">
|
||||
<value type="bool" key="Analyzer.Perf.Settings.UseGlobalSettings">true</value>
|
||||
<value type="bool" key="Analyzer.QmlProfiler.Settings.UseGlobalSettings">true</value>
|
||||
<value type="int" key="Analyzer.Valgrind.Callgrind.CostFormat">0</value>
|
||||
<value type="bool" key="Analyzer.Valgrind.Settings.UseGlobalSettings">true</value>
|
||||
<value type="QString" key="Analyzer.Valgrind.ValgrindExecutable">/usr/bin/valgrind</value>
|
||||
<valuelist type="QVariantList" key="CustomOutputParsers"/>
|
||||
<value type="int" key="PE.EnvironmentAspect.Base">2</value>
|
||||
<valuelist type="QVariantList" key="PE.EnvironmentAspect.Changes"/>
|
||||
<value type="bool" key="PE.EnvironmentAspect.PrintOnRun">false</value>
|
||||
<value type="QString" key="PerfRecordArgsId">-e cpu-cycles --call-graph dwarf,4096 -F 250</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">CMakeProjectManager.CMakeRunConfiguration.</value>
|
||||
<value type="QString" key="ProjectExplorer.RunConfiguration.BuildKey">mcc_telemetry_test</value>
|
||||
<value type="bool" key="ProjectExplorer.RunConfiguration.Customized">false</value>
|
||||
<value type="QString" key="ProjectExplorer.RunConfiguration.UniqueId"></value>
|
||||
<value type="bool" key="RunConfiguration.UseCppDebuggerAuto">true</value>
|
||||
<value type="bool" key="RunConfiguration.UseLibrarySearchPath">true</value>
|
||||
<value type="bool" key="RunConfiguration.UseQmlDebuggerAuto">true</value>
|
||||
<value type="QString" key="RunConfiguration.WorkingDirectory.default">%{RunConfig:Executable:Path}</value>
|
||||
</valuemap>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.Target.RunConfiguration.2">
|
||||
<value type="bool" key="Analyzer.Perf.Settings.UseGlobalSettings">true</value>
|
||||
<value type="bool" key="Analyzer.QmlProfiler.Settings.UseGlobalSettings">true</value>
|
||||
<value type="int" key="Analyzer.Valgrind.Callgrind.CostFormat">0</value>
|
||||
<value type="bool" key="Analyzer.Valgrind.Settings.UseGlobalSettings">true</value>
|
||||
<value type="QString" key="Analyzer.Valgrind.ValgrindExecutable">/usr/bin/valgrind</value>
|
||||
<valuelist type="QVariantList" key="CustomOutputParsers"/>
|
||||
<value type="int" key="PE.EnvironmentAspect.Base">2</value>
|
||||
<valuelist type="QVariantList" key="PE.EnvironmentAspect.Changes"/>
|
||||
<value type="bool" key="PE.EnvironmentAspect.PrintOnRun">false</value>
|
||||
<value type="QString" key="PerfRecordArgsId">-e cpu-cycles --call-graph dwarf,4096 -F 250</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">CMakeProjectManager.CMakeRunConfiguration.</value>
|
||||
<value type="QString" key="ProjectExplorer.RunConfiguration.BuildKey">mcc_coord_test</value>
|
||||
<value type="bool" key="ProjectExplorer.RunConfiguration.Customized">false</value>
|
||||
<value type="QString" key="ProjectExplorer.RunConfiguration.UniqueId"></value>
|
||||
<value type="bool" key="RunConfiguration.UseCppDebuggerAuto">true</value>
|
||||
<value type="bool" key="RunConfiguration.UseLibrarySearchPath">true</value>
|
||||
<value type="bool" key="RunConfiguration.UseQmlDebuggerAuto">true</value>
|
||||
<value type="QString" key="RunConfiguration.WorkingDirectory.default">%{RunConfig:Executable:Path}</value>
|
||||
</valuemap>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.Target.RunConfiguration.3">
|
||||
<value type="bool" key="Analyzer.Perf.Settings.UseGlobalSettings">true</value>
|
||||
<value type="bool" key="Analyzer.QmlProfiler.Settings.UseGlobalSettings">true</value>
|
||||
<value type="int" key="Analyzer.Valgrind.Callgrind.CostFormat">0</value>
|
||||
<value type="bool" key="Analyzer.Valgrind.Settings.UseGlobalSettings">true</value>
|
||||
<value type="QString" key="Analyzer.Valgrind.ValgrindExecutable">/usr/bin/valgrind</value>
|
||||
<valuelist type="QVariantList" key="CustomOutputParsers"/>
|
||||
<value type="int" key="PE.EnvironmentAspect.Base">2</value>
|
||||
<valuelist type="QVariantList" key="PE.EnvironmentAspect.Changes"/>
|
||||
<value type="bool" key="PE.EnvironmentAspect.PrintOnRun">false</value>
|
||||
<value type="QString" key="PerfRecordArgsId">-e cpu-cycles --call-graph dwarf,4096 -F 250</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">CMakeProjectManager.CMakeRunConfiguration.</value>
|
||||
<value type="QString" key="ProjectExplorer.RunConfiguration.BuildKey">mcc_pzone_test</value>
|
||||
<value type="bool" key="ProjectExplorer.RunConfiguration.Customized">false</value>
|
||||
<value type="QString" key="ProjectExplorer.RunConfiguration.UniqueId"></value>
|
||||
<value type="bool" key="RunConfiguration.UseCppDebuggerAuto">true</value>
|
||||
<value type="bool" key="RunConfiguration.UseLibrarySearchPath">true</value>
|
||||
<value type="bool" key="RunConfiguration.UseQmlDebuggerAuto">true</value>
|
||||
<value type="QString" key="RunConfiguration.WorkingDirectory.default">%{RunConfig:Executable:Path}</value>
|
||||
</valuemap>
|
||||
<value type="qlonglong" key="ProjectExplorer.Target.RunConfigurationCount">4</value>
|
||||
</valuemap>
|
||||
<value type="qlonglong" key="ProjectExplorer.Target.BuildConfigurationCount">1</value>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.Target.DeployConfiguration.0">
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
|
||||
<value type="qlonglong" key="ProjectExplorer.BuildStepList.StepsCount">0</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Развёртывание</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Развёртывание</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Deploy</value>
|
||||
</valuemap>
|
||||
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">1</value>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.DeployConfiguration.CustomData"/>
|
||||
<value type="bool" key="ProjectExplorer.DeployConfiguration.CustomDataEnabled">false</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.DefaultDeployConfiguration</value>
|
||||
</valuemap>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.Target.DeployConfiguration.1">
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
|
||||
<value type="QString" key="CMakeProjectManager.MakeStep.BuildPreset"></value>
|
||||
<valuelist type="QVariantList" key="CMakeProjectManager.MakeStep.BuildTargets">
|
||||
<value type="QString"></value>
|
||||
</valuelist>
|
||||
<value type="bool" key="CMakeProjectManager.MakeStep.ClearSystemEnvironment">false</value>
|
||||
<valuelist type="QVariantList" key="CMakeProjectManager.MakeStep.UserEnvironmentChanges"/>
|
||||
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Собрать</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ApplicationManagerPlugin.Deploy.CMakePackageStep</value>
|
||||
</valuemap>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.1">
|
||||
<value type="QString" key="ApplicationManagerPlugin.Deploy.InstallPackageStep.Arguments">install-package --acknowledge</value>
|
||||
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Install Application Manager package</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ApplicationManagerPlugin.Deploy.InstallPackageStep</value>
|
||||
<valuelist type="QVariantList" key="ProjectExplorer.RunConfiguration.LastDeployedFiles"/>
|
||||
<valuelist type="QVariantList" key="ProjectExplorer.RunConfiguration.LastDeployedHosts"/>
|
||||
<valuelist type="QVariantList" key="ProjectExplorer.RunConfiguration.LastDeployedRemotePaths"/>
|
||||
<valuelist type="QVariantList" key="ProjectExplorer.RunConfiguration.LastDeployedSysroots"/>
|
||||
<valuelist type="QVariantList" key="RemoteLinux.LastDeployedLocalTimes"/>
|
||||
<valuelist type="QVariantList" key="RemoteLinux.LastDeployedRemoteTimes"/>
|
||||
</valuemap>
|
||||
<value type="qlonglong" key="ProjectExplorer.BuildStepList.StepsCount">2</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Развёртывание</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Развёртывание</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Deploy</value>
|
||||
</valuemap>
|
||||
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">1</value>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.DeployConfiguration.CustomData"/>
|
||||
<value type="bool" key="ProjectExplorer.DeployConfiguration.CustomDataEnabled">false</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ApplicationManagerPlugin.Deploy.Configuration</value>
|
||||
</valuemap>
|
||||
<value type="qlonglong" key="ProjectExplorer.Target.DeployConfigurationCount">2</value>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.Target.RunConfiguration.0">
|
||||
<value type="bool" key="Analyzer.Perf.Settings.UseGlobalSettings">true</value>
|
||||
<value type="bool" key="Analyzer.QmlProfiler.Settings.UseGlobalSettings">true</value>
|
||||
<value type="int" key="Analyzer.Valgrind.Callgrind.CostFormat">0</value>
|
||||
<value type="bool" key="Analyzer.Valgrind.Settings.UseGlobalSettings">true</value>
|
||||
<value type="QString" key="Analyzer.Valgrind.ValgrindExecutable">/usr/bin/valgrind</value>
|
||||
<valuelist type="QVariantList" key="CustomOutputParsers"/>
|
||||
<value type="int" key="PE.EnvironmentAspect.Base">2</value>
|
||||
<valuelist type="QVariantList" key="PE.EnvironmentAspect.Changes"/>
|
||||
<value type="bool" key="PE.EnvironmentAspect.PrintOnRun">false</value>
|
||||
<value type="QString" key="PerfRecordArgsId">-e cpu-cycles --call-graph dwarf,4096 -F 250</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">CMakeProjectManager.CMakeRunConfiguration.</value>
|
||||
<value type="QString" key="ProjectExplorer.RunConfiguration.BuildKey">exe</value>
|
||||
<value type="bool" key="ProjectExplorer.RunConfiguration.Customized">false</value>
|
||||
<value type="QString" key="ProjectExplorer.RunConfiguration.UniqueId"></value>
|
||||
<value type="bool" key="RunConfiguration.UseCppDebuggerAuto">true</value>
|
||||
<value type="bool" key="RunConfiguration.UseLibrarySearchPath">true</value>
|
||||
<value type="bool" key="RunConfiguration.UseQmlDebuggerAuto">true</value>
|
||||
<value type="QString" key="RunConfiguration.WorkingDirectory.default">%{RunConfig:Executable:Path}</value>
|
||||
</valuemap>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.Target.RunConfiguration.1">
|
||||
<value type="bool" key="Analyzer.Perf.Settings.UseGlobalSettings">true</value>
|
||||
<value type="bool" key="Analyzer.QmlProfiler.Settings.UseGlobalSettings">true</value>
|
||||
<value type="int" key="Analyzer.Valgrind.Callgrind.CostFormat">0</value>
|
||||
<value type="bool" key="Analyzer.Valgrind.Settings.UseGlobalSettings">true</value>
|
||||
<value type="QString" key="Analyzer.Valgrind.ValgrindExecutable">/usr/bin/valgrind</value>
|
||||
<valuelist type="QVariantList" key="CustomOutputParsers"/>
|
||||
<value type="int" key="PE.EnvironmentAspect.Base">2</value>
|
||||
<valuelist type="QVariantList" key="PE.EnvironmentAspect.Changes"/>
|
||||
<value type="bool" key="PE.EnvironmentAspect.PrintOnRun">false</value>
|
||||
<value type="QString" key="PerfRecordArgsId">-e cpu-cycles --call-graph dwarf,4096 -F 250</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">CMakeProjectManager.CMakeRunConfiguration.</value>
|
||||
<value type="QString" key="ProjectExplorer.RunConfiguration.BuildKey">mcc_telemetry_test</value>
|
||||
<value type="bool" key="ProjectExplorer.RunConfiguration.Customized">false</value>
|
||||
<value type="QString" key="ProjectExplorer.RunConfiguration.UniqueId"></value>
|
||||
<value type="bool" key="RunConfiguration.UseCppDebuggerAuto">true</value>
|
||||
<value type="bool" key="RunConfiguration.UseLibrarySearchPath">true</value>
|
||||
<value type="bool" key="RunConfiguration.UseQmlDebuggerAuto">true</value>
|
||||
<value type="QString" key="RunConfiguration.WorkingDirectory.default">%{RunConfig:Executable:Path}</value>
|
||||
</valuemap>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.Target.RunConfiguration.2">
|
||||
<value type="bool" key="Analyzer.Perf.Settings.UseGlobalSettings">true</value>
|
||||
<value type="bool" key="Analyzer.QmlProfiler.Settings.UseGlobalSettings">true</value>
|
||||
<value type="int" key="Analyzer.Valgrind.Callgrind.CostFormat">0</value>
|
||||
<value type="bool" key="Analyzer.Valgrind.Settings.UseGlobalSettings">true</value>
|
||||
<value type="QString" key="Analyzer.Valgrind.ValgrindExecutable">/usr/bin/valgrind</value>
|
||||
<valuelist type="QVariantList" key="CustomOutputParsers"/>
|
||||
<value type="int" key="PE.EnvironmentAspect.Base">2</value>
|
||||
<valuelist type="QVariantList" key="PE.EnvironmentAspect.Changes"/>
|
||||
<value type="bool" key="PE.EnvironmentAspect.PrintOnRun">false</value>
|
||||
<value type="QString" key="PerfRecordArgsId">-e cpu-cycles --call-graph dwarf,4096 -F 250</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">CMakeProjectManager.CMakeRunConfiguration.</value>
|
||||
<value type="QString" key="ProjectExplorer.RunConfiguration.BuildKey">mcc_coord_test</value>
|
||||
<value type="bool" key="ProjectExplorer.RunConfiguration.Customized">false</value>
|
||||
<value type="QString" key="ProjectExplorer.RunConfiguration.UniqueId"></value>
|
||||
<value type="bool" key="RunConfiguration.UseCppDebuggerAuto">true</value>
|
||||
<value type="bool" key="RunConfiguration.UseLibrarySearchPath">true</value>
|
||||
<value type="bool" key="RunConfiguration.UseQmlDebuggerAuto">true</value>
|
||||
<value type="QString" key="RunConfiguration.WorkingDirectory.default">%{RunConfig:Executable:Path}</value>
|
||||
</valuemap>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.Target.RunConfiguration.3">
|
||||
<value type="bool" key="Analyzer.Perf.Settings.UseGlobalSettings">true</value>
|
||||
<value type="bool" key="Analyzer.QmlProfiler.Settings.UseGlobalSettings">true</value>
|
||||
<value type="int" key="Analyzer.Valgrind.Callgrind.CostFormat">0</value>
|
||||
<value type="bool" key="Analyzer.Valgrind.Settings.UseGlobalSettings">true</value>
|
||||
<value type="QString" key="Analyzer.Valgrind.ValgrindExecutable">/usr/bin/valgrind</value>
|
||||
<valuelist type="QVariantList" key="CustomOutputParsers"/>
|
||||
<value type="int" key="PE.EnvironmentAspect.Base">2</value>
|
||||
<valuelist type="QVariantList" key="PE.EnvironmentAspect.Changes"/>
|
||||
<value type="bool" key="PE.EnvironmentAspect.PrintOnRun">false</value>
|
||||
<value type="QString" key="PerfRecordArgsId">-e cpu-cycles --call-graph dwarf,4096 -F 250</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">CMakeProjectManager.CMakeRunConfiguration.</value>
|
||||
<value type="QString" key="ProjectExplorer.RunConfiguration.BuildKey">mcc_pzone_test</value>
|
||||
<value type="bool" key="ProjectExplorer.RunConfiguration.Customized">false</value>
|
||||
<value type="QString" key="ProjectExplorer.RunConfiguration.UniqueId"></value>
|
||||
<value type="bool" key="RunConfiguration.UseCppDebuggerAuto">true</value>
|
||||
<value type="bool" key="RunConfiguration.UseLibrarySearchPath">true</value>
|
||||
<value type="bool" key="RunConfiguration.UseQmlDebuggerAuto">true</value>
|
||||
<value type="QString" key="RunConfiguration.WorkingDirectory.default">%{RunConfig:Executable:Path}</value>
|
||||
</valuemap>
|
||||
<value type="qlonglong" key="ProjectExplorer.Target.RunConfigurationCount">4</value>
|
||||
</valuemap>
|
||||
</data>
|
||||
<data>
|
||||
<variable>ProjectExplorer.Project.TargetCount</variable>
|
||||
<value type="qlonglong">2</value>
|
||||
</data>
|
||||
<data>
|
||||
<variable>Version</variable>
|
||||
<value type="int">22</value>
|
||||
</data>
|
||||
</qtcreator>
|
||||
420
CMakeLists.txt
420
CMakeLists.txt
@@ -1,11 +1,11 @@
|
||||
cmake_minimum_required(VERSION 3.14)
|
||||
|
||||
set(QT_CREATOR_SKIP_MAINTENANCE_TOOL_PROVIDER ON)
|
||||
|
||||
# ******* MOUNT CONTROL COMPONENTS *******
|
||||
|
||||
project(mcc LANGUAGES C CXX Fortran VERSION 0.1)
|
||||
|
||||
|
||||
# set(CMAKE_BUILD_TYPE Release)
|
||||
|
||||
set(CMAKE_CXX_STANDARD 23)
|
||||
@@ -13,13 +13,27 @@ set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
|
||||
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake")
|
||||
|
||||
|
||||
# ******* LIBRARY OPTIONS *******
|
||||
|
||||
option(USE_SPDLOG "Use of SPDLOG library (add implementation of logger class based on this library)" ON)
|
||||
option(USE_ERFA "Use of ERFA library (add implementation of CCTE based on this library)" ON)
|
||||
option(
|
||||
USE_SPDLOG
|
||||
"Use of SPDLOG library (add implementation of logger class based on this library)"
|
||||
ON
|
||||
)
|
||||
|
||||
option(
|
||||
USE_ERFA
|
||||
"Use of ERFA library (add implementation of CCTE based on this library)"
|
||||
ON
|
||||
)
|
||||
|
||||
option(USE_BSPLINE_PCM "Use of FITPACK bivariate splines for PCM" ON)
|
||||
|
||||
option(
|
||||
USE_ASIO
|
||||
"Use of ASIO-library (add generic implementation of network capabilities)"
|
||||
ON
|
||||
)
|
||||
|
||||
option(BUILD_TESTS "Build tests" ON)
|
||||
|
||||
@@ -30,153 +44,248 @@ include(ExternalProject)
|
||||
|
||||
# ******* SPDLOG LIBRARY *******
|
||||
|
||||
if (USE_SPDLOG)
|
||||
if(USE_SPDLOG)
|
||||
set(SPDLOG_USE_STD_FORMAT ON CACHE INTERNAL "Use of C++20 std::format")
|
||||
set(SPDLOG_FMT_EXTERNAL OFF CACHE INTERNAL "Turn off external fmt library")
|
||||
|
||||
set(USE_SPDLOG_SYSTEM ON)
|
||||
|
||||
find_package(spdlog CONFIG)
|
||||
if (NOT ${spdlog_FOUND})
|
||||
FetchContent_Declare(spdlog
|
||||
GIT_REPOSITORY "https://github.com/gabime/spdlog.git"
|
||||
GIT_TAG "v1.15.1"
|
||||
GIT_SHALLOW TRUE
|
||||
GIT_SUBMODULES ""
|
||||
GIT_PROGRESS TRUE
|
||||
CMAKE_ARGS "-DSPDLOG_USE_STD_FORMAT=ON -DSPDLOG_FMT_EXTERNAL=OFF"
|
||||
OVERRIDE_FIND_PACKAGE
|
||||
if(NOT ${spdlog_FOUND})
|
||||
message(STATUS "\tfetch spdlog-lib ...")
|
||||
FetchContent_Declare(
|
||||
spdlog
|
||||
GIT_REPOSITORY "https://github.com/gabime/spdlog.git"
|
||||
GIT_TAG "v1.15.1"
|
||||
GIT_SHALLOW TRUE
|
||||
GIT_SUBMODULES ""
|
||||
GIT_PROGRESS TRUE
|
||||
# CMAKE_ARGS
|
||||
# -DSPDLOG_USE_STD_FORMAT=ON
|
||||
# -DSPDLOG_FMT_EXTERNAL=OFF
|
||||
OVERRIDE_FIND_PACKAGE
|
||||
)
|
||||
find_package(spdlog CONFIG)
|
||||
|
||||
set(SPDLOG_INSTALL ON CACHE BOOL "Enable spdlog installation" FORCE)
|
||||
FetchContent_MakeAvailable(spdlog)
|
||||
|
||||
find_package(spdlog REQUIRED CONFIG)
|
||||
|
||||
set(USE_SPDLOG_SYSTEM OFF)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# ******* ERFA LIBRARY *******
|
||||
|
||||
find_program(MESON_PROG NAMES meson HINTS ENV PATHS)
|
||||
|
||||
if (NOT MESON_PROG)
|
||||
message(FATAL "meson executable can not be found!!!")
|
||||
endif()
|
||||
|
||||
find_program(NINJA_PROG NAMES ninja ninja-build)
|
||||
|
||||
if (NOT NINJA_PROG)
|
||||
message(FATAL "ninja executable can not be found!!!")
|
||||
endif()
|
||||
|
||||
find_package(PkgConfig REQUIRED)
|
||||
|
||||
pkg_check_modules(ERFALIB IMPORTED_TARGET GLOBAL erfa)
|
||||
|
||||
if (NOT ERFALIB_FOUND)
|
||||
message(STATUS "\tfetch erfa-lib ...")
|
||||
# ExternalProject_Add(erfalib
|
||||
# PREFIX ${CMAKE_BINARY_DIR}/erfa_lib
|
||||
# GIT_REPOSITORY "https://github.com/liberfa/erfa.git"
|
||||
# GIT_TAG "v2.0.1"
|
||||
# UPDATE_COMMAND ""
|
||||
# PATCH_COMMAND ""
|
||||
# LOG_CONFIGURE 1
|
||||
# CONFIGURE_COMMAND meson setup --reconfigure -Ddefault_library=static -Dbuildtype=release
|
||||
# -Dprefix=${CMAKE_BINARY_DIR}/erfa_lib -Dlibdir= -Dincludedir= -Ddatadir= <SOURCE_DIR>
|
||||
# BUILD_COMMAND ninja -C <BINARY_DIR>
|
||||
# INSTALL_COMMAND meson install -C <BINARY_DIR>
|
||||
# BUILD_BYPRODUCTS ${CMAKE_BINARY_DIR}/erfa_lib/liberfa.a
|
||||
# )
|
||||
|
||||
# add_library(PkgConfig::ERFALIB STATIC IMPORTED GLOBAL)
|
||||
# set_target_properties(PkgConfig::ERFALIB PROPERTIES IMPORTED_LOCATION ${CMAKE_BINARY_DIR}/erfa_lib/liberfa.a)
|
||||
# set_target_properties(PkgConfig::ERFALIB PROPERTIES INTERFACE_INCLUDE_DIRECTORIES ${CMAKE_BINARY_DIR}/erfa_lib)
|
||||
# add_dependencies(PkgConfig::ERFALIB erfalib)
|
||||
|
||||
# set(CACHE{ERFALIB_INCLUDE_DIRS} TYPE PATH VALUE "${CMAKE_BINARY_DIR}/erfa_lib")
|
||||
# set(CACHE{ERFALIB_LIBRARY_DIRS} TYPE PATH VALUE "${CMAKE_BINARY_DIR}/erfa_lib")
|
||||
# set(CACHE{ERFALIB_LIBRARIES} TYPE STRING VALUE "erfa;m")
|
||||
|
||||
|
||||
FetchContent_Declare(erfalib_project
|
||||
GIT_REPOSITORY "https://github.com/liberfa/erfa.git"
|
||||
GIT_TAG "v2.0.1"
|
||||
GIT_SHALLOW TRUE
|
||||
GIT_PROGRESS TRUE
|
||||
)
|
||||
|
||||
FetchContent_MakeAvailable(erfalib_project)
|
||||
# message(STATUS "ERFA: ${erfalib_project_SOURCE_DIR}")
|
||||
|
||||
message(STATUS "\tbuild erfa-lib ...")
|
||||
execute_process(
|
||||
COMMAND meson setup --reconfigure -Ddefault_library=static -Dbuildtype=release
|
||||
-Dprefix=${CMAKE_BINARY_DIR}/erfa_lib -Dlibdir= -Dincludedir= -Ddatadir= ${CMAKE_BINARY_DIR}/erfa_lib ${erfalib_project_SOURCE_DIR}
|
||||
)
|
||||
|
||||
execute_process(
|
||||
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/erfa_lib
|
||||
COMMAND ninja -C ${CMAKE_BINARY_DIR}/erfa_lib
|
||||
)
|
||||
|
||||
execute_process(
|
||||
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/erfa_lib
|
||||
COMMAND meson install -C ${CMAKE_BINARY_DIR}/erfa_lib
|
||||
)
|
||||
|
||||
set(ENV{PKG_CONFIG_PATH} "${CMAKE_BINARY_DIR}/erfa_lib/pkgconfig")
|
||||
if(USE_ERFA)
|
||||
pkg_check_modules(ERFALIB IMPORTED_TARGET GLOBAL erfa)
|
||||
|
||||
if(NOT ERFALIB_FOUND)
|
||||
message(STATUS "\tfetch erfa-lib ...")
|
||||
# ExternalProject_Add(erfalib
|
||||
# PREFIX ${CMAKE_BINARY_DIR}/erfa_lib
|
||||
# GIT_REPOSITORY "https://github.com/liberfa/erfa.git"
|
||||
# GIT_TAG "v2.0.1"
|
||||
# UPDATE_COMMAND ""
|
||||
# PATCH_COMMAND ""
|
||||
# LOG_CONFIGURE 1
|
||||
# CONFIGURE_COMMAND meson setup --reconfigure -Ddefault_library=static -Dbuildtype=release
|
||||
# -Dprefix=${CMAKE_BINARY_DIR}/erfa_lib -Dlibdir= -Dincludedir= -Ddatadir= <SOURCE_DIR>
|
||||
# BUILD_COMMAND ninja -C <BINARY_DIR>
|
||||
# INSTALL_COMMAND meson install -C <BINARY_DIR>
|
||||
# BUILD_BYPRODUCTS ${CMAKE_BINARY_DIR}/erfa_lib/liberfa.a
|
||||
# )
|
||||
|
||||
# add_library(PkgConfig::ERFALIB STATIC IMPORTED GLOBAL)
|
||||
# set_target_properties(PkgConfig::ERFALIB PROPERTIES IMPORTED_LOCATION ${CMAKE_BINARY_DIR}/erfa_lib/liberfa.a)
|
||||
# set_target_properties(PkgConfig::ERFALIB PROPERTIES INTERFACE_INCLUDE_DIRECTORIES ${CMAKE_BINARY_DIR}/erfa_lib)
|
||||
# add_dependencies(PkgConfig::ERFALIB erfalib)
|
||||
|
||||
# set(CACHE{ERFALIB_INCLUDE_DIRS} TYPE PATH VALUE "${CMAKE_BINARY_DIR}/erfa_lib")
|
||||
# set(CACHE{ERFALIB_LIBRARY_DIRS} TYPE PATH VALUE "${CMAKE_BINARY_DIR}/erfa_lib")
|
||||
# set(CACHE{ERFALIB_LIBRARIES} TYPE STRING VALUE "erfa;m")
|
||||
|
||||
find_program(MESON_PROG NAMES meson HINTS ENV PATHS)
|
||||
|
||||
if(NOT MESON_PROG)
|
||||
message(FATAL "meson executable can not be found!!!")
|
||||
endif()
|
||||
|
||||
find_program(NINJA_PROG NAMES ninja ninja-build)
|
||||
|
||||
if(NOT NINJA_PROG)
|
||||
message(FATAL "ninja executable can not be found!!!")
|
||||
endif()
|
||||
|
||||
FetchContent_Declare(
|
||||
erfalib_project
|
||||
GIT_REPOSITORY "https://github.com/liberfa/erfa.git"
|
||||
GIT_TAG "v2.0.1"
|
||||
GIT_SHALLOW TRUE
|
||||
GIT_PROGRESS TRUE
|
||||
)
|
||||
|
||||
FetchContent_MakeAvailable(erfalib_project)
|
||||
# message(STATUS "ERFA: ${erfalib_project_SOURCE_DIR}")
|
||||
|
||||
message(STATUS "\tbuild erfa-lib ...")
|
||||
execute_process(
|
||||
COMMAND
|
||||
meson setup --reconfigure -Ddefault_library=static
|
||||
-Dbuildtype=release -Dprefix=${CMAKE_BINARY_DIR}/erfa_lib
|
||||
-Dlibdir= -Dincludedir= -Ddatadir= ${CMAKE_BINARY_DIR}/erfa_lib
|
||||
${erfalib_project_SOURCE_DIR}
|
||||
)
|
||||
|
||||
execute_process(
|
||||
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/erfa_lib
|
||||
COMMAND ninja -C ${CMAKE_BINARY_DIR}/erfa_lib
|
||||
)
|
||||
|
||||
execute_process(
|
||||
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/erfa_lib
|
||||
COMMAND meson install -C ${CMAKE_BINARY_DIR}/erfa_lib
|
||||
)
|
||||
|
||||
set(ENV{PKG_CONFIG_PATH} "${CMAKE_BINARY_DIR}/erfa_lib/pkgconfig")
|
||||
pkg_check_modules(ERFALIB IMPORTED_TARGET GLOBAL erfa)
|
||||
endif()
|
||||
|
||||
message(STATUS "ERFA LIBS: ${ERFALIB_LIBRARIES}")
|
||||
message(STATUS "ERFA LIB PATHS: ${ERFALIB_LIBRARY_DIRS}")
|
||||
message(STATUS "ERFA INC PATHS: ${ERFALIB_INCLUDE_DIRS}")
|
||||
endif()
|
||||
|
||||
if(USE_ASIO)
|
||||
pkg_check_modules(ASIOLIB IMPORTED_TARGET GLOBAL asio)
|
||||
|
||||
message(STATUS "ERFA LIBS: ${ERFALIB_LIBRARIES}")
|
||||
message(STATUS "ERFA LIB PATHS: ${ERFALIB_LIBRARY_DIRS}")
|
||||
message(STATUS "ERFA INC PATHS: ${ERFALIB_INCLUDE_DIRS}")
|
||||
set(USE_ASIO_SYSTEM ON)
|
||||
|
||||
if(NOT ASIOLIB_FOUND)
|
||||
message(STATUS "\tfetch asio-lib ...")
|
||||
|
||||
if (USE_BSPLINE_PCM)
|
||||
FetchContent_Declare(
|
||||
asiolib_project
|
||||
PREFIX
|
||||
${CMAKE_BINARY_DIR}/asio
|
||||
GIT_REPOSITORY "https://github.com/chriskohlhoff/asio.git"
|
||||
GIT_TAG "asio-1-36-0"
|
||||
GIT_SHALLOW 1
|
||||
)
|
||||
|
||||
FetchContent_MakeAvailable(asiolib_project)
|
||||
|
||||
execute_process(
|
||||
WORKING_DIRECTORY ${asiolib_project_SOURCE_DIR}/asio
|
||||
COMMAND ./autogen.sh
|
||||
)
|
||||
|
||||
execute_process(
|
||||
WORKING_DIRECTORY ${asiolib_project_SOURCE_DIR}/asio
|
||||
COMMAND ./configure --prefix=${asiolib_project_SOURCE_DIR}/asio
|
||||
)
|
||||
|
||||
set(ENV{PKG_CONFIG_PATH} "${asiolib_project_SOURCE_DIR}/asio")
|
||||
pkg_check_modules(ASIOLIB IMPORTED_TARGET GLOBAL asio)
|
||||
|
||||
message(STATUS "ASIO INC PATHS: ${ASIOLIB_INCLUDE_DIRS}")
|
||||
|
||||
set(USE_ASIO_SYSTEM OFF)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# if(USE_BSPLINE_PCM)
|
||||
# # fitpack by P. Dierckx
|
||||
# add_subdirectory(fitpack)
|
||||
# endif()
|
||||
|
||||
set(MCC_SRC
|
||||
include/mcc/mcc_concepts.h
|
||||
include/mcc/mcc_constants.h
|
||||
include/mcc/mcc_epoch.h
|
||||
include/mcc/mcc_angle.h
|
||||
include/mcc/mcc_coordinate.h
|
||||
include/mcc/mcc_error.h
|
||||
include/mcc/mcc_traits.h
|
||||
include/mcc/mcc_utils.h
|
||||
include/mcc/mcc_pzone.h
|
||||
include/mcc/mcc_pzone_container.h
|
||||
include/mcc/mcc_pcm.h
|
||||
include/mcc/mcc_telemetry.h
|
||||
include/mcc/mcc_movement_controls.h
|
||||
include/mcc/mcc_generic_movecontrols.h
|
||||
include/mcc/mcc_serialization_common.h
|
||||
include/mcc/mcc_deserializer.h
|
||||
include/mcc/mcc_serializer.h
|
||||
include/mcc/mcc_generic_mount.h
|
||||
)
|
||||
|
||||
if(USE_SPDLOG)
|
||||
list(APPEND MCC_SRC include/mcc/mcc_spdlog.h)
|
||||
endif()
|
||||
|
||||
if(USE_ERFA)
|
||||
list(
|
||||
APPEND MCC_SRC
|
||||
include/mcc/mcc_ccte_iers.h
|
||||
include/mcc/mcc_ccte_iers_default.h
|
||||
include/mcc/mcc_ccte_erfa.h
|
||||
)
|
||||
endif()
|
||||
|
||||
if(USE_ASIO)
|
||||
list(
|
||||
APPEND MCC_SRC
|
||||
include/mcc/mcc_netserver_endpoint.h
|
||||
include/mcc/mcc_netserver_proto.h
|
||||
include/mcc/mcc_netserver.h
|
||||
)
|
||||
endif()
|
||||
|
||||
if(USE_BSPLINE_PCM)
|
||||
# fitpack by P. Dierckx
|
||||
list(APPEND MCC_SRC include/mcc/mcc_bsplines.h)
|
||||
add_subdirectory(fitpack)
|
||||
endif()
|
||||
|
||||
set(MCC_SRC mcc_concepts.h mcc_constants.h mcc_epoch.h mcc_angle.h mcc_coordinate.h mcc_error.h
|
||||
mcc_traits.h mcc_utils.h mcc_ccte_iers.h mcc_ccte_iers_default.h mcc_ccte_erfa.h mcc_pzone.h
|
||||
mcc_pzone_container.h mcc_pcm.h mcc_telemetry.h mcc_serializer.h)
|
||||
|
||||
if (USE_SPDLOG)
|
||||
list(APPEND MCC_SRC mcc_spdlog.h)
|
||||
endif()
|
||||
|
||||
add_library(${PROJECT_NAME} INTERFACE ${MCC_SRC})
|
||||
target_compile_features(${PROJECT_NAME} INTERFACE cxx_std_23)
|
||||
target_link_libraries(${PROJECT_NAME} INTERFACE PkgConfig::ERFALIB)
|
||||
# target_link_libraries(${PROJECT_NAME} INTERFACE PkgConfig::ERFALIB fitpack)
|
||||
target_include_directories(
|
||||
${PROJECT_NAME}
|
||||
INTERFACE
|
||||
# $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR};${ERFALIB_INCLUDE_DIRS};${FITPACK_INCLUDE_DIR};>
|
||||
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR};${ERFALIB_INCLUDE_DIRS};>
|
||||
$<INSTALL_INTERFACE:include/${PROJECT_NAME}>
|
||||
"$<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}/include>"
|
||||
"$<INSTALL_INTERFACE:include/${PROJECT_NAME}>"
|
||||
)
|
||||
if (USE_BSPLINE_PCM)
|
||||
target_compile_definitions(${PROJECT_NAME} INTERFACE USE_BSPLINE_PCM)
|
||||
target_link_libraries(${PROJECT_NAME} INTERFACE fitpack)
|
||||
# target_include_directories(
|
||||
# ${PROJECT_NAME}
|
||||
# INTERFACE
|
||||
# $<BUILD_INTERFACE:${FITPACK_INCLUDE_DIR};>)
|
||||
|
||||
if(USE_ERFA)
|
||||
target_link_libraries(${PROJECT_NAME} INTERFACE PkgConfig::ERFALIB)
|
||||
endif()
|
||||
|
||||
# get_target_property(ZZ ${PROJECT_NAME} INTERFACE_INCLUDE_DIRECTORIES)
|
||||
if(USE_BSPLINE_PCM)
|
||||
target_compile_definitions(${PROJECT_NAME} INTERFACE USE_BSPLINE_PCM)
|
||||
target_link_libraries(${PROJECT_NAME} INTERFACE fitpack)
|
||||
target_link_directories(
|
||||
${PROJECT_NAME}
|
||||
INTERFACE "$<BUILD_INTERFACE:${CMAKE_BINARY_DIR}/fitpack>"
|
||||
)
|
||||
endif()
|
||||
|
||||
# message(STATUS "INT: ${ZZ}")
|
||||
if(USE_ASIO)
|
||||
target_link_libraries(${PROJECT_NAME} INTERFACE PkgConfig::ASIOLIB)
|
||||
endif()
|
||||
|
||||
if(USE_SPDLOG)
|
||||
target_link_libraries(${PROJECT_NAME} INTERFACE spdlog::spdlog_header_only)
|
||||
# target_compile_definitions(${PROJECT_NAME} INTERFACE SPDLOG_USE_STD_FORMAT=1 SPDLOG_FMT_EXTERNAL=0)
|
||||
target_compile_definitions(
|
||||
${PROJECT_NAME}
|
||||
INTERFACE SPDLOG_USE_STD_FORMAT=1
|
||||
)
|
||||
endif()
|
||||
|
||||
|
||||
# add_executable(exe EXCLUDE_FROM_ALL main.cpp)
|
||||
# target_link_libraries(exe PUBLIC ${PROJECT_NAME})
|
||||
|
||||
# get_target_property(ZZ exe INCLUDE_DIRECTORIES)
|
||||
|
||||
# message(STATUS "INT: ${ZZ_STRING}")
|
||||
|
||||
|
||||
if (BUILD_TESTS)
|
||||
if(BUILD_TESTS)
|
||||
add_executable(mcc_telemetry_test tests/mcc_telemetry_test.cpp)
|
||||
target_link_libraries(mcc_telemetry_test PRIVATE ${PROJECT_NAME})
|
||||
|
||||
@@ -185,40 +294,79 @@ if (BUILD_TESTS)
|
||||
|
||||
add_executable(mcc_pzone_test tests/mcc_pzone_test.cpp)
|
||||
target_link_libraries(mcc_pzone_test PRIVATE ${PROJECT_NAME})
|
||||
|
||||
add_executable(mcc_netmsg_test tests/mcc_netmsg_test.cpp)
|
||||
target_link_libraries(mcc_netmsg_test PRIVATE ${PROJECT_NAME})
|
||||
|
||||
add_executable(mcc_fitpack_test tests/mcc_fitpack_test.cpp)
|
||||
target_link_libraries(mcc_fitpack_test PRIVATE ${PROJECT_NAME})
|
||||
else()
|
||||
# This is just a stub to allow access to the path and library settings for the ${PROJECT_NAME} target during development
|
||||
add_executable(just_stub EXCLUDE_FROM_ALL main.cpp)
|
||||
target_link_libraries(just_stub PUBLIC ${PROJECT_NAME})
|
||||
endif()
|
||||
|
||||
include(GNUInstallDirs)
|
||||
|
||||
install(
|
||||
TARGETS ${PROJECT_NAME}
|
||||
EXPORT ${PROJECT_NAME}_Targets
|
||||
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
|
||||
)
|
||||
|
||||
include(CMakePackageConfigHelpers)
|
||||
write_basic_package_version_file("${PROJECT_NAME}ConfigVersion.cmake"
|
||||
VERSION ${PROJECT_VERSION}
|
||||
COMPATIBILITY SameMajorVersion)
|
||||
write_basic_package_version_file(
|
||||
"${PROJECT_NAME}ConfigVersion.cmake"
|
||||
VERSION ${PROJECT_VERSION}
|
||||
COMPATIBILITY SameMajorVersion
|
||||
)
|
||||
|
||||
set(MCC_CONFIG_INSTALLDIR
|
||||
${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}
|
||||
# CACHE PATH
|
||||
# "install path for generated library config files"
|
||||
)
|
||||
set(MCC_HEADERS_INSTALLDIR
|
||||
${CMAKE_INSTALL_INCLUDEDIR}/${PROJECT_NAME}
|
||||
# CACHE PATH
|
||||
# "install path for headers"
|
||||
)
|
||||
|
||||
set(MCC_CONFIG_INSTALLDIR ${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME} CACHE PATH "install path for generated library config files")
|
||||
set(MCC_HEADERS_INSTALLDIR ${CMAKE_INSTALL_INCLUDEDIR} CACHE PATH "install path for headers")
|
||||
|
||||
configure_package_config_file("${PROJECT_SOURCE_DIR}/${PROJECT_NAME}Config.cmake.in"
|
||||
"${PROJECT_BINARY_DIR}/${PROJECT_NAME}Config.cmake"
|
||||
INSTALL_DESTINATION
|
||||
${MCC_CONFIG_INSTALLDIR}
|
||||
PATH_VARS MCC_HEADERS_INSTALLDIR)
|
||||
|
||||
#install(EXPORT ${PROJECT_NAME}_Targets FILE ${PROJECT_NAME}Targets.cmake NAMESPACE ${PROJECT_NAME_NAMESPACE}:: DESTINATION ${MCC_CONFIG_INSTALLDIR})
|
||||
#install(FILES "${PROJECT_BINARY_DIR}/${PROJECT_NAME}Config.cmake" "${PROJECT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake" DESTINATION ${MCC_CONFIG_INSTALLDIR})
|
||||
#install(FILES ${MCC_SRC} DESTINATION include/${PROJECT_NAME})
|
||||
configure_package_config_file(
|
||||
"${PROJECT_SOURCE_DIR}/${PROJECT_NAME}Config.cmake.in"
|
||||
"${PROJECT_BINARY_DIR}/${PROJECT_NAME}Config.cmake"
|
||||
INSTALL_DESTINATION ${MCC_CONFIG_INSTALLDIR}
|
||||
PATH_VARS MCC_HEADERS_INSTALLDIR
|
||||
)
|
||||
|
||||
install(
|
||||
EXPORT ${PROJECT_NAME}_Targets
|
||||
FILE ${PROJECT_NAME}Targets.cmake
|
||||
NAMESPACE ${PROJECT_NAME_NAMESPACE}::
|
||||
DESTINATION ${MCC_CONFIG_INSTALLDIR}
|
||||
)
|
||||
install(
|
||||
FILES
|
||||
"${PROJECT_BINARY_DIR}/${PROJECT_NAME}Config.cmake"
|
||||
"${PROJECT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake"
|
||||
DESTINATION ${MCC_CONFIG_INSTALLDIR}
|
||||
)
|
||||
install(FILES ${MCC_SRC} DESTINATION include/${PROJECT_NAME})
|
||||
|
||||
# uninstall target
|
||||
if(NOT TARGET uninstall)
|
||||
configure_file(
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/cmake_uninstall.cmake.in"
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake"
|
||||
IMMEDIATE @ONLY)
|
||||
IMMEDIATE
|
||||
@ONLY
|
||||
)
|
||||
|
||||
add_custom_target(uninstall
|
||||
COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake)
|
||||
add_custom_target(
|
||||
uninstall
|
||||
COMMAND
|
||||
${CMAKE_COMMAND} -P
|
||||
${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake
|
||||
)
|
||||
endif()
|
||||
|
||||
@@ -5,8 +5,8 @@ set(func_name "")
|
||||
file(GLOB src_files "*.f")
|
||||
|
||||
foreach(ff IN LISTS src_files)
|
||||
get_filename_component(sn ${ff} NAME_WE)
|
||||
list(APPEND func_name ${sn})
|
||||
get_filename_component(sn ${ff} NAME_WE)
|
||||
list(APPEND func_name ${sn})
|
||||
endforeach()
|
||||
|
||||
# message(STATUS "${func_name}")
|
||||
@@ -18,21 +18,36 @@ string(REPLACE ";" " " func_str "${func_name}")
|
||||
enable_language(Fortran CXX)
|
||||
|
||||
include(FortranCInterface)
|
||||
FortranCInterface_HEADER(FortranCInterface.h
|
||||
MACRO_NAMESPACE "FC_"
|
||||
# SYMBOL_NAMESPACE "fp_"
|
||||
SYMBOL_NAMESPACE ""
|
||||
# SYMBOLS ${func_str}
|
||||
SYMBOLS ${func_name}
|
||||
FortranCInterface_HEADER(
|
||||
FortranCInterface.h
|
||||
MACRO_NAMESPACE "FC_"
|
||||
# SYMBOL_NAMESPACE "fp_"
|
||||
SYMBOL_NAMESPACE ""
|
||||
# SYMBOLS ${func_str}
|
||||
SYMBOLS ${func_name}
|
||||
)
|
||||
FortranCInterface_VERIFY(CXX)
|
||||
|
||||
# set(FITPACK_INCLUDE_DIR ${CMAKE_CURRENT_BINARY_DIR} PARENT_SCOPE)
|
||||
# include_directories(${BSPLINES_INCLUDE_DIR})
|
||||
# set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
|
||||
|
||||
add_library(fitpack_project STATIC EXCLUDE_FROM_ALL ${src_files} mcc_bsplines.h)
|
||||
# add_library(fitpack_project STATIC EXCLUDE_FROM_ALL ${src_files} mcc_bsplines.h)
|
||||
# add_library(fitpack_project STATIC EXCLUDE_FROM_ALL ${src_files})
|
||||
add_library(fitpack_project STATIC ${src_files})
|
||||
|
||||
# get_target_property(FP_LIBDIR fitpack_project LIBRARY_OUTPUT_DIRECTORY)
|
||||
# message(STATUS "FP_LIBDIR: ${FP_LIBDIR}")
|
||||
|
||||
add_library(fitpack STATIC IMPORTED GLOBAL)
|
||||
set_target_properties(fitpack PROPERTIES IMPORTED_LOCATION ${CMAKE_BINARY_DIR}/fitpack/libfitpack_project.a)
|
||||
set_target_properties(fitpack PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${CMAKE_CURRENT_SOURCE_DIR};${CMAKE_CURRENT_BINARY_DIR}")
|
||||
set_target_properties(
|
||||
fitpack
|
||||
PROPERTIES
|
||||
IMPORTED_LOCATION ${CMAKE_CURRENT_BINARY_DIR}/libfitpack_project.a
|
||||
# PROPERTIES IMPORTED_LOCATION ${FP_LIBDIR}/libfitpack_project.a
|
||||
# IMPORTED_LOCATION ${CMAKE_BINARY_DIR}/fitpack/libfitpack_project.a
|
||||
)
|
||||
set_target_properties(
|
||||
fitpack
|
||||
PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${CMAKE_CURRENT_BINARY_DIR}"
|
||||
# "${CMAKE_CURRENT_SOURCE_DIR};${CMAKE_CURRENT_BINARY_DIR}"
|
||||
)
|
||||
add_dependencies(fitpack fitpack_project)
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
#include "mcc_traits.h"
|
||||
#include "mcc_utils.h"
|
||||
|
||||
|
||||
/* HELPERS TO REPRESENT ANGLE VALUE */
|
||||
|
||||
constexpr double operator""_rads(long double val) // angle in radians (no conversion)
|
||||
@@ -434,25 +433,38 @@ static T1 operator/(const T1& v1, const T2& v2)
|
||||
|
||||
|
||||
std::string MccAngleFancyString(std::convertible_to<MccAngle> auto const& ang,
|
||||
std::format_string<double> val_fmt = "{}")
|
||||
std::format_string<double> val_fmt = "{:.2f}")
|
||||
{
|
||||
using ang_t = std::decay_t<decltype(ang)>;
|
||||
std::string s;
|
||||
|
||||
double abs_ang;
|
||||
if constexpr (std::is_arithmetic_v<std::decay_t<decltype(ang)>>) {
|
||||
if constexpr (std::is_arithmetic_v<ang_t>) {
|
||||
abs_ang = std::abs(ang);
|
||||
} else {
|
||||
abs_ang = std::abs(MccAngle{ang});
|
||||
}
|
||||
|
||||
if (abs_ang < 1.0_arcmins) {
|
||||
std::format_to(std::back_inserter(s), val_fmt, MccAngle{ang}.arcsecs());
|
||||
if constexpr (std::derived_from<ang_t, MccAngle>) {
|
||||
std::format_to(std::back_inserter(s), val_fmt, ang.arcsecs());
|
||||
} else {
|
||||
std::format_to(std::back_inserter(s), val_fmt, MccAngle{ang}.arcsecs());
|
||||
}
|
||||
s += " arcsecs";
|
||||
} else if (abs_ang < 1.0_degs) {
|
||||
std::format_to(std::back_inserter(s), val_fmt, MccAngle{ang}.arcmins());
|
||||
if constexpr (std::derived_from<ang_t, MccAngle>) {
|
||||
std::format_to(std::back_inserter(s), val_fmt, ang.arcmins());
|
||||
} else {
|
||||
std::format_to(std::back_inserter(s), val_fmt, MccAngle{ang}.arcmins());
|
||||
}
|
||||
s += " arcmins";
|
||||
} else {
|
||||
std::format_to(std::back_inserter(s), val_fmt, MccAngle{ang}.degrees());
|
||||
if constexpr (std::derived_from<ang_t, MccAngle>) {
|
||||
std::format_to(std::back_inserter(s), val_fmt, ang.degrees());
|
||||
} else {
|
||||
std::format_to(std::back_inserter(s), val_fmt, MccAngle{ang}.degrees());
|
||||
}
|
||||
s += " degs";
|
||||
}
|
||||
|
||||
@@ -649,7 +661,7 @@ static constexpr bool mcc_is_app_coordpair(MccCoordPairKind kind)
|
||||
};
|
||||
|
||||
|
||||
static constexpr std::string_view MCC_COORDPAIR_KIND_RADEC_ICRS_STR = "RADEC-IRCS";
|
||||
static constexpr std::string_view MCC_COORDPAIR_KIND_RADEC_ICRS_STR = "RADEC-ICRS";
|
||||
static constexpr std::string_view MCC_COORDPAIR_KIND_RADEC_APP_STR = "RADEC-APP";
|
||||
static constexpr std::string_view MCC_COORDPAIR_KIND_RADEC_OBS_STR = "RADEC-OBS";
|
||||
static constexpr std::string_view MCC_COORDPAIR_KIND_HADEC_APP_STR = "HADEC-APP";
|
||||
@@ -715,21 +727,21 @@ static constexpr MccCoordPairKind MccCoordStrToPairKind(R&& spair)
|
||||
}
|
||||
|
||||
|
||||
enum class MccCoordinatePairRep : int {
|
||||
MCC_COORDPAIR_REP_DEGREES, // both angles are in decimal degrees
|
||||
MCC_COORDPAIR_REP_SXGM_HOURDEG, // X is in hour and Y is in degree sexagesimal representation
|
||||
MCC_COORDPAIR_REP_SXGM_DEGDEG // both angles are in sexagesimal degrees
|
||||
};
|
||||
// enum class MccCoordinatePairRep : int {
|
||||
// MCC_COORDPAIR_REP_DEGREES, // both angles are in decimal degrees
|
||||
// MCC_COORDPAIR_REP_SXGM_HOURDEG, // X is in hour and Y is in degree sexagesimal representation
|
||||
// MCC_COORDPAIR_REP_SXGM_DEGDEG // both angles are in sexagesimal degrees
|
||||
// };
|
||||
|
||||
|
||||
// default wide-acceptable sexagesimal representation
|
||||
static constexpr MccCoordinatePairRep MccCoordinatePairToSxgmRep(MccCoordPairKind kind)
|
||||
{
|
||||
return kind == MccCoordPairKind::COORDS_KIND_AZALT || kind == MccCoordPairKind::COORDS_KIND_AZZD ||
|
||||
kind == MccCoordPairKind::COORDS_KIND_XY || kind == MccCoordPairKind::COORDS_KIND_LONLAT ||
|
||||
kind == MccCoordPairKind::COORDS_KIND_GENERIC
|
||||
? MccCoordinatePairRep::MCC_COORDPAIR_REP_SXGM_DEGDEG
|
||||
: MccCoordinatePairRep::MCC_COORDPAIR_REP_SXGM_HOURDEG; // RA-DEC or HA-DEC
|
||||
}
|
||||
// // default wide-acceptable sexagesimal representation
|
||||
// static constexpr MccCoordinatePairRep MccCoordinatePairToSxgmRep(MccCoordPairKind kind)
|
||||
// {
|
||||
// return kind == MccCoordPairKind::COORDS_KIND_AZALT || kind == MccCoordPairKind::COORDS_KIND_AZZD ||
|
||||
// kind == MccCoordPairKind::COORDS_KIND_XY || kind == MccCoordPairKind::COORDS_KIND_LONLAT ||
|
||||
// kind == MccCoordPairKind::COORDS_KIND_GENERIC
|
||||
// ? MccCoordinatePairRep::MCC_COORDPAIR_REP_SXGM_DEGDEG
|
||||
// : MccCoordinatePairRep::MCC_COORDPAIR_REP_SXGM_HOURDEG; // RA-DEC or HA-DEC
|
||||
// }
|
||||
|
||||
} // namespace mcc::impl
|
||||
@@ -366,4 +366,111 @@ int fitpack_eval_spl2d(const TXT& tx,
|
||||
return fitpack_eval_spl2d(tx, ty, coeffs, xv, yv, fv, kx, ky);
|
||||
}
|
||||
|
||||
} // namespace mcc::fitpack
|
||||
|
||||
/* partial derivatives */
|
||||
|
||||
template <std::ranges::contiguous_range TXT,
|
||||
std::ranges::contiguous_range TYT,
|
||||
std::ranges::contiguous_range XT,
|
||||
std::ranges::contiguous_range YT,
|
||||
std::ranges::contiguous_range CoeffT,
|
||||
std::ranges::contiguous_range PderT>
|
||||
int fitpack_parder_spl2d(const TXT& tx,
|
||||
const TYT& ty,
|
||||
const CoeffT& coeffs,
|
||||
const XT& x,
|
||||
const YT& y,
|
||||
PderT& pder,
|
||||
int dx, // partial derivatives order along X
|
||||
int dy, // partial derivatives order along Y
|
||||
int kx = 3,
|
||||
int ky = 3)
|
||||
{
|
||||
static_assert(std::same_as<std::ranges::range_value_t<TXT>, double> &&
|
||||
std::same_as<std::ranges::range_value_t<TYT>, double> &&
|
||||
std::same_as<std::ranges::range_value_t<XT>, double> &&
|
||||
std::same_as<std::ranges::range_value_t<YT>, double> &&
|
||||
std::same_as<std::ranges::range_value_t<CoeffT>, double> &&
|
||||
std::same_as<std::ranges::range_value_t<PderT>, double>,
|
||||
"Input ranges elements type must be double!");
|
||||
|
||||
if (kx < 0 || ky < 0 || dx < 0 || dy < 0) {
|
||||
return 10;
|
||||
}
|
||||
|
||||
int ntx = std::ranges::size(tx);
|
||||
int nty = std::ranges::size(ty);
|
||||
|
||||
auto n_coeffs = (ntx - kx - 1) * (nty - ky - 1);
|
||||
if (std::ranges::size(coeffs) < n_coeffs) {
|
||||
return 10;
|
||||
}
|
||||
|
||||
int mx = std::ranges::size(x), my = std::ranges::size(y);
|
||||
int N = mx * my;
|
||||
|
||||
if (std::ranges::size(pder) < N) {
|
||||
std::ranges::fill_n(std::back_inserter(pder), N - std::ranges::size(pder), 0.0);
|
||||
}
|
||||
|
||||
// mx >=1, my >=1, 0 <= nux < kx, 0 <= nuy < ky, kwrk>=mx+my
|
||||
// lwrk>=mx*(kx+1-nux)+my*(ky+1-nuy)+(nx-kx-1)*(ny-ky-1),
|
||||
|
||||
// compute sizes of working arrays according parder.f
|
||||
int lwrk = mx * (kx + 1 - dx) + my * (ky + 1 - dy) + (ntx - kx - 1) * (nty - ky - 1);
|
||||
std::vector<double> wrk(lwrk);
|
||||
|
||||
int kwrk = mx + my;
|
||||
std::vector<int> iwrk(kwrk);
|
||||
|
||||
|
||||
auto tx_ptr = const_cast<double*>(std::ranges::data(tx));
|
||||
auto ty_ptr = const_cast<double*>(std::ranges::data(ty));
|
||||
auto coeffs_ptr = const_cast<double*>(std::ranges::data(coeffs));
|
||||
auto x_ptr = const_cast<double*>(std::ranges::data(x));
|
||||
auto y_ptr = const_cast<double*>(std::ranges::data(y));
|
||||
|
||||
int ier = 0;
|
||||
|
||||
parder(tx_ptr, &ntx, ty_ptr, &nty, coeffs_ptr, &kx, &ky, &dx, &dy, x_ptr, &mx, y_ptr, &my, std::ranges::data(pder),
|
||||
wrk.data(), &lwrk, iwrk.data(), &kwrk, &ier);
|
||||
|
||||
return ier;
|
||||
}
|
||||
|
||||
// scalar version
|
||||
template <std::ranges::contiguous_range TXT,
|
||||
std::ranges::contiguous_range TYT,
|
||||
typename XT,
|
||||
typename YT,
|
||||
std::ranges::contiguous_range CoeffT,
|
||||
typename PderT>
|
||||
int fitpack_parder_spl2d(const TXT& tx,
|
||||
const TYT& ty,
|
||||
const CoeffT& coeffs,
|
||||
const XT& x,
|
||||
const YT& y,
|
||||
PderT& pder,
|
||||
int dx, // partial derivatives order along X
|
||||
int dy, // partial derivatives order along Y
|
||||
int kx = 3,
|
||||
int ky = 3)
|
||||
{
|
||||
static_assert(std::same_as<std::ranges::range_value_t<TXT>, double> &&
|
||||
std::same_as<std::ranges::range_value_t<TYT>, double> &&
|
||||
std::same_as<std::ranges::range_value_t<CoeffT>, double>,
|
||||
"Input ranges elements type must be double!");
|
||||
|
||||
static_assert(
|
||||
std::convertible_to<XT, double> && std::convertible_to<YT, double> && std::convertible_to<PderT, double>,
|
||||
"XT, YT and FuncT types must be a scalar convertible to double!");
|
||||
|
||||
auto xv = std::vector<double>(1, x);
|
||||
auto yv = std::vector<double>(1, y);
|
||||
auto pv = std::vector<double>(1, pder);
|
||||
|
||||
return fitpack_parder_spl2d(tx, ty, coeffs, xv, yv, pv, dx, dy, kx, ky);
|
||||
}
|
||||
|
||||
|
||||
} // namespace mcc::bsplines
|
||||
@@ -280,15 +280,15 @@ public:
|
||||
}
|
||||
|
||||
|
||||
// latitude and longitude
|
||||
template <mcc_angle_c LAT_T, mcc_angle_c LON_T>
|
||||
void geoPosition(std::pair<LAT_T, LON_T>* coords) const
|
||||
// longitude and latitude
|
||||
template <mcc_angle_c LON_T, mcc_angle_c LAT_T>
|
||||
void geoPosition(std::pair<LON_T, LAT_T>* coords) const
|
||||
{
|
||||
std::lock_guard lock{*_stateMutex};
|
||||
|
||||
if (coords) {
|
||||
coords->first = _currentState.lat;
|
||||
coords->second = _currentState.lon;
|
||||
coords->first = _currentState.lon;
|
||||
coords->second = _currentState.lat;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -58,10 +58,23 @@ concept mcc_error_c = std::default_initializable<T> && (std::convertible_to<T, b
|
||||
|
||||
|
||||
template <mcc_error_c ErrT, mcc_error_c DefErrT>
|
||||
DefErrT mcc_deduced_err(ErrT const& err, DefErrT const& default_err)
|
||||
auto mcc_deduced_err(ErrT const& err, DefErrT const& default_err)
|
||||
// DefErrT mcc_deduced_err(ErrT const& err, DefErrT const& default_err)
|
||||
{
|
||||
if constexpr (std::same_as<ErrT, DefErrT>) {
|
||||
return err;
|
||||
} else if constexpr (std::is_error_code_enum_v<DefErrT>) {
|
||||
if constexpr (std::same_as<ErrT, std::error_code>) {
|
||||
return err;
|
||||
} else {
|
||||
return default_err;
|
||||
}
|
||||
} else if constexpr (std::is_error_condition_enum_v<DefErrT>) {
|
||||
if constexpr (std::same_as<ErrT, std::error_condition>) {
|
||||
return err;
|
||||
} else {
|
||||
return default_err;
|
||||
}
|
||||
} else {
|
||||
return default_err;
|
||||
}
|
||||
@@ -147,6 +160,11 @@ concept mcc_fp_type_like_c =
|
||||
|
||||
/* GEOMETRICAL ANGLE REPRESENTATION CLASS CONCEPT */
|
||||
|
||||
/* REQUIREMENT: in the MCC-library it is assumed that an arithmetic representation of angles are measured in the
|
||||
radians!!! This means that possible conversion operator 'SOME_USER_ANGLE_CLASS::operator double()'
|
||||
must return an angle in radians!
|
||||
*/
|
||||
|
||||
template <typename T>
|
||||
concept mcc_angle_c = mcc_fp_type_like_c<T> && requires(T v, double vd) {
|
||||
// mandatory arithmetic operations
|
||||
@@ -468,11 +486,11 @@ struct mcc_skypoint_interface_t {
|
||||
return std::forward<SelfT>(self).refractInverseCorrection(dZ);
|
||||
}
|
||||
|
||||
// returns apparent sideral time (Greenwich) for the epoch of the celestial point
|
||||
// returns apparent sideral time (Greenwich or local) for the epoch of the celestial point
|
||||
template <std::derived_from<mcc_skypoint_interface_t> SelfT>
|
||||
auto appSideralTime(this SelfT&& self, mcc_angle_c auto* st)
|
||||
auto appSideralTime(this SelfT&& self, mcc_angle_c auto* st, bool is_local)
|
||||
{
|
||||
return std::forward<SelfT>(self).appSideralTime(st);
|
||||
return std::forward<SelfT>(self).appSideralTime(st, is_local);
|
||||
}
|
||||
|
||||
// returns equation of origins for the epoch of the celestial point
|
||||
@@ -481,15 +499,55 @@ struct mcc_skypoint_interface_t {
|
||||
{
|
||||
return std::forward<SelfT>(self).EO(eo);
|
||||
}
|
||||
|
||||
// template <std::derived_from<mcc_skypoint_interface_t> SelfT>
|
||||
// typename std::remove_cvref_t<SelfT>::dist_result_t distance(this SelfT&& self, auto const& sp)
|
||||
// {
|
||||
// return std::forward<SelfT>(self).distance(sp);
|
||||
// }
|
||||
// template <std::derived_from<mcc_skypoint_interface_t> SelfT>
|
||||
// SelfT& operator+=(this SelfT& self, mcc_coord_pair_c auto const& dxy)
|
||||
// {
|
||||
// return self.operator+=(dxy);
|
||||
// }
|
||||
|
||||
// template <std::derived_from<mcc_skypoint_interface_t> SelfT>
|
||||
// SelfT& operator-=(this SelfT& self, mcc_coord_pair_c auto const& dxy)
|
||||
// {
|
||||
// return self.operator-=(dxy);
|
||||
// }
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
concept mcc_skypoint_c = std::derived_from<T, mcc_skypoint_interface_t> && requires(const T t_const) {
|
||||
{ t_const.epoch() } -> mcc_coord_epoch_c;
|
||||
concept mcc_skypoint_c =
|
||||
std::derived_from<T, mcc_skypoint_interface_t> && requires(const T t_const, const T t_other_const, T t) {
|
||||
{ t_const.epoch() } -> mcc_coord_epoch_c;
|
||||
|
||||
// currently stored coordinates pair
|
||||
{ t_const.pairKind() } -> std::same_as<impl::MccCoordPairKind>;
|
||||
};
|
||||
// currently stored coordinates pair kind
|
||||
{ t_const.pairKind() } -> std::same_as<impl::MccCoordPairKind>;
|
||||
|
||||
// currently stored co-longitude coordinate
|
||||
{ t_const.co_lon() } -> std::convertible_to<double>;
|
||||
|
||||
// currently stored co-latitude coordinate
|
||||
{ t_const.co_lat() } -> std::convertible_to<double>;
|
||||
|
||||
requires requires(typename T::dist_result_t res) {
|
||||
requires mcc_angle_c<decltype(res.dist)>; // distance on sphere
|
||||
requires mcc_angle_c<decltype(res.dx)>; // difference along co-longitude coordinate
|
||||
requires mcc_angle_c<decltype(res.dy)>; // difference along co-latitude coordinate
|
||||
requires mcc_angle_c<decltype(res.x2)>; // co-longitude coordinates of target sky point (in the same
|
||||
// coordinate system as 'this')
|
||||
requires mcc_angle_c<decltype(res.y2)>; // co-latitude coordinates of target sky point (in the same
|
||||
// coordinate system as 'this')
|
||||
};
|
||||
|
||||
// distance on sphere between two sky points
|
||||
{ t_const.distance(std::declval<const T&>()) } -> std::same_as<typename T::dist_result_t>;
|
||||
|
||||
// { t_const - t_other_const } -> mcc_coord_pair_c;
|
||||
// { t_const + t_other_const } -> mcc_coord_pair_c;
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -536,9 +594,11 @@ concept mcc_pcm_c = std::derived_from<T, mcc_pcm_interface_t<typename T::error_t
|
||||
requires mcc_error_c<typename T::error_t>;
|
||||
|
||||
// the 'T' class must contain static constexpr member of 'MccMountType' type
|
||||
requires std::same_as<decltype(T::mountType), const MccMountType>;
|
||||
requires std::same_as<decltype(T::pcmMountType), const MccMountType>;
|
||||
// requires std::same_as<decltype(T::mountType), const MccMountType>;
|
||||
[]() {
|
||||
[[maybe_unused]] static constexpr MccMountType val = T::mountType;
|
||||
// [[maybe_unused]] static constexpr MccMountType val = T::mountType;
|
||||
[[maybe_unused]] static constexpr MccMountType val = T::pcmMountType;
|
||||
}(); // to ensure 'mountType' can be used in compile-time context
|
||||
|
||||
// static const variable with name of PCM
|
||||
@@ -566,7 +626,7 @@ concept mcc_pcm_c = std::derived_from<T, mcc_pcm_interface_t<typename T::error_t
|
||||
// static constexpr uint16_t HW_MOVE_ERROR = 555;
|
||||
// }
|
||||
template <typename T>
|
||||
concept mcc_hardware_movement_state_c = requires {
|
||||
concept mcc_hardware_movement_state_c = std::formattable<T, char> && requires {
|
||||
[]() {
|
||||
// // mount axes were stopped
|
||||
// [[maybe_unused]] static constexpr auto v0 = T::HW_MOVE_STOPPED;
|
||||
@@ -616,7 +676,6 @@ concept mcc_hardware_movement_state_c = requires {
|
||||
template <typename T>
|
||||
concept mcc_hardware_state_c = requires(T state) {
|
||||
// encoder co-longitude and co-latiitude positions, as well as its measurement time point
|
||||
// the given constrains on coordinate pair kind can be used to deduce mount type
|
||||
requires mcc_coord_pair_c<decltype(state.XY)> &&
|
||||
(decltype(state.XY)::pairKind == impl::MccCoordPairKind::COORDS_KIND_GENERIC ||
|
||||
decltype(state.XY)::pairKind == impl::MccCoordPairKind::COORDS_KIND_XY);
|
||||
@@ -639,75 +698,20 @@ concept mcc_hardware_c = requires(T t) {
|
||||
// static const variable with name of hardware
|
||||
requires std::formattable<decltype(T::hardwareName), char> && std::is_const_v<decltype(T::hardwareName)>;
|
||||
|
||||
// a type that defines at least HW_MOVE_ERROR, HW_MOVE_STOPPING, HW_MOVE_STOPPED, HW_MOVE_SLEWING,
|
||||
// HW_MOVE_ADJUSTING, HW_MOVE_TRACKING and HW_MOVE_GUIDING compile-time constants. The main purpose of this type is
|
||||
// a possible tunning of hardware hardwareSetState-related commands and detect the stop and error states from
|
||||
// hardware
|
||||
//
|
||||
// e.g. an implementations can be as follows:
|
||||
// enum class hardware_movement_state_t: int {HW_MOVE_ERROR = -1, HW_MOVE_STOPPED = 0, HW_MOVE_STOPPING,
|
||||
// HW_MOVE_SLEWING, HW_MOVE_ADJUSTING, HW_MOVE_TRACKING, HW_MOVE_GUIDING}
|
||||
//
|
||||
// struct hardware_movement_state_t {
|
||||
// static constexpr uint16_t HW_MOVE_STOPPED = 0;
|
||||
// static constexpr uint16_t HW_MOVE_SLEWING = 111;
|
||||
// static constexpr uint16_t HW_MOVE_ADJUSTING = 222;
|
||||
// static constexpr uint16_t HW_MOVE_TRACKING = 333;
|
||||
// static constexpr uint16_t HW_MOVE_GUIDING = 444;
|
||||
// static constexpr uint16_t HW_MOVE_ERROR = 555;
|
||||
// static constexpr uint16_t HW_MOVE_STOPPING = 666;
|
||||
// }
|
||||
|
||||
// the 'T' class must contain static constexpr member of 'MccMountType' type
|
||||
requires std::same_as<decltype(T::hwMountType), const MccMountType>;
|
||||
[]() {
|
||||
[[maybe_unused]] static constexpr MccMountType val = T::hwMountType;
|
||||
}(); // to ensure 'mountType' can be used in compile-time context
|
||||
|
||||
|
||||
requires mcc_hardware_movement_state_c<typename T::hardware_movement_state_t>;
|
||||
|
||||
// requires requires(typename T::hardware_movement_state_t type) {
|
||||
// []() {
|
||||
// // mount axes were stopped
|
||||
// static constexpr auto v0 = T::hardware_movement_state_t::HW_MOVE_STOPPED;
|
||||
|
||||
// // hardware was asked for slewing (move to given celestial point)
|
||||
// static constexpr auto v1 = T::hardware_movement_state_t::HW_MOVE_SLEWING;
|
||||
|
||||
// // hardware was asked for adjusting after slewing
|
||||
// // (adjusting actual mount position to align with target celestial point at the end of slewing process)
|
||||
// static constexpr auto v2 = T::hardware_movement_state_t::HW_MOVE_ADJUSTING;
|
||||
|
||||
// // hardware was asked for tracking (track target celestial point)
|
||||
// static constexpr auto v3 = T::hardware_movement_state_t::HW_MOVE_TRACKING;
|
||||
|
||||
// // hardware was asked for guiding
|
||||
// // (small corrections to align actual mount position with target celestial point)
|
||||
// static constexpr auto v4 = T::hardware_movement_state_t::HW_MOVE_GUIDING;
|
||||
|
||||
// // to detect possible hardware error
|
||||
// static constexpr auto v5 = T::hardware_movement_state_t::HW_MOVE_ERROR;
|
||||
// }();
|
||||
// };
|
||||
|
||||
requires mcc_hardware_state_c<typename T::hardware_state_t> && requires(typename T::hardware_state_t state) {
|
||||
requires std::same_as<decltype(state.movementState), typename T::hardware_movement_state_t>;
|
||||
};
|
||||
|
||||
// requires requires(typename T::hardware_state_t state) {
|
||||
// // encoder co-longitude and co-latiitude positions, as well as its measurement time point
|
||||
// // the given constrains on coordinate pair kind can be used to deduce mount type
|
||||
// requires mcc_coord_pair_c<decltype(state.XY)> &&
|
||||
// ( // for equathorial mount:
|
||||
// decltype(state.XY)::pairKind == impl::MccCoordPairKind::COORDS_KIND_HADEC_OBS ||
|
||||
// // for alt-azimuthal mount:
|
||||
// decltype(state.XY)::pairKind == impl::MccCoordPairKind::COORDS_KIND_AZALT ||
|
||||
// decltype(state.XY)::pairKind == impl::MccCoordPairKind::COORDS_KIND_AZZD);
|
||||
|
||||
// // co-longitude and co-latiitude axis angular speeds, as well as its measurement/computation time point
|
||||
// requires mcc_coord_pair_c<decltype(state.speedXY)> &&
|
||||
// (decltype(state.XY)::pairKind == impl::MccCoordPairKind::COORDS_KIND_GENERIC ||
|
||||
// decltype(state.XY)::pairKind == impl::MccCoordPairKind::COORDS_KIND_XY);
|
||||
|
||||
|
||||
// requires std::same_as<typename T::hardware_movement_state_t, decltype(state.movementState)>;
|
||||
// };
|
||||
|
||||
|
||||
// set hardware state:
|
||||
{ t.hardwareSetState(std::declval<typename T::hardware_state_t const&>()) } -> std::same_as<typename T::error_t>;
|
||||
|
||||
@@ -716,6 +720,8 @@ concept mcc_hardware_c = requires(T t) {
|
||||
|
||||
// { t.hardwareStop() } -> std::same_as<typename T::error_t>; // stop any moving
|
||||
{ t.hardwareInit() } -> std::same_as<typename T::error_t>; // initialize hardware
|
||||
|
||||
{ t.hardwareShutdown() } -> std::same_as<typename T::error_t>; // shutdown hardware
|
||||
};
|
||||
|
||||
|
||||
@@ -726,6 +732,14 @@ concept mcc_telemetry_data_c = requires(T t) {
|
||||
// target celestial point (position on sky where mount must be slewed)
|
||||
requires mcc_skypoint_c<decltype(t.targetPos)>;
|
||||
|
||||
// computed target encoder coordinates
|
||||
requires(mcc_coord_pair_c<decltype(t.targetXY)> &&
|
||||
(decltype(t.targetXY)::pairKind == impl::MccCoordPairKind::COORDS_KIND_GENERIC ||
|
||||
decltype(t.targetXY)::pairKind == impl::MccCoordPairKind::COORDS_KIND_XY));
|
||||
|
||||
// corrections to transform observed celestial coordinates of target to hardware encoder ones
|
||||
requires mcc_pcm_result_c<decltype(t.pcmReverseCorrection)>;
|
||||
|
||||
// mount current celestial position
|
||||
requires mcc_skypoint_c<decltype(t.mountPos)>;
|
||||
|
||||
@@ -779,23 +793,33 @@ struct mcc_telemetry_interface_t {
|
||||
|
||||
// set target position
|
||||
template <std::derived_from<mcc_telemetry_interface_t> SelfT>
|
||||
RetT setTarget(this SelfT&& self, mcc_skypoint_c auto const& pt)
|
||||
RetT setPointingTarget(this SelfT&& self, mcc_skypoint_c auto const& pt)
|
||||
{
|
||||
return std::forward<SelfT>(self).setTarget(pt);
|
||||
}
|
||||
|
||||
// get entered target position
|
||||
template <std::derived_from<mcc_telemetry_interface_t> SelfT>
|
||||
RetT getPointingTarget(this SelfT&& self, mcc_skypoint_c auto* pt)
|
||||
{
|
||||
return std::forward<SelfT>(self).getTarget(pt);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
concept mcc_telemetry_c = std::derived_from<T, mcc_telemetry_interface_t<typename T::error_t>> && requires(T t) {
|
||||
// error type
|
||||
requires mcc_error_c<typename T::error_t>;
|
||||
concept mcc_telemetry_c =
|
||||
std::derived_from<T, mcc_telemetry_interface_t<typename T::error_t>> && requires(T t, const T t_const) {
|
||||
// error type
|
||||
requires mcc_error_c<typename T::error_t>;
|
||||
|
||||
// telemetry data type definition
|
||||
requires mcc_telemetry_data_c<typename T::telemetry_data_t>;
|
||||
// telemetry data type definition
|
||||
requires mcc_telemetry_data_c<typename T::telemetry_data_t>;
|
||||
|
||||
// get telemetry data
|
||||
{ t.telemetryData(std::declval<typename T::telemetry_data_t*>()) } -> std::same_as<typename T::error_t>;
|
||||
};
|
||||
// get telemetry data
|
||||
{ t.telemetryData(std::declval<typename T::telemetry_data_t*>()) } -> std::same_as<typename T::error_t>;
|
||||
|
||||
{ t_const.getPointingTarget() } -> mcc_skypoint_c;
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -903,10 +927,15 @@ struct mcc_pzone_container_interface_t {
|
||||
|
||||
|
||||
template <typename T>
|
||||
concept mcc_pzone_container_c = std::derived_from<T, mcc_pzone_container_interface_t<typename T::error_t>> && requires {
|
||||
// error type
|
||||
requires mcc_error_c<typename T::error_t>;
|
||||
};
|
||||
concept mcc_pzone_container_c =
|
||||
std::derived_from<T, mcc_pzone_container_interface_t<typename T::error_t>> && requires(const T t_const) {
|
||||
// error type
|
||||
requires mcc_error_c<typename T::error_t>;
|
||||
|
||||
[]<std::ranges::range R>(R const&) {
|
||||
return requires { requires std::formattable<std::ranges::range_value_t<R>, char>; };
|
||||
}(t_const.pzoneNames());
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -944,27 +973,28 @@ concept mcc_movement_controls_c = requires(T t) {
|
||||
template <typename T>
|
||||
concept mcc_mount_status_c = requires {
|
||||
[]() {
|
||||
[[maybe_unused]] static constexpr std::array arr = {
|
||||
T::MOUNT_STATUS_ERROR, T::MOUNT_STATUS_IDLE, T::MOUNT_STATUS_INITIALIZATION,
|
||||
T::MOUNT_STATUS_ERROR, T::MOUNT_STATUS_STOPPED, T::MOUNT_STATUS_SLEWING,
|
||||
T::MOUNT_STATUS_ADJUSTING, T::MOUNT_STATUS_GUIDING, T::MOUNT_STATUS_TRACKING};
|
||||
[[maybe_unused]]
|
||||
static constexpr std::array arr = {T::MOUNT_STATUS_ERROR, T::MOUNT_STATUS_IDLE,
|
||||
T::MOUNT_STATUS_INITIALIZATION, T::MOUNT_STATUS_STOPPED,
|
||||
T::MOUNT_STATUS_SLEWING, T::MOUNT_STATUS_ADJUSTING,
|
||||
T::MOUNT_STATUS_GUIDING, T::MOUNT_STATUS_TRACKING};
|
||||
}; // to ensure mount status is compile-time constants
|
||||
};
|
||||
|
||||
|
||||
|
||||
template <typename T>
|
||||
concept mcc_generic_mount_c =
|
||||
mcc_logger_c<T> && mcc_pzone_container_c<T> && mcc_telemetry_c<T> && mcc_movement_controls_c<T> && requires(T t) {
|
||||
// error type
|
||||
requires mcc_error_c<typename T::error_t>;
|
||||
concept mcc_generic_mount_c = mcc_logger_c<T> && mcc_pzone_container_c<T> && mcc_telemetry_c<T> &&
|
||||
mcc_movement_controls_c<T> && requires(T t, const T t_const) {
|
||||
// error type
|
||||
requires mcc_error_c<typename T::error_t>;
|
||||
|
||||
requires mcc_mount_status_c<typename T::mount_status_t>;
|
||||
requires mcc_mount_status_c<typename T::mount_status_t>;
|
||||
|
||||
{ t.initMount() } -> std::same_as<typename T::error_t>;
|
||||
{ t.initMount() } -> std::same_as<typename T::error_t>;
|
||||
|
||||
{ t.mountStatus() } -> std::same_as<typename T::mount_status_t>;
|
||||
};
|
||||
{ t_const.mountStatus() } -> std::same_as<typename T::mount_status_t>;
|
||||
};
|
||||
|
||||
|
||||
} // namespace mcc
|
||||
@@ -18,11 +18,17 @@
|
||||
namespace mcc
|
||||
{
|
||||
|
||||
constexpr double MCC_HALF_PI = std::numbers::pi / 2.0;
|
||||
constexpr double MCC_TWO_PI = std::numbers::pi * 2.0;
|
||||
static constexpr double MCC_DEGRESS_TO_RADS = std::numbers::pi / 180.0;
|
||||
static constexpr double MCC_RADS_TO_DEGRESS = 1.0 / MCC_DEGRESS_TO_RADS;
|
||||
|
||||
static constexpr double MCC_HALF_PI = std::numbers::pi / 2.0;
|
||||
static constexpr double MCC_TWO_PI = std::numbers::pi * 2.0;
|
||||
|
||||
static constexpr double MCC_SIDERAL_TO_UT1_RATIO = 1.002737909350795; // sideral/UT1
|
||||
|
||||
static constexpr double MCC_J2000_MJD = 51544.5;
|
||||
static constexpr double MCC_MJD_ZERO = 2400000.5;
|
||||
|
||||
|
||||
// a value to represent of infinite time duration according to type of duration representation
|
||||
template <traits::mcc_time_duration_c DT>
|
||||
@@ -234,7 +234,7 @@ struct MccSkyRADEC_ICRS : MccCoordPair<MccAngleRA_ICRS, MccAngleDEC_ICRS> {
|
||||
// ignore epoch setting (it is always J2000.0)
|
||||
void setEpoch(mcc_coord_epoch_c auto const&)
|
||||
{
|
||||
static_assert(false, "CANNOT SET EPOCH FOR ICRS-KIND COORDINATE PAIR!!!");
|
||||
// static_assert(false, "CANNOT SET EPOCH FOR ICRS-KIND COORDINATE PAIR!!!");
|
||||
}
|
||||
};
|
||||
|
||||
@@ -344,14 +344,24 @@ struct MccSkyAZALT : MccCoordPair<MccAngleAZ, MccAngleALT> {
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
using MccGenXY = MccCoordPair<MccAngleX, MccAngleY>;
|
||||
|
||||
using MccGeoLONLAT = MccCoordPair<MccAngleLON, MccAngleLAT>;
|
||||
|
||||
// utility type definition: deduce a coordinate pair kind according to mount type
|
||||
// mcc_deduced_coord_pair_t = MccSkyHADEC_OBS for equathorial mounts,
|
||||
// mcc_deduced_coord_pair_t = MccSkyAZZD for altazimuthal ones and
|
||||
// mcc_deduced_coord_pair_t = std::nullptr_t otherwise
|
||||
template <MccMountType MOUNT_TYPE>
|
||||
using mcc_deduced_coord_pair_t =
|
||||
std::conditional_t<mccIsEquatorialMount(MOUNT_TYPE),
|
||||
MccSkyHADEC_OBS,
|
||||
std::conditional_t<mccIsAltAzMount(MOUNT_TYPE), MccSkyAZZD, std::nullptr_t>>;
|
||||
|
||||
static MccSkyHADEC_APP hadec = MccGenXY{};
|
||||
static MccSkyAZALT azalt{MccSkyAZZD{1.0, 1.1}};
|
||||
|
||||
|
||||
// static MccSkyHADEC_APP hadec = MccGenXY{};
|
||||
// static MccSkyAZALT azalt{MccSkyAZZD{1.0, 1.1}};
|
||||
|
||||
|
||||
/* MCC-LIBRARY DEFAULT GENERIC SKY POINT CLASS IMPLEMENTATION */
|
||||
@@ -370,6 +380,14 @@ public:
|
||||
|
||||
using error_t = typename CCTE_T::error_t;
|
||||
|
||||
struct dist_result_t {
|
||||
MccAngle dist{};
|
||||
MccAngle dx{};
|
||||
MccAngle dy{};
|
||||
MccAngle x2{};
|
||||
MccAngle y2{};
|
||||
};
|
||||
|
||||
MccGenericSkyPoint() {}
|
||||
|
||||
template <mcc_coord_pair_c PT>
|
||||
@@ -423,6 +441,17 @@ public:
|
||||
return _epoch;
|
||||
}
|
||||
|
||||
|
||||
double co_lon() const
|
||||
{
|
||||
return _x;
|
||||
}
|
||||
|
||||
double co_lat() const
|
||||
{
|
||||
return _y;
|
||||
}
|
||||
|
||||
template <mcc_coord_pair_c PT>
|
||||
MccGenericSkyPoint& from(const PT& coord_pair)
|
||||
{
|
||||
@@ -475,7 +504,7 @@ public:
|
||||
std::pair<double, double> pos;
|
||||
cctEngine.geoPosition(&pos);
|
||||
|
||||
return MccGeoLONLAT(pos.second, pos.first);
|
||||
return MccGeoLONLAT(pos.first, pos.second);
|
||||
}
|
||||
|
||||
|
||||
@@ -516,6 +545,78 @@ public:
|
||||
return error_t{};
|
||||
}
|
||||
|
||||
// 'inner' transformation
|
||||
error_t to(MccCoordPairKind pair_kind)
|
||||
{
|
||||
return to(pair_kind, _epoch);
|
||||
}
|
||||
|
||||
error_t to(MccCoordPairKind pair_kind, mcc_coord_epoch_c auto const& epoch)
|
||||
{
|
||||
// do not use here "mcc_coord_epoch_c::operator==" to avoid
|
||||
// unnecessary computations (astrometrical algorithms mainly use Julian date as input)
|
||||
if (pair_kind == _pairKind && utils::isEqual(epoch.MJD(), _epoch.MJD())) {
|
||||
_epoch = epoch;
|
||||
|
||||
return error_t{};
|
||||
}
|
||||
|
||||
auto tr_func = [&, this]<mcc_coord_pair_c T>(T& cp) {
|
||||
if constexpr (T::pairKind != MccCoordPairKind::COORDS_KIND_RADEC_ICRS) {
|
||||
cp.setEpoch(epoch);
|
||||
}
|
||||
|
||||
auto err = to(cp);
|
||||
|
||||
if (!err) {
|
||||
from(cp);
|
||||
}
|
||||
|
||||
return err;
|
||||
};
|
||||
|
||||
switch (pair_kind) {
|
||||
case MccCoordPairKind::COORDS_KIND_RADEC_ICRS: {
|
||||
MccSkyRADEC_ICRS cp;
|
||||
return tr_func(cp);
|
||||
} break;
|
||||
case MccCoordPairKind::COORDS_KIND_RADEC_OBS: {
|
||||
MccSkyRADEC_OBS cp;
|
||||
return tr_func(cp);
|
||||
} break;
|
||||
case MccCoordPairKind::COORDS_KIND_RADEC_APP: {
|
||||
MccSkyRADEC_APP cp;
|
||||
return tr_func(cp);
|
||||
} break;
|
||||
case MccCoordPairKind::COORDS_KIND_HADEC_OBS: {
|
||||
MccSkyHADEC_OBS cp;
|
||||
return tr_func(cp);
|
||||
} break;
|
||||
case MccCoordPairKind::COORDS_KIND_HADEC_APP: {
|
||||
MccSkyHADEC_APP cp;
|
||||
return tr_func(cp);
|
||||
} break;
|
||||
case MccCoordPairKind::COORDS_KIND_AZZD: {
|
||||
MccSkyAZZD cp;
|
||||
return tr_func(cp);
|
||||
} break;
|
||||
case MccCoordPairKind::COORDS_KIND_AZALT: {
|
||||
MccSkyAZALT cp;
|
||||
return tr_func(cp);
|
||||
} break;
|
||||
case MccCoordPairKind::COORDS_KIND_GENERIC:
|
||||
case MccCoordPairKind::COORDS_KIND_UNKNOWN:
|
||||
case MccCoordPairKind::COORDS_KIND_LONLAT:
|
||||
case MccCoordPairKind::COORDS_KIND_XY: {
|
||||
MccGenXY cp;
|
||||
return tr_func(cp);
|
||||
} break;
|
||||
default:
|
||||
return error_t{};
|
||||
}
|
||||
|
||||
return error_t{};
|
||||
}
|
||||
|
||||
error_t refractCorrection(mcc_angle_c auto* dZ) const
|
||||
{
|
||||
@@ -581,23 +682,45 @@ public:
|
||||
}
|
||||
|
||||
|
||||
error_t appSideralTime(mcc_angle_c auto* st) const
|
||||
error_t appSideralTime(mcc_angle_c auto* st, bool is_local = false) const
|
||||
{
|
||||
// return Greenwich apparent sideral time since epoch is UTC
|
||||
return cctEngine.apparentSideralTime(_epoch, st, false);
|
||||
return cctEngine.apparentSideralTime(_epoch, st, is_local);
|
||||
}
|
||||
|
||||
|
||||
error_t EO(mcc_angle_c auto* eo)
|
||||
error_t EO(mcc_angle_c auto* eo) const
|
||||
{
|
||||
return cctEngine.equationOrigins(_epoch, eo);
|
||||
}
|
||||
|
||||
|
||||
dist_result_t distance(MccGenericSkyPoint const& sp) const
|
||||
// dist_result_t distance(mcc_skypoint_c auto const& sp)
|
||||
{
|
||||
double x, y;
|
||||
|
||||
if (_pairKind == sp.pairKind() && utils::isEqual(_epoch.MJD(), sp.epoch().MJD())) {
|
||||
x = sp.co_lon();
|
||||
y = sp.co_lat();
|
||||
} else { // convert to the same coordinates kind
|
||||
MccGenericSkyPoint p{sp};
|
||||
p.to(_pairKind, _epoch);
|
||||
|
||||
x = p.co_lon();
|
||||
y = p.co_lat();
|
||||
}
|
||||
|
||||
auto d = utils::distanceOnSphere(_x, _y, x, y);
|
||||
|
||||
return {.dist = std::get<2>(d), .dx = std::get<0>(d), .dy = std::get<1>(d), .x2 = x, .y2 = y};
|
||||
}
|
||||
|
||||
protected:
|
||||
double _x{0.0}, _y{0.0};
|
||||
MccCoordPairKind _pairKind{MccCoordPairKind::COORDS_KIND_RADEC_ICRS};
|
||||
MccCelestialCoordEpoch _epoch{}; // J2000.0
|
||||
|
||||
|
||||
template <mcc_skypoint_c T>
|
||||
void fromOtherSkyPoint(T&& other)
|
||||
{
|
||||
@@ -659,30 +782,30 @@ protected:
|
||||
// HA, DEC to AZ, ALT (AZ from the South through the West)
|
||||
void hadec2azalt(double ha, double dec, double phi, double& az, double& alt) const
|
||||
{
|
||||
eraHd2ae(ha, dec, phi, &az, &alt);
|
||||
// from ERFA "from N" to "from S"
|
||||
if (az > std::numbers::pi) {
|
||||
az -= std::numbers::pi;
|
||||
} else {
|
||||
az += std::numbers::pi;
|
||||
}
|
||||
// eraHd2ae(ha, dec, phi, &az, &alt);
|
||||
// // from ERFA "from N" to "from S"
|
||||
// if (az > std::numbers::pi) {
|
||||
// az -= std::numbers::pi;
|
||||
// } else {
|
||||
// az += std::numbers::pi;
|
||||
// }
|
||||
|
||||
return;
|
||||
// return;
|
||||
|
||||
const auto cos_phi = std::cos(phi), sin_phi = std::sin(phi);
|
||||
const auto cos_dec = std::cos(dec), sin_dec = std::sin(dec);
|
||||
const auto cos_ha = std::cos(ha), sin_ha = std::sin(ha);
|
||||
|
||||
auto x = sin_phi * cos_dec * cos_ha - cos_phi * sin_dec;
|
||||
auto y = -cos_dec * sin_ha;
|
||||
auto y = cos_dec * sin_ha;
|
||||
auto z = cos_phi * cos_dec * cos_ha + sin_phi * sin_dec;
|
||||
|
||||
auto xx = x * x, yy = y * y;
|
||||
decltype(x) r;
|
||||
if (xx < yy) {
|
||||
r = yy * sqrt(1.0 + xx / yy);
|
||||
r = std::abs(y) * sqrt(1.0 + xx / yy);
|
||||
} else {
|
||||
r = xx * sqrt(1.0 + yy / xx);
|
||||
r = std::abs(x) * sqrt(1.0 + yy / xx);
|
||||
}
|
||||
|
||||
az = utils::isEqual(r, 0.0) ? 0.0 : std::atan2(y, x);
|
||||
@@ -697,10 +820,10 @@ protected:
|
||||
// AZ, ALT to HA, DEC (AZ from the South through the West)
|
||||
void azalt2hadec(double az, double alt, double phi, double& ha, double& dec) const
|
||||
{
|
||||
az += std::numbers::pi;
|
||||
eraAe2hd(az, alt, phi, &ha, &dec);
|
||||
// az += std::numbers::pi;
|
||||
// eraAe2hd(az, alt, phi, &ha, &dec);
|
||||
|
||||
return;
|
||||
// return;
|
||||
|
||||
const auto cos_phi = std::cos(phi), sin_phi = std::sin(phi);
|
||||
const auto cos_az = std::cos(az), sin_az = std::sin(az);
|
||||
@@ -713,9 +836,9 @@ protected:
|
||||
auto xx = x * x, yy = y * y;
|
||||
decltype(x) r;
|
||||
if (xx < yy) {
|
||||
r = yy * sqrt(1.0 + xx / yy);
|
||||
r = std::abs(y) * sqrt(1.0 + xx / yy);
|
||||
} else {
|
||||
r = xx * sqrt(1.0 + yy / xx);
|
||||
r = std::abs(x) * sqrt(1.0 + yy / xx);
|
||||
}
|
||||
|
||||
ha = utils::isEqual(r, 0.0) ? 0.0 : std::atan2(y, x);
|
||||
@@ -731,10 +854,22 @@ protected:
|
||||
double phi = cctEngine.getStateERFA().lat;
|
||||
double ra_icrs, dec_icrs, ra, dec, ha, az, zd, alt, lst, eo;
|
||||
|
||||
static_assert(PT::pairKind != MccCoordPairKind::COORDS_KIND_LONLAT, "UNSUPPORTED SKY POINT TRANSFORMATION!");
|
||||
// static_assert(PT::pairKind != MccCoordPairKind::COORDS_KIND_XY, "UNSUPPORTED SKY POINT TRANSFORMATION!");
|
||||
static_assert(PT::pairKind != MccCoordPairKind::COORDS_KIND_GENERIC, "UNSUPPORTED SKY POINT TRANSFORMATION!");
|
||||
static_assert(PT::pairKind != MccCoordPairKind::COORDS_KIND_UNKNOWN, "UNSUPPORTED SKY POINT TRANSFORMATION!");
|
||||
|
||||
|
||||
if constexpr (PT::pairKind == MccCoordPairKind::COORDS_KIND_LONLAT) { // returns geographic site coordinates
|
||||
std::pair<double, double> pos;
|
||||
cctEngine.geoPosition(&pos);
|
||||
|
||||
cpair.setX(pos.first);
|
||||
cpair.setY(pos.second);
|
||||
|
||||
return error_t{};
|
||||
}
|
||||
|
||||
if (_pairKind == MccCoordPairKind::COORDS_KIND_RADEC_ICRS &&
|
||||
PT::pairKind == MccCoordPairKind::COORDS_KIND_RADEC_ICRS) { // from ICRS to ICRS - just copy and exit
|
||||
cpair = PT(typename PT::x_t(_x), typename PT::y_t(_y));
|
||||
@@ -756,7 +891,8 @@ protected:
|
||||
// 1) convert stored coordinates to ICRS ones
|
||||
// 2) convert from the computed ICRS coordinates to required ones
|
||||
MccCoordPairKind pkind = _pairKind;
|
||||
if (!utils::isEqual(_epoch.MJD(), cpair.MJD())) { // convert stored pair to ICRS one (ra_icrs, dec_icrs)
|
||||
if (!utils::isEqual(_epoch.MJD(),
|
||||
cpair.MJD())) { // convert stored pair to ICRS one (ra_icrs, dec_icrs)
|
||||
if (_pairKind != MccCoordPairKind::COORDS_KIND_RADEC_ICRS) {
|
||||
pkind = MccCoordPairKind::COORDS_KIND_RADEC_ICRS;
|
||||
|
||||
@@ -925,7 +1061,8 @@ protected:
|
||||
cpair.setY(dec);
|
||||
} else {
|
||||
obj->hadec2azalt(ha, dec, phi, az, alt);
|
||||
if constexpr (mccIsObsCoordPairKind<PT::pairKind>) { // RADEC_OBS, HADEC_OBS, AZALT, AZZD
|
||||
if constexpr (mccIsObsCoordPairKind<PT::pairKind>) { // RADEC_OBS, HADEC_OBS,
|
||||
// AZALT, AZZD
|
||||
// correct for refraction: alt += dz_refr
|
||||
double dZ;
|
||||
ccte_err = cctEngine.refractionInverseCorrection(MCC_HALF_PI - alt, &dZ);
|
||||
@@ -978,7 +1115,8 @@ protected:
|
||||
};
|
||||
|
||||
|
||||
/* MCC-LIBRARY DEFAULT SKY POINT CLASS IMPLEMENTATION BASED ON THE ERFA LIBRARY */
|
||||
/* MCC-LIBRARY DEFAULT SKY POINT CLASS IMPLEMENTATION BASED ON THE ERFA LIBRARY
|
||||
*/
|
||||
|
||||
typedef MccGenericSkyPoint<mcc::ccte::erfa::MccCCTE_ERFA> MccSkyPoint;
|
||||
|
||||
462
include/mcc/mcc_deserializer.h
Normal file
462
include/mcc/mcc_deserializer.h
Normal file
@@ -0,0 +1,462 @@
|
||||
#pragma once
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include "mcc_coordinate.h"
|
||||
#include "mcc_epoch.h"
|
||||
#include "mcc_serialization_common.h"
|
||||
|
||||
namespace mcc::impl
|
||||
{
|
||||
|
||||
enum class MccDeserializerErrorCode : int {
|
||||
ERROR_OK,
|
||||
ERROR_UNDERLYING_DESERIALIZER,
|
||||
ERROR_INVALID_SERIALIZED_VALUE,
|
||||
ERROR_COORD_TRANSFORM
|
||||
};
|
||||
|
||||
} // namespace mcc::impl
|
||||
|
||||
|
||||
|
||||
namespace std
|
||||
{
|
||||
|
||||
template <>
|
||||
class is_error_code_enum<mcc::impl::MccDeserializerErrorCode> : public true_type
|
||||
{
|
||||
};
|
||||
|
||||
} // namespace std
|
||||
|
||||
|
||||
namespace mcc::impl
|
||||
{
|
||||
|
||||
|
||||
// error category
|
||||
struct MccDeserializerCategory : public std::error_category {
|
||||
MccDeserializerCategory() : std::error_category() {}
|
||||
|
||||
const char* name() const noexcept
|
||||
{
|
||||
return "MCC-DESERIALIZER-ERR-CATEGORY";
|
||||
}
|
||||
|
||||
std::string message(int ec) const
|
||||
{
|
||||
MccDeserializerErrorCode err = static_cast<MccDeserializerErrorCode>(ec);
|
||||
|
||||
switch (err) {
|
||||
case MccDeserializerErrorCode::ERROR_OK:
|
||||
return "OK";
|
||||
case MccDeserializerErrorCode::ERROR_UNDERLYING_DESERIALIZER:
|
||||
return "error returned by underlying deserializer";
|
||||
case MccDeserializerErrorCode::ERROR_INVALID_SERIALIZED_VALUE:
|
||||
return "invalid serialized value";
|
||||
case MccDeserializerErrorCode::ERROR_COORD_TRANSFORM:
|
||||
return "coordinates transformation error";
|
||||
default:
|
||||
return "UNKNOWN";
|
||||
}
|
||||
}
|
||||
|
||||
static const MccDeserializerCategory& get()
|
||||
{
|
||||
static const MccDeserializerCategory constInst;
|
||||
return constInst;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
inline std::error_code make_error_code(MccDeserializerErrorCode ec)
|
||||
{
|
||||
return std::error_code(static_cast<int>(ec), MccDeserializerCategory::get());
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* BASE DESERIALIZER CLASS (FOR IMPLEMENTATIONS BELOW) */
|
||||
|
||||
struct MccDeserializerBase : mcc_deserializer_interface_t<MccError> {
|
||||
using typename mcc_deserializer_interface_t<MccError>::error_t;
|
||||
|
||||
virtual ~MccDeserializerBase() = default;
|
||||
|
||||
|
||||
protected:
|
||||
MccDeserializerBase() = default;
|
||||
|
||||
//
|
||||
// empty == true, if the 'input' is empty or if all elements consist of only spaces
|
||||
//
|
||||
static std::vector<std::string_view> splitValueIntoElements(traits::mcc_input_char_range auto const& input,
|
||||
mcc_serialization_params_c auto const& params,
|
||||
bool& empty)
|
||||
{
|
||||
static_assert(std::ranges::contiguous_range<decltype(input)>, "NOT IMPLEMENTED FOR NON-CONTIGUIUS RANGES!!!");
|
||||
|
||||
std::vector<std::string_view> res;
|
||||
|
||||
if (std::ranges::size(input)) {
|
||||
empty = true;
|
||||
|
||||
std::ranges::for_each(std::views::split(input, params.elem_delim), [&res, &empty](auto const& el) {
|
||||
std::back_inserter(res) = utils::trimSpaces(std::string_view{el.begin(), el.end()});
|
||||
if (empty && res.back().size()) {
|
||||
empty = false;
|
||||
}
|
||||
});
|
||||
} else {
|
||||
empty = true;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
template <typename VT, std::ranges::output_range<VT> R, typename... DeserParamsT>
|
||||
static error_t deserializingRange(mcc_deserializer_c auto& dsr,
|
||||
traits::mcc_input_char_range auto const& input,
|
||||
R& r,
|
||||
mcc_serialization_params_c auto const& params)
|
||||
{
|
||||
if (std::ranges::size(input) == 0) { // ignore an empty input, just return empty range?!!
|
||||
r = R{};
|
||||
return MccDeserializerErrorCode::ERROR_OK;
|
||||
}
|
||||
|
||||
auto r_str = std::views::split(input, params.seq_delim);
|
||||
VT val;
|
||||
|
||||
auto it = r.begin();
|
||||
for (auto const& el : r_str) {
|
||||
auto err = dsr(el, val, std::forward<DeserParamsT>(params)...);
|
||||
if (err) {
|
||||
return mcc_deduced_err(err, MccDeserializerErrorCode::ERROR_UNDERLYING_DESERIALIZER);
|
||||
}
|
||||
|
||||
if (it == r.end()) {
|
||||
std::back_inserter(r) = val;
|
||||
it = r.end();
|
||||
} else {
|
||||
*it = val;
|
||||
++it;
|
||||
}
|
||||
}
|
||||
|
||||
return MccDeserializerErrorCode::ERROR_OK;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/* MAIN (FALLBACK) TEMPLATED IMPLEMENTATION */
|
||||
|
||||
|
||||
template <typename VT>
|
||||
struct MccDeserializer : MccDeserializerBase {
|
||||
static constexpr std::string_view deserializerName{"MCC-FALLBACK-DESERIALIZER"};
|
||||
|
||||
virtual ~MccDeserializer() = default;
|
||||
|
||||
|
||||
template <mcc_serialization_params_c ParamsT = mcc_serialization_params_t>
|
||||
error_t operator()(traits::mcc_input_char_range auto const& input,
|
||||
VT& value,
|
||||
ParamsT const& params = mcc_serialization_params_t{})
|
||||
{
|
||||
if constexpr (std::is_arithmetic_v<VT>) {
|
||||
auto v = mcc::utils::numFromStr<VT>(utils::trimSpaces(input));
|
||||
if (!v.has_value()) {
|
||||
return MccDeserializerErrorCode::ERROR_INVALID_SERIALIZED_VALUE;
|
||||
}
|
||||
|
||||
value = v.value();
|
||||
} else if constexpr (mcc::traits::mcc_output_char_range<VT>) {
|
||||
VT r;
|
||||
if constexpr (traits::mcc_array_c<VT>) {
|
||||
size_t N =
|
||||
std::ranges::size(r) <= std::ranges::size(input) ? std::ranges::size(r) : std::ranges::size(input);
|
||||
|
||||
for (size_t i = 0; i < N; ++i) {
|
||||
r[i] = input[i];
|
||||
}
|
||||
if (std::ranges::size(r) > N) {
|
||||
for (size_t i = N; i < std::ranges::size(r); ++i) {
|
||||
r[i] = '\0';
|
||||
}
|
||||
}
|
||||
} else {
|
||||
std::ranges::copy(input, std::back_inserter(r));
|
||||
}
|
||||
|
||||
value = r;
|
||||
} else if constexpr (std::ranges::range<VT>) {
|
||||
using el_t = std::ranges::range_value_t<VT>;
|
||||
|
||||
static_assert(std::ranges::output_range<VT, el_t>, "INVALID RANGE TYPE!!!");
|
||||
|
||||
// no reference or constants allowed
|
||||
static_assert(!(std::is_reference_v<el_t> || std::is_const_v<el_t>), "INVALID RANGE ELEMENT TYPE!!!");
|
||||
|
||||
MccDeserializer<el_t> dsr;
|
||||
return deserializingRange<el_t>(dsr, input, value, params);
|
||||
} else if constexpr (traits::mcc_time_duration_c<VT>) {
|
||||
typename VT::rep vd;
|
||||
|
||||
MccDeserializer<typename VT::rep> dsr;
|
||||
|
||||
auto err = dsr(utils::trimSpaces(input), vd, params);
|
||||
if (err) {
|
||||
return mcc_deduced_err(err, MccDeserializerErrorCode::ERROR_UNDERLYING_DESERIALIZER);
|
||||
}
|
||||
|
||||
value = VT{vd};
|
||||
} else {
|
||||
static_assert(false, "UNSUPPORTED VALUE TYPE!!!");
|
||||
}
|
||||
|
||||
|
||||
return MccDeserializerErrorCode::ERROR_OK;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/* SPECIALIZATION FOR THE SOME CONCEPTS */
|
||||
|
||||
template <mcc_coord_epoch_c VT>
|
||||
struct MccDeserializer<VT> : MccDeserializerBase {
|
||||
static constexpr std::string_view deserializerName{"MCC-COORD-EPOCH-DESERIALIZER"};
|
||||
|
||||
template <mcc_serialization_params_c ParamsT = mcc_serialization_params_t>
|
||||
error_t operator()(traits::mcc_input_char_range auto const& input,
|
||||
VT& value,
|
||||
ParamsT const& params = mcc_serialization_params_t{})
|
||||
{
|
||||
bool ok = value.fromCharRange(input);
|
||||
if (!ok) {
|
||||
return MccDeserializerErrorCode::ERROR_INVALID_SERIALIZED_VALUE;
|
||||
}
|
||||
|
||||
return MccDeserializerErrorCode::ERROR_OK;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
template <typename VT>
|
||||
requires(!std::is_arithmetic_v<VT> && mcc_angle_c<VT>)
|
||||
struct MccDeserializer<VT> : MccDeserializerBase {
|
||||
static constexpr std::string_view deserializerName{"MCC-ANGLE-DESERIALIZER"};
|
||||
|
||||
template <mcc_serialization_params_c ParamsT = mcc_serialization_params_t>
|
||||
error_t operator()(traits::mcc_input_char_range auto const& input,
|
||||
VT& value,
|
||||
ParamsT const& params = mcc_serialization_params_t{})
|
||||
{
|
||||
bool hms = params.angle_format == MccSerializedAngleFormat::MCC_SERIALIZED_FORMAT_SXGM_HOURS;
|
||||
|
||||
auto res = utils::parsAngleString(input, hms);
|
||||
if (res) { // returned angle is in degrees!!!
|
||||
value = res.value() * MCC_DEGRESS_TO_RADS;
|
||||
} else {
|
||||
return MccDeserializerErrorCode::ERROR_INVALID_SERIALIZED_VALUE;
|
||||
}
|
||||
|
||||
return MccDeserializerErrorCode::ERROR_OK;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template <mcc_skypoint_c VT>
|
||||
struct MccDeserializer<VT> : MccDeserializerBase {
|
||||
static constexpr std::string_view deserializerName{"MCC-SKYPOINT-DESERIALIZER"};
|
||||
|
||||
template <mcc_serialization_params_c ParamsT = mcc_serialization_params_t>
|
||||
error_t operator()(traits::mcc_input_char_range auto const& input,
|
||||
VT& value,
|
||||
ParamsT const& params = mcc_serialization_params_t{})
|
||||
{
|
||||
auto pars = params;
|
||||
|
||||
// valid format: X<elem-delim>Y[<elem-delim>TIME-POINT<elem-delim>PAIR-KIND]
|
||||
// X<elem-delim>Y (assumed RADEC_ICRS and J2000.0 epoch)
|
||||
|
||||
// valid format: X<elem-delim>Y<elem-delim>PAIRKIND<elem-delim>EPOCH
|
||||
// X<elem-delim>Y<elem-delim>PAIRKIND (assumed epoch is NOW, or J2000.0 if PAIRKIND == RADEC-ICRS)
|
||||
// X<elem-delim>Y (assumed RADEC-ICRS and J2000.0 epoch)
|
||||
|
||||
bool empty;
|
||||
|
||||
auto elems = MccDeserializerBase::splitValueIntoElements(input, params, empty);
|
||||
|
||||
if (empty || (elems.size() < 2)) {
|
||||
return MccDeserializerErrorCode::ERROR_INVALID_SERIALIZED_VALUE;
|
||||
}
|
||||
|
||||
MccCoordPairKind pair_kind{MccCoordPairKind::COORDS_KIND_RADEC_ICRS};
|
||||
MccCelestialCoordEpoch epoch; // J2000.0
|
||||
|
||||
MccAngle x, y;
|
||||
MccDeserializer<MccAngle> dsr_ang;
|
||||
|
||||
typename MccDeserializer<MccAngle>::error_t dsr_err;
|
||||
|
||||
if (elems.size() > 2) { // no epoch
|
||||
// deserialize pair kind string
|
||||
pair_kind = MccCoordStrToPairKind(elems[2]);
|
||||
if (pair_kind == MccCoordPairKind::COORDS_KIND_UNKNOWN) {
|
||||
return MccDeserializerErrorCode::ERROR_INVALID_SERIALIZED_VALUE;
|
||||
}
|
||||
|
||||
if (pair_kind != MccCoordPairKind::COORDS_KIND_RADEC_ICRS) {
|
||||
epoch = MccCelestialCoordEpoch::now();
|
||||
}
|
||||
}
|
||||
|
||||
if (elems.size() > 3) { // full format
|
||||
// epoch
|
||||
if (pair_kind != MccCoordPairKind::COORDS_KIND_RADEC_ICRS) { // ignore epoch if PAIRKIND == RADEC-ICRS
|
||||
bool ok = epoch.fromCharRange(elems[3]);
|
||||
if (!ok) {
|
||||
return MccDeserializerErrorCode::ERROR_INVALID_SERIALIZED_VALUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// deserialize X and Y
|
||||
if (params.coordpair_format == MccSerializedCoordPairFormat::MCC_SERIALIZED_FORMAT_SXGM_HOURDEG) {
|
||||
pars.angle_format = MccSerializedAngleFormat::MCC_SERIALIZED_FORMAT_SXGM_HOURS;
|
||||
} else {
|
||||
pars.angle_format = MccSerializedAngleFormat::MCC_SERIALIZED_FORMAT_SXGM_DEGS;
|
||||
}
|
||||
|
||||
dsr_err = dsr_ang(elems[0], x, pars);
|
||||
if (dsr_err) {
|
||||
return mcc_deduced_err(dsr_err, MccDeserializerErrorCode::ERROR_UNDERLYING_DESERIALIZER);
|
||||
}
|
||||
|
||||
pars.angle_format = MccSerializedAngleFormat::MCC_SERIALIZED_FORMAT_SXGM_DEGS;
|
||||
dsr_err = dsr_ang(elems[1], y, pars);
|
||||
if (dsr_err) {
|
||||
return mcc_deduced_err(dsr_err, MccDeserializerErrorCode::ERROR_UNDERLYING_DESERIALIZER);
|
||||
}
|
||||
|
||||
switch (pair_kind) {
|
||||
case MccCoordPairKind::COORDS_KIND_RADEC_ICRS:
|
||||
value.from(MccSkyRADEC_ICRS{(double)x, (double)y});
|
||||
break;
|
||||
case MccCoordPairKind::COORDS_KIND_RADEC_OBS:
|
||||
value.from(MccSkyRADEC_OBS{(double)x, (double)y, epoch});
|
||||
break;
|
||||
case MccCoordPairKind::COORDS_KIND_RADEC_APP:
|
||||
value.from(MccSkyRADEC_APP{(double)x, (double)y, epoch});
|
||||
break;
|
||||
case MccCoordPairKind::COORDS_KIND_HADEC_OBS:
|
||||
value.from(MccSkyHADEC_OBS{(double)x, (double)y, epoch});
|
||||
break;
|
||||
case MccCoordPairKind::COORDS_KIND_HADEC_APP:
|
||||
value.from(MccSkyHADEC_APP{(double)x, (double)y, epoch});
|
||||
break;
|
||||
case MccCoordPairKind::COORDS_KIND_AZZD:
|
||||
value.from(MccSkyAZZD{(double)x, (double)y, epoch});
|
||||
break;
|
||||
case MccCoordPairKind::COORDS_KIND_AZALT:
|
||||
value.from(MccSkyAZALT{(double)x, (double)y, epoch});
|
||||
break;
|
||||
case MccCoordPairKind::COORDS_KIND_XY:
|
||||
value.from(MccGenXY{(double)x, (double)y, epoch});
|
||||
break;
|
||||
case MccCoordPairKind::COORDS_KIND_GENERIC:
|
||||
value.from(MccCoordPair{(double)x, (double)y, epoch});
|
||||
break;
|
||||
case MccCoordPairKind::COORDS_KIND_LONLAT:
|
||||
value.from(MccGeoLONLAT{(double)x, (double)y});
|
||||
break;
|
||||
default:
|
||||
return MccDeserializerErrorCode::ERROR_INVALID_SERIALIZED_VALUE;
|
||||
}
|
||||
|
||||
return MccDeserializerErrorCode::ERROR_OK;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template <>
|
||||
struct MccDeserializer<MccCoordPairKind> : MccDeserializerBase {
|
||||
static constexpr std::string_view deserializerName{"MCC-COORDPAIR-DESERIALIZER"};
|
||||
|
||||
template <mcc_serialization_params_c ParamsT = mcc_serialization_params_t>
|
||||
error_t operator()(traits::mcc_input_char_range auto const& input,
|
||||
MccCoordPairKind& value,
|
||||
ParamsT const& params = mcc_serialization_params_t{})
|
||||
{
|
||||
value = MccCoordStrToPairKind(input);
|
||||
|
||||
if (value == MccCoordPairKind::COORDS_KIND_UNKNOWN) {
|
||||
return MccDeserializerErrorCode::ERROR_INVALID_SERIALIZED_VALUE;
|
||||
}
|
||||
|
||||
return MccDeserializerErrorCode::ERROR_OK;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template <>
|
||||
struct MccDeserializer<MccSerializedAngleFormatPrec> : MccDeserializerBase {
|
||||
static constexpr std::string_view deserializerName{"MCC-ANGLE-FORMAT-PREC-DESERIALIZER"};
|
||||
|
||||
template <mcc_serialization_params_c ParamsT = mcc_serialization_params_t>
|
||||
error_t operator()(traits::mcc_input_char_range auto const& input,
|
||||
MccSerializedAngleFormatPrec& value,
|
||||
ParamsT const& params = mcc_serialization_params_t{})
|
||||
{
|
||||
// valid format: hour_prec[<params.elem_delim>deg_prec<params.elem_delim>decimals]
|
||||
|
||||
std::vector<uint8_t> v;
|
||||
|
||||
auto err = MccDeserializer<decltype(v)>{}(input, v);
|
||||
if (err) {
|
||||
return MccDeserializerErrorCode::ERROR_UNDERLYING_DESERIALIZER;
|
||||
}
|
||||
|
||||
if (v.size() > 0) {
|
||||
value.hour_prec = v[0];
|
||||
}
|
||||
|
||||
if (v.size() > 1) {
|
||||
value.deg_prec = v[1];
|
||||
}
|
||||
|
||||
if (v.size() > 2) {
|
||||
value.decimals = v[2];
|
||||
}
|
||||
|
||||
return MccDeserializerErrorCode::ERROR_OK;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
template <>
|
||||
struct MccDeserializer<MccSerializedCoordPairFormat> : MccDeserializerBase {
|
||||
static constexpr std::string_view deserializerName{"MCC-COORDPAIR-FORMAT-DESERIALIZER"};
|
||||
|
||||
template <mcc_serialization_params_c ParamsT = mcc_serialization_params_t>
|
||||
error_t operator()(traits::mcc_input_char_range auto const& input,
|
||||
MccSerializedCoordPairFormat& value,
|
||||
ParamsT const& params = mcc_serialization_params_t{})
|
||||
{
|
||||
value = MccSerializedCoordPairFormatStrToValue(input);
|
||||
|
||||
if (value != MccSerializedCoordPairFormat::MCC_SERIALIZED_FORMAT_UNKNOWN) {
|
||||
return MccDeserializerErrorCode::ERROR_OK;
|
||||
} else {
|
||||
return MccDeserializerErrorCode::ERROR_INVALID_SERIALIZED_VALUE;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace mcc::impl
|
||||
@@ -198,7 +198,7 @@ public:
|
||||
error_t operator()(traits::mcc_input_char_range auto const& input, VT& value)
|
||||
{
|
||||
if constexpr (std::is_arithmetic_v<VT>) {
|
||||
auto v = mcc::utils::numFromStr<VT>(trimSpaces(input));
|
||||
auto v = mcc::utils::numFromStr<VT>(utils::trimSpaces(input));
|
||||
if (!v.has_value()) {
|
||||
return MccDeserializerErrorCode::ERROR_INVALID_SERIALIZED_VALUE;
|
||||
}
|
||||
@@ -302,8 +302,8 @@ public:
|
||||
{
|
||||
if constexpr (mcc_angle_c<VT>) { // scalar
|
||||
auto res = utils::parsAngleString(input, hms);
|
||||
if (res) {
|
||||
value = res.value();
|
||||
if (res) { // returned angle is in degrees!!!
|
||||
value = res.value() * MCC_DEGRESS_TO_RADS;
|
||||
} else {
|
||||
return MccDeserializerErrorCode::ERROR_INVALID_SERIALIZED_VALUE;
|
||||
}
|
||||
@@ -53,7 +53,7 @@ struct std::formatter<mcc::impl::MccError, char> {
|
||||
// _currFmt.push_back(*(++it));
|
||||
// }
|
||||
|
||||
if (it++ != ctx.end() || it++ != '}') {
|
||||
if (it++ != ctx.end() || *(it++) != '}') {
|
||||
_delim = *(++it);
|
||||
}
|
||||
case '}':
|
||||
268
include/mcc/mcc_generic_mount.h
Normal file
268
include/mcc/mcc_generic_mount.h
Normal file
@@ -0,0 +1,268 @@
|
||||
#pragma once
|
||||
|
||||
|
||||
/****************************************************************************************
|
||||
* *
|
||||
* MOUNT CONTROL COMPONENTS LIBRARY *
|
||||
* *
|
||||
* *
|
||||
* IMPLEMENTATION OF A GENERIC MOUNT CLASS *
|
||||
* (A SOME OF POSSIBLE GENERIC IMPLEMENTATIONS) *
|
||||
* *
|
||||
****************************************************************************************/
|
||||
|
||||
|
||||
|
||||
#include <thread>
|
||||
#include "mcc/mcc_spdlog.h"
|
||||
#include "mcc_error.h"
|
||||
|
||||
namespace mcc::impl
|
||||
{
|
||||
|
||||
enum class MccGenericMountErrorCode : int {
|
||||
ERROR_OK,
|
||||
ERROR_HW_INIT,
|
||||
ERROR_HW_STOP,
|
||||
ERROR_HW_GETSTATE,
|
||||
ERROR_SET_TARGET,
|
||||
ERROR_MOUNT_SLEW,
|
||||
ERROR_MOUNT_TRACK,
|
||||
ERROR_GET_TELEMETRY,
|
||||
ERROR_UNSUPPORTED_TARGET_COORDPAIR,
|
||||
ERROR_PZONE_COMP,
|
||||
ERROR_TARGET_IN_ZONE
|
||||
};
|
||||
|
||||
} // namespace mcc::impl
|
||||
|
||||
|
||||
namespace std
|
||||
{
|
||||
|
||||
template <>
|
||||
class is_error_code_enum<mcc::impl::MccGenericMountErrorCode> : public true_type
|
||||
{
|
||||
};
|
||||
|
||||
} // namespace std
|
||||
|
||||
|
||||
|
||||
namespace mcc::impl
|
||||
{
|
||||
|
||||
// error category
|
||||
struct MccGenericMountCategory : public std::error_category {
|
||||
MccGenericMountCategory() : std::error_category() {}
|
||||
|
||||
const char* name() const noexcept
|
||||
{
|
||||
return "MCC-GENERIC-MOUNT";
|
||||
}
|
||||
|
||||
std::string message(int ec) const
|
||||
{
|
||||
MccGenericMountErrorCode err = static_cast<MccGenericMountErrorCode>(ec);
|
||||
|
||||
switch (err) {
|
||||
case MccGenericMountErrorCode::ERROR_OK:
|
||||
return "OK";
|
||||
case MccGenericMountErrorCode::ERROR_HW_INIT:
|
||||
return "an error occured while initializing mount hardware";
|
||||
case MccGenericMountErrorCode::ERROR_HW_STOP:
|
||||
return "an error occured while stopping mount";
|
||||
case MccGenericMountErrorCode::ERROR_HW_GETSTATE:
|
||||
return "cannot get state of hardware";
|
||||
case MccGenericMountErrorCode::ERROR_SET_TARGET:
|
||||
return "cannot set target coordinates";
|
||||
case MccGenericMountErrorCode::ERROR_MOUNT_SLEW:
|
||||
return "slewing error";
|
||||
case MccGenericMountErrorCode::ERROR_MOUNT_TRACK:
|
||||
return "tracking error";
|
||||
case MccGenericMountErrorCode::ERROR_GET_TELEMETRY:
|
||||
return "cannot get telemetry data";
|
||||
case MccGenericMountErrorCode::ERROR_UNSUPPORTED_TARGET_COORDPAIR:
|
||||
return "unsupported coordinate pair of target";
|
||||
case MccGenericMountErrorCode::ERROR_PZONE_COMP:
|
||||
return "an error occured while computing prohibited zone";
|
||||
case MccGenericMountErrorCode::ERROR_TARGET_IN_ZONE:
|
||||
return "target coordinates are in prohibitted zone";
|
||||
default:
|
||||
return "UNKNOWN";
|
||||
}
|
||||
}
|
||||
|
||||
static const MccGenericMountCategory& get()
|
||||
{
|
||||
static const MccGenericMountCategory constInst;
|
||||
return constInst;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
inline std::error_code make_error_code(MccGenericMountErrorCode ec)
|
||||
{
|
||||
return std::error_code(static_cast<int>(ec), MccGenericMountCategory::get());
|
||||
}
|
||||
|
||||
|
||||
|
||||
template <mcc_telemetry_c TELEMETRY_T,
|
||||
mcc_pzone_container_c PZONE_CONT_T,
|
||||
mcc_movement_controls_c MOVE_CNTRL_T,
|
||||
mcc_logger_c LOGGER_T = utils::MccSpdlogLogger>
|
||||
class MccGenericMount : public TELEMETRY_T, public PZONE_CONT_T, public MOVE_CNTRL_T, public LOGGER_T
|
||||
{
|
||||
public:
|
||||
using LOGGER_T::logDebug;
|
||||
using LOGGER_T::logError;
|
||||
using LOGGER_T::logInfo;
|
||||
using LOGGER_T::logTrace;
|
||||
using LOGGER_T::logWarn;
|
||||
|
||||
typedef MccError error_t;
|
||||
|
||||
using typename TELEMETRY_T::telemetry_data_t;
|
||||
|
||||
enum class mount_status_t : int {
|
||||
MOUNT_STATUS_ERROR,
|
||||
MOUNT_STATUS_IDLE,
|
||||
MOUNT_STATUS_UNINITIALIZED,
|
||||
MOUNT_STATUS_INITIALIZATION,
|
||||
MOUNT_STATUS_STOPPED,
|
||||
MOUNT_STATUS_STOPPING,
|
||||
MOUNT_STATUS_SLEWING,
|
||||
MOUNT_STATUS_ADJUSTING,
|
||||
MOUNT_STATUS_GUIDING,
|
||||
MOUNT_STATUS_TRACKING
|
||||
};
|
||||
|
||||
template <typename... TelemetryCtorTs,
|
||||
typename... PzoneContCtorTs,
|
||||
typename... MoveCntrCtorTs,
|
||||
typename... LoggerCtorTs>
|
||||
MccGenericMount(std::tuple<TelemetryCtorTs...> telemetry_ctor_args,
|
||||
std::tuple<PzoneContCtorTs...> pzone_cont_ctor_ars,
|
||||
std::tuple<MoveCntrCtorTs...> move_cntrl_ctor_ars,
|
||||
std::tuple<LoggerCtorTs...> logger_ctor_args)
|
||||
: TELEMETRY_T(std::make_from_tuple<TELEMETRY_T>(std::move(telemetry_ctor_args))),
|
||||
PZONE_CONT_T(std::make_from_tuple<PZONE_CONT_T>(std::move(pzone_cont_ctor_ars))),
|
||||
MOVE_CNTRL_T(std::make_from_tuple<MOVE_CNTRL_T>(std::move(move_cntrl_ctor_ars))),
|
||||
LOGGER_T(std::make_from_tuple<LOGGER_T>(std::move(logger_ctor_args)))
|
||||
{
|
||||
// logDebug(std::format("Create MccGenericMount class instance (thread: {})", std::this_thread::get_id()));
|
||||
logDebug("Create MccGenericMount class instance (thread: {})", std::this_thread::get_id());
|
||||
}
|
||||
|
||||
template <typename... TelemetryCtorTs,
|
||||
typename... PzoneContCtorTs,
|
||||
typename... MoveCntrCtorTs,
|
||||
typename... LoggerCtorTs>
|
||||
requires std::derived_from<LOGGER_T, utils::MccSpdlogLogger>
|
||||
MccGenericMount(std::tuple<TelemetryCtorTs...> telemetry_ctor_args,
|
||||
std::tuple<PzoneContCtorTs...> pzone_cont_ctor_ars,
|
||||
std::tuple<MoveCntrCtorTs...> move_cntrl_ctor_ars,
|
||||
LoggerCtorTs... logger_ctor_args)
|
||||
: TELEMETRY_T(std::make_from_tuple<TELEMETRY_T>(std::move(telemetry_ctor_args))),
|
||||
PZONE_CONT_T(std::make_from_tuple<PZONE_CONT_T>(pzone_cont_ctor_ars)),
|
||||
MOVE_CNTRL_T(std::make_from_tuple<MOVE_CNTRL_T>(move_cntrl_ctor_ars)),
|
||||
mcc::utils::MccSpdlogLogger(logger_ctor_args...)
|
||||
{
|
||||
// logDebug(std::format("Create MccGenericMount class instance (thread: {})", std::this_thread::get_id()));
|
||||
logDebug("Create MccGenericMount class instance (thread: {})", std::this_thread::get_id());
|
||||
}
|
||||
|
||||
/* movable-only class */
|
||||
|
||||
MccGenericMount(const MccGenericMount&) = delete;
|
||||
MccGenericMount(MccGenericMount&&) = default;
|
||||
|
||||
MccGenericMount& operator=(const MccGenericMount&) = delete;
|
||||
MccGenericMount& operator=(MccGenericMount&&) = default;
|
||||
|
||||
virtual ~MccGenericMount()
|
||||
{
|
||||
// auto err = MOVE_CNTRL_T::stopMount();
|
||||
// if (err) {
|
||||
// logError(formatError(err));
|
||||
// }
|
||||
|
||||
// WARNING: it is assumed here that mount stopping is performed in a derived class or, it is more logicaly,
|
||||
// in MOVE_CNTRL_T-class
|
||||
|
||||
// logDebug(std::format("Delete MccGenericMount class instance (thread: {})", std::this_thread::get_id()));
|
||||
logDebug("Delete MccGenericMount class instance (thread: {})", std::this_thread::get_id());
|
||||
}
|
||||
|
||||
error_t initMount()
|
||||
{
|
||||
logInfo("Start MccGenericMount class initialization (thread: {}) ...", std::this_thread::get_id());
|
||||
|
||||
*_mountStatus = mount_status_t::MOUNT_STATUS_IDLE;
|
||||
|
||||
return *_lastMountError = MccGenericMountErrorCode::ERROR_OK;
|
||||
}
|
||||
|
||||
mount_status_t mountStatus() const
|
||||
{
|
||||
return _mountStatus->load();
|
||||
}
|
||||
|
||||
error_t mountLastError() const
|
||||
{
|
||||
return _lastMountError->load();
|
||||
}
|
||||
|
||||
|
||||
/* log-method wrappers for non-MccSpdlogger classes */
|
||||
|
||||
template <std::formattable<char>... ArgTs>
|
||||
requires(!std::derived_from<LOGGER_T, utils::MccSpdlogLogger>)
|
||||
void logInfo(std::format_string<ArgTs...> fmt, ArgTs&&... args)
|
||||
{
|
||||
LOGGER_T::logInfo(std::format(fmt, std::forward<ArgTs>(args)...));
|
||||
}
|
||||
|
||||
template <std::formattable<char>... ArgTs>
|
||||
requires(!std::derived_from<LOGGER_T, utils::MccSpdlogLogger>)
|
||||
void logDebug(std::format_string<ArgTs...> fmt, ArgTs&&... args)
|
||||
{
|
||||
LOGGER_T::logDebug(std::format(fmt, std::forward<ArgTs>(args)...));
|
||||
}
|
||||
|
||||
template <std::formattable<char>... ArgTs>
|
||||
requires(!std::derived_from<LOGGER_T, utils::MccSpdlogLogger>)
|
||||
void logError(std::format_string<ArgTs...> fmt, ArgTs&&... args)
|
||||
{
|
||||
LOGGER_T::logError(std::format(fmt, std::forward<ArgTs>(args)...));
|
||||
}
|
||||
|
||||
template <std::formattable<char>... ArgTs>
|
||||
requires(!std::derived_from<LOGGER_T, utils::MccSpdlogLogger>)
|
||||
void logWarn(std::format_string<ArgTs...> fmt, ArgTs&&... args)
|
||||
{
|
||||
LOGGER_T::logWarn(std::format(fmt, std::forward<ArgTs>(args)...));
|
||||
}
|
||||
|
||||
template <std::formattable<char>... ArgTs>
|
||||
requires(!std::derived_from<LOGGER_T, utils::MccSpdlogLogger>)
|
||||
void logTrace(std::format_string<ArgTs...> fmt, ArgTs&&... args)
|
||||
{
|
||||
LOGGER_T::logTrace(std::format(fmt, std::forward<ArgTs>(args)...));
|
||||
}
|
||||
|
||||
|
||||
protected:
|
||||
std::unique_ptr<std::atomic<mount_status_t>> _mountStatus{
|
||||
new std::atomic<mount_status_t>{mount_status_t::MOUNT_STATUS_UNINITIALIZED}};
|
||||
|
||||
std::unique_ptr<std::atomic<error_t>> _lastMountError{new std::atomic<error_t>{MccGenericMountErrorCode::ERROR_OK}};
|
||||
|
||||
std::string formatError(error_t const& err, std::string_view prefix = "") const
|
||||
{
|
||||
return std::format("{}{} (category: {}, code: {})", prefix, err.message(), err.category().name(), err.value());
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace mcc::impl
|
||||
715
include/mcc/mcc_generic_movecontrols.h
Normal file
715
include/mcc/mcc_generic_movecontrols.h
Normal file
@@ -0,0 +1,715 @@
|
||||
#pragma once
|
||||
|
||||
/****************************************************************************************
|
||||
* *
|
||||
* MOUNT CONTROL COMPONENTS LIBRARY *
|
||||
* *
|
||||
* *
|
||||
* GENERIC IMPLEMENTATION OF MOUNT MOVEMENT CONTROLS *
|
||||
* *
|
||||
****************************************************************************************/
|
||||
|
||||
|
||||
|
||||
#include <atomic>
|
||||
#include <fstream>
|
||||
#include <future>
|
||||
#include <thread>
|
||||
#include <type_traits>
|
||||
|
||||
|
||||
#include <print>
|
||||
|
||||
#include "mcc_coordinate.h"
|
||||
#include "mcc_error.h"
|
||||
|
||||
namespace mcc::impl
|
||||
{
|
||||
|
||||
// mount movement-related generic errors
|
||||
enum class MccGenericMovementControlsErrorCode : int {
|
||||
ERROR_OK,
|
||||
ERROR_IN_PZONE,
|
||||
ERROR_NEAR_PZONE,
|
||||
ERROR_SLEW_TIMEOUT,
|
||||
ERROR_STOP_TIMEOUT,
|
||||
ERROR_HARDWARE,
|
||||
ERROR_TELEMETRY_TIMEOUT
|
||||
};
|
||||
} // namespace mcc::impl
|
||||
|
||||
namespace std
|
||||
{
|
||||
template <>
|
||||
class is_error_code_enum<mcc::impl::MccGenericMovementControlsErrorCode> : public true_type
|
||||
{
|
||||
};
|
||||
} // namespace std
|
||||
|
||||
namespace mcc::impl
|
||||
{
|
||||
|
||||
// error category
|
||||
struct MccGenericMovementControlsErrorCategory : std::error_category {
|
||||
const char* name() const noexcept
|
||||
{
|
||||
return "MCC-GENERIC-MOVECONTRL";
|
||||
}
|
||||
|
||||
std::string message(int ec) const
|
||||
{
|
||||
MccGenericMovementControlsErrorCode err = static_cast<MccGenericMovementControlsErrorCode>(ec);
|
||||
|
||||
switch (err) {
|
||||
case MccGenericMovementControlsErrorCode::ERROR_OK:
|
||||
return "OK";
|
||||
case MccGenericMovementControlsErrorCode::ERROR_IN_PZONE:
|
||||
return "target is in zone";
|
||||
case MccGenericMovementControlsErrorCode::ERROR_NEAR_PZONE:
|
||||
return "mount is near zone";
|
||||
case MccGenericMovementControlsErrorCode::ERROR_SLEW_TIMEOUT:
|
||||
return "a timeout occured while slewing";
|
||||
case MccGenericMovementControlsErrorCode::ERROR_STOP_TIMEOUT:
|
||||
return "a timeout occured while mount stopping";
|
||||
case MccGenericMovementControlsErrorCode::ERROR_HARDWARE:
|
||||
return "a hardware error occured";
|
||||
case MccGenericMovementControlsErrorCode::ERROR_TELEMETRY_TIMEOUT:
|
||||
return "telemetry data timeout";
|
||||
default:
|
||||
return "unknown";
|
||||
}
|
||||
}
|
||||
|
||||
static const MccGenericMovementControlsErrorCategory& get()
|
||||
{
|
||||
static const MccGenericMovementControlsErrorCategory constInst;
|
||||
return constInst;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
inline std::error_code make_error_code(MccGenericMovementControlsErrorCode ec)
|
||||
{
|
||||
return std::error_code(static_cast<int>(ec), MccGenericMovementControlsErrorCategory::get());
|
||||
}
|
||||
|
||||
|
||||
struct MccGenericMovementControlsParams {
|
||||
// timeout to telemetry updating
|
||||
std::chrono::milliseconds telemetryTimeout{3000};
|
||||
|
||||
// braking acceleration after execution of mount stopping command (in rads/s^2)
|
||||
// it must be given as non-negative value!!!
|
||||
double brakingAccelX{0.0};
|
||||
double brakingAccelY{0.0};
|
||||
|
||||
// ******* slewing mode *******
|
||||
|
||||
// coordinates difference to stop slewing (in radians)
|
||||
double slewToleranceRadius{5.0_arcsecs};
|
||||
|
||||
// slewing trajectory file. if empty - just skip saving
|
||||
std::string slewingPathFilename{};
|
||||
|
||||
|
||||
// ******* tracking mode *******
|
||||
|
||||
// maximal target-to-mount difference for tracking process (in arcsecs)
|
||||
// it it is greater then the current mount coordinates are used as target one
|
||||
double trackingMaxCoordDiff{20.0};
|
||||
|
||||
// tracking trajectory file. if empty - just skip saving
|
||||
std::string trackingPathFilename{};
|
||||
};
|
||||
|
||||
|
||||
/* UTILITY CLASS TO HOLD AND SAVE MOUNT MOVING TRAJECTORY */
|
||||
|
||||
struct MccMovementPathFile {
|
||||
static constexpr std::string_view commentSeq{"# "};
|
||||
static constexpr std::string_view lineDelim{"\n"};
|
||||
|
||||
void setCommentSeq(traits::mcc_input_char_range auto const& s)
|
||||
{
|
||||
_commentSeq.clear();
|
||||
std::ranges::copy(s, std::back_inserter(_commentSeq));
|
||||
}
|
||||
|
||||
void setLineDelim(traits::mcc_input_char_range auto const& s)
|
||||
{
|
||||
_lineDelim.clear();
|
||||
std::ranges::copy(s, std::back_inserter(_lineDelim));
|
||||
}
|
||||
|
||||
// add comment string/strings
|
||||
template <traits::mcc_input_char_range RT, traits::mcc_input_char_range... RTs>
|
||||
void addComment(RT const& r, RTs const&... rs)
|
||||
{
|
||||
std::ranges::copy(_commentSeq, std::back_inserter(_buffer));
|
||||
if constexpr (std::is_pointer_v<std::decay_t<RT>>) { // const char*, char*, char[]
|
||||
std::ranges::copy(std::string_view{r}, std::back_inserter(_buffer));
|
||||
} else {
|
||||
std::ranges::copy(r, std::back_inserter(_buffer));
|
||||
}
|
||||
std::ranges::copy(lineDelim, std::back_inserter(_buffer));
|
||||
|
||||
if constexpr (sizeof...(RTs)) {
|
||||
addComment(rs...);
|
||||
}
|
||||
}
|
||||
|
||||
// comment corresponded to addToPath(mcc_telemetry_data_c auto const& tdata)
|
||||
void addDefaultComment()
|
||||
{
|
||||
addComment("Format (time is in milliseconds, coordinates are in degrees, speeds are in degrees/s):");
|
||||
addComment(
|
||||
" <UNIXTIME> <mount X> <mount Y> <target X> <target Y> <dX_{mount-target}> "
|
||||
"<dY_{mount-target}> <mount-to-target-distance> <mount X-speed> <mount Y-speed> <moving state>");
|
||||
}
|
||||
|
||||
// general purpose method
|
||||
// template <std::formattable<char>... ArgTs>
|
||||
// void addToPath(std::format_string<ArgTs...> fmt, ArgTs&&... args)
|
||||
// {
|
||||
// std::format_to(std::back_inserter(_buffer), fmt, std::forward<ArgTs>(args)...);
|
||||
// std::ranges::copy(lineDelim, std::back_inserter(_buffer));
|
||||
// }
|
||||
|
||||
// general purpose method
|
||||
template <std::formattable<char>... ArgTs>
|
||||
void addToPath(std::string_view fmt, ArgTs&&... args)
|
||||
{
|
||||
std::vformat_to(std::back_inserter(_buffer), fmt, std::make_format_args(args...));
|
||||
std::ranges::copy(lineDelim, std::back_inserter(_buffer));
|
||||
}
|
||||
|
||||
// default-implemented method
|
||||
void addToPath(mcc_telemetry_data_c auto const& tdata)
|
||||
{
|
||||
// UNIX-time millisecs, mount X, mount Y, target X, target Y, dX(mount-target), dY(mount-target), dist, speedX,
|
||||
// speedY, state
|
||||
auto dist = tdata.mountPos.distance(tdata.targetPos);
|
||||
|
||||
using d_t = std::chrono::milliseconds;
|
||||
|
||||
auto tp = std::chrono::duration_cast<d_t>(tdata.mountPos.epoch().UTC().time_since_epoch());
|
||||
|
||||
const std::string_view d_fmt = "{:14.8f}";
|
||||
const auto v = std::views::repeat(d_fmt, 9) | std::views::join_with(' ');
|
||||
std::string fmt = "{} " + std::string(v.begin(), v.end()) + " {}";
|
||||
|
||||
|
||||
int state = (int)tdata.hwState.movementState;
|
||||
auto tp_val = tp.count();
|
||||
|
||||
double mnt_x = MccAngle(tdata.mountPos.co_lon()).degrees(), mnt_y = MccAngle(tdata.mountPos.co_lon()).degrees(),
|
||||
tag_x = dist.x2.degrees(), tag_y = dist.y2.degrees(), dx = dist.dx.degrees(), dy = dist.dy.degrees(),
|
||||
dd = dist.dist.degrees();
|
||||
|
||||
addToPath(std::string_view(fmt.begin(), fmt.end()), tp_val, mnt_x, mnt_y, tag_x, tag_y, dx, dy, dd,
|
||||
tdata.hwState.speedXY.x().degrees(), tdata.hwState.speedXY.y().degrees(), state);
|
||||
}
|
||||
|
||||
void clearPath()
|
||||
{
|
||||
_buffer.clear();
|
||||
}
|
||||
|
||||
bool saveToFile(std::string const& filename, std::ios_base::openmode mode = std::ios::out | std::ios::trunc)
|
||||
{
|
||||
if (filename.empty()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
std::ofstream fst(filename, mode);
|
||||
|
||||
if (fst.is_open()) {
|
||||
fst << _buffer;
|
||||
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
std::string _buffer{};
|
||||
|
||||
std::string _commentSeq{commentSeq};
|
||||
std::string _lineDelim{lineDelim};
|
||||
};
|
||||
|
||||
|
||||
enum class MccGenericMovementControlsPolicy : int { POLICY_ASYNC, POLICY_BLOCKING };
|
||||
|
||||
template <std::movable PARAMS_T,
|
||||
MccGenericMovementControlsPolicy EXEC_POLICY = MccGenericMovementControlsPolicy::POLICY_ASYNC>
|
||||
class MccGenericMovementControls
|
||||
{
|
||||
public:
|
||||
static constexpr MccGenericMovementControlsPolicy executePolicy = EXEC_POLICY;
|
||||
|
||||
static constexpr std::chrono::seconds defaultWaitTimeout{3};
|
||||
|
||||
typedef MccError error_t;
|
||||
|
||||
typedef PARAMS_T movement_params_t;
|
||||
|
||||
template <std::invocable<bool> SLEW_FUNC_T, std::invocable<> TRACK_FUNC_T, std::invocable<> STOP_FUNC_T>
|
||||
MccGenericMovementControls(SLEW_FUNC_T&& slew_func, TRACK_FUNC_T&& track_func, STOP_FUNC_T&& stop_func)
|
||||
: _slewFunc(std::forward<SLEW_FUNC_T>(slew_func)),
|
||||
_trackFunc(std::forward<TRACK_FUNC_T>(track_func)),
|
||||
_stopFunc(std::forward<STOP_FUNC_T>(stop_func))
|
||||
{
|
||||
if constexpr (executePolicy == MccGenericMovementControlsPolicy::POLICY_ASYNC) {
|
||||
// *_stopMovementRequest = false;
|
||||
|
||||
// *_fsmState = STATE_IDLE;
|
||||
|
||||
// // start thread of movements
|
||||
// _fstFuture = std::async(
|
||||
// [this](std::stop_token stoken) {
|
||||
// auto do_state = _fsmState->load();
|
||||
|
||||
// while (!stoken.stop_requested()) {
|
||||
// std::println("\n{:*^80}\n", " WAIT LOCK ");
|
||||
// // wait here ...
|
||||
// _wakeupRequest->wait(false, std::memory_order_relaxed);
|
||||
|
||||
// _wakeupRequest->clear();
|
||||
|
||||
// std::println("\n{:*^80}\n", " UNLOCKED ");
|
||||
|
||||
// // if (stoken.stop_requested()) {
|
||||
// // break;
|
||||
// // }
|
||||
|
||||
// do_state = _fsmState->load();
|
||||
|
||||
// if (do_state & STATE_STOP) {
|
||||
// // if (_fsmState->load() & STATE_STOP) {
|
||||
// *_stopMovementRequest = true;
|
||||
// _stopFunc();
|
||||
// }
|
||||
|
||||
// if (do_state & STATE_SLEW) {
|
||||
// // if (_fsmState->load() & STATE_SLEW) {
|
||||
// *_stopMovementRequest = false;
|
||||
// _slewFunc(_slewAndStop->load());
|
||||
// } else if (do_state & STATE_TRACK) {
|
||||
// // } else if (_fsmState->load() & STATE_TRACK) {
|
||||
// *_stopMovementRequest = false;
|
||||
// _trackFunc();
|
||||
// }
|
||||
// }
|
||||
// },
|
||||
// _fstStopSource.get_token());
|
||||
|
||||
startAsyncMovementCycle();
|
||||
}
|
||||
}
|
||||
|
||||
MccGenericMovementControls(const MccGenericMovementControls&) = delete;
|
||||
MccGenericMovementControls(MccGenericMovementControls&& other) = default;
|
||||
|
||||
MccGenericMovementControls& operator=(const MccGenericMovementControls&) = delete;
|
||||
MccGenericMovementControls& operator=(MccGenericMovementControls&&) = default;
|
||||
|
||||
virtual ~MccGenericMovementControls()
|
||||
{
|
||||
if constexpr (executePolicy == MccGenericMovementControlsPolicy::POLICY_ASYNC) {
|
||||
// *_fsmState = STATE_IDLE;
|
||||
// _fstStopSource.request_stop();
|
||||
|
||||
// _wakeupRequest->test_and_set();
|
||||
// _wakeupRequest->notify_one();
|
||||
|
||||
// std::this_thread::sleep_for(std::chrono::milliseconds(200));
|
||||
|
||||
// if (_fstFuture.valid()) {
|
||||
// auto status = _fstFuture.wait_for(_waitTimeout->load());
|
||||
// }
|
||||
|
||||
stopAsyncMovementCycle();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template <typename SelfT>
|
||||
void stopAsyncMovementCycle(this SelfT&& self)
|
||||
requires(EXEC_POLICY == MccGenericMovementControlsPolicy::POLICY_ASYNC)
|
||||
{
|
||||
*self._fsmState = STATE_IDLE;
|
||||
self._fstStopSource.request_stop();
|
||||
|
||||
self._wakeupRequest->test_and_set();
|
||||
self._wakeupRequest->notify_all();
|
||||
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(200));
|
||||
|
||||
if (self._fstFuture.valid()) {
|
||||
auto status = self._fstFuture.wait_for(self._waitTimeout->load());
|
||||
}
|
||||
}
|
||||
|
||||
template <typename SelfT>
|
||||
void startAsyncMovementCycle(this SelfT& self)
|
||||
requires(EXEC_POLICY == MccGenericMovementControlsPolicy::POLICY_ASYNC)
|
||||
{
|
||||
using self_t = std::decay_t<SelfT>;
|
||||
|
||||
if (self._fstFuture.valid()) {
|
||||
self.stopAsyncMovementCycle();
|
||||
}
|
||||
|
||||
*self._stopMovementRequest = false;
|
||||
|
||||
self._fstStopSource = std::stop_source{};
|
||||
|
||||
*self._fsmState = STATE_IDLE;
|
||||
|
||||
// start thread of movements
|
||||
self._fstFuture = std::async(
|
||||
std::launch::async,
|
||||
[&self](std::stop_token stoken) mutable {
|
||||
auto do_state = self._fsmState->load();
|
||||
|
||||
std::string log_str;
|
||||
while (!stoken.stop_requested()) {
|
||||
log_str = std::format("\n{:*^80}\n", " WAIT LOCK ");
|
||||
if constexpr (mcc_generic_mount_c<self_t>) {
|
||||
self.logTrace(log_str);
|
||||
} else {
|
||||
std::println("{}", log_str);
|
||||
}
|
||||
|
||||
// wait here ...
|
||||
self._wakeupRequest->wait(false, std::memory_order_relaxed);
|
||||
|
||||
self._wakeupRequest->clear();
|
||||
|
||||
log_str = std::format("\n{:*^80}\n", " UNLOCKED ");
|
||||
if constexpr (mcc_generic_mount_c<self_t>) {
|
||||
self.logTrace(log_str);
|
||||
} else {
|
||||
std::println("{}", log_str);
|
||||
}
|
||||
|
||||
// if (stoken.stop_requested()) {
|
||||
// break;
|
||||
// }
|
||||
|
||||
do_state = self._fsmState->load();
|
||||
|
||||
if (do_state & STATE_STOP) {
|
||||
// if (_fsmState->load() & STATE_STOP) {
|
||||
*self._stopMovementRequest = true;
|
||||
self._stopFunc();
|
||||
}
|
||||
|
||||
if (do_state & STATE_SLEW) {
|
||||
// if (_fsmState->load() & STATE_SLEW) {
|
||||
*self._stopMovementRequest = false;
|
||||
self._slewFunc(self._slewAndStop->load());
|
||||
} else if (do_state & STATE_TRACK) {
|
||||
// } else if (_fsmState->load() & STATE_TRACK) {
|
||||
*self._stopMovementRequest = false;
|
||||
self._trackFunc();
|
||||
}
|
||||
}
|
||||
},
|
||||
self._fstStopSource.get_token());
|
||||
}
|
||||
|
||||
error_t slewToTarget(bool slew_and_stop)
|
||||
{
|
||||
// *_stopMovementRequest = false;
|
||||
|
||||
if constexpr (executePolicy == MccGenericMovementControlsPolicy::POLICY_ASYNC) {
|
||||
auto prev_state = _fsmState->load();
|
||||
|
||||
*_fsmState = STATE_SLEW;
|
||||
|
||||
if (prev_state & STATE_SLEW || prev_state & STATE_TRACK) {
|
||||
*_fsmState |= STATE_STOP;
|
||||
|
||||
*_stopMovementRequest = true; // to exit from slewing or tracking
|
||||
}
|
||||
|
||||
*_slewAndStop = slew_and_stop;
|
||||
|
||||
_wakeupRequest->test_and_set();
|
||||
_wakeupRequest->notify_one();
|
||||
|
||||
return MccGenericMovementControlsErrorCode::ERROR_OK;
|
||||
} else if constexpr (executePolicy == MccGenericMovementControlsPolicy::POLICY_BLOCKING) {
|
||||
return _slewFunc(slew_and_stop);
|
||||
} else {
|
||||
static_assert(false, "UNKNOWN EXECUTION POLICY!");
|
||||
}
|
||||
}
|
||||
|
||||
error_t trackTarget()
|
||||
{
|
||||
// *_stopMovementRequest = false;
|
||||
|
||||
if constexpr (executePolicy == MccGenericMovementControlsPolicy::POLICY_ASYNC) {
|
||||
auto prev_state = _fsmState->load();
|
||||
|
||||
if (!(prev_state & STATE_TRACK)) {
|
||||
*_fsmState = STATE_TRACK;
|
||||
|
||||
if (prev_state & STATE_SLEW) {
|
||||
*_fsmState |= STATE_STOP;
|
||||
|
||||
*_stopMovementRequest = true; // to exit from slewing
|
||||
}
|
||||
|
||||
_wakeupRequest->test_and_set();
|
||||
_wakeupRequest->notify_one();
|
||||
} // already tracking, just ignore
|
||||
|
||||
return MccGenericMovementControlsErrorCode::ERROR_OK;
|
||||
} else if constexpr (executePolicy == MccGenericMovementControlsPolicy::POLICY_BLOCKING) {
|
||||
return _trackFunc();
|
||||
} else {
|
||||
static_assert(false, "UNKNOWN EXECUTION POLICY!");
|
||||
}
|
||||
}
|
||||
|
||||
error_t stopMount()
|
||||
{
|
||||
// *_stopMovementRequest = true;
|
||||
|
||||
if constexpr (executePolicy == MccGenericMovementControlsPolicy::POLICY_ASYNC) {
|
||||
*_fsmState = STATE_STOP;
|
||||
|
||||
*_stopMovementRequest = true; // to exit from slewing or tracking
|
||||
|
||||
_wakeupRequest->test_and_set();
|
||||
_wakeupRequest->notify_one();
|
||||
|
||||
return MccGenericMovementControlsErrorCode::ERROR_OK;
|
||||
} else if constexpr (executePolicy == MccGenericMovementControlsPolicy::POLICY_BLOCKING) {
|
||||
return _stopFunc();
|
||||
} else {
|
||||
static_assert(false, "UNKNOWN EXECUTION POLICY!");
|
||||
}
|
||||
}
|
||||
|
||||
error_t setMovementParams(movement_params_t const& pars)
|
||||
{
|
||||
std::lock_guard lock{*_currentMovementParamsMutex};
|
||||
|
||||
_currentMovementParams = pars;
|
||||
|
||||
return MccGenericMovementControlsErrorCode::ERROR_OK;
|
||||
}
|
||||
|
||||
movement_params_t getMovementParams() const
|
||||
{
|
||||
std::lock_guard lock{*_currentMovementParamsMutex};
|
||||
|
||||
return _currentMovementParams;
|
||||
}
|
||||
|
||||
protected:
|
||||
std::unique_ptr<std::mutex> _currentMovementParamsMutex{new std::mutex{}};
|
||||
PARAMS_T _currentMovementParams{};
|
||||
|
||||
std::unique_ptr<std::atomic_bool> _stopMovementRequest{new std::atomic_bool{false}};
|
||||
|
||||
std::function<error_t(bool)> _slewFunc{};
|
||||
std::function<error_t()> _trackFunc{};
|
||||
std::function<error_t()> _stopFunc{};
|
||||
|
||||
std::unique_ptr<std::atomic<std::chrono::nanoseconds>> _waitTimeout{
|
||||
new std::atomic<std::chrono::nanoseconds>{defaultWaitTimeout}};
|
||||
|
||||
|
||||
|
||||
std::conditional_t<executePolicy == MccGenericMovementControlsPolicy::POLICY_ASYNC,
|
||||
std::future<void>,
|
||||
std::nullptr_t>
|
||||
_fstFuture{};
|
||||
|
||||
std::stop_source _fstStopSource{};
|
||||
|
||||
std::unique_ptr<std::atomic_flag> _wakeupRequest{new std::atomic_flag};
|
||||
std::unique_ptr<std::atomic_bool> _slewAndStop{new std::atomic_bool{false}};
|
||||
|
||||
enum { STATE_IDLE = 0x00, STATE_SLEW = 0x01, STATE_TRACK = 0x02, STATE_STOP = 0x04 };
|
||||
|
||||
std::unique_ptr<std::atomic_int> _fsmState{new std::atomic_int};
|
||||
|
||||
|
||||
// template <typename SelfT>
|
||||
// void mainCycle(this SelfT&& self, std::stop_token stoken)
|
||||
// {
|
||||
// using self_t = std::decay_t<SelfT>;
|
||||
|
||||
// auto do_state = _fsmState->load();
|
||||
|
||||
// std::string log_str;
|
||||
|
||||
// while (!stoken.stop_requested()) {
|
||||
// log_str = std::format("\n{:*^80}\n", " WAIT LOCK ");
|
||||
// if constexpr (mcc_generic_mount_c<self_t>) {
|
||||
// self.logTrace(log_str);
|
||||
// } else {
|
||||
// std::println(log_str);
|
||||
// }
|
||||
|
||||
// // wait here ...
|
||||
// _wakeupRequest->wait(false, std::memory_order_relaxed);
|
||||
|
||||
// _wakeupRequest->clear();
|
||||
|
||||
// log_str = std::format("\n{:*^80}\n", " UNLOCKED ");
|
||||
// if constexpr (mcc_generic_mount_c<self_t>) {
|
||||
// self.logTrace(log_str);
|
||||
// } else {
|
||||
// std::println(log_str);
|
||||
// }
|
||||
|
||||
// // if (stoken.stop_requested()) {
|
||||
// // break;
|
||||
// // }
|
||||
|
||||
// do_state = _fsmState->load();
|
||||
|
||||
// if (do_state & STATE_STOP) {
|
||||
// // if (_fsmState->load() & STATE_STOP) {
|
||||
// *_stopMovementRequest = true;
|
||||
// _stopFunc();
|
||||
// }
|
||||
|
||||
// if (do_state & STATE_SLEW) {
|
||||
// // if (_fsmState->load() & STATE_SLEW) {
|
||||
// *_stopMovementRequest = false;
|
||||
// _slewFunc(_slewAndStop->load());
|
||||
// } else if (do_state & STATE_TRACK) {
|
||||
// // } else if (_fsmState->load() & STATE_TRACK) {
|
||||
// *_stopMovementRequest = false;
|
||||
// _trackFunc();
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// utility methods
|
||||
|
||||
// the method calculates the change in coordinates of a point over a given time given the current speed and braking
|
||||
// acceleration. a position after given 'time' interval is returned
|
||||
auto coordsAfterTime(mcc_coord_pair_c auto const& cp,
|
||||
mcc_coord_pair_c auto const& speedXY, // in radians per seconds
|
||||
mcc_coord_pair_c auto const& braking_accelXY, // in radians per seconds in square
|
||||
traits::mcc_time_duration_c auto const& time,
|
||||
mcc_coord_pair_c auto* dxy = nullptr)
|
||||
{
|
||||
// time to stop mount with given current speed and constant braking acceleration
|
||||
double tx_stop = std::abs(speedXY.x()) / braking_accelXY.x();
|
||||
double ty_stop = std::abs(speedXY.y()) / braking_accelXY.y();
|
||||
|
||||
using secs_t = std::chrono::duration<double>; // seconds as double
|
||||
|
||||
double tx = std::chrono::duration_cast<secs_t>(time).count();
|
||||
double ty = std::chrono::duration_cast<secs_t>(time).count();
|
||||
|
||||
if (std::isfinite(tx_stop) && (tx > tx_stop)) {
|
||||
tx = tx_stop;
|
||||
}
|
||||
if (std::isfinite(ty_stop) && (ty > ty_stop)) {
|
||||
ty = ty_stop;
|
||||
}
|
||||
|
||||
// the distance:
|
||||
// here, one must take into account the sign of the speed!!!
|
||||
double dx = speedXY.x() * tx - std::copysign(braking_accelXY.x(), speedXY.x()) * tx * tx / 2.0;
|
||||
double dy = speedXY.y() * ty - std::copysign(braking_accelXY.y(), speedXY.y()) * ty * ty / 2.0;
|
||||
|
||||
std::remove_cvref_t<decltype(cp)> cp_res{};
|
||||
cp_res.setEpoch(cp.epoch() + time);
|
||||
|
||||
cp_res.setX((double)cp.x() + dx);
|
||||
cp_res.setY((double)cp.y() + dy);
|
||||
|
||||
if (dxy) {
|
||||
dxy->setX(dx);
|
||||
dxy->setY(dy);
|
||||
dxy->setEpoch(cp_res.epoch());
|
||||
}
|
||||
|
||||
return cp_res;
|
||||
}
|
||||
|
||||
auto coordsAfterTime(mcc_skypoint_c auto const& sp,
|
||||
mcc_coord_pair_c auto const& speedXY, // in radians per seconds
|
||||
mcc_coord_pair_c auto const& braking_accelXY, // in radians per seconds in square
|
||||
traits::mcc_time_duration_c auto const& time,
|
||||
mcc_coord_pair_c auto* dxy = nullptr)
|
||||
{
|
||||
auto run_func = [&, this](auto& cp) {
|
||||
sp.toAtSameEpoch(cp);
|
||||
|
||||
auto new_cp = coordsAfterTime(cp, speedXY, braking_accelXY, time, dxy);
|
||||
|
||||
std::remove_cvref_t<decltype(sp)> sp_res{};
|
||||
|
||||
sp_res.from(cp);
|
||||
|
||||
return sp_res;
|
||||
};
|
||||
|
||||
switch (sp.pairKind()) {
|
||||
case MccCoordPairKind::COORDS_KIND_RADEC_ICRS: {
|
||||
MccSkyRADEC_ICRS rd;
|
||||
return run_func(rd);
|
||||
};
|
||||
case MccCoordPairKind::COORDS_KIND_RADEC_OBS: {
|
||||
MccSkyRADEC_OBS rd;
|
||||
return run_func(rd);
|
||||
};
|
||||
case MccCoordPairKind::COORDS_KIND_RADEC_APP: {
|
||||
MccSkyRADEC_APP rd;
|
||||
return run_func(rd);
|
||||
};
|
||||
case MccCoordPairKind::COORDS_KIND_HADEC_OBS: {
|
||||
MccSkyHADEC_OBS hd;
|
||||
return run_func(hd);
|
||||
};
|
||||
case MccCoordPairKind::COORDS_KIND_HADEC_APP: {
|
||||
MccSkyHADEC_APP hd;
|
||||
return run_func(hd);
|
||||
};
|
||||
case MccCoordPairKind::COORDS_KIND_AZZD: {
|
||||
MccSkyAZZD azzd;
|
||||
return run_func(azzd);
|
||||
};
|
||||
case MccCoordPairKind::COORDS_KIND_AZALT: {
|
||||
MccSkyAZALT azalt;
|
||||
return run_func(azalt);
|
||||
};
|
||||
case MccCoordPairKind::COORDS_KIND_GENERIC:
|
||||
case MccCoordPairKind::COORDS_KIND_XY: {
|
||||
MccGenXY xy;
|
||||
return run_func(xy);
|
||||
};
|
||||
default:
|
||||
return sp;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template <std::default_initializable PARAMS_T>
|
||||
using MccGenericBlockingMovementControls =
|
||||
MccGenericMovementControls<PARAMS_T, MccGenericMovementControlsPolicy::POLICY_BLOCKING>;
|
||||
|
||||
template <std::default_initializable PARAMS_T>
|
||||
using MccGenericAsyncMovementControls =
|
||||
MccGenericMovementControls<PARAMS_T, MccGenericMovementControlsPolicy::POLICY_ASYNC>;
|
||||
|
||||
|
||||
static_assert(mcc_movement_controls_c<MccGenericAsyncMovementControls<MccGenericMovementControlsParams>>, "!!!");
|
||||
|
||||
} // namespace mcc::impl
|
||||
1059
include/mcc/mcc_movement_controls.h
Normal file
1059
include/mcc/mcc_movement_controls.h
Normal file
File diff suppressed because it is too large
Load Diff
1262
include/mcc/mcc_netserver.h
Normal file
1262
include/mcc/mcc_netserver.h
Normal file
File diff suppressed because it is too large
Load Diff
512
include/mcc/mcc_netserver_endpoint.h
Normal file
512
include/mcc/mcc_netserver_endpoint.h
Normal file
@@ -0,0 +1,512 @@
|
||||
#pragma once
|
||||
|
||||
/* MOUNT CONTROL COMPONENTS LIBRARY */
|
||||
|
||||
|
||||
|
||||
/* NETWORK SERVER ENDPOINT CLASS IMPLEMENTATION */
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <charconv>
|
||||
#include <cstdint>
|
||||
#include <filesystem>
|
||||
#include <ranges>
|
||||
#include <string_view>
|
||||
|
||||
#include "mcc_traits.h"
|
||||
|
||||
namespace mcc::network
|
||||
{
|
||||
|
||||
namespace utils
|
||||
{
|
||||
|
||||
static constexpr bool mcc_char_range_compare(const traits::mcc_char_view auto& what,
|
||||
const traits::mcc_char_view auto& where,
|
||||
bool case_insensitive = false)
|
||||
{
|
||||
if (std::ranges::size(what) == std::ranges::size(where)) {
|
||||
if (case_insensitive) {
|
||||
auto f = std::ranges::search(where,
|
||||
std::views::transform(what, [](const char& ch) { return std::tolower(ch); }));
|
||||
return !f.empty();
|
||||
} else {
|
||||
auto f = std::ranges::search(where, what);
|
||||
return !f.empty();
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace utils
|
||||
|
||||
/*
|
||||
* Very simple various protocols endpoint parser and holder class
|
||||
*
|
||||
* endpoint: proto_mark://host_name:port_num/path
|
||||
* where "path" is optional for all non-local protocol kinds;
|
||||
*
|
||||
* for local kind of protocols the endpoint must be given as:
|
||||
* local://stream/PATH
|
||||
* local://seqpacket/PATH
|
||||
* local://serial/PATH
|
||||
* where 'stream' and 'seqpacket' "host_name"-field marks the
|
||||
* stream-type and seqpacket-type UNIX domain sockets protocols;
|
||||
* 'serial' marks a serial (RS232/485) protocol.
|
||||
* here, possible "port_num" field is allowed but ignored.
|
||||
*
|
||||
* NOTE: "proto_mark" and "host_name" (for local kind) fields are parsed in case-insensitive manner!
|
||||
*
|
||||
* EXAMPLES: tcp://192.168.70.130:3131
|
||||
* local://serial/dev/ttyS1
|
||||
* local://seqpacket/tmp/BM70_SERVER_SOCK
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
class MccNetServerEndpoint
|
||||
{
|
||||
public:
|
||||
static constexpr std::string_view protoHostDelim = "://";
|
||||
static constexpr std::string_view hostPortDelim = ":";
|
||||
static constexpr std::string_view portPathDelim = "/";
|
||||
|
||||
enum proto_id_t : uint8_t {
|
||||
PROTO_ID_LOCAL,
|
||||
PROTO_ID_SEQLOCAL,
|
||||
PROTO_ID_SERLOCAL,
|
||||
PROTO_ID_TCP,
|
||||
PROTO_ID_TLS,
|
||||
PROTO_ID_UNKNOWN
|
||||
};
|
||||
|
||||
static constexpr std::string_view protoMarkLocal{"local"}; // UNIX domain
|
||||
static constexpr std::string_view protoMarkTCP{"tcp"}; // TCP
|
||||
static constexpr std::string_view protoMarkTLS{"tls"}; // TLS
|
||||
|
||||
static constexpr std::array validProtoMarks{protoMarkLocal, protoMarkTCP, protoMarkTLS};
|
||||
|
||||
|
||||
static constexpr std::string_view localProtoTypeStream{"stream"}; // UNIX domain stream
|
||||
static constexpr std::string_view localProtoTypeSeqpacket{"seqpacket"}; // UNIX domain seqpacket
|
||||
static constexpr std::string_view localProtoTypeSerial{"serial"}; // serial (RS232/485)
|
||||
|
||||
static constexpr std::array validLocalProtoTypes{localProtoTypeStream, localProtoTypeSeqpacket,
|
||||
localProtoTypeSerial};
|
||||
|
||||
|
||||
template <traits::mcc_input_char_range R>
|
||||
MccNetServerEndpoint(const R& ept)
|
||||
{
|
||||
fromRange(ept);
|
||||
}
|
||||
|
||||
MccNetServerEndpoint(const MccNetServerEndpoint& other)
|
||||
{
|
||||
copyInst(other);
|
||||
}
|
||||
|
||||
MccNetServerEndpoint(MccNetServerEndpoint&& other)
|
||||
{
|
||||
moveInst(std::move(other));
|
||||
}
|
||||
|
||||
virtual ~MccNetServerEndpoint() = default;
|
||||
|
||||
|
||||
MccNetServerEndpoint& operator=(const MccNetServerEndpoint& other)
|
||||
{
|
||||
copyInst(other);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
MccNetServerEndpoint& operator=(MccNetServerEndpoint&& other)
|
||||
{
|
||||
moveInst(std::move(other));
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <traits::mcc_input_char_range R>
|
||||
requires std::ranges::contiguous_range<R>
|
||||
bool fromRange(const R& ept)
|
||||
{
|
||||
_isValid = false;
|
||||
|
||||
// at least 'ws://a' (proto, proto-host delimiter and at least a single character of hostname)
|
||||
if (std::ranges::size(ept) < 6) {
|
||||
return _isValid;
|
||||
}
|
||||
|
||||
if constexpr (std::is_array_v<std::remove_cvref_t<R>>) {
|
||||
_endpoint = ept;
|
||||
} else {
|
||||
_endpoint.clear();
|
||||
std::ranges::copy(ept, std::back_inserter(_endpoint));
|
||||
}
|
||||
|
||||
auto found = std::ranges::search(_endpoint, protoHostDelim);
|
||||
if (found.empty()) {
|
||||
return _isValid;
|
||||
}
|
||||
|
||||
|
||||
ssize_t idx;
|
||||
if ((idx = checkProtoMark(std::string_view{_endpoint.begin(), found.begin()})) < 0) {
|
||||
return _isValid;
|
||||
}
|
||||
|
||||
_proto = validProtoMarks[idx];
|
||||
|
||||
_host = std::string_view{found.end(), _endpoint.end()};
|
||||
|
||||
auto f1 = std::ranges::search(_host, portPathDelim);
|
||||
// std::string_view port_sv;
|
||||
if (f1.empty() && isLocal()) { // no path, but it is mandatory for 'local'!
|
||||
return _isValid;
|
||||
} else {
|
||||
_host = std::string_view(_host.begin(), f1.begin());
|
||||
|
||||
_path = std::string_view(f1.end(), &*_endpoint.end());
|
||||
|
||||
f1 = std::ranges::search(_host, hostPortDelim);
|
||||
if (f1.empty() && !isLocal()) { // no port, but it is mandatory for non-local!
|
||||
return _isValid;
|
||||
}
|
||||
|
||||
_portView = std::string_view(f1.end(), _host.end());
|
||||
if (_portView.size()) {
|
||||
_host = std::string_view(_host.begin(), f1.begin());
|
||||
|
||||
if (!isLocal()) {
|
||||
// convert port string to int
|
||||
auto end_ptr = _portView.data() + _portView.size();
|
||||
|
||||
auto [ptr, ec] = std::from_chars(_portView.data(), end_ptr, _port);
|
||||
if (ec != std::errc() || ptr != end_ptr) {
|
||||
return _isValid;
|
||||
}
|
||||
} else { // ignore for local
|
||||
_port = -1;
|
||||
}
|
||||
} else {
|
||||
_port = -1;
|
||||
}
|
||||
|
||||
if (isLocal()) { // check for special values
|
||||
idx = 0;
|
||||
if (std::ranges::any_of(validLocalProtoTypes, [&idx, this](const auto& el) {
|
||||
bool ok = utils::mcc_char_range_compare(_host, el, true);
|
||||
if (!ok) {
|
||||
++idx;
|
||||
}
|
||||
return ok;
|
||||
})) {
|
||||
_host = validLocalProtoTypes[idx];
|
||||
} else {
|
||||
return _isValid;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_isValid = true;
|
||||
|
||||
return _isValid;
|
||||
}
|
||||
|
||||
|
||||
bool isValid() const
|
||||
{
|
||||
return _isValid;
|
||||
}
|
||||
|
||||
|
||||
auto endpoint() const
|
||||
{
|
||||
return _endpoint;
|
||||
}
|
||||
|
||||
template <traits::mcc_view_or_output_char_range R>
|
||||
R proto() const
|
||||
{
|
||||
return part<R>(PROTO_PART);
|
||||
}
|
||||
|
||||
std::string_view proto() const
|
||||
{
|
||||
return proto<std::string_view>();
|
||||
}
|
||||
|
||||
template <traits::mcc_view_or_output_char_range R>
|
||||
R host() const
|
||||
{
|
||||
return part<R>(HOST_PART);
|
||||
}
|
||||
|
||||
std::string_view host() const
|
||||
{
|
||||
return host<std::string_view>();
|
||||
}
|
||||
|
||||
int port() const
|
||||
{
|
||||
return _port;
|
||||
}
|
||||
|
||||
template <traits::mcc_view_or_output_char_range R>
|
||||
R portView() const
|
||||
{
|
||||
return part<R>(PORT_PART);
|
||||
}
|
||||
|
||||
std::string_view portView() const
|
||||
{
|
||||
return portView<std::string_view>();
|
||||
}
|
||||
|
||||
template <traits::mcc_output_char_range R, traits::mcc_input_char_range RR = std::string_view>
|
||||
R path(RR&& root_path) const
|
||||
{
|
||||
if (_path.empty()) {
|
||||
if constexpr (traits::mcc_output_char_range<R>) {
|
||||
R res;
|
||||
std::ranges::copy(std::forward<RR>(root_path), std::back_inserter(res));
|
||||
|
||||
return res;
|
||||
} else { // can't add root path!!!
|
||||
return part<R>(PATH_PART);
|
||||
}
|
||||
}
|
||||
|
||||
auto N = std::ranges::distance(root_path.begin(), root_path.end());
|
||||
|
||||
if (N) {
|
||||
R res;
|
||||
std::filesystem::path pt(root_path.begin(), root_path.end());
|
||||
|
||||
if (isLocal() && _path[0] == '\0') {
|
||||
std::ranges::copy(std::string_view(" "), std::back_inserter(res));
|
||||
pt /= _path.substr(1);
|
||||
std::ranges::copy(pt.string(), std::back_inserter(res));
|
||||
*res.begin() = '\0';
|
||||
} else {
|
||||
pt /= _path;
|
||||
std::ranges::copy(pt.string(), std::back_inserter(res));
|
||||
}
|
||||
|
||||
return res;
|
||||
} else {
|
||||
return part<R>(PATH_PART);
|
||||
}
|
||||
}
|
||||
|
||||
template <traits::mcc_input_char_range RR = std::string_view>
|
||||
std::string path(RR&& root_path) const
|
||||
{
|
||||
return path<std::string, RR>(std::forward<RR>(root_path));
|
||||
}
|
||||
|
||||
template <traits::mcc_view_or_output_char_range R>
|
||||
R path() const
|
||||
{
|
||||
return part<R>(PATH_PART);
|
||||
}
|
||||
|
||||
std::string_view path() const
|
||||
{
|
||||
return path<std::string_view>();
|
||||
}
|
||||
|
||||
|
||||
bool isLocal() const
|
||||
{
|
||||
return proto() == protoMarkLocal;
|
||||
}
|
||||
|
||||
bool isLocalStream() const
|
||||
{
|
||||
return host() == localProtoTypeStream;
|
||||
}
|
||||
|
||||
bool isLocalSerial() const
|
||||
{
|
||||
return host() == localProtoTypeSerial;
|
||||
}
|
||||
|
||||
bool isLocalSeqpacket() const
|
||||
{
|
||||
return host() == localProtoTypeSeqpacket;
|
||||
}
|
||||
|
||||
|
||||
bool isTCP() const
|
||||
{
|
||||
return proto() == protoMarkTCP;
|
||||
}
|
||||
|
||||
bool isTLS() const
|
||||
{
|
||||
return proto() == protoMarkTLS;
|
||||
}
|
||||
|
||||
|
||||
// add '\0' char (or replace special-meaning char/char-sequence) to construct UNIX abstract namespace
|
||||
// endpoint path
|
||||
template <typename T = std::nullptr_t>
|
||||
MccNetServerEndpoint& makeAbstract(const T& mark = nullptr)
|
||||
requires(traits::mcc_input_char_range<T> || std::same_as<std::remove_cv_t<T>, char> ||
|
||||
std::is_null_pointer_v<std::remove_cv_t<T>>)
|
||||
{
|
||||
if (!(isLocalStream() || isLocalSeqpacket())) { // only local proto is valid!
|
||||
return *this;
|
||||
}
|
||||
|
||||
if constexpr (std::is_null_pointer_v<T>) { // just insert '\0'
|
||||
auto it = _endpoint.insert(std::string::const_iterator(_path.begin()), '\0');
|
||||
_path = std::string_view(it, _endpoint.end());
|
||||
} else if constexpr (std::same_as<std::remove_cv_t<T>, char>) { // replace a character (mark)
|
||||
auto pos = std::distance(_endpoint.cbegin(), std::string::const_iterator(_path.begin()));
|
||||
if (_endpoint[pos] == mark) {
|
||||
_endpoint[pos] = '\0';
|
||||
}
|
||||
} else { // replace a character range (mark)
|
||||
if (std::ranges::equal(_path | std::views::take(std::ranges::size(mark), mark))) {
|
||||
auto pos = std::distance(_endpoint.cbegin(), std::string::const_iterator(_path.begin()));
|
||||
_endpoint.replace(pos, std::ranges::size(mark), 1, '\0');
|
||||
_path = std::string_view(_endpoint.begin() + pos, _endpoint.end());
|
||||
}
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
protected:
|
||||
std::string _endpoint;
|
||||
std::string_view _proto, _host, _path, _portView;
|
||||
int _port;
|
||||
bool _isValid;
|
||||
|
||||
|
||||
virtual ssize_t checkProtoMark(std::string_view proto_mark)
|
||||
{
|
||||
ssize_t idx = 0;
|
||||
|
||||
// case-insensitive look-up
|
||||
bool found = std::ranges::any_of(MccNetServerEndpoint::validProtoMarks, [&idx, &proto_mark](const auto& el) {
|
||||
bool ok = utils::mcc_char_range_compare(proto_mark, el, true);
|
||||
|
||||
if (!ok) {
|
||||
++idx;
|
||||
}
|
||||
|
||||
return ok;
|
||||
});
|
||||
|
||||
return found ? idx : -1;
|
||||
}
|
||||
|
||||
enum EndpointPart { PROTO_PART, HOST_PART, PATH_PART, PORT_PART };
|
||||
|
||||
template <traits::mcc_view_or_output_char_range R>
|
||||
R part(EndpointPart what) const
|
||||
{
|
||||
R res;
|
||||
|
||||
// if (!_isValid) {
|
||||
// return res;
|
||||
// }
|
||||
|
||||
auto part = _proto;
|
||||
|
||||
switch (what) {
|
||||
case PROTO_PART:
|
||||
part = _proto;
|
||||
break;
|
||||
case HOST_PART:
|
||||
part = _host;
|
||||
break;
|
||||
case PATH_PART:
|
||||
part = _path;
|
||||
break;
|
||||
case PORT_PART:
|
||||
part = _portView;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if constexpr (std::ranges::view<R>) {
|
||||
return {part.begin(), part.end()};
|
||||
} else {
|
||||
std::ranges::copy(part, std::back_inserter(res));
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
void copyInst(const MccNetServerEndpoint& other)
|
||||
{
|
||||
if (&other != this) {
|
||||
if (other._isValid) {
|
||||
_isValid = other._isValid;
|
||||
_endpoint = other._endpoint;
|
||||
_proto = other._proto;
|
||||
|
||||
std::iterator_traits<const char*>::difference_type idx;
|
||||
if (other.isLocal()) { // for 'local' host is one of static class constants
|
||||
_host = other._host;
|
||||
} else {
|
||||
idx = std::distance(other._endpoint.c_str(), other._host.data());
|
||||
_host = std::string_view(_endpoint.c_str() + idx, other._host.size());
|
||||
}
|
||||
|
||||
idx = std::distance(other._endpoint.c_str(), other._path.data());
|
||||
_path = std::string_view(_endpoint.c_str() + idx, other._path.size());
|
||||
|
||||
idx = std::distance(other._endpoint.c_str(), other._portView.data());
|
||||
_portView = std::string_view(_endpoint.c_str() + idx, other._portView.size());
|
||||
|
||||
_port = other._port;
|
||||
} else {
|
||||
_isValid = false;
|
||||
_endpoint = std::string();
|
||||
_proto = std::string_view();
|
||||
_host = std::string_view();
|
||||
_path = std::string_view();
|
||||
_portView = std::string_view();
|
||||
_port = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void moveInst(MccNetServerEndpoint&& other)
|
||||
{
|
||||
if (&other != this) {
|
||||
if (other._isValid) {
|
||||
_isValid = std::move(other._isValid);
|
||||
_endpoint = std::move(other._endpoint);
|
||||
_proto = other._proto;
|
||||
_host = std::move(other._host);
|
||||
_path = std::move(other._path);
|
||||
_port = std::move(other._port);
|
||||
_portView = std::move(other._portView);
|
||||
} else {
|
||||
_isValid = false;
|
||||
_endpoint = std::string();
|
||||
_proto = std::string_view();
|
||||
_host = std::string_view();
|
||||
_path = std::string_view();
|
||||
_portView = std::string_view();
|
||||
_port = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace mcc::network
|
||||
605
include/mcc/mcc_netserver_proto.h
Normal file
605
include/mcc/mcc_netserver_proto.h
Normal file
@@ -0,0 +1,605 @@
|
||||
#pragma once
|
||||
|
||||
/* MOUNT CONTROL COMPONENTS LIBRARY */
|
||||
|
||||
/* BASIC NETWORK PROTOCOL DEFINITIONS */
|
||||
|
||||
|
||||
|
||||
#include <algorithm>
|
||||
#include <string_view>
|
||||
|
||||
|
||||
#include "mcc_deserializer.h"
|
||||
#include "mcc_serializer.h"
|
||||
#include "mcc_utils.h"
|
||||
|
||||
namespace mcc::network
|
||||
{
|
||||
|
||||
/*
|
||||
* The network protocol is the ASCII-based, case-sensitive textual protocol.
|
||||
* The "client-server" communication is performed through messages.
|
||||
* The message is a minimal unit of this communication.
|
||||
* The model of network communication is a simple "client-server" one, i.e.,
|
||||
* client asks - server responds.
|
||||
*
|
||||
* network communication message format:
|
||||
* <keyword>[[<key-param-delim>]<param1>[<param-param-delim>][<param2>]...]<stop-seq>
|
||||
*
|
||||
* where
|
||||
* <keyword> - mandatory message keyword (one or more ASCII symbols)
|
||||
* <key-param-delim>
|
||||
*
|
||||
* e.g.
|
||||
* "TARGET 12:23:45.56 00:32:21.978\n"
|
||||
*/
|
||||
|
||||
|
||||
/* low-level network message format definitions */
|
||||
|
||||
static constexpr std::string_view MCC_COMMPROTO_STOP_SEQ = "\n";
|
||||
static constexpr std::string_view MCC_COMMPROTO_KEYPARAM_DELIM_SEQ = " ";
|
||||
static constexpr std::string_view MCC_COMMPROTO_PARAMPARAM_DELIM_SEQ = ";";
|
||||
static constexpr std::string_view MCC_COMMPROTO_RANGEPARAM_DELIM_SEQ = ",";
|
||||
|
||||
|
||||
/* server special keywords */
|
||||
|
||||
static constexpr std::string_view MCC_COMMPROTO_KEYWORD_SERVER_ACK_STR = "ACK"; // ACK
|
||||
static constexpr std::string_view MCC_COMMPROTO_KEYWORD_SERVER_ERROR_STR = "ERROR"; // mount operational error
|
||||
// pre-defined errors
|
||||
static constexpr std::string_view MCC_COMMPROTO_SERVER_ERROR_INVKEY_STR = "INVKEY"; // invalid keyword
|
||||
static constexpr std::string_view MCC_COMMPROTO_SERVER_ERROR_INVPAR_STR = "INVPAR"; // invalid parameter
|
||||
|
||||
|
||||
/* server control keywords */
|
||||
|
||||
static constexpr std::string_view MCC_COMMPROTO_KEYWORD_RESTART_SERVER_STR = "RESTART"; // restart server
|
||||
|
||||
|
||||
/* BELOW IS ONE OF THE PROTOCOL OPTIONS CORRESPONDING MCC_GENERIC_MOUNT_C CONCEPT */
|
||||
|
||||
|
||||
|
||||
/* keywords */
|
||||
|
||||
// NOTE: THE COORDINATES AND TIME-RELATED QUANTITIES CAN BE EXPRESSED IN THE TWO FORMATS:
|
||||
// 1) fixed-point real number, e.g. 123.43987537359 or -0.09775
|
||||
// 2) sexagesimal number, e.g. 10:43:43.12 or -123:54:12.435
|
||||
//
|
||||
// IN THE FIRST CASE ALL NUMBERS MUST BE INTERPRETATED AS DEGREES,
|
||||
// IN THE SECOND CASE NUMBERS MUST BE INTERPRETATED ACCORDING TO ITS TYPE:
|
||||
// ALL TIME-RELATED QUANTITIES AND RA/HA COORDINATES MUST BE EXPRESSED
|
||||
// IN FORMAT 'HOURS:MINUTES:SECONDS', WHILE DEC/ALT/AZ/ZD COORDINATES MUST
|
||||
// BE EXPRESSED AS '+/-DEGREES:ARCMINUTES:ARCSECONDS'
|
||||
//
|
||||
// USER-ENTERED (FROM NETWORK CLIENTS) COORDINATE PAIR CAN BE PROVIDED IN A MIXED FORM, I.E.,
|
||||
// 12.34436658678 10:32:11.432 or
|
||||
// 10:32:11.432 12.34436658678
|
||||
//
|
||||
// SERVER-RESPONDED COORDINATES ARE ALWAYS IN THE SAME FORMAT, SEXAGESIMAL OR FIXED-POINT
|
||||
//
|
||||
|
||||
// format of output coordinates:
|
||||
// "COORDFMT FMT-type\n"
|
||||
// e.g.:
|
||||
// "COORDFMT SGM\n"
|
||||
// "COORDFMT\n"
|
||||
//
|
||||
// server must return "ACK" or "ERROR INVPAR" in the case of 'set'-operation and
|
||||
// "ACK COORDFMT FMT-type" in the case of 'get'-operation
|
||||
// e.g.:
|
||||
// "COORDFMT FIX\n" -> "ACK\n"
|
||||
// "COORDFMT SXT\n" -> "ERROR INVPAR\n" (invalid parameter of format type)
|
||||
// "COORDFMT\n" -> "ACK COORDFMT FIX\n"
|
||||
//
|
||||
|
||||
static constexpr std::string_view MCC_COMMPROTO_KEYWORD_COORDFMT_STR = "COORDFMT";
|
||||
static constexpr std::string_view MCC_COMMPROTO_KEYWORD_COORDFMT_SEXGM_STR = "SGM"; // sexagesimal
|
||||
static constexpr std::string_view MCC_COMMPROTO_KEYWORD_COORDFMT_FIXED_STR = "FIX"; // fixed point
|
||||
|
||||
|
||||
// precision (number of decimal places) of returned coordinates:
|
||||
// "COORDPREC seconds-prec arcseconds-prec\n"
|
||||
// seconds-prec - precision of hour-based coordinates (RA and HA) or time-related quantities
|
||||
// arcseconds-prec - precision of degree-based coordinates (DEC, AZ, ZD, ALT)
|
||||
// precision must be given as non-negative integer number
|
||||
// e.g.
|
||||
// "COORDPREC 2,1\n" (output sexagesimal RA=12:34:56.67, DEC=32:54:21.9)
|
||||
//
|
||||
static constexpr std::string_view MCC_COMMPROTO_KEYWORD_COORDPREC_STR = "COORDPREC";
|
||||
|
||||
|
||||
// set/get target coordinates
|
||||
// "TARGET X-coord Y-coord XY-kind\n", if 'XY-kind' is omitted then one should assume RADEC_ICRS
|
||||
// e.g.:
|
||||
// "TARGET 12.7683487 10:23:09.75 AZZD\n"
|
||||
// "TARGET HADEC\n"
|
||||
// "TARGET\n"
|
||||
//
|
||||
// server must return "ACK" or "ERROR INVPAR" in the case of 'set'-operation and
|
||||
// "ACK TARGET X-coord Y-coord XY-kind" in the case of 'get'-operation
|
||||
// e.g.:
|
||||
// "TARGET 12.7683487 10:23:09.75 AZZD\n" -> "ACK\n"
|
||||
// "TARGET 12.7683487 10:23:09.75 AZZE\n" -> "ERROR INVPAR\n" (invalid parameter of coordinates pair kind)
|
||||
//
|
||||
// "TARGET HADEC\n" -> "ACK TARGET 20:21:56.32 -01:32:34.2 HADEC\n"
|
||||
// "TARGET\n" -> "ACK TARGET 20:21:56.32 -01:32:34.2 RADEC_ICRS\n"
|
||||
//
|
||||
|
||||
static constexpr std::string_view MCC_COMMPROTO_KEYWORD_TARGET_STR = "TARGET";
|
||||
|
||||
// get mount coordinates:
|
||||
// "MOUNT coord-kind", if 'coord-kind' is omitted then coordinates are according to mount type,
|
||||
// i.e., HADEC for equathorial-type mount and AZZD for alt-azimuthal one
|
||||
// e.g.:
|
||||
// "MOUNT RADEC\n" (get current apparent RA and DEC mount coordinates)
|
||||
//
|
||||
// server must return "ACK MOUNT X-coord Y-coord XY-kind" or "ERROR INVPAR"
|
||||
// e.g.
|
||||
// "MOUNT AZALT\n" -> "ACK MOUNT 1.2332325 54.23321312 AZALT\n"
|
||||
// "MOUNT AZAL\n" -> "ERROR INVPAR\n" (invalid parameter of coordinates pair kind)
|
||||
// "MOUNT\n" -> "ACK MOUNT 1.2332325 54.23321312 AZZD\n" for alt-azimuthal mount
|
||||
// "MOUNT\n" -> "ACK MOUNT 1.2332325 54.23321312 HADEC\n" for equathorial mount
|
||||
|
||||
static constexpr std::string_view MCC_COMMPROTO_KEYWORD_MOUNT_STR = "MOUNT";
|
||||
|
||||
|
||||
// get entered target coordinates:
|
||||
static constexpr std::string_view MCC_COMMPROTO_KEYWORD_ENTEREDTAG_STR = "ENTEREDTAG";
|
||||
|
||||
|
||||
static constexpr std::string_view MCC_COMMPROTO_KEYWORD_TELEMETRY_STR = "TELEMETRY";
|
||||
|
||||
// init mount
|
||||
// "INIT\n"
|
||||
static constexpr std::string_view MCC_COMMPROTO_KEYWORD_INIT_STR = "INIT";
|
||||
|
||||
// stop any movements
|
||||
// "STOP\n"
|
||||
static constexpr std::string_view MCC_COMMPROTO_KEYWORD_STOP_STR = "STOP";
|
||||
|
||||
// slew mount and track target:
|
||||
// "SLEW\n"
|
||||
static constexpr std::string_view MCC_COMMPROTO_KEYWORD_SLEW_STR = "SLEW";
|
||||
|
||||
// slew mount and stop:
|
||||
// "MOVE\n"
|
||||
static constexpr std::string_view MCC_COMMPROTO_KEYWORD_MOVE_STR = "MOVE";
|
||||
|
||||
// track target
|
||||
// "TRACK\n"
|
||||
static constexpr std::string_view MCC_COMMPROTO_KEYWORD_TRACK_STR = "TRACK";
|
||||
|
||||
// get mount status
|
||||
// "STATUS\n"
|
||||
static constexpr std::string_view MCC_COMMPROTO_KEYWORD_STATUS_STR = "STATUS";
|
||||
|
||||
// valid keywords
|
||||
// static constexpr std::array MCC_COMMPROTO_VALID_KEYS = {
|
||||
// MCC_COMMPROTO_KEYWORD_SERVER_ACK_STR, MCC_COMMPROTO_KEYWORD_SERVER_ERROR_STR, MCC_COMMPROTO_KEYWORD_COORDFMT_STR,
|
||||
// MCC_COMMPROTO_KEYWORD_COORDPREC_STR, MCC_COMMPROTO_KEYWORD_TARGET_STR, MCC_COMMPROTO_KEYWORD_MOUNT_STR,
|
||||
// MCC_COMMPROTO_KEYWORD_ENTEREDTAG_STR, MCC_COMMPROTO_KEYWORD_TELEMETRY_STR, MCC_COMMPROTO_KEYWORD_INIT_STR,
|
||||
// MCC_COMMPROTO_KEYWORD_STOP_STR, MCC_COMMPROTO_KEYWORD_SLEW_STR, MCC_COMMPROTO_KEYWORD_MOVE_STR,
|
||||
// MCC_COMMPROTO_KEYWORD_TRACK_STR, MCC_COMMPROTO_KEYWORD_STATUS_STR};
|
||||
|
||||
|
||||
// // hashes of valid keywords
|
||||
// static constexpr std::array MCC_COMMPROTO_VALID_KEYS_HASH = []<size_t... Is>(std::index_sequence<Is...>) {
|
||||
// return std::array{mcc::utils::FNV1aHash(MCC_COMMPROTO_VALID_KEYS[Is])...};
|
||||
// }(std::make_index_sequence<MCC_COMMPROTO_VALID_KEYS.size()>());
|
||||
|
||||
|
||||
|
||||
template <typename T>
|
||||
concept mcc_netmsg_valid_keys_c = requires(T t) {
|
||||
// std::array of valid message keywords
|
||||
[]<size_t N>(std::array<std::string_view, N>) {
|
||||
// to ensure T::NETMSG_VALID_KEYWORDS can be used as compile-time constant
|
||||
static constexpr auto v0 = T::NETMSG_VALID_KEYWORDS[0];
|
||||
return v0;
|
||||
}(T::NETMSG_VALID_KEYWORDS);
|
||||
|
||||
// std::array of valid message keywords hashes
|
||||
[]<size_t N>(std::array<size_t, N>) {
|
||||
// to ensure T::NETMSG_VALID_KEYWORD_HASHES can be used as compile-time constant
|
||||
static constexpr auto v0 = T::NETMSG_VALID_KEYWORD_HASHES[0];
|
||||
return v0;
|
||||
}(T::NETMSG_VALID_KEYWORD_HASHES);
|
||||
|
||||
requires T::NETMSG_VALID_KEYWORDS.size() == T::NETMSG_VALID_KEYWORD_HASHES.size();
|
||||
};
|
||||
|
||||
|
||||
struct MccNetMessageValidKeywords {
|
||||
static constexpr std::array NETMSG_VALID_KEYWORDS = {
|
||||
MCC_COMMPROTO_KEYWORD_SERVER_ACK_STR, MCC_COMMPROTO_KEYWORD_SERVER_ERROR_STR,
|
||||
MCC_COMMPROTO_KEYWORD_COORDFMT_STR, MCC_COMMPROTO_KEYWORD_COORDPREC_STR,
|
||||
MCC_COMMPROTO_KEYWORD_TARGET_STR, MCC_COMMPROTO_KEYWORD_MOUNT_STR,
|
||||
MCC_COMMPROTO_KEYWORD_ENTEREDTAG_STR, MCC_COMMPROTO_KEYWORD_TELEMETRY_STR,
|
||||
MCC_COMMPROTO_KEYWORD_INIT_STR, MCC_COMMPROTO_KEYWORD_STOP_STR,
|
||||
MCC_COMMPROTO_KEYWORD_SLEW_STR, MCC_COMMPROTO_KEYWORD_MOVE_STR,
|
||||
MCC_COMMPROTO_KEYWORD_TRACK_STR, MCC_COMMPROTO_KEYWORD_STATUS_STR};
|
||||
|
||||
|
||||
// hashes of valid keywords
|
||||
static constexpr std::array NETMSG_VALID_KEYWORD_HASHES = []<size_t... Is>(std::index_sequence<Is...>) {
|
||||
return std::array{mcc::utils::FNV1aHash(NETMSG_VALID_KEYWORDS[Is])...};
|
||||
}(std::make_index_sequence<NETMSG_VALID_KEYWORDS.size()>());
|
||||
|
||||
constexpr static const size_t* isKeywordValid(std::string_view key)
|
||||
{
|
||||
const auto hash = mcc::utils::FNV1aHash(key);
|
||||
|
||||
for (auto const& h : NETMSG_VALID_KEYWORD_HASHES) {
|
||||
if (h == hash) {
|
||||
return &h;
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
};
|
||||
|
||||
static_assert(mcc_netmsg_valid_keys_c<MccNetMessageValidKeywords>, "");
|
||||
|
||||
|
||||
template <typename T>
|
||||
concept mcc_netmessage_c = requires(T t) { T(); };
|
||||
|
||||
|
||||
|
||||
template <mcc::traits::mcc_char_range BYTEREPR_T = std::string_view,
|
||||
mcc_netmsg_valid_keys_c BASE_T = MccNetMessageValidKeywords>
|
||||
class MccNetMessage
|
||||
{
|
||||
protected:
|
||||
// just a wrapper class to hold MccSerializer<T> specializations
|
||||
struct DefaultSerializer {
|
||||
template <traits::mcc_output_char_range OR, typename T>
|
||||
auto operator()(OR& bytes, const T& value, mcc_serialization_params_c auto const& pars) const
|
||||
{
|
||||
return impl::MccSerializer<T>{}(bytes, value, pars);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
public:
|
||||
typedef BASE_T valid_keys_t;
|
||||
typedef BYTEREPR_T byte_repr_t;
|
||||
|
||||
enum MccNetMessageError { ERROR_OK, ERROR_EMPTY_MESSAGE, ERROR_INVALID_KEYWORD, ERROR_EMPTY_KEYWORD };
|
||||
|
||||
MccNetMessage() = default;
|
||||
|
||||
template <traits::mcc_input_char_range KT, typename... PTs>
|
||||
MccNetMessage(KT&& key, PTs&&... params)
|
||||
requires traits::mcc_output_char_range<BYTEREPR_T>
|
||||
{
|
||||
construct(_defaultSerializer, std::forward<KT>(key), std::forward<PTs>(params)...);
|
||||
}
|
||||
|
||||
template <traits::mcc_input_char_range R>
|
||||
constexpr MccNetMessage(const R& msg)
|
||||
requires traits::mcc_input_char_range<BYTEREPR_T>
|
||||
{
|
||||
fromCharRange(msg);
|
||||
}
|
||||
|
||||
// constexpr MccNetMessage(const BYTEREPR_T& msg)
|
||||
// requires traits::mcc_input_char_range<BYTEREPR_T>
|
||||
// {
|
||||
// fromCharRange(msg);
|
||||
// }
|
||||
|
||||
virtual ~MccNetMessage() = default;
|
||||
|
||||
template <traits::mcc_input_char_range KT>
|
||||
constexpr bool withKey(const KT& key) const
|
||||
{
|
||||
if constexpr (std::is_pointer_v<std::decay_t<KT>>) {
|
||||
return withKey(std::string_view{key});
|
||||
}
|
||||
|
||||
return mcc::utils::FNV1aHash(key) == _keywordHash;
|
||||
}
|
||||
|
||||
|
||||
template <traits::mcc_view_or_output_char_range R>
|
||||
R keyword() const
|
||||
{
|
||||
if constexpr (traits::mcc_char_view<R>) {
|
||||
return R{_keyword.begin(), _keyword.end()};
|
||||
} else {
|
||||
R r;
|
||||
std::ranges::copy(_keyword, std::back_inserter(r));
|
||||
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
std::string_view keyword() const
|
||||
{
|
||||
return _keyword;
|
||||
}
|
||||
|
||||
|
||||
size_t paramSize() const
|
||||
{
|
||||
return _params.size();
|
||||
}
|
||||
|
||||
template <std::ranges::range R>
|
||||
R params(size_t start_idx = 0, size_t Nelemes = std::numeric_limits<size_t>::max()) const
|
||||
requires(traits::mcc_view_or_output_char_range<R> || traits::mcc_range_of_char_range<R>)
|
||||
{
|
||||
if (start_idx >= _params.size()) {
|
||||
return R{};
|
||||
}
|
||||
|
||||
auto stop_idx = start_idx + Nelemes - 1;
|
||||
if (stop_idx >= _params.size()) {
|
||||
stop_idx = _params.size() - 1;
|
||||
}
|
||||
|
||||
if constexpr (traits::mcc_range_of_char_range<R>) { // returm parameters as array
|
||||
using el_t = std::ranges::range_value_t<R>;
|
||||
|
||||
R r;
|
||||
if constexpr (traits::mcc_char_view<el_t> || traits::mcc_output_char_range<el_t>) {
|
||||
for (size_t i = start_idx; i <= stop_idx; ++i) {
|
||||
auto& el = _params[i];
|
||||
std::back_inserter(r) = el_t{el.begin(), el.end()};
|
||||
}
|
||||
} else {
|
||||
static_assert(false, "UNSUPPORTED RANGE TYPE!!!");
|
||||
}
|
||||
|
||||
return r;
|
||||
} else {
|
||||
if constexpr (traits::mcc_char_view<R>) { // return joined parameters as a single char-range
|
||||
return R{_params[start_idx].begin(), _params[stop_idx].end()};
|
||||
} else {
|
||||
R r;
|
||||
std::ranges::copy(std::string_view{_params[start_idx].begin(), _params[stop_idx].end()},
|
||||
std::back_inserter(r));
|
||||
|
||||
return r;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::string_view params(size_t start_idx = 0, size_t Nelemes = std::numeric_limits<size_t>::max()) const
|
||||
{
|
||||
return params<std::string_view>(start_idx, Nelemes);
|
||||
}
|
||||
|
||||
template <traits::mcc_view_or_output_char_range R>
|
||||
R param(size_t idx) const
|
||||
{
|
||||
if (idx >= _params.size()) {
|
||||
return {};
|
||||
}
|
||||
|
||||
if constexpr (traits::mcc_char_view<R>) {
|
||||
return R{_params[idx].begin(), _params[idx].end()};
|
||||
} else {
|
||||
R r;
|
||||
std::ranges::copy(_params[idx], std::back_inserter(r));
|
||||
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
std::string_view param(size_t idx) const
|
||||
{
|
||||
if (idx >= _params.size()) {
|
||||
return {};
|
||||
}
|
||||
|
||||
return _params[idx];
|
||||
}
|
||||
|
||||
|
||||
template <typename T, typename DeserFuncT>
|
||||
std::expected<T, std::error_code> paramValue(size_t idx, DeserFuncT&& deser_func) const
|
||||
{
|
||||
static_assert(std::invocable<DeserFuncT, typename decltype(_params)::value_type const&, T&,
|
||||
impl::mcc_serialization_params_t const&>,
|
||||
"INVALID DESERIALIZATION FUNCTION!");
|
||||
static_assert(std::same_as<std::invoke_result_t<DeserFuncT, typename decltype(_params)::value_type const&, T&,
|
||||
impl::mcc_serialization_params_t const&>,
|
||||
std::error_code>,
|
||||
"INVALID DESERIALIZATION FUNCTION!");
|
||||
|
||||
if (idx >= _params.size()) {
|
||||
return std::unexpected{std::make_error_code(std::errc::value_too_large)};
|
||||
}
|
||||
|
||||
T val;
|
||||
|
||||
auto ec = std::forward<DeserFuncT>(deser_func)(_params[idx], val, _serializationParams);
|
||||
if (ec) {
|
||||
return std::unexpected(ec);
|
||||
} else {
|
||||
return val;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
std::expected<T, std::error_code> paramValue(size_t idx) const
|
||||
{
|
||||
return paramValue<T>(
|
||||
idx, impl::MccDeserializer<T>{}); // use one of specialization of MccDeserializer templated class
|
||||
}
|
||||
|
||||
|
||||
template <traits::mcc_view_or_output_char_range R>
|
||||
R byteRepr() const
|
||||
{
|
||||
if constexpr (traits::mcc_char_view<R>) {
|
||||
return R{_msgBuffer.begin(), _msgBuffer.end()};
|
||||
} else {
|
||||
R r;
|
||||
std::ranges::copy(_msgBuffer, std::back_inserter(r));
|
||||
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
std::string_view byteRepr() const
|
||||
{
|
||||
return byteRepr<std::string_view>();
|
||||
}
|
||||
|
||||
template <traits::mcc_input_char_range KT, typename... PTs>
|
||||
std::error_code construct(KT&& key, PTs&&... params)
|
||||
requires traits::mcc_output_char_range<BYTEREPR_T>
|
||||
{
|
||||
return construct(_defaultSerializer, std::forward<KT>(key), std::forward<PTs>(params)...);
|
||||
}
|
||||
|
||||
//
|
||||
// serializing function SerFuncT - a callable with the signature:
|
||||
// template<typename T, mcc_output_char_range R>
|
||||
// void ser_func(R&& buffer, const T& val, mcc_serialization_params_t const& pars)
|
||||
//
|
||||
template <typename SerFuncT, traits::mcc_input_char_range KT, typename... PTs>
|
||||
std::error_code construct(SerFuncT&& ser_func, KT&& key, PTs&&... params)
|
||||
requires(traits::mcc_output_char_range<BYTEREPR_T> &&
|
||||
!traits::mcc_input_char_range<std::remove_cvref_t<SerFuncT>>)
|
||||
{
|
||||
if constexpr (std::is_pointer_v<std::decay_t<KT>>) {
|
||||
return construct(std::forward<SerFuncT>(ser_func), std::string_view(key), std::forward<PTs>(params)...);
|
||||
}
|
||||
|
||||
|
||||
if (!std::ranges::size(key)) {
|
||||
return std::make_error_code(std::errc::invalid_argument);
|
||||
}
|
||||
|
||||
auto r = valid_keys_t::isKeywordValid(key);
|
||||
if (!r) {
|
||||
return std::make_error_code(std::errc::not_supported);
|
||||
}
|
||||
|
||||
_keywordHash = *r;
|
||||
|
||||
_msgBuffer = BYTEREPR_T{};
|
||||
|
||||
std::ranges::copy(std::forward<KT>(key), std::back_inserter(_msgBuffer));
|
||||
// _keyword = {_msgBuffer.begin(), _msgBuffer.end()};
|
||||
size_t key_idx = std::distance(_msgBuffer.begin(), _msgBuffer.end());
|
||||
std::vector<size_t> par_idx;
|
||||
|
||||
_params.clear();
|
||||
|
||||
if constexpr (sizeof...(PTs)) {
|
||||
std::ranges::copy(MCC_COMMPROTO_KEYPARAM_DELIM_SEQ, std::back_inserter(_msgBuffer));
|
||||
|
||||
convertFunc(std::forward<SerFuncT>(ser_func), par_idx, std::forward<PTs>(params)...);
|
||||
|
||||
for (size_t i = 0; i < par_idx.size(); i += 2) {
|
||||
_params.emplace_back(_msgBuffer.begin() + par_idx[i], _msgBuffer.begin() + par_idx[i + 1]);
|
||||
}
|
||||
}
|
||||
|
||||
_keyword = std::string_view{_msgBuffer.begin(), _msgBuffer.begin() + key_idx};
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
template <traits::mcc_input_char_range R>
|
||||
constexpr MccNetMessageError fromCharRange(const R& r)
|
||||
{
|
||||
if constexpr (std::is_pointer_v<std::decay_t<R>>) {
|
||||
return fromCharRange(std::string_view(r));
|
||||
}
|
||||
|
||||
|
||||
if (std::ranges::size(r) == 0) {
|
||||
return ERROR_EMPTY_MESSAGE;
|
||||
}
|
||||
|
||||
std::string_view key;
|
||||
|
||||
// auto prev_msg_buff = _msgBuffer;
|
||||
|
||||
if constexpr (traits::mcc_output_char_range<BYTEREPR_T>) {
|
||||
_msgBuffer = BYTEREPR_T{};
|
||||
std::ranges::copy(r, std::back_inserter(_msgBuffer));
|
||||
} else {
|
||||
_msgBuffer = {std::begin(r), std::end(r)};
|
||||
}
|
||||
|
||||
auto found = std::ranges::search(_msgBuffer, MCC_COMMPROTO_KEYPARAM_DELIM_SEQ);
|
||||
|
||||
if (found.empty()) { // only keyword
|
||||
key = mcc::utils::trimSpaces(std::string_view{_msgBuffer.begin(), _msgBuffer.end()});
|
||||
} else {
|
||||
key = mcc::utils::trimSpaces(std::string_view{_msgBuffer.begin(), found.begin()});
|
||||
}
|
||||
|
||||
auto kv = valid_keys_t::isKeywordValid(key);
|
||||
if (!kv) {
|
||||
// _msgBuffer = prev_msg_buff; // restore previous netmessage state
|
||||
return ERROR_INVALID_KEYWORD;
|
||||
}
|
||||
|
||||
_keywordHash = *kv;
|
||||
_keyword = key;
|
||||
|
||||
if (!found.empty()) { // params ...
|
||||
_params.clear();
|
||||
auto pr =
|
||||
std::views::split(std::string_view{found.end(), _msgBuffer.end()}, MCC_COMMPROTO_PARAMPARAM_DELIM_SEQ);
|
||||
for (auto const& p : pr) {
|
||||
_params.emplace_back(p.begin(), p.end());
|
||||
}
|
||||
}
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
protected:
|
||||
size_t _keywordHash{};
|
||||
std::string_view _keyword{};
|
||||
std::vector<std::string_view> _params{};
|
||||
|
||||
BYTEREPR_T _msgBuffer{};
|
||||
|
||||
DefaultSerializer _defaultSerializer{};
|
||||
|
||||
impl::mcc_serialization_params_t _serializationParams{.seq_delim{MCC_COMMPROTO_PARAMPARAM_DELIM_SEQ},
|
||||
.elem_delim{MCC_COMMPROTO_RANGEPARAM_DELIM_SEQ}};
|
||||
|
||||
template <typename SerFuncT, typename T, typename... Ts>
|
||||
void convertFunc(SerFuncT&& ser_func, std::vector<size_t>& idx, const T& par, const Ts&... pars)
|
||||
{
|
||||
if constexpr (std::same_as<T, MccSerializedCoordPairFormat>) {
|
||||
_serializationParams.coordpair_format = par;
|
||||
} else if constexpr (std::same_as<T, MccSerializedAngleFormatPrec>) {
|
||||
_serializationParams.angle_prec = par;
|
||||
} else {
|
||||
idx.emplace_back(std::distance(_msgBuffer.begin(), _msgBuffer.end()));
|
||||
|
||||
std::forward<SerFuncT>(ser_func)(_msgBuffer, par, _serializationParams);
|
||||
|
||||
idx.emplace_back(std::distance(_msgBuffer.begin(), _msgBuffer.end()));
|
||||
|
||||
if constexpr (sizeof...(Ts)) {
|
||||
std::ranges::copy(_serializationParams.seq_delim, std::back_inserter(_msgBuffer));
|
||||
}
|
||||
}
|
||||
|
||||
if constexpr (sizeof...(Ts)) {
|
||||
convertFunc(std::forward<SerFuncT>(ser_func), idx, pars...);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
static_assert(MccNetMessage<std::string, MccNetMessageValidKeywords>{"ACK"}.withKey("ACK"));
|
||||
static_assert(MccNetMessage{"ACK"}.withKey("ACK"));
|
||||
|
||||
} // namespace mcc::network
|
||||
@@ -2,15 +2,21 @@
|
||||
#pragma once
|
||||
|
||||
|
||||
/* MOUNT CONTROL COMPONENTS LIBRARY */
|
||||
/****************************************************************************************
|
||||
* *
|
||||
* MOUNT CONTROL COMPONENTS LIBRARY *
|
||||
* *
|
||||
* *
|
||||
* A REFERENCE "POINTING-CORRECTION-MODEL" CLASS IMPLEMENTATION *
|
||||
* *
|
||||
****************************************************************************************/
|
||||
|
||||
/* A REFERENCE "POINTING-CORRECTION-MODEL" CLASS IMPLEMENTATION */
|
||||
|
||||
|
||||
#include <mutex>
|
||||
|
||||
#ifdef USE_BSPLINE_PCM
|
||||
#include "fitpack/mcc_bsplines.h"
|
||||
#include "mcc_bsplines.h"
|
||||
#endif
|
||||
|
||||
#include "mcc_concepts.h"
|
||||
@@ -26,7 +32,8 @@ enum class MccDefaultPCMErrorCode : int {
|
||||
ERROR_INVALID_INPUTS_BISPLEV,
|
||||
#endif
|
||||
ERROR_EXCEED_MAX_ITERS,
|
||||
ERROR_NULLPTR
|
||||
ERROR_NULLPTR,
|
||||
ERROR_JACINV
|
||||
};
|
||||
|
||||
/* error category definition */
|
||||
@@ -37,7 +44,7 @@ struct MccDefaultPCMCategory : public std::error_category {
|
||||
|
||||
const char* name() const noexcept
|
||||
{
|
||||
return "ADC_GENERIC_DEVICE";
|
||||
return "MCC-DEFAULT-PCM-ERROR-CATEGORY";
|
||||
}
|
||||
|
||||
std::string message(int ec) const
|
||||
@@ -57,6 +64,8 @@ struct MccDefaultPCMCategory : public std::error_category {
|
||||
return "exceed maximum of iterations number";
|
||||
case MccDefaultPCMErrorCode::ERROR_NULLPTR:
|
||||
return "nullptr input argument";
|
||||
case MccDefaultPCMErrorCode::ERROR_JACINV:
|
||||
return "Jacobian is near singular";
|
||||
default:
|
||||
return "UNKNOWN";
|
||||
}
|
||||
@@ -112,7 +121,8 @@ template <MccMountType MOUNT_TYPE>
|
||||
class MccDefaultPCM : public mcc_pcm_interface_t<std::error_code>
|
||||
{
|
||||
public:
|
||||
static constexpr MccMountType mountType = MOUNT_TYPE;
|
||||
// static constexpr MccMountType mountType = MOUNT_TYPE;
|
||||
static constexpr MccMountType pcmMountType = MOUNT_TYPE;
|
||||
|
||||
#ifdef USE_BSPLINE_PCM
|
||||
static constexpr std::string_view pcmName{"MCC-GEOMETRY-BSPLINES-PCM"};
|
||||
@@ -156,6 +166,9 @@ public:
|
||||
|
||||
std::vector<coeff_t> coeffsX{};
|
||||
std::vector<coeff_t> coeffsY{};
|
||||
|
||||
std::vector<coeff_t> inverseCoeffsX{};
|
||||
std::vector<coeff_t> inverseCoeffsY{};
|
||||
};
|
||||
#endif
|
||||
|
||||
@@ -293,7 +306,7 @@ public:
|
||||
// to be computed as observed celestial X and Y cordinate according to mount type (HA-DEC or AZ-ZD)
|
||||
double x, y;
|
||||
|
||||
auto getXY = [&, this](auto& cp) {
|
||||
auto getXY = [&, this](auto& cp) -> error_t {
|
||||
auto err = obs_skycoord.toAtSameEpoch(cp);
|
||||
if (err) {
|
||||
return mcc_deduced_err(err, MccDefaultPCMErrorCode::ERROR_CCTE);
|
||||
@@ -315,13 +328,65 @@ public:
|
||||
|
||||
std::lock_guard lock(*_pcmDataMutex);
|
||||
|
||||
ret = _compResult(x, y, res, true);
|
||||
if (!ret) {
|
||||
if (_pcmData.type != MccDefaultPCMType::PCM_TYPE_BSPLINE) { // compute using Newton-Raphson correction
|
||||
struct {
|
||||
double pcmX, pcmY;
|
||||
} dfx, dfy, df; // partial derivatives
|
||||
|
||||
ret = _computeFuncDeriv(x, y, res, true, &dfx, &dfy);
|
||||
if (!ret) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
dfx.pcmX += 1.0; // a
|
||||
dfx.pcmY += 1.0; // b
|
||||
dfy.pcmX += 1.0; // c
|
||||
dfy.pcmY += 1.0; // d
|
||||
|
||||
// Jacobian determinant
|
||||
auto detJ = dfx.pcmX * dfy.pcmY - dfx.pcmY * dfy.pcmX;
|
||||
if (utils::isEqual(detJ, 0.0)) {
|
||||
return MccDefaultPCMErrorCode::ERROR_JACINV;
|
||||
}
|
||||
|
||||
// | a b |
|
||||
// if A = | c d |, then
|
||||
//
|
||||
// -1 | d -b |
|
||||
// A = 1/detA * | -c a |
|
||||
//
|
||||
|
||||
df.pcmX = dfy.pcmY * res->pcmX - dfx.pcmY * res->pcmY;
|
||||
df.pcmY = -dfy.pcmX * res->pcmX + dfx.pcmX * res->pcmY;
|
||||
|
||||
res->pcmX -= df.pcmX;
|
||||
res->pcmY -= df.pcmY;
|
||||
|
||||
if constexpr (mcc_coord_pair_c<T>) {
|
||||
*hw_pt = MccCoordPair<typename T::x_t, typename T::y_t>{x + res->pcmX, y + res->pcmY};
|
||||
*hw_pt = MccCoordPair<typename T::x_t, typename T::y_t>{res->pcmX, res->pcmY, obs_skycoord.epoch()};
|
||||
}
|
||||
} else { // for B-splines the result is computed directly from inverse B-spline coefficients
|
||||
ret = _computeFuncDeriv(x, y, res);
|
||||
|
||||
if (!ret) {
|
||||
if constexpr (mcc_coord_pair_c<T>) {
|
||||
*hw_pt = MccCoordPair<typename T::x_t, typename T::y_t>{x + res->pcmX, y + res->pcmY,
|
||||
obs_skycoord.epoch()};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// ret = _compResult(x, y, res, true);
|
||||
// if (!ret) {
|
||||
// if constexpr (mcc_coord_pair_c<T>) {
|
||||
// *hw_pt =
|
||||
// MccCoordPair<typename T::x_t, typename T::y_t>{x + res->pcmX, y + res->pcmY,
|
||||
// obs_skycoord.epoch()};
|
||||
// }
|
||||
// }
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -382,6 +447,204 @@ private:
|
||||
|
||||
std::unique_ptr<std::mutex> _pcmDataMutex{new std::mutex};
|
||||
|
||||
|
||||
// compute PCM function and its partial derivatives if asked
|
||||
template <typename DXT = std::nullptr_t, typename DYT = std::nullptr_t>
|
||||
error_t _computeFuncDeriv(double x,
|
||||
double y,
|
||||
mcc_pcm_result_c auto* res,
|
||||
bool inverse = false,
|
||||
DXT derivX = nullptr,
|
||||
DYT derivY = nullptr)
|
||||
requires((std::is_null_pointer_v<DXT> || mcc_pcm_result_c<std::remove_pointer_t<DXT>>) &&
|
||||
(std::is_null_pointer_v<DYT> || mcc_pcm_result_c<std::remove_pointer_t<DYT>>))
|
||||
{
|
||||
if constexpr (std::is_null_pointer_v<DXT> || std::is_null_pointer_v<DYT>) {
|
||||
if (_pcmData.type != MccDefaultPCMType::PCM_TYPE_BSPLINE && inverse) {
|
||||
return MccDefaultPCMErrorCode::ERROR_NULLPTR;
|
||||
}
|
||||
}
|
||||
|
||||
pcm_geom_coeffs_t* geom_coeffs = &_pcmData.geomCoefficients;
|
||||
|
||||
#ifdef USE_BSPLINE_PCM
|
||||
pcm_bspline_t* bspline = &_pcmData.bspline;
|
||||
// pcm_bspline_t* inv_bspline = &_pcmData.inverseBspline;
|
||||
#endif
|
||||
|
||||
#ifdef USE_BSPLINE_PCM
|
||||
if (_pcmData.type == MccDefaultPCMType::PCM_TYPE_GEOMETRY ||
|
||||
_pcmData.type == MccDefaultPCMType::PCM_TYPE_GEOMETRY_BSPLINE) {
|
||||
#endif
|
||||
const auto tanY = std::tan(y);
|
||||
const auto sinX = std::sin(x);
|
||||
const auto cosX = std::cos(x);
|
||||
const auto cosY = std::cos(y);
|
||||
const auto sinY = std::sin(y);
|
||||
|
||||
|
||||
if (utils::isEqual(cosY, 0.0)) {
|
||||
res->pcmX = _pcmData.geomCoefficients.zeroPointX;
|
||||
if constexpr (!std::is_null_pointer_v<DXT>) {
|
||||
derivX->pcmX = 0.0; // dpcmX/dX
|
||||
derivX->pcmY = 0.0; // dpcmX/dY
|
||||
}
|
||||
} else {
|
||||
res->pcmX = geom_coeffs->zeroPointX + geom_coeffs->collimationErr / cosY +
|
||||
geom_coeffs->nonperpendErr * tanY - geom_coeffs->misalignErr1 * cosX * tanY +
|
||||
geom_coeffs->misalignErr2 * sinX * tanY + geom_coeffs->tubeFlexure * _cosPhi * sinX / cosY -
|
||||
geom_coeffs->DECaxisFlexure * (_cosPhi * cosX + _sinPhi * tanY);
|
||||
|
||||
if constexpr (!std::is_null_pointer_v<DXT>) {
|
||||
auto cos2Y = cosY * cosY;
|
||||
|
||||
derivX->pcmX = (geom_coeffs->misalignErr1 * sinX + geom_coeffs->misalignErr2 * cosX) * tanY +
|
||||
geom_coeffs->tubeFlexure * _cosPhi * cosX / cosY +
|
||||
geom_coeffs->DECaxisFlexure * _cosPhi * sinX; // dpcmX/dX
|
||||
|
||||
derivX->pcmY =
|
||||
(geom_coeffs->collimationErr * sinY + geom_coeffs->nonperpendErr -
|
||||
geom_coeffs->misalignErr1 * cosX + geom_coeffs->misalignErr2 * sinX +
|
||||
geom_coeffs->tubeFlexure * _cosPhi * sinX * sinY - geom_coeffs->DECaxisFlexure * _sinPhi) /
|
||||
cos2Y; // dpcmX/dY
|
||||
}
|
||||
}
|
||||
|
||||
res->pcmY = geom_coeffs->zeroPointY + geom_coeffs->misalignErr1 * sinX + geom_coeffs->misalignErr2 * cosX +
|
||||
geom_coeffs->tubeFlexure * (_cosPhi * cosX * sinY - _sinPhi * cosY);
|
||||
|
||||
if constexpr (!std::is_null_pointer_v<DYT>) {
|
||||
derivY->pcmX = geom_coeffs->misalignErr1 * cosX - geom_coeffs->misalignErr2 * sinX -
|
||||
geom_coeffs->tubeFlexure * _cosPhi * sinX * sinY; // dpcmY/dX
|
||||
|
||||
derivY->pcmY = geom_coeffs->tubeFlexure * (_cosPhi * cosX * cosY + _sinPhi * sinY); // dpcmY/dY
|
||||
}
|
||||
|
||||
if constexpr (pcmMountType == MccMountType::FORK_TYPE) {
|
||||
if (!utils::isEqual(cosX, 0.0)) {
|
||||
res->pcmY += geom_coeffs->forkFlexure / cosX;
|
||||
|
||||
if constexpr (!std::is_null_pointer_v<DYT>) {
|
||||
derivY->pcmY += geom_coeffs->forkFlexure * sinX / cosX / cosY; // dpcmY/dY
|
||||
}
|
||||
}
|
||||
}
|
||||
#ifdef USE_BSPLINE_PCM
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef USE_BSPLINE_PCM
|
||||
if (_pcmData.type == MccDefaultPCMType::PCM_TYPE_BSPLINE ||
|
||||
(_pcmData.type == MccDefaultPCMType::PCM_TYPE_GEOMETRY_BSPLINE && !inverse)) {
|
||||
double spl_valX, spl_valY;
|
||||
|
||||
int ret = bsplines::fitpack_eval_spl2d(bspline->knotsX, bspline->knotsY, bspline->coeffsX, x, y, spl_valX,
|
||||
bspline->bsplDegreeX, bspline->bsplDegreeY);
|
||||
|
||||
if (ret) {
|
||||
res->pcmX = std::numeric_limits<double>::quiet_NaN();
|
||||
res->pcmY = std::numeric_limits<double>::quiet_NaN();
|
||||
return MccDefaultPCMErrorCode::ERROR_INVALID_INPUTS_BISPLEV;
|
||||
}
|
||||
|
||||
|
||||
ret = bsplines::fitpack_eval_spl2d(bspline->knotsX, bspline->knotsY, bspline->coeffsY, x, y, spl_valY,
|
||||
bspline->bsplDegreeX, bspline->bsplDegreeY);
|
||||
|
||||
if (ret) {
|
||||
res->pcmX = std::numeric_limits<double>::quiet_NaN();
|
||||
res->pcmY = std::numeric_limits<double>::quiet_NaN();
|
||||
return MccDefaultPCMErrorCode::ERROR_INVALID_INPUTS_BISPLEV;
|
||||
}
|
||||
|
||||
|
||||
res->pcmX += spl_valX;
|
||||
res->pcmY += spl_valY;
|
||||
}
|
||||
|
||||
// compute partial derivatives of the bivariate B-spline
|
||||
if (_pcmData.type == MccDefaultPCMType::PCM_TYPE_GEOMETRY_BSPLINE && inverse) {
|
||||
double dspl_valX, dspl_valY;
|
||||
|
||||
int ret = 0;
|
||||
|
||||
if constexpr (!std::is_null_pointer_v<DXT>) {
|
||||
ret = bsplines::fitpack_parder_spl2d(bspline->knotsX, bspline->knotsY, bspline->coeffsX, x, y,
|
||||
dspl_valX, 1, 0, bspline->bsplDegreeX, bspline->bsplDegreeY);
|
||||
|
||||
if (ret) {
|
||||
return MccDefaultPCMErrorCode::ERROR_INVALID_INPUTS_BISPLEV;
|
||||
}
|
||||
|
||||
derivX->pcmX += dspl_valX; // dpcmX/dX
|
||||
|
||||
ret = bsplines::fitpack_parder_spl2d(bspline->knotsX, bspline->knotsY, bspline->coeffsX, x, y,
|
||||
dspl_valX, 0, 1, bspline->bsplDegreeX, bspline->bsplDegreeY);
|
||||
|
||||
if (ret) {
|
||||
return MccDefaultPCMErrorCode::ERROR_INVALID_INPUTS_BISPLEV;
|
||||
}
|
||||
|
||||
derivX->pcmY += dspl_valX; // dpcmX/dY
|
||||
}
|
||||
|
||||
if constexpr (!std::is_null_pointer_v<DYT>) {
|
||||
ret = bsplines::fitpack_parder_spl2d(bspline->knotsX, bspline->knotsY, bspline->coeffsY, x, y,
|
||||
dspl_valY, 1, 0, bspline->bsplDegreeX, bspline->bsplDegreeY);
|
||||
|
||||
if (ret) {
|
||||
return MccDefaultPCMErrorCode::ERROR_INVALID_INPUTS_BISPLEV;
|
||||
}
|
||||
|
||||
derivY->pcmX += dspl_valY; // dpcmY/dX
|
||||
|
||||
ret = bsplines::fitpack_parder_spl2d(bspline->knotsX, bspline->knotsY, bspline->coeffsY, x, y,
|
||||
dspl_valY, 0, 1, bspline->bsplDegreeX, bspline->bsplDegreeY);
|
||||
|
||||
if (ret) {
|
||||
return MccDefaultPCMErrorCode::ERROR_INVALID_INPUTS_BISPLEV;
|
||||
}
|
||||
|
||||
derivY->pcmY += dspl_valY; // dpcmY/dY
|
||||
}
|
||||
}
|
||||
|
||||
// for inverse PCM the inverse spline coefficients are used (derivatives are not computed)!!!
|
||||
if (_pcmData.type == MccDefaultPCMType::PCM_TYPE_BSPLINE && inverse) {
|
||||
double spl_valX, spl_valY;
|
||||
|
||||
int ret = bsplines::fitpack_eval_spl2d(bspline->knotsX, bspline->knotsY, bspline->inverseCoeffsX, x, y,
|
||||
spl_valX, bspline->bsplDegreeX, bspline->bsplDegreeY);
|
||||
|
||||
if (ret) {
|
||||
res->pcmX = std::numeric_limits<double>::quiet_NaN();
|
||||
res->pcmY = std::numeric_limits<double>::quiet_NaN();
|
||||
|
||||
return MccDefaultPCMErrorCode::ERROR_INVALID_INPUTS_BISPLEV;
|
||||
}
|
||||
|
||||
|
||||
ret = bsplines::fitpack_eval_spl2d(bspline->knotsX, bspline->knotsY, bspline->inverseCoeffsY, x, y,
|
||||
spl_valY, bspline->bsplDegreeX, bspline->bsplDegreeY);
|
||||
|
||||
if (ret) {
|
||||
res->pcmX = std::numeric_limits<double>::quiet_NaN();
|
||||
res->pcmY = std::numeric_limits<double>::quiet_NaN();
|
||||
|
||||
return MccDefaultPCMErrorCode::ERROR_INVALID_INPUTS_BISPLEV;
|
||||
}
|
||||
|
||||
|
||||
res->pcmX = spl_valX;
|
||||
res->pcmY = spl_valY;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
return MccDefaultPCMErrorCode::ERROR_OK;
|
||||
}
|
||||
|
||||
error_t _compResult(double x, double y, mcc_pcm_result_c auto* res, bool inverse)
|
||||
{
|
||||
pcm_geom_coeffs_t* geom_coeffs;
|
||||
@@ -394,11 +657,10 @@ private:
|
||||
bspline = inverse ? &_pcmData.inverseBspline : &_pcmData.bspline;
|
||||
#endif
|
||||
|
||||
if (_pcmData.type == MccDefaultPCMType::PCM_TYPE_GEOMETRY
|
||||
#ifdef USE_BSPLINE_PCM
|
||||
|| _pcmData.type == MccDefaultPCMType::PCM_TYPE_GEOMETRY_BSPLINE
|
||||
if (_pcmData.type == MccDefaultPCMType::PCM_TYPE_GEOMETRY ||
|
||||
_pcmData.type == MccDefaultPCMType::PCM_TYPE_GEOMETRY_BSPLINE) {
|
||||
#endif
|
||||
) {
|
||||
const auto tanY = std::tan(y);
|
||||
const auto sinX = std::sin(x);
|
||||
const auto cosX = std::cos(x);
|
||||
@@ -417,12 +679,15 @@ private:
|
||||
res->pcmY = geom_coeffs->zeroPointY + geom_coeffs->misalignErr1 * sinX + geom_coeffs->misalignErr2 * cosX +
|
||||
geom_coeffs->tubeFlexure * (_cosPhi * cosX * std::sin(y) - _sinPhi * cosY);
|
||||
|
||||
if constexpr (mountType == MccMountType::FORK_TYPE) {
|
||||
// if constexpr (mountType == MccMountType::FORK_TYPE) {
|
||||
if constexpr (pcmMountType == MccMountType::FORK_TYPE) {
|
||||
if (!utils::isEqual(cosX, 0.0)) {
|
||||
res->pcmY += geom_coeffs->forkFlexure / cosX;
|
||||
}
|
||||
}
|
||||
#ifdef USE_BSPLINE_PCM
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef USE_BSPLINE_PCM
|
||||
373
include/mcc/mcc_pcm_construct.h
Normal file
373
include/mcc/mcc_pcm_construct.h
Normal file
@@ -0,0 +1,373 @@
|
||||
#pragma once
|
||||
|
||||
/****************************************************************************************
|
||||
* *
|
||||
* MOUNT CONTROL COMPONENTS LIBRARY *
|
||||
* *
|
||||
* *
|
||||
* "POINTING-CORRECTION-MODEL" FITTER *
|
||||
* *
|
||||
****************************************************************************************/
|
||||
|
||||
#include <eigen3/Eigen/Dense>
|
||||
|
||||
#include "mcc_concepts.h"
|
||||
#include "mcc_coordinate.h"
|
||||
#include "mcc_pcm.h"
|
||||
|
||||
namespace mcc::impl
|
||||
{
|
||||
|
||||
enum class MccDefaultPCMConstructorErrorCode : int {
|
||||
ERROR_OK,
|
||||
ERROR_NOT_ENOUGH_DATA,
|
||||
#ifdef USE_BSPLINE_PCM
|
||||
ERROR_INVALID_KNOTS_NUMBER,
|
||||
ERROR_BSPLINE_FIT
|
||||
#endif
|
||||
};
|
||||
|
||||
// error category
|
||||
|
||||
struct MccDefaultPCMConstructorErrorCategory : std::error_category {
|
||||
MccDefaultPCMConstructorErrorCategory() = default;
|
||||
|
||||
const char* name() const noexcept
|
||||
{
|
||||
return "MCC-DEFAULT-PCM-CONSTRUCTOR-ERROR-CATEGORY";
|
||||
}
|
||||
|
||||
std::string message(int ec) const
|
||||
{
|
||||
MccDefaultPCMConstructorErrorCode err = static_cast<MccDefaultPCMConstructorErrorCode>(ec);
|
||||
|
||||
switch (err) {
|
||||
case MccDefaultPCMConstructorErrorCode::ERROR_OK:
|
||||
return "OK";
|
||||
case MccDefaultPCMConstructorErrorCode::ERROR_NOT_ENOUGH_DATA:
|
||||
return "not enough data point";
|
||||
|
||||
#ifdef USE_BSPLINE_PCM
|
||||
case MccDefaultPCMConstructorErrorCode::ERROR_INVALID_KNOTS_NUMBER:
|
||||
return "invalid number of B-spline knots";
|
||||
case MccDefaultPCMConstructorErrorCode::ERROR_BSPLINE_FIT:
|
||||
return "B-spline fitting error";
|
||||
#endif
|
||||
default:
|
||||
return "UNKNOWN";
|
||||
}
|
||||
}
|
||||
|
||||
static const MccDefaultPCMConstructorErrorCategory& get()
|
||||
{
|
||||
static const MccDefaultPCMConstructorErrorCategory constInst;
|
||||
return constInst;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
inline std::error_code make_error_code(MccDefaultPCMConstructorErrorCode ec)
|
||||
{
|
||||
return std::error_code(static_cast<int>(ec), MccDefaultPCMConstructorErrorCategory::get());
|
||||
}
|
||||
|
||||
} // namespace mcc::impl
|
||||
|
||||
|
||||
namespace std
|
||||
{
|
||||
|
||||
template <>
|
||||
class is_error_code_enum<mcc::impl::MccDefaultPCMConstructorErrorCode> : public true_type
|
||||
{
|
||||
};
|
||||
|
||||
|
||||
} // namespace std
|
||||
|
||||
namespace mcc::impl
|
||||
{
|
||||
|
||||
template <MccMountType MOUNT_TYPE>
|
||||
class MccPCMConstructor
|
||||
{
|
||||
public:
|
||||
using ref_coordpair_t = std::conditional_t<mcc_is_equatorial_mount<MOUNT_TYPE>,
|
||||
MccSkyHADEC_OBS,
|
||||
std::conditional_t<mcc_is_altaz_mount<MOUNT_TYPE>, MccSkyAZZD, void>>;
|
||||
|
||||
static_assert(!std::is_void_v<ref_coordpair_t>, "UNSUPPORTED MOUNT TYPE!");
|
||||
|
||||
struct table_elem_t {
|
||||
double target_colon, target_colat;
|
||||
double hw_colon, hw_colat;
|
||||
double colon_res, colat_res; // target - hw
|
||||
};
|
||||
|
||||
|
||||
struct table_t {
|
||||
std::vector<double> target_colon, target_colat;
|
||||
std::vector<double> hw_colon, hw_colat;
|
||||
std::vector<double> colon_res, colat_res; // target - hw
|
||||
};
|
||||
|
||||
struct compute_result_t {
|
||||
MccDefaultPCMType pcm_type;
|
||||
MccError error{}; // final model computation error
|
||||
|
||||
std::vector<double> model_colon, model_colat; // fitted model values
|
||||
std::vector<double> colon_res, colat_res; // target - model
|
||||
|
||||
#ifdef USE_BSPLINE_PCM
|
||||
int bspline_fit_err{}; // bivariate B-spline fitting exit code (see FITPACK)
|
||||
|
||||
// quantities below are computed only fo pcm_type == MccDefaultPCMType::PCM_TYPE_BSPLINE
|
||||
std::vector<double> inv_model_colon, inv_model_colat; // fitted inverse model values
|
||||
std::vector<double> inv_colon_res, inv_colat_res; // encoder - model
|
||||
#endif
|
||||
};
|
||||
|
||||
MccError addPoint(mcc_skypoint_c auto target_coords,
|
||||
mcc_coord_pair_c auto const& hw_counts,
|
||||
mcc_coord_epoch_c auto const& ref_epoch)
|
||||
requires(decltype(hw_counts)::pairKind == MccCoordPairKind::COORDS_KIND_XY)
|
||||
{
|
||||
auto err = target_coords.to(ref_coordpair_t::pairKind, ref_epoch);
|
||||
if (err) {
|
||||
return mcc_deduced_err(err, MccDefaultPCMErrorCode::ERROR_CCTE);
|
||||
}
|
||||
|
||||
// _table.push_back({target_coords.co_lon(), target_coords.co_lat(), hw_counts.x(), hw_counts.y(),
|
||||
// target_coords.co_lon() - hw_counts.x(), target_coords.co_lat() - hw_counts.y()});
|
||||
|
||||
_table.target_colon.emplace_back(target_coords.co_lon());
|
||||
_table.target_colat.emplace_back(target_coords.co_lon());
|
||||
|
||||
_table.hw_colon.emplace_back(hw_counts.x());
|
||||
_table.hw_colat.emplace_back(hw_counts.y());
|
||||
|
||||
_table.colon_res.emplace_back(target_coords.co_lon() - hw_counts.x());
|
||||
_table.colat_res.emplace_back(target_coords.co_lat() - hw_counts.y());
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
|
||||
MccError addPoint(mcc_skypoint_c auto target_coords, mcc_coord_pair_c auto const& hw_counts)
|
||||
{
|
||||
auto ref_epoch = hw_counts.epoch();
|
||||
|
||||
return addPoint(std::move(target_coords), hw_counts, ref_epoch);
|
||||
}
|
||||
|
||||
|
||||
size_t numberOfPoints() const
|
||||
{
|
||||
return _table.colon_res.size();
|
||||
}
|
||||
|
||||
void deletePoints()
|
||||
{
|
||||
_table.target_colon.clear();
|
||||
_table.target_colat.clear();
|
||||
|
||||
_table.hw_colon.clear();
|
||||
_table.hw_colat.clear();
|
||||
|
||||
_table.colon_res.clear();
|
||||
_table.colat_res.clear();
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// for B-splines interior knots along axes must be given in 'pcm_data'
|
||||
// NOTE: the size of the interior knots array must be at least 2 as
|
||||
// it are interpretated as border knots and final full knots set is:
|
||||
// knots = [input_knots[0], input_knots[0], input_knots[0], input_knots[0], input_knots[1], input_knots[2],
|
||||
// ..., input_knots[N-1], input_knots[N-1], input_knots[N-1], input_knots[N-1]], where N = input_knots.size()
|
||||
//
|
||||
// WARNING: the input knots for inverse B-spline are ignored so the direct and inverse B-spline coefficients are
|
||||
// calculated on the same mesh!
|
||||
compute_result_t computeModel(MccDefaultPCM<MOUNT_TYPE>::pcm_data_t& pcm_data)
|
||||
{
|
||||
compute_result_t result{.pcm_type = pcm_data.type, .error = MccDefaultPCMConstructorErrorCode::ERROR_OK};
|
||||
|
||||
size_t min_data_size = 2; // 2 is for BSPLINE
|
||||
|
||||
if (pcm_data.type == MccDefaultPCMType::PCM_TYPE_GEOMETRY
|
||||
#ifdef USE_BSPLINE_PCM
|
||||
|| pcm_data.type == MccDefaultPCMType::PCM_TYPE_GEOMETRY_BSPLINE
|
||||
#endif
|
||||
) {
|
||||
if constexpr (MOUNT_TYPE == MccMountType::FORK_TYPE) {
|
||||
min_data_size = 9;
|
||||
} else {
|
||||
min_data_size = 8;
|
||||
}
|
||||
|
||||
if (_table.size() < min_data_size) {
|
||||
result.error = MccDefaultPCMConstructorErrorCode::ERROR_NOT_ENOUGH_DATA;
|
||||
return result;
|
||||
}
|
||||
|
||||
// robust linear regression with Tukey's loss function
|
||||
}
|
||||
|
||||
|
||||
#ifdef USE_BSPLINE_PCM
|
||||
if (pcm_data.type == MccDefaultPCMType::PCM_TYPE_BSPLINE ||
|
||||
pcm_data.type == MccDefaultPCMType::PCM_TYPE_GEOMETRY_BSPLINE) {
|
||||
if (pcm_data.bspline.knotsX.size() < 2 || pcm_data.bspline.knotsY.size() < 2) {
|
||||
return MccDefaultPCMConstructorErrorCode::ERROR_INVALID_KNOTS_NUMBER;
|
||||
}
|
||||
|
||||
double resi2x, resi2y; // fitting residuals
|
||||
|
||||
std::vector<double> tx(pcm_data.bspline.knotsX.size() + 6), ty(pcm_data.bspline.knotsY.size() + 6);
|
||||
|
||||
size_t Ncoeffs = (tx.size() - 4) * (ty.size() - 4);
|
||||
|
||||
pcm_data.bspline.coeffsX.resize(Ncoeffs);
|
||||
pcm_data.bspline.coeffsY.resize(Ncoeffs);
|
||||
|
||||
if (pcm_data.type == MccDefaultPCMType::PCM_TYPE_BSPLINE) {
|
||||
if (_table.size() < min_data_size) {
|
||||
result.error = MccDefaultPCMConstructorErrorCode::ERROR_NOT_ENOUGH_DATA;
|
||||
return result;
|
||||
}
|
||||
|
||||
// here both direct and inverse coefficients will be calculated
|
||||
pcm_data.inverseBspline.coeffsX.resize(Ncoeffs);
|
||||
pcm_data.inverseBspline.coeffsY.resize(Ncoeffs);
|
||||
|
||||
// direct (celestial = encoder + pcm)
|
||||
result.bspline_fit_err = bsplines::fitpack_sphere_fit(
|
||||
_table.hw_colat, _table.hw_colon, _table.colon_res, 1.0, pcm_data.bspline.knotsY,
|
||||
pcm_data.bspline.knotsX, pcm_data.bspline.coeffsX, resi2x);
|
||||
if (result.bspline_fit_err > 0) {
|
||||
result.error = MccDefaultPCMConstructorErrorCode::ERROR_BSPLINE_FIT;
|
||||
return result;
|
||||
}
|
||||
|
||||
result.bspline_fit_err = bsplines::fitpack_sphere_fit(
|
||||
_table.hw_colat, _table.hw_colon, _table.colat_res, 1.0, pcm_data.bspline.knotsY,
|
||||
pcm_data.bspline.knotsX, pcm_data.bspline.coeffsY, resi2y);
|
||||
if (result.bspline_fit_err > 0) {
|
||||
result.error = MccDefaultPCMConstructorErrorCode::ERROR_BSPLINE_FIT;
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
// inverse (encoder = celestial + pcm)
|
||||
std::vector<double> colon_res = _table.colon_res;
|
||||
std::vector<double> colat_res = _table.colat_res;
|
||||
for (size_t i = 0; i < colat_res.size(); ++i) {
|
||||
colon_res[i] = -colon_res[i];
|
||||
colat_res[i] = -colat_res[i];
|
||||
}
|
||||
|
||||
result.bspline_fit_err = bsplines::fitpack_sphere_fit(
|
||||
_table.target_colon, _table.target_colat, colon_res, 1.0, pcm_data.bspline.knotsY,
|
||||
pcm_data.bspline.knotsX, pcm_data.bspline.inverseCoeffsX, resi2x);
|
||||
if (result.bspline_fit_err > 0) {
|
||||
result.error = MccDefaultPCMConstructorErrorCode::ERROR_BSPLINE_FIT;
|
||||
return result;
|
||||
}
|
||||
|
||||
result.bspline_fit_err = bsplines::fitpack_sphere_fit(
|
||||
_table.target_colon, _table.target_colat, colat_res, 1.0, pcm_data.bspline.knotsY,
|
||||
pcm_data.bspline.knotsX, pcm_data.bspline.inverseCoeffsY, resi2y);
|
||||
if (result.bspline_fit_err > 0) {
|
||||
result.error = MccDefaultPCMConstructorErrorCode::ERROR_BSPLINE_FIT;
|
||||
return result;
|
||||
}
|
||||
} else { // geometry + B-spline
|
||||
// the fitting for geometrical coefficients is already done above so
|
||||
// one must fit residuals by bivariate B-splines
|
||||
|
||||
std::vector<double> xres(_table.size()), yres(_table.size());
|
||||
// for (size_t i = 0; i < _table.size(); ++i) {
|
||||
// xres = _table[i].target_colon;
|
||||
// yres = _table[i].target_colat;
|
||||
// }
|
||||
for (size_t i = 0; i < _table.size(); ++i) {
|
||||
xres = _table.target_colon[i];
|
||||
yres = _table.target_colat[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
protected:
|
||||
// std::vector<table_elem_t> _table;
|
||||
table_t _table;
|
||||
|
||||
compute_result_t bsplineFitting(MccDefaultPCM<MOUNT_TYPE>::pcm_data_t& pcm_data)
|
||||
{
|
||||
compute_result_t result{.pcm_type = pcm_data.type, .error = MccDefaultPCMConstructorErrorCode::ERROR_OK};
|
||||
|
||||
if (pcm_data.bspline.knotsX.size() < 2 || pcm_data.bspline.knotsY.size() < 2) {
|
||||
return MccDefaultPCMConstructorErrorCode::ERROR_INVALID_KNOTS_NUMBER;
|
||||
}
|
||||
|
||||
double resi2x, resi2y; // fitting residuals
|
||||
|
||||
std::vector<double> tx(pcm_data.bspline.knotsX.size() + 6), ty(pcm_data.bspline.knotsY.size() + 6);
|
||||
|
||||
size_t Ncoeffs = (tx.size() - 4) * (ty.size() - 4);
|
||||
|
||||
pcm_data.bspline.coeffsX.resize(Ncoeffs);
|
||||
pcm_data.bspline.coeffsY.resize(Ncoeffs);
|
||||
|
||||
if (pcm_data.type == MccDefaultPCMType::PCM_TYPE_BSPLINE) {
|
||||
// here both direct and inverse coefficients will be calculated
|
||||
pcm_data.inverseBspline.coeffsX.resize(Ncoeffs);
|
||||
pcm_data.inverseBspline.coeffsY.resize(Ncoeffs);
|
||||
|
||||
// direct (celestial = encoder + pcm)
|
||||
result.bspline_fit_err = bsplines::fitpack_sphere_fit(_table.hw_colat, _table.hw_colon, _table.colon_res,
|
||||
1.0, pcm_data.bspline.knotsY, pcm_data.bspline.knotsX,
|
||||
pcm_data.bspline.coeffsX, resi2x);
|
||||
if (result.bspline_fit_err > 0) {
|
||||
result.error = MccDefaultPCMConstructorErrorCode::ERROR_BSPLINE_FIT;
|
||||
return result;
|
||||
}
|
||||
|
||||
result.bspline_fit_err = bsplines::fitpack_sphere_fit(_table.hw_colat, _table.hw_colon, _table.colat_res,
|
||||
1.0, pcm_data.bspline.knotsY, pcm_data.bspline.knotsX,
|
||||
pcm_data.bspline.coeffsY, resi2y);
|
||||
if (result.bspline_fit_err > 0) {
|
||||
result.error = MccDefaultPCMConstructorErrorCode::ERROR_BSPLINE_FIT;
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
// inverse (encoder = celestial + pcm)
|
||||
std::vector<double> colon_res = _table.colon_res;
|
||||
std::vector<double> colat_res = _table.colat_res;
|
||||
for (size_t i = 0; i < colat_res.size(); ++i) {
|
||||
colon_res[i] = -colon_res[i];
|
||||
colat_res[i] = -colat_res[i];
|
||||
}
|
||||
|
||||
result.bspline_fit_err = bsplines::fitpack_sphere_fit(_table.target_colon, _table.target_colat, colon_res,
|
||||
1.0, pcm_data.bspline.knotsY, pcm_data.bspline.knotsX,
|
||||
pcm_data.bspline.inverseCoeffsX, resi2x);
|
||||
if (result.bspline_fit_err > 0) {
|
||||
result.error = MccDefaultPCMConstructorErrorCode::ERROR_BSPLINE_FIT;
|
||||
return result;
|
||||
}
|
||||
|
||||
result.bspline_fit_err = bsplines::fitpack_sphere_fit(_table.target_colon, _table.target_colat, colat_res,
|
||||
1.0, pcm_data.bspline.knotsY, pcm_data.bspline.knotsX,
|
||||
pcm_data.bspline.inverseCoeffsY, resi2y);
|
||||
if (result.bspline_fit_err > 0) {
|
||||
result.error = MccDefaultPCMConstructorErrorCode::ERROR_BSPLINE_FIT;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace mcc::impl
|
||||
@@ -115,7 +115,7 @@ public:
|
||||
{
|
||||
auto sptr = std::make_shared<decltype(zone)>(std::move(zone));
|
||||
|
||||
_inZoneFunc.emplace_back([sptr](MccSkyPoint const& pt, bool* res) {
|
||||
_inZoneFunc.emplace_back([sptr](MccSkyPoint const& pt, bool* res) -> error_t {
|
||||
auto err = sptr->inPZone(pt, res);
|
||||
if (err) {
|
||||
return mcc_deduced_err(err, MccPZoneContainerErrorCode::ERROR_INZONE_FUNC);
|
||||
@@ -125,7 +125,7 @@ public:
|
||||
});
|
||||
|
||||
|
||||
_timeToZoneFunc.emplace_back([sptr](MccSkyPoint const& pt, duration_t* res) {
|
||||
_timeToZoneFunc.emplace_back([sptr](MccSkyPoint const& pt, duration_t* res) -> error_t {
|
||||
auto err = sptr->timeToPZone(pt, res);
|
||||
if (err) {
|
||||
return mcc_deduced_err(err, MccPZoneContainerErrorCode::ERROR_TIMETO_FUNC);
|
||||
@@ -135,7 +135,7 @@ public:
|
||||
});
|
||||
|
||||
|
||||
_timeFromZoneFunc.emplace_back([sptr](MccSkyPoint const& pt, duration_t* res) {
|
||||
_timeFromZoneFunc.emplace_back([sptr](MccSkyPoint const& pt, duration_t* res) -> error_t {
|
||||
auto err = sptr->timeFromPZone(pt, res);
|
||||
if (err) {
|
||||
return mcc_deduced_err(err, MccPZoneContainerErrorCode::ERROR_TIMEFROM_FUNC);
|
||||
@@ -144,17 +144,26 @@ public:
|
||||
return MccPZoneContainerErrorCode::ERROR_OK;
|
||||
});
|
||||
|
||||
_names.push_back(std::format("{}", zone.pzoneName));
|
||||
|
||||
return _inZoneFunc.size();
|
||||
}
|
||||
|
||||
void clearZones()
|
||||
void clearPZones()
|
||||
{
|
||||
_inZoneFunc.clear();
|
||||
_timeToZoneFunc.clear();
|
||||
_timeFromZoneFunc.clear();
|
||||
|
||||
_names.clear();
|
||||
}
|
||||
|
||||
|
||||
std::vector<std::string> pzoneNames() const
|
||||
{
|
||||
return _names;
|
||||
}
|
||||
|
||||
error_t inPZone(mcc_skypoint_c auto const& coords, bool* at_least_one, std::ranges::output_range<bool> auto* result)
|
||||
{
|
||||
auto err = forEach(_inZoneFunc, coords, result);
|
||||
@@ -188,9 +197,11 @@ public:
|
||||
protected:
|
||||
typedef std::chrono::nanoseconds duration_t;
|
||||
|
||||
std::vector<std::function<error_t(MccSkyPoint const& pt, bool*)>> _inZoneFunc;
|
||||
std::vector<std::function<error_t(MccSkyPoint const& pt, duration_t*)>> _timeToZoneFunc;
|
||||
std::vector<std::function<error_t(MccSkyPoint const& pt, duration_t*)>> _timeFromZoneFunc;
|
||||
std::vector<std::function<error_t(MccSkyPoint const& pt, bool*)>> _inZoneFunc{};
|
||||
std::vector<std::function<error_t(MccSkyPoint const& pt, duration_t*)>> _timeToZoneFunc{};
|
||||
std::vector<std::function<error_t(MccSkyPoint const& pt, duration_t*)>> _timeFromZoneFunc{};
|
||||
|
||||
std::vector<std::string> _names{};
|
||||
|
||||
error_t forEach(auto& func_cont, MccSkyPoint const& pt, auto* result)
|
||||
{
|
||||
@@ -205,7 +216,7 @@ protected:
|
||||
|
||||
res_elem_t res_elem;
|
||||
|
||||
size_t res_sz = std::ranges::size(*result);
|
||||
// size_t res_sz = std::ranges::size(*result);
|
||||
auto it = result->begin();
|
||||
|
||||
for (auto& func : func_cont) {
|
||||
390
include/mcc/mcc_serialization_common.h
Normal file
390
include/mcc/mcc_serialization_common.h
Normal file
@@ -0,0 +1,390 @@
|
||||
#pragma once
|
||||
|
||||
|
||||
/****************************************************************************************
|
||||
* *
|
||||
* MOUNT CONTROL COMPONENTS LIBRARY *
|
||||
* *
|
||||
* *
|
||||
* COMMON DEFINITIONS FOR DATA SERIALIZATION/DESERIALIZATION *
|
||||
* *
|
||||
****************************************************************************************/
|
||||
|
||||
#include "mcc_concepts.h"
|
||||
#include "mcc_error.h"
|
||||
#include "mcc_traits.h"
|
||||
|
||||
namespace mcc
|
||||
{
|
||||
|
||||
|
||||
/* celestial angle serialization */
|
||||
|
||||
enum class MccSerializedAngleFormat {
|
||||
MCC_SERIALIZED_FORMAT_DEGREES, // degrees as floating-point number
|
||||
MCC_SERIALIZED_FORMAT_SXGM_HOURS, // sexagesimal representation: hours:mins:secs
|
||||
MCC_SERIALIZED_FORMAT_SXGM_DEGS, // sexagesimal representation: degs:arcmins:arcsecs
|
||||
MCC_SERIALIZED_FORMAT_UNKNOWN
|
||||
};
|
||||
|
||||
static constexpr std::string_view MCC_SERIALIZED_ANG_FORMAT_DEGREES_STR = "SRANG-FORMAT-DEGREES";
|
||||
static constexpr std::string_view MCC_SERIALIZED_ANG_FORMAT_SXGM_HOURS_STR = "SRANG-FORMAT-SXGM_HOURDEG";
|
||||
static constexpr std::string_view MCC_SERIALIZED_ANG_FORMAT_SXGM_DEGS_STR = "SRANG-FORMAT-SXGM_DEGDEG";
|
||||
|
||||
|
||||
static constexpr std::string_view MccSerializedAngleFormatToStr(MccSerializedAngleFormat fmt)
|
||||
{
|
||||
return fmt == MccSerializedAngleFormat::MCC_SERIALIZED_FORMAT_DEGREES ? MCC_SERIALIZED_ANG_FORMAT_DEGREES_STR
|
||||
: fmt == MccSerializedAngleFormat::MCC_SERIALIZED_FORMAT_SXGM_HOURS
|
||||
? MCC_SERIALIZED_ANG_FORMAT_SXGM_HOURS_STR
|
||||
: fmt == MccSerializedAngleFormat::MCC_SERIALIZED_FORMAT_SXGM_DEGS ? MCC_SERIALIZED_ANG_FORMAT_SXGM_DEGS_STR
|
||||
: MCC_SERIALIZED_ANG_FORMAT_DEGREES_STR;
|
||||
}
|
||||
|
||||
template <traits::mcc_input_char_range R>
|
||||
static constexpr MccSerializedAngleFormat MccSerializedAngleFormatStrToValue(R&& str)
|
||||
{
|
||||
if constexpr (std::is_array_v<std::decay_t<R>>) {
|
||||
return MccSerializedAngleFormatStrToValue(std::string_view{str});
|
||||
}
|
||||
|
||||
const auto hash = mcc::utils::FNV1aHash(std::forward<R>(str));
|
||||
|
||||
return hash == mcc::utils::FNV1aHash(MCC_SERIALIZED_ANG_FORMAT_DEGREES_STR)
|
||||
? MccSerializedAngleFormat::MCC_SERIALIZED_FORMAT_DEGREES
|
||||
: hash == mcc::utils::FNV1aHash(MCC_SERIALIZED_ANG_FORMAT_SXGM_HOURS_STR)
|
||||
? MccSerializedAngleFormat::MCC_SERIALIZED_FORMAT_SXGM_HOURS
|
||||
: hash == mcc::utils::FNV1aHash(MCC_SERIALIZED_ANG_FORMAT_SXGM_DEGS_STR)
|
||||
? MccSerializedAngleFormat::MCC_SERIALIZED_FORMAT_SXGM_DEGS
|
||||
: MccSerializedAngleFormat::MCC_SERIALIZED_FORMAT_UNKNOWN;
|
||||
}
|
||||
|
||||
|
||||
/* coordinates pair serialization */
|
||||
|
||||
enum class MccSerializedCoordPairFormat {
|
||||
MCC_SERIALIZED_FORMAT_DEGREES, // both angles are in degrees as floating-point number
|
||||
MCC_SERIALIZED_FORMAT_SXGM_HOURDEG, // X is in hour (if RA or HA) and Y is in degree sexagesimal representation
|
||||
MCC_SERIALIZED_FORMAT_SXGM_DEGDEG, // both angles are in sexagesimal degrees
|
||||
MCC_SERIALIZED_FORMAT_UNKNOWN
|
||||
};
|
||||
|
||||
static constexpr std::string_view MCC_SERIALIZED_CP_FORMAT_DEGREES_STR = "SRCP-FORMAT-DEGREES";
|
||||
static constexpr std::string_view MCC_SERIALIZED_CP_FORMAT_SXGM_HOURDEG_STR = "SRCP-FORMAT-SXGM_HOURDEG";
|
||||
static constexpr std::string_view MCC_SERIALIZED_CP_FORMAT_SXGM_DEGDEG_STR = "SRCP-FORMAT-SXGM_DEGDEG";
|
||||
|
||||
|
||||
static constexpr std::string_view MccSerializedCoordPairFormatToStr(MccSerializedCoordPairFormat fmt)
|
||||
{
|
||||
return fmt == MccSerializedCoordPairFormat::MCC_SERIALIZED_FORMAT_DEGREES ? MCC_SERIALIZED_CP_FORMAT_DEGREES_STR
|
||||
: fmt == MccSerializedCoordPairFormat::MCC_SERIALIZED_FORMAT_SXGM_HOURDEG
|
||||
? MCC_SERIALIZED_CP_FORMAT_SXGM_HOURDEG_STR
|
||||
: fmt == MccSerializedCoordPairFormat::MCC_SERIALIZED_FORMAT_SXGM_DEGDEG
|
||||
? MCC_SERIALIZED_CP_FORMAT_SXGM_DEGDEG_STR
|
||||
: MCC_SERIALIZED_CP_FORMAT_DEGREES_STR;
|
||||
}
|
||||
|
||||
template <traits::mcc_input_char_range R>
|
||||
static constexpr MccSerializedCoordPairFormat MccSerializedCoordPairFormatStrToValue(R&& str)
|
||||
{
|
||||
if constexpr (std::is_array_v<std::decay_t<R>>) {
|
||||
return MccSerializedCoordPairFormatStrToValue(std::string_view{str});
|
||||
}
|
||||
|
||||
const auto hash = mcc::utils::FNV1aHash(std::forward<R>(str));
|
||||
|
||||
return hash == mcc::utils::FNV1aHash(MCC_SERIALIZED_CP_FORMAT_DEGREES_STR)
|
||||
? MccSerializedCoordPairFormat::MCC_SERIALIZED_FORMAT_DEGREES
|
||||
: hash == mcc::utils::FNV1aHash(MCC_SERIALIZED_CP_FORMAT_SXGM_HOURDEG_STR)
|
||||
? MccSerializedCoordPairFormat::MCC_SERIALIZED_FORMAT_SXGM_HOURDEG
|
||||
: hash == mcc::utils::FNV1aHash(MCC_SERIALIZED_CP_FORMAT_SXGM_DEGDEG_STR)
|
||||
? MccSerializedCoordPairFormat::MCC_SERIALIZED_FORMAT_SXGM_DEGDEG
|
||||
: MccSerializedCoordPairFormat::MCC_SERIALIZED_FORMAT_UNKNOWN;
|
||||
}
|
||||
|
||||
|
||||
/* precision of representation of serialized celestial angle/coordinates pair */
|
||||
|
||||
struct MccSerializedAngleFormatPrec {
|
||||
uint8_t hour_prec = 2; // number of decimal places in hour seconds (sexagesimal format)
|
||||
uint8_t deg_prec = 1; // number of decimal places in arcseconds (sexagesimal format)
|
||||
// slightly better than 0.1 arcsecond precision
|
||||
uint8_t decimals = 6; // number of decimal places in degrees (floating-point number format)
|
||||
// if 0, then number of decimal places is according to formating rules of 'double' type
|
||||
};
|
||||
|
||||
enum class MccTimePointFormat {
|
||||
MCC_TIMEPOINT_FORMAT_DATE, // UTC date
|
||||
MCC_TIMEPOINT_FORMAT_MJD, // MJD
|
||||
MCC_TIMEPOINT_FORMAT_JD, // JD
|
||||
MCC_TIMEPOINT_FORMAT_JEPOCH, // Julian epoch
|
||||
MCC_TIMEPOINT_FORMAT_UNKNOWN
|
||||
};
|
||||
|
||||
static constexpr std::string_view MCC_TIMEPOINT_FORMAT_DATE_STR = "TP-FORMAT-DATE";
|
||||
static constexpr std::string_view MCC_TIMEPOINT_FORMAT_MJD_STR = "TP-FORMAT-MJD";
|
||||
static constexpr std::string_view MCC_TIMEPOINT_FORMAT_JD_STR = "TP-FORMAT-JD";
|
||||
static constexpr std::string_view MCC_TIMEPOINT_FORMAT_JEPOCH_STR = "TP-FORMAT-JEPOCH";
|
||||
|
||||
static constexpr std::string_view MccTimePointFormatToStr(MccTimePointFormat fmt)
|
||||
{
|
||||
return fmt == MccTimePointFormat::MCC_TIMEPOINT_FORMAT_DATE ? MCC_TIMEPOINT_FORMAT_DATE_STR
|
||||
: fmt == MccTimePointFormat::MCC_TIMEPOINT_FORMAT_MJD ? MCC_TIMEPOINT_FORMAT_MJD_STR
|
||||
: fmt == MccTimePointFormat::MCC_TIMEPOINT_FORMAT_JD ? MCC_TIMEPOINT_FORMAT_JD_STR
|
||||
: fmt == MccTimePointFormat::MCC_TIMEPOINT_FORMAT_JEPOCH ? MCC_TIMEPOINT_FORMAT_JEPOCH_STR
|
||||
: MCC_TIMEPOINT_FORMAT_MJD_STR;
|
||||
}
|
||||
|
||||
template <traits::mcc_input_char_range R>
|
||||
static constexpr MccTimePointFormat MccTimePointFormatStrToValue(R&& str)
|
||||
{
|
||||
if constexpr (std::is_array_v<std::decay_t<R>>) {
|
||||
return MccTimePointFormatStrToValue(std::string_view{str});
|
||||
}
|
||||
|
||||
const auto hash = mcc::utils::FNV1aHash(std::forward<R>(str));
|
||||
|
||||
return hash == mcc::utils::FNV1aHash(MCC_TIMEPOINT_FORMAT_DATE_STR) ? MccTimePointFormat::MCC_TIMEPOINT_FORMAT_DATE
|
||||
: hash == mcc::utils::FNV1aHash(MCC_TIMEPOINT_FORMAT_MJD_STR) ? MccTimePointFormat::MCC_TIMEPOINT_FORMAT_MJD
|
||||
: hash == mcc::utils::FNV1aHash(MCC_TIMEPOINT_FORMAT_JD_STR) ? MccTimePointFormat::MCC_TIMEPOINT_FORMAT_JD
|
||||
: hash == mcc::utils::FNV1aHash(MCC_TIMEPOINT_FORMAT_JEPOCH_STR)
|
||||
? MccTimePointFormat::MCC_TIMEPOINT_FORMAT_JEPOCH
|
||||
: MccTimePointFormat::MCC_TIMEPOINT_FORMAT_UNKNOWN;
|
||||
}
|
||||
|
||||
|
||||
/* SERIALIZATION/DESERIALIZATION PROCESS TUNING PARAMETERS */
|
||||
|
||||
// delimiter between items of serializing values sequence
|
||||
static constexpr std::string_view MCC_SERIALIZING_DEFAULT_SEQ_DELIMITER{";"};
|
||||
|
||||
// delimiter between items of aggregative (multi-element) serializing value
|
||||
static constexpr std::string_view MCC_SERIALIZING_DEFAULT_ELEM_DELIMITER{","};
|
||||
|
||||
|
||||
template <typename T>
|
||||
concept mcc_serialization_params_c = std::copyable<T> && requires(T t) {
|
||||
requires traits::mcc_output_char_range<decltype(t.seq_delim)>;
|
||||
requires traits::mcc_output_char_range<decltype(t.elem_delim)>;
|
||||
|
||||
requires std::same_as<decltype(t.angle_format), MccSerializedAngleFormat>;
|
||||
requires std::same_as<decltype(t.angle_prec), MccSerializedAngleFormatPrec>;
|
||||
requires std::same_as<decltype(t.coordpair_format), MccSerializedCoordPairFormat>;
|
||||
requires std::same_as<decltype(t.timepoint_format), MccTimePointFormat>;
|
||||
|
||||
// a format string for mcc_systime_c types (std;:chrono::sys_time)
|
||||
requires std::same_as<decltype(t.systime_format), std::string_view>;
|
||||
|
||||
// if true - normalize angle in sexagesimal format (to control rounding)
|
||||
// (to avoid something like "24:00:00.0" for sexagesimal 'hours:minutes:seconds' format)
|
||||
requires std::convertible_to<decltype(t.norm_sxgm), bool>;
|
||||
|
||||
// if true - interpretate serialized angle in sexagesimal format as 'hours:minutes:seconds'
|
||||
// otherwise as 'degrees:arcmins:arcsecs'
|
||||
requires std::convertible_to<decltype(t.sxgm_hms), bool>;
|
||||
};
|
||||
|
||||
|
||||
/* SERIALIZER/DESERIALIZER CONCEPTS */
|
||||
|
||||
template <mcc_error_c RetT>
|
||||
struct mcc_serializer_interface_t {
|
||||
virtual ~mcc_serializer_interface_t() = default;
|
||||
|
||||
typedef RetT error_t;
|
||||
|
||||
template <std::derived_from<mcc_serializer_interface_t> SelfT, traits::mcc_output_char_range R, typename ValueT>
|
||||
RetT operator()(this SelfT&& self, R& output, ValueT const& value)
|
||||
{
|
||||
return std::forward<SelfT>(self)(output, value);
|
||||
}
|
||||
|
||||
template <std::derived_from<mcc_serializer_interface_t> SelfT, traits::mcc_output_char_range R, typename ValueT>
|
||||
RetT operator()(this SelfT&& self, R& output, ValueT const& value, mcc_serialization_params_c auto const& params)
|
||||
{
|
||||
return std::forward<SelfT>(self)(output, value, params);
|
||||
}
|
||||
|
||||
protected:
|
||||
mcc_serializer_interface_t() = default;
|
||||
};
|
||||
|
||||
|
||||
template <typename T>
|
||||
concept mcc_serializer_c =
|
||||
std::derived_from<T, mcc_serializer_interface_t<typename T::error_t>> && requires(T t, const T t_const) {
|
||||
// static const variable with name of the serializer
|
||||
requires std::formattable<decltype(T::serializerName), char> && std::is_const_v<decltype(T::serializerName)>;
|
||||
|
||||
// // must define a type "params_t"
|
||||
// requires mcc_serialization_params_c<typename T::params_t>;
|
||||
|
||||
// { t.setParams(std::declval<typename T::params_t const&>()) };
|
||||
|
||||
// { t_const.getParams() } -> std::same_as<typename T::params_t>;
|
||||
};
|
||||
|
||||
|
||||
|
||||
template <mcc_error_c RetT>
|
||||
struct mcc_deserializer_interface_t {
|
||||
virtual ~mcc_deserializer_interface_t() = default;
|
||||
|
||||
typedef RetT error_t;
|
||||
|
||||
template <std::derived_from<mcc_deserializer_interface_t> SelfT, traits::mcc_input_char_range R, typename ValueT>
|
||||
RetT operator()(this SelfT&& self, R const& input, ValueT& value)
|
||||
{
|
||||
return std::forward<SelfT>(self)(input, value);
|
||||
}
|
||||
|
||||
template <std::derived_from<mcc_deserializer_interface_t> SelfT, traits::mcc_input_char_range R, typename ValueT>
|
||||
RetT operator()(this SelfT&& self, R const& input, ValueT& value, mcc_serialization_params_c auto& params)
|
||||
{
|
||||
return std::forward<SelfT>(self)(input, value, params);
|
||||
}
|
||||
|
||||
protected:
|
||||
mcc_deserializer_interface_t() = default;
|
||||
};
|
||||
|
||||
|
||||
template <typename T>
|
||||
concept mcc_deserializer_c =
|
||||
std::derived_from<T, mcc_deserializer_interface_t<typename T::error_t>> && requires(T t, const T t_const) {
|
||||
// static const variable with name of the deserializer
|
||||
requires std::formattable<decltype(T::deserializerName), char> &&
|
||||
std::is_const_v<decltype(T::deserializerName)>;
|
||||
|
||||
// // must define a type "params_t"
|
||||
// requires mcc_serialization_params_c<typename T::params_t>;
|
||||
|
||||
// { t.setParams(std::declval<typename T::params_t const&>()) };
|
||||
|
||||
// { t_const.getParams() } -> std::same_as<typename T::params_t>;
|
||||
};
|
||||
|
||||
|
||||
|
||||
/* BASE CLASS IMPLEMENTATION FOR SERIALIZER/DESERIALIZER */
|
||||
|
||||
namespace impl
|
||||
{
|
||||
|
||||
// default definition of serialization/deserialization process parameters structure
|
||||
struct mcc_serialization_params_t {
|
||||
std::string seq_delim{MCC_SERIALIZING_DEFAULT_SEQ_DELIMITER};
|
||||
std::string elem_delim{MCC_SERIALIZING_DEFAULT_ELEM_DELIMITER};
|
||||
|
||||
MccSerializedAngleFormat angle_format{MccSerializedAngleFormat::MCC_SERIALIZED_FORMAT_DEGREES};
|
||||
|
||||
MccSerializedAngleFormatPrec angle_prec{MccSerializedAngleFormatPrec{.hour_prec = 2, .deg_prec = 1, .decimals = 6}};
|
||||
|
||||
MccSerializedCoordPairFormat coordpair_format{MccSerializedCoordPairFormat::MCC_SERIALIZED_FORMAT_SXGM_HOURDEG};
|
||||
|
||||
MccTimePointFormat timepoint_format{MccTimePointFormat::MCC_TIMEPOINT_FORMAT_DATE};
|
||||
|
||||
std::string_view systime_format{"{:%FT%T}"};
|
||||
|
||||
bool norm_sxgm{false};
|
||||
|
||||
bool sxgm_hms{false};
|
||||
};
|
||||
|
||||
|
||||
static_assert(mcc_serialization_params_c<mcc_serialization_params_t>, "!!!");
|
||||
|
||||
namespace details
|
||||
{
|
||||
|
||||
template <mcc_serialization_params_c ParamsT>
|
||||
struct _params_manipulator_t {
|
||||
virtual ~_params_manipulator_t() = default;
|
||||
|
||||
typedef ParamsT params_t;
|
||||
|
||||
template <mcc_serialization_params_c p_t>
|
||||
void setParams(p_t const& pars)
|
||||
{
|
||||
if constexpr (std::same_as<p_t, params_t>) {
|
||||
_params = pars;
|
||||
} else {
|
||||
_params.seq_delim = pars.seq_delim;
|
||||
_params.elem_delim = pars.elem_delim;
|
||||
_params.coordpair_format = pars.coordpair_format;
|
||||
_params.angle_prec = pars.angle_prec;
|
||||
_params.timepoint_format = pars.timepoint_format;
|
||||
_params.norm_sxgm = pars.norm_sxgm;
|
||||
_params.sxgm_hms = pars.sxgm_hms;
|
||||
}
|
||||
}
|
||||
|
||||
template <mcc_serialization_params_c p_t>
|
||||
requires(!std::same_as<p_t, params_t>)
|
||||
p_t getParams() const
|
||||
{
|
||||
p_t pars;
|
||||
|
||||
pars.seq_delim = _params.seq_delim;
|
||||
pars.elem_delim = _params.elem_delim;
|
||||
pars.coordpair_format = _params.coordpair_format;
|
||||
pars.angle_prec = _params.angle_prec;
|
||||
pars.timepoint_format = _params.timepoint_format;
|
||||
pars.norm_sxgm = _params.norm_sxgm;
|
||||
pars.sxgm_hms = _params.sxgm_hms;
|
||||
|
||||
return pars;
|
||||
}
|
||||
|
||||
|
||||
params_t getParams() const
|
||||
{
|
||||
return _params;
|
||||
}
|
||||
|
||||
protected:
|
||||
_params_manipulator_t() = default;
|
||||
|
||||
params_t _params;
|
||||
};
|
||||
|
||||
} // namespace details
|
||||
|
||||
|
||||
|
||||
// struct MccDeserializerBase : mcc_deserializer_interface_t<MccError> {
|
||||
// virtual ~MccDeserializerBase() = default;
|
||||
|
||||
// using typename mcc_deserializer_interface_t<MccError>::error_t;
|
||||
|
||||
// protected:
|
||||
// MccDeserializerBase() = default;
|
||||
// };
|
||||
|
||||
// template <mcc_serialization_params_c ParamsT>
|
||||
// struct MccSerializerBase : mcc_serializer_interface_t<MccError>, details::_params_manipulator_t<ParamsT> {
|
||||
// virtual ~MccSerializerBase() = default;
|
||||
|
||||
// using typename mcc_serializer_interface_t<MccError>::error_t;
|
||||
|
||||
// using typename details::_params_manipulator_t<ParamsT>::params_t;
|
||||
|
||||
// protected:
|
||||
// MccSerializerBase() = default;
|
||||
// };
|
||||
|
||||
// template <mcc_serialization_params_c ParamsT>
|
||||
// struct MccDeserializerBase : mcc_deserializer_interface_t<MccError>, details::_params_manipulator_t<ParamsT> {
|
||||
// virtual ~MccDeserializerBase() = default;
|
||||
|
||||
// using typename mcc_deserializer_interface_t<MccError>::error_t;
|
||||
|
||||
// using typename details::_params_manipulator_t<ParamsT>::params_t;
|
||||
|
||||
// protected:
|
||||
// MccDeserializerBase() = default;
|
||||
// };
|
||||
|
||||
} // namespace impl
|
||||
|
||||
} // namespace mcc
|
||||
777
include/mcc/mcc_serializer.h
Normal file
777
include/mcc/mcc_serializer.h
Normal file
@@ -0,0 +1,777 @@
|
||||
#pragma once
|
||||
|
||||
#include "mcc_coordinate.h"
|
||||
#include "mcc_serialization_common.h"
|
||||
|
||||
namespace mcc::impl
|
||||
{
|
||||
|
||||
enum class MccSerializerErrorCode : int {
|
||||
ERROR_OK,
|
||||
ERROR_UNDERLYING_SERIALIZER,
|
||||
ERROR_INVALID_EPOCH,
|
||||
ERROR_COORD_TRANSFORM
|
||||
};
|
||||
|
||||
} // namespace mcc::impl
|
||||
|
||||
|
||||
|
||||
namespace std
|
||||
{
|
||||
|
||||
template <>
|
||||
class is_error_code_enum<mcc::impl::MccSerializerErrorCode> : public true_type
|
||||
{
|
||||
};
|
||||
|
||||
} // namespace std
|
||||
|
||||
|
||||
namespace mcc::impl
|
||||
{
|
||||
|
||||
// error category
|
||||
struct MccSerializerCategory : public std::error_category {
|
||||
MccSerializerCategory() : std::error_category() {}
|
||||
|
||||
const char* name() const noexcept
|
||||
{
|
||||
return "MCC-SERIALIZER-ERR-CATEGORY";
|
||||
}
|
||||
|
||||
std::string message(int ec) const
|
||||
{
|
||||
MccSerializerErrorCode err = static_cast<MccSerializerErrorCode>(ec);
|
||||
|
||||
switch (err) {
|
||||
case MccSerializerErrorCode::ERROR_OK:
|
||||
return "OK";
|
||||
case MccSerializerErrorCode::ERROR_UNDERLYING_SERIALIZER:
|
||||
return "error returned by underlying serializer";
|
||||
case MccSerializerErrorCode::ERROR_INVALID_EPOCH:
|
||||
return "invalid coordinate epoch";
|
||||
case MccSerializerErrorCode::ERROR_COORD_TRANSFORM:
|
||||
return "coordinates transformation error";
|
||||
default:
|
||||
return "UNKNOWN";
|
||||
}
|
||||
}
|
||||
|
||||
static const MccSerializerCategory& get()
|
||||
{
|
||||
static const MccSerializerCategory constInst;
|
||||
return constInst;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
inline std::error_code make_error_code(MccSerializerErrorCode ec)
|
||||
{
|
||||
return std::error_code(static_cast<int>(ec), MccSerializerCategory::get());
|
||||
}
|
||||
|
||||
|
||||
/* BASE SERIALIZER CLASS (FOR IMPLEMENTATIONS BELOW) */
|
||||
|
||||
struct MccSerializerBase : mcc_serializer_interface_t<MccError> {
|
||||
virtual ~MccSerializerBase() = default;
|
||||
|
||||
using typename mcc_serializer_interface_t<MccError>::error_t;
|
||||
|
||||
protected:
|
||||
MccSerializerBase() = default;
|
||||
|
||||
enum CoordType { CO_LON, CO_LAT };
|
||||
|
||||
static void addElemDelimiter(traits::mcc_output_char_range auto& output,
|
||||
mcc_serialization_params_c auto const& params)
|
||||
{
|
||||
std::format_to(std::back_inserter(output), "{}", params.elem_delim);
|
||||
}
|
||||
|
||||
|
||||
static void addSeqDelimiter(traits::mcc_output_char_range auto& output,
|
||||
mcc_serialization_params_c auto const& params)
|
||||
{
|
||||
std::format_to(std::back_inserter(output), "{}", params.seq_delim);
|
||||
}
|
||||
|
||||
|
||||
// set serialized angle format according to coordinates pair format and type of
|
||||
// serializing mcc_coord_pair_c::pairKind
|
||||
template <MccCoordPairKind PAIRKIND, CoordType TYPE = MccSerializerBase::CO_LON>
|
||||
static void angleFormatFromCoordPairType(mcc_serialization_params_c auto& pars)
|
||||
{
|
||||
if (pars.coordpair_format == MccSerializedCoordPairFormat::MCC_SERIALIZED_FORMAT_DEGREES) {
|
||||
pars.angle_format = MccSerializedAngleFormat::MCC_SERIALIZED_FORMAT_DEGREES;
|
||||
} else { // format to sexagesimal form according to celestial coordinate type
|
||||
if constexpr (TYPE == MccSerializerBase::CO_LON) {
|
||||
if (pars.coordpair_format == MccSerializedCoordPairFormat::MCC_SERIALIZED_FORMAT_SXGM_DEGDEG) {
|
||||
pars.angle_format = MccSerializedAngleFormat::MCC_SERIALIZED_FORMAT_SXGM_DEGS;
|
||||
} else if (pars.coordpair_format == MccSerializedCoordPairFormat::MCC_SERIALIZED_FORMAT_SXGM_HOURDEG) {
|
||||
if constexpr (PAIRKIND == MccCoordPairKind::COORDS_KIND_AZZD ||
|
||||
PAIRKIND == MccCoordPairKind::COORDS_KIND_AZALT ||
|
||||
PAIRKIND == MccCoordPairKind::COORDS_KIND_XY ||
|
||||
PAIRKIND == MccCoordPairKind::COORDS_KIND_GENERIC) { // azimuth is in degrees
|
||||
pars.angle_format = MccSerializedAngleFormat::MCC_SERIALIZED_FORMAT_SXGM_DEGS;
|
||||
pars.norm_sxgm = true;
|
||||
} else { // RA or HA
|
||||
pars.angle_format = MccSerializedAngleFormat::MCC_SERIALIZED_FORMAT_SXGM_HOURS;
|
||||
pars.norm_sxgm = true;
|
||||
}
|
||||
} else {
|
||||
// !!!!!!!!!!!!!!!!!!
|
||||
}
|
||||
} else { // Y-coordinates (co-latitude one, DEC, ALT, ZD, generic X) is always in degrees for celestial
|
||||
// point
|
||||
pars.angle_format = MccSerializedAngleFormat::MCC_SERIALIZED_FORMAT_SXGM_DEGS;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename VT, typename R>
|
||||
requires(std::ranges::input_range<R> && std::same_as<VT, std::ranges::range_value_t<R>>)
|
||||
static error_t serializeRange(mcc_serializer_c auto& sr,
|
||||
R const& r,
|
||||
traits::mcc_output_char_range auto& output,
|
||||
mcc_serialization_params_c auto const& params)
|
||||
{
|
||||
size_t i = 0, N = std::ranges::size(r);
|
||||
|
||||
for (auto const& el : r) {
|
||||
auto err = sr(output, el, params);
|
||||
if (err) {
|
||||
return mcc_deduced_err(err, MccSerializerErrorCode::ERROR_UNDERLYING_SERIALIZER);
|
||||
}
|
||||
if (++i < N) {
|
||||
// MccSerializerBase::addSeqDelimiter(output, params);
|
||||
MccSerializerBase::addElemDelimiter(output, params);
|
||||
}
|
||||
}
|
||||
|
||||
return MccSerializerErrorCode::ERROR_OK;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/* MAIN (FALLBACK) TEMPLATED IMPLEMENTATION */
|
||||
|
||||
template <typename VT>
|
||||
struct MccSerializer : MccSerializerBase {
|
||||
constexpr static std::string_view serializerName{"MCC-FALLBACK-SERIALIZER"};
|
||||
|
||||
template <mcc_serialization_params_c ParamsT = mcc_serialization_params_t>
|
||||
error_t operator()(traits::mcc_output_char_range auto& output,
|
||||
VT const& value,
|
||||
ParamsT const& params = mcc_serialization_params_t{})
|
||||
{
|
||||
if constexpr (std::convertible_to<VT, std::string>) {
|
||||
std::string s = value;
|
||||
std::ranges::copy(s, std::back_inserter(output));
|
||||
// auto err = MccSerializer<std::string>{}(output, static_cast<std::string>(value), params);
|
||||
// if (err) {
|
||||
// return mcc_deduced_err(err, MccSerializerErrorCode::ERROR_UNDERLYING_SERIALIZER);
|
||||
// }
|
||||
} else if constexpr (std::ranges::range<VT>) {
|
||||
using value_t = std::remove_cv_t<std::ranges::range_value_t<VT>>;
|
||||
|
||||
// special range (character sequence)
|
||||
if constexpr (std::same_as<value_t, char>) {
|
||||
std::ranges::copy(value, std::back_inserter(output));
|
||||
} else {
|
||||
MccSerializer<value_t> sr;
|
||||
|
||||
return MccSerializerBase::serializeRange<value_t>(sr, value, output, params);
|
||||
}
|
||||
} else if constexpr (std::formattable<VT, char>) {
|
||||
std::format_to(std::back_inserter(output), "{}", value);
|
||||
} else {
|
||||
static_assert(false, "UNSUPPORTED TYPE!!!");
|
||||
}
|
||||
|
||||
return MccSerializerErrorCode::ERROR_OK;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/* SPECIALIZATION FOR THE SOME CONCEPTS */
|
||||
|
||||
|
||||
template <traits::mcc_time_duration_c VT>
|
||||
struct MccSerializer<VT> : MccSerializerBase {
|
||||
virtual ~MccSerializer() = default;
|
||||
|
||||
constexpr static std::string_view serializerName{"MCC-TIME-DURATION-SERIALIZER"};
|
||||
|
||||
template <mcc_serialization_params_c ParamsT = mcc_serialization_params_t>
|
||||
error_t operator()(traits::mcc_output_char_range auto& output,
|
||||
VT const& value,
|
||||
ParamsT const& params = mcc_serialization_params_t{})
|
||||
{
|
||||
std::format_to(std::back_inserter(output), "{}", value.count());
|
||||
|
||||
return MccSerializerErrorCode::ERROR_OK;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
/* std::chrono::sys_time variants and its sequence */
|
||||
|
||||
template <traits::mcc_systime_c VT>
|
||||
struct MccSerializer<VT> : MccSerializerBase {
|
||||
virtual ~MccSerializer() = default;
|
||||
|
||||
constexpr static std::string_view serializerName{"MCC-SYSTIME-SERIALIZER"};
|
||||
|
||||
template <mcc_serialization_params_c ParamsT = mcc_serialization_params_t>
|
||||
error_t operator()(traits::mcc_output_char_range auto& output,
|
||||
VT const& value,
|
||||
ParamsT const& params = mcc_serialization_params_t{})
|
||||
{
|
||||
// std::vformat_to(std::back_inserter(output), params.systime_format, std::make_format_args(value));
|
||||
auto tp = std::chrono::round<std::chrono::milliseconds>(value);
|
||||
std::vformat_to(std::back_inserter(output), params.systime_format, std::make_format_args(tp));
|
||||
|
||||
return MccSerializerErrorCode::ERROR_OK;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template <typename VT>
|
||||
requires(!std::is_arithmetic_v<VT> && mcc_angle_c<VT>)
|
||||
struct MccSerializer<VT> : MccSerializerBase {
|
||||
constexpr static std::string_view serializerName{"MCC-ANGLE-SERIALIZER"};
|
||||
|
||||
template <mcc_serialization_params_c ParamsT = mcc_serialization_params_t>
|
||||
error_t operator()(traits::mcc_output_char_range auto& output,
|
||||
VT const& value,
|
||||
ParamsT const& params = mcc_serialization_params_t{})
|
||||
{
|
||||
double v = (double)value; // radians (see mcc_angle_c concept)
|
||||
std::string sgm;
|
||||
|
||||
switch (params.angle_format) {
|
||||
case MccSerializedAngleFormat::MCC_SERIALIZED_FORMAT_DEGREES: {
|
||||
v *= MCC_RADS_TO_DEGRESS;
|
||||
std::string_view fmt = "{:." + std::to_string(params.angle_prec.decimals) + "f}";
|
||||
std::vformat_to(std::back_inserter(output), fmt, std::make_format_args(v));
|
||||
|
||||
return MccSerializerErrorCode::ERROR_OK;
|
||||
}
|
||||
// return MccSerializer<double>{}(output, v, params);
|
||||
case MccSerializedAngleFormat::MCC_SERIALIZED_FORMAT_SXGM_DEGS:
|
||||
if (params.norm_sxgm) {
|
||||
sgm = utils::rad2sxg<true>(v, false, params.angle_prec.deg_prec);
|
||||
} else {
|
||||
sgm = utils::rad2sxg<false>(v, false, params.angle_prec.deg_prec);
|
||||
}
|
||||
|
||||
break;
|
||||
case MccSerializedAngleFormat::MCC_SERIALIZED_FORMAT_SXGM_HOURS:
|
||||
if (params.norm_sxgm) {
|
||||
sgm = utils::rad2sxg<true>(v, true, params.angle_prec.hour_prec);
|
||||
} else {
|
||||
sgm = utils::rad2sxg<false>(v, true, params.angle_prec.hour_prec);
|
||||
}
|
||||
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
auto err = MccSerializer<std::string>{}(output, sgm, params);
|
||||
if (err) {
|
||||
return mcc_deduced_err(err, MccSerializerErrorCode::ERROR_UNDERLYING_SERIALIZER);
|
||||
}
|
||||
|
||||
return MccSerializerErrorCode::ERROR_OK;
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
template <mcc_coord_epoch_c VT>
|
||||
struct MccSerializer<VT> : MccSerializerBase {
|
||||
constexpr static std::string_view serializerName{"MCC-COORD-EPOCH-SERIALIZER"};
|
||||
|
||||
template <mcc_serialization_params_c ParamsT = mcc_serialization_params_t>
|
||||
error_t operator()(traits::mcc_output_char_range auto& output,
|
||||
VT const& value,
|
||||
ParamsT const& params = mcc_serialization_params_t{})
|
||||
{
|
||||
double jd;
|
||||
|
||||
switch (params.timepoint_format) {
|
||||
case MccTimePointFormat::MCC_TIMEPOINT_FORMAT_DATE: {
|
||||
auto tp = value.UTC();
|
||||
auto err = MccSerializer<decltype(tp)>{}(output, tp, params);
|
||||
if (err) {
|
||||
return mcc_deduced_err(err, MccSerializerErrorCode::ERROR_UNDERLYING_SERIALIZER);
|
||||
}
|
||||
|
||||
return MccSerializerErrorCode::ERROR_OK;
|
||||
};
|
||||
case MccTimePointFormat::MCC_TIMEPOINT_FORMAT_JEPOCH: {
|
||||
auto ep = value.JEpoch();
|
||||
auto err = MccSerializer<decltype(ep)>{}(output, ep, params);
|
||||
if (err) {
|
||||
return mcc_deduced_err(err, MccSerializerErrorCode::ERROR_UNDERLYING_SERIALIZER);
|
||||
}
|
||||
|
||||
return MccSerializerErrorCode::ERROR_OK;
|
||||
} break;
|
||||
case MccTimePointFormat::MCC_TIMEPOINT_FORMAT_JD:
|
||||
jd = value.MJD() + MCC_J2000_MJD;
|
||||
break;
|
||||
case MccTimePointFormat::MCC_TIMEPOINT_FORMAT_MJD:
|
||||
jd = value.MJD();
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
auto err = MccSerializer<double>{}(output, jd, params);
|
||||
|
||||
if (err) {
|
||||
return mcc_deduced_err(err, MccSerializerErrorCode::ERROR_UNDERLYING_SERIALIZER);
|
||||
}
|
||||
|
||||
return MccSerializerErrorCode::ERROR_OK;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template <mcc_coord_pair_c VT>
|
||||
struct MccSerializer<VT> : MccSerializerBase {
|
||||
constexpr static std::string_view serializerName{"MCC-COORD-PAIR-SERIALIZER"};
|
||||
|
||||
template <mcc_serialization_params_c ParamsT = mcc_serialization_params_t>
|
||||
error_t operator()(traits::mcc_output_char_range auto& output,
|
||||
VT const& value,
|
||||
ParamsT const& params = mcc_serialization_params_t{})
|
||||
{
|
||||
// format: X<elem-delim>Y<elem-delim>PAIRKIND<elem-delim>EPOCH
|
||||
|
||||
auto pars = params;
|
||||
|
||||
|
||||
// X-coordinate
|
||||
MccSerializerBase::angleFormatFromCoordPairType<VT::pairKind, MccSerializerBase::CO_LON>(pars);
|
||||
|
||||
auto err = MccSerializer<MccAngle>{}(output, value.x(), pars);
|
||||
if (err) {
|
||||
return mcc_deduced_err(err, MccSerializerErrorCode::ERROR_UNDERLYING_SERIALIZER);
|
||||
}
|
||||
|
||||
MccSerializerBase::addElemDelimiter(output, params);
|
||||
|
||||
// pars.norm_sxgm = false; // do not normalize co-latitude angle
|
||||
|
||||
// Y-coordinate
|
||||
MccSerializerBase::angleFormatFromCoordPairType<VT::pairKind, MccSerializerBase::CO_LAT>(pars);
|
||||
|
||||
err = MccSerializer<MccAngle>{}(output, value.y(), pars);
|
||||
if (err) {
|
||||
return mcc_deduced_err(err, MccSerializerErrorCode::ERROR_UNDERLYING_SERIALIZER);
|
||||
}
|
||||
|
||||
MccSerializerBase::addElemDelimiter(output, params);
|
||||
|
||||
// pair kind
|
||||
auto pk_err = MccSerializer<std::string_view>{}(output, MccCoordPairKindToStr(VT::pairKind), params);
|
||||
if (pk_err) {
|
||||
return mcc_deduced_err(pk_err, MccSerializerErrorCode::ERROR_UNDERLYING_SERIALIZER);
|
||||
}
|
||||
|
||||
MccSerializerBase::addElemDelimiter(output, params);
|
||||
|
||||
// epoch
|
||||
auto ep = value.epoch();
|
||||
auto ep_err = MccSerializer<decltype(ep)>{}(output, ep, params);
|
||||
if (ep_err) {
|
||||
return mcc_deduced_err(ep_err, MccSerializerErrorCode::ERROR_UNDERLYING_SERIALIZER);
|
||||
}
|
||||
|
||||
|
||||
return MccSerializerErrorCode::ERROR_OK;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template <mcc_skypoint_c VT>
|
||||
struct MccSerializer<VT> : MccSerializerBase {
|
||||
constexpr static std::string_view serializerName{"MCC-SKYPOINT-SERIALIZER"};
|
||||
|
||||
template <mcc_serialization_params_c ParamsT = mcc_serialization_params_t>
|
||||
error_t operator()(traits::mcc_output_char_range auto& output,
|
||||
VT const& value,
|
||||
ParamsT const& params = mcc_serialization_params_t{})
|
||||
{
|
||||
auto serialize_cpair = [&]<typename T>(T& cp) -> error_t {
|
||||
auto ccte_err = value.toAtSameEpoch(cp);
|
||||
if (ccte_err) {
|
||||
return mcc_deduced_err(ccte_err, MccSerializerErrorCode::ERROR_COORD_TRANSFORM);
|
||||
}
|
||||
|
||||
auto err = MccSerializer<T>{}(output, cp, params);
|
||||
if (err) {
|
||||
return mcc_deduced_err(err, MccSerializerErrorCode::ERROR_UNDERLYING_SERIALIZER);
|
||||
}
|
||||
|
||||
return MccSerializerErrorCode::ERROR_OK;
|
||||
};
|
||||
|
||||
switch (value.pairKind()) {
|
||||
case MccCoordPairKind::COORDS_KIND_RADEC_ICRS: {
|
||||
MccSkyRADEC_ICRS cp;
|
||||
return serialize_cpair(cp);
|
||||
}
|
||||
case MccCoordPairKind::COORDS_KIND_RADEC_OBS: {
|
||||
MccSkyRADEC_OBS cp;
|
||||
return serialize_cpair(cp);
|
||||
}
|
||||
case MccCoordPairKind::COORDS_KIND_RADEC_APP: {
|
||||
MccSkyRADEC_APP cp;
|
||||
return serialize_cpair(cp);
|
||||
}
|
||||
case MccCoordPairKind::COORDS_KIND_HADEC_OBS: {
|
||||
MccSkyHADEC_OBS cp;
|
||||
return serialize_cpair(cp);
|
||||
}
|
||||
case MccCoordPairKind::COORDS_KIND_HADEC_APP: {
|
||||
MccSkyHADEC_APP cp;
|
||||
return serialize_cpair(cp);
|
||||
}
|
||||
case MccCoordPairKind::COORDS_KIND_AZZD: {
|
||||
MccSkyAZZD cp;
|
||||
return serialize_cpair(cp);
|
||||
}
|
||||
case MccCoordPairKind::COORDS_KIND_AZALT: {
|
||||
MccSkyAZALT cp;
|
||||
return serialize_cpair(cp);
|
||||
}
|
||||
case MccCoordPairKind::COORDS_KIND_XY: {
|
||||
MccGenXY cp;
|
||||
return serialize_cpair(cp);
|
||||
}
|
||||
case MccCoordPairKind::COORDS_KIND_GENERIC: {
|
||||
MccGenXY cp;
|
||||
return serialize_cpair(cp);
|
||||
}
|
||||
default:
|
||||
return MccSerializerErrorCode::ERROR_COORD_TRANSFORM;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template <mcc_telemetry_data_c VT>
|
||||
struct MccSerializer<VT> : MccSerializerBase {
|
||||
constexpr static std::string_view serializerName{"MCC-TELEMETRY-DATA-SERIALIZER"};
|
||||
|
||||
template <mcc_serialization_params_c ParamsT = mcc_serialization_params_t>
|
||||
error_t operator()(traits::mcc_output_char_range auto& output,
|
||||
VT const& value,
|
||||
ParamsT const& params = mcc_serialization_params_t{})
|
||||
{
|
||||
// FORMAT: RA_OBS_MOUNT, DEC_OBS_MOUNT, RA_APP_MOUNT, DEC_APP_MOUNT, HA_APP_MOUNT, AZ_MOUNT, ZD_MOUNT,
|
||||
// REFR_CORR_MOUNT, ENC_X, ENC_Y, PCM_X, PCM_Y, RA_APP_TAG, DEC_APP_TAG, AZ_TAG, ZD_TAG, LAST, EO, TIMEPOINT,
|
||||
// STATUS
|
||||
|
||||
// NOTE: One must assume that the returned RA coordinates are in format of underlying celestial coordinate
|
||||
// transformation engine used in the mcc_skypoint_c class implementation. E.g. ERFA-library uses the
|
||||
// CIO-based representation of RA
|
||||
|
||||
auto pars_h = params;
|
||||
|
||||
auto pars_d = params;
|
||||
|
||||
|
||||
pars_h.norm_sxgm = true;
|
||||
pars_h.coordpair_format = MccSerializedCoordPairFormat::MCC_SERIALIZED_FORMAT_SXGM_HOURDEG;
|
||||
pars_d.norm_sxgm = true;
|
||||
pars_d.coordpair_format = MccSerializedCoordPairFormat::MCC_SERIALIZED_FORMAT_SXGM_HOURDEG;
|
||||
|
||||
MccSkyRADEC_OBS rd_obs;
|
||||
MccSkyRADEC_APP rd_app;
|
||||
MccSkyHADEC_APP hd_app;
|
||||
MccSkyAZZD azzd;
|
||||
|
||||
// quantities in hour representation
|
||||
MccSerializerBase::angleFormatFromCoordPairType<MccCoordPairKind::COORDS_KIND_RADEC_ICRS,
|
||||
MccSerializerBase::CO_LON>(pars_h);
|
||||
|
||||
// quantities in degree representation
|
||||
MccSerializerBase::angleFormatFromCoordPairType<MccCoordPairKind::COORDS_KIND_RADEC_ICRS,
|
||||
MccSerializerBase::CO_LAT>(pars_d);
|
||||
|
||||
MccSerializer<MccAngle> ang_sr;
|
||||
|
||||
// RA_OBS_MOUNT, DEC_OBS_MOUNT
|
||||
auto ccte_err = value.mountPos.toAtSameEpoch(rd_obs);
|
||||
if (ccte_err) {
|
||||
return mcc_deduced_err(ccte_err, MccSerializerErrorCode::ERROR_COORD_TRANSFORM);
|
||||
}
|
||||
|
||||
auto err = ang_sr(output, rd_obs.x(), pars_h);
|
||||
if (err) {
|
||||
return mcc_deduced_err(err, MccSerializerErrorCode::ERROR_UNDERLYING_SERIALIZER);
|
||||
}
|
||||
|
||||
MccSerializerBase::addElemDelimiter(output, pars_h);
|
||||
|
||||
err = ang_sr(output, rd_obs.y(), pars_d);
|
||||
if (err) {
|
||||
return mcc_deduced_err(err, MccSerializerErrorCode::ERROR_UNDERLYING_SERIALIZER);
|
||||
}
|
||||
|
||||
MccSerializerBase::addElemDelimiter(output, pars_h);
|
||||
|
||||
// RA_APP_MOUNT, DEC_APP_MOUNT
|
||||
ccte_err = value.mountPos.toAtSameEpoch(rd_app);
|
||||
if (ccte_err) {
|
||||
return mcc_deduced_err(ccte_err, MccSerializerErrorCode::ERROR_COORD_TRANSFORM);
|
||||
}
|
||||
|
||||
err = ang_sr(output, rd_app.x(), pars_h);
|
||||
if (err) {
|
||||
return mcc_deduced_err(err, MccSerializerErrorCode::ERROR_UNDERLYING_SERIALIZER);
|
||||
}
|
||||
|
||||
MccSerializerBase::addElemDelimiter(output, pars_h);
|
||||
|
||||
err = ang_sr(output, rd_app.y(), pars_d);
|
||||
if (err) {
|
||||
return mcc_deduced_err(err, MccSerializerErrorCode::ERROR_UNDERLYING_SERIALIZER);
|
||||
}
|
||||
|
||||
MccSerializerBase::addElemDelimiter(output, pars_h);
|
||||
|
||||
// HA_APP_MOUNT
|
||||
ccte_err = value.mountPos.toAtSameEpoch(hd_app);
|
||||
if (ccte_err) {
|
||||
return mcc_deduced_err(ccte_err, MccSerializerErrorCode::ERROR_COORD_TRANSFORM);
|
||||
}
|
||||
|
||||
err = ang_sr(output, hd_app.x(), pars_h);
|
||||
if (err) {
|
||||
return mcc_deduced_err(err, MccSerializerErrorCode::ERROR_UNDERLYING_SERIALIZER);
|
||||
}
|
||||
|
||||
|
||||
MccSerializerBase::addElemDelimiter(output, pars_h);
|
||||
|
||||
// AZ_MOUNT, ZD_MOUNT
|
||||
ccte_err = value.mountPos.toAtSameEpoch(azzd);
|
||||
if (ccte_err) {
|
||||
return mcc_deduced_err(ccte_err, MccSerializerErrorCode::ERROR_COORD_TRANSFORM);
|
||||
}
|
||||
|
||||
err = ang_sr(output, azzd.x(), pars_d);
|
||||
if (err) {
|
||||
return mcc_deduced_err(err, MccSerializerErrorCode::ERROR_UNDERLYING_SERIALIZER);
|
||||
}
|
||||
|
||||
MccSerializerBase::addElemDelimiter(output, pars_h);
|
||||
|
||||
err = ang_sr(output, azzd.y(), pars_d);
|
||||
if (err) {
|
||||
return mcc_deduced_err(err, MccSerializerErrorCode::ERROR_UNDERLYING_SERIALIZER);
|
||||
}
|
||||
|
||||
MccSerializerBase::addElemDelimiter(output, pars_h);
|
||||
|
||||
// refraction correction
|
||||
|
||||
MccAngle ang;
|
||||
ccte_err = value.mountPos.refractCorrection(&ang);
|
||||
if (ccte_err) {
|
||||
return mcc_deduced_err(ccte_err, MccSerializerErrorCode::ERROR_COORD_TRANSFORM);
|
||||
}
|
||||
|
||||
err = ang_sr(output, ang, pars_d);
|
||||
if (err) {
|
||||
return mcc_deduced_err(err, MccSerializerErrorCode::ERROR_UNDERLYING_SERIALIZER);
|
||||
}
|
||||
|
||||
MccSerializerBase::addElemDelimiter(output, pars_h);
|
||||
|
||||
|
||||
// encoder X and Y
|
||||
|
||||
err = ang_sr(output, value.hwState.XY.x(), pars_d);
|
||||
if (err) {
|
||||
return mcc_deduced_err(err, MccSerializerErrorCode::ERROR_UNDERLYING_SERIALIZER);
|
||||
}
|
||||
|
||||
MccSerializerBase::addElemDelimiter(output, pars_h);
|
||||
|
||||
err = ang_sr(output, value.hwState.XY.y(), pars_d);
|
||||
if (err) {
|
||||
return mcc_deduced_err(err, MccSerializerErrorCode::ERROR_UNDERLYING_SERIALIZER);
|
||||
}
|
||||
|
||||
MccSerializerBase::addElemDelimiter(output, pars_h);
|
||||
|
||||
|
||||
// PCM X and Y
|
||||
|
||||
err = ang_sr(output, value.pcmCorrection.pcmX, pars_d);
|
||||
if (err) {
|
||||
return mcc_deduced_err(err, MccSerializerErrorCode::ERROR_UNDERLYING_SERIALIZER);
|
||||
}
|
||||
|
||||
MccSerializerBase::addElemDelimiter(output, pars_h);
|
||||
|
||||
err = ang_sr(output, value.pcmCorrection.pcmY, pars_d);
|
||||
if (err) {
|
||||
return mcc_deduced_err(err, MccSerializerErrorCode::ERROR_UNDERLYING_SERIALIZER);
|
||||
}
|
||||
|
||||
MccSerializerBase::addElemDelimiter(output, pars_h);
|
||||
|
||||
|
||||
// RA_APP_TAG, DEC_APP_TAG
|
||||
ccte_err = value.targetPos.toAtSameEpoch(rd_app);
|
||||
if (ccte_err) {
|
||||
return mcc_deduced_err(ccte_err, MccSerializerErrorCode::ERROR_COORD_TRANSFORM);
|
||||
}
|
||||
|
||||
err = ang_sr(output, rd_app.x(), pars_h);
|
||||
if (err) {
|
||||
return mcc_deduced_err(err, MccSerializerErrorCode::ERROR_UNDERLYING_SERIALIZER);
|
||||
}
|
||||
|
||||
MccSerializerBase::addElemDelimiter(output, pars_h);
|
||||
|
||||
err = ang_sr(output, rd_app.y(), pars_d);
|
||||
if (err) {
|
||||
return mcc_deduced_err(err, MccSerializerErrorCode::ERROR_UNDERLYING_SERIALIZER);
|
||||
}
|
||||
|
||||
MccSerializerBase::addElemDelimiter(output, pars_h);
|
||||
|
||||
// AZ_TAG, ZD_TAG
|
||||
ccte_err = value.targetPos.toAtSameEpoch(azzd);
|
||||
if (ccte_err) {
|
||||
return mcc_deduced_err(ccte_err, MccSerializerErrorCode::ERROR_COORD_TRANSFORM);
|
||||
}
|
||||
|
||||
err = ang_sr(output, azzd.x(), pars_d);
|
||||
if (err) {
|
||||
return mcc_deduced_err(err, MccSerializerErrorCode::ERROR_UNDERLYING_SERIALIZER);
|
||||
}
|
||||
|
||||
MccSerializerBase::addElemDelimiter(output, pars_h);
|
||||
|
||||
err = ang_sr(output, azzd.y(), pars_d);
|
||||
if (err) {
|
||||
return mcc_deduced_err(err, MccSerializerErrorCode::ERROR_UNDERLYING_SERIALIZER);
|
||||
}
|
||||
|
||||
MccSerializerBase::addElemDelimiter(output, pars_h);
|
||||
|
||||
|
||||
// LAST, local apparent sideral time
|
||||
|
||||
ccte_err = value.mountPos.appSideralTime(&ang, true);
|
||||
if (ccte_err) {
|
||||
return mcc_deduced_err(ccte_err, MccSerializerErrorCode::ERROR_COORD_TRANSFORM);
|
||||
}
|
||||
|
||||
err = ang_sr(output, ang, pars_h);
|
||||
if (err) {
|
||||
return mcc_deduced_err(err, MccSerializerErrorCode::ERROR_UNDERLYING_SERIALIZER);
|
||||
}
|
||||
|
||||
MccSerializerBase::addElemDelimiter(output, pars_h);
|
||||
|
||||
|
||||
// EO, equation of origins
|
||||
|
||||
ccte_err = value.mountPos.EO(&ang);
|
||||
if (ccte_err) {
|
||||
return mcc_deduced_err(ccte_err, MccSerializerErrorCode::ERROR_COORD_TRANSFORM);
|
||||
}
|
||||
|
||||
err = ang_sr(output, ang, pars_h);
|
||||
if (err) {
|
||||
return mcc_deduced_err(err, MccSerializerErrorCode::ERROR_UNDERLYING_SERIALIZER);
|
||||
}
|
||||
|
||||
MccSerializerBase::addElemDelimiter(output, pars_h);
|
||||
|
||||
// coordinates epoch
|
||||
|
||||
auto ep_err = MccSerializer<MccCelestialCoordEpoch>{}(output, value.mountPos.epoch(), pars_d);
|
||||
if (ep_err) {
|
||||
return mcc_deduced_err(err, MccSerializerErrorCode::ERROR_UNDERLYING_SERIALIZER);
|
||||
}
|
||||
|
||||
MccSerializerBase::addElemDelimiter(output, pars_h);
|
||||
|
||||
|
||||
// status (it must be formattable, see mcc_concepts.h)
|
||||
|
||||
auto st_err =
|
||||
MccSerializer<decltype(value.hwState.movementState)>{}(output, value.hwState.movementState, pars_d);
|
||||
if (st_err) {
|
||||
return mcc_deduced_err(err, MccSerializerErrorCode::ERROR_UNDERLYING_SERIALIZER);
|
||||
}
|
||||
|
||||
|
||||
return MccSerializerErrorCode::ERROR_OK;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
template <>
|
||||
struct MccSerializer<MccSerializedCoordPairFormat> : MccSerializerBase {
|
||||
constexpr static std::string_view serializerName{"MCC-COORDPAIR-FORMAT-SERIALIZER"};
|
||||
|
||||
template <mcc_serialization_params_c ParamsT = mcc_serialization_params_t>
|
||||
error_t operator()(traits::mcc_output_char_range auto& output,
|
||||
MccSerializedCoordPairFormat const& value,
|
||||
ParamsT const& params = mcc_serialization_params_t{})
|
||||
{
|
||||
std::ranges::copy(MccSerializedCoordPairFormatToStr(value), std::back_inserter(output));
|
||||
|
||||
return MccSerializerErrorCode::ERROR_OK;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template <>
|
||||
struct MccSerializer<MccSerializedAngleFormatPrec> : MccSerializerBase {
|
||||
constexpr static std::string_view serializerName{"MCC-ANGLE-FORMAT-PREC-SERIALIZER"};
|
||||
|
||||
template <mcc_serialization_params_c ParamsT = mcc_serialization_params_t>
|
||||
error_t operator()(traits::mcc_output_char_range auto& output,
|
||||
MccSerializedAngleFormatPrec const& value,
|
||||
ParamsT const& params = mcc_serialization_params_t{})
|
||||
{
|
||||
auto err = MccSerializer<decltype(value.hour_prec)>{}(output, value.hour_prec, params);
|
||||
if (!err) {
|
||||
auto err = MccSerializer<decltype(value.deg_prec)>{}(output, value.deg_prec, params);
|
||||
if (!err) {
|
||||
auto err = MccSerializer<decltype(value.decimals)>{}(output, value.decimals, params);
|
||||
if (err) {
|
||||
return mcc_deduced_err(err, MccSerializerErrorCode::ERROR_UNDERLYING_SERIALIZER);
|
||||
}
|
||||
} else {
|
||||
return mcc_deduced_err(err, MccSerializerErrorCode::ERROR_UNDERLYING_SERIALIZER);
|
||||
}
|
||||
} else {
|
||||
return mcc_deduced_err(err, MccSerializerErrorCode::ERROR_UNDERLYING_SERIALIZER);
|
||||
}
|
||||
|
||||
return MccSerializerErrorCode::ERROR_OK;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
static_assert(mcc_serializer_c<MccSerializer<MccAngle>>, "!!!");
|
||||
|
||||
} // namespace mcc::impl
|
||||
@@ -104,20 +104,26 @@ inline std::error_code make_error_code(MccTelemetryErrorCode ec)
|
||||
|
||||
|
||||
template <mcc_hardware_c HARDWARE_T>
|
||||
class MccTelemetry
|
||||
class MccTelemetry : public mcc_telemetry_interface_t<MccError>
|
||||
{
|
||||
public:
|
||||
typedef HARDWARE_T hardware_t;
|
||||
|
||||
typedef std::error_code error_t;
|
||||
typedef MccError error_t;
|
||||
|
||||
|
||||
struct telemetry_data_t {
|
||||
MccSkyPoint targetPos{};
|
||||
MccSkyPoint targetPos{}; // celestial coordinates
|
||||
|
||||
MccSkyPoint mountPos{};
|
||||
MccGenXY targetXY{}; // encoder coordinates
|
||||
|
||||
typename HARDWARE_T::hardware_state_t hwState{};
|
||||
struct {
|
||||
double pcmX{}, pcmY{};
|
||||
} pcmReverseCorrection{};
|
||||
|
||||
MccSkyPoint mountPos{}; // celestial coordinates
|
||||
|
||||
typename HARDWARE_T::hardware_state_t hwState{}; // here encoder coordinates
|
||||
|
||||
struct {
|
||||
double pcmX{}, pcmY{};
|
||||
@@ -210,8 +216,8 @@ public:
|
||||
mcc_deduced_err(hw_err, MccTelemetryErrorCode::ERROR_HARDWARE_GETSTATE);
|
||||
} else {
|
||||
// compute PCM corrections and observed (corrected for PCM) mount coordinates
|
||||
auto pcm_err = pcm_ptr->computePCM(_tdataPtr->hwState.XY, &_tdataPtr->pcmCorrection,
|
||||
&_tdataPtr->mountPos);
|
||||
auto pcm_err = pcm_ptr->computePCM(_tdataPtr->hwState.XY, &(_tdataPtr->pcmCorrection),
|
||||
&(_tdataPtr->mountPos));
|
||||
|
||||
if (!pcm_err) {
|
||||
// set target coordinates
|
||||
@@ -229,14 +235,46 @@ public:
|
||||
mcc_deduced_err(pcm_err, MccTelemetryErrorCode::ERROR_PCM_COMP);
|
||||
}
|
||||
|
||||
_tdataPtr->pcmReverseCorrection.pcmX = -pcm_corr.pcmX;
|
||||
_tdataPtr->pcmReverseCorrection.pcmY = -pcm_corr.pcmY;
|
||||
} else {
|
||||
_lastUpdateError =
|
||||
mcc_deduced_err(ccte_err, MccTelemetryErrorCode::ERROR_COORD_TRANSFORM);
|
||||
}
|
||||
} else { // observed, apparent or ICRS
|
||||
_tdataPtr->targetPos = _enteredTargetPos;
|
||||
}
|
||||
|
||||
} else { // observed, apparent or ICRS
|
||||
// _tdataPtr->targetPos = _enteredTargetPos;
|
||||
using pcm_t = std::remove_pointer_t<decltype(pcm_ptr)>;
|
||||
|
||||
std::conditional_t<mcc_is_equatorial_mount<pcm_t::pcmMountType>,
|
||||
MccSkyHADEC_OBS,
|
||||
std::conditional_t<mcc_is_altaz_mount<pcm_t::pcmMountType>,
|
||||
MccSkyAZZD, std::nullptr_t>>
|
||||
cp;
|
||||
|
||||
static_assert(!std::is_null_pointer_v<decltype(cp)>, "UNKNOW MOUNT TYPE!");
|
||||
|
||||
// calculate target celestial coordinates (of the same type as .mountPos) at the
|
||||
// epoch of the current mount position
|
||||
cp.setEpoch(_tdataPtr->mountPos.epoch());
|
||||
auto ccte_err = _enteredTargetPos.to(cp);
|
||||
if (ccte_err) {
|
||||
_lastUpdateError =
|
||||
mcc_deduced_err(ccte_err, MccTelemetryErrorCode::ERROR_COORD_TRANSFORM);
|
||||
} else {
|
||||
_tdataPtr->targetPos.from(cp);
|
||||
|
||||
// calculate reverse PCM corrections for the current target position and
|
||||
// its encoder XY
|
||||
auto pcm_err = pcm_ptr->computeInversePCM(_tdataPtr->targetPos,
|
||||
&_tdataPtr->pcmReverseCorrection,
|
||||
&_tdataPtr->targetXY);
|
||||
if (pcm_err) {
|
||||
_lastUpdateError =
|
||||
mcc_deduced_err(pcm_err, MccTelemetryErrorCode::ERROR_PCM_COMP);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
_lastUpdateError = mcc_deduced_err(pcm_err, MccTelemetryErrorCode::ERROR_PCM_COMP);
|
||||
}
|
||||
@@ -278,14 +316,34 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
error_t setTarget(mcc_skypoint_c auto const& sp)
|
||||
error_t setPointingTarget(mcc_skypoint_c auto const& sp)
|
||||
{
|
||||
std::lock_guard lock{*_updateMutex};
|
||||
|
||||
_enteredTargetPos = sp;
|
||||
|
||||
return MccTelemetryErrorCode::ERROR_OK;
|
||||
}
|
||||
|
||||
|
||||
auto getPointingTarget() const
|
||||
{
|
||||
std::lock_guard lock{*_updateMutex};
|
||||
|
||||
return _enteredTargetPos;
|
||||
}
|
||||
|
||||
|
||||
// error_t getPointingTarget(mcc_skypoint_c auto* sp)
|
||||
// {
|
||||
// if (sp) {
|
||||
// *sp = _enteredTargetPos;
|
||||
// }
|
||||
|
||||
// return MccTelemetryErrorCode::ERROR_OK;
|
||||
// }
|
||||
|
||||
|
||||
//
|
||||
// blocks the current thread until telemetry data is received.
|
||||
// the maximum blocking time is equal to the set timeout (see setTelemetryDataTimeout method)
|
||||
@@ -313,12 +371,14 @@ public:
|
||||
return _lastUpdateError;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Set a timeout for the telemetry receiving process
|
||||
//
|
||||
void setTelemetryDataTimeout(traits::mcc_time_duration_c auto const& timeout)
|
||||
template <traits::mcc_time_duration_c DT>
|
||||
void setTelemetryDataTimeout(DT const& timeout)
|
||||
{
|
||||
if constexpr (std::floating_point<typename decltype(timeout)::rep>) {
|
||||
if constexpr (std::floating_point<typename DT::rep>) {
|
||||
if (utils::isEqual(timeout.count(), 0.0) || timeout.count() < 0.0) {
|
||||
return;
|
||||
}
|
||||
@@ -68,7 +68,7 @@ constexpr static std::string_view trimSpaces(const char* r, TrimType type = Trim
|
||||
}
|
||||
|
||||
template <typename T, std::ranges::contiguous_range R>
|
||||
std::optional<T> numFromStr(R&& r)
|
||||
static std::optional<T> numFromStr(R&& r)
|
||||
requires((std::integral<T> || std::floating_point<T>) &&
|
||||
std::same_as<char, std::remove_cvref_t<std::ranges::range_value_t<R>>>)
|
||||
{
|
||||
@@ -340,7 +340,10 @@ static std::string AZZD_rad2sxg(double az, double zd, std::string_view delim = "
|
||||
// "12:43:23.423, 102:43:12.124"
|
||||
// " 12.3453467, 102:43:12.124 "
|
||||
template <mcc::traits::mcc_input_char_range R>
|
||||
std::pair<double, double> parseAnglePair(R&& str, bool hms1 = false, bool hms2 = false, std::string_view delim = ",")
|
||||
static std::pair<double, double> parseAnglePair(R&& str,
|
||||
bool hms1 = false,
|
||||
bool hms2 = false,
|
||||
std::string_view delim = ",")
|
||||
{
|
||||
std::pair<double, double> res{std::numeric_limits<double>::quiet_NaN(), std::numeric_limits<double>::quiet_NaN()};
|
||||
auto found1 = std::ranges::search(std::forward<R>(str), delim);
|
||||
@@ -376,6 +379,40 @@ std::pair<double, double> parseAnglePair(R&& str, bool hms1 = false, bool hms2 =
|
||||
}
|
||||
|
||||
|
||||
// calculate distance between two point on sphere:
|
||||
// the function returns a std::tuple with
|
||||
// 0th element: difference along co-longitude axis
|
||||
// 1st element: difference along co-latitude axis
|
||||
// 2nd element: distance
|
||||
|
||||
static std::tuple<double, double, double> distanceOnSphere(double co_lon1,
|
||||
double co_lat1,
|
||||
double co_lon2,
|
||||
double co_lat2)
|
||||
{
|
||||
std::tuple<double, double, double> res{};
|
||||
|
||||
std::get<0>(res) = co_lon1 - co_lon2;
|
||||
std::get<1>(res) = co_lat1 - co_lat2;
|
||||
|
||||
double cosDco_lon = std::cos(std::abs(std::get<0>(res)));
|
||||
|
||||
double cos1 = std::cos(co_lat1);
|
||||
double sin1 = std::sin(co_lat1);
|
||||
|
||||
double cos2 = std::cos(co_lat2);
|
||||
double sin2 = std::sin(co_lat2);
|
||||
|
||||
double term1 = cos2 * std::sin(std::abs(std::get<0>(res)));
|
||||
double term2 = cos1 * sin2 - sin1 * cos2 * cosDco_lon;
|
||||
|
||||
std::get<2>(res) = std::atan2(sqrt(term1 * term1 + term2 * term2), sin1 * sin2 + cos1 * cos2 * cosDco_lon);
|
||||
|
||||
// std::get<2>(res) = acos(sin1 * sin2 + cos1 * cos2 * cosDco_lon);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
template <traits::mcc_input_char_range R>
|
||||
static constexpr size_t FNV1aHash(const R& r)
|
||||
{
|
||||
@@ -1,8 +1,8 @@
|
||||
#include <iostream>
|
||||
|
||||
// #include <mcc_ccte_erfa.h>
|
||||
#include <mcc_coordinate.h>
|
||||
#include <mcc_serializer.h>
|
||||
#include <mcc/mcc_deserializer.h>
|
||||
#include <mcc/mcc_serializer.h>
|
||||
|
||||
|
||||
using namespace mcc::impl;
|
||||
|
||||
@@ -25,15 +25,31 @@ void serialize(VT const& value)
|
||||
{
|
||||
MccSerializer<VT> ser;
|
||||
std::string s;
|
||||
mcc_serialization_params_t pars{};
|
||||
pars.norm_sxgm = true;
|
||||
pars.coordpair_format = mcc::MccSerializedCoordPairFormat::MCC_SERIALIZED_FORMAT_SXGM_HOURDEG;
|
||||
|
||||
auto err = ser(s, value);
|
||||
auto err = ser(s, value, pars);
|
||||
if (err) {
|
||||
std::cout << "SERIALIZing ERR: " << err << "\n";
|
||||
std::cout << "SERIALIZING ERR: " << err.message() << "\n";
|
||||
} else {
|
||||
std::cout << "SERIALIZED: " << s << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
template <typename VT>
|
||||
void deserialize(mcc::traits::mcc_input_char_range auto const& s, VT& value)
|
||||
{
|
||||
MccDeserializer<VT> deser;
|
||||
|
||||
auto err = deser(s, value);
|
||||
if (err) {
|
||||
std::cout << "DESERIALIZING ERR: " << err << "\n";
|
||||
} else {
|
||||
std::cout << "DESERIALIZION IS OK\n";
|
||||
}
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
skypt_t::cctEngine.setStateERFA(saoras);
|
||||
@@ -122,6 +138,9 @@ int main()
|
||||
std::cout << "\tfor 'double' type: ";
|
||||
serialize(v);
|
||||
|
||||
std::cout << "\tfor 'coord pair' type: ";
|
||||
serialize(icrs);
|
||||
|
||||
std::cout << "\tfor 'coord pair' type: ";
|
||||
serialize(radec_obs);
|
||||
|
||||
@@ -141,5 +160,22 @@ int main()
|
||||
std::cout << "\tfor 'sky point' type: ";
|
||||
serialize(pt);
|
||||
|
||||
|
||||
std::cout << "\n\nDESERIALIZATION TEST:\n";
|
||||
v = 0.0;
|
||||
|
||||
std::string s = "123.7687";
|
||||
|
||||
deserialize(s, v);
|
||||
std::cout << "\tfor 'double' type: v = " << v << "\n";
|
||||
|
||||
s = " 11:22:33.453, -32.19820931,65632.87987987,RADEC-OBS ";
|
||||
deserialize(s, pt);
|
||||
pt.toAtSameEpoch(radec_obs);
|
||||
std::cout << "\tfor 'sky point' type: x = " << radec_obs.x().sexagesimal(true)
|
||||
<< ", y = " << radec_obs.y().degrees() << ", epoch = " << pt.epoch().MJD()
|
||||
<< ", kind = " << MccCoordPairKindToStr(pt.pairKind()) << "\n";
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
127
tests/mcc_fitpack_test.cpp
Normal file
127
tests/mcc_fitpack_test.cpp
Normal file
@@ -0,0 +1,127 @@
|
||||
#include <algorithm>
|
||||
#include <functional>
|
||||
#include <iostream>
|
||||
#include <random>
|
||||
#include <ranges>
|
||||
|
||||
#include <mcc/mcc_bsplines.h>
|
||||
|
||||
int main()
|
||||
{
|
||||
size_t nt = 30, np = 60, N = nt * np, i = 1;
|
||||
// size_t nt = 10, np = 20, N = nt * np, i = 1;
|
||||
double ts = std::numbers::pi / (nt + 1);
|
||||
double ps = 2.0 * std::numbers::pi / (np + 1);
|
||||
|
||||
std::vector<double> tetha(N), phi(N), func(N);
|
||||
|
||||
auto gen_func = [](double st, size_t& idx) {
|
||||
double v = st * idx;
|
||||
++idx;
|
||||
|
||||
return v;
|
||||
};
|
||||
|
||||
auto print_func = [](const auto& r, std::string_view name) {
|
||||
std::cout << name << ": ";
|
||||
for (auto& el : r) {
|
||||
std::cout << el << " ";
|
||||
}
|
||||
std::cout << "\n";
|
||||
};
|
||||
|
||||
|
||||
// std::ranges::generate(tetha, std::bind(gen_func, ts, i));
|
||||
|
||||
// i = 1;
|
||||
// std::ranges::generate(phi, std::bind(gen_func, ps, i));
|
||||
|
||||
size_t k = 1;
|
||||
i = 0;
|
||||
for (size_t j = 0; j < nt; ++j) {
|
||||
std::ranges::fill_n(tetha.begin() + i * np, np, ts * (i + 1));
|
||||
std::ranges::generate(phi | std::views::drop(i * np) | std::views::take(np), std::bind(gen_func, ps, k));
|
||||
++i;
|
||||
k = 1;
|
||||
}
|
||||
|
||||
// std::uniform_real_distribution<double> distr{-0.1, 0.1};
|
||||
std::normal_distribution<double> distr{0.0, 1.0};
|
||||
std::random_device device;
|
||||
std::mt19937 engine{device()};
|
||||
|
||||
std::ranges::generate(func, [ii = 0, &distr, &engine, &tetha, &phi]() mutable {
|
||||
double v = (5.0 + tetha[ii]) * 1.3 + (3.0 + phi[ii]) * 3.1 + distr(engine);
|
||||
++ii;
|
||||
return v;
|
||||
});
|
||||
|
||||
|
||||
int ntk = 24, npk = 29, nf = (ntk + 4) * (npk + 4);
|
||||
// int ntk = 3, npk = 6, nf = (ntk + 4) * (npk + 4);
|
||||
std::vector<double> tk(ntk + 8), pk(npk + 8), coeffs(nf);
|
||||
ts = std::numbers::pi / (ntk + 1);
|
||||
ps = 2.0 * std::numbers::pi / (npk + 1);
|
||||
|
||||
i = 1;
|
||||
std::ranges::generate(tk | std::views::drop(4) | std::views::take(ntk), std::bind(gen_func, ts, i));
|
||||
i = 1;
|
||||
std::ranges::generate(pk | std::views::drop(4) | std::views::take(npk), std::bind(gen_func, ps, i));
|
||||
|
||||
|
||||
double rs = 0.0;
|
||||
int ec = mcc::bsplines::fitpack_sphere_fit(tetha, phi, func, 1.0, tk, pk, coeffs, rs);
|
||||
|
||||
std::cout << "FIT EC = " << ec << "\n";
|
||||
std::cout << "FIT RESI = " << rs << "\n";
|
||||
|
||||
ntk += 8;
|
||||
npk += 8;
|
||||
std::ranges::fill(tk, -1);
|
||||
std::ranges::fill(pk, -1);
|
||||
ec = mcc::bsplines::fitpack_sphere_smooth(tetha, phi, func, 1.0, 1800.0, ntk, npk, tk, pk, coeffs, rs);
|
||||
|
||||
std::cout << "FIT EC = " << ec << "\n";
|
||||
std::cout << "FIT RESI = " << rs << "\n";
|
||||
std::cout << "NKNOTS: " << ntk << ", " << npk << "\n";
|
||||
|
||||
|
||||
print_func(coeffs, "coeffs");
|
||||
|
||||
// print_func(tetha, "tetha");
|
||||
// print_func(phi, "phi");
|
||||
print_func(tk, "tetha_knots");
|
||||
print_func(pk, "phi_knots");
|
||||
print_func(func, "func");
|
||||
|
||||
std::cout << "\n\n";
|
||||
|
||||
k = 1;
|
||||
ts = std::numbers::pi / (nt + 1);
|
||||
std::ranges::generate_n(tetha.begin(), nt, std::bind(gen_func, ts, k));
|
||||
|
||||
std::vector<double> f_func;
|
||||
tetha.resize(nt);
|
||||
phi.resize(np);
|
||||
|
||||
tk.resize(ntk);
|
||||
pk.resize(npk);
|
||||
|
||||
print_func(tetha, "TETHA:");
|
||||
print_func(phi, "PHI:");
|
||||
|
||||
ec = mcc::bsplines::fitpack_eval_spl2d(tk, pk, coeffs, tetha, phi, f_func);
|
||||
// ec = mcc::bsplines::fitpack_eval_spl2d(pk, tk, coeffs, phi, tetha, f_func);
|
||||
std::cout << "EVAL EC = " << ec << "\n";
|
||||
print_func(f_func, "func");
|
||||
|
||||
std::cout << "\n\n";
|
||||
|
||||
for (size_t l = 0; l < f_func.size(); ++l) {
|
||||
auto r = f_func[l] - func[l];
|
||||
std::cout << r << " ";
|
||||
}
|
||||
std::cout << "\n";
|
||||
|
||||
return 0;
|
||||
}
|
||||
77
tests/mcc_netmsg_test.cpp
Normal file
77
tests/mcc_netmsg_test.cpp
Normal file
@@ -0,0 +1,77 @@
|
||||
#include <list>
|
||||
#include <print>
|
||||
|
||||
#include <mcc/mcc_netserver_proto.h>
|
||||
|
||||
int main()
|
||||
{
|
||||
using msg1_t = mcc::network::MccNetMessage<std::string_view>;
|
||||
using msg2_t = mcc::network::MccNetMessage<std::string>;
|
||||
|
||||
mcc::network::MccNetMessage msg3("ACK");
|
||||
|
||||
std::string_view sv{"TARGET 11:22:33.212; -0.23876984; RADEC "};
|
||||
std::vector<char> arr{sv.begin(), sv.end()};
|
||||
|
||||
msg1_t msg1;
|
||||
|
||||
msg1.fromCharRange(arr);
|
||||
|
||||
std::println("msg.key = <{}>", msg1.keyword());
|
||||
std::println("msg.par[1] = <{}>", msg1.param(1));
|
||||
|
||||
std::vector<double> vd{1.1, 2.2, 3.3};
|
||||
msg2_t msg2("ACK", 12.43298042, "EEE", std::chrono::seconds(10), vd);
|
||||
// msg2_t msg2("ACK");
|
||||
|
||||
std::println("msg.bytes = <{}>", msg2.byteRepr());
|
||||
std::println("msg.key = <{}>", msg2.keyword());
|
||||
std::println("msg.par[1] = <{}>", msg2.param(1));
|
||||
std::println("msg.par[2] = <{}>", msg2.param(2));
|
||||
|
||||
|
||||
auto p2 = msg2.paramValue<std::chrono::seconds>(2);
|
||||
std::println("msg.parvalue[2] = <{}>", p2.value_or(std::chrono::seconds{}));
|
||||
|
||||
|
||||
std::print("msg.parvalue[3] = <");
|
||||
auto p3 = msg2.paramValue<decltype(vd)>(3);
|
||||
if (p3.has_value()) {
|
||||
for (auto const& el : p3.value()) {
|
||||
std::print("{} ", el);
|
||||
}
|
||||
}
|
||||
std::println(">");
|
||||
|
||||
|
||||
std::println("msg.par[1-2] joined = <{}>", msg2.params(1, 2));
|
||||
|
||||
auto vv = msg2.params<std::list<std::string_view>>(1, 3);
|
||||
std::print("msg.par[1-3] array = <");
|
||||
for (auto const& el : vv) {
|
||||
std::print("{} ", el);
|
||||
}
|
||||
std::println(">");
|
||||
|
||||
|
||||
std::println("\n\n");
|
||||
|
||||
mcc::impl::MccSkyPoint spt(mcc::impl::MccSkyRADEC_APP{"10:00:00.0"_hms, 12.098687_degs});
|
||||
|
||||
msg2.construct("ACK", "MOUNT", mcc::MccSerializedAngleFormatPrec{3, 2}, spt);
|
||||
std::println("msg2.bytes = <{}>", msg2.byteRepr());
|
||||
|
||||
auto spt_d = msg2.paramValue<mcc::impl::MccSkyPoint>(1);
|
||||
|
||||
if (spt_d) {
|
||||
std::println("msg2.parvalue(1).pairKind() = {}", MccCoordPairKindToStr(spt_d->pairKind()));
|
||||
std::println("msg2.parvalue(1).epoch() = {}", spt_d->epoch().MJD() + mcc::MCC_MJD_ZERO);
|
||||
} else {
|
||||
std::println("cannot deserialize MccSkyPoint value!");
|
||||
}
|
||||
|
||||
msg2.construct("ACK", "MOUNT", mcc::MccSerializedCoordPairFormat::MCC_SERIALIZED_FORMAT_DEGREES, spt);
|
||||
std::println("msg2.bytes = <{}>", msg2.byteRepr());
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,8 +1,8 @@
|
||||
#include <iostream>
|
||||
|
||||
#include <mcc_coordinate.h>
|
||||
#include <mcc_pzone.h>
|
||||
#include <mcc_pzone_container.h>
|
||||
#include <mcc/mcc_coordinate.h>
|
||||
#include <mcc/mcc_pzone.h>
|
||||
#include <mcc/mcc_pzone_container.h>
|
||||
|
||||
using namespace mcc::impl;
|
||||
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
|
||||
#include <random>
|
||||
|
||||
#include <mcc_pcm.h>
|
||||
#include <mcc_telemetry.h>
|
||||
|
||||
#include <mcc/mcc_pcm.h>
|
||||
#include <mcc/mcc_serializer.h>
|
||||
#include <mcc/mcc_telemetry.h>
|
||||
|
||||
static std::random_device rd;
|
||||
static std::mt19937 gen(rd());
|
||||
@@ -14,7 +14,11 @@ static std::uniform_real_distribution<double> y_distrib(1000, 7000);
|
||||
static std::uniform_real_distribution<double> xs_distrib(100, 700);
|
||||
static std::uniform_real_distribution<double> ys_distrib(100, 700);
|
||||
|
||||
static std::uniform_int_distribution<uint8_t> err_distrib(0, 255);
|
||||
|
||||
|
||||
struct hw_t {
|
||||
static constexpr mcc::MccMountType hwMountType{mcc::MccMountType::ALTAZ_TYPE};
|
||||
static constexpr std::string_view hardwareName{"HW-TEST"};
|
||||
|
||||
typedef int error_t;
|
||||
@@ -52,15 +56,47 @@ struct hw_t {
|
||||
|
||||
*state = hardware_state_t{.XY{x_distrib(gen), y_distrib(gen)}, .speedXY{xs_distrib(gen), ys_distrib(gen)}};
|
||||
|
||||
return 0;
|
||||
// return 0;
|
||||
return err_distrib(gen) < 5 ? 1 : 0;
|
||||
}
|
||||
|
||||
error_t hardwareInit()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
error_t hardwareShutdown()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct std::formatter<hw_t::hardware_movement_state_t, char> : std::formatter<std::string_view> {
|
||||
auto format(hw_t::hardware_movement_state_t e, auto& ctx) const
|
||||
{
|
||||
return formatter<std::string_view>::format(e == hw_t::hardware_movement_state_t::HW_MOVE_ERROR ? "ERROR"
|
||||
: e == hw_t::hardware_movement_state_t::HW_MOVE_STOPPED ? "STOPPED"
|
||||
: e == hw_t::hardware_movement_state_t::HW_MOVE_STOPPING ? "STOPPING"
|
||||
: e == hw_t::hardware_movement_state_t::HW_MOVE_SLEWING ? "SLEWING"
|
||||
: e == hw_t::hardware_movement_state_t::HW_MOVE_TRACKING ? "TRACKING"
|
||||
: "UNKNOWN",
|
||||
ctx);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// template <>
|
||||
// struct std::formatter<hw_t::hardware_movement_state_t, char>
|
||||
// : std::formatter<std::underlying_type_t<hw_t::hardware_movement_state_t>, char> {
|
||||
// auto format(hw_t::hardware_movement_state_t e, auto& ctx) const
|
||||
// {
|
||||
// return formatter<std::underlying_type_t<hw_t::hardware_movement_state_t>>::format(
|
||||
// std::underlying_type_t<hw_t::hardware_movement_state_t>(e), ctx);
|
||||
// }
|
||||
// };
|
||||
|
||||
|
||||
|
||||
static_assert(mcc::mcc_hardware_c<hw_t>, "!!!!!");
|
||||
|
||||
@@ -86,5 +122,18 @@ int main()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
mcc::impl::MccSerializer<typename t_t::telemetry_data_t> ser;
|
||||
|
||||
std::string str;
|
||||
|
||||
auto err = ser(str, tdata);
|
||||
if (err) {
|
||||
std::cout << "ERR: " << err.message() << "\n";
|
||||
} else {
|
||||
std::cout << "\n\n";
|
||||
std::cout << str << "\n";
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user