RocketLogger 2.1.2
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
79
84
85char *rl_unit_to_string(rl_unit_t const unit) {
86 if ((unsigned int)unit <
87 (sizeof(RL_UNIT_NAMES) / sizeof(RL_UNIT_NAMES[0]))) {
88 return RL_UNIT_NAMES[unit];
89 } else {
90 return NULL;
91 }
92}
93
94char *rl_file_get_ambient_file_name(char const *const data_file_name) {
95 static char ambient_file_name[PATH_MAX];
96
97 // determine new file name
98 strcpy(ambient_file_name, data_file_name);
99
100 // search for last . character
101 char target = '.';
102 char *file_ending = ambient_file_name;
103 while (strchr(file_ending, target) != NULL) {
104 file_ending = strchr(file_ending, target);
105 file_ending++; // Increment file_ending, otherwise we'll find target at
106 // the same location
107 }
108 file_ending--;
109
110 // add file ending
111 char ambient_file_ending[PATH_MAX] = RL_FILE_AMBIENT_SUFFIX;
112 strcat(ambient_file_ending, file_ending);
113 strcpy(file_ending, ambient_file_ending);
114
115 return ambient_file_name;
116}
117
119 rl_config_t const *const config) {
120
121 // number channels
122 uint16_t channel_count = count_channels(config->channel_enable);
123 // number binary channels
124 uint16_t channel_bin_count = 0;
125 if (config->digital_enable) {
126 channel_bin_count = RL_CHANNEL_DIGITAL_COUNT;
127 }
129 i1l_valid_channel = channel_bin_count++;
130 }
132 i2l_valid_channel = channel_bin_count++;
133 }
134
135 // comment length
136 uint32_t comment_length = RL_FILE_COMMENT_ALIGNMENT_BYTES;
137
138 // timestamps
139 rl_timestamp_t timestamp_realtime;
140 rl_timestamp_t timestamp_monotonic;
141 create_time_stamp(&timestamp_realtime, &timestamp_monotonic);
142
143 // lead_in setup
144 lead_in->file_magic = RL_FILE_MAGIC;
145 lead_in->file_version = RL_FILE_VERSION;
146 lead_in->header_length =
147 sizeof(rl_file_lead_in_t) + comment_length +
148 (channel_count + channel_bin_count) * sizeof(rl_file_channel_t);
149 lead_in->data_block_size = config->sample_rate / config->update_rate;
150 lead_in->data_block_count = 0; // needs to be updated
151 lead_in->sample_count = 0; // needs to be updated
152 lead_in->sample_rate = config->sample_rate;
153 get_mac_addr(lead_in->mac_address);
154 lead_in->start_time = timestamp_realtime;
155 lead_in->comment_length = comment_length;
156 lead_in->channel_bin_count = channel_bin_count;
157 lead_in->channel_count = channel_count;
158}
159
161 rl_config_t const *const config) {
162 // number channels
163 uint16_t channel_count = rl_status.sensor_count;
164
165 // number binary channels
166 uint16_t channel_bin_count = 0;
167
168 // comment length
169 uint32_t comment_length = RL_FILE_COMMENT_ALIGNMENT_BYTES;
170
171 // timestamps
172 rl_timestamp_t time_real;
173 rl_timestamp_t time_monotonic;
174 create_time_stamp(&time_real, &time_monotonic);
175
176 // lead_in setup
177 lead_in->file_magic = RL_FILE_MAGIC;
178 lead_in->file_version = RL_FILE_VERSION;
179 lead_in->header_length =
180 sizeof(rl_file_lead_in_t) + comment_length +
181 (channel_count + channel_bin_count) * sizeof(rl_file_channel_t);
183 lead_in->data_block_count = 0; // needs to be updated
184 lead_in->sample_count = 0; // needs to be updated
185 lead_in->sample_rate =
188 get_mac_addr(lead_in->mac_address);
189 lead_in->start_time = time_real;
190 lead_in->comment_length = comment_length;
191 lead_in->channel_bin_count = channel_bin_count;
192 lead_in->channel_count = channel_count;
193}
194
196 rl_config_t const *const config) {
197 if (config->file_comment == NULL) {
198 header->comment = "";
199 } else {
200 header->comment = config->file_comment;
201 }
202
203 rl_file_setup_data_channels(header, config);
204}
205
207 rl_config_t const *const config) {
208 if (config->file_comment == NULL) {
209 header->comment = "";
210 } else {
211 header->comment = config->file_comment;
212 }
213
215}
216
217void rl_file_store_header_bin(FILE *file_handle,
218 rl_file_header_t *const file_header) {
219
220 int total_channel_count = file_header->lead_in.channel_bin_count +
221 file_header->lead_in.channel_count;
222
223 // check if alignment bytes are needed after header comment
224 int comment_length = strlen(file_header->comment) + 1;
225 int comment_align_bytes = 0;
226 if (comment_length % RL_FILE_COMMENT_ALIGNMENT_BYTES > 0) {
227 comment_align_bytes =
229 (comment_length % RL_FILE_COMMENT_ALIGNMENT_BYTES);
230 }
231
232 file_header->lead_in.comment_length = comment_length + comment_align_bytes;
233
234 file_header->lead_in.header_length =
235 sizeof(rl_file_lead_in_t) + file_header->lead_in.comment_length +
236 total_channel_count * sizeof(rl_file_channel_t);
237
238 // write lead-in
239 fwrite(&(file_header->lead_in), sizeof(rl_file_lead_in_t), 1, file_handle);
240
241 // write comment, add zero bytes for proper header alignment if necessary
242 fwrite(file_header->comment, comment_length, 1, file_handle);
243 if (comment_align_bytes > 0) {
244 uint8_t zero_bytes[RL_FILE_COMMENT_ALIGNMENT_BYTES] = {0};
245 fwrite(zero_bytes, comment_align_bytes, 1, file_handle);
246 }
247
248 // write channel information
249 fwrite(file_header->channel, sizeof(rl_file_channel_t), total_channel_count,
250 file_handle);
251 fflush(file_handle);
252}
253
254void rl_file_store_header_csv(FILE *file_handle,
255 rl_file_header_t const *const file_header) {
256 // lead-in
257 fprintf(file_handle, "RocketLogger CSV File\n");
258 fprintf(file_handle, "File Version,%u\n",
259 (uint32_t)file_header->lead_in.file_version);
260 fprintf(file_handle, "Block Size,%u\n",
261 (uint32_t)file_header->lead_in.data_block_size);
262 fprintf(file_handle, "Block Count,%-20u\n",
263 (uint32_t)file_header->lead_in.data_block_count);
264 fprintf(file_handle, "Sample Count,%-20llu\n",
265 (uint64_t)file_header->lead_in.sample_count);
266 fprintf(file_handle, "Sample Rate,%u\n",
267 (uint32_t)file_header->lead_in.sample_rate);
268 fprintf(file_handle, "MAC Address,%02x",
269 (uint32_t)file_header->lead_in.mac_address[0]);
270
271 for (int i = 1; i < MAC_ADDRESS_LENGTH; i++) {
272 fprintf(file_handle, ":%02x",
273 (uint32_t)file_header->lead_in.mac_address[i]);
274 }
275 fprintf(file_handle, "\n");
276
277 time_t time = (time_t)file_header->lead_in.start_time.sec;
278 fprintf(file_handle, "Start Time,%s", ctime(&time));
279 fprintf(file_handle, "Comment,%s\n", file_header->comment);
280 fprintf(file_handle, "\n");
281
282 // channels
283 for (int i = 0; i < (file_header->lead_in.channel_count +
284 file_header->lead_in.channel_bin_count);
285 i++) {
286 fprintf(file_handle, ",%s", file_header->channel[i].name);
287 switch (file_header->channel[i].channel_scale) {
288 case RL_SCALE_MILLI:
289 fprintf(file_handle, " [m");
290 break;
291 case RL_SCALE_MICRO:
292 fprintf(file_handle, " [u");
293 break;
295 fprintf(file_handle, " [10n");
296 break;
297 case RL_SCALE_NANO:
298 fprintf(file_handle, " [n");
299 break;
301 fprintf(file_handle, " [10p");
302 break;
303 default:
304 break;
305 }
306 switch (file_header->channel[i].unit) {
307 case RL_UNIT_VOLT:
308 fprintf(file_handle, "V]");
309 break;
310 case RL_UNIT_AMPERE:
311 fprintf(file_handle, "A]");
312 break;
313 case RL_UNIT_SECOND:
314 fprintf(file_handle, "s]");
315 break;
316 default:
317 break;
318 }
319 }
320 fprintf(file_handle, "\n");
321 fflush(file_handle);
322}
323
324void rl_file_update_header_bin(FILE *file_handle,
325 rl_file_header_t const *const file_header) {
326
327 // seek to beginning and rewrite lead_in
328 rewind(file_handle);
329 fwrite(&(file_header->lead_in), sizeof(rl_file_lead_in_t), 1, file_handle);
330 fflush(file_handle);
331 fseek(file_handle, 0, SEEK_END);
332}
333
334void rl_file_update_header_csv(FILE *file_handle,
335 rl_file_header_t const *const file_header) {
336 rewind(file_handle);
337 fprintf(file_handle, "RocketLogger CSV File\n");
338 fprintf(file_handle, "File Version,%u\n",
339 (uint32_t)file_header->lead_in.file_version);
340 fprintf(file_handle, "Block Size,%u\n",
341 (uint32_t)file_header->lead_in.data_block_size);
342 fprintf(file_handle, "Block Count,%-20u\n",
343 (uint32_t)file_header->lead_in.data_block_count);
344 fprintf(file_handle, "Sample Count,%-20llu\n",
345 (uint64_t)file_header->lead_in.sample_count);
346 fflush(file_handle);
347 fseek(file_handle, 0, SEEK_END);
348}
349
350int rl_file_add_data_block(FILE *data_file, int32_t const *analog_buffer,
351 uint32_t const *digital_buffer, size_t buffer_size,
352 rl_timestamp_t const *const timestamp_realtime,
353 rl_timestamp_t const *const timestamp_monotonic,
354 rl_config_t const *const config) {
355 // aggregation buffer and configuration
356 int32_t aggregate_analog[RL_CHANNEL_COUNT] = {0};
357 int64_t aggregate_analog_sum[RL_CHANNEL_COUNT] = {0};
358 uint32_t aggregate_digital = ~((uint32_t)0);
359 size_t aggregate_count = RL_SAMPLE_RATE_MIN / config->sample_rate;
360
361 // skip if not storing to file, or invalid file structure
362 if (!config->file_enable) {
363 return 0;
364 }
365 if (data_file == NULL) {
366 rl_log(RL_LOG_ERROR, "invalid data file provided, skip append data");
367 errno = EINVAL;
368 return ERROR;
369 }
370 if (aggregate_count > buffer_size) {
371 rl_log(RL_LOG_ERROR, "cannot aggregate more data than the buffer size, "
372 "skip append data");
373 errno = EINVAL;
374 return ERROR;
375 }
376
377 // write buffer timestamp to file
378 if (config->file_format == RL_FILE_FORMAT_RLD) {
379 fwrite(timestamp_realtime, sizeof(rl_timestamp_t), 1, data_file);
380 fwrite(timestamp_monotonic, sizeof(rl_timestamp_t), 1, data_file);
381 } else if (config->file_format == RL_FILE_FORMAT_CSV) {
382 fprintf(data_file, "%lli.%09lli", timestamp_realtime->sec,
383 timestamp_realtime->nsec);
384 }
385
386 // process data buffers
387 for (size_t i = 0; i < buffer_size; i++) {
388 // point to sample buffer to store by default (updated for aggregates)
389 int32_t const *analog_data = analog_buffer + i * RL_CHANNEL_COUNT;
390 uint32_t const *digital_data = digital_buffer + i;
391
392 // handle aggregation when applicable
393 if (aggregate_count > 1) {
394 bool aggregate_store = false;
395
396 // reset aggregate buffer on window start
397 if (i % aggregate_count == 0) {
398 memset(aggregate_analog_sum, 0, sizeof(aggregate_analog_sum));
399 aggregate_digital = ~(0);
400 }
401
402 switch (config->aggregation_mode) {
404 // store first sample of aggregate window, skip storing others
405 if (i % aggregate_count == 0) {
406 // store data as in non-aggregate mode
407 aggregate_store = true;
408 }
409 break;
410
412 // accumulate data of the aggregate window, store when window complete
413 for (int j = 0; j < RL_CHANNEL_COUNT; j++) {
414 aggregate_analog_sum[j] += *(analog_data + j);
415 }
416 aggregate_digital = aggregate_digital & *digital_data;
417
418 // on last sample of the window: average analog data and store
419 if ((i + 1) % aggregate_count == 0) {
420 // calculate aggregated data block
421 for (int j = 0; j < RL_CHANNEL_COUNT; j++) {
422 aggregate_analog[j] =
423 aggregate_analog_sum[j] / aggregate_count;
424 }
425
426 // store aggregated data
427 analog_data = aggregate_analog;
428 digital_data = &aggregate_digital;
429 aggregate_store = true;
430 }
431 break;
432
433 default:
435 "unknown data aggregation mode, storing all samples.");
436 aggregate_store = true;
437 }
438
439 // skip storing data if no aggregates available
440 if (!aggregate_store) {
441 continue;
442 }
443 }
444
445 // write digital channels
446 if (config->file_format == RL_FILE_FORMAT_RLD) {
447 size_t index = 0;
448 uint32_t data = 0x00;
449
450 // build binary bit field to store
451 if (config->digital_enable) {
452 data |= ((*digital_data & PRU_DIGITAL_INPUT_MASK) << index);
454 }
456 if (*digital_data & PRU_DIGITAL_I1L_VALID_MASK) {
457 data |= (1 << index);
458 }
459 index++;
460 }
462 if (*digital_data & PRU_DIGITAL_I2L_VALID_MASK) {
463 data |= (1 << index);
464 }
465 index++;
466 }
467
468 // write digital data to file if any channel available
469 if (index > 0) {
470 fwrite(&data, sizeof(data), 1, data_file);
471 }
472 } else if (config->file_format == RL_FILE_FORMAT_CSV) {
473 if (config->digital_enable) {
474 uint32_t binary_mask = PRU_DIGITAL_INPUT1_MASK;
475 for (int j = 0; j < RL_CHANNEL_DIGITAL_COUNT; j++) {
476 fprintf(data_file, (RL_FILE_CSV_DELIMITER "%i"),
477 (*digital_data & binary_mask) > 0);
478 binary_mask = binary_mask << 1;
479 }
480 }
482 fprintf(data_file, (RL_FILE_CSV_DELIMITER "%i"),
483 (*digital_data & PRU_DIGITAL_I1L_VALID_MASK) > 0);
484 }
486 fprintf(data_file, (RL_FILE_CSV_DELIMITER "%i"),
487 (*digital_data & PRU_DIGITAL_I2L_VALID_MASK) > 0);
488 }
489 }
490
491 // write analog channels
492 for (int j = 0; j < RL_CHANNEL_COUNT; j++) {
493 // skip disabled channels
494 if (!config->channel_enable[j]) {
495 continue;
496 }
497 // write analog data to file
498 if (config->file_format == RL_FILE_FORMAT_RLD) {
499 fwrite(&analog_data[j], sizeof(int32_t), 1, data_file);
500 } else if (config->file_format == RL_FILE_FORMAT_CSV) {
501 fprintf(data_file, (RL_FILE_CSV_DELIMITER "%d"),
502 analog_data[j]);
503 }
504 }
505
506 // end of data row
507 if (config->file_format == RL_FILE_FORMAT_CSV) {
508 fprintf(data_file, "\n");
509 }
510 }
511
512 // flush processed data if data is stored
513 if (config->file_enable && data_file != NULL) {
514 fflush(data_file);
515 }
516
517 return 1;
518}
519
520int rl_file_add_ambient_block(FILE *ambient_file, int32_t const *ambient_buffer,
521 size_t buffer_size,
522 rl_timestamp_t const *const timestamp_realtime,
523 rl_timestamp_t const *const timestamp_monotonic,
524 rl_config_t const *const config) {
525 // suppress unused parameter warning
526 (void)config;
527
528 // store timestamps
529 fwrite(timestamp_realtime, sizeof(rl_timestamp_t), 1, ambient_file);
530 fwrite(timestamp_monotonic, sizeof(rl_timestamp_t), 1, ambient_file);
531
532 // store sensor data
533 fwrite(ambient_buffer, sizeof(int32_t), buffer_size, ambient_file);
534
535 return 1;
536}
537
539 rl_config_t const *const config) {
540 int total_channel_count = file_header->lead_in.channel_bin_count +
541 file_header->lead_in.channel_count;
542
543 // reset channels
544 memset(file_header->channel, 0,
545 total_channel_count * sizeof(rl_file_channel_t));
546
547 // overall channel index
548 int ch = 0;
549
550 // digital channels
551 if (config->digital_enable) {
552 for (int i = 0; i < RL_CHANNEL_DIGITAL_COUNT; i++) {
553 file_header->channel[ch].unit = RL_UNIT_BINARY;
554 file_header->channel[ch].channel_scale = RL_SCALE_UNIT;
555 file_header->channel[ch].data_size = 0;
556 file_header->channel[ch].valid_data_channel =
558 strcpy(file_header->channel[ch].name, RL_CHANNEL_DIGITAL_NAMES[i]);
559 ch++;
560 }
561 }
562
563 // range valid channels
565 file_header->channel[ch].unit = RL_UNIT_RANGE_VALID;
566 file_header->channel[ch].channel_scale = RL_SCALE_UNIT;
567 file_header->channel[ch].data_size = 0;
569 strcpy(file_header->channel[ch].name, RL_CHANNEL_VALID_NAMES[0]);
570 ch++;
571 }
573 file_header->channel[ch].unit = RL_UNIT_RANGE_VALID;
574 file_header->channel[ch].channel_scale = RL_SCALE_UNIT;
575 file_header->channel[ch].data_size = 0;
577 strcpy(file_header->channel[ch].name, RL_CHANNEL_VALID_NAMES[1]);
578 ch++;
579 }
580
581 // analog channels
582 for (int i = 0; i < RL_CHANNEL_COUNT; i++) {
583 if (config->channel_enable[i]) {
584 if (is_current(i)) {
585 if (is_low_current(i)) {
586 file_header->channel[ch].channel_scale = RL_SCALE_TEN_PICO;
587 if (i == RL_CONFIG_CHANNEL_I1L) {
588 file_header->channel[ch].valid_data_channel =
590 } else {
591 file_header->channel[ch].valid_data_channel =
593 }
594 } else {
595 file_header->channel[ch].channel_scale = RL_SCALE_NANO;
596 file_header->channel[ch].valid_data_channel =
598 }
599 file_header->channel[ch].unit = RL_UNIT_AMPERE;
600 } else if (is_voltage(i)) {
601 file_header->channel[ch].unit = RL_UNIT_VOLT;
602 file_header->channel[ch].channel_scale = RL_SCALE_TEN_NANO;
603 file_header->channel[ch].valid_data_channel =
605 } else {
606 file_header->channel[ch].unit = RL_UNIT_SECOND;
607 file_header->channel[ch].channel_scale = RL_SCALE_NANO;
608 file_header->channel[ch].valid_data_channel =
610 }
611 // if calibration measurement, set unit to undefined
612 if (config->calibration_ignore) {
613 file_header->channel[ch].unit = RL_UNIT_UNDEFINED;
614 file_header->channel[ch].channel_scale = RL_SCALE_UNIT;
615 }
616 file_header->channel[ch].data_size = 4;
617 strncpy(file_header->channel[ch].name, RL_CHANNEL_NAMES[i],
619 ch++;
620 }
621 }
622}
623
625 int total_channel_count =
627
628 // reset channels
629 memset(header->channel, 0, total_channel_count * sizeof(rl_file_channel_t));
630
631 // write channels
632 int ch = 0;
633 for (int i = 0; i < SENSOR_REGISTRY_SIZE; i++) {
635 header->channel[ch].unit = SENSOR_REGISTRY[i].unit;
638 header->channel[ch].data_size = 4;
639 strcpy(header->channel[ch].name, SENSOR_REGISTRY[i].name);
640 ch++;
641 }
642 }
643}
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:217
int i1l_valid_channel
Global variable to determine i1l valid channel index.
Definition: rl_file.c:81
void rl_file_update_header_bin(FILE *file_handle, rl_file_header_t const *const file_header)
Definition: rl_file.c:324
int i2l_valid_channel
Global variable to determine i2l valid channel index.
Definition: rl_file.c:83
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:350
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:254
void rl_file_setup_data_channels(rl_file_header_t *const header, rl_config_t const *const config)
Definition: rl_file.c:538
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:160
void rl_file_setup_ambient_header(rl_file_header_t *const header, rl_config_t const *const config)
Definition: rl_file.c:206
void rl_file_update_header_csv(FILE *file_handle, rl_file_header_t const *const file_header)
Definition: rl_file.c:334
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:520
char * rl_file_get_ambient_file_name(char const *const data_file_name)
Definition: rl_file.c:94
void rl_file_setup_data_header(rl_file_header_t *const header, rl_config_t const *const config)
Definition: rl_file.c:195
void rl_file_setup_ambient_channels(rl_file_header_t *const header)
Definition: rl_file.c:624
char * rl_unit_to_string(rl_unit_t const unit)
Definition: rl_file.c:85
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:118
@ 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