text: /*====================================================================*
   *   
   *   Copyright (c) 2011 Qualcomm Atheros Inc.
   *   
   *   Permission to use, copy, modify, and/or distribute this software 
   *   for any purpose with or without fee is hereby granted, provided 
   *   that the above copyright notice and this permission notice appear 
   *   in all copies.
   *   
   *   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL 
   *   WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED 
   *   WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL  
   *   THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR 
   *   CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 
   *   LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, 
   *   NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 
   *   CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
   *   
   *--------------------------------------------------------------------*/
  
  /*====================================================================r
   *
   *   psnotch.c - Atheros Prescaler Notching Utility
   *
   *   Atheros Powerline Toolkit; 
   *
   *   this program is the Atheros INT6000 Dynamic Notching Utility
   *
   *   this program inspects the following frequency bands for SW signals:
   *
   *       120 m 2,300 - 2,495 kHz tropic band 
   *        90 m 3,200 - 3,400 kHz tropic band 
   *        75 m 3,900 - 4,000 kHz shared with the amateur radio 75/80 meter band 
   *        60 m 4,750 - 5,060 kHz tropic band 
   *        49 m 5,900 - 6,200 kHz   
   *        40 m/41m 7,100 - 7,350 kHz shared with the amateur radio 40 meter band 
   *        31 m 9,400 - 9,900 kHz Currently most heavily used band 
   *        25 m 11,600 - 12,100 kHz   
   *        22 m 13,570 - 13,870 kHz substantially used only in Eurasia 
   *        19 m 15,100 - 15,800 kHz   
   *        16 m 17,480 - 17,900 kHz   
   *        15 m 18,900 - 19,020 kHz almost unused, could become a DRM band 
   *        13 m 21,450 - 21,850 kHz   
   *        11 m 25,600 - 26,100 kHz may be used for local DRM broadcasting
   *
   *
   *   Contributor(s):
   *      Nathaniel Houghton <nhoughto@qca.qualcomm.com>
   *
   *--------------------------------------------------------------------*/
  
  /*====================================================================*"
   *   system header files;
   *--------------------------------------------------------------------*/
  
  #include <stdio.h>
  #include <ctype.h>
  #include <math.h>
  #include <ctype.h>
  #include <sys/types.h>
  #include <sys/stat.h>
  #include <fcntl.h>
  #include <string.h>
  
  /*====================================================================*
   *   custom header files;
   *--------------------------------------------------------------------*/
  
  #include "../tools/getoptv.h"
  #include "../tools/putoptv.h"
  #include "../tools/error.h"
  #include "../tools/flags.h"
  #include "../tools/chars.h"
  #include "../tools/number.h"
  
  /*====================================================================*
   *   custom source files;
   *--------------------------------------------------------------------*/
  
  #ifndef MAKEFILE
  #include "../tools/getoptv.c"
  #include "../tools/putoptv.c"
  #include "../tools/version.c"
  #include "../tools/error.c"
  #include "../tools/uintspec.c"
  #include "../tools/todigit.c"
  #endif
  
  /*====================================================================*
   *   program constants;
   *--------------------------------------------------------------------*/
  
  #define _PRINTF_DEBUG
  
  #define PSNOTCH_VERBOSE (1 << 0)
  #define PSNOTCH_SILENCE (1 << 1)
  #define PSNOTCH_COMMA   (1 << 2)
  
  #define CARRIERS 1155
  #define TONES 917
  #define SLOTS 6
  
  #define INDEX_TO_FREQ(index) ((float)(index + 74)/40.96) 
  #define FREQ_TO_INDEX(freq)  ((unsigned)(40.96 * freq)-74)
  
  /*====================================================================*
   *   program variables;
   *--------------------------------------------------------------------*/
  
  typedef struct carrier 
  
  {
  	uint16_t amplitude;
  	uint8_t slots [SLOTS];
  }
  
  carrier;
  typedef struct map 
  
  {
  	unsigned slots;
  	struct carrier carriers [CARRIERS];
  }
  
  map;
  uint8_t hambands [CARRIERS] = 
  
  {
  	0,
  	0,
  	0,
  	0,
  	0,
  	0,
  	0,
  	0,
  	0,
  	0,
  	0,
  	0,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	2,
  	2,
  	2,
  	2,
  	2,
  	2,
  	2,
  	2,
  	2,
  	2,
  	2,
  	2,
  	2,
  	2,
  	2,
  	2,
  	2,
  	2,
  	2,
  	2,
  	2,
  	2,
  	2,
  	2,
  	2,
  	2,
  	2,
  	2,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	2,
  	2,
  	2,
  	2,
  	2,
  	2,
  	2,
  	2,
  	2,
  	2,
  	2,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	2,
  	2,
  	2,
  	2,
  	2,
  	2,
  	2,
  	2,
  	2,
  	2,
  	2,
  	2,
  	2,
  	2,
  	2,
  	2,
  	2,
  	2,
  	2,
  	2,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	2,
  	2,
  	2,
  	2,
  	2,
  	2,
  	2,
  	2,
  	2,
  	2,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	2,
  	2,
  	2,
  	2,
  	2,
  	2,
  	2,
  	2,
  	2,
  	2,
  	2,
  	2,
  	2,
  	2,
  	2,
  	2,
  	2,
  	2,
  	2,
  	2,
  	2,
  	2,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	2,
  	2,
  	2,
  	2,
  	2,
  	2,
  	2,
  	2,
  	2,
  	2,
  	2,
  	2,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	2,
  	2,
  	2,
  	2,
  	2,
  	2,
  	2,
  	2,
  	2,
  	2,
  	2,
  	2,
  	2,
  	2,
  	2,
  	2,
  	2,
  	2,
  	2,
  	2,
  	2,
  	2,
  	2,
  	2,
  	2,
  	2,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	2,
  	2,
  	2,
  	2,
  	2,
  	2,
  	2,
  	2,
  	2,
  	2,
  	2,
  	2,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	1,
  	0,
  	0,
  	0,
  	0,
  	0,
  	0,
  	0,
  	0,
  	0,
  	0,
  	0,
  	0,
  	0,
  	0,
  	0,
  	0,
  	0,
  	0,
  	0,
  	0,
  	0,
  	0,
  	0,
  	0,
  	0,
  	0,
  	0,
  	0,
  	0,
  	0,
  	0,
  	0,
  	0,
  	0,
  	0,
  	0,
  	0,
  	0,
  	0,
  	0,
  	0,
  	0,
  	0,
  	0,
  	0,
  	0,
  	0,
  	0,
  	0,
  	0,
  	0,
  	0,
  	0,
  	0,
  	0,
  	0,
  	0,
  	0,
  	0,
  	0,
  	0,
  	0,
  	0,
  	0,
  	0,
  	0,
  	0,
  	0,
  	0,
  	0,
  	0,
  	0,
  	0,
  	0,
  	0,
  	0,
  	0,
  	0,
  	0,
  	0,
  	0,
  	0,
  	0,
  	0,
  	0
  };
  
  
  /*====================================================================*
   *   
   *   int read_scalers (struct map * map);
   *
   *   read a prescaler file from stdin; permit comments and blank 
   *   input lines; the set of prescalers are technically known as
   *   an amplitude map;
   *
   *   an amplitude map consists an offset (frequency) and a scaler
   *   (amplitude); we read, check and discard the offset but store
   *   the scaler;
   *
   *--------------------------------------------------------------------*/
  
  void read_scalers (struct map * map) 
  
  {
  	unsigned carriers = 0;
  	unsigned tones = 0;
  	uint32_t carrier;
  	uint32_t amplitude;
  	signed c;
  	while ((c = getc (stdin)) != EOF) 
  	{
  		if (isspace (c)) 
  		{
  			continue;
  		}
  		if ((c == '#') || (c == ';')) 
  		{
  			do 
  			{
  				c = getc (stdin);
  			}
  			while (nobreak (c));
  			continue;
  		}
  		carrier = 0;
  		while (isdigit (c)) 
  		{
  			carrier *= 10;
  			carrier += c - '0';
  			c = getc (stdin);
  		}
  		if (carrier != carriers) 
  		{
  			error (1, 0, "Prescaler %d/%d out of order", carrier, carriers);
  		}
  		if (carrier >= CARRIERS) 
  		{
  			break;
  		}
  		while (isblank (c)) 
  		{
  			c = getc (stdin);
  		}
  		amplitude = 0;
  		while (isxdigit (c)) 
  		{
  			amplitude *= 16;
  			amplitude += todigit (c);
  			c = getc (stdin);
  		}
  		map->carriers [carrier].amplitude = amplitude;
  		if (amplitude) 
  		{
  			tones++;
  		}
  		while ((c != EOF) && (c != '\n')) 
  		{
  			c = getc (stdin);
  		}
  		carriers++;
  	}
  	if (carriers != CARRIERS) 
  	{
  		error (1, 0, "Have %d amplitude map carriers but need %d", carriers, CARRIERS);
  	}
  	if (tones != TONES) 
  	{
  		error (1, 0, "Expected %d amplitude map scalers but read %d", TONES, tones);
  	}
  	return;
  }
  
  
  /*====================================================================*
   *   
   *   void write_scalers (struct map * map);
   *   
   *   print amplitude map on stdout in a format suitabl for input to
   *   program psin or the Windows Device Manager; 
   *
   *
   *--------------------------------------------------------------------*/
  
  void write_scalers (struct map * map) 
  
  {
  	unsigned carrier = 0;
  	for (carrier = 0; carrier < CARRIERS; carrier++) 
  	{
  		printf ("%.8u %.8hX\n", carrier, map->carriers [carrier].amplitude);
  	}
  	return;
  }
  
  
  /*====================================================================*
   *   
   *   void read_tonemaps (struct map * map, FILE *fp);
   *   
   *   read tone map from a file; a tonemap file can be created using
   *   program int6ktone;
   *
   *   input consists of 1159 lines; the first line is a comment; the
   *   next two lines contain GIL and AGC information; the remaining
   *   1155 lines consist of an offset follwed by 5 or 6 slot values;
   *
   *   although 1155 values are read, the first 917 contain tonemap
   *   data and rest contain 0 values; the 917 values correspond to
   *   the 917 amplitude scalers;
   *
   *   the tone map may be read either before or after the amplitude
   *   map is read;
   *
   *
   *--------------------------------------------------------------------*/
  
  void read_tonemaps (struct map * map, FILE *fp) 
  
  {
  	uint8_t slots [SLOTS];
  	unsigned tones = 0;
  	unsigned tone = 0;
  	unsigned slot = 0;
  	signed c;
  	map->slots = SLOTS;
  	memset (slots, 0, sizeof (slots));
  	while ((c = getc (fp)) != EOF) 
  	{
  		if (c == '#') 
  		{
  			while (((c = getc (fp)) != EOF) && (c != '\n'));
  		}
  		if (isspace (c)) 
  		{
  			continue;
  		}
  		tone = 0;
  		while (isdigit (c)) 
  		{
  			tone *= 10;
  			tone += c - '0';
  			c = getc (fp);
  		}
  		if (tone != tones) 
  		{
  			error (1, ECANCELED, "Tonemap %d/%d is out of order", tone, tones);
  		}
  		while (isblank (c)) 
  		{
  			c = getc (fp);
  		}
  		for (slot = 0; slot < SLOTS; slot++) 
  		{
  			unsigned value = 0;
  			while (isdigit (c)) 
  			{
  				value *= 10;
  				value += c - '0';
  				c = getc (fp);
  			}
  			map->carriers [tone].slots [slot] = value;
  			while (isblank (c)) 
  			{
  				c = getc (fp);
  			}
  		}
  		while ((c != EOF) && (c != '\n')) 
  		{
  			c = getc (fp);
  		}
  		tones++;
  	}
  	if (tones != TONES) 
  	{
  		error (0, 0, "Have %d tone map carriers but need %d", tones, TONES);
  	}
  	return;
  }
  
  
  /*====================================================================*
   *
   *   void align_tones (struct map * map);
   *
   *   the tonemap consists of 917 consecutive carriers the amplitude 
   *   map consists of 1155 carriers having 917 non-zero values; this 
   *   function distributes the tonemap entries so that they align to
   *   corresponding amplitude map entries;
   *
   *   alignment cannot be performed until both the amplitude map and
   *   tone map have been read;
   *
   *
   *--------------------------------------------------------------------*/
  
  void align_tones (struct map * map) 
  
  {
  	unsigned carriers = CARRIERS;
  	unsigned tones = TONES;
  	while (carriers--) 
  	{
  		if (map->carriers [carriers].amplitude) 
  		{
  			if (tones) 
  			{
  				tones--;
  				memcpy (&map->carriers [carriers].slots, &map->carriers [tones].slots, SLOTS);
  				memset (&map->carriers [tones].slots, 0, SLOTS);
  			}
  		}
  	}
  	return;
  }
  
  
  /*====================================================================*
   *
   *   unsigned notch_tones (struct map * scalers, unsigned lower, unsigned upper);
   *
   *   scan a range of tones for signals; signals are indicated by low 
   *   mean-square values computed across all slots for a given tone;
   *
   *   there may not be much change from one carrier to the next; we
   *   accentuate changes by squaring then summing slot values; this
   *   produces a reasonably clean parabolic dip in the map where the
   *   signal occurs; 
   *
   *   function watch_tones can be used to observe tone map values and
   *   signal dips over a given range of map values; generally, it is
   *   best to display a wider range of tones than those being notched;
   *
   *
   *--------------------------------------------------------------------*/
  
  unsigned notch_tones (struct map * map, unsigned lower, unsigned upper, unsigned limit) 
  
  {
  	unsigned slot;
  	unsigned notch = 0;
  	while (lower < upper) 
  	{
  		unsigned total = 0;
  		for (slot = 0; slot < map->slots; slot++) 
  		{
  			unsigned value = 0;
  			value = map->carriers [lower].slots [slot];
  			value *= value;
  			total += value;
  		}
  		if (slot) 
  		{
  			total /= slot;
  		}
  		if (total < limit) 
  		{
  			map->carriers [lower].amplitude = 0;
  			notch = 2;
  		}
  		lower++;
  	}
  	return (notch);
  }
  
  
  /*====================================================================*
   *
   *   void watch_tones (struct map * map, unsigned lower, unsigned upper);
   *
   *   print amplitude and tone values over a given range along with a
   *   plot of the values used to detect signal dips; for best effect,
   *   the range used here should exceed the notching range to provide 
   *   context information;
   *
   *
   *--------------------------------------------------------------------*/
  
  void watch_tones (struct map * map, unsigned lower, unsigned upper) 
  
  {
  	unsigned slot;
  	while (lower < upper) 
  	{
  		unsigned total = 0;
  		fprintf (stderr, "%04d %04X", lower, map->carriers [lower].amplitude);
  		for (slot = 0; slot < map->slots; slot++) 
  		{
  			unsigned value = 0;
  			value = map->carriers [lower].slots [slot];
  			fprintf (stderr, " %02X", value);
  			value *= value;
  			total += value;
  		}
  		if (slot) 
  		{
  			total /= slot;
  		}
  		fprintf (stderr, " %6.3f ", INDEX_TO_FREQ (lower));
  		while (total--) 
  		{
  			fprintf (stderr, "#");
  		}
  		fprintf (stderr, "\n");
  		lower++;
  	}
  	return;
  }
  
  
  /*====================================================================*
   *
   *   void watch_tone2 (struct map * map, unsigned lower, unsigned upper);
   *
   *   print amplitude and tone values over a given range along with a
   *   plot of the values used to detect signal dips; for best effect,
   *   the range used here should exceed the notching range to provide 
   *   context information;
   *
   *
   *--------------------------------------------------------------------*/
  
  void watch_tone2 (struct map * map, unsigned lower, unsigned upper) 
  
  {
  	unsigned slot;
  	while (lower < upper) 
  	{
  		unsigned total = 0;
  		fprintf (stderr, "%d,%d", lower, map->carriers [lower].amplitude);
  		for (slot = 0; slot < map->slots; slot++) 
  		{
  			unsigned value = 0;
  			value = map->carriers [lower].slots [slot];
  			fprintf (stderr, ",%d", value);
  			value *= value;
  			total += value;
  		}
  		if (slot) 
  		{
  			total /= slot;
  		}
  		fprintf (stderr, ",%d", total);
  		fprintf (stderr, ",%6.3f", INDEX_TO_FREQ (lower));
  		fprintf (stderr, "\n");
  		lower++;
  	}
  	return;
  }
  
  
  /*====================================================================*
   *   
   *   int main (int argc, char const * argv[]);
   *   
   *   read an amplitude map from stdin and print a notched amplitude 
   *   map on stdout; use a tone map file to determine if a signal is
   *   present where notching chould occur; notching ranges are input
   *   as map offsets, not carrier frequencies;
   *
   *
   *--------------------------------------------------------------------*/
  
  int main (int argc, char const * argv []) 
  
  {
  	char const * optv [] = 
  	{
  		"cf:l:L:t:u:U:qv",
  		PUTOPTV_S_FILTER,
  		"Atheros Prescaler Notching Utility",
  		"c\tcomma delimited output",
  		"f f\tread tonemap file (f)",
  		"t n\tthreshold is (n) units",
  		"l n\tlower notch range is (n)",
  		"L n\tlower graph range is (n)",
  		"u n\tupper notch range is (n)",
  		"U n\tupper graph range is (n)",
  		"v\tverbose output",
  		(char const *)(0)
  	};
  	struct map map;
  	FILE * fp = (FILE *)(0);
  	unsigned lower = CARRIERS-1;
  	unsigned upper = 0;
  	unsigned LOWER = 0;
  	unsigned UPPER = CARRIERS-1;
  	signed limit = 4;
  	signed status = 0;
  	flag_t flags = (flag_t)(0);
  	signed c;
  	memset (&map, 0, sizeof (map));
  	while ((c = getoptv (argc, argv, optv)) != -1) 
  	{
  		switch (c) 
  		{
  		case 'c':
  			_setbits (flags, PSNOTCH_COMMA);
  			break;
  		case 'f':
  			if ((fp = fopen (optarg, "rb")) == (FILE *)(0)) 
  			{
  				error (1, errno, "Can't open %s", optarg);
  			}
  			read_tonemaps (&map, fp);
  			fclose (fp);
  			break;
  		case 'l':
  			lower = (unsigned)(uintspec (optarg, 0, CARRIERS-1));
  			break;
  		case 'u':
  			upper = (unsigned)(uintspec (optarg, 0, CARRIERS-1));
  			break;
  		case 'L':
  			LOWER = (unsigned)(uintspec (optarg, 0, CARRIERS-1));
  			break;
  		case 'U':
  			UPPER = (unsigned)(uintspec (optarg, 0, CARRIERS-1));
  			break;
  		case 't':
  			limit = (signed)(uintspec (optarg, 0, 49));
  			break;
  		case 'q':
  			_setbits (flags, PSNOTCH_SILENCE);
  			break;
  		case 'v':
  			_setbits (flags, PSNOTCH_VERBOSE);
  			break;
  		default:
  			break;
  		}
  	}
  	argv += optind;
  	argc -= optind;
  	read_scalers (&map);
  	align_tones (&map);
  	if (_anyset (flags, PSNOTCH_COMMA)) 
  	{
  		watch_tone2 (&map, LOWER, UPPER);
  	}
  	else if (_anyset (flags, PSNOTCH_VERBOSE)) 
  	{
  		watch_tones (&map, LOWER, UPPER);
  	}
  	if (fp) 
  	{
  		status = notch_tones (&map, lower, upper, limit);
  	}
  	write_scalers (&map);
  	return (status);
  }
  
  