/*
  Pocket radar

  pixel LUT
  https://wokwi.com/projects/327642884399432274

  add pause button
*/

#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <Servo.h>

const int SWEEP_SPD = 1000;
const int MAX_VECTOR = 175;
const int MIN_VECTOR = 5;
const int SERVO_PIN = 3;
const int ECHO_PIN = 11;
const int TRIG_PIN = 12;
const int CENTER_X = 63;  // x center of the sweep
const int CENTER_Y = 63;  // y center of the sweep
const int RADIUS = 61;    // radius for pixel tickmarks
const int OLED_RESET = -1;

// lookup tables for sin/cos calculations
byte lut_x_pixel[36]; // 180 deg / 5 deg
byte lut_y_pixel[36];
int increment = 5;
unsigned long prevMillis = 0;

Adafruit_SSD1306 display(128, 64, &Wire, OLED_RESET);
Servo servo;

long getDistance() {
  digitalWrite(TRIG_PIN, LOW);
  delayMicroseconds(5);
  digitalWrite(TRIG_PIN, HIGH);
  delayMicroseconds(10);
  digitalWrite(TRIG_PIN, LOW);
  long duration = pulseIn(ECHO_PIN, HIGH);
  long cm = (duration / 2) / 29.1;  // Divide by 29.1 or multiply by 0.0343
  //inches = (duration / 2) / 74; // Divide by 74 or multiply by 0.0135
  return cm;
}

void makeLUT()  {
  // pre-calculate x and y positions into look-up tables
  for (int angle = 5; angle < 180; angle += 5) {
    lut_x_pixel[angle / 5] =  sin(radians(angle - 90)) * RADIUS + CENTER_X;
    lut_y_pixel[angle / 5] = -cos(radians(angle - 90)) * RADIUS + CENTER_Y;
    /*
      Serial.print("a: ");
      Serial.print(angle);
      Serial.print(F("\tX: "));
      Serial.print(lut_x_pixel[angle / 5]);
      Serial.print(F("\tY: "));
      Serial.println(lut_y_pixel[angle / 5]);
    */
  }
}

void setup() {
  Serial.begin(115200);
  pinMode(ECHO_PIN, INPUT);
  pinMode(TRIG_PIN, OUTPUT);
  servo.attach(SERVO_PIN);
  makeLUT();
  display.setRotation(2);
  display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
  display.setFont();
  display.setTextSize(0);      // Normal 1:1 pixel scale
  display.setTextColor(WHITE, BLACK); // Draw white text
  display.display();
  delay(100);
  display.clearDisplay(); // clears the screen and buffer
  display.drawCircle( // origin x, y, radius, color
    (display.width() / 2) - 1, display.height(),
    display.height() - 1,
    SSD1306_WHITE);
  display.drawCircle(
    (display.width() / 2) - 1, display.height(),
    (display.height() - 1) / 2,
    SSD1306_WHITE);
  display.setCursor(0, 0);
  display.print("Range:");
  display.setCursor(104, 0);
  display.print("Deg:");
  display.display();
}

void loop() {
  static int bearing = MIN_VECTOR;
  char buffer[4];
  long range = 0;

  if (millis() - prevMillis >= SWEEP_SPD)  {
    prevMillis = millis();

    bearing = bearing + increment;
    if (bearing >= MAX_VECTOR || bearing <= MIN_VECTOR)   {
      increment = -increment;
    }
    servo.write(bearing);

    display.drawLine(
      CENTER_X, CENTER_Y,
      lut_x_pixel[bearing / 5], lut_y_pixel[bearing / 5],
      SSD1306_WHITE);
    display.display();
    delay(50);
    display.drawLine(
      CENTER_X, CENTER_Y,
      lut_x_pixel[bearing / 5], lut_y_pixel[bearing / 5],
      SSD1306_BLACK);
    display.display();

    range = getDistance();
    int screenRange = map (range, 2, 400, 0, RADIUS);

    display.fillCircle( // origin x, y, radius, color
      sin(radians(bearing - 90)) * screenRange + CENTER_X - 1,
      -cos(radians(bearing - 90)) * screenRange + CENTER_Y,
      2,
      SSD1306_WHITE);
    display.display();
    delay(50);
    display.fillCircle( // origin x, y, radius, color
      sin(radians(bearing - 90)) * screenRange + CENTER_X - 1,
      -cos(radians(bearing - 90)) * screenRange + CENTER_Y,
      2,
      SSD1306_BLACK);

    // readouts
    snprintf(buffer, 4, "%3d", range);
    display.setCursor(0, 8);
    display.print(buffer);
    snprintf(buffer, 4, "%3d", bearing);
    display.setCursor(104, 8);
    display.print(buffer);
    display.display();

    Serial.print("Range: ");
    Serial.print(range);
    Serial.print("\tBearing: ");
    Serial.println(bearing);
  }
}
$abcdeabcde151015202530fghijfghij