Инструменты пользователя

Инструменты сайта


banddecoder_code

Различия

Показаны различия между двумя версиями страницы.

Ссылка на это сравнение

Предыдущая версия справа и слеваПредыдущая версия
Следующая версия
Предыдущая версия
banddecoder_code [2026/01/11 11:14] eu8tbanddecoder_code [2026/01/23 08:04] (текущий) eu8t
Строка 1: Строка 1:
-IP 192.168.0.240+IP 192.168.0.240 (можно сменить через настройки)
  
-v0.44+v0.81 (примерно) 
 + 
 +{{:clip2net_menu_260117214628.jpeg?800|}} 
 + 
 +{{:clip2net_menu_260117214613.jpeg?800|}}
  
-{{:clip2net_menu_260110231520.jpeg|}} 
  
-CODE 
  
 <code> <code>
Строка 13: Строка 15:
 #include <Wire.h> #include <Wire.h>
 #include <LiquidCrystal_I2C.h> #include <LiquidCrystal_I2C.h>
 +#include <EEPROM.h>
  
-/================= НАСТРОЙКИ ================= */+/===================================================== 
 +// === CONFIG: все константы устройства в одном месте === 
 +// =====================================================
  
-const float VERSION = 0.44+// --- EEPROM --- 
-LiquidCrystal_I2C lcd(0x27, 16, 2);+const byte EEPROM_MAGIC      = 0x42; 
 +const int  EEPROM_ADDR_MAGIC = 0; 
 +const int  EEPROM_ADDR_IP    = 1  // 1..4
  
-byte mac[] { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; +// --- Версия прошивки --- 
-IPAddress ip(192, 168, 0, 240); +const float VERSION = 0.81;
-unsigned int localPort = 12060;+
  
-EthernetUDP Udp;+// --- CAT / сеть --- 
 +const unsigned long CAT_TIMEOUT = 7000; 
 +const unsigned long NET_TIMEOUT = 5000;
  
-const unsigned long CAT_TIMEOUT = 7000;   // переключение в MANUAL +// --- Пины энкодера --- 
-const unsigned long NET_TIMEOUT 5000;   // только надпись WAIT CAT DATA+const int ENC_A   8; 
 +const int ENC_B   = A1; 
 +const int ENC_BTN = 3;
  
-const int ENC_A   = 10; +// --- Пины реле --- 
-const int ENC_B   3+const int RELAYS[] {4, 5, 6, 7}
-const int ENC_BTN 2;+const int RELAY_COUNT 4;
  
-const int RELAYS[] {4, 5, 6, 7, 8, 9}+// --- Кнопка --- 
-const int RELAY_COUNT sizeof(RELAYS) / sizeof(int);+const unsigned long SHORT_PRESS 100
 +const unsigned long LONG_PRESS  3000; 
 +const unsigned long HOLD_TIME   = 700;
  
-/================= СОСТОЯНИЯ ================= */+// --- Редактор IP --- 
 +const unsigned long EDITOR_CLICK_GUARD 200;
  
-enum Mode { AUTO, MANUAL }; +// --- Анимация CAT --- 
-Mode mode AUTO;+const int CAT_ANIM_STEPS 5;
  
-bool manualForced = false; 
-bool autoFallback = false; 
  
 +// =====================================================
 +// === ГЛОБАЛЬНЫЕ ПЕРЕМЕННЫЕ (состояние устройства) ===
 +// =====================================================
 +
 +// --- IP редактор ---
 +bool ipEditMode = false;
 +byte ipEdit[4];
 +int ipOctetIndex = 0;
 +
 +// --- LCD ---
 +LiquidCrystal_I2C lcd(0x27, 16, 2);
 +
 +// --- Ethernet ---
 +byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
 +IPAddress ip(192, 168, 0, 240);
 +unsigned int localPort = 12060;
 +IPAddress effectiveIP = ip;
 +EthernetUDP Udp;
 +
 +// --- CAT состояние ---
 unsigned long lastCatTime = 0; unsigned long lastCatTime = 0;
 bool catActive = false; bool catActive = false;
- 
 unsigned long lastPacketTime = 0; unsigned long lastPacketTime = 0;
- 
 long lastFreq = 0; long lastFreq = 0;
-int currentBand -1+bool freqReceived = false; 
-int manualBandIndex = 0;+byte catAnimPos 0
 +int catPacketCounter = 0;
  
-/* ================= ДИАПАЗОНЫ ================= */+byte catDot[8] 
 +  0b00000, 
 +  0b00100, 
 +  0b01110, 
 +  0b01110, 
 +  0b01110, 
 +  0b00100, 
 +  0b00000, 
 +  0b00000 
 +};
  
 +// --- Режимы ---
 +enum Mode { AUTO, MANUAL };
 +Mode mode = AUTO;
 +bool manualForced = false;
 +
 +// --- Диапазоны ---
 struct Band { struct Band {
   const char* name;   const char* name;
   long from;   long from;
   long to;   long to;
 +  byte abcdCode;
 }; };
  
 Band bands[] = { Band bands[] = {
-  {"160M", 1800000, 2000000}, +  {"160M", 1800000, 2000000, 0b00000001}, 
-  {"80M",  3500000, 3800000}, +  {"80M",  3500000, 3800000, 0b00000010}, 
-  {"40M",  7000000, 7350000}, +  {"40M",  7000000, 7350000, 0b00000011}, 
-  {"20M", 14000000, 14350000}, +  {"20M", 14000000, 14350000, 0b00000101}, 
-  {"15M", 21000000, 21450000}, +  {"15M", 21000000, 21450000, 0b00000111}, 
-  {"10M", 28000000, 29700000}+  {"10M", 28000000, 29700000, 0b00001001}
 }; };
  
 const int BAND_COUNT = sizeof(bands) / sizeof(Band); const int BAND_COUNT = sizeof(bands) / sizeof(Band);
  
-/================= СЛУЖЕБНЫЕ ================= */+// --- Текущее состояние диапазонов --- 
 +int currentBand -1; 
 +int manualBandIndex 0; 
 + 
 +// --- Энкодер --- 
 +int lastA HIGH; 
 + 
 +// --- Кнопка --- 
 +bool buttonHeld false; 
 +bool pressed false; 
 +unsigned long pressStart 0; 
 +bool ignoreNextEditorClick false; 
 + 
 +// --- LCD обновление --- 
 +Mode lastMode AUTO; 
 +int lastBandIndex -1; 
 +long lastDisplayedFreq 0; 
 +bool forceDisplayUpdate false;
  
 int detectBand(long freq) { int detectBand(long freq) {
Строка 81: Строка 144:
 } }
  
-void setRelays(int bandIndex) { +void setRelaysByABCD(byte abcdCode) { 
-  for (int i = 0; i < RELAY_COUNT; i++) +  for (int i = 0; i < RELAY_COUNT; i++) 
-    digitalWrite(RELAYS[i], (i == bandIndex) HIGH : LOW);+    bool state = (abcdCode >> i) & 1; 
 +    digitalWrite(RELAYS[i], state ? LOW : HIGH); 
 +  } 
 +}
  
-  if (bandIndex < 0+void setRelaysByBand(int bandIndex) { 
-    for (int i = 0; i RELAY_COUNT; i+++  if (bandIndex >= 0 && bandIndex BAND_COUNT
-      digitalWrite(RELAYS[i], LOW);+    setRelaysByABCD(bands[bandIndex].abcdCode); 
 +  else 
 +    setRelaysByABCD(0);
 } }
 +
 +void disableAllRelays() {
 +  setRelaysByABCD(0);
 +}
 +
 +void saveIPToEEPROM(IPAddress ipToSave) {
 +  EEPROM.update(EEPROM_ADDR_MAGIC, EEPROM_MAGIC);
 +  for (int i = 0; i < 4; i++)
 +    EEPROM.update(EEPROM_ADDR_IP + i, ipToSave[i]);
 +}
 +
 +bool loadIPFromEEPROM(IPAddress &out) {
 +  if (EEPROM.read(EEPROM_ADDR_MAGIC) != EEPROM_MAGIC) return false;
 +  byte b[4];
 +  for (int i = 0; i < 4; i++)
 +    b[i] = EEPROM.read(EEPROM_ADDR_IP + i);
 +  out = IPAddress(b[0], b[1], b[2], b[3]);
 +  return true;
 +}
 +
 +void enterIpEditMode() {
 +  ipEditMode = true;
 +
 +  for (int i = 0; i < 4; i++)
 +    ipEdit[i] = effectiveIP[i];
 +
 +  ipOctetIndex = 0;
 +  drawIpEditor();
 +  ignoreNextEditorClick = true;
 +}
 +
 +void drawIpEditor() {
 +  lcd.clear();
 +  lcd.setCursor(0,0);
 +  lcd.print("SET IP:");
 +
 +  lcd.setCursor(0,1);
 +
 +  for (int i = 0; i < 4; i++) {
 +
 +    // подчёркивание перед редактируемым октетом
 +    if (i == ipOctetIndex)
 +      lcd.print("_");
 +    else
 +      lcd.print("");   // ← НИЧЕГО НЕ ПЕЧАТАЕМ
 +
 +    // вывод октета с ведущими нулями
 +    int val = ipEdit[i];
 +    if (val < 100) lcd.print("0");
 +    if (val < 10)  lcd.print("0");
 +    lcd.print(val);
 +
 +    if (i < 3) lcd.print(".");
 +  }
 +}
 +
 +
  
 void printFreqCompact(long f) { void printFreqCompact(long f) {
Строка 106: Строка 231:
 } }
  
-/* ================= ЭКРАН ================= */ 
  
-Mode lastMode AUTO+void runRelayTest() { 
-int lastBandIndex = -1; +  lcd.clear(); 
-long lastDisplayedFreq 0;+  lcd.setCursor(0,0); 
 +  lcd.print("TEST RELAYS"); 
 + 
 +  for (int i 0i < BAND_COUNT; i++) { 
 + 
 +    // включаем реле 
 +    setRelaysByBand(i); 
 + 
 +    // выводим комбинацию ABCD 
 +    lcd.setCursor(0,1); 
 +    for (int 3; b >= 0; b--) 
 +      lcd.print((bands[i].abcdCode >> b) & 1)
 + 
 +    delay(600); 
 +  } 
 + 
 +  disableAllRelays(); 
 +  delay(300); 
 + 
 +  forceDisplayUpdate true; 
 +  updateLCDIfNeeded(); 
 +}
  
 void updateLCDIfNeeded() { void updateLCDIfNeeded() {
 +  if (ipEditMode) return;
   bool changed = false;   bool changed = false;
  
Строка 119: Строка 265:
   if (mode == AUTO && lastBandIndex != currentBand) changed = true;   if (mode == AUTO && lastBandIndex != currentBand) changed = true;
   if (mode == AUTO && lastDisplayedFreq != lastFreq) changed = true;   if (mode == AUTO && lastDisplayedFreq != lastFreq) changed = true;
 +  if (forceDisplayUpdate) { changed = true; forceDisplayUpdate = false; }
  
   if (!changed) return;   if (!changed) return;
  
-  lcd.setCursor(0,0); +  updateTopLine(); 
-  lcd.print("IP:"); +  
-  lcd.print(ip); +
   lcd.setCursor(0,1);   lcd.setCursor(0,1);
   lcd.print("                ");   lcd.print("                ");
Строка 131: Строка 276:
  
   if (mode == AUTO) {   if (mode == AUTO) {
-    lcd.print("[A]");+    lcd.print("[A] ");
     if (currentBand >= 0) lcd.print(bands[currentBand].name);     if (currentBand >= 0) lcd.print(bands[currentBand].name);
     else lcd.print("--");     else lcd.print("--");
 +
     lcd.print(" ");     lcd.print(" ");
     if (catActive) printFreqCompact(lastFreq);     if (catActive) printFreqCompact(lastFreq);
-    else lcd.print("WAIT CAT DATA");+    else lcd.print("NO DATA       ");
  
     lastBandIndex = currentBand;     lastBandIndex = currentBand;
     lastDisplayedFreq = lastFreq;     lastDisplayedFreq = lastFreq;
   } else {   } else {
-    lcd.print("MANUAL ");+    lcd.print("[M] ");
     lcd.print(bands[manualBandIndex].name);     lcd.print(bands[manualBandIndex].name);
 +    lcd.print(" ");
 +    for (int i = 3; i >= 0; i--)
 +      lcd.print((bands[manualBandIndex].abcdCode >> i) & 1);
 +
     lastBandIndex = manualBandIndex;     lastBandIndex = manualBandIndex;
   }   }
Строка 149: Строка 299:
 } }
  
-/================= СТАРТОВЫЙ ЭКРАН ================= */+void updateTopLine() { 
 +  if (ipEditMode) return; 
 +  lcd.setCursor(0,0); 
 +  lcd.print("                ");   
 +  lcd.setCursor(0,0); 
 + 
 +  // === AUTO режим === 
 +  if (mode == AUTO) { 
 +    lcd.print("CAT "); 
 + 
 +    if (catActive) { 
 +      // 5-позиционная анимация 
 +      for (int i 0; i < 5; i++) { 
 +        if (i == catAnimPos) 
 +          lcd.write(byte(0));   // кастомная точка 
 +        else 
 +          lcd.print("."); 
 +      } 
 + 
 +      lcd.print("   "); 
 + 
 +      // Показ реле 
 +      if (currentBand >0) { 
 +        for (int i 3; i >0; i--) 
 +          lcd.print((bands[currentBand].abcdCode >> i) & 1); 
 +      } else { 
 +        lcd.print("----"); 
 +      } 
 + 
 +    } else { 
 +      // CAT пропал 
 +      lcd.print(".....   "); 
 +      if (currentBand >0) { 
 +        for (int i 3; i >0; i--) 
 +          lcd.print((bands[currentBand].abcdCode >> i) & 1); 
 +      } else { 
 +        lcd.print("----"); 
 +      } 
 +    } 
 + 
 +    return; 
 +  } 
 + 
 +  // === MANUAL режим === 
 +  lcd.print("CAT "); 
 +  if (catActive) lcd.print("OK"); 
 +  else lcd.print("--"); 
 +
 + 
  
 void splashScreen() { void splashScreen() {
   lcd.clear();   lcd.clear();
   lcd.setCursor(0,0);   lcd.setCursor(0,0);
-  lcd.print("EW8ZO ver ");+  lcd.print("EW8ZO v");
   lcd.print(VERSION, 2);   lcd.print(VERSION, 2);
   lcd.setCursor(0,1);   lcd.setCursor(0,1);
-  lcd.print("Band Decoder");+  lcd.print("ABCD Decoder");
   delay(2000);   delay(2000);
 } }
  
-/* ================= UDP ================= */ 
  
 void readUDP() { void readUDP() {
Строка 167: Строка 365:
   if (!packetSize) return;   if (!packetSize) return;
  
-  char buf[400];+  char buf[200];
   int len = Udp.read(buf, sizeof(buf) - 1);   int len = Udp.read(buf, sizeof(buf) - 1);
   if (len <= 0) return;   if (len <= 0) return;
   buf[len] = 0;   buf[len] = 0;
  
 +  // Любой пакет = связь жива
   lastPacketTime = millis();   lastPacketTime = millis();
 +  lastCatTime = millis();
 +  catActive = true;
  
-  char* f = strstr(buf"<Freq>"); +  // Если MANUAL был включён автоматически (fallback)а CAT снова появился — возвращаемся в AUTO 
-  if (!freturn;+  if (mode == MANUAL && !manualForced
 +      mode = AUTO; 
 +       
 +   
 +      // Восстанавливаем реле по текущему диапазону 
 +      if (currentBand >= 0) 
 +          setRelaysByBand(currentBand); 
 +   
 +      forceDisplayUpdate = true; 
 +      updateLCDIfNeeded(); 
 +  }
  
-  += 6+   
-  lastFreq atol(f* 10;+  // Двигаем CAT-анимацию каждые 2 пакета   
 +  catPacketCounter++; 
 +  if (catPacketCounter >= 2) {   // ← каждые 2 пакета 
 +      catPacketCounter = 0; 
 +      catAnimPos = (catAnimPos + 1% 5; 
 +      updateTopLine(); 
 +  }
  
-  int b = detectBand(lastFreq); 
-  if (b >= 0) currentBand = b; 
  
-  catActive true+  // Ищем <Freq> 
-  lastCatTime = millis();+  char* f strstr(buf, "<Freq>")
 +  if (f
 +    f += 6;
  
-  if (mode == MANUAL && autoFallback+    lastFreq = atol(f* 10
-    mode = AUTO+    freqReceived true  // ← ВОТ ЭТОТ if ТЕБЕ НУЖЕН
-    autoFallback false; +
-    manualForced = false; +
-    setRelays(currentBand); +
-  }+
  
-  if (mode == AUTOsetRelays(currentBand);+    int b = detectBand(lastFreq); 
 +    if (b >0) 
 +      currentBand = b;
  
 +    // В AUTO обновляем реле
 +    if (mode == AUTO && currentBand >= 0)
 +      setRelaysByBand(currentBand);
 +  }
 +
 +  // Если <Freq> нет — это heartbeat, ничего не трогаем
   updateLCDIfNeeded();   updateLCDIfNeeded();
 } }
  
-/* ================= КНОПКА ================= */ 
  
-void handleButton() { 
-  static bool pressed = false; 
  
-  if (!digitalRead(ENC_BTN)) {+void handleButtonPress() {
     pressed = true;     pressed = true;
-  else +    pressStart = millis(); 
-    if (pressed) { +    buttonHeld = false; 
-      if (mode == AUTO) {+} 
 + 
 +void handleButtonHold(unsigned long held) { 
 + 
 +    // длинное → вход в редактор 
 +    if (!ipEditMode && held >= LONG_PRESS) { 
 +        enterIpEditMode(); 
 +        pressed = false; 
 +        buttonHeld = false; 
 +        return; 
 +    } 
 + 
 +    // жест удержания 
 +    if (!ipEditMode && !buttonHeld && held >= HOLD_TIME) { 
 +        buttonHeld = true; 
 +    } 
 +
 + 
 +void handleIpEditorClick(unsigned long pressTime) { 
 +    static unsigned long lastEditorClick = 0; 
 + 
 +    // игнорируем первый клик после входа в редактор 
 +    if (ignoreNextEditorClick) { 
 +        ignoreNextEditorClick = false; 
 +        return; 
 +    } 
 + 
 +    // длинное → выход без сохранения 
 +    if (pressTime >= LONG_PRESS) { 
 +        ipEditMode = false; 
 +        forceDisplayUpdate = true; 
 +        updateLCDIfNeeded(); 
 +        return; 
 +    } 
 + 
 +    // защита от двойного клика 
 +    if (millis() - lastEditorClick < 200) return; 
 +    lastEditorClick = millis(); 
 + 
 +    // короткое → следующий октет 
 +    if (pressTime >= 50) { 
 +        ipOctetIndex++; 
 + 
 +        if (ipOctetIndex > 3) { 
 +            effectiveIP = IPAddress(ipEdit[0], ipEdit[1], ipEdit[2], ipEdit[3]); 
 +            saveIPToEEPROM(effectiveIP); 
 + 
 +            lcd.clear(); 
 +            lcd.setCursor(0,0); 
 +            lcd.print("IP SAVED"); 
 +            lcd.setCursor(0,1); 
 +            lcd.print(effectiveIP); 
 +            delay(1200); 
 + 
 +            ipEditMode = false; 
 +            forceDisplayUpdate = true; 
 +            updateLCDIfNeeded(); 
 +            return; 
 +        } 
 + 
 +        drawIpEditor(); 
 +    } 
 +
 + 
 +void toggleAutoManual() { 
 + 
 +    if (mode == AUTO) {
         mode = MANUAL;         mode = MANUAL;
         manualForced = true;         manualForced = true;
-        autoFallback false+         
-        setRelays(-1); + 
-      } else {+        manualBandIndex (currentBand >= 0 ? currentBand : 0)
 +        setRelaysByBand(manualBandIndex); 
 +    } 
 +    else { 
 +        if (!catActive) { 
 +            lcd.clear(); 
 +            lcd.setCursor(0,0); 
 +            lcd.print("NO CAT LINK"); 
 +            lcd.setCursor(0,1); 
 +            lcd.print("AUTO DISABLED"); 
 +            delay(1200); 
 + 
 +            forceDisplayUpdate = true; 
 +            updateLCDIfNeeded(); 
 +            return; 
 +        } 
         mode = AUTO;         mode = AUTO;
         manualForced = false;         manualForced = false;
-        autoFallback = false; +         
-        setRelays(currentBand); + 
-      } +        if (currentBand >= 0) 
-      updateLCDIfNeeded();+            setRelaysByBand(currentBand); 
 +        else 
 +            disableAllRelays();
     }     }
-    pressed false+ 
-  }+    forceDisplayUpdate true
 +    updateLCDIfNeeded();
 } }
  
-/* ================= ЭНКОДЕР ================= */+void handleButtonRelease(unsigned long pressTime) {
  
 +    // редактор
 +    if (ipEditMode) {
 +        handleIpEditorClick(pressTime);
 +        return;
 +    }
 +
 +    // длинное → вход в редактор
 +    if (pressTime >= LONG_PRESS) {
 +        enterIpEditMode();
 +        return;
 +    }
 +
 +    // короткое → AUTO/MANUAL
 +    if (!buttonHeld && pressTime >= SHORT_PRESS) {
 +        toggleAutoManual();
 +    }
 +
 +    buttonHeld = false;
 +}
 +
 +
 +//
 +// === КНОПКА С АНТИДРЕБЕЗГОМ И ЗАЩИТОЙ ОТ ЛОЖНЫХ СРАБАТЫВАНИЙ ===
 +//
 +void handleButton() {
 +    static unsigned long lastCheck = 0;
 +
 +    if (millis() - lastCheck < 30) return;
 +    lastCheck = millis();
 +
 +    bool btn = !digitalRead(ENC_BTN);
 +
 +    // начало нажатия
 +    if (btn && !pressed) {
 +        handleButtonPress();
 +        return;
 +    }
 +
 +    // удержание
 +    if (btn && pressed) {
 +        unsigned long held = millis() - pressStart;
 +        handleButtonHold(held);
 +        return;
 +    }
 +
 +    // отпускание
 +    if (!btn && pressed) {
 +        pressed = false;
 +        unsigned long pressTime = millis() - pressStart;
 +        handleButtonRelease(pressTime);
 +        return;
 +    }
 +}
 +
 +
 +
 +//
 +// === ЭНКОДЕР С ЗАЩИТОЙ ОТ ЛОЖНЫХ СРАБАТЫВАНИЙ ===
 +//
 void handleEncoder() { void handleEncoder() {
-  static int lastA HIGH;+  static unsigned long lastMove 0; 
   int A = digitalRead(ENC_A);   int A = digitalRead(ENC_A);
 +  if (A == lastA) return;
  
-  if (A != lastA && A == LOW && mode != AUTO) { +  // реагируем только на фронт A == LOW 
-    if (digitalRead(ENC_B)) +  if (A != lastA && A == LOW) {
-      manualBandIndex = (manualBandIndex + 1) % BAND_COUNT; +
-    else +
-      manualBandIndex = (manualBandIndex - 1 + BAND_COUNT) % BAND_COUNT;+
  
-    updateLCDIfNeeded();+    bool clockwise = digitalRead(ENC_B); 
 + 
 +    // === УДЕРЖАНИЕ КНОПКИ + ПОВОРОТ === 
 +    if (buttonHeld && !ipEditMode) { 
 + 
 +      if (clockwise) { 
 +        runRelayTest(); 
 +      } else { 
 +        // резерв 
 +      } 
 + 
 +      buttonHeld = false; 
 +      lastA = A; 
 +      return; 
 +    } 
 + 
 +    // === РЕЖИМ IP-РЕДАКТОРА === 
 +    if (ipEditMode) { 
 + 
 +      if (millis() - lastMove < 80) { 
 +        lastA = A; 
 +        return; 
 +      } 
 +      lastMove = millis(); 
 + 
 +      int val = ipEdit[ipOctetIndex]; 
 +      if (clockwise) val++; 
 +      else val--; 
 + 
 +      if (val < 0) val = 255; 
 +      if (val > 255) val = 0; 
 + 
 +      ipEdit[ipOctetIndex] = val; 
 +      drawIpEditor(); 
 + 
 +      lastA = A; 
 +      return; 
 +    } 
 + 
 +    // === MANUAL режим === 
 +    if (mode == MANUAL) { 
 + 
 +      if (millis() - lastMove < 50) { 
 +        lastA = A; 
 +        return; 
 +      } 
 +      lastMove = millis(); 
 + 
 +      if (clockwise) 
 +        manualBandIndex = (manualBandIndex + 1) % BAND_COUNT; 
 +      else 
 +        manualBandIndex = (manualBandIndex - 1 + BAND_COUNT) % BAND_COUNT; 
 + 
 +      setRelaysByBand(manualBandIndex); 
 +      forceDisplayUpdate = true; 
 +      updateLCDIfNeeded(); 
 +    }
   }   }
 +
   lastA = A;   lastA = A;
 } }
  
-/* ================= TIMEOUT ================= */+ 
 + 
  
 void checkCatTimeout() { void checkCatTimeout() {
-  if (mode != AUTO) return; 
  
 +  // 1) Сбрасываем CAT независимо от режима
   if (catActive && millis() - lastCatTime > CAT_TIMEOUT) {   if (catActive && millis() - lastCatTime > CAT_TIMEOUT) {
-    catActive = false; +      catActive = false; 
-    mode = MANUAL; + 
-    autoFallback true+      // ОБНОВЛЯЕМ ПЕРВУЮ СТРОКУ 
-    manualForced = false; +      updateTopLine(); 
-    manualBandIndex = (currentBand >= 0) currentBand : 0+  } 
-    setRelays(-1); + 
-    updateLCDIfNeeded();+  // 2) Логика fallback только в AUTO 
 +  if (mode == AUTO && !catActive) { 
 +      mode MANUAL      
 +      manualForced = false; 
 + 
 +      if (currentBand >= 0) 
 +          manualBandIndex = currentBand; 
 +      } 
 +      setRelaysByBand(manualBandIndex); 
 + 
 +      forceDisplayUpdate = true; 
 +      updateLCDIfNeeded();
   }   }
 } }
  
-/* ================= SETUP ================= */ 
  
-void setup() { 
-  Serial.begin(115200); 
-  Serial.println("=== Setup start ==="); 
  
 +
 +void setup() {  
 +  //Serial.begin(115200); delay(500); Serial.println("START DECODER");  
 +
 +  // --- Пины энкодера ---
   pinMode(ENC_A, INPUT_PULLUP);   pinMode(ENC_A, INPUT_PULLUP);
   pinMode(ENC_B, INPUT_PULLUP);   pinMode(ENC_B, INPUT_PULLUP);
   pinMode(ENC_BTN, INPUT_PULLUP);   pinMode(ENC_BTN, INPUT_PULLUP);
  
-  for (int i = 0; i < RELAY_COUNT; i++)+  // --- Пины реле --- 
 +  for (int i = 0; i < RELAY_COUNT; i++) {
     pinMode(RELAYS[i], OUTPUT);     pinMode(RELAYS[i], OUTPUT);
 +    digitalWrite(RELAYS[i], LOW);
 +  }
  
-  setRelays(-1);+  disableAllRelays();
  
-  lcd.begin();     +  // --- LCD --- 
 +  lcd.begin();
   lcd.backlight();   lcd.backlight();
-  splashScreen(); 
  
-  Ethernet.begin(mac, ip); +  // если есть сохранённый — подхватим 
-  Serial.print("Assigned IP: ")+  effectiveIP = ip;  
-  Serial.println(Ethernet.localIP());+  loadIPFromEEPROM(effectiveIP); 
  
 +  // Регистрируем кастомный символ CAT‑точки
 +  lcd.createChar(0, catDot);
 +
 +  // Splash screen
 +  splashScreen();
 +
 +  // --- Ethernet ---
 +  Ethernet.begin(mac, effectiveIP);
   Udp.begin(localPort);   Udp.begin(localPort);
-  Serial.println("UDP started"); 
  
 +  // Первичное отображение IP (потом будет перерисовано updateTopLine)
   lcd.clear();   lcd.clear();
   lcd.setCursor(0,0);   lcd.setCursor(0,0);
   lcd.print("IP:");   lcd.print("IP:");
-  lcd.print(ip);+  lcd.print(effectiveIP);
   lcd.setCursor(0,1);   lcd.setCursor(0,1);
-  lcd.print("WAIT CAT DATA");+  lcd.print("READY");
  
-  Serial.println("=== Setup end ===");+  // --- Начальные значения логики --- 
 +  currentBand -1; 
 +  catActive false; 
 +  manualBandIndex 0;   
 +  lastFreq 0;   
 +  lastPacketTime millis(); 
 + 
 +  disableAllRelays(); 
 + 
 +  // Обновляем дисплей по новой логике 
 +  forceDisplayUpdate true;   
 +  updateLCDIfNeeded(); 
 + 
 +  // Инициализация энкодера (важно!) 
 +  lastA = digitalRead(ENC_A);
 } }
  
-/* ================= LOOP ================= */ 
  
-void loop() {+void loop() {   
 +  // === Всегда читаем UDP ===
   readUDP();   readUDP();
 +
 +  // === Обработка энкодера и кнопки ===
   handleEncoder();   handleEncoder();
   handleButton();   handleButton();
-  checkCatTimeout();  // переключение в MANUAL при CAT_TIMEOUT 
  
-  // только надпись при NET_TIMEOUT +  // === Проверка таймаута CAT === 
-  if (millis() - lastPacketTime NET_TIMEOUT && mode == AUTO) { +  checkCatTimeout(); 
-    lcd.setCursor(0,0); + 
-    lcd.print("IP:"); +  // === Периодическое обновление дисплея === 
-    lcd.print(ip); +  static unsigned long lastDisplayUpdate = 0; 
-    lcd.setCursor(0,1); +  if (!ipEditMode && millis() - lastDisplayUpdate 1000) { 
-    lcd.print("WAIT CAT DATA  "); +    lastDisplayUpdate = millis(); 
-  }+    updateLCDIfNeeded(); 
 +  }   
 +  delay(10);
 } }
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 </code> </code>
banddecoder_code.1768119282.txt.gz · Последнее изменение: eu8t