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