athspectral.c revision 244953
1/*
2 * Copyright (c) 2013 Adrian Chadd <adrian@FreeBSD.org>
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 *    notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 *    notice, this list of conditions and the following disclaimer in the
11 *    documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
14 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
17 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23 * SUCH DAMAGE.
24 *
25 * $FreeBSD: head/tools/tools/ath/athspectral/athspectral.c 244953 2013-01-02 04:02:27Z adrian $
26 */
27
28#include "diag.h"
29
30#include "ah.h"
31#include "ah_internal.h"
32
33#ifndef	ATH_DEFAULT
34#define	ATH_DEFAULT	"ath0"
35#endif
36
37#include <getopt.h>
38#include <errno.h>
39#include <err.h>
40#include <stdlib.h>
41#include <string.h>
42#include <ctype.h>
43#include <unistd.h>
44
45struct spectralhandler {
46	struct		ath_diag atd;
47	int		s;
48	struct ifreq	ifr;
49	int		ah_devid;
50};
51
52int
53spectral_opendev(struct spectralhandler *spectral, const char *devid)
54{
55	HAL_REVS revs;
56
57	spectral->s = socket(AF_INET, SOCK_DGRAM, 0);
58	if (spectral->s < 0) {
59		warn("socket");
60		return 0;
61	}
62
63	strncpy(spectral->atd.ad_name, devid, sizeof (spectral->atd.ad_name));
64
65	/* Get the hardware revision, just to verify things are working */
66	spectral->atd.ad_id = HAL_DIAG_REVS;
67	spectral->atd.ad_out_data = (caddr_t) &revs;
68	spectral->atd.ad_out_size = sizeof(revs);
69	if (ioctl(spectral->s, SIOCGATHDIAG, &spectral->atd) < 0) {
70		warn(spectral->atd.ad_name);
71		return 0;
72	}
73	spectral->ah_devid = revs.ah_devid;
74	return 1;
75}
76
77void
78spectral_closedev(struct spectralhandler *spectral)
79{
80	close(spectral->s);
81	spectral->s = -1;
82}
83
84void
85spectralset(struct spectralhandler *spectral, int op, u_int32_t param)
86{
87	HAL_SPECTRAL_PARAM pe;
88
89	pe.ss_fft_period = HAL_SPECTRAL_PARAM_NOVAL;
90	pe.ss_period = HAL_SPECTRAL_PARAM_NOVAL;
91	pe.ss_count = HAL_SPECTRAL_PARAM_NOVAL;
92	pe.ss_short_report = HAL_SPECTRAL_PARAM_NOVAL;
93	pe.ss_spectral_pri = HAL_SPECTRAL_PARAM_NOVAL;
94	pe.ss_fft_period = HAL_SPECTRAL_PARAM_NOVAL;
95	pe.ss_enabled = HAL_SPECTRAL_PARAM_NOVAL;
96	pe.ss_active = HAL_SPECTRAL_PARAM_NOVAL;
97
98	switch (op) {
99	case SPECTRAL_PARAM_FFT_PERIOD:
100		pe.ss_fft_period = param;
101		break;
102	case SPECTRAL_PARAM_SS_PERIOD:
103		pe.ss_period = param;
104		break;
105	case SPECTRAL_PARAM_SS_COUNT:
106		pe.ss_count = param;
107		break;
108	case SPECTRAL_PARAM_SS_SHORT_RPT:
109		pe.ss_short_report = param;
110		break;
111	}
112
113	spectral->atd.ad_id = SPECTRAL_CONTROL_SET_PARAMS | ATH_DIAG_IN;
114	spectral->atd.ad_out_data = NULL;
115	spectral->atd.ad_out_size = 0;
116	spectral->atd.ad_in_data = (caddr_t) &pe;
117	spectral->atd.ad_in_size = sizeof(HAL_SPECTRAL_PARAM);
118	if (ioctl(spectral->s, SIOCGATHSPECTRAL, &spectral->atd) < 0)
119		err(1, spectral->atd.ad_name);
120}
121
122static void
123spectral_get(struct spectralhandler *spectral)
124{
125	HAL_SPECTRAL_PARAM pe;
126
127	spectral->atd.ad_id = SPECTRAL_CONTROL_GET_PARAMS | ATH_DIAG_DYN;
128	memset(&pe, 0, sizeof(pe));
129
130	spectral->atd.ad_in_data = NULL;
131	spectral->atd.ad_in_size = 0;
132	spectral->atd.ad_out_data = (caddr_t) &pe;
133	spectral->atd.ad_out_size = sizeof(pe);
134
135	if (ioctl(spectral->s, SIOCGATHSPECTRAL, &spectral->atd) < 0)
136		err(1, spectral->atd.ad_name);
137
138	printf("Spectral parameters (raw):\n");
139	printf("   ss_enabled: %d\n", pe.ss_enabled);
140	printf("   ss_active: %d\n", pe.ss_active);
141	printf("   ss_count: %d\n", pe.ss_count);
142	printf("   ss_fft_period: %d\n", pe.ss_fft_period);
143	printf("   ss_period: %d\n", pe.ss_period);
144	printf("   ss_short_report: %d\n", pe.ss_short_report);
145	printf("   radar_bin_thresh_sel: %d\n", pe.radar_bin_thresh_sel);
146}
147
148static void
149spectral_start(struct spectralhandler *spectral)
150{
151	HAL_SPECTRAL_PARAM pe;
152
153	spectral->atd.ad_id = SPECTRAL_CONTROL_START | ATH_DIAG_DYN;
154	memset(&pe, 0, sizeof(pe));
155
156	/*
157	 * XXX don't need these, but need to eliminate the ATH_DIAG_DYN flag
158	 * and debug
159	 */
160	spectral->atd.ad_in_data = NULL;
161	spectral->atd.ad_in_size = 0;
162	spectral->atd.ad_out_data = (caddr_t) &pe;
163	spectral->atd.ad_out_size = sizeof(pe);
164
165	if (ioctl(spectral->s, SIOCGATHSPECTRAL, &spectral->atd) < 0)
166		err(1, spectral->atd.ad_name);
167}
168
169static void
170spectral_stop(struct spectralhandler *spectral)
171{
172	HAL_SPECTRAL_PARAM pe;
173
174	spectral->atd.ad_id = SPECTRAL_CONTROL_STOP | ATH_DIAG_DYN;
175	memset(&pe, 0, sizeof(pe));
176
177	/*
178	 * XXX don't need these, but need to eliminate the ATH_DIAG_DYN flag
179	 * and debug
180	 */
181	spectral->atd.ad_in_data = NULL;
182	spectral->atd.ad_in_size = 0;
183	spectral->atd.ad_out_data = (caddr_t) &pe;
184	spectral->atd.ad_out_size = sizeof(pe);
185
186	if (ioctl(spectral->s, SIOCGATHSPECTRAL, &spectral->atd) < 0)
187		err(1, spectral->atd.ad_name);
188}
189
190static int
191spectral_set_param(struct spectralhandler *spectral, const char *param,
192    const char *val)
193{
194	int v;
195
196	v = atoi(val);
197
198	if (strcmp(param, "ss_short_report") == 0) {
199		spectralset(spectral, SPECTRAL_PARAM_SS_SHORT_RPT, v);
200	} else if (strcmp(param, "ss_fft_period") == 0) {
201		spectralset(spectral, SPECTRAL_PARAM_FFT_PERIOD, v);
202	} else if (strcmp(param, "ss_period") == 0) {
203		spectralset(spectral, SPECTRAL_PARAM_SS_PERIOD, v);
204	} else if (strcmp(param, "ss_count") == 0) {
205		spectralset(spectral, SPECTRAL_PARAM_SS_COUNT, v);
206	} else {
207		return (0);
208	}
209
210#if 0
211	if (strcmp(param, "enabled") == 0) {
212		spectralset(spectral, DFS_PARAM_ENABLE, v);
213	} else if (strcmp(param, "firpwr") == 0) {
214		spectralset(spectral, DFS_PARAM_FIRPWR, v);
215	} else if (strcmp(param, "rrssi") == 0) {
216		spectralset(spectral, DFS_PARAM_RRSSI, v);
217	} else if (strcmp(param, "height") == 0) {
218		spectralset(spectral, DFS_PARAM_HEIGHT, v);
219	} else if (strcmp(param, "prssi") == 0) {
220		spectralset(spectral, DFS_PARAM_PRSSI, v);
221	} else if (strcmp(param, "inband") == 0) {
222		spectralset(spectral, DFS_PARAM_INBAND, v);
223	} else if (strcmp(param, "relpwr") == 0) {
224		spectralset(spectral, DFS_PARAM_RELPWR, v);
225	} else if (strcmp(param, "relstep") == 0) {
226		spectralset(spectral, DFS_PARAM_RELSTEP, v);
227	} else if (strcmp(param, "maxlen") == 0) {
228		spectralset(spectral, DFS_PARAM_MAXLEN, v);
229	} else if (strcmp(param, "usefir128") == 0) {
230		spectralset(spectral, DFS_PARAM_USEFIR128, v);
231	} else if (strcmp(param, "blockspectral") == 0) {
232		spectralset(spectral, DFS_PARAM_BLOCKRADAR, v);
233	} else if (strcmp(param, "enmaxrssi") == 0) {
234		spectralset(spectral, DFS_PARAM_MAXRSSI_EN, v);
235	} else if (strcmp(param, "extchannel") == 0) {
236		spectralset(spectral, DFS_PARAM_EN_EXTCH, v);
237	} else if (strcmp(param, "enrelpwr") == 0) {
238		spectralset(spectral, DFS_PARAM_RELPWR_EN, v);
239	} else if (strcmp(param, "en_relstep_check") == 0) {
240		spectralset(spectral, DFS_PARAM_RELSTEP_EN, v);
241	} else {
242		return 0;
243	}
244#endif
245
246	return 1;
247}
248
249void
250usage(const char *progname)
251{
252	printf("Usage:\n");
253	printf("\t%s: [-i <interface>] <cmd> (<arg>)\n", progname);
254	printf("\t%s: [-h]\n", progname);
255	printf("\n");
256	printf("Valid commands:\n");
257	printf("\tget:\t\tGet current spectral parameters\n");
258	printf("\tset <param> <value>:\t\tSet spectral parameter\n");
259	printf("\tstart: Start spectral scan\n");
260	printf("\tstop: Stop spectral scan\n");
261}
262
263int
264main(int argc, char *argv[])
265{
266	struct spectralhandler spectral;
267	const char *devname = ATH_DEFAULT;
268	const char *progname = argv[0];
269
270	memset(&spectral, 0, sizeof(spectral));
271
272	/* Parse command line options */
273	if (argc >= 2 && strcmp(argv[1], "-h") == 0) {
274		usage(progname);
275		exit(0);
276	}
277	if (argc >= 2 && strcmp(argv[1], "-?") == 0) {
278		usage(progname);
279		exit(0);
280	}
281
282	if (argc >= 2 && strcmp(argv[1], "-i") == 0) {
283		if (argc == 2) {
284			usage(progname);
285			exit(127);
286		}
287		devname = argv[2];
288		argc -= 2; argv += 2;
289	}
290
291	/* At this point we require at least one command */
292	if (argc == 1) {
293		usage(progname);
294		exit(127);
295	}
296
297	if (spectral_opendev(&spectral, devname) == 0)
298		exit(127);
299
300	if (strcasecmp(argv[1], "get") == 0) {
301		spectral_get(&spectral);
302	} else if (strcasecmp(argv[1], "set") == 0) {
303		if (argc < 4) {
304			usage(progname);
305			exit(127);
306		}
307		if (spectral_set_param(&spectral, argv[2], argv[3]) == 0) {
308			usage(progname);
309			exit(127);
310		}
311	} else if (strcasecmp(argv[1], "start") == 0) {
312		spectral_start(&spectral);
313	} else if (strcasecmp(argv[1], "stop") == 0) {
314		spectral_stop(&spectral);
315	} else {
316		usage(progname);
317		exit(127);
318	}
319
320	/* wrap up */
321	spectral_closedev(&spectral);
322	exit(0);
323}
324