athspectral.c revision 245231
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 245231 2013-01-09 18:50:06Z 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 void
191spectral_enable_at_reset(struct spectralhandler *spectral, int val)
192{
193	int v = val;
194
195	spectral->atd.ad_id = SPECTRAL_CONTROL_ENABLE_AT_RESET
196	    | ATH_DIAG_IN;
197
198	/*
199	 * XXX don't need these, but need to eliminate the ATH_DIAG_DYN flag
200	 * and debug
201	 */
202	spectral->atd.ad_out_data = NULL;
203	spectral->atd.ad_out_size = 0;
204	spectral->atd.ad_in_data = (caddr_t) &v;
205	spectral->atd.ad_in_size = sizeof(v);
206
207	printf("%s: val=%d\n", __func__, v);
208
209	if (ioctl(spectral->s, SIOCGATHSPECTRAL, &spectral->atd) < 0)
210		err(1, spectral->atd.ad_name);
211}
212
213static int
214spectral_set_param(struct spectralhandler *spectral, const char *param,
215    const char *val)
216{
217	int v;
218
219	v = atoi(val);
220
221	if (strcmp(param, "ss_short_report") == 0) {
222		spectralset(spectral, SPECTRAL_PARAM_SS_SHORT_RPT, v);
223	} else if (strcmp(param, "ss_fft_period") == 0) {
224		spectralset(spectral, SPECTRAL_PARAM_FFT_PERIOD, v);
225	} else if (strcmp(param, "ss_period") == 0) {
226		spectralset(spectral, SPECTRAL_PARAM_SS_PERIOD, v);
227	} else if (strcmp(param, "ss_count") == 0) {
228		spectralset(spectral, SPECTRAL_PARAM_SS_COUNT, v);
229	} else {
230		return (0);
231	}
232
233#if 0
234	if (strcmp(param, "enabled") == 0) {
235		spectralset(spectral, DFS_PARAM_ENABLE, v);
236	} else if (strcmp(param, "firpwr") == 0) {
237		spectralset(spectral, DFS_PARAM_FIRPWR, v);
238	} else if (strcmp(param, "rrssi") == 0) {
239		spectralset(spectral, DFS_PARAM_RRSSI, v);
240	} else if (strcmp(param, "height") == 0) {
241		spectralset(spectral, DFS_PARAM_HEIGHT, v);
242	} else if (strcmp(param, "prssi") == 0) {
243		spectralset(spectral, DFS_PARAM_PRSSI, v);
244	} else if (strcmp(param, "inband") == 0) {
245		spectralset(spectral, DFS_PARAM_INBAND, v);
246	} else if (strcmp(param, "relpwr") == 0) {
247		spectralset(spectral, DFS_PARAM_RELPWR, v);
248	} else if (strcmp(param, "relstep") == 0) {
249		spectralset(spectral, DFS_PARAM_RELSTEP, v);
250	} else if (strcmp(param, "maxlen") == 0) {
251		spectralset(spectral, DFS_PARAM_MAXLEN, v);
252	} else if (strcmp(param, "usefir128") == 0) {
253		spectralset(spectral, DFS_PARAM_USEFIR128, v);
254	} else if (strcmp(param, "blockspectral") == 0) {
255		spectralset(spectral, DFS_PARAM_BLOCKRADAR, v);
256	} else if (strcmp(param, "enmaxrssi") == 0) {
257		spectralset(spectral, DFS_PARAM_MAXRSSI_EN, v);
258	} else if (strcmp(param, "extchannel") == 0) {
259		spectralset(spectral, DFS_PARAM_EN_EXTCH, v);
260	} else if (strcmp(param, "enrelpwr") == 0) {
261		spectralset(spectral, DFS_PARAM_RELPWR_EN, v);
262	} else if (strcmp(param, "en_relstep_check") == 0) {
263		spectralset(spectral, DFS_PARAM_RELSTEP_EN, v);
264	} else {
265		return 0;
266	}
267#endif
268
269	return 1;
270}
271
272void
273usage(const char *progname)
274{
275	printf("Usage:\n");
276	printf("\t%s: [-i <interface>] <cmd> (<arg>)\n", progname);
277	printf("\t%s: [-h]\n", progname);
278	printf("\n");
279	printf("Valid commands:\n");
280	printf("\tget:\t\tGet current spectral parameters\n");
281	printf("\tset <param> <value>:\t\tSet spectral parameter\n");
282	printf("\tstart: Start spectral scan\n");
283	printf("\tstop: Stop spectral scan\n");
284	printf("\tenable_at_reset <0|1>: enable reporting upon channel reset\n");
285}
286
287int
288main(int argc, char *argv[])
289{
290	struct spectralhandler spectral;
291	const char *devname = ATH_DEFAULT;
292	const char *progname = argv[0];
293
294	memset(&spectral, 0, sizeof(spectral));
295
296	/* Parse command line options */
297	if (argc >= 2 && strcmp(argv[1], "-h") == 0) {
298		usage(progname);
299		exit(0);
300	}
301	if (argc >= 2 && strcmp(argv[1], "-?") == 0) {
302		usage(progname);
303		exit(0);
304	}
305
306	if (argc >= 2 && strcmp(argv[1], "-i") == 0) {
307		if (argc == 2) {
308			usage(progname);
309			exit(127);
310		}
311		devname = argv[2];
312		argc -= 2; argv += 2;
313	}
314
315	/* At this point we require at least one command */
316	if (argc == 1) {
317		usage(progname);
318		exit(127);
319	}
320
321	if (spectral_opendev(&spectral, devname) == 0)
322		exit(127);
323
324	if (strcasecmp(argv[1], "get") == 0) {
325		spectral_get(&spectral);
326	} else if (strcasecmp(argv[1], "set") == 0) {
327		if (argc < 4) {
328			usage(progname);
329			exit(127);
330		}
331		if (spectral_set_param(&spectral, argv[2], argv[3]) == 0) {
332			usage(progname);
333			exit(127);
334		}
335	} else if (strcasecmp(argv[1], "start") == 0) {
336		spectral_start(&spectral);
337	} else if (strcasecmp(argv[1], "stop") == 0) {
338		spectral_stop(&spectral);
339	} else if (strcasecmp(argv[1], "enable_at_reset") == 0) {
340		if (argc < 3) {
341			usage(progname);
342			exit(127);
343		}
344		spectral_enable_at_reset(&spectral, atoi(argv[2]));
345	} else {
346		usage(progname);
347		exit(127);
348	}
349
350	/* wrap up */
351	spectral_closedev(&spectral);
352	exit(0);
353}
354