RocketLogger  2.0.0
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 to default
129 
130  return res;
131 }
132 
138 void button_interrupt_handler(int value) {
139  static time_t timestamp_down = -1;
140  time_t timestamp = time(NULL);
141 
142  // capture timestamp on button press
143  if (value == 0) {
144  timestamp_down = timestamp;
145  }
146  // process button action on button release
147  if (value == 1) {
148  // get duration and reset timestamp down
149  time_t duration = timestamp - timestamp_down;
150  timestamp_down = -1;
151 
152  // skip further processing on invalid timestamp
153  if (duration > timestamp) {
154  return;
155  }
156 
157  // get RocketLogger status
158  rl_status_t status;
159  int ret = rl_status_read(&status);
160  if (ret < 0) {
161  rl_log(RL_LOG_ERROR, "Failed reading status; %d message: %s", errno,
162  strerror(errno));
163  }
164 
165  if (duration >= RL_BUTTON_EXTRA_LONG_PRESS_SEC) {
167  "Registered extra long press, requesting system shutdown.");
168  daemon_shutdown = true;
170  if (!status.sampling) {
171  return;
172  }
173  } else if (duration >= RL_BUTTON_VERY_LONG_PRESS_SEC) {
175  "Registered very long press, requesting system reboot.");
176  daemon_shutdown = true;
178  if (!status.sampling) {
179  return;
180  }
181  } else if (duration >= RL_BUTTON_LONG_PRESS_SEC) {
183  "Registered long press, requesting daemon restart.");
184  daemon_shutdown = true;
186  if (!status.sampling) {
187  return;
188  }
189  }
190 
191  char *cmd[3] = {"rocketlogger", NULL, NULL};
192  if (status.sampling) {
193  cmd[1] = "stop";
194  } else {
195  cmd[1] = "start";
196  }
197 
198  // create child process to start RocketLogger
199  pid_t pid = fork();
200  if (pid < 0) {
201  rl_log(RL_LOG_ERROR, "Failed forking process; %d message: %s",
202  errno, strerror(errno));
203  }
204  if (pid == 0) {
205  // in child process, execute RocketLogger
206  execvp(cmd[0], cmd);
208  "Failed executing `rocketlogger %s`; %d message: %s", cmd,
209  errno, strerror(errno));
210  } else {
211  // in parent process log pid
212  rl_log(RL_LOG_INFO, "Started RocketLogger with pid=%d.", pid);
213  }
214  }
215  // interrupt rate control
216  sleep(RL_DAEMON_MIN_INTERVAL);
217 }
218 
224 static void signal_handler(int signal_number) {
225  // signal to terminate the daemon (systemd stop)
226  if (signal_number == SIGTERM) {
227  signal(signal_number, SIG_IGN);
228  rl_log(RL_LOG_INFO, "Received SIGTERM, shutting down daemon.");
229  daemon_shutdown = true;
230  }
231 }
232 
240 int main(void) {
241  int ret = SUCCESS;
242 
243  // init log module
244  rl_log_init(log_filename, RL_LOG_VERBOSE);
245 
246  // set effective user ID of the process
247  ret = setuid(0);
248  if (ret < 0) {
249  rl_log(RL_LOG_ERROR, "Failed setting effective user ID; %d message: %s",
250  errno, strerror(errno));
251  exit(EXIT_FAILURE);
252  }
253 
254  rl_log(RL_LOG_VERBOSE, "running with real user ID: %d", getuid());
255  rl_log(RL_LOG_VERBOSE, "running with effective user ID: %d", geteuid());
256  rl_log(RL_LOG_VERBOSE, "running with real group ID: %d", getgid());
257  rl_log(RL_LOG_VERBOSE, "running with effective group ID: %d", getegid());
258 
259  // initialize GPIO module
260  gpio_init();
261 
262  // hardware initialization
263  gpio_t *gpio_power = gpio_setup(GPIO_POWER, GPIO_MODE_OUT, "rocketloggerd");
264  if (gpio_power == NULL) {
265  rl_log(RL_LOG_ERROR, "Failed configuring power switch; %d message: %s",
266  errno, strerror(errno));
267  exit(EXIT_FAILURE);
268  }
269  ret = gpio_set_value(gpio_power, 1);
270  if (ret < 0) {
271  rl_log(RL_LOG_ERROR, "Failed powering up cape; %d message: %s", errno,
272  strerror(errno));
273  exit(EXIT_FAILURE);
274  }
275 
276  // wait for converter soft start (> 1 ms)
277  usleep(RL_POWERUP_DELAY_US);
278 
281  if (gpio_button == NULL) {
282  rl_log(RL_LOG_ERROR, "Failed configuring button; %d message: %s", errno,
283  strerror(errno));
284  exit(EXIT_FAILURE);
285  }
286 
287  ret = pwm_init();
288  if (ret < 0) {
289  rl_log(RL_LOG_ERROR, "Failed initializing PWM modules; %d message: %s",
290  errno, strerror(errno));
291  exit(EXIT_FAILURE);
292  }
293 
294  // create shared memory for state
295  ret = rl_status_shm_init();
296  if (ret < 0) {
297  rl_log(RL_LOG_ERROR, "Failed initializing status shared memory.");
298  exit(EXIT_FAILURE);
299  }
300 
301  // register signal handler for SIGTERM (for stopping daemon)
302  struct sigaction signal_action;
303  signal_action.sa_handler = signal_handler;
304  sigemptyset(&signal_action.sa_mask);
305  signal_action.sa_flags = 0;
306 
307  ret = sigaction(SIGTERM, &signal_action, NULL);
308  if (ret < 0) {
310  "can't register signal handler for SIGTERM; %d message: %s",
311  errno, strerror(errno));
312  exit(EXIT_FAILURE);
313  }
314 
315  // calibrate ADC reference voltage
316  rl_log(RL_LOG_INFO, "Performing ADC reference calibration.");
318 
319  // daemon main loop
320  rl_log(RL_LOG_INFO, "RocketLogger daemon running.");
321 
322  daemon_shutdown = false;
323  while (!daemon_shutdown) {
324  // wait for interrupt with infinite timeout
325  int value = gpio_wait_interrupt(gpio_button, NULL);
327  }
328 
329  rl_log(RL_LOG_INFO, "RocketLogger daemon stopped.");
330 
331  // remove shared memory for state
333 
334  // deinitialize and shutdown hardware
335  pwm_deinit();
339  gpio_deinit();
340 
341  // perform requested system action
343  rl_log(RL_LOG_INFO, "Rebooting system.");
344  sync();
345  reboot(RB_AUTOBOOT);
346  } else if(system_action == SYSTEM_ACTION_POWEROFF) {
347  rl_log(RL_LOG_INFO, "Powering off system.");
348  sync();
349  reboot(RB_POWER_OFF);
350  }
351 
352  exit(EXIT_SUCCESS);
353 }
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
void rl_status_reset(rl_status_t *const status)
Definition: rl.c:535
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
bool sampling
Sampling state, true: sampling, false: idle.
Definition: rl.h:203