SDDS ToolKit Programs and Libraries for C and Python
Loading...
Searching...
No Matches
mcs2sdds.c
Go to the documentation of this file.
1/**
2 * @file mcs2sdds.c
3 * @brief Converts EG&G Turbo MCS (Multi-Channel Scaler) data files to SDDS format.
4 *
5 * @details
6 * This program reads an EG&G Turbo MCS file, processes its header and data sections,
7 * and outputs an equivalent SDDS (Self Describing Data Sets) file.
8 *
9 * @section Usage
10 * ```
11 * mcs2sdds <inputfile> <outputfile> [-ascii]
12 * ```
13 *
14 * @section Options
15 * | Option | Description |
16 * |------------|--------------------------------------------------------------------------------|
17 * | `-ascii` | Outputs the SDDS file in ASCII format. Default is binary format. |
18 *
19 * @copyright
20 * - (c) 2002 The University of Chicago, as Operator of Argonne National Laboratory.
21 * - (c) 2002 The Regents of the University of California, as Operator of Los Alamos National Laboratory.
22 *
23 * @license
24 * This file is distributed under the terms of the Software License Agreement
25 * found in the file LICENSE included with this distribution.
26 *
27 * @authors
28 * M. Borland, C. Saunders, R. Soliday
29 */
30
31#include "mdb.h"
32#include "SDDS.h"
33#include "scan.h"
34
35/* Enumeration for option types */
36enum option_type {
37 SET_ASCII,
38 N_OPTIONS
39};
40
41char *option[N_OPTIONS] = {
42 "ascii"};
43
44char *USAGE =
45 "Usage: mcs2sdds <inputfile> <outputfile> [-ascii]\n"
46 "Options:\n"
47 " -ascii Output the SDDS file in ASCII format. By default, binary format is used.\n"
48 "\n"
49 "Link date: " __DATE__ " " __TIME__ ", SVN revision: " SVN_VERSION "\n";
50
51#define MCS -4
52
53void swapshort(short *data);
54void swaplong(long *data);
55void swapulong(unsigned long *data);
56void swapushort(unsigned short *data);
57void swapfloat(float *data);
58
59int main(int argc, char **argv) {
60 char reserved[100]; /* buffer to skip reserved bytes */
61 short f_type; /* MCS file type */
62 char trigger; /* Trigger Flag */
63 char dwell_flag; /* External Dwell Flag */
64 char dwell_units; /* 0=us, 1=ms, 2=sec, 3=ns */
65 char acq_mode; /* Acquisition mode flag 0=replace, 1=sum */
66 unsigned long dwell_913; /* Dwell time in old 913 format */
67 unsigned short pass_length; /* pass length in channels */
68 unsigned long pass_count;
69 unsigned long pass_count_preset;
70 char acq_time[9]; /* buffer for acquisition time */
71 char acq_date[9]; /* buffer for acquisition date */
72 unsigned short mark_chan; /* first marker channel */
73 char mcs_num; /* 1-8 are valid */
74 char cal_flag; /* 0=no calibration */
75 char cal_units[4]; /* calibration units */
76 float cal_zero; /* calibration zero intercept */
77 float cal_slope; /* calibration slope */
78 char id_byte; /* always 0xaa */
79 char detector_len; /* Detector description length */
80 char detector[65]; /* detector description */
81 char sample_len; /* Sample description length */
82 char sample[65]; /* Sample description */
83 char disc_sel; /* 0=SCA otherwise Disc */
84 char disc_edge; /* 0=falling else rising */
85 float disc; /* disc setting in volts */
86 float sca_uld; /* sca upper-level in volts */
87 float sca_lld; /* sca lower-level in volts */
88 float dwell; /* dwell time in dwell_units */
89 char consistent; /* settings consistent flag */
90 char mcs_id[9]; /* MCS ID string "0914-001" */
91
92 FILE *fpi;
93 char *input, *output;
94 SDDS_DATASET SDDS_dataset;
95 SCANNED_ARG *scanned;
96 long i, i_arg;
97 char ts1[256], ts2[256], ts3[256], ts4[256];
98 unsigned long *ucount;
99 long *count, *channel;
100 long ascii;
101 size_t bytesRead;
102
104 argc = scanargs(&scanned, argc, argv);
105 if (argc < 3) {
106 fprintf(stderr, "Error: Insufficient arguments.\n");
107 fprintf(stderr, "%s", USAGE);
108 exit(EXIT_FAILURE);
109 }
110
111 input = output = NULL;
112 ascii = 0;
113 for (i_arg = 1; i_arg < argc; i_arg++) {
114 if (scanned[i_arg].arg_type == OPTION) {
115 switch (match_string(scanned[i_arg].list[0], option, N_OPTIONS, 0)) {
116 case SET_ASCII:
117 ascii = 1;
118 break;
119 default:
120 fprintf(stderr, "Error: Invalid option '%s'.\n", scanned[i_arg].list[0]);
121 fprintf(stderr, "%s", USAGE);
122 exit(EXIT_FAILURE);
123 }
124 } else {
125 if (!input)
126 input = scanned[i_arg].list[0];
127 else if (!output)
128 output = scanned[i_arg].list[0];
129 else {
130 fprintf(stderr, "Error: Too many filenames provided.\n");
131 fprintf(stderr, "%s", USAGE);
132 exit(EXIT_FAILURE);
133 }
134 }
135 }
136
137 if (!input) {
138 SDDS_Bomb("Error: Input file not specified.");
139 }
140 if (!output) {
141 SDDS_Bomb("Error: Output file not specified.");
142 }
143
144 fpi = fopen_e(input, "r", 0);
145
146 /***************************************************************************/
147 /* Header Data */
148 /* Read header info from MCS file */
149 /***************************************************************************/
150 /* Read filetype -4 (MCS) */
151 if (fread(&f_type, sizeof(short), 1, fpi) != 1) {
152 SDDS_Bomb("Error: Unable to read file type.");
153 }
154 swapshort(&f_type);
155 if (f_type != MCS) {
156 fprintf(stderr, "Error: Not a valid MCS file. f_type = %hx\n", f_type);
157 fclose(fpi);
158 exit(EXIT_FAILURE);
159 }
160
161 bytesRead = fread(&trigger, sizeof(char), 1, fpi); /* Read Trigger Flag */
162 (void)bytesRead;
163 bytesRead = fread(&dwell_flag, sizeof(char), 1, fpi); /* Read dwell flag */
164 (void)bytesRead;
165 bytesRead = fread(&dwell_units, sizeof(char), 1, fpi); /* Read dwell units */
166 (void)bytesRead;
167 bytesRead = fread(&acq_mode, sizeof(char), 1, fpi);
168 (void)bytesRead;
169 bytesRead = fread(&dwell_913, sizeof(long), 1, fpi);
170 (void)bytesRead;
171 swapulong(&dwell_913);
172 bytesRead = fread(&pass_length, sizeof(short), 1, fpi);
173 (void)bytesRead;
174 swapushort(&pass_length);
175 bytesRead = fread(&pass_count, sizeof(long), 1, fpi);
176 (void)bytesRead;
177 swapulong(&pass_count);
178 bytesRead = fread(&pass_count_preset, sizeof(long), 1, fpi);
179 (void)bytesRead;
180 swapulong(&pass_count_preset);
181 bytesRead = fread(acq_time, sizeof(char), 8, fpi);
182 (void)bytesRead;
183 bytesRead = fread(acq_date, sizeof(char), 8, fpi);
184 (void)bytesRead;
185 bytesRead = fread(&mark_chan, sizeof(short), 1, fpi);
186 (void)bytesRead;
187 swapushort(&mark_chan);
188 bytesRead = fread(&mcs_num, sizeof(char), 1, fpi);
189 (void)bytesRead;
190 bytesRead = fread(&cal_flag, sizeof(char), 1, fpi);
191 (void)bytesRead;
192 bytesRead = fread(cal_units, sizeof(char), 4, fpi);
193 (void)bytesRead;
194 bytesRead = fread(&cal_zero, sizeof(float), 1, fpi);
195 (void)bytesRead;
196 swapfloat(&cal_zero);
197 bytesRead = fread(&cal_slope, sizeof(float), 1, fpi);
198 (void)bytesRead;
199 swapfloat(&cal_slope);
200 bytesRead = fread(reserved, sizeof(char), 10, fpi);
201 (void)bytesRead;
202 bytesRead = fread(&id_byte, sizeof(char), 1, fpi);
203 (void)bytesRead;
204 bytesRead = fread(reserved, sizeof(char), 1, fpi);
205 (void)bytesRead;
206 bytesRead = fread(&detector_len, sizeof(char), 1, fpi);
207 (void)bytesRead;
208 bytesRead = fread(detector, sizeof(char), 63, fpi);
209 (void)bytesRead;
210 bytesRead = fread(&sample_len, sizeof(char), 1, fpi);
211 (void)bytesRead;
212 bytesRead = fread(sample, sizeof(char), 63, fpi);
213 (void)bytesRead;
214 bytesRead = fread(reserved, sizeof(char), 16, fpi); /* skip view info & reserved */
215 (void)bytesRead;
216 bytesRead = fread(&disc_sel, sizeof(char), 1, fpi);
217 (void)bytesRead;
218 bytesRead = fread(&disc_edge, sizeof(char), 1, fpi);
219 (void)bytesRead;
220 bytesRead = fread(&disc, sizeof(float), 1, fpi);
221 (void)bytesRead;
222 swapfloat(&disc);
223 bytesRead = fread(&sca_uld, sizeof(float), 1, fpi);
224 (void)bytesRead;
225 swapfloat(&sca_uld);
226 bytesRead = fread(&sca_lld, sizeof(float), 1, fpi);
227 (void)bytesRead;
228 swapfloat(&sca_lld);
229 bytesRead = fread(&dwell, sizeof(float), 1, fpi);
230 (void)bytesRead;
231 swapfloat(&dwell);
232 bytesRead = fread(&consistent, sizeof(char), 1, fpi);
233 (void)bytesRead;
234 bytesRead = fread(reserved, sizeof(char), 21, fpi);
235 (void)bytesRead;
236 bytesRead = fread(mcs_id, sizeof(char), 8, fpi);
237 (void)bytesRead;
238 mcs_id[8] = '\0';
239
240 sprintf(ts1, "%d", mcs_num + 1);
241 sprintf(ts2, "%hd", pass_length);
242 sprintf(ts3, "%ld", pass_count);
243 sprintf(ts4, "%ld", pass_count_preset);
244
245 if (!SDDS_InitializeOutput(&SDDS_dataset, ascii ? SDDS_ASCII : SDDS_BINARY, 1, "Turbo MCS data", "Turbo MCS data", output) ||
246 SDDS_DefineParameter(&SDDS_dataset, "MCSNumber", NULL, NULL, "MCS number", NULL, SDDS_SHORT, ts1) < 0 ||
247 SDDS_DefineParameter(&SDDS_dataset, "MCSID", NULL, NULL, "MCS ID", NULL, SDDS_STRING, mcs_id) < 0 ||
248 SDDS_DefineParameter(&SDDS_dataset, "PassLength", NULL, NULL, "Pass length", NULL, SDDS_SHORT, ts2) < 0 ||
249 SDDS_DefineParameter(&SDDS_dataset, "PassCount", NULL, NULL, "Pass count", NULL, SDDS_LONG, ts3) < 0 ||
250 SDDS_DefineParameter(&SDDS_dataset, "PassCountPreset", NULL, NULL, "Pass count preset", NULL, SDDS_LONG, ts4) < 0) {
251 SDDS_PrintErrors(stderr, SDDS_EXIT_PrintErrors | SDDS_VERBOSE_PrintErrors);
252 }
253
254 if (dwell_flag == 0) {
255 if (dwell_units == 0)
256 dwell *= 1e-6;
257 else if (dwell_units == 1)
258 dwell *= 1e-3;
259 else if (dwell_units == 3)
260 dwell *= 1e-9;
261 } else {
262 dwell = -1;
263 }
264
265 sprintf(ts1, "%15.8e", dwell);
266 sprintf(ts2, "%8s %8s", acq_time, acq_date);
267 if (SDDS_DefineParameter(&SDDS_dataset, "DwellTime", NULL, "s", "Dwell time", NULL, SDDS_DOUBLE, ts1) < 0 ||
268 SDDS_DefineParameter(&SDDS_dataset, "TriggerMode", NULL, NULL, "Trigger mode", NULL, SDDS_STRING, trigger ? "external" : "internal") < 0 ||
269 SDDS_DefineParameter(&SDDS_dataset, "AcquisitionMode", NULL, NULL, "Acquisition mode", NULL, SDDS_STRING, acq_mode ? "sum" : "replace") < 0 ||
270 SDDS_DefineParameter(&SDDS_dataset, "TimeStamp", NULL, NULL, "Time at which data collection started", NULL, SDDS_STRING, ts2) < 0) {
271 SDDS_PrintErrors(stderr, SDDS_EXIT_PrintErrors | SDDS_VERBOSE_PrintErrors);
272 }
273
274 sprintf(ts1, "%15.8e", cal_slope);
275 sprintf(ts2, "%15.8e", cal_zero);
276 if (cal_flag && (SDDS_DefineParameter(&SDDS_dataset, "CalibrationSlope", NULL, cal_units, "Spectrum calibration slope", NULL, SDDS_DOUBLE, ts1) < 0 ||
277 SDDS_DefineParameter(&SDDS_dataset, "CalibrationOffset", NULL, cal_units, "Spectrum calibration offset", NULL, SDDS_DOUBLE, ts2) < 0)) {
278 SDDS_PrintErrors(stderr, SDDS_EXIT_PrintErrors | SDDS_VERBOSE_PrintErrors);
279 }
280
281 if (detector_len) {
282 detector[(unsigned)detector_len] = '\0';
283 if (SDDS_DefineParameter(&SDDS_dataset, "HardwareDescription", NULL, NULL, "Hardware description", NULL, SDDS_STRING, detector) < 0) {
284 SDDS_PrintErrors(stderr, SDDS_EXIT_PrintErrors | SDDS_VERBOSE_PrintErrors);
285 }
286 }
287
288 if (sample_len) {
289 sample[(unsigned)sample_len] = '\0';
290 if (SDDS_DefineParameter(&SDDS_dataset, "DataDescription", NULL, NULL, "Data description", NULL, SDDS_STRING, sample) < 0 ||
291 SDDS_DefineParameter(&SDDS_dataset, "mplTitle", NULL, NULL, "MPL Title", NULL, SDDS_STRING, sample) < 0) {
292 SDDS_PrintErrors(stderr, SDDS_EXIT_PrintErrors | SDDS_VERBOSE_PrintErrors);
293 }
294 }
295
296 if (disc_sel == 0) {
297 sprintf(ts1, "%15.8e", sca_lld);
298 sprintf(ts2, "%15.8e", sca_uld);
299 if (SDDS_DefineParameter(&SDDS_dataset, "SCA-LLD", NULL, "V", "SCA Lower-Level Discriminator Setting", NULL, SDDS_DOUBLE, ts1) < 0 ||
300 SDDS_DefineParameter(&SDDS_dataset, "SCA-ULD", NULL, "V", "SCA Upper-Level Discriminator Setting", NULL, SDDS_DOUBLE, ts2) < 0) {
301 SDDS_PrintErrors(stderr, SDDS_EXIT_PrintErrors | SDDS_VERBOSE_PrintErrors);
302 }
303 } else {
304 sprintf(ts1, "%15.8e", disc);
305 if (SDDS_DefineParameter(&SDDS_dataset, "DiscrimLevel", NULL, "V", "Discriminator Level", NULL, SDDS_DOUBLE, ts1) < 0 ||
306 SDDS_DefineParameter(&SDDS_dataset, "DiscrimSlope", NULL, NULL, "Discriminator Slope", NULL, SDDS_STRING, disc_edge ? "+1" : "-1") < 0) {
307 SDDS_PrintErrors(stderr, SDDS_EXIT_PrintErrors | SDDS_VERBOSE_PrintErrors);
308 }
309 }
310
311 if (consistent == 0) {
312 if (SDDS_DefineParameter(&SDDS_dataset, "Inconsistent", NULL, NULL, "Flag indicating whether data and settings are inconsistent", NULL, SDDS_LONG, "1") < 0) {
313 SDDS_PrintErrors(stderr, SDDS_EXIT_PrintErrors | SDDS_VERBOSE_PrintErrors);
314 }
315 fprintf(stderr, "WARNING: Settings are not consistent with data\n");
316 }
317
318 if (SDDS_DefineColumn(&SDDS_dataset, "ChannelNumber", NULL, NULL, "Channel number", NULL, SDDS_LONG, 0) < 0 ||
319 SDDS_DefineColumn(&SDDS_dataset, "EventCount", NULL, NULL, "Number of events", NULL, SDDS_LONG, 0) < 0 ||
320 !SDDS_WriteLayout(&SDDS_dataset) || !SDDS_StartPage(&SDDS_dataset, (long)pass_length)) {
321 SDDS_PrintErrors(stderr, SDDS_EXIT_PrintErrors | SDDS_VERBOSE_PrintErrors);
322 }
323
324 /***************************************************************************/
325 /* Channel Data */
326 /* Output channel data from MCS file */
327 /***************************************************************************/
328 channel = tmalloc(sizeof(*channel) * pass_length);
329 count = tmalloc(sizeof(*count) * pass_length);
330 ucount = tmalloc(sizeof(*ucount) * pass_length);
331 if (fread(ucount, sizeof(*ucount), pass_length, fpi) != pass_length) {
332 SDDS_Bomb("Error: Unable to read channel data.");
333 }
334 for (i = 0; i < (long)pass_length; i++) {
335 swapulong(&ucount[i]);
336 count[i] = (long)ucount[i];
337 channel[i] = i;
338 }
339 if (!SDDS_SetColumn(&SDDS_dataset, SDDS_SET_BY_NAME, channel, (long)pass_length, "ChannelNumber") ||
340 !SDDS_SetColumn(&SDDS_dataset, SDDS_SET_BY_NAME, count, (long)pass_length, "EventCount") ||
341 !SDDS_WritePage(&SDDS_dataset) || !SDDS_Terminate(&SDDS_dataset)) {
342 SDDS_PrintErrors(stderr, SDDS_EXIT_PrintErrors | SDDS_VERBOSE_PrintErrors);
343 }
344
345 fclose(fpi);
346 return EXIT_SUCCESS;
347}
348
349void swapshort(short *data) {
350 unsigned char c1;
351 c1 = *((char *)data);
352 *((char *)data) = *(((char *)data) + 1);
353 *(((char *)data) + 1) = c1;
354}
355
356void swapushort(unsigned short *data) {
357 unsigned char c1;
358 c1 = *((char *)data);
359 *((char *)data) = *(((char *)data) + 1);
360 *(((char *)data) + 1) = c1;
361}
362
363void swaplong(long *data) {
364 long copy;
365 copy = *data;
366 *(((char *)data) + 0) = *(((char *)&copy) + 3);
367 *(((char *)data) + 1) = *(((char *)&copy) + 2);
368 *(((char *)data) + 2) = *(((char *)&copy) + 1);
369 *(((char *)data) + 3) = *(((char *)&copy) + 0);
370}
371
372void swapulong(unsigned long *data) {
373 unsigned long copy;
374 copy = *data;
375 *(((char *)data) + 0) = *(((char *)&copy) + 3);
376 *(((char *)data) + 1) = *(((char *)&copy) + 2);
377 *(((char *)data) + 2) = *(((char *)&copy) + 1);
378 *(((char *)data) + 3) = *(((char *)&copy) + 0);
379}
380
381void swapfloat(float *data) {
382 float copy;
383 copy = *data;
384 *(((char *)data) + 0) = *(((char *)&copy) + 3);
385 *(((char *)data) + 1) = *(((char *)&copy) + 2);
386 *(((char *)data) + 2) = *(((char *)&copy) + 1);
387 *(((char *)data) + 3) = *(((char *)&copy) + 0);
388}
SDDS (Self Describing Data Set) Data Types Definitions and Function Prototypes.
int32_t SDDS_StartPage(SDDS_DATASET *SDDS_dataset, int64_t expected_n_rows)
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_WritePage(SDDS_DATASET *SDDS_dataset)
Writes the current data table to the output file.
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_RegisterProgramName(const char *name)
Registers the executable program name for use in error messages.
Definition SDDS_utils.c:318
void SDDS_Bomb(char *message)
Terminates the program after printing an error message and recorded errors.
Definition SDDS_utils.c:380
#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_SHORT
Identifier for the signed short integer data type.
Definition SDDStypes.h:73
#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
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