/*
1) კონტროლერის ჩართვისას მეხსიერებიდან კითხულობს ბოლო გამორთვისას
არსებულ რეჟიმს. (დაემატება ეს, ჯერ არ ზის)
2) კონტროლერის ჩართვისას, ვთქვათ, ჩართულია პირველი ანტენა
(ინთება მარჯვენა ბოლო ნათურა). არცერთი TX ნათურა არ ანთია.
ამ რეჟიმში მიმღები და გამდამცემი ანტენა ერთი და იგივეა.
კლავიატურაზე 1 დან 8 მდე აკრეფვით, ჩართავთ შესაბამის ანტენას, რომელიც მიმღებიც და
გადამცემიც ერთდოულად იქნება.
3) მეორე (RX Scan Mode) რეჟიმია სადაც ხდება მიმღები (RX) ანტენის არჩევა.
ამრეჟიმის გააქტიურებას ვახდენთ * ღილაკით კლავიატურიდან, ან
Rx Scan Mode ღილაკით პანელიდან. ამ დროს ინთება ყვითელი (შუა) ნათურაც.
ამ დროს სადაც არ უნდა გადართოთ მიმღები ანტენა კლავიატურიდან,
გადამცემი ანტენა, ptt-ს დაჭერით, ირთვება მხოლოდ არჩეული გადამცემი TX ანტენა.
4) სხვა TX ანტენის ასარჩევად, როცა უკვე არჩეულია ანტენა, შესაძლებელია მხოლოდ (RX Scan Mode) რეჟიმის
დატოვების მერე. ამ რეჟიმიდან გამოსვლა ხდება *-ზე (Rx Scan Mode ღილაკი) ხელახალი დაკლიკებით.
5) არსებობს ასევე, Swap რეჟიმში, როცა არჩეული TX და RX ანტენებს შევიძლიათ შეუცვალოთ როლები
და გადამცემი ანტენა გახდეს მიმღები, ხოლო მიმღები - გადამცემი, 9-ს (Swap) ღილაკის დაკლიკებით.
Swap რეჟიმი ჩართვადია მხოლოდ RX Scan Mode რეჟიმში, ანუ როცა TX და RX ანტენები სხვადასხვაა.
Swap რეჟიმში შეუძლებელია ანტენის არჩევა ან შეცვლა, მხოლოდ არჩეული ორი ანტენა ცვლის როლებს.
Swap ის გამორთვა ხდება ისევ 9-ს (Swap) ღილაკის დაკლიკებით ან (RX Scan Mode) რეჟიმის გაუქმებით.
ავტორები: 4L7ZS, 4L4CR და 4L0VE.
*/
#include <Keypad.h>
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27, 16, 2); // I2C address 0x27, 16 columns, 2 rows
// Shift register pins for 74HC595
const int latchPin1 = 6; // CTCP Latch for first 74HC595
const int clockPin1 = 7; // SHCP
const int dataPin1 = 8; // DS
const int latchPin2 = 9; // CTCP Latch for second 74HC595
const int clockPin2 = 10; // SHCP
const int dataPin2 = 11; // DS
const int statusLedPin = 12; // Status LED for RX Scnan Mode
const int swapLedPin = 13; // Status LED for RX-TX swap mode
int activeRelay = 0; // Currently selected antenna (0-7)
int txRelay = 0; // TX antenna in RX Scan Mode
int rxRelay = 0; // RX antenna in RX Scan Mode
bool rxScanMode = false; // Flag for RX Scan Mode
bool swapMode = false; // Flag for Swap Mode
const int pttPin = 2; // Pin for PTT control (HIGH activates TX antenna)
// Antenna names (max 7 characters each)
const String antennaNames[] = {
"Inv-L", // Antenna 1
"FanDip", // Antenna 2
"Inv160", // Antenna 3
"Inv-80", // Antenna 4
"5-Ant", // Antenna 5
"6-Ant", // Antenna 6
"7-Ant", // Antenna 7
"8-Ant" // Antenna 8
};
// 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);
//////
int lastRxRelay = -1;
int lastTxRelay = -1;
int lastActiveRelay = -1;
bool lastPttState = false;
bool lastRxScanMode = false;
bool lastSwapMode = false;
//////
void setup() {
// Initialize LCD
lcd.init();
lcd.backlight();
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("HELLO FROM 4L7ZS");
lcd.setCursor(0, 1);
lcd.print("4L4CR AND 4L0VE");
delay(2000);
// 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
pinMode(swapLedPin, OUTPUT); // Set status LED pin as output
// Initialize all states
activeRelay = 0; // Default to antenna 1
txRelay = 0; // TX starts same as active
rxRelay = 0; // RX starts same as active
rxScanMode = false; // Start in normal mode
swapMode = false; // Swap mode off
// Initialize both latches
digitalWrite(latchPin1, LOW);
shiftOut(dataPin1, clockPin1, LSBFIRST, 1 << 7); // Antenna 1 on Latch1
digitalWrite(latchPin1, HIGH);
digitalWrite(latchPin2, LOW);
shiftOut(dataPin2, clockPin2, LSBFIRST, 0); // Clear Latch2 initially
digitalWrite(latchPin2, HIGH);
// Update LEDs
digitalWrite(statusLedPin, LOW);
digitalWrite(swapLedPin, LOW);
updateLCD(); // Update display
}
void loop() {
checkKeypadInput();
checkPTT();
updateAntennas();
// Check if anything relevant has changed
bool currentPtt = digitalRead(pttPin);
int currentRx = rxScanMode ? rxRelay : activeRelay;
int currentTx = rxScanMode ? txRelay : activeRelay;
if (currentRx != lastRxRelay || currentTx != lastTxRelay ||
currentPtt != lastPttState || rxScanMode != lastRxScanMode ||
swapMode != lastSwapMode) {
updateLCD();
// Update last known states
lastRxRelay = currentRx;
lastTxRelay = currentTx;
lastPttState = currentPtt;
lastRxScanMode = rxScanMode;
lastSwapMode = swapMode;
}
}
void checkKeypadInput() {
char key = keypad.getKey();
if (key) {
if (key == '*') {
toggleRxScanMode();
} else if (rxScanMode) {
// In RX Scan Mode
if (swapMode) {
// If in swap mode, only allow swap toggle (key '9')
if (key == '9') {
toggleSwapMode();
}
// Ignore all other keys
} else {
// Normal RX Scan Mode operation
switch(key) {
case '1': setRxAntenna(0); break;
case '2': setRxAntenna(1); break;
case '3': setRxAntenna(2); break;
case '4': setRxAntenna(3); break;
case '5': setRxAntenna(4); break;
case '6': setRxAntenna(5); break;
case '7': setRxAntenna(6); break;
case '8': setRxAntenna(7); break;
case '9': toggleSwapMode(); break;
}
}
} else {
// In normal mode, keys 1-8 select antenna
switch(key) {
case '1': setActiveAntenna(0); break;
case '2': setActiveAntenna(1); break;
case '3': setActiveAntenna(2); break;
case '4': setActiveAntenna(3); break;
case '5': setActiveAntenna(4); break;
case '6': setActiveAntenna(5); break;
case '7': setActiveAntenna(6); break;
case '8': setActiveAntenna(7); break;
}
}
}
}
void toggleRxScanMode() {
rxScanMode = !rxScanMode;
digitalWrite(statusLedPin, rxScanMode ? HIGH : LOW);
if (rxScanMode) {
// Entering RX Scan Mode
txRelay = activeRelay;
rxRelay = activeRelay;
swapMode = false; // Ensure swap mode is off when entering
digitalWrite(swapLedPin, LOW); // Force swap LED off
updateLatch2();
} else {
// Exiting RX Scan Mode
swapMode = false; // Important: Disable swap mode when leaving
digitalWrite(swapLedPin, LOW); // Ensure LED is off
digitalWrite(latchPin2, LOW);
shiftOut(dataPin2, clockPin2, LSBFIRST, 0);
digitalWrite(latchPin2, HIGH);
}
}
void toggleSwapMode() {
if (rxScanMode) { // Only works in RX Scan Mode
swapMode = !swapMode;
if (swapMode) {
// Swap RX and TX antennas
int temp = rxRelay;
rxRelay = txRelay;
txRelay = temp;
} else {
// Restore original configuration
int temp = rxRelay;
rxRelay = txRelay;
txRelay = temp;
}
digitalWrite(swapLedPin, swapMode ? HIGH : LOW);
updateLatch2();
}
}
void setRxAntenna(int antennaNumber) {
if (antennaNumber < 0 || antennaNumber > 7) return;
// Don't allow antenna changes when in swap mode
if (swapMode) {
return; // Exit without making any changes
}
rxRelay = antennaNumber;
// Only update TX if swap mode is active (though we just prevented this case)
if (swapMode) {
txRelay = antennaNumber;
updateLatch2();
}
}
void setActiveAntenna(int antennaNumber) {
if (antennaNumber < 0 || antennaNumber > 7) return;
activeRelay = antennaNumber;
}
void checkPTT() {
static bool lastPttState = LOW;
bool currentPttState = digitalRead(pttPin);
if (currentPttState != lastPttState) {
lastPttState = currentPttState;
updateAntennas();
}
}
void updateAntennas() {
if (rxScanMode) {
bool pttActive = digitalRead(pttPin);
// Determine which antenna to activate on Latch1
int activeAntenna = pttActive ? txRelay : rxRelay;
byte latch1Pattern = 1 << (7 - activeAntenna);
digitalWrite(latchPin1, LOW);
shiftOut(dataPin1, clockPin1, LSBFIRST, latch1Pattern);
digitalWrite(latchPin1, HIGH);
updateLatch2();
} else {
// Normal mode
byte pattern = 1 << (7 - activeRelay);
digitalWrite(latchPin1, LOW);
shiftOut(dataPin1, clockPin1, LSBFIRST, pattern);
digitalWrite(latchPin1, HIGH);
}
}
void updateLatch2() {
// Latch2 shows TX antenna
byte latch2Pattern = 1 << (7 - txRelay);
digitalWrite(latchPin2, LOW);
shiftOut(dataPin2, clockPin2, LSBFIRST, latch2Pattern);
digitalWrite(latchPin2, HIGH);
}
void updateLCD() {
lcd.clear();
// First line: RX and TX status
lcd.setCursor(0, 0);
lcd.print("RX:");
lcd.print(antennaNames[rxScanMode ? rxRelay : activeRelay]);
lcd.setCursor(10, 0);
if (digitalRead(pttPin)) {
lcd.print(rxScanMode ? "TX_Sc" : "TX");
} else {
lcd.print(rxScanMode ? "RX_Sc" : "RX");
}
// Second line: TX antenna and swap status
lcd.setCursor(0, 1);
lcd.print("TX:");
lcd.print(antennaNames[rxScanMode ? txRelay : activeRelay]);
lcd.setCursor(10, 1);
lcd.print(swapMode ? "Swap" : "NoSwaP");
}
PTT
TX
RX-TX
RX Scan Mode (*)
SWAP
Antenna-1
Antenna-2
Antenna-3
Antenna-4
Antenna-5
Antenna-6
Antenna-7
Antenna-8
1
1