From d74ecf74a6026d43d2dfe611df14c19833e6cc83 Mon Sep 17 00:00:00 2001 From: "Matthias P. Braendli" Date: Sun, 19 Mar 2023 21:21:41 +0100 Subject: Fix WSPR transmitter, support centihz freq --- sw/eval-clock-cw-tx/src/main.rs | 5 +++++ sw/eval-clock-cw-tx/trigger.py | 45 +++++++++++++++++++++++++++++++++++++++++ sw/picardy/src/main.rs | 4 ++-- sw/picardy/src/si_clock.rs | 36 +++++++++++++++++---------------- 4 files changed, 71 insertions(+), 19 deletions(-) create mode 100644 sw/eval-clock-cw-tx/trigger.py (limited to 'sw') diff --git a/sw/eval-clock-cw-tx/src/main.rs b/sw/eval-clock-cw-tx/src/main.rs index 52193b4..c303416 100644 --- a/sw/eval-clock-cw-tx/src/main.rs +++ b/sw/eval-clock-cw-tx/src/main.rs @@ -273,6 +273,11 @@ fn main() -> ! { } }, Mode::WSPR => { + if let Some(f) = usb.take_frequency() { + shared.state.set_vfo(f); + update_siclock_required = true; + } + if shared.state.wspr_freq_offset_updated { update_siclock_required = true; } diff --git a/sw/eval-clock-cw-tx/trigger.py b/sw/eval-clock-cw-tx/trigger.py new file mode 100644 index 0000000..a2b3657 --- /dev/null +++ b/sw/eval-clock-cw-tx/trigger.py @@ -0,0 +1,45 @@ +#!/usr/bin/env python +import sys +import requests +import serial +import random +import datetime +import time + +battery_capacity = requests.get("http://wollinuc.local:5000/stats").json()['capa'] + +def eat(ser): + time.sleep(1) + received = [] + while True: + dat = ser.read(1) + if dat: + received.append(dat) + else: + break + return b''.join(received) + +now = datetime.datetime.utcnow() + +#this script gets called every hour at minutes 13,27,39,53 + +if battery_capacity < 6000: + print(f"Bat cap not enough: {battery_capacity}") +elif battery_capacity < 10000 and now.minute != 13: + print(f"Bat cap not low: {battery_capacity}") +else: + tx_freq = 10138700 + 400 + random.randint(1410, 1490) + print(f"TX freq {tx_freq}") + serial = serial.Serial("/dev/serial/by-id/usb-HB9EGM_Beep_Machine_1-if00", 115200, timeout=0) + serial.write('f{}\n'.format(tx_freq).encode("ascii")) + print(f"Answer: {eat(serial)}") + + while True: + now = datetime.datetime.utcnow() + if now.minute % 2 == 0 and now.second == 00: + break + time.sleep(0.1) + + print(f"{now} TX") + serial.write(b'wspr\n') + print(f"Answer: {eat(serial)}") diff --git a/sw/picardy/src/main.rs b/sw/picardy/src/main.rs index 3beefee..777b5c5 100644 --- a/sw/picardy/src/main.rs +++ b/sw/picardy/src/main.rs @@ -276,7 +276,7 @@ fn main() -> ! { if require_bfo_update { bfo_tune_fail = !siclock.set_bfo(state.bfo()).is_ok(); } - siclock.set_vfo(state.vfo()); + siclock.set_vfo_centihertz(state.vfo() * 100); update_disp_required = true; } @@ -288,7 +288,7 @@ fn main() -> ! { let vfo = state.vfo(); if previous_vfo != vfo { - siclock.set_vfo(vfo); + siclock.set_vfo_centihertz(vfo * 100); } previous_vfo = vfo; diff --git a/sw/picardy/src/si_clock.rs b/sw/picardy/src/si_clock.rs index 6de4c25..4bd2686 100644 --- a/sw/picardy/src/si_clock.rs +++ b/sw/picardy/src/si_clock.rs @@ -1,7 +1,7 @@ /* The MIT License (MIT) - Copyright (c) 2020 Matthias P. Braendli + Copyright (c) 2023 Matthias P. Braendli Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -26,10 +26,10 @@ use core::convert::TryInto; use si5351::{Si5351, Si5351Device}; use embedded_hal::blocking::i2c::{WriteRead, Write}; -const REF_CLOCK : u32 = 25_000_000; +const REF_CLOCK_CHZ : u32 = 25_000_000 * 100; const PLL_A_MULT : u32 = 32; -fn gcd(x: u32, y: u32) -> u32 { +fn gcd(x: u64, y: u64) -> u64 { let mut x = x; let mut y = y; while y != 0 { @@ -40,30 +40,32 @@ fn gcd(x: u32, y: u32) -> u32 { x } -fn clock_settings_for_pll(freq: u32, pll: u32) -> (u16, u32, u32) { +// All calculations in centihertz + +fn clock_settings_for_pll(freq: u64, pll: u64) -> (u16, u32, u32) { let a = pll / freq; let b = pll - (a * freq); let gcd = gcd(b, freq); let b = b / gcd; let c = freq / gcd; - (a.try_into().unwrap(), b, c) + (a.try_into().unwrap(), b.try_into().unwrap(), c.try_into().unwrap()) } -fn clock_settings_with_pll_calculation(freq: u32) -> (u16, u8, u32, u32) { - let mut divider : u32 = 900_000_000 / freq; // Calculate the division ratio. 900,000,000 is the maximum internal +fn clock_settings_with_pll_calculation(freq_chz: u32) -> (u16, u8, u32, u32) { + let mut divider : u32 = (100*900_000_000u64 / freq_chz as u64).try_into().unwrap(); // Calculate the division ratio. 900,000,000 is the maximum internal if (divider % 2) == 1 { divider -= 1 // Ensure an even integer division ratio } - let pll_freq = divider * freq; + let pll_freq : u128 = divider as u128 * freq_chz as u128; // mult is an integer that must be in the range 15..90 - let mult = pll_freq / REF_CLOCK; - let l = pll_freq % REF_CLOCK; + let mult = pll_freq / (REF_CLOCK_CHZ as u128); + let l : u32 = (pll_freq % (REF_CLOCK_CHZ as u128)).try_into().unwrap(); let denom = 1048575; - let num = f64::from(l) * f64::from(denom) / f64::from(REF_CLOCK); + let num = f64::from(l) * f64::from(denom) / f64::from(REF_CLOCK_CHZ); (divider.try_into().unwrap(), mult.try_into().unwrap(), num as u32, denom) } @@ -74,7 +76,7 @@ fn set_bfo(siclock: &mut dyn Si5351, freq: u32) -> Result<(), si5351::Error> siclock.set_clock_enabled(si5351::ClockOutput::Clk2, false); } else { - let (a, b, c) = clock_settings_for_pll(freq, PLL_A_MULT * REF_CLOCK); + let (a, b, c) = clock_settings_for_pll(freq.into(), PLL_A_MULT as u64 * REF_CLOCK_CHZ as u64); siclock.setup_multisynth(si5351::Multisynth::MS2, a, b, c, si5351::OutputDivider::Div1)?; siclock.select_clock_pll(si5351::ClockOutput::Clk2, si5351::PLL::A); siclock.set_clock_enabled(si5351::ClockOutput::Clk2, true); @@ -82,7 +84,7 @@ fn set_bfo(siclock: &mut dyn Si5351, freq: u32) -> Result<(), si5351::Error> siclock.flush_clock_control(si5351::ClockOutput::Clk2) } -fn set_vfo(siclock: &mut dyn Si5351, freq: u32) +fn set_vfo_centihertz(siclock: &mut dyn Si5351, freq: u32) { if freq == 0 { siclock.set_clock_enabled(si5351::ClockOutput::Clk0, false); @@ -107,7 +109,7 @@ impl SiClock I2C: WriteRead + Write, { pub fn new(i2c: I2C, bfo: u32, vfo: u32) -> SiClock { - let mut siclock = Si5351Device::new(i2c, false, REF_CLOCK); + let mut siclock = Si5351Device::new(i2c, false); siclock.init(si5351::CrystalLoad::_10).unwrap(); // See freqplan.py for Si5351 frequency plan @@ -118,7 +120,7 @@ impl SiClock siclock.reset_pll(si5351::PLL::A).unwrap(); - set_vfo(&mut siclock, vfo); + set_vfo_centihertz(&mut siclock, vfo * 100); siclock.reset_pll(si5351::PLL::B).unwrap(); @@ -127,8 +129,8 @@ impl SiClock SiClock{siclock} } - pub fn set_vfo(&mut self, freq: u32) { - set_vfo(&mut self.siclock, freq) + pub fn set_vfo_centihertz(&mut self, freq: u32) { + set_vfo_centihertz(&mut self.siclock, freq) } pub fn set_bfo(&mut self, freq: u32) -> Result<(), si5351::Error> { -- cgit v1.2.3