SDDSlib
All Classes Files Functions Variables Macros Pages
hpwf2sdds.c
Go to the documentation of this file.
1/**
2 * @file hpwf2sdds.c
3 * @brief Converts waveform data from the older HP oscilloscope's verbose format to SDDS (Self Describing Data Sets) format.
4 *
5 * This program reads a waveform from an HP scope output file and converts it into the SDDS format,
6 * which is widely used for storing and sharing scientific data. The user can specify various
7 * options to customize the conversion process, including setting signal names, descriptions,
8 * MPL (Matplotlib) labels, and the major order of data storage.
9 *
10 * ## Usage
11 *
12 * ```
13 * hpwf2sdds <inputfile> <outputfile> [options]
14 * ```
15 *
16 * - `<inputfile>`: Path to the input file containing the HP waveform data.
17 * - `<outputfile>`: Path where the converted SDDS file will be saved.
18 *
19 * ## Options
20 *
21 * - `-signalname=<name>`: Specifies the name of the signal in the SDDS file.
22 * - `-description=<text>,<contents>`: Provides a description for the SDDS data set.
23 * - `-mpllabels=<title>,<topline>`: Sets the title and topline labels for MPL (Matplotlib) plots.
24 * - `-majorOrder=row|column`: Determines the major order of data storage, either row-major or column-major.
25 *
26 * @copyright
27 * - (c) 2002 The University of Chicago, as Operator of Argonne National Laboratory.
28 * - (c) 2002 The Regents of the University of California, as Operator of Los Alamos National Laboratory.
29 *
30 * @license
31 * This file is distributed under the terms of the Software License Agreement
32 * found in the file LICENSE included with this distribution.
33 *
34 * @author M. Borland, C. Saunders, R. Soliday, H. Shang
35 */
36
37#include "mdb.h"
38#include "SDDS.h"
39#include "scan.h"
40#include "match_string.h"
41
42/* Enumeration for option types */
43enum option_type {
44 SET_SIGNAL_NAME,
45 SET_DESCRIPTION,
46 SET_MPL_LABELS,
47 SET_MAJOR_ORDER,
48 N_OPTIONS
49};
50
51static char *option[N_OPTIONS] = {
52 "signalname", "description", "mpllabels", "majorOrder"};
53
54char *USAGE =
55 "Usage: hpwf2sdds <inputfile> <outputfile> [options]\n"
56 "\n"
57 "Options:\n"
58 " -signalname=<name> Specify the signal name in the SDDS file.\n"
59 " -description=<text>,<contents> Provide a description for the SDDS data set.\n"
60 " -mpllabels=<title>,<topline> Set the title and topline labels for MPL plots.\n"
61 " -majorOrder=row|column Set the major order of data storage.\n"
62 "\n"
63 "Example:\n"
64 " hpwf2sdds waveform.txt waveform.sdds -signalname=Voltage -description=\"Test Signal\",\"Generated by HP oscilloscope\" \\\n"
65 " -mpllabels=\"Voltage Signal\",\"Time (s)\" -majorOrder=column\n"
66 "\n"
67 "This program converts HP verbose format waveforms to SDDS format.\n\n"
68 "Program by Michael Borland (" __DATE__ " " __TIME__ ", SVN revision: " SVN_VERSION ")\n";
69
70typedef struct {
71 char *HP_name; /* Name of the parameter in HP format */
72 char *SDDS_name; /* Corresponding name in SDDS format */
73 char *value_string; /* Value as a string */
74 long type; /* Data type in SDDS format */
76
77#define HP_PARAMETERS 23
78HP_PARAMETER HP_parameter[HP_PARAMETERS] = {
79 {"Type", "Type", NULL, SDDS_STRING},
80 {"Points", "Points", NULL, SDDS_LONG},
81 {"Count", "Count", NULL, SDDS_LONG},
82 {"XInc", "XInc", NULL, SDDS_DOUBLE},
83 {"XOrg", "XOrg", NULL, SDDS_DOUBLE},
84 {"XRef", "XRef", NULL, SDDS_DOUBLE},
85 {"YData range", "YDataRange", NULL, SDDS_DOUBLE},
86 {"YData center", "YDataCenter", NULL, SDDS_DOUBLE},
87 {"Coupling", "Coupling", NULL, SDDS_STRING},
88 {"XRange", "XRange", NULL, SDDS_DOUBLE},
89 {"XOffset", "XOffset", NULL, SDDS_DOUBLE},
90 {"YRange", "YRange", NULL, SDDS_DOUBLE},
91 {"YOffset", "YOffset", NULL, SDDS_DOUBLE},
92 {"Date", "Date", NULL, SDDS_STRING},
93 {"Time", "Time", NULL, SDDS_STRING},
94 {"Frame", "Frame", NULL, SDDS_STRING},
95 {"Acq mode", "AcqMode", NULL, SDDS_STRING},
96 {"Completion", "Completion", NULL, SDDS_STRING},
97 {"X Units", "XUnits", NULL, SDDS_STRING},
98 {"Y Units", "YUnits", NULL, SDDS_STRING},
99 {"Max Bandwidth", "MaxBandwidth", NULL, SDDS_DOUBLE},
100 {"Min Bandwidth", "MinBandwidth", NULL, SDDS_DOUBLE},
101 {NULL, NULL, NULL, 0},
102};
103
104char *HP_DataMarker = "Data";
105char *HP_XIncrementName = "XInc";
106char *HP_XOriginName = "XOrg";
107char *HP_XReferenceName = "XRef";
108char *HP_XUnitsName = "X Units";
109char *HP_YUnitsName = "Y Units";
110char *HP_PointsName = "Points";
111
112#define BUFSIZE 256
113
114int main(int argc, char **argv) {
115 SDDS_TABLE SDDS_table;
116 SCANNED_ARG *scanned;
117 long i, i_arg, index, points;
118 char *input, *output, buffer[BUFSIZE];
119 char *signal_name, *ptr, *parameter_name;
120 char *mpl_title, *mpl_topline, *descrip_text, *descrip_contents;
121 FILE *fpi;
122 double xIncrement, xOrigin, xReference;
123 char *xUnits, *yUnits;
124 double *time, *data;
125 unsigned long majorOrderFlag;
126 short columnMajorOrder = -1;
127
128 argc = scanargs(&scanned, argc, argv);
129 if (argc < 3) {
130 fprintf(stderr, "Error: Insufficient arguments provided.\n\n%s", USAGE);
131 return EXIT_FAILURE;
132 }
133
134 input = output = signal_name = xUnits = yUnits = NULL;
135 mpl_title = mpl_topline = descrip_text = descrip_contents = NULL;
136
137 for (i_arg = 1; i_arg < argc; i_arg++) {
138 if (scanned[i_arg].arg_type == OPTION) {
139 delete_chars(scanned[i_arg].list[0], "_");
140 /* Process options here */
141 switch (match_string(scanned[i_arg].list[0], option, N_OPTIONS, 0)) {
142 case SET_MAJOR_ORDER:
143 majorOrderFlag = 0;
144 scanned[i_arg].n_items--;
145 if (scanned[i_arg].n_items > 0 &&
146 !scanItemList(&majorOrderFlag, scanned[i_arg].list + 1, &scanned[i_arg].n_items, 0,
147 "row", -1, NULL, 0, SDDS_ROW_MAJOR_ORDER,
148 "column", -1, NULL, 0, SDDS_COLUMN_MAJOR_ORDER, NULL)) {
149 fprintf(stderr, "Error: Invalid syntax or value for -majorOrder option.\n");
150 return EXIT_FAILURE;
151 }
152 if (majorOrderFlag & SDDS_COLUMN_MAJOR_ORDER)
153 columnMajorOrder = 1;
154 else if (majorOrderFlag & SDDS_ROW_MAJOR_ORDER)
155 columnMajorOrder = 0;
156 break;
157 case SET_SIGNAL_NAME:
158 if (scanned[i_arg].n_items != 2) {
159 fprintf(stderr, "Error: Invalid syntax for -signalname option.\n");
160 return EXIT_FAILURE;
161 }
162 signal_name = scanned[i_arg].list[1];
163 break;
164 case SET_DESCRIPTION:
165 if (scanned[i_arg].n_items != 3) {
166 fprintf(stderr, "Error: Invalid syntax for -description option.\n");
167 return EXIT_FAILURE;
168 }
169 descrip_text = scanned[i_arg].list[1];
170 descrip_contents = scanned[i_arg].list[2];
171 break;
172 case SET_MPL_LABELS:
173 if (scanned[i_arg].n_items != 3) {
174 fprintf(stderr, "Error: Invalid syntax for -mpllabels option.\n");
175 return EXIT_FAILURE;
176 }
177 mpl_title = scanned[i_arg].list[1];
178 mpl_topline = scanned[i_arg].list[2];
179 break;
180 default:
181 fprintf(stderr, "Error: Unrecognized option '%s'.\n", scanned[i_arg].list[0]);
182 return EXIT_FAILURE;
183 }
184 } else {
185 if (!input)
186 input = scanned[i_arg].list[0];
187 else if (!output)
188 output = scanned[i_arg].list[0];
189 else {
190 fprintf(stderr, "Error: Too many filenames provided.\n");
191 return EXIT_FAILURE;
192 }
193 }
194 }
195
196 if (!input) {
197 fprintf(stderr, "Error: Input file not specified.\n\n%s", USAGE);
198 return EXIT_FAILURE;
199 }
200 if (!output) {
201 fprintf(stderr, "Error: Output file not specified.\n\n%s", USAGE);
202 return EXIT_FAILURE;
203 }
204 if (!signal_name) {
205 fprintf(stderr, "Error: -signalname option not specified.\n\n%s", USAGE);
206 return EXIT_FAILURE;
207 }
208
209 fpi = fopen_e(input, "r", 0);
210 parameter_name = buffer;
211 while (fgets(buffer, BUFSIZE, fpi)) {
212 if (!(ptr = strchr(buffer, ':'))) {
213 fprintf(stderr, "Error: Missing colon in parameter tag '%s'.\n", buffer);
214 return EXIT_FAILURE;
215 }
216 *ptr++ = '\0';
217 if (strcmp(HP_DataMarker, parameter_name) == 0)
218 break;
219 index = 0;
220 while (HP_parameter[index].HP_name) {
221 if (strcmp(HP_parameter[index].HP_name, parameter_name) == 0)
222 break;
223 index++;
224 }
225 if (!HP_parameter[index].HP_name) {
226 fprintf(stderr, "Error: Unrecognized parameter name '%s'.\n", parameter_name);
227 return EXIT_FAILURE;
228 }
229 if (HP_parameter[index].value_string) {
230 fprintf(stderr, "Error: Duplicate entry for parameter '%s'.\n", parameter_name);
231 return EXIT_FAILURE;
232 }
234 cp_str(&HP_parameter[index].value_string, ptr);
235 }
236
237 if (!SDDS_InitializeOutput(&SDDS_table, SDDS_BINARY, 0, descrip_text, descrip_contents, output)) {
238 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors);
239 return EXIT_FAILURE;
240 }
241 if (columnMajorOrder != -1)
242 SDDS_table.layout.data_mode.column_major = columnMajorOrder;
243
244 index = 0;
245 while (HP_parameter[index].HP_name) {
246 if (!HP_parameter[index].value_string) {
247 index++;
248 continue;
249 }
250 if (strcmp(HP_parameter[index].HP_name, HP_XIncrementName) == 0) {
251 if (sscanf(HP_parameter[index].value_string, "%lf", &xIncrement) != 1) {
252 fprintf(stderr, "Error: Unable to parse value for X increment.\n");
253 return EXIT_FAILURE;
254 }
255 } else if (strcmp(HP_parameter[index].HP_name, HP_XOriginName) == 0) {
256 if (sscanf(HP_parameter[index].value_string, "%lf", &xOrigin) != 1) {
257 fprintf(stderr, "Error: Unable to parse value for X origin.\n");
258 return EXIT_FAILURE;
259 }
260 } else if (strcmp(HP_parameter[index].HP_name, HP_XReferenceName) == 0) {
261 if (sscanf(HP_parameter[index].value_string, "%lf", &xReference) != 1) {
262 fprintf(stderr, "Error: Unable to parse value for X reference.\n");
263 return EXIT_FAILURE;
264 }
265 } else if (strcmp(HP_parameter[index].HP_name, HP_XUnitsName) == 0) {
266 xUnits = HP_parameter[index].value_string;
267 } else if (strcmp(HP_parameter[index].HP_name, HP_YUnitsName) == 0) {
268 yUnits = HP_parameter[index].value_string;
269 } else if (strcmp(HP_parameter[index].HP_name, HP_PointsName) == 0) {
270 if (sscanf(HP_parameter[index].value_string, "%ld", &points) != 1) {
271 fprintf(stderr, "Error: Unable to parse value for number of points.\n");
272 return EXIT_FAILURE;
273 }
274 }
275 if (SDDS_DefineParameter(&SDDS_table, HP_parameter[index].SDDS_name, NULL, NULL,
276 HP_parameter[index].HP_name, NULL,
277 HP_parameter[index].type, HP_parameter[index].value_string) < 0) {
278 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors);
279 return EXIT_FAILURE;
280 }
281 index++;
282 }
283
284 if (mpl_title && (SDDS_DefineParameter(&SDDS_table, "mplTitle", NULL, NULL, NULL, NULL, SDDS_STRING, mpl_title) < 0 ||
285 SDDS_DefineParameter(&SDDS_table, "mplTopline", NULL, NULL, NULL, NULL, SDDS_STRING, mpl_topline) < 0)) {
286 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors);
287 return EXIT_FAILURE;
288 }
289
290 if (SDDS_DefineColumn(&SDDS_table, "t", NULL, xUnits, NULL, NULL, SDDS_DOUBLE, 0) < 0 ||
291 SDDS_DefineColumn(&SDDS_table, signal_name, NULL, yUnits, NULL, NULL, SDDS_DOUBLE, 0) < 0 ||
292 !SDDS_WriteLayout(&SDDS_table) ||
293 !SDDS_StartTable(&SDDS_table, points)) {
294 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors);
295 return EXIT_FAILURE;
296 }
297 fflush(SDDS_table.layout.fp);
298
299 data = tmalloc(sizeof(*data) * points);
300 time = tmalloc(sizeof(*time) * points);
301 for (i = 0; i < points; i++) {
302 if (!fgets(buffer, BUFSIZE, fpi)) {
303 fprintf(stderr, "Error: Insufficient data in input file.\n");
304 return EXIT_FAILURE;
305 }
306 time[i] = xOrigin + (i - xReference) * xIncrement;
307 if (sscanf(buffer, "%lf", &data[i]) != 1) {
308 fprintf(stderr, "Error: Invalid data format in input file at line %ld.\n", i + 1);
309 return EXIT_FAILURE;
310 }
311 }
312
313 if (!SDDS_SetColumn(&SDDS_table, SDDS_SET_BY_NAME, time, points, "t") ||
314 !SDDS_SetColumn(&SDDS_table, SDDS_SET_BY_NAME, data, points, signal_name) ||
315 !SDDS_WriteTable(&SDDS_table) ||
316 !SDDS_Terminate(&SDDS_table)) {
317 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors);
318 return EXIT_FAILURE;
319 }
320
321 free(data);
322 free(time);
323 fclose(fpi);
324 return EXIT_SUCCESS;
325}
326
327char *process_column_definition(char **argv, long argc) {
328 char buffer[SDDS_MAXLINE], *ptr;
329 long i;
330
331 if (argc < 1)
332 return NULL;
333 snprintf(buffer, sizeof(buffer), "&column name=%s, ", argv[0]);
334 for (i = 1; i < argc; i++) {
335 if (!strchr(argv[i], '=')) {
336 return NULL;
337 }
338 strcat(buffer, argv[i]);
339 strcat(buffer, ", ");
340 }
341 if (!strstr(buffer, "type="))
342 strcat(buffer, "type=character ");
343 strcat(buffer, "&end");
344 cp_str(&ptr, buffer);
345 return ptr;
346}
SDDS (Self Describing Data Set) Data Types Definitions and Function Prototypes.
int32_t SDDS_SetColumn(SDDS_DATASET *SDDS_dataset, int32_t mode, void *data, int64_t rows,...)
Sets the values for one data column in the current data table of an SDDS dataset.
int32_t SDDS_Terminate(SDDS_DATASET *SDDS_dataset)
int32_t SDDS_InitializeOutput(SDDS_DATASET *SDDS_dataset, int32_t data_mode, int32_t lines_per_row, const char *description, const char *contents, const char *filename)
Initializes the SDDS output dataset.
int32_t SDDS_DefineColumn(SDDS_DATASET *SDDS_dataset, const char *name, const char *symbol, const char *units, const char *description, const char *format_string, int32_t type, int32_t field_length)
Defines a data column within the SDDS dataset.
int32_t SDDS_WriteLayout(SDDS_DATASET *SDDS_dataset)
Writes the SDDS layout header to the output file.
int32_t SDDS_DefineParameter(SDDS_DATASET *SDDS_dataset, const char *name, const char *symbol, const char *units, const char *description, const char *format_string, int32_t type, char *fixed_value)
Defines a data parameter with a fixed string value.
void SDDS_PrintErrors(FILE *fp, int32_t mode)
Prints recorded error messages to a specified file stream.
Definition SDDS_utils.c:432
void SDDS_RemovePadding(char *s)
Removes leading and trailing whitespace from a string.
#define SDDS_STRING
Identifier for the string data type.
Definition SDDStypes.h:85
#define SDDS_LONG
Identifier for the signed 32-bit integer data type.
Definition SDDStypes.h:61
#define SDDS_DOUBLE
Identifier for the double data type.
Definition SDDStypes.h:37
void * tmalloc(uint64_t size_of_block)
Allocates a memory block of the specified size with zero initialization.
Definition array.c:59
char * cp_str(char **s, char *t)
Copies a string, allocating memory for storage.
Definition cp_str.c:28
char * delete_chars(char *s, char *t)
Removes all occurrences of characters found in string t from string s.
FILE * fopen_e(char *file, char *open_mode, long mode)
Opens a file with error checking, messages, and aborts.
Definition fopen_e.c:30
long match_string(char *string, char **option, long n_options, long mode)
Matches a given string against an array of option strings based on specified modes.
int scanargs(SCANNED_ARG **scanned, int argc, char **argv)
Definition scanargs.c:36
long scanItemList(unsigned long *flags, char **item, long *items, unsigned long mode,...)
Scans a list of items and assigns values based on provided keywords and types.