RocketLogger  2.0.1
rocketlogger.c
Go to the documentation of this file.
1 
32 #include <argp.h>
33 #include <ctype.h>
34 #include <error.h>
35 #include <stdint.h>
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <string.h>
39 
40 #include <linux/limits.h>
41 #include <unistd.h>
42 
43 #include "log.h"
44 #include "rl.h"
45 #include "rl_lib.h"
46 #include "version.h"
47 
51 #define ARGP_ARGUMENTS_COUNT 1
52 
53 #define OPT_FILE_SIZE 1
54 
55 #define OPT_SAMPLES_COUNT 2
56 
57 #define OPT_SET_DEFAULT 3
58 
59 #define OPT_RESET_DEFAULT 4
60 
61 #define OPT_CALIBRATION 5
62 
63 #define OPT_JSON 6
64 
65 #define OPT_CLI 7
66 
70 const char *argp_program_version = "RocketLogger Command Line Interface";
71 
75 const char *argp_program_bug_address = "<https://github.com/ETHZ-TEC/RocketLogger/issues>";
76 
80 static char doc[] =
81  "RocketLogger CLI -- manage your RocketLogger measurements.\n"
82  "Control or configure measurements using the actions specified by ACTION. "
83  "Supported values for ACTION are:\n"
84  "\n"
85  " Measurement control:\n"
86  " start\tStart a new measurement with provided configuration\n"
87  " stop\tStop measurement running in the background\n"
88  "\n"
89  " Measurement configuration and status management:\n"
90  " config\tDisplay configuration, not starting a new or affecting a "
91  "running measurement\n"
92  " status\tDisplay the current sampling status\n";
93 
97 static char args_doc[] = "ACTION";
98 
102 static struct argp_option options[] = {
103  {0, 0, 0, OPTION_DOC, "Basic measurement configuration options:", 1},
104  {"samples", OPT_SAMPLES_COUNT, "COUNT", 0,
105  "Number of samples to record before stopping measurement (k, M, G, T "
106  "scaling suffixes can be used).",
107  0},
108  {"channel", 'c', "SELECTION", 0, "Channel selection to sample. A comma "
109  "separated list of the channel names (V1, "
110  "V2, V3, V4, I1L, I1H, I2L, and/or I2H) "
111  "or 'all' to enable all channels.",
112  0},
113  {"rate", 'r', "RATE", 0, "Sampling rate in Hz. Supported values are: 1, "
114  "10, 100, 1k, 2k, 4k, 8k, 16k, 32k, 64k.",
115  0},
116  {"update", 'u', "RATE", 0,
117  "Measurement data update rate in Hz. Supported values: 1, 2, 5, 10.", 0},
118  {"output", 'o', "FILE", 0,
119  "Store data to specified file. Use zero to disable file storage.", 0},
120  {"interactive", 'i', 0, 0,
121  "Display measurement data in the command line interface.", 0},
122  {"background", 'b', 0, 0,
123  "Start measurement in the background and exit after start.", 0},
124 
125  {0, 0, 0, OPTION_DOC,
126  "Measurement configuration options for storing measurement files:", 3},
127  {"format", 'f', "FORMAT", 0, "Select file format: 'csv', 'rld'.", 0},
128  {"size", OPT_FILE_SIZE, "SIZE", 0,
129  "Select max file size (k, M, G, T scaling suffixes can be used).", 0},
130  {"comment", 'C', "COMMENT", 0, "Comment stored in file header. Comment is "
131  "ignored if file saving is disabled.",
132  0},
133 
134  {0, 0, 0, OPTION_DOC, "Setting and resetting the stored default:", 4},
135  {"default", OPT_SET_DEFAULT, 0, 0, "Set current configuration as default. "
136  "Supported for all measurement "
137  "configurations.",
138  0},
139  {"reset", OPT_RESET_DEFAULT, 0, 0,
140  "Reset default configuration to factory defaults and ignores any other "
141  "provided configuration without notice. Only allowed in combination with "
142  "the 'config' action.",
143  0},
144 
145  {0, 0, 0, OPTION_DOC, "Optional arguments for extended sampling features:",
146  5},
147  {"digital", 'd', "BOOL", OPTION_ARG_OPTIONAL,
148  "Enable logging of digital inputs. Enabled by default.", 0},
149  {"ambient", 'a', "BOOL", OPTION_ARG_OPTIONAL,
150  "Enable logging of ambient sensors, if available. Disabled by default.",
151  0},
152  {"aggregate", 'g', "MODE", 0, "Data aggregation mode for low sample rates. "
153  "Existing modes: 'average', 'downsample'.",
154  0},
155  {"high-range", 'h', "SELECTION", 0,
156  "Force high range measurements on selected channels. A comma separated "
157  "list of the channel names (I1H and/or I2H) or 'all' to force high range "
158  "measurements all channels. Inactive per default.",
159  0},
160  {"calibration", OPT_CALIBRATION, 0, 0, "Ignore existing calibration "
161  "values. Use this option for device "
162  "calibration measurements only.",
163  0},
164  {"web", 'w', "BOOL", OPTION_ARG_OPTIONAL,
165  "Enable web server plotting. Enabled per default.", 0},
166 
167  {0, 0, 0, OPTION_DOC, "Optional arguments for status and config actions:",
168  6},
169  {"json", OPT_JSON, 0, 0,
170  "Print configuration or status as JSON formatted string.", 0},
171  {"cli", OPT_CLI, 0, 0, "Print configuration as full CLI command.", 0},
172 
173  {0, 0, 0, OPTION_DOC, "Generic program switches:", 7},
174  {"verbose", 'v', 0, 0, "Produce verbose output", 0},
175  {"quiet", 'q', 0, 0, "Do not produce any output", 0},
176  {"silent", 's', 0, OPTION_ALIAS, 0, 0},
177 
178  {0, 0, 0, 0, 0, 0},
179 };
180 
184 struct arguments {
189  bool cli;
190  bool json;
191  bool silent;
192  bool verbose;
193 };
194 
195 /* local function declarations */
196 static error_t parse_opt(int key, char *arg, struct argp_state *state);
197 static void parse_bool(char const *arg, struct argp_state *state,
198  bool *const value);
199 static void parse_bool_named_list(char const *arg, struct argp_state *state,
200  char const *const *const names,
201  bool *const values, int size);
202 static void parse_uint32(char const *arg, struct argp_state *state,
203  uint32_t *const value);
204 static void parse_uint64(char const *arg, struct argp_state *state,
205  uint64_t *const value);
206 static void print_config(rl_config_t const *const config);
207 static void print_version(FILE *stream, struct argp_state *state);
208 
212 void (*argp_program_version_hook)(FILE *, struct argp_state *) = print_version;
213 
217 static struct argp argp = {
218  .options = options,
219  .parser = parse_opt,
220  .args_doc = args_doc,
221  .doc = doc,
222 };
223 
227 static char const *const log_filename = RL_MEASUREMENT_LOG_FILE;
228 
236 int main(int argc, char *argv[]) {
237  rl_config_t config;
238 
239  // load default configuration
240  int res = rl_config_read_default(&config);
241  if (res < 0) {
242  error(EXIT_FAILURE, errno, "failed reading default configuration file");
243  }
244 
245  // argument structure with default values
246  struct arguments arguments = {
247  .args = {NULL},
248  .config = &config,
249  .config_reset = false,
250  .config_set_default = false,
251  .cli = false,
252  .json = false,
253  .silent = false,
254  .verbose = false,
255  };
256 
257  // parse CLI arguments and options using argp
258  int argp_status = argp_parse(&argp, argc, argv, 0, 0, &arguments);
259  if (argp_status != 0) {
260  error(0, argp_status, "argument parsing failed");
261  }
262 
263  // init log module with appropriate verbosity level
264  if (arguments.verbose) {
265  rl_log_init(log_filename, RL_LOG_VERBOSE);
266  } else if (arguments.silent) {
267  rl_log_init(log_filename, RL_LOG_IGNORE);
268  } else {
269  rl_log_init(log_filename, RL_LOG_WARNING);
270  }
271 
272  // set effective user ID of the process
273  int ret = setuid(0);
274  if (ret < 0) {
275  rl_log(RL_LOG_ERROR, "Failed setting effective user ID. %d message: %s",
276  errno, strerror(errno));
277  exit(EXIT_FAILURE);
278  }
279 
280  rl_log(RL_LOG_VERBOSE, "running with real user ID: %d", getuid());
281  rl_log(RL_LOG_VERBOSE, "running with effective user ID: %d", geteuid());
282  rl_log(RL_LOG_VERBOSE, "running with real group ID: %d", getgid());
283  rl_log(RL_LOG_VERBOSE, "running with effective group ID: %d", getegid());
284 
285 
286  char const *const action = arguments.args[0];
287 
288  // validate arguments
289  bool valid_action =
290  (strcmp(action, "start") == 0 || strcmp(action, "stop") == 0 ||
291  strcmp(action, "config") == 0 || strcmp(action, "status") == 0);
292  if (!valid_action) {
293  rl_log(RL_LOG_ERROR, "unknown action '%s'", action);
294  exit(EXIT_FAILURE);
295  }
296 
297  if (arguments.cli && arguments.json) {
298  rl_log(RL_LOG_ERROR, "cannot format in output as JSON and and CLI "
299  "string at the same time.");
300  exit(EXIT_FAILURE);
301  }
302 
303  // validate sampling configuration
304  int valid_config = rl_config_validate(&config);
305  if (valid_config < 0) {
306  rl_log(RL_LOG_ERROR, "invalid configuration, check message above");
307  exit(EXIT_FAILURE);
308  }
309 
310  // reset config if requested
311  if (arguments.config_reset) {
312  if (strcmp(action, "config") != 0) {
314  "the --reset option is only allowed for config action.");
315  exit(EXIT_FAILURE);
316  }
318  rl_log(RL_LOG_INFO, "Configuration was reset to factory default.");
319  }
320  // store config as default
323  if (!(arguments.silent || arguments.json | arguments.cli)) {
324  printf("The following configuration was saved as new default:\n");
326  }
327  }
328 
329  // configure and run system in the requested MODE
330  if (strcmp(action, "start") == 0) {
331  // check if already sampling
332  if (rl_is_sampling()) {
333  rl_log(RL_LOG_ERROR, "RocketLogger is still running.\n"
334  "Stop with `rocketlogger stop` first.\n");
335  exit(EXIT_FAILURE);
336  }
337 
338  if (arguments.verbose) {
339  print_config(&config);
340  }
341  rl_log(RL_LOG_INFO, "Starting measurement...\n");
342  rl_run(&config);
343  }
344  if (strcmp(action, "stop") == 0) {
345  // exit with error if not sampling
346  if (!rl_is_sampling()) {
347  rl_log(RL_LOG_ERROR, "RocketLogger is not running.\n");
348  exit(EXIT_FAILURE);
349  }
350 
351  if (!arguments.silent) {
352  printf("Wait for measurement to stop...\n");
353  }
354  rl_stop();
355  }
356  if (strcmp(action, "config") == 0) {
357  if (arguments.json) {
359  } else if (arguments.cli) {
361  } else {
363  }
364  }
365  if (strcmp(action, "status") == 0) {
366  rl_status_t status;
367  int res = rl_get_status(&status);
368  if (res < 0) {
369  rl_log(RL_LOG_ERROR, "Failed getting RocketLogger status (%d).\n",
370  res);
371  exit(EXIT_FAILURE);
372  }
373  if (arguments.json) {
374  rl_status_print_json(&status);
375  } else {
376  rl_status_print(&status);
377  }
378  }
379  exit(EXIT_SUCCESS);
380 }
381 
390 static error_t parse_opt(int key, char *arg, struct argp_state *state) {
391  // get pointer to where run configuration is stored
392  struct arguments *arguments = state->input;
394 
395  // parse actual argument
396  switch (key) {
397  /* options with shortcuts */
398  case 'q':
399  case 's':
400  /* quiet/silent switch: no value */
401  arguments->silent = true;
402  arguments->verbose = false;
403  break;
404  case 'v':
405  /* verbose switch: no value */
406  arguments->verbose = true;
407  arguments->silent = false;
408  break;
409  case 'b':
410  /* run in background: no value */
411  config->background_enable = true;
412  break;
413  case 'i':
414  /* display measurements interactively: no value */
415  config->interactive_enable = true;
416  break;
417  case 'c':
418  /* channel selection: mandatory SELECTION value */
419  parse_bool_named_list(arg, state, RL_CHANNEL_NAMES,
421  break;
422  case 'r':
423  /* sampling rate: mandatory RATE value */
424  parse_uint32(arg, state, &config->sample_rate);
425  break;
426  case 'u':
427  /* measurement update rate: mandatory RATE value */
428  parse_uint32(arg, state, &config->update_rate);
429  break;
430  case 'o':
431  /* measurement output file: mandatory FILE value */
432  if (arg != NULL) {
433  if (strlen(arg) == 1 && arg[0] == '0') {
434  config->file_enable = false;
435  } else {
436  config->file_enable = true;
437  strncpy(config->file_name, arg, PATH_MAX - 1);
438  }
439  } else {
440  argp_usage(state);
441  }
442  break;
443  case 'f':
444  /* measurement file format: mandatory FORMAT value */
445  if (strcmp(arg, "csv") == 0 || strcmp(arg, "CSV") == 0) {
447  } else if (strcmp(arg, "rld") == 0 || strcmp(arg, "RLD") == 0) {
449  } else {
450  argp_usage(state);
451  }
452  break;
453  case 'C':
454  /* measurement file comment: mandatory COMMENT value */
455  if (arg != NULL) {
456  config->file_comment = arg;
457  } else {
458  argp_usage(state);
459  }
460  break;
461  case 'd':
462  /* digital channel: optional BOOL value */
463  if (arg != NULL) {
464  parse_bool(arg, state, &config->digital_enable);
465  } else {
466  config->digital_enable = true;
467  }
468  break;
469  case 'a':
470  /* ambient sensors: optional BOOL value */
471  if (arg != NULL) {
472  parse_bool(arg, state, &config->ambient_enable);
473  } else {
474  config->ambient_enable = true;
475  }
476  break;
477  case 'g':
478  /* data aggregation mode: mandatory MODE value */
479  if (strcmp(arg, "downsample") == 0) {
481  } else if (strcmp(arg, "average") == 0) {
483  } else {
484  argp_usage(state);
485  }
486  break;
487  case 'h':
488  /* force high-range current measurement: mandatory SELECTION value */
489  parse_bool_named_list(arg, state, RL_CHANNEL_FORCE_NAMES,
492  break;
493  case 'w':
494  /* web interface enable: optional BOOL value */
495  if (arg != NULL) {
496  parse_bool(arg, state, &config->web_enable);
497  } else {
498  config->web_enable = true;
499  }
500  break;
501 
502  /* options without shortcuts */
503  case OPT_SAMPLES_COUNT:
504  /* sample count: mandatory COUNT value */
505  parse_uint64(arg, state, &config->sample_limit);
506  break;
507  case OPT_FILE_SIZE:
508  /* maximum file size: mandatory SIZE value */
509  parse_uint64(arg, state, &config->file_size);
510  break;
511  case OPT_CLI:
512  /* CLI format the config output: no value */
513  arguments->cli = true;
514  break;
515  case OPT_JSON:
516  /* JSON format the status and config output: no value */
517  arguments->json = true;
518  break;
519  case OPT_SET_DEFAULT:
520  /* set configuration as default: no value */
522  break;
523  case OPT_RESET_DEFAULT:
524  /* reset configuration to system default: no value */
525  arguments->config_reset = true;
526  break;
527  case OPT_CALIBRATION:
528  /* perform calibration measurement: no value */
529  config->calibration_ignore = true;
530  break;
531 
532  /* unnamed argument options */
533  case ARGP_KEY_ARG:
534  // check for too many arguments
535  if (state->arg_num >= ARGP_ARGUMENTS_COUNT) {
536  argp_usage(state);
537  }
538  arguments->args[state->arg_num] = arg;
539  break;
540  case ARGP_KEY_END:
541  // check for not enough arguments
542  if (state->arg_num < ARGP_ARGUMENTS_COUNT) {
543  argp_usage(state);
544  }
545  break;
546  default:
547  return ARGP_ERR_UNKNOWN;
548  }
549 
550  return 0;
551 }
552 
562 static void parse_bool(char const *arg, struct argp_state *state,
563  bool *const value) {
564  if (strlen(arg) == 1) {
565  if (arg[0] == '0') {
566  *value = false;
567  return;
568  } else if (arg[0] == '1') {
569  *value = true;
570  return;
571  }
572  }
573  if (strcmp(arg, "true") == 0 || strcmp(arg, "True") == 0 ||
574  strcmp(arg, "TRUE") == 0) {
575  *value = true;
576  return;
577  }
578  if (strcmp(arg, "false") == 0 || strcmp(arg, "False") == 0 ||
579  strcmp(arg, "FALSE") == 0) {
580  *value = false;
581  return;
582  }
583  argp_usage(state);
584 }
585 
599 static void parse_bool_named_list(char const *arg, struct argp_state *state,
600  char const *const *const names,
601  bool *const values, int size) {
602  // check for all enable argument
603  if (strcmp(arg, "all") == 0) {
604  memset(values, true, size * sizeof(bool));
605  return;
606  }
607  // reset values
608  memset(values, false, size * sizeof(bool));
609 
610  // split input by comma
611  char const *split_pos = arg;
612  while (*arg != '\0') {
613  // find next argument name
614  split_pos = strchr(arg, ',');
615  char arg_name[16] = {0};
616  if (split_pos == NULL) {
617  strncpy(arg_name, arg, sizeof(arg_name) - 1);
618  arg = arg + strlen(arg); // set to end to exit loop when done
619  } else {
620  strncpy(arg_name, arg, split_pos - arg);
621  arg = split_pos + 1; // next argument starts right after comma
622  }
623 
624  // convert parsed name
625  char *ptr = arg_name;
626  do {
627  *ptr = toupper(*ptr);
628  } while (*ptr++);
629 
630  // process channel name
631  int i = 0;
632  while (i < size) {
633  if (strcmp(arg_name, names[i]) == 0) {
634  values[i] = true;
635  break;
636  }
637  i++;
638  }
639  // check valid channel was set
640  if (i == size) {
641  argp_usage(state);
642  return;
643  }
644  }
645 }
646 
656 static void parse_uint32(char const *arg, struct argp_state *state,
657  uint32_t *const value) {
658  uint64_t temp;
659  parse_uint64(arg, state, &temp);
660  if ((temp >> 32) == 0) {
661  *value = (uint32_t)temp;
662  } else {
663  argp_usage(state);
664  }
665 }
666 
676 static void parse_uint64(char const *arg, struct argp_state *state,
677  uint64_t *const value) {
678  char *suffix = NULL;
679  *value = strtoull(arg, &suffix, 10);
680 
681  // check for scaling suffix and apply it iteratively
682  if (suffix != NULL) {
683  switch (*suffix) {
684  case 'T':
685  *value = *value * 1000;
686  /* FALL THROUGH */
687  case 'G':
688  *value = *value * 1000;
689  /* FALL THROUGH */
690  case 'M':
691  *value = *value * 1000;
692  /* FALL THROUGH */
693  case 'k':
694  *value = *value * 1000;
695  /* FALL THROUGH */
696  case '\0':
697  break;
698  default:
699  argp_usage(state);
700  return;
701  }
702  } else {
703  argp_usage(state);
704  return;
705  }
706 }
707 
714 static void print_version(FILE *stream, struct argp_state *state) {
715  (void)state; // suppress unused parameter warning
716  fprintf(stream, "%s %s\n", argp_program_version, PROJECT_VERSION);
717  fprintf(stream, " git@%s (%s)\n", GIT_DESCRIPTION, GIT_DATE);
718  fprintf(stream, " compiled at %s\n", COMPILE_DATE);
719 }
720 
726 static void print_config(rl_config_t const *const config) {
727  printf("\nRocketLogger Configuration:\n");
729  printf("\n");
730 }
int rl_log(rl_log_level_t log_level, char const *const format,...)
Definition: log.c:82
int rl_log_init(char const *const log_file, rl_log_level_t verbosity)
Definition: log.c:49
@ RL_LOG_ERROR
Error.
Definition: log.h:49
@ RL_LOG_WARNING
Warning.
Definition: log.h:50
@ RL_LOG_VERBOSE
Verbose.
Definition: log.h:52
@ RL_LOG_INFO
Information.
Definition: log.h:51
@ RL_LOG_IGNORE
Ignore log (only for verbosity configuration)
Definition: log.h:48
char const *const RL_CHANNEL_NAMES[RL_CHANNEL_COUNT]
RocketLogger channel names.
Definition: rl.c:95
void rl_status_print_json(rl_status_t const *const status)
Definition: rl.c:731
char const *const RL_CHANNEL_FORCE_NAMES[RL_CHANNEL_SWITCHED_COUNT]
RocketLogger force range channel names.
Definition: rl.c:99
void rl_config_print_json(rl_config_t const *const config)
Definition: rl.c:275
void rl_config_reset(rl_config_t *const config)
Definition: rl.c:360
void rl_config_print(rl_config_t const *const config)
Definition: rl.c:142
int rl_config_read_default(rl_config_t *const config)
Definition: rl.c:364
int rl_config_write_default(rl_config_t const *const config)
Definition: rl.c:414
int rl_config_validate(rl_config_t const *const config)
Definition: rl.c:431
void rl_status_print(rl_status_t const *const status)
Definition: rl.c:709
void rl_config_print_cmd(rl_config_t const *const config)
Definition: rl.c:211
@ RL_FILE_FORMAT_RLD
CSV format.
Definition: rl.h:143
@ RL_FILE_FORMAT_CSV
Definition: rl.h:142
#define RL_CHANNEL_SWITCHED_COUNT
Number of RocketLogger switched channels (allowing to force range)
Definition: rl.h:58
#define RL_MEASUREMENT_LOG_FILE
RocketLogger measurement log file.
Definition: rl.h:49
#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
int rl_stop(void)
Definition: rl_lib.c:185
bool rl_is_sampling(void)
Definition: rl_lib.c:59
int rl_run(rl_config_t *const config)
Definition: rl_lib.c:100
int rl_get_status(rl_status_t *const status)
Definition: rl_lib.c:77
int main(int argc, char *argv[])
Definition: rocketlogger.c:236
#define OPT_SAMPLES_COUNT
Definition: rocketlogger.c:55
#define OPT_JSON
Definition: rocketlogger.c:63
const char * argp_program_version
Definition: rocketlogger.c:70
#define OPT_SET_DEFAULT
Definition: rocketlogger.c:57
#define ARGP_ARGUMENTS_COUNT
Definition: rocketlogger.c:51
#define OPT_CLI
Definition: rocketlogger.c:65
#define OPT_RESET_DEFAULT
Definition: rocketlogger.c:59
const char * argp_program_bug_address
Definition: rocketlogger.c:75
#define OPT_CALIBRATION
Definition: rocketlogger.c:61
void(* argp_program_version_hook)(FILE *, struct argp_state *)
Definition: rocketlogger.c:212
#define OPT_FILE_SIZE
Definition: rocketlogger.c:53
rl_config_t * config
program arguments
Definition: rocketlogger.c:186
bool config_set_default
whether to reset the stored default config
Definition: rocketlogger.c:188
bool verbose
flag for silent output
Definition: rocketlogger.c:192
bool cli
whether to save provided config as default
Definition: rocketlogger.c:189
bool json
flag for CLI command formatted config output
Definition: rocketlogger.c:190
bool silent
flag for JSON formatted output
Definition: rocketlogger.c:191
char * args[ARGP_ARGUMENTS_COUNT]
Definition: rocketlogger.c:185
bool config_reset
pointer to sampling configuration
Definition: rocketlogger.c:187
Definition: rl.h:154
bool channel_force_range[RL_CHANNEL_SWITCHED_COUNT]
Current channels to force to high range.
Definition: rl.h:170
char file_name[PATH_MAX]
Data file name.
Definition: rl.h:184
bool interactive_enable
Display measurement data interactively in CLI while sampling.
Definition: rl.h:160
char const * file_comment
File comment.
Definition: rl.h:190
uint64_t file_size
Maximum data file size.
Definition: rl.h:188
rl_aggregation_mode_t aggregation_mode
Sample aggregation mode (for sampling rates below lowest native one)
Definition: rl.h:172
bool background_enable
Put the measurement process in background after successful start.
Definition: rl.h:158
bool ambient_enable
Enable logging of ambient sensor.
Definition: rl.h:180
uint64_t sample_limit
Sample limit (0 for continuous)
Definition: rl.h:162
bool web_enable
Enable web interface connection.
Definition: rl.h:176
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
Definition: rl.h:201
char const *const COMPILE_DATE
Compilation date of the program.
char const *const PROJECT_VERSION
The RocketLogger software version string.
char const *const GIT_DESCRIPTION
Git code revision description of the code base.
char const *const GIT_DATE
Date of the of last git commit.