diff --git a/xrd.py b/xrd.py index 21dd33e..75ca243 100644 --- a/xrd.py +++ b/xrd.py @@ -25,7 +25,7 @@ class AutoFMAM(TEF6686): if frequency < 2700: self.modulation = Modulation.AM else: self.modulation = Modulation.FM def Tune_To(self, mode, frequency: int | None): - if frequency is not None: + if frequency is not None: self.set_modulation(frequency) self.last_tune = frequency if self.modulation == Modulation.FM: self.FM_Tune_To(mode, frequency) @@ -33,7 +33,11 @@ class AutoFMAM(TEF6686): def Get_Quality_Data(self): if self.modulation == Modulation.FM: return self.FM_Get_Quality_Data() elif self.modulation == Modulation.AM: return self.AM_Get_Quality_Data() - + def Set_Bandwidth(self, bw_client: int): + if self.modulation == Modulation.FM: + auto = (bw_client == 0) + self.FM_Set_Bandwidth(auto, 2360 if auto else (bw_client // 100)) + elif self.modulation == Modulation.AM: self.AM_Set_Bandwidth(bw_client) STEREO_BLENDING = False @@ -68,7 +72,8 @@ class State: last_eqims: int = (INITIAL_EQ << 1) | INITIAL_IMS forced_mono: bool = False deemp: int = 0 - bw: int = 0 + bw_fm: int = 0 + bw_am: int = 0 scan_start: int = 8750 scan_stop: int = 10800 scan_step: int = 10 @@ -103,10 +108,10 @@ def authenticate(conn: socket.socket): data = conn.recv(len(expected_hash)) if not data: break - if data.strip() == expected_hash.strip(): + if data.strip() == expected_hash.strip(): conn.sendall(b"o1,0\nOK\n") return True - else: + else: conn.sendall(b"a0\n") # You failed break conn.close() @@ -118,9 +123,10 @@ def process_command(tef: AutoFMAM, data: bytes, state: State, conn: socket.socke if cmd.startswith(b"T"): freq = int(cmd.decode().removeprefix("T").strip()) if freq < 153 or freq > 108000: continue + mode = TEF6686.TuneTo_Mode.FM_Jump if tef.modulation == Modulation.AM: mode = TEF6686.TuneTo_Mode.Preset - + tef.set_modulation(freq) match tef.modulation: case Modulation.FM: @@ -148,10 +154,11 @@ def process_command(tef: AutoFMAM, data: bytes, state: State, conn: socket.socke elif cmd.startswith(b"x"): tef.Tune_To(TEF6686.TuneTo_Mode.Preset, tef.last_tune) elif cmd.startswith(b"X"): tef.APPL_Set_OperationMode(True) # turn off elif cmd.startswith(b"W"): - state.bw = int(cmd.decode().removeprefix("W").strip()) - auto = (state.bw == 0) - tef.FM_Set_Bandwidth(auto, 2360 if auto else (state.bw // 100)) - out += f"W{state.bw}\n".encode() + bw = int(cmd.decode().removeprefix("W").strip()) + if tef.modulation == Modulation.FM: state.bw_fm = bw + else: state.bw_am = bw + tef.Set_Bandwidth(bw) + out += f"W{bw}\n".encode() elif cmd.startswith(b"?"): out += b">XRD Python driver\n" elif cmd.startswith(b"S"): cmd = cmd[1:] @@ -163,23 +170,28 @@ def process_command(tef: AutoFMAM, data: bytes, state: State, conn: socket.socke case 99: state.scan_step = (arg + 5) // 10 case 119: state.scan_bw = arg else: - start = True + saved_last_tune = tef.last_tune - tef.FM_Set_Bandwidth((state.scan_bw == 0), state.scan_bw) + tef.Set_Bandwidth(state.scan_bw) conn.sendall(b"U") + start = True for freq in range(state.scan_start, state.scan_stop + state.scan_step, state.scan_step): - if not start: conn.sendall(b", ") # Prevent trailing comma, because the FM-DX-Webserver spectrum plugin treats us as actual firmware and throws as harder api, without it we're treated as a module + if not start: conn.sendall(b", ") start = False - tef.FM_Tune_To(TEF6686.TuneTo_Mode.Search, freq) # Auto mutes, less commands sent + tef.Tune_To(TEF6686.TuneTo_Mode.Search, freq) time.sleep(0.0067) # sick seven - _, level, *_ = d if (d := tef.FM_Get_Quality_Data()) else (None, None) + _, level, *_ = d if (d := tef.Get_Quality_Data()) else (None, None) if level is None: continue conn.sendall(str(freq * 10).encode() + b" = " + str((level / 10) + 11.25).encode()) conn.sendall(b"\n") - tef.FM_Set_Bandwidth((state.bw == 0), 2360 if (state.bw == 0) else (state.bw // 100)) - tef.Tune_To(TEF6686.TuneTo_Mode.Preset, tef.last_tune) + tef.Tune_To(TEF6686.TuneTo_Mode.Preset, saved_last_tune) + tef.Set_Bandwidth(state.bw_fm if tef.modulation == Modulation.FM else state.bw_am) + elif cmd.startswith(b"M"): + mod = int(cmd.decode().removeprefix("M").strip()) + if mod == 1: tef.Tune_To(TEF6686.TuneTo_Mode.Preset, state.last_tune_am) + else: tef.Tune_To(TEF6686.TuneTo_Mode.Preset, state.last_tune_fm) return out @@ -213,11 +225,11 @@ def send_signal_status(tef: AutoFMAM, conn: socket.socket, state: State): status, level, usn, wam, _, bandwidth, *_ = res ms_since_tune = (status & 0x3ff) / 10 - if ms_since_tune < 45: return # Give only "quality data" + if ms_since_tune < 60: return # Give only "quality data" level = level / 10 - if level > 120: return - level += 11.25 + if level > 120 or level < -20: return + level += 11.25 # Convert to dbf data = b"S" @@ -240,7 +252,7 @@ def send_signal_status(tef: AutoFMAM, conn: socket.socket, state: State): @periodic(RDS_UPDATE_INTERVAL) def send_rds_data(tef: AutoFMAM, conn: socket.socket, state: State): if tef.modulation != Modulation.FM: return - + res = tef.FM_Get_RDS_Data__decoder() if res is None: return status, A, B, C, D, dec_error = res @@ -310,7 +322,7 @@ def run_server(): conn.sendall(f"G{bin(state.last_eqims).removeprefix('0b').zfill(2)}\n".encode()) conn.sendall(f"B{int(state.forced_mono)}\n".encode()) conn.sendall(f"D{state.deemp}\n".encode()) - conn.sendall(f"W{state.bw}\n".encode()) + conn.sendall(f"W{state.bw_fm}\n".encode()) conn.sendall(f"M{tef.modulation}\n".encode()) while True: @@ -332,6 +344,6 @@ def run_server(): time.sleep(0.03) import traceback -if __name__ == "__main__": +if __name__ == "__main__": try: run_server() except Exception as e: traceback.print_exception(e) \ No newline at end of file