// ============================================================================
// CREATED AND DESIGNED BY: MARVIN A. QUIZZAGAN
// DATE: MARCH 10, 2026 FINAL. 100% WORKING. FAVORITE
// UPDATED: D13 HIGH-PRIORITY REAL TRUCK REVERSE BEEP
//
// FUNCTION SUMMARY
//
// INPUTS
// D9 → Mirrors to A0
// D8 → Mirrors to A1 and used for HOLD command
// D7 → Internal pull-up, inverted output to A2
// D4 → HOLD input
// D2 → HOLD input
// D13 → Internal pull-up, HIGH PRIORITY reverse trigger input
//
// OUTPUTS
// A0 → Mirrors D9
// A1 → Mirrors D8
// A2 → Inverted output of D7
// D3 → Alert / reverse-beep output
//
// CONTROL
// Hold D8 + D4 + D2 LOW simultaneously:
//
// If latched alert is OFF
// → Hold for LONG_HOLD_ON_MS (5s) → latched alert activates
//
// If latched alert is ON
// → Hold for LONG_HOLD_OFF_MS (1.5s) → latched alert deactivates
//
// PRIORITY
// D13 LOW = HIGHEST PRIORITY
// → Forces D3 into realistic truck reverse beeping
// → Overrides normal latched beep pattern
//
// NORMAL ALERT PATTERN (WHEN LATCHED)
// beep-beep-beep (fast) → pause 3 seconds → repeat
//
// TRUCK REVERSE PATTERN (WHEN D13 LOW)
// BEEEP ... pause ... BEEEP ... pause ... continuously
//
// NOTE
// External pull-up resistors required on D9, D8, D4, and D2.
// D7 and D13 use internal pull-up.
// ============================================================================
const byte IN1 = 9;
const byte OUT1 = A0;
const byte IN2 = 8;
const byte OUT2 = A1;
const byte IN3 = 7;
const byte OUT3 = A2;
const byte HOLD1 = 4;
const byte HOLD2 = 2;
const byte REV_IN = 13; // D13 = reverse trigger, INPUT_PULLUP
const byte LATCH_OUT = 3; // D3 = beeping output
// ---------------- Hold Timing ----------------
const unsigned long LONG_HOLD_ON_MS = 5000;
const unsigned long LONG_HOLD_OFF_MS = 1500;
// ---------------- Debounce ----------------
const unsigned long DEBOUNCE_MS = 25;
// ---------------- Normal Latched Alert Pattern ----------------
// beep-beep-beep (fast) -> pause 3 sec -> repeat
const unsigned long ALERT_BEEP_HIGH_MS = 80;
const unsigned long ALERT_BEEP_LOW_MS = 80;
const unsigned long ALERT_BEEP_PAUSE_MS = 3000;
// ---------------- Realistic Truck Reverse Pattern ----------------
// More like a real truck / forklift:
// BEEEP ... pause ... BEEEP ... pause ...
const unsigned long REV_BEEP_HIGH_MS = 320;
const unsigned long REV_BEEP_LOW_MS = 680;
// ---------------- Mode Values ----------------
#define MODE_OFF 0
#define MODE_ALERT 1
#define MODE_REVERSE 2
// ---------------- States ----------------
bool latchState = false;
bool mustReleaseHold = false;
unsigned long longHoldStartMs = 0;
// ---------------- Debounce ----------------
bool stableRead(byte pin) {
struct S { byte raw, stable; unsigned long t; };
static S s[20];
byte r = digitalRead(pin);
if (r != s[pin].raw) {
s[pin].raw = r;
s[pin].t = millis();
}
if (millis() - s[pin].t >= DEBOUNCE_MS) {
s[pin].stable = s[pin].raw;
}
return s[pin].stable;
}
// ---------------- Beeper States ----------------
byte currentMode = MODE_OFF;
unsigned long beepT0 = 0;
byte beepCount = 0;
// Alert FSM
byte alertState = 0;
// Reverse FSM
byte reverseState = 0;
// ---------------- Reset FSM ----------------
void resetBeeperFSM() {
digitalWrite(LATCH_OUT, LOW);
alertState = 0;
reverseState = 0;
beepT0 = 0;
beepCount = 0;
}
// ---------------- Beeper Engine ----------------
void serviceD3Beep(byte requestedMode) {
unsigned long now = millis();
if (requestedMode != currentMode) {
currentMode = requestedMode;
resetBeeperFSM();
}
// ---------------- OFF ----------------
if (currentMode == MODE_OFF) {
digitalWrite(LATCH_OUT, LOW);
}
// ---------------- ALERT MODE ----------------
else if (currentMode == MODE_ALERT) {
switch (alertState) {
case 0:
digitalWrite(LATCH_OUT, HIGH);
alertState = 1;
beepT0 = now;
beepCount = 0;
break;
case 1:
if (now - beepT0 >= ALERT_BEEP_HIGH_MS) {
digitalWrite(LATCH_OUT, LOW);
alertState = 2;
beepT0 = now;
}
break;
case 2:
if (now - beepT0 >= ALERT_BEEP_LOW_MS) {
beepCount++;
if (beepCount >= 3) {
digitalWrite(LATCH_OUT, LOW);
alertState = 3;
beepT0 = now;
beepCount = 0;
} else {
digitalWrite(LATCH_OUT, HIGH);
alertState = 1;
beepT0 = now;
}
}
break;
case 3:
if (now - beepT0 >= ALERT_BEEP_PAUSE_MS) {
digitalWrite(LATCH_OUT, HIGH);
alertState = 1;
beepT0 = now;
}
break;
}
}
// ---------------- REVERSE MODE ----------------
else if (currentMode == MODE_REVERSE) {
switch (reverseState) {
case 0:
digitalWrite(LATCH_OUT, HIGH);
reverseState = 1;
beepT0 = now;
break;
case 1:
if (now - beepT0 >= REV_BEEP_HIGH_MS) {
digitalWrite(LATCH_OUT, LOW);
reverseState = 2;
beepT0 = now;
}
break;
case 2:
if (now - beepT0 >= REV_BEEP_LOW_MS) {
digitalWrite(LATCH_OUT, HIGH);
reverseState = 1;
beepT0 = now;
}
break;
}
}
}
// ---------------- Setup ----------------
void setup() {
pinMode(IN1, INPUT); // external pull-up
pinMode(IN2, INPUT); // external pull-up
pinMode(IN3, INPUT_PULLUP); // internal pull-up
pinMode(HOLD1, INPUT); // external pull-up
pinMode(HOLD2, INPUT); // external pull-up
pinMode(REV_IN, INPUT_PULLUP); // D13 internal pull-up
pinMode(OUT1, OUTPUT);
pinMode(OUT2, OUTPUT);
pinMode(OUT3, OUTPUT);
pinMode(LATCH_OUT, OUTPUT);
latchState = false;
resetBeeperFSM();
// initialize debounce
stableRead(IN1);
stableRead(IN2);
stableRead(IN3);
stableRead(HOLD1);
stableRead(HOLD2);
stableRead(REV_IN);
}
// ---------------- Main Loop ----------------
void loop() {
// -------- Mirror outputs (all original functions remain the same) --------
digitalWrite(OUT1, stableRead(IN1));
digitalWrite(OUT2, stableRead(IN2));
digitalWrite(OUT3, !stableRead(IN3));
// -------- Priority selection for D3 mode --------
bool reverseActive = (stableRead(REV_IN) == LOW);
byte requestedMode;
if (reverseActive) {
// HIGHEST PRIORITY: reverse alarm overrides everything
requestedMode = MODE_REVERSE;
} else if (latchState) {
// normal latched alert only if reverse input is not active
requestedMode = MODE_ALERT;
} else {
requestedMode = MODE_OFF;
}
// -------- Service D3 beeper --------
serviceD3Beep(requestedMode);
// -------- Hold detection (unchanged behavior) --------
bool holdOK = (stableRead(HOLD1) == LOW) &&
(stableRead(HOLD2) == LOW);
bool d8Low = (stableRead(IN2) == LOW);
if (mustReleaseHold) {
if (!holdOK || !d8Low) {
mustReleaseHold = false;
} else {
return;
}
}
if (holdOK && d8Low) {
if (longHoldStartMs == 0) {
longHoldStartMs = millis();
} else {
unsigned long requiredMs =
latchState ? LONG_HOLD_OFF_MS : LONG_HOLD_ON_MS;
if (millis() - longHoldStartMs >= requiredMs) {
latchState = !latchState;
mustReleaseHold = true;
longHoldStartMs = 0;
}
}
} else {
longHoldStartMs = 0;
}
}