DIY Smart Station-Avoiding Spirit Radio

Designed and programmed by Two Faces. An experimental prototype.

This radio skips over stations automatically as it scans through the FM frequencies, in tenths or hundredths of Mhz. It can scan in-order or randomly. The delay between stations, as well as the width of the avoided area are adjustable. You can also select just a portion of the dial to scan within.
A minimum or maximum station power threshold can be set so that it can skip frequencies with too high or too low of a signal. By default, we have it set to skip over any frequency with more than ‘5’ as the power level, so we hear only the empty space between stations.

Ingredients

Optional


Hardware Construction

Connect the 5V+ and GND pins between the Uno and the TEA5767 Module.

Next connect the data pins. SLC connects to Uno pin A5, SDA connects to Uno pin A4. (SCL & SLC mean the same thing)

Special versions of the Uno like this one have extra places where you can connect to these pins, which is what we did in our prototype pictured below.

Both can be powered together by a USB battery connected to the Uno’s USB port.

***IMPORTANT
The display needs one of it’s pins moved to be compatible with the FM module.
I cut two pins, and ran a wire between one of then and another pin. Keep this in mind if you are using wires with connectors as well, this wire will need to be connected to the display the way my soldered wire does.


Photos of Our Prototype Construction


Firmware Code

For the Arduino IDE

Don’t forget to download the appropriate libraries

MCUFRIEND Library

TEA5767 Library

The Code

This code is Open Source so that the community can debunk and debug it’s use with full scientific disclosure. This code is provided in good faith with the understanding that it is not to be distributed in a commercial product, in whole or in part, without the written permission of Two Faces.


#include <MCUFRIEND_kbv.h>
MCUFRIEND_kbv tft;  // hard-wired for UNO shields anyway.
#include <TouchScreen.h>
#include <Wire.h>
#include <TEA5767.h>
#include "img.h"
TEA5767 radio = TEA5767();

float freq = 88;
byte stren;
float lastFreq;
bool touch;
byte spd;
bool scan;
bool scanRev;
byte si[200];
bool hide[200];
byte index;
byte oldIndex;
float startFreq = 88;
byte param;
bool autoHide;
byte hideWidth;
bool hund;  // hundreths
byte maxStr = 4;
byte minStr;
bool shuf;
float fi;
byte minI = 0;
byte maxI = 199;

char *name = "woz.lol";                      //edit name of shield
const int XP = 8, XM = A2, YP = A3, YM = 9;  //240x320 ID=0x9341
const int TS_LEFT = 929, TS_RT = 94, TS_TOP = 76, TS_BOT = 906;

TouchScreen ts = TouchScreen(XP, YP, XM, YM, 300);
TSPoint tp;

#define MINPRESSURE 200
#define MAXPRESSURE 1000

#define LCD_RESET 0

int16_t BOXSIZE;
int16_t PENRADIUS = 1;
uint16_t ID, oldcolor, currentcolor;
uint8_t Orientation = 2;  //PORTRAIT

// Assign human-readable names to some common 16-bit color values:
#define BLACK 0x0000
#define BLUE 0x001F
#define RED 0xF800
#define GREEN 0x07E0
#define CYAN 0x07FF
#define MAGENTA 0xF81F
#define YELLOW 0xFFE0
#define WHITE 0xFFFF

void setup(void) {
  Wire.begin();
  randomSeed(radio.getSignalLevel());
  lastFreq = 0;

  tft.reset();
  ID = tft.readID();
  tft.begin(ID);
  Serial.begin(9600);
  tft.setRotation(Orientation);

  BOXSIZE = tft.width() / 6;
  tft.fillScreen(BLACK);

  tft.drawBitmap(5, tft.height() - BOXSIZE + 7, rbshuf, 31, 26, BLUE);
  tft.drawBitmap(BOXSIZE + 3, tft.height() - BOXSIZE + 8, rbspeed, 35, 26, YELLOW);
  tft.drawBitmap(BOXSIZE * 2 + 7, tft.height() - BOXSIZE + 6, rbrange, 28, 28, MAGENTA);
  tft.drawBitmap(BOXSIZE * 3 + 4, tft.height() - BOXSIZE + 11, rb1, 33, 21, MAGENTA);
  tft.drawBitmap(BOXSIZE * 4 + 7, tft.height() - BOXSIZE + 14, rbwidth, 28, 18, CYAN);
  tft.drawLine(BOXSIZE * 4 + 19 - (6 * hideWidth), tft.height() - BOXSIZE + 9, BOXSIZE * 4 + 22 + (6 * hideWidth), tft.height() - BOXSIZE + 9, CYAN);
  tft.drawLine(BOXSIZE * 4 + 18 - (6 * hideWidth), tft.height() - BOXSIZE + 7, BOXSIZE * 4 + 18 - (6 * hideWidth), tft.height() - BOXSIZE + 11, CYAN);
  tft.drawLine(BOXSIZE * 4 + 23 + (6 * hideWidth), tft.height() - BOXSIZE + 7, BOXSIZE * 4 + 23 + (6 * hideWidth), tft.height() - BOXSIZE + 11, CYAN);
  tft.drawBitmap(BOXSIZE * 5 + 7, tft.height() - BOXSIZE + 14, rbwidth, 28, 18, CYAN);
  tft.drawBitmap(BOXSIZE * 5 + 15, tft.height() - BOXSIZE + 4, rbx, 12, 11, CYAN);

  tft.drawBitmap(tft.width() - BOXSIZE + 9, tft.height() - BOXSIZE * 2 + 4, rbbottom, 24, 33, GREEN);
  tft.drawBitmap(tft.width() - BOXSIZE + 9, tft.height() - BOXSIZE * 3 + 3, rbtop, 24, 34, RED);
  tft.drawBitmap(tft.width() - BOXSIZE + 4, tft.height() - BOXSIZE * 4 + 3, rbauto, 35, 34, CYAN);
  tft.drawBitmap(tft.width() - BOXSIZE + 7, tft.height() - BOXSIZE * 5 + 8, rbplay, 28, 23, WHITE);

  tft.setTextSize(1);
  tft.setCursor(143, 15);
  tft.setTextColor(GREEN);
  tft.print("Min");
  tft.setTextColor(CYAN);
  tft.setTextColor(WHITE);
  tft.print("  Power  ");
  tft.setTextColor(RED);
  tft.print("Max");

  updateHund();
  updateRange();
  updateBar();
  updateStr();
  updateSpd();
  updateArrows();
  updateFreq();
}

void loop() {
  touchCheck();

  if (scan) {
    if (shuf) {
      index = (random(minI, maxI));
      while ((!autoHide) && ((hide[index]) || ((hideWidth) && (index < 199) && (hide[index + 1])) || ((hideWidth) && (index > 0) && (hide[index - 1])) || ((hideWidth == 2) && (index < 198) && (hide[index + 2])) || ((hideWidth == 2) && (index > 1) && (hide[index - 2])))) {
        index = (random(minI, maxI));
      }
      fi = index;
      freq = (fi / 10) + startFreq;
      float r = random(10) / 100.00;
      if (hund) freq = freq - .05 + r;
    } else {
      if (hund) {
        if (scanRev) {
          freq -= .01;
          fi = index;
          if (freq <= (fi / 10) + startFreq - .05) {
            index--;
            if ((index == 255) || (index < minI)) {
              index = maxI;
              fi = index;
              freq = (fi / 10) + startFreq;
            }
          }
        } else {
          freq += .01;
          fi = index;
          if (freq >= (fi / 10) + startFreq + .05) {
            index++;
            if ((index > 199) || (index > maxI)) {
              index = minI;
              fi = index;
              freq = (fi / 10) + startFreq;
            }
          }
        }
      } else {  // if not hund
        if (scanRev) {
          index--;
          if ((index == 255) || (index < minI) || (index > maxI)) {
            if (index < 199) tft.fillRect(((index + 1) - (((index + 1) / 50) * 50)) * 4, (((index + 1) / 50) * 60) + 86, 4, 4, BLACK);
            index = maxI;
          }
        } else {
          index++;
          if ((index > 199) || (index > maxI) || (index < minI)) {
            tft.fillRect(((index - 1) - (((index - 1) / 50) * 50)) * 4, (((index - 1) / 50) * 60) + 86, 4, 4, BLACK);
            index = minI;
          }
        }
        fi = index;
        freq = (fi / 10) + startFreq;
      }
    }

    updateFreq();
    scanDelay();
  }  // end if scan active

  touch = false;
}

void scanDelay() {
  for (int c = 0; c <= sq(spd); c++) {
    touchCheck();
    if (touch) return;
  }
}

void updateFreq() {
  byte row;

  if ((scan) && ((hide[index]) || ((hideWidth) && (index < 199) && (hide[index + 1])) || ((hideWidth) && (index > 0) && (hide[index - 1])) || ((hideWidth == 2) && (index < 198) && (hide[index + 2])) || ((hideWidth == 2) && (index > 1) && (hide[index - 2])))) {
    touch = true;
  } else {
    if (freq != lastFreq) {
      radio.setFrequency(freq);
      if ((freq >= 100) && (lastFreq < 100) || (freq <= 100) && (lastFreq > 100)) {
        updateHund();
      }
      lastFreq = freq;
      delay(20);
      stren = radio.getSignalLevel();
      if ((scan) && (autoHide) && ((stren < minStr) || (stren > maxStr))) {
        hide[index] = true;
        touch = true;
      } else if ((scan) && (autoHide)) {
        hide[index] = false;
      }

      tft.fillRect(0, 0, 130, 21, BLACK);

      tft.setCursor(0, 0);
      tft.setTextColor(WHITE);
      tft.setTextSize(3);
      tft.print(freq, 2);
      tft.setTextSize(1);
      tft.print("MHz");

      tft.fillRect(177, 0, 24, 14, BLACK);

      tft.setCursor(177, 0);
      tft.setTextSize(2);
      if (hide[index]) {
        tft.setTextColor(CYAN);
      } else {
        tft.setTextColor(WHITE);
      }
      if (stren < 10) tft.print("0");
      tft.print(stren);

      updateBar();
    }
  }

  if (index == 0) tft.fillRect(196, 251, 4, 4, BLACK);
  if (index == 199) tft.fillRect(0, 86, 4, 4, BLACK);
  row = index / 50;
  // tft.fillRect(((index - 1) - (((index - 1) / 50) * 50)) * 4, (((index - 1) / 50) * 60) + 86, 4, 4, BLACK);
  // if (index < 199) tft.fillRect(((index + 1) - (((index + 1) / 50) * 50)) * 4, (((index + 1) / 50) * 60) + 86, 4, 4, BLACK);
  tft.fillRect((oldIndex - ((oldIndex / 50) * 50)) * 4, ((oldIndex / 50) * 60) + 86, 4, 4, BLACK);
  oldIndex = index;
  tft.fillRect((index - (row * 50)) * 4, (row * 60) + 86, 4, 4, WHITE);
}

void updateRange() {
  byte row;
  tft.fillRect(0, 31, 101, 8, BLACK);
  tft.setTextColor(MAGENTA);
  tft.setTextSize(1);
  tft.setCursor(0, 31);
  fi = minI;
  tft.print(startFreq + (fi / 10), 2);
  tft.print("-");
  fi = maxI + 1;
  tft.print(startFreq + (fi / 10), 2);
  tft.print(" MHz");

  for (int ti = 0; ti < 200; ti++) {
    row = ti / 50;
    tft.fillRect((ti - (row * 50)) * 4, (row * 60) + 90, 4, 4, tft.color565(0, 0, 0));
    tft.fillRect((ti - (row * 50)) * 4, (row * 60) + 90, 4, 3 + ((ti % 10) == 0) - 2 * ((ti >= minI) && (ti <= maxI)), tft.color565(128, 128 * ((ti >= minI) && (ti <= maxI)), 128));
  }
}

void updateBar() {
  byte row;
  row = index / 50;
  if (hide[index]) {
    tft.fillRect((index - (row * 50)) * 4, (row * 60) + 40, 4, 45, tft.color565(0, 64, 64));
  } else {
    tft.fillRect((index - (row * 50)) * 4, (row * 60) + 40, 4, 45, BLACK);
  }
  tft.fillRect((index - (row * 50)) * 4, (row * 60) + 85 - (stren * 3), 4, stren * 3, tft.color565(255 - (stren * 17), stren * 17, hide[index] * 128));
}

void updateStr() {
  tft.fillRect(140, 0, 36, 14, BLACK);
  tft.setCursor(140, 0);
  tft.setTextSize(2);
  tft.setTextColor(GREEN);
  if (minStr < 10) tft.print("0");
  tft.print(minStr);
  tft.print("<");
  tft.setCursor(200, 0);
  tft.fillRect(200, 0, 36, 14, BLACK);
  tft.setTextColor(RED);
  tft.print("<");
  if (maxStr < 10) tft.print("0");
  tft.print(maxStr);
}

void updateSpd() {
  tft.fillRect(212, 22, 24, 17, BLACK);
  tft.setTextSize(1);
  tft.setCursor(182, 25);
  tft.setTextColor(YELLOW);
  tft.print("Wait ");
  tft.setTextSize(2);
  tft.print(spd);
}

void updateHund() {
  tft.setTextSize(3);
  tft.setTextColor(BLACK);
  tft.setCursor(54, 6);
  tft.print("___");
  tft.setTextColor(WHITE);
  tft.setCursor(54 + (hund * 18) + ((freq >= 100) * 18), 6);
  tft.print("_");
}

void boxReset() {
  tft.drawRect(BOXSIZE * 2 + 2, tft.height() - BOXSIZE + 1, BOXSIZE - 2, BOXSIZE - 2, BLACK);
  tft.drawRect(BOXSIZE + 2, tft.height() - BOXSIZE + 1, BOXSIZE - 2, BOXSIZE - 2, BLACK);
  tft.drawRect(BOXSIZE * 4 + 2, tft.height() - BOXSIZE + 1, BOXSIZE - 2, BOXSIZE - 2, BLACK);
  tft.drawRect(tft.width() - BOXSIZE + 2, tft.height() - BOXSIZE * 2 + 1, BOXSIZE - 2, BOXSIZE - 2, BLACK);
  tft.drawRect(tft.width() - BOXSIZE + 2, tft.height() - BOXSIZE * 3 + 1, BOXSIZE - 2, BOXSIZE - 2, BLACK);
  tft.drawBitmap(BOXSIZE * 2 + 7, tft.height() - BOXSIZE + 6, rbrange, 28, 28, MAGENTA);
}

void updateArrows() {

  switch (param) {
    case 0:
      tft.drawBitmap(tft.width() - BOXSIZE + 7, tft.height() - BOXSIZE * 6 + 2, rbdown, 28, 34, WHITE);
      tft.drawBitmap(tft.width() - BOXSIZE + 7, tft.height() - BOXSIZE * 7 + 4, rbup, 28, 34, WHITE);
      break;
    case 1:
    case 2:
      tft.drawBitmap(tft.width() - BOXSIZE + 7, tft.height() - BOXSIZE * 6 + 2, rbdown, 28, 34, MAGENTA);
      tft.drawBitmap(tft.width() - BOXSIZE + 7, tft.height() - BOXSIZE * 7 + 4, rbup, 28, 34, MAGENTA);
      break;
    case 3:
      tft.drawBitmap(tft.width() - BOXSIZE + 7, tft.height() - BOXSIZE * 6 + 2, rbdown, 28, 34, YELLOW);
      tft.drawBitmap(tft.width() - BOXSIZE + 7, tft.height() - BOXSIZE * 7 + 4, rbup, 28, 34, YELLOW);
      break;
    case 4:
      tft.drawBitmap(tft.width() - BOXSIZE + 7, tft.height() - BOXSIZE * 6 + 2, rbdown, 28, 34, GREEN);
      tft.drawBitmap(tft.width() - BOXSIZE + 7, tft.height() - BOXSIZE * 7 + 4, rbup, 28, 34, GREEN);
      break;
    case 5:
      tft.drawBitmap(tft.width() - BOXSIZE + 7, tft.height() - BOXSIZE * 6 + 2, rbdown, 28, 34, RED);
      tft.drawBitmap(tft.width() - BOXSIZE + 7, tft.height() - BOXSIZE * 7 + 4, rbup, 28, 34, RED);
      break;
  }
}

void touchCheck() {
  byte row;
  uint16_t xpos, ypos;  //screen coordinates
  tp = ts.getPoint();   //tp.x, tp.y are ADC values

  pinMode(XM, OUTPUT);
  pinMode(YP, OUTPUT);

  if (tp.z > MINPRESSURE && tp.z < MAXPRESSURE) {
    //  tp = ts.getPoint();   //tp.x, tp.y are ADC values
    if (!touch) {
      touch = true;
      switch (Orientation) {
        case 0:
          xpos = map(tp.x, TS_LEFT, TS_RT, 0, tft.width());
          ypos = map(tp.y, TS_TOP, TS_BOT, 0, tft.height());
          break;
        case 1:
          xpos = map(tp.y, TS_TOP, TS_BOT, 0, tft.width());
          ypos = map(tp.x, TS_RT, TS_LEFT, 0, tft.height());
          break;
        case 2:
          xpos = map(tp.x, TS_RT, TS_LEFT, 0, tft.width());
          ypos = map(tp.y, TS_BOT, TS_TOP, 0, tft.height());
          break;
        case 3:
          xpos = map(tp.y, TS_BOT, TS_TOP, 0, tft.width());
          ypos = map(tp.x, TS_LEFT, TS_RT, 0, tft.height());
          break;
      }

      if (ypos > tft.height() - BOXSIZE) {
        if (xpos < BOXSIZE) {
          if (shuf) {
            shuf = false;
            tft.drawRect(2, tft.height() - BOXSIZE + 1, BOXSIZE - 2, BOXSIZE - 2, BLACK);
          } else {
            shuf = true;
            tft.drawRect(2, tft.height() - BOXSIZE + 1, BOXSIZE - 2, BOXSIZE - 2, WHITE);
          }
          delay(400);
        } else if (xpos < BOXSIZE * 2) {
          if (param == 3) {  // speed
            tft.drawRect(BOXSIZE * 1 + 2, tft.height() - BOXSIZE + 1, BOXSIZE - 2, BOXSIZE - 2, BLACK);
            param = 0;
            updateArrows();
          } else {
            param = 3;
            updateArrows();
            boxReset();
            tft.drawRect(BOXSIZE + 2, tft.height() - BOXSIZE + 1, BOXSIZE - 2, BOXSIZE - 2, WHITE);
          }
          delay(400);
        } else if (xpos < BOXSIZE * 3) {
          if (param < 3) {
            param++;
          } else {
            param = 1;
          }
          if (param > 2) {  //                   // range
            tft.drawRect(BOXSIZE * 2 + 2, tft.height() - BOXSIZE + 1, BOXSIZE - 2, BOXSIZE - 2, BLACK);
            tft.drawBitmap(BOXSIZE * 2 + 7, tft.height() - BOXSIZE + 6, rbrange, 28, 28, MAGENTA);
            param = 0;
            updateArrows();
          } else {
            updateArrows();
            boxReset();
            tft.drawRect(BOXSIZE * 2 + 2, tft.height() - BOXSIZE + 1, BOXSIZE - 2, BOXSIZE - 2, WHITE);
            if (param == 1) {
              tft.drawLine(BOXSIZE * 2 + 8, tft.height() - BOXSIZE + 6, BOXSIZE * 2 + 8, tft.height() - BOXSIZE + 10, WHITE);
              tft.drawLine(BOXSIZE * 2 + 10, tft.height() - BOXSIZE + 8, BOXSIZE * 2 + 19, tft.height() - BOXSIZE + 8, WHITE);
            } else {
              tft.drawBitmap(BOXSIZE * 2 + 7, tft.height() - BOXSIZE + 6, rbrange, 28, 28, MAGENTA);
              tft.drawLine(BOXSIZE * 2 + 20, tft.height() - BOXSIZE + 8, BOXSIZE * 2 + 32, tft.height() - BOXSIZE + 8, WHITE);
              tft.drawLine(BOXSIZE * 2 + 33, tft.height() - BOXSIZE + 6, BOXSIZE * 2 + 33, tft.height() - BOXSIZE + 10, WHITE);
            }
          }
          delay(400);
        } else if (xpos < BOXSIZE * 4) {  // hund
          if (hund) {
            tft.drawRect(BOXSIZE * 3 + 2, tft.height() - BOXSIZE + 1, BOXSIZE - 2, BOXSIZE - 2, BLACK);
            hund = false;
          } else {
            tft.drawRect(BOXSIZE * 3 + 2, tft.height() - BOXSIZE + 1, BOXSIZE - 2, BOXSIZE - 2, WHITE);
            hund = true;
          }
          updateHund();
          delay(400);
        } else if (xpos < BOXSIZE * 5) {  //hide width
          tft.drawLine(BOXSIZE * 4 + 19 - (6 * hideWidth), tft.height() - BOXSIZE + 9, BOXSIZE * 4 + 22 + (6 * hideWidth), tft.height() - BOXSIZE + 9, BLACK);
          tft.drawLine(BOXSIZE * 4 + 18 - (6 * hideWidth), tft.height() - BOXSIZE + 7, BOXSIZE * 4 + 18 - (6 * hideWidth), tft.height() - BOXSIZE + 11, BLACK);
          tft.drawLine(BOXSIZE * 4 + 23 + (6 * hideWidth), tft.height() - BOXSIZE + 7, BOXSIZE * 4 + 23 + (6 * hideWidth), tft.height() - BOXSIZE + 11, BLACK);
          hideWidth++;
          if (hideWidth > 2) hideWidth = 0;
          tft.drawLine(BOXSIZE * 4 + 19 - (6 * hideWidth), tft.height() - BOXSIZE + 9, BOXSIZE * 4 + 22 + (6 * hideWidth), tft.height() - BOXSIZE + 9, CYAN);
          tft.drawLine(BOXSIZE * 4 + 18 - (6 * hideWidth), tft.height() - BOXSIZE + 7, BOXSIZE * 4 + 18 - (6 * hideWidth), tft.height() - BOXSIZE + 11, CYAN);
          tft.drawLine(BOXSIZE * 4 + 23 + (6 * hideWidth), tft.height() - BOXSIZE + 7, BOXSIZE * 4 + 23 + (6 * hideWidth), tft.height() - BOXSIZE + 11, CYAN);
          tft.drawRect(BOXSIZE * 4 + 2, tft.height() - BOXSIZE + 1, BOXSIZE - 2, BOXSIZE - 2, WHITE);
          delay(400);
          tft.drawRect(BOXSIZE * 4 + 2, tft.height() - BOXSIZE + 1, BOXSIZE - 2, BOXSIZE - 2, BLACK);
        } else if (xpos < BOXSIZE * 6) {
          if (hide[index]) {
            hide[index] = false;
          } else {
            hide[index] = true;
          }
          tft.drawRect(BOXSIZE * 5 + 2, tft.height() - BOXSIZE + 1, BOXSIZE - 2, BOXSIZE - 2, WHITE);
          delay(200);
          tft.drawRect(BOXSIZE * 5 + 2, tft.height() - BOXSIZE + 1, BOXSIZE - 2, BOXSIZE - 2, BLACK);
          updateBar();
        }
      }  // end bottom row
      if ((xpos > tft.width() - BOXSIZE) && (ypos < tft.height() - BOXSIZE)) {
        if (ypos > tft.height() - BOXSIZE * 2) {
          if (param == 4) {  // minStr
            tft.drawRect(tft.width() - BOXSIZE + 2, tft.height() - BOXSIZE * 2 + 1, BOXSIZE - 2, BOXSIZE - 2, BLACK);
            param = 0;
            updateArrows();
          } else {
            param = 4;
            updateArrows();
            boxReset();
            tft.drawRect(tft.width() - BOXSIZE + 2, tft.height() - BOXSIZE * 2 + 1, BOXSIZE - 2, BOXSIZE - 2, WHITE);
          }
          delay(400);
        } else if (ypos > tft.height() - BOXSIZE * 3) {
          if (param == 5) {  // maxStr
            tft.drawRect(tft.width() - BOXSIZE + 2, tft.height() - BOXSIZE * 3 + 1, BOXSIZE - 2, BOXSIZE - 2, BLACK);
            param = 0;
            updateArrows();
          } else {
            param = 5;
            updateArrows();
            boxReset();
            tft.drawRect(tft.width() - BOXSIZE + 2, tft.height() - BOXSIZE * 3 + 1, BOXSIZE - 2, BOXSIZE - 2, WHITE);
          }
          delay(400);
        } else if (ypos > tft.height() - BOXSIZE * 4) {
          if (autoHide) {  // autoHide
            tft.drawRect(tft.width() - BOXSIZE + 2, tft.height() - BOXSIZE * 4 + 1, BOXSIZE - 2, BOXSIZE - 2, BLACK);
            autoHide = false;
          } else {
            tft.drawRect(tft.width() - BOXSIZE + 2, tft.height() - BOXSIZE * 4 + 1, BOXSIZE - 2, BOXSIZE - 2, WHITE);
            autoHide = true;
          }
          delay(400);
        } else if (ypos > tft.height() - BOXSIZE * 5) {
          if (scan) {  // play
            tft.drawRect(tft.width() - BOXSIZE + 2, tft.height() - BOXSIZE * 5 + 1, BOXSIZE - 2, BOXSIZE - 2, BLACK);
            scan = false;
          } else {
            tft.drawRect(tft.width() - BOXSIZE + 2, tft.height() - BOXSIZE * 5 + 1, BOXSIZE - 2, BOXSIZE - 2, WHITE);
            scan = true;
          }
          delay(400);
        } else if (ypos > tft.height() - BOXSIZE * 6) {  // down
          touch = false;
          tft.drawRect(tft.width() - BOXSIZE + 2, tft.height() - BOXSIZE * 6 + 1, BOXSIZE - 2, BOXSIZE - 2, WHITE);
          switch (param) {
            case 0:
              if (scan) scanRev = true;
              if (hund) {
                freq -= .01;
                fi = index;
                if (freq <= (fi / 10) + startFreq - .05) {
                  index--;
                  if (index == 255) {
                    index = 199;
                    freq = startFreq + 19.9;
                  }
                }
              } else {
                index--;
                if (index == 255) index = 199;
                fi = index;
                freq = (fi / 10) + startFreq;
              }
              updateFreq();
              break;
            case 1:
              minI--;
              if (minI == 255) minI = 0;
              updateRange();
              break;
            case 2:
              maxI--;
              if (maxI == 255) maxI = 0;
              updateRange();
              break;
            case 3:  //speed
              spd--;
              if (spd > 99) spd = 99;
              updateSpd();
              break;
            case 4:
              minStr--;
              if (minStr == 255) minStr = 15;
              updateStr();
              break;
            case 5:
              maxStr--;
              if (maxStr == 255) maxStr = 15;
              updateStr();
              break;
          }
          delay(100);
          tft.drawRect(tft.width() - BOXSIZE + 2, tft.height() - BOXSIZE * 6 + 1, BOXSIZE - 2, BOXSIZE - 2, BLACK);
        } else if (ypos > tft.height() - BOXSIZE * 7) {  // up
          touch = false;
          tft.drawRect(tft.width() - BOXSIZE + 2, tft.height() - BOXSIZE * 7 + 1, BOXSIZE - 2, BOXSIZE - 2, WHITE);
          switch (param) {
            case 0:
              if (scan) scanRev = false;
              if (hund) {
                freq += .01;
                fi = index;
                if (freq >= (fi / 10) + startFreq + .05) {
                  index++;
                  if (index > 199) {
                    index = 0;
                    freq = startFreq;
                  }
                }
              } else {
                index++;
                if (index > 199) index = 0;
                fi = index;
                freq = (fi / 10) + startFreq;
              }
              updateFreq();
              break;
            case 1:
              minI++;
              if (minI > 199) minI = 199;
              updateRange();
              break;
            case 2:
              maxI++;
              if (maxI > 199) maxI = 199;
              updateRange();
              break;
            case 3:  //speed
              spd++;
              if (spd > 99) spd = 0;
              updateSpd();
              break;
            case 4:
              minStr++;
              if (minStr > 15) minStr = 0;
              updateStr();
              break;
            case 5:
              maxStr++;
              if (maxStr > 15) maxStr = 0;
              updateStr();
              break;
          }
          delay(100);
          tft.drawRect(tft.width() - BOXSIZE + 2, tft.height() - BOXSIZE * 7 + 1, BOXSIZE - 2, BOXSIZE - 2, BLACK);
        }
      }  // end right column of buttons

      if (xpos < 140 && ypos < 20) {
        boxReset();
        param = 0;
        updateArrows();
      }  //end check

      if ((xpos < tft.width() - BOXSIZE) && (ypos > 30) && (ypos < tft.height() - BOXSIZE)) {

        for (byte ti = 0; ti < 200; ti++) {

          row = ti / 50;
          if ((xpos == (ti - (row * 50)) * 4) && (ypos > (row * 60) + 30) && (ypos < (row * 60) + 90)) {
            switch (param) {  //
              case 1:
                minI = ti;
                updateRange();
                break;
              case 2:
                maxI = ti;
                updateRange();
                break;
              default:
                tft.fillRect((index - ((index / 50) * 50)) * 4, ((index / 50) * 60) + 86, 4, 4, BLACK);

                index = ti;
                fi = index;
                freq = (fi / 10) + startFreq;
                updateFreq();
                updateBar();
                break;
            }
          }
        }
      }  //end check

    }  //end check if new touch
  }    //end touch check
}

// contents of img.h
// image bitmaps file (Arduino tab)

// 'rbplay', 28x23px
const unsigned char rbplay [] PROGMEM = {
  0x80, 0x01, 0xf1, 0xf0, 0xc0, 0x01, 0xf1, 0xf0, 0xe0, 0x01, 0xf1, 0xf0, 0xf0, 0x01, 0xf1, 0xf0, 
  0xf8, 0x01, 0xf1, 0xf0, 0xfc, 0x01, 0xf1, 0xf0, 0xfe, 0x01, 0xf1, 0xf0, 0xff, 0x01, 0xf1, 0xf0, 
  0xff, 0x81, 0xf1, 0xf0, 0xff, 0xc1, 0xf1, 0xf0, 0xff, 0xe1, 0xf1, 0xf0, 0xff, 0xf1, 0xf1, 0xf0, 
  0xff, 0xe1, 0xf1, 0xf0, 0xff, 0xc1, 0xf1, 0xf0, 0xff, 0x81, 0xf1, 0xf0, 0xff, 0x01, 0xf1, 0xf0, 
  0xfe, 0x01, 0xf1, 0xf0, 0xfc, 0x01, 0xf1, 0xf0, 0xf8, 0x01, 0xf1, 0xf0, 0xf0, 0x01, 0xf1, 0xf0, 
  0xe0, 0x01, 0xf1, 0xf0, 0xc0, 0x01, 0xf1, 0xf0, 0x80, 0x01, 0xf1, 0xf0
};
// 'rbshuf', 31x26px
const unsigned char rbshuf [] PROGMEM = {
	0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x1c, 
	0x7f, 0x00, 0x03, 0xfe, 0xff, 0xc0, 0x0f, 0xfe, 0x01, 0xe0, 0x1e, 0x1c, 0x00, 0x70, 0x38, 0x38, 
	0x00, 0x38, 0x70, 0x70, 0x00, 0x1c, 0x60, 0x20, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 
	0x00, 0x07, 0x00, 0x00, 0x00, 0x03, 0x80, 0x00, 0x00, 0x01, 0x80, 0x00, 0x00, 0x01, 0xc0, 0x00, 
	0x00, 0x18, 0xe0, 0x20, 0x00, 0x38, 0x70, 0x70, 0x00, 0x70, 0x38, 0x38, 0x01, 0xe0, 0x1e, 0x1c, 
	0xff, 0xc0, 0x0f, 0xfe, 0x7f, 0x00, 0x03, 0xfe, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x38, 
	0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x20
};
// 'rbdown', 28x34px
const unsigned char rbdown [] PROGMEM = {
  0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x1f, 0x80, 0x00, 0x00, 0x1f, 0x80, 0x00, 
  0x00, 0x3f, 0xc0, 0x00, 0x00, 0x3f, 0xc0, 0x00, 0x00, 0x3f, 0xc0, 0x00, 0x00, 0x3f, 0xc0, 0x00, 
  0x00, 0x3f, 0xc0, 0x00, 0x00, 0x3f, 0xc0, 0x00, 0x00, 0x3f, 0xc0, 0x00, 0x00, 0x3f, 0xc0, 0x00, 
  0x00, 0x3f, 0xc0, 0x00, 0x00, 0x3f, 0xc0, 0x00, 0x00, 0x3f, 0xc0, 0x00, 0x18, 0x3f, 0xc1, 0x80, 
  0x7c, 0x3f, 0xc3, 0xe0, 0xfe, 0x3f, 0xc7, 0xf0, 0xff, 0x3f, 0xcf, 0xf0, 0xff, 0xbf, 0xdf, 0xf0, 
  0xff, 0xff, 0xff, 0xf0, 0x7f, 0xff, 0xff, 0xe0, 0x3f, 0xff, 0xff, 0xc0, 0x1f, 0xff, 0xff, 0x80, 
  0x0f, 0xff, 0xff, 0x00, 0x07, 0xff, 0xfe, 0x00, 0x03, 0xff, 0xfc, 0x00, 0x01, 0xff, 0xf8, 0x00, 
  0x00, 0xff, 0xf0, 0x00, 0x00, 0x7f, 0xe0, 0x00, 0x00, 0x3f, 0xc0, 0x00, 0x00, 0x1f, 0x80, 0x00, 
  0x00, 0x0f, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00
};
// 'rbrange', 28x28px
const unsigned char rbrange [] PROGMEM = {
  0x40, 0x00, 0x00, 0x20, 0x40, 0x00, 0x00, 0x20, 0x7f, 0xff, 0xff, 0xe0, 0x40, 0x00, 0x00, 0x20, 
  0x40, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xf0, 0x80, 0x00, 0x00, 0x10, 0x80, 0x00, 0x00, 0x10, 
  0x80, 0x00, 0x00, 0x10, 0x80, 0x00, 0x00, 0x30, 0xff, 0xff, 0xff, 0xf0, 0x80, 0x00, 0x00, 0x10, 
  0x8f, 0xc0, 0x00, 0x10, 0x98, 0x60, 0x7f, 0x90, 0x90, 0x20, 0x00, 0x10, 0xa0, 0x10, 0x00, 0x10, 
  0xa0, 0x10, 0x7f, 0x90, 0xa0, 0x10, 0x00, 0x10, 0x90, 0x20, 0x00, 0x10, 0x98, 0x60, 0x7f, 0x90, 
  0x87, 0x80, 0x00, 0x10, 0x80, 0x00, 0x00, 0x30, 0x7f, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00
};
// 'rbbottom', 24x33px
const unsigned char rbbottom [] PROGMEM = {
  0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x7e, 0x00, 0x00, 0xfc, 0x00, 0x03, 0xf8, 0x00, 
  0x0f, 0xe0, 0x00, 0x3f, 0x80, 0x00, 0xfe, 0x00, 0x03, 0xfc, 0x00, 0x0f, 0xf0, 0x00, 0x1f, 0xc0, 
  0x00, 0x7f, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x3f, 0xc0, 0x00, 0x0f, 0xf0, 0x00, 0x03, 0xf8, 0x00, 
  0x00, 0xfe, 0x00, 0x00, 0x3f, 0x80, 0x00, 0x0f, 0xe0, 0x00, 0x07, 0xf8, 0x00, 0x01, 0xfc, 0x00, 
  0x00, 0x7e, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x7f, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00
};
// 'rb1', 33x21px
const unsigned char rb1 [] PROGMEM = {
  0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x02, 0x07, 0x06, 0x00, 0x07, 0x02, 0x0f, 0x0e, 0x00, 0x05, 
  0x02, 0x09, 0x8a, 0x00, 0x01, 0x04, 0x08, 0x82, 0x00, 0x01, 0x04, 0x10, 0x82, 0x00, 0x01, 0x04, 
  0x10, 0x82, 0x00, 0x01, 0x04, 0x10, 0x82, 0x00, 0x01, 0x04, 0x10, 0x82, 0x00, 0x01, 0x04, 0x10, 
  0x82, 0x00, 0x01, 0x08, 0x10, 0x82, 0x00, 0x01, 0x08, 0x10, 0x82, 0x00, 0x01, 0x08, 0x10, 0x82, 
  0x00, 0x01, 0x08, 0x10, 0x82, 0x00, 0x01, 0x08, 0x08, 0x82, 0x00, 0x01, 0x08, 0x09, 0x82, 0x00, 
  0x47, 0xc8, 0x8d, 0x0f, 0x80, 0x47, 0xd0, 0x87, 0x0f, 0x80, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 
  0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
// 'rbspeed', 35x26px
const unsigned char rbspeed [] PROGMEM = {
  0x00, 0x00, 0x0f, 0xc0, 0x00, 0x00, 0x00, 0x0f, 0xc0, 0x00, 0x00, 0x00, 0x03, 0x80, 0x00, 0x00, 
  0x00, 0x07, 0x80, 0x00, 0x00, 0x00, 0x3f, 0xf0, 0x00, 0x07, 0xf8, 0x7f, 0xfc, 0x00, 0x07, 0xfd, 
  0xf0, 0x1e, 0x00, 0x00, 0x01, 0xc1, 0x0f, 0x00, 0x00, 0x03, 0x83, 0x03, 0x80, 0x00, 0x07, 0x03, 
  0x03, 0x80, 0x3f, 0xc7, 0x03, 0x01, 0xc0, 0x00, 0x06, 0x03, 0x01, 0xc0, 0x00, 0x0e, 0x03, 0x00, 
  0xc0, 0x00, 0x0e, 0x03, 0x00, 0xc0, 0x7f, 0x8e, 0x01, 0xf8, 0xc0, 0x00, 0x0e, 0x00, 0x00, 0xc0, 
  0x00, 0x0e, 0x00, 0x00, 0xc0, 0x00, 0x06, 0x00, 0x01, 0xc0, 0x3f, 0xc7, 0x00, 0x01, 0x80, 0x00, 
  0x03, 0x00, 0x03, 0x80, 0x00, 0x03, 0x80, 0x07, 0x00, 0x00, 0x01, 0xc0, 0x0f, 0x00, 0x07, 0xf8, 
  0xf0, 0x3e, 0x00, 0x07, 0xfc, 0x7f, 0xf8, 0x00, 0x00, 0x00, 0x1f, 0xe0, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00
};
// 'rbx', 12x11px
const unsigned char rbx [] PROGMEM = {
  0xc0, 0x30, 0x60, 0x60, 0x30, 0xc0, 0x19, 0x80, 0x0f, 0x00, 0x06, 0x00, 0x0f, 0x00, 0x19, 0x80, 
  0x30, 0xc0, 0x60, 0x60, 0xc0, 0x30
};
// 'rbauto', 35x34px
const unsigned char rbauto [] PROGMEM = {
  0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x07, 0x80, 0x00, 0x00, 0x00, 
  0x1f, 0x9c, 0x00, 0x00, 0x00, 0x7f, 0x9f, 0x00, 0x00, 0x01, 0xe7, 0x03, 0xc0, 0x00, 0x03, 0x86, 
  0x00, 0xe0, 0x00, 0x07, 0x04, 0x00, 0x70, 0x00, 0x0e, 0x00, 0x00, 0x38, 0x00, 0x1c, 0x03, 0xc0, 
  0x1c, 0x00, 0x38, 0x03, 0xc0, 0x0e, 0x00, 0x30, 0x03, 0xc0, 0x06, 0x00, 0x70, 0xf3, 0xcf, 0x07, 
  0x00, 0x60, 0xf3, 0xcf, 0x03, 0x00, 0x60, 0xf3, 0xcf, 0x03, 0x00, 0x60, 0xf3, 0xcf, 0x03, 0x00, 
  0xe4, 0xf3, 0xcf, 0x39, 0x80, 0xc4, 0xf3, 0xcf, 0x39, 0x80, 0xc4, 0xf3, 0xcf, 0x39, 0x80, 0xe4, 
  0xf3, 0xcf, 0x39, 0x80, 0x64, 0xf3, 0xcf, 0x23, 0x80, 0x64, 0xf3, 0xcf, 0x2b, 0x00, 0x64, 0xf3, 
  0xcf, 0x2f, 0x00, 0x20, 0xf3, 0xcf, 0x2f, 0xe0, 0x00, 0xf3, 0xcf, 0x2f, 0xc0, 0x1f, 0x33, 0xcf, 
  0x27, 0x00, 0x3f, 0x93, 0xcf, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x10, 0x00, 0x3e, 0x00, 0x00, 0x38, 
  0x00, 0x37, 0x80, 0x00, 0x70, 0x00, 0x11, 0xc0, 0x01, 0xe0, 0x00, 0x00, 0xf8, 0x0f, 0x80, 0x00, 
  0x00, 0x3f, 0xff, 0x00, 0x00, 0x00, 0x0f, 0xf8, 0x00, 0x00
};
// 'rbwidth', 28x18px
const unsigned char rbwidth [] PROGMEM = {
  0x00, 0x0f, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x03, 0xcf, 0x3c, 0x00, 
  0x03, 0xcf, 0x3c, 0x00, 0x03, 0xcf, 0x3c, 0x00, 0x03, 0xcf, 0x3c, 0x00, 0xf3, 0xcf, 0x3c, 0xf0, 
  0xf3, 0xcf, 0x3c, 0xf0, 0xf3, 0xcf, 0x3c, 0xf0, 0xf3, 0xcf, 0x3c, 0xf0, 0xf3, 0xcf, 0x3c, 0xf0, 
  0xf3, 0xcf, 0x3c, 0xf0, 0xf3, 0xcf, 0x3c, 0xf0, 0xf3, 0xcf, 0x3c, 0xf0, 0xf3, 0xcf, 0x3c, 0xf0, 
  0xf3, 0xcf, 0x3c, 0xf0, 0xf3, 0xcf, 0x3c, 0xf0
};
// 'rbtop', 24x34px
const unsigned char rbtop [] PROGMEM = {
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 
  0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 
  0x00, 0x7e, 0x00, 0x00, 0x3f, 0x80, 0x00, 0x1f, 0xe0, 0x00, 0x07, 0xf0, 0x00, 0x01, 0xfc, 0x00, 
  0x00, 0x7f, 0x00, 0x00, 0x1f, 0xc0, 0x00, 0x0f, 0xf0, 0x00, 0x03, 0xfc, 0x00, 0x00, 0xfe, 0x00, 
  0x00, 0xfe, 0x00, 0x03, 0xf8, 0x00, 0x0f, 0xf0, 0x00, 0x3f, 0xc0, 0x00, 0x7f, 0x00, 0x01, 0xfc, 
  0x00, 0x07, 0xf0, 0x00, 0x1f, 0xc0, 0x00, 0x3f, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x38, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
// 'rbup', 28x34px
const unsigned char rbup [] PROGMEM = {
  0x00, 0x06, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x1f, 0x80, 0x00, 0x00, 0x3f, 0xc0, 0x00, 
  0x00, 0x7f, 0xe0, 0x00, 0x00, 0xff, 0xf0, 0x00, 0x01, 0xff, 0xf8, 0x00, 0x03, 0xff, 0xfc, 0x00, 
  0x07, 0xff, 0xfe, 0x00, 0x0f, 0xff, 0xff, 0x00, 0x1f, 0xff, 0xff, 0x80, 0x3f, 0xff, 0xff, 0xc0, 
  0x7f, 0xff, 0xff, 0xe0, 0xff, 0xff, 0xff, 0xf0, 0xff, 0xbf, 0xdf, 0xf0, 0xff, 0x3f, 0xcf, 0xf0, 
  0xfe, 0x3f, 0xc7, 0xf0, 0x7c, 0x3f, 0xc3, 0xe0, 0x18, 0x3f, 0xc1, 0x80, 0x00, 0x3f, 0xc0, 0x00, 
  0x00, 0x3f, 0xc0, 0x00, 0x00, 0x3f, 0xc0, 0x00, 0x00, 0x3f, 0xc0, 0x00, 0x00, 0x3f, 0xc0, 0x00, 
  0x00, 0x3f, 0xc0, 0x00, 0x00, 0x3f, 0xc0, 0x00, 0x00, 0x3f, 0xc0, 0x00, 0x00, 0x3f, 0xc0, 0x00, 
  0x00, 0x3f, 0xc0, 0x00, 0x00, 0x3f, 0xc0, 0x00, 0x00, 0x1f, 0x80, 0x00, 0x00, 0x1f, 0x80, 0x00, 
  0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};