# 23th Feb 2026
# request s-meter from IC7300 MKI or MK II or IC9700
# see end of code for more info.

from machine import UART, Pin, PWM
import time

# -----------------------------
# UART setup
# -----------------------------
uart = UART(0,baudrate=19200,tx=Pin(0),rx=Pin(1),timeout=10)

CIV_START = 0xFE
CIV_END   = 0xFD
RADIO_ADDR = 0x94   # IC7300 MK I
# RADIO_ADDR = 0xB6   # IC7300 MK II
# RADIO_ADDR = 0xA2   # IC9700
PC_ADDR    = 0xE0
CMD_S_METER = 0x15
SUB_S_METER = 0x02

led_onboard = machine.Pin(25, machine.Pin.OUT)

pwm = PWM(Pin(16))
pwm.freq(100_000)

# Send S-meter request
def request_s_meter():
    frame = bytearray([
        CIV_START, CIV_START,
        RADIO_ADDR, PC_ADDR,
        CMD_S_METER, SUB_S_METER,
        CIV_END])
    uart.write(frame)

# Read one complete CI-V frame
def read_civ_frame(timeout_ms=200):
    start = time.ticks_ms()
    buf = bytearray()

    while time.ticks_diff(time.ticks_ms(), start) < timeout_ms:
        if uart.any():
            b = uart.read(1)
            if not b:
                continue
            b = b[0]
            if len(buf) == 0 and b != CIV_START:    # Wait for FE FE
                continue
            buf.append(b)
            if b == CIV_END:  # End of frame
                return buf
    return None

# Parse S-meter frame
def parse_s_meter(frame):
    if len(frame) < 9: # Expected: FE FE E0 94 15 02 xx yy FD
        return None

    if (frame[0] != CIV_START or
        frame[1] != CIV_START or
        frame[4] != CMD_S_METER or
        frame[5] != SUB_S_METER):
        return None

    msb = frame[6]
    lsb = frame[7]

    raw_value = (msb*100) + lsb
    return raw_value

# raw to s-meter converter
def raw_to_s_units(raw):
    if raw < 120:
        return int (raw / 120*9)
    else:
        return "S9+%d dB" %((int(raw)-120)/3)

# PWM output
def analougue_out(raw):
    duty = int(raw * 257)
    pwm.duty_u16(duty)


# Main loop
while True:
    uart.read()               # clear UART
    request_s_meter()         # request s-meter
    time.sleep(0.05)
    uart.read(7)              # remove send frames
    frame = read_civ_frame()  # read s-meter frames

    if frame:
        value = parse_s_meter(frame)     # 0-255 raw s-meter
        value_2 = raw_to_s_units(value)  # change to aprox s-meter values
        if value is not None:
            print("Raw S-meter value:", value, "S-meter value:", value_2)
            analougue_out(value)

    led_onboard(1)   # flash on board (green) led
    time.sleep_ms(100)        
    led_onboard(0)

    time.sleep(1)   # repeat every second
    
# to ignore other CI-V frames: clear UART then request s-meter data
# set up to do this every 1 second
# on-board green led flashs
# PWM o/p on pin GP16 - use Low Pass filter on this o/p + buffer

# UART Tx on GP0, UART Rx on GP1
# 7417 is 5V logic while Pi Pico is 3V: so use 5-3V pot div for Rx
#  
