First commit
This commit is contained in:
commit
0a28bac78a
37 changed files with 1963 additions and 0 deletions
325
gclog.c
Normal file
325
gclog.c
Normal file
|
|
@ -0,0 +1,325 @@
|
|||
#ifndef _GNU_SOURCE
|
||||
#define _GNU_SOURCE
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <signal.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
#include "logger.h"
|
||||
#include "ini.h"
|
||||
#include "diygeiger.h"
|
||||
#include "gqgeiger.h"
|
||||
#include "tcpcli.h"
|
||||
|
||||
#define GCLOG_VERSION "0.2.3"
|
||||
#define GCLOG_BUILD "2016-02-28"
|
||||
#define BUF_SIZE 1000
|
||||
#ifndef MIN
|
||||
#define MIN(a,b) ((a)<(b)?(a):(b))
|
||||
#endif
|
||||
#ifndef MAX
|
||||
#define MAX(a,b) ((a)>(b)?(a):(b))
|
||||
#endif
|
||||
|
||||
enum EGeiger { SIM, DIY, GQ };
|
||||
static const char *GeigerNames[] = { "Geiger simulator", "DIY/MyGeiger/NET-IO Geiger Kit", "GQ GMC Geiger Counter" };
|
||||
static volatile bool Running = true;
|
||||
|
||||
int div_round_closest(int n, int d) {
|
||||
return (n < 0) ^ (d < 0) ? (n - d/2) / d : (n + d/2) / d;
|
||||
}
|
||||
|
||||
char * string_copy(const char *src) {
|
||||
char *dst = calloc(strlen(src) + 1, sizeof(char));
|
||||
strcpy(dst, src);
|
||||
|
||||
return dst;
|
||||
}
|
||||
|
||||
bool string_isset(char *str) {
|
||||
return str != NULL && strlen(str) > 0;
|
||||
}
|
||||
|
||||
void try_free(char *buf) {
|
||||
if (buf != NULL)
|
||||
free(buf);
|
||||
}
|
||||
|
||||
void signal_handler(int sig) {
|
||||
switch (sig) {
|
||||
case SIGTERM:
|
||||
case SIGINT:
|
||||
case SIGQUIT:
|
||||
case SIGHUP:
|
||||
Running = false;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
int geiger_open(enum EGeiger type, const char *device) {
|
||||
int fd = -1;
|
||||
time_t t = time(NULL);
|
||||
struct tm *tm = gmtime(&t);
|
||||
|
||||
if (type == GQ) {
|
||||
if ((fd = gq_open(device)) != -1) {
|
||||
gq_set_date(fd, tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday);
|
||||
gq_set_time(fd, tm->tm_hour, tm->tm_min, tm->tm_sec);
|
||||
}
|
||||
}
|
||||
else if (type == DIY) {
|
||||
fd = diy_open(device);
|
||||
}
|
||||
else if (type == SIM) {
|
||||
fd = STDIN_FILENO;
|
||||
}
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
void geiger_close(enum EGeiger type, int device) {
|
||||
if (type == GQ)
|
||||
gq_close(device);
|
||||
else if (type == DIY)
|
||||
diy_close(device);
|
||||
}
|
||||
|
||||
int geiger_get_cpm(enum EGeiger type, int device) {
|
||||
if (type == GQ)
|
||||
return gq_get_cpm(device);
|
||||
else if (type == DIY)
|
||||
return diy_get_cpm(device);
|
||||
else if (type == SIM)
|
||||
return 12; // Guaranteed to be random. :-)
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool send_netc(const char *id, int cpm) {
|
||||
char *req;
|
||||
int sock;
|
||||
char buf[BUF_SIZE] = { 0 };
|
||||
|
||||
asprintf(&req, "GET /push.php?id=%s&v=w32_1.1.3.1085&c=%d HTTP/1.1\r\nHost: radiation.netc.com\r\n\r\n", id, cpm);
|
||||
|
||||
if ((sock = tcp_connect("radiation.netc.com", "80")) != -1) {
|
||||
tcp_send(sock, req);
|
||||
tcp_receive(sock, buf, BUF_SIZE);
|
||||
tcp_close(sock);
|
||||
}
|
||||
|
||||
free(req);
|
||||
|
||||
return sock != -1 && strstr(buf, "Ok.") != NULL;
|
||||
}
|
||||
|
||||
bool send_radmon(const char *user, const char *pass, int cpm, const struct tm *tm) {
|
||||
char ch[22], *req;
|
||||
int sock;
|
||||
char buf[BUF_SIZE] = { 0 };
|
||||
|
||||
strftime(ch, 22, "%Y-%m-%d%%20%H:%M:%S", tm);
|
||||
asprintf(&req, "GET /radmon.php?user=%s&password=%s&function=submit&datetime=%s&value=%d&unit=CPM HTTP/1.1\r\nHost: www.radmon.org\r\n\r\n", user, pass, ch, cpm);
|
||||
|
||||
if ((sock = tcp_connect("www.radmon.org", "80")) != -1) {
|
||||
tcp_send(sock, req);
|
||||
tcp_receive(sock, buf, BUF_SIZE);
|
||||
tcp_close(sock);
|
||||
}
|
||||
|
||||
free(req);
|
||||
|
||||
return sock != -1 && strstr(buf, "Incorrect login.") == NULL;
|
||||
}
|
||||
|
||||
bool send_safecast(const char *key, unsigned int dev, int cpm, const struct tm *tm, float lat, float lng, const char *loc) {
|
||||
char ch[21], *pld, *req;
|
||||
int sock;
|
||||
char buf[BUF_SIZE] = { 0 };
|
||||
|
||||
strftime(ch, 21, "%Y-%m-%dT%H:%M:%SZ", tm);
|
||||
asprintf(&pld, "{\"latitude\":\"%.4f\",\"longitude\":\"%.4f\",\"location_name\":\"%s\",\"device_id\":\"%u\",\"captured_at\":\"%s\",\"value\":\"%d\",\"unit\":\"cpm\"}", lat, lng, loc, dev, ch, cpm);
|
||||
asprintf(&req, "POST /measurements.json?api_key=%s HTTP/1.1\r\nHost: api.safecast.org\r\nContent-Type: application/json\r\nContent-Length: %zu\r\n\r\n%s", key, strlen(pld), pld);
|
||||
|
||||
if ((sock = tcp_connect("api.safecast.org", "80")) != -1) {
|
||||
tcp_send(sock, req);
|
||||
tcp_receive(sock, buf, BUF_SIZE);
|
||||
tcp_close(sock);
|
||||
}
|
||||
|
||||
free(pld);
|
||||
free(req);
|
||||
|
||||
return sock != -1 && strstr(buf, "201 Created") != NULL;
|
||||
}
|
||||
|
||||
void print_usage() {
|
||||
printf(" ___ Geiger Counter LOGger daemon\n");
|
||||
printf(" \\_/ Version %s (Build %s)\n", GCLOG_VERSION, GCLOG_BUILD);
|
||||
printf(".--,O.--,\n");
|
||||
printf(" \\/ \\/ Copyright (C) 2014-16 Steffen Lange, gclog@stelas.de\n\n");
|
||||
printf("This program comes with ABSOLUTELY NO WARRANTY.\n");
|
||||
printf("This is free software, and you are welcome to redistribute it\n");
|
||||
printf("under certain conditions. See the file COPYING for details.\n\n");
|
||||
printf("Usage: gclog -c <file> [-d]\n");
|
||||
printf(" -c <file> load configuration from file\n");
|
||||
printf(" -d activate verbose mode\n\n");
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
bool debug = false;
|
||||
unsigned int interval = 60;
|
||||
enum EGeiger device_type = SIM;
|
||||
char *device_port = NULL;
|
||||
float latitude = 0.0, longitude = 0.0;
|
||||
char *location = NULL;
|
||||
char *netc_id = NULL;
|
||||
char *radmon_user = NULL, *radmon_pass = NULL;
|
||||
char *safecast_key = NULL;
|
||||
unsigned int safecast_device = 0;
|
||||
|
||||
print_usage();
|
||||
|
||||
pid_t pid;
|
||||
|
||||
if ((pid = fork()) == -1) {
|
||||
fprintf(stderr, "%s: fork() failed.\n", argv[0]);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
if (pid > 0) {
|
||||
// Luke, I'm your father.
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
if (setsid() == -1) {
|
||||
fprintf(stderr, "%s: setsid() failed.\n", argv[0]);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
signal(SIGTERM, signal_handler);
|
||||
signal(SIGINT, signal_handler);
|
||||
signal(SIGQUIT, signal_handler);
|
||||
signal(SIGHUP, signal_handler);
|
||||
|
||||
log_open("gclog");
|
||||
|
||||
int opt;
|
||||
struct map_t *ini;
|
||||
char *val;
|
||||
|
||||
while ((opt = getopt(argc, argv, "c:d")) != -1) {
|
||||
switch (opt) {
|
||||
case 'd':
|
||||
debug = true;
|
||||
break;
|
||||
|
||||
case 'c':
|
||||
ini = load_ini(optarg);
|
||||
if ((val = map_get(ini, "interval")) != NULL)
|
||||
interval = MAX(atoi(val), 1);
|
||||
if ((val = map_get(ini, "device.type")) != NULL) {
|
||||
if (strcmp(val, "sim") == 0)
|
||||
device_type = SIM;
|
||||
else if (strcmp(val, "diy") == 0)
|
||||
device_type = DIY;
|
||||
else if (strcmp(val, "gq") == 0)
|
||||
device_type = GQ;
|
||||
}
|
||||
if ((val = map_get(ini, "device.port")) != NULL)
|
||||
device_port = string_copy(val);
|
||||
if ((val = map_get(ini, "latitude")) != NULL)
|
||||
latitude = MIN(MAX(atof(val), -90.0), 90.0);
|
||||
if ((val = map_get(ini, "longitude")) != NULL)
|
||||
longitude = MIN(MAX(atof(val), -180.0), 180.0);
|
||||
if ((val = map_get(ini, "location")) != NULL)
|
||||
location = string_copy(val);
|
||||
if ((val = map_get(ini, "netc.id")) != NULL)
|
||||
netc_id = string_copy(val);
|
||||
if ((val = map_get(ini, "radmon.user")) != NULL)
|
||||
radmon_user = string_copy(val);
|
||||
if ((val = map_get(ini, "radmon.pass")) != NULL)
|
||||
radmon_pass = string_copy(val);
|
||||
if ((val = map_get(ini, "safecast.key")) != NULL)
|
||||
safecast_key = string_copy(val);
|
||||
if ((val = map_get(ini, "safecast.device")) != NULL)
|
||||
safecast_device = atoi(val);
|
||||
map_free(ini);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (debug)
|
||||
printf("Configuration:\n\t\t%s on %s,\n\t\tLocation: %s (%f, %f)\n\t\tnetc.com: %s,\n\t\tradmon.org: %s / %s,\n\t\tsafecast.org: %s (Device ID %u),\n\t\t%us interval\n\n", GeigerNames[device_type], device_port, location, latitude, longitude, netc_id, radmon_user, radmon_pass, safecast_key, safecast_device, interval);
|
||||
|
||||
int fd = -1;
|
||||
|
||||
if (string_isset(device_port) && ((fd = geiger_open(device_type, device_port)) != -1)) {
|
||||
fclose(stdin);
|
||||
fclose(stdout);
|
||||
fclose(stderr);
|
||||
|
||||
time_t last = time(NULL);
|
||||
int cpm, sum = 0, count = 0;
|
||||
|
||||
while (Running) {
|
||||
if ((cpm = geiger_get_cpm(device_type, fd)) > 0) {
|
||||
sum += cpm;
|
||||
count++;
|
||||
}
|
||||
|
||||
if (difftime(time(NULL), last) >= interval) {
|
||||
if (count > 0) {
|
||||
struct tm *tm = gmtime(&last);
|
||||
cpm = div_round_closest(sum, count);
|
||||
|
||||
if (debug) {
|
||||
char *cpmstr;
|
||||
asprintf(&cpmstr, "CPM: %d (= %d/%d), Timestamp: %s", cpm, sum, count, asctime(tm));
|
||||
log_inform(cpmstr);
|
||||
free(cpmstr);
|
||||
}
|
||||
|
||||
if (string_isset(netc_id))
|
||||
if(!send_netc(netc_id, cpm))
|
||||
log_warn("Upload to netc.com failed.");
|
||||
if (string_isset(radmon_user) && string_isset(radmon_pass))
|
||||
if (!send_radmon(radmon_user, radmon_pass, cpm, tm))
|
||||
log_warn("Upload to radmon.org failed.");
|
||||
if (string_isset(safecast_key) && string_isset(location))
|
||||
if(!send_safecast(safecast_key, safecast_device, cpm, tm, latitude, longitude, location))
|
||||
log_warn("Upload to safecast.org failed.");
|
||||
|
||||
time(&last);
|
||||
sum = count = 0;
|
||||
}
|
||||
else
|
||||
log_exclaim("Reading ZERO value from Geiger tube.");
|
||||
}
|
||||
|
||||
// Let the cpu breathe.
|
||||
sleep(1);
|
||||
}
|
||||
|
||||
geiger_close(device_type, fd);
|
||||
}
|
||||
else
|
||||
perror("FATAL ERROR: Could not access Geiger counter");
|
||||
|
||||
try_free(device_port);
|
||||
try_free(location);
|
||||
try_free(netc_id);
|
||||
try_free(radmon_user);
|
||||
try_free(radmon_pass);
|
||||
try_free(safecast_key);
|
||||
|
||||
log_close();
|
||||
|
||||
return fd == -1 ? EXIT_FAILURE : EXIT_SUCCESS;
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue