1244953Sadrian/*
2244953Sadrian * Copyright (c) 2013 Adrian Chadd <adrian@FreeBSD.org>
3244953Sadrian *
4244953Sadrian * Redistribution and use in source and binary forms, with or without
5244953Sadrian * modification, are permitted provided that the following conditions
6244953Sadrian * are met:
7244953Sadrian * 1. Redistributions of source code must retain the above copyright
8244953Sadrian *    notice, this list of conditions and the following disclaimer.
9244953Sadrian * 2. Redistributions in binary form must reproduce the above copyright
10244953Sadrian *    notice, this list of conditions and the following disclaimer in the
11244953Sadrian *    documentation and/or other materials provided with the distribution.
12244953Sadrian *
13244953Sadrian * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
14244953Sadrian * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15244953Sadrian * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16244953Sadrian * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
17244953Sadrian * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18244953Sadrian * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19244953Sadrian * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20244953Sadrian * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21244953Sadrian * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22244953Sadrian * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23244953Sadrian * SUCH DAMAGE.
24244953Sadrian *
25244953Sadrian * $FreeBSD$
26244953Sadrian */
27244953Sadrian
28244953Sadrian#include "diag.h"
29244953Sadrian
30244953Sadrian#include "ah.h"
31244953Sadrian#include "ah_internal.h"
32244953Sadrian
33244953Sadrian#include <getopt.h>
34244953Sadrian#include <errno.h>
35244953Sadrian#include <err.h>
36244953Sadrian#include <stdlib.h>
37244953Sadrian#include <string.h>
38244953Sadrian#include <ctype.h>
39244953Sadrian#include <unistd.h>
40244953Sadrian
41244953Sadrianstruct spectralhandler {
42244953Sadrian	struct		ath_diag atd;
43244953Sadrian	int		s;
44244953Sadrian	struct ifreq	ifr;
45244953Sadrian	int		ah_devid;
46244953Sadrian};
47244953Sadrian
48244953Sadrianint
49244953Sadrianspectral_opendev(struct spectralhandler *spectral, const char *devid)
50244953Sadrian{
51244953Sadrian	HAL_REVS revs;
52244953Sadrian
53244953Sadrian	spectral->s = socket(AF_INET, SOCK_DGRAM, 0);
54244953Sadrian	if (spectral->s < 0) {
55244953Sadrian		warn("socket");
56244953Sadrian		return 0;
57244953Sadrian	}
58244953Sadrian
59244953Sadrian	strncpy(spectral->atd.ad_name, devid, sizeof (spectral->atd.ad_name));
60244953Sadrian
61244953Sadrian	/* Get the hardware revision, just to verify things are working */
62244953Sadrian	spectral->atd.ad_id = HAL_DIAG_REVS;
63244953Sadrian	spectral->atd.ad_out_data = (caddr_t) &revs;
64244953Sadrian	spectral->atd.ad_out_size = sizeof(revs);
65244953Sadrian	if (ioctl(spectral->s, SIOCGATHDIAG, &spectral->atd) < 0) {
66251737Sadrian		warn("%s", spectral->atd.ad_name);
67244953Sadrian		return 0;
68244953Sadrian	}
69244953Sadrian	spectral->ah_devid = revs.ah_devid;
70244953Sadrian	return 1;
71244953Sadrian}
72244953Sadrian
73244953Sadrianvoid
74244953Sadrianspectral_closedev(struct spectralhandler *spectral)
75244953Sadrian{
76244953Sadrian	close(spectral->s);
77244953Sadrian	spectral->s = -1;
78244953Sadrian}
79244953Sadrian
80244953Sadrianvoid
81244953Sadrianspectralset(struct spectralhandler *spectral, int op, u_int32_t param)
82244953Sadrian{
83244953Sadrian	HAL_SPECTRAL_PARAM pe;
84244953Sadrian
85244953Sadrian	pe.ss_fft_period = HAL_SPECTRAL_PARAM_NOVAL;
86244953Sadrian	pe.ss_period = HAL_SPECTRAL_PARAM_NOVAL;
87244953Sadrian	pe.ss_count = HAL_SPECTRAL_PARAM_NOVAL;
88244953Sadrian	pe.ss_short_report = HAL_SPECTRAL_PARAM_NOVAL;
89244953Sadrian	pe.ss_spectral_pri = HAL_SPECTRAL_PARAM_NOVAL;
90244953Sadrian	pe.ss_fft_period = HAL_SPECTRAL_PARAM_NOVAL;
91244953Sadrian	pe.ss_enabled = HAL_SPECTRAL_PARAM_NOVAL;
92244953Sadrian	pe.ss_active = HAL_SPECTRAL_PARAM_NOVAL;
93244953Sadrian
94244953Sadrian	switch (op) {
95244953Sadrian	case SPECTRAL_PARAM_FFT_PERIOD:
96244953Sadrian		pe.ss_fft_period = param;
97244953Sadrian		break;
98244953Sadrian	case SPECTRAL_PARAM_SS_PERIOD:
99244953Sadrian		pe.ss_period = param;
100244953Sadrian		break;
101244953Sadrian	case SPECTRAL_PARAM_SS_COUNT:
102244953Sadrian		pe.ss_count = param;
103244953Sadrian		break;
104244953Sadrian	case SPECTRAL_PARAM_SS_SHORT_RPT:
105244953Sadrian		pe.ss_short_report = param;
106244953Sadrian		break;
107244953Sadrian	}
108244953Sadrian
109244953Sadrian	spectral->atd.ad_id = SPECTRAL_CONTROL_SET_PARAMS | ATH_DIAG_IN;
110244953Sadrian	spectral->atd.ad_out_data = NULL;
111244953Sadrian	spectral->atd.ad_out_size = 0;
112244953Sadrian	spectral->atd.ad_in_data = (caddr_t) &pe;
113244953Sadrian	spectral->atd.ad_in_size = sizeof(HAL_SPECTRAL_PARAM);
114244953Sadrian	if (ioctl(spectral->s, SIOCGATHSPECTRAL, &spectral->atd) < 0)
115251737Sadrian		err(1, "%s", spectral->atd.ad_name);
116244953Sadrian}
117244953Sadrian
118244953Sadrianstatic void
119244953Sadrianspectral_get(struct spectralhandler *spectral)
120244953Sadrian{
121244953Sadrian	HAL_SPECTRAL_PARAM pe;
122244953Sadrian
123244953Sadrian	spectral->atd.ad_id = SPECTRAL_CONTROL_GET_PARAMS | ATH_DIAG_DYN;
124244953Sadrian	memset(&pe, 0, sizeof(pe));
125244953Sadrian
126244953Sadrian	spectral->atd.ad_in_data = NULL;
127244953Sadrian	spectral->atd.ad_in_size = 0;
128244953Sadrian	spectral->atd.ad_out_data = (caddr_t) &pe;
129244953Sadrian	spectral->atd.ad_out_size = sizeof(pe);
130244953Sadrian
131244953Sadrian	if (ioctl(spectral->s, SIOCGATHSPECTRAL, &spectral->atd) < 0)
132251737Sadrian		err(1, "%s", spectral->atd.ad_name);
133244953Sadrian
134244953Sadrian	printf("Spectral parameters (raw):\n");
135244953Sadrian	printf("   ss_enabled: %d\n", pe.ss_enabled);
136244953Sadrian	printf("   ss_active: %d\n", pe.ss_active);
137244953Sadrian	printf("   ss_count: %d\n", pe.ss_count);
138244953Sadrian	printf("   ss_fft_period: %d\n", pe.ss_fft_period);
139244953Sadrian	printf("   ss_period: %d\n", pe.ss_period);
140244953Sadrian	printf("   ss_short_report: %d\n", pe.ss_short_report);
141244953Sadrian	printf("   radar_bin_thresh_sel: %d\n", pe.radar_bin_thresh_sel);
142244953Sadrian}
143244953Sadrian
144244953Sadrianstatic void
145244953Sadrianspectral_start(struct spectralhandler *spectral)
146244953Sadrian{
147244953Sadrian	HAL_SPECTRAL_PARAM pe;
148244953Sadrian
149244953Sadrian	spectral->atd.ad_id = SPECTRAL_CONTROL_START | ATH_DIAG_DYN;
150244953Sadrian	memset(&pe, 0, sizeof(pe));
151244953Sadrian
152244953Sadrian	/*
153244953Sadrian	 * XXX don't need these, but need to eliminate the ATH_DIAG_DYN flag
154244953Sadrian	 * and debug
155244953Sadrian	 */
156244953Sadrian	spectral->atd.ad_in_data = NULL;
157244953Sadrian	spectral->atd.ad_in_size = 0;
158244953Sadrian	spectral->atd.ad_out_data = (caddr_t) &pe;
159244953Sadrian	spectral->atd.ad_out_size = sizeof(pe);
160244953Sadrian
161244953Sadrian	if (ioctl(spectral->s, SIOCGATHSPECTRAL, &spectral->atd) < 0)
162251737Sadrian		err(1, "%s", spectral->atd.ad_name);
163244953Sadrian}
164244953Sadrian
165244953Sadrianstatic void
166244953Sadrianspectral_stop(struct spectralhandler *spectral)
167244953Sadrian{
168244953Sadrian	HAL_SPECTRAL_PARAM pe;
169244953Sadrian
170244953Sadrian	spectral->atd.ad_id = SPECTRAL_CONTROL_STOP | ATH_DIAG_DYN;
171244953Sadrian	memset(&pe, 0, sizeof(pe));
172244953Sadrian
173244953Sadrian	/*
174244953Sadrian	 * XXX don't need these, but need to eliminate the ATH_DIAG_DYN flag
175244953Sadrian	 * and debug
176244953Sadrian	 */
177244953Sadrian	spectral->atd.ad_in_data = NULL;
178244953Sadrian	spectral->atd.ad_in_size = 0;
179244953Sadrian	spectral->atd.ad_out_data = (caddr_t) &pe;
180244953Sadrian	spectral->atd.ad_out_size = sizeof(pe);
181244953Sadrian
182244953Sadrian	if (ioctl(spectral->s, SIOCGATHSPECTRAL, &spectral->atd) < 0)
183251737Sadrian		err(1, "%s", spectral->atd.ad_name);
184244953Sadrian}
185244953Sadrian
186245231Sadrianstatic void
187245231Sadrianspectral_enable_at_reset(struct spectralhandler *spectral, int val)
188245231Sadrian{
189245231Sadrian	int v = val;
190245231Sadrian
191245231Sadrian	spectral->atd.ad_id = SPECTRAL_CONTROL_ENABLE_AT_RESET
192245231Sadrian	    | ATH_DIAG_IN;
193245231Sadrian
194245231Sadrian	/*
195245231Sadrian	 * XXX don't need these, but need to eliminate the ATH_DIAG_DYN flag
196245231Sadrian	 * and debug
197245231Sadrian	 */
198245231Sadrian	spectral->atd.ad_out_data = NULL;
199245231Sadrian	spectral->atd.ad_out_size = 0;
200245231Sadrian	spectral->atd.ad_in_data = (caddr_t) &v;
201245231Sadrian	spectral->atd.ad_in_size = sizeof(v);
202245231Sadrian
203245231Sadrian	printf("%s: val=%d\n", __func__, v);
204245231Sadrian
205245231Sadrian	if (ioctl(spectral->s, SIOCGATHSPECTRAL, &spectral->atd) < 0)
206251737Sadrian		err(1, "%s", spectral->atd.ad_name);
207245231Sadrian}
208245231Sadrian
209244953Sadrianstatic int
210244953Sadrianspectral_set_param(struct spectralhandler *spectral, const char *param,
211244953Sadrian    const char *val)
212244953Sadrian{
213244953Sadrian	int v;
214244953Sadrian
215244953Sadrian	v = atoi(val);
216244953Sadrian
217244953Sadrian	if (strcmp(param, "ss_short_report") == 0) {
218244953Sadrian		spectralset(spectral, SPECTRAL_PARAM_SS_SHORT_RPT, v);
219244953Sadrian	} else if (strcmp(param, "ss_fft_period") == 0) {
220244953Sadrian		spectralset(spectral, SPECTRAL_PARAM_FFT_PERIOD, v);
221244953Sadrian	} else if (strcmp(param, "ss_period") == 0) {
222244953Sadrian		spectralset(spectral, SPECTRAL_PARAM_SS_PERIOD, v);
223244953Sadrian	} else if (strcmp(param, "ss_count") == 0) {
224244953Sadrian		spectralset(spectral, SPECTRAL_PARAM_SS_COUNT, v);
225244953Sadrian	} else {
226244953Sadrian		return (0);
227244953Sadrian	}
228244953Sadrian
229244953Sadrian#if 0
230244953Sadrian	if (strcmp(param, "enabled") == 0) {
231244953Sadrian		spectralset(spectral, DFS_PARAM_ENABLE, v);
232244953Sadrian	} else if (strcmp(param, "firpwr") == 0) {
233244953Sadrian		spectralset(spectral, DFS_PARAM_FIRPWR, v);
234244953Sadrian	} else if (strcmp(param, "rrssi") == 0) {
235244953Sadrian		spectralset(spectral, DFS_PARAM_RRSSI, v);
236244953Sadrian	} else if (strcmp(param, "height") == 0) {
237244953Sadrian		spectralset(spectral, DFS_PARAM_HEIGHT, v);
238244953Sadrian	} else if (strcmp(param, "prssi") == 0) {
239244953Sadrian		spectralset(spectral, DFS_PARAM_PRSSI, v);
240244953Sadrian	} else if (strcmp(param, "inband") == 0) {
241244953Sadrian		spectralset(spectral, DFS_PARAM_INBAND, v);
242244953Sadrian	} else if (strcmp(param, "relpwr") == 0) {
243244953Sadrian		spectralset(spectral, DFS_PARAM_RELPWR, v);
244244953Sadrian	} else if (strcmp(param, "relstep") == 0) {
245244953Sadrian		spectralset(spectral, DFS_PARAM_RELSTEP, v);
246244953Sadrian	} else if (strcmp(param, "maxlen") == 0) {
247244953Sadrian		spectralset(spectral, DFS_PARAM_MAXLEN, v);
248244953Sadrian	} else if (strcmp(param, "usefir128") == 0) {
249244953Sadrian		spectralset(spectral, DFS_PARAM_USEFIR128, v);
250244953Sadrian	} else if (strcmp(param, "blockspectral") == 0) {
251244953Sadrian		spectralset(spectral, DFS_PARAM_BLOCKRADAR, v);
252244953Sadrian	} else if (strcmp(param, "enmaxrssi") == 0) {
253244953Sadrian		spectralset(spectral, DFS_PARAM_MAXRSSI_EN, v);
254244953Sadrian	} else if (strcmp(param, "extchannel") == 0) {
255244953Sadrian		spectralset(spectral, DFS_PARAM_EN_EXTCH, v);
256244953Sadrian	} else if (strcmp(param, "enrelpwr") == 0) {
257244953Sadrian		spectralset(spectral, DFS_PARAM_RELPWR_EN, v);
258244953Sadrian	} else if (strcmp(param, "en_relstep_check") == 0) {
259244953Sadrian		spectralset(spectral, DFS_PARAM_RELSTEP_EN, v);
260244953Sadrian	} else {
261244953Sadrian		return 0;
262244953Sadrian	}
263244953Sadrian#endif
264244953Sadrian
265244953Sadrian	return 1;
266244953Sadrian}
267244953Sadrian
268244953Sadrianvoid
269244953Sadrianusage(const char *progname)
270244953Sadrian{
271244953Sadrian	printf("Usage:\n");
272244953Sadrian	printf("\t%s: [-i <interface>] <cmd> (<arg>)\n", progname);
273244953Sadrian	printf("\t%s: [-h]\n", progname);
274244953Sadrian	printf("\n");
275244953Sadrian	printf("Valid commands:\n");
276244953Sadrian	printf("\tget:\t\tGet current spectral parameters\n");
277244953Sadrian	printf("\tset <param> <value>:\t\tSet spectral parameter\n");
278244953Sadrian	printf("\tstart: Start spectral scan\n");
279244953Sadrian	printf("\tstop: Stop spectral scan\n");
280245231Sadrian	printf("\tenable_at_reset <0|1>: enable reporting upon channel reset\n");
281244953Sadrian}
282244953Sadrian
283244953Sadrianint
284244953Sadrianmain(int argc, char *argv[])
285244953Sadrian{
286244953Sadrian	struct spectralhandler spectral;
287244953Sadrian	const char *devname = ATH_DEFAULT;
288244953Sadrian	const char *progname = argv[0];
289244953Sadrian
290244953Sadrian	memset(&spectral, 0, sizeof(spectral));
291244953Sadrian
292244953Sadrian	/* Parse command line options */
293244953Sadrian	if (argc >= 2 && strcmp(argv[1], "-h") == 0) {
294244953Sadrian		usage(progname);
295244953Sadrian		exit(0);
296244953Sadrian	}
297244953Sadrian	if (argc >= 2 && strcmp(argv[1], "-?") == 0) {
298244953Sadrian		usage(progname);
299244953Sadrian		exit(0);
300244953Sadrian	}
301244953Sadrian
302244953Sadrian	if (argc >= 2 && strcmp(argv[1], "-i") == 0) {
303244953Sadrian		if (argc == 2) {
304244953Sadrian			usage(progname);
305244953Sadrian			exit(127);
306244953Sadrian		}
307244953Sadrian		devname = argv[2];
308244953Sadrian		argc -= 2; argv += 2;
309244953Sadrian	}
310244953Sadrian
311244953Sadrian	/* At this point we require at least one command */
312244953Sadrian	if (argc == 1) {
313244953Sadrian		usage(progname);
314244953Sadrian		exit(127);
315244953Sadrian	}
316244953Sadrian
317244953Sadrian	if (spectral_opendev(&spectral, devname) == 0)
318244953Sadrian		exit(127);
319244953Sadrian
320244953Sadrian	if (strcasecmp(argv[1], "get") == 0) {
321244953Sadrian		spectral_get(&spectral);
322244953Sadrian	} else if (strcasecmp(argv[1], "set") == 0) {
323244953Sadrian		if (argc < 4) {
324244953Sadrian			usage(progname);
325244953Sadrian			exit(127);
326244953Sadrian		}
327244953Sadrian		if (spectral_set_param(&spectral, argv[2], argv[3]) == 0) {
328244953Sadrian			usage(progname);
329244953Sadrian			exit(127);
330244953Sadrian		}
331244953Sadrian	} else if (strcasecmp(argv[1], "start") == 0) {
332244953Sadrian		spectral_start(&spectral);
333244953Sadrian	} else if (strcasecmp(argv[1], "stop") == 0) {
334244953Sadrian		spectral_stop(&spectral);
335245231Sadrian	} else if (strcasecmp(argv[1], "enable_at_reset") == 0) {
336245231Sadrian		if (argc < 3) {
337245231Sadrian			usage(progname);
338245231Sadrian			exit(127);
339245231Sadrian		}
340245231Sadrian		spectral_enable_at_reset(&spectral, atoi(argv[2]));
341244953Sadrian	} else {
342244953Sadrian		usage(progname);
343244953Sadrian		exit(127);
344244953Sadrian	}
345244953Sadrian
346244953Sadrian	/* wrap up */
347244953Sadrian	spectral_closedev(&spectral);
348244953Sadrian	exit(0);
349244953Sadrian}
350