350 lines
9.9 KiB
C
350 lines
9.9 KiB
C
/*
|
|
* Copyright 2018 Christoph Haas
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify it
|
|
* under the terms of the standard MIT license. See LICENSE for more details.
|
|
*/
|
|
|
|
#include "gclogger.h"
|
|
|
|
extern char *optarg;
|
|
extern int optind;
|
|
|
|
static volatile bool running = true;
|
|
|
|
static int confighandler(void* config, const char* section, const char* name, const char* value) {
|
|
configuration* pconfig = (configuration*)config;
|
|
|
|
#define MATCH(s, n) strcmp(section, s) == 0 && strcmp(name, n) == 0
|
|
if (MATCH("device", "port")) {
|
|
pconfig->dev_port = strdup(value);
|
|
} else if (MATCH("device", "baud")) {
|
|
pconfig->dev_baud = atoi(value);
|
|
} else if (MATCH("device", "location")) {
|
|
pconfig->dev_location = strdup(value);
|
|
} else if (MATCH("device", "latitude")) {
|
|
pconfig->dev_latitude = atof(value);
|
|
} else if (MATCH("device", "longitude")) {
|
|
pconfig->dev_longitude = atof(value);
|
|
} else if (MATCH("device", "interval")) {
|
|
pconfig->dev_interval = atoi(value);
|
|
} else if (MATCH("custlog", "url")) {
|
|
pconfig->custlog_url = strdup(value);
|
|
} else if (MATCH("custlog", "type")) {
|
|
pconfig->custlog_type = strdup(value);
|
|
} else if (MATCH("custlog", "id")) {
|
|
pconfig->custlog_id = strdup(value);
|
|
} else if (MATCH("custlog", "param_id")) {
|
|
pconfig->custlog_param_id = strdup(value);
|
|
} else if (MATCH("custlog", "param_cpm")) {
|
|
pconfig->custlog_param_cpm = strdup(value);
|
|
} else if (MATCH("custlog", "param_temp")) {
|
|
pconfig->custlog_param_temp = strdup(value);
|
|
} else if (MATCH("custlog", "param_lng")) {
|
|
pconfig->custlog_param_lng = strdup(value);
|
|
} else if (MATCH("custlog", "param_lat")) {
|
|
pconfig->custlog_param_lat = strdup(value);
|
|
} else if (MATCH("custlog", "param_loc")) {
|
|
pconfig->custlog_param_loc = strdup(value);
|
|
} else if (MATCH("custlog", "param_version")) {
|
|
pconfig->custlog_param_version = strdup(value);
|
|
} else if (MATCH("custlog", "param_time")) {
|
|
pconfig->custlog_param_time = strdup(value);
|
|
} else if (MATCH("csv", "path")) {
|
|
pconfig->csv_path = strdup(value);
|
|
} else {
|
|
return 0; /* unknown section/name, error */
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
bool str_isset(char *str) {
|
|
return str != NULL && str[0] != '\0';
|
|
}
|
|
|
|
void init_configuration(configuration* config) {
|
|
config->debug = false;
|
|
|
|
config->dev_port = "";
|
|
config->dev_baud = 115200;
|
|
config->dev_location = "";
|
|
config->dev_latitude = 0.0;
|
|
config->dev_longitude = 0.0;
|
|
config->dev_interval = 60;
|
|
config->custlog_url = "";
|
|
config->custlog_type = "GET";
|
|
config->custlog_id = "";
|
|
config->custlog_param_id = "id";
|
|
config->custlog_param_cpm = "cpm";
|
|
config->custlog_param_temp = "temp";
|
|
config->custlog_param_lng = "lng";
|
|
config->custlog_param_lat = "lat";
|
|
config->custlog_param_loc = "loc";
|
|
config->custlog_param_version = "version";
|
|
config->custlog_param_time = "time";
|
|
config->csv_path = "";
|
|
}
|
|
|
|
void signal_handler(int sig) {
|
|
switch (sig) {
|
|
case SIGTERM:
|
|
case SIGINT:
|
|
case SIGQUIT:
|
|
case SIGHUP:
|
|
running = false;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
bool send_custlog(const configuration config, int cpm, float temperature, const char *version, struct tm *tm) {
|
|
CURL *curl;
|
|
CURLcode res;
|
|
|
|
curl = curl_easy_init();
|
|
|
|
if(curl) {
|
|
char *url_buffer = NULL;
|
|
size_t url_size;
|
|
char *post_buffer = NULL;
|
|
size_t post_size;
|
|
|
|
if(strncmp(config.custlog_type, "GET", 3) == 0) {
|
|
// first get size of final url
|
|
url_size = snprintf(NULL, 0, "%s?%s=%s&%s=%d&%s=%f&%s=%s&%s=%ld&%s=%f&%s=%f&%s=%s",
|
|
config.custlog_url,
|
|
config.custlog_param_id, config.custlog_id,
|
|
config.custlog_param_cpm, cpm,
|
|
config.custlog_param_temp, temperature,
|
|
config.custlog_param_version, version,
|
|
config.custlog_param_time, mktime(tm),
|
|
config.custlog_param_lng, config.dev_longitude,
|
|
config.custlog_param_lat, config.dev_latitude,
|
|
config.custlog_param_loc, config.dev_location);
|
|
|
|
// now allocate buffer and build url
|
|
url_buffer = (char *)malloc(url_size + 1);
|
|
snprintf(url_buffer, url_size+1,"%s?%s=%s&%s=%d&%s=%f&%s=%s&%s=%ld&%s=%f&%s=%f&%s=%s",
|
|
config.custlog_url,
|
|
config.custlog_param_id, config.custlog_id,
|
|
config.custlog_param_cpm, cpm,
|
|
config.custlog_param_temp, temperature,
|
|
config.custlog_param_version, version,
|
|
config.custlog_param_time, mktime(tm),
|
|
config.custlog_param_lng, config.dev_longitude,
|
|
config.custlog_param_lat, config.dev_latitude,
|
|
config.custlog_param_loc, config.dev_location);
|
|
|
|
if(config.debug) {
|
|
printf("Final url: %s\n", url_buffer);
|
|
}
|
|
} else {
|
|
url_buffer = strdup(config.custlog_url);
|
|
}
|
|
|
|
curl_easy_setopt(curl, CURLOPT_URL, url_buffer);
|
|
|
|
if(strncmp(config.custlog_type, "POST", 4) == 0) {
|
|
// first get size of final url
|
|
post_size = snprintf(NULL, 0, "%s=%s&%s=%d&%s=%f&%s=%s&%s=%ld&%s=%f&%s=%f&%s=%s",
|
|
config.custlog_param_id, config.custlog_id,
|
|
config.custlog_param_cpm, cpm,
|
|
config.custlog_param_temp, temperature,
|
|
config.custlog_param_version, version,
|
|
config.custlog_param_time, mktime(tm),
|
|
config.custlog_param_lng, config.dev_longitude,
|
|
config.custlog_param_lat, config.dev_latitude,
|
|
config.custlog_param_loc, config.dev_location);
|
|
|
|
// now allocate buffer and build url
|
|
post_buffer = (char *)malloc(post_size + 1);
|
|
snprintf(post_buffer, post_size+1,"%s=%s&%s=%d&%s=%f&%s=%s&%s=%ld&%s=%f&%s=%f&%s=%s",
|
|
config.custlog_param_id, config.custlog_id,
|
|
config.custlog_param_cpm, cpm,
|
|
config.custlog_param_temp, temperature,
|
|
config.custlog_param_version, version,
|
|
config.custlog_param_time, mktime(tm),
|
|
config.custlog_param_lng, config.dev_longitude,
|
|
config.custlog_param_lat, config.dev_latitude,
|
|
config.custlog_param_loc, config.dev_location);
|
|
|
|
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, post_buffer);
|
|
}
|
|
|
|
#ifdef SKIP_PEER_VERIFICATION
|
|
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);
|
|
#endif
|
|
|
|
#ifdef SKIP_HOSTNAME_VERIFICATION
|
|
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L);
|
|
#endif
|
|
|
|
res = curl_easy_perform(curl);
|
|
if(res != CURLE_OK)
|
|
printf("curl_easy_perform() failed: %s\n", curl_easy_strerror(res));
|
|
else
|
|
printf("curl_easy_perform() ok!");
|
|
|
|
free(url_buffer);
|
|
if(post_buffer != NULL)
|
|
free(post_buffer);
|
|
curl_easy_cleanup(curl);
|
|
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool send_tocsv(const configuration config, int cpm, float temperature, const char *version, const struct tm *tm) {
|
|
FILE *fp;
|
|
|
|
if ((fp = fopen(config.csv_path, "a")) == NULL) {
|
|
printf("Error while opening the csv file '%s'.\n", config.csv_path);
|
|
return false;
|
|
}
|
|
|
|
char *ts = asctime(tm);
|
|
ts[strlen(ts) - 1] = 0; // get rid of \n
|
|
fprintf(fp, "%s,%d,%07.3f,%s\n", ts, cpm, temperature, version);
|
|
|
|
fclose(fp);
|
|
|
|
return true;
|
|
}
|
|
|
|
void show_usage() {
|
|
printf("Geiger Counter Logger\n");
|
|
printf("Version %s\n", GCLOGGER_VERSION);
|
|
printf("Copyright (C) 2018 Christoph Haas, christoph.h@sprinternet.at\n\n");
|
|
printf("This program comes with ABSOLUTELY NO WARRANTY.\n");
|
|
printf("This is free software, and you are welcome to redistribute it.\n\n");
|
|
printf("Usage: gclogger -c <file> [-d]\n");
|
|
printf(" -c <file> configuration file path\n");
|
|
printf(" -d enable verbose mode\n\n");
|
|
}
|
|
|
|
int main(int argc, char *argv[]) {
|
|
int opt = 0;
|
|
int gc_fd = -1;
|
|
configuration config;
|
|
|
|
// setup signal handlers
|
|
signal(SIGTERM, signal_handler);
|
|
signal(SIGINT, signal_handler);
|
|
signal(SIGQUIT, signal_handler);
|
|
signal(SIGHUP, signal_handler);
|
|
|
|
// setup curl
|
|
curl_global_init(CURL_GLOBAL_DEFAULT);
|
|
|
|
// parse config file
|
|
init_configuration(&config);
|
|
while ((opt = getopt(argc, argv, "c:d")) != -1) {
|
|
switch (opt) {
|
|
case 'd':
|
|
config.debug = true;
|
|
break;
|
|
|
|
case 'c':
|
|
if (ini_parse(optarg, confighandler, &config) < 0) {
|
|
printf("Can't load config file '%s'\n", optarg);
|
|
return 1;
|
|
}
|
|
printf("Config loaded from '%s': device_port=%s, interval=%d\n",
|
|
optarg, config.dev_port, config.dev_interval);
|
|
break;
|
|
|
|
default: /* '?' */
|
|
show_usage();
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
}
|
|
|
|
// additional check if extra/no arguments where given
|
|
if (optind < argc || argc == 1) {
|
|
show_usage();
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
|
|
// check if device port is set
|
|
if(!str_isset(config.dev_port)) {
|
|
printf("Device port must be set!'\n");
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
|
|
gc_fd = gmc_open(config.dev_port, config.dev_baud);
|
|
|
|
// check if device connection was successful
|
|
if(gc_fd == -1) {
|
|
printf("Connection to device (%s) failed!'\n", config.dev_port);
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
|
|
// read version
|
|
char version[15] = { 0 };
|
|
if(gmc_get_version(gc_fd, version) == -1) {
|
|
printf("Unable to read Geiger counter version!'\n");
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
|
|
if (config.debug) {
|
|
printf("GC VERSION: %s\n", version);
|
|
}
|
|
|
|
time_t last = time(NULL);
|
|
int cpm, sum = 0, count = 0, tcount = 0;
|
|
float temperature, tsum = 0;
|
|
|
|
// main loop
|
|
while (running) {
|
|
// read cpm
|
|
if ((cpm = gmc_get_cpm(gc_fd)) > 0) {
|
|
sum += cpm;
|
|
count++;
|
|
}
|
|
|
|
// read temperature
|
|
tsum += gmc_get_temperature(gc_fd);
|
|
tcount++;
|
|
|
|
if (difftime(time(NULL), last) >= config.dev_interval) {
|
|
if (count > 0) {
|
|
struct tm *tm = gmtime(&last);
|
|
cpm = sum / count;
|
|
temperature = tsum / tcount;
|
|
|
|
if (config.debug) {
|
|
printf("CPM: %d (= %d/%d), TEMP: %07.3f, Timestamp: %s\n", cpm, sum, count, temperature, asctime(tm));
|
|
}
|
|
|
|
// log to custom REST api
|
|
if (str_isset(config.custlog_url)) {
|
|
printf("Uploading to %s.\n", config.custlog_url);
|
|
if(!send_custlog(config, cpm, temperature, version, tm)) {
|
|
printf("Upload to %s failed.\n", config.custlog_url);
|
|
}
|
|
}
|
|
|
|
// log to csv
|
|
if (str_isset(config.csv_path)) {
|
|
if(!send_tocsv(config, cpm, temperature, version, tm)) {
|
|
printf("Logging to %s failed.\n", config.csv_path);
|
|
}
|
|
}
|
|
|
|
time(&last);
|
|
sum = tsum = count = tcount = 0;
|
|
} else {
|
|
printf("Reading ZERO value from Geiger tube.\n");
|
|
}
|
|
}
|
|
|
|
sleep(1); // sleep one second
|
|
}
|
|
|
|
gmc_close(gc_fd);
|
|
|
|
return EXIT_SUCCESS;
|
|
}
|