/*
*************Four Banger*********
3/26/2015 hacked together by Mike North aka mikkojay on multiple forums.
The latest info and updates for this sketch may be found at ButtonBanger.com
The mini/nano has 1k of eeprom and a 12v regulator. At the moment of writing this (3/2015) the
pro mini could be found on ebay for $2.33 shipped which is insanely cheap. Speaking of insanely cheap,
how about a 4 relay module, optocoupled and all, for $3.30 shipped? This means that for under $6 you
could have a very tidy little programmable prop controller.
I also found a nice "5 button board" on ebay that should work nicely as a manual programmer.
For audio, we are currently using the Catalex module because it is cheaper, smaller, and has a jack.
reset_delay is programmed using the following procedure:
-While in ambient mode, hold down the menu button (button 3) for 3+ seconds.
-RECORD_LED will blink 3 times.
-enter desired delay seconds by entering the number in binary, 8 digits (up to 255 seconds)
- This is done by using the - and + buttons on the programming board.
- Entering - is a zero, entering + is a one
- For example, we want a delay of 1.5 minutes, or 90 seconds.
-- In windows calculator, enter 90 (programming mode) in decimal, then switch view to binary.
-- you then get: 1011010
-- This would be entered starting with the lowest(rightmost) digit, padded with zeros for a total of 8 digits.
-- Imagine it as a dip switch panel with 8 positions.
0 1 0 1 1 0 1 0
-- The sequence would be: -,+,-,+,+,-,+,-
-- The RECORD_LED will blink 3 times to indicate the successful setting of this value.
*/
#include <EEPROM.h>
//#include <SoftwareSerial/SoftwareSerial.h>
#include "MiniAudio.h"
volatile bool stampok = true;
volatile byte stamp_buff[5] = {6,70,4,1,4}; //holder for stamp
volatile bool pir_ok = true;
int pirValue = 0; // value read from the pir pin
//these are the free standing defines
#define RECORD_PIN 2 //the pin number of our recording switch
#define BUTTON_1_PIN 6 //the pin number of our "1" switch, may be marked as - on programming board
#define BUTTON_2_PIN 5 //the pin number of our "2" switch, may be marked as + on programming board
#define BUTTON3_MENU_PIN 8 //the pin number of our "3" switch, may be marked as Menu on programming board
#define BUTTON4_TRIGGER_PIN 7 //pin number of our trigger, same as 4 switch, may be marked Auto on prog board
#define RECORD_LED 3 //red led
#define PLAY_LED 4 //green led
#define PIR_INPUT_PIN A5 //PIR read from analog input pin
/*
//these are the host board pin assignments
#define RECORD_PIN 9 //the pin number of our recording switch
#define BUTTON_1_PIN 4 //the pin number of our "1" switch, may be marked as - on programming board
#define BUTTON_2_PIN 5 //the pin number of our "2" switch, may be marked as + on programming board
#define BUTTON3_MENU_PIN 2 //the pin number of our "3" switch, may be marked as Menu on programming board
#define BUTTON4_TRIGGER_PIN 3 //pin number of our trigger, same as 4 switch, may be marked Auto on prog board
#define RECORD_LED 8 //red led
#define PLAY_LED 7 //green led
#define PIR_INPUT_PIN A6 //PIR read from analog input pin
*/
#define AUDIO_PIN 10 //mp3 serial out
#define TRIGGER_TTL_PIN 11 //alt input for a TTL trigger- uses internal pull up
#define TRIGGER_OUT_PIN 12
#define ARDUINO_LED 13 //board led
#define DEBOUNCE 6 // button debouncer, how many ms to debounce, 5+ ms is usually plenty
//eeprom offsets
//sequence data 0 - 979
const int SAMPLE_COUNT = 980; //saving last 20 bytes for config use (total of 1k eeprom)
const int MARK_OFFSET = 980; //start byte of stamp
//980-984 stamp
const int MS_PER_EVENT_SLOT = 985;
const int TRIGGER_LOW_SLOT = 986;
const int TTL_TYPES_SLOT = 987;
const int RESET_DELAY_SLOT = 988;
const int HI_SAMPLE_LB = 989;
const int HI_SAMPLE_UB = 990;
const int REC_LOCK_SLOT = 991;
const int AMBIENT_ON_DELAY_SLOT = 992;
const int BOOT_DELAY_SLOT = 993;
const int VOLUME_SLOT = 994;
bool AMBIENT_ON_DELAY = true;
const int TTL_COUNT = 4; //number of TTL outputs
const int INPUT_COUNT = 6; //reading from 6 io pins
bool TTL_TYPES[TTL_COUNT] = {1,1,1,1}; //translated TTL Types
int8_t TTL_PINS[TTL_COUNT];
int8_t SWITCH_PINS[INPUT_COUNT];
volatile byte pressed[INPUT_COUNT];
volatile uint8_t TTL_TYPE_BYTE = 15;
int val = 0; // variable to store the read value
unsigned int hi_sample = 0;
uint8_t MS_PER_EVENT_OPTS[4] = {200,100,50,40}; //5,10,20,25 fps
volatile uint8_t MS_PER_EVENT = 50; //default is 20 frames per sec (50 ms each)
volatile uint8_t RESET_DELAY_SECS = 30; //default will be 30 secs I suppose
volatile byte samples[SAMPLE_COUNT]; //working buffer so we don't read from eeprom constantly
volatile uint8_t PIR_ANALOG_NORMALLY = LOW;
volatile uint8_t record_lock = 0X0; //if 1, we are locked
const int SERIAL_WAIT = 5; //delay for serial reads
volatile uint8_t BOOT_DELAY_SECS = 10; //delay before the prop "goes hot"
volatile uint8_t _volume = 30;
volatile bool IS_HOT = true;
MiniAudio _MA;
/*********************************************************************/
void setup()
{
Serial.begin(115200); //we talk to the PC at 115200
delay(100);
//map our pins
TTL_PINS[0] = A0;
TTL_PINS[1] = A1;
TTL_PINS[2] = A2;
TTL_PINS[3] = A3;
SWITCH_PINS[0] = BUTTON_1_PIN;
SWITCH_PINS[1] = BUTTON_2_PIN;
SWITCH_PINS[2] = BUTTON3_MENU_PIN;
SWITCH_PINS[3] = BUTTON4_TRIGGER_PIN;
SWITCH_PINS[4] = RECORD_PIN;
SWITCH_PINS[5] = TRIGGER_TTL_PIN;
//init output pins
for (int i = 0; i < TTL_COUNT; i++)
{
pinMode(TTL_PINS[i], OUTPUT);
digitalWrite(TTL_PINS[i], TTL_TYPES[i]); //HIGH = off
}
//init input pins
for (int i = 0; i < INPUT_COUNT; i++)
{
pinMode(SWITCH_PINS[i], INPUT);
digitalWrite(SWITCH_PINS[i], HIGH); // connect internal pull-up
}
// initialize the LED pin as an output:
pinMode(ARDUINO_LED, OUTPUT);
digitalWrite(ARDUINO_LED, LOW);
//if they are holding down the play/Auto button on power up, do a factory reset
pinMode(RECORD_LED, OUTPUT);
pinMode(PLAY_LED, OUTPUT);
digitalWrite(RECORD_LED, LOW);
digitalWrite(PLAY_LED, HIGH);
digitalWrite(PLAY_LED, LOW);
pinMode(TRIGGER_OUT_PIN, OUTPUT);
digitalWrite(TRIGGER_OUT_PIN, HIGH); // connect internal pull-up
//check for previous fault and explain why with an error code
//CheckMCU();
if(digitalRead(SWITCH_PINS[3]) == LOW)
{
delay(1000); //make them hold for a full second then check again
if(digitalRead(SWITCH_PINS[3]) == LOW)
{
burn_config(); //will burn defaults
blink_alert();
while(digitalRead(SWITCH_PINS[3]) == HIGH){}
}
}
//read config from eeprom
read_config();
_MA.Init(AUDIO_PIN,_volume);
set_ambient_out();
_MA.PlayAmbient();
buffer_samples();
report_config();
check_pir();
delay(100);
if(BOOT_DELAY_SECS > 0)
{
Serial.println(F("Waiting for Boot Delay..."));
blink_times(BOOT_DELAY_SECS); //this uses 1 second per blink
}
Serial.println(F("Ready"));
clear_rx_buffer(); //just in case someone has been asking HEY HEY Do this do that while we were busy
}
void check_switches()
{
//this is dumbed-down debounce check.
//it looks at all input in one sweep.
//button is ussumed off at first
//2 samples are taken for each input, separated by n milliseconds.
//if the samples are both on, we consider it a true on condition
static byte state1[INPUT_COUNT];
static byte state2[INPUT_COUNT];
static long lasttime;
byte index;
for (index = 0; index < INPUT_COUNT; index++)
{
pressed[index] = 1; //not pressed
state1[index] = digitalRead(SWITCH_PINS[index]); // read the button
}
delay(DEBOUNCE);
for (index = 0; index < INPUT_COUNT; index++)
{
state2[index] = digitalRead(SWITCH_PINS[index]); // read the button
if (state1[index] + state2[index] == 0)
{
pressed[index] = 0;
}
}
}
void CheckMCU()
{
return;
int times = 0;
if(MCUSR & (1<<PORF )) times = 1; //Power-on Reset
if(MCUSR & (1<<EXTRF)) times = 2; //External reset
if(MCUSR & (1<<BORF )) times = 3; //Brownout reset
if(MCUSR & (1<<WDRF )) times = 4; //Watchdog reset
if(times > 0)
{
blink_alert();
delay(1000);
blink_times(times);
delay(1000);
blink_alert();
delay(500);
}
MCUSR = 0;
}
void check_pir()
{
pir_ok = false;
int waitmax = 45;
Serial.println(F("Checking for PIR..."));
for(int i = 0; i < waitmax; i++)
{
blink_times(1);
pirValue = analogRead(PIR_INPUT_PIN);
if(PIR_ANALOG_NORMALLY == LOW)
{
if (pirValue < 20)
{
pir_ok = true;
break;
}
}
else
{
if (pirValue > 900)
{
pir_ok = true;
break;
}
}
}
if(pir_ok)
{
Serial.println(F("PIR found, 10 sec wait..."));
//courtesy delay of 10 secs
for(int i = 0; i < 10; i++)
{
blink_once();
}
Serial.println(F("PIR ready"));
}
else
Serial.println(F("PIR not found, ignoring PIR"));
}
void buffer_samples()
{
//fetch whatever eeprom values we have into buffer
if(hi_sample > 0)
{
for (int i = 0; i < SAMPLE_COUNT; i++)
{
samples[i] = EEPROM.read(i);
}
}
}
void read_config()
{
byte dtemp = 0;
stampok = true;
for(int i = 0; i < 5; i++)
{
dtemp = EEPROM.read(MARK_OFFSET + i);
if(dtemp != stamp_buff[i])
{
stampok = false;
break;
}
}
if(stampok) //control number so we don't read in junk
{
PIR_ANALOG_NORMALLY = EEPROM.read(TRIGGER_LOW_SLOT);
hi_sample = EEPROM.read(HI_SAMPLE_UB); //read the high/upper byte into hi_sample
hi_sample = hi_sample << 8;
//bitshift the high byte left 8 bits to make room for the low byte
hi_sample = hi_sample | EEPROM.read(HI_SAMPLE_LB); //read the low byte
//get reset_delay out of EEPROM, represents seconds
MS_PER_EVENT = EEPROM.read(MS_PER_EVENT_SLOT);
if(MS_PER_EVENT < 40)
MS_PER_EVENT = 50;
RESET_DELAY_SECS = EEPROM.read(RESET_DELAY_SLOT);
BOOT_DELAY_SECS = EEPROM.read(BOOT_DELAY_SLOT);
record_lock = EEPROM.read(REC_LOCK_SLOT);
AMBIENT_ON_DELAY = EEPROM.read(AMBIENT_ON_DELAY_SLOT);
TTL_TYPE_BYTE = EEPROM.read(TTL_TYPES_SLOT);
_volume = EEPROM.read(VOLUME_SLOT);
if(_volume < 1 || _volume > 30)
_volume = 30;
_MA.Init(AUDIO_PIN,_volume);
for (int i = 0; i < TTL_COUNT; i++)
{
TTL_TYPES[i] = bitRead(TTL_TYPE_BYTE,i); //default to TTL low Output default, active high
}
}
else
{
init_defaults();
}
}
void report_config()
{
Serial.print(F("FourBanger v"));
for (int i = 3; i < 5; i++)
{
Serial.print(stamp_buff[i]);
delay(1);
if(i < 4)
Serial.print(".");
else
Serial.println();
}
if(stampok) //control number so we don't read in junk
{
Serial.println(F("Config OK"));
}
else
{
Serial.println(F("Config NOT FOUND, using defaults"));
}
Serial.print(F("PIR Normally Hi/Low: "));
Serial.println(PIR_ANALOG_NORMALLY);
Serial.print(F("PIR Input Pin: "));
Serial.println(PIR_INPUT_PIN);
Serial.print(F("MS Per Event: "));
Serial.println(MS_PER_EVENT);
Serial.print(F("Event Count: "));
Serial.println(hi_sample);
Serial.print(F("Reset Delay Secs: "));
Serial.println(RESET_DELAY_SECS);
Serial.print(F("Boot Delay Secs: "));
Serial.println(BOOT_DELAY_SECS);
if(record_lock > 0)
Serial.println(F("Recording Locked"));
Serial.print(F("TTL TYPES: "));
for (int i = 0; i < TTL_COUNT; i++)
{
Serial.print(TTL_TYPES[i]);
if(i<TTL_COUNT - 1)
Serial.print(",");
else
Serial.println();
}
Serial.print(F("TTL PINS: "));
for (int i = 0; i < TTL_COUNT; i++)
{
Serial.print(TTL_PINS[i]);
if(i<TTL_COUNT - 1)
Serial.print(",");
else
Serial.println();
}
}
void init_defaults()
{
_volume = 30;
for (int i = 0; i < TTL_COUNT; i++)
{
TTL_TYPES[i] = true; //default to TTL low Output default, active high
}
}
byte softRead(byte pin)
{
for (int i = 0; i < INPUT_COUNT; i++)
{
if (SWITCH_PINS[i] == pin)
return pressed[i];
}
return 0; //unknown pin
}
void loop()
{
check_serial();
if(IS_HOT)
{
check_switches();
if (softRead(BUTTON4_TRIGGER_PIN) == LOW || softRead(TRIGGER_TTL_PIN) == LOW || pir_triggered())
{
play_sequence();
}
else
{
if (softRead(RECORD_PIN) == LOW)
{
record_sequence();
}
else if (softRead(BUTTON3_MENU_PIN) == LOW)
{
configure_reset_delay();
}
else if (softRead(BUTTON_1_PIN) == LOW)
{
set_volume(false);
}
else if (softRead(BUTTON_2_PIN) == LOW)
{
set_volume(true);
}
}
}
}
bool set_volume(bool up)
{
uint8_t newvol = _volume;
if(up && _volume < 30)
newvol++;
if(!up && _volume > 1)
newvol--;
if(newvol != _volume)
{
_volume = newvol;
EEPROM.write(VOLUME_SLOT,_volume);
_MA.SetVolume(_volume);
}
}
bool pir_triggered()
{
if(pir_ok == false) return false;
pirValue = analogRead(PIR_INPUT_PIN);
if(PIR_ANALOG_NORMALLY == LOW)
{
if (pirValue > 600) return true;
}
else
{
if (pirValue < 20) return true;
}
return false;
}
void record_sequence()
{
int held_count = 0;
//do not begin until they let up on the button
while (digitalRead(RECORD_PIN) == LOW)
{
delay(1);
held_count++;
if(held_count > 3000)
{
if(record_lock > 0)
{
record_lock = 0;
Serial.println(F("Recording enabled"));
}
else
{
record_lock = 1;
Serial.println(F("Recording disabled"));
}
EEPROM.write(REC_LOCK_SLOT,record_lock);
blink_alert();
while (digitalRead(RECORD_PIN) == LOW){} //so recording does not get triggered again
return;
}
}
if(record_lock > 0)
{
Serial.println(F("Recording disabled"));
Serial.println(F("Hold Rec button for 3+ seconds to enable"));
blink_alert();
return;
}
//clear buffer
for(int i = 0; i < SAMPLE_COUNT;i++)
{
samples[i] = 0;
}
digitalWrite(RECORD_LED, HIGH); //let them know we are recording
_MA.PlayScare();
Serial.println(F("Recording manually..."));
hi_sample = 0;
for(int i = 0; i < SAMPLE_COUNT;i++)
{
//each byte sample has 8 bits. since we have 4 relays, that means one byte
// can actually store 2 sets of 4 on/off states.
hi_sample++;
check_switches();
for(int x = 0;x < TTL_COUNT; x++)
{
if (softRead(SWITCH_PINS[x]) == LOW) bitSet(samples[i],x);
}
OutputTTL(samples[i],0); //output lower half
if (softRead(RECORD_PIN) == LOW) break;
delay(MS_PER_EVENT - DEBOUNCE);
hi_sample++;
check_switches();
for(int x = 0;x < TTL_COUNT; x++)
{
if (softRead(SWITCH_PINS[x]) == LOW) bitSet(samples[i],x + TTL_COUNT);
}
OutputTTL(samples[i],4); //output the upper half
delay(MS_PER_EVENT - DEBOUNCE);
if (softRead(RECORD_PIN) == LOW) break;
}
//set all outputs off
set_ambient_out();
digitalWrite(RECORD_LED, LOW);
//save samples to EEPROM
for (int i = 0; i < SAMPLE_COUNT; i++)
{
EEPROM.write(i,samples[i]);
}
burn_config();
//blink to let them know we saved
Serial.println(F("Recording complete"));
Serial.print(F("Samples recorded: "));
Serial.println(hi_sample);
blink_alert();
delay(1000);
_MA.PlayAmbient();
check_switches();
clear_rx_buffer();
}
void burn_config()
{
//called after recording, write variables to eeprom so that we restore on next restart
//write the stamp
for(int i = 0; i < 5; i++)
EEPROM.write(MARK_OFFSET + i,stamp_buff[i]);
stampok = true; //now that we have written it
//write the hi_sample value to eeprom
EEPROM.write(HI_SAMPLE_UB, highByte(hi_sample));//writes the first byte of hi_sample
EEPROM.write(HI_SAMPLE_LB, lowByte(hi_sample));//writes the second byte of hi_sample
EEPROM.write(MS_PER_EVENT_SLOT,MS_PER_EVENT);
EEPROM.write(RESET_DELAY_SLOT,RESET_DELAY_SECS);
EEPROM.write(BOOT_DELAY_SLOT,BOOT_DELAY_SECS);
EEPROM.write(TTL_TYPES_SLOT,TTL_TYPE_BYTE);
EEPROM.write(AMBIENT_ON_DELAY_SLOT,AMBIENT_ON_DELAY);
EEPROM.write(TRIGGER_LOW_SLOT,PIR_ANALOG_NORMALLY);
EEPROM.write(VOLUME_SLOT,_volume);
}
void play_sequence()
{
if (hi_sample == 0) return; //nothing recorded
bool was_hot = IS_HOT;
IS_HOT = false;
digitalWrite(PLAY_LED, HIGH);
digitalWrite(TRIGGER_OUT_PIN, LOW); //trigger output pin for daisy chain
delay(100); // .1 sec should be sufficient
digitalWrite(TRIGGER_OUT_PIN, HIGH); //put back
_MA.PlayScare();
Serial.println(F("Playing sequence..."));
int play_sample = 0;
for(int i = 0; i < SAMPLE_COUNT;i++)
{
play_sample++;
if(play_sample > hi_sample) break;
OutputTTL(samples[i],0);
delay(MS_PER_EVENT);
play_sample++;
if(play_sample > hi_sample) break;
OutputTTL(samples[i],4);
delay(MS_PER_EVENT);
}
if(RESET_DELAY_SECS > 0)
{
Serial.print(F("Waiting delay secs: "));
Serial.println(RESET_DELAY_SECS);
}
set_ambient_out();
if(AMBIENT_ON_DELAY) //true means go back to ambient audio before the delay
_MA.PlayAmbient();
blink_times(RESET_DELAY_SECS); //this uses 1 second per blink
digitalWrite(PLAY_LED, LOW);
digitalWrite(RECORD_LED, LOW);
if(!AMBIENT_ON_DELAY) //true means go back to ambient audio before the delay
_MA.PlayAmbient();
Serial.println(F("Sequence complete"));
check_switches();
clear_rx_buffer(); //this will wipe any crap that may have been transmitted in the time we were playing
IS_HOT = was_hot;
}
void set_ambient_out()
{
//set all outputs to default
byte n = 0;
OutputTTL(n,0);
}
//writes the upper or 4 or lower 4 of one byte to our 4 TTL pins.
//It will use the usage booleans to know whether to invert
void OutputTTL(byte val, int offset)
{
for(int x = 0;x < TTL_COUNT; x++)
{
if(TTL_TYPES[x])
digitalWrite(TTL_PINS[x], !(bitRead(val,x + offset)));
else
digitalWrite(TTL_PINS[x], bitRead(val,x + offset));
}
}
//the whole reset delay thing is a total pain to set manually.
//I am leaving it in, but it will most likely never be called.
//setting this property in the GUI is 100% easier
void configure_reset_delay()
{
Serial.println(F("configuring reset delay..."));
unsigned long time1 = millis();
while (digitalRead(BUTTON3_MENU_PIN) == LOW)
{
delay(100);
if(millis() - time1 > 3000) break;
}
if(millis() - time1 < 3000) return; //only do this if they hold the button down for 3 secs
blink_alert();
RESET_DELAY_SECS = 0;
//do nothing until the switch is released
while (digitalRead(BUTTON3_MENU_PIN) == LOW)
{
delay(10);
}
//the switch states for the 1 and 0 pin
byte switch1 = digitalRead(BUTTON_2_PIN);
byte switch0 = digitalRead(BUTTON_1_PIN);
byte bitnumber = 0; //the number of bits recorded so far
//runs until all 8 bits have been recorded into the address.
while (bitnumber < 8)
{
//first, make sure both switches are released before accepting new bit.
if (switch0 == LOW || switch1 == LOW)
{
blink_once(); //flash off pin 13 to indicate bit accepted
//remain in the while loop while either switch is pressed, then delay half a second to avoid bounce and signal to the user that the bit has been accepted.
while (switch0 == LOW || switch1 == LOW)
{
switch0 = digitalRead(BUTTON_1_PIN);
switch1 = digitalRead(BUTTON_2_PIN);
}
delay(500);
}//end if
//The switches have been released, now wait for the new bit.
digitalWrite(RECORD_LED, HIGH);
digitalWrite(PLAY_LED, HIGH); //turn on to indicate ready for new bit.
switch0 = digitalRead(BUTTON_1_PIN);
switch1 = digitalRead(BUTTON_2_PIN);
if (switch1 == LOW)
{//execute if 1 pin is pressed
bitSet(RESET_DELAY_SECS, bitnumber); //write a 1 to the appropriate bit of reset_delay
bitnumber++;
}
else if (switch0 == LOW)
{//execute if 0 pin is pressed
bitClear(RESET_DELAY_SECS, bitnumber);
bitnumber++;
}
} //end while loop
//write the new address to EEPROM
blink_once();
EEPROM.write(RESET_DELAY_SLOT, RESET_DELAY_SECS);//writes the first byte of reset_delay
blink_alert();
digitalWrite(PLAY_LED, LOW);
digitalWrite(RECORD_LED, LOW);
Serial.print(F("new reset_delay: "));
Serial.println(RESET_DELAY_SECS);
}
void blink_alert()
{
for (byte i = 0; i < 15; i++)
{ //blink LED 4 times when new address is received.
digitalWrite(RECORD_LED, (i & 1));
digitalWrite(ARDUINO_LED, (i & 1));
//i & 1 will bitwise-and to 1 if i is odd, 0 if even.
delay(100);
}
}
void blink_green()
{
for (byte i = 0; i < 3; i++)
{ //blink LED 4 times when new address is received.
digitalWrite(PLAY_LED, (i & 1));
//i & 1 will bitwise-and to 1 if i is odd, 0 if even.
delay(1000);
}
}
void blink_once()
{
digitalWrite(RECORD_LED, HIGH);
digitalWrite(ARDUINO_LED, HIGH);
delay(500);
digitalWrite(RECORD_LED, LOW);
digitalWrite(ARDUINO_LED, LOW);
delay(500);
}
void blink_times(int times)
{
for(int i = 0; i < times; i++)
{
Serial.print(F("."));
digitalWrite(RECORD_LED, HIGH);
digitalWrite(ARDUINO_LED, HIGH);
delay(500);
digitalWrite(RECORD_LED, LOW);
digitalWrite(ARDUINO_LED, LOW);
delay(500);
}
}
void check_serial()
{
if (Serial.available() > 0)
{
byte b = Serial.read();
if (b == '@') // command header.
{
delay(SERIAL_WAIT);
if (Serial.available() > 0)
{
b = Serial.read();
delay(SERIAL_WAIT);
switch (b)
{
case 'V':
//return version
delay(SERIAL_WAIT);
for (int i = 0; i < 5; i++)
{
Serial.print(stamp_buff[i]);
delay(1);
if(i < 4) Serial.print(".");
}
break;
case 'H':
//go hot
IS_HOT = true;
Serial.println(F("Ready"));
break;
case 'C':
//go cold
IS_HOT = false;
Serial.println(F("Standby..."));
break;
case 'D':
//download eeprom contents back to Serial
tx_memory();
break;
case 'U':
rx_memory(); //here comes an Upload
break;
case 'P': //ping back
report_config();
break;
case 'T': //trigger test
play_sequence();
break;
case 'M': //manual TTL state command
b = Serial.read(); //get the state byte
OutputTTL(b,0);
break;
case 'I': //PIR test
pir_tester();
break;
default:
Serial.print(F("unk char:"));
Serial.print(b);
clear_rx_buffer();
break;
}
}
}
}
}
void pir_tester()
{
byte b_now = 0;
byte b_last = 0;
if(pir_triggered()) b_last += 1;
if(!digitalRead(TRIGGER_TTL_PIN)) b_last += 2;
if(pir_ok == false)
{
Serial.println(F("PIR not available"));
Serial.println(F("PIR test aborted"));
return;
}
Serial.print(F("PIR Normally Hi/Low: "));
Serial.println(PIR_ANALOG_NORMALLY);
Serial.println(F("Starting PIR tester"));
delay(500);
//pretty much any serial message sent will break out of this loop
while (Serial.available() == 0)
{
b_now = 0;
if(pir_triggered()) b_now += 1;
if(!digitalRead(TRIGGER_TTL_PIN)) b_now += 2;
if(b_now != b_last)
{
b_last = b_now;
Serial.print(b_now);
}
delay(50);
}
clear_rx_buffer();
}
//read 4 bytes from the Serial buffer and return as a 32bit integer
unsigned long SerialInt()
{
byte b[4];
for(int i = 0; i < 4; i++)
{
while(Serial.available() == 0){}
b[i] = Serial.read();
}
return (unsigned long)(((unsigned long)b[3] << 24) | ((unsigned long)b[2] << 16) | ((unsigned long)b[1] << 8) | (b[0]));
}
void rx_memory()
{
while(Serial.available() == 0){}
int howmany = SerialInt();
for(int i = 0; i < howmany; i++)
{
int waited = 0;
while(Serial.available() == 0)
{
waited++;
if(waited > 1000)
{
Serial.print(F("Stuck on: "));
Serial.println(i);
Serial.println(F("Upload terminated, please retry"));
return;
}
delay(1);
}
byte b = Serial.read();
if(i < 1000) EEPROM.write(i,b);
}
Serial.print(F("Uploaded eeprom with "));
Serial.print(howmany);
Serial.println(F(" bytes"));
read_config();
set_ambient_out();
report_config();
check_pir();
buffer_samples(); //transfer into working buffer
}
void tx_memory()
{
//tell them it is coming
Serial.print(F("@EDUMP1000"));
delay(1000);
for(int i = 0; i < 1000; i++)
{
byte b = EEPROM.read(i);
Serial.write(b);
delay(1);
}
}
void clear_rx_buffer()
{
while(Serial.available() != 0)
{
byte b = Serial.read();
delay(1);
}
}
Comments