fmscan: Correctly calculate percentages for display during scan.
[fmtools.git] / fm.c
blobbe76ce12d08895789969813b99b56139b38dc56c
1 /* fm.c - simple V4L2 compatible tuner for radio cards
3 Copyright (C) 2004, 2006, 2009 Ben Pfaff <blp@cs.stanford.edu>
4 Copyright (C) 1998 Russell Kroll <rkroll@exploits.org>
6 This program is free software; you can redistribute it and/or modify it
7 under the terms of the GNU General Public License as published by the Free
8 Software Foundation; either version 2 of the License, or (at your option)
9 any later version.
11 This program is distributed in the hope that it will be useful, but WITHOUT
12 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
14 more details.
16 You should have received a copy of the GNU General Public License along with
17 this program. If not, see <http://www.gnu.org/licenses/>.
20 #include <math.h>
21 #include <errno.h>
22 #include <stdio.h>
23 #include <fcntl.h>
24 #include <stdbool.h>
25 #include <stdint.h>
26 #include <stdlib.h>
27 #include <unistd.h>
28 #include <getopt.h>
29 #include <string.h>
30 #include <limits.h>
32 #include "fmlib.h"
34 #define DEFAULT_DEVICE "/dev/radio0"
36 static double
37 clamp(double percent)
39 return percent < 0.0 ? 0.0 : percent > 100.0 ? 100.0 : percent;
42 static int
43 convert_time (const char *string)
45 if (strcmp(string, "forever") == 0 ||
46 strcmp(string, "-") == 0 ||
47 atoi(string) < 0)
48 return 0;
49 else if (strcmp(string, "none") == 0 ||
50 strcmp(string, "0") == 0)
51 return -1;
52 else
54 char worktime[80+1];
55 int inttime;
56 const char *suffix;
58 suffix = string + strspn(string, "0123456789");
60 strncpy(worktime, string, suffix - string);
61 worktime[suffix - string] = '\0';
62 inttime = atoi(worktime);
64 switch (*suffix)
66 case 's':
67 case '\0':
68 break;
69 case 'm':
70 inttime *= 60;
71 break;
72 case 'h':
73 inttime *= 60 * 60;
74 break;
75 case 'd':
76 inttime *= 24 * 60 * 60;
77 break;
78 default:
79 break;
82 return inttime;
88 static char *
89 format_time (char *buffer, const char *string)
91 if (strcmp(string, "forever") == 0 ||
92 strcmp(string, "-") == 0 ||
93 atoi(string) < 0)
94 strcpy(buffer, "forever");
95 else if (strcmp(string, "none") == 0 ||
96 strcmp(string, "0") == 0)
97 strcpy(buffer, "none");
98 else
100 char worktime[80+1];
101 const char *suffix;
102 char *format;
103 int int_time;
105 suffix = string + strspn(string, "0123456789");
106 strncpy(worktime, string, suffix - string);
107 worktime[suffix - string] = '\0';
108 int_time = atoi(worktime);
110 switch (*suffix)
112 case 'm':
113 format = "%d minute(s)";
114 break;
115 case 'h':
116 format = "%d hour(s)";
117 break;
118 case 'd':
119 format = "%d day(s)";
120 break;
121 case 's':
122 case '\0':
123 default:
124 format = "%d second(s)";
125 break;
128 sprintf(buffer, format, int_time);
131 return buffer;
134 static void
135 maybe_sleep(const struct tuner *tuner, const char *wait_time)
137 char message[80+1];
138 int int_wait_time;
140 int_wait_time = convert_time(wait_time);
142 if (int_wait_time > 0)
144 printf("Sleeping for %s\n", format_time(message, wait_time));
145 tuner_sleep(tuner, int_wait_time);
146 } else if (int_wait_time == 0)
148 printf("Sleeping forever...CTRL-C exits\n");
149 for (;;)
150 pause();
154 static void
155 usage(void)
157 printf("fmtools fm version %s\n\n", VERSION);
158 printf("usage: %s [-h] [-o] [-q] [-d <dev>] [-t <tuner>] "
159 "[-T none|forever|time] <freq>|on|off [<volume>]\n\n",
160 program_name);
161 printf("A small controller for Video for Linux radio devices.\n\n");
162 printf(" -h display this help\n");
163 printf(" -o override frequency range limits of card\n");
164 printf(" -q quiet mode\n");
165 printf(" -d <dev> select device (default: /dev/radio0)\n");
166 printf(" -t <tuner> select tuner (default: 0)\n");
167 printf(" -T <time> after setting frequency, sleep for some time\n"\
168 " (default: none; -=forever)\n");
169 printf(" <freq> frequency in MHz (i.e. 94.3)\n");
170 printf(" on turn radio on\n");
171 printf(" off turn radio off (mute)\n");
172 printf(" + increase volume\n");
173 printf(" - decrease volume\n");
174 printf(" <volume> percentage (0-100)\n");
175 exit(EXIT_SUCCESS);
178 static void
179 getconfig(const char *fn,
180 double *defaultvol, double *increment, char *wait_time)
182 FILE *conf;
183 char buf[256];
185 if (!fn) {
186 snprintf(buf, sizeof buf, "%s/.fmrc", getenv("HOME"));
187 fn = buf;
189 conf = fopen(fn, "r");
191 if (!conf)
192 return;
194 while(fgets(buf, sizeof(buf), conf)) {
195 buf[strlen(buf)-1] = 0;
196 if (!strncmp(buf, "VOL", 3))
197 sscanf(buf, "%*s %lf", defaultvol);
198 if (!strncmp(buf, "INCR", 3))
199 sscanf(buf, "%*s %lf", increment);
200 if (!strncmp(buf, "TIME", 4))
201 sscanf(buf, "%*s %s", wait_time);
204 fclose(conf);
207 int main(int argc, char **argv)
209 struct tuner tuner;
210 const char *device = NULL;
211 int index = 0;
212 bool quiet = false;
213 bool override = false;
214 const char *config_file = NULL;
215 double defaultvol = 12.5;
216 double increment = 10;
217 char wait_time_buf[256+1] = "";
218 const char *wait_time = NULL;
220 program_name = argv[0];
222 /* need at least a frequency */
223 if (argc < 2)
224 fatal(0, "usage: %s [-h] [-o] [-q] [-d <dev>] [-t <tuner>] "
225 "[-T time|forever|none] "
226 "<freq>|on|off [<volume>]\n", program_name);
228 for (;;) {
229 int option = getopt(argc, argv, "+qhot:T:c:d:");
230 if (option == -1)
231 break;
233 switch (option) {
234 case 'q':
235 quiet = 1;
236 break;
237 case 'o':
238 override = 1;
239 break;
240 case 't':
241 index = atoi(optarg);
242 break;
243 case 'T':
244 wait_time = optarg;
245 break;
246 case 'd':
247 device = optarg;
248 break;
249 case 'c':
250 config_file = optarg;
251 break;
252 case 'h':
253 default:
254 usage();
255 break;
259 getconfig(config_file, &defaultvol, &increment, wait_time_buf);
260 if (!wait_time)
261 wait_time = *wait_time_buf ? wait_time_buf : "none";
263 argc -= optind;
264 argv += optind;
266 if (argc == 0) /* no frequency, on|off, or +|- given */
267 usage();
269 tuner_open(&tuner, device, index);
271 if (!strcmp(argv[0], "off")) {
272 tuner_set_mute(&tuner, true);
273 if (!quiet)
274 printf("Radio muted\n");
275 } else if (!strcmp(argv[0], "on")) {
276 tuner_set_mute(&tuner, false);
277 if (!quiet)
278 printf("Radio on at %.2f%% volume\n",
279 tuner_get_volume(&tuner));
280 } else if (!strcmp(argv[0], "+") || !strcmp(argv[0], "-")) {
281 double new_volume = tuner_get_volume(&tuner);
282 if (argv[0][0] == '+')
283 new_volume += increment;
284 else
285 new_volume -= increment;
286 new_volume = clamp(new_volume);
288 if (!quiet)
289 printf("Setting volume to %.2f%%\n",
290 new_volume);
292 tuner_set_volume(&tuner, new_volume);
293 } else if (atof(argv[0])) {
294 double frequency = atof(argv[0]);
295 double volume = argc > 1 ? clamp(atof(argv[1])) : defaultvol;
296 tuner_set_freq(&tuner, frequency * 16000.0, override);
297 tuner_set_volume(&tuner, volume);
298 if (!quiet)
299 printf("Radio tuned to %2.2f MHz at %.2f%% volume\n",
300 frequency, volume);
301 } else {
302 fatal(0, "unrecognized command syntax; use --help for help");
304 maybe_sleep(&tuner, wait_time);
305 tuner_close(&tuner);
306 return 0;