RocketLogger 2.1.0
rl_file.c
Go to the documentation of this file.
1/*
2 * Copyright (c) 2016-2020, ETH Zurich, Computer Engineering Group
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * * Redistributions of source code must retain the above copyright notice, this
9 * list of conditions and the following disclaimer.
10 *
11 * * Redistributions in binary form must reproduce the above copyright notice,
12 * this list of conditions and the following disclaimer in the documentation
13 * and/or other materials provided with the distribution.
14 *
15 * * Neither the name of the copyright holder nor the names of its
16 * contributors may be used to endorse or promote products derived from
17 * this software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
23 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 */
31
32#include <errno.h>
33#include <stdint.h>
34#include <stdio.h>
35#include <stdlib.h>
36#include <string.h>
37
38#include <linux/limits.h>
39#include <time.h>
40
41#include "log.h"
42#include "pru.h"
43#include "rl.h"
44#include "rl_file.h"
45#include "sensor/sensor.h"
46#include "util.h"
47
48#include "rl_file.h"
49
50char *RL_UNIT_NAMES[] = {
51 "",
52 "V",
53 "A",
54 "",
55 "",
56 "lx",
57 "C",
58 "",
59 "%",
60 "P",
61 "s",
62};
63
71 rl_config_t const *const config);
72
80
85
86char *rl_unit_to_string(rl_unit_t const unit) {
87 if ((unsigned int)unit <
88 (sizeof(RL_UNIT_NAMES) / sizeof(RL_UNIT_NAMES[0]))) {
89 return RL_UNIT_NAMES[unit];
90 } else {
91 return NULL;
92 }
93}
94
95char *rl_file_get_ambient_file_name(char const *const data_file_name) {
96 static char ambient_file_name[PATH_MAX];
97
98 // determine new file name
99 strcpy(ambient_file_name, data_file_name);
100
101 // search for last . character
102 char target = '.';
103 char *file_ending = ambient_file_name;
104 while (strchr(file_ending, target) != NULL) {
105 file_ending = strchr(file_ending, target);
106 file_ending++; // Increment file_ending, otherwise we'll find target at
107 // the same location
108 }
109 file_ending--;
110
111 // add file ending
112 char ambient_file_ending[PATH_MAX] = RL_FILE_AMBIENT_SUFFIX;
113 strcat(ambient_file_ending, file_ending);
114 strcpy(file_ending, ambient_file_ending);
115
116 return ambient_file_name;
117}
118
120 rl_config_t const *const config) {
121
122 // number channels
123 uint16_t channel_count = count_channels(config->channel_enable);
124 // number binary channels
125 uint16_t channel_bin_count = 0;
126 if (config->digital_enable) {
127 channel_bin_count = RL_CHANNEL_DIGITAL_COUNT;
128 }
130 i1l_valid_channel = channel_bin_count++;
131 }
133 i2l_valid_channel = channel_bin_count++;
134 }
135
136 // comment length
137 uint32_t comment_length = RL_FILE_COMMENT_ALIGNMENT_BYTES;
138
139 // timestamps
140 rl_timestamp_t timestamp_realtime;
141 rl_timestamp_t timestamp_monotonic;
142 create_time_stamp(&timestamp_realtime, &timestamp_monotonic);
143
144 // lead_in setup
145 lead_in->file_magic = RL_FILE_MAGIC;
146 lead_in->file_version = RL_FILE_VERSION;
147 lead_in->header_length =
148 sizeof(rl_file_lead_in_t) + comment_length +
149 (channel_count + channel_bin_count) * sizeof(rl_file_channel_t);
150 lead_in->data_block_size = config->sample_rate / config->update_rate;
151 lead_in->data_block_count = 0; // needs to be updated
152 lead_in->sample_count = 0; // needs to be updated
153 lead_in->sample_rate = config->sample_rate;
154 get_mac_addr(lead_in->mac_address);
155 lead_in->start_time = timestamp_realtime;
156 lead_in->comment_length = comment_length;
157 lead_in->channel_bin_count = channel_bin_count;
158 lead_in->channel_count = channel_count;
159}
160
162 rl_config_t const *const config) {
163 // number channels
164 uint16_t channel_count = rl_status.sensor_count;
165
166 // number binary channels
167 uint16_t channel_bin_count = 0;
168
169 // comment length
170 uint32_t comment_length = RL_FILE_COMMENT_ALIGNMENT_BYTES;
171
172 // timestamps
173 rl_timestamp_t time_real;
174 rl_timestamp_t time_monotonic;
175 create_time_stamp(&time_real, &time_monotonic);
176
177 // lead_in setup
178 lead_in->file_magic = RL_FILE_MAGIC;
179 lead_in->file_version = RL_FILE_VERSION;
180 lead_in->header_length =
181 sizeof(rl_file_lead_in_t) + comment_length +
182 (channel_count + channel_bin_count) * sizeof(rl_file_channel_t);
184 lead_in->data_block_count = 0; // needs to be updated
185 lead_in->sample_count = 0; // needs to be updated
186 lead_in->sample_rate =
189 get_mac_addr(lead_in->mac_address);
190 lead_in->start_time = time_real;
191 lead_in->comment_length = comment_length;
192 lead_in->channel_bin_count = channel_bin_count;
193 lead_in->channel_count = channel_count;
194}
195
197 rl_config_t const *const config) {
198 if (config->file_comment == NULL) {
199 header->comment = "";
200 } else {
201 header->comment = config->file_comment;
202 }
203
204 rl_file_setup_data_channels(header, config);
205}
206
208 rl_config_t const *const config) {
209 if (config->file_comment == NULL) {
210 header->comment = "";
211 } else {
212 header->comment = config->file_comment;
213 }
214
216}
217
218void rl_file_store_header_bin(FILE *file_handle,
219 rl_file_header_t *const file_header) {
220
221 int total_channel_count = file_header->lead_in.channel_bin_count +
222 file_header->lead_in.channel_count;
223
224 // check if alignment bytes are needed after header comment
225 int comment_length = strlen(file_header->comment) + 1;
226 int comment_align_bytes = 0;
227 if (comment_length % RL_FILE_COMMENT_ALIGNMENT_BYTES > 0) {
228 comment_align_bytes =
230 (comment_length % RL_FILE_COMMENT_ALIGNMENT_BYTES);
231 }
232
233 file_header->lead_in.comment_length = comment_length + comment_align_bytes;
234
235 file_header->lead_in.header_length =
236 sizeof(rl_file_lead_in_t) + file_header->lead_in.comment_length +
237 total_channel_count * sizeof(rl_file_channel_t);
238
239 // write lead-in
240 fwrite(&(file_header->lead_in), sizeof(rl_file_lead_in_t), 1, file_handle);
241
242 // write comment, add zero bytes for proper header alignment if necessary
243 fwrite(file_header->comment, comment_length, 1, file_handle);
244 if (comment_align_bytes > 0) {
245 uint8_t zero_bytes[RL_FILE_COMMENT_ALIGNMENT_BYTES] = {0};
246 fwrite(zero_bytes, comment_align_bytes, 1, file_handle);
247 }
248
249 // write channel information
250 fwrite(file_header->channel, sizeof(rl_file_channel_t), total_channel_count,
251 file_handle);
252 fflush(file_handle);
253}
254
255void rl_file_store_header_csv(FILE *file_handle,
256 rl_file_header_t const *const file_header) {
257 // lead-in
258 fprintf(file_handle, "RocketLogger CSV File\n");
259 fprintf(file_handle, "File Version,%u\n",
260 (uint32_t)file_header->lead_in.file_version);
261 fprintf(file_handle, "Block Size,%u\n",
262 (uint32_t)file_header->lead_in.data_block_size);
263 fprintf(file_handle, "Block Count,%-20u\n",
264 (uint32_t)file_header->lead_in.data_block_count);
265 fprintf(file_handle, "Sample Count,%-20llu\n",
266 (uint64_t)file_header->lead_in.sample_count);
267 fprintf(file_handle, "Sample Rate,%u\n",
268 (uint32_t)file_header->lead_in.sample_rate);
269 fprintf(file_handle, "MAC Address,%02x",
270 (uint32_t)file_header->lead_in.mac_address[0]);
271
272 for (int i = 1; i < MAC_ADDRESS_LENGTH; i++) {
273 fprintf(file_handle, ":%02x",
274 (uint32_t)file_header->lead_in.mac_address[i]);
275 }
276 fprintf(file_handle, "\n");
277
278 time_t time = (time_t)file_header->lead_in.start_time.sec;
279 fprintf(file_handle, "Start Time,%s", ctime(&time));
280 fprintf(file_handle, "Comment,%s\n", file_header->comment);
281 fprintf(file_handle, "\n");
282
283 // channels
284 for (int i = 0; i < (file_header->lead_in.channel_count +
285 file_header->lead_in.channel_bin_count);
286 i++) {
287 fprintf(file_handle, ",%s", file_header->channel[i].name);
288 switch (file_header->channel[i].channel_scale) {
289 case RL_SCALE_MILLI:
290 fprintf(file_handle, " [m");
291 break;
292 case RL_SCALE_MICRO:
293 fprintf(file_handle, " [u");
294 break;
296 fprintf(file_handle, " [10n");
297 break;
298 case RL_SCALE_NANO:
299 fprintf(file_handle, " [n");
300 break;
302 fprintf(file_handle, " [10p");
303 break;
304 default:
305 break;
306 }
307 switch (file_header->channel[i].unit) {
308 case RL_UNIT_VOLT:
309 fprintf(file_handle, "V]");
310 break;
311 case RL_UNIT_AMPERE:
312 fprintf(file_handle, "A]");
313 break;
314 case RL_UNIT_SECOND:
315 fprintf(file_handle, "s]");
316 break;
317 default:
318 break;
319 }
320 }
321 fprintf(file_handle, "\n");
322 fflush(file_handle);
323}
324
325void rl_file_update_header_bin(FILE *file_handle,
326 rl_file_header_t const *const file_header) {
327
328 // seek to beginning and rewrite lead_in
329 rewind(file_handle);
330 fwrite(&(file_header->lead_in), sizeof(rl_file_lead_in_t), 1, file_handle);
331 fflush(file_handle);
332 fseek(file_handle, 0, SEEK_END);
333}
334
335void rl_file_update_header_csv(FILE *file_handle,
336 rl_file_header_t const *const file_header) {
337 rewind(file_handle);
338 fprintf(file_handle, "RocketLogger CSV File\n");
339 fprintf(file_handle, "File Version,%u\n",
340 (uint32_t)file_header->lead_in.file_version);
341 fprintf(file_handle, "Block Size,%u\n",
342 (uint32_t)file_header->lead_in.data_block_size);
343 fprintf(file_handle, "Block Count,%-20u\n",
344 (uint32_t)file_header->lead_in.data_block_count);
345 fprintf(file_handle, "Sample Count,%-20llu\n",
346 (uint64_t)file_header->lead_in.sample_count);
347 fflush(file_handle);
348 fseek(file_handle, 0, SEEK_END);
349}
350
351int rl_file_add_data_block(FILE *data_file, int32_t const *analog_buffer,
352 uint32_t const *digital_buffer, size_t buffer_size,
353 rl_timestamp_t const *const timestamp_realtime,
354 rl_timestamp_t const *const timestamp_monotonic,
355 rl_config_t const *const config) {
356 // aggregation buffer and configuration
357 int32_t aggregate_analog[RL_CHANNEL_COUNT] = {0};
358 int64_t aggregate_analog_sum[RL_CHANNEL_COUNT] = {0};
359 uint32_t aggregate_digital = ~((uint32_t)0);
360 size_t aggregate_count = RL_SAMPLE_RATE_MIN / config->sample_rate;
361
362 // skip if not storing to file, or invalid file structure
363 if (!config->file_enable) {
364 return 0;
365 }
366 if (data_file == NULL) {
367 rl_log(RL_LOG_ERROR, "invalid data file provided, skip append data");
368 errno = EINVAL;
369 return ERROR;
370 }
371 if (aggregate_count > buffer_size) {
372 rl_log(RL_LOG_ERROR, "cannot aggregate more data than the buffer size, "
373 "skip append data");
374 errno = EINVAL;
375 return ERROR;
376 }
377
378 // write buffer timestamp to file
379 if (config->file_format == RL_FILE_FORMAT_RLD) {
380 fwrite(timestamp_realtime, sizeof(rl_timestamp_t), 1, data_file);
381 fwrite(timestamp_monotonic, sizeof(rl_timestamp_t), 1, data_file);
382 } else if (config->file_format == RL_FILE_FORMAT_CSV) {
383 fprintf(data_file, "%lli.%09lli", timestamp_realtime->sec,
384 timestamp_realtime->nsec);
385 }
386
387 // process data buffers
388 for (size_t i = 0; i < buffer_size; i++) {
389 // point to sample buffer to store by default (updated for aggregates)
390 int32_t const *analog_data = analog_buffer + i * RL_CHANNEL_COUNT;
391 uint32_t const *digital_data = digital_buffer + i;
392
393 // handle aggregation when applicable
394 if (aggregate_count > 1) {
395 bool aggregate_store = false;
396
397 // reset aggregate buffer on window start
398 if (i % aggregate_count == 0) {
399 memset(aggregate_analog_sum, 0, sizeof(aggregate_analog_sum));
400 aggregate_digital = ~(0);
401 }
402
403 switch (config->aggregation_mode) {
405 // store first sample of aggregate window, skip storing others
406 if (i % aggregate_count == 0) {
407 // store data as in non-aggregate mode
408 aggregate_store = true;
409 }
410 break;
411
413 // accumulate data of the aggregate window, store when window complete
414 for (int j = 0; j < RL_CHANNEL_COUNT; j++) {
415 aggregate_analog_sum[j] += *(analog_data + j);
416 }
417 aggregate_digital = aggregate_digital & *digital_data;
418
419 // on last sample of the window: average analog data and store
420 if ((i + 1) % aggregate_count == 0) {
421 // calculate aggregated data block
422 for (int j = 0; j < RL_CHANNEL_COUNT; j++) {
423 aggregate_analog[j] =
424 aggregate_analog_sum[j] / aggregate_count;
425 }
426
427 // store aggregated data
428 analog_data = aggregate_analog;
429 digital_data = &aggregate_digital;
430 aggregate_store = true;
431 }
432 break;
433
434 default:
436 "unknown data aggregation mode, storing all samples.");
437 aggregate_store = true;
438 }
439
440 // skip storing data if no aggregates available
441 if (!aggregate_store) {
442 continue;
443 }
444 }
445
446 // write digital channels
447 if (config->file_format == RL_FILE_FORMAT_RLD) {
448 size_t index = 0;
449 uint32_t data = 0x00;
450
451 // build binary bit field to store
452 if (config->digital_enable) {
453 data |= ((*digital_data & PRU_DIGITAL_INPUT_MASK) << index);
455 }
457 if (*digital_data & PRU_DIGITAL_I1L_VALID_MASK) {
458 data |= (1 << index);
459 }
460 index++;
461 }
463 if (*digital_data & PRU_DIGITAL_I2L_VALID_MASK) {
464 data |= (1 << index);
465 }
466 index++;
467 }
468
469 // write digital data to file if any channel available
470 if (index > 0) {
471 fwrite(&data, sizeof(data), 1, data_file);
472 }
473 } else if (config->file_format == RL_FILE_FORMAT_CSV) {
474 if (config->digital_enable) {
475 uint32_t binary_mask = PRU_DIGITAL_INPUT1_MASK;
476 for (int j = 0; j < RL_CHANNEL_DIGITAL_COUNT; j++) {
477 fprintf(data_file, (RL_FILE_CSV_DELIMITER "%i"),
478 (*digital_data & binary_mask) > 0);
479 binary_mask = binary_mask << 1;
480 }
481 }
483 fprintf(data_file, (RL_FILE_CSV_DELIMITER "%i"),
484 (*digital_data & PRU_DIGITAL_I1L_VALID_MASK) > 0);
485 }
487 fprintf(data_file, (RL_FILE_CSV_DELIMITER "%i"),
488 (*digital_data & PRU_DIGITAL_I2L_VALID_MASK) > 0);
489 }
490 }
491
492 // write analog channels
493 for (int j = 0; j < RL_CHANNEL_COUNT; j++) {
494 // skip disabled channels
495 if (!config->channel_enable[j]) {
496 continue;
497 }
498 // write analog data to file
499 if (config->file_format == RL_FILE_FORMAT_RLD) {
500 fwrite(&analog_data[j], sizeof(int32_t), 1, data_file);
501 } else if (config->file_format == RL_FILE_FORMAT_CSV) {
502 fprintf(data_file, (RL_FILE_CSV_DELIMITER "%d"),
503 analog_data[j]);
504 }
505 }
506
507 // end of data row
508 if (config->file_format == RL_FILE_FORMAT_CSV) {
509 fprintf(data_file, "\n");
510 }
511 }
512
513 // flush processed data if data is stored
514 if (config->file_enable && data_file != NULL) {
515 fflush(data_file);
516 }
517
518 return 1;
519}
520
521int rl_file_add_ambient_block(FILE *ambient_file, int32_t const *ambient_buffer,
522 size_t buffer_size,
523 rl_timestamp_t const *const timestamp_realtime,
524 rl_timestamp_t const *const timestamp_monotonic,
525 rl_config_t const *const config) {
526 // suppress unused parameter warning
527 (void)config;
528
529 // store timestamps
530 fwrite(timestamp_realtime, sizeof(rl_timestamp_t), 1, ambient_file);
531 fwrite(timestamp_monotonic, sizeof(rl_timestamp_t), 1, ambient_file);
532
533 // store sensor data
534 fwrite(ambient_buffer, sizeof(int32_t), buffer_size, ambient_file);
535
536 return 1;
537}
538
540 rl_config_t const *const config) {
541 int total_channel_count = file_header->lead_in.channel_bin_count +
542 file_header->lead_in.channel_count;
543
544 // reset channels
545 memset(file_header->channel, 0,
546 total_channel_count * sizeof(rl_file_channel_t));
547
548 // overall channel index
549 int ch = 0;
550
551 // digital channels
552 if (config->digital_enable) {
553 for (int i = 0; i < RL_CHANNEL_DIGITAL_COUNT; i++) {
554 file_header->channel[ch].unit = RL_UNIT_BINARY;
555 file_header->channel[ch].channel_scale = RL_SCALE_UNIT;
556 file_header->channel[ch].data_size = 0;
557 file_header->channel[ch].valid_data_channel =
559 strcpy(file_header->channel[ch].name, RL_CHANNEL_DIGITAL_NAMES[i]);
560 ch++;
561 }
562 }
563
564 // range valid channels
566 file_header->channel[ch].unit = RL_UNIT_RANGE_VALID;
567 file_header->channel[ch].channel_scale = RL_SCALE_UNIT;
568 file_header->channel[ch].data_size = 0;
570 strcpy(file_header->channel[ch].name, RL_CHANNEL_VALID_NAMES[0]);
571 ch++;
572 }
574 file_header->channel[ch].unit = RL_UNIT_RANGE_VALID;
575 file_header->channel[ch].channel_scale = RL_SCALE_UNIT;
576 file_header->channel[ch].data_size = 0;
578 strcpy(file_header->channel[ch].name, RL_CHANNEL_VALID_NAMES[1]);
579 ch++;
580 }
581
582 // analog channels
583 for (int i = 0; i < RL_CHANNEL_COUNT; i++) {
584 if (config->channel_enable[i]) {
585 if (is_current(i)) {
586 if (is_low_current(i)) {
587 file_header->channel[ch].channel_scale = RL_SCALE_TEN_PICO;
588 if (i == RL_CONFIG_CHANNEL_I1L) {
589 file_header->channel[ch].valid_data_channel =
591 } else {
592 file_header->channel[ch].valid_data_channel =
594 }
595 } else {
596 file_header->channel[ch].channel_scale = RL_SCALE_NANO;
597 file_header->channel[ch].valid_data_channel =
599 }
600 file_header->channel[ch].unit = RL_UNIT_AMPERE;
601 } else if (is_voltage(i)) {
602 file_header->channel[ch].unit = RL_UNIT_VOLT;
603 file_header->channel[ch].channel_scale = RL_SCALE_TEN_NANO;
604 file_header->channel[ch].valid_data_channel =
606 } else {
607 file_header->channel[ch].unit = RL_UNIT_SECOND;
608 file_header->channel[ch].channel_scale = RL_SCALE_NANO;
609 file_header->channel[ch].valid_data_channel =
611 }
612 // if calibration measurement, set unit to undefined
613 if (config->calibration_ignore) {
614 file_header->channel[ch].unit = RL_UNIT_UNDEFINED;
615 file_header->channel[ch].channel_scale = RL_SCALE_UNIT;
616 }
617 file_header->channel[ch].data_size = 4;
618 strncpy(file_header->channel[ch].name, RL_CHANNEL_NAMES[i],
620 ch++;
621 }
622 }
623}
624
626 int total_channel_count =
628
629 // reset channels
630 memset(header->channel, 0, total_channel_count * sizeof(rl_file_channel_t));
631
632 // write channels
633 int ch = 0;
634 for (int i = 0; i < SENSOR_REGISTRY_SIZE; i++) {
636 header->channel[ch].unit = SENSOR_REGISTRY[i].unit;
639 header->channel[ch].data_size = 4;
640 strcpy(header->channel[ch].name, SENSOR_REGISTRY[i].name);
641 ch++;
642 }
643 }
644}
rl_calibration_t data
The actual calibration data.
Definition: calibration.h:9
int rl_log(rl_log_level_t log_level, char const *const format,...)
Definition: log.c:82
@ RL_LOG_ERROR
Error.
Definition: log.h:49
@ RL_LOG_WARNING
Warning.
Definition: log.h:50
#define PRU_DIGITAL_INPUT1_MASK
Definition: pru.h:54
#define PRU_DIGITAL_I1L_VALID_MASK
Definition: pru.h:60
#define PRU_DIGITAL_I2L_VALID_MASK
Definition: pru.h:61
#define PRU_DIGITAL_INPUT_MASK
Definition: pru.h:53
char const *const RL_CHANNEL_NAMES[RL_CHANNEL_COUNT]
RocketLogger channel names.
Definition: rl.c:95
char const *const RL_CHANNEL_VALID_NAMES[RL_CHANNEL_SWITCHED_COUNT]
RocketLogger valid channel names.
Definition: rl.c:107
char const *const RL_CHANNEL_DIGITAL_NAMES[RL_CHANNEL_DIGITAL_COUNT]
RocketLogger digital channel names.
Definition: rl.c:103
#define RL_CONFIG_CHANNEL_I2L
Definition: rl.h:89
@ RL_FILE_FORMAT_RLD
CSV format.
Definition: rl.h:143
@ RL_FILE_FORMAT_CSV
Definition: rl.h:142
#define RL_SENSOR_SAMPLE_RATE
Ambient sensor read out rate in samples per second.
Definition: rl.h:66
#define RL_SAMPLE_RATE_MIN
Minimum native sample rate of the ADC in samples per second.
Definition: rl.h:62
#define ERROR
Function return value for errors (use errno to indicate the error)
Definition: rl.h:46
#define RL_CHANNEL_DIGITAL_COUNT
Number of RocketLogger digital channels.
Definition: rl.h:60
#define RL_CONFIG_CHANNEL_I1L
Definition: rl.h:87
#define RL_CHANNEL_COUNT
Number of RocketLogger analog channels.
Definition: rl.h:56
@ RL_AGGREGATION_MODE_AVERAGE
Aggregate using down sampling.
Definition: rl.h:130
@ RL_AGGREGATION_MODE_DOWNSAMPLE
Definition: rl.h:129
void rl_file_store_header_bin(FILE *file_handle, rl_file_header_t *const file_header)
Definition: rl_file.c:218
int i1l_valid_channel
Global variable to determine i1l valid channel index.
Definition: rl_file.c:82
void rl_file_update_header_bin(FILE *file_handle, rl_file_header_t const *const file_header)
Definition: rl_file.c:325
int i2l_valid_channel
Global variable to determine i2l valid channel index.
Definition: rl_file.c:84
int rl_file_add_data_block(FILE *data_file, int32_t const *analog_buffer, uint32_t const *digital_buffer, size_t buffer_size, rl_timestamp_t const *const timestamp_realtime, rl_timestamp_t const *const timestamp_monotonic, rl_config_t const *const config)
Definition: rl_file.c:351
char * RL_UNIT_NAMES[]
Definition: rl_file.c:50
void rl_file_store_header_csv(FILE *file_handle, rl_file_header_t const *const file_header)
Definition: rl_file.c:255
void rl_file_setup_data_channels(rl_file_header_t *const header, rl_config_t const *const config)
Definition: rl_file.c:539
void rl_file_setup_ambient_lead_in(rl_file_lead_in_t *const lead_in, rl_config_t const *const config)
Definition: rl_file.c:161
void rl_file_setup_ambient_header(rl_file_header_t *const header, rl_config_t const *const config)
Definition: rl_file.c:207
void rl_file_update_header_csv(FILE *file_handle, rl_file_header_t const *const file_header)
Definition: rl_file.c:335
int rl_file_add_ambient_block(FILE *ambient_file, int32_t const *ambient_buffer, size_t buffer_size, rl_timestamp_t const *const timestamp_realtime, rl_timestamp_t const *const timestamp_monotonic, rl_config_t const *const config)
Definition: rl_file.c:521
char * rl_file_get_ambient_file_name(char const *const data_file_name)
Definition: rl_file.c:95
void rl_file_setup_data_header(rl_file_header_t *const header, rl_config_t const *const config)
Definition: rl_file.c:196
void rl_file_setup_ambient_channels(rl_file_header_t *const header)
Definition: rl_file.c:625
char * rl_unit_to_string(rl_unit_t const unit)
Definition: rl_file.c:86
void rl_file_setup_data_lead_in(rl_file_lead_in_t *const lead_in, rl_config_t const *const config)
Definition: rl_file.c:119
@ RL_UNIT_VOLT
Voltage (electric)
Definition: rl_file.h:86
@ RL_UNIT_UNDEFINED
Undefined unit.
Definition: rl_file.h:96
@ RL_UNIT_AMPERE
Current (electric)
Definition: rl_file.h:87
@ RL_UNIT_BINARY
Binary signal.
Definition: rl_file.h:88
@ RL_UNIT_RANGE_VALID
Range valid information.
Definition: rl_file.h:89
@ RL_UNIT_SECOND
Second (time delta)
Definition: rl_file.h:95
enum rl_unit rl_unit_t
Definition: rl_file.h:102
#define RL_FILE_COMMENT_ALIGNMENT_BYTES
Comment alignment in bytes.
Definition: rl_file.h:55
#define RL_SCALE_MICRO
Definition: rl_file.h:73
#define RL_SCALE_TEN_NANO
Definition: rl_file.h:72
#define RL_FILE_VERSION
File format version of current implementation.
Definition: rl_file.h:46
#define RL_SCALE_NANO
Definition: rl_file.h:71
#define RL_SCALE_MILLI
Definition: rl_file.h:74
#define RL_SCALE_TEN_PICO
Definition: rl_file.h:70
#define RL_SCALE_UNIT
Definition: rl_file.h:75
#define RL_FILE_AMBIENT_DATA_BLOCK_SIZE
Ambient sensor data file block size in measurements.
Definition: rl_file.h:64
struct rl_file_lead_in rl_file_lead_in_t
Definition: rl_file.h:137
#define RL_FILE_CHANNEL_NAME_LENGTH
Maximum channel description length.
Definition: rl_file.h:49
#define RL_FILE_AMBIENT_SUFFIX
Ambient sensor data file name suffix.
Definition: rl_file.h:61
#define RL_FILE_MAGIC
File header magic number (ascii RLD)
Definition: rl_file.h:43
#define RL_FILE_CHANNEL_NO_LINK
No additional range valid information available.
Definition: rl_file.h:52
#define RL_FILE_CSV_DELIMITER
CSV value delimiter character.
Definition: rl_file.h:58
struct rl_file_channel rl_file_channel_t
Definition: rl_file.h:158
const rl_sensor_t SENSOR_REGISTRY[SENSOR_REGISTRY_SIZE]
Definition: sensor.c:63
#define SENSOR_REGISTRY_SIZE
Number of sensor registered.
Definition: sensor.h:47
Definition: rl.h:154
char const * file_comment
File comment.
Definition: rl.h:190
rl_aggregation_mode_t aggregation_mode
Sample aggregation mode (for sampling rates below lowest native one)
Definition: rl.h:172
rl_file_format_t file_format
File format.
Definition: rl.h:186
uint32_t sample_rate
Sampling rate.
Definition: rl.h:164
bool channel_enable[RL_CHANNEL_COUNT]
Channels to sample.
Definition: rl.h:168
uint32_t update_rate
Data update rate.
Definition: rl.h:166
bool file_enable
Enable storing measurements to file.
Definition: rl.h:182
bool digital_enable
Enable digital inputs.
Definition: rl.h:174
bool calibration_ignore
Perform calibration measurement (ignore existing calibration)
Definition: rl.h:178
char name[RL_FILE_CHANNEL_NAME_LENGTH]
Channel name/description.
Definition: rl_file.h:152
uint16_t data_size
Datum size in bytes (for voltage and current)
Definition: rl_file.h:148
rl_unit_t unit
Channel unit.
Definition: rl_file.h:144
int32_t channel_scale
Channel scale (in power of ten, for voltage and current)
Definition: rl_file.h:146
uint16_t valid_data_channel
Link to channel valid data (for low-range current channels)
Definition: rl_file.h:150
rl_file_channel_t * channel
Channels definitions (binary and normal)
Definition: rl_file.h:169
rl_file_lead_in_t lead_in
File header lead in (constant size)
Definition: rl_file.h:165
char const * comment
Comment field.
Definition: rl_file.h:167
uint32_t comment_length
Comment length.
Definition: rl_file.h:127
uint16_t sample_rate
Sampling rate of the measurement.
Definition: rl_file.h:121
uint16_t file_version
File version number.
Definition: rl_file.h:111
rl_timestamp_t start_time
Start time of the measurement in UNIX time, UTC.
Definition: rl_file.h:125
uint64_t sample_count
Total sample count.
Definition: rl_file.h:119
uint8_t mac_address[MAC_ADDRESS_LENGTH]
Instrument ID (mac address)
Definition: rl_file.h:123
uint16_t channel_count
Analog channel count.
Definition: rl_file.h:131
uint32_t data_block_count
Number of data blocks stored in the file.
Definition: rl_file.h:117
uint32_t data_block_size
Size of the data blocks in the file in rows.
Definition: rl_file.h:115
uint16_t header_length
Total size of the header in bytes.
Definition: rl_file.h:113
uint32_t file_magic
File magic constant.
Definition: rl_file.h:109
uint16_t channel_bin_count
Binary channel count.
Definition: rl_file.h:129
int32_t scale
Definition: sensor.h:59
rl_unit_t unit
Definition: sensor.h:58
char name[SENSOR_NAME_LENGTH]
Definition: sensor.h:55
Definition: rl.h:201
uint16_t sensor_count
Number of sensors found connected to the system.
Definition: rl.h:221
bool sensor_available[RL_SENSOR_COUNT_MAX]
Identifiers of sensors found.
Definition: rl.h:223
int64_t nsec
Nanoseconds.
Definition: util.h:53
int64_t sec
Seconds in UNIX time (UTC)
Definition: util.h:51
bool is_current(int index)
Definition: util.c:49
int count_channels(bool const channels[RL_CHANNEL_COUNT])
Definition: util.c:72
void create_time_stamp(rl_timestamp_t *const timestamp_realtime, rl_timestamp_t *const timestamp_monotonic)
Definition: util.c:90
void get_mac_addr(uint8_t mac_address[MAC_ADDRESS_LENGTH])
Definition: util.c:112
bool is_low_current(int index)
Definition: util.c:57
bool is_voltage(int index)
Definition: util.c:64
#define MAC_ADDRESS_LENGTH
MAC address length in bytes.
Definition: util.h:41