SDDS ToolKit Programs and Libraries for C and Python
All Classes Files Functions Variables Macros Pages
sdds2agilentArb.c
Go to the documentation of this file.
1/**
2 * @file sdds2agilentArb.c
3 * @brief Converts SDDS files to Agilent Arbitrary Waveform files.
4 *
5 * @details
6 * This program reads an SDDS file, extracts the "I" and "Q" floating-point columns,
7 * scales the data to fit the [-32767, 32767] range, and writes the results to an
8 * output file in a binary format compatible with Agilent arbitrary waveform generators.
9 * The program supports input and output via pipes, little-endian to big-endian
10 * conversion, and error handling for invalid options and inputs.
11 *
12 * @section Usage
13 * ```
14 * sdds2agilentArb [<inputFile>] [<outputFile>] [-pipe[=in][,out]]
15 * ```
16 *
17 * @section Options
18 * | Option | Description |
19 * |-------------------------------------|-------------------------------------------------------------------|
20 * | `-pipe` | Use pipes for input and/or output. |
21 *
22 * @subsection Requirements
23 * - Input file must contain the "I" and "Q" floating-point columns.
24 *
25 * @copyright
26 * - (c) 2002 The University of Chicago, as Operator of Argonne National Laboratory.
27 * - (c) 2002 The Regents of the University of California, as Operator of Los Alamos National Laboratory.
28 *
29 * @license
30 * This file is distributed under the terms of the Software License Agreement
31 * found in the file LICENSE included with this distribution.
32 *
33 * @author
34 * R. Soliday
35 */
36
37#include "SDDS.h"
38#include "mdb.h"
39#include "scan.h"
40#if defined(_WIN32)
41# include <io.h>
42# include <fcntl.h>
43#endif
44
45/* Enumeration for option types */
46enum option_type {
47 SET_PIPE,
48 N_OPTIONS
49};
50
51char *option[N_OPTIONS] =
52 {
53 "pipe"
54 };
55
56char *usage =
57 "sdds2agilentArb [<inputFile>] [<outputFile>] [-pipe[=in][,out]]\n\n"
58 "Converts SDDS to Agilent Arbitrary Waveform files.\n"
59 "Program by Robert Soliday. (" __DATE__ " " __TIME__ ", SVN revision: " SVN_VERSION ")\n";
60
61int main(int argc, char *argv[]) {
62 SCANNED_ARG *scanned;
63 long i_arg;
64 unsigned long pipe_flags = 0;
65 char *input = NULL, *output = NULL;
66 FILE *fd;
67 SDDS_DATASET sdds_dataset;
68
69 long points;
70 double *i_wave;
71 double *q_wave;
72 double max_amp = 0;
73 double min_amp = 0;
74 int i;
75 double scale;
76 short *waveform = NULL;
77 char buf;
78 char *p_char;
79
81 argc = scanargs(&scanned, argc, argv);
82 if (argc < 2) {
83 fprintf(stderr, "%s", usage);
84 return 1;
85 }
86 for (i_arg = 1; i_arg < argc; i_arg++) {
87 if (scanned[i_arg].arg_type == OPTION) {
88 switch (match_string(scanned[i_arg].list[0], option, N_OPTIONS, 0)) {
89 case SET_PIPE:
90 if (!processPipeOption(scanned[i_arg].list + 1,
91 scanned[i_arg].n_items - 1, &pipe_flags)) {
92 fprintf(stderr, "invalid -pipe syntax\n");
93 return 1;
94 }
95 break;
96 default:
97 fprintf(stderr, "invalid option seen\n");
98 fprintf(stderr, "%s", usage);
99 return 1;
100 }
101 } else {
102 if (!input)
103 input = scanned[i_arg].list[0];
104 else if (!output)
105 output = scanned[i_arg].list[0];
106 else {
107 fprintf(stderr, "too many filenames\n");
108 fprintf(stderr, "%s", usage);
109 return 1;
110 }
111 }
112 }
113 processFilenames("sdds2agilentArb", &input, &output, pipe_flags, 0, NULL);
114
115 if (!SDDS_InitializeInput(&sdds_dataset, input)) {
116 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
117 }
118 if ((SDDS_CheckColumn(&sdds_dataset, "I", NULL, SDDS_ANY_FLOATING_TYPE,
119 NULL)) != SDDS_CHECK_OKAY) {
120 fprintf(stderr, "error: Floating type column named I does not exist\n");
121 return 1;
122 }
123 if ((SDDS_CheckColumn(&sdds_dataset, "Q", NULL, SDDS_ANY_FLOATING_TYPE,
124 NULL)) != SDDS_CHECK_OKAY) {
125 fprintf(stderr, "error: Floating type column named Q does not exist\n");
126 return 1;
127 }
128
129 if (SDDS_ReadTable(&sdds_dataset) != 1) {
130 fprintf(stderr, "error: No data found in SDDS file\n");
131 return 1;
132 }
133 points = SDDS_RowCount(&sdds_dataset);
134
135 i_wave = SDDS_GetColumnInDoubles(&sdds_dataset, "I");
136 q_wave = SDDS_GetColumnInDoubles(&sdds_dataset, "Q");
137 if (!SDDS_Terminate(&sdds_dataset)) {
138 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors);
139 exit(1);
140 }
141
142 max_amp = i_wave[0];
143 min_amp = i_wave[0];
144 for (i = 0; i < points; i++) {
145 if (max_amp < i_wave[i])
146 max_amp = i_wave[i];
147 else if (min_amp > i_wave[i])
148 min_amp = i_wave[i];
149 if (max_amp < q_wave[i])
150 max_amp = q_wave[i];
151 else if (min_amp > q_wave[i])
152 min_amp = q_wave[i];
153 }
154 max_amp = fabs(max_amp);
155 min_amp = fabs(min_amp);
156 if (min_amp > max_amp)
157 max_amp = min_amp;
158
159 scale = 32767 / max_amp;
160 waveform = malloc(sizeof(short) * points * 2);
161 for (i = 0; i < points; i++) {
162 waveform[2 * i] = (short)floor(i_wave[i] * scale + 0.5);
163 waveform[2 * i + 1] = (short)floor(q_wave[i] * scale + 0.5);
164 }
165 free(i_wave);
166 free(q_wave);
167
169 p_char = (char *)&waveform[0];
170 for (i = 0; i < 2 * points; i++) {
171 buf = *p_char;
172 *p_char = *(p_char + 1);
173 *(p_char + 1) = buf;
174 p_char += 2;
175 }
176 }
177
178 if (!output) {
179#if defined(_WIN32)
180 if (_setmode(_fileno(stdout), _O_BINARY) == -1) {
181 fprintf(stderr, "error: unable to set stdout to binary mode\n");
182 exit(1);
183 }
184#endif
185 fd = stdout;
186 } else {
187 fd = fopen(output, "wb");
188 }
189 if (fd == NULL) {
190 fprintf(stderr, "unable to open output file for writing\n");
191 exit(1);
192 }
193 fwrite((void *)waveform, sizeof(short), points * 2, fd);
194 fclose(fd);
195 if (waveform)
196 free(waveform);
197 free_scanargs(&scanned, argc);
198
199 return 0;
200}
SDDS (Self Describing Data Set) Data Types Definitions and Function Prototypes.
double * SDDS_GetColumnInDoubles(SDDS_DATASET *SDDS_dataset, char *column_name)
Retrieves the data of a specified numerical column as an array of doubles, considering only rows mark...
int32_t SDDS_InitializeInput(SDDS_DATASET *SDDS_dataset, char *filename)
Definition SDDS_input.c:49
int32_t SDDS_Terminate(SDDS_DATASET *SDDS_dataset)
int32_t SDDS_CheckColumn(SDDS_DATASET *SDDS_dataset, char *name, char *units, int32_t type, FILE *fp_message)
Checks if a column exists in the SDDS dataset with the specified name, units, and type.
void SDDS_PrintErrors(FILE *fp, int32_t mode)
Prints recorded error messages to a specified file stream.
Definition SDDS_utils.c:432
void SDDS_RegisterProgramName(const char *name)
Registers the executable program name for use in error messages.
Definition SDDS_utils.c:288
int32_t SDDS_IsBigEndianMachine()
Determines whether the current machine uses big-endian byte ordering.
#define SDDS_ANY_FLOATING_TYPE
Special identifier used by SDDS_Check*() routines to accept any floating-point type.
Definition SDDStypes.h:165
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 processPipeOption(char **item, long items, unsigned long *flags)
Definition scanargs.c:356
void processFilenames(char *programName, char **input, char **output, unsigned long pipeFlags, long noWarnings, long *tmpOutputUsed)
Definition scanargs.c:390
void free_scanargs(SCANNED_ARG **scanned, int argc)
Definition scanargs.c:584