diff --git a/README.md b/README.md index cf23dd5..e2ddf5c 100644 --- a/README.md +++ b/README.md @@ -26,7 +26,7 @@ Features: * no scan sound * squelch by user input level -* 0.2 .. 3.2MHz frequency ranges +* 0.1 .. 3.2MHz frequency ranges * ticks by frequency (100,500,1000KHz) * catch signal peak frequency * automatic frequency change step @@ -41,8 +41,11 @@ How to start: How to operate: -* press **8** / **2** for zoom in / zoom out -* press and hold **3** / **9** to set squelch level +* press **UP** / **DOWN** key to change frequency +* press **1** / **7** to control measurement time (increasing "sensitivity") +* press **2** / **8** to to set frequency change step +* press **9** / **3** for zoom in / zoom out +* press and hold **\*** / **F** to set squelch level * press **5** to toggle backlight * press **0** to remove frequency from sspectrum to scan * press **EXIT** to disable spectrum view diff --git a/libs/k5_uv_system/api.s b/libs/k5_uv_system/api.s index bf2b86c..d8c3f50 100644 --- a/libs/k5_uv_system/api.s +++ b/libs/k5_uv_system/api.s @@ -43,6 +43,12 @@ BK4819Reset = 0xa7cc + 1; .globl IntDivide IntDivide = 0x128 + 1; +.globl Strlen +Strlen = 0x1c0 + 1; + +.globl BK4819SetChannelBandwidth +BK4819SetChannelBandwidth = 0xaa48 + 1; + .globl BK4819WriteFrequency BK4819WriteFrequency = 0xaabc + 1; diff --git a/libs/k5_uv_system/system.hpp b/libs/k5_uv_system/system.hpp index 672b8bf..c0ac537 100644 --- a/libs/k5_uv_system/system.hpp +++ b/libs/k5_uv_system/system.hpp @@ -23,6 +23,8 @@ extern "C" { void AirCopyFskSetup(); void BK4819Reset(); int IntDivide(int s32Divident, int s32Divisor); + int Strlen(const char *string); + void BK4819SetChannelBandwidth(bool narrow); void BK4819WriteFrequency(unsigned int u32Frequency); void BK4819SetPaGain(unsigned short u16PaBias, unsigned int u32Frequency); void BK4819ConfigureAndStartTxFsk(); diff --git a/libs/lcd/lcd.hpp b/libs/lcd/lcd.hpp index 22ef78f..c649f1b 100644 --- a/libs/lcd/lcd.hpp +++ b/libs/lcd/lcd.hpp @@ -1,6 +1,7 @@ #pragma once #include #include +#include "system.hpp" struct ILcd { virtual void UpdateScreen() = 0; @@ -161,7 +162,7 @@ template class CDisplay { } void Print(const char *C8String) const { - for (unsigned char i = 0; i < strlen(C8String); i++) { + for (unsigned char i = 0; i < Strlen(C8String); i++) { PrintCharacter(C8String[i]); } } @@ -256,24 +257,17 @@ template class CDisplay { startIdx = 8 - i; } - // If the number was 0, we write a single 0. - /* if (startIdx == 0) - U8NumBuff[0] = '0'; */ - // Print the string from the start index - if (u8FixedDigtsCnt) { - startIdx = 9 - u8DigsToCut - u8FixedDigtsCnt; - } + startIdx = 9 - u8DigsToCut - u8FixedDigtsCnt; const char *str = U8NumBuff + startIdx; - const char len = strlen(str); + const char len = Strlen(str); const char dot[1] = {64}; for (unsigned char i = 0; i < len; i++) { if (pointAt == len - i) { - u16CoursorPosition++; - auto *pCoursorPosition = Bitmap.GetCoursorData(u16CoursorPosition); + auto *pCoursorPosition = Bitmap.GetCoursorData(u16CoursorPosition + 1); memcpy(pCoursorPosition, dot, 1); - u16CoursorPosition++; + u16CoursorPosition += 2; } PrintCharacter(str[i]); } diff --git a/src/spectrum_fagci/keys.hpp b/src/spectrum_fagci/keys.hpp new file mode 100644 index 0000000..82396bf --- /dev/null +++ b/src/spectrum_fagci/keys.hpp @@ -0,0 +1,26 @@ +enum Keys { + NUM0, + NUM1, + NUM2, + NUM3, + NUM4, + NUM5, + NUM6, + NUM7, + NUM8, + NUM9, + MENU, // 10 + UP, // 11 + DOWN, // 12 + EXIT, // 13 + ASTERISK, // 14 + FUNCTION, // 15 + _NA16, + _NA17, + _NA18, + _NA19, + _NA20, + _NA21, + FN2, // 22 + FN1, // 23 +}; diff --git a/src/spectrum_fagci/spectrum.hpp b/src/spectrum_fagci/spectrum.hpp index 508e35b..db54775 100644 --- a/src/spectrum_fagci/spectrum.hpp +++ b/src/spectrum_fagci/spectrum.hpp @@ -1,4 +1,5 @@ #pragma once +#include "keys.hpp" #include "radio.hpp" #include "system.hpp" #include "types.hpp" @@ -6,10 +7,18 @@ template class CSpectrum { public: - static constexpr auto ExitKey = 13; static constexpr auto DrawingEndY = 42; static constexpr auto BarPos = 5 * 128; + static constexpr auto ModesCount = 7; + static constexpr auto LastLowBWModeIndex = 3; + + static constexpr u32 modeHalfSpectrumBW[ModesCount] = { + 16_KHz, 50_KHz, 100_KHz, 200_KHz, 400_KHz, 800_KHz, 1600_KHz}; + static constexpr u16 modeScanStep[ModesCount] = { + 1_KHz, 3125_Hz, 6250_Hz, 12500_Hz, 25_KHz, 25_KHz, 25_KHz}; + static constexpr u8 modeXdiv[ModesCount] = {2, 2, 2, 2, 2, 1, 0}; + u8 rssiHistory[128] = {}; u32 fMeasure; @@ -18,16 +27,13 @@ template class CSpectrum { u8 peakI = 0; u32 peakF = 0; u8 rssiMin = 255; - - u16 scanDelay = 1200; - - bool resetBlacklist = false; + u8 btnCounter = 0; CSpectrum() : DisplayBuff(gDisplayBuffer), Display(DisplayBuff), - FontSmallNr(gSmallDigs), frequencyChangeStep(400_KHz), bwMul(2), - rssiTriggerLevel(60) { + FontSmallNr(gSmallDigs), scanDelay(800), mode(5), rssiTriggerLevel(50) { Display.SetFont(&FontSmallNr); + frequencyChangeStep = modeHalfSpectrumBW[mode]; }; void Scan() { @@ -37,7 +43,7 @@ template class CSpectrum { fMeasure = GetFStart(); - RadioDriver.ToggleAFDAC(false); + // RadioDriver.ToggleAFDAC(false); MuteAF(); u16 scanStep = GetScanStep(); @@ -73,7 +79,7 @@ template class CSpectrum { void DrawSpectrum() { for (u8 x = 0; x < 128; ++x) { - auto v = rssiHistory[x >> BWMul2XDiv()]; + auto v = rssiHistory[x >> modeXdiv[mode]]; if (v != 255) { Display.DrawHLine(Rssi2Y(v), DrawingEndY, x); } @@ -84,13 +90,10 @@ template class CSpectrum { Display.SetCoursorXY(0, 0); Display.PrintFixedDigitsNumber3(scanDelay, 2, 2, 1); - Display.SetCoursorXY(112, 0); - Display.PrintFixedDigitsNumber3(GetBW(), 4, 2, 1); - - /* Display.SetCoursorXY(0, 0); - Display.PrintFixedDigitsNumber2(rssiMinV, 0); */ + Display.SetCoursorXY(105, 0); + Display.PrintFixedDigitsNumber3(GetBW(), 3, 3, 2); - Display.SetCoursorXY(44, 0); + Display.SetCoursorXY(42, 0); Display.PrintFixedDigitsNumber3(peakF, 2, 6, 3); Display.SetCoursorXY(0, 48); @@ -99,11 +102,8 @@ template class CSpectrum { Display.SetCoursorXY(98, 48); Display.PrintFixedDigitsNumber3(GetFEnd(), 4, 4, 1); - Display.SetCoursorXY(57, 48); - Display.PrintFixedDigitsNumber3(frequencyChangeStep, 4, 2, 1); - - /* Display.SetCoursorXY(0, 8); - Display.PrintFixedDigitsNumber2(rssiMaxV, 0); */ + Display.SetCoursorXY(52, 48); + Display.PrintFixedDigitsNumber3(frequencyChangeStep, 3, 3, 2); } void DrawRssiTriggerLevel() { @@ -127,61 +127,56 @@ template class CSpectrum { } } - void OnKey(u8 key) { - switch (key) { - case 14: - UpdateRssiTriggerLevel(1); - DelayMs(90); - break; - case 15: - UpdateRssiTriggerLevel(-1); - DelayMs(90); - break; - } - } - void OnKeyDown(u8 key) { switch (key) { - case 1: + case Keys::NUM1: if (scanDelay < 8000) { - scanDelay += 200; + scanDelay += 100; rssiMin = 255; } break; - case 7: - if (scanDelay > 800) { - scanDelay -= 200; + case Keys::NUM7: + if (scanDelay > 400) { + scanDelay -= 100; rssiMin = 255; } break; - case 3: + case Keys::NUM3: UpdateBWMul(1); resetBlacklist = true; break; - case 9: + case Keys::NUM9: UpdateBWMul(-1); resetBlacklist = true; break; - case 2: + case Keys::NUM2: UpdateFreqChangeStep(100_KHz); break; - case 8: + case Keys::NUM8: UpdateFreqChangeStep(-100_KHz); break; - case 11: // up + case Keys::UP: UpdateCurrentFreq(frequencyChangeStep); resetBlacklist = true; break; - case 12: // down + case Keys::DOWN: UpdateCurrentFreq(-frequencyChangeStep); resetBlacklist = true; break; - case 5: + case Keys::NUM5: ToggleBacklight(); break; - case 0: + case Keys::NUM0: Blacklist(); break; + case Keys::ASTERISK: + UpdateRssiTriggerLevel(1); + DelayMs(90); + break; + case Keys::FUNCTION: + UpdateRssiTriggerLevel(-1); + DelayMs(90); + break; } ResetPeak(); } @@ -189,21 +184,29 @@ template class CSpectrum { bool HandleUserInput() { btnPrev = btn; btn = PollKeyboard(); - if (btn == ExitKey) { + if (btn == Keys::EXIT) { DeInit(); return false; } - OnKey(btn); - if (btn != 255 && btnPrev == 255) { - OnKeyDown(btn); + + if (btn != 255) { + if (btn == btnPrev && btnCounter < 255) { + btnCounter++; + } + if (btnPrev == 255 || btnCounter > 16) { + OnKeyDown(btn); + } + return true; } + + btnCounter = 0; return true; } void Render() { DisplayBuff.ClearAll(); DrawTicks(); - DrawArrow(peakI << BWMul2XDiv()); + DrawArrow(peakI << modeXdiv[mode]); DrawSpectrum(); DrawRssiTriggerLevel(); DrawNums(); @@ -212,24 +215,26 @@ template class CSpectrum { void Update() { if (peakRssi >= rssiTriggerLevel) { - Listen(1600); - return; + ToggleGreen(true); + GPIOC->DATA |= GPIO_PIN_4; + Listen(); } - Scan(); - } - - void UpdateRssiTriggerLevel(i32 diff) { - if ((diff > 0 && rssiTriggerLevel < 255) || - (diff < 0 && rssiTriggerLevel > 0)) { - rssiTriggerLevel += diff; + if (peakRssi < rssiTriggerLevel) { + ToggleGreen(false); + GPIOC->DATA &= ~GPIO_PIN_4; + Scan(); } } + void UpdateRssiTriggerLevel(i32 diff) { rssiTriggerLevel += diff; } + void UpdateBWMul(i32 diff) { - if ((diff > 0 && bwMul < 4) || (diff < 0 && bwMul > 0)) { - bwMul += diff; + if ((diff > 0 && mode < (ModesCount - 1)) || (diff < 0 && mode > 0)) { + mode += diff; + SetBW(); + rssiMin = 255; + frequencyChangeStep = modeHalfSpectrumBW[mode]; } - frequencyChangeStep = 100_KHz << bwMul; } void UpdateCurrentFreq(i64 diff) { @@ -267,7 +272,10 @@ template class CSpectrum { oldAFSettings = BK4819Read(0x47); oldBWSettings = BK4819Read(0x43); MuteAF(); - SetWideBW(); + SetBW(); + ResetPeak(); + resetBlacklist = true; + ToggleGreen(false); isInitialized = true; } @@ -277,51 +285,35 @@ template class CSpectrum { RadioDriver.SetFrequency(currentFreq); RestoreOldAFSettings(); BK4819Write(0x43, oldBWSettings); + ToggleGreen(true); isInitialized = false; } - void ResetPeak() { - peakRssi = 0; - peakF = currentFreq; - peakT = 0; - } + void ResetPeak() { peakRssi = 0; } - void SetWideBW() { - auto Reg = BK4819Read(0x43); - Reg &= ~(0b11 << 4); - BK4819Write(0x43, Reg | (0b11 << 4)); - } + void SetBW() { BK4819SetChannelBandwidth(mode <= LastLowBWModeIndex); } void MuteAF() { BK4819Write(0x47, 0); } void RestoreOldAFSettings() { BK4819Write(0x47, oldAFSettings); } - void Listen(u16 durationMs) { + void Listen() { if (fMeasure != peakF) { fMeasure = peakF; RadioDriver.SetFrequency(fMeasure); RestoreOldAFSettings(); - RadioDriver.ToggleAFDAC(true); + // RadioDriver.ToggleAFDAC(true); } for (u8 i = 0; i < 16 && PollKeyboard() == 255; ++i) { - DelayMs(durationMs >> 4); + DelayMs(64); } peakRssi = rssiHistory[peakI] = GetRssi(); } - u16 GetScanStep() { return 25_KHz >> (2 >> bwMul); } - u32 GetBW() { return 200_KHz << bwMul; } - u32 GetFStart() { return currentFreq - (100_KHz << bwMul); } - u32 GetFEnd() { return currentFreq + (100_KHz << bwMul); } + u16 GetScanStep() { return modeScanStep[mode]; } + u32 GetBW() { return modeHalfSpectrumBW[mode] << 1; } + u32 GetFStart() { return currentFreq - modeHalfSpectrumBW[mode]; } + u32 GetFEnd() { return currentFreq + modeHalfSpectrumBW[mode]; } - u8 BWMul2XDiv() { return clamp(4 - bwMul, 0, 2); } - u8 GetMeasurementsCount() { - if (bwMul == 3) { - return 64; - } - if (bwMul > 3) { - return 128; - } - return 32; - } + u8 GetMeasurementsCount() { return 128 >> modeXdiv[mode]; } void ResetRSSI() { RadioDriver.ToggleRXDSP(false); @@ -331,8 +323,9 @@ template class CSpectrum { u8 GetRssi() { ResetRSSI(); - DelayUs(scanDelay); - return (BK4819Read(0x67) & 0x1FF) >> 1; + DelayUs(scanDelay << (mode <= LastLowBWModeIndex)); + auto v = BK4819Read(0x67) & 0x1FF; + return v < 255 ? v : 255; } bool IsFlashLightOn() { return GPIOC->DATA & GPIO_PIN_3; } @@ -343,37 +336,32 @@ template class CSpectrum { void ToggleBacklight() { GPIOB->DATA ^= GPIO_PIN_6; } + void ToggleRed(bool flag) { BK4819SetGpio(5, flag); } + void ToggleGreen(bool flag) { BK4819SetGpio(6, flag); } + u8 Rssi2Y(u8 rssi) { return DrawingEndY - clamp(rssi - rssiMin, 0, DrawingEndY); } i32 clamp(i32 v, i32 min, i32 max) { - if (v <= min) - return min; - if (v >= max) - return max; - return v; - } - - u32 modulo(u32 num, u32 div) { - while (num >= div) - num -= div; - return num; + return v <= min ? min : (v >= max ? max : v); } TUV_K5Display DisplayBuff; CDisplay Display; const TUV_K5SmallNumbers FontSmallNr; - u32 frequencyChangeStep; - u8 bwMul; + u16 scanDelay; + u8 mode; u8 rssiTriggerLevel; - u8 btn = 255; - u8 btnPrev = 255; + u8 btn; + u8 btnPrev; u32 currentFreq; u16 oldAFSettings; u16 oldBWSettings; + u32 frequencyChangeStep; - bool isInitialized = false; + bool isInitialized; + bool resetBlacklist; };