diff --git a/libs/lcd/lcd.hpp b/libs/lcd/lcd.hpp index 4b6d071..1320faa 100644 --- a/libs/lcd/lcd.hpp +++ b/libs/lcd/lcd.hpp @@ -49,6 +49,11 @@ public: u16CoursorPosition = (u8Line * Bitmap.SizeX) + u8X; } + void SetCoursorXY(unsigned char x, unsigned char y) const + { + u16CoursorPosition = x + (y << 4); + } + void SetFont(const IFont *pFont) const { pCurrentFont = pFont; @@ -267,4 +272,4 @@ private: const BitmapType &Bitmap; mutable const IFont *pCurrentFont; mutable unsigned short u16CoursorPosition; -}; \ No newline at end of file +}; diff --git a/libs/radio/radio.hpp b/libs/radio/radio.hpp index 84f449e..fa862d5 100644 --- a/libs/radio/radio.hpp +++ b/libs/radio/radio.hpp @@ -74,12 +74,12 @@ namespace Radio // Fw.BK4819WriteFrequency(u32FrequencyD10); // } - unsigned int GetFrequency() + static unsigned int GetFrequency() { return (Fw.BK4819Read(0x39) << 16) | Fw.BK4819Read(0x38); } - signed short GetRssi() + static signed short GetRssi() { short s16Rssi = ((Fw.BK4819Read(0x67) >> 1) & 0xFF); return s16Rssi - 160; @@ -95,7 +95,7 @@ namespace Radio return Fw.BK4819Read(0x0C) & 0b10; } - void SetFrequency(unsigned int u32Freq) + static void SetFrequency(unsigned int u32Freq) { Fw.BK4819Write(0x39, ((u32Freq >> 16) & 0xFFFF)); Fw.BK4819Write(0x38, (u32Freq & 0xFFFF)); @@ -283,4 +283,4 @@ namespace Radio } } }; -} \ No newline at end of file +} diff --git a/src/spectrum_fagci/spectrum.hpp b/src/spectrum_fagci/spectrum.hpp index 6b884d7..67c26e6 100644 --- a/src/spectrum_fagci/spectrum.hpp +++ b/src/spectrum_fagci/spectrum.hpp @@ -1,7 +1,7 @@ #pragma once +#include "radio.hpp" #include "system.hpp" #include "uv_k5_display.hpp" -#include "radio.hpp" typedef unsigned char u8; typedef signed short i16; @@ -11,82 +11,71 @@ typedef unsigned int u32; typedef signed long long i64; typedef unsigned long long u64; -static constexpr auto operator""_Hz(u64 Hz) { return Hz / 10; } -static constexpr auto operator""_KHz(u64 KHz) { return KHz * 1000_Hz; } -static constexpr auto operator""_MHz(u64 KHz) { return KHz * 1000_KHz; } -static constexpr auto operator""_ms(u64 us) { return us * 1000; } -static constexpr auto operator""_s(u64 us) { return us * 1000_ms; } - -template &RadioDriver> +template &RadioDriver> class CSpectrum { public: static constexpr auto ExitKey = 13; - static constexpr auto DrawingSizeY = 16 + 6 * 8; static constexpr auto DrawingEndY = 42; static constexpr auto BarPos = 5 * 128; u8 rssiHistory[128] = {}; u8 measurementsCount = 32; - u8 rssiMin = 255, rssiMax = 0; + u8 rssiMin = 255; u8 highestPeakX = 0; u8 highestPeakT = 0; u8 highestPeakRssi = 0; u32 highestPeakF = 0; - u32 FStart, FEnd, fMeasure; + u32 FStart; CSpectrum() : DisplayBuff(FwData.pDisplayBuffer), FontSmallNr(FwData.pSmallDigs), Display(DisplayBuff), scanDelay(800), sampleZoom(2), scanStep(25_KHz), - rssiTriggerLevel(65) { + frequencyChangeStep(100_KHz), rssiTriggerLevel(65) { Display.SetFont(&FontSmallNr); }; - inline void Measure() { - if (highestPeakRssi >= rssiTriggerLevel) { - // listen - if (fMeasure != highestPeakF) { - fMeasure = highestPeakF; - SetFrequency(fMeasure); - } - Fw.BK4819Write(0x47, u16OldAfSettings); - Fw.DelayUs(1_s); - - // check signal level - Fw.BK4819Write(0x47, 0); // AF - - highestPeakRssi = GetRssi(fMeasure, scanDelay); - - rssiHistory[highestPeakX >> sampleZoom] = highestPeakRssi; - return; + inline bool ListenPeak() { + if (highestPeakRssi < rssiTriggerLevel) { + return false; } - u8 rssi = 0; - u8 xPeak = 64; - u32 fPeak = currentFreq; + // measure peak for this moment + highestPeakRssi = GetRssi(highestPeakF); // also sets freq for us + rssiHistory[highestPeakX >> sampleZoom] = highestPeakRssi; - Fw.BK4819Write(0x47, 0); + if (highestPeakRssi >= rssiTriggerLevel) { + Listen(1000000); + return true; + } + + return false; + } + + inline void Scan() { + u8 rssi = 0, rssiMax = 0; + u8 iPeak = 0; + u32 fPeak = currentFreq, fMeasure = FStart; rssiMin = 255; - rssiMax = 0; - fMeasure = FStart; for (u8 i = 0; i < measurementsCount; ++i, fMeasure += scanStep) { - rssi = rssiHistory[i] = GetRssi(fMeasure, scanDelay); + rssi = rssiHistory[i] = GetRssi(fMeasure); if (rssi < rssiMin) { rssiMin = rssi; } if (rssi > rssiMax) { rssiMax = rssi; fPeak = fMeasure; - xPeak = i << sampleZoom; + iPeak = i; } } ++highestPeakT; - if (highestPeakT >= 8 || rssiMax > highestPeakRssi) { + if (rssiMax > highestPeakRssi || highestPeakT >= (8 << sampleZoom)) { highestPeakT = 0; highestPeakRssi = rssiMax; - highestPeakX = xPeak; + highestPeakX = iPeak << sampleZoom; highestPeakF = fPeak; } } @@ -98,25 +87,28 @@ public: } inline void DrawNums() { - Display.SetCoursor(0, 0); + Display.SetCoursorXY(0, 0); Display.PrintFixedDigitsNumber2(scanDelay, 0); - Display.SetCoursor(0, 8 * 2 + 5 * 7); + Display.SetCoursorXY(51, 0); Display.PrintFixedDigitsNumber2(scanStep << (7 - sampleZoom)); - Display.SetCoursor(1, 8 * 2 + 6 * 7); + Display.SetCoursorXY(58, 8); Display.PrintFixedDigitsNumber2(scanStep); - Display.SetCoursor(1, 8 * 2 + 13 * 7); + Display.SetCoursorXY(107, 8); Display.PrintFixedDigitsNumber2(highestPeakRssi, 0); - Display.SetCoursor(0, 8 * 2 + 10 * 7); + Display.SetCoursorXY(86, 0); Display.PrintFixedDigitsNumber2(highestPeakF); - Display.SetCoursor(6, 8 * 2 + 4 * 7); + Display.SetCoursorXY(44, 48); Display.PrintFixedDigitsNumber2(currentFreq); - Display.SetCoursor(1, 0); + Display.SetCoursorXY(100, 48); + Display.PrintFixedDigitsNumber2(frequencyChangeStep); + + Display.SetCoursorXY(0, 8); Display.PrintFixedDigitsNumber2(rssiTriggerLevel, 0); } @@ -150,7 +142,7 @@ public: } void HandleUserInput() { - switch (u8LastBtnPressed) { + switch (lastButtonPressed) { case 1: UpdateScanDelay(200); break; @@ -176,10 +168,16 @@ public: UpdateScanStep(1); break; case 11: // up - UpdateCurrentFreq(100_KHz); + UpdateCurrentFreq(frequencyChangeStep); break; case 12: // down - UpdateCurrentFreq(-100_KHz); + UpdateCurrentFreq(-frequencyChangeStep); + break; + case 14: + UpdateFreqChangeStep(100_KHz); + break; + case 15: + UpdateFreqChangeStep(-100_KHz); break; default: isUserInput = false; @@ -198,7 +196,7 @@ public: void Update() { if (bDisplayCleared) { - currentFreq = GetFrequency(); + currentFreq = RadioDriver.GetFrequency(); OnUserInput(); u16OldAfSettings = Fw.BK4819Read(0x47); Fw.BK4819Write(0x47, 0); // mute AF during scan @@ -207,7 +205,8 @@ public: HandleUserInput(); - Measure(); + if (!ListenPeak()) + Scan(); } void UpdateRssiTriggerLevel(i32 diff) { @@ -241,11 +240,15 @@ public: OnUserInput(); } + void UpdateFreqChangeStep(i64 diff) { + frequencyChangeStep = clamp(frequencyChangeStep + diff, 100_KHz, 2_MHz); + OnUserInput(); + } + inline void OnUserInput() { isUserInput = true; u32 halfOfScanRange = scanStep << (6 - sampleZoom); FStart = currentFreq - halfOfScanRange; - FEnd = currentFreq + halfOfScanRange; // reset peak highestPeakT = 0; @@ -253,7 +256,7 @@ public: highestPeakX = 64; highestPeakF = currentFreq; - Fw.DelayUs(90_ms); + Fw.DelayUs(90000); } void Handle() { @@ -269,8 +272,8 @@ public: return; } - u8LastBtnPressed = Fw.PollKeyboard(); - if (u8LastBtnPressed == ExitKey) { + lastButtonPressed = Fw.PollKeyboard(); + if (lastButtonPressed == ExitKey) { working = false; RestoreParams(); return; @@ -285,28 +288,26 @@ private: bDisplayCleared = true; DisplayBuff.ClearAll(); Fw.FlushFramebufferToScreen(); - SetFrequency(currentFreq); + RadioDriver.SetFrequency(currentFreq); Fw.BK4819Write(0x47, u16OldAfSettings); // set previous AF settings } } - void SetFrequency(u32 f) { - Fw.BK4819Write(0x39, (f >> 16) & 0xFFFF); - Fw.BK4819Write(0x38, f & 0xFFFF); - Fw.BK4819Write(0x30, 0); - Fw.BK4819Write(0x30, 0xbff1); + inline void Listen(u32 duration) { + Fw.BK4819Write(0x47, u16OldAfSettings); + for (u8 i = 0; i < 16 && lastButtonPressed == 255; ++i) { + lastButtonPressed = Fw.PollKeyboard(); + Fw.DelayUs(duration >> 4); + } + Fw.BK4819Write(0x47, 0); } - u8 GetRssi(u32 f, u32 delay = 800) { - SetFrequency(f); - Fw.DelayUs(delay); + u8 GetRssi(u32 f) { + RadioDriver.SetFrequency(f); + Fw.DelayUs(scanDelay); return Fw.BK4819Read(0x67); } - u32 GetFrequency() { - return (Fw.BK4819Read(0x39) << 16) | Fw.BK4819Read(0x38); - } - inline bool IsFlashLightOn() { return GPIOC->DATA & GPIO_PIN_3; } inline void TurnOffFlashLight() { GPIOC->DATA &= ~GPIO_PIN_3; @@ -335,13 +336,14 @@ private: const TUV_K5SmallNumbers FontSmallNr; CDisplay Display; - u8 u8LastBtnPressed; + u8 lastButtonPressed; u32 currentFreq; u16 u16OldAfSettings; u16 scanDelay; u8 sampleZoom; u32 scanStep; + u32 frequencyChangeStep; u8 rssiTriggerLevel; bool working = false;