/*
1) კონტროლერის ჩართვისას მეხსიერებიდან კითხულობს ბოლო გამორთვისას არსებულ რეჟიმს.
2) კონტროლერის ჩართვისას, ვთქვათ, ჩართულია
პირველი ანტენა (ინთება მარჯვენა ბოლო ნათურა). არცერთი TX ნათურა არ ანთია.
ამ რეჟიმში მიმღები და გამდამცემი ანტენა ერთი და იგივეა.
კლავიატურაზე 1 დან 8 მდე აკრეფვით, ჩართავთ შესაბამის ანტენას, რომელიც მიმღებიც და
გადამცემიც ერთდოულად იქნება.
3) მეორე (სპლიტ) რეჟიმია მიმღები (RX) და გადამცემი (TX) ანტენების არჩევა.
გადამცემ ანტენას ვირჩევთ * - N - # კომბინაციით, სადაც N არის გადამცემი
ანტენის ნომერი. ამ დროს სადაც არ უნდა გადართოთ მიმღები ანტენა კლავიატურიდან,
გადამცემი ანტენა, ptt-ს დაჭერით, ირთვება მხოლოდ არჩეული გადამცემი ანტენა.
4) ვთქვათ არჩეულია TX ანტენა, და გვინდა ცოტახნით RX და TX ანტენა იყოს ერთი დაიგივე.
ანუ TX ანტენა იყოს RX არჩეული ანტენა. ვაკლიკებთ #-ს და ეს ე.წ. "სპლიტ" რეჟიმი პაუზდება.
ხელმეორედ #-ს დაჭერით აქტიურდება ისევ სპლიტ რეჟიმი.
5) სხვა TX ანტენის ასარჩევად, როცა უკვე არჩეულია ანტენა, შესაძლებელია ისევ
* - N - # კომბინაცია ახალი TX ანტენის ასარჩევად.
6) *-0-# კომბინაცია აუქმებს TX ანტენას, ანუ აუქმებს სპლიტ რეჟიმს.
7) არსებობს ასევე, Swap რეჟიმში, როცა არჩეული TX და RX ანტენებს შევიძლიათ შეუცვალოთ როლები
და გადამცემი ანტენა გახდეს მიმღები, ხოლო მიმღები - გადამცემი, 9-ს დაკლიკებით.
ამ დროს ინთება ყვითელი (შუა) ნათურაც (Reverse).
ავტორები: 4L7ZS, 4L4CR და 4L0VE.
*/
#include <Keypad.h>
#include <EEPROM.h>
//EEPROM
const int EEPROM_ACTIVE_RELAY_ADDR = 0; // EEPROM address to store activeRelay
const int EEPROM_PTT_RELAY_ADDR = 1; // EEPROM address to store pttRelay
const int EEPROM_SWAP_MODE_ADDR = 2; // EEPROM address to store swap mode status
// Shift register pins for 74HC595
const int latchPin1 = 6; // CTCP Latch for first 74HC595 (keypad-selected antenna)
const int clockPin1 = 7; // SHCP
const int dataPin1 = 8; // DS
const int latchPin2 = 9; // CTCP Latch for second 74HC595 (PTT-selected antenna)
const int clockPin2 = 10; // SHCP
const int dataPin2 = 11; // DS
const int statusLedPin = 12; // Status LED for RX-TX swap mode
int activeRelay = -1; // Relay currently selected by keypad
int pttRelay = -1; // Relay activated when PTT is HIGH
const int pttPin = 2; // Pin for PTT control (HIGH activates pttRelay)
bool pttSelectMode = false; // Flag for PTT selection mode
bool rxTxModePaused = false; // Flag to toggle RX-TX mode pause
bool swapModeActive = false; // Flag to indicate if swap mode is active
// Keypad configuration
const byte ROWS = 4; // Four rows
const byte COLS = 3; // Three columns
char keys[ROWS][COLS] = {
{'1', '2', '3'},
{'4', '5', '6'},
{'7', '8', '9'},
{'*', '0', '#'}
};
byte rowPins[ROWS] = {A0, A1, A2, A3}; // Connect to the row pinouts of the keypad
byte colPins[COLS] = {3, 4, 5}; // Connect to the column pinouts of the keypad
Keypad keypad = Keypad(makeKeymap(keys), rowPins, colPins, ROWS, COLS);
/////////////////
String lastRXDisplay = "";
String lastTXDisplay = "";
String lastModeDisplay = "";
String lastSwapDisplay = "";
/////////////////
void activateRelay(int relayIndex, bool isPTT = false);
void activatePTTIndicator();
void updateShiftRegister1(byte data);
void updateShiftRegister2(byte data);
void turnOffAllRelays();
void waitForPttSelection();
void swapRxTxAntennas();
void updateStatusLed();
void setup() {
// Set shift register pins as outputs
pinMode(latchPin1, OUTPUT);
pinMode(clockPin1, OUTPUT);
pinMode(dataPin1, OUTPUT);
pinMode(latchPin2, OUTPUT);
pinMode(clockPin2, OUTPUT);
pinMode(dataPin2, OUTPUT);
pinMode(pttPin, INPUT); // Set PTT pin as input
pinMode(statusLedPin, OUTPUT); // Set status LED pin as output
// Load settings from EEPROM
activeRelay = EEPROM.read(EEPROM_ACTIVE_RELAY_ADDR);
if (activeRelay > 7 || activeRelay < -1) { // Validate EEPROM value
activeRelay = 0; // Default to antenna 1 if invalid
EEPROM.write(EEPROM_ACTIVE_RELAY_ADDR, activeRelay);
}
pttRelay = EEPROM.read(EEPROM_PTT_RELAY_ADDR);
if (pttRelay > 7 || pttRelay < -1) { // Validate EEPROM value
pttRelay = -1; // Default to no PTT antenna if invalid
EEPROM.write(EEPROM_PTT_RELAY_ADDR, pttRelay);
}
// Load swap mode with proper validation
byte storedSwap = EEPROM.read(EEPROM_SWAP_MODE_ADDR);
if (storedSwap <= 1) { // Valid value (0 or 1)
swapModeActive = (storedSwap == 1);
} else { // Invalid (including fresh EEPROM 0xFF)
swapModeActive = false;
EEPROM.write(EEPROM_SWAP_MODE_ADDR, 0); // Explicitly write 0
}
// Initialize relays based on loaded values
if (activeRelay != -1) {
activateRelay(activeRelay);
} else {
turnOffAllRelays();
}
updateStatusLed(); // Ensure LED reflects initial state
}
void loop() {
// Check if PTT pin is HIGH or LOW
if (digitalRead(pttPin) == HIGH && pttRelay != -1 && !rxTxModePaused) {
// PTT mode is on and RX-TX mode is active, activate the PTT antenna
activateRelay(pttRelay, true); // Set PTT LED
} else if (digitalRead(pttPin) == LOW || rxTxModePaused) {
// PTT mode is off or RX-TX mode is paused, return to last keypad-selected antenna
if (activeRelay != -1) {
activateRelay(activeRelay);
} else {
turnOffAllRelays();
}
}
// Check keypad input
char key = keypad.getKey();
if (key) {
if (pttSelectMode) {
waitForPttSelection(); // Enter PTT selection mode
} else {
// Normal antenna selection mode
if (key >= '1' && key <= '8') {
int relayIndex = key - '1'; // Convert '1' to 0, ..., '8' to 7
activeRelay = relayIndex; // Update activeRelay to store the last selection
if (EEPROM.read(EEPROM_ACTIVE_RELAY_ADDR) != activeRelay) {
EEPROM.write(EEPROM_ACTIVE_RELAY_ADDR, activeRelay); // Save to EEPROM only if different
}
activateRelay(activeRelay);
swapModeActive = false; // Reset swap mode if antenna selection changes
updateStatusLed(); // Reflect status
} else if (key == '0') {
activeRelay = -1; // Reset active relay variable
if (EEPROM.read(EEPROM_ACTIVE_RELAY_ADDR) != activeRelay) {
EEPROM.write(EEPROM_ACTIVE_RELAY_ADDR, activeRelay); // Save only if changed
}
turnOffAllRelays(); // Turn off all relays
swapModeActive = false; // Reset swap mode if no antennas are active
updateStatusLed(); // Reflect status
} else if (key == '*') {
// Enter PTT antenna selection mode
pttSelectMode = true;
waitForPttSelection(); // Start waiting for PTT antenna selection
} else if (key == '#') {
// Toggle RX-TX mode pause
rxTxModePaused = !rxTxModePaused;
} else if (key == '9' && pttRelay != -1) {
// If PTT is selected, swap RX and TX antennas
swapRxTxAntennas();
}
}
}
}
void waitForPttSelection() {
int tempPttRelay = -1; // Temporary variable to hold the selected antenna number
while (true) {
char pttKey = keypad.getKey();
if (pttKey) {
if (pttKey >= '1' && pttKey <= '8') {
// Set the temporary relay selection
tempPttRelay = pttKey - '1';
} else if (pttKey == '0') {
// Option to clear the PTT antenna
tempPttRelay = -1; // Indicate clearing the PTT relay
} else if (pttKey == '#') {
// Confirm the PTT relay selection or clearing
pttRelay = tempPttRelay;
if (EEPROM.read(EEPROM_PTT_RELAY_ADDR) != pttRelay) {
EEPROM.write(EEPROM_PTT_RELAY_ADDR, pttRelay); // Save only if changed
}
pttSelectMode = false; // Exit PTT selection mode
activatePTTIndicator(); // Update LED on second 74HC595
break;
}
}
}
}
void swapRxTxAntennas() {
if (pttRelay != -1) {
// Swap the RX and TX antennas when PTT is selected
int tempRelay = activeRelay;
activeRelay = pttRelay; // TX becomes the previously selected RX antenna
pttRelay = tempRelay; // RX becomes the previously selected TX antenna
// Save the new values to EEPROM if they changed
if (EEPROM.read(EEPROM_ACTIVE_RELAY_ADDR) != activeRelay) {
EEPROM.write(EEPROM_ACTIVE_RELAY_ADDR, activeRelay);
}
if (EEPROM.read(EEPROM_PTT_RELAY_ADDR) != pttRelay) {
EEPROM.write(EEPROM_PTT_RELAY_ADDR, pttRelay);
}
swapModeActive = !swapModeActive; // Toggle the swap mode flag
EEPROM.write(EEPROM_SWAP_MODE_ADDR, swapModeActive ? 1 : 0); // Save swap mode status
updateStatusLed(); // Update LED indicator
// Re-activate both RX and TX antennas with updated roles
activateRelay(activeRelay); // RX
activateRelay(pttRelay, true); // TX
}
}
void activateRelay(int relayIndex, bool isPTT = false) {
// First shift register for normal antenna selection
byte relayState = 1 << relayIndex;
updateShiftRegister1(relayState);
if (!isPTT) {
activatePTTIndicator(); // Update PTT LED state separately if not in PTT mode
}
}
void activatePTTIndicator() {
byte pttState = (pttRelay != -1 && !rxTxModePaused) ? (1 << pttRelay) : 0;
updateShiftRegister2(pttState); // Only update PTT LEDs
}
void turnOffAllRelays() {
updateShiftRegister1(0); // Turn off all relays on first shift register
updateShiftRegister2(0); // Turn off all LEDs on second shift register
swapModeActive = false; // Ensure swap mode resets if all relays are off
updateStatusLed(); // Reflect status
}
void updateShiftRegister1(byte data) {
digitalWrite(latchPin1, LOW); // Begin latch
shiftOut(dataPin1, clockPin1, MSBFIRST, data); // Shift out the bits
digitalWrite(latchPin1, HIGH); // End latch to output data
}
void updateShiftRegister2(byte data) {
digitalWrite(latchPin2, LOW); // Begin latch
shiftOut(dataPin2, clockPin2, MSBFIRST, data); // Shift out the bits
digitalWrite(latchPin2, HIGH); // End latch to output data
}
void updateStatusLed() {
digitalWrite(statusLedPin, swapModeActive ? HIGH : LOW);
}
PTT
TX
RX-TX
<-REVERSE->