/*
1) პირველი რეჟიმია "ნორმალური" რეჟიმი. კონტროლერის ჩართვისას, ვთქვათ, ჩართულია პირველი ანტენა
(შესბამისი ნომრის ლედ ნათურა ანთია). არცერთი TX ნათურა არ ანთია.
ამ რეჟიმში მიმღები და გამდამცემი ანტენა ერთი და იგივეა.
კლავიატურაზე 1-დან-8 მდე აკრეფვით, ჩართავთ შესაბამის ანტენას, რომელიც მიმღებიც (RX) და
გადამცემიც (TX) ერთდოულად იქნება.
2) მეორე (RX Scan Mode) რეჟიმია, სადაც ხდება მიმღები (RX) ანტენის არჩევა.
ამრეჟიმის გააქტიურებას ვახდენთ * ღილაკით კლავიატურიდან. ამავდროულად ინთება TX ანტენის ლედ ნათურაც.
TX ანტენა იქნება ის, რომელიც იყო ბოლო მოქმედების დროს "ნორმალურ" რეჟიმი.
ამ დროს სადაც არ უნდა გადართოთ მიმღები ანტენა კლავიატურიდან,
გადამცემი ანტენა, ptt-ს დაჭერით, ირთვება მხოლოდ არჩეული გადამცემი TX ანტენა.
3) მესამე (TX Scan Mode) რეჟიმია სადაც ხდება გადამცემი (TX) ანტენის არჩევა. ამ რჟიმში შესვლა
შესაძლებელია # ზე დაკლიკებით. რჟიმიდან გამოსვლა ხდება #-ზე ხელახალი დაკლიკებით.
(2)-დან (3) რეჟიმში, ან (3)-დან (2)-ში გადასვლა ხდება ეგრევე * ან # ის დაკლიკებით.
4) არსებობს ასევე, Swap რეჟიმი, როცა არჩეული TX და RX ანტენებს შევიძლიათ შეუცვალოთ როლები
და გადამცემი ანტენა გახდეს მიმღები, ხოლო მიმღები - გადამცემი, 09-ს ღილაკიების კომბინაციით.
Swap რეჟიმი ჩართვადია მხოლოდ RX Scan Mode ან TX Scan Mode რეჟიმში, ანუ როცა TX და RX ანტენები სხვადასხვაა.
Swap რეჟიმში შეუძლებელია ანტენის არჩევა ან შეცვლა, მხოლოდ არჩეული ორი ანტენა ცვლის როლებს.
Swap ის გამორთვა ხდება ისევ 09 კომბინაციით, ან (RX Scan Mode) რეჟიმის (*-ით) ან (TX Scan Mode) რეჟიმის (#-ით) გაუქმებით).
ანუ, SWAP რეჟიმიდან 3 გზაა: ა) 09, ბ) *, გ) # კომბინაციებით.
ა) SWAP-დან 09-ით გამოსვლა დაგაბრუნებს იმ რეჟიმში რომელიდანაც გადახვედი SWAP-ში.
ბ) SWAP-დან *-ით გამოსვლა გადაგიყვანს ეგრევე RX Scan Mode -ში.
გ) SWAP-დან #-ით გამოსვლა გადაგიყვანს ეგრევე TX Scan Mode -ში.
დ) გადასვლა (RX Scan Mode) -> (TX Scan Mode): TX-RX ანტენა ხდება, რაც იყო RX (იმიტომ, რომ RX სკანირებას ახდენდი)
ე) გადასვლა (TX Scan Mode) -> (RX Scan Mode): TX-RX ანტენა ხდება, რაც იყო TX (იმიტომ, რომ TX სკანირებას ახდენდი)
ავტორები: 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 = 13; // Status LED for RX or TX Scan Mode
const int swapLedPin = 12; // Status LED for RX<->TX swap mode
int activeRelay = 0; // Currently selected antenna (0-7)
int txRelay = 0; // TX antenna in RX/TX Scan Mode
int rxRelay = 0; // RX antenna in RX/TX Scan Mode
bool rxScanMode = false; // Flag for RX Scan Mode
bool txScanMode = false; // Flag for TX 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", // Antenna1
"FanDip", // Antenna2
"Inv160", // Antenna3
"Inv-80", // Antenna4
"5-Ant", // Antenna5
"6-Ant", // Antenna6
"7-Ant", // Antenna7
"8-Ant" // Antenna8
};
// 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 lastTxScanMode = false;
bool lastSwapMode = false;
bool zeroPressed = 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 swap 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
txScanMode = 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 || txScanMode) ? rxRelay : activeRelay;
int currentTx = (rxScanMode || txScanMode) ? txRelay : activeRelay;
if (currentRx != lastRxRelay || currentTx != lastTxRelay ||
currentPtt != lastPttState || rxScanMode != lastRxScanMode ||
txScanMode != lastTxScanMode || swapMode != lastSwapMode) {
updateLCD();
// Update last known states
lastRxRelay = currentRx;
lastTxRelay = currentTx;
lastPttState = currentPtt;
lastRxScanMode = rxScanMode;
lastTxScanMode = txScanMode;
lastSwapMode = swapMode;
}
}
void checkKeypadInput() {
char key = keypad.getKey();
if (key) {
if (key == '0') {
zeroPressed = true; // Set flag, wait for next key
return;
}
if (zeroPressed) {
if (key == '9') {
toggleSwapMode(); // Enter or exit swapMode
}
zeroPressed = false; // Reset flag regardless
return;
}
if (key == '*') {
toggleRxScanMode();
} else if (key == '#') {
toggleTxScanMode();
} else if (rxScanMode || txScanMode) {
// In RX or TX Scan Mode
if (swapMode) {
// In SwapMode, allow swapping with 9
if (key == '9') {
// Only swap antennas, do not toggle mode
int temp = rxRelay;
rxRelay = txRelay;
txRelay = temp;
updateLatch2(); // Update hardware
}
// Ignore other keys
} else {
// Normal Scan Mode operation
switch(key) {
case '1': setScanAntenna(0); break;
case '2': setScanAntenna(1); break;
case '3': setScanAntenna(2); break;
case '4': setScanAntenna(3); break;
case '5': setScanAntenna(4); break;
case '6': setScanAntenna(5); break;
case '7': setScanAntenna(6); break;
case '8': setScanAntenna(7); 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() {
bool cameFromTxScan = false;
if (txScanMode) {
rxRelay = txRelay;
txScanMode = false;
cameFromTxScan = true;
}
rxScanMode = !rxScanMode;
digitalWrite(statusLedPin, rxScanMode ? HIGH : LOW);
if (rxScanMode) {
if (!cameFromTxScan) {
txRelay = activeRelay;
rxRelay = activeRelay;
}
swapMode = false;
digitalWrite(swapLedPin, LOW);
updateLatch2();
} else {
activeRelay = rxRelay;
swapMode = false;
digitalWrite(swapLedPin, LOW);
digitalWrite(latchPin2, LOW);
shiftOut(dataPin2, clockPin2, LSBFIRST, 0);
digitalWrite(latchPin2, HIGH);
}
}
void toggleTxScanMode() {
bool cameFromRxScan = false;
if (rxScanMode) {
txRelay = rxRelay;
rxScanMode = false;
cameFromRxScan = true;
}
txScanMode = !txScanMode;
digitalWrite(statusLedPin, txScanMode ? HIGH : LOW);
if (txScanMode) {
if (!cameFromRxScan) {
rxRelay = activeRelay;
txRelay = activeRelay;
}
swapMode = false;
digitalWrite(swapLedPin, LOW);
updateLatch2();
} else {
activeRelay = txRelay;
swapMode = false;
digitalWrite(swapLedPin, LOW);
digitalWrite(latchPin2, LOW);
shiftOut(dataPin2, clockPin2, LSBFIRST, 0);
digitalWrite(latchPin2, HIGH);
}
}
void toggleSwapMode() {
if (rxScanMode || txScanMode) { // Only works in RX or TX 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 setScanAntenna(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
}
if (rxScanMode) {
// In RX Scan Mode, set RX antenna
rxRelay = antennaNumber;
} else if (txScanMode) {
// In TX Scan Mode, set TX antenna
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 || txScanMode) {
bool pttActive = digitalRead(pttPin);
// Determine which antenna to activate on Latch1
int activeAntenna;
if (rxScanMode) {
activeAntenna = pttActive ? txRelay : rxRelay;
} else { // TX Scan Mode
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 || txScanMode) ? rxRelay : activeRelay]);
lcd.setCursor(10, 0);
if (digitalRead(pttPin)) {
if (rxScanMode) {
lcd.print("TX_Sc");
} else if (txScanMode) {
lcd.print("TXScM");
} else {
lcd.print("TX");
}
} else {
if (rxScanMode) {
lcd.print("RXScM");
} else if (txScanMode) {
lcd.print("TXScM");
} else {
lcd.print("RX");
}
}
// Second line: TX antenna and swap status
lcd.setCursor(0, 1);
lcd.print("TX:");
lcd.print(antennaNames[(rxScanMode || txScanMode) ? txRelay : activeRelay]);
lcd.setCursor(10, 1);
if (swapMode) {
lcd.print("Swap");
} else {
lcd.print("NoSwaP");
}
}
PTT
TX
RX-TX
RX Scan Mode (*)
SWAP
1
1