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#ifndef	ATH_DEFAULT
34244953Sadrian#define	ATH_DEFAULT	"ath0"
35244953Sadrian#endif
36244953Sadrian
37244953Sadrian#include <getopt.h>
38244953Sadrian#include <errno.h>
39244953Sadrian#include <err.h>
40244953Sadrian#include <stdlib.h>
41244953Sadrian#include <string.h>
42244953Sadrian#include <ctype.h>
43244953Sadrian#include <unistd.h>
44244953Sadrian
45244953Sadrianstruct spectralhandler {
46244953Sadrian	struct		ath_diag atd;
47244953Sadrian	int		s;
48244953Sadrian	struct ifreq	ifr;
49244953Sadrian	int		ah_devid;
50244953Sadrian};
51244953Sadrian
52244953Sadrianint
53244953Sadrianspectral_opendev(struct spectralhandler *spectral, const char *devid)
54244953Sadrian{
55244953Sadrian	HAL_REVS revs;
56244953Sadrian
57244953Sadrian	spectral->s = socket(AF_INET, SOCK_DGRAM, 0);
58244953Sadrian	if (spectral->s < 0) {
59244953Sadrian		warn("socket");
60244953Sadrian		return 0;
61244953Sadrian	}
62244953Sadrian
63244953Sadrian	strncpy(spectral->atd.ad_name, devid, sizeof (spectral->atd.ad_name));
64244953Sadrian
65244953Sadrian	/* Get the hardware revision, just to verify things are working */
66244953Sadrian	spectral->atd.ad_id = HAL_DIAG_REVS;
67244953Sadrian	spectral->atd.ad_out_data = (caddr_t) &revs;
68244953Sadrian	spectral->atd.ad_out_size = sizeof(revs);
69244953Sadrian	if (ioctl(spectral->s, SIOCGATHDIAG, &spectral->atd) < 0) {
70251737Sadrian		warn("%s", spectral->atd.ad_name);
71244953Sadrian		return 0;
72244953Sadrian	}
73244953Sadrian	spectral->ah_devid = revs.ah_devid;
74244953Sadrian	return 1;
75244953Sadrian}
76244953Sadrian
77244953Sadrianvoid
78244953Sadrianspectral_closedev(struct spectralhandler *spectral)
79244953Sadrian{
80244953Sadrian	close(spectral->s);
81244953Sadrian	spectral->s = -1;
82244953Sadrian}
83244953Sadrian
84244953Sadrianvoid
85244953Sadrianspectralset(struct spectralhandler *spectral, int op, u_int32_t param)
86244953Sadrian{
87244953Sadrian	HAL_SPECTRAL_PARAM pe;
88244953Sadrian
89244953Sadrian	pe.ss_fft_period = HAL_SPECTRAL_PARAM_NOVAL;
90244953Sadrian	pe.ss_period = HAL_SPECTRAL_PARAM_NOVAL;
91244953Sadrian	pe.ss_count = HAL_SPECTRAL_PARAM_NOVAL;
92244953Sadrian	pe.ss_short_report = HAL_SPECTRAL_PARAM_NOVAL;
93244953Sadrian	pe.ss_spectral_pri = HAL_SPECTRAL_PARAM_NOVAL;
94244953Sadrian	pe.ss_fft_period = HAL_SPECTRAL_PARAM_NOVAL;
95244953Sadrian	pe.ss_enabled = HAL_SPECTRAL_PARAM_NOVAL;
96244953Sadrian	pe.ss_active = HAL_SPECTRAL_PARAM_NOVAL;
97244953Sadrian
98244953Sadrian	switch (op) {
99244953Sadrian	case SPECTRAL_PARAM_FFT_PERIOD:
100244953Sadrian		pe.ss_fft_period = param;
101244953Sadrian		break;
102244953Sadrian	case SPECTRAL_PARAM_SS_PERIOD:
103244953Sadrian		pe.ss_period = param;
104244953Sadrian		break;
105244953Sadrian	case SPECTRAL_PARAM_SS_COUNT:
106244953Sadrian		pe.ss_count = param;
107244953Sadrian		break;
108244953Sadrian	case SPECTRAL_PARAM_SS_SHORT_RPT:
109244953Sadrian		pe.ss_short_report = param;
110244953Sadrian		break;
111244953Sadrian	}
112244953Sadrian
113244953Sadrian	spectral->atd.ad_id = SPECTRAL_CONTROL_SET_PARAMS | ATH_DIAG_IN;
114244953Sadrian	spectral->atd.ad_out_data = NULL;
115244953Sadrian	spectral->atd.ad_out_size = 0;
116244953Sadrian	spectral->atd.ad_in_data = (caddr_t) &pe;
117244953Sadrian	spectral->atd.ad_in_size = sizeof(HAL_SPECTRAL_PARAM);
118244953Sadrian	if (ioctl(spectral->s, SIOCGATHSPECTRAL, &spectral->atd) < 0)
119251737Sadrian		err(1, "%s", spectral->atd.ad_name);
120244953Sadrian}
121244953Sadrian
122244953Sadrianstatic void
123244953Sadrianspectral_get(struct spectralhandler *spectral)
124244953Sadrian{
125244953Sadrian	HAL_SPECTRAL_PARAM pe;
126244953Sadrian
127244953Sadrian	spectral->atd.ad_id = SPECTRAL_CONTROL_GET_PARAMS | ATH_DIAG_DYN;
128244953Sadrian	memset(&pe, 0, sizeof(pe));
129244953Sadrian
130244953Sadrian	spectral->atd.ad_in_data = NULL;
131244953Sadrian	spectral->atd.ad_in_size = 0;
132244953Sadrian	spectral->atd.ad_out_data = (caddr_t) &pe;
133244953Sadrian	spectral->atd.ad_out_size = sizeof(pe);
134244953Sadrian
135244953Sadrian	if (ioctl(spectral->s, SIOCGATHSPECTRAL, &spectral->atd) < 0)
136251737Sadrian		err(1, "%s", spectral->atd.ad_name);
137244953Sadrian
138244953Sadrian	printf("Spectral parameters (raw):\n");
139244953Sadrian	printf("   ss_enabled: %d\n", pe.ss_enabled);
140244953Sadrian	printf("   ss_active: %d\n", pe.ss_active);
141244953Sadrian	printf("   ss_count: %d\n", pe.ss_count);
142244953Sadrian	printf("   ss_fft_period: %d\n", pe.ss_fft_period);
143244953Sadrian	printf("   ss_period: %d\n", pe.ss_period);
144244953Sadrian	printf("   ss_short_report: %d\n", pe.ss_short_report);
145244953Sadrian	printf("   radar_bin_thresh_sel: %d\n", pe.radar_bin_thresh_sel);
146244953Sadrian}
147244953Sadrian
148244953Sadrianstatic void
149244953Sadrianspectral_start(struct spectralhandler *spectral)
150244953Sadrian{
151244953Sadrian	HAL_SPECTRAL_PARAM pe;
152244953Sadrian
153244953Sadrian	spectral->atd.ad_id = SPECTRAL_CONTROL_START | ATH_DIAG_DYN;
154244953Sadrian	memset(&pe, 0, sizeof(pe));
155244953Sadrian
156244953Sadrian	/*
157244953Sadrian	 * XXX don't need these, but need to eliminate the ATH_DIAG_DYN flag
158244953Sadrian	 * and debug
159244953Sadrian	 */
160244953Sadrian	spectral->atd.ad_in_data = NULL;
161244953Sadrian	spectral->atd.ad_in_size = 0;
162244953Sadrian	spectral->atd.ad_out_data = (caddr_t) &pe;
163244953Sadrian	spectral->atd.ad_out_size = sizeof(pe);
164244953Sadrian
165244953Sadrian	if (ioctl(spectral->s, SIOCGATHSPECTRAL, &spectral->atd) < 0)
166251737Sadrian		err(1, "%s", spectral->atd.ad_name);
167244953Sadrian}
168244953Sadrian
169244953Sadrianstatic void
170244953Sadrianspectral_stop(struct spectralhandler *spectral)
171244953Sadrian{
172244953Sadrian	HAL_SPECTRAL_PARAM pe;
173244953Sadrian
174244953Sadrian	spectral->atd.ad_id = SPECTRAL_CONTROL_STOP | ATH_DIAG_DYN;
175244953Sadrian	memset(&pe, 0, sizeof(pe));
176244953Sadrian
177244953Sadrian	/*
178244953Sadrian	 * XXX don't need these, but need to eliminate the ATH_DIAG_DYN flag
179244953Sadrian	 * and debug
180244953Sadrian	 */
181244953Sadrian	spectral->atd.ad_in_data = NULL;
182244953Sadrian	spectral->atd.ad_in_size = 0;
183244953Sadrian	spectral->atd.ad_out_data = (caddr_t) &pe;
184244953Sadrian	spectral->atd.ad_out_size = sizeof(pe);
185244953Sadrian
186244953Sadrian	if (ioctl(spectral->s, SIOCGATHSPECTRAL, &spectral->atd) < 0)
187251737Sadrian		err(1, "%s", spectral->atd.ad_name);
188244953Sadrian}
189244953Sadrian
190245231Sadrianstatic void
191245231Sadrianspectral_enable_at_reset(struct spectralhandler *spectral, int val)
192245231Sadrian{
193245231Sadrian	int v = val;
194245231Sadrian
195245231Sadrian	spectral->atd.ad_id = SPECTRAL_CONTROL_ENABLE_AT_RESET
196245231Sadrian	    | ATH_DIAG_IN;
197245231Sadrian
198245231Sadrian	/*
199245231Sadrian	 * XXX don't need these, but need to eliminate the ATH_DIAG_DYN flag
200245231Sadrian	 * and debug
201245231Sadrian	 */
202245231Sadrian	spectral->atd.ad_out_data = NULL;
203245231Sadrian	spectral->atd.ad_out_size = 0;
204245231Sadrian	spectral->atd.ad_in_data = (caddr_t) &v;
205245231Sadrian	spectral->atd.ad_in_size = sizeof(v);
206245231Sadrian
207245231Sadrian	printf("%s: val=%d\n", __func__, v);
208245231Sadrian
209245231Sadrian	if (ioctl(spectral->s, SIOCGATHSPECTRAL, &spectral->atd) < 0)
210251737Sadrian		err(1, "%s", spectral->atd.ad_name);
211245231Sadrian}
212245231Sadrian
213244953Sadrianstatic int
214244953Sadrianspectral_set_param(struct spectralhandler *spectral, const char *param,
215244953Sadrian    const char *val)
216244953Sadrian{
217244953Sadrian	int v;
218244953Sadrian
219244953Sadrian	v = atoi(val);
220244953Sadrian
221244953Sadrian	if (strcmp(param, "ss_short_report") == 0) {
222244953Sadrian		spectralset(spectral, SPECTRAL_PARAM_SS_SHORT_RPT, v);
223244953Sadrian	} else if (strcmp(param, "ss_fft_period") == 0) {
224244953Sadrian		spectralset(spectral, SPECTRAL_PARAM_FFT_PERIOD, v);
225244953Sadrian	} else if (strcmp(param, "ss_period") == 0) {
226244953Sadrian		spectralset(spectral, SPECTRAL_PARAM_SS_PERIOD, v);
227244953Sadrian	} else if (strcmp(param, "ss_count") == 0) {
228244953Sadrian		spectralset(spectral, SPECTRAL_PARAM_SS_COUNT, v);
229244953Sadrian	} else {
230244953Sadrian		return (0);
231244953Sadrian	}
232244953Sadrian
233244953Sadrian#if 0
234244953Sadrian	if (strcmp(param, "enabled") == 0) {
235244953Sadrian		spectralset(spectral, DFS_PARAM_ENABLE, v);
236244953Sadrian	} else if (strcmp(param, "firpwr") == 0) {
237244953Sadrian		spectralset(spectral, DFS_PARAM_FIRPWR, v);
238244953Sadrian	} else if (strcmp(param, "rrssi") == 0) {
239244953Sadrian		spectralset(spectral, DFS_PARAM_RRSSI, v);
240244953Sadrian	} else if (strcmp(param, "height") == 0) {
241244953Sadrian		spectralset(spectral, DFS_PARAM_HEIGHT, v);
242244953Sadrian	} else if (strcmp(param, "prssi") == 0) {
243244953Sadrian		spectralset(spectral, DFS_PARAM_PRSSI, v);
244244953Sadrian	} else if (strcmp(param, "inband") == 0) {
245244953Sadrian		spectralset(spectral, DFS_PARAM_INBAND, v);
246244953Sadrian	} else if (strcmp(param, "relpwr") == 0) {
247244953Sadrian		spectralset(spectral, DFS_PARAM_RELPWR, v);
248244953Sadrian	} else if (strcmp(param, "relstep") == 0) {
249244953Sadrian		spectralset(spectral, DFS_PARAM_RELSTEP, v);
250244953Sadrian	} else if (strcmp(param, "maxlen") == 0) {
251244953Sadrian		spectralset(spectral, DFS_PARAM_MAXLEN, v);
252244953Sadrian	} else if (strcmp(param, "usefir128") == 0) {
253244953Sadrian		spectralset(spectral, DFS_PARAM_USEFIR128, v);
254244953Sadrian	} else if (strcmp(param, "blockspectral") == 0) {
255244953Sadrian		spectralset(spectral, DFS_PARAM_BLOCKRADAR, v);
256244953Sadrian	} else if (strcmp(param, "enmaxrssi") == 0) {
257244953Sadrian		spectralset(spectral, DFS_PARAM_MAXRSSI_EN, v);
258244953Sadrian	} else if (strcmp(param, "extchannel") == 0) {
259244953Sadrian		spectralset(spectral, DFS_PARAM_EN_EXTCH, v);
260244953Sadrian	} else if (strcmp(param, "enrelpwr") == 0) {
261244953Sadrian		spectralset(spectral, DFS_PARAM_RELPWR_EN, v);
262244953Sadrian	} else if (strcmp(param, "en_relstep_check") == 0) {
263244953Sadrian		spectralset(spectral, DFS_PARAM_RELSTEP_EN, v);
264244953Sadrian	} else {
265244953Sadrian		return 0;
266244953Sadrian	}
267244953Sadrian#endif
268244953Sadrian
269244953Sadrian	return 1;
270244953Sadrian}
271244953Sadrian
272244953Sadrianvoid
273244953Sadrianusage(const char *progname)
274244953Sadrian{
275244953Sadrian	printf("Usage:\n");
276244953Sadrian	printf("\t%s: [-i <interface>] <cmd> (<arg>)\n", progname);
277244953Sadrian	printf("\t%s: [-h]\n", progname);
278244953Sadrian	printf("\n");
279244953Sadrian	printf("Valid commands:\n");
280244953Sadrian	printf("\tget:\t\tGet current spectral parameters\n");
281244953Sadrian	printf("\tset <param> <value>:\t\tSet spectral parameter\n");
282244953Sadrian	printf("\tstart: Start spectral scan\n");
283244953Sadrian	printf("\tstop: Stop spectral scan\n");
284245231Sadrian	printf("\tenable_at_reset <0|1>: enable reporting upon channel reset\n");
285244953Sadrian}
286244953Sadrian
287244953Sadrianint
288244953Sadrianmain(int argc, char *argv[])
289244953Sadrian{
290244953Sadrian	struct spectralhandler spectral;
291244953Sadrian	const char *devname = ATH_DEFAULT;
292244953Sadrian	const char *progname = argv[0];
293244953Sadrian
294244953Sadrian	memset(&spectral, 0, sizeof(spectral));
295244953Sadrian
296244953Sadrian	/* Parse command line options */
297244953Sadrian	if (argc >= 2 && strcmp(argv[1], "-h") == 0) {
298244953Sadrian		usage(progname);
299244953Sadrian		exit(0);
300244953Sadrian	}
301244953Sadrian	if (argc >= 2 && strcmp(argv[1], "-?") == 0) {
302244953Sadrian		usage(progname);
303244953Sadrian		exit(0);
304244953Sadrian	}
305244953Sadrian
306244953Sadrian	if (argc >= 2 && strcmp(argv[1], "-i") == 0) {
307244953Sadrian		if (argc == 2) {
308244953Sadrian			usage(progname);
309244953Sadrian			exit(127);
310244953Sadrian		}
311244953Sadrian		devname = argv[2];
312244953Sadrian		argc -= 2; argv += 2;
313244953Sadrian	}
314244953Sadrian
315244953Sadrian	/* At this point we require at least one command */
316244953Sadrian	if (argc == 1) {
317244953Sadrian		usage(progname);
318244953Sadrian		exit(127);
319244953Sadrian	}
320244953Sadrian
321244953Sadrian	if (spectral_opendev(&spectral, devname) == 0)
322244953Sadrian		exit(127);
323244953Sadrian
324244953Sadrian	if (strcasecmp(argv[1], "get") == 0) {
325244953Sadrian		spectral_get(&spectral);
326244953Sadrian	} else if (strcasecmp(argv[1], "set") == 0) {
327244953Sadrian		if (argc < 4) {
328244953Sadrian			usage(progname);
329244953Sadrian			exit(127);
330244953Sadrian		}
331244953Sadrian		if (spectral_set_param(&spectral, argv[2], argv[3]) == 0) {
332244953Sadrian			usage(progname);
333244953Sadrian			exit(127);
334244953Sadrian		}
335244953Sadrian	} else if (strcasecmp(argv[1], "start") == 0) {
336244953Sadrian		spectral_start(&spectral);
337244953Sadrian	} else if (strcasecmp(argv[1], "stop") == 0) {
338244953Sadrian		spectral_stop(&spectral);
339245231Sadrian	} else if (strcasecmp(argv[1], "enable_at_reset") == 0) {
340245231Sadrian		if (argc < 3) {
341245231Sadrian			usage(progname);
342245231Sadrian			exit(127);
343245231Sadrian		}
344245231Sadrian		spectral_enable_at_reset(&spectral, atoi(argv[2]));
345244953Sadrian	} else {
346244953Sadrian		usage(progname);
347244953Sadrian		exit(127);
348244953Sadrian	}
349244953Sadrian
350244953Sadrian	/* wrap up */
351244953Sadrian	spectral_closedev(&spectral);
352244953Sadrian	exit(0);
353244953Sadrian}
354