@@ -101,8 +107,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
const ZOOM_MARGIN = 10;
- import WebGLImpl from "../common/AMCImplementation_WebGL.js"
- import LayerViewImpl from "../common/AMCImplementation_LayerView.js"
+ import WebGLImpl from "@core/common/AMCImplementation_WebGL.js"
+ import LayerViewImpl from "@core/common/AMCImplementation_LayerView.js"
export default {
props: ["Application", "module"],
@@ -128,11 +134,33 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
showJumps: true,
loadingLayerData: false,
loadingScatterplot: false,
- hoverOverData: true
+ hoverOverData: true,
+ appliedCoordinateTransform: ""
}),
methods: {
+ applyCoordinateTransform: function () {
+ const platform = this.module.platform;
+ if (!platform || !this.LayerViewerInstance)
+ return;
+
+ const transform = [
+ Number(platform.transformangle) || 0,
+ Number(platform.rotationcenterx) || 0,
+ Number(platform.rotationcentery) || 0,
+ Number(platform.translationx) || 0,
+ Number(platform.translationy) || 0
+ ];
+ const transformKey = transform.join(",");
+ if (transformKey === this.appliedCoordinateTransform)
+ return;
+
+ this.LayerViewerInstance.setCoordinateTransform(...transform);
+ this.appliedCoordinateTransform = transformKey;
+ this.LayerViewerInstance.RenderScene(true);
+ },
+
onResize: function () {
let domelement = this.$refs.layerViewDiv;
if (!domelement)
@@ -157,8 +185,12 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
this.LayerViewerInstance.setColorMode ("laseron");
}
else if (this.LayerViewerInstance.layerPointsMode == "laseron") {
+ this.LayerViewerInstance.setColorMode ("powerramp");
+ }
+ else if (this.LayerViewerInstance.layerPointsMode == "powerramp") {
this.LayerViewerInstance.setColorMode ("uniform");
- } else {
+ }
+ else {
this.LayerViewerInstance.setColorMode ("time");
}
},
@@ -168,12 +200,26 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
this.LayerViewerInstance.updateLoadedLayer ();
},
+ onToggleShowLaserOffClick: function () {
+ this.LayerViewerInstance.showLaserOffPoints = !this.LayerViewerInstance.showLaserOffPoints;
+ this.LayerViewerInstance.updateLayerPoints();
+ },
+
onResetViewClick: function () {
let platform = this.module.platform;
if (platform) {
- this.LayerViewerInstance.CenterOnRectangle (- ZOOM_MARGIN, - ZOOM_MARGIN, platform.sizex + ZOOM_MARGIN, platform.sizey + ZOOM_MARGIN);
+ // Origin is machine-zero's location inside the plate (from lower-left),
+ // so plate corners in machine coords span -origin .. (size - origin).
+ let ox = platform.originx || 0;
+ let oy = platform.originy || 0;
+ let sx = platform.sizex;
+ let sy = platform.sizey;
+ // Optional per-axis padding (in mm) enlarging the reset zoom window.
+ let px = platform.paddingx || 0;
+ let py = platform.paddingy || 0;
+ this.LayerViewerInstance.CenterOnRectangle (- ox - ZOOM_MARGIN - px, - oy - ZOOM_MARGIN - py, (sx - ox) + ZOOM_MARGIN + px, (sy - oy) + ZOOM_MARGIN + py);
this.LayerViewerInstance.RenderScene (true);
}
},
@@ -240,6 +286,10 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
return "Color: LaserOn";
}
+ if (this.LayerViewerInstance.layerPointsMode == "powerramp") {
+ return "Color: Power";
+ }
+
return "Color: Uniform";
},
@@ -256,10 +306,10 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
if (pathBoundaries.radius > 0) {
- const left = pathBoundaries.center.x - pathBoundaries.radius + platform.sizex / 2;
- const right = pathBoundaries.center.x + pathBoundaries.radius + platform.sizex / 2;
- const top = pathBoundaries.center.y - pathBoundaries.radius + platform.sizey / 2;
- const bottom = pathBoundaries.center.y + pathBoundaries.radius + platform.sizey / 2;
+ const left = pathBoundaries.center.x - pathBoundaries.radius + platform.originx;
+ const right = pathBoundaries.center.x + pathBoundaries.radius + platform.originx;
+ const top = pathBoundaries.center.y - pathBoundaries.radius + platform.originy;
+ const bottom = pathBoundaries.center.y + pathBoundaries.radius + platform.originy;
this.LayerViewerInstance.CenterOnRectangle (left, top, right, bottom);
this.LayerViewerInstance.RenderScene (true);
@@ -308,7 +358,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
{
this.LayerViewerInstance.clearPoints ();
- return this.Application.axiosGetArrayBufferRequest("/ui/pointcloud/" + scatterplotuuid)
+ return this.Application.axiosGetArrayBufferRequest("/pointcloud/" + scatterplotuuid)
.then(responseData => {
let pointcoordinates = new Float32Array(responseData.data);
@@ -332,7 +382,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
{
this.LayerViewerInstance.clearPointsChannelData (pointsChannelName);
- return this.Application.axiosGetArrayBufferRequest("/ui/pointchanneldata/" + scatterplotuuid + "/" + pointsChannelName)
+ return this.Application.axiosGetArrayBufferRequest("/pointchanneldata/" + scatterplotuuid + "/" + pointsChannelName)
.then(responseData => {
const contentType = responseData.headers['content-type'];
@@ -357,6 +407,12 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
} else {
console.log(`${key}: ${floatArray.length}`);
}
+ } else if (key.toLowerCase() === 'power') {
+ if (this.LayerViewerInstance) {
+ this.LayerViewerInstance.loadPointsChannelData ("laser", key.toLowerCase(), floatArray);
+ } else {
+ console.log(`${key}: ${floatArray.length}`);
+ }
}
} else {
console.warn(`Key "${key}" is not an array and will be ignored.`);
@@ -389,6 +445,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
let module = this.module;
let platform = this.module.platform;
if (platform && sender) {
+ this.applyCoordinateTransform();
if (module.isActive () && (sender.uuid === module.uuid)) {
@@ -581,13 +638,15 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
const mouseX = event.clientX - renderElementPosition.left;
const mouseY = event.clientY - renderElementPosition.top;
- let pointIndex = this.LayerViewerInstance.glInstance.getRaycasterCollisions ("layerdata_points", mouseX, mouseY);
+ let rawPointIndex = this.LayerViewerInstance.glInstance.getRaycasterCollisions ("layerdata_points", mouseX, mouseY);
+ let pointIndex = this.LayerViewerInstance.resolvePointIndex (rawPointIndex);
if (pointIndex >= 0) {
let pointPosition = this.LayerViewerInstance.getPointPosition (pointIndex);
let pointVelocity = this.LayerViewerInstance.getPointVelocity (pointIndex);
let pointAcceleration = this.LayerViewerInstance.getPointAcceleration (pointIndex);
let pointJerk = this.LayerViewerInstance.getPointJerk (pointIndex);
+ let pointPower = this.LayerViewerInstance.getPointPower (pointIndex);
let infoCaption = `Point ID = ${pointIndex.toFixed(0)}\n`;
if (pointPosition) {
@@ -605,7 +664,10 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
let jerkinmeterspersecondsquared = pointJerk.j / 1000000.0;
infoCaption += `Jerk: ${jerkinmeterspersecondsquared.toFixed(4)} km/s³\n`;
}
-
+ if (pointPower) {
+ let powerinwatts = pointPower; // * 1000.0;
+ infoCaption += `Power: ${powerinwatts.toFixed(4)} W\n`;
+ }
this.lastMouseX = mouseX;
this.lastMouseY = mouseY;
@@ -632,8 +694,12 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
const laserpower = this.LayerViewerInstance.segmentProperties[lineIndex].laserpower;
const laserspeed = this.LayerViewerInstance.segmentProperties[lineIndex].laserspeed;
+ const profilename = this.LayerViewerInstance.segmentProperties[lineIndex].profilename;
let infoCaption = `Line ID = ${lineIndex.toFixed(0)}\n${x1.toFixed(3)} / ${y1.toFixed(3)} - ${x2.toFixed(3)} / ${y2.toFixed(3)} mm\n`;
infoCaption += `${laserpower.toFixed(0)}W / ${laserspeed.toFixed (1)} mm/s`;
+ if (profilename) {
+ infoCaption += `\nProfile: ${profilename}`;
+ }
infoboxDiv.innerText = infoCaption;
infoboxDiv.style.background = 'rgba(0, 0, 0, 0.7)';
}
@@ -666,24 +732,24 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
},
- created () {
- this.module.onDataHasChanged = null;
- if (this.module.platform) {
- this.module.platform.displayed_layer = 0;
- this.module.platform.displayed_build = 0;
- }
-
- this.glInstance = this.Application.retrieveWebGLInstance (module.uuid);
+ created () {
+ this.module.onDataHasChanged = null;
+ if (this.module.platform) {
+ this.module.platform.displayed_layer = 0;
+ this.module.platform.displayed_build = 0;
+ }
+
+ this.glInstance = this.Application.retrieveWebGLInstance (this.module.uuid);
- if (!this.glInstance) {
- this.glInstance = new WebGLImpl ();
+ if (!this.glInstance) {
+ this.glInstance = new WebGLImpl ();
+ this.Application.storeWebGLInstance (this.module.uuid, this.glInstance);
+ }
- this.Application.storeWebGLInstance (this.glInstance);
- this.LayerViewerInstance = new LayerViewImpl (this.glInstance);
- this.LayerViewerInstance.RenderScene (true);
-
- }
- },
+ // Always create a fresh LayerViewerInstance wrapping the (possibly cached) glInstance.
+ this.LayerViewerInstance = new LayerViewImpl (this.glInstance);
+ this.LayerViewerInstance.RenderScene (true);
+ },
unmounted ()
{
@@ -725,7 +791,15 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
}
this.LayerViewerInstance.setOrigin (platform.originx, platform.originy);
- this.LayerViewerInstance.CenterOnRectangle (- ZOOM_MARGIN, - ZOOM_MARGIN, platform.sizex + ZOOM_MARGIN, platform.sizey + ZOOM_MARGIN);
+ this.applyCoordinateTransform();
+ let ox = platform.originx || 0;
+ let oy = platform.originy || 0;
+ let sx = platform.sizex;
+ let sy = platform.sizey;
+ // Optional per-axis padding (in mm) enlarging the reset zoom window.
+ let px = platform.paddingx || 0;
+ let py = platform.paddingy || 0;
+ this.LayerViewerInstance.CenterOnRectangle (- ox - ZOOM_MARGIN - px, - oy - ZOOM_MARGIN - py, (sx - ox) + ZOOM_MARGIN + px, (sy - oy) + ZOOM_MARGIN + py);
this.viewed_platform_uuid = platform.uuid;
}
diff --git a/Client/vue2/src/modules/AMCModule_Logs.vue b/Client/vue2/src/modules/AMCModule_Logs.vue
new file mode 100644
index 00000000..61c0e9f3
--- /dev/null
+++ b/Client/vue2/src/modules/AMCModule_Logs.vue
@@ -0,0 +1,457 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+ mdi-arrow-collapse-down
+
+
+ Scroll to bottom
+
+
+
+
+
+
+
+
+ mdi-format-list-numbered
+
+
+ Limit shown entries ({{ effectiveLimit }})
+
+
+
+
+ {{ opt.label }}
+
+
+
+
+
+
+
+
+
+
+
+ mdi-filter-variant
+
+
+
+ {{ subsystemFilter ? 'Filter: ' + subsystemFilter : 'Filter by subsystem' }}
+
+
+
+
+
+ mdi-filter-off-outline
+
+ Clear filter
+
+
+
+ {{ sys }}
+
+
+ No entries
+
+
+
+
+
+
+
+
+
+
+ mdi-download
+
+
+ Download log
+
+
+
+
+ mdi-code-json
+ Current view – JSON
+
+
+ mdi-code-json
+ All historic – JSON
+
+
+
+ mdi-file-delimited-outline
+ Current view – CSV
+
+
+ mdi-file-delimited-outline
+ All historic – CSV
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Client/vue2/src/modules/AMCModule_Paragraph.vue b/Client/vue2/src/modules/AMCModule_Paragraph.vue
new file mode 100644
index 00000000..f84b9ce8
--- /dev/null
+++ b/Client/vue2/src/modules/AMCModule_Paragraph.vue
@@ -0,0 +1,129 @@
+
+
+
+
+
+
+ {{ module.text }}
+
+
+
+
+
+
+
+
diff --git a/Client/vue2/src/modules/AMCModule_ParameterList.vue b/Client/vue2/src/modules/AMCModule_ParameterList.vue
new file mode 100644
index 00000000..87c7d5e2
--- /dev/null
+++ b/Client/vue2/src/modules/AMCModule_ParameterList.vue
@@ -0,0 +1,501 @@
+
+
+
+
+
+
+ {{ filterSummary }}
+
+ mdi-download
+ CSV
+
+
+
+
+ mdi-tune-variant
+
+
+
+
+
+
+
+
+ {{ isFavorite(item) ? 'mdi-star' : 'mdi-star-outline' }}
+
+
+
+
+
+ mdi-check
+ mdi-close
+
+ {{ item.paramValue }}
+ {{ item.paramValue }}
+
+
+
+ No entries available
+
+
+
+
+
+ Save view preset
+
+
+
+
+
+ Cancel
+ Save
+
+
+
+
+
+
+
+
+
+
diff --git a/Client/vue2/src/modules/AMCModule_PartList.vue b/Client/vue2/src/modules/AMCModule_PartList.vue
new file mode 100644
index 00000000..8721362c
--- /dev/null
+++ b/Client/vue2/src/modules/AMCModule_PartList.vue
@@ -0,0 +1,221 @@
+
+
+
+
+
+
{{ loadingText }}
+
{{ errorMessage }}
+
No build selected.
+
+
+
+
+
+
+ Parts ({{ parts.length }})
+
+
+
+
+ |
+ Part name |
+ Part number |
+
+
+
+
+ | No parts in this build. |
+
+
+ | mdi-cube-outline |
+ {{ part.name || '—' }} |
+ {{ part.partnumber || '—' }} |
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Client/src/modules/AMCModule_ContentItem_Chart.vue b/Client/vue2/src/modules/AMCModule_Separator.vue
similarity index 50%
rename from Client/src/modules/AMCModule_ContentItem_Chart.vue
rename to Client/vue2/src/modules/AMCModule_Separator.vue
index d238cd11..a98c78dc 100644
--- a/Client/src/modules/AMCModule_ContentItem_Chart.vue
+++ b/Client/vue2/src/modules/AMCModule_Separator.vue
@@ -1,6 +1,6 @@
+
+
+
+
+
+ {{ iconName }}
+
+ {{ module.title }}
+ — {{ module.description }}
+
+
+
+
+
+
+
+
diff --git a/Client/vue2/src/modules/AMCModule_StatusList.vue b/Client/vue2/src/modules/AMCModule_StatusList.vue
new file mode 100644
index 00000000..9df60aee
--- /dev/null
+++ b/Client/vue2/src/modules/AMCModule_StatusList.vue
@@ -0,0 +1,157 @@
+
+
+
+
+
+
{{ module.title }}
+
+ {{ module.loadingtext || 'No status available.' }}
+
+
+ {{ row.label }}
+ {{ renderRow(row).text }}
+ {{ renderRow(row).text }}
+
+
+
+
+
+
+
+
diff --git a/Client/vue2/src/modules/AMCModule_TableBase.vue b/Client/vue2/src/modules/AMCModule_TableBase.vue
new file mode 100644
index 00000000..1d08df3e
--- /dev/null
+++ b/Client/vue2/src/modules/AMCModule_TableBase.vue
@@ -0,0 +1,264 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Client/src/modules/AMCModule_Tabs.vue b/Client/vue2/src/modules/AMCModule_Tabs.vue
similarity index 52%
rename from Client/src/modules/AMCModule_Tabs.vue
rename to Client/vue2/src/modules/AMCModule_Tabs.vue
index 02bb83e8..b3a6c5d7 100644
--- a/Client/src/modules/AMCModule_Tabs.vue
+++ b/Client/vue2/src/modules/AMCModule_Tabs.vue
@@ -30,62 +30,75 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-
-
-
+
+
+
+
-
{{ moduleTab.caption }}
-
-
-
-
-
+
+
+
-
-
-
-
-
-
-
+
+
-
-
+
-
+
+
+
diff --git a/Client/vue2/src/modules/AMCModule_TogglePanel.vue b/Client/vue2/src/modules/AMCModule_TogglePanel.vue
new file mode 100644
index 00000000..2e6ba115
--- /dev/null
+++ b/Client/vue2/src/modules/AMCModule_TogglePanel.vue
@@ -0,0 +1,133 @@
+
+
+
+
+
+
+
+ {{ toggle.label }}
+ {{ stateLabel(toggle) }}
+
+
+
+
+
+
+
+
+
+
diff --git a/Client/src/modules/AMCModule_ContentItem_Upload.vue b/Client/vue2/src/modules/AMCModule_Upload.vue
similarity index 54%
rename from Client/src/modules/AMCModule_ContentItem_Upload.vue
rename to Client/vue2/src/modules/AMCModule_Upload.vue
index cbb59085..a06d3fb4 100644
--- a/Client/src/modules/AMCModule_ContentItem_Upload.vue
+++ b/Client/vue2/src/modules/AMCModule_Upload.vue
@@ -30,51 +30,44 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-
+
+
+
-
\ No newline at end of file
+
diff --git a/Client/src/modules/AMCModule_Logs.vue b/Client/vue2/src/modules/AMCModule_VideoStream.vue
similarity index 67%
rename from Client/src/modules/AMCModule_Logs.vue
rename to Client/vue2/src/modules/AMCModule_VideoStream.vue
index 77e16738..0bfb0294 100644
--- a/Client/src/modules/AMCModule_Logs.vue
+++ b/Client/vue2/src/modules/AMCModule_VideoStream.vue
@@ -30,44 +30,38 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-
-
-
-
-
+
+
![Video Stream]()
+
- export default {
- props: ["Application", "module"],
-
- components: {
- },
-
- data: () => ({
- Headers: [
- { text: 'Time', value: 'logTime', width: "50pt", fixed: true },
- { text: 'Subsystem', value: 'logSubsystem', width: "50pt", fixed: true },
- { text: 'Text', value: 'logText' },
- ],
-
- logsAvailable: false,
- tab: null
- })
-
- };
-
-
\ No newline at end of file
+
diff --git a/Client/src/vuetify.js b/Client/vue2/src/vuetify.js
similarity index 85%
rename from Client/src/vuetify.js
rename to Client/vue2/src/vuetify.js
index 834fe0a4..fe1bbf44 100644
--- a/Client/src/vuetify.js
+++ b/Client/vue2/src/vuetify.js
@@ -36,13 +36,19 @@ Vue.use(Vuetify);
export default new Vuetify({
theme: {
+ dark: false,
themes: {
light: {
- primary: '#808080',
- secondary: '#1e1e1e',
- accent: '#666666',
- error: '#DD2222',
+ primary: '#C8102E',
+ secondary: '#3C3C3C',
+ accent: '#C8102E',
+ error: '#C8102E',
+ info: '#2979FF',
+ success: '#43A047',
+ warning: '#F9A825',
+ background: '#E0E3E7',
+ surface: '#FFFFFF',
},
},
- },
+ },
});
diff --git a/Client/vue.config.js b/Client/vue2/vue.config.js
similarity index 90%
rename from Client/vue.config.js
rename to Client/vue2/vue.config.js
index 43e322ec..723a51ef 100644
--- a/Client/vue.config.js
+++ b/Client/vue2/vue.config.js
@@ -28,8 +28,17 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
+const path = require('path');
+
module.exports = {
"transpileDependencies": [
"vuetify"
- ]
+ ],
+ configureWebpack: {
+ resolve: {
+ alias: {
+ '@core': path.resolve(__dirname, '../core')
+ }
+ }
+ }
}
\ No newline at end of file
diff --git a/DevTools/CMakeLists_Distrib.txt b/DevTools/CMakeLists_Distrib.txt
index b7174787..07fbc660 100644
--- a/DevTools/CMakeLists_Distrib.txt
+++ b/DevTools/CMakeLists_Distrib.txt
@@ -26,7 +26,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
]]
-cmake_minimum_required(VERSION 3.5)
+cmake_minimum_required(VERSION 3.10)
set(CMAKE_C_IMPLICIT_LINK_LIBRARIES "")
diff --git a/DevTools/build_clean_distrib_linux64.sh b/DevTools/build_clean_distrib_linux64.sh
index 87dcf0ed..4ee0f0cd 100644
--- a/DevTools/build_clean_distrib_linux64.sh
+++ b/DevTools/build_clean_distrib_linux64.sh
@@ -1,9 +1,6 @@
#!/bin/bash
set -e
-# disable go modules
-export GO111MODULE="off"
-
scriptpath="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
echo "script path: $scriptpath"
cd "$scriptpath"
@@ -40,4 +37,3 @@ cmake ..
cmake --build . --config Release
cd Output
-
diff --git a/DevTools/build_clean_distrib_rpi.sh b/DevTools/build_clean_distrib_rpi.sh
index d22dabf1..0faaa1e2 100644
--- a/DevTools/build_clean_distrib_rpi.sh
+++ b/DevTools/build_clean_distrib_rpi.sh
@@ -1,9 +1,6 @@
#!/bin/bash
set -e
-# disable go modules
-export GO111MODULE="off"
-
scriptpath="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
echo "script path: $scriptpath"
cd "$scriptpath"
@@ -40,4 +37,3 @@ cmake ..
cmake --build . --config Release
cd Output
-
diff --git a/DevTools/build_clean_distrib_win64.bat b/DevTools/build_clean_distrib_win64.bat
index 948759d1..4c1bb8fa 100644
--- a/DevTools/build_clean_distrib_win64.bat
+++ b/DevTools/build_clean_distrib_win64.bat
@@ -6,7 +6,7 @@ SET /p DEVPACKAGE=
/dev/null 2>&1; then
+ echo "lcov not found. Please install lcov/genhtml before running coverage."
+ exit 1
+fi
+
+mkdir -p "$BUILD_DIR"
+if [[ ! -f "$BUILD_DIR/githash.txt" ]]; then
+ GITHASH=""
+ if command -v git >/dev/null 2>&1; then
+ GITHASH="$(git -C "$ROOT_DIR" rev-parse --short=8 HEAD 2>/dev/null || true)"
+ fi
+ if [[ -z "$GITHASH" && -f "$ROOT_DIR/build_linux64/githash.txt" ]]; then
+ GITHASH="$(cat "$ROOT_DIR/build_linux64/githash.txt" 2>/dev/null || true)"
+ fi
+ if [[ -z "$GITHASH" && -f "$ROOT_DIR/githash.txt" ]]; then
+ GITHASH="$(cat "$ROOT_DIR/githash.txt" 2>/dev/null || true)"
+ fi
+ if [[ -z "$GITHASH" ]]; then
+ echo "githash.txt not found and git hash unavailable. Run build_clean_linux64.sh or ensure githash.txt exists."
+ exit 1
+ fi
+ printf "%s\n" "$GITHASH" > "$BUILD_DIR/githash.txt"
+fi
+
+if [[ ! -f "$BUILD_DIR/clientdirhash.txt" ]]; then
+ CLIENTHASH=""
+ if [[ -f "$ROOT_DIR/build_linux64/clientdirhash.txt" ]]; then
+ CLIENTHASH="$(cat "$ROOT_DIR/build_linux64/clientdirhash.txt" 2>/dev/null || true)"
+ fi
+ if [[ -z "$CLIENTHASH" && -f "$ROOT_DIR/clientdirhash.txt" ]]; then
+ CLIENTHASH="$(cat "$ROOT_DIR/clientdirhash.txt" 2>/dev/null || true)"
+ fi
+ if [[ -z "$CLIENTHASH" ]]; then
+ echo "clientdirhash.txt not found. Run build_clean_linux64.sh or ensure clientdirhash.txt exists."
+ exit 1
+ fi
+ printf "%s\n" "$CLIENTHASH" > "$BUILD_DIR/clientdirhash.txt"
+fi
+
+cmake -S "$ROOT_DIR" -B "$BUILD_DIR" -DINCLUDE_TESTS=ON -DENABLE_COVERAGE=ON
+
+TARGETS=()
+if [[ $RUN_UNITTEST -eq 1 ]]; then
+ TARGETS+=("amc_unittest")
+fi
+if [[ ${#TESTDEFS[@]} -gt 0 ]]; then
+ TARGETS+=("amc_test")
+fi
+if [[ ${#EXTRA_TARGETS[@]} -gt 0 ]]; then
+ TARGETS+=("${EXTRA_TARGETS[@]}")
+fi
+
+if [[ ${#TARGETS[@]} -gt 0 ]]; then
+ cmake --build "$BUILD_DIR" --target "${TARGETS[@]}"
+fi
+
+pushd "$BUILD_DIR" >/dev/null
+lcov --directory . --zerocounters
+
+if [[ $RUN_UNITTEST -eq 1 ]]; then
+ ./Output/amc_unittest
+fi
+
+if [[ ${#TESTDEFS[@]} -gt 0 ]]; then
+ CMD=(./Output/amc_test)
+ for def in "${TESTDEFS[@]}"; do
+ CMD+=(--testdefinition "$def")
+ done
+ "${CMD[@]}"
+fi
+
+lcov --capture --directory . --base-directory "$ROOT_DIR" --output-file coverage.info
+lcov --ignore-errors unused --remove coverage.info \
+ '/usr/*' \
+ "$ROOT_DIR/3RD_PARTY/*" \
+ "$ROOT_DIR/Framework/*" \
+ "$ROOT_DIR/Libraries/*" \
+ "$ROOT_DIR/SDK/*" \
+ "$ROOT_DIR/submodules/*" \
+ --output-file coverage.info
+genhtml coverage.info --output-directory coverage_html
+echo "Coverage report: $BUILD_DIR/coverage_html/index.html"
+popd >/dev/null
diff --git a/DevTools/packageManager.arm b/DevTools/packageManager.arm
deleted file mode 100644
index 59097910..00000000
Binary files a/DevTools/packageManager.arm and /dev/null differ
diff --git a/DevTools/packageManager.exe b/DevTools/packageManager.exe
deleted file mode 100644
index 1cbad191..00000000
Binary files a/DevTools/packageManager.exe and /dev/null differ
diff --git a/DevTools/packageManager.linux64 b/DevTools/packageManager.linux64
deleted file mode 100644
index bdc43c28..00000000
Binary files a/DevTools/packageManager.linux64 and /dev/null differ
diff --git a/DevTools/package_manager.exe b/DevTools/package_manager.exe
new file mode 100644
index 00000000..92de7cef
Binary files /dev/null and b/DevTools/package_manager.exe differ
diff --git a/Documentation/API/source/Drivers/ADS/CMakeLists_dynamic.txt b/Documentation/API/source/Drivers/ADS/CMakeLists_dynamic.txt
index 0db43f08..a1743c9f 100644
--- a/Documentation/API/source/Drivers/ADS/CMakeLists_dynamic.txt
+++ b/Documentation/API/source/Drivers/ADS/CMakeLists_dynamic.txt
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 3.5)
+cmake_minimum_required(VERSION 3.10)
set(CMAKE_CURRENT_BINDING_DIR ${CMAKE_CURRENT_SOURCE_DIR}/.)
project(LibMCDriver_ADSExample_CPPDynamic)
diff --git a/Documentation/API/source/Drivers/ADS/CMakeLists_implicit.txt b/Documentation/API/source/Drivers/ADS/CMakeLists_implicit.txt
index 6490dde3..000bb58a 100644
--- a/Documentation/API/source/Drivers/ADS/CMakeLists_implicit.txt
+++ b/Documentation/API/source/Drivers/ADS/CMakeLists_implicit.txt
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 3.5)
+cmake_minimum_required(VERSION 3.10)
set(CMAKE_CURRENT_BINDING_DIR ${CMAKE_CURRENT_SOURCE_DIR}/.)
project(LibMCDriver_ADSExample_CPPImplicit)
diff --git a/Documentation/API/source/Drivers/BuR/CMakeLists_dynamic.txt b/Documentation/API/source/Drivers/BuR/CMakeLists_dynamic.txt
index e4da181d..d2881321 100644
--- a/Documentation/API/source/Drivers/BuR/CMakeLists_dynamic.txt
+++ b/Documentation/API/source/Drivers/BuR/CMakeLists_dynamic.txt
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 3.5)
+cmake_minimum_required(VERSION 3.10)
set(CMAKE_CURRENT_BINDING_DIR ${CMAKE_CURRENT_SOURCE_DIR}/.)
project(LibMCDriver_BuRExample_CPPDynamic)
diff --git a/Documentation/API/source/Drivers/BuR/CMakeLists_implicit.txt b/Documentation/API/source/Drivers/BuR/CMakeLists_implicit.txt
index 3c145441..664627fa 100644
--- a/Documentation/API/source/Drivers/BuR/CMakeLists_implicit.txt
+++ b/Documentation/API/source/Drivers/BuR/CMakeLists_implicit.txt
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 3.5)
+cmake_minimum_required(VERSION 3.10)
set(CMAKE_CURRENT_BINDING_DIR ${CMAKE_CURRENT_SOURCE_DIR}/.)
project(LibMCDriver_BuRExample_CPPImplicit)
diff --git a/Documentation/API/source/Drivers/Duet/CMakeLists_dynamic.txt b/Documentation/API/source/Drivers/Duet/CMakeLists_dynamic.txt
index f35238fd..00660151 100644
--- a/Documentation/API/source/Drivers/Duet/CMakeLists_dynamic.txt
+++ b/Documentation/API/source/Drivers/Duet/CMakeLists_dynamic.txt
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 3.5)
+cmake_minimum_required(VERSION 3.10)
set(CMAKE_CURRENT_BINDING_DIR ${CMAKE_CURRENT_SOURCE_DIR}/.)
project(LibMCDriver_DuetExample_CPPDynamic)
diff --git a/Documentation/API/source/Drivers/Duet/CMakeLists_implicit.txt b/Documentation/API/source/Drivers/Duet/CMakeLists_implicit.txt
index 51ebc7b3..17c74b17 100644
--- a/Documentation/API/source/Drivers/Duet/CMakeLists_implicit.txt
+++ b/Documentation/API/source/Drivers/Duet/CMakeLists_implicit.txt
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 3.5)
+cmake_minimum_required(VERSION 3.10)
set(CMAKE_CURRENT_BINDING_DIR ${CMAKE_CURRENT_SOURCE_DIR}/.)
project(LibMCDriver_DuetExample_CPPImplicit)
diff --git a/Documentation/API/source/Drivers/LibOAPC/CMakeLists_dynamic.txt b/Documentation/API/source/Drivers/LibOAPC/CMakeLists_dynamic.txt
index 510677fb..a6611a13 100644
--- a/Documentation/API/source/Drivers/LibOAPC/CMakeLists_dynamic.txt
+++ b/Documentation/API/source/Drivers/LibOAPC/CMakeLists_dynamic.txt
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 3.5)
+cmake_minimum_required(VERSION 3.10)
set(CMAKE_CURRENT_BINDING_DIR ${CMAKE_CURRENT_SOURCE_DIR}/.)
project(LibMCDriver_LibOAPCExample_CPPDynamic)
diff --git a/Documentation/API/source/Drivers/LibOAPC/CMakeLists_implicit.txt b/Documentation/API/source/Drivers/LibOAPC/CMakeLists_implicit.txt
index aa7275c1..3a92a143 100644
--- a/Documentation/API/source/Drivers/LibOAPC/CMakeLists_implicit.txt
+++ b/Documentation/API/source/Drivers/LibOAPC/CMakeLists_implicit.txt
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 3.5)
+cmake_minimum_required(VERSION 3.10)
set(CMAKE_CURRENT_BINDING_DIR ${CMAKE_CURRENT_SOURCE_DIR}/.)
project(LibMCDriver_LibOAPCExample_CPPImplicit)
diff --git a/Documentation/API/source/Drivers/Marlin/CMakeLists_dynamic.txt b/Documentation/API/source/Drivers/Marlin/CMakeLists_dynamic.txt
index c70dc39f..a2166924 100644
--- a/Documentation/API/source/Drivers/Marlin/CMakeLists_dynamic.txt
+++ b/Documentation/API/source/Drivers/Marlin/CMakeLists_dynamic.txt
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 3.5)
+cmake_minimum_required(VERSION 3.10)
set(CMAKE_CURRENT_BINDING_DIR ${CMAKE_CURRENT_SOURCE_DIR}/.)
project(LibMCDriver_MarlinExample_CPPDynamic)
diff --git a/Documentation/API/source/Drivers/Marlin/CMakeLists_implicit.txt b/Documentation/API/source/Drivers/Marlin/CMakeLists_implicit.txt
index a6cc70ba..b1541662 100644
--- a/Documentation/API/source/Drivers/Marlin/CMakeLists_implicit.txt
+++ b/Documentation/API/source/Drivers/Marlin/CMakeLists_implicit.txt
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 3.5)
+cmake_minimum_required(VERSION 3.10)
set(CMAKE_CURRENT_BINDING_DIR ${CMAKE_CURRENT_SOURCE_DIR}/.)
project(LibMCDriver_MarlinExample_CPPImplicit)
diff --git a/Documentation/API/source/Drivers/OPCUA/CMakeLists_dynamic.txt b/Documentation/API/source/Drivers/OPCUA/CMakeLists_dynamic.txt
index ccbbf381..56e439aa 100644
--- a/Documentation/API/source/Drivers/OPCUA/CMakeLists_dynamic.txt
+++ b/Documentation/API/source/Drivers/OPCUA/CMakeLists_dynamic.txt
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 3.5)
+cmake_minimum_required(VERSION 3.10)
set(CMAKE_CURRENT_BINDING_DIR ${CMAKE_CURRENT_SOURCE_DIR}/.)
project(LibMCDriver_OPCUAExample_CPPDynamic)
diff --git a/Documentation/API/source/Drivers/OPCUA/CMakeLists_implicit.txt b/Documentation/API/source/Drivers/OPCUA/CMakeLists_implicit.txt
index 8e6507ad..8030823a 100644
--- a/Documentation/API/source/Drivers/OPCUA/CMakeLists_implicit.txt
+++ b/Documentation/API/source/Drivers/OPCUA/CMakeLists_implicit.txt
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 3.5)
+cmake_minimum_required(VERSION 3.10)
set(CMAKE_CURRENT_BINDING_DIR ${CMAKE_CURRENT_SOURCE_DIR}/.)
project(LibMCDriver_OPCUAExample_CPPImplicit)
diff --git a/Documentation/API/source/Drivers/Rasterizer/CMakeLists_dynamic.txt b/Documentation/API/source/Drivers/Rasterizer/CMakeLists_dynamic.txt
index b35346cd..a276d801 100644
--- a/Documentation/API/source/Drivers/Rasterizer/CMakeLists_dynamic.txt
+++ b/Documentation/API/source/Drivers/Rasterizer/CMakeLists_dynamic.txt
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 3.5)
+cmake_minimum_required(VERSION 3.10)
set(CMAKE_CURRENT_BINDING_DIR ${CMAKE_CURRENT_SOURCE_DIR}/.)
project(LibMCDriver_RasterizerExample_CPPDynamic)
diff --git a/Documentation/API/source/Drivers/Rasterizer/CMakeLists_implicit.txt b/Documentation/API/source/Drivers/Rasterizer/CMakeLists_implicit.txt
index 8cfb2dad..45c7a2b5 100644
--- a/Documentation/API/source/Drivers/Rasterizer/CMakeLists_implicit.txt
+++ b/Documentation/API/source/Drivers/Rasterizer/CMakeLists_implicit.txt
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 3.5)
+cmake_minimum_required(VERSION 3.10)
set(CMAKE_CURRENT_BINDING_DIR ${CMAKE_CURRENT_SOURCE_DIR}/.)
project(LibMCDriver_RasterizerExample_CPPImplicit)
diff --git a/Documentation/API/source/Drivers/RayLase/CMakeLists_dynamic.txt b/Documentation/API/source/Drivers/RayLase/CMakeLists_dynamic.txt
index f1fc2147..046606dc 100644
--- a/Documentation/API/source/Drivers/RayLase/CMakeLists_dynamic.txt
+++ b/Documentation/API/source/Drivers/RayLase/CMakeLists_dynamic.txt
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 3.5)
+cmake_minimum_required(VERSION 3.10)
set(CMAKE_CURRENT_BINDING_DIR ${CMAKE_CURRENT_SOURCE_DIR}/.)
project(LibMCDriver_RaylaseExample_CPPDynamic)
diff --git a/Documentation/API/source/Drivers/RayLase/CMakeLists_implicit.txt b/Documentation/API/source/Drivers/RayLase/CMakeLists_implicit.txt
index 6d37daa3..b2a07405 100644
--- a/Documentation/API/source/Drivers/RayLase/CMakeLists_implicit.txt
+++ b/Documentation/API/source/Drivers/RayLase/CMakeLists_implicit.txt
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 3.5)
+cmake_minimum_required(VERSION 3.10)
set(CMAKE_CURRENT_BINDING_DIR ${CMAKE_CURRENT_SOURCE_DIR}/.)
project(LibMCDriver_RaylaseExample_CPPImplicit)
diff --git a/Documentation/API/source/Drivers/S7Net/CMakeLists_dynamic.txt b/Documentation/API/source/Drivers/S7Net/CMakeLists_dynamic.txt
index f582ad0b..84749f66 100644
--- a/Documentation/API/source/Drivers/S7Net/CMakeLists_dynamic.txt
+++ b/Documentation/API/source/Drivers/S7Net/CMakeLists_dynamic.txt
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 3.5)
+cmake_minimum_required(VERSION 3.10)
set(CMAKE_CURRENT_BINDING_DIR ${CMAKE_CURRENT_SOURCE_DIR}/.)
project(LibMCDriver_S7NetExample_CPPDynamic)
diff --git a/Documentation/API/source/Drivers/S7Net/CMakeLists_implicit.txt b/Documentation/API/source/Drivers/S7Net/CMakeLists_implicit.txt
index 2d4528f5..c697757f 100644
--- a/Documentation/API/source/Drivers/S7Net/CMakeLists_implicit.txt
+++ b/Documentation/API/source/Drivers/S7Net/CMakeLists_implicit.txt
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 3.5)
+cmake_minimum_required(VERSION 3.10)
set(CMAKE_CURRENT_BINDING_DIR ${CMAKE_CURRENT_SOURCE_DIR}/.)
project(LibMCDriver_S7NetExample_CPPImplicit)
diff --git a/Documentation/API/source/Drivers/ScanLab/CMakeLists_dynamic.txt b/Documentation/API/source/Drivers/ScanLab/CMakeLists_dynamic.txt
index 60ff4437..0781715b 100644
--- a/Documentation/API/source/Drivers/ScanLab/CMakeLists_dynamic.txt
+++ b/Documentation/API/source/Drivers/ScanLab/CMakeLists_dynamic.txt
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 3.5)
+cmake_minimum_required(VERSION 3.10)
set(CMAKE_CURRENT_BINDING_DIR ${CMAKE_CURRENT_SOURCE_DIR}/.)
project(LibMCDriver_ScanLabExample_CPPDynamic)
diff --git a/Documentation/API/source/Drivers/ScanLab/CMakeLists_implicit.txt b/Documentation/API/source/Drivers/ScanLab/CMakeLists_implicit.txt
index 25ae10db..ee372e52 100644
--- a/Documentation/API/source/Drivers/ScanLab/CMakeLists_implicit.txt
+++ b/Documentation/API/source/Drivers/ScanLab/CMakeLists_implicit.txt
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 3.5)
+cmake_minimum_required(VERSION 3.10)
set(CMAKE_CURRENT_BINDING_DIR ${CMAKE_CURRENT_SOURCE_DIR}/.)
project(LibMCDriver_ScanLabExample_CPPImplicit)
diff --git a/Documentation/API/source/Drivers/ScanLabOIE/CMakeLists_dynamic.txt b/Documentation/API/source/Drivers/ScanLabOIE/CMakeLists_dynamic.txt
index ca30fc31..71bb3817 100644
--- a/Documentation/API/source/Drivers/ScanLabOIE/CMakeLists_dynamic.txt
+++ b/Documentation/API/source/Drivers/ScanLabOIE/CMakeLists_dynamic.txt
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 3.5)
+cmake_minimum_required(VERSION 3.10)
set(CMAKE_CURRENT_BINDING_DIR ${CMAKE_CURRENT_SOURCE_DIR}/.)
project(LibMCDriver_ScanLabOIEExample_CPPDynamic)
diff --git a/Documentation/API/source/Drivers/ScanLabOIE/CMakeLists_implicit.txt b/Documentation/API/source/Drivers/ScanLabOIE/CMakeLists_implicit.txt
index 93cfa41f..490514bd 100644
--- a/Documentation/API/source/Drivers/ScanLabOIE/CMakeLists_implicit.txt
+++ b/Documentation/API/source/Drivers/ScanLabOIE/CMakeLists_implicit.txt
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 3.5)
+cmake_minimum_required(VERSION 3.10)
set(CMAKE_CURRENT_BINDING_DIR ${CMAKE_CURRENT_SOURCE_DIR}/.)
project(LibMCDriver_ScanLabOIEExample_CPPImplicit)
diff --git a/Documentation/API/source/Drivers/TCPIP/CMakeLists_dynamic.txt b/Documentation/API/source/Drivers/TCPIP/CMakeLists_dynamic.txt
index a7754656..e557e47a 100644
--- a/Documentation/API/source/Drivers/TCPIP/CMakeLists_dynamic.txt
+++ b/Documentation/API/source/Drivers/TCPIP/CMakeLists_dynamic.txt
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 3.5)
+cmake_minimum_required(VERSION 3.10)
set(CMAKE_CURRENT_BINDING_DIR ${CMAKE_CURRENT_SOURCE_DIR}/.)
project(LibMCDriver_TCPIPExample_CPPDynamic)
diff --git a/Documentation/API/source/Drivers/TCPIP/CMakeLists_implicit.txt b/Documentation/API/source/Drivers/TCPIP/CMakeLists_implicit.txt
index 7f0ce2fb..408dc4b0 100644
--- a/Documentation/API/source/Drivers/TCPIP/CMakeLists_implicit.txt
+++ b/Documentation/API/source/Drivers/TCPIP/CMakeLists_implicit.txt
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 3.5)
+cmake_minimum_required(VERSION 3.10)
set(CMAKE_CURRENT_BINDING_DIR ${CMAKE_CURRENT_SOURCE_DIR}/.)
project(LibMCDriver_TCPIPExample_CPPImplicit)
diff --git a/Documentation/API/source/Drivers/UART/CMakeLists_dynamic.txt b/Documentation/API/source/Drivers/UART/CMakeLists_dynamic.txt
index a961bc54..caa2b834 100644
--- a/Documentation/API/source/Drivers/UART/CMakeLists_dynamic.txt
+++ b/Documentation/API/source/Drivers/UART/CMakeLists_dynamic.txt
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 3.5)
+cmake_minimum_required(VERSION 3.10)
set(CMAKE_CURRENT_BINDING_DIR ${CMAKE_CURRENT_SOURCE_DIR}/.)
project(LibMCDriver_UARTExample_CPPDynamic)
diff --git a/Documentation/API/source/Drivers/UART/CMakeLists_implicit.txt b/Documentation/API/source/Drivers/UART/CMakeLists_implicit.txt
index a8fc0cf5..202bad2a 100644
--- a/Documentation/API/source/Drivers/UART/CMakeLists_implicit.txt
+++ b/Documentation/API/source/Drivers/UART/CMakeLists_implicit.txt
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 3.5)
+cmake_minimum_required(VERSION 3.10)
set(CMAKE_CURRENT_BINDING_DIR ${CMAKE_CURRENT_SOURCE_DIR}/.)
project(LibMCDriver_UARTExample_CPPImplicit)
diff --git a/Documentation/API/source/Drivers/Ximc/CMakeLists_dynamic.txt b/Documentation/API/source/Drivers/Ximc/CMakeLists_dynamic.txt
index 2d0a2a23..355d937e 100644
--- a/Documentation/API/source/Drivers/Ximc/CMakeLists_dynamic.txt
+++ b/Documentation/API/source/Drivers/Ximc/CMakeLists_dynamic.txt
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 3.5)
+cmake_minimum_required(VERSION 3.10)
set(CMAKE_CURRENT_BINDING_DIR ${CMAKE_CURRENT_SOURCE_DIR}/.)
project(LibMCDriver_XimcExample_CPPDynamic)
diff --git a/Documentation/API/source/Drivers/Ximc/CMakeLists_implicit.txt b/Documentation/API/source/Drivers/Ximc/CMakeLists_implicit.txt
index aacf4dd4..3d350ec7 100644
--- a/Documentation/API/source/Drivers/Ximc/CMakeLists_implicit.txt
+++ b/Documentation/API/source/Drivers/Ximc/CMakeLists_implicit.txt
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 3.5)
+cmake_minimum_required(VERSION 3.10)
set(CMAKE_CURRENT_BINDING_DIR ${CMAKE_CURRENT_SOURCE_DIR}/.)
project(LibMCDriver_XimcExample_CPPImplicit)
diff --git a/Documentation/API/source/Environment/CMakeLists_dynamic.txt b/Documentation/API/source/Environment/CMakeLists_dynamic.txt
index 79892ca3..d747a7da 100644
--- a/Documentation/API/source/Environment/CMakeLists_dynamic.txt
+++ b/Documentation/API/source/Environment/CMakeLists_dynamic.txt
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 3.5)
+cmake_minimum_required(VERSION 3.10)
set(CMAKE_CURRENT_BINDING_DIR ${CMAKE_CURRENT_SOURCE_DIR}/.)
project(LibMCEnvExample_CPPDynamic)
diff --git a/Documentation/API/source/Environment/CMakeLists_implicit.txt b/Documentation/API/source/Environment/CMakeLists_implicit.txt
index f343bdea..955374a8 100644
--- a/Documentation/API/source/Environment/CMakeLists_implicit.txt
+++ b/Documentation/API/source/Environment/CMakeLists_implicit.txt
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 3.5)
+cmake_minimum_required(VERSION 3.10)
set(CMAKE_CURRENT_BINDING_DIR ${CMAKE_CURRENT_SOURCE_DIR}/.)
project(LibMCEnvExample_CPPImplicit)
diff --git a/Documentation/Introduction/AutodeskMachineControlFramework.md b/Documentation/Introduction/AutodeskMachineControlFramework.md
index be5a4b95..1d84e03c 100644
--- a/Documentation/Introduction/AutodeskMachineControlFramework.md
+++ b/Documentation/Introduction/AutodeskMachineControlFramework.md
@@ -284,14 +284,140 @@ As those are many configurations, in order to balance complexity with the need o
### 1.3. Modular Architecture and the need for a Client-Server system
-There are a lot of ways and opinions how one could define a modular architecture.
+There are many interpretations of "modular architecture", but in AMCF the meaning is practical: each part of the system should be replaceable or extensible without rewriting the entire stack. A machine builder should be able to swap a driver, add a new build strategy, or customize the operator workflow while keeping safety logic, scheduling, and API contracts intact. Modularity only exists if separation of concerns is enforced by clear boundaries, stable interfaces, and explicit data ownership. This reduces integration risk, accelerates vendor onboarding, and prevents long-term drift between UI and machine behavior.
+
+At the highest level, AMCF is organized into three layers: a deterministic core server that owns state, scheduling, and safety-relevant decisions; a client layer that renders the UI and communicates over a stable API; and a plugin/driver layer that integrates hardware and process logic. Each layer is independently replaceable as long as its interface contract is respected. The server is the single source of truth, the client is a consumer and operator interface, and the plugin layer is the only place that should know about proprietary device details.
+
+This structure naturally leads to a client-server architecture. In industrial control systems, the UI is only one of several consumers of machine state and services. Other consumers include automated test harnesses, remote service tools, analytics pipelines, and manufacturing execution systems (MES). A client-server design formalizes that all machine functionality is exposed as a service usable by any authorized client. This is critical for integration with factory ecosystems, for multi-client access, and for consistent behavior across different deployment contexts.
+
+The server is designed to run headless with identical behavior whether a UI is attached or not. It can run on an industrial PC, a rack-mounted server, or a virtualized environment for simulation and testing. Clients can be local (HMI), remote (service), or distributed. Because the server owns state and arbitrates actions, multiple clients can connect simultaneously without introducing inconsistent behavior. The server validates all actions under the same safety and scheduling constraints, ensuring that client diversity does not compromise correctness.
+
+The client-server split also prevents tight coupling between UI logic and machine logic. In tightly coupled systems, UI features become de facto control logic and are hard to test or reuse. AMCF enforces that control actions are implemented in the server and exposed via API endpoints. The UI does not "own" functionality; it only presents it. This keeps control logic testable with automated clients and makes UI redesigns low risk with respect to core machine behavior.
+
+Determinism and safety are major reasons to keep the server authoritative. Machine control requires predictable timing, state transitions, and interlocks. The server enforces these constraints without being affected by UI latency or network variability. By isolating timing-sensitive logic in the server, AMCF ensures safety-critical transitions execute under controlled conditions.
+
+The plugin and driver layer is the mechanism that localizes hardware differences. Machines vary in sensors, actuators, motion controllers, scanners, cameras, and safety devices. AMCF isolates hardware integration into drivers and plugin interfaces so machine builders can tailor their hardware stack without modifying the core. Vendor-specific SDKs or protocols belong here, not in the server or client. This keeps the server stable and makes new hardware onboarding a localized change rather than a system-wide refactor.
+
+Because drivers and plugins are modular, they can be tested in isolation. Simulation drivers can provide deterministic responses for unit and integration tests, and process logic can be exercised without real hardware. The same API surface used in production is used in tests, which reduces the need for custom harnesses and makes test results representative. A simulated server can also support UI development and regression testing without constant access to a physical machine.
+
+From a deployment and operations perspective, the client-server model separates update cycles. UI features often evolve faster than core machine logic, so a workflow or dashboard can ship without touching the server. Conversely, a server security or safety patch can be deployed without rebuilding the UI, reducing downtime and validation effort.
+
+Scalability, security, and resilience also improve. As machines become more connected, a server with a single authoritative state can serve multiple clients with controlled permissions. Authentication and authorization are enforced in one place, and client commands are validated as untrusted input. If a UI disconnects or a network link fails, the server continues operating safely and clients can recover state through the API.
+
+In practice, the architecture supports common deployment patterns without special cases:
+
+- Local HMI with server on the same machine for low-latency control.
+- Remote UI clients over a network for monitoring and service.
+- Headless server operation with automated clients or scripts for testing and integration.
+
+All of these use the same API contract, which makes them predictable and easier to maintain.
+
+Finally, modularity is essential for long-term evolution. Machines often live for decades, while UI technologies and hardware components evolve quickly. A stable server with versioned interfaces allows new clients, plugins, and drivers to evolve independently. This is a strategy for managing change across the lifetime of a machine, not just a technical preference.
+
+In summary, AMCF’s modular architecture provides strong boundaries between control logic, hardware integration, and user interaction. The client-server split enables determinism, safety, multi-client support, independent updates, robust testing, and long-term maintainability. It allows AMCF to function as a platform rather than a single-purpose application, supporting diverse machines and workflows while keeping the core stable and reliable.
### 1.4. Plugin mechanism and choice of programming language
+Every machine is a specialized system. The framework therefore exposes extension points for:
+
+- Drivers (hardware connectivity)
+- Process logic (build strategies, motion sequences)
+- UI modules (custom operator workflows)
+
+AMCF standardizes these extension points with a strict interface contract rather than ad hoc C++ headers. The contract is defined in XML and consumed by the Autodesk Component Toolkit (ACT), which generates the bindings, ABI headers, and wrapper code used across the framework. This is a deliberate design choice: interface definitions are treated as declarative specifications, while generated artifacts are treated as build outputs. Developers change the XML, regenerate, and then implement or consume the resulting interfaces. This avoids hand-crafted glue code, enforces consistency, and makes interface evolution explicit and auditable.
+
+ACT XML files live alongside the framework and drivers. Examples include `ACT/LibMCEnv.xml` for core environment interfaces, `SDK/ACT/LibAMCF.xml` for the public SDK, and `Drivers/*/ACT/LibMCDriver_*.xml` for hardware drivers. These XML files describe the library namespace, versioning, error codes, data types, and the classes and methods exposed by the component. XML is used because it is concise, diff-friendly, and easy to validate. It also scales well across different interface scopes: a core server API, a single driver, or a UI plugin can all be expressed with the same schema.
+
+The XML definition is the single source of truth for interface shape. It captures:
+
+- Library identity and version metadata (library name, namespace, base name).
+- Error codes and error descriptions to keep API behavior consistent.
+- Types, enums, and data structures shared across components.
+- Class and method signatures, including parameters and return values.
+- Import relationships between components, where one interface depends on another.
+
+From that XML, ACT generates the bindings and ABI layers that allow components to interact safely. In this repository, the generated output includes C and C++ headers, dynamic loader wrappers, ABI definitions, and language-specific bindings for the SDK. You can see these outputs in folders such as `Framework/HeadersCore`, `Framework/InterfacesCore`, `SDK/Headers`, and in each driver’s `Headers` and `Interfaces` directories. Generated source and header files are clearly marked as ACT output; they should not be edited directly. The workflow is always: edit the XML, run ACT to regenerate, and then update implementation code as needed.
+
+This approach also explains the choice of programming language. Plugins and drivers are implemented in C++ because machine control and hardware access require deterministic performance, tight memory control, and straightforward integration with existing SDKs. C++ also maps well onto the ABI layer that ACT generates. However, by using ACT-generated bindings, AMCF can expose those same interfaces to additional languages where appropriate, especially for higher-level integration and client tooling. The SDK includes bindings in multiple languages (for example C, C++, Python, and NodeJS), which makes it possible to integrate with external systems or build tooling without re-implementing the core logic. The interface surface remains the same because it is defined once in XML and re-generated for each target language.
+
+ACT is also what makes versioning and backward compatibility tractable. Because interfaces are declarative, changes can be reviewed in a single file and then propagated to all bindings in a controlled manner. This reduces the risk of ABI mismatches between the server, plugins, and clients. It also means that changes to error codes, types, or method signatures are visible and can be enforced during code review, which supports long-term maintainability and supports multiple platform builds without custom glue.
+
+For driver development, the XML approach is particularly valuable. A driver can import core components (for example `LibMCEnv`) to reuse shared types and services while defining only the driver-specific API. The generated headers provide a consistent interface to the server, while the implementation stays focused on vendor SDK integration and device-specific logic. This keeps driver code smaller and more predictable, and it avoids diverging conventions from one driver to the next. The same mechanism is used for UI plugins and process logic modules, which makes the overall plugin ecosystem easier to extend and document.
+
+In short, AMCF’s plugin mechanism depends on ACT as the interface definition and code generation layer. XML definitions make contracts explicit, reduce ambiguity, and allow consistent bindings across languages. C++ remains the primary implementation language for performance and control, while ACT-generated bindings open the ecosystem to other languages for integration, tooling, and client development. This combination gives AMCF both the low-level control required for machine operation and the flexibility needed for long-term platform growth.
+
### 1.5. The Hourglass pattern and Stable ABIs
+The hourglass model in AMCF is realized through ACT’s ABI strategy. At the top, you can have a rich, high-level class architecture: interfaces, inheritance, and structured types that make sense to an SDK user or driver author. At the bottom, you can have many different consumers and host environments that each want a simple, stable way to call into that architecture. The narrow middle is a plain C ABI that acts as the stable contract between them.
+
+ACT takes the declarative interface definition and generates a flat C DLL surface. Each class instance becomes a handle, and each method becomes a function that takes that handle plus serialized parameters. The C ABI uses standard error codes for all calls, which ensures a consistent failure model regardless of language or runtime. This layer is intentionally minimal: no C++ name mangling, no exceptions, no STL types, and no compiler-specific ABI details. The result is a binary interface that remains stable across compiler versions and across languages.
+
+On the consumer side, ACT-generated bindings reconstruct the richer class model. The C ABI functions are wrapped into language-native classes or interfaces, exposing idiomatic method calls, typed parameters, and resource lifetimes. From the point of view of a client, it feels like using a normal SDK. Under the hood, each call is routed through the C ABI, with error codes translated into language-native exceptions or return types. This "expand again" step is what preserves developer ergonomics while keeping the ABI compatible and predictable.
+
+The benefit of this pattern is that the complex class hierarchy is not the ABI; the ABI is the thin C layer. That means new languages can be supported by generating new wrappers without changing the core, and drivers or plugins compiled with older toolchains can keep working against newer servers as long as the C layer remains compatible. It also means that runtime loading becomes simple and uniform: every plugin is just a DLL with a defined set of exported C functions, and every consumer speaks the same function-level contract.
+
+This model also makes it straightforward to integrate proprietary third-party code. A plugin or driver can link against vendor SDKs, hardware libraries, or closed-source toolkits internally while exposing only the stable C ABI to the outside. The proprietary dependency stays encapsulated behind the handle-based interface, so the rest of the system does not have to understand or adapt to vendor-specific binaries, compilers, or error models. As long as the plugin respects the ABI contract, the core remains unaffected and stability is preserved.
+
+The hourglass approach helps manage change at different speeds. Vendor SDKs may update frequently, operating systems may add new requirements, and clients may demand new UX capabilities. Those changes can be absorbed at the edges without forcing a ripple through the system, because the middle remains narrow and stable. ACT’s generated C ABI becomes the governance point for compatibility, allowing the framework to enforce versioning, detect mismatches early, and keep older components operational during a transition.
+
+In practice, this means API boundaries are strict. Input and output types are explicit, error codes are formalized, and versioning is part of the design, not an afterthought. The narrow middle becomes a safe place to stand: a known set of behaviors that clients and drivers can trust. The wide edges remain free to innovate, but they do so by speaking the same stable language. Over time, this approach protects the system from fragmentation, keeps long-lived deployments supportable, and allows AMCF to grow in capability without sacrificing reliability.
+
### 1.6. API First Design guidelines and best practices
+API-first means the server API is the primary product surface, and everything else
+(UI, scripts, automation, and integrations) is a client of that API. If a feature
+is important for operators or external systems, it must be reachable through a
+documented endpoint. This keeps the behavior consistent across clients, reduces
+hidden state, and makes integration predictable. It also forces the team to think
+about stability and supportability before a feature ships.
+
+API-first has a few core implications for the framework. The server owns the
+domain model and state transitions; the UI only visualizes and orchestrates.
+Business rules live in the server API layer so that a button click and a remote
+integration call have the same effect. Features must be implemented as API
+capabilities first, then consumed by UI or plugins. This prevents UI-only logic,
+ensures testability, and avoids subtle discrepancies between local and remote
+operation.
+
+To keep the API reliable and evolvable, design endpoints as explicit contracts.
+Every request should return structured data and explicit error codes, never rely
+on ad-hoc text or ambiguous HTTP status mapping. Favor clear, typed payloads over
+deeply nested or under-specified blobs. When a request changes server state,
+make the operation explicit and document the required preconditions (e.g.,
+machine state, permissions, or resource locks). Where possible, design actions
+to be idempotent so clients can retry safely. Use pagination for lists, stable
+identifiers for resources, and consistent naming across endpoints.
+
+Versioning is non-negotiable. Any breaking change must be introduced as a new
+API version, with existing versions kept operational for a defined period. Add
+new fields in a backward-compatible way and avoid changing semantics of existing
+fields. Deprecate with a clear migration path, and document the planned removal
+window. This approach protects older UI packages and external integrations while
+allowing forward progress. In practice, API versioning should be reflected in
+endpoint paths and in the generated client bindings where applicable.
+
+Security and permissions must be enforced at the API boundary. Do not depend on
+UI behavior for access control. Every endpoint should validate permissions based
+on roles and session context, and return clear errors when access is denied. If
+an action has safety implications, the API should require explicit confirmation
+or a stronger permission scope, and that requirement should be documented.
+
+Observability is part of the contract. API calls should generate structured
+logs, meaningful error codes, and correlate with build/job identifiers when
+relevant. This makes it possible to trace behavior in the field and tie a
+failure to a specific build, configuration, or machine state. For long-running
+operations, provide status or progress endpoints and consistent polling or event
+mechanisms. Avoid hidden background tasks that cannot be queried or cancelled.
+
+Finally, design the API so it is pleasant to consume. Documentation should
+describe the purpose of each endpoint, the request and response models, and
+example payloads. Keep names consistent, provide clear field descriptions, and
+call out invariants. A simple rule is to treat the API docs as a first-class
+deliverable that changes in lockstep with the code. Tests should validate both
+success and failure cases, and new features should add API-level tests alongside
+implementation changes. When in doubt, ask: could a third-party integration
+reliably use this endpoint without reading the server code? If the answer is
+no, the API is not yet first-class.
### 1.7. Serialization principles, XML, JSON and binary storage
### 1.8. Resource handling and file access
@@ -304,6 +430,14 @@ There are a lot of ways and opinions how one could define a modular architecture
### 2.2. Using of git hashes in the core code
+The framework embeds git hashes into build artifacts to track provenance. This allows the machine operator and developer to identify the exact source revision of a running system, which is critical for:
+
+- Debugging field issues
+- Reproducing test results
+- Verifying compatibility of plugins and packages
+
+Build scripts store hashes in `build_/githash.txt` and package metadata, and the server exposes this information in its output folder and logs.
+
### 2.3. Stable APIs, Backwards compatibility and Data migration
### 2.4. Separation of Data and Logic and forward compatibilty.
@@ -312,6 +446,8 @@ There are a lot of ways and opinions how one could define a modular architecture
### 2.6. Testing Framework
+Testing is integrated into the CMake build and includes both unit tests and system tests. The unit test framework in `Implementation/UnitTest` is built into the `amc_unittest` binary, while driver tests live under `Tests/Test`. Tests are expected to run against deterministic inputs and use simulation drivers where possible.
+
## 3. General Backend Architecture
### 3.1. Client Server Implementation
@@ -485,4 +621,3 @@ There are a lot of ways and opinions how one could define a modular architecture
# VII Tutorials
# VIII AMCF REST API Documentation
-
diff --git a/Documentation/Website/index.html b/Documentation/Website/index.html
index dada04b7..2298e0c4 100644
--- a/Documentation/Website/index.html
+++ b/Documentation/Website/index.html
@@ -371,7 +371,7 @@ Schaeffler
Evobeam
With a background in electron beam welding and vacuum
- machines, Evobeam's SLAvam 300 system ventures into Powder Bed Fusion, and offers high temperature
+ machines, Evobeam's SLaVAM 300 system ventures into Powder Bed Fusion, and offers high temperature
processes up to 1000° degree C in a vacuum atmosphere.
- Your Windows development environment should host Visual Studio, CMake, Go and git.
+ Your Windows development environment should host Visual Studio, CMake and git.
@@ -911,4 +911,4 @@ Communit