tweak counting
[trinked.git] / main.c
1 /*-------------------------------------------------------------------------
2  * main.c
3  *
4  * Copyright (c) 2016, Teodor Sigaev <teodor@sigaev.ru>
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25  * SUCH DAMAGE.
26  *-------------------------------------------------------------------------
27  */
28
29 #include <fcntl.h>
30 #include <stdbool.h>
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <string.h>
34 #include <unistd.h>
35 #include <hidapi/hidapi.h>
36 #include <sys/param.h>
37
38 #include <trinket.h>
39
40 static char*    dbdir = NULL;
41 static int              period = (300); /* in seconds */
42 static char*    pidfile = NULL;
43 static char*    logfile = NULL;
44 static bool             daemonize = false;
45 static char             tfile[MAXPATHLEN],
46                                 ofile[MAXPATHLEN];
47
48 static const double coefficient = (248e-6 / 2637.0);
49
50 static void
51 usage(const char *errmsg) {
52         puts("trinketd - collecting info from AtomPro");
53         puts("Copyright (c) 2016, Teodor Sigaev <teodor@sigaev.ru>");
54         puts("trinketd [-d] [-l logfile] [-p pidfile] [-P period] [-D datadir]");
55
56         if (errmsg) {
57                 puts("");
58                 puts(errmsg);
59         }
60
61         exit(1);
62 }
63
64 static void
65 main_loop() {
66         double  prevDose,
67                         curDose;
68
69 restart:
70         prevDose = -1;
71
72         if (trinketOpen() != ERR_OK) {
73                 fprintf(stderr, "trinketOpen fails\n");
74                 sleep(1);
75                 goto restart;
76         }
77
78         while(42 && stopRequest == false) {
79                 if (trinketGetCumDose(&curDose) != ERR_OK) {
80                         fprintf(stderr, "trinketGetCumDose fails\n");
81                         trinketClose();
82                         sleep(1);
83                         goto restart;
84                 }
85
86                 if (prevDose >= 0.0) {
87                         double  counts = curDose - prevDose;
88                         double  radlevel = coefficient * counts * 3600.0 / (double)period;
89                         FILE    *fh = stdout;
90                         bool    successOpen = true;
91
92                         if (daemonize) {
93                                 if ((fh = fopen(tfile, "w")) == NULL) {
94                                         fprintf(stderr, "fopen fails\n");
95                                         successOpen = false;
96                                 }
97                         }
98
99                         if (successOpen) {
100                                 fprintf(fh, "total: %lld\n", (long long)curDose);
101                                 fprintf(fh, "counts: %lld\n", (long long)counts);
102                                 fprintf(fh, "radlevel: %e\n", radlevel);
103                         }
104
105                         if (fh && fh != stdout) {
106                                 fflush(fh);
107                                 fclose(fh);
108                                 rename(tfile, ofile);
109                         }
110                 }
111
112                 prevDose = curDose;
113                 sleep(period);
114         }
115
116         trinketClose();
117 }
118
119
120 extern char *optarg;
121 extern int opterr, optind;
122
123 int
124 main(int argn, char* argv[]) {
125         int i;
126         int     pidfd,
127                 logfd;
128
129         opterr = 0;
130         while((i=getopt(argn,argv,"dD:p:P:h")) != EOF) {
131                 switch(i) {
132                         case 'd':
133                                 daemonize = true;
134                                 break;
135                         case 'D':
136                                 dbdir = strdup(optarg);
137                                 break;
138                         case 'p':
139                                 pidfile = strdup(optarg);
140                                 break;
141                         case 'P':
142                                 period = atoi(optarg);
143                                 break;
144                         case 'h':
145                         default:
146                                 usage(NULL);
147                 }
148         }
149
150         if (opterr || optind != argn)
151                 usage("argument err");
152
153         if (period <= 0)
154                 usage("Collecting period could not be zero nor negative");
155
156         if (daemonize && !dbdir)
157                 usage("trinketd: it is useless to use -d without -D");
158
159         if (dbdir && strlen(dbdir) > MAXPATHLEN - 32)
160                 usage("datadir is too long");
161
162         if (pidfile) {
163                 pidfd = open(pidfile, O_CREAT | O_WRONLY | O_TRUNC, 0666);
164                 if (pidfd < 0)
165                         usage("could not write pidfile");
166         }
167
168         if (logfile) {
169                 logfd = open(logfile, O_CREAT | O_WRONLY | O_APPEND, 0666);
170                 if (logfd < 0)
171                         usage("could not write logfile");
172         }
173
174         if (daemonize) {
175                 if (daemon(0, 0) == -1)
176                         usage("could not daemonize");
177         }
178
179         if (pidfile) {
180                 char pid[64];
181
182                 snprintf(pid, sizeof(pid), "%lld", (long long)getpid());
183                 if (write(pidfd, pid, strlen(pid)) != strlen(pid))
184                         usage("could not write pid");
185                 close(pidfd);
186         }
187
188         if (logfile) {
189                 dup2(logfd, fileno(stderr));
190                 close(logfd);
191         }
192
193         if (hid_init() < 0) {
194                 fprintf(stderr, "hid_init fails\n");
195                 exit(1);
196         }
197
198         if (dbdir) {
199                 snprintf(tfile, MAXPATHLEN, "%s/trinket.tmp", dbdir);
200                 snprintf(ofile, MAXPATHLEN, "%s/trinket.dat", dbdir);
201         }
202
203         main_loop();
204
205         hid_exit();
206         return 0;
207 }