Repository navigation
Streaming data capture, RTC6 large-layer exposure, resumable downloads and Svelte client fixes (Data capture rebased 2026 11 04) - #98
Open
yrodzikau wants to merge 17 commits into
Conversation
…Footer and DialogTitle to keep long 3MF names and buttons inside dialogs On the Build Library page, selecting a build opened the details dialog with the 3MF file name and the "Close"/"Select" buttons running past the dialog border. DialogContent is a single-column CSS grid whose implicit auto column grows to the min-content width of its widest child. A file name without spaces is one unbreakable word, so the column grew beyond the 500px dialog box and the right-aligned footer moved with it. The fix is applied to the shared shadcn-svelte dialog components, so every dialog in the Svelte client gets it. feat(dialog-content): cap the content column and wrap long words - Add grid-cols-[minmax(0,1fr)]: the column can no longer grow wider than the dialog, so header, body and footer stay inside the border. - Add wrap-anywhere (overflow-wrap: anywhere). The property is inherited, so long names, paths and module content wrap in every dialog. Unlike wrap-break-word it also lowers the min-content width, which the grid column needs in order to shrink. Button captions keep whitespace-nowrap and stay on one line. feat(dialog-footer): wrap footer buttons - Add sm:flex-wrap. Buttons are shrink-0 and whitespace-nowrap, so several or long buttons (e.g. multiple <button> entries in a <buildlist>) now move to the next row instead of overflowing. feat(dialog-title): reserve space for the close button - Add pe-6 so a title that wraps does not run under the absolutely positioned close (X) button. Affected dialogs: - Build Library details dialog (ModuleBuildList): fixes the reported overflow. - Build History details dialog (ModuleExecutionList): same markup, same fix. - config.xml dialogs rendered in routes/+page.svelte (e.g. pausedialog): long titles now wrap instead of being clipped. Notes: - components/ui/dialog/* are shadcn-svelte generated files. Running "shadcn-svelte add dialog" again will overwrite these changes. - <buttongroup> rows (ModuleButtonGroup) still do not wrap. In config.xml dialogs, long captions produce a horizontal scrollbar. This commit does not change that. - The prebuilt package Artifacts/clientdist/clientpackage_svelte.zip is not part of this commit. Rebuild it with Artifacts/build_client_svelte_clean.bat and commit it separately. Signed-off-by: Yury Rodzikau <y.rodzikau@c1-technologies.com>
…oad/Set Active and tab visibility The Svelte client showed the config.xml defaults on the ScanlabOCM System Settings page instead of the active machine configuration. The page fills its fields in the "onshowsystemsettings" show event with UIEnvironment::SetUIProperty, but the V2 frontend (/api/frontend) did not include the show event and ignored values set by SetUIProperty. feat(ui): send the page show event in the V2 frontend - CUIPage::frontendWritePageStatusToJSON() writes "showevent", so AMCPage.setActive() triggers it again. feat(ui): report values and visibility set by UI event handlers - CUIFrontendState::writeModuleAttributesToJSON() writes the session client variable with the attribute's name, if one exists, instead of the definition value. Attributes bound with sync: are still evaluated from the state machine, as in the legacy syncClientVariables(). - Add CUIFrontendDefinitionAttribute::isSynchronized(), writeClientValueToFrontendJSON() and CUIFrontendDefinitionModuleStore::getPath(). feat(svelte-client): fix the configuration list fallback buttons - Load and Set Active no longer send their placeholder id as the button UUID, which the server rejected with "invalid uuid string". - Remove the Delete fallback: no plugin handles "deleteconfiguration". feat(svelte-client): hide invisible tabs in ModuleTabs feat(unittest): add the UIFrontend test group Signed-off-by: Yury Rodzikau <y.rodzikau@c1-technologies.com>
Client variables take precedence over module attributes in the new frontend, so the resource name written by populateClientVariables() overrode the resolved UUID and the Svelte client could not load the platform image. Resolve the name in all three places through a shared helper; an empty name yields the null UUID (empty string for the dark image, meaning "fall back to the light one"). Signed-off-by: Yury Rodzikau <y.rodzikau@c1-technologies.com>
… in the snackbar - triggerUIEvent(): an errorcode in the /event response or a request failure is shown via the new showEventError(); a failed event no longer runs the success path - add showSnackBar() that sets every SnackBar field and bumps a new Sequence counter, so repeated identical messages restart auto-hide - Snackbar.svelte depends on Sequence - App.vue: snackBarVisible gets a setter, otherwise Vuetify cannot reset Visible and the next error is never shown - triggerWidgetRequest(): optional failureCallback(err) for callers that need to roll back optimistic UI state Signed-off-by: Yury Rodzikau <y.rodzikau@c1-technologies.com>
Signed-off-by: Yury Rodzikau <y.rodzikau@c1-technologies.com>
…ture set - load scatter plot points and the laser channel (laseron, power), color modes, LaserOff point toggle, toolpath visibility toggle - hover info for the point or toolpath segment under the cursor, throttled to one raycast per animation frame - layer slider: correct range (layercount - 1), send changelayer only on release, -/+ step buttons, sliderfixed support, follow the server only on changed values, optimistic change with rollback on failure - platform label and loading indicator - re-attach the canvas and resize observer when the module is hidden and shown again - ignore stale toolpath/scatter plot responses, treat the null UUID as "no build"/"no image" - remove the mouse-move debug logging from WebGLLocalizedPointsElement Signed-off-by: Yury Rodzikau <y.rodzikau@c1-technologies.com>
…n modal dialogs that the user cannot close, for the "Pausing Build…" / "Canceling Build…" wait screens State machines cannot open dialogs and UI event handlers cannot set machine parameters, so a dialog could only be opened by a click and closed by the user. The pause/resume/cancel build controls need dialogs that main opens while it finishes the current layer, that cannot be dismissed, and that close by themselves once the machine is ready. This adds that generically; the ScanlabOCM machine uses it for "Pausing Build…" and "Canceling Build…". feat(ui-core): dialog attributes sync:active and closable - <dialog> accepts `active` / `sync:active` and `closable` (default "1"), stored as CUIExpression in CUIDialog, validated at startup, passed through addDialog_Unsafe (signature extended). - /api/frontend emits "closable" for every dialog and "active" only for dialogs with an active expression, so event-driven dialogs stay untouched. Legacy /api/ui/state emits "closable" too. New keys AMC_API_KEY_UI_DIALOGACTIVE / AMC_API_KEY_UI_DIALOGCLOSABLE. - The server is authoritative: a dialog is open while the bound parameter is true and re-asserted on every frontend poll. feat(client-core): follow server-driven dialog state - AMCApplicationDialog initialises `closable` and `serverDriven` in the constructor (Vue 2 reactivity). - retrieveFrontendState() indexes dialog modules into frontendLookup and calls new _syncServerDrivenDialogs(), which opens a dialog via showDialog() when "active" turns true and clears dialogIsActive when it turns false. Dialogs without "active" keep the client-action driven behaviour. feat(svelte-client): non-closable dialogs - Dialog.Content gets showCloseButton, escapeKeydownBehavior and interactOutsideBehavior from dialog.closable; setDialogOpen() ignores close requests for closable="0"; dialogIsClosable() reads through the poll tick so the property mutation re-renders. feat(vue2-client): non-closable dialogs - v-dialog gets :persistent and :no-click-animation for closable === false. Backward compatible: dialogs without the new attributes behave as before. Signed-off-by: Yury Rodzikau <y.rodzikau@c1-technologies.com>
…e platform
feat(create_package_xml): write the resolved client variant into amc_server.xml
The package builder already resolved which web client to ship (from the
`--client` flag, then the `client` attribute on `<machinedefinition>` in
config.xml, then the default `vue2`) and wrote it to the package XML as
`<coreclients default="...">`. The generated amc_server.xml, however, was
written without a `client` attribute on the `<amc>` root element.
The server reads that attribute at startup to pick the client package,
so every clean build silently reset the served UI to the Vue 2 client
until `client="svelte"` was re-added to amc_server.xml by hand.
The `<amc>` element now carries `client="<variant>"` with the same
resolved value that goes into the package XML, e.g.:
<amc xmlns="http://schemas.autodesk.com/amc/2020/06" client="svelte">
Both files are generated in one run, so the package SHA-256 recorded in
amc_server.xml always matches the package XML written alongside it.
feat(build_clean_win64): pass -A x64 to the Visual Studio generator
The Windows clean build configures CMake with an explicit x64 platform
instead of relying on the generator default. This makes the architecture
deterministic across machines with different default toolchains.
Signed-off-by: Yury Rodzikau <y.rodzikau@c1-technologies.com>
…erView CenterOnRectangle() works in plate coordinates: the plate image is drawn from (0, 0) to (sizex, sizey) and the toolpath is shifted by the origin. The framing introduced with "Layer Viewer updates" subtracted the origin from the frame, which put the plate corner into the view center for origin = (sizex/2, sizey/2) on the ScanlabOCM machine. centerOnPlatform() frames 0 .. size again, keeping the paddingx/paddingy attributes and the auto-framing behaviour. The Vue 2 client is unchanged. Signed-off-by: Yury Rodzikau <y.rodzikau@c1-technologies.com>
…ble v2 format, selective DataTableReader, api/datatable REST endpoints, datacapture web module and incremental RTC recording readout
Continuous high-rate sensor data (an RTC recording at 100 kHz over a whole
build, tens of gigabytes) could only be stored as in-memory DataTables, one
per layer. This change adds a streaming capture path that writes chunks to
segmented storage streams from a background thread, a chunked columnar
on-disk format with per-page statistics, a reader that touches only the
pages a request needs, REST endpoints and a web module on top of it, and an
incremental readout in the ScanLab driver so that the RTC recording can be
streamed while the layer is still being exposed. Implements the design
"Streaming Data Capture and Chunked Columnar Storage" (draft v2 with the v3
corrections): one producer per capture, captures live only inside a build
execution, retention by storage limit with oldest-first deletion, new v2
signature.
feat(libmcenv): DataCapture write API and DataTableReader
- New classes DataCaptureOptions (chunk row count, segment size, queue
depth, backpressure mode Block/DropOldest/Fail, storage limit,
compression, per-column encoding and double quantisation),
DataCaptureChunk (column-wise and row-wise setters) and DataCapture
(AddColumn, BeginChunk, CommitChunk, Flush, counters, Finish, Abort,
AddColumnsFromDataTable, AppendDataTable).
- New class DataTableReader: row count, first available row, schema,
segment and chunk information with min/max statistics, typed range
reads, ReadColumnDownsampled (Stride, MinMax, Average),
FindChunksInValueRange and ExtractDataTable.
- BuildExecution gains CreateDataCaptureOptions, CreateDataCapture,
HasDataCapture, GetDataCaptureRowCount, GetDataCaptureSegmentCount,
LoadDataCaptureSegment and OpenDataCaptureReader. A capture can only be
created while the execution is in process.
- The capture engine (libmcenv_datacaptureinstance) uses a pool of
MaxQueuedChunks + 1 buffers, a bounded queue, a writer thread that
encodes and writes pages, and a finalizer thread that registers the
segment, finishes the storage stream (SHA-256) and enforces the storage
limit, so that the writer never waits for the database. A chunk is never
split across segments; a segment rolls over before a chunk that would
exceed the configured size.
- DataTableColumnType gains FloatColumn, BoolColumn and TimestampColumn;
DataTable gains GetRowCount64 and typed accessors for the new types;
LoadFromStream reads both the v1 and the v2 format and reports
truncated or corrupt segments with dedicated error codes.
- New enums DataCaptureBackpressureMode, DataCaptureStatus,
DataCaptureCompression, DataCaptureEncoding and
DataTableDownsampleMode; error codes 10266 to 10299. All interface
changes are additive.
feat(core): DataTable v2 format, encodings and selective reader
- amc_datatableformat: append-only segment layout with signature
0x6A9B23E2: 64-byte header, one page per column and chunk with a 32-byte
page header, a footer with the schema and a page directory (file offset,
sizes, row count, codec, encoding, typed min and max), and a 16-byte
trailer that locates the footer. Segment builder, chunk encoder with
per-page fallback to PLAIN or uncompressed when a step does not shrink
the page, and a validating segment reader.
- amc_datatableencoding: DELTA (Parquet DELTA_BINARY_PACKED, blocks of
128 values in 4 miniblocks, zigzag ULEB128), BITPACK for bool columns,
LZ4 and Deflate codecs, opt-in double quantisation stored as integer
multiples of a step.
- amc_datacapturereader: lazy multi-segment reader with an LRU of open
segments and a page cache, binary search of segments and chunks,
downsampling that takes min and max from the page directory for chunks
that lie inside one bucket.
- amc_datacapturequery: JSON, CSV and binary (float64 and float32)
responses, bucketed downsampling in the shape of the journal envelope,
response cap of 1,000,000 values.
feat(libmcdata): data capture manifest and retention
- Database schema version 24 with the tables datacaptures,
datacapture_columns and datacapture_segments.
- New class DataCapture (columns, segments, row count, stored size,
Finish, Abort); BuildJobExecution gains CreateDataCapture,
HasDataCapture, RetrieveDataCapture, GetDataCaptureCount and
RetrieveDataCaptureByIndex; BuildJobHandler gains RetrieveDataCapture.
- Storage gains DiscardRandomWriteStream, GetDataCaptureStorageSize and
EnforceDataCaptureStorageLimit: the oldest stored segments of all
captures are deleted until the total size is below the limit; purged
segments keep their manifest row with status purged.
- MIME type application/amcf-datatable is registered; error codes 453 to
464.
feat(api): api/datatable REST endpoints
- GET api/datatable/execution/{uuid} lists the captures of a build
execution.
- GET api/datatable/{uuid}/info returns schema, row counts, segments and
the value range of every column.
- GET api/datatable/{uuid}?format=json|csv|bin|bin32&columns=&fromrow=
&rowcount=&downsample=none|stride|minmax|average&targetpoints= returns
rows or downsampled data; requests above 1,000,000 values are rejected
with a hint.
- GET api/datatable/{uuid}/segment/{index} issues a download ticket for
one native segment stream.
- All endpoints require a session; row parameters are parsed strictly.
feat(ui-core, client-core, svelte-client): datacapture content item and module
- New content item type "datacapture" with the attributes title,
captureuuid (usually bound to a state machine parameter) and
defaultcolumns, registered as frontend attributes of the differential
frontend state.
- Client core module AMCModule_DataCapture and schema entry.
- Svelte module ModuleDataCapture: min/max envelope chart at the pixel
width of the chart with zoom to a row window, a paged table of exact
rows, CSV export of the current window within the value cap, segment
download through a ticket, refresh while the capture is recording.
- dataCaptureApi.ts wraps the REST endpoints; UPlotChart gains an
optional formatX prop so that the x axis can show row indices.
feat(driver-scanlab): incremental readout of an RTC recording
- RTCRecording gains StartListWithRecording, ReadRecordedData and
DiscardRecords, so that a plugin can read the recorded data from the
card piece by piece while the list executes and hand every piece on at
once. ExecuteListWithRecording is built on the same code and keeps its
polling sequence. New error code 1163 RECORDINGREADOUTNOTSTARTED.
feat(build): lz4 sources are compiled into libmc and amc_unittest.
test: 72 unit tests cover the v1 compatibility changes, the v2 format
(round trips of all column types, rollover, truncation, known-answer
bytes of the delta encoding), the capture engine (chunk validation, all
backpressure modes, retention, abort, abandoned captures,
AppendDataTable), the reader (page skipping, downsampling, purged
segments) and the query layer.
Verification: amc_unittest 541 tests pass on upstream/develop 6ee32c6
(this change is rebased onto it; the DataCapture migration is schema step
23 to 24 because upstream took 23 for named configuration versions, and
the error codes start at 10266 because upstream took 10265). On the bench
the recording of an RTC6 card streamed at 100 kHz over four layers (8.0
million rows, 17 bytes per row instead of 52 in the per-layer tables) and
an RTC plus OIE recording over three layers (8.9 million rows, 15 columns,
23 bytes per row instead of 92); every capture matched the per-layer
tables value for value, the exposure time per layer was unchanged against
the blocking readout, and the capture of a cancelled build was closed by
the end-of-build signal within one second.
Known limits: readers see only closed segments while a capture is
recording; after a hard stop of the server the rows of the open segment
are lost and the capture stays in status recording; a min/max envelope
over a window smaller than about 100 million rows decodes every page of
the column; only std::exception is caught in the engine threads; the
Vue2 client has no component for the datacapture item.
Signed-off-by: Yury Rodzikau <y.rodzikau@c1-technologies.com>
…sure so microvector layers larger than one list mark continuously Until now a microvector layer had to fit into one RTC6 list (4 194 304 positions), and the driver estimated the list usage with the worst case of two positions per vector. On hardware a 3.15 M vector layer was rejected with "RTC list capacity exceeded" although it would have fit, and any layer above the list size could not be marked at all. The ScanLab driver now measures the list usage exactly and, when a layer is larger than a list, marks it in one continuous exposure by alternating the two RTC6 lists while the laser keeps running. The RTC6 has no circular queue mode; alternating lists with automatic list changes is the replacement its manual describes (Doc.Rev.1.1.5, ch. 6.4.6, p. 118-119, 383, 599, 758). feat(capacity): exact list capacity instead of a worst-case estimate - The driver pre-scans the layer and counts the power commands the deduplicating download will really emit, using the same power quantization as the download itself (one command per change, two for the dual analog port). - A layer that fits by exact count is marked from one list exactly as before. - The capacity error reports the exact numbers (vectors, power commands, margin, positions left in the open list) and names the configuration switch that enables alternating lists. feat(exposure): layers larger than one list are marked without interruption - The layer is written as segments: every full list is closed and the card is told to continue in the other list the moment it reaches the end, so the laser signals are untouched at the boundary and marking does not stop. - The first segment is streamed as before (prebuffer, then execution starts while the rest downloads); each further segment is written into the list the card has just left. A list is only reused after the card has confirmed that it finished it, so unprocessed commands are never overwritten. - The overrun protection of the streamed download is kept and extended: a download into the list the card executes is still checked for the output pointer catching up, a download into the other list cannot collide. - Opt-in per machine; off by default. Without the opt-in the driver behaves as before, apart from the exact capacity count. feat(exposure): safe behaviour when the card gets ahead of the download - If the card has already finished its segment before the next list change could be armed, the next segment is started explicitly once enough of it is written. The marking then has a gap at that point; the event is counted and logged as a warning so that it is never silent. - Any error during the download stops the list execution, switches the laser off, neutralises a list change that is still armed (otherwise it would fire in the next layer and run stale list memory) and resets the layer state. - Waiting for a list to become free has a timeout derived from the segment size; on timeout the card's list status is logged and the layer fails. feat(diagnostics): per-layer visibility of the segmented exposure - Log lines for the capacity decision, every segment boundary (list, vector count, wait time, whether the automatic change was armed) and a summary with segment count, fallbacks, minimum download margin and maximum list wait. - New driver API for the machine plugin: enable alternating lists with an optional test-aid capacity limit (forces many segments on an ordinary layer) and a tail reserve per segment, and read the statistics of the last layer. - RTC6 list handling calls needed for this (protected list opening, list status bits, list-relative pointers) are added to the SDK wrapper and recorded in the SDK call journal like every other call. - Bindings and interfaces regenerated with ACT from LibMCDriver_ScanLab.xml. Verified on the RTC6 Ethernet card #20421070 on 2026-10-07: a 3-layer job (1.98 M / 3.15 M / 3.13 M vectors) marked from one list each, and a 60 155 411 vector layer marked as 15 segments with 0 fallbacks, a minimum margin of 2 072 268 positions and a maximum list wait of 31.8 s. Design document: Plan/RTC6_DoubleBuffering_Implementation_Plan_2026-10-07.html. Signed-off-by: Yury Rodzikau <y.rodzikau@c1-technologies.com>
…the exposure of large microvector layers and let long-running UI events finish without a timeout The download of a microvector layer was one blocking driver call. For a layer that is marked from alternating RTC6 lists it returns only when the last segment is written, i.e. after most of the layer has been marked. During that time the caller cannot read out the RTC recording, although the measurement memory is a ring buffer of 4 194 304 entries per channel and has to be read while a long layer is being marked. The ScanLab driver now also offers the download as a session of short steps that never wait for the card, so that the machine plugin can read out the recording between two steps. The readout is prepared for running in parallel to the download and reads the measurement memory completely at its wrap-around. In the web client, UI events get their own request timeout, because loading a large recording takes longer than the 10 s of an ordinary request. feat(exposure): stepwise download of a microvector layer - New driver API on the RTC context: BeginMicrovectorStreaming writes the first part of the layer and, on the streamed path, starts list execution; ContinueMicrovectorStreaming writes the next part within a time budget in milliseconds and reports when the layer is complete. - A step returns when its time budget is used up, when the next list is not free yet or when the layer is complete. It never waits for the card: the wait for a list to become free is one status poll per step, with the same timeout as before. A budget of 0 writes a single block of 20 000 vectors. - Layers that are not streamed (small layers, sequential download) are written completely by BeginMicrovectorStreaming. It then reports that execution has not been started and the caller executes the list as usual. - AddMicrovectorMovement keeps its behaviour; it is now the blocking wrapper around the same steps. - The microvector buffer is not copied. It must stay valid and unchanged until the layer is complete or the session has been aborted. feat(exposure): safe handling of an interrupted download - An error in any step stops the list execution, switches the laser off, neutralises a list change that is still armed and resets the layer state, exactly as the blocking call did. - New driver API AbortMicrovectorStreaming does the same on request, for a caller that fails between two steps, and logs a warning with the number of vectors written so far. Without an active session it does nothing. - A second download while a session is active and a step without a session are rejected with an error. A step after completion reports completion and does nothing. - A session that is still open when the next list is set up is dropped with a warning; that list is not running any more, so only the bookkeeping is reset. feat(recording): readout in parallel to the download - The incremental readout no longer reports the end of the recording while a stepwise download is in progress. The card can be idle between two segments of a layer (explicit start of a segment after the card got ahead of the download), and this must not be taken for the end of the layer. fix(recording): complete readout at the wrap-around of the measurement memory - At the wrap-around the last block ended one entry before the end of the measurement memory, so one sample per channel was skipped at every wrap. The block now ends exactly at the end of the memory. - The card rejects a block that crosses the end of the memory with RTC error 16 (confirmed on hardware on 2026-10-07), so the size must not be raised. - A readout position beyond the measurement memory at a wrap-around is reported as a data recording overflow. feat(client-core): own request timeout for UI events - Requests to the event endpoint use a timeout of 120 s instead of the general 10 s. A UI event runs plugin code on the server: loading a recording of 60 million rows for the SMC Viewer takes 10 to 50 s, longer than the client waited. - All other requests keep their timeouts. feat(driver-scanlab): interface definition and bindings - The three new methods are added to LibMCDriver_ScanLab.xml, the C++ dynamic bindings and the interface wrapper. Signed-off-by: Yury Rodzikau <y.rodzikau@c1-technologies.com>
…ver reliably on Windows when the gRPC, ScanLab OIE and ScanLab SMC drivers initialize at the same time On Windows about every second start of amc_server ended with one state machine in fatalerror: plc_grpc, less often scanner or pathplanning, failed with "COULDNOTLOADLIBRARY: the library could not be loaded". Which of them failed changed from start to start, and the message named neither the library nor the Windows error. The gRPC, ScanLab OIE and ScanLab SMC drivers now load their libraries independent of process-wide state, so that their state machines can initialize at the same time. Cause: each driver unpacks its DLLs into its own temporary directory and loads the main DLL by absolute path. The Windows loader searches the dependencies of that DLL by name (abseil, protobuf, re2 and libcrypto for gRPC; Qt5Core, Qt5Network and libssl for OIE; RtcService and xerces for SMC), so the drivers set the DLL directory of the process to their own directory right before LoadLibraryW, OIE and SMC the current directory as well. Both are one value for the whole process, and the three state machines run their init step in their own threads within a few tens of milliseconds. A second thread could replace the directory between the two calls of the first, whose dependencies were then searched in the wrong place. fix(driver-scanlaboie, driver-scanlabsmc): SDK load independent of the DLL directory - The OIE and the SMC library are loaded with LoadLibraryExW and LOAD_WITH_ALTERED_SEARCH_PATH. With the absolute file name the loader resolves the dependencies from the directory of the library itself, whatever another thread has set in the meantime. - The calls that set the DLL directory and the current directory stay in place; the SMC library may read files relative to the current directory. fix(driver-grpc): wrapper library loaded ahead of the generated binding - The LoadLibraryW call for the gRPC wrapper is part of its ACT-generated binding and is not changed. The driver loads the wrapper DLL first, in the same way as above; the binding then finds the module already in the process and no dependency search takes place. - The handle of the preloaded module is kept for the lifetime of the process, like the handle the wrapper holds itself. fix(diagnostics): retry and an error message that names the cause - A load is attempted up to five times with a pause of 200 ms; before a repeated attempt the driver sets its directory again. This covers a dependency the loader still picks up by name. - The exception names the library and carries the Windows error code, e.g. 126 when the DLL or one of its dependencies is not found. - Windows only; the Linux load path is unchanged. Not chosen: a shared mutex around the two calls would have to be adopted by every driver that touches this state and be held at each later directory switch; initializing the state machines one after another would not cover the directory switches the OIE and SMC drivers make at run time. Known limit: the A3200, TML, OPC UA, OpenCV and LibOAPC drivers set the DLL directory in the same way and are unchanged; they were not part of the affected configuration. Verified on the bench on 2026-10-07 (Windows, amc_server built from 101ce4a): with all three drivers changed 5 of 5 starts came up, every library loading at the first attempt. Signed-off-by: Yury Rodzikau <y.rodzikau@c1-technologies.com>
…temporary SMC files after use and letting plugins switch off the simulation output Planning a large layer with SCANmotionControl left several gigabytes of temporary files per layer in the working directory until the SMC context was released, so multi-layer jobs filled the system drive. The driver now removes each temporary file as soon as its content has been handed over, and plugins that never read the SMC simulation output can stop SMC from writing it in the first place. feat: delete the module recording (.slm) right after it has been read LoadRawSimulationData deletes the temporary module file as soon as the raw content has been copied to the caller. The job destructor removes a file that was never read (exception in the plugin, context re-creation after an error). A failed deletion is logged as a warning and the file stays managed, so the working directory cleanup removes it at the latest. A second read of the same job reports SIMULATIONWORKINGFILEISNOTINITIALIZED. The call also validates the size of the caller's buffer and reports BUFFERTOOSMALL instead of writing past it. feat: delete the RTC log record file after it has been parsed ReadLogRecordFile (hardware mode, SMC 1.x) removes its temporary CSV when the data table has been filled, on the normal path and when the parser or the table throws. feat: allow switching off the SMC simulation file output SMCConfiguration gets SetSimulationFileOutputEnabled and GetSimulationFileOutputEnabled. The default is true and keeps the previous behaviour. With false the generated SMC configuration sets DisableFileOutput, so SMC writes no simulation output at all; this saves several gigabytes of disk space and minutes of planning time per large layer. LoadSimulationData then fails with the new error SIMULATIONFILEOUTPUTDISABLED instead of failing on a missing file. feat: delete the complete SMC simulation output set after it has been read When the simulation output is enabled, LoadSimulationData removes the output files of the job after the data table has been filled. SMC rotates its output into <name>.csv, <name>.1.csv, <name>.2.csv and writes <name>.xml, so the whole set is removed by prefix instead of the single file name SMC reports. The job remembers the name at the end of Execute, and the destructor deletes the set for jobs whose data was never read. docs: document the single-read semantics in the interface description The IDL descriptions of LoadSimulationData and LoadRawSimulationData state that the data can be read once and that the temporary files are deleted afterwards. The generated headers and interface wrappers are updated accordingly. Signed-off-by: Yury Rodzikau <y.rodzikau@c1-technologies.com>
…sume, let background operations hand a download to the user's browser and cancel it, and show button tooltips Large downloads such as the ZIP of all build recordings (9 GB on the rig) broke on Windows at 2 GiB and needed four copies of the file in memory, and a plugin had to build such an archive inside the UI event that the button triggered, so the request timed out, a page reload lost the result and nothing could be cancelled. The framework now streams downloads from disk and gives state machines the means to prepare an archive on their own thread, hand the download to the browser of the session that asked for it, follow the delivery and cancel it in a way the browser shows as a failed download. feat: stream downloads of any size with pause and resume The download endpoint sends storage streams in 4 MiB chunks through the HTTP content provider instead of loading them into memory, so the file size no longer matters and the first byte leaves at once. Responses carry Content-Length, Accept-Ranges, a strong ETag and Last-Modified, answer HEAD, and serve single byte ranges with 206, so browser download managers can pause, resume and continue after a connection drop. The server validates Range and If-Range itself, because the HTTP library does not check ranges of streamed bodies: unsatisfiable or multiple ranges get 416 with Content-Range: bytes */N, a stale If-Range gets the full body, and ranges are ignored on every non-streamed response. The socket write timeout is 30 s and at most four downloads run at the same time; further ones get 503 with Retry-After. feat: expire and revoke download tickets and log every download Download tickets are valid for 24 hours and can be revoked; an expired or revoked ticket answers 410 Gone, also for a resume. Every download is logged with the client address, the number of bytes sent and whether it completed (database schema 25). feat: hand a download from a state machine to the browser of one session A state machine can start a download in the browser of a given client session: the server creates the ticket for the user of that session and queues a "streamdownload" client action for it. Pending actions reach the browser as the "actions" event of the live update stream or as the "pendingactions" field of the polling response. Of several tabs of one session only the first one to claim an action (POST api/frontend/actions/<uuid>/claim, 409 for the others) executes it; unclaimed actions expire after 30 s. State machines can read the delivery progress of a stream (active connections, bytes delivered without a gap, completion), cancel its downloads so that running connections stop, the tickets are revoked and queued actions are dropped, delete a finished stream and keep only the newest archives of a name. feat: keep the disk clean of unfinished and outdated archives A ZIP stream that is discarded or released without Finish deletes its file and its database entry, finished writers release their handles, and ZIP streams left behind by a crash or a forced stop are removed at server start. Errors of the storage stream read callbacks now reach the caller instead of being reported as success. feat: show tooltips on buttons Buttons accept a hint attribute, also bound with sync:hint to a state machine parameter; the client shows it as the tooltip and accessible label of the button. feat: download via the browser download manager, ignore double clicks The client downloads through a programmatic click on a link with the download attribute instead of window.open, so popup blocking and page memory no longer limit the size; the file name sent by the server is used. A button whose previous event is still pending does not send a second one, so a double click cannot start and cancel an operation. Client actions from event responses, widget responses and the session queue run through one function; the temporary one-hour timeout of the recordings download event is removed. feat: unit tests for the download registry, ranges and storage Signed-off-by: Yury Rodzikau <y.rodzikau@c1-technologies.com>
…e server log instead of the console The OIE driver printed its packet diagnostics (xy fallbacks, signal-count mismatches, callback exceptions) to std::cout, which nobody keeps on the rigs, and swallowed the error events of the OIE SDK entirely. When the measurement tag was lost on 2026-10-13, no trace of the OIE side survived. The device now counts in the SDK callback thread only (atomics, the first occurrence of each category under a diagnostics mutex) and writes through the driver environment from the plugin thread: feat: every RetrieveCurrentRecording reports the categories whose counter grew since the last report, with the first packet, tag and error text. feat: ClearCurrentRecording logs a summary of the previous layer: packets not retrieved since the last retrieval, packets since the previous clear (recorded and skipped), all counters and the last measurement tag. feat: onErrorEvent counts the events and keeps the first and the last error code and value. feat: the app start and the recording frequency are logged as info lines. AddDevice hands the driver environment to the device instance; a null environment switches the output off. The ACT interface is unchanged. Signed-off-by: Yury Rodzikau <y.rodzikau@c1-technologies.com>
…ToUniqueEmulatedDevice The new driver method enables the pylon camera emulation (PYLON_CAMEMU) only for the time of the connection, enumerates the devices, picks the single device of the class BaslerCamEmu and opens it under the given connection identifier. Physical cameras are ignored, so the emulator can be selected while a real camera is connected, and the environment variable never reaches a later enumeration of physical cameras. The existing methods are unchanged. Generated interfaces and bindings were regenerated with ACT 1.8.0-develop; the diff contains only the new method. Signed-off-by: Yury Rodzikau <y.rodzikau@c1-technologies.com>
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
This PR brings the
data_capturework ontodevelop. The branch was rebased ontodevelopat 8873718 ("Added Svelte package") on 4 November 2026. Two commits thatdevelopalready covers were dropped (sharedtriggerButtonEventin BuildList/ExecutionList, page-level scrolling; PRs #81, #82, #90), andModuleLayerView.sveltewas re-merged on top of the upstream "Layer Viewer updates" and "Updated Layer View" commits.17 commits, 14 self-contained changes. All ACT interface changes are additive; existing machine configurations and plugins keep working unchanged. Each commit message carries the full rationale, design and verification of its change.
Refs #
What is included
Server and framework
api/datatable, datacapture UI module, incremental RTC recording readout (99ec7da). Continuous high-rate sensor data (an RTC recording at 100 kHz over a whole build) is written from a background thread into segmented storage streams, stored in a chunked columnar format with per-page statistics and DELTA/BITPACK/LZ4/Deflate encodings, read selectively by aDataTableReader, exposed through REST endpoints and shown in a newdatacapturecontent item. Retention by storage limit, oldest segments first. 72 unit tests.streamdownloadclient action for one session, follow the delivery and cancel it.<button hint|sync:hint>shows a tooltip.<dialog>acceptsactive/sync:activeandclosable; the server re-asserts the state on every frontend poll. Used for the "Pausing Build…" and "Canceling Build…" wait screens. Svelte and Vue 2 clients./api/frontendincludes the page show event and reports values set by UI event handlers throughSetUIProperty; configuration list fallback buttons send a valid UUID; invisible tabs are hidden; the LayerView base image name is resolved to its UUID. New UIFrontend unit test group.createPackageXMLwrites the resolved client variant asclient="…"into the generatedamc_server.xml;build_clean_win64.batpins-A x64.ScanLab RTC6 driver
BeginMicrovectorStreaming/ContinueMicrovectorStreaming/AbortMicrovectorStreaminglet the plugin read out the RTC recording between download steps of a long layer; the readout at the wrap-around of the measurement memory no longer skips one sample per channel. UI event requests in the client core get a 120 s timeout.Other drivers
LoadLibraryExWwithLOAD_WITH_ALTERED_SEARCH_PATHand a preloaded gRPC wrapper remove the race on the process-wide DLL directory that failed about every second server start. Linux unchanged.SMCConfiguration::SetSimulationFileOutputEnabled(false)setsDisableFileOutput.ConnectToUniqueEmulatedDevice(bb86f77). Connects to the pylon camera emulator without exposingPYLON_CAMEMUto later enumerations of physical cameras.Web clients
centerOnPlatform()frames the plate in plate coordinates again;WebGLScreenPointsElementrenders points in groups of 524 288 because some GPU drivers silently truncate a singlePOINTSdraw call above about 2 million points (observed with the Parallels display adapter through ANGLE/Direct3D 11).Interface and behaviour changes to review
DataCaptureOptions,DataCaptureChunk,DataCapture,DataTableReader,BuildExecution.*DataCapture*, new DataTable column types, download and client action methods), LibMCData (DataCapture, download tickets and log), LibMC (download and client action handling), LibMCDriver_ScanLab (recording readout, alternating lists, stepwise download), LibMCDriver_ScanLabSMC (SetSimulationFileOutputEnabled), LibMCDriver_Pylon (ConnectToUniqueEmulatedDevice). Bindings and headers regenerated with ACT.developuses: LibMCData 454–468, LibMC 721–729, LibMCEnv 10270–10306 (upstream owns 10266–10269 for the Formula API), LibMCDriver_ScanLab 1168. The commit bodies written before the rebase still quote the old numbers.datacaptures,datacapture_columns,datacapture_segmentsand the download log, ordered after the named-configuration-versions step ofdevelop. MIME typeapplication/amcf-datatable.GET api/datatable/execution/{uuid},api/datatable/{uuid}/info,api/datatable/{uuid}?format=json|csv|bin|bin32&…,api/datatable/{uuid}/segment/{index}; download endpoint with HEAD,Range/If-Range, 206/416/410/503;POST api/frontend/actions/{uuid}/claim;pendingactionsin the polling response andactionsin the live update stream.<dialog active|sync:active closable>,<button hint|sync:hint>, content item<datacapture title captureuuid defaultcolumns>.sync:attributes are still evaluated from the state machine.LoadSimulationData/LoadRawSimulationDataread their data once; the temporary files are deleted afterwards (documented in the IDL).Known limits
recording; the Vue 2 client has no component for thedatacaptureitem.<buttongroup>rows in config.xml dialogs still do not wrap; the shadcn-svelte dialog components are generated files andshadcn-svelte add dialogwould overwrite the layout fix.Verification
build_win64build,amc_unittest599 of 599 tests passed (the timing-sensitiveExecComputeElapsedTimefailed once while two builds ran in parallel and passed on the repeat run), Svelte client package rebuilt (Artifacts/clientdist/clientpackage_svelte.zipis part of the PR),amc_serversmoke start with REST login,/api/frontendand/api/executions,svelte-checkwithout new errors in Svelte or TypeScript sources (the pre-existingtimelineDurationerror inModuleLayerView.svelteremains; the untyped core JavaScript gains 18 implicit-any diagnostics of the kinddevelopalready has 980 of).