minimize time to trinket is opened
[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 int              tics = 1;
43 static char*    pidfile = NULL;
44 static char*    logfile = NULL;
45 static bool             daemonize = false;
46 static char             tfile[MAXPATHLEN],
47                                 ofile[MAXPATHLEN];
48
49 static const double coefficient = (248e-6 / 2637.0);
50
51 static void
52 usage(const char *errmsg) {
53         puts("trinketd - collecting info from AtomPro");
54         puts("Copyright (c) 2016, Teodor Sigaev <teodor@sigaev.ru>");
55         puts("trinketd [-d] [-l logfile] [-p pidfile] [-P period] [-D datadir] [-i tics]");
56
57         if (errmsg) {
58                 puts("");
59                 puts(errmsg);
60         }
61
62         exit(1);
63 }
64
65 static void
66 main_loop() {
67         double  *prevDose,
68                         curDose;
69         int             i;
70         int             collected = 0;
71
72         prevDose = malloc(sizeof(*prevDose) * (tics + 1));
73         if (!prevDose) {
74                 fprintf(stderr, "could not allocate array, exiting...\n");
75                 return;
76         }
77
78         while(42) {
79
80                 if (trinketOpen() != ERR_OK) {
81                         fprintf(stderr, "trinketOpen fails\n");
82                         sleep(1);
83                         continue;
84                 }
85
86                 if (trinketGetCumDose(&curDose) != ERR_OK) {
87                         fprintf(stderr, "trinketGetCumDose fails\n");
88                         trinketClose();
89                         sleep(1);
90                         continue;
91                 }
92
93                 trinketClose();
94
95                 if (collected <= tics) {
96                         prevDose[collected++] = curDose;
97                 } else {
98                         for (i=1; i<=tics; i++)
99                                 prevDose[i - 1] = prevDose[i];
100                         prevDose[tics] = curDose;
101                 }
102
103                 if (collected > 1) {
104                         double  counts = curDose - prevDose[0];
105                         double  radlevel = 1e6 * coefficient * counts * 3600.0 /
106                                                                 (double)(period * (collected - 1));
107                         FILE    *fh = stdout;
108                         bool    successOpen = true;
109
110                         if (daemonize) {
111                                 if ((fh = fopen(tfile, "w")) == NULL) {
112                                         fprintf(stderr, "fopen fails\n");
113                                         successOpen = false;
114                                 }
115                         }
116
117                         if (successOpen) {
118                                 fprintf(fh, "total: %lld\n", (long long)curDose);
119                                 fprintf(fh, "counts: %lld\n", (long long)counts);
120                                 fprintf(fh, "tics: %d\n", collected - 1);
121                                 fprintf(fh, "radlevel: %.02f\n", radlevel);
122                         }
123
124                         if (fh && fh != stdout) {
125                                 fflush(fh);
126                                 fclose(fh);
127                                 rename(tfile, ofile);
128                         }
129                 }
130
131                 sleep(period);
132         }
133 }
134
135
136 extern char *optarg;
137 extern int opterr, optind;
138
139 int
140 main(int argn, char* argv[]) {
141         int i;
142         int     pidfd,
143                 logfd;
144
145         opterr = 0;
146         while((i=getopt(argn,argv,"dD:i:l:p:P:h")) != EOF) {
147                 switch(i) {
148                         case 'd':
149                                 daemonize = true;
150                                 break;
151                         case 'D':
152                                 dbdir = strdup(optarg);
153                                 break;
154                         case 'i':
155                                 tics = atoi(optarg);
156                                 break;
157                         case 'l':
158                                 logfile = strdup(optarg);
159                                 break;
160                         case 'p':
161                                 pidfile = strdup(optarg);
162                                 break;
163                         case 'P':
164                                 period = atoi(optarg);
165                                 break;
166                         case 'h':
167                         default:
168                                 usage(NULL);
169                 }
170         }
171
172         if (opterr || optind != argn)
173                 usage("argument err");
174
175         if (period <= 0)
176                 usage("Collecting period could not be zero nor negative");
177
178         if (tics <= 0)
179                 usage("Number of tics could not be zero nor negative");
180
181         if (daemonize && !dbdir)
182                 usage("trinketd: it is useless to use -d without -D");
183
184         if (dbdir && strlen(dbdir) > MAXPATHLEN - 32)
185                 usage("datadir is too long");
186
187         if (pidfile) {
188                 pidfd = open(pidfile, O_CREAT | O_WRONLY | O_TRUNC, 0666);
189                 if (pidfd < 0)
190                         usage("could not write pidfile");
191         }
192
193         if (logfile) {
194                 logfd = open(logfile, O_CREAT | O_WRONLY | O_APPEND, 0666);
195                 if (logfd < 0)
196                         usage("could not write logfile");
197         }
198
199         if (daemonize) {
200                 if (daemon(0, 0) == -1)
201                         usage("could not daemonize");
202         }
203
204         if (pidfile) {
205                 char pid[64];
206
207                 snprintf(pid, sizeof(pid), "%lld", (long long)getpid());
208                 if (write(pidfd, pid, strlen(pid)) != strlen(pid))
209                         usage("could not write pid");
210                 close(pidfd);
211         }
212
213         if (logfile) {
214                 dup2(logfd, fileno(stderr));
215                 close(logfd);
216         }
217
218         if (hid_init() < 0) {
219                 fprintf(stderr, "hid_init fails\n");
220                 exit(1);
221         }
222
223         if (dbdir) {
224                 snprintf(tfile, MAXPATHLEN, "%s/trinket.tmp", dbdir);
225                 snprintf(ofile, MAXPATHLEN, "%s/trinket.dat", dbdir);
226         }
227
228         main_loop();
229
230         hid_exit();
231         return 0;
232 }