//------------------------------------------------------
// Geophone interface
// 2026.09.19 RSP
// Target: ATmega328PB 16MHz Pololu A*
//
// Takes geophone signal from amplifier,
// outputs to display (CYD) and neopixel bar graph.
//------------------------------------------------------

#include <Adafruit_NeoPixel.h>
#define PIX_PIN 6
#define NUMPIXELS 16 // Popular NeoPixel ring size
Adafruit_NeoPixel pixels(NUMPIXELS, PIX_PIN, NEO_GRB + NEO_KHZ800);

// all switches wired to ground
//   SW1 is ON-OFF-ON toggle or band switch
//   SW2 is ON-OFF-(ON) (run-continue-stop)
#define SW1A_PIN 4 // run
#define SW1B_PIN 5 // stop, momentary
#define SW2A_PIN 8 // sample rate: low
#define SW2B_PIN 9 // sample rate: high
#define RUN_LED_PIN 7

void setup()
{
  Serial1.begin(115200);
  pinMode( LED_BUILTIN, OUTPUT );
  pinMode( RUN_LED_PIN, OUTPUT );
  pinMode( SW1A_PIN,  INPUT_PULLUP );
  pinMode( SW1B_PIN,  INPUT_PULLUP );
  pinMode( SW2A_PIN, INPUT_PULLUP );
  pinMode( SW2B_PIN, INPUT_PULLUP );
  pixels.begin(); // INITIALIZE NeoPixel strip object (REQUIRED)
}

//------------------------------------------------------

uint32_t poll_rates[3] = { 2,5,10 }; // 500/sec, 250/sec, 100/sec
byte     poll_rate_index = 1;

void processCh( char ch )
{
  if (ch == 'S') digitalWrite( RUN_LED_PIN, LOW );
}
    
boolean waitFor( char ch, uint32_t msec )
{
  for (uint32_t tm=millis(); true; )
  {
    int c = Serial1.read();
    processCh(c);
    if (c == ch) return true;

    if (millis()-tm >= msec) break;
  }
  return false;
}
 
void loop()
{
  // get sample rate setting
  if (!digitalRead( SW2A_PIN ))
    poll_rate_index = 0; // high speed
  else if (!digitalRead( SW2B_PIN ))
    poll_rate_index = 2; // low speed
  else
    poll_rate_index = 1; // medium speed
    
  // send samples to display
  static uint32_t tm = millis();
  if (millis()-tm >= poll_rates[poll_rate_index])
  { tm += poll_rates[poll_rate_index];

    // collect sample
    int val_adc = analogRead(A0) >> 2; 
    int ave_adc = analogRead(A1) >> 2;
    int ref_adc = analogRead(A2) >> 2;
    ave_adc -= ref_adc;
    if (ave_adc < 0) ave_adc = 0;
    ave_adc *= 2;
    if (ave_adc > 255) ave_adc = 255;
    
    // send to display
    char hexBuffer[10]; // Must be large enough to hold characters + null terminator
    sprintf(hexBuffer, "%02X%02X\x0D", val_adc, ave_adc);
    Serial1.write(hexBuffer);

    // light up pixel string
    byte px = ave_adc >> 4;
    for (byte i=0; i < 16; i++)
      pixels.setPixelColor(i, pixels.Color(i < px ? 8:0, 0, 0));
    pixels.show(); 

    // diagnostic - output sample rate/2 on builtin LED
    digitalWrite( LED_BUILTIN, !digitalRead( LED_BUILTIN ) );  
  }

  // watch control switch
  if (!digitalRead(RUN_LED_PIN) && !digitalRead(SW1A_PIN)) // run
  {
    Serial1.write('R'); Serial1.write(13); // send RUN
    if (waitFor( 'R',1000 ))
      digitalWrite( RUN_LED_PIN, HIGH );
  }    
  if (!digitalRead(SW1B_PIN)) // stop
  { 
    Serial1.write('S'); Serial1.write(13); // send STOP
    digitalWrite( RUN_LED_PIN, LOW );
    delay(1000);
  }

  waitFor( 0,0 ); // process commands from display
}
