// PA144 controller met NANO  2025-9-24 Jaap van Oosten
// Bepaald de sequense van schakelen van antenne relais en de 50V voeding. Zodat de kontact overgang stroomvrij is.
// Geeft alarm op te hoog stuurniveau van de power FET en SWR, de verstarker gaat dan in doorlaat. 
// De reset knop zet het alarm af nadat de oorzaak is verholpen.
// Stuurt leds voor TX PTT LNA en ANT alarm SWR en of overdrive.
// De koel ventilator heeft temperauur afhankelijke PWM toerental regeling.
// schakelt 12V op de coax kern naar mast preamp in RX toestand , is uitschakelbaar.
// OLED display 128x64 toont de waarden 
// SH1106 OLED NTC temp PWM gestuurde ventilator centrifugaal 12V 0.6A
// Gemaakt met hulp van Copilot AI en WOKWI simulator.
// 
#include <Adafruit_GFX.h>
//#include <Adafruit_SSD1306.h>
#include <Adafruit_SH110X.h>
#include <Wire.h>
#include <math.h>
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_RESET    -1
Adafruit_SH1106G display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
// Pinnen
#define FAN_PIN 9
#define PTT_PIN 2
#define SWR_ALARM 7
#define SWR_ResetButton 8
#define NTC_PIN A6
#define FWD_PIN A0
#define REF_PIN A1
#define SHUNT_PIN A2
#define DRIVE_PIN A3
#define AntRelay 4         // IRF510   low= ON opto pull down  low is gate  high( max 5V zener)  eerst 
#define TxPWRPIN 6         //  BTS  low= ON opto pull down                                        na 20mS 
bool PTTstate = true;   // PTT in 
bool TxState = false;   // PTT in 
bool TxEnable = true;     //  enable Tx
bool alarmTriggered = false;
// debug timing
int timePTT;
int timeRelay;
int timeBTS;
int rawValue;
float swr = 1;
float powerThreshold = 5.0; // minimum vermogen voor DSWR test
float alarmswr = 1;
float tempC;
float DriveLevel;
//5-4-2022
unsigned int VoltDriveLevel =0;    // Sensor PA ingang 50R  50k potmeter
int peakFwd = 0;
int peakRef = 0;
//float peakFwd = 0;
//float peakRef = 0;
// peek hold en decay power bar
const unsigned long peakHoldTime = 2000; // 3 seconden hangtijd
unsigned long peakTimestamp = 0;
bool swrTrip = false;
float readTempNTC() {
  int adc = analogRead(NTC_PIN);
  float voltage = adc * (5.0 / 1023.0);
  tempC = (voltage - 0.5) * 10;  // eenvoudige benadering
  return tempC;
}
float readSWR() {
  float fwd = analogRead(FWD_PIN);
  float ref = analogRead(REF_PIN);
  if (fwd < 10) return 1.0;
  float ratio = ref / fwd;
  return (1 + ratio) / (1 - ratio);
}
void setup() {
  pinMode(FAN_PIN, OUTPUT);
  // aanpassing voor gebruik van D9 voor PWM
  // Reset Timer1 registers
   TCCR1A = 0;
  TCCR1B = 0;
  // Stel Fast PWM mode in (Mode 14: WGM13:WGM10 = 1110)
  TCCR1A |= (1 << COM1A1);               // Non-inverting mode op D9
  TCCR1A |= (1 << WGM11);
  TCCR1B |= (1 << WGM13) | (1 << WGM12);
  // Prescaler instellen op 8 → PWM-frequentie ≈ 2 kHz
  TCCR1B |= (1 << CS11);
  // TOP-waarde instellen voor 2 kHz bij 16 MHz klok
  // Bereken TOP-waarde: ICR1 = 2,000,000 / 7,000 ≈ 286
  ICR1 = 286;  //7kHz
  // Duty cycle instellen (bijv. 50%)
  OCR1A = 143; //7kHz
  pinMode(PTT_PIN, INPUT_PULLUP);
  pinMode(SWR_ALARM, OUTPUT);
  pinMode(SWR_ResetButton, INPUT_PULLUP);
  pinMode(AntRelay,OUTPUT);
  pinMode(TxPWRPIN,OUTPUT);
  display.begin(0x3c, true);
  display.clearDisplay();
  display.setTextSize(1);
  display.setTextColor(SH110X_WHITE);
  display.setCursor(0, 0);
  display.println("144MHz PA 24-9-2025");
  display.display();
  delay (3000);
  Serial.begin(9600);
  delay(1000);
}
void loop() {
 
//                 delay (2000);      // voor debug loop vertraging
// test PTT ingang
PTTstate = digitalRead(PTT_PIN);
       timePTT = millis() ;
  if (PTTstate == 0 & TxEnable){     //  enable TxTxEnable ) { // PTT gnd transmit
      if (TxState == false)  // start TX sequentie
      {
        digitalWrite(AntRelay, HIGH); //coaxrelay ON
        timeRelay = millis() - timePTT ;
        delay(10); // 2sec voorr test             //18-6-2024 Sequenzer delay was 20mS  swr pieken bij inschakellen TX geeft Alarm hielp niet 
        digitalWrite(TxPWRPIN, HIGH); //Power PA -ON
        timeBTS = millis() -timePTT;
        TxState = true;
      }
 
  if (TxEnable == false) 
  {
     digitalWrite(TxPWRPIN, LOW);  //PA uit
     digitalWrite(AntRelay, LOW); //coaxrelay uit
  }
   LeesSwrVoltages();
  }
     // eind PTT=0  = uit
      if (PTTstate == true) { // schakel terug naar ontvangst indien nog in TX mode
      
      if (TxState == true)
      { 
      digitalWrite(TxPWRPIN, LOW); //PWR PA off  dwz optocoupler uit BTS gate hoog
      delay(10); // 20 ms  TX eerst uit 
      digitalWrite(AntRelay, LOW); //  op ontvangst
      TxState = false;
      }
   LeesSwrVoltages();  // 
    }
  
}
 
void LeesSwrVoltages(){
 int fwdRaw = analogRead(FWD_PIN);
 int refRaw = analogRead(REF_PIN);
  int fwdLevel = map(fwdRaw, 0, 1023, 0, 100);
  int refLevel = map(refRaw, 0, 1023, 0, 100);
  float forward = (float)fwdRaw;
  float reflected = (float)refRaw;
  //VoltDriveLevel = analogRead(DRIVE_PIN);   // sensor Voltage op 50R ingang dummy
  float forwardVoltage = forward * ((800.0 / 1023) / 5.0);
  float forwardPower = (forwardVoltage * forwardVoltage) / 50.0;
  
  // nieuw voor piek hang 
   // Nieuwe piek?
  if (fwdLevel > peakFwd) {
    peakFwd = fwdLevel;
    peakTimestamp = millis();
  }
    // Hangtijd verstreken?
  if (millis() - peakTimestamp > peakHoldTime) {
    if (peakFwd > fwdLevel) {
//      peakFwd--; // Langzaam afnemen
      peakFwd-=2; // Langzaam afnemen
    } else {
      peakFwd = fwdLevel; // Bijwerken naar actuele waarde
    }
  }
  // reflected piek hang
if (refLevel > peakRef) {
    peakRef = refLevel;
    peakTimestamp = millis();
  }
    // Hangtijd verstreken?
  if (millis() - peakTimestamp > peakHoldTime) {
    if (peakRef > refLevel) {
    //  peakRef--; // Langzaam afnemen
    peakRef-=2; // Langzaam afnemen
    } else {
      peakRef = refLevel; // Bijwerken naar actuele waarde
    }
  }  
    // einde piek hang 
  rawValue = analogRead(DRIVE_PIN);
  DriveLevel = rawValue * (20.0 / 1023);  // schaalfactor
  if (DriveLevel>15) {
// VoltDriveLevel  alarm 9-10-2024
   digitalWrite(TxPWRPIN, LOW);  //PA uit
       alarmTriggered = true;
    alarmswr = DriveLevel;
    TxEnable = false;
 
}   
  if (forward > powerThreshold && forward > reflected) {
    swr = (forward + reflected) / (forward - reflected);
  } else {
    swr = 0;
  }
  if (digitalRead(SWR_ResetButton) == LOW) {
    alarmTriggered = false;
    TxEnable = true;
   /// SWR_ALARM =0:
  }
  if ((forward > powerThreshold) && (swr > 3.0)) {
    alarmTriggered = true;
    alarmswr = swr ;
    TxEnable = false;
  }
  digitalWrite(SWR_ALARM, alarmTriggered ? HIGH : LOW);
  if (swr > 10.0) swr = 10.0;
  int swrPercent = (int)(log10(swr) * 100.0 / log10(10.0));
display.clearDisplay();
// formule: x = 30 + ((log10(val) - log10(min)) / (log10(max) - log10(min))) * 90; 
// SWR schaalverdeling (1–10)
float swrMin = log10(1);
float swrMax = log10(10);
for (int swrVal = 1; swrVal <= 10; swrVal++) {
  float logSWR = log10(swrVal);
  int x = 30 + (int)((logSWR - swrMin) / (swrMax - swrMin) * 90);
  display.drawLine(x, 20, x, 22, SH110X_WHITE); // SWR schaal
}
// Power schaalverdeling (1–800W)
float pwrMin = log10(1);
float pwrMax = log10(800);
for (int pwrVal = 1; pwrVal <= 800; pwrVal *= 2) {
  float logPWR = log10(pwrVal);
  int x = 30 + (int)((logPWR - pwrMin) / (pwrMax - pwrMin) * 90);
  display.drawLine(x, 0, x, 2, SH110X_WHITE);  // FWD schaal
  //display.drawLine(x, 10, x, 12, SH110X_WHITE); // REF schaal
}
// FWD bar + peak
display.setCursor(0, 0);
display.print("FWD:");
//display.fillRect(30, 0, fwdLevel * 0.9, 8, SH110X_WHITE);
display.fillRect(30, 0, peakFwd * 0.9, 8, SH110X_WHITE);
int peakXfwd = 30 + (peakFwd * 0.9);
display.drawLine(peakXfwd, 0, peakXfwd, 7, SH110X_WHITE);  // piek-lijn
// REF bar + peak
display.setCursor(0, 10);
display.print("REF:");
display.fillRect(30, 10, peakRef * 0.9, 8, SH110X_WHITE);
int peakXref = 30 + (peakRef * 0.9);
display.drawLine(peakXref, 10, peakXref, 17, SH110X_WHITE);  // piek-lijn
// SWR bar
display.setCursor(0, 20);
display.print("SWR:");
display.fillRect(30, 20, swrPercent * 0.9, 8, SH110X_WHITE);
// SWR value
display.setCursor(70, 35);
display.print("SWR: ");
display.print(swr, 2);
// Power value
display.setCursor(0, 35);
display.print("PWR: ");
display.print(forwardPower, 0);
display.print("W");
//SupplyCurent
display.setCursor(0, 45);
   rawValue = analogRead(SHUNT_PIN);
 float SupplyCurrent = rawValue * (30.0 / 1023);  // schaalfactor
  display.print(SupplyCurrent, 1);
  display.print(" A");
 
 // Stuurnieau
display.setCursor(80, 45);
    rawValue = analogRead(DRIVE_PIN);
  DriveLevel = rawValue * (20.0 / 1023);  // schaalfactor
  display.print(DriveLevel, 1);
  display.print(" W");
 
// Alarm status
display.setCursor(0, 55);
if (alarmTriggered) {
  display.print("ALARM! ");
  display.print(alarmswr, 2);
} else {
  display.print("OK        ");
}
float tempC = readTempNTC();
  int pwm = map(tempC, 20, 50, 0, 255);
  pwm = constrain(pwm, 0, 255);
  analogWrite(FAN_PIN, pwm);
  display.setCursor(75, 55);
  display.print("T: ");
  display.print(tempC);
  //display.println(" C");
  display.display();
}
// test timing
//   Serial.print("timePTT "); 
//   Serial.print(timePTT );
//   Serial.print("  timeRelay "); 
//   Serial.print(timeRelay);
//   Serial.print("  timeBTS "); 
//   Serial.println(timeBTS);
 // Serial.print("Forward Power: ");
 // Serial.print(forwardPower, 2);
 // Serial.print(" W | Reflected: ");
 // Serial.print(reflected, 2);
 // Serial.print(" | SWR: ");
 // Serial.print(swr, 2);
 // Serial.print(" | T: ");
 // Serial.print(tempC, 2);
 // Serial.print(" | PTT:");
 // Serial.println(PTTstate);
 // delay(10);
//}  werd niet gezien !