saveData
Overview
saveData is a data-storage client included with the sscan module. It monitors sscan records via Channel Access, and writes scan data to disk in the MDA (Multi-Dimensional Archive) binary file format. saveData runs as a dedicated high-priority thread within the IOC and handles 1D through 4D scans automatically, including nested multidimensional scans where multiple sscan records are chained together.
saveData coordinates with sscan records using the AWAIT/AAWAIT handshake mechanism to ensure that scan data arrays are not overwritten before they have been written to disk. For details on how the sscan record implements this handshake, see section 1.3.5 of the sscan record documentation.
Important: Once saveData is initialized, scan records that it monitors will always write data files. There is no runtime on/off switch for data storage. Data storage is configured at boot time by specifying which sscan records to monitor in the
saveData.reqfile. The only way to disable data storage is to remove saveData from the startup script and reboot.
Setup
Loading the database
Load saveData.db to create the PVs that saveData uses for status, file paths, and user configuration:
dbLoadRecords("$(SSCAN)/sscanApp/Db/saveData.db", "P=xxx:")
Alternatively, the sscan.iocsh script loads this database (along with standardScans.db and scanProgress.db) automatically:
iocshLoad("$(SSCAN)/iocsh/sscan.iocsh", "PREFIX=xxx:,SSCAN=$(SSCAN)")
Configuration file (saveData.req)
saveData is configured by a request file (typically named saveData.req) that must be placed in the IOC’s startup directory. The file uses an INI-style format with [section] headers, # comments, and macro substitution using $(MACRO) syntax. Macros are defined by the second argument to saveData_Init().
The following sections are recognized:
| Section | Required | Purpose |
|---|---|---|
[prefix] | No | IOC prefix, used in data file names. Punctuation characters are replaced with underscores. |
[status] | Yes | PV name for the saveData status indicator (mbbi). |
[message] | No | PV name for status messages (stringout). |
[filename] | No | PV name where saveData writes the current MDA filename. |
[fullPathName] | No | PV name where saveData writes the full file path. Accessed as a long string (appends .$). |
[counter] | Yes | PV name for the scan number counter (longout). |
[fileSystem] | Yes | PV name for the file system / mount point path. Accessed as a long string. |
[subdir] | Yes | PV name for the subdirectory under the file system. Accessed as a long string. |
[basename] | No | PV name for a user-specified file base name. If not provided or not connected, the IOC prefix is used. Accessed as a long string. |
[realTime1D] | No | PV name for the real-time 1D writing toggle (bo). |
[scanRecord] | No | List of sscan record names to monitor (one per line). saveData will set AAWAIT=1 on each. |
[extraPV] | No | List of additional PVs to include in every data file. An optional quoted description string can follow each PV name. |
Example saveData.req:
[prefix]
$(P)
[status]
$(P)saveData_status
[message]
$(P)saveData_message
[filename]
$(P)saveData_fileName
[fullPathName]
$(P)saveData_fullPathName
[counter]
$(P)saveData_scanNumber
[fileSystem]
$(P)saveData_fileSystem
[subdir]
$(P)saveData_subDir
[basename]
$(P)saveData_baseName
[realTime1D]
$(P)saveData_realTime1D
[scanRecord]
$(P)scanH
$(P)scan1
$(P)scan2
$(P)scan3
$(P)scan4
[extraPV]
$(P)saveData_comment1
$(P)saveData_comment2
$(P)scaler1.TP
$(P)scan1.P1SM "scan mode"
In the [extraPV] section, each line contains a PV name optionally followed by a quoted description string. If no description is provided, saveData will fetch the PV’s .DESC field. Extra PVs are read at the beginning of each scan and their values are written into the MDA file’s extra-PV section.
Initialization
After iocInit, initialize saveData with:
saveData_Init("saveData.req", "P=xxx:")
Arguments:
- fname – Name of the configuration file (searched in the IOC’s startup directory).
- macros – Macro substitution string (e.g.,
"P=xxx:"). Macros are substituted in PV names throughout the configuration file.
saveData_Init can only be called once. It spawns the saveData thread and suspends the calling thread (the IOC shell) until initialization is complete and all Channel Access connections have been attempted.
Autosave
If you use autosave, include saveData_settings.req in your autosave request file:
file saveData_settings.req P=$(P)
This saves and restores the following fields across IOC reboots:
| PV | Description |
|---|---|
$(P)saveData_fileSystem.$ | File system path (long string) |
$(P)saveData_subDir.$ | Subdirectory (long string) |
$(P)saveData_baseName.$ | Base file name (long string) |
$(P)saveData_scanNumber | Scan number counter |
$(P)saveData_realTime1D | Real-time 1D writing toggle |
$(P)saveData_maxAllowedRetries | Maximum allowed retries |
$(P)saveData_retryWaitInSecs | Wait time between retries (seconds) |
Runtime PVs
All PVs use the macro $(P) as a prefix. Load these by loading saveData.db.
Status and messaging
| PV Suffix | Type | Description |
|---|---|---|
saveData_status | mbbi | Status: 0=”Inactive”, 1=”Active”, 2=”Mount err”, 3=”I/O err” |
saveData_message | stringout | Status/error message from saveData |
File path configuration
| PV Suffix | Type | Max Length | Description |
|---|---|---|---|
saveData_fileSystem | lso | 256 | File system or mount point path (e.g., /data/) |
saveData_subDir | lso | 256 | Subdirectory under the file system |
saveData_baseName | lso | 256 | User-specified base name for data files |
saveData_fileName | lso | 256 | Current MDA filename (written by saveData) |
saveData_fullPathName | lso | 512 | Full path of the current data file (written by saveData) |
Scan control
| PV Suffix | Type | Description |
|---|---|---|
saveData_scanNumber | longout | Current scan file number (0-9999, auto-incremented) |
saveData_realTime1D | bo | If “Yes”, write 1D scan data point-by-point as it is acquired, rather than only at the end of the scan |
saveData_comment1 | stringout | User comment 1 (included in data files as an extra PV) |
saveData_comment2 | stringout | User comment 2 (included in data files as an extra PV) |
Retry mechanism
If a file write fails (e.g., due to a network filesystem error), saveData will retry up to maxAllowedRetries times, waiting retryWaitInSecs seconds between each attempt. If all retries are exhausted, the write is abandoned.
| PV Suffix | Type | Default | Description |
|---|---|---|---|
saveData_maxAllowedRetries | longout | 10 | Maximum number of write retries |
saveData_retryWaitInSecs | longout | 15 | Seconds to wait between retries |
saveData_currRetries | longout | 0 | Current retry count (for the current write attempt) |
saveData_totalRetries | longout | 0 | Cumulative retry count across all scans |
saveData_abandonedWrites | longout | 0 | Number of writes that were abandoned after exhausting retries |
File naming
Data files are named using the pattern <basename>NNNN.mda, where NNNN is a four-digit scan number from the saveData_scanNumber PV. The scan number auto-increments after each file is written.
- If
saveData_baseNameis set, its value is used as the base name. - If
saveData_baseNameis empty, the IOC prefix (from the[prefix]section) is used, with punctuation characters replaced by underscores (e.g., prefixxxx:becomesxxx_). - If a file with the computed name already exists, saveData appends a duplicate counter:
<basename>NNNN_MM.mda(whereMMincrements until a unique name is found).
Data file output
saveData writes scan data in the MDA binary format. See the MDA File Format documentation for the complete format specification.
For multidimensional scans, saveData detects the scan hierarchy by examining the trigger PV fields (T1PV-T4PV) of each monitored sscan record. When a trigger PV points to another monitored sscan record’s EXSC field (with trigger command value 1.0), saveData links the two scans as outer and inner dimensions.
Real-time 1D writing
When saveData_realTime1D is set to “Yes”, saveData writes 1D scan data point-by-point as each data point is acquired, rather than waiting for the entire scan to complete. This allows partial data recovery if a scan is aborted or the IOC crashes mid-scan. The file is updated in-place by seeking to the appropriate position and overwriting the current-point counter and data values.
Diagnostic commands
The following iocsh commands are available for troubleshooting:
| Command | Arguments | Description |
|---|---|---|
saveData_PrintScanInfo | name | Print connection status and configuration for the named sscan record |
saveData_Priority | priority | Change the saveData thread priority |
saveData_SetCptWait_ms | ms | Set the minimum wait time (in milliseconds) between current-point monitor postings |
saveData_Version | (none) | Print the saveData version string |
saveData_Info | (none) | Print overall saveData status and configuration |
Debug variables
The following variables can be set from the iocsh to control debug output:
| Variable | Default | Description |
|---|---|---|
debug_saveData | 0 | General debug verbosity level. Higher values produce more output. |
debug_saveDataMsg | 0 | Message queue debug verbosity level. |
saveData_MessagePolicy | 0 | Controls how current-point monitor messages are queued. 0=wait for space; 1=drop if full; 2=drop if full and time hasn’t elapsed; 3=wait if time has elapsed. |