Compare commits

...

163 Commits

Author SHA1 Message Date
eried da380261b2 Version bump 2021-11-01 11:49:42 +01:00
eried 790ebdff31 Updating the contributors list 2021-11-01 11:48:14 +01:00
eried cf906684cc Merge branch 'next' 2021-11-01 11:46:06 +01:00
Erwin Ried 848dba44d8 Merge pull request #395 from Brumi-2021/New-Feature-Add-Gain_TX-control-to-the-Replay-App
Add Gain_TX control to the Replay App
2021-10-06 01:15:32 +02:00
Erwin Ried 5a21c1c76a Merge pull request #413 from Brumi-2021/New_Feature_Remove_Initial_short_Ant_DC_bias_pulse_when_cold_reset
Update main.cpp
2021-09-27 13:08:52 +02:00
Brumi-2021 b335886f42 Update main.cpp
Remove initial short wrong Ant-DC_BIAS pulse. (250 msegs aprox)
2021-09-25 16:37:30 +02:00
Erwin Ried f12eb55f6b Merge pull request #412 from ArjanOnwezen/fix-backlight-time-out
Fixed #398: Changed datatype to be able to store > 255 second for backlight timer
2021-09-06 06:29:28 +02:00
Arjan Onwezen 6871126100 changed datatype to be able to store > 255 second for backlight timer 2021-09-03 16:46:41 +02:00
Erwin Ried 5b4c3514fb Merge pull request #396 from texasyojimbo/next
Create ISM.TXT
2021-07-31 02:18:20 +02:00
AD5NL af7242f7d1 Create ISM.TXT
Center frequencies for ISM bands. These are probably where we should be transmitting if unlicensed.
2021-07-26 15:39:31 -05:00
Brumi-2021 03eae70555 Add Gain_TX control to the Replay App
Current Replay App , shows in the user menu a UI to select two kind of controls for the RF output level :
1-) LNA GAIN (0..40 ) dB => but it has no TX effect because it is the RX-LNA . GAIN
2-) RF AMP (0 / +14dBm , (that was correct , we have two IC's , RX / TX ) (sw is controlling weill .

Note, although SW Version 1.40 do not leave to control drictly the GAIN TX
, that Replay App , in fact, it was using the inheritated selected GAIN TX from any previous usage of MIC App.

That Pull request alllows now to have the following controls
1-) GAIN TX (0..47 ) dB (now it is OK
2-) RF AMP (0 / +14dBm , (that was correct , we have two IC's , RX / TX ) (sw is controlling weill .

Remakrs : After the change , now we can control the GAIN TX , but not "in the fly" . When we are in the Replay loop , any change of the FREQUENCY or GAIN TX will be ignored , till we play STOP / START the loop again. (but the AMP RF (0 /+14 dBs) it works in the loop withouth any problems (same as before ) .
2021-07-15 18:15:44 +02:00
Erwin Ried 010f06c77c Merge pull request #382 from teixeluis/hotfix-adsb-position
Hotfix to issue #362 - ADS-B RX app aircraft position jitter
2021-06-25 10:13:21 +02:00
teixeluis 2f86fa7e99 Merge branch 'hotfix-adsb-position' of https://github.com/teixeluis/portapack-mayhem into hotfix-adsb-position 2021-06-24 15:16:59 +01:00
teixeluis fe806b7bdc Fixed the mixing of aircraft coordinates in the details view, by
checking if the ICAO address of the frame and the current item
in the details view match. Slight refactor by placing the decimal
to string conversion function into the string_format module.

Added fix in the scope of issue #365

FrequencyStepView field in TransmitterView class

FrequencyStepView field in TransmitterView class

Update ui_transmitter.hpp

Update credits

Fixed left padding of the decimal part of the numbers.
2021-06-24 15:16:19 +01:00
teixeluis 22e8add4dd Fixed left padding of the decimal part of the numbers. 2021-06-24 15:10:06 +01:00
teixeluis 93ce2b04c0 Merge branch 'next' into hotfix-adsb-position 2021-06-24 13:44:48 +01:00
teixeluis b09439afb1 Fixed the mixing of aircraft coordinates in the details view, by
checking if the ICAO address of the frame and the current item
in the details view match. Slight refactor by placing the decimal
to string conversion function into the string_format module.
2021-06-23 23:52:15 +01:00
teixeluis 97349b06ef Fixes to the log and screen rendering of the geo coordinates. 2021-06-23 19:54:34 +01:00
Erwin Ried 8329b66926 Update credits 2021-06-22 12:44:19 +02:00
Erwin Ried 52376b12b2 Merge pull request #359 from XxOinvizioNxX/next
Add FrequencyStepView field to the TransmitterView class
2021-06-22 12:30:59 +02:00
Erwin Ried 95f72991c4 Merge pull request #367 from teixeluis/hotfix-rx-hang-issue-365
Added fix in the scope of issue #365
2021-06-22 12:29:51 +02:00
teixeluis 2ceb49e4f2 Added more precise function to calculate NL (based on cmath lib).
Created constants for some of the values scattered in the code.
2021-06-19 23:41:06 +01:00
Erwin Ried 8afd83a4e1 Merge pull request #381 from teixeluis/feature-radiosondes-beep-371
Radiosonde beep pitch RSSI improvements. Keeping current frequency in battery backed RAM
2021-06-17 21:48:14 +02:00
teixeluis 8aff0bb4d8 Improved tone generator for proper frequency control. Also
features a square wave mode.
Added proportional beep duration based on the RSSI as well.
Now reading the current radiosonde frequency from the
battery backed RAM instead starting with the same frequency
all the time.
2021-06-16 23:23:47 +01:00
Erwin Ried 7fe6a3b04e Merge pull request #379 from ArjanOnwezen/category-length-display-fix
fix save frequency gui glitch
2021-06-15 10:20:31 +02:00
Arjan Onwezen c8a8a69832 fix save frequency gui glitch 2021-06-14 21:58:15 +02:00
Erwin Ried de994d5911 Merge pull request #378 from ArjanOnwezen/adding-radiosonde-txt
Adding radiosonde txt
2021-06-14 21:10:10 +02:00
Arjan Onwezen 935db5b58b Added radiosonde.txt 2021-06-14 18:15:42 +02:00
Arjan Onwezen 81f7875764 Added radiosonde.txt 2021-06-14 18:10:45 +02:00
Erwin Ried 0f511508a3 Merge pull request #376 from teixeluis/feature-radiosondes-beep-371
Feature radiosondes beep - working pitch RSSI
2021-06-14 10:35:48 +02:00
teixeluis a80d91fb1e More improvements to the rssi tone. Added saving of the tuned frequency
to the radio model persistent store.
2021-06-13 23:35:33 +01:00
teixeluis 43e123bafe Used temporarily for experimental purposes, no longer needed. 2021-06-11 00:25:24 +01:00
teixeluis fb0672925e Merge remote-tracking branch 'portapack-mayhem/next' into feature-radiosondes-beep-371 2021-06-11 00:15:56 +01:00
teixeluis c2dc7d1cf5 Slight improvement of the tone generator. 2021-06-11 00:13:56 +01:00
teixeluis edcd780402 Improved the pitch RSSI. Still looking for better approach. 2021-06-10 12:10:24 +01:00
teixeluis c85e6a4d52 Now getting rssi events.Pitch changes still to be improved. 2021-06-09 09:10:01 +01:00
Erwin Ried 414ed9a0ec Merge pull request #374 from teixeluis/feature-radiosondes-beep-371
Feature radiosondes beep 371
2021-06-09 05:16:34 +02:00
teixeluis f8f5963bcf Merge remote-tracking branch 'portapack-mayhem/next' into feature-radiosondes-beep-371 2021-06-08 23:11:01 +01:00
teixeluis 9040e780bc Added beep on radiosonde packet decoding, and volume widget to control its level. 2021-06-08 23:07:37 +01:00
Erwin Ried f1ba8c3dee Merge pull request #361 from ArjanOnwezen/iso-date-time
ISO datetime for Clock, FileManager, Frequency manager, added clock UI options
2021-06-07 23:48:19 +02:00
Erwin Ried 3f1af56dfc Merge pull request #372 from ArjanOnwezen/fix-freq-manager-save-file
fix for freq manager save file
2021-06-07 23:47:00 +02:00
Arjan Onwezen 226c0c2d80 fix for freq manager save file 2021-06-06 01:31:30 +02:00
teixeluis d74e1830f8 Added fix in the scope of issue #365 2021-05-22 20:57:48 +01:00
Arjan Onwezen 6bc2cbeda9 ISO datetime for Clock, FileManager, Frequency manager
Added option to show/hide clock (with/without date)
2021-05-17 23:16:15 +02:00
Frey Hertz e76609a74a Update ui_transmitter.hpp 2021-05-14 23:00:09 +03:00
Frey Hertz 97f3f773fb FrequencyStepView field in TransmitterView class 2021-05-14 22:57:25 +03:00
Frey Hertz bf0b9b9881 FrequencyStepView field in TransmitterView class 2021-05-14 22:49:26 +03:00
Erwin Ried 182059b3c6 Merge pull request #358 from ArjanOnwezen/proc_aprsrc_cpp_warning_fix
proc_aprsrx.cpp compile warning fix
2021-05-12 12:40:47 +02:00
Arjan Onwezen c307e9d5ae proc_aprsrx.cpp compile warning fix 2021-05-12 08:09:04 +02:00
Erwin Ried a090f1fb0d Merge pull request #354 from ArjanOnwezen/ui_aprs_rx_cpp_warning_fix
ui_aprs_rx.cpp compiler warning fix
2021-05-12 02:20:55 +02:00
Erwin Ried 62b789e432 Merge pull request #353 from ArjanOnwezen/dsp_modulate_cpp_warning_fix
dsp_modulelate.cpp compiler warning fix
2021-05-12 02:20:17 +02:00
Erwin Ried 42b33c4526 Merge pull request #355 from ArjanOnwezen/aprs_packet_hpp_warning_fix
aprs_packet.hpp compiler warning fix
2021-05-12 02:19:57 +02:00
Erwin Ried a95c3a3e63 Merge pull request #357 from ArjanOnwezen/ui_adsb_rx_hpp_warning_fix
ui_adsb_rx.hpp compiler warning fix
2021-05-12 02:19:41 +02:00
Arjan Onwezen a3ef7d069e ui_adsb_rx.hpp compiler warning fix 2021-05-11 21:47:55 +02:00
Arjan Onwezen f5c3219035 aprs_packet.hpp compiler warning fix 2021-05-10 21:30:45 +02:00
Arjan Onwezen a2e4a15229 dsp.modulelate.cpp compiler warning fix 2021-05-10 19:31:48 +02:00
Arjan Onwezen 1a8319b86e /havoc/firmware/application/apps/ui_aprs_rx.cpp:51:7: warning: unused variable 'entry_age' [-Wunused-variable]
/havoc/firmware/application/apps/ui_aprs_rx.cpp:345:12: warning: unused variable 'age' [-Wunused-variable]
2021-05-10 16:28:46 +02:00
Erwin Ried 2ab4ed591d Update ui_about_simple.cpp 2021-05-03 04:00:39 +02:00
Erwin Ried 4f74e262d2 Merge pull request #351 from ArjanOnwezen/add-gsm-nl.txt
Added GSM-NL.txt contaning Dutch GSM frequencies
2021-05-03 03:59:38 +02:00
Arjan Onwezen 88ca1234d9 Added GSM-NL.txt contaning Dutch GSM frequencies 2021-05-02 18:54:33 +02:00
eried 433529b4cb Merge branch 'next' 2021-04-22 12:12:45 +02:00
eried f161e85f96 Merge branch 'next' of https://github.com/eried/portapack-mayhem into next 2021-04-22 12:11:52 +02:00
Erwin Ried f1fd9a3db1 Removing the warning
Does not applies anymore with the latest release
2021-04-22 12:11:32 +02:00
eried 85e4a43cbd Version bump 2021-04-22 09:34:52 +02:00
Erwin Ried 5f778c1734 Update ui_about_simple.cpp 2021-04-19 10:04:50 +02:00
Erwin Ried c19bcc17af Merge pull request #341 from fossum/feature/adding-snap-values-to-calls
Added a couple snap values to the calls app.
2021-04-19 10:04:07 +02:00
Eric Fossum d60299af95 Added a couple snap values to the calls app. 2021-04-17 22:20:28 +00:00
eried 57ed3ebb43 Merge branch 'pr/325' into next 2021-04-14 09:30:53 +02:00
eried dfa1a98575 Update hackrf 2021-04-14 09:29:45 +02:00
Erwin Ried e21fbbf234 Merge pull request #329 from aldude999/next
AM/SSB/DSB Microphone Functionality
2021-04-14 09:26:09 +02:00
Erwin Ried 136209dc8d Update ui_about_simple.cpp 2021-04-14 09:25:38 +02:00
Erwin Ried 838451f491 Merge pull request #339 from eried/recognition-of-audio-chip
Recognition of audio chip
2021-04-14 09:24:46 +02:00
Erwin Ried 2da482f393 Merge pull request #336 from RedFox-Fr/next
Updates to somes files in sdcard/FREQMAN
2021-04-14 09:22:07 +02:00
Erwin Ried 4cafce3286 Merge pull request #337 from eried/update-hackrf-submodule
Update hackrf submodule
2021-04-14 09:21:36 +02:00
RedFox-Fr f9685517ea Update somes sdcard/FREQMAN files 2021-04-14 00:54:10 +02:00
RedFox-Fr d020016413 Update somes sdcard/FREQMAN files. 2021-04-14 00:45:13 +02:00
Erwin Ried 4c50401df2 Update ui_about_simple.cpp 2021-04-12 13:29:01 +02:00
Erwin Ried d57edd5e25 Merge pull request #333 from zhang00963/next
Automatic recognition of audio chip patch
2021-04-12 12:47:34 +02:00
eried 594890744b New GSM-FR.TXT file for sdcard/FREQMAN
https: //github.com/eried/portapack-mayhem/issues/334
Co-Authored-By: RedFox-Fr <82333326+RedFox-Fr@users.noreply.github.com>
2021-04-12 12:46:34 +02:00
zhang00963 a0eaa70ff4 Realize the automatic recognition of audio chip, including ak4951en/wm8731/wm8731s,Try to fix the max2837 temperature problem 2021-04-11 02:19:31 +08:00
eried 9402634602 Update hackrf 2021-03-25 14:50:22 +01:00
Erwin Ried 41864f06e7 Delete ui_mictx.cpp.1 2021-03-22 10:10:01 +01:00
Erwin Ried 133bfbf07b Delete ui_mictx.hpp.1 2021-03-22 10:09:41 +01:00
DESKTOP-R56EVJP\Alex f65852ff05 Rebased code from new eried repo commits. Changed to to reflect strijar implementation. Fixed previous issue with old ssb-am-tx ui_mictx code. 2021-03-21 20:21:50 -05:00
Erwin Ried 603b7fb1ab Merge pull request #286 from GullCode/ui_looking_glass_warning_fix
Fixed redefined define, possibly overflowing variable, missing constructors
2021-03-16 14:46:23 +01:00
Erwin Ried 9d437aee6a Merge pull request #278 from GullCode/tv_collector_warning_fix
removed unused variables
2021-03-15 11:45:50 +01:00
Erwin Ried fe98a58a4f Merge pull request #277 from GullCode/adsb_warning_fix
Fix adsb warnings
2021-03-15 11:45:32 +01:00
Erwin Ried ee2ebc8302 Merge pull request #272 from euquiq/RADIOSONDE_METEOMAN_LAT_LON_BUG_FIX
Fix bug on radiosonde Meteoman Lat & lon calculation
2021-03-15 11:44:21 +01:00
East2West f15cf78101 Add APRS Receiving App 2021-03-11 22:27:19 -06:00
Erwin Ried f56e8930dc Update dockerfile 2021-03-11 10:34:10 +01:00
Erwin Ried f98c96e98a Update dockerfile-nogit 2021-03-11 10:33:54 +01:00
Erwin Ried de92faf67b Same as the other dockerfile, using get-pip.py 3.4
https://stackoverflow.com/questions/65896334/python-pip-broken-wiith-sys-stderr-writeferror-exc
2021-02-16 09:50:34 +01:00
Erwin Ried 27f354f841 Latest pip broken
https://stackoverflow.com/questions/65896334/python-pip-broken-wiith-sys-stderr-writeferror-exc
2021-02-16 09:49:48 +01:00
Erwin Ried eca25898f2 Merge pull request #276 from GullCode/chibios_warning_fix
Fix warning: cast between incompatible function types
2021-02-16 09:12:22 +01:00
Erwin Ried aea807e1f4 Merge pull request #280 from GullCode/proc_am_audio_warning_fix
Quoted out unused variable
2021-02-16 09:11:20 +01:00
Erwin Ried 8807ab179b Merge pull request #283 from GullCode/proc_btlerx_warning_fix
Quoted CRC calculus as it's unused, voided message
2021-02-16 09:10:42 +01:00
Erwin Ried 7049373d67 Merge pull request #288 from GullCode/ui_navigation_warning_fix
Added missing brace
2021-02-16 09:10:08 +01:00
Erwin Ried 3c30c127e2 Update ui_navigation.cpp 2021-02-16 09:09:49 +01:00
Erwin Ried b82b0f15d0 Merge pull request #311 from ImDroided/next
Added Pocsag bitrate
2021-02-15 09:52:15 +01:00
ImDroided 62c1e4e028 Added Pocsag bitrate
I added 3200 to the bitrates in pocsag per a user request on Facebook.
2021-02-14 12:52:56 -06:00
GullCode cd8732c24f Direct casting to int instead of new var 2021-02-05 23:08:54 +01:00
Erwin Ried 4f90c5efee Updating contributors list 2021-02-03 22:23:12 +01:00
Erwin Ried e0e57e5af2 Merge pull request #290 from GullCode/ui_tv_warning_fix
removed unused var
2021-02-03 22:20:34 +01:00
Erwin Ried d59b0d44d3 Merge pull request #282 from GullCode/proc_am_tv_warning_fix
Quoted unused vars and voided one
2021-02-03 22:09:06 +01:00
Erwin Ried 5ca7398bd9 Merge pull request #279 from GullCode/proc_capture_warning_fix
fix unused result
2021-02-03 22:08:43 +01:00
Erwin Ried dbb46edcb6 Merge pull request #285 from GullCode/proc_nrfrx_warning_fix
Removed unused and voided a var
2021-02-03 22:07:58 +01:00
Erwin Ried 68e75cc98e Merge pull request #293 from GullCode/ui_scanner_warning_fix
Fixed uninitialized / missing switch cases, unused
2021-02-03 22:07:13 +01:00
Erwin Ried f0ca95ee7e Merge pull request #274 from GullCode/sonde_packet_warning_fix
Moved calibytes and calfrchk to cpp file to avoid unused warning
2021-02-03 22:06:27 +01:00
GullCode 1a48fb8c5a removed a var, added a void, removed a unused initializer 2021-01-28 10:08:57 +01:00
Erwin Ried 1a3a60f6ac Merge pull request #281 from GullCode/proc_audio_tx_warning_fix
Added missing initialisation
2021-01-28 00:23:42 +01:00
Erwin Ried 77a7f48958 Merge pull request #284 from GullCode/proc_pocsag_warning_fix
Added missing initialisations
2021-01-28 00:23:10 +01:00
Erwin Ried 523877e0d1 Merge pull request #287 from GullCode/ais_packet_warning_fix
Added missing default constructor
2021-01-28 00:22:37 +01:00
Erwin Ried 282416169d Merge pull request #289 from GullCode/ertkey_warning_fix
Added missing default constructor
2021-01-28 00:18:31 +01:00
Erwin Ried 8e8e156477 Merge pull request #291 from GullCode/ui_fileman_warning_fix
Added a voided v
2021-01-28 00:16:40 +01:00
Erwin Ried b1135aab0a Merge pull request #292 from GullCode/ui_morse_warning_fix
added a voided var
2021-01-28 00:16:27 +01:00
Erwin Ried 36f9e0cb7c Merge pull request #294 from GullCode/ui_settings_warning_fix
Added missing initializer
2021-01-28 00:16:07 +01:00
Erwin Ried 9bd74f32d0 Merge pull request #295 from GullCode/ui_sonde_warning_fix
Added missing initializer
2021-01-28 00:15:39 +01:00
Erwin Ried dd0042b5f1 Merge pull request #297 from GullCode/soundboard_app_warning_fix
added a voided var
2021-01-28 00:14:55 +01:00
GullCode fb61ad55c0 added a voided var 2021-01-27 17:20:07 +01:00
GullCode ca7b5e110c Added missing initializer 2021-01-27 17:10:37 +01:00
GullCode a6a41ca5a5 Added missing initialize 2021-01-27 17:08:09 +01:00
GullCode 02d69e54eb Fixed uninitialized / missing switch cases, unused 2021-01-27 17:03:20 +01:00
GullCode b75ef345a5 added a voided var 2021-01-27 16:57:42 +01:00
GullCode 8c84719598 Added two voided vars 2021-01-27 16:54:17 +01:00
GullCode 8bfeba0d89 Added a voided v 2021-01-27 16:50:48 +01:00
GullCode c3c680fc04 removed unused var 2021-01-27 16:46:58 +01:00
GullCode f0457c106d Added missing default constructor 2021-01-27 16:43:13 +01:00
GullCode 5d73175a17 Added missing brace 2021-01-27 16:39:50 +01:00
GullCode 45b874694e Added missing default constructor 2021-01-27 16:36:44 +01:00
GullCode 42113434f0 Fixed redefined define, possibly overflowing variable, missing constructors 2021-01-27 16:30:09 +01:00
GullCode e9e4d20302 Removed unused and voided a var 2021-01-27 16:11:20 +01:00
GullCode ec520bf08c Added missing initialisations 2021-01-27 16:07:03 +01:00
GullCode 486c1d6bcd Quoted CRC calculus as it's unused, voided message 2021-01-27 16:02:59 +01:00
GullCode b7eb095dd8 Quoted unused vars and voided one 2021-01-27 15:58:56 +01:00
GullCode 3c14d38286 Added missing initialisation 2021-01-27 15:54:45 +01:00
GullCode 3166a66756 Quoted out unused variable 2021-01-27 15:52:17 +01:00
GullCode 961e115cc6 fix unused result 2021-01-27 15:48:41 +01:00
GullCode 1483160df4 removed unused variables 2021-01-27 15:45:04 +01:00
GullCode c3fe053eb2 Fix adsb warnings 2021-01-27 15:38:05 +01:00
GullCode 6c2950cfe8 Fix warning: cast between incompatible function types from 'void (*)(void *)' to 'msg_t (*)(void *)' 2021-01-27 15:32:46 +01:00
Erwin Ried 89d46d59ee Merge pull request #275 from GullCode/channel_stat_collector_warning_fix
Fix __SIMD32 warning
2021-01-27 15:22:39 +01:00
Erwin Ried 0d7aa1d32c Merge pull request #273 from GullCode/spi_image_warning_fix
missing contructor
2021-01-27 15:17:42 +01:00
GullCode 266e398224 Fix __SIMD32 warning 2021-01-27 15:16:43 +01:00
GullCode e75677d366 Moved calibytes and calfrchk to cpp file to avoid unused warning 2021-01-27 15:09:02 +01:00
GullCode 1c1d3e9897 missing contructor 2021-01-27 14:57:22 +01:00
euquiq 50bab791dd Fix bug on radiosonde Meteoman Lat & lon calculation
The underlying function used for calculating Latitude and Longitude -also used in other places inside the radiosonde app- was returning a positive value always.

But it needs to cope with negative values also (i.e. Lat and Lon)

Fixed by just changing the returning value into int32_t (even if the calculation is done in uint32_t, the actual sign is passed thru when returning the calculated value -those are the same 4 bytes, interpreted either as (before) unsigned or (now) signed)
2021-01-25 23:41:19 -03:00
Erwin Ried 19ebf14e8c Update README.md 2021-01-20 11:03:39 +01:00
eried 8b6442ee79 Merge branch 'next' 2021-01-20 10:53:24 +01:00
eried 456b55d552 Merge branch 'next' of https://github.com/eried/portapack-mayhem into next 2021-01-20 10:52:56 +01:00
Erwin Ried 3dfb23481f Update README.md 2021-01-20 10:29:13 +01:00
eried 000b2d3e7d Version bump 2021-01-20 10:02:52 +01:00
Erwin Ried faa4affba1 Update README.md 2021-01-20 09:42:21 +01:00
Erwin Ried 099afda51c Update README.md 2021-01-20 09:41:25 +01:00
Erwin Ried 5c09efe8f6 Update README.md 2021-01-20 08:33:58 +01:00
Erwin Ried 157f08bc49 Update README.md 2021-01-20 08:32:27 +01:00
Erwin Ried d5e6d9d662 Merge pull request #257 from strijar/waterfall-bar
Waterfall filter bar
2021-01-12 21:57:19 +01:00
Erwin Ried 64bdd3e018 Merge pull request #263 from euquiq/JAMMER-TX_COOLDOWN_TIMERS_IN_SECONDS
JAMMER NOW INCLUDES TWO TIMERS
2021-01-12 21:57:04 +01:00
euquiq 928bce083a Cosmetics + Jammer now in green + Jitter
I think the Jammer deserves a green icon, since it actually does it job pretty well.

Then there is a Jitter parameter. It allows to introduce a jitter from 1/60th of a second up to 60/60th of a second (a full one). It will delay / move forward either the TX or the cooldown period for a maximum of a half of the time you choose as jitter.

Meaning: If I choose 60/60th, a full second of jitter, it will produce a random number from 1 to 60.

Then it will calculate jitter = 30 - randomnumber

THen it will "add" that (positive or negative) time to the  time counter for the next jitter change of state.
2021-01-08 11:54:21 -03:00
euquiq 8859c3d80c JAMMER NOW INCLUDES TWO TIMERS
Each driving the TX and COOLDOWN timers.
2021-01-07 17:51:38 -03:00
Белоусов Олег 1e9406d091 Cleaned up a bit 2020-12-24 11:14:23 +03:00
Белоусов Олег 63f6a885d8 Implemented correct display of the filter indicator on the waterfall 2020-12-23 18:00:51 +03:00
Erwin Ried 608c8c3597 Merge pull request #222 from euquiq/simplify-persistent-memory-ui-config
just making Persistent Memory easier to read
2020-11-23 12:05:07 +01:00
euquiq 6aee1c9c30 just making Persistent Memory easier to read
Some internal code re-writing in order to simplify a bit, and hopefully making it easier to understand what's going on inside there.
2020-11-03 02:14:16 -03:00
126 changed files with 3662 additions and 527 deletions
+1 -1
View File
@@ -39,7 +39,7 @@ This fork (**Mayhem**) uses *major.minor.release* [semantic versioning](https://
## What about Havoc/GridRF/jamesshao8/jboone's?
* jboone's PortaPack: the [vanilla](https://en.wikipedia.org/wiki/Vanilla_software) experience
* Havoc: It was the most popular fork of jboone's PortaPack, currrently, it is not being maintained nor updated
* jamesshao8: He keeps his own version of the fork, while not attached as a fork to anything
* jamesshao8: He keeps his own version of the fork, while not attached as a fork to anything. Latest functions do not follow the license and are not being published with source code, so keep this in mind
* GridRF: They sell PortaPack clones with their own firmware based on a old version, which has no sourcecode available
## How can I collaborate
+1 -1
View File
@@ -18,7 +18,7 @@ RUN apt-get update && \
apt-get -qy autoremove
#Install current pip from PyPa
RUN curl https://bootstrap.pypa.io/get-pip.py -o get-pip.py && \
RUN curl https://bootstrap.pypa.io/pip/3.4/get-pip.py -o get-pip.py && \
python get-pip.py
#Fetch additional dependencies from Python 2.x pip
+2 -2
View File
@@ -15,7 +15,7 @@ RUN apt-get update && \
apt-get -qy autoremove
#Install current pip from PyPa
RUN curl https://bootstrap.pypa.io/get-pip.py -o get-pip.py && \
RUN curl https://bootstrap.pypa.io/pip/3.4/get-pip.py -o get-pip.py && \
python3 get-pip.py
#Fetch additional dependencies from Python 3.x pip
@@ -38,4 +38,4 @@ RUN mkdir ~/bin && cd ~/bin && \
for tool in gcc g++ cpp c++;do ln -s $(which ccache) arm-none-eabi-$tool;done
CMD cd .. && cd build && \
cmake .. && make firmware
cmake .. && make firmware
+2
View File
@@ -140,6 +140,7 @@ set(CPPSRC
${COMMON}/png_writer.cpp
${COMMON}/pocsag.cpp
${COMMON}/pocsag_packet.cpp
${COMMON}/aprs_packet.cpp
${COMMON}/portapack_io.cpp
${COMMON}/portapack_persistent_memory.cpp
${COMMON}/portapack_shared_memory.cpp
@@ -218,6 +219,7 @@ set(CPPSRC
apps/ui_adsb_rx.cpp
apps/ui_adsb_tx.cpp
apps/ui_afsk_rx.cpp
apps/ui_aprs_rx.cpp
apps/ui_btle_rx.cpp
apps/ui_nrf_rx.cpp
apps/ui_aprs_tx.cpp
+2 -1
View File
@@ -199,7 +199,7 @@ void AnalogTvView::on_show_options_rf_gain() {
void AnalogTvView::on_show_options_modulation() {
std::unique_ptr<Widget> widget;
const auto modulation = static_cast<ReceiverModel::Mode>(receiver_model.modulation());
static_cast<ReceiverModel::Mode>(receiver_model.modulation());
tv.show_audio_spectrum_view(true);
set_options_widget(std::move(widget));
@@ -216,6 +216,7 @@ void AnalogTvView::on_reference_ppm_correction_changed(int32_t v) {
}
void AnalogTvView::on_headphone_volume_changed(int32_t v) {
(void)v; //avoid warning
//tv::TVView::set_headphone_volume(this,v);
}
+1 -1
View File
@@ -107,7 +107,7 @@ private:
std::unique_ptr<Widget> options_widget { };
tv::TVWidget tv { true };
tv::TVWidget tv { };
void on_tuning_frequency_changed(rf::Frequency f);
void on_baseband_bandwidth_changed(uint32_t bandwidth_hz);
+2
View File
@@ -50,6 +50,8 @@ struct ERTKey {
{
}
ERTKey( const ERTKey& other ) = default;
ERTKey& operator=(const ERTKey& other) {
id = other.id;
commodity_type = other.commodity_type;
+2 -1
View File
@@ -90,7 +90,8 @@ private:
{
{ "512bps ", 0 },
{ "1200bps", 1 },
{ "2400bps", 2 }
{ "2400bps", 2 },
{ "3200bps", 3 }
}
};
OptionsField options_phase {
+9 -2
View File
@@ -139,7 +139,12 @@ void ReplayAppView::start() {
}
);
}
field_rfgain.on_change = [this](int32_t v) {
tx_gain = v;
};
field_rfgain.set_value(tx_gain);
receiver_model.set_tx_gain(tx_gain);
radio::enable({
receiver_model.tuning_frequency(),
sample_rate * 8 ,
@@ -180,6 +185,8 @@ ReplayAppView::ReplayAppView(
NavigationView& nav
) : nav_ (nav)
{
tx_gain = 35;field_rfgain.set_value(tx_gain);
baseband::run_image(portapack::spi_flash::image_tag_replay);
add_children({
@@ -190,7 +197,7 @@ ReplayAppView::ReplayAppView(
&text_duration,
&progressbar,
&field_frequency,
&field_lna,
&field_rfgain,
&field_rf_amp,
&check_loop,
&button_play,
+9 -3
View File
@@ -51,6 +51,7 @@ private:
static constexpr ui::Dim header_height = 3 * 16;
uint32_t sample_rate = 0;
int32_t tx_gain { 47 };
static constexpr uint32_t baseband_bandwidth = 2500000;
const size_t read_size { 16384 };
const size_t buffer_count { 3 };
@@ -75,7 +76,7 @@ private:
bool ready_signal { false };
Labels labels {
{ { 10 * 8, 2 * 16 }, "LNA: A:", Color::light_grey() }
{ { 10 * 8, 2 * 16 }, "GAIN A:", Color::light_grey() }
};
Button button_open {
@@ -103,8 +104,13 @@ private:
FrequencyField field_frequency {
{ 0 * 8, 2 * 16 },
};
LNAGainField field_lna {
{ 14 * 8, 2 * 16 }
NumberField field_rfgain {
{ 14 * 8, 2 * 16 },
2,
{ 0, 47 },
1,
' '
};
RFAmpField field_rf_amp {
{ 19 * 8, 2 * 16 }
+6 -1
View File
@@ -110,7 +110,11 @@ void SoundBoardView::start_tx(const uint32_t id) {
1536000 / 20, // Update vu-meter at 20Hz
transmitter_model.channel_bandwidth(),
0, // Gain is unused
TONES_F2D(tone_key_frequency(tone_key_index), 1536000)
TONES_F2D(tone_key_frequency(tone_key_index), 1536000),
0, //AM
0, //DSB
0, //USB
0 //LSB
);
baseband::set_sample_rate(sample_rate);
@@ -130,6 +134,7 @@ void SoundBoardView::start_tx(const uint32_t id) {
}*/
void SoundBoardView::on_tx_progress(const uint32_t progress) {
(void)progress ; // avoid warning
//progressbar.set_value(progress);
}
@@ -28,9 +28,13 @@ namespace ui
console.writeln("\x1B\x06Mayhem:\x1B\x10");
console.writeln("eried,euquiq,gregoryfenton");
console.writeln("johnelder,jwetzell,nnemanjan00");
console.writeln("N0vaPixel,klockee,jamesshao8");
console.writeln("ITAxReal,rascafr,mcules");
console.writeln("dqs105,strijar");
console.writeln("N0vaPixel,klockee,GullCode");
console.writeln("jamesshao8,ITAxReal,rascafr");
console.writeln("mcules,dqs105,strijar");
console.writeln("zhang00963,RedFox-Fr,aldude999");
console.writeln("East2West,fossum,ArjanOnwezen");
console.writeln("vXxOinvizioNxX,teixeluis");
console.writeln("Brumi-2021,texasyojimbo");
console.writeln("");
break;
@@ -74,4 +78,4 @@ namespace ui
button_ok.focus();
}
} /* namespace ui */
} /* namespace ui */
+31 -13
View File
@@ -20,6 +20,8 @@
* Boston, MA 02110-1301, USA.
*/
#include <strings.h>
#include "ui_adsb_rx.hpp"
#include "ui_alphanum.hpp"
@@ -205,7 +207,7 @@ void ADSBRxView::on_frame(const ADSBFrameMessage * message) {
auto frame = message->frame;
uint32_t ICAO_address = frame.get_ICAO_address();
if (frame.check_CRC() && frame.get_ICAO_address()) {
if (frame.check_CRC() && ICAO_address) {
rtcGetTime(&RTCD1, &datetime);
auto& entry = ::on_packet(recent, ICAO_address);
frame.set_rx_timestamp(datetime.minute() * 60 + datetime.second());
@@ -222,33 +224,49 @@ void ADSBRxView::on_frame(const ADSBFrameMessage * message) {
uint8_t msg_sub = frame.get_msg_sub();
uint8_t * raw_data = frame.get_raw_data();
if ((msg_type >= 1) && (msg_type <= 4)) {
if ((msg_type >= AIRCRAFT_ID_L) && (msg_type <= AIRCRAFT_ID_H)) {
callsign = decode_frame_id(frame);
entry.set_callsign(callsign);
logentry+=callsign+" ";
} else if (((msg_type >= 9) && (msg_type <= 18)) || ((msg_type >= 20) && (msg_type <= 22))) {
}
//
else if (((msg_type >= AIRBORNE_POS_BARO_L) && (msg_type <= AIRBORNE_POS_BARO_H)) ||
((msg_type >= AIRBORNE_POS_GPS_L) && (msg_type <= AIRBORNE_POS_GPS_H))) {
entry.set_frame_pos(frame, raw_data[6] & 4);
if (entry.pos.valid) {
str_info = "Alt:" + to_string_dec_int(entry.pos.altitude) +
" Lat:" + to_string_dec_int(entry.pos.latitude) +
"." + to_string_dec_int((int)abs(entry.pos.latitude * 1000) % 100, 2, '0') +
" Lon:" + to_string_dec_int(entry.pos.longitude) +
"." + to_string_dec_int((int)abs(entry.pos.longitude * 1000) % 100, 2, '0');
entry.set_info_string(str_info);
logentry+=str_info+ " ";
" Lat:" + to_string_decimal(entry.pos.latitude, 2) +
" Lon:" + to_string_decimal(entry.pos.longitude, 2);
if (send_updates)
// printing the coordinates in the log file with more
// resolution, as we are not constrained by screen
// real estate there:
std::string log_info = "Alt:" + to_string_dec_int(entry.pos.altitude) +
" Lat:" + to_string_decimal(entry.pos.latitude, 7) +
" Lon:" + to_string_decimal(entry.pos.longitude, 7);
entry.set_info_string(str_info);
logentry+=log_info + " ";
// we only want to update the details view if the frame
// we received has the same ICAO address, i.e. belongs to
// the same aircraft:
if(send_updates && details_view->get_current_entry().ICAO_address == ICAO_address) {
details_view->update(entry);
}
}
} else if(msg_type == 19 && msg_sub >= 1 && msg_sub <= 4){
} else if(msg_type == AIRBORNE_VEL && msg_sub >= VEL_GND_SUBSONIC && msg_sub <= VEL_AIR_SUPERSONIC){
entry.set_frame_velo(frame);
logentry += "Type:" + to_string_dec_uint(msg_sub) +
" Hdg:" + to_string_dec_uint(entry.velo.heading) +
" Spd: "+ to_string_dec_int(entry.velo.speed);
if (send_updates)
// same here:
if (send_updates && details_view->get_current_entry().ICAO_address == ICAO_address) {
details_view->update(entry);
}
}
}
recent_entries_view.set_dirty();
+31 -5
View File
@@ -36,9 +36,33 @@ using namespace adsb;
namespace ui {
#define ADSB_DECAY_A 10 // In seconds
#define ADSB_DECAY_B 30
#define ADSB_DECAY_C 60 // Can be used for removing old entries, RecentEntries already caps to 64
#define ADSB_DECAY_A 10 // In seconds
#define ADSB_DECAY_B 30
#define ADSB_DECAY_C 60 // Can be used for removing old entries, RecentEntries already caps to 64
#define AIRCRAFT_ID_L 1 // aircraft ID message type (lowest type id)
#define AIRCRAFT_ID_H 4 // aircraft ID message type (highest type id)
#define SURFACE_POS_L 5 // surface position (lowest type id)
#define SURFACE_POS_H 8 // surface position (highest type id)
#define AIRBORNE_POS_BARO_L 9 // airborne position (lowest type id)
#define AIRBORNE_POS_BARO_H 18 // airborne position (highest type id)
#define AIRBORNE_VEL 19 // airborne velocities
#define AIRBORNE_POS_GPS_L 20 // airborne position (lowest type id)
#define AIRBORNE_POS_GPS_H 22 // airborne position (highest type id)
#define RESERVED_L 23 // reserved for other uses
#define RESERVED_H 31 // reserved for other uses
#define VEL_GND_SUBSONIC 1
#define VEL_GND_SUPERSONIC 2
#define VEL_AIR_SUBSONIC 3
#define VEL_AIR_SUPERSONIC 4
#define O_E_FRAME_TIMEOUT 20 // timeout between odd and even frames
struct AircraftRecentEntry {
using Key = uint32_t;
@@ -49,7 +73,7 @@ struct AircraftRecentEntry {
uint16_t hits { 0 };
uint32_t age { 0 };
adsb_pos pos { false, 0, 0, 0 };
adsb_vel velo { false, 0, 999 };
adsb_vel velo { false, 0, 999, 0 };
ADSBFrame frame_pos_even { };
ADSBFrame frame_pos_odd { };
@@ -82,7 +106,7 @@ struct AircraftRecentEntry {
frame_pos_odd = frame;
if (!frame_pos_even.empty() && !frame_pos_odd.empty()) {
if (abs(frame_pos_even.get_rx_timestamp() - frame_pos_odd.get_rx_timestamp()) < 20)
if (abs(frame_pos_even.get_rx_timestamp() - frame_pos_odd.get_rx_timestamp()) < O_E_FRAME_TIMEOUT)
pos = decode_frame_pos(frame_pos_even, frame_pos_odd);
}
}
@@ -137,6 +161,8 @@ public:
void update(const AircraftRecentEntry& entry);
std::string title() const override { return "Details"; };
AircraftRecentEntry get_current_entry() { return entry_copy; }
private:
AircraftRecentEntry entry_copy { 0 };
+409
View File
@@ -0,0 +1,409 @@
/*
* Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
* Copyright (C) 2017 Furrtek
*
* This file is part of PortaPack.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#include "ui_aprs_rx.hpp"
#include "audio.hpp"
#include "rtc_time.hpp"
#include "baseband_api.hpp"
#include "string_format.hpp"
#include "portapack_persistent_memory.hpp"
using namespace portapack;
void APRSLogger::log_raw_data(const std::string& data) {
rtc::RTC datetime;
rtcGetTime(&RTCD1, &datetime);
log_file.write_entry(datetime, data);
}
namespace ui {
template<>
void RecentEntriesTable<APRSRecentEntries>::draw(
const Entry& entry,
const Rect& target_rect,
Painter& painter,
const Style& style
) {
char aged_color;
Color target_color;
// auto entry_age = entry.age;
target_color = Color::green();
aged_color = 0x10;
std::string entry_string = "\x1B";
entry_string += aged_color;
entry_string += entry.source_formatted;
entry_string.append(10 - entry.source_formatted.size(),' ');
entry_string += " ";
entry_string += (entry.hits <= 999 ? to_string_dec_uint(entry.hits, 4) : "999+");
entry_string += " ";
entry_string += entry.time_string;
painter.draw_string(
target_rect.location(),
style,
entry_string
);
if (entry.has_position){
painter.draw_bitmap(target_rect.location() + Point(12 * 8, 0), bitmap_target, target_color, style.background);
}
}
void APRSRxView::focus() {
options_region.focus();
}
void APRSRxView::update_freq(rf::Frequency f) {
receiver_model.set_tuning_frequency(f);
}
APRSRxView::APRSRxView(NavigationView& nav, Rect parent_rect) : View(parent_rect) {
baseband::run_image(portapack::spi_flash::image_tag_aprs_rx);
add_children({
&rssi,
&channel,
&field_rf_amp,
&field_lna,
&field_vga,
&options_region,
&field_frequency,
&record_view,
&console
});
// DEBUG
record_view.on_error = [&nav](std::string message) {
nav.display_modal("Error", message);
};
record_view.set_sampling_rate(24000);
options_region.on_change = [this](size_t, int32_t i) {
if (i == 0){
field_frequency.set_value(144390000);
}
if(i == 1){
field_frequency.set_value(144800000);
}
if(i == 2){
field_frequency.set_value(145175000);
}
};
field_frequency.set_value(receiver_model.tuning_frequency());
field_frequency.set_step(100);
field_frequency.on_change = [this](rf::Frequency f) {
update_freq(f);
};
field_frequency.on_edit = [this, &nav]() {
auto new_view = nav.push<FrequencyKeypadView>(receiver_model.tuning_frequency());
new_view->on_changed = [this](rf::Frequency f) {
update_freq(f);
field_frequency.set_value(f);
};
};
options_region.set_selected_index(0, true);
logger = std::make_unique<APRSLogger>();
if (logger)
logger->append("APRS_RX_LOG.TXT");
baseband::set_aprs(1200);
audio::set_rate(audio::Rate::Hz_24000);
audio::output::start();
receiver_model.set_sampling_rate(3072000);
receiver_model.set_baseband_bandwidth(1750000);
receiver_model.set_modulation(ReceiverModel::Mode::NarrowbandFMAudio);
receiver_model.enable();
}
void APRSRxView::on_packet(const APRSPacketMessage* message){
std::string str_console = "\x1B";
aprs::APRSPacket packet = message->packet;
std::string stream_text = packet.get_stream_text();
str_console += (char)((console_color++ & 3) + 9);
str_console += stream_text;
if(logger){
logger->log_raw_data(stream_text);
}
//if(reset_console){ //having more than one console causes issues when switching tabs where one is disabled, and the other enabled breaking the scoll setup.
// console.on_hide();
// console.on_show();
// reset_console = false;
//}
console.writeln(str_console);
}
void APRSRxView::on_data(uint32_t value, bool is_data) {
std::string str_console = "\x1B";
std::string str_byte = "";
if (is_data) {
// Colorize differently after message splits
str_console += (char)((console_color & 3) + 9);
if (value == '\n') {
// Message split
console.writeln("");
console_color++;
if (logger) {
logger->log_raw_data(str_log);
str_log = "";
}
}
else {
if ((value >= 32) && (value < 127)) {
str_console += (char)value; // Printable
str_byte += (char)value;
} else {
str_console += "[" + to_string_hex(value, 2) + "]"; // Not printable
str_byte += "[" + to_string_hex(value, 2) + "]";
}
console.write(str_console);
if (logger) str_log += str_byte;
}
} else {
}
}
void APRSRxView::on_show(){
//some bug where the display scroll area is set to the entire screen when switching from the list tab with details showing back to the stream view.
//reset_console = true;
}
APRSRxView::~APRSRxView() {
audio::output::stop();
receiver_model.disable();
baseband::shutdown();
}
void APRSTableView::on_show_list() {
details_view.hidden(true);
recent_entries_view.hidden(false);
send_updates = false;
focus();
}
void APRSTableView::on_show_detail(const APRSRecentEntry& entry) {
recent_entries_view.hidden(true);
details_view.hidden(false);
details_view.set_entry(entry);
details_view.update();
details_view.focus();
detailed_entry_key = entry.key();
send_updates = true;
}
APRSTableView::APRSTableView(NavigationView& nav, Rect parent_rec) : View(parent_rec), nav_ {nav} {
add_children({
&recent_entries_view,
&details_view
});
hidden(true);
details_view.hidden(true);
recent_entries_view.set_parent_rect({0, 0, 240, 280});
details_view.set_parent_rect({0, 0, 240, 280});
recent_entries_view.on_select = [this](const APRSRecentEntry& entry) {
this->on_show_detail(entry);
};
details_view.on_close = [this]() {
this->on_show_list();
};
/* for(size_t i = 0; i <32 ; i++){
std::string id = "test" + i;
auto& entry = ::on_packet(recent, i);
entry.set_source_formatted(id);
}
recent_entries_view.set_dirty(); */
/*
std::string str1 = "test1";
std::string str12 = "test2";
std::string str13 = "test2";
auto& entry = ::on_packet(recent, 0x1);
entry.set_source_formatted(str1);
auto& entry2 = ::on_packet(recent, 0x2);
entry2.set_source_formatted(str12);
auto& entry3 = ::on_packet(recent, 0x2);
entry2.set_source_formatted(str13);
recent_entries_view.set_dirty();
*/
}
void APRSTableView::on_pkt(const APRSPacketMessage* message){
aprs::APRSPacket packet = message->packet;
rtc::RTC datetime;
std::string str_timestamp;
std::string source_formatted = packet.get_source_formatted();
std::string info_string = packet.get_stream_text();
rtcGetTime(&RTCD1, &datetime);
auto& entry = ::on_packet(recent, packet.get_source());
entry.reset_age();
entry.inc_hit();
str_timestamp = to_string_datetime(datetime, HMS);
entry.set_time_string(str_timestamp);
entry.set_info_string(info_string);
entry.set_source_formatted(source_formatted);
if(entry.has_position && !packet.has_position()){
//maintain position info
}
else {
entry.set_has_position(packet.has_position());
entry.set_pos(packet.get_position());
}
if( entry.key() == details_view.entry().key() ) {
details_view.set_entry(entry);
details_view.update();
}
recent_entries_view.set_dirty();
}
void APRSTableView::on_show(){
on_show_list();
}
void APRSTableView::on_hide(){
details_view.hidden(true);
}
void APRSTableView::focus(){
recent_entries_view.focus();
}
APRSTableView::~APRSTableView(){
}
void APRSDetailsView::focus() {
button_done.focus();
}
void APRSDetailsView::set_entry(const APRSRecentEntry& entry){
entry_copy = entry;
}
void APRSDetailsView::update() {
if(!hidden()){
//uint32_t age = entry_copy.age;
console.clear(true);
console.write(entry_copy.info_string);
button_see_map.hidden(!entry_copy.has_position);
}
if (send_updates)
geomap_view->update_position(entry_copy.pos.latitude, entry_copy.pos.longitude, 0);
}
APRSDetailsView::~APRSDetailsView() {
}
APRSDetailsView::APRSDetailsView(
NavigationView& nav
)
{
add_children({
&console,
&button_done,
&button_see_map
});
button_done.on_select = [this, &nav](Button&) {
console.clear(true);
this->on_close();
};
button_see_map.on_select = [this, &nav](Button&) {
geomap_view = nav.push<GeoMapView>(
entry_copy.source_formatted,
0, //entry_copy.pos.altitude,
GeoPos::alt_unit::FEET,
entry_copy.pos.latitude,
entry_copy.pos.longitude,
0, /*entry_copy.velo.heading,*/
[this]() {
send_updates = false;
hidden(false);
update();
});
send_updates = true;
hidden(true);
};
};
APRSRXView::APRSRXView(NavigationView& nav) : nav_ {nav} {
add_children({
&tab_view,
&view_stream,
&view_table
});
}
void APRSRXView::focus(){
tab_view.focus();
}
APRSRXView::~APRSRXView() {
}
} /* namespace ui */
+276
View File
@@ -0,0 +1,276 @@
/*
* Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
* Copyright (C) 2017 Furrtek
*
* This file is part of PortaPack.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#ifndef __UI_APRS_RX_H__
#define __UI_APRS_RX_H__
#include "ui.hpp"
#include "ui_navigation.hpp"
#include "ui_receiver.hpp"
#include "ui_record_view.hpp" // DEBUG
#include "ui_geomap.hpp"
#include "recent_entries.hpp"
#include "ui_tabview.hpp"
#include "log_file.hpp"
#include "utility.hpp"
class APRSLogger {
public:
Optional<File::Error> append(const std::string& filename) {
return log_file.append(filename);
}
void log_raw_data(const std::string& data);
private:
LogFile log_file { };
};
namespace ui {
struct APRSRecentEntry {
using Key = uint64_t;
static constexpr Key invalid_key = 0xffffffffffffffff;
uint16_t hits { 0 };
uint32_t age { 0 };
uint64_t source;
std::string source_formatted { " " };
std::string time_string { "" };
std::string info_string { "" };
aprs::aprs_pos pos;
bool has_position = false;
APRSRecentEntry(uint64_t src)
{
source = src;
}
Key key() const {
return source;
}
void set_source_formatted(std::string& new_source) {
source_formatted = new_source;
}
void inc_hit() {
hits++;
}
void set_info_string(std::string& new_info_string) {
info_string = new_info_string;
}
void set_time_string(std::string& new_time_string) {
time_string = new_time_string;
}
void set_pos(aprs::aprs_pos pos_in){
pos = pos_in;
}
void set_has_position(bool has_pos){
has_position = has_pos;
}
void reset_age() {
age = 0;
}
void inc_age() {
age++;
}
};
class APRSDetailsView : public View {
public:
APRSDetailsView(NavigationView&);
~APRSDetailsView();
APRSDetailsView(const APRSDetailsView&) = delete;
APRSDetailsView(APRSDetailsView&&) = delete;
APRSDetailsView& operator=(const APRSDetailsView&) = delete;
APRSDetailsView& operator=(APRSDetailsView&&) = delete;
void focus() override;
void update();
void set_entry(const APRSRecentEntry& entry);
const APRSRecentEntry& entry() const { return entry_copy; };
std::string title() const override { return "Details"; };
std::function<void(void)> on_close { };
private:
APRSRecentEntry entry_copy { 0 };
GeoMapView* geomap_view { nullptr };
bool send_updates { false };
Console console {
{ 0, 0 * 16, 240, 224 }
};
Button button_done {
{ 160, 14 * 16, 8 * 8, 3 * 16 },
"Close"
};
Button button_see_map {
{ 80, 14 * 16, 8 * 8, 3 * 16 },
"Map"
};
};
using APRSRecentEntries = RecentEntries<APRSRecentEntry>;
class APRSTableView: public View {
public:
APRSTableView(NavigationView& nav, Rect parent_rec);
~APRSTableView();
void on_show() override;
void on_hide() override;
void focus() override;
void on_pkt(const APRSPacketMessage* message);
std::string title() const override { return "Stations"; };
private:
NavigationView& nav_;
const RecentEntriesColumns columns { {
{ "Source", 9 },
{ "Loc", 6 },
{ "Hits", 4 },
{ "Time", 8 }
} };
APRSRecentEntries recent { };
RecentEntriesView<RecentEntries<APRSRecentEntry>> recent_entries_view { columns, recent };
APRSDetailsView details_view { nav_ };
uint32_t detailed_entry_key { 0 };
bool send_updates { false };
void on_show_list();
void on_show_detail(const APRSRecentEntry& entry);
};
class APRSRxView : public View {
public:
APRSRxView(NavigationView& nav, Rect parent_rect);
~APRSRxView();
void on_show() override;
void focus() override;
std::string title() const override { return "APRS RX"; };
void on_packet(const APRSPacketMessage* message);
private:
void on_data(uint32_t value, bool is_data);
bool reset_console = false;
uint8_t console_color { 0 };
std::string str_log { "" };
RFAmpField field_rf_amp {
{ 13 * 8, 0 * 16 }
};
LNAGainField field_lna {
{ 15 * 8, 0 * 16 }
};
VGAGainField field_vga {
{ 18 * 8, 0 * 16 }
};
RSSI rssi {
{ 21 * 8, 0, 6 * 8, 4 },
};
Channel channel {
{ 21 * 8, 5, 6 * 8, 4 },
};
OptionsField options_region {
{ 0 * 8, 0 * 8 },
3,
{
{ "NA ", 0 },
{ "EUR", 1 },
{ "AUS", 2 }
}
};
FrequencyField field_frequency {
{ 3 * 8, 0 * 16 },
};
// DEBUG
RecordView record_view {
{ 0 * 8, 1 * 16, 30 * 8, 1 * 16 },
u"AFS_????", RecordView::FileType::WAV, 4096, 4
};
Console console {
{ 0, 2 * 16, 240, 240 }
};
void update_freq(rf::Frequency f);
std::unique_ptr<APRSLogger> logger { };
};
class APRSRXView : public View {
public:
APRSRXView(NavigationView& nav);
~APRSRXView();
void focus() override;
std::string title() const override { return "APRS RX"; };
private:
NavigationView& nav_;
Rect view_rect = { 0, 3 * 8, 240, 280 };
APRSRxView view_stream { nav_, view_rect };
APRSTableView view_table { nav_, view_rect };
TabView tab_view {
{ "Stream", Color::cyan(), &view_stream },
{ "List", Color::yellow(), &view_table }
};
MessageHandlerRegistration message_handler_packet {
Message::ID::APRSPacket,
[this](Message* const p) {
const auto message = static_cast<const APRSPacketMessage*>(p);
this->view_stream.on_packet(message);
this->view_table.on_pkt(message);
}
};
};
} /* namespace ui */
#endif/*__UI_APRS_RX_H__*/
+2 -1
View File
@@ -121,7 +121,8 @@ void TemperatureWidget::paint(Painter& painter) {
}
TemperatureWidget::temperature_t TemperatureWidget::temperature(const sample_t sensor_value) const {
return -35 + sensor_value * 4; //max2837 datasheet temp 25ºC has sensor value: 15
/*It seems to be a temperature difference of 25C*/
return -40 +(sensor_value * 4.31)+25; //max2837 datasheet temp 25ºC has sensor value: 15
}
std::string TemperatureWidget::temperature_str(const temperature_t temperature) const {
+1
View File
@@ -216,6 +216,7 @@ FileSaveView::FileSaveView(
}*/
void FileLoadView::refresh_widgets(const bool v) {
(void)v; //avoid unused warning
set_dirty();
}
+3
View File
@@ -48,6 +48,9 @@ FreqManBaseView::FreqManBaseView(
} else
error_ = ERROR_NOFILES;
// initialize
change_category(last_category_id);
// Default function
on_change_category = [this](int32_t category_id) {
change_category(category_id);
+5 -5
View File
@@ -64,7 +64,7 @@ protected:
OptionsField options_category {
{ 9 * 8, 4 },
12,
14,
{ }
};
@@ -103,19 +103,19 @@ private:
};
Labels labels {
{ { 2 * 8, 14 * 8 }, "Save as:", Color::white() }
{ { 1 * 8, 12 * 8 }, "Save as:", Color::white() }
};
Button button_save_name {
{ 2 * 8, 17 * 8, 14 * 8, 48 },
{ 1 * 8, 17 * 8, 12 * 8, 48 },
"Name (set)"
};
Button button_save_timestamp {
{ 2 * 8, 25 * 8, 14 * 8, 48 },
{ 1 * 8, 25 * 8, 12 * 8, 48 },
"Timestamp:"
};
LiveDateTime live_timestamp {
{ 17 * 8, 27 * 8, 11 * 8, 16 }
{ 14 * 8, 27 * 8, 16 * 8, 16 }
};
};
+61 -1
View File
@@ -274,6 +274,7 @@ void JammerView::start_tx() {
transmitter_model.enable();
baseband::set_jammer(true, (JammerType)options_type.selected_index(), options_speed.selected_index_value());
mscounter = 0; //euquiq: Reset internal ms counter for do_timer()
} else {
if (out_of_ranges)
nav_.display_modal("Error", "Jamming bandwidth too large.\nMust be less than 24MHz.");
@@ -289,6 +290,59 @@ void JammerView::stop_tx() {
radio::disable();
baseband::set_jammer(false, JammerType::TYPE_FSK, 0);
jamming = false;
cooling = false;
}
//called each 1/60th of second
void JammerView::on_timer() {
if (++mscounter == 60) {
mscounter = 0;
if (jamming)
{
if (cooling)
{
if (++seconds >= field_timepause.value())
{ //Re-start TX
transmitter_model.enable();
button_transmit.set_text("STOP");
baseband::set_jammer(true, (JammerType)options_type.selected_index(), options_speed.selected_index_value());
int32_t jitter_amount = field_jitter.value();
if (jitter_amount)
{
lfsr_v = lfsr_iterate(lfsr_v);
jitter_amount = (jitter_amount / 2) - (lfsr_v & jitter_amount);
mscounter += jitter_amount;
}
cooling = false;
seconds = 0;
}
}
else
{
if (++seconds >= field_timetx.value()) //Start cooling period:
{
transmitter_model.disable();
button_transmit.set_text("PAUSED");
baseband::set_jammer(false, JammerType::TYPE_FSK, 0);
int32_t jitter_amount = field_jitter.value();
if (jitter_amount)
{
lfsr_v = lfsr_iterate(lfsr_v);
jitter_amount = (jitter_amount / 2) - (lfsr_v & jitter_amount);
mscounter += jitter_amount;
}
cooling = true;
seconds = 0;
}
}
}
}
}
JammerView::JammerView(
@@ -309,6 +363,9 @@ JammerView::JammerView(
&text_range_total,
&options_speed,
&options_hop,
&field_timetx,
&field_timepause,
&field_jitter,
&button_transmit
});
@@ -321,8 +378,11 @@ JammerView::JammerView(
options_hop.set_selected_index(1); // 50ms
button_transmit.set_style(&style_val);
field_timetx.set_value(30);
field_timepause.set_value(1);
button_transmit.on_select = [this](Button&) {
if (jamming)
if (jamming || cooling)
stop_tx();
else
start_tx();
+61 -84
View File
@@ -28,6 +28,7 @@
#include "transmitter_model.hpp"
#include "message.hpp"
#include "jammer.hpp"
#include "lfsr_random.hpp"
using namespace jammer;
@@ -57,78 +58,11 @@ private:
.foreground = Color::grey(),
};
/*static constexpr jammer_range_t range_presets[] = {
// GSM900 Orange
{ true, 935000000, 945000000 }, // BW:10M
// GSM1800 Orange
{ true, 1808000000, 1832000000 }, // BW:24M
// GSM900 SFR
{ true, 950000000, 960000000 }, // BW:10M
// GSM1800 SFR
{ true, 1832000000, 1853000000 }, // BW:21M
// GSM900 Bouygues
{ true, 925000000, 935000000 }, // BW:10M
// GSM1800 Bouygues
{ true, 1858000000, 1880000000 }, // BW:22M
// GSM900 Free
{ true, 945000000, 950000000 }, // BW:5M
// GSM-R
{ true, 921000000, 925000000 }, // BW:4M
// DECT
{ true, 1880000000, 1900000000 }, // BW: 20MHz
// PMV AFSK
{ true, 162930000, 162970000 }, // BW: 40kHz
// ISM 433
{ true, 433050000, 434790000 }, // Center: 433.92MHz BW: 0.2%
// ISM 868
{ true, 868000000, 868200000 }, // Center: 868.2MHz BW: 40kHz
// GPS L1
{ true, 1575420000 - 500000, 1575420000 + 500000 }, // BW: 1MHz
// GPS L2
{ true, 1227600000 - 1000000, 1227600000 + 1000000 }, // BW: 2MHz
// WLAN 2.4G CH1
{ true, 2412000000 - 11000000, 2412000000 + 11000000}, // BW: 22MHz
// WLAN 2.4G CH2
{ true, 2417000000 - 11000000, 2417000000 + 11000000}, // BW: 22MHz
// WLAN 2.4G CH3
{ true, 2422000000 - 11000000, 2422000000 + 11000000}, // BW: 22MHz
// WLAN 2.4G CH4
{ true, 2427000000 - 11000000, 2427000000 + 11000000}, // BW: 22MHz
// WLAN 2.4G CH5
{ true, 2432000000 - 11000000, 2432000000 + 11000000}, // BW: 22MHz
// WLAN 2.4G CH6
{ true, 2437000000 - 11000000, 2437000000 + 11000000}, // BW: 22MHz
// WLAN 2.4G CH7
{ true, 2442000000 - 11000000, 2442000000 + 11000000}, // BW: 22MHz
// WLAN 2.4G CH8
{ true, 2447000000 - 11000000, 2447000000 + 11000000}, // BW: 22MHz
// WLAN 2.4G CH9
{ true, 2452000000 - 11000000, 2452000000 + 11000000}, // BW: 22MHz
// WLAN 2.4G CH10
{ true, 2457000000 - 11000000, 2457000000 + 11000000}, // BW: 22MHz
// WLAN 2.4G CH11
{ true, 2462000000 - 11000000, 2462000000 + 11000000}, // BW: 22MHz
// WLAN 2.4G CH12
{ true, 2467000000 - 11000000, 2467000000 + 11000000}, // BW: 22MHz
// WLAN 2.4G CH13
{ true, 2472000000 - 11000000, 2472000000 + 11000000}, // BW: 22MHz
};*/
Labels labels {
{ { 2 * 8, 9 * 8 + 4 }, "Start", Color::light_grey() },
{ { 23 * 8, 9 * 8 + 4 }, "Stop", Color::light_grey() },
{ { 12 * 8, 6 * 8 }, "Center", Color::light_grey() },
{ { 12 * 8 + 4, 14 * 8 }, "Width", Color::light_grey() }
{ { 2 * 8, 8 * 8 + 4 }, "Start", Color::light_grey() },
{ { 23 * 8, 8 * 8 + 4 }, "Stop", Color::light_grey() },
{ { 12 * 8, 5 * 8 - 4}, "Center", Color::light_grey() },
{ { 12 * 8 + 4, 13 * 8 }, "Width", Color::light_grey() }
};
Checkbox check_enabled {
@@ -143,19 +77,19 @@ private:
};
Button button_start {
{ 0 * 8, 6 * 16, 11 * 8, 28 },
{ 0 * 8, 11 * 8, 11 * 8, 28 },
""
};
Button button_stop {
{ 19 * 8, 6 * 16, 11 * 8, 28 },
{ 19 * 8, 11 * 8, 11 * 8, 28 },
""
};
Button button_center {
{ 76, 4 * 16, 11 * 8, 28 },
{ 76, 4 * 15 - 4, 11 * 8, 28 },
""
};
Button button_width {
{ 76, 8 * 16, 11 * 8, 28 },
{ 76, 8 * 15, 11 * 8, 28 },
""
};
};
@@ -178,12 +112,17 @@ private:
NavigationView& nav_;
void start_tx();
void on_timer();
void stop_tx();
void set_jammer_channel(uint32_t i, uint32_t width, uint64_t center, uint32_t duration);
void on_retune(const rf::Frequency freq, const uint32_t range);
JammerChannel * jammer_channels = (JammerChannel*)shared_memory.bb_data.data;
bool jamming { false };
bool cooling { false }; //euquiq: Indicates jammer in cooldown
uint16_t seconds = 0; //euquiq: seconds counter for toggling tx / cooldown
int16_t mscounter = 0; //euquiq: Internal ms counter for do_timer()
lfsr_word_t lfsr_v = 1; //euquiq: Used to generate "random" Jitter
static constexpr Style style_val {
.font = font::fixed_8x16,
@@ -209,13 +148,19 @@ private:
};
Labels labels {
{ { 3 * 8, 12 * 16 }, "Type:", Color::light_grey() },
{ { 2 * 8, 13 * 16 }, "Speed:", Color::light_grey() },
{ { 5 * 8, 14 * 16 }, "Hop:", Color::light_grey() }
{ { 2 * 8, 23 * 8 }, "Type:", Color::light_grey() },
{ { 1 * 8, 25 * 8 }, "Speed:", Color::light_grey() },
{ { 3 * 8, 27 * 8 }, "Hop:", Color::light_grey() },
{ { 4 * 8, 29 * 8 }, "TX:", Color::light_grey() },
{ { 1 * 8, 31 * 8 }, "Sle3p:", Color::light_grey() }, //euquiq: Token of appreciation to TheSle3p, which made this ehnancement a reality with his bounty.
{ { 0 * 8, 33 * 8 }, "Jitter:", Color::light_grey() }, //Maybe the repository curator can keep the "mystype" for some versions.
{ { 11 * 8, 29 * 8 }, "Secs.", Color::light_grey() },
{ { 11 * 8, 31 * 8 }, "Secs.", Color::light_grey() },
{ { 11 * 8, 33 * 8 }, "/60", Color::light_grey() }
};
OptionsField options_type {
{ 9 * 8, 12 * 16 },
{ 7 * 8, 23 * 8 },
8,
{
{ "Rand FSK", 0 },
@@ -226,16 +171,16 @@ private:
};
Text text_range_number {
{ 22 * 8, 12 * 16, 2 * 8, 16 },
{ 16 * 8, 23 * 8, 2 * 8, 16 },
"--"
};
Text text_range_total {
{ 24 * 8, 12 * 16, 3 * 8, 16 },
{ 18 * 8, 23 * 8, 3 * 8, 16 },
"/--"
};
OptionsField options_speed {
{ 9 * 8, 13 * 16 },
{ 7 * 8, 25 * 8 },
6,
{
{ "10Hz ", 10 },
@@ -247,7 +192,7 @@ private:
};
OptionsField options_hop {
{ 9 * 8, 14 * 16 },
{ 7 * 8, 27 * 8 },
5,
{
{ "10ms ", 1 },
@@ -259,9 +204,33 @@ private:
{ "10s ", 1000 }
}
};
NumberField field_timetx {
{ 7 * 8, 29 * 8 },
3,
{ 1, 180 },
1,
' ',
};
NumberField field_timepause {
{ 8 * 8, 31 * 8 },
2,
{ 1, 60 },
1,
' ',
};
NumberField field_jitter {
{ 8 * 8, 33 * 8 },
2,
{ 1, 60 },
1,
' ',
};
Button button_transmit {
{ 9 * 8, 16 * 16, 96, 48 },
{ 148, 212, 80, 80},
"START"
};
@@ -272,6 +241,14 @@ private:
this->on_retune(message->freq, message->range);
}
};
MessageHandlerRegistration message_handler_frame_sync {
Message::ID::DisplayFrameSync,
[this](const Message* const) {
this->on_timer();
}
};
};
} /* namespace ui */
@@ -100,7 +100,7 @@ void GlassView::on_channel_spectrum(const ChannelSpectrum &spectrum)
}
if (pixel_index)
f_center += SEARCH_SLICE_WIDTH; //Move into the next bandwidth slice NOTE: spectrum.sampling_rate = SEARCH_SLICE_WIDTH
f_center += LOOKING_GLASS_SLICE_WIDTH; //Move into the next bandwidth slice NOTE: spectrum.sampling_rate = LOOKING_GLASS_SLICE_WIDTH
else
f_center = f_center_ini; //Start a new sweep
@@ -143,8 +143,8 @@ void GlassView::on_range_changed()
else
field_marker.set_step(marker_step); //step needs to be a pixel wide.
f_center_ini = f_min + (SEARCH_SLICE_WIDTH / 2); //Initial center frequency for sweep
f_center_ini += SEARCH_SLICE_WIDTH; //euquiq: Why do I need to move the center ???!!! (shift needed for marker accuracy)
f_center_ini = f_min + (LOOKING_GLASS_SLICE_WIDTH / 2); //Initial center frequency for sweep
f_center_ini += LOOKING_GLASS_SLICE_WIDTH; //euquiq: Why do I need to move the center ???!!! (shift needed for marker accuracy)
PlotMarker(field_marker.value()); //Refresh marker on screen
@@ -153,20 +153,20 @@ void GlassView::on_range_changed()
max_power = 0;
bins_Hz_size = 0; //reset amount of Hz filled up by pixels
baseband::set_spectrum(SEARCH_SLICE_WIDTH, field_trigger.value());
baseband::set_spectrum(LOOKING_GLASS_SLICE_WIDTH, field_trigger.value());
receiver_model.set_tuning_frequency(f_center_ini); //tune rx for this slice
}
void GlassView::PlotMarker(rf::Frequency pos)
void GlassView::PlotMarker(rf::Frequency fpos)
{
pos = pos * MHZ_DIV;
int64_t pos = fpos * MHZ_DIV;
pos -= f_min;
pos = pos / marker_pixel_step; //Real pixel
portapack::display.fill_rectangle({0, 100, 240, 8}, Color::black()); //Clear old marker and whole marker rectangle btw
portapack::display.fill_rectangle({pos - 2, 100, 5, 3}, Color::red()); //Red marker middle
portapack::display.fill_rectangle({pos - 1, 103, 3, 3}, Color::red()); //Red marker middle
portapack::display.fill_rectangle({pos, 106, 1, 2}, Color::red()); //Red marker middle
portapack::display.fill_rectangle({(int16_t)pos - 2, 100, 5, 3}, Color::red()); //Red marker middle
portapack::display.fill_rectangle({(int16_t)pos - 1, 103, 3, 3}, Color::red()); //Red marker middle
portapack::display.fill_rectangle({(int16_t)pos, 106, 1, 2}, Color::red()); //Red marker middle
}
GlassView::GlassView(
@@ -216,10 +216,12 @@ GlassView::GlassView(
filter_config.set_selected_index(0);
filter_config.on_change = [this](size_t n, OptionsField::value_t v) {
(void)n;
min_color_power = v;
};
range_presets.on_change = [this](size_t n, OptionsField::value_t v) {
(void)n;
field_frequency_min.set_value(presets_db[v].min,false);
field_frequency_max.set_value(presets_db[v].max,false);
this->on_range_changed();
@@ -240,11 +242,11 @@ GlassView::GlassView(
field_trigger.set_value(32); //Defaults to 32, as normal triggering resolution
field_trigger.on_change = [this](int32_t v) {
baseband::set_spectrum(SEARCH_SLICE_WIDTH, v);
baseband::set_spectrum(LOOKING_GLASS_SLICE_WIDTH, v);
};
display.scroll_set_area( 109, 319);
baseband::set_spectrum(SEARCH_SLICE_WIDTH, field_trigger.value()); //trigger:
baseband::set_spectrum(LOOKING_GLASS_SLICE_WIDTH, field_trigger.value()); //trigger:
// Discord User jteich: WidebandSpectrum::on_message to set the trigger value. In WidebandSpectrum::execute ,
// it keeps adding the output of the fft to the buffer until "trigger" number of calls are made,
//at which time it pushes the buffer up with channel_spectrum.feed
@@ -252,8 +254,8 @@ GlassView::GlassView(
on_range_changed();
receiver_model.set_modulation(ReceiverModel::Mode::SpectrumAnalysis);
receiver_model.set_sampling_rate(SEARCH_SLICE_WIDTH); //20mhz
receiver_model.set_baseband_bandwidth(SEARCH_SLICE_WIDTH); // possible values: 1.75/2.5/3.5/5/5.5/6/7/8/9/10/12/14/15/20/24/28MHz
receiver_model.set_sampling_rate(LOOKING_GLASS_SLICE_WIDTH); //20mhz
receiver_model.set_baseband_bandwidth(LOOKING_GLASS_SLICE_WIDTH); // possible values: 1.75/2.5/3.5/5/5.5/6/7/8/9/10/12/14/15/20/24/28MHz
receiver_model.set_squelch_level(0);
receiver_model.enable();
}
@@ -33,7 +33,7 @@
namespace ui
{
#define SEARCH_SLICE_WIDTH 20000000 // Each slice bandwidth 20 MHz
#define LOOKING_GLASS_SLICE_WIDTH 20000000 // Each slice bandwidth 20 MHz
#define MHZ_DIV 1000000
#define X2_MHZ_DIV 2000000
@@ -41,6 +41,10 @@
{
public:
GlassView(NavigationView &nav);
GlassView( const GlassView &);
GlassView& operator=(const GlassView &nav);
~GlassView();
std::string title() const override { return "Looking Glass"; };
@@ -77,7 +81,7 @@
rf::Frequency f_center { 0 };
rf::Frequency f_center_ini { 0 };
rf::Frequency marker_pixel_step { 0 };
rf::Frequency each_bin_size { SEARCH_SLICE_WIDTH / 240 };
rf::Frequency each_bin_size { LOOKING_GLASS_SLICE_WIDTH / 240 };
rf::Frequency bins_Hz_size { 0 };
uint8_t min_color_power { 0 };
uint32_t pixel_index { 0 };
@@ -180,4 +184,4 @@
};
}
+77 -7
View File
@@ -65,8 +65,13 @@ void MicTXView::configure_baseband() {
sampling_rate / 20, // Update vu-meter at 20Hz
transmitting ? transmitter_model.channel_bandwidth() : 0,
mic_gain,
TONES_F2D(tone_key_frequency(tone_key_index), sampling_rate)
TONES_F2D(tone_key_frequency(tone_key_index), sampling_rate),
enable_am,
enable_dsb,
enable_usb,
enable_lsb
);
}
void MicTXView::set_tx(bool enable) {
@@ -143,8 +148,20 @@ void MicTXView::rxaudio(bool is_on) {
if (is_on) {
audio::input::stop();
baseband::shutdown();
baseband::run_image(portapack::spi_flash::image_tag_nfm_audio);
receiver_model.set_modulation(ReceiverModel::Mode::NarrowbandFMAudio);
if (enable_am || enable_usb || enable_lsb || enable_dsb) {
baseband::run_image(portapack::spi_flash::image_tag_am_audio);
receiver_model.set_modulation(ReceiverModel::Mode::AMAudio);
if (options_mode.selected_index() < 4)
receiver_model.set_am_configuration(options_mode.selected_index() - 1);
else
receiver_model.set_am_configuration(0);
}
else {
baseband::run_image(portapack::spi_flash::image_tag_nfm_audio);
receiver_model.set_modulation(ReceiverModel::Mode::NarrowbandFMAudio);
}
receiver_model.set_sampling_rate(3072000);
receiver_model.set_baseband_bandwidth(1750000);
// receiver_model.set_tuning_frequency(field_frequency.value()); //probably this too can be commented out.
@@ -155,15 +172,15 @@ void MicTXView::rxaudio(bool is_on) {
receiver_model.enable();
audio::output::start();
} else { //These incredibly convoluted steps are required for the vumeter to reappear when stopping RX.
receiver_model.set_modulation(ReceiverModel::Mode::NarrowbandFMAudio); //This fixes something with AM RX...
receiver_model.disable();
baseband::shutdown();
baseband::run_image(portapack::spi_flash::image_tag_mic_tx);
audio::input::start();
// transmitter_model.enable();
audio::output::stop();
audio::input::start();
portapack::pin_i2s0_rx_sda.mode(3);
// transmitting = false;
configure_baseband();
// transmitter_model.disable();
}
}
@@ -198,11 +215,13 @@ MicTXView::MicTXView(
&field_bw,
&field_rfgain,
&field_rfamp,
&options_mode,
&field_frequency,
&options_tone_key,
&check_rogerbeep,
&check_rxactive,
&field_volume,
&field_rxbw,
&field_squelch,
&field_rxfrequency,
&field_rxlna,
@@ -262,6 +281,42 @@ MicTXView::MicTXView(
};
field_rfamp.set_value(rf_amp ? 14 : 0);
options_mode.on_change = [this](size_t, int32_t v) {
enable_am = false;
enable_usb = false;
enable_lsb = false;
enable_dsb = false;
switch(v) {
case 0:
enable_am = false;
enable_usb = false;
enable_lsb = false;
enable_dsb = false;
field_bw.set_value(transmitter_model.channel_bandwidth() / 1000);
//if (rx_enabled)
rxaudio(rx_enabled); //Update now if we have RX audio on
break;
case 1:
enable_am = true;
rxaudio(rx_enabled); //Update now if we have RX audio on
break;
case 2:
enable_usb = true;
rxaudio(rx_enabled); //Update now if we have RX audio on
break;
case 3:
enable_lsb = true;
rxaudio(rx_enabled); //Update now if we have RX audio on
break;
case 4:
enable_dsb = true;
rxaudio(rx_enabled); //Update now if we have RX audio on
break;
}
//configure_baseband();
};
/*
check_va.on_select = [this](Checkbox&, bool v) {
va_enabled = v;
@@ -331,6 +386,21 @@ MicTXView::MicTXView(
field_volume.set_value((receiver_model.headphone_volume() - audio::headphone::volume_range().max).decibel() + 99);
field_volume.on_change = [this](int32_t v) { this->on_headphone_volume_changed(v); };
field_rxbw.on_change = [this](size_t, int32_t v) {
switch(v) {
case 0:
receiver_model.set_nbfm_configuration(0);
break;
case 1:
receiver_model.set_nbfm_configuration(1);
break;
case 2:
receiver_model.set_nbfm_configuration(2);
break;
}
};
field_rxbw.set_selected_index(2);
field_squelch.on_change = [this](int32_t v) {
receiver_model.set_squelch_level(100 - v);
};
+31 -1
View File
@@ -99,19 +99,27 @@ private:
int32_t focused_ui { 2 };
bool button_touch { false };
//AM TX Stuff
bool enable_am { false };
bool enable_dsb { false };
bool enable_usb { false };
bool enable_lsb { false };
Labels labels {
{ { 3 * 8, 1 * 8 }, "MIC. GAIN:", Color::light_grey() },
{ { 3 * 8, 3 * 8 }, "F:", Color::light_grey() },
{ { 15 * 8, 3 * 8 }, "BW: kHz", Color::light_grey() },
{ { 15 * 8, 3 * 8 }, "BW: FM kHz", Color::light_grey() },
{ { 3 * 8, 5 * 8 }, "GAIN:", Color::light_grey() },
{ {11 * 8, 5 * 8 }, "Amp:", Color::light_grey() },
{ { 18 * 8, (5 * 8) }, "Mode:", Color::light_grey() },
{ { 3 * 8, 8 * 8 }, "TX Activation:", Color::light_grey() },
{ { 4 * 8, 10 * 8 }, "LVL:", Color::light_grey() },
{ {12 * 8, 10 * 8 }, "ATT:", Color::light_grey() },
{ {20 * 8, 10 * 8 }, "DEC:", Color::light_grey() },
{ { 4 * 8, ( 13 * 8 ) - 2 }, "TONE KEY:", Color::light_grey() },
{ { 9 * 8, 23 * 8 }, "VOL:", Color::light_grey() },
{ {17 * 8, 23 * 8 }, "FM RXBW:", Color::light_grey() },
{ {17 * 8, 25 * 8 }, "SQ:", Color::light_grey() },
{ { 5 * 8, 25 * 8 }, "F:", Color::light_grey() },
{ { 5 * 8, 27 * 8 }, "LNA:", Color::light_grey()},
@@ -162,6 +170,18 @@ private:
14,
' '
};
OptionsField options_mode {
{ 24 * 8, 5 * 8 },
3,
{
{ "FM", 0 },
{ "AM", 1 },
{ "USB", 2 },
{ "LSB", 3 },
{ "DSB", 4 }
}
};
/*
Checkbox check_va {
{ 3 * 8, (10 * 8) - 4 },
@@ -231,6 +251,16 @@ private:
' ',
};
OptionsField field_rxbw {
{ 25 * 8, 23 * 8},
3,
{
{"8k5", 0},
{"11k", 1},
{"16k", 2}
}
};
NumberField field_squelch {
{ 20 * 8, 25 * 8 },
2,
+1
View File
@@ -226,6 +226,7 @@ MorseView::MorseView(
};
options_loop.on_change = [this](size_t i, uint32_t n) {
(void)i; //avoid unused warning
loop = n;
};
+13 -6
View File
@@ -172,7 +172,7 @@ void ScannerView::show_max() { //show total number of freqs to scan
ScannerView::ScannerView(
NavigationView& nav
) : nav_ { nav }
) : nav_ { nav } , loaded_file_name { "SCANNER" }
{
add_children({
&labels,
@@ -364,7 +364,7 @@ ScannerView::ScannerView(
big_display.set(frequency_list[current_index]); //After showing an error
}
else {
auto result = scanner_file.append(freq_file_path); //Second: append if it is not there
scanner_file.append(freq_file_path); //Second: append if it is not there
scanner_file.write_line(frequency_to_add + ",d=ADD FQ");
}
} else
@@ -409,7 +409,12 @@ void ScannerView::frequency_file_load(std::string file_name, bool stop_all_befor
case FM_2: def_step = 50000; break ;
case N_1: def_step = 25000; break ;
case N_2: def_step = 250000; break ;
case AIRBAND:def_step= 8330; break ;
case AIRBAND: def_step= 8330; break ;
case ERROR_STEP:
case STEP_DEF:
default:
def_step = step_mode.selected_index_value(); //Use def_step from manual selector
break ;
}
frequency_list.push_back(entry.frequency_a); //Store starting freq and description
description_list.push_back("R" + to_string_short_freq(entry.frequency_a)
@@ -435,7 +440,7 @@ void ScannerView::frequency_file_load(std::string file_name, bool stop_all_befor
}
else
{
loaded_file_name = 'SCANNER'; // back to the default frequency file
loaded_file_name = "SCANNER"; // back to the default frequency file
desc_cycle.set(" NO " + file_name + ".TXT FILE ..." );
}
audio::output::stop();
@@ -504,7 +509,9 @@ size_t ScannerView::change_mode(uint8_t new_mod) { //Before this, do a scan_thre
using option_t = std::pair<std::string, int32_t>;
using options_t = std::vector<option_t>;
options_t bw;
field_bw.on_change = [this](size_t n, OptionsField::value_t) { };
field_bw.on_change = [this](size_t n, OptionsField::value_t) {
(void)n; //avoid unused warning
};
switch (new_mod) {
case NFM: //bw 16k (2) default
@@ -556,4 +563,4 @@ void ScannerView::start_scan_thread() {
scan_thread = std::make_unique<ScannerThread>(frequency_list);
}
} /* namespace ui */
} /* namespace ui */
+6 -4
View File
@@ -212,12 +212,14 @@ private:
true
};
OptionsField options_snap {
{ 17 * 8, 15 * 8 },
7,
{
{ 17 * 8, 15 * 8 }, // Position
7, // Length
{ // Options
{ "25kHz ", 25000 },
{ "12.5kHz", 12500 },
{ "8.33kHz", 8333 }
{ "8.33kHz", 8333 },
{ "2.5kHz", 2500 },
{ "500Hz", 500 }
}
};
+17 -2
View File
@@ -155,7 +155,7 @@ SetRadioView::SetRadioView(
});
SetFrequencyCorrectionModel model {
static_cast<int8_t>(portapack::persistent_memory::correction_ppb() / 1000)
static_cast<int8_t>(portapack::persistent_memory::correction_ppb() / 1000) , 0
};
form_init(model);
@@ -285,15 +285,17 @@ SetUIView::SetUIView(NavigationView& nav) {
&checkbox_bloff,
&options_bloff,
&checkbox_showsplash,
&checkbox_showclock,
&options_clockformat,
&button_ok
});
checkbox_speaker.set_value(persistent_memory::config_speaker());
checkbox_showsplash.set_value(persistent_memory::config_splash());
checkbox_showclock.set_value(!persistent_memory::hide_clock());
//checkbox_login.set_value(persistent_memory::config_login());
uint32_t backlight_timer = persistent_memory::config_backlight_timer();
if (backlight_timer) {
checkbox_bloff.set_value(true);
options_bloff.set_by_value(backlight_timer);
@@ -301,6 +303,12 @@ SetUIView::SetUIView(NavigationView& nav) {
options_bloff.set_selected_index(0);
}
if (persistent_memory::clock_with_date()) {
options_clockformat.set_selected_index(1);
} else {
options_clockformat.set_selected_index(0);
}
checkbox_speaker.on_select = [this](Checkbox&, bool v) {
if (v) audio::output::speaker_mute(); //Just mute audio if speaker is disabled
@@ -316,7 +324,14 @@ SetUIView::SetUIView(NavigationView& nav) {
else
persistent_memory::set_config_backlight_timer(0);
if (checkbox_showclock.value()){
if (options_clockformat.selected_index() == 1)
persistent_memory::set_clock_with_date(true);
else
persistent_memory::set_clock_with_date(false);
}
persistent_memory::set_config_splash(checkbox_showsplash.value());
persistent_memory::set_clock_hidden(!checkbox_showclock.value());
//persistent_memory::set_config_login(checkbox_login.value());
nav.pop();
};
+23 -8
View File
@@ -51,8 +51,8 @@ public:
private:
Labels labels {
{ { 6 * 8, 7 * 16 }, "YYYY/MM/DD HH:MM:SS", Color::grey() },
{ { 10 * 8, 9 * 16 }, "/ / : :", Color::light_grey() }
{ { 6 * 8, 7 * 16 }, "YYYY-MM-DD HH:MM:SS", Color::grey() },
{ { 10 * 8, 9 * 16 }, "- - : :", Color::light_grey() }
};
NumberField field_year {
@@ -226,19 +226,19 @@ private:
};*/
Checkbox checkbox_speaker {
{ 3 * 8, 2 * 16 },
{ 3 * 8, 4 * 16 },
20,
"Hide H1 Speaker option"
};
Checkbox checkbox_bloff {
{ 3 * 8, 5 * 16 },
{ 3 * 8, 6 * 16 },
20,
"Backlight off after:"
};
OptionsField options_bloff {
{ 52, 6 * 16 + 8 },
10,
{ 52, 7 * 16 + 8 },
20,
{
{ "5 seconds", 5 },
{ "15 seconds", 15 },
@@ -252,10 +252,25 @@ private:
Checkbox checkbox_showsplash {
{ 3 * 8, 9 * 16 },
11,
20,
"Show splash"
};
Checkbox checkbox_showclock {
{ 3 * 8, 11 * 16 },
20,
"Show clock with:"
};
OptionsField options_clockformat {
{ 52, 12 * 16 + 8 },
20,
{
{ "time only", 0 },
{ "time and date", 1 }
}
};
Button button_ok {
{ 2 * 8, 16 * 16, 12 * 8, 32 },
"Save"
+47 -3
View File
@@ -22,6 +22,7 @@
#include "ui_sonde.hpp"
#include "baseband_api.hpp"
#include "audio.hpp"
#include "portapack.hpp"
#include <cstring>
@@ -50,6 +51,8 @@ SondeView::SondeView(NavigationView& nav) {
&field_lna,
&field_vga,
&rssi,
&field_volume,
&check_beep,
&check_log,
&check_crc,
&text_signature,
@@ -63,6 +66,9 @@ SondeView::SondeView(NavigationView& nav) {
&button_see_map
});
// start from the frequency currently stored in the receiver_model:
target_frequency_ = receiver_model.tuning_frequency();
field_frequency.set_value(target_frequency_);
field_frequency.set_step(500); //euquiq: was 10000, but we are using this for fine-tunning
field_frequency.on_change = [this](rf::Frequency f) {
@@ -80,6 +86,10 @@ SondeView::SondeView(NavigationView& nav) {
geopos.set_read_only(true);
check_beep.on_select = [this](Checkbox&, bool v) {
beep = v;
};
check_log.on_select = [this](Checkbox&, bool v) {
logging = v;
};
@@ -107,16 +117,37 @@ SondeView::SondeView(NavigationView& nav) {
gps_info.lon,
999); //set a dummy heading out of range to draw a cross...probably not ideal?
};
logger = std::make_unique<SondeLogger>();
if (logger)
logger->append(u"sonde.txt");
// initialize audio:
field_volume.set_value((receiver_model.headphone_volume() - audio::headphone::volume_range().max).decibel() + 99);
field_volume.on_change = [this](int32_t v) {
this->on_headphone_volume_changed(v);
};
audio::output::start();
audio::output::speaker_unmute();
// inject a PitchRSSIConfigureMessage in order to arm
// the pitch rssi events that will be used by the
// processor:
const PitchRSSIConfigureMessage message { true, 0 };
shared_memory.application_queue.push(message);
baseband::set_pitch_rssi(0, true);
}
SondeView::~SondeView() {
baseband::set_pitch_rssi(0, false);
radio::disable();
baseband::shutdown();
audio::output::stop();
}
void SondeView::focus() {
@@ -156,18 +187,31 @@ void SondeView::on_packet(const sonde::Packet &packet)
}
gps_info = packet.get_GPS_data();
geopos.set_altitude(gps_info.alt);
geopos.set_lat(gps_info.lat);
geopos.set_lon(gps_info.lon);
if (logger && logging)
if (logger && logging) {
logger->on_packet(packet);
}
if(beep) {
baseband::request_beep();
}
}
}
void SondeView::on_headphone_volume_changed(int32_t v) {
const auto new_volume = volume_t::decibel(v - 99) + audio::headphone::volume_range().max;
receiver_model.set_headphone_volume(new_volume);
}
void SondeView::set_target_frequency(const uint32_t new_value) {
target_frequency_ = new_value;
radio::set_tuning_frequency(tuning_frequency());
//radio::set_tuning_frequency(tuning_frequency());
// we better remember the tuned frequency, by using this function instead:
receiver_model.set_tuning_frequency(target_frequency_);
}
uint32_t SondeView::tuning_frequency() const {
+28 -6
View File
@@ -55,7 +55,7 @@ class SondeView : public View {
public:
static constexpr uint32_t sampling_rate = 2457600;
static constexpr uint32_t baseband_bandwidth = 1750000;
SondeView(NavigationView& nav);
~SondeView();
@@ -68,10 +68,14 @@ private:
uint32_t target_frequency_ { 402700000 };
bool logging { false };
bool use_crc { false };
sonde::GPS_data gps_info;
sonde::temp_humid temp_humid_info;
std::string sonde_id;
bool beep { false };
sonde::GPS_data gps_info { };
sonde::temp_humid temp_humid_info { };
std::string sonde_id { };
// AudioOutput audio_output { };
Labels labels {
{ { 4 * 8, 2 * 16 }, "Type:", Color::light_grey() },
{ { 6 * 8, 3 * 16 }, "ID:", Color::light_grey() },
@@ -103,14 +107,29 @@ private:
{ 21 * 8, 0, 6 * 8, 4 },
};
NumberField field_volume {
{ 28 * 8, 0 * 16 },
2,
{ 0, 99 },
1,
' ',
};
Checkbox check_beep {
{ 22 * 8, 6 * 16 },
3,
"Beep"
};
Checkbox check_log {
{ 23 * 8, 6 * 16 },
{ 22 * 8, 8 * 16 },
3,
"Log"
};
Checkbox check_crc {
{ 23 * 8, 8 * 16 },
{ 22 * 8, 10 * 16 },
3,
"CRC"
};
@@ -170,7 +189,10 @@ private:
};
void on_packet(const sonde::Packet& packet);
void on_headphone_volume_changed(int32_t v);
void set_target_frequency(const uint32_t new_value);
uint32_t tuning_frequency() const;
};
+14 -2
View File
@@ -130,6 +130,13 @@ void set_afsk(const uint32_t baudrate, const uint32_t word_length, const uint32_
send_message(&message);
}
void set_aprs(const uint32_t baudrate) {
const APRSRxConfigureMessage message {
baudrate
};
send_message(&message);
}
void set_btle(const uint32_t baudrate, const uint32_t word_length, const uint32_t trigger_value, const bool trigger_word) {
const BTLERxConfigureMessage message {
baudrate,
@@ -176,13 +183,18 @@ void kill_afsk() {
}
void set_audiotx_config(const uint32_t divider, const float deviation_hz, const float audio_gain,
const uint32_t tone_key_delta) {
const uint32_t tone_key_delta, const bool am_enabled, const bool dsb_enabled,
const bool usb_enabled, const bool lsb_enabled) {
const AudioTXConfigMessage message {
divider,
deviation_hz,
audio_gain,
tone_key_delta,
(float)persistent_memory::tone_mix() / 100.0f
(float)persistent_memory::tone_mix() / 100.0f,
am_enabled,
dsb_enabled,
usb_enabled,
lsb_enabled
};
send_message(&message);
}
+3 -1
View File
@@ -61,13 +61,15 @@ void set_tones_config(const uint32_t bw, const uint32_t pre_silence, const uint1
void kill_tone();
void set_sstv_data(const uint8_t vis_code, const uint32_t pixel_duration);
void set_audiotx_config(const uint32_t divider, const float deviation_hz, const float audio_gain,
const uint32_t tone_key_delta);
const uint32_t tone_key_delta, const bool am_enabled, const bool dsb_enabled,
const bool usb_enabled, const bool lsb_enabled);
void set_fifo_data(const int8_t * data);
void set_pitch_rssi(int32_t avg, bool enabled);
void set_afsk_data(const uint32_t afsk_samples_per_bit, const uint32_t afsk_phase_inc_mark, const uint32_t afsk_phase_inc_space,
const uint8_t afsk_repeat, const uint32_t afsk_bw, const uint8_t symbol_count);
void kill_afsk();
void set_afsk(const uint32_t baudrate, const uint32_t word_length, const uint32_t trigger_value, const bool trigger_word);
void set_aprs(const uint32_t baudrate);
void set_btle(const uint32_t baudrate, const uint32_t word_length, const uint32_t trigger_value, const bool trigger_word);
+4
View File
@@ -140,6 +140,9 @@ Continuous (Fox-oring)
#include "sd_card.hpp"
#include <string.h>
#include "rffc507x.hpp" /* c/m, avoiding initial short ON Ant_DC_Bias pulse, from cold reset */
rffc507x::RFFC507x first_if;
static void event_loop() {
ui::Context context;
@@ -160,6 +163,7 @@ static void event_loop() {
}
int main(void) {
first_if.init(); /* To avoid initial short Ant_DC_Bias pulse ,we need quick set up GP01_RFF507X =1 */
if( portapack::init() ) {
portapack::display.init();
+11 -8
View File
@@ -83,7 +83,7 @@ TransmitterModel transmitter_model;
TemperatureLogger temperature_logger;
bool antenna_bias { false };
uint8_t bl_tick_counter { 0 };
uint32_t bl_tick_counter { 0 };
void set_antenna_bias(const bool v) {
antenna_bias = v;
@@ -179,20 +179,23 @@ static PortaPackModel portapack_model() {
static Optional<PortaPackModel> model;
if( !model.is_valid() ) {
if( audio_codec_wm8731.detected() ) {
model = PortaPackModel::R1_20150901;
} else {
/*For the time being, it is impossible to distinguish the hardware of R1 and R2 from the software level*/
/*At this point, I2c is not ready.*/
//if( audio_codec_wm8731.detected() ) {
// model = PortaPackModel::R1_20150901;
//} else {
model = PortaPackModel::R2_20170522;
}
//}
}
return model.value();
}
static audio::Codec* portapack_audio_codec() {
return (portapack_model() == PortaPackModel::R2_20170522)
? static_cast<audio::Codec*>(&audio_codec_ak4951)
: static_cast<audio::Codec*>(&audio_codec_wm8731)
/* I2C ready OK, Automatic recognition of audio chip */
return (audio_codec_wm8731.detected())
? static_cast<audio::Codec*>(&audio_codec_wm8731)
: static_cast<audio::Codec*>(&audio_codec_ak4951)
;
}
+1 -1
View File
@@ -54,7 +54,7 @@ extern TransmitterModel transmitter_model;
extern bool speaker_mode;
void set_speaker_mode(const bool v);
extern uint8_t bl_tick_counter;
extern uint32_t bl_tick_counter;
extern bool antenna_bias;
extern TemperatureLogger temperature_logger;
+6 -8
View File
@@ -111,14 +111,12 @@ void set_direction(const rf::Direction new_direction) {
// Hack to fix the CPLD (clocking ?) bug: toggle CPLD SRAM overlay depending on new direction
// Use CPLD's EEPROM config when transmitting
// Use the SRAM overlay when receiving
if (direction != new_direction) {
if (new_direction == rf::Direction::Transmit) {
hackrf::cpld::init_from_eeprom();
} else {
if( !hackrf::cpld::load_sram() ) {
chSysHalt();
}
}
// teixeluis: undone "Hack to fix the CPLD (clocking ?) bug".
// Apparently with current CPLD code from the hackrf repo,
// toggling CPLD overlay should no longer be necessary:
if (direction != new_direction && new_direction == rf::Direction::Transmit) {
hackrf::cpld::init_from_eeprom();
}
direction = new_direction;
+8
View File
@@ -171,7 +171,11 @@ void ReceiverModel::enable() {
update_baseband_bandwidth();
update_sampling_rate();
update_modulation();
// TODO: would challenge if this should belong to the
// receiver_model namespace:
update_headphone_volume();
led_rx.on();
}
@@ -182,6 +186,10 @@ void ReceiverModel::disable() {
// TODO: Responsibility for enabling/disabling the radio is muddy.
// Some happens in ReceiverModel, some inside radio namespace.
radio::disable();
// TODO: we are doing this repeatedly in different levels of the
// call stack. Keeping it for now, but there seem to be too many
// redundant calls:
led_rx.off();
}
+19 -1
View File
@@ -179,6 +179,24 @@ public:
}
}
}
else if( event == ui::KeyEvent::Up ) {
if(selected_key == recent.front().key()){
return false;
}
else {
advance(-1);
return true;
}
}
else if( event == ui::KeyEvent::Down ) {
if( selected_key == recent.back().key()) {
return false;
}
else {
advance(1);
return true;
}
}
return false;
}
@@ -264,7 +282,7 @@ public:
// TODO: What happens here shouldn't matter if I do proper damage detection!
}
void on_focus() override {
void focus() override {
_table.focus();
}
+24 -7
View File
@@ -112,6 +112,23 @@ std::string to_string_dec_int(
return q;
}
std::string to_string_decimal(float decimal, int8_t precision) {
double integer_part;
double fractional_part;
std::string result;
fractional_part = modf(decimal, &integer_part) * pow(10, precision);
if (fractional_part < 0) {
fractional_part = -fractional_part;
}
result = to_string_dec_int(integer_part) + "." + to_string_dec_uint(fractional_part, precision, '0');
return result;
}
std::string to_string_short_freq(const uint64_t f) {
auto final_str = to_string_dec_int(f / 1000000,4) + "." + to_string_dec_int((f / 100) % 10000, 4, '0');
return final_str;
@@ -165,8 +182,8 @@ std::string to_string_datetime(const rtc::RTC& value, const TimeFormat format) {
std::string string { "" };
if (format == YMDHMS) {
string += to_string_dec_uint(value.year(), 4) + "/" +
to_string_dec_uint(value.month(), 2, '0') + "/" +
string += to_string_dec_uint(value.year(), 4) + "-" +
to_string_dec_uint(value.month(), 2, '0') + "-" +
to_string_dec_uint(value.day(), 2, '0') + " ";
}
@@ -189,11 +206,11 @@ std::string to_string_timestamp(const rtc::RTC& value) {
}
std::string to_string_FAT_timestamp(const FATTimestamp& timestamp) {
return to_string_dec_uint((timestamp.FAT_date >> 9) + 1980) + "/" +
to_string_dec_uint((timestamp.FAT_date >> 5) & 0xF, 2) + "/" +
to_string_dec_uint((timestamp.FAT_date & 0x1F), 2) + " " +
to_string_dec_uint((timestamp.FAT_time >> 11), 2) + ":" +
to_string_dec_uint((timestamp.FAT_time >> 5) & 0x3F, 2);
return to_string_dec_uint((timestamp.FAT_date >> 9) + 1980) + "-" +
to_string_dec_uint((timestamp.FAT_date >> 5) & 0xF, 2, '0') + "-" +
to_string_dec_uint((timestamp.FAT_date & 0x1F), 2, '0') + " " +
to_string_dec_uint((timestamp.FAT_time >> 11), 2, '0') + ":" +
to_string_dec_uint((timestamp.FAT_time >> 5) & 0x3F, 2, '0');
}
std::string unit_auto_scale(double n, const uint32_t base_nano, uint32_t precision) {
+2
View File
@@ -43,6 +43,8 @@ const char unit_prefix[7] { 'n', 'u', 'm', 0, 'k', 'M', 'G' };
std::string to_string_bin(const uint32_t n, const uint8_t l = 0);
std::string to_string_dec_uint(const uint32_t n, const int32_t l = 0, const char fill = ' ');
std::string to_string_dec_int(const int32_t n, const int32_t l = 0, const char fill = 0);
std::string to_string_decimal(float decimal, int8_t precision);
std::string to_string_hex(const uint64_t n, const int32_t l = 0);
std::string to_string_hex_array(uint8_t * const array, const int32_t l = 0);
+8 -11
View File
@@ -63,17 +63,9 @@ GeoPos::GeoPos(
const auto changed_fn = [this](int32_t) {
float lat_value = lat();
float lon_value = lon();
double integer_part;
double fractional_part;
fractional_part = modf(lat_value, &integer_part) * 100000;
if (fractional_part < 0)
fractional_part = -fractional_part;
text_lat_decimal.set(to_string_dec_int(integer_part) + "." + to_string_dec_uint(fractional_part, 5));
fractional_part = modf(lon_value, &integer_part) * 100000;
if (fractional_part < 0)
fractional_part = -fractional_part;
text_lon_decimal.set(to_string_dec_int(integer_part) + "." + to_string_dec_uint(fractional_part, 5));
text_lat_decimal.set(to_string_decimal(lat_value, 5));
text_lon_decimal.set(to_string_decimal(lon_value, 5));
if (on_change && report_change)
on_change(altitude(), lat_value, lon_value);
@@ -264,8 +256,13 @@ void GeoMapView::focus() {
void GeoMapView::update_position(float lat, float lon, uint16_t angle) {
lat_ = lat;
lon_ = lon;
// Stupid hack to avoid an event loop
geopos.set_report_change(false);
geopos.set_lat(lat_);
geopos.set_lon(lon_);
geopos.set_report_change(true);
geomap.set_angle(angle);
geomap.move(lon_, lat_);
geomap.set_dirty();
+2 -1
View File
@@ -75,8 +75,9 @@ void RSSI::paint(Painter& painter) {
Color::black()
);
if (pitch_rssi_enabled)
if (pitch_rssi_enabled) {
baseband::set_pitch_rssi((avg_ - raw_min) * 2000 / raw_delta, true);
}
}
void RSSI::set_pitch_rssi(bool enabled) {
+23 -32
View File
@@ -94,13 +94,16 @@ void FrequencyScale::set_spectrum_sampling_rate(const int new_sampling_rate) {
}
void FrequencyScale::set_channel_filter(
const int pass_frequency,
const int stop_frequency
const int low_frequency,
const int high_frequency,
const int transition
) {
if( (channel_filter_pass_frequency != pass_frequency) ||
(channel_filter_stop_frequency != stop_frequency) ) {
channel_filter_pass_frequency = pass_frequency;
channel_filter_stop_frequency = stop_frequency;
if( (channel_filter_low_frequency != low_frequency) ||
(channel_filter_high_frequency != high_frequency) ||
(channel_filter_transition != transition) ) {
channel_filter_low_frequency = low_frequency;
channel_filter_high_frequency = high_frequency;
channel_filter_transition = transition;
set_dirty();
}
}
@@ -184,41 +187,28 @@ void FrequencyScale::draw_frequency_ticks(Painter& painter, const Rect r) {
}
void FrequencyScale::draw_filter_ranges(Painter& painter, const Rect r) {
if( channel_filter_pass_frequency ) {
if( channel_filter_low_frequency != channel_filter_high_frequency ) {
const auto x_center = r.width() / 2;
const auto pass_offset = channel_filter_pass_frequency * spectrum_bins / spectrum_sampling_rate;
const auto stop_offset = channel_filter_stop_frequency * spectrum_bins / spectrum_sampling_rate;
const auto x_low = x_center + channel_filter_low_frequency * spectrum_bins / spectrum_sampling_rate;
const auto x_high = x_center + channel_filter_high_frequency * spectrum_bins / spectrum_sampling_rate;
const auto pass_x_lo = x_center - pass_offset;
const auto pass_x_hi = x_center + pass_offset;
if( channel_filter_transition ) {
const auto trans = channel_filter_transition * spectrum_bins / spectrum_sampling_rate;
if( channel_filter_stop_frequency ) {
const auto stop_x_lo = x_center - stop_offset;
const auto stop_x_hi = x_center + stop_offset;
const Rect r_stop_lo {
r.left() + stop_x_lo, r.bottom() - filter_band_height,
pass_x_lo - stop_x_lo, filter_band_height
const Rect r_all {
r.left() + x_low - trans, r.bottom() - filter_band_height,
x_high - x_low + trans*2, filter_band_height
};
painter.fill_rectangle(
r_stop_lo,
Color::yellow()
);
const Rect r_stop_hi {
r.left() + pass_x_hi, r.bottom() - filter_band_height,
stop_x_hi - pass_x_hi, filter_band_height
};
painter.fill_rectangle(
r_stop_hi,
r_all,
Color::yellow()
);
}
const Rect r_pass {
r.left() + pass_x_lo, r.bottom() - filter_band_height,
pass_x_hi - pass_x_lo, filter_band_height
r.left() + x_low, r.bottom() - filter_band_height,
x_high - x_low, filter_band_height
};
painter.fill_rectangle(
r_pass,
@@ -390,8 +380,9 @@ void WaterfallWidget::on_channel_spectrum(const ChannelSpectrum& spectrum) {
sampling_rate = spectrum.sampling_rate;
frequency_scale.set_spectrum_sampling_rate(sampling_rate);
frequency_scale.set_channel_filter(
spectrum.channel_filter_pass_frequency,
spectrum.channel_filter_stop_frequency
spectrum.channel_filter_low_frequency,
spectrum.channel_filter_high_frequency,
spectrum.channel_filter_transition
);
}
+4 -3
View File
@@ -82,7 +82,7 @@ public:
bool on_key(const KeyEvent key) override;
void set_spectrum_sampling_rate(const int new_sampling_rate);
void set_channel_filter(const int pass_frequency, const int stop_frequency);
void set_channel_filter(const int low_frequency, const int high_frequency, const int transition);
void paint(Painter& painter) override;
@@ -96,8 +96,9 @@ private:
SignalToken signal_token_tick_second { };
int spectrum_sampling_rate { 0 };
const int spectrum_bins = std::tuple_size<decltype(ChannelSpectrum::db)>::value;
int channel_filter_pass_frequency { 0 };
int channel_filter_stop_frequency { 0 };
int channel_filter_low_frequency { 0 };
int channel_filter_high_frequency { 0 };
int channel_filter_transition { 0 };
void clear();
void clear_background(Painter& painter, const Rect r);
@@ -103,6 +103,7 @@ void TransmitterView::set_transmitting(const bool transmitting) {
void TransmitterView::on_show() {
field_frequency.set_value(transmitter_model.tuning_frequency());
field_frequency_step.set_by_value(receiver_model.frequency_step());
field_gain.set_value(transmitter_model.tx_gain());
field_amp.set_value(transmitter_model.rf_amp() ? 14 : 0);
@@ -122,6 +123,7 @@ TransmitterView::TransmitterView(
add_children({
&field_frequency,
&field_frequency_step,
&text_gain,
&field_gain,
&button_start,
@@ -157,6 +159,10 @@ TransmitterView::TransmitterView(
if (on_edit_frequency)
on_edit_frequency();
};
field_frequency_step.on_change = [this](size_t, OptionsField::value_t v) {
this->field_frequency.set_step(v);
};
field_gain.on_change = [this](uint32_t tx_gain) {
on_tx_gain_changed(tx_gain);
+7 -3
View File
@@ -124,11 +124,11 @@ private:
};
Text text_bw {
{ 11 * 8, 1 * 8, 9 * 8, 1 * 16 },
"BW: kHz"
{ 18 * 8, 1 * 8, 3 * 8, 1 * 16 },
"kHz"
};
NumberField field_bw {
{ 14 * 8, 1 * 8 },
{ 15 * 8, 1 * 8 },
3,
{ 1, 150 },
1,
@@ -152,6 +152,10 @@ private:
{ 21 * 8, 1 * 8, 9 * 8, 32 },
"START"
};
FrequencyStepView field_frequency_step {
{ 10 * 8 - 4, 1 * 8 },
};
void on_tuning_frequency_changed(rf::Frequency f);
void on_channel_bandwidth_changed(uint32_t channel_bandwidth);
+1 -1
View File
@@ -182,7 +182,7 @@ void TVView::clear() {
/* TVWidget *******************************************************/
TVWidget::TVWidget(const bool cursor) {
TVWidget::TVWidget() {
add_children({
&tv_view,
&field_xcorr
+1 -1
View File
@@ -92,7 +92,7 @@ class TVWidget : public View {
public:
std::function<void(int32_t offset)> on_select { };
TVWidget(const bool cursor = false);
TVWidget();
TVWidget(const TVWidget&) = delete;
TVWidget(TVWidget&&) = delete;
+19 -5
View File
@@ -34,6 +34,7 @@
#include "ui_adsb_rx.hpp"
#include "ui_adsb_tx.hpp"
#include "ui_afsk_rx.hpp"
#include "ui_aprs_rx.hpp"
#include "ui_btle_rx.hpp"
#include "ui_nrf_rx.hpp"
#include "ui_aprs_tx.hpp"
@@ -67,7 +68,7 @@
#include "ui_view_wav.hpp"
#include "ui_whipcalc.hpp"
#include "acars_app.hpp"
//#include "acars_app.hpp"
#include "ais_app.hpp"
#include "analog_audio_app.hpp"
#include "analog_tv_app.hpp"
@@ -349,13 +350,21 @@ InformationView::InformationView(
});
version.set_style(&style_infobar);
ltime.set_hide_clock(portapack::persistent_memory::hide_clock());
ltime.set_style(&style_infobar);
ltime.set_seconds_enabled(true);
ltime.set_date_enabled(false);
ltime.set_date_enabled(portapack::persistent_memory::clock_with_date());
set_dirty();
}
void InformationView::refresh() {
ltime.set_hide_clock(portapack::persistent_memory::hide_clock());
ltime.set_seconds_enabled(true);
ltime.set_date_enabled(portapack::persistent_memory::clock_with_date());
}
/* Navigation ************************************************************/
bool NavigationView::is_top() const {
@@ -386,6 +395,7 @@ void NavigationView::pop() {
update_view();
}
}
void NavigationView::pop_modal() {
@@ -468,7 +478,8 @@ ReceiversMenuView::ReceiversMenuView(NavigationView& nav) {
{ "POCSAG", ui::Color::green(), &bitmap_icon_pocsag, [&nav](){ nav.push<POCSAGAppView>(); } },
{ "Radiosnde", ui::Color::green(), &bitmap_icon_sonde, [&nav](){ nav.push<SondeView>(); } },
{ "TPMS Cars", ui::Color::green(), &bitmap_icon_tpms, [&nav](){ nav.push<TPMSAppView>(); } },
/*{ "APRS", ui::Color::dark_grey(), &bitmap_icon_aprs, [&nav](){ nav.push<NotImplementedView>(); } },
{ "APRS", ui::Color::green(), &bitmap_icon_aprs, [&nav](){ nav.push<APRSRXView>(); } }
/*
{ "DMR", ui::Color::dark_grey(), &bitmap_icon_dmr, [&nav](){ nav.push<NotImplementedView>(); } },
{ "SIGFOX", ui::Color::dark_grey(), &bitmap_icon_fox, [&nav](){ nav.push<NotImplementedView>(); } }, // SIGFRXView
{ "LoRa", ui::Color::dark_grey(), &bitmap_icon_lora, [&nav](){ nav.push<NotImplementedView>(); } },
@@ -488,7 +499,7 @@ TransmittersMenuView::TransmittersMenuView(NavigationView& nav) {
{ "APRS", ui::Color::green(), &bitmap_icon_aprs, [&nav](){ nav.push<APRSTXView>(); } },
{ "BHT Xy/EP", ui::Color::green(), &bitmap_icon_bht, [&nav](){ nav.push<BHTView>(); } },
{ "GPS Sim", ui::Color::yellow(), &bitmap_icon_gps_sim, [&nav](){ nav.push<GpsSimAppView>(); } },
{ "Jammer", ui::Color::yellow(), &bitmap_icon_jammer, [&nav](){ nav.push<JammerView>(); } },
{ "Jammer", ui::Color::green(), &bitmap_icon_jammer, [&nav](){ nav.push<JammerView>(); } },
{ "Key fob", ui::Color::orange(), &bitmap_icon_keyfob, [&nav](){ nav.push<KeyfobView>(); } },
{ "LGE tool", ui::Color::yellow(), &bitmap_icon_lge, [&nav](){ nav.push<LGEView>(); } },
{ "Morse", ui::Color::green(), &bitmap_icon_morse, [&nav](){ nav.push<MorseView>(); } },
@@ -604,6 +615,7 @@ SystemView::SystemView(
}
else{
add_child(&info_view);
info_view.refresh();
}
this->status_view.set_back_enabled(!this->navigation_view.is_top());
@@ -625,7 +637,9 @@ SystemView::SystemView(
navigation_view.push<SystemMenuView>();
if (portapack::persistent_memory::config_splash())
{
navigation_view.push<BMPView>();
}
status_view.set_back_enabled(false);
status_view.set_title_image_enabled(true);
status_view.set_dirty();
+5 -3
View File
@@ -212,9 +212,9 @@ private:
class InformationView : public View {
public:
InformationView(NavigationView& nav);
void refresh();
private:
static constexpr auto version_string = "v1.3.0";
static constexpr auto version_string = "v1.4.1";
NavigationView& nav_;
Rectangle backdrop {
@@ -228,8 +228,10 @@ private:
};
LiveDateTime ltime {
{174, 0, 8 * 8, 16}
{86, 0, 19 * 8, 16}
};
};
class BMPView : public View {
+11
View File
@@ -113,6 +113,8 @@ set(CPPSRC
baseband_stats_collector.cpp
dsp_decimate.cpp
dsp_demodulate.cpp
dsp_hilbert.cpp
dsp_modulate.cpp
dsp_goertzel.cpp
matched_filter.cpp
spectrum_collector.cpp
@@ -125,6 +127,7 @@ set(CPPSRC
${COMMON}/dsp_fft.cpp
${COMMON}/dsp_fir_taps.cpp
${COMMON}/dsp_iir.cpp
${COMMON}/dsp_sos.cpp
fxpt_atan2.cpp
rssi.cpp
rssi_dma.cpp
@@ -312,6 +315,14 @@ set(MODE_CPPSRC
proc_afskrx.cpp
)
DeclareTargets(PAFR afskrx)
### APRS RX
set(MODE_CPPSRC
proc_aprsrx.cpp
)
DeclareTargets(PAPR aprsrx)
### NRF RX
set(MODE_CPPSRC
@@ -35,7 +35,7 @@ class ChannelStatsCollector {
public:
template<typename Callback>
void feed(const buffer_c16_t& src, Callback callback) {
auto src_p = src.p;
void *src_p = src.p;
while(src_p < &src.p[src.count]) {
const uint32_t sample = *__SIMD32(src_p)++;
const uint32_t mag_sq = __SMUAD(sample, sample);
+57
View File
@@ -0,0 +1,57 @@
/*
* Copyright (C) 2020 Belousov Oleg
*
* This file is part of PortaPack.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#include "dsp_hilbert.hpp"
#include "dsp_sos_config.hpp"
namespace dsp {
HilbertTransform::HilbertTransform() {
n = 0;
sos_i.configure(half_band_lpf_config);
sos_q.configure(half_band_lpf_config);
}
void HilbertTransform::execute(float in, float &out_i, float &out_q) {
float a = 0, b = 0;
switch (n) {
case 0: a = in; b = 0; break;
case 1: a = 0; b = -in; break;
case 2: a = -in; b = 0; break;
case 3: a = 0; b = in; break;
}
float i = sos_i.execute(a) * 2.0f;
float q = sos_q.execute(b) * 2.0f;
switch (n) {
case 0: out_i = i; out_q = q; break;
case 1: out_i = -q; out_q = i; break;
case 2: out_i = -i; out_q = -q; break;
case 3: out_i = q; out_q = -i; break;
}
n = (n + 1) % 4;
}
} /* namespace dsp */
+44
View File
@@ -0,0 +1,44 @@
/*
* Copyright (C) 2020 Belousov Oleg
*
* This file is part of PortaPack.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#ifndef __DSP_HILBERT_H__
#define __DSP_HILBERT_H__
#include "dsp_sos.hpp"
#include "dsp_types.hpp"
namespace dsp {
class HilbertTransform {
public:
HilbertTransform();
void execute(float in, float &out_i, float &out_q);
private:
uint8_t n = 0;
SOSFilter<5> sos_i;
SOSFilter<5> sos_q;
};
} /* namespace dsp */
#endif/*__DSP_HILBERT_H__*/
+137
View File
@@ -0,0 +1,137 @@
/*
* Copyright (C) 2020 Belousov Oleg
*
* This file is part of PortaPack.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#include "dsp_modulate.hpp"
#include "sine_table_int8.hpp"
namespace dsp {
namespace modulate {
Modulator::~Modulator() {
}
Mode Modulator::get_mode() {
return mode;
}
void Modulator::set_mode(Mode new_mode) {
mode = new_mode;
}
void Modulator::set_over(uint32_t new_over) {
over = new_over;
}
///
SSB::SSB() : hilbert() {
mode = Mode::LSB;
}
void SSB::execute(const buffer_s16_t& audio, const buffer_c8_t& buffer) {
int32_t sample = 0;
int8_t re = 0, im = 0;
for (size_t counter = 0; counter < buffer.count; counter++) {
if (counter % 128 == 0) {
float i = 0.0, q = 0.0;
sample = audio.p[counter / over] >> 2;
//switch (mode) {
//case Mode::LSB:
hilbert.execute(sample / 32768.0f, i, q);
//case Mode::USB: hilbert.execute(sample / 32768.0f, q, i);
//default: break;
//}
i *= 64.0f;
q *= 64.0f;
switch (mode) {
case Mode::LSB: re = q; im = i; break;
case Mode::USB: re = i; im = q; break;
default: re = 0; im = 0; break;
}
//re = q;
//im = i;
//break;
}
buffer.p[counter] = { re, im };
}
}
///
FM::FM() {
mode = Mode::FM;
}
void FM::set_fm_delta(uint32_t new_delta) {
fm_delta = new_delta;
}
void FM::execute(const buffer_s16_t& audio, const buffer_c8_t& buffer) {
int32_t sample = 0;
int8_t re, im;
for (size_t counter = 0; counter < buffer.count; counter++) {
if (counter % over == 0) {
sample = audio.p[counter / over] >> 8;
delta = sample * fm_delta;
}
phase += delta;
sphase = phase >> 24;
re = (sine_table_i8[(sphase + 64) & 255]);
im = (sine_table_i8[sphase]);
buffer.p[counter] = { re, im };
}
}
AM::AM() {
mode = Mode::AM;
}
void AM::execute(const buffer_s16_t& audio, const buffer_c8_t& buffer) {
int32_t sample = 0;
int8_t re = 0, im = 0;
float q = 0.0;
for (size_t counter = 0; counter < buffer.count; counter++) {
if (counter % 128 == 0) {
sample = audio.p[counter / over] >> 2;
}
q = sample / 32768.0f;
q *= 64.0f;
switch (mode) {
case Mode::AM: re = q + 20; im = q + 20; break;
case Mode::DSB: re = q; im = q; break;
default: break;
}
buffer.p[counter] = { re, im };
}
}
}
}
+96
View File
@@ -0,0 +1,96 @@
/*
* Copyright (C) 2020 Belousov Oleg
*
* This file is part of PortaPack.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#ifndef __DSP_MODULATE_H__
#define __DSP_MODULATE_H__
#include "dsp_types.hpp"
#include "dsp_hilbert.hpp"
namespace dsp {
namespace modulate {
enum class Mode {
None,
AM,
DSB,
LSB,
USB,
FM
};
///
class Modulator {
public:
virtual void execute(const buffer_s16_t& audio, const buffer_c8_t& buffer) = 0;
virtual ~Modulator();
Mode get_mode();
void set_mode(Mode new_mode);
void set_over(uint32_t new_over);
protected:
uint32_t over = 1;
Mode mode = Mode::None;
};
///
class SSB : public Modulator {
public:
SSB();
virtual void execute(const buffer_s16_t& audio, const buffer_c8_t& buffer);
private:
dsp::HilbertTransform hilbert;
};
///
class FM : public Modulator {
public:
FM();
virtual void execute(const buffer_s16_t& audio, const buffer_c8_t& buffer);
void set_fm_delta(uint32_t new_delta);
///
private:
uint32_t fm_delta { 0 };
uint32_t phase { 0 }, sphase { 0 };
int32_t sample { 0 }, delta { };
};
class AM : public Modulator {
public:
AM();
virtual void execute(const buffer_s16_t& audio, const buffer_c8_t& buffer);
};
} /* namespace modulate */
} /* namespace dsp */
#endif/*__DSP_MODULATE_H__*/
+5 -4
View File
@@ -35,7 +35,7 @@ void NarrowbandAMAudio::execute(const buffer_c8_t& buffer) {
const auto decim_0_out = decim_0.execute(buffer, dst_buffer);
const auto decim_1_out = decim_1.execute(decim_0_out, dst_buffer);
channel_spectrum.feed(decim_1_out, channel_filter_pass_f, channel_filter_stop_f);
channel_spectrum.feed(decim_1_out, channel_filter_low_f, channel_filter_high_f, channel_filter_transition);
const auto decim_2_out = decim_2.execute(decim_1_out, dst_buffer);
const auto channel_out = channel_filter.execute(decim_2_out, dst_buffer);
@@ -87,14 +87,15 @@ void NarrowbandAMAudio::configure(const AMConfigureMessage& message) {
constexpr size_t decim_2_output_fs = decim_2_input_fs / decim_2_decimation_factor;
constexpr size_t channel_filter_input_fs = decim_2_output_fs;
const size_t channel_filter_output_fs = channel_filter_input_fs / channel_filter_decimation_factor;
//const size_t channel_filter_output_fs = channel_filter_input_fs / channel_filter_decimation_factor;
decim_0.configure(message.decim_0_filter.taps, 33554432);
decim_1.configure(message.decim_1_filter.taps, 131072);
decim_2.configure(message.decim_2_filter.taps, decim_2_decimation_factor);
channel_filter.configure(message.channel_filter.taps, channel_filter_decimation_factor);
channel_filter_pass_f = message.channel_filter.pass_frequency_normalized * channel_filter_input_fs;
channel_filter_stop_f = message.channel_filter.stop_frequency_normalized * channel_filter_input_fs;
channel_filter_low_f = message.channel_filter.low_frequency_normalized * channel_filter_input_fs;
channel_filter_high_f = message.channel_filter.high_frequency_normalized * channel_filter_input_fs;
channel_filter_transition = message.channel_filter.transition_normalized * channel_filter_input_fs;
channel_spectrum.set_decimation_factor(1.0f);
modulation_ssb = (message.modulation == AMConfigureMessage::Modulation::SSB);
audio_output.configure(message.audio_hpf_config);
+3 -2
View File
@@ -64,8 +64,9 @@ private:
dsp::decimate::FIRC16xR16x32Decim8 decim_1 { };
dsp::decimate::FIRAndDecimateComplex decim_2 { };
dsp::decimate::FIRAndDecimateComplex channel_filter { };
uint32_t channel_filter_pass_f = 0;
uint32_t channel_filter_stop_f = 0;
int32_t channel_filter_low_f = 0;
int32_t channel_filter_high_f = 0;
int32_t channel_filter_transition = 0;
bool modulation_ssb = false;
dsp::demodulate::AM demod_am { };
+6 -4
View File
@@ -43,14 +43,15 @@ void WidebandFMAudio::execute(const buffer_c8_t& buffer) {
const buffer_c16_t buffer_c16 {spectrum.data(),spectrum.size(),buffer.sampling_rate};
channel_spectrum.feed(buffer_c16);
int8_t re, im;
int8_t mag;
int8_t re ;
//int8_t im;
//int8_t mag;
for (size_t i = 0; i < 128; i++)
{
re = buffer.p[i].real();
im = buffer.p[i].imag();
mag = __builtin_sqrtf((re * re) + (im * im)) ;
//im = buffer.p[i].imag();
//mag = __builtin_sqrtf((re * re) + (im * im)) ;
const unsigned int v = re + 127.0f; //timescope
audio_spectrum.db[i] = std::max(0U, std::min(255U, v));
}
@@ -75,6 +76,7 @@ void WidebandFMAudio::on_message(const Message* const message) {
}
void WidebandFMAudio::configure(const WFMConfigureMessage& message) {
(void)message; // avoid warning
configured = true;
}
+257
View File
@@ -0,0 +1,257 @@
/*
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
* Copyright (C) 2016 Furrtek
*
* This file is part of PortaPack.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#include "proc_aprsrx.hpp"
#include "portapack_shared_memory.hpp"
#include "event_m4.hpp"
#include "stdio.h"
void APRSRxProcessor::execute(const buffer_c8_t& buffer) {
// This is called at 3072000 / 2048 = 1500Hz
if (!configured) return;
// FM demodulation
const auto decim_0_out = decim_0.execute(buffer, dst_buffer); // 2048 / 8 = 256 (512 I/Q samples)
const auto decim_1_out = decim_1.execute(decim_0_out, dst_buffer); // 256 / 8 = 32 (64 I/Q samples)
const auto channel_out = channel_filter.execute(decim_1_out, dst_buffer); // 32 / 2 = 16 (32 I/Q samples)
feed_channel_stats(channel_out);
auto audio = demod.execute(channel_out, audio_buffer);
audio_output.write(audio);
// Audio signal processing
for (size_t c = 0; c < audio.count; c++) {
const int32_t sample_int = audio.p[c] * 32768.0f;
int32_t current_sample = __SSAT(sample_int, 16);
current_sample /= 128;
// Delay line put
delay_line[delay_line_index & 0x3F] = current_sample;
// Delay line get, and LPF
sample_mixed = (delay_line[(delay_line_index - (samples_per_bit/2)) & 0x3F] * current_sample) / 4;
sample_filtered = prev_mixed + sample_mixed + (prev_filtered / 2);
delay_line_index++;
prev_filtered = sample_filtered;
prev_mixed = sample_mixed;
// Slice
sample_bits <<= 1;
uint8_t bit = (sample_filtered < -20) ? 1 : 0;
sample_bits |= bit;
/*
int16_t scaled = bit == 1 ? 32767 : -32767;
if( stream ) {
const size_t bytes_to_write = sizeof(scaled) * 1;
const auto result = stream->write(&scaled, bytes_to_write);
}
*/
// Check for "clean" transition: either 0011 or 1100
if ((((sample_bits >> 2) ^ sample_bits) & 3) == 3) {
// Adjust phase
if (phase < 0x8000)
phase += 0x800; // Is this a proper value ?
else
phase -= 0x800;
}
phase += phase_inc;
if (phase >= 0x10000) {
phase &= 0xFFFF;
if (true) {
uint8_t bit;
if(__builtin_popcount(sample_bits & 0xFF) >= 0x05){
bit = 0x1;
}
else {
bit = 0x0;
}
if(parse_bit(bit)){
parse_packet();
}
}
}
}
}
void APRSRxProcessor::parse_packet(){
//validate crc
if(packet_buffer_size >= aprs::APRS_MIN_LENGTH){
uint16_t crc = 0xFFFF;
for(size_t i = 0; i < packet_buffer_size; i++){
uint8_t byte = packet_buffer[i];
crc = ((crc >> 8) ^ crc_ccitt_tab[(crc ^ byte) & 0xFF]) & 0xFFFF;
}
if(crc == 0xF0B8){
parse_ax25();
}
}
}
void APRSRxProcessor::parse_ax25(){
aprs_packet.clear();
aprs_packet.set_valid_checksum(true);
for(size_t i = 0; i < packet_buffer_size; i++){
aprs_packet.set(i, packet_buffer[i]);
}
APRSPacketMessage packet_message { aprs_packet };
shared_memory.application_queue.push(packet_message);
}
bool APRSRxProcessor::parse_bit(const uint8_t current_bit){
uint8_t decoded_bit = ~(current_bit ^ last_bit) & 0x1;
last_bit = current_bit;
//int16_t log = decoded_bit == 0 ? -32768 : 32767;
//if(stream){
// const size_t bytes_to_write = sizeof(log) * 1;
// const auto result = stream->write(&log, bytes_to_write);
//}
if(decoded_bit & 0x1){
if(ones_count < 8){
ones_count++;
}
}
else {
if(ones_count > 6){ //not valid
state = WAIT_FLAG;
current_byte = 0;
ones_count = 0;
byte_index = 0;
packet_buffer_size = 0;
return false;
}
else if(ones_count == 6){ //flag
bool done = false;
if(state == IN_FRAME){
done = true;
}
else {
packet_buffer_size = 0;
}
state = WAIT_FRAME;
current_byte = 0;
ones_count = 0;
byte_index = 0;
return done;
}
else if(ones_count == 5){ //bit stuff
ones_count = 0;
return false;
}
else {
ones_count = 0;
}
}
//store
current_byte = current_byte >> 1;
current_byte |= (decoded_bit == 0x1 ? 0x80 : 0x0);
byte_index++;
if(byte_index >= 8){
byte_index = 0;
if(state == WAIT_FRAME){
state = IN_FRAME;
}
if(state == IN_FRAME){
if(packet_buffer_size + 1 >= 256){
state = WAIT_FLAG;
current_byte = 0;
ones_count = 0;
byte_index = 0;
packet_buffer_size = 0;
return false;
}
packet_buffer[packet_buffer_size++] = current_byte;
}
}
return false;
}
void APRSRxProcessor::on_message(const Message* const message) {
if (message->id == Message::ID::APRSRxConfigure)
configure(*reinterpret_cast<const APRSRxConfigureMessage*>(message));
if(message->id == Message::ID::CaptureConfig)
capture_config(*reinterpret_cast<const CaptureConfigMessage*>(message));
}
void APRSRxProcessor::capture_config(const CaptureConfigMessage& message) {
if( message.config ) {
//stream = std::make_unique<StreamInput>(message.config);
audio_output.set_stream(std::make_unique<StreamInput>(message.config));
} else {
//stream.reset();
audio_output.set_stream(nullptr);
}
}
void APRSRxProcessor::configure(const APRSRxConfigureMessage& message) {
decim_0.configure(taps_11k0_decim_0.taps, 33554432);
decim_1.configure(taps_11k0_decim_1.taps, 131072);
channel_filter.configure(taps_11k0_channel.taps, 2);
demod.configure(audio_fs, 5000);
audio_output.configure(audio_24k_hpf_300hz_config, audio_24k_deemph_300_6_config, 0);
samples_per_bit = audio_fs / message.baudrate;
phase_inc = (0x10000 * message.baudrate) / audio_fs;
phase = 0;
// Delay line
delay_line_index = 0;
state = WAIT_FLAG;
configured = true;
}
int main() {
EventDispatcher event_dispatcher { std::make_unique<APRSRxProcessor>() };
event_dispatcher.run();
return 0;
}
+148
View File
@@ -0,0 +1,148 @@
/*
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
* Copyright (C) 2016 Furrtek
*
* This file is part of PortaPack.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#ifndef __PROC_APRSRX_H__
#define __PROC_APRSRX_H__
#include "baseband_processor.hpp"
#include "baseband_thread.hpp"
#include "rssi_thread.hpp"
#include "dsp_decimate.hpp"
#include "dsp_demodulate.hpp"
#include "stream_input.hpp"
#include "audio_output.hpp"
#include "fifo.hpp"
#include "message.hpp"
#include "aprs_packet.hpp"
static uint16_t crc_ccitt_tab[256] = {
0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
};
class APRSRxProcessor : public BasebandProcessor {
public:
void execute(const buffer_c8_t& buffer) override;
void on_message(const Message* const message) override;
private:
static constexpr size_t baseband_fs = 3072000;
static constexpr size_t audio_fs = baseband_fs / 8 / 8 / 2;
size_t samples_per_bit { };
enum State {
WAIT_FLAG,
WAIT_FRAME,
IN_FRAME
};
BasebandThread baseband_thread { baseband_fs, this, NORMALPRIO + 20, baseband::Direction::Receive };
RSSIThread rssi_thread { NORMALPRIO + 10 };
std::array<complex16_t, 512> dst { };
const buffer_c16_t dst_buffer {
dst.data(),
dst.size()
};
std::array<float, 32> audio { };
const buffer_f32_t audio_buffer {
audio.data(),
audio.size()
};
// Array size ok down to 375 bauds (24000 / 375)
std::array<int32_t, 64> delay_line { 0 };
dsp::decimate::FIRC8xR16x24FS4Decim8 decim_0 { };
dsp::decimate::FIRC16xR16x32Decim8 decim_1 { };
dsp::decimate::FIRAndDecimateComplex channel_filter { };
std::unique_ptr<StreamInput> stream { };
dsp::demodulate::FM demod { };
AudioOutput audio_output { };
State state { };
size_t delay_line_index { };
uint32_t bit_counter { 0 };
uint32_t word_bits { 0 };
uint32_t sample_bits { 0 };
uint32_t phase { }, phase_inc { };
int32_t sample_mixed { }, prev_mixed { }, sample_filtered { }, prev_filtered { };
uint8_t last_bit;
uint8_t ones_count = 0;
uint8_t current_byte = 0;
uint8_t byte_index = 0;
uint8_t packet_buffer[256];
size_t packet_buffer_size = 0;
bool configured { false };
bool wait_start { };
bool bit_value { };
aprs::APRSPacket aprs_packet;
void configure(const APRSRxConfigureMessage& message);
void capture_config(const CaptureConfigMessage& message);
void parse_packet();
bool parse_bit(const uint8_t bit);
void parse_ax25();
};
#endif/*__PROC_TPMS_H__*/
+1 -1
View File
@@ -50,7 +50,7 @@ private:
int32_t sample { 0 }, delta { };
int8_t re { 0 }, im { 0 };
size_t progress_interval_samples, progress_samples = 0;
size_t progress_interval_samples = 0 , progress_samples = 0;
bool configured { false };
uint32_t bytes_read { 0 };
+7 -7
View File
@@ -53,7 +53,6 @@ void BTLERxProcessor::execute(const buffer_c8_t& buffer) {
auto audio_oversampled = demod.execute(buffer_c16, work_audio_buffer);*/
// Audio signal processing
for (size_t c = 0; c < audio_oversampled.count; c++) {
int result;
/*const int32_t sample_int = audio_oversampled.p[c] * 32768.0f;
int32_t current_sample = __SSAT(sample_int, 16);
@@ -107,9 +106,9 @@ void BTLERxProcessor::execute(const buffer_c8_t& buffer) {
uint8_t packet_data[500];
int packet_length;
uint32_t packet_crc;
uint32_t calced_crc;
//uint32_t calced_crc; // NOTE: restore when CRC is passing
uint64_t packet_addr_l;
uint32_t result;
//uint32_t result; // NOTE: restore when CRC is passing
uint8_t crc[3];
uint8_t packet_header_arr[2];
@@ -255,21 +254,21 @@ void BTLERxProcessor::execute(const buffer_c8_t& buffer) {
counter = counter + 1;
}
for (v=0;v<3;v++) crc_result=(crc_result<<8)|crc[v];
calced_crc = crc_result;
//calced_crc = crc_result; // NOTE: restore when CRC is passing
packet_crc=0;
for (int c=0;c<3;c++) packet_crc=(packet_crc<<8)|packet_data[packet_length+2+c];
if (packet_addr_l==0x8E89BED6)
//if (packet_crc==calced_crc)
//if (packet_crc==calced_crc) // NOTE: restore when CRC is passing
{
uint8_t mac_data[6];
int counter = 0;
for (int i = 7; i >= 2; i--)
{
uint8_t byte_temp6 = (uint8_t) (((packet_data[i] * 0x0802LU & 0x22110LU) | (packet_data[i] * 0x8020LU & 0x88440LU)) * 0x10101LU >> 16);
//result = byte_temp6;
mac_data[counter] = byte_temp6;
//result = byte_temp6; // NOTE: restore when CRC is passing
mac_data[counter] = byte_temp6;
counter = counter + 1;
}
@@ -325,6 +324,7 @@ void BTLERxProcessor::on_message(const Message* const message) {
}
void BTLERxProcessor::configure(const BTLERxConfigureMessage& message) {
(void)message; //avoid warning
decim_0.configure(taps_200k_wfm_decim_0.taps, 33554432);
decim_1.configure(taps_200k_wfm_decim_1.taps, 131072);
demod.configure(audio_fs, 5000);
+9 -4
View File
@@ -44,7 +44,11 @@ void CaptureProcessor::execute(const buffer_c8_t& buffer) {
if( stream ) {
const size_t bytes_to_write = sizeof(*decimator_out.p) * decimator_out.count;
const auto result = stream->write(decimator_out.p, bytes_to_write);
const size_t written = stream->write(decimator_out.p, bytes_to_write);
if( written != bytes_to_write )
{
//TODO eventually report error somewhere
}
}
feed_channel_stats(channel);
@@ -52,7 +56,7 @@ void CaptureProcessor::execute(const buffer_c8_t& buffer) {
spectrum_samples += channel.count;
if( spectrum_samples >= spectrum_interval_samples ) {
spectrum_samples -= spectrum_interval_samples;
channel_spectrum.feed(channel, channel_filter_pass_f, channel_filter_stop_f);
channel_spectrum.feed(channel, channel_filter_low_f, channel_filter_high_f, channel_filter_transition);
}
}
@@ -85,8 +89,9 @@ void CaptureProcessor::samplerate_config(const SamplerateConfigMessage& message)
size_t decim_1_input_fs = decim_0_output_fs;
size_t decim_1_output_fs = decim_1_input_fs / decim_1.decimation_factor;
channel_filter_pass_f = taps_200k_decim_1.pass_frequency_normalized * decim_1_input_fs; // 162760.416666667
channel_filter_stop_f = taps_200k_decim_1.stop_frequency_normalized * decim_1_input_fs; // 337239.583333333
channel_filter_low_f = taps_200k_decim_1.low_frequency_normalized * decim_1_input_fs;
channel_filter_high_f = taps_200k_decim_1.high_frequency_normalized * decim_1_input_fs;
channel_filter_transition = taps_200k_decim_1.transition_normalized * decim_1_input_fs;
spectrum_interval_samples = decim_1_output_fs / spectrum_rate_hz;
spectrum_samples = 0;
+3 -2
View File
@@ -60,8 +60,9 @@ private:
dsp::decimate::FIRC8xR16x24FS4Decim4 decim_0 { };
dsp::decimate::FIRC16xR16x16Decim2 decim_1 { };
uint32_t channel_filter_pass_f = 0;
uint32_t channel_filter_stop_f = 0;
int32_t channel_filter_low_f = 0;
int32_t channel_filter_high_f = 0;
int32_t channel_filter_transition = 0;
std::unique_ptr<StreamInput> stream { };
+3 -2
View File
@@ -30,8 +30,9 @@
#include "utility.hpp"
ReplayProcessor::ReplayProcessor() {
channel_filter_pass_f = taps_200k_decim_1.pass_frequency_normalized * 1000000; // 162760.416666667
channel_filter_stop_f = taps_200k_decim_1.stop_frequency_normalized * 1000000; // 337239.583333333
channel_filter_low_f = taps_200k_decim_1.low_frequency_normalized * 1000000;
channel_filter_high_f = taps_200k_decim_1.high_frequency_normalized * 1000000;
channel_filter_transition = taps_200k_decim_1.transition_normalized * 1000000;
spectrum_samples = 0;
+3 -2
View File
@@ -55,8 +55,9 @@ private:
baseband_fs
};
uint32_t channel_filter_pass_f = 0;
uint32_t channel_filter_stop_f = 0;
int32_t channel_filter_low_f = 0;
int32_t channel_filter_high_f = 0;
int32_t channel_filter_transition = 0;
std::unique_ptr<StreamOutput> stream { };
+37 -1
View File
@@ -35,6 +35,7 @@ void MicTXProcessor::execute(const buffer_c8_t& buffer){
if (!configured) return;
audio_input.read_audio_buffer(audio_buffer);
modulator->execute(audio_buffer, buffer);
for (size_t i = 0; i < buffer.count; i++) {
@@ -70,6 +71,7 @@ void MicTXProcessor::execute(const buffer_c8_t& buffer){
sample = beep_gen.process(0);
}
/*
sample = tone_gen.process(sample);
// FM
@@ -87,6 +89,7 @@ void MicTXProcessor::execute(const buffer_c8_t& buffer){
}
buffer.p[i] = { re, im };
*/
}
}
@@ -96,7 +99,40 @@ void MicTXProcessor::on_message(const Message* const msg) {
switch(msg->id) {
case Message::ID::AudioTXConfig:
fm_delta = config_message.deviation_hz * (0xFFFFFFUL / baseband_fs);
if (fm_enabled) {
dsp::modulate::FM *fm = new dsp::modulate::FM();
fm->set_fm_delta(config_message.deviation_hz * (0xFFFFFFUL / baseband_fs));
modulator = fm;
}
if (usb_enabled) {
modulator = new dsp::modulate::SSB();
modulator->set_mode(dsp::modulate::Mode::USB);
}
if (lsb_enabled) {
modulator = new dsp::modulate::SSB();
modulator->set_mode(dsp::modulate::Mode::LSB);
}
if (am_enabled) {
modulator = new dsp::modulate::AM();
modulator->set_mode(dsp::modulate::Mode::AM);
}
if (dsb_enabled) {
modulator = new dsp::modulate::AM();
modulator->set_mode(dsp::modulate::Mode::DSB);
}
modulator->set_over(baseband_fs / 24000);
am_enabled = config_message.am_enabled;
usb_enabled = config_message.usb_enabled;
lsb_enabled = config_message.lsb_enabled;
dsb_enabled = config_message.dsb_enabled;
if (!am_enabled || !usb_enabled || !lsb_enabled || !dsb_enabled) {
fm_enabled = true;
}
audio_gain = config_message.audio_gain;
divider = config_message.divider;
+9 -1
View File
@@ -27,6 +27,7 @@
#include "baseband_thread.hpp"
#include "audio_input.hpp"
#include "tone_gen.hpp"
#include "dsp_modulate.hpp"
class MicTXProcessor : public BasebandProcessor {
public:
@@ -50,7 +51,14 @@ private:
AudioInput audio_input { };
ToneGen tone_gen { };
ToneGen beep_gen { };
dsp::modulate::Modulator *modulator;
bool am_enabled { false };
bool fm_enabled { true };
bool usb_enabled { false };
bool lsb_enabled { false };
bool dsb_enabled { false };
uint32_t divider { };
float audio_gain { };
uint64_t power_acc { 0 };
+4 -3
View File
@@ -39,7 +39,7 @@ void NarrowbandFMAudio::execute(const buffer_c8_t& buffer) {
const auto decim_0_out = decim_0.execute(buffer, dst_buffer);
const auto decim_1_out = decim_1.execute(decim_0_out, dst_buffer);
channel_spectrum.feed(decim_1_out, channel_filter_pass_f, channel_filter_stop_f);
channel_spectrum.feed(decim_1_out, channel_filter_low_f, channel_filter_high_f, channel_filter_transition);
const auto channel_out = channel_filter.execute(decim_1_out, dst_buffer);
@@ -145,8 +145,9 @@ void NarrowbandFMAudio::configure(const NBFMConfigureMessage& message) {
decim_1.configure(message.decim_1_filter.taps, 131072);
channel_filter.configure(message.channel_filter.taps, message.channel_decimation);
demod.configure(demod_input_fs, message.deviation);
channel_filter_pass_f = message.channel_filter.pass_frequency_normalized * channel_filter_input_fs;
channel_filter_stop_f = message.channel_filter.stop_frequency_normalized * channel_filter_input_fs;
channel_filter_low_f = message.channel_filter.low_frequency_normalized * channel_filter_input_fs;
channel_filter_high_f = message.channel_filter.high_frequency_normalized * channel_filter_input_fs;
channel_filter_transition = message.channel_filter.transition_normalized * channel_filter_input_fs;
channel_spectrum.set_decimation_factor(1.0f);
audio_output.configure(message.audio_hpf_config, message.audio_deemph_config, (float)message.squelch_level / 100.0);
+3 -2
View File
@@ -73,8 +73,9 @@ private:
dsp::decimate::FIRC8xR16x24FS4Decim8 decim_0 { };
dsp::decimate::FIRC16xR16x32Decim8 decim_1 { };
dsp::decimate::FIRAndDecimateComplex channel_filter { };
uint32_t channel_filter_pass_f = 0;
uint32_t channel_filter_stop_f = 0;
int32_t channel_filter_low_f = 0;
int32_t channel_filter_high_f = 0;
int32_t channel_filter_transition = 0;
// For CTCSS decoding
dsp::decimate::FIR64AndDecimateBy2Real ctcss_filter { };
+1 -4
View File
@@ -37,7 +37,6 @@ void NRFRxProcessor::execute(const buffer_c8_t& buffer) {
auto audio_oversampled = demod.execute(decim_0_out, work_audio_buffer);
// Audio signal processing
for (size_t c = 0; c < audio_oversampled.count; c++) {
int result;
int g_srate = 4; //4 for 250KPS
//int g_srate = 1; //1 for 1MPS, not working yet
int32_t current_sample = audio_oversampled.p[c]; //if I directly use this, some results can pass crc but not correct.
@@ -48,11 +47,8 @@ void NRFRxProcessor::execute(const buffer_c8_t& buffer) {
skipSamples = skipSamples - 1;
if (skipSamples<1)
{
int32_t threshold_tmp=0;
for (int c=0;c<8*g_srate;c++)
{
@@ -272,6 +268,7 @@ void NRFRxProcessor::on_message(const Message* const message) {
}
void NRFRxProcessor::configure(const NRFRxConfigureMessage& message) {
(void)message; //avoir unused warning
decim_0.configure(taps_200k_wfm_decim_0.taps, 33554432);
decim_1.configure(taps_200k_wfm_decim_1.taps, 131072);
demod.configure(audio_fs, 5000);
+1 -1
View File
@@ -95,7 +95,7 @@ private:
bool configured = false;
rx_states rx_state { WAITING };
pocsag::BitRate bitrate { pocsag::BitRate::FSK1200 };
bool phase;
bool phase = false ;
uint32_t codeword_count { 0 };
pocsag::POCSAGPacket packet { };
+4 -3
View File
@@ -29,8 +29,9 @@
#include "utility.hpp"
ReplayProcessor::ReplayProcessor() {
channel_filter_pass_f = taps_200k_decim_1.pass_frequency_normalized * 1000000; // 162760.416666667
channel_filter_stop_f = taps_200k_decim_1.stop_frequency_normalized * 1000000; // 337239.583333333
channel_filter_low_f = taps_200k_decim_1.low_frequency_normalized * 1000000;
channel_filter_high_f = taps_200k_decim_1.high_frequency_normalized * 1000000;
channel_filter_transition = taps_200k_decim_1.transition_normalized * 1000000;
spectrum_samples = 0;
@@ -70,7 +71,7 @@ void ReplayProcessor::execute(const buffer_c8_t& buffer) {
spectrum_samples += buffer.count;
if( spectrum_samples >= spectrum_interval_samples ) {
spectrum_samples -= spectrum_interval_samples;
channel_spectrum.feed(iq_buffer, channel_filter_pass_f, channel_filter_stop_f);
channel_spectrum.feed(iq_buffer, channel_filter_low_f, channel_filter_high_f, channel_filter_transition);
txprogress_message.progress = bytes_read; // Inform UI about progress
txprogress_message.done = false;
+3 -2
View File
@@ -54,8 +54,9 @@ private:
baseband_fs / 8
};
uint32_t channel_filter_pass_f = 0;
uint32_t channel_filter_stop_f = 0;
int32_t channel_filter_low_f = 0;
int32_t channel_filter_high_f = 0;
int32_t channel_filter_transition = 0;
std::unique_ptr<StreamOutput> stream { };
+94
View File
@@ -26,9 +26,16 @@
#include "event_m4.hpp"
#include "audio_output.hpp"
SondeProcessor::SondeProcessor() {
decim_0.configure(taps_11k0_decim_0.taps, 33554432);
decim_1.configure(taps_11k0_decim_1.taps, 131072);
audio_output.configure(false);
tone_gen.configure(BEEP_BASE_FREQ, 1.0, ToneGen::tone_type::sine, AUDIO_SAMPLE_RATE);
}
void SondeProcessor::execute(const buffer_c8_t& buffer) {
@@ -47,10 +54,97 @@ void SondeProcessor::execute(const buffer_c8_t& buffer) {
clock_recovery_fsk_4800(mf.get_output());
}
}
if(pitch_rssi_enabled) {
if(beep_play) {
// if we let the buffer underrun, for some reason
// once it starts looping it ignores zero (silence)
// samples, so we need to keep feeding the buffer
// and not be able to take advantage of the circular
// buffer loop:
//beep_play = false;
generate_beep();
}
if(silence_play) {
//silence_play = false;
generate_silence();
}
}
}
void SondeProcessor::on_message(const Message* const msg) {
switch(msg->id) {
case Message::ID::RequestSignal:
if ((*reinterpret_cast<const RequestSignalMessage*>(msg)).signal == RequestSignalMessage::Signal::BeepRequest) {
float rssi_ratio = (float) last_rssi / (float) RSSI_CEILING;
int beep_duration = 0;
if(rssi_ratio <= PROPORTIONAL_BEEP_THRES) {
beep_duration = BEEP_MIN_DURATION;
}
else if(rssi_ratio < 1) {
beep_duration = (int) rssi_ratio * BEEP_DURATION_RANGE + BEEP_MIN_DURATION;
}
else {
beep_duration = BEEP_DURATION_RANGE + BEEP_MIN_DURATION;
}
play_beep();
chThdSleepMilliseconds(beep_duration);
stop_beep();
}
break;
case Message::ID::PitchRSSIConfigure:
pitch_rssi_config(*reinterpret_cast<const PitchRSSIConfigureMessage*>(msg));
break;
default:
break;
}
}
void SondeProcessor::play_beep() {
beep_play = true;
silence_play = false;
}
void SondeProcessor::stop_beep() {
beep_play = false;
silence_play = true;
}
void SondeProcessor::generate_beep() {
// here we let the samples be created using the ToneGen class:
for(uint8_t i = 0; i < sizeof(audio_buffer.p); i++) {
audio_buffer.p[i] = (int16_t) ((tone_gen.process(0) >> 16) & 0x0000FFFF);
}
audio_output.write(audio_buffer);
}
void SondeProcessor::generate_silence() {
for(uint8_t i = 0; i < sizeof(audio_buffer.p); i++) {
audio_buffer.p[i] = 0;
}
audio_output.write(audio_buffer);
}
void SondeProcessor::pitch_rssi_config(const PitchRSSIConfigureMessage& message) {
pitch_rssi_enabled = message.enabled;
uint32_t freq = (int) ((float) message.rssi * (float) RSSI_PITCH_WEIGHT + (float) BEEP_BASE_FREQ);
last_rssi = message.rssi;
tone_gen.configure(freq, 1.0, ToneGen::tone_type::sine, AUDIO_SAMPLE_RATE);
}
int main() {
EventDispatcher event_dispatcher { std::make_unique<SondeProcessor>() };
event_dispatcher.run();
return 0;
}
+51 -2
View File
@@ -88,19 +88,51 @@
#include "message.hpp"
#include "portapack_shared_memory.hpp"
#include "audio_output.hpp"
#include "tone_gen.hpp"
#include "buffer.hpp"
#include <cstdint>
#include <cstddef>
#include <bitset>
#define BEEP_MIN_DURATION 60
#define BEEP_DURATION_RANGE 100
#define BEEP_BASE_FREQ 200
#define RSSI_CEILING 1000
#define PROPORTIONAL_BEEP_THRES 0.8
#define RSSI_PITCH_WEIGHT 0.5
#define AUDIO_SAMPLE_RATE 24000
class SondeProcessor : public BasebandProcessor {
public:
SondeProcessor();
void execute(const buffer_c8_t& buffer) override;
void on_message(const Message* const msg);
private:
static constexpr size_t baseband_fs = 2457600;
std::array<int16_t, 32> audio { };
const buffer_s16_t audio_buffer {
(int16_t*) audio.data(),
sizeof(audio) / sizeof(int16_t)
};
AudioOutput audio_output { };
bool beep_play { false };
bool silence_play { false };
bool pitch_rssi_enabled { false };
uint32_t last_rssi { 0 };
ToneGen tone_gen { };
BasebandThread baseband_thread { baseband_fs, this, NORMALPRIO + 20, baseband::Direction::Receive };
RSSIThread rssi_thread { NORMALPRIO + 10 };
@@ -149,6 +181,23 @@ private:
shared_memory.application_queue.push(message);
}
};
void play_beep();
void stop_beep();
/**
* Used for filling the audio buffer with the waveform
* generated by the ToneGen class:
*
*/
void generate_beep();
/**
* Used for filling the audio buffer with silence:
*/
void generate_silence();
void pitch_rssi_config(const PitchRSSIConfigureMessage& message);
};
#endif/*__PROC_ERT_H__*/
+4 -3
View File
@@ -43,7 +43,7 @@ void WidebandFMAudio::execute(const buffer_c8_t& buffer) {
spectrum_samples += channel.count;
if( spectrum_samples >= spectrum_interval_samples ) {
spectrum_samples -= spectrum_interval_samples;
channel_spectrum.feed(channel, channel_filter_pass_f, channel_filter_stop_f);
channel_spectrum.feed(channel, channel_filter_low_f, channel_filter_high_f, channel_filter_transition);
}
/* 384kHz complex<int16_t>[256]
@@ -169,8 +169,9 @@ void WidebandFMAudio::configure(const WFMConfigureMessage& message) {
decim_0.configure(message.decim_0_filter.taps, 33554432);
decim_1.configure(message.decim_1_filter.taps, 131072);
channel_filter_pass_f = message.decim_1_filter.pass_frequency_normalized * decim_1_input_fs;
channel_filter_stop_f = message.decim_1_filter.stop_frequency_normalized * decim_1_input_fs;
channel_filter_low_f = message.decim_1_filter.low_frequency_normalized * decim_1_input_fs;
channel_filter_high_f = message.decim_1_filter.high_frequency_normalized * decim_1_input_fs;
channel_filter_transition = message.decim_1_filter.transition_normalized * decim_1_input_fs;
demod.configure(demod_input_fs, message.deviation);
audio_filter.configure(message.audio_filter.taps);
audio_output.configure(message.audio_hpf_config, message.audio_deemph_config);
+3 -2
View File
@@ -67,8 +67,9 @@ private:
dsp::decimate::FIRC8xR16x24FS4Decim4 decim_0 { };
dsp::decimate::FIRC16xR16x16Decim2 decim_1 { };
uint32_t channel_filter_pass_f = 0;
uint32_t channel_filter_stop_f = 0;
int32_t channel_filter_low_f = 0;
int32_t channel_filter_high_f = 0;
int32_t channel_filter_transition = 0;
dsp::demodulate::FM demod { };
dsp::decimate::DecimateBy2CIC4Real audio_dec_1 { };
+1 -1
View File
@@ -53,7 +53,7 @@ void WidebandSpectrum::execute(const buffer_c8_t& buffer) {
};
channel_spectrum.feed(
buffer_c16,
0, 0
0, 0, 0
);
phase = 0;
} else {
+9 -6
View File
@@ -78,12 +78,14 @@ void SpectrumCollector::set_decimation_factor(
void SpectrumCollector::feed(
const buffer_c16_t& channel,
const uint32_t filter_pass_frequency,
const uint32_t filter_stop_frequency
const int32_t filter_low_frequency,
const int32_t filter_high_frequency,
const int32_t filter_transition
) {
// Called from baseband processing thread.
channel_filter_pass_frequency = filter_pass_frequency;
channel_filter_stop_frequency = filter_stop_frequency;
channel_filter_low_frequency = filter_low_frequency;
channel_filter_high_frequency = filter_high_frequency;
channel_filter_transition = filter_transition;
channel_spectrum_decimator.feed(
channel,
@@ -136,8 +138,9 @@ void SpectrumCollector::update() {
ChannelSpectrum spectrum;
spectrum.sampling_rate = channel_spectrum_sampling_rate;
spectrum.channel_filter_pass_frequency = channel_filter_pass_frequency;
spectrum.channel_filter_stop_frequency = channel_filter_stop_frequency;
spectrum.channel_filter_low_frequency = channel_filter_low_frequency;
spectrum.channel_filter_high_frequency = channel_filter_high_frequency;
spectrum.channel_filter_transition = channel_filter_transition;
for(size_t i=0; i<spectrum.db.size(); i++) {
const auto corrected_sample = spectrum_window_hamming_3(channel_spectrum, i);
const auto mag2 = magnitude_squared(corrected_sample * (1.0f / 32768.0f));
+6 -4
View File
@@ -40,8 +40,9 @@ public:
void feed(
const buffer_c16_t& channel,
const uint32_t filter_pass_frequency,
const uint32_t filter_stop_frequency
const int32_t filter_low_frequency,
const int32_t filter_high_frequency,
const int32_t filter_transition
);
private:
@@ -53,8 +54,9 @@ private:
bool streaming { false };
std::array<std::complex<float>, 256> channel_spectrum { };
uint32_t channel_spectrum_sampling_rate { 0 };
uint32_t channel_filter_pass_frequency { 0 };
uint32_t channel_filter_stop_frequency { 0 };
int32_t channel_filter_low_frequency { 0 };
int32_t channel_filter_high_frequency { 0 };
int32_t channel_filter_transition { 0 };
void post_message(const buffer_c16_t& data);
+41 -3
View File
@@ -23,18 +23,56 @@
#include "tone_gen.hpp"
#include "sine_table_int8.hpp"
int32_t ToneGen::tone_sine() {
int32_t tone_sample = sine_table_i8[tone_phase_] * 0x1000000;
tone_phase_ += delta_;
return tone_sample;
}
int32_t ToneGen::tone_square() {
int32_t tone_sample = 0;
if(tone_phase_ < (UINT32_MAX / 2)) {
tone_sample = INT32_MAX;
}
else {
tone_sample = INT32_MIN;
}
tone_phase_ += delta_;
return tone_sample;
}
void ToneGen::configure(const uint32_t delta, const float tone_mix_weight) {
delta_ = delta;
delta_ = (uint8_t) ((delta & 0xFF000000U) >> 24);
tone_mix_weight_ = tone_mix_weight;
input_mix_weight_ = 1.0 - tone_mix_weight;
current_tone_type_ = sine;
}
void ToneGen::configure(const uint32_t freq, const float tone_mix_weight, const tone_type tone_type, const uint32_t sample_rate) {
delta_ = (uint8_t) ((freq * sizeof(sine_table_i8)) / sample_rate);
tone_mix_weight_ = tone_mix_weight;
input_mix_weight_ = 1.0 - tone_mix_weight;
current_tone_type_ = tone_type;
}
int32_t ToneGen::process(const int32_t sample_in) {
if (!delta_)
return sample_in;
int32_t tone_sample = sine_table_i8[(tone_phase_ & 0xFF000000U) >> 24];
tone_phase_ += delta_;
int32_t tone_sample = 0;
if(current_tone_type_ == sine) {
tone_sample = tone_sine();
}
else if(current_tone_type_ == square) {
tone_sample = tone_square();
}
return (sample_in * input_mix_weight_) + (tone_sample * tone_mix_weight_);
}
+21 -4
View File
@@ -28,19 +28,36 @@
class ToneGen {
public:
enum tone_type { sine, square };
/*ToneGen(const size_t sample_rate
) : sample_rate_ { sample_rate }
{};*/
void configure(const uint32_t delta, const float tone_mix_weight);
void configure(const uint32_t freq, const float tone_mix_weight, const tone_type tone_type, const uint32_t sample_rate);
int32_t process(const int32_t sample_in);
private:
//size_t sample_rate_;
tone_type current_tone_type_ { sine };
float input_mix_weight_ { 1 };
float tone_mix_weight_ { 0 };
uint32_t delta_ { 0 };
uint32_t tone_phase_ { 0 };
uint8_t delta_ { 0 };
uint8_t tone_phase_ { 0 };
/**
* Generator function which selects every other sample from the reference sine waveform to the output sample:
*/
int32_t tone_sine();
/**
* Generator function for square waves:
*/
int32_t tone_square();
};
#endif
#endif /* __TONE_GEN_H__ */
-2
View File
@@ -88,11 +88,9 @@ void TvCollector::post_message(const buffer_c16_t& data) {
// Called from baseband processing thread.
float re, im;
float mag;
float max;
if( streaming && !channel_spectrum_request_update ) {
for(size_t i=0; i<256; i++)
{
const auto s = data.p[i];
re = (float)(data.p[i].real());
im = (float)(data.p[i].imag());
mag = __builtin_sqrtf((re * re) + (im * im)) ;
+1 -1
View File
@@ -119,7 +119,7 @@ void chSysInit(void) {
serve interrupts in its context while keeping the lowest energy saving
mode compatible with the system status.*/
chThdCreateStatic(_idle_thread_wa, sizeof(_idle_thread_wa), IDLEPRIO,
(tfunc_t)_idle_thread, NULL);
(void *)_idle_thread, NULL);
#endif
}
+28 -12
View File
@@ -141,7 +141,11 @@ float cpr_mod(float a, float b) {
return a - (b * floor(a / b));
}
int cpr_NL(float lat) {
int cpr_NL_precise(float lat) {
return (int) floor(2 * PI / acos(1 - ((1 - cos(PI / (2 * NZ))) / pow(cos(PI * lat / 180), 2))));
}
int cpr_NL_approx(float lat) {
if (lat < 0)
lat = -lat; // Symmetry
@@ -150,7 +154,19 @@ int cpr_NL(float lat) {
return 59 - c;
}
return 1;
return 1;
}
int cpr_NL(float lat) {
// TODO prove that the approximate function is good
// enough for the precision we need. Uncomment if
// that is true. No performance penalty was noticed
// from testing, but if you find it might be an issue,
// switch to cpr_NL_approx() instead:
//return cpr_NL_approx(lat);
return cpr_NL_precise(lat);
}
int cpr_N(float lat, int is_odd) {
@@ -185,18 +201,18 @@ void encode_frame_pos(ADSBFrame& frame, const uint32_t ICAO_address, const int32
// CPR encoding
// Info from: http://antena.fe.uni-lj.si/literatura/Razno/Avionika/modes/CPRencoding.pdf
delta_lat = 360.0 / ((4.0 * 15.0) - time_parity); // NZ = 15
yz = floor(131072.0 * (cpr_mod(latitude, delta_lat) / delta_lat) + 0.5);
rlat = delta_lat * ((yz / 131072.0) + floor(latitude / delta_lat));
delta_lat = 360.0 / ((4.0 * NZ) - time_parity); // NZ = 15
yz = floor(CPR_MAX_VALUE * (cpr_mod(latitude, delta_lat) / delta_lat) + 0.5);
rlat = delta_lat * ((yz / CPR_MAX_VALUE) + floor(latitude / delta_lat));
if ((cpr_NL(rlat) - time_parity) > 0)
delta_lon = 360.0 / cpr_N(rlat, time_parity);
else
delta_lon = 360.0;
xz = floor(131072.0 * (cpr_mod(longitude, delta_lon) / delta_lon) + 0.5);
xz = floor(CPR_MAX_VALUE * (cpr_mod(longitude, delta_lon) / delta_lon) + 0.5);
lat = cpr_mod(yz, 131072.0);
lon = cpr_mod(xz, 131072.0);
lat = cpr_mod(yz, CPR_MAX_VALUE);
lon = cpr_mod(xz, CPR_MAX_VALUE);
frame.push_byte((altitude_coded << 4) | ((uint32_t)time_parity << 2) | (lat >> 15)); // T = 0
frame.push_byte(lat >> 7);
@@ -258,7 +274,7 @@ adsb_pos decode_frame_pos(ADSBFrame& frame_even, ADSBFrame& frame_odd) {
// Compute longitude
if (time_even > time_odd) {
// Use even frame
// Use even frame2
ni = cpr_N(latE, 0);
Dlon = 360.0 / ni;
@@ -279,7 +295,7 @@ adsb_pos decode_frame_pos(ADSBFrame& frame_even, ADSBFrame& frame_odd) {
position.latitude = latO;
}
if (position.longitude > 180) position.longitude -= 360;
if (position.longitude >= 180) position.longitude -= 360;
position.valid = true;
@@ -319,14 +335,14 @@ void encode_frame_velo(ADSBFrame& frame, const uint32_t ICAO_address, const uint
// Decoding method from dump1090
adsb_vel decode_frame_velo(ADSBFrame& frame){
adsb_vel velo {false, 0, 0};
adsb_vel velo {false, 0, 0, 0};
uint8_t * frame_data = frame.get_raw_data();
uint8_t velo_type = frame.get_msg_sub();
if(velo_type >= 1 && velo_type <= 4){ //vertical rate is always present
velo.v_rate = (((frame_data[8] & 0x07 ) << 6) | ((frame_data[9]) >> 2) - 1) * 64;
velo.v_rate = (((frame_data[8] & 0x07 ) << 6) | ((frame_data[9] >> 2) - 1)) * 64;
if((frame_data[8] & 0x8) >> 3) velo.v_rate *= -1; //check v_rate sign
}
+4
View File
@@ -83,6 +83,10 @@ const float adsb_lat_lut[58] = {
86.53536998, 87.00000000
};
const float PI = 3.14159265358979323846;
const float NZ = 15.0;
void make_frame_adsb(ADSBFrame& frame, const uint32_t ICAO_address);
void encode_frame_id(ADSBFrame& frame, const uint32_t ICAO_address, const std::string& callsign);
+1 -1
View File
@@ -69,7 +69,7 @@ public:
}
uint8_t * get_raw_data() const {
return (uint8_t* const)raw_data;
return (uint8_t* )raw_data;
}
void make_CRC() {
+3
View File
@@ -42,6 +42,7 @@ struct DateTime {
template<size_t FieldSize, int32_t DegMax, uint32_t NAValue>
struct LatLonBase {
constexpr LatLonBase(
) : LatLonBase { raw_not_available }
{
@@ -58,6 +59,8 @@ struct LatLonBase {
) : raw_ { other.raw_ }
{
}
LatLonBase& operator=( const LatLonBase &)=default;
int32_t normalized() const {
return static_cast<int32_t>(raw() << sign_extend_shift) / (1 << sign_extend_shift);
+27
View File
@@ -0,0 +1,27 @@
/*
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
* Copyright (C) 2016 Furrtek
*
* This file is part of PortaPack.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#include "aprs_packet.hpp"
namespace aprs {
} /* namespace zwave */
+495
View File
@@ -0,0 +1,495 @@
/*
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
* Copyright (C) 2016 Furrtek
*
* This file is part of PortaPack.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#ifndef __APRS_PACKET_H__
#define __APRS_PACKET_H__
#include <cstdint>
#include <cstddef>
#include <cctype>
#include "baseband.hpp"
namespace aprs {
const int APRS_MIN_LENGTH = 18; //14 bytes address, control byte and pid. 2 CRC.
struct aprs_pos{
float latitude;
float longitude;
uint8_t symbol_code;
uint8_t sym_table_id;
};
enum ADDRESS_TYPE {
SOURCE,
DESTINATION,
REPEATER
};
class APRSPacket {
public:
void set_timestamp(const Timestamp& value) {
timestamp_ = value;
}
Timestamp timestamp() const {
return timestamp_;
}
void set(const size_t index, const uint8_t data) {
payload[index] = data;
if(index + 1 > payload_size){
payload_size = index + 1;
}
}
uint32_t operator[](const size_t index) const {
return payload[index];
}
uint8_t size() const {
return payload_size;
}
void set_valid_checksum(const bool valid) {
valid_checksum = valid;
}
bool is_valid_checksum() const {
return valid_checksum;
}
uint64_t get_source(){
uint64_t source = 0x0;
for(uint8_t i = SOURCE_START; i < SOURCE_START + ADDRESS_SIZE; i++){
source |= ( ((uint64_t)payload[i]) << ((i - SOURCE_START) * 8));
}
return source;
}
std::string get_source_formatted(){
parse_address(SOURCE_START, SOURCE);
return std::string(address_buffer);
}
std::string get_destination_formatted(){
parse_address(DESTINATION_START, DESTINATION);
return std::string(address_buffer);
}
std::string get_digipeaters_formatted(){
uint8_t position = DIGIPEATER_START;
bool has_more = parse_address(SOURCE_START, REPEATER);
std::string repeaters = "";
while(has_more){
has_more = parse_address(position, REPEATER);
repeaters += std::string(address_buffer);
position += ADDRESS_SIZE;
if(has_more){
repeaters += ">";
}
}
return repeaters;
}
uint8_t get_number_of_digipeaters(){
uint8_t position = DIGIPEATER_START;
bool has_more = parse_address(SOURCE_START, REPEATER);
uint8_t repeaters = 0;
while(has_more){
has_more = parse_address(position, REPEATER);
position += ADDRESS_SIZE;
repeaters++;
}
return repeaters;
}
uint8_t get_information_start_index(){
return DIGIPEATER_START + (get_number_of_digipeaters() * ADDRESS_SIZE) + 2;
}
std::string get_information_text_formatted(){
std::string information_text = "";
for(uint8_t i = get_information_start_index(); i < payload_size - 2; i++){
information_text += payload[i];
}
return information_text;
}
std::string get_stream_text(){
std::string stream = get_source_formatted() + ">" + get_destination_formatted() + ";" + get_digipeaters_formatted() + ";" + get_information_text_formatted();
return stream;
}
char get_data_type_identifier(){
char ident = '\0';
for(uint8_t i = get_information_start_index(); i < payload_size - 2; i++){
ident = payload[i];
break;
}
return ident;
}
bool has_position(){
char ident = get_data_type_identifier();
return
ident == '!' ||
ident == '=' ||
ident == '/' ||
ident == '@' ||
ident == ';' ||
ident == '`' ||
ident == '\''||
ident == 0x1d||
ident == 0x1c;
}
aprs_pos get_position(){
aprs::aprs_pos pos;
char ident = get_data_type_identifier();
std::string info_text = get_information_text_formatted();
std::string lat_str, lng_str;
char first;
//bool supports_compression = true;
bool is_mic_e_format = false;
std::string::size_type start;
switch(ident){
case '/':
case '@':
start = 8;
break;
case '=':
case '!':
start = 1;
break;
case ';':
start = 18;
//supports_compression = false;
break;
case '`':
case '\'':
case 0x1c:
case 0x1d:
is_mic_e_format = true;
break;
default:
return pos;
}
if(is_mic_e_format){
parse_mic_e_format(pos);
}
else {
if(start < info_text.size()){
first = info_text.at(start);
if(std::isdigit(first)){
if(start + 18 < info_text.size()){
lat_str = info_text.substr(start, 8);
pos.sym_table_id = info_text.at(start + 8);
lng_str = info_text.substr(start + 9, 9);
pos.symbol_code = info_text.at(start + 18);
pos.latitude = parse_lat_str(lat_str);
pos.longitude = parse_lng_str(lng_str);
}
}
else {
if(start + 9 < info_text.size()){
pos.sym_table_id = info_text.at(start);
lat_str = info_text.substr(start + 1, 4);
lng_str = info_text.substr(start + 5, 4);
pos.symbol_code = info_text.at(start + 9);
pos.latitude = parse_lat_str_cmp(lat_str);
pos.longitude = parse_lng_str_cmp(lng_str);
}
}
}
}
return pos;
}
void clear() {
payload_size = 0;
}
private:
const uint8_t DIGIPEATER_START = 14;
const uint8_t SOURCE_START = 7;
const uint8_t DESTINATION_START = 0;
const uint8_t ADDRESS_SIZE = 7;
bool valid_checksum = false;
uint8_t payload[256];
char address_buffer[15];
uint8_t payload_size;
Timestamp timestamp_ { };
float parse_lat_str_cmp(const std::string& lat_str){
return 90.0 - ( (lat_str.at(0) - 33) * (91*91*91) + (lat_str.at(1) - 33) * (91*91) + (lat_str.at(2) - 33) * 91 + (lat_str.at(3)) ) / 380926.0;
}
float parse_lng_str_cmp(const std::string& lng_str){
return -180.0 + ( (lng_str.at(0) - 33) * (91*91*91) + (lng_str.at(1) - 33) * (91*91) + (lng_str.at(2) - 33) * 91 + (lng_str.at(3)) ) / 190463.0;
}
uint8_t parse_digits(const std::string& str){
if(str.at(0) == ' '){
return 0;
}
uint8_t end = str.find_last_not_of(' ') + 1;
std::string sub = str.substr(0, end);
if(!is_digits(sub)){
return 0;
}
else {
return std::stoi(sub);
}
}
bool is_digits(const std::string& str){
return str.find_last_not_of("0123456789") == std::string::npos;
}
float parse_lat_str(const std::string& lat_str){
float lat = 0.0;
std::string str_lat_deg = lat_str.substr(0, 2);
std::string str_lat_min = lat_str.substr(2, 2);
std::string str_lat_hund = lat_str.substr(5, 2);
std::string dir = lat_str.substr(7, 1);
uint8_t lat_deg = parse_digits(str_lat_deg);
uint8_t lat_min = parse_digits(str_lat_min);
uint8_t lat_hund = parse_digits(str_lat_hund);
lat += lat_deg;
lat += (lat_min + (lat_hund/ 100.0))/60.0;
if(dir.c_str()[0] == 'S'){
lat = -lat;
}
return lat;
}
float parse_lng_str(std::string& lng_str){
float lng = 0.0;
std::string str_lng_deg = lng_str.substr(0, 3);
std::string str_lng_min = lng_str.substr(3, 2);
std::string str_lng_hund = lng_str.substr(6, 2);
std::string dir = lng_str.substr(8, 1);
uint8_t lng_deg = parse_digits(str_lng_deg);
uint8_t lng_min = parse_digits(str_lng_min);
uint8_t lng_hund = parse_digits(str_lng_hund);
lng += lng_deg;
lng += (lng_min + (lng_hund/ 100.0))/60.0;
if(dir.c_str()[0] == 'W'){
lng = -lng;
}
return lng;
}
void parse_mic_e_format(aprs::aprs_pos& pos){
std::string lat_str = "";
std::string lng_str = "";
bool is_north = false;
bool is_west = false;
uint8_t lng_offset = 0;
for(uint8_t i = DESTINATION_START; i < DESTINATION_START + ADDRESS_SIZE - 1; i++){
uint8_t ascii = payload[i] >> 1;
lat_str += get_mic_e_lat_digit(ascii);
if(i - DESTINATION_START == 3){
lat_str += ".";
}
if(i - DESTINATION_START == 3){
is_north = is_mic_e_lat_N(ascii);
}
if(i - DESTINATION_START == 4){
lng_offset = get_mic_e_lng_offset(ascii);
}
if(i - DESTINATION_START == 5){
is_west = is_mic_e_lng_W(ascii);
}
}
if(is_north){
lat_str += "N";
}
else {
lat_str += "S";
}
pos.latitude = parse_lat_str(lat_str);
float lng = 0.0;
uint8_t information_start = get_information_start_index() + 1;
for(uint8_t i = information_start; i < information_start + 3 && i < payload_size - 2; i++){
uint8_t ascii = payload[i];
if(i - information_start == 0){ //deg
ascii -=28;
ascii += lng_offset;
if(ascii >= 180 && ascii <= 189){
ascii -= 80;
}
else if (ascii >= 190 && ascii <= 199){
ascii -= 190;
}
lng += ascii;
}
else if(i - information_start == 1){ //min
ascii -= 28;
if(ascii >= 60){
ascii -= 60;
}
lng += ascii/60.0;
}
else if(i - information_start == 2){ //hundredth minutes
ascii -= 28;
lng += (ascii/100.0)/60.0;
}
}
if(is_west){
lng = -lng;
}
pos.longitude = lng;
}
uint8_t get_mic_e_lat_digit(uint8_t ascii){
if(ascii >= '0' && ascii <= '9'){
return ascii;
}
if(ascii >= 'A' && ascii <= 'J'){
return ascii - 17;
}
if(ascii >= 'P' && ascii <='Y'){
return ascii - 32;
}
if(ascii == 'K' || ascii == 'L' || ascii == 'Z'){
return ' ';
}
return '\0';
}
bool is_mic_e_lat_N(uint8_t ascii){
if(ascii >= 'P' && ascii <='Z'){
return true;
}
return false; //not technical definition, but the other case is invalid
}
bool is_mic_e_lng_W(uint8_t ascii){
if(ascii >= 'P' && ascii <='Z'){
return true;
}
return false; //not technical definition, but the other case is invalid
}
uint8_t get_mic_e_lng_offset(uint8_t ascii){
if(ascii >= 'P' && ascii <='Z'){
return 100;
}
return 0; //not technical definition, but the other case is invalid
}
bool parse_address(uint8_t start, ADDRESS_TYPE address_type){
uint8_t byte = 0;
uint8_t has_more = false;
uint8_t ssid = 0;
uint8_t buffer_index = 0;
for(uint8_t i = start; i < start + ADDRESS_SIZE && i < payload_size - 2; i++){
byte = payload[i];
if(i - start == 6){
has_more = (byte & 0x1) == 0;
ssid = (byte >> 1) & 0x0F;
if(ssid != 0 || address_type == REPEATER){
address_buffer[buffer_index++] = '-';
if(ssid < 10){
address_buffer[buffer_index++] = '0' + ssid;
address_buffer[buffer_index++] = '\0';
}
else {
address_buffer[buffer_index++] = '1';
address_buffer[buffer_index++] = '0' + ssid - 10;
address_buffer[buffer_index++] = '\0';
}
}
else {
address_buffer[buffer_index++] = '\0';
}
}
else {
byte >>= 1;
if(byte != ' '){
address_buffer[buffer_index++] = byte;
}
}
}
return has_more;
}
};
} /* namespace aprs */
#endif/*__APRS_PACKET_H__*/
+72 -50
View File
@@ -30,15 +30,17 @@
template<size_t N>
struct fir_taps_real {
float pass_frequency_normalized;
float stop_frequency_normalized;
float low_frequency_normalized;
float high_frequency_normalized;
float transition_normalized;
std::array<int16_t, N> taps;
};
template<size_t N>
struct fir_taps_complex {
float pass_frequency_normalized;
float stop_frequency_normalized;
float low_frequency_normalized;
float high_frequency_normalized;
float transition_normalized;
std::array<complex16_t, N> taps;
};
@@ -46,8 +48,9 @@ struct fir_taps_complex {
// IFIR image-reject filter: fs=3072000, pass=8000, stop=344000, decim=8, fout=384000
constexpr fir_taps_real<24> taps_16k0_decim_0 {
.pass_frequency_normalized = 8000.0f / 3072000.0f,
.stop_frequency_normalized = 344000.0f / 3072000.0f,
.low_frequency_normalized = -8000.0f / 3072000.0f,
.high_frequency_normalized = 8000.0f / 3072000.0f,
.transition_normalized = 336000.0f / 3072000.0f,
.taps = { {
1, 67, 165, 340, 599, 944, 1361, 1820,
2278, 2684, 2988, 3152, 3152, 2988, 2684, 2278,
@@ -57,8 +60,9 @@ constexpr fir_taps_real<24> taps_16k0_decim_0 {
// IFIR prototype filter: fs=384000, pass=8000, stop=40000, decim=8, fout=48000
constexpr fir_taps_real<32> taps_16k0_decim_1 {
.pass_frequency_normalized = 8000.0f / 384000.0f,
.stop_frequency_normalized = 40000.0f / 384000.0f,
.low_frequency_normalized = -8000.0f / 384000.0f,
.high_frequency_normalized = 8000.0f / 384000.0f,
.transition_normalized = 32000.0f / 384000.0f,
.taps = { {
-26, -125, -180, -275, -342, -359, -286, -90,
250, 733, 1337, 2011, 2688, 3289, 3740, 3982,
@@ -69,8 +73,9 @@ constexpr fir_taps_real<32> taps_16k0_decim_1 {
// Channel filter: fs=48000, pass=8000, stop=12400, decim=1, fout=48000
constexpr fir_taps_real<32> taps_16k0_channel {
.pass_frequency_normalized = 8000.0f / 48000.0f,
.stop_frequency_normalized = 12400.0f / 48000.0f,
.low_frequency_normalized = -8000.0f / 48000.0f,
.high_frequency_normalized = 8000.0f / 48000.0f,
.transition_normalized = 4400.0f / 48000.0f,
.taps = { {
-73, -285, -376, -8, 609, 538, -584, -1387,
-148, 2173, 1959, -2146, -5267, -297, 12915, 24737,
@@ -83,8 +88,9 @@ constexpr fir_taps_real<32> taps_16k0_channel {
// IFIR image-reject filter: fs=3072000, pass=5500, stop=341500, decim=8, fout=384000
constexpr fir_taps_real<24> taps_11k0_decim_0 {
.pass_frequency_normalized = 5500.0f / 3072000.0f,
.stop_frequency_normalized = 341500.0f / 3072000.0f,
.low_frequency_normalized = -5500.0f / 3072000.0f,
.high_frequency_normalized = 5500.0f / 3072000.0f,
.transition_normalized = 336000.0f / 3072000.0f,
.taps = { {
38, 102, 220, 406, 668, 1004, 1397, 1822,
2238, 2603, 2875, 3020, 3020, 2875, 2603, 2238,
@@ -94,8 +100,9 @@ constexpr fir_taps_real<24> taps_11k0_decim_0 {
// IFIR prototype filter: fs=384000, pass=5500, stop=42500, decim=8, fout=48000
constexpr fir_taps_real<32> taps_11k0_decim_1 {
.pass_frequency_normalized = 5500.0f / 384000.0f,
.stop_frequency_normalized = 42500.0f / 384000.0f,
.low_frequency_normalized = -5500.0f / 384000.0f,
.high_frequency_normalized = 5500.0f / 384000.0f,
.transition_normalized = 37000.0f / 384000.0f,
.taps = { {
-42, -87, -157, -234, -298, -318, -255, -75,
246, 713, 1306, 1976, 2656, 3265, 3724, 3971,
@@ -106,8 +113,9 @@ constexpr fir_taps_real<32> taps_11k0_decim_1 {
// Channel filter: fs=48000, pass=5500, stop=8900, decim=1, fout=48000
constexpr fir_taps_real<32> taps_11k0_channel {
.pass_frequency_normalized = 5500.0f / 48000.0f,
.stop_frequency_normalized = 8900.0f / 48000.0f,
.low_frequency_normalized = -5500.0f / 48000.0f,
.high_frequency_normalized = 5500.0f / 48000.0f,
.transition_normalized = 3400.0f / 48000.0f,
.taps = { {
-68, -345, -675, -867, -582, 247, 1222, 1562,
634, -1379, -3219, -3068, 310, 6510, 13331, 17795,
@@ -120,8 +128,9 @@ constexpr fir_taps_real<32> taps_11k0_channel {
// IFIR image-reject filter: fs=3072000, pass=4250, stop=340250, decim=8, fout=384000
constexpr fir_taps_real<24> taps_4k25_decim_0 {
.pass_frequency_normalized = 4250.0f / 3072000.0f,
.stop_frequency_normalized = 340250.0f / 3072000.0f,
.low_frequency_normalized = -4250.0f / 3072000.0f,
.high_frequency_normalized = 4250.0f / 3072000.0f,
.transition_normalized = 33600.0f / 3072000.0f,
.taps = { {
38, 103, 222, 409, 671, 1006, 1399, 1821,
2236, 2599, 2868, 3012, 3012, 2868, 2599, 2236,
@@ -131,8 +140,9 @@ constexpr fir_taps_real<24> taps_4k25_decim_0 {
// IFIR prototype filter: fs=384000, pass=4250, stop=43750, decim=8, fout=48000
constexpr fir_taps_real<32> taps_4k25_decim_1 {
.pass_frequency_normalized = 4250.0f / 384000.0f,
.stop_frequency_normalized = 43750.0f / 384000.0f,
.low_frequency_normalized = -4250.0f / 384000.0f,
.high_frequency_normalized = 4250.0f / 384000.0f,
.transition_normalized = 39500.0f / 384000.0f,
.taps = { {
-33, -74, -139, -214, -280, -306, -254, -87,
222, 682, 1274, 1951, 2644, 3268, 3741, 3996,
@@ -143,8 +153,9 @@ constexpr fir_taps_real<32> taps_4k25_decim_1 {
// Channel filter: fs=48000, pass=4250, stop=7900, decim=1, fout=48000
constexpr fir_taps_real<32> taps_4k25_channel {
.pass_frequency_normalized = 4250.0f / 48000.0f,
.stop_frequency_normalized = 7900.0f / 48000.0f,
.low_frequency_normalized = -4250.0f / 48000.0f,
.high_frequency_normalized = 4250.0f / 48000.0f,
.transition_normalized = 3650.0f / 48000.0f,
.taps = { {
-58, -14, 153, 484, 871, 1063, 770, -141,
-1440, -2488, -2435, -614, 3035, 7771, 12226, 14927,
@@ -161,8 +172,6 @@ constexpr fir_taps_real<32> taps_4k25_channel {
* sum(abs(taps)): 125270
*/
/*constexpr fir_taps_real<64> taps_64_lp_025_025 {
.pass_frequency_normalized = 0.025f,
.stop_frequency_normalized = 0.025f,
.taps = { {
0, 0, -3, -7, -13, -20, -27, -32,
-34, -33, -25, -10, 13, 47, 94, 152,
@@ -183,8 +192,9 @@ constexpr fir_taps_real<32> taps_4k25_channel {
* sum(abs(taps)): 125270
*/
constexpr fir_taps_real<64> taps_64_lp_025_025 {
.pass_frequency_normalized = 0.0125f,
.stop_frequency_normalized = 0.0125f,
.low_frequency_normalized = 0,
.high_frequency_normalized = 0,
.transition_normalized = 0,
.taps = { {
0, 0, 2, 6, 12, 20, 32, 46,
64, 85, 110, 138, 169, 204, 241, 281,
@@ -201,8 +211,9 @@ constexpr fir_taps_real<64> taps_64_lp_025_025 {
// IFIR image-reject filter: fs=3072000, pass=3000, stop=339000, decim=8, fout=384000
constexpr fir_taps_real<24> taps_6k0_decim_0 {
.pass_frequency_normalized = 3000.0f / 3072000.0f,
.stop_frequency_normalized = 339000.0f / 3072000.0f,
.low_frequency_normalized = -3000.0f / 3072000.0f,
.high_frequency_normalized = 3000.0f / 3072000.0f,
.transition_normalized = 336000.0f / 3072000.0f,
.taps = { {
39, 104, 224, 412, 674, 1008, 1400, 1821,
2234, 2594, 2863, 3006, 3006, 2863, 2594, 2234,
@@ -212,8 +223,9 @@ constexpr fir_taps_real<24> taps_6k0_decim_0 {
// IFIR prototype filter: fs=384000, pass=3000, stop=45000, decim=8, fout=48000
constexpr fir_taps_real<32> taps_6k0_decim_1 {
.pass_frequency_normalized = 3000.0f / 384000.0f,
.stop_frequency_normalized = 45000.0f / 384000.0f,
.low_frequency_normalized = -3000.0f / 384000.0f,
.high_frequency_normalized = 3000.0f / 384000.0f,
.transition_normalized = 43000.0f / 384000.0f,
.taps = { {
-26, -63, -123, -195, -263, -295, -253, -99,
199, 651, 1242, 1927, 2633, 3273, 3760, 4023,
@@ -224,8 +236,9 @@ constexpr fir_taps_real<32> taps_6k0_decim_1 {
// IFIR prototype filter: fs=48000, pass=3000, stop=6700, decim=4, fout=12000
constexpr fir_taps_real<32> taps_6k0_decim_2 {
.pass_frequency_normalized = 3000.0f / 48000.0f,
.stop_frequency_normalized = 6700.0f / 48000.0f,
.low_frequency_normalized = -3000.0f / 48000.0f,
.high_frequency_normalized = 3000.0f / 48000.0f,
.transition_normalized = 3700.0f / 48000.0f,
.taps = { {
95, 178, 247, 208, -21, -474, -1080, -1640,
-1857, -1411, -83, 2134, 4978, 7946, 10413, 11815,
@@ -239,8 +252,9 @@ constexpr fir_taps_real<32> taps_6k0_decim_2 {
* slightly larger than 32767 (33312).
*/
constexpr fir_taps_complex<64> taps_6k0_dsb_channel {
.pass_frequency_normalized = 3000.0f / 12000.0f,
.stop_frequency_normalized = 3300.0f / 12000.0f,
.low_frequency_normalized = -3000.0f / 12000.0f,
.high_frequency_normalized = 3000.0f / 12000.0f,
.transition_normalized = 300.0f / 12000.0f,
.taps = { {
{ -69, 0 }, { -140, 0 }, { 119, 0 }, { 89, 0 },
{ -132, 0 }, { -134, 0 }, { 197, 0 }, { 167, 0 },
@@ -265,8 +279,9 @@ constexpr fir_taps_complex<64> taps_6k0_dsb_channel {
// IFIR prototype filter: fs=12000, pass=3000, stop=3300, decim=1, fout=12000
constexpr fir_taps_complex<64> taps_2k8_usb_channel {
.pass_frequency_normalized = 3000.0f / 12000.0f,
.stop_frequency_normalized = 3300.0f / 12000.0f,
.low_frequency_normalized = 0,
.high_frequency_normalized = 3000.0f / 12000.0f,
.transition_normalized = 300.0f / 12000.0f,
.taps = { {
{ -146, 0 }, { -41, -45 }, { -1, 10 }, { -95, 69 },
{ -194, -41 }, { -91, -158 }, { 14, -43 }, { -150, 67 },
@@ -291,8 +306,9 @@ constexpr fir_taps_complex<64> taps_2k8_usb_channel {
// IFIR prototype filter: fs=12000, pass=3000, stop=3300, decim=1, fout=12000
constexpr fir_taps_complex<64> taps_2k8_lsb_channel {
.pass_frequency_normalized = 3000.0f / 12000.0f,
.stop_frequency_normalized = 3300.0f / 12000.0f,
.low_frequency_normalized = -3000.0f / 12000.0f,
.high_frequency_normalized = 0,
.transition_normalized = 300.0f / 12000.0f,
.taps = { {
{ -146, 0 }, { -41, 45 }, { -1, -10 }, { -95, -69 },
{ -194, 41 }, { -91, 158 }, { 14, 43 }, { -150, -67 },
@@ -316,8 +332,9 @@ constexpr fir_taps_complex<64> taps_2k8_lsb_channel {
// USB AM 700Hz filter: fs=12000, start=600, end=800, width=200, stop=40db, decim=1, fout=12000
constexpr fir_taps_complex<64> taps_0k7_usb_channel {
.pass_frequency_normalized = 3000.0f / 12000.0f,
.stop_frequency_normalized = 3300.0f / 12000.0f,
.low_frequency_normalized = 600.0f / 12000.0f,
.high_frequency_normalized = 800.0f / 12000.0f,
.transition_normalized = 200.0f / 12000.0f,
.taps = { {
{ 531, 0 }, { 192, 73 }, { 181, 163 }, { 129, 254 },
{ 34, 328 }, { -97, 364 }, { -251, 345 }, { -403, 261 },
@@ -342,8 +359,9 @@ constexpr fir_taps_complex<64> taps_0k7_usb_channel {
// IFIR image-reject filter: fs=3072000, pass=100000, stop=484000, decim=4, fout=768000
constexpr fir_taps_real<24> taps_200k_wfm_decim_0 = {
.pass_frequency_normalized = 100000.0f / 3072000.0f,
.stop_frequency_normalized = 484000.0f / 3072000.0f,
.low_frequency_normalized = -100000.0f / 3072000.0f,
.high_frequency_normalized = 100000.0f / 3072000.0f,
.transition_normalized = 384000.0f / 3072000.0f,
.taps = { {
48, -18, -151, -364, -557, -548, -139, 789,
2187, 3800, 5230, 6071, 6071, 5230, 3800, 2187,
@@ -353,8 +371,9 @@ constexpr fir_taps_real<24> taps_200k_wfm_decim_0 = {
// IFIR prototype filter: fs=768000, pass=100000, stop=284000, decim=2, fout=384000
constexpr fir_taps_real<16> taps_200k_wfm_decim_1 = {
.pass_frequency_normalized = 100000.0f / 768000.0f,
.stop_frequency_normalized = 284000.0f / 768000.0f,
.low_frequency_normalized = -100000.0f / 768000.0f,
.high_frequency_normalized = 100000.0f / 768000.0f,
.transition_normalized = 184000.0f / 768000.0f,
.taps = { {
-67, -123, 388, 622, -1342, -2185, 4599, 14486,
14486, 4599, -2185, -1342, 622, 388, -123, -67,
@@ -369,8 +388,9 @@ constexpr fir_taps_real<16> taps_200k_wfm_decim_1 = {
* sum(abs(taps)): 125270
*/
constexpr fir_taps_real<64> taps_64_lp_156_198 {
.pass_frequency_normalized = 0.156f,
.stop_frequency_normalized = 0.196f,
.low_frequency_normalized = -0.156f,
.high_frequency_normalized = 0.156f,
.transition_normalized = 0.04f,
.taps = { {
-27, 166, 104, -36, -174, -129, 109, 287,
148, -232, -430, -130, 427, 597, 49, -716,
@@ -387,8 +407,9 @@ constexpr fir_taps_real<64> taps_64_lp_156_198 {
// IFIR image-reject filter: fs=2457600, pass=100000, stop=407200, decim=4, fout=614400
static constexpr fir_taps_real<24> taps_200k_decim_0 = {
.pass_frequency_normalized = 100000.0f / 2457600.0f,
.stop_frequency_normalized = 407200.0f / 2457600.0f,
.low_frequency_normalized = -100000.0f / 2457600.0f,
.high_frequency_normalized = 100000.0f / 2457600.0f,
.transition_normalized = 307200.0f / 2457600.0f,
.taps = { {
90, 94, 4, -240, -570, -776, -563, 309,
1861, 3808, 5618, 6710, 6710, 5618, 3808, 1861,
@@ -398,8 +419,9 @@ static constexpr fir_taps_real<24> taps_200k_decim_0 = {
// IFIR prototype filter: fs=614400, pass=100000, stop=207200, decim=2, fout=307200
static constexpr fir_taps_real<16> taps_200k_decim_1 = {
.pass_frequency_normalized = 100000.0f / 614400.0f,
.stop_frequency_normalized = 207200.0f / 614400.0f,
.low_frequency_normalized = -100000.0f / 614400.0f,
.high_frequency_normalized = 100000.0f / 614400.0f,
.transition_normalized = 107200.0f / 614400.0f,
.taps = { {
-132, -256, 545, 834, -1507, -2401, 4666, 14583,
14583, 4666, -2401, -1507, 834, 545, -256, -132,
+26
View File
@@ -55,3 +55,29 @@ void IIRBiquadFilter::execute(const buffer_f32_t& buffer_in, const buffer_f32_t&
void IIRBiquadFilter::execute_in_place(const buffer_f32_t& buffer) {
execute(buffer, buffer);
}
void IIRBiquadDF2Filter::configure(const iir_biquad_df2_config_t& config) {
b0 = config[0] / config[3];
b1 = config[1] / config[3];
b2 = config[2] / config[3];
a1 = config[4] / config[3];
a2 = config[5] / config[3];
}
// scipy.signal.sosfilt
//
// x_n = x[i, n] # make a temporary copy
// # Use direct II transposed structure:
// x[i, n] = b[s, 0] * x_n + zi[i, s, 0]
// zi[i, s, 0] = (b[s, 1] * x_n - a[s, 0] * x[i, n] + zi[i, s, 1])
// zi[i, s, 1] = (b[s, 2] * x_n - a[s, 1] * x[i, n])
float IIRBiquadDF2Filter::execute(float x) {
float y;
y = b0 * x + z0;
z0 = b1 * x - a1 * y + z1;
z1 = b2 * x - a2 * y;
return y;
}
+20
View File
@@ -31,6 +31,9 @@ struct iir_biquad_config_t {
std::array<float, 3> a;
};
// 0..2 - b, 3..5 - a
typedef std::array<float, 6> iir_biquad_df2_config_t;
constexpr iir_biquad_config_t iir_config_passthrough {
{ { 1.0f, 0.0f, 0.0f } },
{ { 0.0f, 0.0f, 0.0f } },
@@ -67,4 +70,21 @@ private:
std::array<float, 3> y { { 0.0f, 0.0f, 0.0f } };
};
class IIRBiquadDF2Filter {
public:
void configure(const iir_biquad_df2_config_t& config);
float execute(float z);
private:
float b0 = 0;
float b1 = 0;
float b2 = 0;
float a1 = 0;
float a2 = 0;
float z0 = 0;
float z1 = 0;
};
#endif/*__DSP_IIR_H__*/
+22
View File
@@ -0,0 +1,22 @@
/*
* Copyright (C) 2020 Belousov Oleg
*
* This file is part of PortaPack.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#include "dsp_sos.hpp"
+51
View File
@@ -0,0 +1,51 @@
/*
* Copyright (C) 2020 Belousov Oleg
*
* This file is part of PortaPack.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#ifndef __DSP_SOS_H__
#define __DSP_SOS_H__
#include "dsp_iir.hpp"
#include <cstdint>
#include <cstddef>
template <size_t N>
class SOSFilter {
public:
void configure(const iir_biquad_df2_config_t config[N]) {
for (size_t i = 0; i < N; i++)
filters[i].configure(config[i]);
}
float execute(float value) {
for (auto &filter : filters)
value = filter.execute(value);
return value;
}
private:
IIRBiquadDF2Filter filters[N];
};
#endif/*__DSP_SOS_H__*/

Some files were not shown because too many files have changed in this diff Show More