RocketLogger  2.0.1
rocketloggerd.c
Go to the documentation of this file.
1 
32 #include <errno.h>
33 #include <stdint.h>
34 #include <stdlib.h>
35 #include <string.h>
36 #include <time.h>
37 
38 #include <signal.h>
39 #include <sys/reboot.h>
40 #include <unistd.h>
41 
42 #include "gpio.h"
43 #include "log.h"
44 #include "pwm.h"
45 #include "rl.h"
46 #include "rl_lib.h"
47 
49 #define RL_DAEMON_MIN_INTERVAL 1
50 
52 #define RL_CALIBRATION_DURATION_SEC 1
53 
55 #define RL_POWERUP_DELAY_US 5000
56 
58 #define RL_BUTTON_LONG_PRESS_SEC 3
59 
61 #define RL_BUTTON_VERY_LONG_PRESS_SEC 6
62 
64 #define RL_BUTTON_EXTRA_LONG_PRESS_SEC 10
65 
73 };
74 
78 typedef enum system_action system_action_t;
79 
80 
82 static char const *const log_filename = RL_DAEMON_LOG_FILE;
83 
85 volatile bool daemon_shutdown = false;
86 
89 
92 
95 
106 int adc_calibrate(uint64_t duration) {
107  if (duration == 0) {
108  errno = EINVAL;
109  return -1;
110  }
111 
112  // configure run with minimal data output
113  static rl_config_t rl_config_calibration;
114  rl_config_reset(&rl_config_calibration);
115  rl_config_calibration.background_enable = false;
116  rl_config_calibration.interactive_enable = false;
117  rl_config_calibration.web_enable = false;
118  rl_config_calibration.file_enable = false;
119  rl_config_calibration.sample_rate = RL_SAMPLE_RATE_MIN;
120  rl_config_calibration.sample_limit = RL_SAMPLE_RATE_MIN * duration;
121 
122  // perform calibration run
123  int res = rl_run(&rl_config_calibration);
124 
125  // reset sampling status counters
131 
132  return res;
133 }
134 
140 void button_interrupt_handler(int value) {
141  static time_t timestamp_down = -1;
142  time_t timestamp = time(NULL);
143 
144  // capture timestamp on button press
145  if (value == 0) {
146  timestamp_down = timestamp;
147  }
148  // process button action on button release
149  if (value == 1) {
150  // get duration and reset timestamp down
151  time_t duration = timestamp - timestamp_down;
152  timestamp_down = -1;
153 
154  // skip further processing on invalid timestamp
155  if (duration > timestamp) {
156  return;
157  }
158 
159  // get RocketLogger status
160  rl_status_t status;
161  int ret = rl_status_read(&status);
162  if (ret < 0) {
163  rl_log(RL_LOG_ERROR, "Failed reading status; %d message: %s", errno,
164  strerror(errno));
165  }
166 
167  if (duration >= RL_BUTTON_EXTRA_LONG_PRESS_SEC) {
169  "Registered extra long press, requesting system shutdown.");
170  daemon_shutdown = true;
172  if (!status.sampling) {
173  return;
174  }
175  } else if (duration >= RL_BUTTON_VERY_LONG_PRESS_SEC) {
177  "Registered very long press, requesting system reboot.");
178  daemon_shutdown = true;
180  if (!status.sampling) {
181  return;
182  }
183  } else if (duration >= RL_BUTTON_LONG_PRESS_SEC) {
185  "Registered long press, requesting daemon restart.");
186  daemon_shutdown = true;
188  if (!status.sampling) {
189  return;
190  }
191  }
192 
193  char *cmd[3] = {"rocketlogger", NULL, NULL};
194  if (status.sampling) {
195  cmd[1] = "stop";
196  } else {
197  cmd[1] = "start";
198  }
199 
200  // create child process to start RocketLogger
201  pid_t pid = fork();
202  if (pid < 0) {
203  rl_log(RL_LOG_ERROR, "Failed forking process; %d message: %s",
204  errno, strerror(errno));
205  }
206  if (pid == 0) {
207  // in child process, execute RocketLogger
208  execvp(cmd[0], cmd);
210  "Failed executing `rocketlogger %s`; %d message: %s", cmd,
211  errno, strerror(errno));
212  } else {
213  // in parent process log pid
214  rl_log(RL_LOG_INFO, "Started RocketLogger with pid=%d.", pid);
215  }
216  }
217  // interrupt rate control
218  sleep(RL_DAEMON_MIN_INTERVAL);
219 }
220 
226 static void signal_handler(int signal_number) {
227  // signal to terminate the daemon (systemd stop)
228  if (signal_number == SIGTERM) {
229  signal(signal_number, SIG_IGN);
230  rl_log(RL_LOG_INFO, "Received SIGTERM, shutting down daemon.");
231  daemon_shutdown = true;
232  }
233 }
234 
242 int main(void) {
243  int ret = SUCCESS;
244 
245  // init log module
246  rl_log_init(log_filename, RL_LOG_VERBOSE);
247 
248  // set effective user ID of the process
249  ret = setuid(0);
250  if (ret < 0) {
251  rl_log(RL_LOG_ERROR, "Failed setting effective user ID; %d message: %s",
252  errno, strerror(errno));
253  exit(EXIT_FAILURE);
254  }
255 
256  rl_log(RL_LOG_VERBOSE, "running with real user ID: %d", getuid());
257  rl_log(RL_LOG_VERBOSE, "running with effective user ID: %d", geteuid());
258  rl_log(RL_LOG_VERBOSE, "running with real group ID: %d", getgid());
259  rl_log(RL_LOG_VERBOSE, "running with effective group ID: %d", getegid());
260 
261  // initialize GPIO module
262  gpio_init();
263 
264  // hardware initialization
265  gpio_t *gpio_power = gpio_setup(GPIO_POWER, GPIO_MODE_OUT, "rocketloggerd");
266  if (gpio_power == NULL) {
267  rl_log(RL_LOG_ERROR, "Failed configuring power switch; %d message: %s",
268  errno, strerror(errno));
269  exit(EXIT_FAILURE);
270  }
271  ret = gpio_set_value(gpio_power, 1);
272  if (ret < 0) {
273  rl_log(RL_LOG_ERROR, "Failed powering up cape; %d message: %s", errno,
274  strerror(errno));
275  exit(EXIT_FAILURE);
276  }
277 
278  // wait for converter soft start (> 1 ms)
279  usleep(RL_POWERUP_DELAY_US);
280 
283  if (gpio_button == NULL) {
284  rl_log(RL_LOG_ERROR, "Failed configuring button; %d message: %s", errno,
285  strerror(errno));
286  exit(EXIT_FAILURE);
287  }
288 
289  ret = pwm_init();
290  if (ret < 0) {
291  rl_log(RL_LOG_ERROR, "Failed initializing PWM modules; %d message: %s",
292  errno, strerror(errno));
293  exit(EXIT_FAILURE);
294  }
295 
296  // create shared memory for state
297  ret = rl_status_shm_init();
298  if (ret < 0) {
299  rl_log(RL_LOG_ERROR, "Failed initializing status shared memory.");
300  exit(EXIT_FAILURE);
301  }
302 
303  // register signal handler for SIGTERM (for stopping daemon)
304  struct sigaction signal_action;
305  signal_action.sa_handler = signal_handler;
306  sigemptyset(&signal_action.sa_mask);
307  signal_action.sa_flags = 0;
308 
309  ret = sigaction(SIGTERM, &signal_action, NULL);
310  if (ret < 0) {
312  "can't register signal handler for SIGTERM; %d message: %s",
313  errno, strerror(errno));
314  exit(EXIT_FAILURE);
315  }
316 
317  // calibrate ADC reference voltage
318  rl_log(RL_LOG_INFO, "Performing ADC reference calibration.");
320 
321  // check error status
322  rl_status_t status;
323  rl_status_read(&status);
324  if (status.error) {
325  rl_log(RL_LOG_ERROR, "ADC reference calibration failed, terminating.");
326  } else {
327  // daemon main loop
328  rl_log(RL_LOG_INFO, "RocketLogger daemon running.");
329 
330  daemon_shutdown = false;
331  while (!daemon_shutdown) {
332  // wait for interrupt with infinite timeout
333  int value = gpio_wait_interrupt(gpio_button, NULL);
335  }
336 
337  rl_log(RL_LOG_INFO, "RocketLogger daemon stopped.");
338  }
339 
340  rl_status_read(&status);
341 
342  // remove shared memory for state
344 
345  // deinitialize and shutdown hardware
346  pwm_deinit();
350  gpio_deinit();
351 
352  // perform requested system action
354  rl_log(RL_LOG_INFO, "Rebooting system.");
355  sync();
356  reboot(RB_AUTOBOOT);
357  } else if (system_action == SYSTEM_ACTION_POWEROFF) {
358  rl_log(RL_LOG_INFO, "Powering off system.");
359  sync();
360  reboot(RB_POWER_OFF);
361  }
362 
363  if (status.error) {
364  exit(EXIT_FAILURE);
365  }
366  exit(EXIT_SUCCESS);
367 }
gpio_t * gpio_setup(int gpio_number, gpio_mode_t mode, const char *name)
Definition: gpio.c:103
int gpio_set_value(gpio_t *gpio, int value)
Definition: gpio.c:135
int gpio_init()
Definition: gpio.c:77
gpio_t * gpio_setup_interrupt(int gpio_number, gpio_interrupt_t edge, const char *name)
Definition: gpio.c:148
void gpio_release(gpio_t *gpio)
Definition: gpio.c:130
void gpio_deinit()
Definition: gpio.c:92
int gpio_wait_interrupt(gpio_t *gpio, const struct timespec *timeout)
Definition: gpio.c:187
#define GPIO_POWER
GPIO number of RocketLogger cape power enable.
Definition: gpio.h:49
@ GPIO_INTERRUPT_BOTH
Interrupt on both edges.
Definition: gpio.h:66
@ GPIO_MODE_OUT
GPIO write mode.
Definition: gpio.h:56
struct gpiod_line gpio_t
Definition: gpio.h:72
#define GPIO_BUTTON
GPIO number of start/stop button.
Definition: gpio.h:47
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_VERBOSE
Verbose.
Definition: log.h:52
@ RL_LOG_INFO
Information.
Definition: log.h:51
void pwm_deinit(void)
Definition: pwm.c:60
int pwm_init(void)
Definition: pwm.c:37
int rl_status_write(rl_status_t *const status)
Definition: rl.c:641
void rl_config_reset(rl_config_t *const config)
Definition: rl.c:360
int rl_status_read(rl_status_t *const status)
Definition: rl.c:602
int rl_status_shm_init(void)
Definition: rl.c:565
int rl_status_shm_deinit(void)
Definition: rl.c:579
rl_status_t rl_status
Global RocketLogger status variable.
Definition: rl.c:112
#define RL_SAMPLE_RATE_MIN
Minimum native sample rate of the ADC in samples per second.
Definition: rl.h:62
#define SUCCESS
Function return value for successful completion.
Definition: rl.h:44
#define RL_DAEMON_LOG_FILE
RocketLogger daemon log file.
Definition: rl.h:51
int rl_run(rl_config_t *const config)
Definition: rl_lib.c:100
gpio_t * gpio_power
GPIO handle for power switch.
Definition: rocketloggerd.c:91
#define RL_POWERUP_DELAY_US
Delay on cape power up (in microseconds)
Definition: rocketloggerd.c:55
#define RL_BUTTON_VERY_LONG_PRESS_SEC
Min duration of a very long button press (in seconds)
Definition: rocketloggerd.c:61
int main(void)
#define RL_BUTTON_LONG_PRESS_SEC
Min duration of a long button press (in seconds)
Definition: rocketloggerd.c:58
volatile bool daemon_shutdown
Flag to terminate the infinite daemon loop.
Definition: rocketloggerd.c:85
enum system_action system_action_t
Definition: rocketloggerd.c:78
void button_interrupt_handler(int value)
#define RL_DAEMON_MIN_INTERVAL
Minimal time interval between two interrupts (in seconds)
Definition: rocketloggerd.c:49
gpio_t * gpio_button
GPIO handle for user button.
Definition: rocketloggerd.c:94
int adc_calibrate(uint64_t duration)
system_action
Definition: rocketloggerd.c:69
@ SYSTEM_ACTION_POWEROFF
power off the system
Definition: rocketloggerd.c:72
@ SYSTEM_ACTION_REBOOT
reboot the system
Definition: rocketloggerd.c:71
@ SYSTEM_ACTION_NONE
perform no system action
Definition: rocketloggerd.c:70
#define RL_CALIBRATION_DURATION_SEC
Duration of calibration run (in seconds)
Definition: rocketloggerd.c:52
#define RL_BUTTON_EXTRA_LONG_PRESS_SEC
Min duration of an extra long button press (in seconds)
Definition: rocketloggerd.c:64
Definition: rl.h:154
bool interactive_enable
Display measurement data interactively in CLI while sampling.
Definition: rl.h:160
bool background_enable
Put the measurement process in background after successful start.
Definition: rl.h:158
uint64_t sample_limit
Sample limit (0 for continuous)
Definition: rl.h:162
bool web_enable
Enable web interface connection.
Definition: rl.h:176
uint32_t sample_rate
Sampling rate.
Definition: rl.h:164
bool file_enable
Enable storing measurements to file.
Definition: rl.h:182
Definition: rl.h:201
uint64_t buffer_count
Number of buffers taken.
Definition: rl.h:209
bool error
Whether the logger is in an error state.
Definition: rl.h:205
bool sampling
Sampling state, true: sampling, false: idle.
Definition: rl.h:203
uint64_t sample_count
Number of samples taken.
Definition: rl.h:207