SDDS ToolKit Programs and Libraries for C and Python
Loading...
Searching...
No Matches
tek2sdds.c
Go to the documentation of this file.
1/**
2 * @file tek2sdds.c
3 * @brief Converts waveforms from Tektronix ASCII format to SDDS format.
4 *
5 * @details
6 * This program processes Tektronix ASCII files containing waveform data and converts them into
7 * SDDS format for improved interoperability and analysis. It supports defining signal names,
8 * setting descriptions, and specifying data layouts using various options.
9 *
10 * @section Usage
11 * ```
12 * tek2sdds <inputfile> <outputfile>
13 * -signalname=<name>
14 * [-description=<text>,<contents>]
15 * [-mpllabels=<title>,<topline>]
16 * [-majorOrder=row|column]
17 * ```
18 *
19 * @section Options
20 * | Required | Description |
21 * |---------------------------------------|---------------------------------------------------------------------------------------|
22 * | `-signalname` | Specifies the name of the signal to use in the SDDS file. |
23 *
24 * | Optional | Description |
25 * |---------------------------------------|---------------------------------------------------------------------------------------|
26 * | `-description` | Adds a description with specified text and contents to the SDDS output. |
27 * | `-mpllabels` | Sets MPL labels such as the title and topline for graphing purposes. |
28 * | `-majorOrder` | Defines the major order for data layout in the SDDS file (row or column). |
29 *
30 * @copyright
31 * - (c) 2002 The University of Chicago, as Operator of Argonne National Laboratory.
32 * - (c) 2002 The Regents of the University of California, as Operator of Los Alamos National Laboratory.
33 *
34 * @license
35 * This file is distributed under the terms of the Software License Agreement
36 * found in the file LICENSE included with this distribution.
37 *
38 * @author
39 * M. Borland, C. Saunders, R. Soliday, H. Shang
40 */
41
42#include "mdb.h"
43#include "SDDS.h"
44#include "scan.h"
45#include "match_string.h"
46
47#include <stdlib.h>
48
49/* Enumeration for option types */
50enum option_type {
51 SET_SIGNAL_NAME,
52 SET_DESCRIPTION,
53 SET_MPL_LABELS,
54 SET_MAJOR_ORDER,
55 N_OPTIONS
56};
57
58static char *option[N_OPTIONS] = {
59 "signalname",
60 "description",
61 "mpllabels",
62 "majorOrder",
63};
64
65char *USAGE =
66 "tek2sdds <inputfile> <outputfile>\n"
67 " -signalname=<name>\n"
68 " [-description=<text>,<contents>]\n"
69 " [-mpllabels=<title>,<topline>]\n"
70 " [-majorOrder=row|column]\n"
71 "Options:\n"
72 " -signalname=<name> (required) Name of the signal\n"
73 " -description=<text>,<contents> (optional) Description text and contents\n"
74 " -mpllabels=<title>,<topline> (optional) MPL labels: title and topline\n"
75 " -majorOrder=row|column (optional) Major order of data\n"
76 "\n"
77 "This program converts Tektronix ASCII format waveforms to SDDS format.\n"
78 "\n"
79 "Program by Michael Borland (" __DATE__ " " __TIME__ ", SVN revision: " SVN_VERSION ")\n";
80
81typedef struct
82{
83 char *TEK_name, *SDDS_name, *value_string;
84 long type;
86
87#define TEK_PARAMETERS 23
88TEK_PARAMETER TEK_parameter[TEK_PARAMETERS] = {
89 {"ACSTATE", "ACStart", NULL, SDDS_STRING},
90 {"NR.PT", "Points", NULL, SDDS_LONG},
91 {"WFID", "WaveformID", NULL, SDDS_STRING},
92 {"XMULT", "XMultiplier", NULL, SDDS_DOUBLE},
93 {"LABEL", "TekLabel", NULL, SDDS_STRING},
94 {"TIME", "TimeStamp", NULL, SDDS_STRING},
95 {"DATE", "DateStamp", NULL, SDDS_STRING},
96 {"TSTIME", "TSTime", NULL, SDDS_DOUBLE},
97 {"XINCR", "XIncrement", NULL, SDDS_DOUBLE},
98 {"XZERO", "XZero", NULL, SDDS_DOUBLE},
99 {"XUNIT", "XUnits", NULL, SDDS_STRING},
100 {"YUNIT", "YUnits", NULL, SDDS_STRING},
101 {"YZERO", "YZero", NULL, SDDS_DOUBLE},
102 {"YMULT", "YMultiplier", NULL, SDDS_DOUBLE},
103 {"ENCDG", "Encoding", NULL, SDDS_STRING},
104 {"BYT/NR", "TEKBytesPerNumber", NULL, SDDS_LONG},
105 {"BYT.OR", "TEKByteOrder", NULL, SDDS_STRING},
106 {NULL, NULL, NULL, 0},
107};
108
109char *TEK_PreambleString = "WFMPRE ";
110char *TEK_DataMarker = "CURVE ";
111char *TEK_PointsName = "NR.PT";
112char *TEK_XIncrementName = "XINCR";
113char *TEK_XZeroName = "XZERO";
114char *TEK_XUnitsName = "XUNIT";
115char *TEK_YUnitsName = "YUNIT";
116char *TEK_YZeroName = "YZERO";
117char *TEK_YMultiplierName = "YMULT";
118char *TEK_EncodingName = "ENCDG";
119char *TEK_BytesPerNumberName = "BYT/NR";
120char *TEK_ByteOrderName = "BYT.OR";
121
122#define BUFSIZE 256
123
124long GetNextItem(char *buffer, long bufsize, FILE *fpi);
125
126int main(int argc, char **argv) {
127 SDDS_TABLE SDDS_table;
128 SCANNED_ARG *scanned;
129 long i, i_arg, index, points, bytes_per_number;
130 // long lsb_first;
131 char *input, *output, buffer[BUFSIZE];
132 char *signal_name, *ptr, *parameter_name;
133 char *mpl_title, *mpl_topline, *descrip_text, *descrip_contents;
134 FILE *fpi;
135 long code, binary;
136 double xIncrement, xZero, yMultiplier, yZero;
137 char *xUnits, *yUnits;
138 double *time, *data;
139 short columnMajorOrder = 0;
140 unsigned long majorOrderFlag;
141 size_t bytesRead;
142
143 xUnits = yUnits = NULL;
144
145 argc = scanargs(&scanned, argc, argv);
146 if (argc < 3) {
147 bomb(NULL, USAGE);
148 }
149
150 input = output = signal_name = NULL;
151 mpl_title = mpl_topline = descrip_text = descrip_contents = NULL;
152 binary = 0;
153
154 for (i_arg = 1; i_arg < argc; i_arg++) {
155 if (scanned[i_arg].arg_type == OPTION) {
156 delete_chars(scanned[i_arg].list[0], "_");
157 /* process options here */
158 switch (match_string(scanned[i_arg].list[0], option, N_OPTIONS, 0)) {
159 case SET_MAJOR_ORDER:
160 majorOrderFlag = 0;
161 scanned[i_arg].n_items--;
162 if (scanned[i_arg].n_items > 0 &&
163 (!scanItemList(&majorOrderFlag, scanned[i_arg].list + 1, &scanned[i_arg].n_items, 0,
164 "row", -1, NULL, 0, SDDS_ROW_MAJOR_ORDER,
165 "column", -1, NULL, 0, SDDS_COLUMN_MAJOR_ORDER, NULL)))
166 SDDS_Bomb("invalid -majorOrder syntax/values");
167 if (majorOrderFlag & SDDS_COLUMN_MAJOR_ORDER)
168 columnMajorOrder = 1;
169 else if (majorOrderFlag & SDDS_ROW_MAJOR_ORDER)
170 columnMajorOrder = 0;
171 break;
172 case SET_SIGNAL_NAME:
173 if (scanned[i_arg].n_items != 2) {
174 bomb("invalid -signalname syntax", USAGE);
175 }
176 signal_name = scanned[i_arg].list[1];
177 break;
178 case SET_DESCRIPTION:
179 if (scanned[i_arg].n_items != 3) {
180 bomb("invalid -description syntax", USAGE);
181 }
182 descrip_text = scanned[i_arg].list[1];
183 descrip_contents = scanned[i_arg].list[2];
184 break;
185 case SET_MPL_LABELS:
186 if (scanned[i_arg].n_items != 3) {
187 bomb("invalid -mpllabels syntax", USAGE);
188 }
189 mpl_title = scanned[i_arg].list[1];
190 mpl_topline = scanned[i_arg].list[2];
191 break;
192 default:
193 bomb("invalid option seen", USAGE);
194 break;
195 }
196 } else {
197 if (!input)
198 input = scanned[i_arg].list[0];
199 else if (!output)
200 output = scanned[i_arg].list[0];
201 else
202 bomb("too many filenames", USAGE);
203 }
204 }
205 if (!input)
206 SDDS_Bomb("input file not seen");
207 if (!output)
208 SDDS_Bomb("output file not seen");
209 if (!signal_name)
210 signal_name = "V";
211
212 fpi = fopen_e(input, "r", 0);
213 if (fread(buffer, 1, strlen(TEK_PreambleString), fpi) != strlen(TEK_PreambleString) ||
214 strncmp(TEK_PreambleString, buffer, strlen(TEK_PreambleString)) != 0)
215 SDDS_Bomb("file does not appear to be in Tektronix format");
216
217 parameter_name = buffer;
218 while ((code = GetNextItem(buffer, BUFSIZE, fpi)) < 3) {
219 if (!(ptr = strchr(buffer, ':')))
220 SDDS_Bomb("error parsing input file--missing colon on parameter tag");
221 *ptr++ = 0;
222 if (strcmp(TEK_DataMarker, parameter_name) == 0)
223 break;
224 index = 0;
225 while (TEK_parameter[index].TEK_name) {
226 if (strcmp(TEK_parameter[index].TEK_name, parameter_name) == 0)
227 break;
228 index++;
229 }
230 if (!TEK_parameter[index].TEK_name) {
231 fprintf(stderr, "warning: parameter %s is not recognized\n", parameter_name);
232 continue;
233 }
234 if (TEK_parameter[index].value_string) {
235 fprintf(stderr, "error: duplicate entries for parameter %s\n", parameter_name);
236 exit(EXIT_FAILURE);
237 }
239 SDDS_CopyString(&TEK_parameter[index].value_string, ptr);
240 if (code == 2 || code == 3)
241 break;
242 }
243 if (code != 2)
244 SDDS_Bomb("unexpected end of file");
245
246 if (fread(buffer, 1, strlen(TEK_DataMarker), fpi) != strlen(TEK_DataMarker) ||
247 strncmp(TEK_DataMarker, buffer, strlen(TEK_DataMarker)) != 0)
248 SDDS_Bomb("CURVE item missing or not in right place");
249
250 if (!SDDS_InitializeOutput(&SDDS_table, SDDS_BINARY, 0, descrip_text, descrip_contents, output))
251 SDDS_PrintErrors(stderr, SDDS_EXIT_PrintErrors | SDDS_VERBOSE_PrintErrors);
252 SDDS_table.layout.data_mode.column_major = columnMajorOrder;
253
254 index = 0;
255 while (TEK_parameter[index].TEK_name) {
256 if (!TEK_parameter[index].value_string) {
257 index++;
258 continue;
259 }
260 if (strcmp(TEK_parameter[index].TEK_name, TEK_XIncrementName) == 0) {
261 if (sscanf(TEK_parameter[index].value_string, "%lf", &xIncrement) != 1)
262 SDDS_Bomb("unable to scan value for x increment");
263 } else if (strcmp(TEK_parameter[index].TEK_name, TEK_XZeroName) == 0) {
264 if (sscanf(TEK_parameter[index].value_string, "%lf", &xZero) != 1)
265 SDDS_Bomb("unable to scan value for x zero");
266 } else if (strcmp(TEK_parameter[index].TEK_name, TEK_YZeroName) == 0) {
267 if (sscanf(TEK_parameter[index].value_string, "%lf", &yZero) != 1)
268 SDDS_Bomb("unable to scan value for y zero");
269 } else if (strcmp(TEK_parameter[index].TEK_name, TEK_YMultiplierName) == 0) {
270 if (sscanf(TEK_parameter[index].value_string, "%lf", &yMultiplier) != 1)
271 SDDS_Bomb("unable to scan value for y multiplier");
272 } else if (strcmp(TEK_parameter[index].TEK_name, TEK_XUnitsName) == 0) {
273 xUnits = TEK_parameter[index].value_string;
274 str_tolower(xUnits);
275 } else if (strcmp(TEK_parameter[index].TEK_name, TEK_YUnitsName) == 0) {
276 yUnits = TEK_parameter[index].value_string;
277 str_tolower(yUnits);
278 } else if (strcmp(TEK_parameter[index].TEK_name, TEK_PointsName) == 0) {
279 if (sscanf(TEK_parameter[index].value_string, "%ld", &points) != 1)
280 SDDS_Bomb("unable to scan value for number of points");
281 } else if (strcmp(TEK_parameter[index].TEK_name, TEK_EncodingName) == 0) {
282 if (strcmp(TEK_parameter[index].value_string, "ASCII") == 0)
283 binary = 0;
284 else if (strcmp(TEK_parameter[index].value_string, "BINARY") == 0)
285 binary = 1;
286 else
287 SDDS_Bomb("data encoding is neither ASCII nor BINARY");
288 } else if (strcmp(TEK_parameter[index].TEK_name, TEK_BytesPerNumberName) == 0) {
289 if (sscanf(TEK_parameter[index].value_string, "%ld", &bytes_per_number) != 1)
290 SDDS_Bomb("unable to scan value bytes per number");
291 } else if (strcmp(TEK_parameter[index].value_string, TEK_ByteOrderName) == 0) {
292 // lsb_first = 1;
293 if (strcmp(TEK_parameter[index].value_string, "LSB") != 0) {
294 // lsb_first = 0;
295 }
296 }
297 if (SDDS_DefineParameter(&SDDS_table, TEK_parameter[index].SDDS_name, NULL, NULL, TEK_parameter[index].TEK_name,
298 NULL, TEK_parameter[index].type, TEK_parameter[index].value_string) < 0)
299 SDDS_PrintErrors(stderr, SDDS_EXIT_PrintErrors | SDDS_VERBOSE_PrintErrors);
300 index++;
301 }
302
303 if (mpl_title &&
304 (SDDS_DefineParameter(&SDDS_table, "mplTitle", NULL, NULL, NULL, NULL, SDDS_STRING, mpl_title) < 0 ||
305 SDDS_DefineParameter(&SDDS_table, "mplTopline", NULL, NULL, NULL, NULL, SDDS_STRING, mpl_topline) < 0))
306 SDDS_PrintErrors(stderr, SDDS_EXIT_PrintErrors | SDDS_VERBOSE_PrintErrors);
307
308 if (SDDS_DefineColumn(&SDDS_table, "t", NULL, xUnits, NULL, NULL, SDDS_DOUBLE, 0) < 0 ||
309 SDDS_DefineColumn(&SDDS_table, signal_name, NULL, yUnits, NULL, NULL, SDDS_DOUBLE, 0) < 0 ||
310 !SDDS_WriteLayout(&SDDS_table) || !SDDS_StartTable(&SDDS_table, points))
311 SDDS_PrintErrors(stderr, SDDS_EXIT_PrintErrors | SDDS_VERBOSE_PrintErrors);
312
313 data = tmalloc(sizeof(*data) * points);
314 time = tmalloc(sizeof(*time) * points);
315 if (!binary) {
316 for (i = 0; i < points; i++) {
317
318 if (!(code = GetNextItem(buffer, BUFSIZE, fpi)))
319 SDDS_Bomb("insufficient data in input file");
320 if (code == 4) {
321 points = i;
322 break;
323 }
324 time[i] = xZero + i * xIncrement;
325 if (sscanf(buffer, "%lf", data + i) != 1)
326 SDDS_Bomb("invalid data in input file");
327 data[i] = yZero + data[i] * yMultiplier;
328 }
329 } else {
330 short sdata;
331 bytesRead = fread(buffer, sizeof(char), 4, fpi);
332 (void)bytesRead;
333 for (i = 0; i < points; i++) {
334 if (fread(&sdata, sizeof(sdata), 1, fpi) != 1) {
335 fprintf(stderr, "file ends unexpectedly\n");
336 points = i;
337 break;
338 }
339 time[i] = xZero + i * xIncrement;
340 data[i] = sdata;
341 data[i] = yZero + data[i] * yMultiplier;
342 }
343 }
344
345 if (!SDDS_SetColumn(&SDDS_table, SDDS_SET_BY_NAME, time, points, "t") ||
346 !SDDS_SetColumn(&SDDS_table, SDDS_SET_BY_NAME, data, points, signal_name) ||
347 !SDDS_WriteTable(&SDDS_table) ||
348 !SDDS_Terminate(&SDDS_table))
349 SDDS_PrintErrors(stderr, SDDS_EXIT_PrintErrors | SDDS_VERBOSE_PrintErrors);
350 return EXIT_SUCCESS;
351}
352
353long GetNextItem(char *buffer, long bufsize, FILE *fpi) {
354 long i;
355 char c;
356
357 i = c = 0;
358 while (i < bufsize && (c = getc(fpi)) != EOF) {
359 if (c == ',' || c == ';' || c == '%')
360 break;
361 buffer[i++] = c;
362 }
363 if (c == EOF && i == 0)
364 return 0;
365 buffer[i] = '\0';
366 if (c == ',')
367 return 1;
368 if (c == ';')
369 return 2;
370 if (c == EOF)
371 return 3;
372 fprintf(stderr, "warning: invalid data seen--ignoring\n");
373 return 4;
374}
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:474
void SDDS_Bomb(char *message)
Terminates the program after printing an error message and recorded errors.
Definition SDDS_utils.c:380
int32_t SDDS_CopyString(char **target, const char *source)
Copies a source string to a target string with memory allocation.
Definition SDDS_utils.c:922
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:65
void bomb(char *error, char *usage)
Reports error messages to the terminal and aborts the program.
Definition bomb.c:26
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.
char * str_tolower(char *s)
Convert a string to lower case.
Definition str_tolower.c:27