187 Commits

Author SHA1 Message Date
Krzysiek Egzmont
c2a085734c Restore old 1o11 am_fix gains table 2024-02-05 22:11:12 +01:00
Krzysiek Egzmont
1098e8c386 Fix DTMF_auto_reset_time sanity check bug 2024-02-04 22:54:31 +01:00
losehu
ce2dd10d45 The dbMax range is more stringent
"If you want the dbMax value to always be greater than dbMin, there should be at least a '+1'."
2024-02-01 20:41:16 +01:00
Krzysiek Egzmont
a22760c0b4 Fix #434: Don't send tail tone when STE is off 2024-01-29 22:48:37 +01:00
Krzysiek Egzmont
aa92e93c56 Refactor 2024-01-29 22:42:38 +01:00
Krzysiek Egzmont
dc1808b1fe FIX #444: build error when ENABLE_DTMF_CALLING disabled 2024-01-29 16:50:58 +01:00
Krzysiek Egzmont
dff4384dbe FIX #397: Duplex off not working when UNLOCK ALL is used 2024-01-29 16:34:55 +01:00
Krzysiek Egzmont
f85ed9440d Refactor 2024-01-28 23:57:15 +01:00
Krzysiek Egzmont
604a5b430f PTTID sanity check 2024-01-28 22:07:08 +01:00
Krzysiek Egzmont
ed5ebc4854 FIX #441: Setting ENABLE_NO_CODE_SCAN_TIMEOUT at 1 or 0 has no effect 2024-01-28 21:59:20 +01:00
egzumer
c74c0d20fc README.md, recommend other forks 2024-01-22 00:03:43 +01:00
Krzysiek Egzmont
46e2d1a0fd FM radio band selection #230 2024-01-15 22:30:12 +01:00
Krzysiek Egzmont
adbc466c49 Refactor 2024-01-15 17:01:42 +01:00
Krzysiek Egzmont
f8ff71aaa3 Fix #193: DTMF interrupt temporarily disabled after TX causing DTMF tones lost 2024-01-14 00:58:40 +01:00
Krzysiek Egzmont
ea3b5b23a9 Refactor 2024-01-14 00:25:02 +01:00
Krzysiek Egzmont
8941576887 Fix #286: Lack of continuous tuning and monitor lockout while holding up/down button in monitor mode. 2024-01-13 23:35:33 +01:00
Krzysiek Egzmont
04b0bd8c93 Refactor 2024-01-13 23:30:44 +01:00
wu58430
4efabfc2b6 Prohibit entering submenus when displaying DTMF information 2024-01-12 17:51:36 +01:00
Krzysiek Egzmont
9472bbb58b Fix #384: FM radio getting stuck off on unrecognized incoming CTCSS tone 2024-01-12 15:54:36 +01:00
Krzysiek Egzmont
685ecb062b Refactor 2024-01-12 15:54:35 +01:00
Krzysiek Egzmont
3bf993d8b8 Cleanup the ENABLE_SQUELCH_MORE_SENSITIVE option, it was still applying some corrections even if disabled 2024-01-09 02:42:47 +01:00
Yuri_su
01ccaaf212 Update app.c fix DTMF not reply
If set DTMF reply only, sometimes the DTMF call will not reply.
2024-01-08 23:40:01 +01:00
Krzysiek Egzmont
ed5ae7842b Fix #366: Scan list 2 ignored everywhere 2024-01-01 20:50:21 +01:00
Krzysiek Egzmont
ac8c51d605 Fix s-meter and DTMF overlaying problem 2023-12-31 13:31:39 +01:00
Wouter van Gulik
429cffc0bc ui/menu.c: Simplify code; move name printing into main switch statement.
This saves a few bytes of flash.
2023-12-30 20:38:59 +01:00
Wouter van Gulik
fbdaf6631d menu: use const char* const 2023-12-30 20:35:11 +01:00
Krzysiek Egzmont
f8feef1ad5 Refactor 2023-12-30 20:22:55 +01:00
Krzysiek Egzmont
42a45a7ef2 Update README 2023-12-30 15:35:28 +01:00
Krzysiek Egzmont
3f012b3afe Fix uart BK regs reading/writing 2023-12-30 15:32:11 +01:00
Juan Antonio
289418f1c7 Reduce nesting 2023-12-28 22:08:57 +01:00
Juan Antonio
ea733115de init.c: Declare loop variables in the loop 2023-12-28 22:08:57 +01:00
Juan Antonio
e5cff16d98 Merge guarded code. Simplify DTMF_CheckGroupCall 2023-12-28 22:08:56 +01:00
Krzysiek Egzmont
f35ce8d789 Menu style build option ENABLE_CUSTOM_MENU_LAYOUT 2023-12-28 22:08:56 +01:00
Juan Antonio
36ecde86e9 Reduce nesting 2023-12-28 22:08:56 +01:00
Krzysiek Egzmont
8f6e1be5e0 Refactor 2023-12-28 22:08:56 +01:00
Juan Antonio
cceba5a474 Add missing UI_DisplayClear() 2023-12-26 03:01:24 +01:00
Krzysiek Egzmont
1882ab0cc1 Refactor 2023-12-26 01:40:04 +01:00
Krzysiek Egzmont
995045006f Read/write BK4819 regs through UART 2023-12-25 23:52:15 +01:00
Krzysiek Egzmont
38ec40b0db Faster AGC debugging print 2023-12-25 22:49:58 +01:00
Juan Antonio
cbf4a7c140 Use function table. Simplify logic
Size: 60364 -> 60220
2023-12-25 22:49:06 +01:00
Juan Antonio
7a7010da55 Unify PrintSmall functions
Size: 60420 -> 60364
2023-12-25 22:49:06 +01:00
Juan Antonio
78a45d9bbd Create function to zero gFrameBuffer
Size: 60464 -> 60420
2023-12-25 22:49:06 +01:00
Juan Antonio
f8ef687026 Use pointers to avoid some string copying
Size: 60664 -> 60464
2023-12-25 22:49:06 +01:00
Juan Antonio
1281bbf033 Remove redundant mensets. Memmove -> memcpy
* The whole gEeprom has been zero'd before. Moreover, strcpy null-terminates.
* There's no aliasing between gEeprom.* and Data.

Size: 60760 -> 60664
2023-12-25 22:49:06 +01:00
Juan Antonio
edf1f983d6 Ignore k5_eeprom.raw 2023-12-25 22:49:06 +01:00
Juan Antonio
b0d131d546 Fix include directives 2023-12-25 22:49:06 +01:00
Wouter van Gulik
ab61c4e74f Makefile: always provide VERSION_STRING if none set.
Without this set the compile-without-docker script did not work. They do
not have git installed.
2023-12-25 01:01:53 +01:00
Juan Antonio
986c0ce368 Fix RX not honoring Backlight on TX/RX settings properly
Fixes #317
2023-12-24 22:56:35 +01:00
Juan Antonio
e929a79765 Move variable declaration outside of guarded region
Fixes #328
2023-12-24 20:55:29 +01:00
Juan Antonio
d75209bad0 Rename str_ptr to adhere to the current style 2023-12-24 13:34:05 +01:00
Juan Antonio
ee0ba9886d Simplify DTMF_FindContact 2023-12-24 13:34:05 +01:00
Juan Antonio
084fe4dd26 Fix 1750Hz so that it can perform STE
1750Hz and CTCSS tones can be send together.
2023-12-24 13:34:05 +01:00
Juan Antonio
a715389a8b Add Doxygen configuration file and makefile target
It can be used to generate sometimes useful call-graphs.
2023-12-24 13:34:05 +01:00
Juan Antonio
6f1cabc807 Simplify gSchedulePowerSave logic
There was quite convoluted logic there, and what I believe, was a bug.

Rationale:

Both,
- gBatterySaveCountdown_10ms = battery_save_count_10ms;, and
- gSchedulePowerSave = false
are always executed inside FUNCTION_Select().

So the code is equivalent to:

if (any of those OR'd) {
	gBatterySaveCountdown_10ms = battery_save_count_10ms;
	gSchedulePowerSave = false; (but only if we have NOAA disabled)
} else {
	[other stuff from FUNCTION_Select()]
	gBatterySaveCountdown_10ms = battery_save_count_10ms;
	gSchedulePowerSave = false; (regarless of having NOAA or not)
}

So:
- OR is true, have NOAA-> don't clear gSchedulePowerSave
	-> implies we will enter here, again, until the OR is false, but only if we have NOAA.
- OR is False -> clear gSchedulePowerSave.

Moreover, checking with DualTachyon code at
6f8afac886/app/app.c (L747)
gSchedulePowerSave is always set to false if it was true.
2023-12-24 13:34:05 +01:00
Juan Antonio
a08420a0b7 Simply some logic. Unify some #ifdef regions 2023-12-24 13:34:05 +01:00
Juan Antonio
1f4f026162 Simplify APP_EndTransmission
* Unify Roger-Beep selection
 * Extract function for DTMF EoT
2023-12-24 13:34:05 +01:00
Juan Antonio
34f2168856 Spectrum warp-around when switching steps 2023-12-24 13:34:05 +01:00
Juan Antonio
bc9bb489e6 Un-unroll some loops and save a few bytes 2023-12-24 13:34:05 +01:00
Juan Antonio
7d982f1f8d Correct include guard #endif placement 2023-12-22 20:26:07 +01:00
Krzysiek Egzmont
2cc60da9ab Fix #314:Reset current bar when blacklisting in scan range 2023-12-22 20:22:39 +01:00
Krzysiek Egzmont
39eb3e835e Scan range in spectrum 2023-12-19 18:25:45 +01:00
egzumer
0d66eb8577 Update README.md 2023-12-19 17:37:24 +01:00
Krzysiek Egzmont
13b6bb06b2 Spectrum analyzer, more frequency steps 2023-12-19 03:08:18 +01:00
Krzysiek Egzmont
88f3537af0 9kHz, 20kHz, 200kHz frequency steps added #295 2023-12-18 17:12:33 +01:00
Krzysiek Egzmont
de8c501d65 S0, S9 settings even more constrained 2023-12-18 15:27:31 +01:00
egzumer
76bbaf9442 Update README.md 2023-12-18 15:23:02 +01:00
Krzysiek Egzmont
c4d9cfc895 Add AM-fix build option to EEPROM 2023-12-17 03:47:17 +01:00
Juan Antonio
2a75f8a9be Refactoring #285
Signed-off-by: Krzysiek Egzmont <egzumer@gmail.com>
2023-12-16 18:34:54 +01:00
Krzysiek Egzmont
e7a21c470f Makefile Mac build fix #284 2023-12-15 21:08:50 +01:00
Krzysiek Egzmont
fc679c77a4 Fix other backlight menu issues #275 2023-12-15 18:08:40 +01:00
Krzysiek Egzmont
1151cf8667 Backlight brightness tuned down for backlight menu entries #275 2023-12-15 16:54:18 +01:00
Krzysiek Egzmont
af6b542da1 Cleanup 2023-12-15 13:47:07 +01:00
Juan Antonio
cc49a5007c Fix #275 Backlight does not get back to MAX brightness after exiting backlight menu entries
Backlight is set to FULL when interacting with backlight menu entries,
but it is not set back to MAX when exiting from those entries. This
commit corrects that behaviour.
2023-12-15 13:00:08 +01:00
Juan Antonio
a99d2dd1b1 Fix #272: Backlight time doubled 2023-12-15 02:56:25 +01:00
Juan Antonio
9dc79ce868 Fix compilation errors when UART is disabled 2023-12-14 22:03:44 +01:00
Juan Antonio
80fa310646 Fix use of wrong ENABLE guard 2023-12-14 22:03:44 +01:00
Juan Antonio
7f5236c44e Fix compilation errors when FM radio is disabled 2023-12-14 22:03:44 +01:00
Juan Antonio
4b583bf2bd Assign NOP function when the flashlight is disabled 2023-12-14 22:03:44 +01:00
Krzysiek Egzmont
fa5d3c1594 FIX #269: battery indicator always at 4 bars 2023-12-14 15:07:33 +01:00
Juan Antonio
1a53586922 Simplify logic in radio.c 2023-12-14 11:11:06 +01:00
Juan Antonio
687b63abb6 Fix signature 2023-12-14 11:11:06 +01:00
Juan Antonio
06f1c651bc Make LogUart receive a const char* const 2023-12-14 11:11:06 +01:00
Juan Antonio
33e4e3c4e0 Make AUDIO_PlayVoice static as it is only used inside of its module 2023-12-14 11:11:06 +01:00
Krzysiek Egzmont
93b97eff0a FIX #264: compilation error 2023-12-14 11:05:46 +01:00
egzumer
8638d37431 Update README.md 2023-12-13 19:19:29 +01:00
Krzysiek Egzmont
716e9e23b8 README.md - add Github Codespace building manual 2023-12-13 19:04:29 +01:00
Juan Antonio
d0ae34f9b4 Replace memmove by memcpy 2023-12-13 16:07:07 +01:00
Juan Antonio
bd17aea72b Make SETTINGS_InitEEPROM zero struct gEeprom 2023-12-13 16:07:07 +01:00
Juan Antonio
34d688b101 Logic simplification. Replace memmove by memcpy 2023-12-13 16:07:07 +01:00
Juan Antonio
8c7f736797 Simplify come battery logic 2023-12-13 16:07:07 +01:00
Juan Antonio
a19579a888 Make makefile options settable from envars 2023-12-13 16:07:07 +01:00
Krzysiek Egzmont
00a2bc75b8 Tighter constraints for S0, S9 s-meter EEPROM settings #252 2023-12-13 13:48:18 +01:00
Krzysiek Egzmont
268c4dece3 S0 and S9 value settings #174 2023-12-12 18:51:38 +01:00
Krzysiek Egzmont
0c2fc6184c Fix #234: Bring back FM radio status indicator, show dual watch inactive while in FM radio 2023-12-12 00:52:26 +01:00
Krzysiek Egzmont
6bdce2d0e2 Refactor 2023-12-12 00:45:09 +01:00
g4eml
42a2e16e0e Update am_fix.c 2023-12-10 22:15:53 +01:00
Juan Antonio
2e69acbdc4 Fix aircopy bypassing TX restrictions & refactor
And scrapes together a few more bytes.
2023-12-09 19:07:20 +01:00
Krzysiek Egzmont
eb6a3d0867 Fix compile error 2023-12-09 16:21:11 +01:00
Krzysiek Egzmont
e22cc4ccd0 Code comments 2023-12-09 15:51:40 +01:00
Juan Antonio
a153e63be1 Add function to test if serial configuration is in progress
This was formely tested all over using testing for the state of
gSerialConfigCountDown_500ms in a couple of ways. This logic have been
extracted into a function to make the code more readable.
Also testing it with > 0 was a bit misleading as the variable is
unsigned so tesing with == and != is enough.
2023-12-09 15:50:59 +01:00
Juan Antonio
4322a7d8a9 Drop gScreenToDisplay switch and use function table
Saves some bytes
2023-12-09 15:50:59 +01:00
Juan Antonio
1203fdf0ca Use stepping instead of branching using modulus
Modulus operations are very costly and generally should be avoided.
They also take a few bytes.

This version is actually a quite faster.
2023-12-09 15:50:59 +01:00
Juan Antonio
cfc4763dd1 Scrape together a few bytes 2023-12-09 15:50:59 +01:00
Juan Antonio
b6a49db31d FM Radio: Simplify logic 2023-12-08 23:18:19 +01:00
Juan Antonio
82ddbcd375 Refactor stepFruencyTable & drop ARRAY_SIZE for frequencyBandTable 2023-12-08 23:17:33 +01:00
Juan Antonio
335c2ec9cd ACTION_Handle: Drop switch in favour of a function array 2023-12-08 01:43:12 +01:00
Juan Antonio
4249d917f8 Refactor of app/action.c
* Extracted funcionts
* Simplified logic of some functions
* Moved things arround a bit. Conditional code moved to the end
2023-12-08 01:43:12 +01:00
Juan Antonio
2164461449 Use function to check if in RX mode 2023-12-08 01:43:12 +01:00
Juan Antonio
c3906f42f8 Update .gitignore 2023-12-08 01:43:12 +01:00
Juan Antonio
d055fb0024 Reorder audio.c 2023-12-08 01:43:12 +01:00
Juan Antonio
c4ad9c6501 Unguard ACTION_OPT_BLMIN_TMP_OFF like the rest 2023-12-08 01:43:12 +01:00
Juan Antonio
4fd1ab8899 Remove redudant symbol 2023-12-08 01:43:12 +01:00
Krzysiek Egzmont
0793b68971 Write build options to EEPROM for CHIRP to use. 2023-12-07 22:51:48 +01:00
Krzysiek Egzmont
f7061c3195 FIX #206: missing 254.1Hz CTCSS code 2023-12-07 22:03:22 +01:00
Krzysiek Egzmont
5e78916dd3 AM-fix cleanup 2023-12-07 21:08:12 +01:00
Krzysiek Egzmont
13c17ad073 Fix #211: AM reception chopping 2023-12-07 20:48:36 +01:00
Krzysiek Egzmont
c697596806 FIX #194: Spectrum going crazy when AM-fix is active 2023-12-07 17:45:20 +01:00
g4eml
5c1cb4f2fc FIX #180: round frequency to half the step to support half channel offsets 2023-12-07 15:39:24 +01:00
Juan Antonio
754d2ce5fb Make Flashlight optional 2023-12-07 00:46:59 +01:00
Juan Antonio
c76a96c3ad Add enum for TR/TX mode 2023-12-07 00:46:59 +01:00
Juan Antonio
cd032c39d2 Refactor alarm code
- Fixes Alarms bypassing TX restrictions

- Adds enumerations

- Makes use of mode ALARM_STATE_SITE_ALARM (formely ALARM_STATE_ALARM) instead
  checking against ALARM_STATE_TXALARM && ALARM_MODE == ALARM_MODE_TONE
  all over the place
2023-12-07 00:46:59 +01:00
Juan Antonio
103bdf212f Use enum for Flaslight & return early 2023-12-07 00:44:51 +01:00
Juan Antonio
bafe372cbc Simplify backlight logic 2023-12-07 00:44:51 +01:00
Krzysiek Egzmont
88f7b90237 FIX #197: DWCode,UPCode display error 2023-12-07 00:33:05 +01:00
Krzysiek Egzmont
66f1f545c3 Refactor 2023-12-06 23:08:57 +01:00
Krzysiek Egzmont
e5659ad6ab Fix battery save broken in last commits 2023-12-06 20:36:15 +01:00
Krzysiek Egzmont
c1a009cc2f AM fix modification 2023-12-06 17:54:32 +01:00
Krzysiek Egzmont
e95f577074 Real AM fix attempt, messy 2023-12-05 23:14:43 +01:00
Juan Antonio
52bdd408c4 Refactor, merge #186 2023-12-05 02:01:43 +01:00
Krzysiek Egzmont
ed395ab638 FIX #185: Allow manual changing of gain values in spectrum when AM fix is active 2023-12-05 00:45:22 +01:00
Krzysiek Egzmont
86438ef3ce Improve AM-fix 2023-12-05 00:22:30 +01:00
Krzysiek Egzmont
f3297c29cb AGC debugging option 2023-12-04 22:58:27 +01:00
Krzysiek Egzmont
e039e65ee4 Refactoring 2023-12-04 22:53:59 +01:00
Krzysiek Egzmont
e2b81bf9c8 Refactoring 2023-12-03 21:46:17 +01:00
g4eml
9ca3ccd744 AM-Fix for Spectrum 2023-12-02 23:16:14 +01:00
Krzysiek Egzmont
d944ff4a34 Fix #170: ChName saves a name with wrong settings when used in frequency mode 2023-12-02 23:06:22 +01:00
Krzysiek Egzmont
cfa745fda0 Refactor 2023-12-02 22:59:36 +01:00
Krzysiek Egzmont
b505f81958 FIX #166: Switching to AM overwrites channel CTCSS/DCS (and some other) settings 2023-12-02 18:36:00 +01:00
Krzysiek Egzmont
235a1a2f14 Refactor 2023-12-02 18:04:19 +01:00
Krzysiek Egzmont
a4cefe3401 FIX #167: F7+ band accessible even if WIDE_RX = 0 2023-12-02 15:31:19 +01:00
Krzysiek Egzmont
5a2086fcd0 Improve AM-fix #160 2023-12-01 02:14:28 +01:00
Krzysiek Egzmont
c341570838 Refactor cleanup 2023-12-01 02:14:28 +01:00
Krzysiek Egzmont
292e2e7e7e Fix build error 2023-11-30 14:34:04 +01:00
Krzysiek Egzmont
44ff33613a Refactoring 2023-11-29 17:55:47 +01:00
Krzysiek Egzmont
f9e10da9ee FIX #158: Don't allow to enter DTMF input when scan range is active 2023-11-29 17:38:31 +01:00
Joe Matthews
5ad8229d7c chore: cleanup README.md a bit 2023-11-29 17:00:52 +01:00
Joe Matthews
90609ca5c5 fix: cannot compile with docker on m1 mac 2023-11-29 17:00:52 +01:00
Krzysiek Egzmont
59b3251713 Github actions update 2023-11-29 02:18:34 +01:00
Krzysiek Egzmont
fbb4d08b88 S-meter values readjusted according to measurements from #53 2023-11-29 01:23:20 +01:00
Krzysiek Egzmont
050e04bcfd Enable/disable DTMF calling compile option 2023-11-28 23:00:01 +01:00
Krzysiek Egzmont
7857e8ed7a Scan range function #132 2023-11-28 20:13:02 +01:00
Krzysiek Egzmont
4c3eb98e31 Refactor 2023-11-27 22:51:36 +01:00
Krzysiek Egzmont
fe49f250b0 FM radio button actions changed to be the same as in VFO mode 2023-11-27 19:36:49 +01:00
Krzysiek Egzmont
3c643208ff FIX #152: Zero digit being entered when exiting FM radio with F+0 2023-11-27 13:42:47 +01:00
Krzysiek Egzmont
dc47842892 Refactor 2023-11-27 13:33:39 +01:00
Krzysiek Egzmont
9f22e8a9df FIX #151: Use aviation channels to frequency conversion scheme for 8.33 step rounding 2023-11-27 01:43:36 +01:00
Krzysiek Egzmont
07588853e4 Versioning modified 2023-11-27 00:50:08 +01:00
Krzysiek Egzmont
199b1a27f1 Spectrum: decimal point deletion fix #148, slower buttons repeats 2023-11-26 19:06:18 +01:00
Krzysiek Egzmont
a0d052b68b Spectrum refactor 2023-11-25 19:28:21 +01:00
Krzysiek Egzmont
9a3249a667 FIX #121: Rise tones volume 2023-11-23 21:20:24 +01:00
Krzysiek Egzmont
ffdc0e03b5 FIX #114, #120: Restart monitor mode on PTT release, long press EXIT exits monitor mode 2023-11-23 21:02:47 +01:00
Krzysiek Egzmont
d8d4384b20 Refactoring 2023-11-23 19:48:47 +01:00
Krzysiek Egzmont
0ce7d7bdc3 FIX #129: Bug in radio initialization after reset. 2023-11-22 23:40:39 +01:00
Krzysiek Egzmont
fb30ec8c86 Refactor 2023-11-22 23:40:20 +01:00
Krzysiek Egzmont
67307463e2 FIX #92: Adjust s-meter values 2023-11-22 14:52:16 +01:00
Krzysiek Egzmont
fdd7fc063e Cleanup docker container after build 2023-11-22 14:51:53 +01:00
Krzysiek Egzmont
592810b7d7 FIX #125: Frequency input on the first VFO blanks the display on the second 2023-11-20 22:32:39 +01:00
Krzysiek Egzmont
6e5e7e7aef FIX #85: Equalize tones volume in DTMF codes, fix wrong DTMF frequency values 2023-11-20 21:24:09 +01:00
ErikS-web
cd0dc71de6 Update README.md
Type error corrected
2023-11-18 21:26:37 +01:00
Krzysiek Egzmont
a43a3f949f READ MANUAL prompt for unlocking TX 2023-11-09 10:33:28 +01:00
Krzysiek Egzmont
d7b6cdf444 Modify release GH action 2023-11-08 18:57:50 +01:00
BG8LGP
7916d79ff1 Add github actions #86 2023-11-08 02:35:59 +01:00
Krzysiek Egzmont
49cec54cd3 TX on all bands #68 2023-11-08 01:43:06 +01:00
Krzysiek Egzmont
f154aebd38 Refactoring 2023-11-08 01:29:14 +01:00
ErikS-web
aaa55c5742 Update README.md
Cosmetic corrections
2023-11-07 21:49:20 +01:00
ErikS-web
345f1444f5 Update README.md
spelling mistake corrected
2023-11-07 21:39:22 +01:00
Krzysiek Egzmont
7e91d67b53 Mic bar in the same style as an s-meter 2023-11-07 17:11:25 +01:00
Krzysiek Egzmont
ba29176f33 Don't display mic bar over low the battery popup 2023-11-07 17:11:25 +01:00
Krzysiek Egzmont
05feff432e Rename build option 2023-11-07 17:11:24 +01:00
egzumer
cf4f85cb22 Update README.md 2023-11-07 17:09:07 +01:00
Krzysiek Egzmont
a0c2181197 Fix build error 2023-11-06 21:58:27 +01:00
Krzysiek Egzmont
b4abf369e1 FIX #76: Apollo Quindar mutes microphone 2023-11-06 16:20:45 +01:00
Krzysiek Egzmont
be0636d69b Readme update 2023-11-06 15:57:22 +01:00
wrobepio
23986a8648 Add "BLMIN TMP OFF" function for programmable buttons 2023-11-06 15:55:13 +01:00
Krzysiek Egzmont
b1d3a95ca2 Replace RX CSS menu scanning procedure with BK scanning method 2023-11-06 01:25:44 +01:00
Krzysiek Egzmont
1238bf090c Refactoring of cxcss and channel/frequency scanner code 2023-11-06 01:23:36 +01:00
Krzysiek Egzmont
5987e03141 Change names of some submenu items #80 2023-11-04 17:53:33 +01:00
90 changed files with 6874 additions and 6864 deletions

49
.github/workflows/main.yml vendored Normal file
View File

@@ -0,0 +1,49 @@
on:
push:
jobs:
build:
runs-on: ubuntu-22.04
container:
image: archlinux:latest
steps:
- name: base-devel
run: pacman -Syyu base-devel --noconfirm
- name: arm-none-eabi-gcc
run: pacman -Syyu arm-none-eabi-gcc --noconfirm
- name: arm-none-eabi-newlib
run: pacman -Syyu arm-none-eabi-newlib --noconfirm
- name: git
run: pacman -Syyu git --noconfirm
- name: python-pip
run: pacman -Syyu python-pip --noconfirm
- name: python-crcmod
run: pacman -Syyu python-crcmod --noconfirm
- name: Checkout
uses: actions/checkout@v3
- name: safe.directory
run: git config --global --add safe.directory /__w/uv-k5-firmware-custom/uv-k5-firmware-custom
- name: Make
run: make
- name: size
run: arm-none-eabi-size firmware
- name: 'Upload Artifact'
uses: actions/upload-artifact@v3
with:
name: firmware
path: firmware*.bin
- name: Upload binaries to release
if: ${{ startsWith(github.ref, 'refs/tags/v') }}
uses: svenstaro/upload-release-action@v2
with:
repo_token: ${{ secrets.GITHUB_TOKEN }}
file: firmware.packed.bin
asset_name: egzumer_$tag.packed.bin
tag: ${{ github.ref }}
overwrite: true
release_name: release ${{ github.ref_name }}

5
.gitignore vendored
View File

@@ -4,3 +4,8 @@ firmware
/firmware.packed.bin
/firmware.bin
/compiled-firmware
.cache
compile_commands.json
.vscode
/docs
k5_eeprom.raw

View File

@@ -1,4 +1,4 @@
FROM archlinux:latest
FROM --platform=amd64 archlinux:latest
RUN pacman -Syyu base-devel --noconfirm
RUN pacman -Syyu arm-none-eabi-gcc --noconfirm
RUN pacman -Syyu arm-none-eabi-newlib --noconfirm

17
Doxyfile Normal file
View File

@@ -0,0 +1,17 @@
OUTPUT_DIRECTORY = docs
GENERATE_LATEX = NO
GENERATE_RTF = NO
GENERATE_MAN = NO
OPTIMIZE_OUTPUT_FOR_C = YES
HAVE_DOT = YES
EXTRACT_ALL = YES
EXTRACT_PRIVATE = YES
EXTRACT_STATIC = YES
CALL_GRAPH = YES
CALLER_GRAPH = YES
DISABLE_INDEX = YES
GENERATE_TREEVIEW = YES
RECURSIVE = YES
COLLABORATION_GRAPH = YES
GRAPHICAL_HIERARCHY = YES
DOT_MULTI_TARGETS = YES

194
Makefile
View File

@@ -2,41 +2,55 @@
# compile options (see README.md for descriptions)
# 0 = disable
# 1 = enable
#
ENABLE_CLANG := 0
ENABLE_SWD := 0
ENABLE_OVERLAY := 0
ENABLE_LTO := 1
ENABLE_UART := 1
ENABLE_AIRCOPY := 0
ENABLE_FMRADIO := 1
ENABLE_NOAA := 0
ENABLE_VOICE := 0
ENABLE_VOX := 1
ENABLE_ALARM := 0
ENABLE_TX1750 := 0
ENABLE_PWRON_PASSWORD := 0
ENABLE_BIG_FREQ := 1
ENABLE_SMALL_BOLD := 1
ENABLE_KEEP_MEM_NAME := 1
ENABLE_WIDE_RX := 1
ENABLE_TX_WHEN_AM := 0
ENABLE_F_CAL_MENU := 0
ENABLE_CTCSS_TAIL_PHASE_SHIFT := 0
ENABLE_BOOT_BEEPS := 0
ENABLE_SHOW_CHARGE_LEVEL := 1
ENABLE_REVERSE_BAT_SYMBOL := 0
ENABLE_CODE_SCAN_TIMEOUT := 0
ENABLE_AM_FIX := 1
ENABLE_AM_FIX_SHOW_DATA := 0
ENABLE_SQUELCH_MORE_SENSITIVE := 1
ENABLE_FASTER_CHANNEL_SCAN := 1
ENABLE_RSSI_BAR := 1
ENABLE_AUDIO_BAR := 1
ENABLE_COPY_CHAN_TO_VFO := 1
ENABLE_SPECTRUM := 1
ENABLE_REDUCE_LOW_MID_TX_POWER:= 0
ENABLE_BYP_RAW_DEMODULATORS := 0
# ---- STOCK QUANSHENG FERATURES ----
ENABLE_UART ?= 1
ENABLE_AIRCOPY ?= 0
ENABLE_FMRADIO ?= 1
ENABLE_NOAA ?= 0
ENABLE_VOICE ?= 0
ENABLE_VOX ?= 1
ENABLE_ALARM ?= 0
ENABLE_TX1750 ?= 0
ENABLE_PWRON_PASSWORD ?= 0
ENABLE_DTMF_CALLING ?= 1
ENABLE_FLASHLIGHT ?= 1
# ---- CUSTOM MODS ----
ENABLE_BIG_FREQ ?= 1
ENABLE_SMALL_BOLD ?= 1
ENABLE_CUSTOM_MENU_LAYOUT ?= 1
ENABLE_KEEP_MEM_NAME ?= 1
ENABLE_WIDE_RX ?= 1
ENABLE_TX_WHEN_AM ?= 0
ENABLE_F_CAL_MENU ?= 0
ENABLE_CTCSS_TAIL_PHASE_SHIFT ?= 0
ENABLE_BOOT_BEEPS ?= 0
ENABLE_SHOW_CHARGE_LEVEL ?= 0
ENABLE_REVERSE_BAT_SYMBOL ?= 0
ENABLE_NO_CODE_SCAN_TIMEOUT ?= 1
ENABLE_AM_FIX ?= 1
ENABLE_SQUELCH_MORE_SENSITIVE ?= 1
ENABLE_FASTER_CHANNEL_SCAN ?= 1
ENABLE_RSSI_BAR ?= 1
ENABLE_AUDIO_BAR ?= 1
ENABLE_COPY_CHAN_TO_VFO ?= 1
ENABLE_SPECTRUM ?= 1
ENABLE_REDUCE_LOW_MID_TX_POWER?= 0
ENABLE_BYP_RAW_DEMODULATORS ?= 0
ENABLE_BLMIN_TMP_OFF ?= 0
ENABLE_SCAN_RANGES ?= 1
# ---- DEBUGGING ----
ENABLE_AM_FIX_SHOW_DATA ?= 0
ENABLE_AGC_SHOW_DATA ?= 0
ENABLE_UART_RW_BK_REGS ?= 0
# ---- COMPILER/LINKER OPTIONS ----
ENABLE_CLANG ?= 0
ENABLE_SWD ?= 0
ENABLE_OVERLAY ?= 0
ENABLE_LTO ?= 1
#############################################################
@@ -99,12 +113,16 @@ ifeq ($(ENABLE_AIRCOPY),1)
OBJS += app/aircopy.o
endif
OBJS += app/app.o
OBJS += app/chFrScanner.o
OBJS += app/common.o
OBJS += app/dtmf.o
ifeq ($(ENABLE_FLASHLIGHT),1)
OBJS += app/flashlight.o
endif
ifeq ($(ENABLE_FMRADIO),1)
OBJS += app/fm.o
endif
OBJS += app/generic.o
OBJS += app/common.o
OBJS += app/main.o
OBJS += app/menu.o
ifeq ($(ENABLE_SPECTRUM), 1)
@@ -151,24 +169,30 @@ OBJS += ui/welcome.o
OBJS += version.o
OBJS += main.o
ifeq ($(OS), Windows_NT)
TOP := $(dir $(realpath $(lastword $(MAKEFILE_LIST))))
else
TOP := $(shell pwd)
ifeq ($(OS), Windows_NT) # windows
TOP := $(dir $(realpath $(lastword $(MAKEFILE_LIST))))
RM = del /Q
FixPath = $(subst /,\,$1)
WHERE = where
NULL_OUTPUT = nul
else # unix
TOP := $(shell pwd)
RM = rm -f
FixPath = $1
WHERE = which
NULL_OUTPUT = /dev/null
endif
AS = arm-none-eabi-gcc
CC =
LD = arm-none-eabi-gcc
ifeq ($(ENABLE_CLANG),0)
CC += arm-none-eabi-gcc
CC = arm-none-eabi-gcc
# Use GCC's linker to avoid undefined symbol errors
# LD += arm-none-eabi-gcc
else
# May need to adjust this to match your system
CC += clang --sysroot=/usr/arm-none-eabi --target=arm-none-eabi
CC = clang --sysroot=/usr/arm-none-eabi --target=arm-none-eabi
# Bloats binaries to 512MB
# LD = ld.lld
endif
@@ -176,12 +200,22 @@ endif
OBJCOPY = arm-none-eabi-objcopy
SIZE = arm-none-eabi-size
AUTHOR_STRING ?= EGZUMER
# the user might not have/want git installed
# can set own version string here (max 7 chars)
GIT_HASH := $(shell git rev-parse --short HEAD)
#GIT_HASH := 230930b
ifneq (, $(shell $(WHERE) git))
VERSION_STRING ?= $(shell git describe --tags --exact-match 2>$(NULL_OUTPUT))
ifeq (, $(VERSION_STRING))
VERSION_STRING := $(shell git rev-parse --short HEAD)
endif
endif
# If there is still no VERSION_STRING we need to make one.
# It is needed for the firmware packing script
ifeq (, $(VERSION_STRING))
VERSION_STRING := NOGIT
endif
#VERSION_STRING := 230930b
$(info GIT_HASH = $(GIT_HASH))
ASFLAGS = -c -mcpu=cortex-m0
ifeq ($(ENABLE_OVERLAY),1)
@@ -190,17 +224,18 @@ endif
CFLAGS =
ifeq ($(ENABLE_CLANG),0)
CFLAGS += -Os -Wall -Werror -mcpu=cortex-m0 -fno-builtin -fshort-enums -fno-delete-null-pointer-checks -std=c11 -MMD
CFLAGS += -Os -Wall -Werror -mcpu=cortex-m0 -fno-builtin -fshort-enums -fno-delete-null-pointer-checks -std=c2x -MMD
#CFLAGS += -Os -Wall -Werror -mcpu=cortex-m0 -fno-builtin -fshort-enums -fno-delete-null-pointer-checks -std=c11 -MMD
#CFLAGS += -Os -Wall -Werror -mcpu=cortex-m0 -fno-builtin -fshort-enums -fno-delete-null-pointer-checks -std=c99 -MMD
#CFLAGS += -Os -Wall -Werror -mcpu=cortex-m0 -fno-builtin -fshort-enums -fno-delete-null-pointer-checks -std=gnu99 -MMD
#CFLAGS += -Os -Wall -Werror -mcpu=cortex-m0 -fno-builtin -fshort-enums -fno-delete-null-pointer-checks -std=gnu11 -MMD
else
# Oz needed to make it fit on flash
CFLAGS += -Oz -Wall -Werror -mcpu=cortex-m0 -fno-builtin -fshort-enums -fno-delete-null-pointer-checks -std=c11 -MMD
CFLAGS += -Oz -Wall -Werror -mcpu=cortex-m0 -fno-builtin -fshort-enums -fno-delete-null-pointer-checks -std=c2x -MMD
endif
ifeq ($(ENABLE_LTO),1)
CFLAGS += -flto=2
CFLAGS += -flto=auto
else
# We get most of the space savings if LTO creates problems
CFLAGS += -ffunction-sections -fdata-sections
@@ -214,7 +249,7 @@ CFLAGS += -Wextra
#CFLAGS += -Wpedantic
CFLAGS += -DPRINTF_INCLUDE_CONFIG_H
CFLAGS += -DGIT_HASH=\"$(GIT_HASH)\"
CFLAGS += -DAUTHOR_STRING=\"$(AUTHOR_STRING)\" -DVERSION_STRING=\"$(VERSION_STRING)\"
ifeq ($(ENABLE_SPECTRUM),1)
CFLAGS += -DENABLE_SPECTRUM
@@ -282,8 +317,8 @@ endif
ifeq ($(ENABLE_REVERSE_BAT_SYMBOL),1)
CFLAGS += -DENABLE_REVERSE_BAT_SYMBOL
endif
ifeq ($(ENABLE_CODE_SCAN_TIMEOUT),1)
CFLAGS += -DENABLE_CODE_SCAN_TIMEOUT
ifeq ($(ENABLE_NO_CODE_SCAN_TIMEOUT),1)
CFLAGS += -DENABLE_NO_CODE_SCAN_TIMEOUT
endif
ifeq ($(ENABLE_AM_FIX),1)
CFLAGS += -DENABLE_AM_FIX
@@ -291,9 +326,6 @@ endif
ifeq ($(ENABLE_AM_FIX_SHOW_DATA),1)
CFLAGS += -DENABLE_AM_FIX_SHOW_DATA
endif
ifeq ($(ENABLE_AM_FIX_TEST1),1)
CFLAGS += -DENABLE_AM_FIX_TEST1
endif
ifeq ($(ENABLE_SQUELCH_MORE_SENSITIVE),1)
CFLAGS += -DENABLE_SQUELCH_MORE_SENSITIVE
endif
@@ -324,23 +356,34 @@ endif
ifeq ($(ENABLE_BYP_RAW_DEMODULATORS),1)
CFLAGS += -DENABLE_BYP_RAW_DEMODULATORS
endif
ifeq ($(ENABLE_BLMIN_TMP_OFF),1)
CFLAGS += -DENABLE_BLMIN_TMP_OFF
endif
ifeq ($(ENABLE_SCAN_RANGES),1)
CFLAGS += -DENABLE_SCAN_RANGES
endif
ifeq ($(ENABLE_DTMF_CALLING),1)
CFLAGS += -DENABLE_DTMF_CALLING
endif
ifeq ($(ENABLE_AGC_SHOW_DATA),1)
CFLAGS += -DENABLE_AGC_SHOW_DATA
endif
ifeq ($(ENABLE_FLASHLIGHT),1)
CFLAGS += -DENABLE_FLASHLIGHT
endif
ifeq ($(ENABLE_UART_RW_BK_REGS),1)
CFLAGS += -DENABLE_UART_RW_BK_REGS
endif
ifeq ($(ENABLE_CUSTOM_MENU_LAYOUT),1)
CFLAGS += -DENABLE_CUSTOM_MENU_LAYOUT
endif
LDFLAGS =
ifeq ($(ENABLE_CLANG),0)
LDFLAGS += -mcpu=cortex-m0 -nostartfiles -Wl,-T,firmware.ld
else
# Fix warning about implied executable stack
LDFLAGS += -z noexecstack -mcpu=cortex-m0 -nostartfiles -Wl,-T,firmware.ld
endif
LDFLAGS += -z noexecstack -mcpu=cortex-m0 -nostartfiles -Wl,-T,firmware.ld -Wl,--gc-sections
# Use newlib-nano instead of newlib
LDFLAGS += --specs=nano.specs
ifeq ($(ENABLE_LTO),0)
# Throw away unneeded func/data sections like LTO does
LDFLAGS += -Wl,--gc-sections
endif
ifeq ($(DEBUG),1)
ASFLAGS += -g
CFLAGS += -g
@@ -356,17 +399,7 @@ LIBS =
DEPS = $(OBJS:.o=.d)
ifdef OS
RM = del /Q
FixPath = $(subst /,\,$1)
WHERE = where
else
ifeq ($(shell uname), Linux)
RM = rm -f
FixPath = $1
WHERE = which
endif
endif
ifneq (, $(shell $(WHERE) python))
MY_PYTHON := python
@@ -391,7 +424,7 @@ else ifneq (,$(HAS_CRCMOD))
$(info !!!!!!!! run: pip install crcmod)
$(info )
else
-$(MY_PYTHON) fw-pack.py $<.bin $(GIT_HASH) $<.packed.bin
-$(MY_PYTHON) fw-pack.py $<.bin $(AUTHOR_STRING) $(VERSION_STRING) $<.packed.bin
endif
$(SIZE) $<
@@ -421,3 +454,6 @@ bsp/dp32g030/%.h: hardware/dp32g030/%.def
clean:
$(RM) $(call FixPath, $(TARGET).bin $(TARGET).packed.bin $(TARGET) $(OBJS) $(DEPS))
doxygen:
doxygen

238
README.md
View File

@@ -1,38 +1,67 @@
# Main features:
- many of OneOfEleven mods, including AM fix
- fagci spectrum analyzer (**F+5** to turn on)
- some other mods introduced by me
# Open re-implementation of the Quansheng UV-K5/K6/5R v2.1.27 firmware
# Manual
This repository is a merge of [OneOfEleven custom firmware](https://github.com/OneOfEleven/uv-k5-firmware-custom) with [fagci spectrum analizer](https://github.com/fagci/uv-k5-firmware-fagci-mod/tree/refactor) plus my few changes.<br>
All is a cloned and customized version of DualTachyon's open firmware found [here](https://github.com/DualTachyon/uv-k5-firmware) ... a cool achievement !
* [Radio operation](https://github.com/egzumer/uv-k5-firmware-custom/wiki/Radio-operation)
> [!TIP]
> There is a work done by others on forks of this repository. I encourage you to take a look at those too.
You can use below links to see comparison between forks.<br>
https://gitpop2.vercel.app/egzumer/uv-k5-firmware-custom<br>
https://useful-forks.github.io/?repo=egzumer/uv-k5-firmware-custom
* [Menu](https://github.com/egzumer/uv-k5-firmware-custom/wiki/Menu)
* [Button functions](https://github.com/egzumer/uv-k5-firmware-custom/wiki/Button-functions)
* [Spectrum analyzer](https://github.com/egzumer/uv-k5-firmware-custom/wiki/Spectrum-analyzer)
* [Flashing the firmware](https://github.com/egzumer/uv-k5-firmware-custom/wiki/Flashing-the-firmware)
<img src="images/main.jpg" width=300 /><img src="images/spectrum.jpg" width=300 /><img src="images/audiobar.jpg" width=300 /><img src="images/rssibar.jpg" width=300 />
# Open reimplementation of the Quan Sheng UV-K5 v2.1.27 firmware
This repository is a merge of OneOfEleven custom firmware with fagci spectrum analizer plus my few changes.
https://github.com/OneOfEleven/uv-k5-firmware-custom<br>
https://github.com/fagci/uv-k5-firmware-fagci-mod/tree/refactor
All is a cloned and customized version of DualTachyon's open firmware found here ..
https://github.com/DualTachyon/uv-k5-firmware .. a cool achievement !
Use this firmware at your own risk (entirely). There is absolutely no guarantee that it will work in any way shape or form on your radio(s), it may even brick your radio(s), in which case, you'd need to buy another radio.
> [!WARNING]
> Use this firmware at your own risk (entirely). There is absolutely no guarantee that it will work in any way shape or form on your radio(s), it may even brick your radio(s), in which case, you'd need to buy another radio.
Anyway, have fun.
# Radio performance
## Table of Contents
* [Main Features](#main-features)
* [Manual](#manual)
* [Radio Performance](#radio-performance)
* [User Customization](#user-customization)
* [Compiler](#compiler)
* [Building](#building)
* [Credits](#credits)
* [Other sources of information](#other-sources-of-information)
* [License](#license)
* [Example changes/updates](#example-changesupdates)
## Main features:
* many of OneOfEleven mods:
* AM fix, huge improvement in reception quality
* long press buttons functions replicating F+ action
* fast scanning
* channel name editing in the menu
* channel name + frequency display option
* shortcut for scan-list assignment (long press `5 NOAA`)
* scan-list toggle (long press `* Scan` while scanning)
* configurable button function selectable from menu
* battery percentage/voltage on status bar, selectable from menu
* longer backlight times
* mic bar
* RSSI s-meter
* more frequency steps
* squelch more sensitive
* fagci spectrum analyzer (**F+5** to turn on)
* some other mods introduced by me:
* SSB demodulation (adopted from fagci)
* backlight dimming
* battery voltage calibration from menu
* better battery percentage calculation, selectable for 1600mAh or 2200mAh
* more configurable button functions
* long press MENU as another configurable button
* better DCS/CTCSS scanning in the menu (`* SCAN` while in RX DCS/CTCSS menu item)
* Piotr022 style s-meter
* restore initial freq/channel when scanning stopped with EXIT, remember last found transmission with MENU button
* reordered and renamed menu entries
* LCD interference crash fix
* many others...
## Manual
Up to date manual is available in the [Wiki section](https://github.com/egzumer/uv-k5-firmware-custom/wiki)
## Radio performance
Please note that the Quansheng UV-Kx radios are not professional quality transceivers, their
performance is strictly limited. The RX front end has no track-tuned band pass filtering
@@ -43,77 +72,68 @@ easy (AM mode will suffer far more than FM ever will), the receiver simply doesn
great dynamic range, which results in distorted AM audio with stronger RX'ed signals.
There is nothing more anyone can do in firmware/software to improve that, once the RX gain
adjustment I do (AM fix) reaches the hardwares limit, your AM RX audio will be all but
non-existant (just like Quansheng's firmware).
non-existent (just like Quansheng's firmware).
On the other hand, FM RX audio will/should be fine.
But, they are nice toys for the price, fun to play with.
# User customization
## User customization
You can customize the firmware by enabling/disabling various compile options, this allows
us to remove certain firmware features in order to make room in the flash for others.
You'll find the options at the top of "Makefile" ('0' = disable, '1' = enable) ..
```
ENABLE_CLANG := 0 **experimental, builds with clang instead of gcc (LTO will be disabled if you enable this)
ENABLE_SWD := 0 only needed if using CPU's SWD port (debugging/programming)
ENABLE_OVERLAY := 0 cpu FLASH stuff, not needed
ENABLE_LTO := 0 **experimental, reduces size of compiled firmware but might break EEPROM reads (OVERLAY will be disabled if you enable this)
ENABLE_UART := 1 without this you can't configure radio via PC !
ENABLE_AIRCOPY := 0 easier to just enter frequency with butts
ENABLE_FMRADIO := 0 WBFM VHF broadcast band receiver
ENABLE_NOAA := 0 everything NOAA (only of any use in the USA)
ENABLE_VOICE := 0 want to hear voices ?
ENABLE_VOX := 0
ENABLE_ALARM := 0 TX alarms
ENABLE_1750HZ := 0 side key 1750Hz TX tone (older style repeater access)
ENABLE_PWRON_PASSWORD := 1 power-on password stuff
ENABLE_BIG_FREQ := 0 big font frequencies (like original QS firmware)
ENABLE_SMALL_BOLD := 1 bold channel name/no. (when name + freq channel display mode)
ENABLE_KEEP_MEM_NAME := 1 maintain channel name when (re)saving memory channel
ENABLE_WIDE_RX := 1 full 18MHz to 1300MHz RX (though front-end/PA not designed for full range)
ENABLE_TX_WHEN_AM := 0 allow TX (always FM) when RX is set to AM
ENABLE_F_CAL_MENU := 0 enable/disable the radios hidden frequency calibration menu
ENABLE_CTCSS_TAIL_PHASE_SHIFT := 1 standard CTCSS tail phase shift rather than QS's own 55Hz tone method
ENABLE_BOOT_BEEPS := 0 gives user audio feedback on volume knob position at boot-up
ENABLE_SHOW_CHARGE_LEVEL := 0 show the charge level when the radio is on charge
ENABLE_REVERSE_BAT_SYMBOL := 1 mirror the battery symbol on the status bar (+ pole on the right)
ENABLE_CODE_SCAN_TIMEOUT := 0 enable/disable 32-sec CTCSS/DCS scan timeout (press exit butt instead of time-out to end scan)
ENABLE_AM_FIX := 1 dynamically adjust the front end gains when in AM mode to helo prevent AM demodulator saturation, ignore the on-screen RSSI level (for now)
ENABLE_AM_FIX_SHOW_DATA := 1 show debug data for the AM fix (still tweaking it)
ENABLE_SQUELCH_MORE_SENSITIVE := 0 make squelch levels a little bit more sensitive - I plan to let user adjust the values themselves
ENABLE_FASTER_CHANNEL_SCAN := 0 increases the channel scan speed, but the squelch is also made more twitchy
ENABLE_RSSI_BAR := 1 enable a dBm/Sn RSSI bar graph level inplace of the little antenna symbols
ENABLE_AUDIO_BAR := 0 experimental, display an audo bar level when TX'ing
ENABLE_COPY_CHAN_TO_VFO := 1 copy current channel into the other VFO. Long press Menu key ('M')
#ENABLE_SINGLE_VFO_CHAN := 1 not yet implemented - single VFO on display when possible
#ENABLE_BAND_SCOPE := 1 not yet implemented - spectrum/pan-adapter
```
# New/modified function keys
|Build option | Description |
| --- | ---- |
|🧰 **STOCK QUANSHENG FERATURES**||
| ENABLE_UART | without this you can't configure radio via PC ! |
| ENABLE_AIRCOPY | easier to just enter frequency with butts |
| ENABLE_FMRADIO | WBFM VHF broadcast band receiver |
| ENABLE_NOAA | everything NOAA (only of any use in the USA) |
| ENABLE_VOICE | want to hear voices ? |
| ENABLE_VOX | |
| ENABLE_ALARM | TX alarms |
| ENABLE_TX1750 | side key 1750Hz TX tone (older style repeater access)|
| ENABLE_PWRON_PASSWORD | power-on password stuff |
| ENABLE_DTMF_CALLING | DTMF calling fuctionality, sending calls, receiving calls, group calls, contacts list etc. |
| ENABLE_FLASHLIGHT | enable top flashlight LED (on, blink, SOS) |
|🧰 **CUSTOM MODS**||
| ENABLE_BIG_FREQ | big font frequencies (like original QS firmware) |
| ENABLE_SMALL_BOLD | bold channel name/no. (when name + freq channel display mode) |
| ENABLE_CUSTOM_MENU_LAYOUT | changes how the menu looks like |
| ENABLE_KEEP_MEM_NAME | maintain channel name when (re)saving memory channel|
| ENABLE_WIDE_RX | full 18MHz to 1300MHz RX (though front-end/PA not designed for full range)|
| ENABLE_TX_WHEN_AM | allow TX (always FM) when RX is set to AM|
| ENABLE_F_CAL_MENU | enable the radios hidden frequency calibration menu |
| ENABLE_CTCSS_TAIL_PHASE_SHIFT | standard CTCSS tail phase shift rather than QS's own 55Hz tone method|
| ENABLE_BOOT_BEEPS | gives user audio feedback on volume knob position at boot-up |
| ENABLE_SHOW_CHARGE_LEVEL | show the charge level when the radio is on charge |
| ENABLE_REVERSE_BAT_SYMBOL | mirror the battery symbol on the status bar (+ pole on the right) |
| ENABLE_NO_CODE_SCAN_TIMEOUT | disable 32-sec CTCSS/DCS scan timeout (press exit butt instead of time-out to end scan) |
| ENABLE_AM_FIX | dynamically adjust the front end gains when in AM mode to help prevent AM demodulator saturation, ignore the on-screen RSSI level (for now) |
| ENABLE_AM_FIX_SHOW_DATA | show debug data for the AM fix |
| ENABLE_SQUELCH_MORE_SENSITIVE | make squelch levels a little bit more sensitive - I plan to let user adjust the values themselves |
| ENABLE_FASTER_CHANNEL_SCAN | increases the channel scan speed, but the squelch is also made more twitchy |
| ENABLE_RSSI_BAR | enable a dBm/Sn RSSI bar graph level in place of the little antenna symbols |
| ENABLE_AUDIO_BAR | experimental, display an audio bar level when TX'ing |
| ENABLE_COPY_CHAN_TO_VFO | copy current channel settings into frequency mode. Long press `1 BAND` when in channel mode |
| ENABLE_SPECTRUM | fagci spectrum analyzer, activated with `F` + `5 NOAA`|
| ENABLE_REDUCE_LOW_MID_TX_POWER | makes medium and low power settings even lower |
| ENABLE_BYP_RAW_DEMODULATORS | additional BYP (bypass?) and RAW demodulation options, proved not to be very useful, but it is there if you want to experiment |
| ENABLE_BLMIN_TMP_OFF | additional function for configurable buttons that toggles `BLMin` on and off wihout saving it to the EEPROM |
| ENABLE_SCAN_RANGES | scan range mode for frequency scanning, see wiki for instructions (radio operation -> frequency scanning) |
|🧰 **DEBUGGING** ||
| ENABLE_AM_FIX_SHOW_DATA| displays settings used by AM-fix when AM transmission is received |
| ENABLE_AGC_SHOW_DATA | displays AGC settings |
| ENABLE_UART_RW_BK_REGS | adds 2 extra commands that allow to read and write BK4819 registers |
|🧰 **COMPILER/LINKER OPTIONS**||
| ENABLE_CLANG | **experimental, builds with clang instead of gcc (LTO will be disabled if you enable this) |
| ENABLE_SWD | only needed if using CPU's SWD port (debugging/programming) |
| ENABLE_OVERLAY | cpu FLASH stuff, not needed |
| ENABLE_LTO | reduces size of compiled firmware but might break EEPROM reads (OVERLAY will be disabled if you enable this) |
* Long-press 'M' .. Copy selected channel into same VFO, then switch VFO to frequency mode
*
* Long-press '7' .. Toggle selected channel scanlist setting .. if VOX is disabled in Makefile
* or
* Long-press '5' .. Toggle selected channel scanlist setting .. if NOAA is disabled in Makefile
*
* Long-press '*' .. Start scanning, then toggles the scanning between scanlists 1, 2 or ALL channels
# Some changes made from the Quansheng firmware
* Various Quansheng firmware bugs fixed
* Added new bugs
* Mic menu includes max gain possible
* AM RX everywhere (left the TX as is)
* An attempt to improve the AM RX audio (demodulator getting saturated/overloaded in Quansheng firmware)
* keypad-5/NOAA button now toggles scanlist-1 on/off for current channel when held down - IF NOAA not used
* Better backlight times (inc always on)
* Live DTMF decoder option, though the decoder needs some coeff tuning changes to decode other radios it seems
* Various menu re-wordings (trying to reduce 'WTH does that mean ?')
* ..
# Compiler
## Compiler
arm-none-eabi GCC version 10.3.1 is recommended, which is the current version on Ubuntu 22.04.03 LTS.
Other versions may generate a flash file that is too big.
@@ -122,12 +142,33 @@ You can get an appropriate version from: https://developer.arm.com/downloads/-/g
clang may be used but isn't fully supported. Resulting binaries may also be bigger.
You can get it from: https://releases.llvm.org/download.html
# Building
## Building
If you have docker installed you can use `compile-with-docker.bat`, the output files are created in `compiled-firmware` folder. This method gives significantly smaller binaries, I've seen differences up to 1kb, so it can fit more functionalities this way. The challange can be (or not) installing the docker itself.
### Github Codespace build method
This is the least demanding option as you don't have to install enything on your computer. All you need is Github account.
To compile directly in windows:
1. Go to https://github.com/egzumer/uv-k5-firmware-custom
1. Click green `Code` button
1. Change tab from `Local` to `Codespace`
1. Click green `Create codespace on main` button
<img src="images/codespace1.png" width=700 />
5. Open `Makefile`
1. Edit build options, save `Makefile` changes
1. Run `./compile-with-docker.sh` in terminal window
1. Open folder `compiled-firmware`
1. Right click `firmware.packed.bin`
1. Click `Download`, now you should have a firmware on your computer that you can proceed to flash on your radio. You can use [online flasher](https://egzumer.github.io/uvtools)
<img src="images/codespace2.png" width=700 />
### Docker build method
If you have docker installed you can use [compile-with-docker.bat](./compile-with-docker.bat) (Windows) or [compile-with-docker.sh](./compile-with-docker.sh) (Linux/Mac), the output files are created in `compiled-firmware` folder. This method gives significantly smaller binaries, I've seen differences up to 1kb, so it can fit more functionalities this way. The challenge can be (or not) installing docker itself.
### Windows environment build method
1. Open windows command line and run:
```
@@ -154,7 +195,7 @@ To compile directly in windows:
I've left some notes in the win_make.bat file to maybe help with stuff.
# Credits
## Credits
Many thanks to various people on Telegram for putting up with me during this effort and helping:
@@ -172,7 +213,12 @@ Many thanks to various people on Telegram for putting up with me during this eff
* @d1ced95
* and others I forget
# License
## Other sources of information
[ludwich66 - Quansheng UV-K5 Wiki](https://github.com/ludwich66/Quansheng_UV-K5_Wiki/wiki)<br>
[amnemonic - tools and sources of information](https://github.com/amnemonic/Quansheng_UV-K5_Firmware)
## License
Copyright 2023 Dual Tachyon
https://github.com/DualTachyon
@@ -189,7 +235,7 @@ You may obtain a copy of the License at
See the License for the specific language governing permissions and
limitations under the License.
# Example changes/updates
## Example changes/updates
<p float="left">
<img src="/images/image1.png" width=300 />

790
am_fix.c
View File

@@ -29,461 +29,423 @@
#include "frequencies.h"
#include "functions.h"
#include "misc.h"
#include "settings.h"
#ifdef ENABLE_AGC_SHOW_DATA
#include "ui/main.h"
#endif
#ifdef ENABLE_AM_FIX
typedef struct
{
uint16_t reg_val;
int8_t gain_dB;
} __attribute__((packed)) t_gain_table;
typedef struct
{
uint16_t reg_val;
int8_t gain_dB;
} __attribute__((packed)) t_gain_table;
// REG_10 AGC gain table
//
// <15:10> ???
//
// <9:8> = LNA Gain Short
// 3 = 0dB < original value
// 2 = -24dB // was -11
// 1 = -30dB // was -16
// 0 = -33dB // was -19
//
// <7:5> = LNA Gain
// 7 = 0dB
// 6 = -2dB
// 5 = -4dB < original value
// 4 = -6dB
// 3 = -9dB
// 2 = -14dB
// 1 = -19dB
// 0 = -24dB
//
// <4:3> = MIXER Gain
// 3 = 0dB < original value
// 2 = -3dB
// 1 = -6dB
// 0 = -8dB
//
// <2:0> = PGA Gain
// 7 = 0dB
// 6 = -3dB < original value
// 5 = -6dB
// 4 = -9dB
// 3 = -15dB
// 2 = -21dB
// 1 = -27dB
// 0 = -33dB
// REG_10 AGC gain table
//
// <15:10> ???
//
// <9:8> = LNA Gain Short
// 3 = 0dB < original value
// 2 = -19dB // was -11
// 1 = -24dB // was -16
// 0 = -28dB // was -19
//
// <7:5> = LNA Gain
// 7 = 0dB
// 6 = -2dB
// 5 = -4dB < original value
// 4 = -6dB
// 3 = -9dB
// 2 = -14dB
// 1 = -19dB
// 0 = -24dB
//
// <4:3> = MIXER Gain
// 3 = 0dB < original value
// 2 = -3dB
// 1 = -6dB
// 0 = -8dB
//
// <2:0> = PGA Gain
// 7 = 0dB
// 6 = -3dB < original value
// 5 = -6dB
// 4 = -9dB
// 3 = -15dB
// 2 = -21dB
// 1 = -27dB
// 0 = -33dB
// front end register dB values
//
// these values need to be accurate for the code to properly/reliably switch
// between table entries when adjusting the front end registers.
//
// these 4 tables need a measuring/calibration update
//
//
// QUESTION: why do I have to surround the negative numbers in brackets ???
// if I don't add the brackets, reading the table returns unexpected/different values !!!
//
//
// front end register dB values
//
// these values need to be accurate for the code to properly/reliably switch
// between table entries when adjusting the front end registers.
//
// these 4 tables need a measuring/calibration update
//
//// static const int16_t lna_short_dB[] = { -19, -16, -11, 0}; // was (but wrong)
// static const int16_t lna_short_dB[] = { (-33), (-30), (-24), 0}; // corrected'ish
// static const int16_t lna_short_dB[] = { (-28), (-24), (-19), 0}; // corrected'ish
// static const int16_t lna_dB[] = { (-24), (-19), (-14), ( -9), (-6), (-4), (-2), 0};
// static const int16_t mixer_dB[] = { ( -8), ( -6), ( -3), 0};
// static const int16_t pga_dB[] = { (-33), (-27), (-21), (-15), (-9), (-6), (-3), 0};
// lookup table is hugely easier than writing code to do the same
//
static const t_gain_table gain_table[] =
{
{0x035E, -17}, // 0 .. 3 2 3 6 .. 0dB -14dB 0dB -3dB .. -17dB original
// lookup table is hugely easier than writing code to do the same
//
#ifdef ENABLE_AM_FIX_TEST1
#define LOOKUP_TABLE 1
// test table that lets me manually set the lna-short register
// to measure it's actual dB change using an RF signal generator
#if LOOKUP_TABLE
static const t_gain_table gain_table[] =
{
{0x03BE, -7}, // 0 .. 3 5 3 6 .. 0dB -4dB 0dB -3dB .. -7dB original
{0x005E, -50}, // 1 .. 0 2 3 6 .. -33dB -14dB 0dB -3dB .. -50dB
{0x015E, -47}, // 2 .. 1 2 3 6 .. -30dB -14dB 0dB -3dB .. -47dB
{0x025E, -41}, // 3 .. 2 2 3 6 .. -24dB -14dB 0dB -3dB .. -41dB
{0x035E, -17} // 4 .. 3 2 3 6 .. 0dB -14dB 0dB -3dB .. -17dB original
};
static const unsigned int original_index = 1;
{0x0000, -98}, // 1 .. 0 0 0 0 .. -33dB -24dB -8dB -33dB .. -98dB
{0x0008, -96}, // 2 .. 0 0 1 0 .. -33dB -24dB -6dB -33dB .. -96dB
{0x0100, -95}, // 3 .. 1 0 0 0 .. -30dB -24dB -8dB -33dB .. -95dB
{0x0020, -93}, // 4 .. 0 1 0 0 .. -33dB -19dB -8dB -33dB .. -93dB
{0x0001, -92}, // 5 .. 0 0 0 1 .. -33dB -24dB -8dB -27dB .. -92dB
{0x0028, -91}, // 6 .. 0 1 1 0 .. -33dB -19dB -6dB -33dB .. -91dB
{0x0009, -90}, // 7 .. 0 0 1 1 .. -33dB -24dB -6dB -27dB .. -90dB
{0x0101, -89}, // 8 .. 1 0 0 1 .. -30dB -24dB -8dB -27dB .. -89dB
{0x0030, -88}, // 9 .. 0 1 2 0 .. -33dB -19dB -3dB -33dB .. -88dB
{0x0118, -87}, // 10 .. 1 0 3 0 .. -30dB -24dB 0dB -33dB .. -87dB
{0x0002, -86}, // 11 .. 0 0 0 2 .. -33dB -24dB -8dB -21dB .. -86dB
{0x0130, -85}, // 12 .. 1 1 2 0 .. -30dB -19dB -3dB -33dB .. -85dB
{0x0019, -84}, // 13 .. 0 0 3 1 .. -33dB -24dB 0dB -27dB .. -84dB
{0x0060, -83}, // 14 .. 0 3 0 0 .. -33dB -9dB -8dB -33dB .. -83dB
{0x0138, -82}, // 15 .. 1 1 3 0 .. -30dB -19dB 0dB -33dB .. -82dB
{0x0119, -81}, // 16 .. 1 0 3 1 .. -30dB -24dB 0dB -27dB .. -81dB
{0x0058, -80}, // 17 .. 0 2 3 0 .. -33dB -14dB 0dB -33dB .. -80dB
{0x0141, -79}, // 18 .. 1 2 0 1 .. -30dB -14dB -8dB -27dB .. -79dB
{0x0070, -78}, // 19 .. 0 3 2 0 .. -33dB -9dB -3dB -33dB .. -78dB
{0x0180, -77}, // 20 .. 1 4 0 0 .. -30dB -6dB -8dB -33dB .. -77dB
{0x0139, -76}, // 21 .. 1 1 3 1 .. -30dB -19dB 0dB -27dB .. -76dB
{0x0013, -75}, // 22 .. 0 0 2 3 .. -33dB -24dB -3dB -15dB .. -75dB
{0x0161, -74}, // 23 .. 1 3 0 1 .. -30dB -9dB -8dB -27dB .. -74dB
{0x01C0, -73}, // 24 .. 1 6 0 0 .. -30dB -2dB -8dB -33dB .. -73dB
{0x00E8, -72}, // 25 .. 0 7 1 0 .. -33dB 0dB -6dB -33dB .. -72dB
{0x00D0, -71}, // 26 .. 0 6 2 0 .. -33dB -2dB -3dB -33dB .. -71dB
{0x0239, -70}, // 27 .. 2 1 3 1 .. -24dB -19dB 0dB -27dB .. -70dB
{0x006A, -69}, // 28 .. 0 3 1 2 .. -33dB -9dB -6dB -21dB .. -69dB
{0x0006, -68}, // 29 .. 0 0 0 6 .. -33dB -24dB -8dB -3dB .. -68dB
{0x00B1, -67}, // 30 .. 0 5 2 1 .. -33dB -4dB -3dB -27dB .. -67dB
{0x000E, -66}, // 31 .. 0 0 1 6 .. -33dB -24dB -6dB -3dB .. -66dB
{0x015A, -65}, // 32 .. 1 2 3 2 .. -30dB -14dB 0dB -21dB .. -65dB
{0x022B, -64}, // 33 .. 2 1 1 3 .. -24dB -19dB -6dB -15dB .. -64dB
{0x01F8, -63}, // 34 .. 1 7 3 0 .. -30dB 0dB 0dB -33dB .. -63dB
{0x0163, -62}, // 35 .. 1 3 0 3 .. -30dB -9dB -8dB -15dB .. -62dB
{0x0035, -61}, // 36 .. 0 1 2 5 .. -33dB -19dB -3dB -6dB .. -61dB
{0x0214, -60}, // 37 .. 2 0 2 4 .. -24dB -24dB -3dB -9dB .. -60dB
{0x01D9, -59}, // 38 .. 1 6 3 1 .. -30dB -2dB 0dB -27dB .. -59dB
{0x0145, -58}, // 39 .. 1 2 0 5 .. -30dB -14dB -8dB -6dB .. -58dB
{0x02A2, -57}, // 40 .. 2 5 0 2 .. -24dB -4dB -8dB -21dB .. -57dB
{0x02D1, -56}, // 41 .. 2 6 2 1 .. -24dB -2dB -3dB -27dB .. -56dB
{0x00B3, -55}, // 42 .. 0 5 2 3 .. -33dB -4dB -3dB -15dB .. -55dB
{0x0216, -54}, // 43 .. 2 0 2 6 .. -24dB -24dB -3dB -3dB .. -54dB
{0x0066, -53}, // 44 .. 0 3 0 6 .. -33dB -9dB -8dB -3dB .. -53dB
{0x00C4, -52}, // 45 .. 0 6 0 4 .. -33dB -2dB -8dB -9dB .. -52dB
{0x006E, -51}, // 46 .. 0 3 1 6 .. -33dB -9dB -6dB -3dB .. -51dB
{0x015D, -50}, // 47 .. 1 2 3 5 .. -30dB -14dB 0dB -6dB .. -50dB
{0x00AD, -49}, // 48 .. 0 5 1 5 .. -33dB -4dB -6dB -6dB .. -49dB
{0x007D, -48}, // 49 .. 0 3 3 5 .. -33dB -9dB 0dB -6dB .. -48dB
{0x00D4, -47}, // 50 .. 0 6 2 4 .. -33dB -2dB -3dB -9dB .. -47dB
{0x01B4, -46}, // 51 .. 1 5 2 4 .. -30dB -4dB -3dB -9dB .. -46dB
{0x030B, -45}, // 52 .. 3 0 1 3 .. 0dB -24dB -6dB -15dB .. -45dB
{0x00CE, -44}, // 53 .. 0 6 1 6 .. -33dB -2dB -6dB -3dB .. -44dB
{0x01B5, -43}, // 54 .. 1 5 2 5 .. -30dB -4dB -3dB -6dB .. -43dB
{0x0097, -42}, // 55 .. 0 4 2 7 .. -33dB -6dB -3dB 0dB .. -42dB
{0x0257, -41}, // 56 .. 2 2 2 7 .. -24dB -14dB -3dB 0dB .. -41dB
{0x02B4, -40}, // 57 .. 2 5 2 4 .. -24dB -4dB -3dB -9dB .. -40dB
{0x027D, -39}, // 58 .. 2 3 3 5 .. -24dB -9dB 0dB -6dB .. -39dB
{0x01DD, -38}, // 59 .. 1 6 3 5 .. -30dB -2dB 0dB -6dB .. -38dB
{0x02AE, -37}, // 60 .. 2 5 1 6 .. -24dB -4dB -6dB -3dB .. -37dB
{0x0379, -36}, // 61 .. 3 3 3 1 .. 0dB -9dB 0dB -27dB .. -36dB
{0x035A, -35}, // 62 .. 3 2 3 2 .. 0dB -14dB 0dB -21dB .. -35dB
{0x02B6, -34}, // 63 .. 2 5 2 6 .. -24dB -4dB -3dB -3dB .. -34dB
{0x030E, -33}, // 64 .. 3 0 1 6 .. 0dB -24dB -6dB -3dB .. -33dB
{0x0307, -32}, // 65 .. 3 0 0 7 .. 0dB -24dB -8dB 0dB .. -32dB
{0x02BE, -31}, // 66 .. 2 5 3 6 .. -24dB -4dB 0dB -3dB .. -31dB
{0x037A, -30}, // 67 .. 3 3 3 2 .. 0dB -9dB 0dB -21dB .. -30dB
{0x02DE, -29}, // 68 .. 2 6 3 6 .. -24dB -2dB 0dB -3dB .. -29dB
{0x0345, -28}, // 69 .. 3 2 0 5 .. 0dB -14dB -8dB -6dB .. -28dB
{0x03A3, -27}, // 70 .. 3 5 0 3 .. 0dB -4dB -8dB -15dB .. -27dB
{0x0364, -26}, // 71 .. 3 3 0 4 .. 0dB -9dB -8dB -9dB .. -26dB
{0x032F, -25}, // 72 .. 3 1 1 7 .. 0dB -19dB -6dB 0dB .. -25dB
{0x0393, -24}, // 73 .. 3 4 2 3 .. 0dB -6dB -3dB -15dB .. -24dB
{0x0384, -23}, // 74 .. 3 4 0 4 .. 0dB -6dB -8dB -9dB .. -23dB
{0x0347, -22}, // 75 .. 3 2 0 7 .. 0dB -14dB -8dB 0dB .. -22dB
{0x03EB, -21}, // 76 .. 3 7 1 3 .. 0dB 0dB -6dB -15dB .. -21dB
{0x03D3, -20}, // 77 .. 3 6 2 3 .. 0dB -2dB -3dB -15dB .. -20dB
{0x03BB, -19}, // 78 .. 3 5 3 3 .. 0dB -4dB 0dB -15dB .. -19dB
{0x037C, -18}, // 79 .. 3 3 3 4 .. 0dB -9dB 0dB -9dB .. -18dB
{0x03CC, -17}, // 80 .. 3 6 1 4 .. 0dB -2dB -6dB -9dB .. -17dB
{0x03C5, -16}, // 81 .. 3 6 0 5 .. 0dB -2dB -8dB -6dB .. -16dB
{0x03EC, -15}, // 82 .. 3 7 1 4 .. 0dB 0dB -6dB -9dB .. -15dB
{0x035F, -14}, // 83 .. 3 2 3 7 .. 0dB -14dB 0dB 0dB .. -14dB
{0x03BC, -13}, // 84 .. 3 5 3 4 .. 0dB -4dB 0dB -9dB .. -13dB
{0x038F, -12}, // 85 .. 3 4 1 7 .. 0dB -6dB -6dB 0dB .. -12dB
{0x03E6, -11}, // 86 .. 3 7 0 6 .. 0dB 0dB -8dB -3dB .. -11dB
{0x03AF, -10}, // 87 .. 3 5 1 7 .. 0dB -4dB -6dB 0dB .. -10dB
{0x03F5, -9}, // 88 .. 3 7 2 5 .. 0dB 0dB -3dB -6dB .. -9dB
{0x03D6, -8}, // 89 .. 3 6 2 6 .. 0dB -2dB -3dB -3dB .. -8dB
{0x03BE, -7}, // 90 .. 3 5 3 6 .. 0dB -4dB 0dB -3dB .. -7dB original
{0x03F6, -6}, // 91 .. 3 7 2 6 .. 0dB 0dB -3dB -3dB .. -6dB
{0x03DE, -5}, // 92 .. 3 6 3 6 .. 0dB -2dB 0dB -3dB .. -5dB
{0x03BF, -4}, // 93 .. 3 5 3 7 .. 0dB -4dB 0dB 0dB .. -4dB
{0x03F7, -3}, // 94 .. 3 7 2 7 .. 0dB 0dB -3dB 0dB .. -3dB
{0x03DF, -2}, // 95 .. 3 6 3 7 .. 0dB -2dB 0dB 0dB .. -2dB
{0x03FF, 0}, // 96 .. 3 7 3 7 .. 0dB 0dB 0dB 0dB .. 0dB
};
const uint8_t gain_table_size = ARRAY_SIZE(gain_table);
#else
{0x0000, -98}, // 1 .. 0 0 0 0 .. -33dB -24dB -8dB -33dB .. -98dB
{0x0008, -96}, // 2 .. 0 0 1 0 .. -33dB -24dB -6dB -33dB .. -96dB
{0x0100, -95}, // 3 .. 1 0 0 0 .. -30dB -24dB -8dB -33dB .. -95dB
{0x0020, -93}, // 4 .. 0 1 0 0 .. -33dB -19dB -8dB -33dB .. -93dB
{0x0001, -92}, // 5 .. 0 0 0 1 .. -33dB -24dB -8dB -27dB .. -92dB
{0x0028, -91}, // 6 .. 0 1 1 0 .. -33dB -19dB -6dB -33dB .. -91dB
{0x0009, -90}, // 7 .. 0 0 1 1 .. -33dB -24dB -6dB -27dB .. -90dB
{0x0101, -89}, // 8 .. 1 0 0 1 .. -30dB -24dB -8dB -27dB .. -89dB
{0x0030, -88}, // 9 .. 0 1 2 0 .. -33dB -19dB -3dB -33dB .. -88dB
{0x0118, -87}, // 10 .. 1 0 3 0 .. -30dB -24dB 0dB -33dB .. -87dB
{0x0002, -86}, // 11 .. 0 0 0 2 .. -33dB -24dB -8dB -21dB .. -86dB
{0x0130, -85}, // 12 .. 1 1 2 0 .. -30dB -19dB -3dB -33dB .. -85dB
{0x0019, -84}, // 13 .. 0 0 3 1 .. -33dB -24dB 0dB -27dB .. -84dB
{0x0060, -83}, // 14 .. 0 3 0 0 .. -33dB -9dB -8dB -33dB .. -83dB
{0x0138, -82}, // 15 .. 1 1 3 0 .. -30dB -19dB 0dB -33dB .. -82dB
{0x0119, -81}, // 16 .. 1 0 3 1 .. -30dB -24dB 0dB -27dB .. -81dB
{0x0058, -80}, // 17 .. 0 2 3 0 .. -33dB -14dB 0dB -33dB .. -80dB
{0x0141, -79}, // 18 .. 1 2 0 1 .. -30dB -14dB -8dB -27dB .. -79dB
{0x0070, -78}, // 19 .. 0 3 2 0 .. -33dB -9dB -3dB -33dB .. -78dB
{0x0180, -77}, // 20 .. 1 4 0 0 .. -30dB -6dB -8dB -33dB .. -77dB
{0x0139, -76}, // 21 .. 1 1 3 1 .. -30dB -19dB 0dB -27dB .. -76dB
{0x0013, -75}, // 22 .. 0 0 2 3 .. -33dB -24dB -3dB -15dB .. -75dB
{0x0161, -74}, // 23 .. 1 3 0 1 .. -30dB -9dB -8dB -27dB .. -74dB
{0x01C0, -73}, // 24 .. 1 6 0 0 .. -30dB -2dB -8dB -33dB .. -73dB
{0x00E8, -72}, // 25 .. 0 7 1 0 .. -33dB 0dB -6dB -33dB .. -72dB
{0x00D0, -71}, // 26 .. 0 6 2 0 .. -33dB -2dB -3dB -33dB .. -71dB
{0x0239, -70}, // 27 .. 2 1 3 1 .. -24dB -19dB 0dB -27dB .. -70dB
{0x006A, -69}, // 28 .. 0 3 1 2 .. -33dB -9dB -6dB -21dB .. -69dB
{0x0006, -68}, // 29 .. 0 0 0 6 .. -33dB -24dB -8dB -3dB .. -68dB
{0x00B1, -67}, // 30 .. 0 5 2 1 .. -33dB -4dB -3dB -27dB .. -67dB
{0x000E, -66}, // 31 .. 0 0 1 6 .. -33dB -24dB -6dB -3dB .. -66dB
{0x015A, -65}, // 32 .. 1 2 3 2 .. -30dB -14dB 0dB -21dB .. -65dB
{0x022B, -64}, // 33 .. 2 1 1 3 .. -24dB -19dB -6dB -15dB .. -64dB
{0x01F8, -63}, // 34 .. 1 7 3 0 .. -30dB 0dB 0dB -33dB .. -63dB
{0x0163, -62}, // 35 .. 1 3 0 3 .. -30dB -9dB -8dB -15dB .. -62dB
{0x0035, -61}, // 36 .. 0 1 2 5 .. -33dB -19dB -3dB -6dB .. -61dB
{0x0214, -60}, // 37 .. 2 0 2 4 .. -24dB -24dB -3dB -9dB .. -60dB
{0x01D9, -59}, // 38 .. 1 6 3 1 .. -30dB -2dB 0dB -27dB .. -59dB
{0x0145, -58}, // 39 .. 1 2 0 5 .. -30dB -14dB -8dB -6dB .. -58dB
{0x02A2, -57}, // 40 .. 2 5 0 2 .. -24dB -4dB -8dB -21dB .. -57dB
{0x02D1, -56}, // 41 .. 2 6 2 1 .. -24dB -2dB -3dB -27dB .. -56dB
{0x00B3, -55}, // 42 .. 0 5 2 3 .. -33dB -4dB -3dB -15dB .. -55dB
{0x0216, -54}, // 43 .. 2 0 2 6 .. -24dB -24dB -3dB -3dB .. -54dB
{0x0066, -53}, // 44 .. 0 3 0 6 .. -33dB -9dB -8dB -3dB .. -53dB
{0x00C4, -52}, // 45 .. 0 6 0 4 .. -33dB -2dB -8dB -9dB .. -52dB
{0x006E, -51}, // 46 .. 0 3 1 6 .. -33dB -9dB -6dB -3dB .. -51dB
{0x015D, -50}, // 47 .. 1 2 3 5 .. -30dB -14dB 0dB -6dB .. -50dB
{0x00AD, -49}, // 48 .. 0 5 1 5 .. -33dB -4dB -6dB -6dB .. -49dB
{0x007D, -48}, // 49 .. 0 3 3 5 .. -33dB -9dB 0dB -6dB .. -48dB
{0x00D4, -47}, // 50 .. 0 6 2 4 .. -33dB -2dB -3dB -9dB .. -47dB
{0x01B4, -46}, // 51 .. 1 5 2 4 .. -30dB -4dB -3dB -9dB .. -46dB
{0x030B, -45}, // 52 .. 3 0 1 3 .. 0dB -24dB -6dB -15dB .. -45dB
{0x00CE, -44}, // 53 .. 0 6 1 6 .. -33dB -2dB -6dB -3dB .. -44dB
{0x01B5, -43}, // 54 .. 1 5 2 5 .. -30dB -4dB -3dB -6dB .. -43dB
{0x0097, -42}, // 55 .. 0 4 2 7 .. -33dB -6dB -3dB 0dB .. -42dB
{0x0257, -41}, // 56 .. 2 2 2 7 .. -24dB -14dB -3dB 0dB .. -41dB
{0x02B4, -40}, // 57 .. 2 5 2 4 .. -24dB -4dB -3dB -9dB .. -40dB
{0x027D, -39}, // 58 .. 2 3 3 5 .. -24dB -9dB 0dB -6dB .. -39dB
{0x01DD, -38}, // 59 .. 1 6 3 5 .. -30dB -2dB 0dB -6dB .. -38dB
{0x02AE, -37}, // 60 .. 2 5 1 6 .. -24dB -4dB -6dB -3dB .. -37dB
{0x0379, -36}, // 61 .. 3 3 3 1 .. 0dB -9dB 0dB -27dB .. -36dB
{0x035A, -35}, // 62 .. 3 2 3 2 .. 0dB -14dB 0dB -21dB .. -35dB
{0x02B6, -34}, // 63 .. 2 5 2 6 .. -24dB -4dB -3dB -3dB .. -34dB
{0x030E, -33}, // 64 .. 3 0 1 6 .. 0dB -24dB -6dB -3dB .. -33dB
{0x0307, -32}, // 65 .. 3 0 0 7 .. 0dB -24dB -8dB 0dB .. -32dB
{0x02BE, -31}, // 66 .. 2 5 3 6 .. -24dB -4dB 0dB -3dB .. -31dB
{0x037A, -30}, // 67 .. 3 3 3 2 .. 0dB -9dB 0dB -21dB .. -30dB
{0x02DE, -29}, // 68 .. 2 6 3 6 .. -24dB -2dB 0dB -3dB .. -29dB
{0x0345, -28}, // 69 .. 3 2 0 5 .. 0dB -14dB -8dB -6dB .. -28dB
{0x03A3, -27}, // 70 .. 3 5 0 3 .. 0dB -4dB -8dB -15dB .. -27dB
{0x0364, -26}, // 71 .. 3 3 0 4 .. 0dB -9dB -8dB -9dB .. -26dB
{0x032F, -25}, // 72 .. 3 1 1 7 .. 0dB -19dB -6dB 0dB .. -25dB
{0x0393, -24}, // 73 .. 3 4 2 3 .. 0dB -6dB -3dB -15dB .. -24dB
{0x0384, -23}, // 74 .. 3 4 0 4 .. 0dB -6dB -8dB -9dB .. -23dB
{0x0347, -22}, // 75 .. 3 2 0 7 .. 0dB -14dB -8dB 0dB .. -22dB
{0x03EB, -21}, // 76 .. 3 7 1 3 .. 0dB 0dB -6dB -15dB .. -21dB
{0x03D3, -20}, // 77 .. 3 6 2 3 .. 0dB -2dB -3dB -15dB .. -20dB
{0x03BB, -19}, // 78 .. 3 5 3 3 .. 0dB -4dB 0dB -15dB .. -19dB
{0x037C, -18}, // 79 .. 3 3 3 4 .. 0dB -9dB 0dB -9dB .. -18dB
{0x03CC, -17}, // 80 .. 3 6 1 4 .. 0dB -2dB -6dB -9dB .. -17dB
{0x03C5, -16}, // 81 .. 3 6 0 5 .. 0dB -2dB -8dB -6dB .. -16dB
{0x03EC, -15}, // 82 .. 3 7 1 4 .. 0dB 0dB -6dB -9dB .. -15dB
{0x035F, -14}, // 83 .. 3 2 3 7 .. 0dB -14dB 0dB 0dB .. -14dB
{0x03BC, -13}, // 84 .. 3 5 3 4 .. 0dB -4dB 0dB -9dB .. -13dB
{0x038F, -12}, // 85 .. 3 4 1 7 .. 0dB -6dB -6dB 0dB .. -12dB
{0x03E6, -11}, // 86 .. 3 7 0 6 .. 0dB 0dB -8dB -3dB .. -11dB
{0x03AF, -10}, // 87 .. 3 5 1 7 .. 0dB -4dB -6dB 0dB .. -10dB
{0x03F5, -9 }, // 88 .. 3 7 2 5 .. 0dB 0dB -3dB -6dB .. -9dB
{0x03D6, -8 }, // 89 .. 3 6 2 6 .. 0dB -2dB -3dB -3dB .. -8dB
{0x03BE, -7 }, // 90 .. 3 5 3 6 .. 0dB -4dB 0dB -3dB .. -7dB original
{0x03F6, -6 }, // 91 .. 3 7 2 6 .. 0dB 0dB -3dB -3dB .. -6dB
{0x03DE, -5 }, // 92 .. 3 6 3 6 .. 0dB -2dB 0dB -3dB .. -5dB
{0x03BF, -4 }, // 93 .. 3 5 3 7 .. 0dB -4dB 0dB 0dB .. -4dB
{0x03F7, -3 }, // 94 .. 3 7 2 7 .. 0dB 0dB -3dB 0dB .. -3dB
{0x03DF, -2 }, // 95 .. 3 6 3 7 .. 0dB -2dB 0dB 0dB .. -2dB
{0x03FF, 0 }, // 96 .. 3 7 3 7 .. 0dB 0dB 0dB 0dB .. 0dB
};
t_gain_table gain_table[100] = {{0x03BE, -7}}; //original
uint8_t gain_table_size = 0;
static const unsigned int original_index = 90;
void CreateTable()
{
typedef union {
struct {
uint8_t pgaIdx:3;
uint8_t mixerIdx:2;
uint8_t lnaIdx:3;
uint8_t lnaSIdx:2;
};
uint16_t __raw;
} GainData;
static const int8_t lna_short_dB[] = {-28, -24, -19, 0}; // corrected'ish
static const int8_t lna_dB[] = {-24, -19, -14, -9, -6, -4, -2, 0};
static const int8_t mixer_dB[] = { -8, -6, -3, 0};
static const int8_t pga_dB[] = {-33, -27, -21, -15, -9, -6, -3, 0};
unsigned i;
for (uint8_t lnaSIdx = 0; lnaSIdx < ARRAY_SIZE(lna_short_dB); lnaSIdx++) {
for (uint8_t lnaIdx = 0; lnaIdx < ARRAY_SIZE(lna_dB); lnaIdx++) {
for (uint8_t mixerIdx = 0; mixerIdx < ARRAY_SIZE(mixer_dB); mixerIdx++) {
for (uint8_t pgaIdx = 0; pgaIdx < ARRAY_SIZE(pga_dB); pgaIdx++) {
int16_t db = lna_short_dB[lnaSIdx] + lna_dB[lnaIdx] + mixer_dB[mixerIdx] + pga_dB[pgaIdx];
GainData gainData = {{
pgaIdx,
mixerIdx,
lnaIdx,
lnaSIdx,
}};
for (i = 1; i < ARRAY_SIZE(gain_table); i++) {
t_gain_table * gain = &gain_table[i];
if (db == gain->gain_dB)
break;
if (db > gain->gain_dB)
continue;
if (db < gain->gain_dB) {
if(gain->gain_dB)
memmove(gain + 1, gain, 100 - i);
gain->gain_dB = db;
gain->reg_val = gainData.__raw;
break;
}
gain->gain_dB = db;
gain->reg_val = gainData.__raw;
break;
}
}
}
}
}
gain_table_size = i+1;
}
#endif
#ifdef ENABLE_AM_FIX_SHOW_DATA
// display update rate
static const unsigned int display_update_rate = 250 / 10; // max 250ms display update rate
unsigned int counter = 0;
#endif
unsigned int gain_table_index[2] = {0, 0};
// used simply to detect a changed gain setting
unsigned int gain_table_index_prev[2] = {0, 0};
// holds the previous RSSI level .. we do an average of old + new RSSI reading
int16_t prev_rssi[2] = {0, 0};
// to help reduce gain hunting, peak hold count down tick
unsigned int hold_counter[2] = {0, 0};
// -89dBm, any higher and the AM demodulator starts to saturate/clip/distort
const int16_t desired_rssi = (-89 + 160) * 2;
int8_t currentGainDiff;
bool enabled = true;
void AM_fix_init(void)
{ // called at boot-up
for (int i = 0; i < 2; i++) {
gain_table_index[i] = 0; // re-start with original QS setting
}
#if !LOOKUP_TABLE
CreateTable();
#endif
}
void AM_fix_reset(const unsigned vfo)
{ // reset the AM fixer upper
if (vfo > 1)
return;
#ifdef ENABLE_AM_FIX_SHOW_DATA
// display update rate
static const unsigned int display_update_rate = 250 / 10; // max 250ms display update rate
unsigned int counter = 0;
counter = 0;
#endif
#ifdef ENABLE_AM_FIX_TEST1
// user manually sets the table index .. used to calibrate the desired dB gain table
unsigned int gain_table_index[2] = {1 + gSetting_AM_fix_test1, 1 + gSetting_AM_fix_test1};
#else
unsigned int gain_table_index[2] = {original_index, original_index};
#endif
prev_rssi[vfo] = 0;
hold_counter[vfo] = 0;
gain_table_index_prev[vfo] = 0;
}
// used simply to detect a changed gain setting
unsigned int gain_table_index_prev[2] = {0, 0};
// adjust the RX gain to try and prevent the AM demodulator from
// saturating/overloading/clipping (distorted AM audio)
//
// we're actually doing the BK4819's job for it here, but as the chip
// won't/don't do it for itself, we're left to bodging it ourself by
// playing with the RF front end gain setting
//
void AM_fix_10ms(const unsigned vfo)
{
if(!gSetting_AM_fix || !enabled || vfo > 1 )
return;
// holds the previous RSSI level .. we do an average of old + new RSSI reading
int16_t prev_rssi[2] = {0, 0};
if (gCurrentFunction != FUNCTION_FOREGROUND && !FUNCTION_IsRx()) {
#ifdef ENABLE_AM_FIX_SHOW_DATA
counter = display_update_rate; // queue up a display update as soon as we switch to RX mode
#endif
return;
}
// to help reduce gain hunting, peak hold count down tick
unsigned int hold_counter[2] = {0, 0};
// used to correct the RSSI readings after our RF gain adjustments
int16_t rssi_gain_diff[2] = {0, 0};
// used to limit the max RF gain
unsigned int max_index = ARRAY_SIZE(gain_table) - 1;
#ifndef ENABLE_AM_FIX_TEST1
// -89dBm, any higher and the AM demodulator starts to saturate/clip/distort
const int16_t desired_rssi = (-89 + 160) * 2;
#endif
void AM_fix_init(void)
{ // called at boot-up
unsigned int i;
for (i = 0; i < 2; i++)
{
#ifdef ENABLE_AM_FIX_TEST1
gain_table_index[i] = 1 + gSetting_AM_fix_test1;
#else
gain_table_index[i] = original_index; // re-start with original QS setting
#endif
#ifdef ENABLE_AM_FIX_SHOW_DATA
if (counter > 0) {
if (++counter >= display_update_rate) { // trigger a display update
counter = 0;
gUpdateDisplay = true;
}
}
#endif
#if 0
{ // set a maximum gain to use
// const int16_t max_gain_dB = gain_dB[original_index];
const int16_t max_gain_dB = -10;
static uint32_t lastFreq[2];
if(gEeprom.VfoInfo[vfo].pRX->Frequency != lastFreq[vfo]) {
lastFreq[vfo] = gEeprom.VfoInfo[vfo].pRX->Frequency;
AM_fix_reset(vfo);
}
max_index = ARRAY_SIZE(gain_table);
while (--max_index > 1)
// if (gain_dB[max_index] <= max_gain_dB)
if (gain_table[max_index].gain_dB <= max_gain_dB)
int16_t rssi;
{ // sample the current RSSI level
// average it with the previous rssi (a bit of noise/spike immunity)
const int16_t new_rssi = BK4819_GetRSSI();
rssi = (prev_rssi[vfo] > 0) ? (prev_rssi[vfo] + new_rssi) / 2 : new_rssi;
prev_rssi[vfo] = new_rssi;
}
#ifdef ENABLE_AM_FIX_SHOW_DATA
{
static int16_t lastRssi;
if (lastRssi != rssi) { // rssi changed
lastRssi = rssi;
if (counter == 0) {
counter = 1;
gUpdateDisplay = true; // trigger a display update
}
}
}
#endif
// automatically adjust the RF RX gain
// update the gain hold counter
if (hold_counter[vfo] > 0)
hold_counter[vfo]--;
// dB difference between actual and desired RSSI level
int16_t diff_dB = (rssi - desired_rssi) / 2;
if (diff_dB > 0) { // decrease gain
unsigned int index = gain_table_index[vfo]; // current position we're at
if (diff_dB >= 10) { // jump immediately to a new gain setting
// this greatly speeds up initial gain reduction (but reduces noise/spike immunity)
const int16_t desired_gain_dB = (int16_t)gain_table[index].gain_dB - diff_dB + 8; // get no closer than 8dB (bit of noise/spike immunity)
// scan the table to see what index to jump straight too
while (index > 1)
if (gain_table[--index].gain_dB <= desired_gain_dB)
break;
}
#else
// use the full range of available gains
max_index = ARRAY_SIZE(gain_table) - 1;
#endif
else
{ // incrementally reduce the gain .. taking it slow improves noise/spike immunity
if (index > 1)
index--; // slow step-by-step gain reduction
}
index = MAX(1u, index);
if (gain_table_index[vfo] != index)
{
gain_table_index[vfo] = index;
hold_counter[vfo] = 30; // 300ms hold
}
}
void AM_fix_reset(const int vfo)
{ // reset the AM fixer upper
if (diff_dB >= -6) // 6dB hysterisis (help reduce gain hunting)
hold_counter[vfo] = 30; // 300ms hold
#ifdef ENABLE_AM_FIX_SHOW_DATA
counter = 0;
#endif
prev_rssi[vfo] = 0;
hold_counter[vfo] = 0;
rssi_gain_diff[vfo] = 0;
#ifdef ENABLE_AM_FIX_TEST1
// gain_table_index[vfo] = 1 + gSetting_AM_fix_test1;
#else
// gain_table_index[vfo] = original_index; // re-start with original QS setting
#endif
gain_table_index_prev[vfo] = 0;
if (hold_counter[vfo] == 0)
{ // hold has been released, we're free to increase gain
const unsigned int index = gain_table_index[vfo] + 1; // move up to next gain index
gain_table_index[vfo] = MIN(index, gain_table_size - 1u);
}
// adjust the RX gain to try and prevent the AM demodulator from
// saturating/overloading/clipping (distorted AM audio)
//
// we're actually doing the BK4819's job for it here, but as the chip
// won't/don't do it for itself, we're left to bodging it ourself by
// playing with the RF front end gain setting
//
void AM_fix_10ms(const int vfo)
{
int16_t diff_dB;
int16_t rssi;
switch (gCurrentFunction)
{
case FUNCTION_TRANSMIT:
case FUNCTION_BAND_SCOPE:
case FUNCTION_POWER_SAVE:
#ifdef ENABLE_AM_FIX_SHOW_DATA
counter = display_update_rate; // queue up a display update as soon as we switch to RX mode
#endif
return;
{ // apply the new settings to the front end registers
const unsigned int index = gain_table_index[vfo];
// only adjust stuff if we're in one of these modes
case FUNCTION_FOREGROUND:
case FUNCTION_RECEIVE:
case FUNCTION_MONITOR:
case FUNCTION_INCOMING:
break;
}
// remember the new table index
gain_table_index_prev[vfo] = index;
currentGainDiff = gain_table[0].gain_dB - gain_table[index].gain_dB;
BK4819_WriteRegister(BK4819_REG_13, gain_table[index].reg_val);
#ifdef ENABLE_AGC_SHOW_DATA
UI_MAIN_PrintAGC(true);
#endif
}
#ifdef ENABLE_AM_FIX_SHOW_DATA
if (counter > 0)
{
if (++counter >= display_update_rate)
{ // trigger a display update
counter = 0;
gUpdateDisplay = true;
}
}
#endif
{ // sample the current RSSI level
// average it with the previous rssi (a bit of noise/spike immunity)
const int16_t new_rssi = BK4819_GetRSSI();
rssi = (prev_rssi[vfo] > 0) ? (prev_rssi[vfo] + new_rssi) / 2 : new_rssi;
prev_rssi[vfo] = new_rssi;
}
// save the corrected RSSI level
#ifdef ENABLE_AM_FIX_SHOW_DATA
{
const int16_t new_rssi = rssi - rssi_gain_diff[vfo];
if (gCurrentRSSI[vfo] != new_rssi)
{
gCurrentRSSI[vfo] = new_rssi;
if (counter == 0)
{ // trigger a display update
counter = 1;
gUpdateDisplay = true;
}
}
}
#else
gCurrentRSSI[vfo] = rssi - rssi_gain_diff[vfo];
#endif
#ifdef ENABLE_AM_FIX_TEST1
// user is manually adjusting a gain register - don't do anything automatically
{
int i = 1 + (int)gSetting_AM_fix_test1;
i = (i < 1) ? 1 : (i > ((int)ARRAY_SIZE(gain_table) - 1) ? ARRAY_SIZE(gain_table) - 1 : i;
if (gain_table_index[vfo] == i)
return; // no change
gain_table_index[vfo] = i;
}
#else
// automatically adjust the RF RX gain
// update the gain hold counter
if (hold_counter[vfo] > 0)
hold_counter[vfo]--;
// dB difference between actual and desired RSSI level
diff_dB = (rssi - desired_rssi) / 2;
if (diff_dB > 0)
{ // decrease gain
unsigned int index = gain_table_index[vfo]; // current position we're at
if (diff_dB >= 10)
{ // jump immediately to a new gain setting
// this greatly speeds up initial gain reduction (but reduces noise/spike immunity)
const int16_t desired_gain_dB = (int16_t)gain_table[index].gain_dB - diff_dB + 8; // get no closer than 8dB (bit of noise/spike immunity)
// scan the table to see what index to jump straight too
while (index > 1)
if (gain_table[--index].gain_dB <= desired_gain_dB)
break;
//index = (gain_table_index[vfo] + index) / 2; // easy does it
}
else
{ // incrementally reduce the gain .. taking it slow improves noise/spike immunity
// if (index >= (1 + 3) && diff_dB >= 3)
// index -= 3; // faster gain reduction
// else
if (index > 1)
index--; // slow step-by-step gain reduction
}
index = (index < 1) ? 1 : (index > max_index) ? max_index : index;
if (gain_table_index[vfo] != index)
{
gain_table_index[vfo] = index;
hold_counter[vfo] = 30; // 300ms hold
}
}
if (diff_dB >= -6) // 6dB hysterisis (help reduce gain hunting)
hold_counter[vfo] = 30; // 300ms hold
if (hold_counter[vfo] == 0)
{ // hold has been released, we're free to increase gain
const unsigned int index = gain_table_index[vfo] + 1; // move up to next gain index
gain_table_index[vfo] = (index <= max_index) ? index : max_index; // limit the gain index
}
#if 0
if (gain_table_index[vfo] == gain_table_index_prev[vfo])
return; // no gain change - this is to reduce writing to the BK chip on ever call
#endif
#ifdef ENABLE_AM_FIX_SHOW_DATA
if (counter == 0) {
counter = 1;
gUpdateDisplay = true;
}
#endif
}
#ifdef ENABLE_AM_FIX_SHOW_DATA
void AM_fix_print_data(const unsigned vfo, char *s) {
if (s != NULL && vfo < ARRAY_SIZE(gain_table_index)) {
const unsigned int index = gain_table_index[vfo];
sprintf(s, "%2u %4ddB %3u", index, gain_table[index].gain_dB, prev_rssi[vfo]);
counter = 0;
}
}
#endif
{ // apply the new settings to the front end registers
const unsigned int index = gain_table_index[vfo];
// remember the new table index
gain_table_index_prev[vfo] = index;
BK4819_WriteRegister(BK4819_REG_13, gain_table[index].reg_val);
// offset the RSSI reading to the rest of the firmware to cancel out the gain adjustments we make
// RF gain difference from original QS setting
rssi_gain_diff[vfo] = ((int16_t)gain_table[index].gain_dB - gain_table[original_index].gain_dB) * 2;
}
// save the corrected RSSI level
gCurrentRSSI[vfo] = rssi - rssi_gain_diff[vfo];
#ifdef ENABLE_AM_FIX_SHOW_DATA
if (counter == 0)
{
counter = 1;
gUpdateDisplay = true;
}
#endif
}
#ifdef ENABLE_AM_FIX_SHOW_DATA
void AM_fix_print_data(const int vfo, char *s)
{
if (s != NULL && vfo >= 0 && vfo < (int)ARRAY_SIZE(gain_table_index))
{
const unsigned int index = gain_table_index[vfo];
// sprintf(s, "%2u.%u %4ddB %3u", index, ARRAY_SIZE(gain_table) - 1, gain_table[index].gain_dB, prev_rssi[vfo]);
sprintf(s, "%2u %4ddB %3u", index, gain_table[index].gain_dB, prev_rssi[vfo]);
counter = 0;
}
}
#endif
int8_t AM_fix_get_gain_diff()
{
return currentGainDiff;
}
void AM_fix_enable(bool on)
{
enabled = on;
}
#endif

View File

@@ -21,15 +21,15 @@
#include <stdbool.h>
#ifdef ENABLE_AM_FIX
extern int16_t rssi_gain_diff[2];
void AM_fix_init(void);
void AM_fix_reset(const int vfo);
void AM_fix_10ms(const int vfo);
void AM_fix_reset(const unsigned vfo);
void AM_fix_10ms(const unsigned vfo);
#ifdef ENABLE_AM_FIX_SHOW_DATA
void AM_fix_print_data(const int vfo, char *s);
void AM_fix_print_data(const unsigned vfo, char *s);
#endif
int8_t AM_fix_get_gain_diff();
void AM_fix_enable(bool on);
#endif
#endif

View File

@@ -14,12 +14,17 @@
* limitations under the License.
*/
#include <assert.h>
#include <string.h>
#include "app/action.h"
#include "app/app.h"
#include "app/chFrScanner.h"
#include "app/common.h"
#include "app/dtmf.h"
#ifdef ENABLE_FLASHLIGHT
#include "app/flashlight.h"
#endif
#ifdef ENABLE_FMRADIO
#include "app/fm.h"
#endif
@@ -31,29 +36,73 @@
#endif
#include "driver/bk4819.h"
#include "driver/gpio.h"
#include "driver/backlight.h"
#include "functions.h"
#include "misc.h"
#include "settings.h"
#include "ui/inputbox.h"
#include "ui/ui.h"
static void ACTION_FlashLight(void)
{
switch (gFlashLightState)
{
case 0:
gFlashLightState++;
GPIO_SetBit(&GPIOC->DATA, GPIOC_PIN_FLASHLIGHT);
break;
case 1:
case 2:
gFlashLightState++;
break;
default:
gFlashLightState = 0;
GPIO_ClearBit(&GPIOC->DATA, GPIOC_PIN_FLASHLIGHT);
}
}
#if defined(ENABLE_FMRADIO)
static void ACTION_Scan_FM(bool bRestart);
#endif
#if defined(ENABLE_ALARM) || defined(ENABLE_TX1750)
static void ACTION_AlarmOr1750(bool b1750);
inline static void ACTION_Alarm() { ACTION_AlarmOr1750(false); }
inline static void ACTION_1750() { ACTION_AlarmOr1750(true); };
#endif
inline static void ACTION_ScanRestart() { ACTION_Scan(true); };
void (*action_opt_table[])(void) = {
[ACTION_OPT_NONE] = &FUNCTION_NOP,
[ACTION_OPT_POWER] = &ACTION_Power,
[ACTION_OPT_MONITOR] = &ACTION_Monitor,
[ACTION_OPT_SCAN] = &ACTION_ScanRestart,
[ACTION_OPT_KEYLOCK] = &COMMON_KeypadLockToggle,
[ACTION_OPT_A_B] = &COMMON_SwitchVFOs,
[ACTION_OPT_VFO_MR] = &COMMON_SwitchVFOMode,
[ACTION_OPT_SWITCH_DEMODUL] = &ACTION_SwitchDemodul,
#ifdef ENABLE_FLASHLIGHT
[ACTION_OPT_FLASHLIGHT] = &ACTION_FlashLight,
#else
[ACTION_OPT_FLASHLIGHT] = &FUNCTION_NOP,
#endif
#ifdef ENABLE_VOX
[ACTION_OPT_VOX] = &ACTION_Vox,
#else
[ACTION_OPT_VOX] = &FUNCTION_NOP,
#endif
#ifdef ENABLE_FMRADIO
[ACTION_OPT_FM] = &ACTION_FM,
#else
[ACTION_OPT_FM] = &FUNCTION_NOP,
#endif
#ifdef ENABLE_ALARM
[ACTION_OPT_ALARM] = &ACTION_Alarm,
#else
[ACTION_OPT_ALARM] = &FUNCTION_NOP,
#endif
#ifdef ENABLE_TX1750
[ACTION_OPT_1750] = &ACTION_1750,
#else
[ACTION_OPT_1750] = &FUNCTION_NOP,
#endif
#ifdef ENABLE_BLMIN_TMP_OFF
[ACTION_OPT_BLMIN_TMP_OFF] = &ACTION_BlminTmpOff,
#else
[ACTION_OPT_BLMIN_TMP_OFF] = &FUNCTION_NOP,
#endif
};
static_assert(ARRAY_SIZE(action_opt_table) == ACTION_OPT_LEN);
void ACTION_Power(void)
{
@@ -61,310 +110,171 @@ void ACTION_Power(void)
gTxVfo->OUTPUT_POWER = OUTPUT_POWER_LOW;
gRequestSaveChannel = 1;
//gRequestSaveChannel = 2; // auto save the channel
#ifdef ENABLE_VOICE
gAnotherVoiceID = VOICE_ID_POWER;
#endif
gRequestDisplayScreen = gScreenToDisplay;
#ifdef ENABLE_VOICE
gAnotherVoiceID = VOICE_ID_POWER;
#endif
}
void ACTION_Monitor(void)
{
if (gCurrentFunction != FUNCTION_MONITOR)
{ // enable the monitor
if (gCurrentFunction != FUNCTION_MONITOR) { // enable the monitor
RADIO_SelectVfos();
#ifdef ENABLE_NOAA
if (gRxVfo->CHANNEL_SAVE >= NOAA_CHANNEL_FIRST && gIsNoaaMode)
gNoaaChannel = gRxVfo->CHANNEL_SAVE - NOAA_CHANNEL_FIRST;
#endif
#ifdef ENABLE_NOAA
if (IS_NOAA_CHANNEL(gRxVfo->CHANNEL_SAVE) && gIsNoaaMode)
gNoaaChannel = gRxVfo->CHANNEL_SAVE - NOAA_CHANNEL_FIRST;
#endif
RADIO_SetupRegisters(true);
APP_StartListening(FUNCTION_MONITOR, false);
APP_StartListening(FUNCTION_MONITOR);
return;
}
gMonitor = false;
if (gScanStateDir != SCAN_OFF)
{
if (gScanStateDir != SCAN_OFF) {
gScanPauseDelayIn_10ms = scan_pause_delay_in_1_10ms;
gScheduleScanListen = false;
gScanPauseMode = true;
}
#ifdef ENABLE_NOAA
if (gEeprom.DUAL_WATCH == DUAL_WATCH_OFF && gIsNoaaMode)
{
gNOAA_Countdown_10ms = NOAA_countdown_10ms;
gScheduleNOAA = false;
}
#endif
#ifdef ENABLE_NOAA
if (gEeprom.DUAL_WATCH == DUAL_WATCH_OFF && gIsNoaaMode) {
gNOAA_Countdown_10ms = NOAA_countdown_10ms;
gScheduleNOAA = false;
}
#endif
RADIO_SetupRegisters(true);
#ifdef ENABLE_FMRADIO
if (gFmRadioMode)
{
FM_Start();
gRequestDisplayScreen = DISPLAY_FM;
}
else
#endif
gRequestDisplayScreen = gScreenToDisplay;
#ifdef ENABLE_FMRADIO
if (gFmRadioMode) {
FM_Start();
gRequestDisplayScreen = DISPLAY_FM;
}
else
#endif
gRequestDisplayScreen = gScreenToDisplay;
}
void ACTION_Scan(bool bRestart)
{
(void)bRestart;
#ifdef ENABLE_FMRADIO
if (gFmRadioMode)
{
if (gCurrentFunction != FUNCTION_RECEIVE &&
gCurrentFunction != FUNCTION_MONITOR &&
gCurrentFunction != FUNCTION_TRANSMIT)
{
GUI_SelectNextDisplay(DISPLAY_FM);
gMonitor = false;
if (gFM_ScanState != FM_SCAN_OFF)
{
FM_PlayAndUpdate();
#ifdef ENABLE_VOICE
gAnotherVoiceID = VOICE_ID_SCANNING_STOP;
#endif
}
else
{
uint16_t Frequency;
if (bRestart)
{
gFM_AutoScan = true;
gFM_ChannelPosition = 0;
FM_EraseChannels();
Frequency = gEeprom.FM_LowerLimit;
}
else
{
gFM_AutoScan = false;
gFM_ChannelPosition = 0;
Frequency = gEeprom.FM_FrequencyPlaying;
}
BK1080_GetFrequencyDeviation(Frequency);
FM_Tune(Frequency, 1, bRestart);
#ifdef ENABLE_VOICE
gAnotherVoiceID = VOICE_ID_SCANNING_BEGIN;
#endif
}
}
if (gFmRadioMode) {
ACTION_Scan_FM(bRestart);
return;
}
#endif
if (gScreenToDisplay != DISPLAY_SCANNER)
{ // not scanning
if (SCANNER_IsScanning()) {
return;
}
gMonitor = false;
// not scanning
gMonitor = false;
DTMF_clear_RX();
#ifdef ENABLE_DTMF_CALLING
DTMF_clear_RX();
#endif
gDTMF_RX_live_timeout = 0;
memset(gDTMF_RX_live, 0, sizeof(gDTMF_RX_live));
gDTMF_RX_live_timeout = 0;
memset(gDTMF_RX_live, 0, sizeof(gDTMF_RX_live));
RADIO_SelectVfos();
RADIO_SelectVfos();
#ifdef ENABLE_NOAA
if (!IS_NOAA_CHANNEL(gRxVfo->CHANNEL_SAVE))
#endif
{
GUI_SelectNextDisplay(DISPLAY_MAIN);
if (gScanStateDir != SCAN_OFF)
{ // already scanning
if (IS_MR_CHANNEL(gNextMrChannel))
{ // channel mode
// keep scanning but toggle between scan lists
gEeprom.SCAN_LIST_DEFAULT = (gEeprom.SCAN_LIST_DEFAULT + 1) % 3;
// jump to the next channel
SCANNER_ScanChannels(false, gScanStateDir);
gScanPauseDelayIn_10ms = 1;
gScheduleScanListen = false;
gUpdateStatus = true;
}
else
{ // stop scanning
SCANNER_Stop();
#ifdef ENABLE_VOICE
gAnotherVoiceID = VOICE_ID_SCANNING_STOP;
#endif
}
}
else
{ // start scanning
SCANNER_ScanChannels(true, SCAN_FWD);
#ifdef ENABLE_VOICE
AUDIO_SetVoiceID(0, VOICE_ID_SCANNING_BEGIN);
AUDIO_PlaySingleVoice(true);
#endif
// clear the other vfo's rssi level (to hide the antenna symbol)
gVFO_RSSI_bar_level[(gEeprom.RX_VFO + 1) & 1u] = 0;
// let the user see DW is not active
gDualWatchActive = false;
gUpdateStatus = true;
}
}
if (IS_NOAA_CHANNEL(gRxVfo->CHANNEL_SAVE)) {
return;
}
else
// if (!bRestart)
if (!bRestart && IS_MR_CHANNEL(gNextMrChannel))
{ // channel mode, keep scanning but toggle between scan lists
#endif
GUI_SelectNextDisplay(DISPLAY_MAIN);
if (gScanStateDir != SCAN_OFF) {
// already scanning
if (!IS_MR_CHANNEL(gNextMrChannel)) {
CHFRSCANNER_Stop();
#ifdef ENABLE_VOICE
gAnotherVoiceID = VOICE_ID_SCANNING_STOP;
#endif
return;
}
// channel mode. Keep scanning but toggle between scan lists
gEeprom.SCAN_LIST_DEFAULT = (gEeprom.SCAN_LIST_DEFAULT + 1) % 3;
// jump to the next channel
SCANNER_ScanChannels(false, gScanStateDir);
CHFRSCANNER_Start(false, gScanStateDir);
gScanPauseDelayIn_10ms = 1;
gScheduleScanListen = false;
} else {
// start scanning
CHFRSCANNER_Start(true, SCAN_FWD);
gUpdateStatus = true;
}
else
{ // stop scanning
gMonitor = false;
SCANNER_Stop();
#ifdef ENABLE_VOICE
gAnotherVoiceID = VOICE_ID_SCANNING_STOP;
#endif
gRequestDisplayScreen = DISPLAY_MAIN;
#ifdef ENABLE_VOICE
AUDIO_SetVoiceID(0, VOICE_ID_SCANNING_BEGIN);
AUDIO_PlaySingleVoice(true);
#endif
// clear the other vfo's rssi level (to hide the antenna symbol)
gVFO_RSSI_bar_level[(gEeprom.RX_VFO + 1) & 1U] = 0;
// let the user see DW is not active
gDualWatchActive = false;
}
gUpdateStatus = true;
}
#ifdef ENABLE_VOX
void ACTION_Vox(void)
{
gEeprom.VOX_SWITCH = !gEeprom.VOX_SWITCH;
gRequestSaveSettings = true;
gFlagReconfigureVfos = true;
#ifdef ENABLE_VOICE
gAnotherVoiceID = VOICE_ID_VOX;
#endif
gUpdateStatus = true;
}
#endif
#if defined(ENABLE_ALARM) || defined(ENABLE_TX1750)
static void ACTION_AlarmOr1750(const bool b1750)
{
(void)b1750;
gInputBoxIndex = 0;
#if defined(ENABLE_ALARM) && defined(ENABLE_TX1750)
gAlarmState = b1750 ? ALARM_STATE_TX1750 : ALARM_STATE_TXALARM;
gAlarmRunningCounter = 0;
#elif defined(ENABLE_ALARM)
gAlarmState = ALARM_STATE_TXALARM;
gAlarmRunningCounter = 0;
#else
gAlarmState = ALARM_STATE_TX1750;
#endif
gFlagPrepareTX = true;
if (gScreenToDisplay != DISPLAY_MENU) // 1of11 .. don't close the menu
gRequestDisplayScreen = DISPLAY_MAIN;
}
#endif
#ifdef ENABLE_FMRADIO
void ACTION_FM(void)
{
if (gCurrentFunction != FUNCTION_TRANSMIT && gCurrentFunction != FUNCTION_MONITOR)
{
if (gFmRadioMode)
{
FM_TurnOff();
gInputBoxIndex = 0;
#ifdef ENABLE_VOX
gVoxResumeCountdown = 80;
#endif
gFlagReconfigureVfos = true;
gRequestDisplayScreen = DISPLAY_MAIN;
return;
}
gMonitor = false;
RADIO_SelectVfos();
RADIO_SetupRegisters(true);
FM_Start();
gInputBoxIndex = 0;
gRequestDisplayScreen = DISPLAY_FM;
}
}
#endif
void ACTION_SwitchDemodul(void)
{
gRequestSaveChannel = 1;
gTxVfo->Modulation++;
if(gTxVfo->Modulation == MODULATION_UKNOWN)
gTxVfo->Modulation = MODULATION_FM;
gRequestSaveChannel = 1;
}
void ACTION_Handle(KEY_Code_t Key, bool bKeyPressed, bool bKeyHeld)
{
if (gScreenToDisplay == DISPLAY_MAIN && gDTMF_InputMode) // entering DTMF code
{
if (Key == KEY_SIDE1 && !bKeyHeld && bKeyPressed) // side1 btn pressed
{
gBeepToPlay = BEEP_1KHZ_60MS_OPTIONAL;
if (gDTMF_InputBox_Index > 0) // DTMF codes are in the input box
{
gDTMF_InputBox[--gDTMF_InputBox_Index] = '-'; // delete one code
if (gDTMF_InputBox_Index > 0)
{
gPttWasReleased = true;
gRequestDisplayScreen = DISPLAY_MAIN;
return;
}
}
#ifdef ENABLE_VOICE
gAnotherVoiceID = VOICE_ID_CANCEL;
#endif
gRequestDisplayScreen = DISPLAY_MAIN;
gDTMF_InputMode = false; // turn off DTMF input box if no codes left
}
if (gScreenToDisplay == DISPLAY_MAIN && gDTMF_InputMode){
// entering DTMF code
gPttWasReleased = true;
if (Key != KEY_SIDE1 || bKeyHeld || !bKeyPressed){
return;
}
// side1 btn pressed
gBeepToPlay = BEEP_1KHZ_60MS_OPTIONAL;
gRequestDisplayScreen = DISPLAY_MAIN;
if (gDTMF_InputBox_Index <= 0) {
// turn off DTMF input box if no codes left
gDTMF_InputMode = false;
return;
}
// DTMF codes are in the input box
gDTMF_InputBox[--gDTMF_InputBox_Index] = '-'; // delete one code
#ifdef ENABLE_VOICE
gAnotherVoiceID = VOICE_ID_CANCEL;
#endif
return;
}
uint8_t funcShort = ACTION_OPT_NONE;
uint8_t funcLong = ACTION_OPT_NONE;
enum ACTION_OPT_t funcShort = ACTION_OPT_NONE;
enum ACTION_OPT_t funcLong = ACTION_OPT_NONE;
switch(Key) {
case KEY_SIDE1:
funcShort = gEeprom.KEY_1_SHORT_PRESS_ACTION;
@@ -401,54 +311,133 @@ void ACTION_Handle(KEY_Code_t Key, bool bKeyPressed, bool bKeyHeld)
// held or released after short press beyond this point
switch (funcShort)
{
default:
case ACTION_OPT_NONE:
break;
case ACTION_OPT_FLASHLIGHT:
ACTION_FlashLight();
break;
case ACTION_OPT_POWER:
ACTION_Power();
break;
case ACTION_OPT_MONITOR:
ACTION_Monitor();
break;
case ACTION_OPT_SCAN:
ACTION_Scan(true);
break;
case ACTION_OPT_VOX:
#ifdef ENABLE_VOX
ACTION_Vox();
#endif
break;
case ACTION_OPT_ALARM:
#ifdef ENABLE_ALARM
ACTION_AlarmOr1750(false);
#endif
break;
action_opt_table[funcShort]();
}
#ifdef ENABLE_FMRADIO
case ACTION_OPT_FM:
ACTION_FM();
break;
void ACTION_FM(void)
{
if (gCurrentFunction != FUNCTION_TRANSMIT && gCurrentFunction != FUNCTION_MONITOR)
{
gInputBoxIndex = 0;
if (gFmRadioMode) {
FM_TurnOff();
gFlagReconfigureVfos = true;
gRequestDisplayScreen = DISPLAY_MAIN;
#ifdef ENABLE_VOX
gVoxResumeCountdown = 80;
#endif
case ACTION_OPT_1750:
#ifdef ENABLE_TX1750
ACTION_AlarmOr1750(true);
#endif
break;
case ACTION_OPT_KEYLOCK:
COMMON_KeypadLockToggle();
break;
case ACTION_OPT_A_B:
COMMON_SwitchVFOs();
break;
case ACTION_OPT_VFO_MR:
COMMON_SwitchVFOMode();
break;
case ACTION_OPT_SWITCH_DEMODUL:
ACTION_SwitchDemodul();
break;
return;
}
gMonitor = false;
RADIO_SelectVfos();
RADIO_SetupRegisters(true);
FM_Start();
gRequestDisplayScreen = DISPLAY_FM;
}
}
static void ACTION_Scan_FM(bool bRestart)
{
if (FUNCTION_IsRx())
return;
GUI_SelectNextDisplay(DISPLAY_FM);
gMonitor = false;
if (gFM_ScanState != FM_SCAN_OFF) {
FM_PlayAndUpdate();
#ifdef ENABLE_VOICE
gAnotherVoiceID = VOICE_ID_SCANNING_STOP;
#endif
return;
}
uint16_t freq;
if (bRestart) {
gFM_AutoScan = true;
gFM_ChannelPosition = 0;
FM_EraseChannels();
freq = BK1080_GetFreqLoLimit(gEeprom.FM_Band);
} else {
gFM_AutoScan = false;
gFM_ChannelPosition = 0;
freq = gEeprom.FM_FrequencyPlaying;
}
BK1080_GetFrequencyDeviation(freq);
FM_Tune(freq, 1, bRestart);
#ifdef ENABLE_VOICE
gAnotherVoiceID = VOICE_ID_SCANNING_BEGIN;
#endif
}
#endif
#if defined(ENABLE_ALARM) || defined(ENABLE_TX1750)
static void ACTION_AlarmOr1750(const bool b1750)
{
#if defined(ENABLE_ALARM)
const AlarmState_t alarm_mode = (gEeprom.ALARM_MODE == ALARM_MODE_TONE) ? ALARM_STATE_TXALARM : ALARM_STATE_SITE_ALARM;
gAlarmRunningCounter = 0;
#endif
#if defined(ENABLE_ALARM) && defined(ENABLE_TX1750)
gAlarmState = b1750 ? ALARM_STATE_TX1750 : alarm_mode;
#elif defined(ENABLE_ALARM)
gAlarmState = alarm_mode;
#else
gAlarmState = ALARM_STATE_TX1750;
#endif
(void)b1750;
gInputBoxIndex = 0;
gFlagPrepareTX = gAlarmState != ALARM_STATE_OFF;
if (gScreenToDisplay != DISPLAY_MENU) // 1of11 .. don't close the menu
gRequestDisplayScreen = DISPLAY_MAIN;
}
#endif
#ifdef ENABLE_VOX
void ACTION_Vox(void)
{
gEeprom.VOX_SWITCH = !gEeprom.VOX_SWITCH;
gRequestSaveSettings = true;
gFlagReconfigureVfos = true;
gUpdateStatus = true;
#ifdef ENABLE_VOICE
gAnotherVoiceID = VOICE_ID_VOX;
#endif
}
#endif
#ifdef ENABLE_BLMIN_TMP_OFF
void ACTION_BlminTmpOff(void)
{
if(++gEeprom.BACKLIGHT_MIN_STAT == BLMIN_STAT_UNKNOWN) {
gEeprom.BACKLIGHT_MIN_STAT = BLMIN_STAT_ON;
BACKLIGHT_SetBrightness(gEeprom.BACKLIGHT_MIN);
} else {
BACKLIGHT_SetBrightness(0);
}
}
#endif

View File

@@ -19,22 +19,22 @@
#include "driver/keyboard.h"
//static void ACTION_FlashLight(void)
void ACTION_Power(void);
void ACTION_Monitor(void);
void ACTION_Scan(bool bRestart);
#ifdef ENABLE_VOX
void ACTION_Vox(void);
#endif
#ifdef ENABLE_ALARM
//static void ACTION_AlarmOr1750(bool b1750)
#endif
#ifdef ENABLE_FMRADIO
void ACTION_FM(void);
#endif
void ACTION_SwitchDemodul(void);
#ifdef ENABLE_BLMIN_TMP_OFF
void ACTION_BlminTmpOff(void);
#endif
void ACTION_Handle(KEY_Code_t Key, bool bKeyPressed, bool bKeyHeld);
#endif

View File

@@ -28,18 +28,26 @@
#include "ui/inputbox.h"
#include "ui/ui.h"
static const uint16_t Obfuscation[8] = {0x6C16, 0xE614, 0x912E, 0x400D, 0x3521, 0x40D5, 0x0313, 0x80E9};
static const uint16_t Obfuscation[8] = { 0x6C16, 0xE614, 0x912E, 0x400D, 0x3521, 0x40D5, 0x0313, 0x80E9 };
AIRCOPY_State_t gAircopyState;
uint16_t gAirCopyBlockNumber;
uint16_t gErrorsDuringAirCopy;
uint8_t gAirCopyIsSendMode;
uint16_t gAirCopyBlockNumber;
uint16_t gErrorsDuringAirCopy;
uint8_t gAirCopyIsSendMode;
uint16_t g_FSK_Buffer[36];
uint16_t g_FSK_Buffer[36];
void AIRCOPY_SendMessage(void)
bool AIRCOPY_SendMessage(void)
{
unsigned int i;
static uint8_t gAircopySendCountdown = 1;
if (gAircopyState != AIRCOPY_TRANSFER) {
return 1;
}
if (--gAircopySendCountdown) {
return 1;
}
g_FSK_Buffer[1] = (gAirCopyBlockNumber & 0x3FF) << 6;
@@ -47,11 +55,13 @@ void AIRCOPY_SendMessage(void)
g_FSK_Buffer[34] = CRC_Calculate(&g_FSK_Buffer[1], 2 + 64);
for (i = 0; i < 34; i++)
for (unsigned int i = 0; i < 34; i++) {
g_FSK_Buffer[i + 1] ^= Obfuscation[i % 8];
}
if (++gAirCopyBlockNumber >= 0x78)
if (++gAirCopyBlockNumber >= 0x78) {
gAircopyState = AIRCOPY_COMPLETE;
}
RADIO_SetTxParameters();
@@ -60,170 +70,172 @@ void AIRCOPY_SendMessage(void)
BK4819_ToggleGpioOut(BK4819_GPIO1_PIN29_PA_ENABLE, false);
gAircopySendCountdown = 30;
return 0;
}
void AIRCOPY_StorePacket(void)
{
uint16_t Status;
if (gFSKWriteIndex < 36)
if (gFSKWriteIndex < 36) {
return;
}
gFSKWriteIndex = 0;
gUpdateDisplay = true;
Status = BK4819_ReadRegister(BK4819_REG_0B);
uint16_t Status = BK4819_ReadRegister(BK4819_REG_0B);
BK4819_PrepareFSKReceive();
// Doc says bit 4 should be 1 = CRC OK, 0 = CRC FAIL, but original firmware checks for FAIL.
if ((Status & 0x0010U) == 0 && g_FSK_Buffer[0] == 0xABCD && g_FSK_Buffer[35] == 0xDCBA)
{
uint16_t CRC;
unsigned int i;
for (i = 0; i < 34; i++)
g_FSK_Buffer[i + 1] ^= Obfuscation[i % 8];
CRC = CRC_Calculate(&g_FSK_Buffer[1], 2 + 64);
if (g_FSK_Buffer[34] == CRC)
{
const uint16_t *pData;
uint16_t Offset;
Offset = g_FSK_Buffer[1];
if (Offset < 0x1E00)
{
pData = &g_FSK_Buffer[2];
for (i = 0; i < 8; i++)
{
EEPROM_WriteBuffer(Offset, pData);
pData += 4;
Offset += 8;
}
if (Offset == 0x1E00)
gAircopyState = AIRCOPY_COMPLETE;
gAirCopyBlockNumber++;
return;
}
}
if ((Status & 0x0010U) != 0 || g_FSK_Buffer[0] != 0xABCD || g_FSK_Buffer[35] != 0xDCBA) {
gErrorsDuringAirCopy++;
return;
}
gErrorsDuringAirCopy++;
for (unsigned int i = 0; i < 34; i++) {
g_FSK_Buffer[i + 1] ^= Obfuscation[i % 8];
}
uint16_t CRC = CRC_Calculate(&g_FSK_Buffer[1], 2 + 64);
if (g_FSK_Buffer[34] != CRC) {
gErrorsDuringAirCopy++;
return;
}
uint16_t Offset = g_FSK_Buffer[1];
if (Offset >= 0x1E00) {
gErrorsDuringAirCopy++;
return;
}
const uint16_t *pData = &g_FSK_Buffer[2];
for (unsigned int i = 0; i < 8; i++) {
EEPROM_WriteBuffer(Offset, pData);
pData += 4;
Offset += 8;
}
if (Offset == 0x1E00) {
gAircopyState = AIRCOPY_COMPLETE;
}
gAirCopyBlockNumber++;
}
static void AIRCOPY_Key_DIGITS(KEY_Code_t Key, bool bKeyPressed, bool bKeyHeld)
{
if (!bKeyHeld && bKeyPressed)
{
uint32_t Frequency;
unsigned int i;
INPUTBOX_Append(Key);
gRequestDisplayScreen = DISPLAY_AIRCOPY;
if (gInputBoxIndex < 6)
{
#ifdef ENABLE_VOICE
gAnotherVoiceID = (VOICE_ID_t)Key;
#endif
return;
}
gInputBoxIndex = 0;
Frequency = StrToUL(INPUTBOX_GetAscii()) * 100;
for (i = 0; i < ARRAY_SIZE(frequencyBandTable); i++)
{
if (Frequency >= frequencyBandTable[i].lower && Frequency < frequencyBandTable[i].upper)
{
#ifdef ENABLE_VOICE
gAnotherVoiceID = (VOICE_ID_t)Key;
#endif
gRxVfo->Band = i;
Frequency = FREQUENCY_RoundToStep(Frequency, gRxVfo->StepFrequency);
gRxVfo->freq_config_RX.Frequency = Frequency;
gRxVfo->freq_config_TX.Frequency = Frequency;
RADIO_ConfigureSquelchAndOutputPower(gRxVfo);
gCurrentVfo = gRxVfo;
RADIO_SetupRegisters(true);
BK4819_SetupAircopy();
BK4819_ResetFSK();
return;
}
}
gRequestDisplayScreen = DISPLAY_AIRCOPY;
if (bKeyHeld || !bKeyPressed) {
return;
}
INPUTBOX_Append(Key);
gRequestDisplayScreen = DISPLAY_AIRCOPY;
if (gInputBoxIndex < 6) {
#ifdef ENABLE_VOICE
gAnotherVoiceID = (VOICE_ID_t)Key;
#endif
return;
}
gInputBoxIndex = 0;
uint32_t Frequency = StrToUL(INPUTBOX_GetAscii()) * 100;
for (unsigned int i = 0; i < BAND_N_ELEM; i++) {
if (Frequency < frequencyBandTable[i].lower || Frequency >= frequencyBandTable[i].upper) {
continue;
}
if (TX_freq_check(Frequency)) {
continue;
}
#ifdef ENABLE_VOICE
gAnotherVoiceID = (VOICE_ID_t)Key;
#endif
Frequency = FREQUENCY_RoundToStep(Frequency, gRxVfo->StepFrequency);
gRxVfo->Band = i;
gRxVfo->freq_config_RX.Frequency = Frequency;
gRxVfo->freq_config_TX.Frequency = Frequency;
RADIO_ConfigureSquelchAndOutputPower(gRxVfo);
gCurrentVfo = gRxVfo;
RADIO_SetupRegisters(true);
BK4819_SetupAircopy();
BK4819_ResetFSK();
return;
}
gRequestDisplayScreen = DISPLAY_AIRCOPY;
}
static void AIRCOPY_Key_EXIT(bool bKeyPressed, bool bKeyHeld)
{
if (!bKeyHeld && bKeyPressed)
{
if (gInputBoxIndex == 0)
{
gFSKWriteIndex = 0;
gAirCopyBlockNumber = 0;
gErrorsDuringAirCopy = 0;
gInputBoxIndex = 0;
gAirCopyIsSendMode = 0;
BK4819_PrepareFSKReceive();
gAircopyState = AIRCOPY_TRANSFER;
}
else
gInputBox[--gInputBoxIndex] = 10;
gRequestDisplayScreen = DISPLAY_AIRCOPY;
if (bKeyHeld || !bKeyPressed) {
return;
}
if (gInputBoxIndex == 0) {
gFSKWriteIndex = 0;
gAirCopyBlockNumber = 0;
gInputBoxIndex = 0;
gErrorsDuringAirCopy = 0;
gAirCopyIsSendMode = 0;
BK4819_PrepareFSKReceive();
gAircopyState = AIRCOPY_TRANSFER;
} else {
gInputBox[--gInputBoxIndex] = 10;
}
gRequestDisplayScreen = DISPLAY_AIRCOPY;
}
static void AIRCOPY_Key_MENU(bool bKeyPressed, bool bKeyHeld)
{
if (!bKeyHeld && bKeyPressed)
{
gFSKWriteIndex = 0;
gAirCopyBlockNumber = 0;
gInputBoxIndex = 0;
gAirCopyIsSendMode = 1;
g_FSK_Buffer[0] = 0xABCD;
g_FSK_Buffer[1] = 0;
g_FSK_Buffer[35] = 0xDCBA;
AIRCOPY_SendMessage();
GUI_DisplayScreen();
gAircopyState = AIRCOPY_TRANSFER;
if (bKeyHeld || !bKeyPressed) {
return;
}
gFSKWriteIndex = 0;
gAirCopyBlockNumber = 0;
gInputBoxIndex = 0;
gAirCopyIsSendMode = 1;
g_FSK_Buffer[0] = 0xABCD;
g_FSK_Buffer[1] = 0;
g_FSK_Buffer[35] = 0xDCBA;
GUI_DisplayScreen();
gAircopyState = AIRCOPY_TRANSFER;
}
void AIRCOPY_ProcessKeys(KEY_Code_t Key, bool bKeyPressed, bool bKeyHeld)
{
switch (Key)
{
case KEY_0:
case KEY_1:
case KEY_2:
case KEY_3:
case KEY_4:
case KEY_5:
case KEY_6:
case KEY_7:
case KEY_8:
case KEY_9:
AIRCOPY_Key_DIGITS(Key, bKeyPressed, bKeyHeld);
break;
case KEY_MENU:
AIRCOPY_Key_MENU(bKeyPressed, bKeyHeld);
break;
case KEY_EXIT:
AIRCOPY_Key_EXIT(bKeyPressed, bKeyHeld);
break;
default:
break;
switch (Key) {
case KEY_0:
case KEY_1:
case KEY_2:
case KEY_3:
case KEY_4:
case KEY_5:
case KEY_6:
case KEY_7:
case KEY_8:
case KEY_9:
AIRCOPY_Key_DIGITS(Key, bKeyPressed, bKeyHeld);
break;
case KEY_MENU:
AIRCOPY_Key_MENU(bKeyPressed, bKeyHeld);
break;
case KEY_EXIT:
AIRCOPY_Key_EXIT(bKeyPressed, bKeyHeld);
break;
default:
break;
}
}

View File

@@ -37,11 +37,10 @@ extern uint8_t gAirCopyIsSendMode;
extern uint16_t g_FSK_Buffer[36];
void AIRCOPY_SendMessage(void);
bool AIRCOPY_SendMessage(void);
void AIRCOPY_StorePacket(void);
void AIRCOPY_ProcessKeys(KEY_Code_t Key, bool bKeyPressed, bool bKeyHeld);
#endif
#endif

1864
app/app.c

File diff suppressed because it is too large Load Diff

View File

@@ -24,7 +24,8 @@
#include "radio.h"
void APP_EndTransmission(void);
void APP_StartListening(FUNCTION_Type_t Function, const bool reset_am_fix);
void APP_StartListening(FUNCTION_Type_t function);
uint32_t APP_SetFreqByStepAndLimits(VFO_Info_t *pInfo, int8_t direction, uint32_t lower, uint32_t upper);
uint32_t APP_SetFrequencyByStep(VFO_Info_t *pInfo, int8_t direction);
void APP_Update(void);
void APP_TimeSlice10ms(void);

273
app/chFrScanner.c Normal file
View File

@@ -0,0 +1,273 @@
#include "app/app.h"
#include "app/chFrScanner.h"
#include "functions.h"
#include "misc.h"
#include "settings.h"
int8_t gScanStateDir;
bool gScanKeepResult;
bool gScanPauseMode;
#ifdef ENABLE_SCAN_RANGES
uint32_t gScanRangeStart;
uint32_t gScanRangeStop;
#endif
typedef enum {
SCAN_NEXT_CHAN_SCANLIST1 = 0,
SCAN_NEXT_CHAN_SCANLIST2,
SCAN_NEXT_CHAN_DUAL_WATCH,
SCAN_NEXT_CHAN_MR,
SCAN_NEXT_NUM
} scan_next_chan_t;
scan_next_chan_t currentScanList;
uint32_t initialFrqOrChan;
uint8_t initialCROSS_BAND_RX_TX;
uint32_t lastFoundFrqOrChan;
static void NextFreqChannel(void);
static void NextMemChannel(void);
void CHFRSCANNER_Start(const bool storeBackupSettings, const int8_t scan_direction)
{
if (storeBackupSettings) {
initialCROSS_BAND_RX_TX = gEeprom.CROSS_BAND_RX_TX;
gEeprom.CROSS_BAND_RX_TX = CROSS_BAND_OFF;
gScanKeepResult = false;
}
RADIO_SelectVfos();
gNextMrChannel = gRxVfo->CHANNEL_SAVE;
currentScanList = SCAN_NEXT_CHAN_SCANLIST1;
gScanStateDir = scan_direction;
if (IS_MR_CHANNEL(gNextMrChannel))
{ // channel mode
if (storeBackupSettings) {
initialFrqOrChan = gRxVfo->CHANNEL_SAVE;
lastFoundFrqOrChan = initialFrqOrChan;
}
NextMemChannel();
}
else
{ // frequency mode
if (storeBackupSettings) {
initialFrqOrChan = gRxVfo->freq_config_RX.Frequency;
lastFoundFrqOrChan = initialFrqOrChan;
}
NextFreqChannel();
}
gScanPauseDelayIn_10ms = scan_pause_delay_in_2_10ms;
gScheduleScanListen = false;
gRxReceptionMode = RX_MODE_NONE;
gScanPauseMode = false;
}
void CHFRSCANNER_ContinueScanning(void)
{
if (IS_FREQ_CHANNEL(gNextMrChannel))
{
if (gCurrentFunction == FUNCTION_INCOMING)
APP_StartListening(gMonitor ? FUNCTION_MONITOR : FUNCTION_RECEIVE);
else
NextFreqChannel(); // switch to next frequency
}
else
{
if (gCurrentCodeType == CODE_TYPE_OFF && gCurrentFunction == FUNCTION_INCOMING)
APP_StartListening(gMonitor ? FUNCTION_MONITOR : FUNCTION_RECEIVE);
else
NextMemChannel(); // switch to next channel
}
gScanPauseMode = false;
gRxReceptionMode = RX_MODE_NONE;
gScheduleScanListen = false;
}
void CHFRSCANNER_Found(void)
{
switch (gEeprom.SCAN_RESUME_MODE)
{
case SCAN_RESUME_TO:
if (!gScanPauseMode)
{
gScanPauseDelayIn_10ms = scan_pause_delay_in_1_10ms;
gScheduleScanListen = false;
gScanPauseMode = true;
}
break;
case SCAN_RESUME_CO:
case SCAN_RESUME_SE:
gScanPauseDelayIn_10ms = 0;
gScheduleScanListen = false;
break;
}
if (IS_MR_CHANNEL(gRxVfo->CHANNEL_SAVE)) { //memory scan
lastFoundFrqOrChan = gRxVfo->CHANNEL_SAVE;
}
else { // frequency scan
lastFoundFrqOrChan = gRxVfo->freq_config_RX.Frequency;
}
gScanKeepResult = true;
}
void CHFRSCANNER_Stop(void)
{
if(initialCROSS_BAND_RX_TX != CROSS_BAND_OFF) {
gEeprom.CROSS_BAND_RX_TX = initialCROSS_BAND_RX_TX;
initialCROSS_BAND_RX_TX = CROSS_BAND_OFF;
}
gScanStateDir = SCAN_OFF;
const uint32_t chFr = gScanKeepResult ? lastFoundFrqOrChan : initialFrqOrChan;
const bool channelChanged = chFr != initialFrqOrChan;
if (IS_MR_CHANNEL(gNextMrChannel)) {
gEeprom.MrChannel[gEeprom.RX_VFO] = chFr;
gEeprom.ScreenChannel[gEeprom.RX_VFO] = chFr;
RADIO_ConfigureChannel(gEeprom.RX_VFO, VFO_CONFIGURE_RELOAD);
if(channelChanged) {
SETTINGS_SaveVfoIndices();
gUpdateStatus = true;
}
}
else {
gRxVfo->freq_config_RX.Frequency = chFr;
RADIO_ApplyOffset(gRxVfo);
RADIO_ConfigureSquelchAndOutputPower(gRxVfo);
if(channelChanged) {
SETTINGS_SaveChannel(gRxVfo->CHANNEL_SAVE, gEeprom.RX_VFO, gRxVfo, 1);
}
}
RADIO_SetupRegisters(true);
gUpdateDisplay = true;
}
static void NextFreqChannel(void)
{
#ifdef ENABLE_SCAN_RANGES
if(gScanRangeStart) {
gRxVfo->freq_config_RX.Frequency = APP_SetFreqByStepAndLimits(gRxVfo, gScanStateDir, gScanRangeStart, gScanRangeStop);
}
else
#endif
gRxVfo->freq_config_RX.Frequency = APP_SetFrequencyByStep(gRxVfo, gScanStateDir);
RADIO_ApplyOffset(gRxVfo);
RADIO_ConfigureSquelchAndOutputPower(gRxVfo);
RADIO_SetupRegisters(true);
#ifdef ENABLE_FASTER_CHANNEL_SCAN
gScanPauseDelayIn_10ms = 9; // 90ms
#else
gScanPauseDelayIn_10ms = scan_pause_delay_in_6_10ms;
#endif
gUpdateDisplay = true;
}
static void NextMemChannel(void)
{
static unsigned int prev_mr_chan = 0;
const bool enabled = (gEeprom.SCAN_LIST_DEFAULT < 2) ? gEeprom.SCAN_LIST_ENABLED[gEeprom.SCAN_LIST_DEFAULT] : true;
const int chan1 = (gEeprom.SCAN_LIST_DEFAULT < 2) ? gEeprom.SCANLIST_PRIORITY_CH1[gEeprom.SCAN_LIST_DEFAULT] : -1;
const int chan2 = (gEeprom.SCAN_LIST_DEFAULT < 2) ? gEeprom.SCANLIST_PRIORITY_CH2[gEeprom.SCAN_LIST_DEFAULT] : -1;
const unsigned int prev_chan = gNextMrChannel;
unsigned int chan = 0;
if (enabled)
{
switch (currentScanList)
{
case SCAN_NEXT_CHAN_SCANLIST1:
prev_mr_chan = gNextMrChannel;
if (chan1 >= 0)
{
if (RADIO_CheckValidChannel(chan1, false, 0))
{
currentScanList = SCAN_NEXT_CHAN_SCANLIST1;
gNextMrChannel = chan1;
break;
}
}
[[fallthrough]];
case SCAN_NEXT_CHAN_SCANLIST2:
if (chan2 >= 0)
{
if (RADIO_CheckValidChannel(chan2, false, 0))
{
currentScanList = SCAN_NEXT_CHAN_SCANLIST2;
gNextMrChannel = chan2;
break;
}
}
[[fallthrough]];
// this bit doesn't yet work if the other VFO is a frequency
case SCAN_NEXT_CHAN_DUAL_WATCH:
// dual watch is enabled - include the other VFO in the scan
// if (gEeprom.DUAL_WATCH != DUAL_WATCH_OFF)
// {
// chan = (gEeprom.RX_VFO + 1) & 1u;
// chan = gEeprom.ScreenChannel[chan];
// if (IS_MR_CHANNEL(chan))
// {
// currentScanList = SCAN_NEXT_CHAN_DUAL_WATCH;
// gNextMrChannel = chan;
// break;
// }
// }
default:
case SCAN_NEXT_CHAN_MR:
currentScanList = SCAN_NEXT_CHAN_MR;
gNextMrChannel = prev_mr_chan;
chan = 0xff;
break;
}
}
if (!enabled || chan == 0xff)
{
chan = RADIO_FindNextChannel(gNextMrChannel + gScanStateDir, gScanStateDir, (gEeprom.SCAN_LIST_DEFAULT < 2) ? true : false, gEeprom.SCAN_LIST_DEFAULT);
if (chan == 0xFF)
{ // no valid channel found
chan = MR_CHANNEL_FIRST;
}
gNextMrChannel = chan;
}
if (gNextMrChannel != prev_chan)
{
gEeprom.MrChannel[ gEeprom.RX_VFO] = gNextMrChannel;
gEeprom.ScreenChannel[gEeprom.RX_VFO] = gNextMrChannel;
RADIO_ConfigureChannel(gEeprom.RX_VFO, VFO_CONFIGURE_RELOAD);
RADIO_SetupRegisters(true);
gUpdateDisplay = true;
}
#ifdef ENABLE_FASTER_CHANNEL_SCAN
gScanPauseDelayIn_10ms = 9; // 90ms .. <= ~60ms it misses signals (squelch response and/or PLL lock time) ?
#else
gScanPauseDelayIn_10ms = scan_pause_delay_in_3_10ms;
#endif
if (enabled)
if (++currentScanList >= SCAN_NEXT_NUM)
currentScanList = SCAN_NEXT_CHAN_SCANLIST1; // back round we go
}

23
app/chFrScanner.h Normal file
View File

@@ -0,0 +1,23 @@
#ifndef APP_CHFRSCANNER_H
#define APP_CHFRSCANNER_H
#include <stdbool.h>
#include <stdint.h>
// scan direction, if not equal SCAN_OFF indicates
// that we are in a process of scanning channels/frequencies
extern int8_t gScanStateDir;
extern bool gScanKeepResult;
extern bool gScanPauseMode;
#ifdef ENABLE_SCAN_RANGES
extern uint32_t gScanRangeStart;
extern uint32_t gScanRangeStop;
#endif
void CHFRSCANNER_Found(void);
void CHFRSCANNER_Stop(void);
void CHFRSCANNER_Start(const bool storeBackupSettings, const int8_t scan_direction);
void CHFRSCANNER_ContinueScanning(void);
#endif

View File

@@ -1,3 +1,4 @@
#include "app/chFrScanner.h"
#include "audio.h"
#include "functions.h"
#include "misc.h"
@@ -23,6 +24,9 @@ void COMMON_KeypadLockToggle()
void COMMON_SwitchVFOs()
{
#ifdef ENABLE_SCAN_RANGES
gScanRangeStart = 0;
#endif
gEeprom.TX_VFO ^= 1;
if (gEeprom.CROSS_BAND_RX_TX != CROSS_BAND_OFF)

View File

@@ -17,6 +17,7 @@
#include <string.h>
#include <stdio.h> // NULL
#include "app/chFrScanner.h"
#ifdef ENABLE_FMRADIO
#include "app/fm.h"
#endif
@@ -40,14 +41,15 @@ uint8_t gDTMF_InputBox_Index = 0;
bool gDTMF_InputMode = false;
uint8_t gDTMF_PreviousIndex = 0;
char gDTMF_RX_live[20];
uint8_t gDTMF_RX_live_timeout = 0;
#ifdef ENABLE_DTMF_CALLING
char gDTMF_RX[17];
uint8_t gDTMF_RX_index = 0;
uint8_t gDTMF_RX_timeout = 0;
bool gDTMF_RX_pending = false;
char gDTMF_RX_live[20];
uint8_t gDTMF_RX_live_timeout = 0;
bool gIsDtmfContactValid;
char gDTMF_ID[4];
char gDTMF_Caller[4];
@@ -57,12 +59,16 @@ uint8_t gDTMF_DecodeRingCountdown_500ms;
uint8_t gDTMF_chosen_contact;
uint8_t gDTMF_auto_reset_time_500ms;
DTMF_CallState_t gDTMF_CallState;
DTMF_ReplyState_t gDTMF_ReplyState;
DTMF_CallMode_t gDTMF_CallMode;
bool gDTMF_IsTx;
uint8_t gDTMF_TxStopCountdown_500ms;
bool gDTMF_IsGroupCall;
#endif
DTMF_ReplyState_t gDTMF_ReplyState;
#ifdef ENABLE_DTMF_CALLING
void DTMF_clear_RX(void)
{
gDTMF_RX_timeout = 0;
@@ -70,6 +76,39 @@ void DTMF_clear_RX(void)
gDTMF_RX_pending = false;
memset(gDTMF_RX, 0, sizeof(gDTMF_RX));
}
#endif
void DTMF_SendEndOfTransmission(void)
{
if (gCurrentVfo->DTMF_PTT_ID_TX_MODE == PTT_ID_APOLLO)
BK4819_PlaySingleTone(2475, 250, 28, gEeprom.DTMF_SIDE_TONE);
else if ((gCurrentVfo->DTMF_PTT_ID_TX_MODE == PTT_ID_TX_DOWN || gCurrentVfo->DTMF_PTT_ID_TX_MODE == PTT_ID_BOTH)
#ifdef ENABLE_DTMF_CALLING
&& gDTMF_CallState == DTMF_CALL_STATE_NONE
#endif
) { // end-of-tx
if (gEeprom.DTMF_SIDE_TONE) {
AUDIO_AudioPathOn();
gEnableSpeaker = true;
SYSTEM_DelayMs(60);
}
BK4819_EnterDTMF_TX(gEeprom.DTMF_SIDE_TONE);
BK4819_PlayDTMFString(
gEeprom.DTMF_DOWN_CODE,
0,
gEeprom.DTMF_FIRST_CODE_PERSIST_TIME,
gEeprom.DTMF_HASH_CODE_PERSIST_TIME,
gEeprom.DTMF_CODE_PERSIST_TIME,
gEeprom.DTMF_CODE_INTERVAL_TIME);
AUDIO_AudioPathOff();
gEnableSpeaker = false;
}
BK4819_ExitDTMF_TX(true);
}
bool DTMF_ValidateCodes(char *pCode, const unsigned int size)
{
@@ -93,36 +132,31 @@ bool DTMF_ValidateCodes(char *pCode, const unsigned int size)
return true;
}
#ifdef ENABLE_DTMF_CALLING
bool DTMF_GetContact(const int Index, char *pContact)
{
int i = -1;
if (Index >= 0 && Index < MAX_DTMF_CONTACTS && pContact != NULL)
{
EEPROM_ReadBuffer(0x1C00 + (Index * 16), pContact, 16);
i = (int)pContact[0] - ' ';
if (Index < 0 || Index >= MAX_DTMF_CONTACTS || pContact == NULL) {
return false;
}
return (i < 0 || i >= 95) ? false : true;
EEPROM_ReadBuffer(0x1C00 + (Index * 16), pContact, 16);
// check whether the first character is printable or not
return (pContact[0] >= ' ' && pContact[0] < 127);
}
bool DTMF_FindContact(const char *pContact, char *pResult)
{
char Contact[16];
unsigned int i;
pResult[0] = 0;
for (i = 0; i < MAX_DTMF_CONTACTS; i++)
{
unsigned int j;
if (!DTMF_GetContact(i, Contact))
for (unsigned int i = 0; i < MAX_DTMF_CONTACTS; i++) {
char Contact[16];
if (!DTMF_GetContact(i, Contact)) {
return false;
}
for (j = 0; j < 3; j++)
if (pContact[j] != Contact[j + 8])
break;
if (j == 3)
{
memmove(pResult, Contact, 8);
if (memcmp(pContact, Contact + 8, 3) == 0) {
memcpy(pResult, Contact, 8);
pResult[8] = 0;
return true;
}
@@ -131,6 +165,8 @@ bool DTMF_FindContact(const char *pContact, char *pResult)
return false;
}
#endif
char DTMF_GetCharacter(const unsigned int code)
{
switch (code)
@@ -154,8 +190,8 @@ char DTMF_GetCharacter(const unsigned int code)
default: return 0xff;
}
}
bool DTMF_CompareMessage(const char *pMsg, const char *pTemplate, const unsigned int size, const bool bCheckGroup)
#ifdef ENABLE_DTMF_CALLING
static bool CompareMessage(const char *pMsg, const char *pTemplate, const unsigned int size, const bool bCheckGroup)
{
unsigned int i;
for (i = 0; i < size; i++)
@@ -173,13 +209,14 @@ bool DTMF_CompareMessage(const char *pMsg, const char *pTemplate, const unsigned
DTMF_CallMode_t DTMF_CheckGroupCall(const char *pMsg, const unsigned int size)
{
unsigned int i;
for (i = 0; i < size; i++)
if (pMsg[i] == gEeprom.DTMF_GROUP_CALL_CODE)
break;
for (unsigned int i = 0; i < size; i++)
if (pMsg[i] == gEeprom.DTMF_GROUP_CALL_CODE) {
return DTMF_CALL_MODE_GROUP;
}
return (i < size) ? DTMF_CALL_MODE_GROUP : DTMF_CALL_MODE_NOT_GROUP;
return DTMF_CALL_MODE_NOT_GROUP;
}
#endif
void DTMF_clear_input_box(void)
{
@@ -200,6 +237,7 @@ void DTMF_Append(const char code)
gDTMF_InputBox[gDTMF_InputBox_Index++] = code;
}
#ifdef ENABLE_DTMF_CALLING
void DTMF_HandleRequest(void)
{ // proccess the RX'ed DTMF characters
@@ -209,7 +247,7 @@ void DTMF_HandleRequest(void)
if (!gDTMF_RX_pending)
return; // nothing new received
if (gScanStateDir != SCAN_OFF || gCssScanMode != CSS_SCAN_MODE_OFF)
if (gScanStateDir != SCAN_OFF || gCssBackgroundScan)
{ // we're busy scanning
DTMF_clear_RX();
return;
@@ -230,7 +268,7 @@ void DTMF_HandleRequest(void)
Offset = gDTMF_RX_index - strlen(String);
if (DTMF_CompareMessage(gDTMF_RX + Offset, String, strlen(String), true))
if (CompareMessage(gDTMF_RX + Offset, String, strlen(String), true))
{ // bugger
if (gEeprom.PERMIT_REMOTE_KILL)
@@ -271,7 +309,7 @@ void DTMF_HandleRequest(void)
Offset = gDTMF_RX_index - strlen(String);
if (DTMF_CompareMessage(gDTMF_RX + Offset, String, strlen(String), true))
if (CompareMessage(gDTMF_RX + Offset, String, strlen(String), true))
{ // shit, we're back !
gSetting_KILLED = false;
@@ -291,13 +329,12 @@ void DTMF_HandleRequest(void)
if (gDTMF_RX_index >= 2)
{ // look for ACK reply
char *pPrintStr = "AB";
strcpy(String, "AB");
Offset = gDTMF_RX_index - strlen(pPrintStr);
Offset = gDTMF_RX_index - strlen(String);
if (DTMF_CompareMessage(gDTMF_RX + Offset, String, strlen(String), true))
{ // ends with "AB"
if (CompareMessage(gDTMF_RX + Offset, pPrintStr, strlen(pPrintStr), true)) {
// ends with "AB"
if (gDTMF_ReplyState != DTMF_REPLY_NONE) // 1of11
// if (gDTMF_CallState != DTMF_CALL_STATE_NONE) // 1of11
@@ -320,7 +357,7 @@ void DTMF_HandleRequest(void)
Offset = gDTMF_RX_index - strlen(String);
if (DTMF_CompareMessage(gDTMF_RX + Offset, String, strlen(String), false))
if (CompareMessage(gDTMF_RX + Offset, String, strlen(String), false))
{ // we got a response
gDTMF_State = DTMF_STATE_CALL_OUT_RSP;
DTMF_clear_RX();
@@ -342,15 +379,15 @@ void DTMF_HandleRequest(void)
Offset = gDTMF_RX_index - strlen(String) - 3;
if (DTMF_CompareMessage(gDTMF_RX + Offset, String, strlen(String), true))
if (CompareMessage(gDTMF_RX + Offset, String, strlen(String), true))
{ // it's for us !
gDTMF_CallState = DTMF_CALL_STATE_RECEIVED;
memset(gDTMF_Callee, 0, sizeof(gDTMF_Callee));
memset(gDTMF_Caller, 0, sizeof(gDTMF_Caller));
memmove(gDTMF_Callee, gDTMF_RX + Offset + 0, 3);
memmove(gDTMF_Caller, gDTMF_RX + Offset + 4, 3);
memcpy(gDTMF_Callee, gDTMF_RX + Offset + 0, 3);
memcpy(gDTMF_Caller, gDTMF_RX + Offset + 4, 3);
DTMF_clear_RX();
@@ -379,27 +416,33 @@ void DTMF_HandleRequest(void)
}
}
}
#endif
void DTMF_Reply(void)
{
uint16_t Delay;
#ifdef ENABLE_DTMF_CALLING
char String[23];
#endif
const char *pString = NULL;
switch (gDTMF_ReplyState)
{
case DTMF_REPLY_ANI:
if (gDTMF_CallMode == DTMF_CALL_MODE_DTMF)
{
pString = gDTMF_String;
}
else
#ifdef ENABLE_DTMF_CALLING
if (gDTMF_CallMode != DTMF_CALL_MODE_DTMF)
{ // append our ID code onto the end of the DTMF code to send
sprintf(String, "%s%c%s", gDTMF_String, gEeprom.DTMF_SEPARATE_CODE, gEeprom.ANI_DTMF_ID);
pString = String;
}
break;
else
#endif
{
pString = gDTMF_String;
}
break;
#ifdef ENABLE_DTMF_CALLING
case DTMF_REPLY_AB:
pString = "AB";
break;
@@ -408,10 +451,13 @@ void DTMF_Reply(void)
sprintf(String, "%s%c%s", gEeprom.ANI_DTMF_ID, gEeprom.DTMF_SEPARATE_CODE, "AAAAA");
pString = String;
break;
#endif
default:
case DTMF_REPLY_NONE:
if (gDTMF_CallState != DTMF_CALL_STATE_NONE ||
if (
#ifdef ENABLE_DTMF_CALLING
gDTMF_CallState != DTMF_CALL_STATE_NONE ||
#endif
gCurrentVfo->DTMF_PTT_ID_TX_MODE == PTT_ID_APOLLO ||
gCurrentVfo->DTMF_PTT_ID_TX_MODE == PTT_ID_OFF ||
gCurrentVfo->DTMF_PTT_ID_TX_MODE == PTT_ID_TX_DOWN)

View File

@@ -75,14 +75,25 @@ extern uint8_t gDTMF_InputBox_Index;
extern bool gDTMF_InputMode;
extern uint8_t gDTMF_PreviousIndex;
extern char gDTMF_RX_live[20];
extern uint8_t gDTMF_RX_live_timeout;
extern DTMF_ReplyState_t gDTMF_ReplyState;
bool DTMF_ValidateCodes(char *pCode, const unsigned int size);
char DTMF_GetCharacter(const unsigned int code);
void DTMF_clear_input_box(void);
void DTMF_Append(const char code);
void DTMF_Reply(void);
void DTMF_SendEndOfTransmission(void);
#ifdef ENABLE_DTMF_CALLING
extern char gDTMF_RX[17];
extern uint8_t gDTMF_RX_index;
extern uint8_t gDTMF_RX_timeout;
extern bool gDTMF_RX_pending;
extern char gDTMF_RX_live[20];
extern uint8_t gDTMF_RX_live_timeout;
extern bool gIsDtmfContactValid;
extern char gDTMF_ID[4];
extern char gDTMF_Caller[4];
@@ -92,21 +103,17 @@ extern uint8_t gDTMF_DecodeRingCountdown_500ms;
extern uint8_t gDTMF_chosen_contact;
extern uint8_t gDTMF_auto_reset_time_500ms;
extern DTMF_CallState_t gDTMF_CallState;
extern DTMF_ReplyState_t gDTMF_ReplyState;
extern DTMF_CallMode_t gDTMF_CallMode;
extern bool gDTMF_IsTx;
extern uint8_t gDTMF_TxStopCountdown_500ms;
void DTMF_clear_RX(void);
bool DTMF_ValidateCodes(char *pCode, const unsigned int size);
DTMF_CallMode_t DTMF_CheckGroupCall(const char *pDTMF, const unsigned int size);
bool DTMF_GetContact(const int Index, char *pContact);
bool DTMF_FindContact(const char *pContact, char *pResult);
char DTMF_GetCharacter(const unsigned int code);
bool DTMF_CompareMessage(const char *pDTMF, const char *pTemplate, const unsigned int size, const bool bFlag);
DTMF_CallMode_t DTMF_CheckGroupCall(const char *pDTMF, const unsigned int size);
void DTMF_clear_input_box(void);
void DTMF_Append(const char vode);
void DTMF_HandleRequest(void);
void DTMF_Reply(void);
#endif
#endif

66
app/flashlight.c Normal file
View File

@@ -0,0 +1,66 @@
#ifdef ENABLE_FLASHLIGHT
#include "driver/gpio.h"
#include "bsp/dp32g030/gpio.h"
#include "flashlight.h"
enum FlashlightMode_t gFlashLightState;
void FlashlightTimeSlice()
{
if (gFlashLightState == FLASHLIGHT_BLINK && (gFlashLightBlinkCounter & 15u) == 0) {
GPIO_FlipBit(&GPIOC->DATA, GPIOC_PIN_FLASHLIGHT);
return;
}
if (gFlashLightState == FLASHLIGHT_SOS) {
const uint16_t u = 15;
static uint8_t c;
static uint16_t next;
if (gFlashLightBlinkCounter - next > 7 * u) {
c = 0;
next = gFlashLightBlinkCounter + 1;
return;
}
if (gFlashLightBlinkCounter == next) {
if (c==0) {
GPIO_ClearBit(&GPIOC->DATA, GPIOC_PIN_FLASHLIGHT);
} else {
GPIO_FlipBit(&GPIOC->DATA, GPIOC_PIN_FLASHLIGHT);
}
if (c >= 18) {
next = gFlashLightBlinkCounter + 7 * u;
c = 0;
} else if(c==7 || c==9 || c==11) {
next = gFlashLightBlinkCounter + 3 * u;
} else {
next = gFlashLightBlinkCounter + u;
}
c++;
}
}
}
void ACTION_FlashLight(void)
{
switch (gFlashLightState) {
case FLASHLIGHT_OFF:
gFlashLightState++;
GPIO_SetBit(&GPIOC->DATA, GPIOC_PIN_FLASHLIGHT);
break;
case FLASHLIGHT_ON:
case FLASHLIGHT_BLINK:
gFlashLightState++;
break;
case FLASHLIGHT_SOS:
default:
gFlashLightState = 0;
GPIO_ClearBit(&GPIOC->DATA, GPIOC_PIN_FLASHLIGHT);
}
}
#endif

23
app/flashlight.h Normal file
View File

@@ -0,0 +1,23 @@
#ifndef APP_FLASHLIGHT_H
#define APP_FLASHLIGHT_H
#ifdef ENABLE_FLASHLIGHT
#include <stdint.h>
enum FlashlightMode_t {
FLASHLIGHT_OFF = 0,
FLASHLIGHT_ON,
FLASHLIGHT_BLINK,
FLASHLIGHT_SOS
};
extern enum FlashlightMode_t gFlashLightState;
extern volatile uint16_t gFlashLightBlinkCounter;
void FlashlightTimeSlice(void);
void ACTION_FlashLight(void);
#endif
#endif

499
app/fm.c
View File

@@ -47,21 +47,32 @@ bool gFM_FoundFrequency;
bool gFM_AutoScan;
uint16_t gFM_RestoreCountdown_10ms;
const uint8_t BUTTON_STATE_PRESSED = 1 << 0;
const uint8_t BUTTON_STATE_HELD = 1 << 1;
const uint8_t BUTTON_EVENT_PRESSED = BUTTON_STATE_PRESSED;
const uint8_t BUTTON_EVENT_HELD = BUTTON_STATE_PRESSED | BUTTON_STATE_HELD;
const uint8_t BUTTON_EVENT_SHORT = 0;
const uint8_t BUTTON_EVENT_LONG = BUTTON_STATE_HELD;
static void Key_FUNC(KEY_Code_t Key, uint8_t state);
bool FM_CheckValidChannel(uint8_t Channel)
{
return (Channel < ARRAY_SIZE(gFM_Channels) && (gFM_Channels[Channel] >= 760 && gFM_Channels[Channel] < 1080)) ? true : false;
return Channel < ARRAY_SIZE(gFM_Channels) &&
gFM_Channels[Channel] >= BK1080_GetFreqLoLimit(gEeprom.FM_Band) &&
gFM_Channels[Channel] < BK1080_GetFreqHiLimit(gEeprom.FM_Band);
}
uint8_t FM_FindNextChannel(uint8_t Channel, uint8_t Direction)
{
unsigned int i;
for (i = 0; i < ARRAY_SIZE(gFM_Channels); i++)
{
for (unsigned i = 0; i < ARRAY_SIZE(gFM_Channels); i++) {
if (Channel == 0xFF)
Channel = ARRAY_SIZE(gFM_Channels) - 1;
else
if (Channel >= ARRAY_SIZE(gFM_Channels))
else if (Channel >= ARRAY_SIZE(gFM_Channels))
Channel = 0;
if (FM_CheckValidChannel(Channel))
return Channel;
@@ -75,11 +86,9 @@ int FM_ConfigureChannelState(void)
{
gEeprom.FM_FrequencyPlaying = gEeprom.FM_SelectedFrequency;
if (gEeprom.FM_IsMrMode)
{
if (gEeprom.FM_IsMrMode) {
const uint8_t Channel = FM_FindNextChannel(gEeprom.FM_SelectedChannel, FM_CHANNEL_UP);
if (Channel == 0xFF)
{
if (Channel == 0xFF) {
gEeprom.FM_IsMrMode = false;
return -1;
}
@@ -97,21 +106,19 @@ void FM_TurnOff(void)
gFM_RestoreCountdown_10ms = 0;
AUDIO_AudioPathOff();
gEnableSpeaker = false;
BK1080_Init(0, false);
BK1080_Init0();
gUpdateStatus = true;
}
void FM_EraseChannels(void)
{
unsigned int i;
uint8_t Template[8];
memset(Template, 0xFF, sizeof(Template));
for (i = 0; i < 5; i++)
for (unsigned i = 0; i < 5; i++)
EEPROM_WriteBuffer(0x0E40 + (i * 8), Template);
memset(gFM_Channels, 0xFF, sizeof(gFM_Channels));
@@ -131,35 +138,32 @@ void FM_Tune(uint16_t Frequency, int8_t Step, bool bFlag)
gAskToDelete = false;
gEeprom.FM_FrequencyPlaying = Frequency;
if (!bFlag)
{
if (!bFlag) {
Frequency += Step;
if (Frequency < gEeprom.FM_LowerLimit)
Frequency = gEeprom.FM_UpperLimit;
else
if (Frequency > gEeprom.FM_UpperLimit)
Frequency = gEeprom.FM_LowerLimit;
if (Frequency < BK1080_GetFreqLoLimit(gEeprom.FM_Band))
Frequency = BK1080_GetFreqHiLimit(gEeprom.FM_Band);
else if (Frequency > BK1080_GetFreqHiLimit(gEeprom.FM_Band))
Frequency = BK1080_GetFreqLoLimit(gEeprom.FM_Band);
gEeprom.FM_FrequencyPlaying = Frequency;
}
gFM_ScanState = Step;
BK1080_SetFrequency(gEeprom.FM_FrequencyPlaying);
BK1080_SetFrequency(gEeprom.FM_FrequencyPlaying, gEeprom.FM_Band/*, gEeprom.FM_Space*/);
}
void FM_PlayAndUpdate(void)
{
gFM_ScanState = FM_SCAN_OFF;
if (gFM_AutoScan)
{
if (gFM_AutoScan) {
gEeprom.FM_IsMrMode = true;
gEeprom.FM_SelectedChannel = 0;
}
FM_ConfigureChannelState();
BK1080_SetFrequency(gEeprom.FM_FrequencyPlaying);
BK1080_SetFrequency(gEeprom.FM_FrequencyPlaying, gEeprom.FM_Band/*, gEeprom.FM_Space*/);
SETTINGS_SaveFM();
gFmPlayCountdown_10ms = 0;
@@ -180,42 +184,36 @@ int FM_CheckFrequencyLock(uint16_t Frequency, uint16_t LowerLimit)
// This is supposed to be a signed value, but above function is unsigned
const uint16_t Deviation = BK1080_REG_07_GET_FREQD(Test2);
if (BK1080_REG_07_GET_SNR(Test2) >= 2)
{
const uint16_t Status = BK1080_ReadRegister(BK1080_REG_10);
if ((Status & BK1080_REG_10_MASK_AFCRL) == BK1080_REG_10_AFCRL_NOT_RAILED && BK1080_REG_10_GET_RSSI(Status) >= 10)
{
//if (Deviation > -281 && Deviation < 280)
if (Deviation < 280 || Deviation > 3815)
{
// not BLE(less than or equal)
if (Frequency > LowerLimit && (Frequency - BK1080_BaseFrequency) == 1)
{
if (BK1080_FrequencyDeviation & 0x800)
goto Bail;
if (BK1080_FrequencyDeviation < 20)
goto Bail;
}
// not BLT(less than)
if (Frequency >= LowerLimit && (BK1080_BaseFrequency - Frequency) == 1)
{
if ((BK1080_FrequencyDeviation & 0x800) == 0)
goto Bail;
// if (BK1080_FrequencyDeviation > -21)
if (BK1080_FrequencyDeviation > 4075)
goto Bail;
}
ret = 0;
}
}
if (BK1080_REG_07_GET_SNR(Test2) <= 2) {
goto Bail;
}
const uint16_t Status = BK1080_ReadRegister(BK1080_REG_10);
if ((Status & BK1080_REG_10_MASK_AFCRL) != BK1080_REG_10_AFCRL_NOT_RAILED || BK1080_REG_10_GET_RSSI(Status) < 10) {
goto Bail;
}
//if (Deviation > -281 && Deviation < 280)
if (Deviation >= 280 && Deviation <= 3815) {
goto Bail;
}
// not BLE(less than or equal)
if (Frequency > LowerLimit && (Frequency - BK1080_BaseFrequency) == 1) {
if (BK1080_FrequencyDeviation & 0x800 || (BK1080_FrequencyDeviation < 20))
goto Bail;
}
// not BLT(less than)
if (Frequency >= LowerLimit && (BK1080_BaseFrequency - Frequency) == 1) {
if ((BK1080_FrequencyDeviation & 0x800) == 0 || (BK1080_FrequencyDeviation > 4075))
goto Bail;
}
ret = 0;
Bail:
BK1080_FrequencyDeviation = Deviation;
BK1080_BaseFrequency = Frequency;
@@ -223,155 +221,142 @@ Bail:
return ret;
}
static void FM_Key_DIGITS(KEY_Code_t Key, bool bKeyPressed, bool bKeyHeld)
static void Key_DIGITS(KEY_Code_t Key, uint8_t state)
{
#define STATE_FREQ_MODE 0
#define STATE_MR_MODE 1
#define STATE_SAVE 2
enum { STATE_FREQ_MODE, STATE_MR_MODE, STATE_SAVE };
if (!bKeyHeld && bKeyPressed)
{
if (!gWasFKeyPressed)
{
uint8_t State;
if (state == BUTTON_EVENT_SHORT && !gWasFKeyPressed) {
uint8_t State;
if (gAskToDelete)
{
if (gAskToDelete) {
gBeepToPlay = BEEP_500HZ_60MS_DOUBLE_BEEP_OPTIONAL;
return;
}
if (gAskToSave) {
State = STATE_SAVE;
}
else {
if (gFM_ScanState != FM_SCAN_OFF) {
gBeepToPlay = BEEP_500HZ_60MS_DOUBLE_BEEP_OPTIONAL;
return;
}
if (gAskToSave)
{
State = STATE_SAVE;
State = gEeprom.FM_IsMrMode ? STATE_MR_MODE : STATE_FREQ_MODE;
}
INPUTBOX_Append(Key);
gRequestDisplayScreen = DISPLAY_FM;
if (State == STATE_FREQ_MODE) {
if (gInputBoxIndex == 1) {
if (gInputBox[0] > 1) {
gInputBox[1] = gInputBox[0];
gInputBox[0] = 0;
gInputBoxIndex = 2;
}
}
else
{
if (gFM_ScanState != FM_SCAN_OFF)
{
gBeepToPlay = BEEP_500HZ_60MS_DOUBLE_BEEP_OPTIONAL;
else if (gInputBoxIndex > 3) {
uint32_t Frequency;
gInputBoxIndex = 0;
Frequency = StrToUL(INPUTBOX_GetAscii());
if (Frequency < BK1080_GetFreqLoLimit(gEeprom.FM_Band) || BK1080_GetFreqHiLimit(gEeprom.FM_Band) < Frequency) {
gBeepToPlay = BEEP_500HZ_60MS_DOUBLE_BEEP_OPTIONAL;
gRequestDisplayScreen = DISPLAY_FM;
return;
}
State = gEeprom.FM_IsMrMode ? STATE_MR_MODE : STATE_FREQ_MODE;
gEeprom.FM_SelectedFrequency = (uint16_t)Frequency;
#ifdef ENABLE_VOICE
gAnotherVoiceID = (VOICE_ID_t)Key;
#endif
gEeprom.FM_FrequencyPlaying = gEeprom.FM_SelectedFrequency;
BK1080_SetFrequency(gEeprom.FM_FrequencyPlaying, gEeprom.FM_Band/*, gEeprom.FM_Space*/);
gRequestSaveFM = true;
return;
}
}
else if (gInputBoxIndex == 2) {
uint8_t Channel;
INPUTBOX_Append(Key);
gInputBoxIndex = 0;
Channel = ((gInputBox[0] * 10) + gInputBox[1]) - 1;
gRequestDisplayScreen = DISPLAY_FM;
if (State == STATE_FREQ_MODE)
{
if (gInputBoxIndex == 1)
{
if (gInputBox[0] > 1)
{
gInputBox[1] = gInputBox[0];
gInputBox[0] = 0;
gInputBoxIndex = 2;
}
}
else
if (gInputBoxIndex > 3)
{
uint32_t Frequency;
gInputBoxIndex = 0;
Frequency = StrToUL(INPUTBOX_GetAscii());
if (Frequency < gEeprom.FM_LowerLimit || gEeprom.FM_UpperLimit < Frequency)
{
gBeepToPlay = BEEP_500HZ_60MS_DOUBLE_BEEP_OPTIONAL;
gRequestDisplayScreen = DISPLAY_FM;
return;
}
gEeprom.FM_SelectedFrequency = (uint16_t)Frequency;
#ifdef ENABLE_VOICE
gAnotherVoiceID = (VOICE_ID_t)Key;
#endif
gEeprom.FM_FrequencyPlaying = gEeprom.FM_SelectedFrequency;
BK1080_SetFrequency(gEeprom.FM_FrequencyPlaying);
if (State == STATE_MR_MODE) {
if (FM_CheckValidChannel(Channel)) {
#ifdef ENABLE_VOICE
gAnotherVoiceID = (VOICE_ID_t)Key;
#endif
gEeprom.FM_SelectedChannel = Channel;
gEeprom.FM_FrequencyPlaying = gFM_Channels[Channel];
BK1080_SetFrequency(gEeprom.FM_FrequencyPlaying, gEeprom.FM_Band/*, gEeprom.FM_Space*/);
gRequestSaveFM = true;
return;
}
}
else
if (gInputBoxIndex == 2)
{
uint8_t Channel;
else if (Channel < 20) {
#ifdef ENABLE_VOICE
gAnotherVoiceID = (VOICE_ID_t)Key;
#endif
gRequestDisplayScreen = DISPLAY_FM;
gInputBoxIndex = 0;
Channel = ((gInputBox[0] * 10) + gInputBox[1]) - 1;
if (State == STATE_MR_MODE)
{
if (FM_CheckValidChannel(Channel))
{
#ifdef ENABLE_VOICE
gAnotherVoiceID = (VOICE_ID_t)Key;
#endif
gEeprom.FM_SelectedChannel = Channel;
gEeprom.FM_FrequencyPlaying = gFM_Channels[Channel];
BK1080_SetFrequency(gEeprom.FM_FrequencyPlaying);
gRequestSaveFM = true;
return;
}
}
else
if (Channel < 20)
{
#ifdef ENABLE_VOICE
gAnotherVoiceID = (VOICE_ID_t)Key;
#endif
gRequestDisplayScreen = DISPLAY_FM;
gInputBoxIndex = 0;
gFM_ChannelPosition = Channel;
return;
}
gBeepToPlay = BEEP_500HZ_60MS_DOUBLE_BEEP_OPTIONAL;
gFM_ChannelPosition = Channel;
return;
}
#ifdef ENABLE_VOICE
gAnotherVoiceID = (VOICE_ID_t)Key;
#endif
gBeepToPlay = BEEP_500HZ_60MS_DOUBLE_BEEP_OPTIONAL;
return;
}
#ifdef ENABLE_VOICE
gAnotherVoiceID = (VOICE_ID_t)Key;
#endif
}
else
Key_FUNC(Key, state);
}
static void Key_FUNC(KEY_Code_t Key, uint8_t state)
{
if (state == BUTTON_EVENT_SHORT || state == BUTTON_EVENT_HELD) {
bool autoScan = gWasFKeyPressed || (state == BUTTON_EVENT_HELD);
gBeepToPlay = BEEP_1KHZ_60MS_OPTIONAL;
gWasFKeyPressed = false;
gUpdateStatus = true;
gRequestDisplayScreen = DISPLAY_FM;
switch (Key)
{
switch (Key) {
case KEY_0:
ACTION_FM();
break;
case KEY_1:
gEeprom.FM_Band++;
gRequestSaveFM = true;
break;
// case KEY_2:
// gEeprom.FM_Space = (gEeprom.FM_Space + 1) % 3;
// gRequestSaveFM = true;
// break;
case KEY_3:
gEeprom.FM_IsMrMode = !gEeprom.FM_IsMrMode;
if (!FM_ConfigureChannelState())
{
BK1080_SetFrequency(gEeprom.FM_FrequencyPlaying);
if (!FM_ConfigureChannelState()) {
BK1080_SetFrequency(gEeprom.FM_FrequencyPlaying, gEeprom.FM_Band/*, gEeprom.FM_Space*/);
gRequestSaveFM = true;
}
else
gBeepToPlay = BEEP_500HZ_60MS_DOUBLE_BEEP_OPTIONAL;
break;
case KEY_2:
ACTION_Scan(true);
break;
case KEY_3:
ACTION_Scan(false);
case KEY_STAR:
ACTION_Scan(autoScan);
break;
default:
@@ -381,22 +366,16 @@ static void FM_Key_DIGITS(KEY_Code_t Key, bool bKeyPressed, bool bKeyHeld)
}
}
static void FM_Key_EXIT(bool bKeyPressed, bool bKeyHeld)
static void Key_EXIT(uint8_t state)
{
if (bKeyHeld)
return;
if (!bKeyPressed)
if (state != BUTTON_EVENT_SHORT)
return;
gBeepToPlay = BEEP_1KHZ_60MS_OPTIONAL;
if (gFM_ScanState == FM_SCAN_OFF)
{
if (gInputBoxIndex == 0)
{
if (!gAskToSave && !gAskToDelete)
{
if (gFM_ScanState == FM_SCAN_OFF) {
if (gInputBoxIndex == 0) {
if (!gAskToSave && !gAskToDelete) {
ACTION_FM();
return;
}
@@ -404,135 +383,102 @@ static void FM_Key_EXIT(bool bKeyPressed, bool bKeyHeld)
gAskToSave = false;
gAskToDelete = false;
}
else
{
else {
gInputBox[--gInputBoxIndex] = 10;
if (gInputBoxIndex)
{
if (gInputBoxIndex != 1)
{
if (gInputBoxIndex) {
if (gInputBoxIndex != 1) {
gRequestDisplayScreen = DISPLAY_FM;
return;
}
if (gInputBox[0] != 0)
{
if (gInputBox[0] != 0) {
gRequestDisplayScreen = DISPLAY_FM;
return;
}
}
gInputBoxIndex = 0;
}
#ifdef ENABLE_VOICE
gAnotherVoiceID = VOICE_ID_CANCEL;
#endif
#ifdef ENABLE_VOICE
gAnotherVoiceID = VOICE_ID_CANCEL;
#endif
}
else
{
else {
FM_PlayAndUpdate();
#ifdef ENABLE_VOICE
gAnotherVoiceID = VOICE_ID_SCANNING_STOP;
#endif
#ifdef ENABLE_VOICE
gAnotherVoiceID = VOICE_ID_SCANNING_STOP;
#endif
}
gRequestDisplayScreen = DISPLAY_FM;
}
static void FM_Key_MENU(bool bKeyPressed, bool bKeyHeld)
static void Key_MENU(uint8_t state)
{
if (bKeyHeld)
if (state != BUTTON_EVENT_SHORT)
return;
if (!bKeyPressed)
return;
gRequestDisplayScreen = DISPLAY_FM;
gBeepToPlay = BEEP_1KHZ_60MS_OPTIONAL;
if (gFM_ScanState == FM_SCAN_OFF)
{
if (!gEeprom.FM_IsMrMode)
{
if (gAskToSave)
{
if (gFM_ScanState == FM_SCAN_OFF) {
if (!gEeprom.FM_IsMrMode) {
if (gAskToSave) {
gFM_Channels[gFM_ChannelPosition] = gEeprom.FM_FrequencyPlaying;
gAskToSave = false;
gRequestSaveFM = true;
gRequestSaveFM = true;
}
else
gAskToSave = true;
gAskToSave = !gAskToSave;
}
else
{
if (gAskToDelete)
{
else {
if (gAskToDelete) {
gFM_Channels[gEeprom.FM_SelectedChannel] = 0xFFFF;
FM_ConfigureChannelState();
BK1080_SetFrequency(gEeprom.FM_FrequencyPlaying);
BK1080_SetFrequency(gEeprom.FM_FrequencyPlaying, gEeprom.FM_Band/*, gEeprom.FM_Space*/);
gRequestSaveFM = true;
gAskToDelete = false;
}
else
gAskToDelete = true;
gAskToDelete = !gAskToDelete;
}
}
else
{
if (gFM_AutoScan || !gFM_FoundFrequency)
{
else {
if (gFM_AutoScan || !gFM_FoundFrequency) {
gBeepToPlay = BEEP_500HZ_60MS_DOUBLE_BEEP_OPTIONAL;
gInputBoxIndex = 0;
return;
}
if (gAskToSave)
{
if (gAskToSave) {
gFM_Channels[gFM_ChannelPosition] = gEeprom.FM_FrequencyPlaying;
gAskToSave = false;
gRequestSaveFM = true;
}
else
gAskToSave = true;
gAskToSave = !gAskToSave;
}
}
static void FM_Key_UP_DOWN(bool bKeyPressed, bool bKeyHeld, int8_t Step)
static void Key_UP_DOWN(uint8_t state, int8_t Step)
{
if (bKeyHeld || !bKeyPressed)
{
if (gInputBoxIndex)
return;
if (!bKeyPressed)
return;
}
else
{
if (gInputBoxIndex)
{
if (state == BUTTON_EVENT_PRESSED) {
if (gInputBoxIndex) {
gBeepToPlay = BEEP_500HZ_60MS_DOUBLE_BEEP_OPTIONAL;
return;
}
gBeepToPlay = BEEP_1KHZ_60MS_OPTIONAL;
} else if (gInputBoxIndex || state!=BUTTON_EVENT_HELD) {
return;
}
if (gAskToSave)
{
if (gAskToSave) {
gRequestDisplayScreen = DISPLAY_FM;
gFM_ChannelPosition = NUMBER_AddWithWraparound(gFM_ChannelPosition, Step, 0, 19);
return;
}
if (gFM_ScanState != FM_SCAN_OFF)
{
if (gFM_AutoScan)
{
if (gFM_ScanState != FM_SCAN_OFF) {
if (gFM_AutoScan) {
gBeepToPlay = BEEP_500HZ_60MS_DOUBLE_BEEP_OPTIONAL;
return;
}
@@ -542,8 +488,7 @@ static void FM_Key_UP_DOWN(bool bKeyPressed, bool bKeyHeld, int8_t Step)
return;
}
if (gEeprom.FM_IsMrMode)
{
if (gEeprom.FM_IsMrMode) {
const uint8_t Channel = FM_FindNextChannel(gEeprom.FM_SelectedChannel + Step, Step);
if (Channel == 0xFF || gEeprom.FM_SelectedChannel == Channel)
goto Bail;
@@ -551,14 +496,13 @@ static void FM_Key_UP_DOWN(bool bKeyPressed, bool bKeyHeld, int8_t Step)
gEeprom.FM_SelectedChannel = Channel;
gEeprom.FM_FrequencyPlaying = gFM_Channels[Channel];
}
else
{
else {
uint16_t Frequency = gEeprom.FM_SelectedFrequency + Step;
if (Frequency < gEeprom.FM_LowerLimit)
Frequency = gEeprom.FM_UpperLimit;
else
if (Frequency > gEeprom.FM_UpperLimit)
Frequency = gEeprom.FM_LowerLimit;
if (Frequency < BK1080_GetFreqLoLimit(gEeprom.FM_Band))
Frequency = BK1080_GetFreqHiLimit(gEeprom.FM_Band);
else if (Frequency > BK1080_GetFreqHiLimit(gEeprom.FM_Band))
Frequency = BK1080_GetFreqLoLimit(gEeprom.FM_Band);
gEeprom.FM_FrequencyPlaying = Frequency;
gEeprom.FM_SelectedFrequency = gEeprom.FM_FrequencyPlaying;
@@ -567,38 +511,33 @@ static void FM_Key_UP_DOWN(bool bKeyPressed, bool bKeyHeld, int8_t Step)
gRequestSaveFM = true;
Bail:
BK1080_SetFrequency(gEeprom.FM_FrequencyPlaying);
BK1080_SetFrequency(gEeprom.FM_FrequencyPlaying, gEeprom.FM_Band/*, gEeprom.FM_Space*/);
gRequestDisplayScreen = DISPLAY_FM;
}
void FM_ProcessKeys(KEY_Code_t Key, bool bKeyPressed, bool bKeyHeld)
{
switch (Key)
{
case KEY_0:
case KEY_1:
case KEY_2:
case KEY_3:
case KEY_4:
case KEY_5:
case KEY_6:
case KEY_7:
case KEY_8:
case KEY_9:
FM_Key_DIGITS(Key, bKeyPressed, bKeyHeld);
uint8_t state = bKeyPressed + 2 * bKeyHeld;
switch (Key) {
case KEY_0...KEY_9:
Key_DIGITS(Key, state);
break;
case KEY_STAR:
Key_FUNC(Key, state);
break;
case KEY_MENU:
FM_Key_MENU(bKeyPressed, bKeyHeld);
return;
Key_MENU(state);
break;
case KEY_UP:
FM_Key_UP_DOWN(bKeyPressed, bKeyHeld, 1);
Key_UP_DOWN(state, 1);
break;
case KEY_DOWN:
FM_Key_UP_DOWN(bKeyPressed, bKeyHeld, -1);
Key_UP_DOWN(state, -1);
break;;
case KEY_EXIT:
FM_Key_EXIT(bKeyPressed, bKeyHeld);
Key_EXIT(state);
break;
case KEY_F:
GENERIC_Key_F(bKeyPressed, bKeyHeld);
@@ -615,10 +554,8 @@ void FM_ProcessKeys(KEY_Code_t Key, bool bKeyPressed, bool bKeyHeld)
void FM_Play(void)
{
if (!FM_CheckFrequencyLock(gEeprom.FM_FrequencyPlaying, gEeprom.FM_LowerLimit))
{
if (!gFM_AutoScan)
{
if (!FM_CheckFrequencyLock(gEeprom.FM_FrequencyPlaying, BK1080_GetFreqLoLimit(gEeprom.FM_Band))) {
if (!gFM_AutoScan) {
gFmPlayCountdown_10ms = 0;
gFM_FoundFrequency = true;
@@ -635,15 +572,14 @@ void FM_Play(void)
if (gFM_ChannelPosition < 20)
gFM_Channels[gFM_ChannelPosition++] = gEeprom.FM_FrequencyPlaying;
if (gFM_ChannelPosition >= 20)
{
if (gFM_ChannelPosition >= 20) {
FM_PlayAndUpdate();
GUI_SelectNextDisplay(DISPLAY_FM);
return;
}
}
if (gFM_AutoScan && gEeprom.FM_FrequencyPlaying >= gEeprom.FM_UpperLimit)
if (gFM_AutoScan && gEeprom.FM_FrequencyPlaying >= BK1080_GetFreqHiLimit(1))
FM_PlayAndUpdate();
else
FM_Tune(gEeprom.FM_FrequencyPlaying, gFM_ScanState, false);
@@ -653,11 +589,12 @@ void FM_Play(void)
void FM_Start(void)
{
gDualWatchActive = false;
gFmRadioMode = true;
gFM_ScanState = FM_SCAN_OFF;
gFM_RestoreCountdown_10ms = 0;
BK1080_Init(gEeprom.FM_FrequencyPlaying, true);
BK1080_Init(gEeprom.FM_FrequencyPlaying, gEeprom.FM_Band/*, gEeprom.FM_Space*/);
AUDIO_AudioPathOn();

View File

@@ -38,10 +38,10 @@ extern uint8_t gFM_ChannelPosition;
// Doubts about whether this should be signed or not
extern uint16_t gFM_FrequencyDeviation;
extern bool gFM_FoundFrequency;
extern bool gFM_AutoScan;
extern uint16_t gFM_RestoreCountdown_10ms;
bool FM_CheckValidChannel(uint8_t Channel);
// returns first valid channel starting at Channel
uint8_t FM_FindNextChannel(uint8_t Channel, uint8_t Direction);
int FM_ConfigureChannelState(void);
void FM_TurnOff(void);
@@ -59,4 +59,3 @@ void FM_Start(void);
#endif
#endif

View File

@@ -17,6 +17,7 @@
#include <string.h>
#include "app/app.h"
#include "app/chFrScanner.h"
#include "app/common.h"
#ifdef ENABLE_FMRADIO
@@ -38,17 +39,14 @@
void GENERIC_Key_F(bool bKeyPressed, bool bKeyHeld)
{
if (gInputBoxIndex > 0)
{
if (gInputBoxIndex > 0) {
if (!bKeyHeld && bKeyPressed) // short pressed
gBeepToPlay = BEEP_500HZ_60MS_DOUBLE_BEEP_OPTIONAL;
return;
}
if (bKeyHeld || !bKeyPressed) // held or released
{
if (bKeyHeld || bKeyPressed) // held or pressed (cannot be held and not pressed I guess, so it checks only if HELD?)
{
if (bKeyHeld || !bKeyPressed) { // held or released
if (bKeyHeld || bKeyPressed) { // held or pressed (cannot be held and not pressed I guess, so it checks only if HELD?)
if (!bKeyHeld) // won't ever pass
return;
@@ -57,47 +55,43 @@ void GENERIC_Key_F(bool bKeyPressed, bool bKeyHeld)
COMMON_KeypadLockToggle();
}
else // released
{
#ifdef ENABLE_FMRADIO
if ((gFmRadioMode || gScreenToDisplay != DISPLAY_MAIN) && gScreenToDisplay != DISPLAY_FM)
return;
#else
if (gScreenToDisplay != DISPLAY_MAIN)
return;
#endif
else { // released
#ifdef ENABLE_FMRADIO
if ((gFmRadioMode || gScreenToDisplay != DISPLAY_MAIN) && gScreenToDisplay != DISPLAY_FM)
return;
#else
if (gScreenToDisplay != DISPLAY_MAIN)
return;
#endif
gWasFKeyPressed = !gWasFKeyPressed; // toggle F function
if (gWasFKeyPressed)
gKeyInputCountdown = key_input_timeout_500ms;
#ifdef ENABLE_VOICE
if (!gWasFKeyPressed)
gAnotherVoiceID = VOICE_ID_CANCEL;
#endif
#ifdef ENABLE_VOICE
if (!gWasFKeyPressed)
gAnotherVoiceID = VOICE_ID_CANCEL;
#endif
gUpdateStatus = true;
}
}
else // short pressed
{
else { // short pressed
#ifdef ENABLE_FMRADIO
if (gScreenToDisplay != DISPLAY_FM)
#endif
{
gBeepToPlay = BEEP_1KHZ_60MS_OPTIONAL;
return;
}
#ifdef ENABLE_FMRADIO
if (gFM_ScanState == FM_SCAN_OFF) // not scanning
{
gBeepToPlay = BEEP_1KHZ_60MS_OPTIONAL;
return;
}
#endif
#ifdef ENABLE_FMRADIO
if (gFM_ScanState == FM_SCAN_OFF) { // not scanning
gBeepToPlay = BEEP_1KHZ_60MS_OPTIONAL;
return;
}
#endif
gBeepToPlay = BEEP_440HZ_500MS;
gPttWasReleased = true;
}
}
@@ -106,31 +100,26 @@ void GENERIC_Key_PTT(bool bKeyPressed)
{
gInputBoxIndex = 0;
if (!bKeyPressed || gSerialConfigCountDown_500ms > 0)
if (!bKeyPressed || SerialConfigInProgress())
{ // PTT released
if (gCurrentFunction == FUNCTION_TRANSMIT)
{ // we are transmitting .. stop
if (gFlagEndTransmission)
{
if (gCurrentFunction == FUNCTION_TRANSMIT) {
// we are transmitting .. stop
if (gFlagEndTransmission) {
FUNCTION_Select(FUNCTION_FOREGROUND);
}
else
{
else {
APP_EndTransmission();
if (gEeprom.REPEATER_TAIL_TONE_ELIMINATION == 0)
FUNCTION_Select(FUNCTION_FOREGROUND);
else
gRTTECountdown = gEeprom.REPEATER_TAIL_TONE_ELIMINATION * 10;
gRTTECountdown_10ms = gEeprom.REPEATER_TAIL_TONE_ELIMINATION * 10;
}
gFlagEndTransmission = false;
#ifdef ENABLE_VOX
gVOX_NoiseDetected = false;
#endif
#ifdef ENABLE_VOX
gVOX_NoiseDetected = false;
#endif
RADIO_SetVfoState(VFO_STATE_NORMAL);
if (gScreenToDisplay != DISPLAY_MENU) // 1of11 .. don't close the menu
@@ -142,43 +131,25 @@ void GENERIC_Key_PTT(bool bKeyPressed)
// PTT pressed
if (gScanStateDir != SCAN_OFF || // frequency/channel scanning
gScreenToDisplay == DISPLAY_SCANNER || // CTCSS/CDCSS scanning
gCssScanMode != CSS_SCAN_MODE_OFF) // " "
{ // we're scanning .. stop
if (gScreenToDisplay == DISPLAY_SCANNER)
{ // CTCSS/CDCSS scanning .. stop
gEeprom.CROSS_BAND_RX_TX = gBackup_CROSS_BAND_RX_TX;
gFlagStopScan = true;
gVfoConfigureMode = VFO_CONFIGURE_RELOAD;
gFlagResetVfos = true;
}
else
if (gScanStateDir != SCAN_OFF)
{ // frequency/channel scanning . .stop
SCANNER_Stop();
}
else
if (gCssScanMode != CSS_SCAN_MODE_OFF)
{ // CTCSS/CDCSS scanning .. stop
MENU_StopCssScan();
#ifdef ENABLE_VOICE
gAnotherVoiceID = VOICE_ID_SCANNING_STOP;
#endif
}
if (SCANNER_IsScanning()) {
SCANNER_Stop(); // CTCSS/CDCSS scanning .. stop
goto cancel_tx;
}
if (gScanStateDir != SCAN_OFF) {
CHFRSCANNER_Stop(); // frequency/channel scanning . .stop
goto cancel_tx;
}
#ifdef ENABLE_FMRADIO
if (gFM_ScanState != FM_SCAN_OFF)
{ // FM radio is scanning .. stop
if (gFM_ScanState != FM_SCAN_OFF) { // FM radio is scanning .. stop
FM_PlayAndUpdate();
#ifdef ENABLE_VOICE
gAnotherVoiceID = VOICE_ID_SCANNING_STOP;
#endif
#ifdef ENABLE_VOICE
gAnotherVoiceID = VOICE_ID_SCANNING_STOP;
#endif
gRequestDisplayScreen = DISPLAY_FM;
goto cancel_tx;
}
@@ -189,8 +160,7 @@ void GENERIC_Key_PTT(bool bKeyPressed)
goto start_tx; // listening to the FM radio .. start TX'ing
#endif
if (gCurrentFunction == FUNCTION_TRANSMIT && gRTTECountdown == 0)
{ // already transmitting
if (gCurrentFunction == FUNCTION_TRANSMIT && gRTTECountdown_10ms == 0) {// already transmitting
gInputBoxIndex = 0;
return;
}
@@ -198,20 +168,20 @@ void GENERIC_Key_PTT(bool bKeyPressed)
if (gScreenToDisplay != DISPLAY_MENU) // 1of11 .. don't close the menu
gRequestDisplayScreen = DISPLAY_MAIN;
if (!gDTMF_InputMode && gDTMF_InputBox_Index == 0)
goto start_tx; // wasn't entering a DTMF code .. start TX'ing (maybe)
// was entering a DTMF string
if (gDTMF_InputBox_Index > 0 || gDTMF_PreviousIndex > 0)
{ // going to transmit a DTMF string
if (gDTMF_InputBox_Index > 0 || gDTMF_PreviousIndex > 0) { // going to transmit a DTMF string
if (gDTMF_InputBox_Index == 0 && gDTMF_PreviousIndex > 0)
gDTMF_InputBox_Index = gDTMF_PreviousIndex; // use the previous DTMF string
if (gDTMF_InputBox_Index < sizeof(gDTMF_InputBox))
gDTMF_InputBox[gDTMF_InputBox_Index] = 0; // NULL term the string
#ifdef ENABLE_DTMF_CALLING
// append our DTMF ID to the inputted DTMF code -
// IF the user inputted code is exactly 3 digits long and D-DCD is enabled
if (gDTMF_InputBox_Index == 3 && gTxVfo->DTMF_DECODING_ENABLE > 0)
@@ -219,12 +189,12 @@ void GENERIC_Key_PTT(bool bKeyPressed)
else
gDTMF_CallMode = DTMF_CALL_MODE_DTMF;
gDTMF_State = DTMF_STATE_0;
#endif
// remember the DTMF string
gDTMF_PreviousIndex = gDTMF_InputBox_Index;
strcpy(gDTMF_String, gDTMF_InputBox);
gDTMF_ReplyState = DTMF_REPLY_ANI;
gDTMF_State = DTMF_STATE_0;
}
DTMF_clear_input_box();
@@ -233,17 +203,23 @@ start_tx:
// request start TX
gFlagPrepareTX = true;
goto done;
cancel_tx:
if (gPttIsPressed)
{
if (gPttIsPressed) {
gPttWasPressed = true;
}
done:
done:
gPttDebounceCounter = 0;
if (gScreenToDisplay != DISPLAY_MENU && gRequestDisplayScreen != DISPLAY_FM) // 1of11 .. don't close the menu
if (gScreenToDisplay != DISPLAY_MENU
#ifdef ENABLE_FMRADIO
&& gRequestDisplayScreen != DISPLAY_FM
#endif
) {
// 1of11 .. don't close the menu
gRequestDisplayScreen = DISPLAY_MAIN;
}
gUpdateStatus = true;
gUpdateDisplay = true;
}

View File

@@ -18,6 +18,7 @@
#include "app/action.h"
#include "app/app.h"
#include "app/chFrScanner.h"
#include "app/common.h"
#ifdef ENABLE_FMRADIO
#include "app/fm.h"
@@ -45,22 +46,23 @@
void toggle_chan_scanlist(void)
{ // toggle the selected channels scanlist setting
if (gScreenToDisplay == DISPLAY_SCANNER || !IS_MR_CHANNEL(gTxVfo->CHANNEL_SAVE))
if (SCANNER_IsScanning())
return;
if (gTxVfo->SCANLIST1_PARTICIPATION)
{
if (gTxVfo->SCANLIST2_PARTICIPATION)
gTxVfo->SCANLIST1_PARTICIPATION = 0;
else
gTxVfo->SCANLIST2_PARTICIPATION = 1;
if(!IS_MR_CHANNEL(gTxVfo->CHANNEL_SAVE)) {
#ifdef ENABLE_SCAN_RANGES
gScanRangeStart = gScanRangeStart ? 0 : gTxVfo->pRX->Frequency;
gScanRangeStop = gEeprom.VfoInfo[!gEeprom.TX_VFO].freq_config_RX.Frequency;
if(gScanRangeStart > gScanRangeStop)
SWAP(gScanRangeStart, gScanRangeStop);
#endif
return;
}
else
{
if (gTxVfo->SCANLIST2_PARTICIPATION)
gTxVfo->SCANLIST2_PARTICIPATION = 0;
else
gTxVfo->SCANLIST1_PARTICIPATION = 1;
if (gTxVfo->SCANLIST1_PARTICIPATION ^ gTxVfo->SCANLIST2_PARTICIPATION){
gTxVfo->SCANLIST2_PARTICIPATION = gTxVfo->SCANLIST1_PARTICIPATION;
} else {
gTxVfo->SCANLIST1_PARTICIPATION = !gTxVfo->SCANLIST1_PARTICIPATION;
}
SETTINGS_UpdateChannel(gTxVfo->CHANNEL_SAVE, gTxVfo, true);
@@ -71,30 +73,19 @@ void toggle_chan_scanlist(void)
static void processFKeyFunction(const KEY_Code_t Key, const bool beep)
{
uint8_t Band;
uint8_t Vfo = gEeprom.TX_VFO;
if (gScreenToDisplay == DISPLAY_MENU)
{
// if (beep)
gBeepToPlay = BEEP_500HZ_60MS_DOUBLE_BEEP_OPTIONAL;
if (gScreenToDisplay == DISPLAY_MENU) {
gBeepToPlay = BEEP_500HZ_60MS_DOUBLE_BEEP_OPTIONAL;
return;
}
// if (beep)
gBeepToPlay = BEEP_1KHZ_60MS_OPTIONAL;
gBeepToPlay = BEEP_1KHZ_60MS_OPTIONAL;
switch (Key)
{
switch (Key) {
case KEY_0:
#ifdef ENABLE_FMRADIO
ACTION_FM();
#else
// TODO: make use of this function key
#endif
break;
@@ -105,66 +96,60 @@ static void processFKeyFunction(const KEY_Code_t Key, const bool beep)
gBeepToPlay = BEEP_1KHZ_60MS_OPTIONAL;
#ifdef ENABLE_COPY_CHAN_TO_VFO
if (gEeprom.VFO_OPEN && gCssScanMode == CSS_SCAN_MODE_OFF)
{
if (!gEeprom.VFO_OPEN || gCssBackgroundScan) {
gBeepToPlay = BEEP_500HZ_60MS_DOUBLE_BEEP_OPTIONAL;
return;
}
if (gScanStateDir != SCAN_OFF)
{
if (gCurrentFunction != FUNCTION_INCOMING ||
gRxReceptionMode == RX_MODE_NONE ||
gScanPauseDelayIn_10ms == 0)
{ // scan is running (not paused)
return;
}
}
const uint8_t vfo = gEeprom.TX_VFO;
if (IS_MR_CHANNEL(gEeprom.ScreenChannel[vfo]))
{ // copy channel to VFO, then swap to the VFO
const unsigned int channel = FREQ_CHANNEL_FIRST + gEeprom.VfoInfo[vfo].Band;
gEeprom.ScreenChannel[vfo] = channel;
gEeprom.VfoInfo[vfo].CHANNEL_SAVE = channel;
RADIO_SelectVfos();
RADIO_ApplyOffset(gRxVfo);
RADIO_ConfigureSquelchAndOutputPower(gRxVfo);
RADIO_SetupRegisters(true);
//SETTINGS_SaveChannel(channel, gEeprom.RX_VFO, gRxVfo, 1);
gUpdateDisplay = true;
if (gScanStateDir != SCAN_OFF) {
if (gCurrentFunction != FUNCTION_INCOMING ||
gRxReceptionMode == RX_MODE_NONE ||
gScanPauseDelayIn_10ms == 0)
{ // scan is running (not paused)
return;
}
}
else
{
gBeepToPlay = BEEP_500HZ_60MS_DOUBLE_BEEP_OPTIONAL;
const uint8_t vfo = gEeprom.TX_VFO;
if (IS_MR_CHANNEL(gEeprom.ScreenChannel[vfo]))
{ // copy channel to VFO, then swap to the VFO
gEeprom.ScreenChannel[vfo] = FREQ_CHANNEL_FIRST + gEeprom.VfoInfo[vfo].Band;
gEeprom.VfoInfo[vfo].CHANNEL_SAVE = gEeprom.ScreenChannel[vfo];
RADIO_SelectVfos();
RADIO_ApplyOffset(gRxVfo);
RADIO_ConfigureSquelchAndOutputPower(gRxVfo);
RADIO_SetupRegisters(true);
//SETTINGS_SaveChannel(channel, gEeprom.RX_VFO, gRxVfo, 1);
gUpdateDisplay = true;
}
#endif
return;
}
if(gTxVfo->Band == 6 && gTxVfo->pRX->Frequency < 100000000) {
gTxVfo->pRX->Frequency = 100000000;
#ifdef ENABLE_WIDE_RX
if(gTxVfo->Band == BAND7_470MHz && gTxVfo->pRX->Frequency < _1GHz_in_KHz) {
gTxVfo->pRX->Frequency = _1GHz_in_KHz;
return;
}
else {
Band = gTxVfo->Band + 1;
if (gSetting_350EN || Band != BAND5_350MHz) {
if (Band > BAND7_470MHz)
Band = BAND1_50MHz;
}
else
Band = BAND6_400MHz;
#endif
gTxVfo->Band += 1;
gTxVfo->Band = Band;
gEeprom.ScreenChannel[Vfo] = FREQ_CHANNEL_FIRST + Band;
gEeprom.FreqChannel[Vfo] = FREQ_CHANNEL_FIRST + Band;
if (gTxVfo->Band == BAND5_350MHz && !gSetting_350EN) {
// skip if not enabled
gTxVfo->Band += 1;
} else if (gTxVfo->Band >= BAND_N_ELEM){
// go arround if overflowed
gTxVfo->Band = BAND1_50MHz;
}
gEeprom.ScreenChannel[Vfo] = FREQ_CHANNEL_FIRST + gTxVfo->Band;
gEeprom.FreqChannel[Vfo] = FREQ_CHANNEL_FIRST + gTxVfo->Band;
gRequestSaveVFO = true;
gVfoConfigureMode = VFO_CONFIGURE_RELOAD;
@@ -192,27 +177,24 @@ static void processFKeyFunction(const KEY_Code_t Key, const bool beep)
case KEY_4:
gWasFKeyPressed = false;
gFlagStartScan = true;
gScanSingleFrequency = false;
gBackup_CROSS_BAND_RX_TX = gEeprom.CROSS_BAND_RX_TX;
gEeprom.CROSS_BAND_RX_TX = CROSS_BAND_OFF;
gUpdateStatus = true;
gUpdateStatus = true;
if (beep)
gBeepToPlay = BEEP_1KHZ_60MS_OPTIONAL;
SCANNER_Start(false);
gRequestDisplayScreen = DISPLAY_SCANNER;
break;
case KEY_5:
if(beep) {
#ifdef ENABLE_NOAA
if (!IS_NOAA_CHANNEL(gTxVfo->CHANNEL_SAVE))
{
if (!IS_NOAA_CHANNEL(gTxVfo->CHANNEL_SAVE)) {
gEeprom.ScreenChannel[Vfo] = gEeprom.NoaaChannel[gEeprom.TX_VFO];
}
else
{
else {
gEeprom.ScreenChannel[Vfo] = gEeprom.FreqChannel[gEeprom.TX_VFO];
#ifdef ENABLE_VOICE
gAnotherVoiceID = VOICE_ID_FREQUENCY_MODE;
@@ -251,8 +233,7 @@ static void processFKeyFunction(const KEY_Code_t Key, const bool beep)
break;
case KEY_9:
if (RADIO_CheckValidChannel(gEeprom.CHAN_1_CALL, false, 0))
{
if (RADIO_CheckValidChannel(gEeprom.CHAN_1_CALL, false, 0)) {
gEeprom.MrChannel[Vfo] = gEeprom.CHAN_1_CALL;
gEeprom.ScreenChannel[Vfo] = gEeprom.CHAN_1_CALL;
#ifdef ENABLE_VOICE
@@ -281,15 +262,10 @@ static void processFKeyFunction(const KEY_Code_t Key, const bool beep)
static void MAIN_Key_DIGITS(KEY_Code_t Key, bool bKeyPressed, bool bKeyHeld)
{
if (bKeyHeld)
{ // key held down
if (bKeyPressed)
{
if (gScreenToDisplay == DISPLAY_MAIN)
{
if (gInputBoxIndex > 0)
{ // delete any inputted chars
if (bKeyHeld) { // key held down
if (bKeyPressed) {
if (gScreenToDisplay == DISPLAY_MAIN) {
if (gInputBoxIndex > 0) { // delete any inputted chars
gInputBoxIndex = 0;
gRequestDisplayScreen = DISPLAY_MAIN;
}
@@ -300,7 +276,6 @@ static void MAIN_Key_DIGITS(KEY_Code_t Key, bool bKeyPressed, bool bKeyHeld)
processFKeyFunction(Key, false);
}
}
return;
}
@@ -310,24 +285,15 @@ static void MAIN_Key_DIGITS(KEY_Code_t Key, bool bKeyPressed, bool bKeyHeld)
return; // don't use the key till it's released
}
if (!gWasFKeyPressed)
{ // F-key wasn't pressed
if (!gWasFKeyPressed) { // F-key wasn't pressed
const uint8_t Vfo = gEeprom.TX_VFO;
gKeyInputCountdown = key_input_timeout_500ms;
INPUTBOX_Append(Key);
gRequestDisplayScreen = DISPLAY_MAIN;
if (IS_MR_CHANNEL(gTxVfo->CHANNEL_SAVE))
{ // user is entering channel number
if (IS_MR_CHANNEL(gTxVfo->CHANNEL_SAVE)) { // user is entering channel number
uint16_t Channel;
if (gInputBoxIndex != 3)
{
if (gInputBoxIndex != 3) {
#ifdef ENABLE_VOICE
gAnotherVoiceID = (VOICE_ID_t)Key;
#endif
@@ -337,10 +303,9 @@ static void MAIN_Key_DIGITS(KEY_Code_t Key, bool bKeyPressed, bool bKeyHeld)
gInputBoxIndex = 0;
Channel = ((gInputBox[0] * 100) + (gInputBox[1] * 10) + gInputBox[2]) - 1;
const uint16_t Channel = ((gInputBox[0] * 100) + (gInputBox[1] * 10) + gInputBox[2]) - 1;
if (!RADIO_CheckValidChannel(Channel, false, 0))
{
if (!RADIO_CheckValidChannel(Channel, false, 0)) {
gBeepToPlay = BEEP_500HZ_60MS_DOUBLE_BEEP_OPTIONAL;
return;
}
@@ -363,79 +328,60 @@ static void MAIN_Key_DIGITS(KEY_Code_t Key, bool bKeyPressed, bool bKeyHeld)
if (IS_FREQ_CHANNEL(gTxVfo->CHANNEL_SAVE))
{ // user is entering a frequency
uint32_t Frequency;
bool isGigaF = gTxVfo->pRX->Frequency >= 100000000;
if (gInputBoxIndex < 6 + isGigaF)
{
#ifdef ENABLE_VOICE
gAnotherVoiceID = (VOICE_ID_t)Key;
#endif
#ifdef ENABLE_VOICE
gAnotherVoiceID = (VOICE_ID_t)Key;
#endif
bool isGigaF = gTxVfo->pRX->Frequency >= _1GHz_in_KHz;
if (gInputBoxIndex < 6 + isGigaF) {
return;
}
gInputBoxIndex = 0;
Frequency = StrToUL(INPUTBOX_GetAscii()) * 100;
uint32_t Frequency = StrToUL(INPUTBOX_GetAscii()) * 100;
// clamp the frequency entered to some valid value
if (Frequency < frequencyBandTable[0].lower)
{
if (Frequency < frequencyBandTable[0].lower) {
Frequency = frequencyBandTable[0].lower;
}
else
if (Frequency >= BX4819_band1.upper && Frequency < BX4819_band2.lower)
{
else if (Frequency >= BX4819_band1.upper && Frequency < BX4819_band2.lower) {
const uint32_t center = (BX4819_band1.upper + BX4819_band2.lower) / 2;
Frequency = (Frequency < center) ? BX4819_band1.upper : BX4819_band2.lower;
}
else
if (Frequency > frequencyBandTable[ARRAY_SIZE(frequencyBandTable) - 1].upper)
{
Frequency = frequencyBandTable[ARRAY_SIZE(frequencyBandTable) - 1].upper;
else if (Frequency > frequencyBandTable[BAND_N_ELEM - 1].upper) {
Frequency = frequencyBandTable[BAND_N_ELEM - 1].upper;
}
{
const FREQUENCY_Band_t band = FREQUENCY_GetBand(Frequency);
const FREQUENCY_Band_t band = FREQUENCY_GetBand(Frequency);
#ifdef ENABLE_VOICE
gAnotherVoiceID = (VOICE_ID_t)Key;
#endif
if (gTxVfo->Band != band) {
gTxVfo->Band = band;
gEeprom.ScreenChannel[Vfo] = band + FREQ_CHANNEL_FIRST;
gEeprom.FreqChannel[Vfo] = band + FREQ_CHANNEL_FIRST;
if (gTxVfo->Band != band)
{
gTxVfo->Band = band;
gEeprom.ScreenChannel[Vfo] = band + FREQ_CHANNEL_FIRST;
gEeprom.FreqChannel[Vfo] = band + FREQ_CHANNEL_FIRST;
SETTINGS_SaveVfoIndices();
SETTINGS_SaveVfoIndices();
RADIO_ConfigureChannel(Vfo, VFO_CONFIGURE_RELOAD);
}
Frequency = FREQUENCY_RoundToStep(Frequency, gTxVfo->StepFrequency);
if (Frequency >= BX4819_band1.upper && Frequency < BX4819_band2.lower)
{ // clamp the frequency to the limit
const uint32_t center = (BX4819_band1.upper + BX4819_band2.lower) / 2;
Frequency = (Frequency < center) ? BX4819_band1.upper - gTxVfo->StepFrequency : BX4819_band2.lower;
}
gTxVfo->freq_config_RX.Frequency = Frequency;
gRequestSaveChannel = 1;
return;
RADIO_ConfigureChannel(Vfo, VFO_CONFIGURE_RELOAD);
}
Frequency = FREQUENCY_RoundToStep(Frequency, gTxVfo->StepFrequency);
if (Frequency >= BX4819_band1.upper && Frequency < BX4819_band2.lower)
{ // clamp the frequency to the limit
const uint32_t center = (BX4819_band1.upper + BX4819_band2.lower) / 2;
Frequency = (Frequency < center) ? BX4819_band1.upper - gTxVfo->StepFrequency : BX4819_band2.lower;
}
gTxVfo->freq_config_RX.Frequency = Frequency;
gRequestSaveChannel = 1;
return;
}
#ifdef ENABLE_NOAA
else
if (IS_NOAA_CHANNEL(gTxVfo->CHANNEL_SAVE))
{ // user is entering NOAA channel
uint8_t Channel;
if (gInputBoxIndex != 2)
{
if (gInputBoxIndex != 2) {
#ifdef ENABLE_VOICE
gAnotherVoiceID = (VOICE_ID_t)Key;
#endif
@@ -445,9 +391,8 @@ static void MAIN_Key_DIGITS(KEY_Code_t Key, bool bKeyPressed, bool bKeyHeld)
gInputBoxIndex = 0;
Channel = (gInputBox[0] * 10) + gInputBox[1];
if (Channel >= 1 && Channel <= ARRAY_SIZE(NoaaFrequencyTable))
{
uint8_t Channel = (gInputBox[0] * 10) + gInputBox[1];
if (Channel >= 1 && Channel <= ARRAY_SIZE(NoaaFrequencyTable)) {
Channel += NOAA_CHANNEL_FIRST;
#ifdef ENABLE_VOICE
gAnotherVoiceID = (VOICE_ID_t)Key;
@@ -474,59 +419,54 @@ static void MAIN_Key_DIGITS(KEY_Code_t Key, bool bKeyPressed, bool bKeyHeld)
static void MAIN_Key_EXIT(bool bKeyPressed, bool bKeyHeld)
{
if (!bKeyHeld && bKeyPressed)
{ // exit key pressed
if (!bKeyHeld && bKeyPressed) { // exit key pressed
gBeepToPlay = BEEP_1KHZ_60MS_OPTIONAL;
#ifdef ENABLE_DTMF_CALLING
if (gDTMF_CallState != DTMF_CALL_STATE_NONE && gCurrentFunction != FUNCTION_TRANSMIT)
{ // clear CALL mode being displayed
gDTMF_CallState = DTMF_CALL_STATE_NONE;
gUpdateDisplay = true;
return;
}
#endif
#ifdef ENABLE_FMRADIO
if (!gFmRadioMode)
#endif
#ifdef ENABLE_FMRADIO
if (!gFmRadioMode)
#endif
{
if (gScanStateDir == SCAN_OFF)
{
if (gScanStateDir == SCAN_OFF) {
if (gInputBoxIndex == 0)
return;
gInputBox[--gInputBoxIndex] = 10;
gKeyInputCountdown = key_input_timeout_500ms;
#ifdef ENABLE_VOICE
if (gInputBoxIndex == 0)
gAnotherVoiceID = VOICE_ID_CANCEL;
#endif
#ifdef ENABLE_VOICE
if (gInputBoxIndex == 0)
gAnotherVoiceID = VOICE_ID_CANCEL;
#endif
}
else
{
else {
gScanKeepResult = false;
SCANNER_Stop();
CHFRSCANNER_Stop();
#ifdef ENABLE_VOICE
gAnotherVoiceID = VOICE_ID_SCANNING_STOP;
#endif
#ifdef ENABLE_VOICE
gAnotherVoiceID = VOICE_ID_SCANNING_STOP;
#endif
}
gRequestDisplayScreen = DISPLAY_MAIN;
return;
}
#ifdef ENABLE_FMRADIO
ACTION_FM();
#endif
#ifdef ENABLE_FMRADIO
ACTION_FM();
#endif
return;
}
if (bKeyHeld && bKeyPressed)
{ // exit key held down
if (bKeyHeld && bKeyPressed) { // exit key held down
if (gInputBoxIndex > 0 || gDTMF_InputBox_Index > 0 || gDTMF_InputMode)
{ // cancel key input mode (channel/frequency entry)
gDTMF_InputMode = false;
@@ -541,22 +481,16 @@ static void MAIN_Key_EXIT(bool bKeyPressed, bool bKeyHeld)
static void MAIN_Key_MENU(const bool bKeyPressed, const bool bKeyHeld)
{
if (bKeyPressed && !bKeyHeld)
// menu key pressed
if (bKeyPressed && !bKeyHeld) // menu key pressed
gBeepToPlay = BEEP_1KHZ_60MS_OPTIONAL;
if (bKeyHeld)
{ // menu key held down (long press)
if (bKeyPressed)
{ // long press MENU key
if (bKeyHeld) { // menu key held down (long press)
if (bKeyPressed) { // long press MENU key
gWasFKeyPressed = false;
if (gScreenToDisplay == DISPLAY_MAIN)
{
if (gInputBoxIndex > 0)
{ // delete any inputted chars
if (gScreenToDisplay == DISPLAY_MAIN) {
if (gInputBoxIndex > 0) { // delete any inputted chars
gInputBoxIndex = 0;
gRequestDisplayScreen = DISPLAY_MAIN;
}
@@ -571,15 +505,13 @@ static void MAIN_Key_MENU(const bool bKeyPressed, const bool bKeyHeld)
return;
}
if (!bKeyPressed && !gDTMF_InputMode)
{ // menu key released
const bool bFlag = (gInputBoxIndex == 0);
if (!bKeyPressed && !gDTMF_InputMode) { // menu key released
const bool bFlag = !gInputBoxIndex;
gInputBoxIndex = 0;
if (bFlag)
{
if (bFlag) {
if (gScanStateDir != SCAN_OFF) {
SCANNER_Stop();
CHFRSCANNER_Stop();
return;
}
@@ -589,8 +521,7 @@ static void MAIN_Key_MENU(const bool bKeyPressed, const bool bKeyHeld)
gAnotherVoiceID = VOICE_ID_MENU;
#endif
}
else
{
else {
gRequestDisplayScreen = DISPLAY_MAIN;
}
}
@@ -601,15 +532,13 @@ static void MAIN_Key_STAR(bool bKeyPressed, bool bKeyHeld)
if (gCurrentFunction == FUNCTION_TRANSMIT)
return;
if (gInputBoxIndex)
{
if (gInputBoxIndex) {
if (!bKeyHeld && bKeyPressed)
gBeepToPlay = BEEP_500HZ_60MS_DOUBLE_BEEP_OPTIONAL;
return;
}
if (bKeyHeld && !gWasFKeyPressed) // long press
{
if (bKeyHeld && !gWasFKeyPressed){ // long press
if (!bKeyPressed) // released
return;
@@ -619,10 +548,7 @@ static void MAIN_Key_STAR(bool bKeyPressed, bool bKeyHeld)
return;
}
if (bKeyPressed) // just pressed
{
// gBeepToPlay = BEEP_1KHZ_60MS_OPTIONAL;
gBeepToPlay = BEEP_880HZ_40MS_OPTIONAL;
if (bKeyPressed) { // just pressed
return;
}
@@ -630,15 +556,17 @@ static void MAIN_Key_STAR(bool bKeyPressed, bool bKeyHeld)
if (!gWasFKeyPressed) // pressed without the F-key
{
#ifdef ENABLE_NOAA
if (gScanStateDir == SCAN_OFF && !IS_NOAA_CHANNEL(gTxVfo->CHANNEL_SAVE))
#else
if (gScanStateDir == SCAN_OFF)
#endif
if (gScanStateDir == SCAN_OFF
#ifdef ENABLE_NOAA
&& !IS_NOAA_CHANNEL(gTxVfo->CHANNEL_SAVE)
#endif
#ifdef ENABLE_SCAN_RANGES
&& gScanRangeStart == 0
#endif
)
{ // start entering a DTMF string
memmove(gDTMF_InputBox, gDTMF_String, MIN(sizeof(gDTMF_InputBox), sizeof(gDTMF_String) - 1));
gBeepToPlay = BEEP_1KHZ_60MS_OPTIONAL;
memcpy(gDTMF_InputBox, gDTMF_String, MIN(sizeof(gDTMF_InputBox), sizeof(gDTMF_String) - 1));
gDTMF_InputBox_Index = 0;
gDTMF_InputMode = true;
@@ -646,28 +574,27 @@ static void MAIN_Key_STAR(bool bKeyPressed, bool bKeyHeld)
gRequestDisplayScreen = DISPLAY_MAIN;
}
else
gBeepToPlay = BEEP_500HZ_60MS_DOUBLE_BEEP_OPTIONAL;
}
else
{ // with the F-key
gWasFKeyPressed = false;
#ifdef ENABLE_NOAA
if (IS_NOAA_CHANNEL(gTxVfo->CHANNEL_SAVE))
{
gBeepToPlay = BEEP_500HZ_60MS_DOUBLE_BEEP_OPTIONAL;
return;
}
#endif
#ifdef ENABLE_NOAA
if (IS_NOAA_CHANNEL(gTxVfo->CHANNEL_SAVE)) {
gBeepToPlay = BEEP_500HZ_60MS_DOUBLE_BEEP_OPTIONAL;
return;
}
#endif
// scan the CTCSS/DCS code
gFlagStartScan = true;
gScanSingleFrequency = true;
gBackup_CROSS_BAND_RX_TX = gEeprom.CROSS_BAND_RX_TX;
gEeprom.CROSS_BAND_RX_TX = CROSS_BAND_OFF;
SCANNER_Start(true);
gRequestDisplayScreen = DISPLAY_SCANNER;
}
gPttWasReleased = true;
gUpdateStatus = true;
}
@@ -675,58 +602,45 @@ static void MAIN_Key_UP_DOWN(bool bKeyPressed, bool bKeyHeld, int8_t Direction)
{
uint8_t Channel = gEeprom.ScreenChannel[gEeprom.TX_VFO];
if (bKeyHeld || !bKeyPressed)
{
if (bKeyHeld || !bKeyPressed) { // key held or released
if (gInputBoxIndex > 0)
return;
return; // leave if input box active
if (!bKeyPressed)
{
if (!bKeyHeld)
if (!bKeyPressed) {
if (!bKeyHeld || IS_FREQ_CHANNEL(Channel))
return;
if (IS_FREQ_CHANNEL(Channel))
return;
#ifdef ENABLE_VOICE
AUDIO_SetDigitVoice(0, gTxVfo->CHANNEL_SAVE + 1);
gAnotherVoiceID = (VOICE_ID_t)0xFE;
#endif
// if released long button press and not in freq mode
#ifdef ENABLE_VOICE
AUDIO_SetDigitVoice(0, gTxVfo->CHANNEL_SAVE + 1); // say channel number
gAnotherVoiceID = (VOICE_ID_t)0xFE;
#endif
return;
}
}
else
{
if (gInputBoxIndex > 0)
{
else { // short pressed
if (gInputBoxIndex > 0) {
gBeepToPlay = BEEP_500HZ_60MS_DOUBLE_BEEP_OPTIONAL;
return;
}
gBeepToPlay = BEEP_1KHZ_60MS_OPTIONAL;
}
if (gScanStateDir == SCAN_OFF)
{
#ifdef ENABLE_NOAA
if (!IS_NOAA_CHANNEL(Channel))
#endif
if (gScanStateDir == SCAN_OFF) {
#ifdef ENABLE_NOAA
if (!IS_NOAA_CHANNEL(Channel))
#endif
{
uint8_t Next;
if (IS_FREQ_CHANNEL(Channel))
{ // step/down in frequency
if (IS_FREQ_CHANNEL(Channel)) { // step/down in frequency
const uint32_t frequency = APP_SetFrequencyByStep(gTxVfo, Direction);
if (RX_freq_check(frequency) < 0)
{ // frequency not allowed
if (RX_freq_check(frequency) < 0) { // frequency not allowed
gBeepToPlay = BEEP_500HZ_60MS_DOUBLE_BEEP_OPTIONAL;
return;
}
gTxVfo->freq_config_RX.Frequency = frequency;
BK4819_SetFrequency(frequency);
BK4819_RX_TurnOn();
gRequestSaveChannel = 1;
return;
}
@@ -734,29 +648,25 @@ static void MAIN_Key_UP_DOWN(bool bKeyPressed, bool bKeyHeld, int8_t Direction)
Next = RADIO_FindNextChannel(Channel + Direction, Direction, false, 0);
if (Next == 0xFF)
return;
if (Channel == Next)
return;
gEeprom.MrChannel[gEeprom.TX_VFO] = Next;
gEeprom.MrChannel[gEeprom.TX_VFO] = Next;
gEeprom.ScreenChannel[gEeprom.TX_VFO] = Next;
if (!bKeyHeld)
{
#ifdef ENABLE_VOICE
AUDIO_SetDigitVoice(0, Next + 1);
gAnotherVoiceID = (VOICE_ID_t)0xFE;
#endif
if (!bKeyHeld) {
#ifdef ENABLE_VOICE
AUDIO_SetDigitVoice(0, Next + 1);
gAnotherVoiceID = (VOICE_ID_t)0xFE;
#endif
}
}
#ifdef ENABLE_NOAA
else
{
Channel = NOAA_CHANNEL_FIRST + NUMBER_AddWithWraparound(gEeprom.ScreenChannel[gEeprom.TX_VFO] - NOAA_CHANNEL_FIRST, Direction, 0, 9);
gEeprom.NoaaChannel[gEeprom.TX_VFO] = Channel;
gEeprom.ScreenChannel[gEeprom.TX_VFO] = Channel;
}
#endif
#ifdef ENABLE_NOAA
else {
Channel = NOAA_CHANNEL_FIRST + NUMBER_AddWithWraparound(gEeprom.ScreenChannel[gEeprom.TX_VFO] - NOAA_CHANNEL_FIRST, Direction, 0, 9);
gEeprom.NoaaChannel[gEeprom.TX_VFO] = Channel;
gEeprom.ScreenChannel[gEeprom.TX_VFO] = Channel;
}
#endif
gRequestSaveVFO = true;
gVfoConfigureMode = VFO_CONFIGURE_RELOAD;
@@ -764,26 +674,24 @@ static void MAIN_Key_UP_DOWN(bool bKeyPressed, bool bKeyHeld, int8_t Direction)
}
// jump to the next channel
SCANNER_ScanChannels(false, Direction);
CHFRSCANNER_Start(false, Direction);
gScanPauseDelayIn_10ms = 1;
gScheduleScanListen = false;
gScheduleScanListen = false;
gPttWasReleased = true;
}
void MAIN_ProcessKeys(KEY_Code_t Key, bool bKeyPressed, bool bKeyHeld)
{
#ifdef ENABLE_FMRADIO
if (gFmRadioMode && Key != KEY_PTT && Key != KEY_EXIT)
{
if (!bKeyHeld && bKeyPressed)
gBeepToPlay = BEEP_500HZ_60MS_DOUBLE_BEEP_OPTIONAL;
return;
}
#endif
#ifdef ENABLE_FMRADIO
if (gFmRadioMode && Key != KEY_PTT && Key != KEY_EXIT) {
if (!bKeyHeld && bKeyPressed)
gBeepToPlay = BEEP_500HZ_60MS_DOUBLE_BEEP_OPTIONAL;
return;
}
#endif
if (gDTMF_InputMode && bKeyPressed && !bKeyHeld)
{
if (gDTMF_InputMode && bKeyPressed && !bKeyHeld) {
const char Character = DTMF_GetCharacter(Key);
if (Character != 0xFF)
{ // add key to DTMF string
@@ -802,18 +710,8 @@ void MAIN_ProcessKeys(KEY_Code_t Key, bool bKeyPressed, bool bKeyHeld)
// Key = KEY_SIDE2; // what's this doing ???
// }
switch (Key)
{
case KEY_0:
case KEY_1:
case KEY_2:
case KEY_3:
case KEY_4:
case KEY_5:
case KEY_6:
case KEY_7:
case KEY_8:
case KEY_9:
switch (Key) {
case KEY_0...KEY_9:
MAIN_Key_DIGITS(Key, bKeyPressed, bKeyHeld);
break;
case KEY_MENU:

View File

@@ -40,13 +40,14 @@
#endif
#include "ui/inputbox.h"
#include "ui/menu.h"
#include "ui/menu.h"
#include "ui/ui.h"
#ifndef ARRAY_SIZE
#define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))
#endif
uint8_t gUnlockAllTxConfCnt;
#ifdef ENABLE_F_CAL_MENU
void writeXtalFreqCal(const int32_t value, const bool update_eeprom)
{
@@ -75,27 +76,39 @@
}
#endif
void MENU_StartCssScan(int8_t Direction)
void MENU_StartCssScan(void)
{
gCssScanMode = CSS_SCAN_MODE_SCANNING;
SCANNER_Start(true);
gUpdateStatus = true;
gCssBackgroundScan = true;
gMenuScrollDirection = Direction;
gRequestDisplayScreen = DISPLAY_MENU;
}
RADIO_SelectVfos();
void MENU_CssScanFound(void)
{
if(gScanCssResultType == CODE_TYPE_DIGITAL || gScanCssResultType == CODE_TYPE_REVERSE_DIGITAL) {
gMenuCursor = UI_MENU_GetMenuIdx(MENU_R_DCS);
}
else if(gScanCssResultType == CODE_TYPE_CONTINUOUS_TONE) {
gMenuCursor = UI_MENU_GetMenuIdx(MENU_R_CTCS);
}
MENU_SelectNextCode();
MENU_ShowCurrentSetting();
gScanPauseDelayIn_10ms = scan_pause_delay_in_2_10ms;
gScheduleScanListen = false;
gUpdateStatus = true;
gUpdateDisplay = true;
}
void MENU_StopCssScan(void)
{
gCssScanMode = CSS_SCAN_MODE_OFF;
gUpdateStatus = true;
gCssBackgroundScan = false;
RADIO_SetupRegisters(true);
#ifdef ENABLE_VOICE
gAnotherVoiceID = VOICE_ID_SCANNING_STOP;
#endif
gUpdateDisplay = true;
gUpdateStatus = true;
}
int MENU_GetLimits(uint8_t menu_id, int32_t *pMin, int32_t *pMax)
@@ -109,7 +122,7 @@ int MENU_GetLimits(uint8_t menu_id, int32_t *pMin, int32_t *pMax)
case MENU_STEP:
*pMin = 0;
*pMax = ARRAY_SIZE(gStepFrequencyTable) - 1;
*pMax = STEP_N_ELEM - 1;
break;
case MENU_ABR:
@@ -120,12 +133,12 @@ int MENU_GetLimits(uint8_t menu_id, int32_t *pMin, int32_t *pMax)
case MENU_ABR_MIN:
*pMin = 0;
*pMax = 9;
break;
break;
case MENU_ABR_MAX:
*pMin = 1;
*pMax = 10;
break;
break;
case MENU_F_LOCK:
*pMin = 0;
@@ -184,7 +197,7 @@ int MENU_GetLimits(uint8_t menu_id, int32_t *pMin, int32_t *pMax)
case MENU_R_CTCS:
case MENU_T_CTCS:
*pMin = 0;
*pMax = ARRAY_SIZE(CTCSS_Options) - 1;
*pMax = ARRAY_SIZE(CTCSS_Options);
break;
case MENU_W_N:
@@ -210,13 +223,6 @@ int MENU_GetLimits(uint8_t menu_id, int32_t *pMin, int32_t *pMax)
*pMax = ARRAY_SIZE(gSubMenu_RX_TX) - 1;
break;
#ifdef ENABLE_AM_FIX_TEST1
case MENU_AM_FIX_TEST1:
*pMin = 0;
*pMax = ARRAY_SIZE(gSubMenu_AM_fix_test1) - 1;
break;
#endif
#ifdef ENABLE_AM_FIX
case MENU_AM_FIX:
#endif
@@ -230,7 +236,9 @@ int MENU_GetLimits(uint8_t menu_id, int32_t *pMin, int32_t *pMax)
case MENU_S_ADD2:
case MENU_STE:
case MENU_D_ST:
#ifdef ENABLE_DTMF_CALLING
case MENU_D_DCD:
#endif
case MENU_D_LIVE_DEC:
#ifdef ENABLE_NOAA
case MENU_NOAA_S:
@@ -240,7 +248,6 @@ int MENU_GetLimits(uint8_t menu_id, int32_t *pMin, int32_t *pMax)
case MENU_500TX:
case MENU_350EN:
case MENU_SCREN:
case MENU_TX_EN:
*pMin = 0;
*pMax = ARRAY_SIZE(gSubMenu_OFF_ON) - 1;
break;
@@ -297,11 +304,12 @@ int MENU_GetLimits(uint8_t menu_id, int32_t *pMin, int32_t *pMax)
*pMax = 2;
break;
#ifdef ENABLE_DTMF_CALLING
case MENU_D_RSP:
*pMin = 0;
*pMax = ARRAY_SIZE(gSubMenu_D_RSP) - 1;
break;
#endif
case MENU_PTT_ID:
*pMin = 0;
*pMax = ARRAY_SIZE(gSubMenu_PTT_ID) - 1;
@@ -312,21 +320,23 @@ int MENU_GetLimits(uint8_t menu_id, int32_t *pMin, int32_t *pMax)
*pMax = ARRAY_SIZE(gSubMenu_BAT_TXT) - 1;
break;
#ifdef ENABLE_DTMF_CALLING
case MENU_D_HOLD:
*pMin = 5;
*pMax = 60;
break;
#endif
case MENU_D_PRE:
*pMin = 3;
*pMax = 99;
break;
#ifdef ENABLE_DTMF_CALLING
case MENU_D_LIST:
*pMin = 1;
*pMax = 16;
break;
#endif
#ifdef ENABLE_F_CAL_MENU
case MENU_F_CALI:
*pMin = -50;
@@ -364,17 +374,16 @@ void MENU_AcceptSetting(void)
{
int32_t Min;
int32_t Max;
uint8_t Code;
FREQ_Config_t *pConfig = &gTxVfo->freq_config_RX;
if (!MENU_GetLimits(GetCurrentMenuId(), &Min, &Max))
if (!MENU_GetLimits(UI_MENU_GetCurrentMenuId(), &Min, &Max))
{
if (gSubMenuSelection < Min) gSubMenuSelection = Min;
else
if (gSubMenuSelection > Max) gSubMenuSelection = Max;
}
switch (GetCurrentMenuId())
switch (UI_MENU_GetCurrentMenuId())
{
default:
return;
@@ -403,62 +412,45 @@ void MENU_AcceptSetting(void)
// Fallthrough
case MENU_R_DCS:
if (gSubMenuSelection == 0)
{
if (pConfig->CodeType != CODE_TYPE_DIGITAL && pConfig->CodeType != CODE_TYPE_REVERSE_DIGITAL)
{
gRequestSaveChannel = 1;
case MENU_R_DCS: {
if (gSubMenuSelection == 0) {
if (pConfig->CodeType == CODE_TYPE_CONTINUOUS_TONE) {
return;
}
Code = 0;
pConfig->Code = 0;
pConfig->CodeType = CODE_TYPE_OFF;
}
else
if (gSubMenuSelection < 105)
{
else if (gSubMenuSelection < 105) {
pConfig->CodeType = CODE_TYPE_DIGITAL;
Code = gSubMenuSelection - 1;
pConfig->Code = gSubMenuSelection - 1;
}
else
{
else {
pConfig->CodeType = CODE_TYPE_REVERSE_DIGITAL;
Code = gSubMenuSelection - 105;
pConfig->Code = gSubMenuSelection - 105;
}
pConfig->Code = Code;
gRequestSaveChannel = 1;
return;
}
case MENU_T_CTCS:
pConfig = &gTxVfo->freq_config_TX;
[[fallthrough]];
case MENU_R_CTCS:
if (gSubMenuSelection == 0)
{
if (pConfig->CodeType != CODE_TYPE_CONTINUOUS_TONE)
{
gRequestSaveChannel = 1;
case MENU_R_CTCS: {
if (gSubMenuSelection == 0) {
if (pConfig->CodeType != CODE_TYPE_CONTINUOUS_TONE) {
return;
}
Code = 0;
pConfig->Code = Code;
pConfig->Code = 0;
pConfig->CodeType = CODE_TYPE_OFF;
BK4819_ExitSubAu();
}
else
{
else {
pConfig->Code = gSubMenuSelection - 1;
pConfig->CodeType = CODE_TYPE_CONTINUOUS_TONE;
Code = gSubMenuSelection - 1;
pConfig->Code = Code;
BK4819_SetCTCSSFrequency(CTCSS_Options[Code]);
}
gRequestSaveChannel = 1;
return;
}
case MENU_SFT_D:
gTxVfo->TX_OFFSET_FREQUENCY_DIRECTION = gSubMenuSelection;
gRequestSaveChannel = 1;
@@ -503,20 +495,13 @@ void MENU_AcceptSetting(void)
return;
case MENU_MEM_NAME:
{ // trailing trim
for (int i = 9; i >= 0; i--)
{
if (edit[i] != ' ' && edit[i] != '_' && edit[i] != 0x00 && edit[i] != 0xff)
break;
edit[i] = ' ';
}
for (int i = 9; i >= 0; i--) {
if (edit[i] != ' ' && edit[i] != '_' && edit[i] != 0x00 && edit[i] != 0xff)
break;
edit[i] = ' ';
}
// save the channel name
memset(gTxVfo->Name, 0, sizeof(gTxVfo->Name));
memmove(gTxVfo->Name, edit, 10);
SETTINGS_SaveChannel(gSubMenuSelection, gEeprom.TX_VFO, gTxVfo, 3);
gFlagReconfigureVfos = true;
SETTINGS_SaveChannelName(gSubMenuSelection, edit);
return;
case MENU_SAVE:
@@ -528,7 +513,7 @@ void MENU_AcceptSetting(void)
gEeprom.VOX_SWITCH = gSubMenuSelection != 0;
if (gEeprom.VOX_SWITCH)
gEeprom.VOX_LEVEL = gSubMenuSelection - 1;
BOARD_EEPROM_LoadCalibration();
SETTINGS_LoadCalibration();
gFlagReconfigureVfos = true;
gUpdateStatus = true;
break;
@@ -546,7 +531,7 @@ void MENU_AcceptSetting(void)
case MENU_ABR_MAX:
gEeprom.BACKLIGHT_MAX = gSubMenuSelection;
gEeprom.BACKLIGHT_MIN = MIN(gSubMenuSelection - 1, gEeprom.BACKLIGHT_MIN);
break;
break;
case MENU_ABR_ON_TX_RX:
gSetting_backlight_on_tx_rx = gSubMenuSelection;
@@ -612,7 +597,7 @@ void MENU_AcceptSetting(void)
case MENU_MIC:
gEeprom.MIC_SENSITIVITY = gSubMenuSelection;
BOARD_EEPROM_LoadCalibration();
SETTINGS_LoadCalibration();
gFlagReconfigureVfos = true;
break;
@@ -648,6 +633,7 @@ void MENU_AcceptSetting(void)
gEeprom.DTMF_SIDE_TONE = gSubMenuSelection;
break;
#ifdef ENABLE_DTMF_CALLING
case MENU_D_RSP:
gEeprom.DTMF_DECODE_RESPONSE = gSubMenuSelection;
break;
@@ -655,7 +641,7 @@ void MENU_AcceptSetting(void)
case MENU_D_HOLD:
gEeprom.DTMF_auto_reset_time = gSubMenuSelection;
break;
#endif
case MENU_D_PRE:
gEeprom.DTMF_PRELOAD_TIME = gSubMenuSelection * 10;
break;
@@ -669,11 +655,13 @@ void MENU_AcceptSetting(void)
gSetting_battery_text = gSubMenuSelection;
break;
#ifdef ENABLE_DTMF_CALLING
case MENU_D_DCD:
gTxVfo->DTMF_DECODING_ENABLE = gSubMenuSelection;
DTMF_clear_RX();
gRequestSaveChannel = 1;
return;
#endif
case MENU_D_LIVE_DEC:
gSetting_live_DTMF_decoder = gSubMenuSelection;
@@ -685,6 +673,7 @@ void MENU_AcceptSetting(void)
gUpdateStatus = true;
break;
#ifdef ENABLE_DTMF_CALLING
case MENU_D_LIST:
gDTMF_chosen_contact = gSubMenuSelection - 1;
if (gIsDtmfContactValid)
@@ -692,11 +681,11 @@ void MENU_AcceptSetting(void)
GUI_SelectNextDisplay(DISPLAY_MAIN);
gDTMF_InputMode = true;
gDTMF_InputBox_Index = 3;
memmove(gDTMF_InputBox, gDTMF_ID, 4);
memcpy(gDTMF_InputBox, gDTMF_ID, 4);
gRequestDisplayScreen = DISPLAY_INVALID;
}
return;
#endif
case MENU_PONMSG:
gEeprom.POWER_ON_DISPLAY_MODE = gSubMenuSelection;
break;
@@ -718,14 +707,6 @@ void MENU_AcceptSetting(void)
break;
#endif
#ifdef ENABLE_AM_FIX_TEST1
case MENU_AM_FIX_TEST1:
gSetting_AM_fix_test1 = gSubMenuSelection;
gVfoConfigureMode = VFO_CONFIGURE_RELOAD;
gFlagResetVfos = true;
break;
#endif
#ifdef ENABLE_NOAA
case MENU_NOAA_S:
gEeprom.NOAA_AUTO_SCAN = gSubMenuSelection;
@@ -740,17 +721,25 @@ void MENU_AcceptSetting(void)
return;
case MENU_RESET:
BOARD_FactoryReset(gSubMenuSelection);
SETTINGS_FactoryReset(gSubMenuSelection);
return;
case MENU_350TX:
gSetting_350TX = gSubMenuSelection;
break;
case MENU_F_LOCK:
case MENU_F_LOCK: {
if(gSubMenuSelection == F_LOCK_NONE) { // select 10 times to enable
gUnlockAllTxConfCnt++;
if(gUnlockAllTxConfCnt < 10)
return;
}
else
gUnlockAllTxConfCnt = 0;
gSetting_F_LOCK = gSubMenuSelection;
break;
}
case MENU_200TX:
gSetting_200TX = gSubMenuSelection;
break;
@@ -770,10 +759,6 @@ void MENU_AcceptSetting(void)
gFlagReconfigureVfos = true;
break;
case MENU_TX_EN:
gSetting_TX_EN = gSubMenuSelection;
break;
#ifdef ENABLE_F_CAL_MENU
case MENU_F_CALI:
writeXtalFreqCal(gSubMenuSelection, true);
@@ -808,7 +793,7 @@ void MENU_AcceptSetting(void)
&gEeprom.KEY_2_SHORT_PRESS_ACTION,
&gEeprom.KEY_2_LONG_PRESS_ACTION,
&gEeprom.KEY_M_LONG_PRESS_ACTION};
*fun[GetCurrentMenuId()-MENU_F1SHRT] = gSubMenu_SIDEFUNCTIONS[gSubMenuSelection].id;
*fun[UI_MENU_GetCurrentMenuId()-MENU_F1SHRT] = gSubMenu_SIDEFUNCTIONS[gSubMenuSelection].id;
}
break;
@@ -817,53 +802,12 @@ void MENU_AcceptSetting(void)
gRequestSaveSettings = true;
}
void MENU_SelectNextCode(void)
{
int32_t UpperLimit;
if (GetCurrentMenuId() == MENU_R_DCS)
UpperLimit = 208;
//UpperLimit = ARRAY_SIZE(DCS_Options);
else if (GetCurrentMenuId() == MENU_R_CTCS)
UpperLimit = ARRAY_SIZE(CTCSS_Options) - 1;
else
return;
gSubMenuSelection = NUMBER_AddWithWraparound(gSubMenuSelection, gMenuScrollDirection, 1, UpperLimit);
if (GetCurrentMenuId() == MENU_R_DCS)
{
if (gSubMenuSelection > 104)
{
gSelectedCodeType = CODE_TYPE_REVERSE_DIGITAL;
gSelectedCode = gSubMenuSelection - 105;
}
else
{
gSelectedCodeType = CODE_TYPE_DIGITAL;
gSelectedCode = gSubMenuSelection - 1;
}
}
else
{
gSelectedCodeType = CODE_TYPE_CONTINUOUS_TONE;
gSelectedCode = gSubMenuSelection - 1;
}
RADIO_SetupRegisters(true);
gScanPauseDelayIn_10ms = (gSelectedCodeType == CODE_TYPE_CONTINUOUS_TONE) ? scan_pause_delay_in_3_10ms : scan_pause_delay_in_4_10ms;
gUpdateDisplay = true;
}
static void MENU_ClampSelection(int8_t Direction)
{
int32_t Min;
int32_t Max;
if (!MENU_GetLimits(GetCurrentMenuId(), &Min, &Max))
if (!MENU_GetLimits(UI_MENU_GetCurrentMenuId(), &Min, &Max))
{
int32_t Selection = gSubMenuSelection;
if (Selection < Min) Selection = Min;
@@ -875,7 +819,7 @@ static void MENU_ClampSelection(int8_t Direction)
void MENU_ShowCurrentSetting(void)
{
switch (GetCurrentMenuId())
switch (UI_MENU_GetCurrentMenuId())
{
case MENU_SQL:
gSubMenuSelection = gEeprom.SQUELCH_LEVEL;
@@ -889,28 +833,41 @@ void MENU_ShowCurrentSetting(void)
gSubMenuSelection = gTxVfo->OUTPUT_POWER;
break;
case MENU_RESET:
gSubMenuSelection = 0;
break;
case MENU_R_DCS:
switch (gTxVfo->freq_config_RX.CodeType)
{
case MENU_R_CTCS:
{
DCS_CodeType_t type = gTxVfo->freq_config_RX.CodeType;
uint8_t code = gTxVfo->freq_config_RX.Code;
int menuid = UI_MENU_GetCurrentMenuId();
if(gScanUseCssResult) {
gScanUseCssResult = false;
type = gScanCssResultType;
code = gScanCssResultCode;
}
if((menuid==MENU_R_CTCS) ^ (type==CODE_TYPE_CONTINUOUS_TONE)) { //not the same type
gSubMenuSelection = 0;
break;
}
switch (type) {
case CODE_TYPE_CONTINUOUS_TONE:
case CODE_TYPE_DIGITAL:
gSubMenuSelection = gTxVfo->freq_config_RX.Code + 1;
gSubMenuSelection = code + 1;
break;
case CODE_TYPE_REVERSE_DIGITAL:
gSubMenuSelection = gTxVfo->freq_config_RX.Code + 105;
gSubMenuSelection = code + 105;
break;
default:
gSubMenuSelection = 0;
break;
}
break;
case MENU_RESET:
gSubMenuSelection = 0;
break;
case MENU_R_CTCS:
gSubMenuSelection = (gTxVfo->freq_config_RX.CodeType == CODE_TYPE_CONTINUOUS_TONE) ? gTxVfo->freq_config_RX.Code + 1 : 0;
break;
break;
}
case MENU_T_DCS:
switch (gTxVfo->freq_config_TX.CodeType)
@@ -983,7 +940,7 @@ void MENU_ShowCurrentSetting(void)
case MENU_ABR_MAX:
gSubMenuSelection = gEeprom.BACKLIGHT_MAX;
break;
break;
case MENU_ABR_ON_TX_RX:
gSubMenuSelection = gSetting_backlight_on_tx_rx;
@@ -1075,6 +1032,7 @@ void MENU_ShowCurrentSetting(void)
gSubMenuSelection = gEeprom.DTMF_SIDE_TONE;
break;
#ifdef ENABLE_DTMF_CALLING
case MENU_D_RSP:
gSubMenuSelection = gEeprom.DTMF_DECODE_RESPONSE;
break;
@@ -1082,7 +1040,7 @@ void MENU_ShowCurrentSetting(void)
case MENU_D_HOLD:
gSubMenuSelection = gEeprom.DTMF_auto_reset_time;
break;
#endif
case MENU_D_PRE:
gSubMenuSelection = gEeprom.DTMF_PRELOAD_TIME / 10;
break;
@@ -1095,6 +1053,7 @@ void MENU_ShowCurrentSetting(void)
gSubMenuSelection = gSetting_battery_text;
return;
#ifdef ENABLE_DTMF_CALLING
case MENU_D_DCD:
gSubMenuSelection = gTxVfo->DTMF_DECODING_ENABLE;
break;
@@ -1102,7 +1061,7 @@ void MENU_ShowCurrentSetting(void)
case MENU_D_LIST:
gSubMenuSelection = gDTMF_chosen_contact + 1;
break;
#endif
case MENU_D_LIVE_DEC:
gSubMenuSelection = gSetting_live_DTMF_decoder;
break;
@@ -1124,13 +1083,6 @@ void MENU_ShowCurrentSetting(void)
gSubMenuSelection = gSetting_AM_fix;
break;
#endif
#ifdef ENABLE_AM_FIX_TEST1
case MENU_AM_FIX_TEST1:
gSubMenuSelection = gSetting_AM_fix_test1;
break;
#endif
#ifdef ENABLE_NOAA
case MENU_NOAA_S:
gSubMenuSelection = gEeprom.NOAA_AUTO_SCAN;
@@ -1169,10 +1121,6 @@ void MENU_ShowCurrentSetting(void)
gSubMenuSelection = gSetting_ScrambleEnable;
break;
case MENU_TX_EN:
gSubMenuSelection = gSetting_TX_EN;
break;
#ifdef ENABLE_F_CAL_MENU
case MENU_F_CALI:
gSubMenuSelection = gEeprom.BK4819_XTAL_FREQ_LOW;
@@ -1185,7 +1133,7 @@ void MENU_ShowCurrentSetting(void)
case MENU_BATTYP:
gSubMenuSelection = gEeprom.BATTERY_TYPE;
break;
break;
case MENU_F1SHRT:
case MENU_F1LONG:
@@ -1199,14 +1147,14 @@ void MENU_ShowCurrentSetting(void)
&gEeprom.KEY_2_SHORT_PRESS_ACTION,
&gEeprom.KEY_2_LONG_PRESS_ACTION,
&gEeprom.KEY_M_LONG_PRESS_ACTION};
uint8_t id = *fun[GetCurrentMenuId()-MENU_F1SHRT];
uint8_t id = *fun[UI_MENU_GetCurrentMenuId()-MENU_F1SHRT];
for(int i = 0; i < gSubMenu_SIDEFUNCTIONS_size; i++) {
if(gSubMenu_SIDEFUNCTIONS[i].id==id) {
gSubMenuSelection = i;
break;
}
}
break;
}
@@ -1228,7 +1176,7 @@ static void MENU_Key_0_to_9(KEY_Code_t Key, bool bKeyPressed, bool bKeyHeld)
gBeepToPlay = BEEP_1KHZ_60MS_OPTIONAL;
if (GetCurrentMenuId() == MENU_MEM_NAME && edit_index >= 0)
if (UI_MENU_GetCurrentMenuId() == MENU_MEM_NAME && edit_index >= 0)
{ // currently editing the channel name
if (edit_index < 10)
@@ -1293,7 +1241,7 @@ static void MENU_Key_0_to_9(KEY_Code_t Key, bool bKeyPressed, bool bKeyHeld)
return;
}
if (GetCurrentMenuId() == MENU_OFFSET)
if (UI_MENU_GetCurrentMenuId() == MENU_OFFSET)
{
uint32_t Frequency;
@@ -1308,18 +1256,18 @@ static void MENU_Key_0_to_9(KEY_Code_t Key, bool bKeyPressed, bool bKeyHeld)
#ifdef ENABLE_VOICE
gAnotherVoiceID = (VOICE_ID_t)Key;
#endif
Frequency = StrToUL(INPUTBOX_GetAscii())*100;
gSubMenuSelection = FREQUENCY_RoundToStep(Frequency, gTxVfo->StepFrequency);
gInputBoxIndex = 0;
return;
}
if (GetCurrentMenuId() == MENU_MEM_CH ||
GetCurrentMenuId() == MENU_DEL_CH ||
GetCurrentMenuId() == MENU_1_CALL ||
GetCurrentMenuId() == MENU_MEM_NAME)
if (UI_MENU_GetCurrentMenuId() == MENU_MEM_CH ||
UI_MENU_GetCurrentMenuId() == MENU_DEL_CH ||
UI_MENU_GetCurrentMenuId() == MENU_1_CALL ||
UI_MENU_GetCurrentMenuId() == MENU_MEM_NAME)
{ // enter 3-digit channel number
if (gInputBoxIndex < 3)
@@ -1348,7 +1296,7 @@ static void MENU_Key_0_to_9(KEY_Code_t Key, bool bKeyPressed, bool bKeyHeld)
return;
}
if (MENU_GetLimits(GetCurrentMenuId(), &Min, &Max))
if (MENU_GetLimits(UI_MENU_GetCurrentMenuId(), &Min, &Max))
{
gInputBoxIndex = 0;
gBeepToPlay = BEEP_500HZ_60MS_DOUBLE_BEEP_OPTIONAL;
@@ -1389,11 +1337,15 @@ static void MENU_Key_EXIT(bool bKeyPressed, bool bKeyHeld)
gBeepToPlay = BEEP_1KHZ_60MS_OPTIONAL;
if (gCssScanMode == CSS_SCAN_MODE_OFF)
if (!gCssBackgroundScan)
{
/* Backlight related menus set full brightness. Set it back to the configured value,
just in case we are exiting from one of them. */
BACKLIGHT_TurnOn();
if (gIsInSubMenu)
{
if (gInputBoxIndex == 0 || GetCurrentMenuId() != MENU_OFFSET)
if (gInputBoxIndex == 0 || UI_MENU_GetCurrentMenuId() != MENU_OFFSET)
{
gAskForConfirmation = 0;
gIsInSubMenu = false;
@@ -1449,12 +1401,18 @@ static void MENU_Key_MENU(const bool bKeyPressed, const bool bKeyHeld)
if (!gIsInSubMenu)
{
#ifdef ENABLE_VOICE
if (GetCurrentMenuId() != MENU_SCR)
if (UI_MENU_GetCurrentMenuId() != MENU_SCR)
gAnotherVoiceID = MenuList[gMenuCursor].voice_id;
#endif
if (UI_MENU_GetCurrentMenuId() == MENU_UPCODE
|| UI_MENU_GetCurrentMenuId() == MENU_DWCODE
#ifdef ENABLE_DTMF_CALLING
|| UI_MENU_GetCurrentMenuId() == MENU_ANI_ID
#endif
)
return;
#if 1
if (GetCurrentMenuId() == MENU_DEL_CH || GetCurrentMenuId() == MENU_MEM_NAME)
if (UI_MENU_GetCurrentMenuId() == MENU_DEL_CH || UI_MENU_GetCurrentMenuId() == MENU_MEM_NAME)
if (!RADIO_CheckValidChannel(gSubMenuSelection, false, 0))
return; // invalid channel
#endif
@@ -1462,7 +1420,7 @@ static void MENU_Key_MENU(const bool bKeyPressed, const bool bKeyHeld)
gAskForConfirmation = 0;
gIsInSubMenu = true;
// if (GetCurrentMenuId() != MENU_D_LIST)
// if (UI_MENU_GetCurrentMenuId() != MENU_D_LIST)
{
gInputBoxIndex = 0;
edit_index = -1;
@@ -1471,14 +1429,14 @@ static void MENU_Key_MENU(const bool bKeyPressed, const bool bKeyHeld)
return;
}
if (GetCurrentMenuId() == MENU_MEM_NAME)
if (UI_MENU_GetCurrentMenuId() == MENU_MEM_NAME)
{
if (edit_index < 0)
{ // enter channel name edit mode
if (!RADIO_CheckValidChannel(gSubMenuSelection, false, 0))
return;
BOARD_fetchChannelName(edit, gSubMenuSelection);
SETTINGS_FetchChannelName(edit, gSubMenuSelection);
// pad the channel name out with '_'
edit_index = strlen(edit);
@@ -1488,7 +1446,7 @@ static void MENU_Key_MENU(const bool bKeyPressed, const bool bKeyHeld)
edit_index = 0; // 'edit_index' is going to be used as the cursor position
// make a copy so we can test for change when exiting the menu item
memmove(edit_original, edit, sizeof(edit_original));
memcpy(edit_original, edit, sizeof(edit_original));
return;
}
@@ -1500,16 +1458,11 @@ static void MENU_Key_MENU(const bool bKeyPressed, const bool bKeyHeld)
return; // next char
// exit
if (memcmp(edit_original, edit, sizeof(edit_original)) == 0)
{ // no change - drop it
gFlagAcceptSetting = false;
gIsInSubMenu = false;
gAskForConfirmation = 0;
}
else
{
gFlagAcceptSetting = false;
gAskForConfirmation = 0;
gFlagAcceptSetting = false;
gAskForConfirmation = 0;
if (memcmp(edit_original, edit, sizeof(edit_original)) == 0) {
// no change - drop it
gIsInSubMenu = false;
}
}
}
@@ -1518,10 +1471,10 @@ static void MENU_Key_MENU(const bool bKeyPressed, const bool bKeyHeld)
if (gIsInSubMenu)
{
if (GetCurrentMenuId() == MENU_RESET ||
GetCurrentMenuId() == MENU_MEM_CH ||
GetCurrentMenuId() == MENU_DEL_CH ||
GetCurrentMenuId() == MENU_MEM_NAME)
if (UI_MENU_GetCurrentMenuId() == MENU_RESET ||
UI_MENU_GetCurrentMenuId() == MENU_MEM_CH ||
UI_MENU_GetCurrentMenuId() == MENU_DEL_CH ||
UI_MENU_GetCurrentMenuId() == MENU_MEM_NAME)
{
switch (gAskForConfirmation)
{
@@ -1534,7 +1487,7 @@ static void MENU_Key_MENU(const bool bKeyPressed, const bool bKeyHeld)
UI_DisplayMenu();
if (GetCurrentMenuId() == MENU_RESET)
if (UI_MENU_GetCurrentMenuId() == MENU_RESET)
{
#ifdef ENABLE_VOICE
AUDIO_SetVoiceID(0, VOICE_ID_CONFIRM);
@@ -1562,14 +1515,10 @@ static void MENU_Key_MENU(const bool bKeyPressed, const bool bKeyHeld)
}
}
if (gCssScanMode != CSS_SCAN_MODE_OFF)
{
gCssScanMode = CSS_SCAN_MODE_OFF;
gUpdateStatus = true;
}
SCANNER_Stop();
#ifdef ENABLE_VOICE
if (GetCurrentMenuId() == MENU_SCR)
if (UI_MENU_GetCurrentMenuId() == MENU_SCR)
gAnotherVoiceID = (gSubMenuSelection == 0) ? VOICE_ID_SCRAMBLER_OFF : VOICE_ID_SCRAMBLER_ON;
else
gAnotherVoiceID = VOICE_ID_CONFIRM;
@@ -1585,7 +1534,7 @@ static void MENU_Key_STAR(const bool bKeyPressed, const bool bKeyHeld)
gBeepToPlay = BEEP_1KHZ_60MS_OPTIONAL;
if (GetCurrentMenuId() == MENU_MEM_NAME && edit_index >= 0)
if (UI_MENU_GetCurrentMenuId() == MENU_MEM_NAME && edit_index >= 0)
{ // currently editing the channel name
if (edit_index < 10)
@@ -1612,26 +1561,12 @@ static void MENU_Key_STAR(const bool bKeyPressed, const bool bKeyHeld)
if (gRxVfo->Modulation == MODULATION_FM)
#endif
{
if (GetCurrentMenuId() == MENU_R_CTCS || GetCurrentMenuId() == MENU_R_DCS)
if ((UI_MENU_GetCurrentMenuId() == MENU_R_CTCS || UI_MENU_GetCurrentMenuId() == MENU_R_DCS) && gIsInSubMenu)
{ // scan CTCSS or DCS to find the tone/code of the incoming signal
if (gCssScanMode == CSS_SCAN_MODE_OFF)
{
MENU_StartCssScan(1);
gRequestDisplayScreen = DISPLAY_MENU;
#ifdef ENABLE_VOICE
AUDIO_SetVoiceID(0, VOICE_ID_SCANNING_BEGIN);
AUDIO_PlaySingleVoice(1);
#endif
}
if (!SCANNER_IsScanning())
MENU_StartCssScan();
else
{
MENU_StopCssScan();
gRequestDisplayScreen = DISPLAY_MENU;
#ifdef ENABLE_VOICE
gAnotherVoiceID = VOICE_ID_SCANNING_STOP;
#endif
}
}
gPttWasReleased = true;
@@ -1647,7 +1582,7 @@ static void MENU_Key_UP_DOWN(bool bKeyPressed, bool bKeyHeld, int8_t Direction)
uint8_t Channel;
bool bCheckScanList;
if (GetCurrentMenuId() == MENU_MEM_NAME && gIsInSubMenu && edit_index >= 0)
if (UI_MENU_GetCurrentMenuId() == MENU_MEM_NAME && gIsInSubMenu && edit_index >= 0)
{ // change the character
if (bKeyPressed && edit_index < 10 && Direction != 0)
{
@@ -1682,12 +1617,7 @@ static void MENU_Key_UP_DOWN(bool bKeyPressed, bool bKeyHeld, int8_t Direction)
if (!bKeyPressed)
return;
if (gCssScanMode != CSS_SCAN_MODE_OFF)
{
MENU_StartCssScan(Direction);
gPttWasReleased = true;
gRequestDisplayScreen = DISPLAY_MENU;
if (SCANNER_IsScanning()) {
return;
}
@@ -1699,7 +1629,10 @@ static void MENU_Key_UP_DOWN(bool bKeyPressed, bool bKeyHeld, int8_t Direction)
gRequestDisplayScreen = DISPLAY_MENU;
if (GetCurrentMenuId() != MENU_ABR && gEeprom.BACKLIGHT_TIME == 0) // backlight always off and not in the backlight menu
if (UI_MENU_GetCurrentMenuId() != MENU_ABR
&& UI_MENU_GetCurrentMenuId() != MENU_ABR_MIN
&& UI_MENU_GetCurrentMenuId() != MENU_ABR_MAX
&& gEeprom.BACKLIGHT_TIME == 0) // backlight always off and not in the backlight menu
{
BACKLIGHT_TurnOff();
}
@@ -1707,7 +1640,7 @@ static void MENU_Key_UP_DOWN(bool bKeyPressed, bool bKeyHeld, int8_t Direction)
return;
}
if (GetCurrentMenuId() == MENU_OFFSET)
if (UI_MENU_GetCurrentMenuId() == MENU_OFFSET)
{
int32_t Offset = (Direction * gTxVfo->StepFrequency) + gSubMenuSelection;
if (Offset < 99999990)
@@ -1725,7 +1658,7 @@ static void MENU_Key_UP_DOWN(bool bKeyPressed, bool bKeyHeld, int8_t Direction)
VFO = 0;
switch (GetCurrentMenuId())
switch (UI_MENU_GetCurrentMenuId())
{
case MENU_DEL_CH:
case MENU_1_CALL:
@@ -1785,7 +1718,7 @@ void MENU_ProcessKeys(KEY_Code_t Key, bool bKeyPressed, bool bKeyHeld)
MENU_Key_STAR(bKeyPressed, bKeyHeld);
break;
case KEY_F:
if (GetCurrentMenuId() == MENU_MEM_NAME && edit_index >= 0)
if (UI_MENU_GetCurrentMenuId() == MENU_MEM_NAME && edit_index >= 0)
{ // currently editing the channel name
if (!bKeyHeld && bKeyPressed)
{
@@ -1817,11 +1750,11 @@ void MENU_ProcessKeys(KEY_Code_t Key, bool bKeyPressed, bool bKeyHeld)
if (gScreenToDisplay == DISPLAY_MENU)
{
if (GetCurrentMenuId() == MENU_VOL ||
if (UI_MENU_GetCurrentMenuId() == MENU_VOL ||
#ifdef ENABLE_F_CAL_MENU
GetCurrentMenuId() == MENU_F_CALI ||
UI_MENU_GetCurrentMenuId() == MENU_F_CALI ||
#endif
GetCurrentMenuId() == MENU_BATCAL)
UI_MENU_GetCurrentMenuId() == MENU_BATCAL)
{
gMenuCountdown = menu_timeout_long_500ms;
}

View File

@@ -23,11 +23,13 @@
void writeXtalFreqCal(const int32_t value, const bool update_eeprom);
#endif
extern uint8_t gUnlockAllTxConfCnt;
int MENU_GetLimits(uint8_t menu_id, int32_t *pMin, int32_t *pMax);
void MENU_AcceptSetting(void);
void MENU_SelectNextCode(void);
void MENU_ShowCurrentSetting(void);
void MENU_StartCssScan(int8_t Direction);
void MENU_StartCssScan(void);
void MENU_CssScanFound(void);
void MENU_StopCssScan(void);
void MENU_ProcessKeys(KEY_Code_t Key, bool bKeyPressed, bool bKeyHeld);

View File

@@ -17,6 +17,7 @@
#include "app/app.h"
#include "app/dtmf.h"
#include "app/generic.h"
#include "app/menu.h"
#include "app/scanner.h"
#include "audio.h"
#include "driver/bk4819.h"
@@ -29,68 +30,45 @@
DCS_CodeType_t gScanCssResultType;
uint8_t gScanCssResultCode;
bool gFlagStartScan;
bool gFlagStopScan;
bool gScanSingleFrequency;
uint8_t gScannerEditState;
bool gScanSingleFrequency; // scan CTCSS/DCS codes for current frequency
SCAN_SaveState_t gScannerSaveState;
uint8_t gScanChannel;
uint32_t gScanFrequency;
bool gScanPauseMode;
SCAN_CssState_t gScanCssState;
volatile bool gScheduleScanListen = true;
volatile uint16_t gScanPauseDelayIn_10ms;
uint8_t gScanProgressIndicator;
uint8_t gScanHitCount;
bool gScanUseCssResult;
int8_t gScanStateDir;
bool gScanKeepResult;
typedef enum {
SCAN_NEXT_CHAN_SCANLIST1 = 0,
SCAN_NEXT_CHAN_SCANLIST2,
SCAN_NEXT_CHAN_DUAL_WATCH,
SCAN_NEXT_CHAN_MR,
SCAN_NEXT_NUM
} scan_next_chan_t;
STEP_Setting_t stepSetting;
uint8_t scanHitCount;
scan_next_chan_t currentScanList;
uint32_t initialFrqOrChan;
uint8_t initialCROSS_BAND_RX_TX;
uint32_t lastFoundFrqOrChan;
static void SCANNER_Key_DIGITS(KEY_Code_t Key, bool bKeyPressed, bool bKeyHeld)
{
if (!bKeyHeld && bKeyPressed)
{
if (gScannerEditState == 1)
{
uint16_t Channel;
if (gScannerSaveState == SCAN_SAVE_CHAN_SEL) {
gBeepToPlay = BEEP_1KHZ_60MS_OPTIONAL;
INPUTBOX_Append(Key);
gRequestDisplayScreen = DISPLAY_SCANNER;
if (gInputBoxIndex < 3)
{
#ifdef ENABLE_VOICE
gAnotherVoiceID = (VOICE_ID_t)Key;
#endif
if (gInputBoxIndex < 3) {
#ifdef ENABLE_VOICE
gAnotherVoiceID = (VOICE_ID_t)Key;
#endif
return;
}
gInputBoxIndex = 0;
Channel = ((gInputBox[0] * 100) + (gInputBox[1] * 10) + gInputBox[2]) - 1;
if (IS_MR_CHANNEL(Channel))
{
#ifdef ENABLE_VOICE
gAnotherVoiceID = (VOICE_ID_t)Key;
#endif
gShowChPrefix = RADIO_CheckValidChannel(Channel, false, 0);
gScanChannel = (uint8_t)Channel;
uint16_t chan = ((gInputBox[0] * 100) + (gInputBox[1] * 10) + gInputBox[2]) - 1;
if (IS_MR_CHANNEL(chan)) {
#ifdef ENABLE_VOICE
gAnotherVoiceID = (VOICE_ID_t)Key;
#endif
gShowChPrefix = RADIO_CheckValidChannel(chan, false, 0);
gScanChannel = (uint8_t)chan;
return;
}
}
@@ -101,28 +79,17 @@ static void SCANNER_Key_DIGITS(KEY_Code_t Key, bool bKeyPressed, bool bKeyHeld)
static void SCANNER_Key_EXIT(bool bKeyPressed, bool bKeyHeld)
{
if (!bKeyHeld && bKeyPressed)
{
if (!bKeyHeld && bKeyPressed) { // short pressed
gBeepToPlay = BEEP_1KHZ_60MS_OPTIONAL;
switch (gScannerEditState)
{
case 0:
switch (gScannerSaveState) {
case SCAN_SAVE_NO_PROMPT:
SCANNER_Stop();
gRequestDisplayScreen = DISPLAY_MAIN;
gEeprom.CROSS_BAND_RX_TX = gBackup_CROSS_BAND_RX_TX;
gUpdateStatus = true;
gFlagStopScan = true;
gVfoConfigureMode = VFO_CONFIGURE_RELOAD;
gFlagResetVfos = true;
#ifdef ENABLE_VOICE
gAnotherVoiceID = VOICE_ID_CANCEL;
#endif
break;
case 1:
if (gInputBoxIndex > 0)
{
case SCAN_SAVE_CHAN_SEL:
if (gInputBoxIndex > 0) {
gInputBox[--gInputBoxIndex] = 10;
gRequestDisplayScreen = DISPLAY_SCANNER;
break;
@@ -130,11 +97,11 @@ static void SCANNER_Key_EXIT(bool bKeyPressed, bool bKeyHeld)
// Fallthrough
case 2:
gScannerEditState = 0;
#ifdef ENABLE_VOICE
gAnotherVoiceID = VOICE_ID_CANCEL;
#endif
case SCAN_SAVE_CHANNEL:
gScannerSaveState = SCAN_SAVE_NO_PROMPT;
#ifdef ENABLE_VOICE
gAnotherVoiceID = VOICE_ID_CANCEL;
#endif
gRequestDisplayScreen = DISPLAY_SCANNER;
break;
}
@@ -143,40 +110,28 @@ static void SCANNER_Key_EXIT(bool bKeyPressed, bool bKeyHeld)
static void SCANNER_Key_MENU(bool bKeyPressed, bool bKeyHeld)
{
uint8_t Channel;
if (bKeyHeld)
if (bKeyHeld || !bKeyPressed) // ignore long press or release button events
return;
if (!bKeyPressed)
return;
if (gScanCssState == SCAN_CSS_STATE_OFF && !gScanSingleFrequency)
{
if (gScanCssState == SCAN_CSS_STATE_OFF && !gScanSingleFrequency) {
gBeepToPlay = BEEP_500HZ_60MS_DOUBLE_BEEP_OPTIONAL;
return;
}
if (gScanCssState == SCAN_CSS_STATE_SCANNING)
{
if (gScanSingleFrequency)
{
gBeepToPlay = BEEP_500HZ_60MS_DOUBLE_BEEP_OPTIONAL;
return;
}
if (gScanCssState == SCAN_CSS_STATE_SCANNING && gScanSingleFrequency) {
gBeepToPlay = BEEP_500HZ_60MS_DOUBLE_BEEP_OPTIONAL;
return;
}
if (gScanCssState == SCAN_CSS_STATE_FAILED)
{
if (gScanCssState == SCAN_CSS_STATE_FAILED) {
gBeepToPlay = BEEP_500HZ_60MS_DOUBLE_BEEP_OPTIONAL;
return;
}
gBeepToPlay = BEEP_1KHZ_60MS_OPTIONAL;
switch (gScannerEditState)
{
case 0:
switch (gScannerSaveState) {
case SCAN_SAVE_NO_PROMPT:
if (!gScanSingleFrequency)
{
uint32_t freq250 = FREQUENCY_RoundToStep(gScanFrequency, 250);
@@ -186,60 +141,54 @@ static void SCANNER_Key_MENU(bool bKeyPressed, bool bKeyHeld)
uint32_t diff625 = gScanFrequency > freq625 ? gScanFrequency - freq625 : freq625 - gScanFrequency;
if(diff250 > diff625) {
gStepSetting = STEP_6_25kHz;
stepSetting = STEP_6_25kHz;
gScanFrequency = freq625;
}
else {
gStepSetting = STEP_2_5kHz;
stepSetting = STEP_2_5kHz;
gScanFrequency = freq250;
}
}
if (IS_MR_CHANNEL(gTxVfo->CHANNEL_SAVE))
{
gScannerEditState = 1;
if (IS_MR_CHANNEL(gTxVfo->CHANNEL_SAVE)) {
gScannerSaveState = SCAN_SAVE_CHAN_SEL;
gScanChannel = gTxVfo->CHANNEL_SAVE;
gShowChPrefix = RADIO_CheckValidChannel(gTxVfo->CHANNEL_SAVE, false, 0);
}
else
{
gScannerEditState = 2;
else {
gScannerSaveState = SCAN_SAVE_CHANNEL;
}
gScanCssState = SCAN_CSS_STATE_FOUND;
#ifdef ENABLE_VOICE
gAnotherVoiceID = VOICE_ID_MEMORY_CHANNEL;
#endif
#ifdef ENABLE_VOICE
gAnotherVoiceID = VOICE_ID_MEMORY_CHANNEL;
#endif
gRequestDisplayScreen = DISPLAY_SCANNER;
gUpdateStatus = true;
break;
case 1:
if (gInputBoxIndex == 0)
{
case SCAN_SAVE_CHAN_SEL:
if (gInputBoxIndex == 0) {
gBeepToPlay = BEEP_1KHZ_60MS_OPTIONAL;
gRequestDisplayScreen = DISPLAY_SCANNER;
gScannerEditState = 2;
gScannerSaveState = SCAN_SAVE_CHANNEL;
}
break;
case 2:
if (!gScanSingleFrequency)
{
case SCAN_SAVE_CHANNEL:
if (!gScanSingleFrequency) {
RADIO_InitInfo(gTxVfo, gTxVfo->CHANNEL_SAVE, gScanFrequency);
if (gScanUseCssResult)
{
if (gScanUseCssResult) {
gTxVfo->freq_config_RX.CodeType = gScanCssResultType;
gTxVfo->freq_config_RX.Code = gScanCssResultCode;
}
gTxVfo->freq_config_TX = gTxVfo->freq_config_RX;
gTxVfo->STEP_SETTING = gStepSetting;
gTxVfo->STEP_SETTING = stepSetting;
}
else
{
else {
RADIO_ConfigureChannel(0, VFO_CONFIGURE_RELOAD);
RADIO_ConfigureChannel(1, VFO_CONFIGURE_RELOAD);
@@ -249,25 +198,24 @@ static void SCANNER_Key_MENU(bool bKeyPressed, bool bKeyHeld)
gTxVfo->freq_config_TX.Code = gScanCssResultCode;
}
if (IS_MR_CHANNEL(gTxVfo->CHANNEL_SAVE))
{
Channel = gScanChannel;
gEeprom.MrChannel[gEeprom.TX_VFO] = Channel;
uint8_t chan;
if (IS_MR_CHANNEL(gTxVfo->CHANNEL_SAVE)) {
chan = gScanChannel;
gEeprom.MrChannel[gEeprom.TX_VFO] = chan;
}
else
{
Channel = gTxVfo->Band + FREQ_CHANNEL_FIRST;
gEeprom.FreqChannel[gEeprom.TX_VFO] = Channel;
else {
chan = gTxVfo->Band + FREQ_CHANNEL_FIRST;
gEeprom.FreqChannel[gEeprom.TX_VFO] = chan;
}
gTxVfo->CHANNEL_SAVE = Channel;
gEeprom.ScreenChannel[gEeprom.TX_VFO] = Channel;
#ifdef ENABLE_VOICE
gAnotherVoiceID = VOICE_ID_CONFIRM;
#endif
gRequestDisplayScreen = DISPLAY_SCANNER;
gRequestSaveChannel = 2;
gScannerEditState = 0;
gTxVfo->CHANNEL_SAVE = chan;
gEeprom.ScreenChannel[gEeprom.TX_VFO] = chan;
#ifdef ENABLE_VOICE
gAnotherVoiceID = VOICE_ID_CONFIRM;
#endif
gRequestDisplayScreen = DISPLAY_SCANNER;
gRequestSaveChannel = 2;
gScannerSaveState = SCAN_SAVE_NO_PROMPT;
break;
default:
@@ -278,23 +226,20 @@ static void SCANNER_Key_MENU(bool bKeyPressed, bool bKeyHeld)
static void SCANNER_Key_STAR(bool bKeyPressed, bool bKeyHeld)
{
if (!bKeyHeld && bKeyPressed)
{
if (!bKeyHeld && bKeyPressed) {
gBeepToPlay = BEEP_1KHZ_60MS_OPTIONAL;
gFlagStartScan = true;
SCANNER_Start(gScanSingleFrequency);
}
return;
}
static void SCANNER_Key_UP_DOWN(bool bKeyPressed, bool pKeyHeld, int8_t Direction)
{
if (pKeyHeld)
{
if (pKeyHeld) {
if (!bKeyPressed)
return;
}
else
{
else {
if (!bKeyPressed)
return;
@@ -302,8 +247,7 @@ static void SCANNER_Key_UP_DOWN(bool bKeyPressed, bool pKeyHeld, int8_t Directio
gBeepToPlay = BEEP_1KHZ_60MS_OPTIONAL;
}
if (gScannerEditState == 1)
{
if (gScannerSaveState == SCAN_SAVE_CHAN_SEL) {
gScanChannel = NUMBER_AddWithWraparound(gScanChannel, Direction, 0, MR_CHANNEL_LAST);
gShowChPrefix = RADIO_CheckValidChannel(gScanChannel, false, 0);
gRequestDisplayScreen = DISPLAY_SCANNER;
@@ -314,8 +258,7 @@ static void SCANNER_Key_UP_DOWN(bool bKeyPressed, bool pKeyHeld, int8_t Directio
void SCANNER_ProcessKeys(KEY_Code_t Key, bool bKeyPressed, bool bKeyHeld)
{
switch (Key)
{
switch (Key) {
case KEY_0:
case KEY_1:
case KEY_2:
@@ -353,13 +296,16 @@ void SCANNER_ProcessKeys(KEY_Code_t Key, bool bKeyPressed, bool bKeyHeld)
}
}
void SCANNER_Start(void)
void SCANNER_Start(bool singleFreq)
{
uint8_t BackupStep;
uint16_t BackupFrequency;
gScanSingleFrequency = singleFreq;
gMonitor = false;
#ifdef ENABLE_VOICE
gAnotherVoiceID = VOICE_ID_SCANNING_BEGIN;
#endif
BK4819_StopScan();
RADIO_SelectVfos();
#ifdef ENABLE_NOAA
@@ -367,13 +313,13 @@ void SCANNER_Start(void)
gRxVfo->CHANNEL_SAVE = FREQ_CHANNEL_FIRST + BAND6_400MHz;
#endif
BackupStep = gRxVfo->STEP_SETTING;
BackupFrequency = gRxVfo->StepFrequency;
uint8_t backupStep = gRxVfo->STEP_SETTING;
uint16_t backupFrequency = gRxVfo->StepFrequency;
RADIO_InitInfo(gRxVfo, gRxVfo->CHANNEL_SAVE, gRxVfo->pRX->Frequency);
gRxVfo->STEP_SETTING = BackupStep;
gRxVfo->StepFrequency = BackupFrequency;
gRxVfo->STEP_SETTING = backupStep;
gRxVfo->StepFrequency = backupFrequency;
RADIO_SetupRegisters(true);
@@ -381,34 +327,34 @@ void SCANNER_Start(void)
gIsNoaaMode = false;
#endif
if (gScanSingleFrequency)
{
if (gScanSingleFrequency) {
gScanCssState = SCAN_CSS_STATE_SCANNING;
gScanFrequency = gRxVfo->pRX->Frequency;
gStepSetting = gRxVfo->STEP_SETTING;
stepSetting = gRxVfo->STEP_SETTING;
BK4819_PickRXFilterPathBasedOnFrequency(gScanFrequency);
BK4819_SetScanFrequency(gScanFrequency);
gUpdateStatus = true;
}
else
{
else {
gScanCssState = SCAN_CSS_STATE_OFF;
gScanFrequency = 0xFFFFFFFF;
BK4819_PickRXFilterPathBasedOnFrequency(0xFFFFFFFF);
BK4819_PickRXFilterPathBasedOnFrequency(gScanFrequency);
BK4819_EnableFrequencyScan();
gUpdateStatus = true;
}
#ifdef ENABLE_DTMF_CALLING
DTMF_clear_RX();
#endif
gScanDelay_10ms = scan_delay_10ms;
gScanCssResultCode = 0xFF;
gScanCssResultType = 0xFF;
gScanHitCount = 0;
scanHitCount = 0;
gScanUseCssResult = false;
g_CxCSS_TAIL_Found = false;
g_CDCSS_Lost = false;
@@ -418,242 +364,165 @@ void SCANNER_Start(void)
g_VOX_Lost = false;
#endif
g_SquelchLost = false;
gScannerEditState = 0;
gScannerSaveState = SCAN_SAVE_NO_PROMPT;
gScanProgressIndicator = 0;
}
void SCANNER_Found()
{
switch (gEeprom.SCAN_RESUME_MODE)
{
case SCAN_RESUME_TO:
if (!gScanPauseMode)
{
gScanPauseDelayIn_10ms = scan_pause_delay_in_1_10ms;
gScheduleScanListen = false;
gScanPauseMode = true;
}
break;
case SCAN_RESUME_CO:
case SCAN_RESUME_SE:
gScanPauseDelayIn_10ms = 0;
gScheduleScanListen = false;
break;
}
if (IS_MR_CHANNEL(gRxVfo->CHANNEL_SAVE)) { //memory scan
lastFoundFrqOrChan = gRxVfo->CHANNEL_SAVE;
}
else { // frequency scan
lastFoundFrqOrChan = gRxVfo->freq_config_RX.Frequency;
}
gScanKeepResult = true;
}
void SCANNER_Stop(void)
{
if(initialCROSS_BAND_RX_TX != CROSS_BAND_OFF) {
gEeprom.CROSS_BAND_RX_TX = initialCROSS_BAND_RX_TX;
initialCROSS_BAND_RX_TX = CROSS_BAND_OFF;
if(SCANNER_IsScanning()) {
gEeprom.CROSS_BAND_RX_TX = gBackup_CROSS_BAND_RX_TX;
gVfoConfigureMode = VFO_CONFIGURE_RELOAD;
gFlagResetVfos = true;
gUpdateStatus = true;
gCssBackgroundScan = false;
gScanUseCssResult = false;
#ifdef ENABLE_VOICE
gAnotherVoiceID = VOICE_ID_CANCEL;
#endif
BK4819_StopScan();
}
gScanStateDir = SCAN_OFF;
}
const uint32_t chFr = gScanKeepResult ? lastFoundFrqOrChan : initialFrqOrChan;
const bool channelChanged = chFr != initialFrqOrChan;
if (IS_MR_CHANNEL(gNextMrChannel)) {
gEeprom.MrChannel[gEeprom.RX_VFO] = chFr;
gEeprom.ScreenChannel[gEeprom.RX_VFO] = chFr;
RADIO_ConfigureChannel(gEeprom.RX_VFO, VFO_CONFIGURE_RELOAD);
void SCANNER_TimeSlice10ms(void)
{
if (!SCANNER_IsScanning())
return;
if (gScanDelay_10ms > 0) {
gScanDelay_10ms--;
return;
}
if (gScannerSaveState != SCAN_SAVE_NO_PROMPT) {
return;
}
switch (gScanCssState) {
case SCAN_CSS_STATE_OFF: {
// must be RF frequency scanning if we're here ?
uint32_t result;
if (!BK4819_GetFrequencyScanResult(&result))
break;
int32_t delta = result - gScanFrequency;
gScanFrequency = result;
if (delta < 0)
delta = -delta;
if (delta < 100)
scanHitCount++;
else
scanHitCount = 0;
BK4819_DisableFrequencyScan();
if (scanHitCount < 3) {
BK4819_EnableFrequencyScan();
}
else {
BK4819_SetScanFrequency(gScanFrequency);
gScanCssResultCode = 0xFF;
gScanCssResultType = 0xFF;
scanHitCount = 0;
gScanUseCssResult = false;
gScanProgressIndicator = 0;
gScanCssState = SCAN_CSS_STATE_SCANNING;
if(!gCssBackgroundScan)
GUI_SelectNextDisplay(DISPLAY_SCANNER);
gUpdateStatus = true;
}
gScanDelay_10ms = scan_delay_10ms;
//gScanDelay_10ms = 1; // 10ms
break;
}
case SCAN_CSS_STATE_SCANNING: {
uint32_t cdcssFreq;
uint16_t ctcssFreq;
BK4819_CssScanResult_t scanResult = BK4819_GetCxCSSScanResult(&cdcssFreq, &ctcssFreq);
if (scanResult == BK4819_CSS_RESULT_NOT_FOUND)
break;
BK4819_Disable();
if (scanResult == BK4819_CSS_RESULT_CDCSS) {
const uint8_t Code = DCS_GetCdcssCode(cdcssFreq);
if (Code != 0xFF)
{
gScanCssResultCode = Code;
gScanCssResultType = CODE_TYPE_DIGITAL;
gScanCssState = SCAN_CSS_STATE_FOUND;
gScanUseCssResult = true;
gUpdateStatus = true;
}
}
else if (scanResult == BK4819_CSS_RESULT_CTCSS) {
const uint8_t Code = DCS_GetCtcssCode(ctcssFreq);
if (Code != 0xFF) {
if (Code == gScanCssResultCode && gScanCssResultType == CODE_TYPE_CONTINUOUS_TONE) {
if (++scanHitCount >= 2) {
gScanCssState = SCAN_CSS_STATE_FOUND;
gScanUseCssResult = true;
gUpdateStatus = true;
}
}
else
scanHitCount = 0;
gScanCssResultType = CODE_TYPE_CONTINUOUS_TONE;
gScanCssResultCode = Code;
}
}
if (gScanCssState < SCAN_CSS_STATE_FOUND) { // scanning or off
BK4819_SetScanFrequency(gScanFrequency);
gScanDelay_10ms = scan_delay_10ms;
break;
}
if(gCssBackgroundScan) {
gCssBackgroundScan = false;
if(gScanUseCssResult)
MENU_CssScanFound();
}
else
GUI_SelectNextDisplay(DISPLAY_SCANNER);
break;
}
default:
gCssBackgroundScan = false;
break;
}
}
void SCANNER_TimeSlice500ms(void)
{
if (SCANNER_IsScanning() && gScannerSaveState == SCAN_SAVE_NO_PROMPT && gScanCssState < SCAN_CSS_STATE_FOUND) {
gScanProgressIndicator++;
#ifndef ENABLE_NO_CODE_SCAN_TIMEOUT
if (gScanProgressIndicator > 32) {
if (gScanCssState == SCAN_CSS_STATE_SCANNING && !gScanSingleFrequency)
gScanCssState = SCAN_CSS_STATE_FOUND;
else
gScanCssState = SCAN_CSS_STATE_FAILED;
if(channelChanged) {
SETTINGS_SaveVfoIndices();
gUpdateStatus = true;
}
}
else {
gRxVfo->freq_config_RX.Frequency = chFr;
RADIO_ApplyOffset(gRxVfo);
RADIO_ConfigureSquelchAndOutputPower(gRxVfo);
if(channelChanged) {
SETTINGS_SaveChannel(gRxVfo->CHANNEL_SAVE, gEeprom.RX_VFO, gRxVfo, 1);
}
}
RADIO_SetupRegisters(true);
gUpdateDisplay = true;
}
static void NextFreqChannel(void)
{
gRxVfo->freq_config_RX.Frequency = APP_SetFrequencyByStep(gRxVfo, gScanStateDir);
RADIO_ApplyOffset(gRxVfo);
RADIO_ConfigureSquelchAndOutputPower(gRxVfo);
RADIO_SetupRegisters(true);
#ifdef ENABLE_FASTER_CHANNEL_SCAN
gScanPauseDelayIn_10ms = 9; // 90ms
#else
gScanPauseDelayIn_10ms = scan_pause_delay_in_6_10ms;
#endif
gUpdateDisplay = true;
}
static void NextMemChannel(void)
{
static unsigned int prev_mr_chan = 0;
const bool enabled = (gEeprom.SCAN_LIST_DEFAULT < 2) ? gEeprom.SCAN_LIST_ENABLED[gEeprom.SCAN_LIST_DEFAULT] : true;
const int chan1 = (gEeprom.SCAN_LIST_DEFAULT < 2) ? gEeprom.SCANLIST_PRIORITY_CH1[gEeprom.SCAN_LIST_DEFAULT] : -1;
const int chan2 = (gEeprom.SCAN_LIST_DEFAULT < 2) ? gEeprom.SCANLIST_PRIORITY_CH2[gEeprom.SCAN_LIST_DEFAULT] : -1;
const unsigned int prev_chan = gNextMrChannel;
unsigned int chan = 0;
if (enabled)
{
switch (currentScanList)
{
case SCAN_NEXT_CHAN_SCANLIST1:
prev_mr_chan = gNextMrChannel;
if (chan1 >= 0)
{
if (RADIO_CheckValidChannel(chan1, false, 0))
{
currentScanList = SCAN_NEXT_CHAN_SCANLIST1;
gNextMrChannel = chan1;
break;
}
}
[[fallthrough]];
case SCAN_NEXT_CHAN_SCANLIST2:
if (chan2 >= 0)
{
if (RADIO_CheckValidChannel(chan2, false, 0))
{
currentScanList = SCAN_NEXT_CHAN_SCANLIST2;
gNextMrChannel = chan2;
break;
}
}
[[fallthrough]];
// this bit doesn't yet work if the other VFO is a frequency
case SCAN_NEXT_CHAN_DUAL_WATCH:
// dual watch is enabled - include the other VFO in the scan
// if (gEeprom.DUAL_WATCH != DUAL_WATCH_OFF)
// {
// chan = (gEeprom.RX_VFO + 1) & 1u;
// chan = gEeprom.ScreenChannel[chan];
// if (IS_MR_CHANNEL(chan))
// {
// currentScanList = SCAN_NEXT_CHAN_DUAL_WATCH;
// gNextMrChannel = chan;
// break;
// }
// }
default:
case SCAN_NEXT_CHAN_MR:
currentScanList = SCAN_NEXT_CHAN_MR;
gNextMrChannel = prev_mr_chan;
chan = 0xff;
break;
}
}
if (!enabled || chan == 0xff)
{
chan = RADIO_FindNextChannel(gNextMrChannel + gScanStateDir, gScanStateDir, (gEeprom.SCAN_LIST_DEFAULT < 2) ? true : false, gEeprom.SCAN_LIST_DEFAULT);
if (chan == 0xFF)
{ // no valid channel found
chan = MR_CHANNEL_FIRST;
}
gNextMrChannel = chan;
}
if (gNextMrChannel != prev_chan)
{
gEeprom.MrChannel[ gEeprom.RX_VFO] = gNextMrChannel;
gEeprom.ScreenChannel[gEeprom.RX_VFO] = gNextMrChannel;
RADIO_ConfigureChannel(gEeprom.RX_VFO, VFO_CONFIGURE_RELOAD);
RADIO_SetupRegisters(true);
gUpdateDisplay = true;
}
#ifdef ENABLE_FASTER_CHANNEL_SCAN
gScanPauseDelayIn_10ms = 9; // 90ms .. <= ~60ms it misses signals (squelch response and/or PLL lock time) ?
#else
gScanPauseDelayIn_10ms = scan_pause_delay_in_3_10ms;
#endif
if (enabled)
if (++currentScanList >= SCAN_NEXT_NUM)
currentScanList = SCAN_NEXT_CHAN_SCANLIST1; // back round we go
else if(gCssBackgroundScan) {
gUpdateDisplay = true;
}
}
void SCANNER_ScanChannels(const bool storeBackupSettings, const int8_t scan_direction)
bool SCANNER_IsScanning(void)
{
if (storeBackupSettings) {
initialCROSS_BAND_RX_TX = gEeprom.CROSS_BAND_RX_TX;
gEeprom.CROSS_BAND_RX_TX = CROSS_BAND_OFF;
gScanKeepResult = false;
}
RADIO_SelectVfos();
gNextMrChannel = gRxVfo->CHANNEL_SAVE;
currentScanList = SCAN_NEXT_CHAN_SCANLIST1;
gScanStateDir = scan_direction;
if (IS_MR_CHANNEL(gNextMrChannel))
{ // channel mode
if (storeBackupSettings) {
initialFrqOrChan = gRxVfo->CHANNEL_SAVE;
lastFoundFrqOrChan = initialFrqOrChan;
}
NextMemChannel();
}
else
{ // frequency mode
if (storeBackupSettings) {
initialFrqOrChan = gRxVfo->freq_config_RX.Frequency;
lastFoundFrqOrChan = initialFrqOrChan;
}
NextFreqChannel();
}
gScanPauseDelayIn_10ms = scan_pause_delay_in_2_10ms;
gScheduleScanListen = false;
gRxReceptionMode = RX_MODE_NONE;
gScanPauseMode = false;
}
void SCANNER_ContinueScanning()
{
if (IS_FREQ_CHANNEL(gNextMrChannel))
{
if (gCurrentFunction == FUNCTION_INCOMING)
APP_StartListening(gMonitor ? FUNCTION_MONITOR : FUNCTION_RECEIVE, true);
else
NextFreqChannel(); // switch to next frequency
}
else
{
if (gCurrentCodeType == CODE_TYPE_OFF && gCurrentFunction == FUNCTION_INCOMING)
APP_StartListening(gMonitor ? FUNCTION_MONITOR : FUNCTION_RECEIVE, true);
else
NextMemChannel(); // switch to next channel
}
gScanPauseMode = false;
gRxReceptionMode = RX_MODE_NONE;
gScheduleScanListen = false;
return gCssBackgroundScan || (gScreenToDisplay == DISPLAY_SCANNER);
}

View File

@@ -20,50 +20,38 @@
#include "dcs.h"
#include "driver/keyboard.h"
enum SCAN_CssState_t
typedef enum
{
SCAN_CSS_STATE_OFF = 0,
SCAN_CSS_STATE_OFF,
SCAN_CSS_STATE_SCANNING,
SCAN_CSS_STATE_FOUND,
SCAN_CSS_STATE_FAILED
};
} SCAN_CssState_t;
typedef enum SCAN_CssState_t SCAN_CssState_t;
enum
typedef enum
{
SCAN_REV = -1,
SCAN_OFF = 0,
SCAN_FWD = +1
};
SCAN_SAVE_NO_PROMPT, // saving process not initiated
SCAN_SAVE_CHAN_SEL, // "SAVE: ", channel select prompt, actives only in channel mode
SCAN_SAVE_CHANNEL, // "SAVE?" prompt, waits for confirmation to save settings to channel, or current VFO
} SCAN_SaveState_t;
extern DCS_CodeType_t gScanCssResultType;
extern uint8_t gScanCssResultCode;
extern bool gFlagStartScan;
extern bool gFlagStopScan;
extern bool gScanSingleFrequency;
extern uint8_t gScannerEditState;
extern SCAN_SaveState_t gScannerSaveState;
extern uint8_t gScanChannel;
extern uint32_t gScanFrequency;
extern bool gScanPauseMode;
extern SCAN_CssState_t gScanCssState;
extern volatile bool gScheduleScanListen;
extern volatile uint16_t gScanPauseDelayIn_10ms;
extern uint8_t gScanProgressIndicator;
extern uint8_t gScanHitCount;
extern bool gScanUseCssResult;
// scan direction, if not equal SCAN_OFF indicates
// that we are in a process of scanning channels/frequencies
extern int8_t gScanStateDir;
extern bool gScanKeepResult;
void SCANNER_ProcessKeys(KEY_Code_t Key, bool bKeyPressed, bool bKeyHeld);
void SCANNER_Start(void);
void SCANNER_Found();
void SCANNER_Start(bool singleFreq);
void SCANNER_Stop(void);
void SCANNER_ScanChannels(const bool storeBackupSettings, const int8_t scan_direction);
void SCANNER_ContinueScanning();
void SCANNER_TimeSlice10ms(void);
void SCANNER_TimeSlice500ms(void);
bool SCANNER_IsScanning(void);
#endif

View File

@@ -13,23 +13,31 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "app/spectrum.h"
#include "driver/backlight.h"
#include "am_fix.h"
#include "audio.h"
#include "misc.h"
#ifdef ENABLE_SCAN_RANGES
#include "chFrScanner.h"
#endif
#include "driver/backlight.h"
#include "frequencies.h"
#include "ui/helper.h"
#include "ui/main.h"
struct FrequencyBandInfo {
uint32_t lower;
uint32_t upper;
uint32_t middle;
uint32_t lower;
uint32_t upper;
uint32_t middle;
};
#define F_MIN frequencyBandTable[0].lower
#define F_MAX frequencyBandTable[ARRAY_SIZE(frequencyBandTable) - 1].upper
#define F_MAX frequencyBandTable[BAND_N_ELEM - 1].upper
const uint16_t RSSI_MAX_VALUE = 65535;
static uint16_t R30, R37, R3D, R43, R47, R48, R7E;
static uint32_t initialFreq;
static char String[32];
@@ -41,6 +49,7 @@ bool redrawScreen = false;
bool newScanStart = true;
bool preventKeypress = true;
bool audioState = true;
bool lockAGC = false;
State currentState = SPECTRUM, previousState = SPECTRUM;
@@ -48,26 +57,31 @@ PeakInfo peak;
ScanInfo scanInfo;
KeyboardState kbd = {KEY_INVALID, KEY_INVALID, 0};
#ifdef ENABLE_SCAN_RANGES
static uint16_t blacklistFreqs[15];
static uint8_t blacklistFreqsIdx;
#endif
const char *bwOptions[] = {" 25k", "12.5k", "6.25k"};
const uint8_t modulationTypeTuneSteps[] = {100, 50, 10};
const uint8_t modTypeReg47Values[] = {1, 7, 5};
SpectrumSettings settings = {stepsCount: STEPS_64,
scanStepIndex: S_STEP_25_0kHz,
frequencyChangeStep: 80000,
scanDelay: 3200,
rssiTriggerLevel: 150,
backlightState: true,
bw: BK4819_FILTER_BW_WIDE,
listenBw: BK4819_FILTER_BW_WIDE,
modulationType: false,
dbMin: -130,
dbMax: -50};
SpectrumSettings settings = {.stepsCount = STEPS_64,
.scanStepIndex = S_STEP_25_0kHz,
.frequencyChangeStep = 80000,
.scanDelay = 3200,
.rssiTriggerLevel = 150,
.backlightState = true,
.bw = BK4819_FILTER_BW_WIDE,
.listenBw = BK4819_FILTER_BW_WIDE,
.modulationType = false,
.dbMin = -130,
.dbMax = -50};
uint32_t fMeasure = 0;
uint32_t currentFreq, tempFreq;
uint16_t rssiHistory[128];
int vfo;
uint8_t freqInputIndex = 0;
uint8_t freqInputDotIndex = 0;
KEY_Code_t freqInputArr[10];
@@ -98,17 +112,28 @@ static uint8_t DBm2S(int dbm) {
return i;
}
static int Rssi2DBm(uint16_t rssi) { return (rssi >> 1) - 160; }
static int Rssi2DBm(uint16_t rssi) {
return (rssi / 2) - 160 + dBmCorrTable[gRxVfo->Band];
}
static uint16_t GetRegMenuValue(uint8_t st) {
RegisterSpec s = registerSpecs[st];
return (BK4819_ReadRegister(s.num) >> s.offset) & s.mask;
}
void LockAGC()
{
RADIO_SetupAGC(settings.modulationType==MODULATION_AM, lockAGC);
lockAGC = true;
}
static void SetRegMenuValue(uint8_t st, bool add) {
uint16_t v = GetRegMenuValue(st);
RegisterSpec s = registerSpecs[st];
if(s.num == BK4819_REG_13)
LockAGC();
uint16_t reg = BK4819_ReadRegister(s.num);
if (add && v <= s.mask - s.inc) {
v += s.inc;
@@ -125,21 +150,13 @@ static void SetRegMenuValue(uint8_t st, bool add) {
// GUI functions
static void PutPixel(uint8_t x, uint8_t y, bool fill) {
if (fill) {
gFrameBuffer[y >> 3][x] |= 1 << (y & 7);
} else {
gFrameBuffer[y >> 3][x] &= ~(1 << (y & 7));
}
UI_DrawPixelBuffer(gFrameBuffer, x, y, fill);
}
static void PutPixelStatus(uint8_t x, uint8_t y, bool fill) {
if (fill) {
gStatusLine[x] |= 1 << y;
} else {
gStatusLine[x] &= ~(1 << y);
}
UI_DrawPixelBuffer(&gStatusLine, x, y, fill);
}
static void DrawHLine(int sy, int ey, int nx, bool fill) {
static void DrawVLine(int sy, int ey, int nx, bool fill) {
for (int i = sy; i <= ey; i++) {
if (i < 56 && nx < 128) {
PutPixel(nx, i, fill);
@@ -204,24 +221,29 @@ static void ToggleAFBit(bool on) {
BK4819_WriteRegister(BK4819_REG_47, reg);
}
static const BK4819_REGISTER_t registers_to_save[] ={
BK4819_REG_30,
BK4819_REG_37,
BK4819_REG_3D,
BK4819_REG_43,
BK4819_REG_47,
BK4819_REG_48,
BK4819_REG_7E,
};
static uint16_t registers_stack [sizeof(registers_to_save)];
static void BackupRegisters() {
R30 = BK4819_ReadRegister(BK4819_REG_30);
R37 = BK4819_ReadRegister(BK4819_REG_37);
R3D = BK4819_ReadRegister(BK4819_REG_3D);
R43 = BK4819_ReadRegister(BK4819_REG_43);
R47 = BK4819_ReadRegister(BK4819_REG_47);
R48 = BK4819_ReadRegister(BK4819_REG_48);
R7E = BK4819_ReadRegister(BK4819_REG_7E);
for (uint32_t i = 0; i < ARRAY_SIZE(registers_to_save); i++){
registers_stack[i] = BK4819_ReadRegister(registers_to_save[i]);
}
}
static void RestoreRegisters() {
BK4819_WriteRegister(BK4819_REG_30, R30);
BK4819_WriteRegister(BK4819_REG_37, R37);
BK4819_WriteRegister(BK4819_REG_3D, R3D);
BK4819_WriteRegister(BK4819_REG_43, R43);
BK4819_WriteRegister(BK4819_REG_47, R47);
BK4819_WriteRegister(BK4819_REG_48, R48);
BK4819_WriteRegister(BK4819_REG_7E, R7E);
for (uint32_t i = 0; i < ARRAY_SIZE(registers_to_save); i++){
BK4819_WriteRegister(registers_to_save[i], registers_stack[i]);
}
}
static void ToggleAFDAC(bool on) {
@@ -252,12 +274,24 @@ static void ResetPeak() {
}
bool IsCenterMode() { return settings.scanStepIndex < S_STEP_2_5kHz; }
uint8_t GetStepsCount() { return 128 >> settings.stepsCount; }
// scan step in 0.01khz
uint16_t GetScanStep() { return scanStepValues[settings.scanStepIndex]; }
uint16_t GetStepsCount()
{
#ifdef ENABLE_SCAN_RANGES
if(gScanRangeStart) {
return (gScanRangeStop - gScanRangeStart) / GetScanStep();
}
#endif
return 128 >> settings.stepsCount;
}
uint32_t GetBW() { return GetStepsCount() * GetScanStep(); }
uint32_t GetFStart() {
return IsCenterMode() ? currentFreq - (GetBW() >> 1) : currentFreq;
}
uint32_t GetFEnd() { return currentFreq + GetBW(); }
static void TuneToPeak() {
@@ -283,7 +317,12 @@ uint16_t GetRssi() {
while ((BK4819_ReadRegister(0x63) & 0b11111111) >= 255) {
SYSTICK_DelayUs(100);
}
return BK4819_GetRSSI();
uint16_t rssi = BK4819_GetRSSI();
#ifdef ENABLE_AM_FIX
if(settings.modulationType==MODULATION_AM && gSetting_AM_fix)
rssi += AM_fix_get_gain_diff()*2;
#endif
return rssi;
}
static void ToggleAudio(bool on) {
@@ -301,6 +340,7 @@ static void ToggleAudio(bool on) {
static void ToggleRX(bool on) {
isListening = on;
RADIO_SetupAGC(on, lockAGC);
BK4819_ToggleGpioOut(BK4819_GPIO6_PIN2_GREEN, on);
ToggleAudio(on);
@@ -338,6 +378,10 @@ static void ResetBlacklist() {
if (rssiHistory[i] == RSSI_MAX_VALUE)
rssiHistory[i] = 0;
}
#ifdef ENABLE_SCAN_RANGES
memset(blacklistFreqs, 0, sizeof(blacklistFreqs));
blacklistFreqsIdx = 0;
#endif
}
static void RelaunchScan() {
@@ -384,25 +428,43 @@ static void UpdatePeakInfo() {
UpdatePeakInfoForce();
}
static void Measure() { rssiHistory[scanInfo.i] = scanInfo.rssi = GetRssi(); }
static void SetRssiHistory(uint16_t idx, uint16_t rssi)
{
#ifdef ENABLE_SCAN_RANGES
if(scanInfo.measurementsCount > 128) {
uint8_t i = (uint32_t)ARRAY_SIZE(rssiHistory) * 1000 / scanInfo.measurementsCount * idx / 1000;
if(rssiHistory[i] < rssi || isListening)
rssiHistory[i] = rssi;
rssiHistory[(i+1)%128] = 0;
return;
}
#endif
rssiHistory[idx] = rssi;
}
static void Measure()
{
uint16_t rssi = scanInfo.rssi = GetRssi();
SetRssiHistory(scanInfo.i, rssi);
}
// Update things by keypress
static uint16_t dbm2rssi(int dBm)
{
return (dBm + 160)*2;
static uint16_t dbm2rssi(int dBm) {
return (dBm + 160 - dBmCorrTable[gRxVfo->Band]) * 2;
}
static void ClampRssiTriggerLevel()
{
settings.rssiTriggerLevel = clamp(settings.rssiTriggerLevel, dbm2rssi(settings.dbMin), dbm2rssi(settings.dbMax));
static void ClampRssiTriggerLevel() {
settings.rssiTriggerLevel =
clamp(settings.rssiTriggerLevel, dbm2rssi(settings.dbMin),
dbm2rssi(settings.dbMax));
}
static void UpdateRssiTriggerLevel(bool inc) {
if (inc)
settings.rssiTriggerLevel += 2;
settings.rssiTriggerLevel += 2;
else
settings.rssiTriggerLevel -= 2;
settings.rssiTriggerLevel -= 2;
ClampRssiTriggerLevel();
@@ -413,7 +475,7 @@ static void UpdateRssiTriggerLevel(bool inc) {
static void UpdateDBMax(bool inc) {
if (inc && settings.dbMax < 10) {
settings.dbMax += 1;
} else if (!inc && settings.dbMax > settings.dbMin) {
} else if (!inc && settings.dbMax > 12+settings.dbMin) {
settings.dbMax -= 1;
} else {
return;
@@ -426,13 +488,12 @@ static void UpdateDBMax(bool inc) {
}
static void UpdateScanStep(bool inc) {
if (inc && settings.scanStepIndex < S_STEP_100_0kHz) {
settings.scanStepIndex++;
} else if (!inc && settings.scanStepIndex > 0) {
settings.scanStepIndex--;
if (inc) {
settings.scanStepIndex = settings.scanStepIndex != S_STEP_100_0kHz ? settings.scanStepIndex + 1 : 0;
} else {
return;
settings.scanStepIndex = settings.scanStepIndex != 0 ? settings.scanStepIndex - 1 : S_STEP_100_0kHz;
}
settings.frequencyChangeStep = GetBW() >> 1;
RelaunchScan();
ResetBlacklist();
@@ -482,6 +543,8 @@ static void ToggleModulation() {
settings.modulationType = MODULATION_FM;
}
RADIO_SetModulation(settings.modulationType);
RelaunchScan();
redrawScreen = true;
}
@@ -541,6 +604,8 @@ static void UpdateFreqInput(KEY_Code_t key) {
}
if (key == KEY_EXIT) {
freqInputIndex--;
if (freqInputDotIndex == freqInputIndex)
freqInputDotIndex = 0;
} else {
freqInputArr[freqInputIndex++] = key;
}
@@ -554,7 +619,7 @@ static void UpdateFreqInput(KEY_Code_t key) {
for (int i = 0; i < 10; ++i) {
if (i < freqInputIndex) {
digitKey = freqInputArr[i];
freqInputString[i] = digitKey <= KEY_9 ? '0' + digitKey-KEY_0 : '.';
freqInputString[i] = digitKey <= KEY_9 ? '0' + digitKey - KEY_0 : '.';
} else {
freqInputString[i] = '-';
}
@@ -562,14 +627,14 @@ static void UpdateFreqInput(KEY_Code_t key) {
uint32_t base = 100000; // 1MHz in BK units
for (int i = dotIndex - 1; i >= 0; --i) {
tempFreq += (freqInputArr[i]-KEY_0) * base;
tempFreq += (freqInputArr[i] - KEY_0) * base;
base *= 10;
}
base = 10000; // 0.1MHz in BK units
if (dotIndex < freqInputIndex) {
for (int i = dotIndex + 1; i < freqInputIndex; ++i) {
tempFreq += (freqInputArr[i]-KEY_0) * base;
tempFreq += (freqInputArr[i] - KEY_0) * base;
base /= 10;
}
}
@@ -577,12 +642,26 @@ static void UpdateFreqInput(KEY_Code_t key) {
}
static void Blacklist() {
rssiHistory[peak.i] = RSSI_MAX_VALUE;
#ifdef ENABLE_SCAN_RANGES
blacklistFreqs[blacklistFreqsIdx++ % ARRAY_SIZE(blacklistFreqs)] = peak.i;
#endif
SetRssiHistory(peak.i, RSSI_MAX_VALUE);
ResetPeak();
ToggleRX(false);
newScanStart = true;
ResetScanStats();
}
#ifdef ENABLE_SCAN_RANGES
static bool IsBlacklisted(uint16_t idx)
{
for(uint8_t i = 0; i < ARRAY_SIZE(blacklistFreqs); i++)
if(blacklistFreqs[i] == idx)
return true;
return false;
}
#endif
// Draw things
// applied x2 to prevent initial rounding
@@ -593,7 +672,7 @@ uint8_t Rssi2PX(uint16_t rssi, uint8_t pxMin, uint8_t pxMax) {
const uint8_t PX_RANGE = pxMax - pxMin;
int dbm = clamp(rssi - (160 << 1), DB_MIN, DB_MAX);
int dbm = clamp(Rssi2DBm(rssi) << 1, DB_MIN, DB_MAX);
return ((dbm - DB_MIN) * PX_RANGE + DB_RANGE / 2) / DB_RANGE + pxMin;
}
@@ -606,7 +685,7 @@ static void DrawSpectrum() {
for (uint8_t x = 0; x < 128; ++x) {
uint16_t rssi = rssiHistory[x >> settings.stepsCount];
if (rssi != RSSI_MAX_VALUE) {
DrawHLine(Rssi2Y(rssi), DrawingEndY, x, true);
DrawVLine(Rssi2Y(rssi), DrawingEndY, x, true);
}
}
}
@@ -620,41 +699,34 @@ static void DrawStatus() {
#endif
GUI_DisplaySmallest(String, 0, 1, true, true);
for (int i = 0; i < 4; i++) {
BOARD_ADC_GetBatteryInfo(&gBatteryVoltages[i], &gBatteryCurrent);
BOARD_ADC_GetBatteryInfo(&gBatteryVoltages[gBatteryCheckCounter++ % 4],
&gBatteryCurrent);
uint16_t voltage = (gBatteryVoltages[0] + gBatteryVoltages[1] +
gBatteryVoltages[2] + gBatteryVoltages[3]) /
4 * 760 / gBatteryCalibration[3];
unsigned perc = BATTERY_VoltsToPercent(voltage);
// sprintf(String, "%d %d", voltage, perc);
// GUI_DisplaySmallest(String, 48, 1, true, true);
gStatusLine[116] = 0b00011100;
gStatusLine[117] = 0b00111110;
for (int i = 118; i <= 126; i++) {
gStatusLine[i] = 0b00100010;
}
uint16_t Voltage;
uint8_t v = 0;
Voltage = (gBatteryVoltages[0] + gBatteryVoltages[1] + gBatteryVoltages[2] +
gBatteryVoltages[3]) /
4;
for(uint8_t i = 5; i > 0; i--) {
if(Voltage > gBatteryCalibration[i - 1]) {
v = i;
break;
}
}
gStatusLine[127] = 0b01111110;
for (int i = 126; i >= 116; i--) {
gStatusLine[i] = 0b01000010;
}
v <<= 1;
for (int i = 125; i >= 116; i--) {
if (126 - i <= v) {
gStatusLine[i + 2] = 0b01111110;
for (unsigned i = 127; i >= 118; i--) {
if (127 - i <= (perc + 5) * 9 / 100) {
gStatusLine[i] = 0b00111110;
}
}
gStatusLine[117] = 0b01111110;
gStatusLine[116] = 0b00011000;
}
static void DrawF(uint32_t f) {
sprintf(String, "%u.%05u", f / 100000, f % 100000);
UI_PrintStringSmall(String, 8, 127, 0);
UI_PrintStringSmallNormal(String, 8, 127, 0);
sprintf(String, "%3s", gModulationStr[settings.modulationType]);
GUI_DisplaySmallest(String, 116, 1, false, true);
@@ -699,9 +771,11 @@ static void DrawRssiTriggerLevel() {
}
static void DrawTicks() {
uint32_t f = GetFStart() % 100000;
uint32_t step = GetScanStep();
for (uint8_t i = 0; i < 128; i += (1 << settings.stepsCount), f += step) {
uint32_t f = GetFStart();
uint32_t span = GetFEnd() - GetFStart();
uint32_t step = span / 128;
for (uint8_t i = 0; i < 128; i += (1 << settings.stepsCount)) {
f = GetFStart() + span * i / 128;
uint8_t barValue = 0b00000001;
(f % 10000) < step && (barValue |= 0b00000010);
(f % 50000) < step && (barValue |= 0b00000100);
@@ -712,19 +786,13 @@ static void DrawTicks() {
// center
if (IsCenterMode()) {
gFrameBuffer[5][62] = 0x80;
gFrameBuffer[5][63] = 0x80;
memset(gFrameBuffer[5] + 62, 0x80, 5);
gFrameBuffer[5][64] = 0xff;
gFrameBuffer[5][65] = 0x80;
gFrameBuffer[5][66] = 0x80;
} else {
memset(gFrameBuffer[5] + 1, 0x80, 3);
memset(gFrameBuffer[5] + 124, 0x80, 3);
gFrameBuffer[5][0] = 0xff;
gFrameBuffer[5][1] = 0x80;
gFrameBuffer[5][2] = 0x80;
gFrameBuffer[5][3] = 0x80;
gFrameBuffer[5][124] = 0x80;
gFrameBuffer[5][125] = 0x80;
gFrameBuffer[5][126] = 0x80;
gFrameBuffer[5][127] = 0xff;
}
}
@@ -759,10 +827,16 @@ static void OnKeyDown(uint8_t key) {
UpdateFreqChangeStep(false);
break;
case KEY_UP:
UpdateCurrentFreq(true);
#ifdef ENABLE_SCAN_RANGES
if(!gScanRangeStart)
#endif
UpdateCurrentFreq(true);
break;
case KEY_DOWN:
UpdateCurrentFreq(false);
#ifdef ENABLE_SCAN_RANGES
if(!gScanRangeStart)
#endif
UpdateCurrentFreq(false);
break;
case KEY_SIDE1:
Blacklist();
@@ -774,7 +848,10 @@ static void OnKeyDown(uint8_t key) {
UpdateRssiTriggerLevel(false);
break;
case KEY_5:
FreqInput();
#ifdef ENABLE_SCAN_RANGES
if(!gScanRangeStart)
#endif
FreqInput();
break;
case KEY_0:
ToggleModulation();
@@ -783,7 +860,10 @@ static void OnKeyDown(uint8_t key) {
ToggleListeningBW();
break;
case KEY_4:
ToggleStepsCount();
#ifdef ENABLE_SCAN_RANGES
if(!gScanRangeStart)
#endif
ToggleStepsCount();
break;
case KEY_SIDE2:
ToggleBacklight();
@@ -905,6 +985,7 @@ void OnKeyDownStill(KEY_Code_t key) {
case KEY_EXIT:
if (!menuState) {
SetState(SPECTRUM);
lockAGC = false;
monitorMode = false;
RelaunchScan();
break;
@@ -916,9 +997,7 @@ void OnKeyDownStill(KEY_Code_t key) {
}
}
static void RenderFreqInput() {
UI_PrintString(freqInputString, 2, 127, 0, 8);
}
static void RenderFreqInput() { UI_PrintString(freqInputString, 2, 127, 0, 8); }
static void RenderStatus() {
memset(gStatusLine, 0, sizeof(gStatusLine));
@@ -928,7 +1007,7 @@ static void RenderStatus() {
static void RenderSpectrum() {
DrawTicks();
DrawArrow(peak.i << settings.stepsCount);
DrawArrow(128u * peak.i / GetStepsCount());
DrawSpectrum();
DrawRssiTriggerLevel();
DrawF(peak.f);
@@ -940,14 +1019,14 @@ static void RenderStill() {
const uint8_t METER_PAD_LEFT = 3;
for (int i = 0; i < 121; i++) {
if (i % 10 == 0) {
gFrameBuffer[2][i + METER_PAD_LEFT] = 0b01110000;
} else if (i % 5 == 0) {
gFrameBuffer[2][i + METER_PAD_LEFT] = 0b00110000;
} else {
gFrameBuffer[2][i + METER_PAD_LEFT] = 0b00010000;
}
memset(&gFrameBuffer[2][METER_PAD_LEFT], 0b00010000, 121);
for (int i = 0; i < 121; i+=5) {
gFrameBuffer[2][i + METER_PAD_LEFT] = 0b00110000;
}
for (int i = 0; i < 121; i+=10) {
gFrameBuffer[2][i + METER_PAD_LEFT] = 0b01110000;
}
uint8_t x = Rssi2PX(scanInfo.rssi, 0, 121);
@@ -996,7 +1075,7 @@ static void RenderStill() {
}
static void Render() {
memset(gFrameBuffer, 0, sizeof(gFrameBuffer));
UI_DisplayClear();
switch (currentState) {
case SPECTRUM:
@@ -1017,17 +1096,17 @@ bool HandleUserInput() {
kbd.prev = kbd.current;
kbd.current = GetKey();
if (kbd.current == KEY_INVALID) {
kbd.counter = 0;
return true;
}
if (kbd.current == kbd.prev && kbd.counter <= 16) {
kbd.counter++;
if (kbd.current != KEY_INVALID && kbd.current == kbd.prev) {
if (kbd.counter < 16)
kbd.counter++;
else
kbd.counter -= 3;
SYSTEM_DelayMs(20);
} else {
kbd.counter = 0;
}
if (kbd.counter == 3 || kbd.counter > 16) {
if (kbd.counter == 3 || kbd.counter == 16) {
switch (currentState) {
case SPECTRUM:
OnKeyDown(kbd.current);
@@ -1045,7 +1124,11 @@ bool HandleUserInput() {
}
static void Scan() {
if (rssiHistory[scanInfo.i] != RSSI_MAX_VALUE) {
if (rssiHistory[scanInfo.i] != RSSI_MAX_VALUE
#ifdef ENABLE_SCAN_RANGES
&& !IsBlacklisted(scanInfo.i)
#endif
) {
SetF(scanInfo.f);
Measure();
UpdateScanInfo();
@@ -1066,6 +1149,10 @@ static void UpdateScan() {
return;
}
if(scanInfo.measurementsCount < 128)
memset(&rssiHistory[scanInfo.measurementsCount], 0,
sizeof(rssiHistory) - scanInfo.measurementsCount*sizeof(rssiHistory[0]));
redrawScreen = true;
preventKeypress = false;
@@ -1118,10 +1205,39 @@ static void UpdateListening() {
}
ToggleRX(false);
newScanStart = true;
ResetScanStats();
}
static void Tick() {
#ifdef ENABLE_AM_FIX
if (gNextTimeslice) {
gNextTimeslice = false;
if(settings.modulationType == MODULATION_AM && !lockAGC) {
AM_fix_10ms(vfo); //allow AM_Fix to apply its AGC action
}
}
#endif
#ifdef ENABLE_SCAN_RANGES
if (gNextTimeslice_500ms) {
gNextTimeslice_500ms = false;
// if a lot of steps then it takes long time
// we don't want to wait for whole scan
// listening has it's own timer
if(GetStepsCount()>128 && !isListening) {
UpdatePeakInfo();
if (IsPeakOverLevel()) {
ToggleRX(true);
TuneToPeak();
return;
}
redrawScreen = true;
preventKeypress = false;
}
}
#endif
if (!preventKeypress) {
HandleUserInput();
}
@@ -1151,25 +1267,40 @@ static void Tick() {
void APP_RunSpectrum() {
// TX here coz it always? set to active VFO
currentFreq = initialFreq =
gEeprom.VfoInfo[gEeprom.TX_VFO].pRX->Frequency;
vfo = gEeprom.TX_VFO;
// set the current frequency in the middle of the display
#ifdef ENABLE_SCAN_RANGES
if(gScanRangeStart) {
currentFreq = initialFreq = gScanRangeStart;
for(uint8_t i = 0; i < ARRAY_SIZE(scanStepValues); i++) {
if(scanStepValues[i] >= gTxVfo->StepFrequency) {
settings.scanStepIndex = i;
break;
}
}
settings.stepsCount = STEPS_128;
}
else
#endif
currentFreq = initialFreq = gTxVfo->pRX->Frequency -
((GetStepsCount() / 2) * GetScanStep());
BackupRegisters();
isListening = true; // to turn off RX later
redrawStatus = true;
redrawScreen = false; // we will wait until scan done
redrawScreen = true;
newScanStart = true;
ToggleRX(true), ToggleRX(false); // hack to prevent noise when squelch off
RADIO_SetModulation(settings.modulationType = MODULATION_FM);
RADIO_SetModulation(settings.modulationType = gTxVfo->Modulation);
BK4819_SetFilterBandwidth(settings.listenBw = BK4819_FILTER_BW_WIDE, false);
RelaunchScan();
for (int i = 0; i < 128; ++i) {
rssiHistory[i] = 0;
}
memset(rssiHistory, 0, sizeof(rssiHistory));
isInitialized = true;

View File

@@ -29,7 +29,6 @@
#include "../driver/systick.h"
#include "../external/printf/printf.h"
#include "../font.h"
#include "../frequencies.h"
#include "../helper/battery.h"
#include "../misc.h"
#include "../radio.h"
@@ -46,9 +45,8 @@ static const uint8_t U8RssiMap[] = {
};
static const uint16_t scanStepValues[] = {
1, 10, 50, 100,
250, 500, 625, 833, 1000, 1250, 2500, 10000,
1, 10, 50, 100, 250, 500, 625, 833,
1000, 1250, 1500, 2000, 2500, 5000, 10000,
};
static const uint16_t scanStepBWRegValues[] = {
@@ -111,7 +109,10 @@ typedef enum ScanStep {
S_STEP_8_33kHz,
S_STEP_10_0kHz,
S_STEP_12_5kHz,
S_STEP_15_0kHz,
S_STEP_20_0kHz,
S_STEP_25_0kHz,
S_STEP_50_0kHz,
S_STEP_100_0kHz,
} ScanStep;
@@ -137,17 +138,17 @@ typedef struct KeyboardState {
typedef struct ScanInfo {
uint16_t rssi, rssiMin, rssiMax;
uint8_t i, iPeak;
uint16_t i, iPeak;
uint32_t f, fPeak;
uint16_t scanStep;
uint8_t measurementsCount;
uint16_t measurementsCount;
} ScanInfo;
typedef struct PeakInfo {
uint16_t t;
uint16_t rssi;
uint32_t f;
uint8_t i;
uint16_t i;
} PeakInfo;
void APP_RunSpectrum(void);

View File

@@ -36,10 +36,12 @@
#include "functions.h"
#include "misc.h"
#include "settings.h"
#include "version.h"
#if defined(ENABLE_OVERLAY)
#include "sram-overlay.h"
#endif
#include "version.h"
#define DMA_INDEX(x, y) (((x) + (y)) % sizeof(UART_DMA_Buffer))
@@ -226,6 +228,8 @@ static bool IsBadChallenge(const uint32_t *pKey, const uint32_t *pIn, const uint
return false;
}
// session init, sends back version info and state
// timestamp is a session id really
static void CMD_0514(const uint8_t *pBuffer)
{
const CMD_0514_t *pCmd = (const CMD_0514_t *)pBuffer;
@@ -244,6 +248,7 @@ static void CMD_0514(const uint8_t *pBuffer)
SendVersion();
}
// read eeprom
static void CMD_051B(const uint8_t *pBuffer)
{
const CMD_051B_t *pCmd = (const CMD_051B_t *)pBuffer;
@@ -274,6 +279,7 @@ static void CMD_051B(const uint8_t *pBuffer)
SendReply(&Reply, pCmd->Size + 8);
}
// write eeprom
static void CMD_051D(const uint8_t *pBuffer)
{
const CMD_051D_t *pCmd = (const CMD_051D_t *)pBuffer;
@@ -314,12 +320,13 @@ static void CMD_051D(const uint8_t *pBuffer)
}
if (bReloadEeprom)
BOARD_EEPROM_Init();
SETTINGS_InitEEPROM();
}
SendReply(&Reply, sizeof(Reply));
}
// read RSSI
static void CMD_0527(void)
{
REPLY_0527_t Reply;
@@ -333,6 +340,7 @@ static void CMD_0527(void)
SendReply(&Reply, sizeof(Reply));
}
// read ADC
static void CMD_0529(void)
{
REPLY_0529_t Reply;
@@ -387,6 +395,11 @@ static void CMD_052D(const uint8_t *pBuffer)
SendReply(&Reply, sizeof(Reply));
}
// session init, sends back version info and state
// timestamp is a session id really
// this command also disables dual watch, crossband,
// DTMF side tones, freq reverse, PTT ID, DTMF decoding, frequency offset
// exits power save, sets main VFO to upper,
static void CMD_052F(const uint8_t *pBuffer)
{
const CMD_052F_t *pCmd = (const CMD_052F_t *)pBuffer;
@@ -400,7 +413,9 @@ static void CMD_052F(const uint8_t *pBuffer)
gEeprom.VfoInfo[0].pTX = &gEeprom.VfoInfo[0].freq_config_TX;
gEeprom.VfoInfo[0].TX_OFFSET_FREQUENCY_DIRECTION = TX_OFFSET_FREQUENCY_DIRECTION_OFF;
gEeprom.VfoInfo[0].DTMF_PTT_ID_TX_MODE = PTT_ID_OFF;
#ifdef ENABLE_DTMF_CALLING
gEeprom.VfoInfo[0].DTMF_DECODING_ENABLE = false;
#endif
#ifdef ENABLE_NOAA
gIsNoaaMode = false;
@@ -419,6 +434,44 @@ static void CMD_052F(const uint8_t *pBuffer)
SendVersion();
}
#ifdef ENABLE_UART_RW_BK_REGS
static void CMD_0601_ReadBK4819Reg(const uint8_t *pBuffer)
{
typedef struct __attribute__((__packed__)) {
Header_t header;
uint8_t reg;
} CMD_0601_t;
CMD_0601_t *cmd = (CMD_0601_t*) pBuffer;
struct __attribute__((__packed__)) {
Header_t header;
struct __attribute__((__packed__)) {
uint8_t reg;
uint16_t value;
} data;
} reply;
reply.header.ID = 0x0601;
reply.header.Size = sizeof(reply.data);
reply.data.reg = cmd->reg;
reply.data.value = BK4819_ReadRegister(cmd->reg);
SendReply(&reply, sizeof(reply));
}
static void CMD_0602_WriteBK4819Reg(const uint8_t *pBuffer)
{
typedef struct __attribute__((__packed__)) {
Header_t header;
uint8_t reg;
uint16_t value;
} CMD_0602_t;
CMD_0602_t *cmd = (CMD_0602_t*) pBuffer;
BK4819_WriteRegister(cmd->reg, cmd->value);
}
#endif
bool UART_IsCommandAvailable(void)
{
uint16_t Index;
@@ -477,11 +530,11 @@ bool UART_IsCommandAvailable(void)
if (TailIndex < Index)
{
const uint16_t ChunkSize = sizeof(UART_DMA_Buffer) - Index;
memmove(UART_Command.Buffer, UART_DMA_Buffer + Index, ChunkSize);
memmove(UART_Command.Buffer + ChunkSize, UART_DMA_Buffer, TailIndex);
memcpy(UART_Command.Buffer, UART_DMA_Buffer + Index, ChunkSize);
memcpy(UART_Command.Buffer + ChunkSize, UART_DMA_Buffer, TailIndex);
}
else
memmove(UART_Command.Buffer, UART_DMA_Buffer + Index, TailIndex - Index);
memcpy(UART_Command.Buffer, UART_DMA_Buffer + Index, TailIndex - Index);
TailIndex = DMA_INDEX(TailIndex, 2);
if (TailIndex < gUART_WriteIndex)
@@ -550,12 +603,22 @@ void UART_HandleCommand(void)
CMD_052F(UART_Command.Buffer);
break;
case 0x05DD:
case 0x05DD: // reset
#if defined(ENABLE_OVERLAY)
overlay_FLASH_RebootToBootloader();
#else
NVIC_SystemReset();
#endif
break;
#ifdef ENABLE_UART_RW_BK_REGS
case 0x0601:
CMD_0601_ReadBK4819Reg(UART_Command.Buffer);
break;
case 0x0602:
CMD_0602_WriteBK4819Reg(UART_Command.Buffer);
break;
#endif
}
}

556
audio.c
View File

@@ -31,50 +31,11 @@
#include "settings.h"
#include "ui/ui.h"
#ifdef ENABLE_VOICE
static const uint8_t VoiceClipLengthChinese[58] =
{
0x32, 0x32, 0x32, 0x37, 0x37, 0x32, 0x32, 0x32,
0x32, 0x37, 0x37, 0x32, 0x64, 0x64, 0x64, 0x64,
0x64, 0x69, 0x64, 0x69, 0x5A, 0x5F, 0x5F, 0x64,
0x64, 0x69, 0x64, 0x64, 0x69, 0x69, 0x69, 0x64,
0x64, 0x6E, 0x69, 0x5F, 0x64, 0x64, 0x64, 0x69,
0x69, 0x69, 0x64, 0x69, 0x64, 0x64, 0x55, 0x5F,
0x5A, 0x4B, 0x4B, 0x46, 0x46, 0x69, 0x64, 0x6E,
0x5A, 0x64,
};
static const uint8_t VoiceClipLengthEnglish[76] =
{
0x50, 0x32, 0x2D, 0x2D, 0x2D, 0x37, 0x37, 0x37,
0x32, 0x32, 0x3C, 0x37, 0x46, 0x46, 0x4B, 0x82,
0x82, 0x6E, 0x82, 0x46, 0x96, 0x64, 0x46, 0x6E,
0x78, 0x6E, 0x87, 0x64, 0x96, 0x96, 0x46, 0x9B,
0x91, 0x82, 0x82, 0x73, 0x78, 0x64, 0x82, 0x6E,
0x78, 0x82, 0x87, 0x6E, 0x55, 0x78, 0x64, 0x69,
0x9B, 0x5A, 0x50, 0x3C, 0x32, 0x55, 0x64, 0x64,
0x50, 0x46, 0x46, 0x46, 0x4B, 0x4B, 0x50, 0x50,
0x55, 0x4B, 0x4B, 0x32, 0x32, 0x32, 0x32, 0x37,
0x41, 0x32, 0x3C, 0x37,
};
VOICE_ID_t gVoiceID[8];
uint8_t gVoiceReadIndex;
uint8_t gVoiceWriteIndex;
volatile uint16_t gCountdownToPlayNextVoice_10ms;
volatile bool gFlagPlayQueuedVoice;
VOICE_ID_t gAnotherVoiceID = VOICE_ID_INVALID;
#endif
BEEP_Type_t gBeepToPlay = BEEP_NONE;
void AUDIO_PlayBeep(BEEP_Type_t Beep)
{
uint16_t ToneConfig;
uint16_t ToneFrequency;
uint16_t Duration;
if (Beep != BEEP_880HZ_60MS_TRIPLE_BEEP &&
Beep != BEEP_500HZ_60MS_DOUBLE_BEEP &&
@@ -84,31 +45,32 @@ void AUDIO_PlayBeep(BEEP_Type_t Beep)
!gEeprom.BEEP_CONTROL)
return;
#ifdef ENABLE_AIRCOPY
if (gScreenToDisplay == DISPLAY_AIRCOPY)
return;
#endif
#ifdef ENABLE_AIRCOPY
if (gScreenToDisplay == DISPLAY_AIRCOPY)
return;
#endif
if (gCurrentFunction == FUNCTION_RECEIVE)
return;
if (gCurrentFunction == FUNCTION_MONITOR)
return;
ToneConfig = BK4819_ReadRegister(BK4819_REG_71);
#ifdef ENABLE_FMRADIO
if (gFmRadioMode)
BK1080_Mute(true);
#endif
AUDIO_AudioPathOff();
if (gCurrentFunction == FUNCTION_POWER_SAVE && gRxIdleMode)
BK4819_RX_TurnOn();
#ifdef ENABLE_FMRADIO
if (gFmRadioMode)
BK1080_Mute(true);
#endif
SYSTEM_DelayMs(20);
uint16_t ToneConfig = BK4819_ReadRegister(BK4819_REG_71);
uint16_t ToneFrequency;
switch (Beep)
{
default:
@@ -133,7 +95,7 @@ void AUDIO_PlayBeep(BEEP_Type_t Beep)
ToneFrequency = 880;
break;
}
BK4819_PlayTone(ToneFrequency, true);
SYSTEM_DelayMs(2);
@@ -142,6 +104,7 @@ void AUDIO_PlayBeep(BEEP_Type_t Beep)
SYSTEM_DelayMs(60);
uint16_t Duration;
switch (Beep)
{
case BEEP_880HZ_60MS_TRIPLE_BEEP:
@@ -161,18 +124,15 @@ void AUDIO_PlayBeep(BEEP_Type_t Beep)
BK4819_ExitTxMute();
Duration = 60;
break;
case BEEP_880HZ_40MS_OPTIONAL:
case BEEP_440HZ_40MS_OPTIONAL:
BK4819_ExitTxMute();
Duration = 40;
break;
case BEEP_880HZ_200MS:
BK4819_ExitTxMute();
Duration = 200;
break;
case BEEP_440HZ_500MS:
case BEEP_880HZ_500MS:
default:
@@ -187,10 +147,6 @@ void AUDIO_PlayBeep(BEEP_Type_t Beep)
AUDIO_AudioPathOff();
#ifdef ENABLE_VOX
gVoxResumeCountdown = 80;
#endif
SYSTEM_DelayMs(5);
BK4819_TurnsOffTones_TurnsOnRX();
SYSTEM_DelayMs(5);
@@ -199,254 +155,288 @@ void AUDIO_PlayBeep(BEEP_Type_t Beep)
if (gEnableSpeaker)
AUDIO_AudioPathOn();
#ifdef ENABLE_FMRADIO
if (gFmRadioMode)
BK1080_Mute(false);
#endif
#ifdef ENABLE_FMRADIO
if (gFmRadioMode)
BK1080_Mute(false);
#endif
if (gCurrentFunction == FUNCTION_POWER_SAVE && gRxIdleMode)
BK4819_Sleep();
#ifdef ENABLE_VOX
gVoxResumeCountdown = 80;
#endif
}
#ifdef ENABLE_VOICE
void AUDIO_PlayVoice(uint8_t VoiceID)
static const uint8_t VoiceClipLengthChinese[58] =
{
0x32, 0x32, 0x32, 0x37, 0x37, 0x32, 0x32, 0x32,
0x32, 0x37, 0x37, 0x32, 0x64, 0x64, 0x64, 0x64,
0x64, 0x69, 0x64, 0x69, 0x5A, 0x5F, 0x5F, 0x64,
0x64, 0x69, 0x64, 0x64, 0x69, 0x69, 0x69, 0x64,
0x64, 0x6E, 0x69, 0x5F, 0x64, 0x64, 0x64, 0x69,
0x69, 0x69, 0x64, 0x69, 0x64, 0x64, 0x55, 0x5F,
0x5A, 0x4B, 0x4B, 0x46, 0x46, 0x69, 0x64, 0x6E,
0x5A, 0x64,
};
static const uint8_t VoiceClipLengthEnglish[76] =
{
0x50, 0x32, 0x2D, 0x2D, 0x2D, 0x37, 0x37, 0x37,
0x32, 0x32, 0x3C, 0x37, 0x46, 0x46, 0x4B, 0x82,
0x82, 0x6E, 0x82, 0x46, 0x96, 0x64, 0x46, 0x6E,
0x78, 0x6E, 0x87, 0x64, 0x96, 0x96, 0x46, 0x9B,
0x91, 0x82, 0x82, 0x73, 0x78, 0x64, 0x82, 0x6E,
0x78, 0x82, 0x87, 0x6E, 0x55, 0x78, 0x64, 0x69,
0x9B, 0x5A, 0x50, 0x3C, 0x32, 0x55, 0x64, 0x64,
0x50, 0x46, 0x46, 0x46, 0x4B, 0x4B, 0x50, 0x50,
0x55, 0x4B, 0x4B, 0x32, 0x32, 0x32, 0x32, 0x37,
0x41, 0x32, 0x3C, 0x37,
};
VOICE_ID_t gVoiceID[8];
uint8_t gVoiceReadIndex;
uint8_t gVoiceWriteIndex;
volatile uint16_t gCountdownToPlayNextVoice_10ms;
volatile bool gFlagPlayQueuedVoice;
VOICE_ID_t gAnotherVoiceID = VOICE_ID_INVALID;
static void AUDIO_PlayVoice(uint8_t VoiceID)
{
unsigned int i;
GPIO_SetBit(&GPIOA->DATA, GPIOA_PIN_VOICE_0);
SYSTEM_DelayMs(20);
GPIO_ClearBit(&GPIOA->DATA, GPIOA_PIN_VOICE_0);
for (i = 0; i < 8; i++)
{
unsigned int i;
if ((VoiceID & 0x80U) == 0)
GPIO_ClearBit(&GPIOA->DATA, GPIOA_PIN_VOICE_1);
else
GPIO_SetBit(&GPIOA->DATA, GPIOA_PIN_VOICE_1);
SYSTICK_DelayUs(1000);
GPIO_SetBit(&GPIOA->DATA, GPIOA_PIN_VOICE_0);
SYSTEM_DelayMs(20);
SYSTICK_DelayUs(1200);
GPIO_ClearBit(&GPIOA->DATA, GPIOA_PIN_VOICE_0);
for (i = 0; i < 8; i++)
{
if ((VoiceID & 0x80U) == 0)
GPIO_ClearBit(&GPIOA->DATA, GPIOA_PIN_VOICE_1);
else
GPIO_SetBit(&GPIOA->DATA, GPIOA_PIN_VOICE_1);
SYSTICK_DelayUs(1000);
GPIO_SetBit(&GPIOA->DATA, GPIOA_PIN_VOICE_0);
SYSTICK_DelayUs(1200);
GPIO_ClearBit(&GPIOA->DATA, GPIOA_PIN_VOICE_0);
VoiceID <<= 1;
SYSTICK_DelayUs(200);
}
VoiceID <<= 1;
SYSTICK_DelayUs(200);
}
void AUDIO_PlaySingleVoice(bool bFlag)
}
void AUDIO_PlaySingleVoice(bool bFlag)
{
uint8_t VoiceID;
uint8_t Delay;
VoiceID = gVoiceID[0];
if (gEeprom.VOICE_PROMPT != VOICE_PROMPT_OFF && gVoiceWriteIndex > 0)
{
uint8_t VoiceID;
uint8_t Delay;
VoiceID = gVoiceID[0];
if (gEeprom.VOICE_PROMPT != VOICE_PROMPT_OFF && gVoiceWriteIndex > 0)
if (gEeprom.VOICE_PROMPT == VOICE_PROMPT_CHINESE)
{ // Chinese
if (VoiceID >= ARRAY_SIZE(VoiceClipLengthChinese))
goto Bailout;
Delay = VoiceClipLengthChinese[VoiceID];
VoiceID += VOICE_ID_CHI_BASE;
}
else
{ // English
if (VoiceID >= ARRAY_SIZE(VoiceClipLengthEnglish))
goto Bailout;
Delay = VoiceClipLengthEnglish[VoiceID];
VoiceID += VOICE_ID_ENG_BASE;
}
if (FUNCTION_IsRx()) // 1of11
BK4819_SetAF(BK4819_AF_MUTE);
#ifdef ENABLE_FMRADIO
if (gFmRadioMode)
BK1080_Mute(true);
#endif
AUDIO_AudioPathOn();
#ifdef ENABLE_VOX
gVoxResumeCountdown = 2000;
#endif
SYSTEM_DelayMs(5);
AUDIO_PlayVoice(VoiceID);
if (gVoiceWriteIndex == 1)
Delay += 3;
if (bFlag)
{
if (gEeprom.VOICE_PROMPT == VOICE_PROMPT_CHINESE)
{ // Chinese
if (VoiceID >= ARRAY_SIZE(VoiceClipLengthChinese))
goto Bailout;
Delay = VoiceClipLengthChinese[VoiceID];
SYSTEM_DelayMs(Delay * 10);
if (FUNCTION_IsRx()) // 1of11
RADIO_SetModulation(gRxVfo->Modulation);
#ifdef ENABLE_FMRADIO
if (gFmRadioMode)
BK1080_Mute(false);
#endif
if (!gEnableSpeaker)
AUDIO_AudioPathOff();
gVoiceWriteIndex = 0;
gVoiceReadIndex = 0;
#ifdef ENABLE_VOX
gVoxResumeCountdown = 80;
#endif
return;
}
gVoiceReadIndex = 1;
gCountdownToPlayNextVoice_10ms = Delay;
gFlagPlayQueuedVoice = false;
return;
}
Bailout:
gVoiceReadIndex = 0;
gVoiceWriteIndex = 0;
}
void AUDIO_SetVoiceID(uint8_t Index, VOICE_ID_t VoiceID)
{
if (Index >= ARRAY_SIZE(gVoiceID))
return;
if (Index == 0)
{
gVoiceWriteIndex = 0;
gVoiceReadIndex = 0;
}
gVoiceID[Index] = VoiceID;
gVoiceWriteIndex++;
}
uint8_t AUDIO_SetDigitVoice(uint8_t Index, uint16_t Value)
{
uint16_t Remainder;
uint8_t Result;
uint8_t Count;
if (Index == 0)
{
gVoiceWriteIndex = 0;
gVoiceReadIndex = 0;
}
Count = 0;
Result = Value / 1000U;
Remainder = Value % 1000U;
if (Remainder < 100U)
{
if (Remainder < 10U)
goto Skip;
}
else
{
Result = Remainder / 100U;
gVoiceID[gVoiceWriteIndex++] = (VOICE_ID_t)Result;
Count++;
Remainder -= Result * 100U;
}
Result = Remainder / 10U;
gVoiceID[gVoiceWriteIndex++] = (VOICE_ID_t)Result;
Count++;
Remainder -= Result * 10U;
Skip:
gVoiceID[gVoiceWriteIndex++] = (VOICE_ID_t)Remainder;
return Count + 1U;
}
void AUDIO_PlayQueuedVoice(void)
{
uint8_t VoiceID;
uint8_t Delay;
bool Skip;
Skip = false;
if (gVoiceReadIndex != gVoiceWriteIndex && gEeprom.VOICE_PROMPT != VOICE_PROMPT_OFF)
{
VoiceID = gVoiceID[gVoiceReadIndex];
if (gEeprom.VOICE_PROMPT == VOICE_PROMPT_CHINESE)
{
if (VoiceID < ARRAY_SIZE(VoiceClipLengthChinese))
{
Delay = VoiceClipLengthChinese[VoiceID];
VoiceID += VOICE_ID_CHI_BASE;
}
else
{ // English
if (VoiceID >= ARRAY_SIZE(VoiceClipLengthEnglish))
goto Bailout;
Delay = VoiceClipLengthEnglish[VoiceID];
Skip = true;
}
else
{
if (VoiceID < ARRAY_SIZE(VoiceClipLengthEnglish))
{
Delay = VoiceClipLengthEnglish[VoiceID];
VoiceID += VOICE_ID_ENG_BASE;
}
if (gCurrentFunction == FUNCTION_RECEIVE ||
gCurrentFunction == FUNCTION_MONITOR ||
gCurrentFunction == FUNCTION_INCOMING) // 1of11
BK4819_SetAF(BK4819_AF_MUTE);
#ifdef ENABLE_FMRADIO
if (gFmRadioMode)
BK1080_Mute(true);
#endif
AUDIO_AudioPathOn();
else
Skip = true;
}
gVoiceReadIndex++;
if (!Skip)
{
if (gVoiceReadIndex == gVoiceWriteIndex)
Delay += 3;
AUDIO_PlayVoice(VoiceID);
gCountdownToPlayNextVoice_10ms = Delay;
gFlagPlayQueuedVoice = false;
#ifdef ENABLE_VOX
gVoxResumeCountdown = 2000;
#endif
SYSTEM_DelayMs(5);
AUDIO_PlayVoice(VoiceID);
if (gVoiceWriteIndex == 1)
Delay += 3;
if (bFlag)
{
SYSTEM_DelayMs(Delay * 10);
if (gCurrentFunction == FUNCTION_RECEIVE ||
gCurrentFunction == FUNCTION_MONITOR ||
gCurrentFunction == FUNCTION_INCOMING) // 1of11
RADIO_SetModulation(gRxVfo->Modulation);
#ifdef ENABLE_FMRADIO
if (gFmRadioMode)
BK1080_Mute(false);
#endif
if (!gEnableSpeaker)
AUDIO_AudioPathOff();
gVoiceWriteIndex = 0;
gVoiceReadIndex = 0;
#ifdef ENABLE_VOX
gVoxResumeCountdown = 80;
#endif
return;
}
gVoiceReadIndex = 1;
gCountdownToPlayNextVoice_10ms = Delay;
gFlagPlayQueuedVoice = false;
return;
}
Bailout:
gVoiceReadIndex = 0;
gVoiceWriteIndex = 0;
}
void AUDIO_SetVoiceID(uint8_t Index, VOICE_ID_t VoiceID)
{
if (Index >= ARRAY_SIZE(gVoiceID))
return;
if (Index == 0)
{
gVoiceWriteIndex = 0;
gVoiceReadIndex = 0;
}
gVoiceID[Index] = VoiceID;
gVoiceWriteIndex++;
}
uint8_t AUDIO_SetDigitVoice(uint8_t Index, uint16_t Value)
{
uint16_t Remainder;
uint8_t Result;
uint8_t Count;
if (Index == 0)
{
gVoiceWriteIndex = 0;
gVoiceReadIndex = 0;
}
Count = 0;
Result = Value / 1000U;
Remainder = Value % 1000U;
if (Remainder < 100U)
{
if (Remainder < 10U)
goto Skip;
}
else
{
Result = Remainder / 100U;
gVoiceID[gVoiceWriteIndex++] = (VOICE_ID_t)Result;
Count++;
Remainder -= Result * 100U;
}
Result = Remainder / 10U;
gVoiceID[gVoiceWriteIndex++] = (VOICE_ID_t)Result;
Count++;
Remainder -= Result * 10U;
Skip:
gVoiceID[gVoiceWriteIndex++] = (VOICE_ID_t)Remainder;
return Count + 1U;
}
void AUDIO_PlayQueuedVoice(void)
{
uint8_t VoiceID;
uint8_t Delay;
bool Skip;
Skip = false;
if (gVoiceReadIndex != gVoiceWriteIndex && gEeprom.VOICE_PROMPT != VOICE_PROMPT_OFF)
{
VoiceID = gVoiceID[gVoiceReadIndex];
if (gEeprom.VOICE_PROMPT == VOICE_PROMPT_CHINESE)
{
if (VoiceID < ARRAY_SIZE(VoiceClipLengthChinese))
{
Delay = VoiceClipLengthChinese[VoiceID];
VoiceID += VOICE_ID_CHI_BASE;
}
else
Skip = true;
}
else
{
if (VoiceID < ARRAY_SIZE(VoiceClipLengthEnglish))
{
Delay = VoiceClipLengthEnglish[VoiceID];
VoiceID += VOICE_ID_ENG_BASE;
}
else
Skip = true;
}
gVoiceReadIndex++;
if (!Skip)
{
if (gVoiceReadIndex == gVoiceWriteIndex)
Delay += 3;
AUDIO_PlayVoice(VoiceID);
gCountdownToPlayNextVoice_10ms = Delay;
gFlagPlayQueuedVoice = false;
#ifdef ENABLE_VOX
gVoxResumeCountdown = 2000;
#endif
return;
}
return;
}
if (gCurrentFunction == FUNCTION_RECEIVE ||
gCurrentFunction == FUNCTION_MONITOR ||
gCurrentFunction == FUNCTION_INCOMING) // 1of11
RADIO_SetModulation(gRxVfo->Modulation);
#ifdef ENABLE_FMRADIO
if (gFmRadioMode)
BK1080_Mute(false);
#endif
if (!gEnableSpeaker)
AUDIO_AudioPathOff();
#ifdef ENABLE_VOX
gVoxResumeCountdown = 80;
#endif
gVoiceWriteIndex = 0;
gVoiceReadIndex = 0;
}
if (FUNCTION_IsRx())
{
RADIO_SetModulation(gRxVfo->Modulation); // 1of11
}
#ifdef ENABLE_FMRADIO
if (gFmRadioMode)
BK1080_Mute(false);
#endif
if (!gEnableSpeaker)
AUDIO_AudioPathOff();
#ifdef ENABLE_VOX
gVoxResumeCountdown = 80;
#endif
gVoiceWriteIndex = 0;
gVoiceReadIndex = 0;
}
#endif

View File

@@ -149,7 +149,6 @@ static inline void AUDIO_AudioPathOff(void) {
extern volatile bool gFlagPlayQueuedVoice;
extern VOICE_ID_t gAnotherVoiceID;
void AUDIO_PlayVoice(uint8_t VoiceID);
void AUDIO_PlaySingleVoice(bool bFlag);
void AUDIO_SetVoiceID(uint8_t Index, VOICE_ID_t VoiceID);
uint8_t AUDIO_SetDigitVoice(uint8_t Index, uint16_t Value);
@@ -157,4 +156,3 @@ static inline void AUDIO_AudioPathOff(void) {
#endif
#endif

128
bitmaps.c
View File

@@ -6,27 +6,16 @@
const uint8_t BITMAP_POWERSAVE[8] =
{
#if 0
// "S"
0b00000000,
0b00100110,
0b01001001,
0b01001001,
0b01001001,
0b01001001,
0b01001001,
0b00110010
#else
// "PS"
0b00000000,
0b01111111,
0b00010001,
0b00001110,
0b00000000,
0b01000110,
0b01001001,
0b00110001
#endif
// "PS"
0b00000000,
0b01111111,
0b00010001,
0b00001110,
0b00000000,
0b01000110,
0b01001001,
0b00110001
};
const uint8_t BITMAP_TX[8] =
@@ -53,6 +42,20 @@ const uint8_t BITMAP_RX[8] =
0b00000000
};
const uint8_t BITMAP_FM[10] =
{ // "FM"
0b00000000,
0b01111111,
0b00001001,
0b00000001,
0b00000000,
0b01111111,
0b00000010,
0b00001100,
0b00000010,
0b01111111
};
const uint8_t BITMAP_BatteryLevel[2] =
{
0b01011101,
@@ -162,43 +165,28 @@ const uint8_t BITMAP_F_Key[6] =
};
#endif
#if 0
const uint8_t BITMAP_WX[12] =
{ // "WX"
0b00000000,
0b01111111,
0b00100000,
0b00011000,
0b00100000,
0b01111111,
0b00000000,
0b01100011,
0b00010100,
0b00001000,
0b00010100,
0b01100011
};
#else
// 'XB' (cross-band/cross-VFO)
const uint8_t BITMAP_XB[12] =
{ // "XB"
0b00000000,
0b01100011,
0b00010100,
0b00001000,
0b00010100,
0b01100011,
0b00000000,
0b01111111,
0b01001001,
0b01001001,
0b01001001,
0b00110110
};
#endif
const uint8_t BITMAP_TDR1[15] =
// 'XB' (cross-band/cross-VFO)
const uint8_t BITMAP_XB[12] =
{ // "XB"
0b00000000,
0b01100011,
0b00010100,
0b00001000,
0b00010100,
0b01100011,
0b00000000,
0b01111111,
0b01001001,
0b01001001,
0b01001001,
0b00110110
};
const uint8_t BITMAP_TDR1[16] =
{ // "DWR"
0b00000000,
0b01111111,
0b01000001,
0b01000001,
@@ -216,8 +204,9 @@ const uint8_t BITMAP_TDR1[15] =
0b01000110
};
const uint8_t BITMAP_TDR2[9] =
const uint8_t BITMAP_TDR2[10] =
{ // "><" .. DW on hold
0b00000000,
0b00100010,
0b00110110,
0b00011100,
@@ -270,18 +259,6 @@ const uint8_t BITMAP_Antenna[5] =
0b00000011
};
const uint8_t BITMAP_MARKER[8] =
{
0b11111111,
0b11111111,
0b01111110,
0b01111110,
0b00111100,
0b00111100,
0b00011000,
0b00011000
};
const uint8_t BITMAP_VFO_Default[8] =
{
0b00000000,
@@ -335,3 +312,16 @@ const uint8_t BITMAP_compand[6] =
0b01000010,
0b00100100
};
#ifndef ENABLE_CUSTOM_MENU_LAYOUT
const uint8_t BITMAP_CurrentIndicator[8] = {
0xFF,
0xFF,
0x7E,
0x7E,
0x3C,
0x3C,
0x18,
0x18
};
#endif

View File

@@ -7,7 +7,7 @@
extern const uint8_t BITMAP_POWERSAVE[8];
extern const uint8_t BITMAP_TX[8];
extern const uint8_t BITMAP_RX[8];
extern const uint8_t BITMAP_FM[10];
extern const uint8_t BITMAP_BatteryLevel[2];
extern const uint8_t BITMAP_BatteryLevel1[17];
@@ -23,8 +23,8 @@ extern const uint8_t BITMAP_F_Key[6];
extern const uint8_t BITMAP_XB[12];
extern const uint8_t BITMAP_TDR1[15];
extern const uint8_t BITMAP_TDR2[9];
extern const uint8_t BITMAP_TDR1[16];
extern const uint8_t BITMAP_TDR2[10];
#ifdef ENABLE_VOICE
extern const uint8_t BITMAP_VoicePrompt[9];
@@ -36,8 +36,6 @@ extern const uint8_t BITMAP_TDR2[9];
extern const uint8_t BITMAP_Antenna[5];
extern const uint8_t BITMAP_MARKER[8];
extern const uint8_t BITMAP_VFO_Default[8];
extern const uint8_t BITMAP_VFO_NotDefault[8];
@@ -46,5 +44,8 @@ extern const uint8_t BITMAP_ScanList2[6];
extern const uint8_t BITMAP_compand[6];
#ifndef ENABLE_CUSTOM_MENU_LAYOUT
extern const uint8_t BITMAP_CurrentIndicator[8];
#endif
#endif

392
board.c
View File

@@ -16,7 +16,6 @@
#include <string.h>
#include "app/dtmf.h"
#ifdef ENABLE_FMRADIO
#include "app/fm.h"
#endif
@@ -30,7 +29,7 @@
#ifdef ENABLE_FMRADIO
#include "driver/bk1080.h"
#endif
#include "driver/bk4819.h"
#include "driver/crc.h"
#include "driver/eeprom.h"
#include "driver/flash.h"
@@ -44,16 +43,6 @@
#if defined(ENABLE_OVERLAY)
#include "sram-overlay.h"
#endif
#include "ui/menu.h"
static const uint32_t gDefaultFrequencyTable[] =
{
14500000, //
14550000, //
43300000, //
43320000, //
43350000 //
};
#if defined(ENABLE_OVERLAY)
void BOARD_FLASH_Init(void)
@@ -61,10 +50,10 @@ static const uint32_t gDefaultFrequencyTable[] =
FLASH_Init(FLASH_READ_MODE_1_CYCLE);
FLASH_ConfigureTrimValues();
SYSTEM_ConfigureClocks();
overlay_FLASH_MainClock = 48000000;
overlay_FLASH_ClockMultiplier = 48;
FLASH_Init(FLASH_READ_MODE_2_CYCLE);
}
#endif
@@ -504,378 +493,13 @@ void BOARD_Init(void)
BOARD_GPIO_Init();
BACKLIGHT_InitHardware();
BOARD_ADC_Init();
ST7565_Init(true);
#ifdef ENABLE_FMRADIO
BK1080_Init(0, false);
#endif
CRC_Init();
}
void BOARD_EEPROM_Init(void)
{
unsigned int i;
uint8_t Data[16];
memset(Data, 0, sizeof(Data));
// 0E70..0E77
EEPROM_ReadBuffer(0x0E70, Data, 8);
gEeprom.CHAN_1_CALL = IS_MR_CHANNEL(Data[0]) ? Data[0] : MR_CHANNEL_FIRST;
gEeprom.SQUELCH_LEVEL = (Data[1] < 10) ? Data[1] : 1;
gEeprom.TX_TIMEOUT_TIMER = (Data[2] < 11) ? Data[2] : 1;
#ifdef ENABLE_NOAA
gEeprom.NOAA_AUTO_SCAN = (Data[3] < 2) ? Data[3] : false;
#endif
gEeprom.KEY_LOCK = (Data[4] < 2) ? Data[4] : false;
#ifdef ENABLE_VOX
gEeprom.VOX_SWITCH = (Data[5] < 2) ? Data[5] : false;
gEeprom.VOX_LEVEL = (Data[6] < 10) ? Data[6] : 1;
#endif
gEeprom.MIC_SENSITIVITY = (Data[7] < 5) ? Data[7] : 4;
// 0E78..0E7F
EEPROM_ReadBuffer(0x0E78, Data, 8);
gEeprom.BACKLIGHT_MAX = (Data[0] & 0xF) <= 10 ? (Data[0] & 0xF) : 10;
gEeprom.BACKLIGHT_MIN = (Data[0] >> 4) < gEeprom.BACKLIGHT_MAX ? (Data[0] >> 4) : 0;
gEeprom.CHANNEL_DISPLAY_MODE = (Data[1] < 4) ? Data[1] : MDF_FREQUENCY; // 4 instead of 3 - extra display mode
gEeprom.CROSS_BAND_RX_TX = (Data[2] < 3) ? Data[2] : CROSS_BAND_OFF;
gEeprom.BATTERY_SAVE = (Data[3] < 5) ? Data[3] : 4;
gEeprom.DUAL_WATCH = (Data[4] < 3) ? Data[4] : DUAL_WATCH_CHAN_A;
gEeprom.BACKLIGHT_TIME = (Data[5] < ARRAY_SIZE(gSubMenu_BACKLIGHT)) ? Data[5] : 3;
gEeprom.TAIL_TONE_ELIMINATION = (Data[6] < 2) ? Data[6] : false;
gEeprom.VFO_OPEN = (Data[7] < 2) ? Data[7] : true;
// 0E80..0E87
EEPROM_ReadBuffer(0x0E80, Data, 8);
gEeprom.ScreenChannel[0] = IS_VALID_CHANNEL(Data[0]) ? Data[0] : (FREQ_CHANNEL_FIRST + BAND6_400MHz);
gEeprom.ScreenChannel[1] = IS_VALID_CHANNEL(Data[3]) ? Data[3] : (FREQ_CHANNEL_FIRST + BAND6_400MHz);
gEeprom.MrChannel[0] = IS_MR_CHANNEL(Data[1]) ? Data[1] : MR_CHANNEL_FIRST;
gEeprom.MrChannel[1] = IS_MR_CHANNEL(Data[4]) ? Data[4] : MR_CHANNEL_FIRST;
gEeprom.FreqChannel[0] = IS_FREQ_CHANNEL(Data[2]) ? Data[2] : (FREQ_CHANNEL_FIRST + BAND6_400MHz);
gEeprom.FreqChannel[1] = IS_FREQ_CHANNEL(Data[5]) ? Data[5] : (FREQ_CHANNEL_FIRST + BAND6_400MHz);
#ifdef ENABLE_NOAA
gEeprom.NoaaChannel[0] = IS_NOAA_CHANNEL(Data[6]) ? Data[6] : NOAA_CHANNEL_FIRST;
gEeprom.NoaaChannel[1] = IS_NOAA_CHANNEL(Data[7]) ? Data[7] : NOAA_CHANNEL_FIRST;
#endif
ST7565_Init();
#ifdef ENABLE_FMRADIO
{ // 0E88..0E8F
struct
{
uint16_t SelectedFrequency;
uint8_t SelectedChannel;
uint8_t IsMrMode;
uint8_t Padding[8];
} __attribute__((packed)) FM;
EEPROM_ReadBuffer(0x0E88, &FM, 8);
gEeprom.FM_LowerLimit = 760;
gEeprom.FM_UpperLimit = 1080;
if (FM.SelectedFrequency < gEeprom.FM_LowerLimit || FM.SelectedFrequency > gEeprom.FM_UpperLimit)
gEeprom.FM_SelectedFrequency = 960;
else
gEeprom.FM_SelectedFrequency = FM.SelectedFrequency;
gEeprom.FM_SelectedChannel = FM.SelectedChannel;
gEeprom.FM_IsMrMode = (FM.IsMrMode < 2) ? FM.IsMrMode : false;
}
// 0E40..0E67
EEPROM_ReadBuffer(0x0E40, gFM_Channels, sizeof(gFM_Channels));
FM_ConfigureChannelState();
BK1080_Init0();
#endif
// 0E90..0E97
EEPROM_ReadBuffer(0x0E90, Data, 8);
gEeprom.BEEP_CONTROL = Data[0] & 1;
gEeprom.KEY_M_LONG_PRESS_ACTION = ((Data[0] >> 1) < ACTION_OPT_LEN) ? (Data[0] >> 1) : ACTION_OPT_NONE;
gEeprom.KEY_1_SHORT_PRESS_ACTION = (Data[1] < ACTION_OPT_LEN) ? Data[1] : ACTION_OPT_MONITOR;
gEeprom.KEY_1_LONG_PRESS_ACTION = (Data[2] < ACTION_OPT_LEN) ? Data[2] : ACTION_OPT_FLASHLIGHT;
gEeprom.KEY_2_SHORT_PRESS_ACTION = (Data[3] < ACTION_OPT_LEN) ? Data[3] : ACTION_OPT_SCAN;
gEeprom.KEY_2_LONG_PRESS_ACTION = (Data[4] < ACTION_OPT_LEN) ? Data[4] : ACTION_OPT_NONE;
gEeprom.SCAN_RESUME_MODE = (Data[5] < 3) ? Data[5] : SCAN_RESUME_CO;
gEeprom.AUTO_KEYPAD_LOCK = (Data[6] < 2) ? Data[6] : false;
gEeprom.POWER_ON_DISPLAY_MODE = (Data[7] < 4) ? Data[7] : POWER_ON_DISPLAY_MODE_VOLTAGE;
#if defined(ENABLE_UART) || defined(ENABLED_AIRCOPY)
CRC_Init();
#endif
// 0E98..0E9F
EEPROM_ReadBuffer(0x0E98, Data, 8);
memmove(&gEeprom.POWER_ON_PASSWORD, Data, 4);
// 0EA0..0EA7
#ifdef ENABLE_VOICE
EEPROM_ReadBuffer(0x0EA0, Data, 8);
gEeprom.VOICE_PROMPT = (Data[0] < 3) ? Data[0] : VOICE_PROMPT_ENGLISH;
#endif
// 0EA8..0EAF
EEPROM_ReadBuffer(0x0EA8, Data, 8);
#ifdef ENABLE_ALARM
gEeprom.ALARM_MODE = (Data[0] < 2) ? Data[0] : true;
#endif
gEeprom.ROGER = (Data[1] < 3) ? Data[1] : ROGER_MODE_OFF;
gEeprom.REPEATER_TAIL_TONE_ELIMINATION = (Data[2] < 11) ? Data[2] : 0;
gEeprom.TX_VFO = (Data[3] < 2) ? Data[3] : 0;
gEeprom.BATTERY_TYPE = (Data[4] < BATTERY_TYPE_UNKNOWN) ? Data[4] : BATTERY_TYPE_1600_MAH;
// 0ED0..0ED7
EEPROM_ReadBuffer(0x0ED0, Data, 8);
gEeprom.DTMF_SIDE_TONE = (Data[0] < 2) ? Data[0] : true;
gEeprom.DTMF_SEPARATE_CODE = DTMF_ValidateCodes((char *)(Data + 1), 1) ? Data[1] : '*';
gEeprom.DTMF_GROUP_CALL_CODE = DTMF_ValidateCodes((char *)(Data + 2), 1) ? Data[2] : '#';
gEeprom.DTMF_DECODE_RESPONSE = (Data[3] < 4) ? Data[3] : 0;
gEeprom.DTMF_auto_reset_time = (Data[4] < 61) ? Data[4] : (Data[4] >= 5) ? Data[4] : 10;
gEeprom.DTMF_PRELOAD_TIME = (Data[5] < 101) ? Data[5] * 10 : 300;
gEeprom.DTMF_FIRST_CODE_PERSIST_TIME = (Data[6] < 101) ? Data[6] * 10 : 100;
gEeprom.DTMF_HASH_CODE_PERSIST_TIME = (Data[7] < 101) ? Data[7] * 10 : 100;
// 0ED8..0EDF
EEPROM_ReadBuffer(0x0ED8, Data, 8);
gEeprom.DTMF_CODE_PERSIST_TIME = (Data[0] < 101) ? Data[0] * 10 : 100;
gEeprom.DTMF_CODE_INTERVAL_TIME = (Data[1] < 101) ? Data[1] * 10 : 100;
gEeprom.PERMIT_REMOTE_KILL = (Data[2] < 2) ? Data[2] : true;
// 0EE0..0EE7
EEPROM_ReadBuffer(0x0EE0, Data, 8);
if (DTMF_ValidateCodes((char *)Data, 8))
memmove(gEeprom.ANI_DTMF_ID, Data, 8);
else
{
memset(gEeprom.ANI_DTMF_ID, 0, sizeof(gEeprom.ANI_DTMF_ID));
strcpy(gEeprom.ANI_DTMF_ID, "123");
}
// 0EE8..0EEF
EEPROM_ReadBuffer(0x0EE8, Data, 8);
if (DTMF_ValidateCodes((char *)Data, 8))
memmove(gEeprom.KILL_CODE, Data, 8);
else
{
memset(gEeprom.KILL_CODE, 0, sizeof(gEeprom.KILL_CODE));
strcpy(gEeprom.KILL_CODE, "ABCD9");
}
// 0EF0..0EF7
EEPROM_ReadBuffer(0x0EF0, Data, 8);
if (DTMF_ValidateCodes((char *)Data, 8))
memmove(gEeprom.REVIVE_CODE, Data, 8);
else
{
memset(gEeprom.REVIVE_CODE, 0, sizeof(gEeprom.REVIVE_CODE));
strcpy(gEeprom.REVIVE_CODE, "9DCBA");
}
// 0EF8..0F07
EEPROM_ReadBuffer(0x0EF8, Data, 16);
if (DTMF_ValidateCodes((char *)Data, 16))
memmove(gEeprom.DTMF_UP_CODE, Data, 16);
else
{
memset(gEeprom.DTMF_UP_CODE, 0, sizeof(gEeprom.DTMF_UP_CODE));
strcpy(gEeprom.DTMF_UP_CODE, "12345");
}
// 0F08..0F17
EEPROM_ReadBuffer(0x0F08, Data, 16);
if (DTMF_ValidateCodes((char *)Data, 16))
memmove(gEeprom.DTMF_DOWN_CODE, Data, 16);
else
{
memset(gEeprom.DTMF_DOWN_CODE, 0, sizeof(gEeprom.DTMF_DOWN_CODE));
strcpy(gEeprom.DTMF_DOWN_CODE, "54321");
}
// 0F18..0F1F
EEPROM_ReadBuffer(0x0F18, Data, 8);
// gEeprom.SCAN_LIST_DEFAULT = (Data[0] < 2) ? Data[0] : false;
gEeprom.SCAN_LIST_DEFAULT = (Data[0] < 3) ? Data[0] : false; // we now have 'all' channel scan option
for (i = 0; i < 2; i++)
{
const unsigned int j = 1 + (i * 3);
gEeprom.SCAN_LIST_ENABLED[i] = (Data[j + 0] < 2) ? Data[j] : false;
gEeprom.SCANLIST_PRIORITY_CH1[i] = Data[j + 1];
gEeprom.SCANLIST_PRIORITY_CH2[i] = Data[j + 2];
}
// 0F40..0F47
EEPROM_ReadBuffer(0x0F40, Data, 8);
gSetting_F_LOCK = (Data[0] < 6) ? Data[0] : F_LOCK_OFF;
gSetting_350TX = (Data[1] < 2) ? Data[1] : false; // was true
gSetting_KILLED = (Data[2] < 2) ? Data[2] : false;
gSetting_200TX = (Data[3] < 2) ? Data[3] : false;
gSetting_500TX = (Data[4] < 2) ? Data[4] : false;
gSetting_350EN = (Data[5] < 2) ? Data[5] : true;
gSetting_ScrambleEnable = (Data[6] < 2) ? Data[6] : true;
gSetting_TX_EN = (Data[7] & (1u << 0)) ? true : false;
gSetting_live_DTMF_decoder = (Data[7] & (1u << 1)) ? true : false;
gSetting_battery_text = (((Data[7] >> 2) & 3u) <= 2) ? (Data[7] >> 2) & 3 : 2;
#ifdef ENABLE_AUDIO_BAR
gSetting_mic_bar = (Data[7] & (1u << 4)) ? true : false;
#endif
#ifdef ENABLE_AM_FIX
gSetting_AM_fix = (Data[7] & (1u << 5)) ? true : false;
#endif
gSetting_backlight_on_tx_rx = (Data[7] >> 6) & 3u;
if (!gEeprom.VFO_OPEN)
{
gEeprom.ScreenChannel[0] = gEeprom.MrChannel[0];
gEeprom.ScreenChannel[1] = gEeprom.MrChannel[1];
}
// 0D60..0E27
EEPROM_ReadBuffer(0x0D60, gMR_ChannelAttributes, sizeof(gMR_ChannelAttributes));
// 0F30..0F3F
EEPROM_ReadBuffer(0x0F30, gCustomAesKey, sizeof(gCustomAesKey));
bHasCustomAesKey = false;
for (i = 0; i < ARRAY_SIZE(gCustomAesKey); i++)
{
if (gCustomAesKey[i] != 0xFFFFFFFFu)
{
bHasCustomAesKey = true;
return;
}
}
}
void BOARD_EEPROM_LoadCalibration(void)
{
// uint8_t Mic;
EEPROM_ReadBuffer(0x1EC0, gEEPROM_RSSI_CALIB[3], 8);
memcpy(gEEPROM_RSSI_CALIB[4], gEEPROM_RSSI_CALIB[3], 8);
memcpy(gEEPROM_RSSI_CALIB[5], gEEPROM_RSSI_CALIB[3], 8);
memcpy(gEEPROM_RSSI_CALIB[6], gEEPROM_RSSI_CALIB[3], 8);
EEPROM_ReadBuffer(0x1EC8, gEEPROM_RSSI_CALIB[0], 8);
memcpy(gEEPROM_RSSI_CALIB[1], gEEPROM_RSSI_CALIB[0], 8);
memcpy(gEEPROM_RSSI_CALIB[2], gEEPROM_RSSI_CALIB[0], 8);
EEPROM_ReadBuffer(0x1F40, gBatteryCalibration, 12);
if (gBatteryCalibration[0] >= 5000)
{
gBatteryCalibration[0] = 1900;
gBatteryCalibration[1] = 2000;
}
gBatteryCalibration[5] = 2300;
#ifdef ENABLE_VOX
EEPROM_ReadBuffer(0x1F50 + (gEeprom.VOX_LEVEL * 2), &gEeprom.VOX1_THRESHOLD, 2);
EEPROM_ReadBuffer(0x1F68 + (gEeprom.VOX_LEVEL * 2), &gEeprom.VOX0_THRESHOLD, 2);
#endif
//EEPROM_ReadBuffer(0x1F80 + gEeprom.MIC_SENSITIVITY, &Mic, 1);
//gEeprom.MIC_SENSITIVITY_TUNING = (Mic < 32) ? Mic : 15;
gEeprom.MIC_SENSITIVITY_TUNING = gMicGain_dB2[gEeprom.MIC_SENSITIVITY];
{
struct
{
int16_t BK4819_XtalFreqLow;
uint16_t EEPROM_1F8A;
uint16_t EEPROM_1F8C;
uint8_t VOLUME_GAIN;
uint8_t DAC_GAIN;
} __attribute__((packed)) Misc;
// radio 1 .. 04 00 46 00 50 00 2C 0E
// radio 2 .. 05 00 46 00 50 00 2C 0E
EEPROM_ReadBuffer(0x1F88, &Misc, 8);
gEeprom.BK4819_XTAL_FREQ_LOW = (Misc.BK4819_XtalFreqLow >= -1000 && Misc.BK4819_XtalFreqLow <= 1000) ? Misc.BK4819_XtalFreqLow : 0;
gEEPROM_1F8A = Misc.EEPROM_1F8A & 0x01FF;
gEEPROM_1F8C = Misc.EEPROM_1F8C & 0x01FF;
gEeprom.VOLUME_GAIN = (Misc.VOLUME_GAIN < 64) ? Misc.VOLUME_GAIN : 58;
gEeprom.DAC_GAIN = (Misc.DAC_GAIN < 16) ? Misc.DAC_GAIN : 8;
BK4819_WriteRegister(BK4819_REG_3B, 22656 + gEeprom.BK4819_XTAL_FREQ_LOW);
// BK4819_WriteRegister(BK4819_REG_3C, gEeprom.BK4819_XTAL_FREQ_HIGH);
}
}
uint32_t BOARD_fetchChannelFrequency(const int channel)
{
struct
{
uint32_t frequency;
uint32_t offset;
} __attribute__((packed)) info;
EEPROM_ReadBuffer(channel * 16, &info, sizeof(info));
return info.frequency;
}
void BOARD_fetchChannelName(char *s, const int channel)
{
int i;
if (s == NULL)
return;
memset(s, 0, 11); // 's' had better be large enough !
if (channel < 0)
return;
if (!RADIO_CheckValidChannel(channel, false, 0))
return;
EEPROM_ReadBuffer(0x0F50 + (channel * 16), s + 0, 8);
EEPROM_ReadBuffer(0x0F58 + (channel * 16), s + 8, 2);
for (i = 0; i < 10; i++)
if (s[i] < 32 || s[i] > 127)
break; // invalid char
s[i--] = 0; // null term
while (i >= 0 && s[i] == 32) // trim trailing spaces
s[i--] = 0; // null term
}
void BOARD_FactoryReset(bool bIsAll)
{
uint16_t i;
uint8_t Template[8];
memset(Template, 0xFF, sizeof(Template));
for (i = 0x0C80; i < 0x1E00; i += 8)
{
if (
!(i >= 0x0EE0 && i < 0x0F18) && // ANI ID + DTMF codes
!(i >= 0x0F30 && i < 0x0F50) && // AES KEY + F LOCK + Scramble Enable
!(i >= 0x1C00 && i < 0x1E00) && // DTMF contacts
!(i >= 0x0EB0 && i < 0x0ED0) && // Welcome strings
!(i >= 0x0EA0 && i < 0x0EA8) && // Voice Prompt
(bIsAll ||
(
!(i >= 0x0D60 && i < 0x0E28) && // MR Channel Attributes
!(i >= 0x0F18 && i < 0x0F30) && // Scan List
!(i >= 0x0F50 && i < 0x1C00) && // MR Channel Names
!(i >= 0x0E40 && i < 0x0E70) && // FM Channels
!(i >= 0x0E88 && i < 0x0E90) // FM settings
))
)
{
EEPROM_WriteBuffer(i, Template);
}
}
if (bIsAll)
{
RADIO_InitInfo(gRxVfo, FREQ_CHANNEL_FIRST + BAND6_400MHz, 43350000);
// set the first few memory channels
for (i = 0; i < ARRAY_SIZE(gDefaultFrequencyTable); i++)
{
const uint32_t Frequency = gDefaultFrequencyTable[i];
gRxVfo->freq_config_RX.Frequency = Frequency;
gRxVfo->freq_config_TX.Frequency = Frequency;
gRxVfo->Band = FREQUENCY_GetBand(Frequency);
SETTINGS_SaveChannel(MR_CHANNEL_FIRST + i, 0, gRxVfo, 2);
}
}
}

View File

@@ -26,11 +26,6 @@ void BOARD_PORTCON_Init(void);
void BOARD_ADC_Init(void);
void BOARD_ADC_GetBatteryInfo(uint16_t *pVoltage, uint16_t *pCurrent);
void BOARD_Init(void);
void BOARD_EEPROM_Init(void);
void BOARD_EEPROM_LoadCalibration(void);
uint32_t BOARD_fetchChannelFrequency(const int channel);
void BOARD_fetchChannelName(char *s, const int channel);
void BOARD_FactoryReset(bool bIsAll);
#endif

View File

@@ -1,4 +1,4 @@
@echo off
docker build -t uvk5 .
docker run -v %CD%\compiled-firmware:/app/compiled-firmware uvk5 /bin/bash -c "cd /app && make clean && make && cp firmware* compiled-firmware/"
docker run --rm -v %CD%\compiled-firmware:/app/compiled-firmware uvk5 /bin/bash -c "cd /app && make clean && make && cp firmware* compiled-firmware/"
pause

View File

@@ -1,3 +1,3 @@
#!/bin/sh
docker build -t uvk5 .
docker run -v ${PWD}/compiled-firmware:/app/compiled-firmware uvk5 /bin/bash -c "cd /app && make && cp firmware* compiled-firmware/"
docker run --rm -v ${PWD}/compiled-firmware:/app/compiled-firmware uvk5 /bin/bash -c "cd /app && make && cp firmware* compiled-firmware/"

View File

@@ -1,18 +1,48 @@
#ifndef DEBUGGING_H
#define DEBUGGING_H
#ifdef ENABLE_UART
#include "driver/uart.h"
#include "driver/bk4819.h"
#include "string.h"
#include "external/printf/printf.h"
#include "am_fix.h"
static inline void LogUart(char * str)
static inline void LogUart(const char *const str)
{
UART_Send(str, strlen(str));
UART_Send(str, strlen(str));
}
static inline void LogUartf(const char* format, ...)
{
char buffer[128];
va_list va;
va_start(va, format);
vsnprintf(buffer, (size_t)-1, format, va);
va_end(va);
UART_Send(buffer, strlen(buffer));
}
static inline void LogRegUart(uint16_t reg)
{
uint16_t regVal = BK4819_ReadRegister(reg);
char buf[32];
sprintf(buf, "reg%02X: %04X\n", reg, regVal);
LogUart(buf);
}
static inline void LogPrint()
{
uint16_t rssi = BK4819_GetRSSI();
uint16_t reg7e = BK4819_ReadRegister(0x7E);
char buf[32];
sprintf(buf, "reg7E: %d %2d %6d %2d %d rssi: %d\n", (reg7e >> 15),
(reg7e >> 12) & 0b111, (reg7e >> 5) & 0b1111111,
(reg7e >> 2) & 0b111, (reg7e >> 0) & 0b11, rssi);
LogUart(buf);
}
#endif
#endif
#endif

View File

@@ -22,7 +22,7 @@
#include "settings.h"
// this is decremented once every 500ms
uint16_t gBacklightCountdown = 0;
uint16_t gBacklightCountdown_500ms = 0;
bool backlightOn;
void BACKLIGHT_InitHardware()
@@ -54,48 +54,47 @@ void BACKLIGHT_InitHardware()
void BACKLIGHT_TurnOn(void)
{
if (gEeprom.BACKLIGHT_TIME != 0) {
backlightOn = true;
BACKLIGHT_SetBrightness(gEeprom.BACKLIGHT_MAX);
}
else {
if (gEeprom.BACKLIGHT_TIME == 0) {
BACKLIGHT_TurnOff();
return;
}
switch (gEeprom.BACKLIGHT_TIME)
{
backlightOn = true;
BACKLIGHT_SetBrightness(gEeprom.BACKLIGHT_MAX);
switch (gEeprom.BACKLIGHT_TIME) {
default:
case 1: // 5 sec
gBacklightCountdown = 5;
break;
case 2: // 10 sec
gBacklightCountdown = 10;
break;
case 3: // 20 sec
gBacklightCountdown = 20;
gBacklightCountdown_500ms = 1 + (2 << (gEeprom.BACKLIGHT_TIME - 1)) * 5;
break;
case 4: // 1 min
gBacklightCountdown = 60;
break;
case 5: // 2 min
gBacklightCountdown = 60 * 2;
break;
case 6: // 4 min
gBacklightCountdown = 60 * 4;
gBacklightCountdown_500ms = 1 + (2 << (gEeprom.BACKLIGHT_TIME - 4)) * 60;
break;
case 7: // always on
gBacklightCountdown = 0;
gBacklightCountdown_500ms = 0;
break;
}
gBacklightCountdown *= 2;
}
void BACKLIGHT_TurnOff()
{
#ifdef ENABLE_BLMIN_TMP_OFF
register uint8_t tmp;
if (gEeprom.BACKLIGHT_MIN_STAT == BLMIN_STAT_ON)
tmp = gEeprom.BACKLIGHT_MIN;
else
tmp = 0;
BACKLIGHT_SetBrightness(tmp);
#else
BACKLIGHT_SetBrightness(gEeprom.BACKLIGHT_MIN);
gBacklightCountdown = 0;
#endif
gBacklightCountdown_500ms = 0;
backlightOn = false;
}
@@ -104,8 +103,16 @@ bool BACKLIGHT_IsOn()
return backlightOn;
}
static uint8_t currentBrightness;
void BACKLIGHT_SetBrightness(uint8_t brigtness)
{
currentBrightness = brigtness;
PWM_PLUS0_CH0_COMP = (1 << brigtness) - 1;
//PWM_PLUS0_SWLOAD = 1;
}
uint8_t BACKLIGHT_GetBrightness(void)
{
return currentBrightness;
}

View File

@@ -20,14 +20,22 @@
#include <stdint.h>
#include <stdbool.h>
extern uint16_t gBacklightCountdown;
extern uint16_t gBacklightCountdown_500ms;
extern uint8_t gBacklightBrightness;
#ifdef ENABLE_BLMIN_TMP_OFF
typedef enum {
BLMIN_STAT_ON,
BLMIN_STAT_OFF,
BLMIN_STAT_UNKNOWN
} BLMIN_STAT_t;
#endif
void BACKLIGHT_InitHardware();
void BACKLIGHT_TurnOn();
void BACKLIGHT_TurnOff();
bool BACKLIGHT_IsOn();
void BACKLIGHT_SetBrightness(uint8_t brigtness);
uint8_t BACKLIGHT_GetBrightness(void);
#endif

View File

@@ -39,16 +39,19 @@ static bool gIsInitBK1080;
uint16_t BK1080_BaseFrequency;
uint16_t BK1080_FrequencyDeviation;
void BK1080_Init(uint16_t Frequency, bool bDoScan)
void BK1080_Init0(void)
{
BK1080_Init(0,0/*,0*/);
}
void BK1080_Init(uint16_t freq, uint8_t band/*, uint8_t space*/)
{
unsigned int i;
if (bDoScan)
{
if (freq) {
GPIO_ClearBit(&GPIOB->DATA, GPIOB_PIN_BK1080);
if (!gIsInitBK1080)
{
if (!gIsInitBK1080) {
for (i = 0; i < ARRAY_SIZE(BK1080_RegisterTable); i++)
BK1080_WriteRegister(i, BK1080_RegisterTable[i]);
@@ -61,20 +64,14 @@ void BK1080_Init(uint16_t Frequency, bool bDoScan)
gIsInitBK1080 = true;
}
else
{
else {
BK1080_WriteRegister(BK1080_REG_02_POWER_CONFIGURATION, 0x0201);
}
BK1080_WriteRegister(BK1080_REG_05_SYSTEM_CONFIGURATION2, 0x0A5F);
BK1080_WriteRegister(BK1080_REG_03_CHANNEL, Frequency - 760);
SYSTEM_DelayMs(10);
BK1080_WriteRegister(BK1080_REG_03_CHANNEL, (Frequency - 760) | 0x8000);
BK1080_WriteRegister(BK1080_REG_05_SYSTEM_CONFIGURATION2, 0x0A1F);
BK1080_SetFrequency(freq, band/*, space*/);
}
else
{
else {
BK1080_WriteRegister(BK1080_REG_02_POWER_CONFIGURATION, 0x0241);
GPIO_SetBit(&GPIOB->DATA, GPIOB_PIN_BK1080);
}
@@ -108,11 +105,22 @@ void BK1080_Mute(bool Mute)
BK1080_WriteRegister(BK1080_REG_02_POWER_CONFIGURATION, Mute ? 0x4201 : 0x0201);
}
void BK1080_SetFrequency(uint16_t Frequency)
void BK1080_SetFrequency(uint16_t frequency, uint8_t band/*, uint8_t space*/)
{
BK1080_WriteRegister(BK1080_REG_03_CHANNEL, Frequency - 760);
//uint8_t spacings[] = {20,10,5};
//space %= 3;
uint16_t channel = (frequency - BK1080_GetFreqLoLimit(band))/* * 10 / spacings[space]*/;
uint16_t regval = BK1080_ReadRegister(BK1080_REG_05_SYSTEM_CONFIGURATION2);
regval = (regval & ~(0b11 << 6)) | ((band & 0b11) << 6);
//regval = (regval & ~(0b11 << 4)) | ((space & 0b11) << 4);
BK1080_WriteRegister(BK1080_REG_05_SYSTEM_CONFIGURATION2, regval);
BK1080_WriteRegister(BK1080_REG_03_CHANNEL, channel);
SYSTEM_DelayMs(10);
BK1080_WriteRegister(BK1080_REG_03_CHANNEL, (Frequency - 760) | 0x8000);
BK1080_WriteRegister(BK1080_REG_03_CHANNEL, channel | 0x8000);
}
void BK1080_GetFrequencyDeviation(uint16_t Frequency)
@@ -120,3 +128,17 @@ void BK1080_GetFrequencyDeviation(uint16_t Frequency)
BK1080_BaseFrequency = Frequency;
BK1080_FrequencyDeviation = BK1080_ReadRegister(BK1080_REG_07) / 16;
}
uint16_t BK1080_GetFreqLoLimit(uint8_t band)
{
uint16_t lim[] = {875, 760, 760, 640};
return lim[band % 4];
}
uint16_t BK1080_GetFreqHiLimit(uint8_t band)
{
band %= 4;
uint16_t lim[] = {1080, 1080, 900, 760};
return lim[band % 4];
}

View File

@@ -24,11 +24,14 @@
extern uint16_t BK1080_BaseFrequency;
extern uint16_t BK1080_FrequencyDeviation;
void BK1080_Init(uint16_t Frequency, bool bDoScan);
void BK1080_Init0(void);
void BK1080_Init(uint16_t Frequency, uint8_t band/*, uint8_t space*/);
uint16_t BK1080_ReadRegister(BK1080_Register_t Register);
void BK1080_WriteRegister(BK1080_Register_t Register, uint16_t Value);
void BK1080_Mute(bool Mute);
void BK1080_SetFrequency(uint16_t Frequency);
uint16_t BK1080_GetFreqLoLimit(uint8_t band);
uint16_t BK1080_GetFreqHiLimit(uint8_t band);
void BK1080_SetFrequency(uint16_t frequency, uint8_t band/*, uint8_t space*/);
void BK1080_GetFrequencyDeviation(uint16_t Frequency);
#endif

View File

@@ -17,6 +17,7 @@
#ifndef BK4819_REGS_H
#define BK4819_REGS_H
#include <stdint.h>
typedef struct {
const char *name;
@@ -41,10 +42,15 @@ enum BK4819_REGISTER_t {
BK4819_REG_0C = 0x0CU,
BK4819_REG_0D = 0x0DU,
BK4819_REG_0E = 0x0EU,
// RX AGC Gain Table[0]
BK4819_REG_10 = 0x10U,
// RX AGC Gain Table[1]
BK4819_REG_11 = 0x11U,
// RX AGC Gain Table[2]
BK4819_REG_12 = 0x12U,
// RX AGC Gain Table[3]
BK4819_REG_13 = 0x13U,
// RX AGC Gain Table[-1]
BK4819_REG_14 = 0x14U,
BK4819_REG_19 = 0x19U,
BK4819_REG_1F = 0x1FU,
@@ -72,6 +78,12 @@ enum BK4819_REGISTER_t {
BK4819_REG_46 = 0x46U,
BK4819_REG_47 = 0x47U,
BK4819_REG_48 = 0x48U,
// REG_49<15:14> 0b00; High/Low Lo selection:
// 0X: Auto High/Low Lo
// 10: Low Lo
// 11: High Lo
// REG_49<13:7> 0x50; RF AGC high threshold, 1 dB/LSB
// REG_49<6:0> 0x30; RF AGC low threshold, 1 dB/LSB
BK4819_REG_49 = 0x49U,
BK4819_REG_4D = 0x4DU,
BK4819_REG_4E = 0x4EU,
@@ -100,9 +112,22 @@ enum BK4819_REGISTER_t {
BK4819_REG_78 = 0x78U,
BK4819_REG_79 = 0x79U,
BK4819_REG_7A = 0x7AU,
// REG_7B<15:0> 0xae34 RSSI table
BK4819_REG_7B = 0x7BU,
// REG_7C<15:0> 0x8000 RSSI table
BK4819_REG_7C = 0x7CU,
BK4819_REG_7D = 0x7DU,
// REG_7E<15> 0; AGC fix mode:
// 1: Fix
// 0: Auto
// REG_7E<14:12> 0b011; AGC fix index:
// 011: Max.
// …
// 100: Min.
// REG_7E<5:3> 0b101; DC filter bandwidth for TX (MIC in):
// 000: Bypass DC filter
// REG_7E<2:0> 0b110; DC filter bandwidth for RX (IF in):
// 000: Bypass DC filter
BK4819_REG_7E = 0x7EU,
};
@@ -363,4 +388,3 @@ enum {
};
#endif

View File

@@ -14,15 +14,20 @@
* limitations under the License.
*/
#include <stdio.h> // NULL
#include <stdint.h>
#include <stdio.h>
#include "settings.h"
#include "../audio.h"
#include "../bsp/dp32g030/gpio.h"
#include "../bsp/dp32g030/portcon.h"
#include "audio.h"
#include "bk4819.h"
#include "bsp/dp32g030/gpio.h"
#include "bsp/dp32g030/portcon.h"
#include "driver/gpio.h"
#include "driver/system.h"
#include "driver/systick.h"
#include "gpio.h"
#include "system.h"
#include "systick.h"
#ifndef ARRAY_SIZE
#define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))
@@ -30,6 +35,9 @@
static const uint16_t FSK_RogerTable[7] = {0xF1A2, 0x7446, 0x61A4, 0x6544, 0x4E8A, 0xE044, 0xEA84};
static const uint8_t DTMF_TONE1_GAIN = 65;
static const uint8_t DTMF_TONE2_GAIN = 93;
static uint16_t gBK4819_GpioOutState;
bool gRxIdleMode;
@@ -52,8 +60,8 @@ void BK4819_Init(void)
BK4819_WriteRegister(BK4819_REG_37, 0x1D0F);
BK4819_WriteRegister(BK4819_REG_36, 0x0022);
BK4819_DisableAGC();
// BK4819_EnableAGC();
BK4819_InitAGC(false);
BK4819_SetAGC(true);
BK4819_WriteRegister(BK4819_REG_19, 0b0001000001000001); // <15> MIC AGC 1 = disable 0 = enable
@@ -124,7 +132,6 @@ static uint16_t BK4819_ReadU16(void)
PORTCON_PORTC_IE = (PORTCON_PORTC_IE & ~PORTCON_PORTC_IE_C2_MASK) | PORTCON_PORTC_IE_C2_BITS_ENABLE;
GPIOC->DIR = (GPIOC->DIR & ~GPIO_DIR_2_MASK) | GPIO_DIR_2_BITS_INPUT;
SYSTICK_DelayUs(1);
Value = 0;
for (i = 0; i < 16; i++)
{
@@ -233,19 +240,46 @@ void BK4819_WriteU16(uint16_t Data)
}
}
void BK4819_DisableAGC()
void BK4819_SetAGC(bool enable)
{
// REG_10
uint16_t regVal = BK4819_ReadRegister(BK4819_REG_7E);
if(!(regVal & (1 << 15)) == enable)
return;
BK4819_WriteRegister(BK4819_REG_7E, (regVal & ~(1 << 15) & ~(0b111 << 12))
| (!enable << 15) // 0 AGC fix mode
| (3u << 12) // 3 AGC fix index
);
// if(enable) {
// BK4819_WriteRegister(BK4819_REG_7B, 0x8420);
// }
// else {
// BK4819_WriteRegister(BK4819_REG_7B, 0x318C);
// BK4819_WriteRegister(BK4819_REG_7C, 0x595E);
// BK4819_WriteRegister(BK4819_REG_20, 0x8DEF);
// for (uint8_t i = 0; i < 8; i++) {
// //BK4819_WriteRegister(BK4819_REG_06, ((i << 13) | 0x2500u) + 0x036u);
// BK4819_WriteRegister(BK4819_REG_06, (i & 7) << 13 | 0x4A << 7 | 0x36);
// }
// }
}
void BK4819_InitAGC(bool amModulation)
{
// REG_10, REG_11, REG_12 REG_13, REG_14
//
// 0x0038 Rx AGC Gain Table[0]. (Index Max->Min is 3,2,1,0,-1)
// Rx AGC Gain Table[]. (Index Max->Min is 3,2,1,0,-1)
//
// <15:10> ???
//
// <9:8> LNA Gain Short
// 3 = 0dB <<<
// 2 = -24dB // was -11
// 1 = -30dB // was -16
// 0 = -33dB // was -19
// 3 = 0dB <<< 1o11 read from spectrum reference manual
// 2 = -24dB -19 -11
// 1 = -30dB -24 -16
// 0 = -33dB -28 -19
//
// <7:5> LNA Gain
// 7 = 0dB
@@ -273,74 +307,60 @@ void BK4819_DisableAGC()
// 1 = -27dB
// 0 = -33dB
//
BK4819_WriteRegister(BK4819_REG_13, (3u << 8) | (5u << 5) | (3u << 3) | (6u << 0)); // 000000 11 101 11 110
BK4819_WriteRegister(BK4819_REG_12, 0x037B); // 000000 11 011 11 011
BK4819_WriteRegister(BK4819_REG_11, 0x027B); // 000000 10 011 11 011
BK4819_WriteRegister(BK4819_REG_10, 0x007A); // 000000 00 011 11 010
BK4819_WriteRegister(BK4819_REG_14, 0x0019); // 000000 00 000 11 001
BK4819_WriteRegister(BK4819_REG_13, 0x03BE); // 0x03BE / 000000 11 101 11 110 / -7dB
BK4819_WriteRegister(BK4819_REG_12, 0x037B); // 0x037B / 000000 11 011 11 011 / -24dB
BK4819_WriteRegister(BK4819_REG_11, 0x027B); // 0x027B / 000000 10 011 11 011 / -43dB
BK4819_WriteRegister(BK4819_REG_10, 0x007A); // 0x007A / 000000 00 011 11 010 / -58dB
if(amModulation) {
BK4819_WriteRegister(BK4819_REG_14, 0x0000);
BK4819_WriteRegister(BK4819_REG_49, (0 << 14) | (50 << 7) | (32 << 0));
}
else{
BK4819_WriteRegister(BK4819_REG_14, 0x0019); // 0x0019 / 000000 00 000 11 001 / -79dB
BK4819_WriteRegister(BK4819_REG_49, (0 << 14) | (84 << 7) | (56 << 0)); //0x2A38 / 00 1010100 0111000 / 84, 56
}
BK4819_WriteRegister(BK4819_REG_49, 0x2A38);
BK4819_WriteRegister(BK4819_REG_7B, 0x8420);
}
void BK4819_EnableAGC()
{
// REG_10
//
// 0x0038 Rx AGC Gain Table[0]. (Index Max->Min is 3,2,1,0,-1)
//
// (15:10> ???
//
// <9:8> LNA Gain Short
// 3 = 0dB << original
// 2 = -24dB // was -11
// 1 = -30dB // was -16
// 0 = -33dB // was -19
//
// <7:5> LNA Gain
// 7 = 0dB
// 6 = -2dB
// 5 = -4dB
// 4 = -6dB
// 3 = -9dB
// 2 = -14dB << original
// 1 = -19dB
// 0 = -24dB
//
// <4:3> MIXER Gain
// 3 = 0dB << original
// 2 = -3dB
// 1 = -6dB
// 0 = -8dB
//
// <2:0> PGA Gain
// 7 = 0dB
// 6 = -3dB << original
// 5 = -6dB
// 4 = -9dB
// 3 = -15dB
// 2 = -21dB
// 1 = -27dB
// 0 = -33dB
//
BK4819_WriteRegister(BK4819_REG_13, (3u << 8) | (5u << 5) | (3u << 3) | (6u << 0));
int8_t BK4819_GetRxGain_dB(void)
{
union {
struct {
uint16_t pga:3;
uint16_t mixer:2;
uint16_t lna:3;
uint16_t lnaS:2;
};
uint16_t __raw;
} agcGainReg;
BK4819_WriteRegister(BK4819_REG_12, 0x037C); // 000000 11 011 11 100
BK4819_WriteRegister(BK4819_REG_11, 0x027B); // 000000 10 011 11 011
BK4819_WriteRegister(BK4819_REG_10, 0x007A); // 000000 00 011 11 010
BK4819_WriteRegister(BK4819_REG_14, 0x0018); // 000000 00 000 11 000
union {
struct {
uint16_t _ : 5;
uint16_t agcSigStrength : 7;
int16_t gainIdx : 3;
uint16_t agcEnab : 1;
};
uint16_t __raw;
} reg7e;
BK4819_WriteRegister(BK4819_REG_49, 0x2A38);
BK4819_WriteRegister(BK4819_REG_7B, 0x318C);
reg7e.__raw = BK4819_ReadRegister(BK4819_REG_7E);
uint8_t gainAddr = reg7e.gainIdx < 0 ? BK4819_REG_14 : BK4819_REG_10 + reg7e.gainIdx;
agcGainReg.__raw = BK4819_ReadRegister(gainAddr);
int8_t lnaShortTab[] = {-28, -24, -19, 0};
int8_t lnaTab[] = {-24, -19, -14, -9, -6, -4, -2, 0};
int8_t mixerTab[] = {-8, -6, -3, 0};
int8_t pgaTab[] = {-33, -27, -21, -15, -9, -6, -3, 0};
return lnaShortTab[agcGainReg.lnaS] + lnaTab[agcGainReg.lna] + mixerTab[agcGainReg.mixer] + pgaTab[agcGainReg.pga];
}
BK4819_WriteRegister(BK4819_REG_7C, 0x595E);
BK4819_WriteRegister(BK4819_REG_20, 0x8DEF);
for (uint8_t i = 0; i < 8; i++) {
//BK4819_WriteRegister(BK4819_REG_06, ((i << 13) | 0x2500u) + 0x036u);
BK4819_WriteRegister(BK4819_REG_06, (i & 7) << 13 | 0x4A << 7 | 0x36);
}
int16_t BK4819_GetRSSI_dBm(void)
{
uint16_t rssi = BK4819_GetRSSI();
return (rssi / 2) - 160;// - BK4819_GetRxGain_dB();
}
void BK4819_ToggleGpioOut(BK4819_GPIO_PIN_t Pin, bool bSet)
@@ -588,89 +608,54 @@ void BK4819_SetFilterBandwidth(const BK4819_FilterBandwidth_t Bandwidth, const b
//
// <1:0> 0 ???
uint16_t val;
uint16_t val = 0;
switch (Bandwidth)
{
default:
case BK4819_FILTER_BW_WIDE: // 25kHz
if (weak_no_different)
{ // make the RX bandwidth the same with weak signals
val =
(0u << 15) | // 0
(4u << 12) | // *3 RF filter bandwidth
(4u << 9) | // *0 RF filter bandwidth when signal is weak
(6u << 6) | // *0 AFTxLPF2 filter Band Width
(2u << 4) | // 2 BW Mode Selection
(1u << 3) | // 1
(0u << 2) | // 0 Gain after FM Demodulation
(0u << 0); // 0
}
else
{ // with weak RX signals the RX bandwidth is reduced
val = // 0x3028); // 0 011 000 000 10 1 0 00
(0u << 15) | // 0
(4u << 12) | // *3 RF filter bandwidth
(2u << 9) | // *0 RF filter bandwidth when signal is weak
(6u << 6) | // *0 AFTxLPF2 filter Band Width
(2u << 4) | // 2 BW Mode Selection
(1u << 3) | // 1
(0u << 2) | // 0 Gain after FM Demodulation
(0u << 0); // 0
val = (4u << 12) | // *3 RF filter bandwidth
(6u << 6) | // *0 AFTxLPF2 filter Band Width
(2u << 4) | // 2 BW Mode Selection
(1u << 3) | // 1
(0u << 2); // 0 Gain after FM Demodulation
if (weak_no_different) {
// make the RX bandwidth the same with weak signals
val |= (4u << 9); // *0 RF filter bandwidth when signal is weak
} else {
/// with weak RX signals the RX bandwidth is reduced
val |= (2u << 9); // *0 RF filter bandwidth when signal is weak
}
break;
case BK4819_FILTER_BW_NARROW: // 12.5kHz
if (weak_no_different)
{
val =
(0u << 15) | // 0
(4u << 12) | // *4 RF filter bandwidth
(4u << 9) | // *0 RF filter bandwidth when signal is weak
(0u << 6) | // *1 AFTxLPF2 filter Band Width
(0u << 4) | // 0 BW Mode Selection
(1u << 3) | // 1
(0u << 2) | // 0 Gain after FM Demodulation
(0u << 0); // 0
}
else
{
val = // 0x4048); // 0 100 000 001 00 1 0 00
(0u << 15) | // 0
(4u << 12) | // *4 RF filter bandwidth
(2u << 9) | // *0 RF filter bandwidth when signal is weak
(0u << 6) | // *1 AFTxLPF2 filter Band Width
(0u << 4) | // 0 BW Mode Selection
(1u << 3) | // 1
(0u << 2) | // 0 Gain after FM Demodulation
(0u << 0); // 0
val = (4u << 12) | // *4 RF filter bandwidth
(0u << 6) | // *1 AFTxLPF2 filter Band Width
(0u << 4) | // 0 BW Mode Selection
(1u << 3) | // 1
(0u << 2); // 0 Gain after FM Demodulation
if (weak_no_different) {
val |= (4u << 9); // *0 RF filter bandwidth when signal is weak
} else {
val |= (2u << 9);
}
break;
case BK4819_FILTER_BW_NARROWER: // 6.25kHz
if (weak_no_different)
{
val =
(0u << 15) | // 0
(3u << 12) | // 3 RF filter bandwidth
(3u << 9) | // *0 RF filter bandwidth when signal is weak
(1u << 6) | // 1 AFTxLPF2 filter Band Width
(1u << 4) | // 1 BW Mode Selection
(1u << 3) | // 1
(0u << 2) | // 0 Gain after FM Demodulation
(0u << 0); // 0
}
else
{
val =
(0u << 15) | // 0
(3u << 12) | // 3 RF filter bandwidth
(0u << 9) | // 0 RF filter bandwidth when signal is weak
(1u << 6) | // 1 AFTxLPF2 filter Band Width
(1u << 4) | // 1 BW Mode Selection
(1u << 3) | // 1
(0u << 2) | // 1 Gain after FM Demodulation
(0u << 0); // 0
val = (3u << 12) | // 3 RF filter bandwidth
(3u << 9) | // *0 RF filter bandwidth when signal is weak
(1u << 6) | // 1 AFTxLPF2 filter Band Width
(1u << 4) | // 1 BW Mode Selection
(1u << 3) | // 1
(0u << 2); // 0 Gain after FM Demodulation
if (weak_no_different) {
val |= (3u << 9);
} else {
val |= (0u << 9); // 0 RF filter bandwidth when signal is weak
}
break;
}
@@ -696,7 +681,7 @@ void BK4819_SetupPowerAmplifier(const uint8_t bias, const uint32_t frequency)
// 7 = max
// 0 = min
//
// 280MHz gain 1 = 1 gain 2 = 0 gain 1 = 4 gain 2 = 2
// 280MHz g1=1 g2=0 (-14.9dBm), g1=4 g2=2 (0.13dBm)
const uint8_t gain = (frequency < 28000000) ? (1u << 3) | (0u << 0) : (4u << 3) | (2u << 0);
const uint8_t enable = 1;
BK4819_WriteRegister(BK4819_REG_36, (bias << 8) | (enable << 7) | (gain << 0));
@@ -825,16 +810,18 @@ void BK4819_RX_TurnOn(void)
// Turn off everything
BK4819_WriteRegister(BK4819_REG_30, 0);
// Enable VCO Calibration
// Enable RX Link
// Enable AF DAC
// Enable PLL/VCO
// Disable PA Gain
// Disable MIC ADC
// Disable TX DSP
// Enable RX DSP
//
BK4819_WriteRegister(BK4819_REG_30, 0b1011111111110001); // 1 0 1111 1 1 1111 0 0 0 1
BK4819_WriteRegister(BK4819_REG_30,
BK4819_REG_30_ENABLE_VCO_CALIB |
BK4819_REG_30_DISABLE_UNKNOWN |
BK4819_REG_30_ENABLE_RX_LINK |
BK4819_REG_30_ENABLE_AF_DAC |
BK4819_REG_30_ENABLE_DISC_MODE |
BK4819_REG_30_ENABLE_PLL_VCO |
BK4819_REG_30_DISABLE_PA_GAIN |
BK4819_REG_30_DISABLE_MIC_ADC |
BK4819_REG_30_DISABLE_TX_DSP |
BK4819_REG_30_ENABLE_RX_DSP );
}
void BK4819_PickRXFilterPathBasedOnFrequency(uint32_t Frequency)
@@ -984,15 +971,15 @@ void BK4819_EnableDTMF(void)
void BK4819_PlayTone(uint16_t Frequency, bool bTuningGainSwitch)
{
uint16_t ToneConfig;
uint16_t ToneConfig = BK4819_REG_70_ENABLE_TONE1;
BK4819_EnterTxMute();
BK4819_SetAF(BK4819_AF_BEEP);
if (bTuningGainSwitch == 0)
ToneConfig = BK4819_REG_70_ENABLE_TONE1 | (96u << BK4819_REG_70_SHIFT_TONE1_TUNING_GAIN);
ToneConfig |= 96u << BK4819_REG_70_SHIFT_TONE1_TUNING_GAIN;
else
ToneConfig = BK4819_REG_70_ENABLE_TONE1 | (28u << BK4819_REG_70_SHIFT_TONE1_TUNING_GAIN);
ToneConfig |= 28u << BK4819_REG_70_SHIFT_TONE1_TUNING_GAIN;
BK4819_WriteRegister(BK4819_REG_70, ToneConfig);
BK4819_WriteRegister(BK4819_REG_30, 0);
@@ -1001,10 +988,11 @@ void BK4819_PlayTone(uint16_t Frequency, bool bTuningGainSwitch)
BK4819_WriteRegister(BK4819_REG_71, scale_freq(Frequency));
}
// level 0 ~ 127
void BK4819_PlaySingleTone(const unsigned int tone_Hz, const unsigned int delay, const unsigned int level, const bool play_speaker)
{
BK4819_EnterTxMute();
if (play_speaker)
{
AUDIO_AudioPathOn();
@@ -1013,9 +1001,7 @@ void BK4819_PlaySingleTone(const unsigned int tone_Hz, const unsigned int delay,
else
BK4819_SetAF(BK4819_AF_MUTE);
// level 0 ~ 127
// BK4819_WriteRegister(BK4819_REG_70, BK4819_REG_70_ENABLE_TONE1 | (96u << BK4819_REG_70_SHIFT_TONE1_TUNING_GAIN));
// BK4819_WriteRegister(BK4819_REG_70, BK4819_REG_70_ENABLE_TONE1 | (28u << BK4819_REG_70_SHIFT_TONE1_TUNING_GAIN));
BK4819_WriteRegister(BK4819_REG_70, BK4819_REG_70_ENABLE_TONE1 | ((level & 0x7f) << BK4819_REG_70_SHIFT_TONE1_TUNING_GAIN));
BK4819_EnableTXLink();
@@ -1032,9 +1018,10 @@ void BK4819_PlaySingleTone(const unsigned int tone_Hz, const unsigned int delay,
AUDIO_AudioPathOff();
BK4819_SetAF(BK4819_AF_MUTE);
}
BK4819_WriteRegister(BK4819_REG_70, 0x0000);
BK4819_WriteRegister(BK4819_REG_30, 0xC1FE);
BK4819_ExitTxMute();
}
void BK4819_EnterTxMute(void)
@@ -1127,11 +1114,15 @@ void BK4819_ExitBypass(void)
// 0 ~ 7
// 0 = bypass DC filter
//
BK4819_WriteRegister(BK4819_REG_7E, // 0x302E); // 0 011 000000 101 110
(0u << 15) | // 0 AGC fix mode
(3u << 12) | // 3 AGC fix index
(5u << 3) | // 5 DC Filter band width for Tx (MIC In)
(6u << 0)); // 6 DC Filter band width for Rx (I.F In)
uint16_t regVal = BK4819_ReadRegister(BK4819_REG_7E);
// 0x302E / 0 011 000000 101 110
BK4819_WriteRegister(BK4819_REG_7E, (regVal & ~(0b111 << 3))
| (5u << 3) // 5 DC Filter band width for Tx (MIC In)
);
}
void BK4819_PrepareTransmit(void)
@@ -1208,9 +1199,9 @@ void BK4819_EnterDTMF_TX(bool bLocalLoopback)
BK4819_WriteRegister(BK4819_REG_70,
BK4819_REG_70_MASK_ENABLE_TONE1 |
(83u << BK4819_REG_70_SHIFT_TONE1_TUNING_GAIN) |
(DTMF_TONE1_GAIN << BK4819_REG_70_SHIFT_TONE1_TUNING_GAIN) |
BK4819_REG_70_MASK_ENABLE_TONE2 |
(83u << BK4819_REG_70_SHIFT_TONE2_TUNING_GAIN));
(DTMF_TONE2_GAIN << BK4819_REG_70_SHIFT_TONE2_TUNING_GAIN));
BK4819_EnableTXLink();
}
@@ -1243,33 +1234,46 @@ void BK4819_EnableTXLink(void)
void BK4819_PlayDTMF(char Code)
{
uint16_t tone1 = 0;
uint16_t tone2 = 0;
struct DTMF_TonePair {
uint16_t tone1;
uint16_t tone2;
};
const struct DTMF_TonePair tones[] = {
{941, 1336},
{697, 1209},
{697, 1336},
{697, 1477},
{770, 1209},
{770, 1336},
{770, 1477},
{852, 1209},
{852, 1336},
{852, 1477},
{697, 1633},
{770, 1633},
{852, 1633},
{941, 1633},
{941, 1209},
{941, 1477},
};
const struct DTMF_TonePair *pSelectedTone = NULL;
switch (Code)
{
case '0': tone1 = 941; tone2 = 1336; break;
case '1': tone1 = 679; tone2 = 1209; break;
case '2': tone1 = 697; tone2 = 1336; break;
case '3': tone1 = 679; tone2 = 1477; break;
case '4': tone1 = 770; tone2 = 1209; break;
case '5': tone1 = 770; tone2 = 1336; break;
case '6': tone1 = 770; tone2 = 1477; break;
case '7': tone1 = 852; tone2 = 1209; break;
case '8': tone1 = 852; tone2 = 1336; break;
case '9': tone1 = 852; tone2 = 1477; break;
case 'A': tone1 = 679; tone2 = 1633; break;
case 'B': tone1 = 770; tone2 = 1633; break;
case 'C': tone1 = 852; tone2 = 1633; break;
case 'D': tone1 = 941; tone2 = 1633; break;
case '*': tone1 = 941; tone2 = 1209; break;
case '#': tone1 = 941; tone2 = 1477; break;
case '0'...'9': pSelectedTone = &tones[0 + Code - '0']; break;
case 'A'...'D': pSelectedTone = &tones[10 + Code - 'A']; break;
case '*': pSelectedTone = &tones[14]; break;
case '#': pSelectedTone = &tones[15]; break;
default: pSelectedTone = NULL;
}
if (tone1 > 0)
BK4819_WriteRegister(BK4819_REG_71, (((uint32_t)tone1 * 103244) + 5000) / 10000); // with rounding
if (tone2 > 0)
BK4819_WriteRegister(BK4819_REG_72, (((uint32_t)tone2 * 103244) + 5000) / 10000); // with rounding
if (pSelectedTone) {
BK4819_WriteRegister(BK4819_REG_71, (((uint32_t)pSelectedTone->tone1 * 103244) + 5000) / 10000); // with rounding
BK4819_WriteRegister(BK4819_REG_72, (((uint32_t)pSelectedTone->tone2 * 103244) + 5000) / 10000); // with rounding
}
}
void BK4819_PlayDTMFString(const char *pString, bool bDelayFirst, uint16_t FirstCodePersistTime, uint16_t HashCodePersistTime, uint16_t CodePersistTime, uint16_t CodeInternalTime)
@@ -1319,8 +1323,7 @@ void BK4819_TransmitTone(bool bLocalLoopback, uint32_t Frequency)
//
// set the tone amplitude
//
// BK4819_WriteRegister(BK4819_REG_70, BK4819_REG_70_MASK_ENABLE_TONE1 | (96u << BK4819_REG_70_SHIFT_TONE1_TUNING_GAIN));
BK4819_WriteRegister(BK4819_REG_70, BK4819_REG_70_MASK_ENABLE_TONE1 | (28u << BK4819_REG_70_SHIFT_TONE1_TUNING_GAIN));
BK4819_WriteRegister(BK4819_REG_70, BK4819_REG_70_MASK_ENABLE_TONE1 | (66u << BK4819_REG_70_SHIFT_TONE1_TUNING_GAIN));
BK4819_WriteRegister(BK4819_REG_71, scale_freq(Frequency));
@@ -1392,18 +1395,16 @@ void BK4819_GenTail(uint8_t Tail)
}
}
void BK4819_EnableCDCSS(void)
void BK4819_PlayCDCSSTail(void)
{
BK4819_GenTail(0); // CTC134
BK4819_WriteRegister(BK4819_REG_51, 0x804A);
BK4819_WriteRegister(BK4819_REG_51, 0x804A); // 1 0 0 0 0 0 0 0 0 1001010
}
void BK4819_EnableCTCSS(void)
void BK4819_PlayCTCSSTail(void)
{
#ifdef ENABLE_CTCSS_TAIL_PHASE_SHIFT
//BK4819_GenTail(1); // 120° phase shift
BK4819_GenTail(2); // 180° phase shift
//BK4819_GenTail(3); // 240° phase shift
#else
BK4819_GenTail(4); // 55Hz tone freq
#endif
@@ -1445,7 +1446,7 @@ void BK4819_EnableCTCSS(void)
// 0 = min
// 127 = max
BK4819_WriteRegister(BK4819_REG_51, 0x904A); // 1 0 0 1 0 0 0 0 0 1001010
BK4819_WriteRegister(BK4819_REG_51, 0x904A); // 1 0 0 1 0 0 0 0 0 1001010
}
uint16_t BK4819_GetRSSI(void)
@@ -1685,7 +1686,7 @@ void BK4819_PrepareFSKReceive(void)
BK4819_WriteRegister(BK4819_REG_59, 0x3068);
}
void BK4819_PlayRoger(void)
static void BK4819_PlayRogerNormal(void)
{
#if 0
const uint32_t tone1_Hz = 500;
@@ -1696,11 +1697,11 @@ void BK4819_PlayRoger(void)
const uint32_t tone2_Hz = 1310;
#endif
BK4819_EnterTxMute();
BK4819_SetAF(BK4819_AF_MUTE);
// BK4819_WriteRegister(BK4819_REG_70, BK4819_REG_70_ENABLE_TONE1 | (96u << BK4819_REG_70_SHIFT_TONE1_TUNING_GAIN));
BK4819_WriteRegister(BK4819_REG_70, BK4819_REG_70_ENABLE_TONE1 | (28u << BK4819_REG_70_SHIFT_TONE1_TUNING_GAIN));
BK4819_WriteRegister(BK4819_REG_70, BK4819_REG_70_ENABLE_TONE1 | (66u << BK4819_REG_70_SHIFT_TONE1_TUNING_GAIN));
BK4819_EnableTXLink();
SYSTEM_DelayMs(50);
@@ -1721,30 +1722,41 @@ void BK4819_PlayRoger(void)
BK4819_WriteRegister(BK4819_REG_30, 0xC1FE); // 1 1 0000 0 1 1111 1 1 1 0
}
void BK4819_PlayRogerMDC(void)
{
unsigned int i;
struct reg_value {
BK4819_REGISTER_t reg;
uint16_t value;
};
struct reg_value RogerMDC_Configuration [] = {
{ BK4819_REG_58, 0x37C3 }, // FSK Enable,
// RX Bandwidth FFSK 1200/1800
// 0xAA or 0x55 Preamble
// 11 RX Gain,
// 101 RX Mode
// TX FFSK 1200/1800
{ BK4819_REG_72, 0x3065 }, // Set Tone-2 to 1200Hz
{ BK4819_REG_70, 0x00E0 }, // Enable Tone-2 and Set Tone2 Gain
{ BK4819_REG_5D, 0x0D00 }, // Set FSK data length to 13 bytes
{ BK4819_REG_59, 0x8068 }, // 4 byte sync length, 6 byte preamble, clear TX FIFO
{ BK4819_REG_59, 0x0068 }, // Same, but clear TX FIFO is now unset (clearing done)
{ BK4819_REG_5A, 0x5555 }, // First two sync bytes
{ BK4819_REG_5B, 0x55AA }, // End of sync bytes. Total 4 bytes: 555555aa
{ BK4819_REG_5C, 0xAA30 }, // Disable CRC
};
BK4819_SetAF(BK4819_AF_MUTE);
BK4819_WriteRegister(BK4819_REG_58, 0x37C3); // FSK Enable,
// RX Bandwidth FFSK 1200/1800
// 0xAA or 0x55 Preamble
// 11 RX Gain,
// 101 RX Mode
// TX FFSK 1200/1800
BK4819_WriteRegister(BK4819_REG_72, 0x3065); // Set Tone-2 to 1200Hz
BK4819_WriteRegister(BK4819_REG_70, 0x00E0); // Enable Tone-2 and Set Tone2 Gain
BK4819_WriteRegister(BK4819_REG_5D, 0x0D00); // Set FSK data length to 13 bytes
BK4819_WriteRegister(BK4819_REG_59, 0x8068); // 4 byte sync length, 6 byte preamble, clear TX FIFO
BK4819_WriteRegister(BK4819_REG_59, 0x0068); // Same, but clear TX FIFO is now unset (clearing done)
BK4819_WriteRegister(BK4819_REG_5A, 0x5555); // First two sync bytes
BK4819_WriteRegister(BK4819_REG_5B, 0x55AA); // End of sync bytes. Total 4 bytes: 555555aa
BK4819_WriteRegister(BK4819_REG_5C, 0xAA30); // Disable CRC
for (unsigned int i = 0; i < ARRAY_SIZE(RogerMDC_Configuration); i++) {
BK4819_WriteRegister(RogerMDC_Configuration[i].reg, RogerMDC_Configuration[i].value);
}
// Send the data from the roger table
for (i = 0; i < 7; i++)
for (unsigned int i = 0; i < ARRAY_SIZE(FSK_RogerTable); i++) {
BK4819_WriteRegister(BK4819_REG_5F, FSK_RogerTable[i]);
}
SYSTEM_DelayMs(20);
@@ -1759,6 +1771,15 @@ void BK4819_PlayRogerMDC(void)
BK4819_WriteRegister(BK4819_REG_58, 0x0000);
}
void BK4819_PlayRoger(void)
{
if (gEeprom.ROGER == ROGER_MODE_ROGER) {
BK4819_PlayRogerNormal();
} else if (gEeprom.ROGER == ROGER_MODE_MDC) {
BK4819_PlayRogerMDC();
}
}
void BK4819_Enable_AfDac_DiscMode_TxDsp(void)
{
BK4819_WriteRegister(BK4819_REG_30, 0x0000);
@@ -1781,7 +1802,12 @@ void BK4819_PlayDTMFEx(bool bLocalLoopback, char Code)
BK4819_EnterTxMute();
BK4819_SetAF(bLocalLoopback ? BK4819_AF_BEEP : BK4819_AF_MUTE);
BK4819_WriteRegister(BK4819_REG_70, 0xD3D3);
BK4819_WriteRegister(BK4819_REG_70,
BK4819_REG_70_MASK_ENABLE_TONE1 |
(DTMF_TONE1_GAIN << BK4819_REG_70_SHIFT_TONE1_TUNING_GAIN) |
BK4819_REG_70_MASK_ENABLE_TONE2 |
(DTMF_TONE2_GAIN << BK4819_REG_70_SHIFT_TONE2_TUNING_GAIN));
BK4819_EnableTXLink();

View File

@@ -38,7 +38,7 @@ enum BK4819_AF_Type_t
BK4819_AF_UNKNOWN5 = 11u, // distorted
BK4819_AF_UNKNOWN6 = 12u, // distorted
BK4819_AF_UNKNOWN7 = 13u, // interesting
BK4819_AF_UNKNOWN8 = 14u, // interesting
BK4819_AF_UNKNOWN8 = 14u, // interesting
BK4819_AF_UNKNOWN9 = 15u // not a lot
};
@@ -72,8 +72,8 @@ void BK4819_SetRegValue(RegisterSpec s, uint16_t v);
void BK4819_WriteU8(uint8_t Data);
void BK4819_WriteU16(uint16_t Data);
void BK4819_EnableAGC();
void BK4819_DisableAGC();
void BK4819_SetAGC(bool enable);
void BK4819_InitAGC(bool amModulation);
void BK4819_ToggleGpioOut(BK4819_GPIO_PIN_t Pin, bool bSet);
@@ -132,10 +132,12 @@ void BK4819_PlayDTMFString(const char *pString, bool bDelayFirst, uint16_t F
void BK4819_TransmitTone(bool bLocalLoopback, uint32_t Frequency);
void BK4819_GenTail(uint8_t Tail);
void BK4819_EnableCDCSS(void);
void BK4819_EnableCTCSS(void);
void BK4819_PlayCDCSSTail(void);
void BK4819_PlayCTCSSTail(void);
uint16_t BK4819_GetRSSI(void);
int8_t BK4819_GetRxGain_dB(void);
int16_t BK4819_GetRSSI_dBm(void);
uint8_t BK4819_GetGlitchIndicator(void);
uint8_t BK4819_GetExNoiceIndicator(void);
uint16_t BK4819_GetVoiceAmplitudeOut(void);
@@ -159,15 +161,13 @@ uint8_t BK4819_GetCTCType(void);
void BK4819_SendFSKData(uint16_t *pData);
void BK4819_PrepareFSKReceive(void);
void BK4819_PlayRoger(void);
void BK4819_PlayRogerMDC(void);
void BK4819_Enable_AfDac_DiscMode_TxDsp(void);
void BK4819_GetVoxAmp(uint16_t *pResult);
void BK4819_SetScrambleFrequencyControlWord(uint32_t Frequency);
void BK4819_PlayDTMFEx(bool bLocalLoopback, char Code);
#endif

View File

@@ -14,8 +14,8 @@
* limitations under the License.
*/
#include "bsp/dp32g030/crc.h"
#include "driver/crc.h"
#include "../bsp/dp32g030/crc.h"
#include "crc.h"
void CRC_Init(void)
{
@@ -47,4 +47,3 @@ uint16_t CRC_Calculate(const void *pBuffer, uint16_t Size)
return Crc;
}

View File

@@ -47,16 +47,17 @@ void EEPROM_WriteBuffer(uint16_t Address, const void *pBuffer)
uint8_t buffer[8];
EEPROM_ReadBuffer(Address, buffer, 8);
if (memcmp(pBuffer, buffer, 8) != 0)
{
I2C_Start();
I2C_Write(0xA0);
I2C_Write((Address >> 8) & 0xFF);
I2C_Write((Address >> 0) & 0xFF);
I2C_WriteBuffer(pBuffer, 8);
I2C_Stop();
if (memcmp(pBuffer, buffer, 8) == 0) {
return;
}
I2C_Start();
I2C_Write(0xA0);
I2C_Write((Address >> 8) & 0xFF);
I2C_Write((Address >> 0) & 0xFF);
I2C_WriteBuffer(pBuffer, 8);
I2C_Stop();
// give the EEPROM time to burn the data in (apparently takes 5ms)
SYSTEM_DelayMs(8);
}

View File

@@ -137,18 +137,13 @@ int I2C_ReadBuffer(void *pBuffer, uint8_t Size)
uint8_t *pData = (uint8_t *)pBuffer;
uint8_t i;
if (Size == 1) {
*pData = I2C_Read(true);
return 1;
}
for (i = 0; i < Size - 1; i++) {
SYSTICK_DelayUs(1);
pData[i] = I2C_Read(false);
}
SYSTICK_DelayUs(1);
pData[i++] = I2C_Read(true);
pData[i] = I2C_Read(true);
return Size;
}

View File

@@ -117,19 +117,13 @@ KEY_Code_t KEYBOARD_Poll(void)
GPIOA->DATA &= keyboard[j].set_to_zero_mask;
// Read all 4 GPIO pins at once .. with de-noise, max of 8 sample loops
for (i = 0, k = 0, reg = 0; i < 3 && k < 8; i++, k++)
{
uint16_t reg2;
for (i = 0, k = 0, reg = 0; i < 3 && k < 8; i++, k++) {
SYSTICK_DelayUs(1);
reg2 = GPIOA->DATA;
if (reg != reg2)
{ // noise
reg = reg2;
i = 0;
}
uint16_t reg2 = GPIOA->DATA;
i *= reg == reg2;
reg = reg2;
}
if (i < 3)
break; // noise is too bad

View File

@@ -25,118 +25,59 @@
#include "driver/system.h"
#include "misc.h"
uint8_t gStatusLine[128];
uint8_t gFrameBuffer[7][128];
void ST7565_DrawLine(const unsigned int Column, const unsigned int Line, const unsigned int Size, const uint8_t *pBitmap)
{
unsigned int i;
SPI_ToggleMasterMode(&SPI0->CR, false);
ST7565_SelectColumnAndLine(Column + 4U, Line);
uint8_t gStatusLine[LCD_WIDTH];
uint8_t gFrameBuffer[FRAME_LINES][LCD_WIDTH];
static void DrawLine(uint8_t column, uint8_t line, const uint8_t * lineBuffer, unsigned size_defVal)
{
ST7565_SelectColumnAndLine(column + 4, line);
GPIO_SetBit(&GPIOB->DATA, GPIOB_PIN_ST7565_A0);
if (pBitmap != NULL)
{
for (i = 0; i < Size; i++)
{
while ((SPI0->FIFOST & SPI_FIFOST_TFF_MASK) != SPI_FIFOST_TFF_BITS_NOT_FULL) {}
SPI0->WDR = pBitmap[i];
}
for (unsigned i = 0; i < size_defVal; i++) {
while ((SPI0->FIFOST & SPI_FIFOST_TFF_MASK) != SPI_FIFOST_TFF_BITS_NOT_FULL) {}
SPI0->WDR = lineBuffer ? lineBuffer[i] : size_defVal;
}
else
{
for (i = 0; i < Size; i++)
{
while ((SPI0->FIFOST & SPI_FIFOST_TFF_MASK) != SPI_FIFOST_TFF_BITS_NOT_FULL) {}
SPI0->WDR = 0;
}
}
SPI_WaitForUndocumentedTxFifoStatusBit();
}
void ST7565_DrawLine(const unsigned int Column, const unsigned int Line, const uint8_t *pBitmap, const unsigned int Size)
{
SPI_ToggleMasterMode(&SPI0->CR, false);
DrawLine(Column, Line, pBitmap, Size);
SPI_ToggleMasterMode(&SPI0->CR, true);
}
void ST7565_BlitFullScreen(void)
{
unsigned int Line;
SPI_ToggleMasterMode(&SPI0->CR, false);
ST7565_WriteByte(0x40);
for (Line = 0; Line < ARRAY_SIZE(gFrameBuffer); Line++)
{
unsigned int Column;
ST7565_SelectColumnAndLine(4, Line + 1);
GPIO_SetBit(&GPIOB->DATA, GPIOB_PIN_ST7565_A0);
for (Column = 0; Column < ARRAY_SIZE(gFrameBuffer[0]); Column++)
{
while ((SPI0->FIFOST & SPI_FIFOST_TFF_MASK) != SPI_FIFOST_TFF_BITS_NOT_FULL) {}
SPI0->WDR = gFrameBuffer[Line][Column];
}
SPI_WaitForUndocumentedTxFifoStatusBit();
for (unsigned line = 0; line < FRAME_LINES; line++) {
DrawLine(0, line+1, gFrameBuffer[line], LCD_WIDTH);
}
SPI_ToggleMasterMode(&SPI0->CR, true);
}
#if 0
// whats the delay for I wonder, it holds things up :(
SYSTEM_DelayMs(20);
#else
// SYSTEM_DelayMs(1);
#endif
void ST7565_BlitLine(unsigned line)
{
SPI_ToggleMasterMode(&SPI0->CR, false);
ST7565_WriteByte(0x40); // start line ?
DrawLine(0, line+1, gFrameBuffer[line], LCD_WIDTH);
SPI_ToggleMasterMode(&SPI0->CR, true);
}
void ST7565_BlitStatusLine(void)
{ // the top small text line on the display
unsigned int i;
SPI_ToggleMasterMode(&SPI0->CR, false);
ST7565_WriteByte(0x40); // start line ?
ST7565_SelectColumnAndLine(4, 0);
GPIO_SetBit(&GPIOB->DATA, GPIOB_PIN_ST7565_A0);
for (i = 0; i < ARRAY_SIZE(gStatusLine); i++)
{
while ((SPI0->FIFOST & SPI_FIFOST_TFF_MASK) != SPI_FIFOST_TFF_BITS_NOT_FULL) {}
SPI0->WDR = gStatusLine[i];
}
SPI_WaitForUndocumentedTxFifoStatusBit();
DrawLine(0, 0, gStatusLine, LCD_WIDTH);
SPI_ToggleMasterMode(&SPI0->CR, true);
}
void ST7565_FillScreen(uint8_t Value)
void ST7565_FillScreen(uint8_t value)
{
unsigned int i;
// reset some of the displays settings to try and overcome the radios hardware problem - RF corrupting the display
ST7565_Init(false);
SPI_ToggleMasterMode(&SPI0->CR, false);
for (i = 0; i < 8; i++)
{
unsigned int j;
ST7565_SelectColumnAndLine(0, i);
GPIO_SetBit(&GPIOB->DATA, GPIOB_PIN_ST7565_A0);
for (j = 0; j < 132; j++)
{
while ((SPI0->FIFOST & SPI_FIFOST_TFF_MASK) != SPI_FIFOST_TFF_BITS_NOT_FULL) {}
SPI0->WDR = Value;
}
SPI_WaitForUndocumentedTxFifoStatusBit();
for (unsigned i = 0; i < 8; i++) {
DrawLine(0, i, NULL, value);
}
SPI_ToggleMasterMode(&SPI0->CR, true);
}
@@ -205,40 +146,33 @@ uint8_t cmds[] = {
ST7565_CMD_DISPLAY_ON_OFF | 1, // Display ON/OFF: ON
};
void ST7565_Init(const bool full)
void ST7565_Init(void)
{
if (full) {
SPI0_Init();
ST7565_HardwareReset();
SPI_ToggleMasterMode(&SPI0->CR, false);
ST7565_WriteByte(ST7565_CMD_SOFTWARE_RESET); // software reset
SYSTEM_DelayMs(120);
}
else
SPI_ToggleMasterMode(&SPI0->CR, false);
SPI0_Init();
ST7565_HardwareReset();
SPI_ToggleMasterMode(&SPI0->CR, false);
ST7565_WriteByte(ST7565_CMD_SOFTWARE_RESET); // software reset
SYSTEM_DelayMs(120);
for(uint8_t i = 0; i < 8; i++)
ST7565_WriteByte(cmds[i]);
if (full) {
ST7565_WriteByte(ST7565_CMD_POWER_CIRCUIT | 0b011); // VB=0 VR=1 VF=1
SYSTEM_DelayMs(1);
ST7565_WriteByte(ST7565_CMD_POWER_CIRCUIT | 0b110); // VB=1 VR=1 VF=0
SYSTEM_DelayMs(1);
ST7565_WriteByte(ST7565_CMD_POWER_CIRCUIT | 0b011); // VB=0 VR=1 VF=1
SYSTEM_DelayMs(1);
ST7565_WriteByte(ST7565_CMD_POWER_CIRCUIT | 0b110); // VB=1 VR=1 VF=0
SYSTEM_DelayMs(1);
for(uint8_t i = 0; i < 4; i++) // why 4 times?
ST7565_WriteByte(ST7565_CMD_POWER_CIRCUIT | 0b111); // VB=1 VR=1 VF=1
SYSTEM_DelayMs(40);
for(uint8_t i = 0; i < 4; i++) // why 4 times?
ST7565_WriteByte(ST7565_CMD_POWER_CIRCUIT | 0b111); // VB=1 VR=1 VF=1
SYSTEM_DelayMs(40);
}
ST7565_WriteByte(ST7565_CMD_SET_START_LINE | 0); // line 0
ST7565_WriteByte(ST7565_CMD_DISPLAY_ON_OFF | 1); // D=1
SPI_WaitForUndocumentedTxFifoStatusBit();
SPI_ToggleMasterMode(&SPI0->CR, true);
if (full)
ST7565_FillScreen(0x00);
ST7565_FillScreen(0x00);
}
void ST7565_FixInterfGlitch(void)

View File

@@ -22,15 +22,17 @@
#define LCD_WIDTH 128
#define LCD_HEIGHT 64
#define FRAME_LINES 7
extern uint8_t gStatusLine[128];
extern uint8_t gFrameBuffer[7][128];
extern uint8_t gStatusLine[LCD_WIDTH];
extern uint8_t gFrameBuffer[FRAME_LINES][LCD_WIDTH];
void ST7565_DrawLine(const unsigned int Column, const unsigned int Line, const unsigned int Size, const uint8_t *pBitmap);
void ST7565_DrawLine(const unsigned int Column, const unsigned int Line, const uint8_t *pBitmap, const unsigned int Size);
void ST7565_BlitFullScreen(void);
void ST7565_BlitLine(unsigned line);
void ST7565_BlitStatusLine(void);
void ST7565_FillScreen(uint8_t Value);
void ST7565_Init(const bool full);
void ST7565_Init(void);
void ST7565_FixInterfGlitch(void);
void ST7565_HardwareReset(void);
void ST7565_SelectColumnAndLine(uint8_t Column, uint8_t Line);

View File

@@ -14,10 +14,10 @@
* limitations under the License.
*/
#include "bsp/dp32g030/pmu.h"
#include "bsp/dp32g030/syscon.h"
#include "driver/system.h"
#include "driver/systick.h"
#include "../bsp/dp32g030/pmu.h"
#include "../bsp/dp32g030/syscon.h"
#include "system.h"
#include "systick.h"
void SYSTEM_DelayMs(uint32_t Delay)
{

View File

@@ -15,8 +15,8 @@
*/
#include "ARMCM0.h"
#include "driver/systick.h"
#include "misc.h"
#include "systick.h"
#include "../misc.h"
// 0x20000324
static uint32_t gTickMultiplier;
@@ -29,17 +29,21 @@ void SYSTICK_Init(void)
void SYSTICK_DelayUs(uint32_t Delay)
{
const uint32_t ticks = Delay * gTickMultiplier;
uint32_t i = 0;
uint32_t Start = SysTick->LOAD;
uint32_t Previous = SysTick->VAL;
const uint32_t ticks = Delay * gTickMultiplier;
uint32_t elapsed_ticks = 0;
uint32_t Start = SysTick->LOAD;
uint32_t Previous = SysTick->VAL;
do {
uint32_t Current;
uint32_t Delta;
while ((Current = SysTick->VAL) == Previous) {}
Delta = (Current < Previous) ? -Current : Start - Current;
i += Delta + Previous;
Previous = Current;
} while (i < ticks);
}
do {
Current = SysTick->VAL;
} while (Current == Previous);
uint32_t Delta = ((Current < Previous) ? - Current : Start - Current);
elapsed_ticks += Delta + Previous;
Previous = Current;
} while (elapsed_ticks < ticks);
}

View File

@@ -17,32 +17,32 @@
#include "frequencies.h"
#include "misc.h"
#include "settings.h"
#include <assert.h>
// the BK4819 has 2 bands it covers, 18MHz ~ 630MHz and 760MHz ~ 1300MHz
const freq_band_table_t BX4819_band1 = { 1800000, 63000000};
const freq_band_table_t BX4819_band2 = {84000000, 130000000};
const freq_band_table_t frequencyBandTable[7] =
#define BX4819_band1_lower 1800000
#define BX4819_band2_upper 130000000
const freq_band_table_t BX4819_band1 = {BX4819_band1_lower, 63000000};
const freq_band_table_t BX4819_band2 = {84000000, BX4819_band2_upper};
const freq_band_table_t frequencyBandTable[] =
{
#ifndef ENABLE_WIDE_RX
// QS original
{.lower = 5000000, .upper = 7600000},
{.lower = 10800000, .upper = 13700000},
{.lower = 13700000, .upper = 17400000},
{.lower = 17400000, .upper = 35000000},
{.lower = 35000000, .upper = 40000000},
{.lower = 40000000, .upper = 47000000},
{.lower = 47000000, .upper = 60000000}
[BAND1_50MHz ]={.lower = 5000000, .upper = 7600000},
[BAND7_470MHz]={.lower = 47000000, .upper = 60000000},
#else
// extended range
{.lower = BX4819_band1.lower, .upper = 10800000},
{.lower = 10800000, .upper = 13700000},
{.lower = 13700000, .upper = 17400000},
{.lower = 17400000, .upper = 35000000},
{.lower = 35000000, .upper = 40000000},
{.lower = 40000000, .upper = 47000000},
{.lower = 47000000, .upper = BX4819_band2.upper}
[BAND1_50MHz ]={.lower = BX4819_band1_lower, .upper = 10800000},
[BAND7_470MHz]={.lower = 47000000, .upper = BX4819_band2_upper},
#endif
[BAND2_108MHz]={.lower = 10800000, .upper = 13700000},
[BAND3_137MHz]={.lower = 13700000, .upper = 17400000},
[BAND4_174MHz]={.lower = 17400000, .upper = 35000000},
[BAND5_350MHz]={.lower = 35000000, .upper = 40000000},
[BAND6_400MHz]={.lower = 40000000, .upper = 47000000}
};
#ifdef ENABLE_NOAA
@@ -62,22 +62,49 @@ const freq_band_table_t frequencyBandTable[7] =
#endif
// this order of steps has to be preserved for backwards compatibility with other/stock firmwares
const uint16_t gStepFrequencyTable[] = {
250, 500, 625, 1000, 1250, 2500, 833,
1, 5, 10, 25, 50, 100, 125, 1500, 3000, 5000, 10000, 12500, 25000, 50000
};
const uint8_t StepSortedIndexes[] = {
STEP_0_01kHz, STEP_0_05kHz, STEP_0_1kHz, STEP_0_25kHz, STEP_0_5kHz, STEP_1kHz, STEP_1_25kHz, STEP_2_5kHz, STEP_5kHz, STEP_6_25kHz,
STEP_8_33kHz, STEP_10kHz, STEP_12_5kHz, STEP_15kHz, STEP_25kHz, STEP_30kHz, STEP_50kHz, STEP_100kHz,
STEP_125kHz, STEP_250kHz, STEP_500kHz
// standard steps
[STEP_2_5kHz] = 250,
[STEP_5kHz] = 500,
[STEP_6_25kHz] = 625,
[STEP_10kHz] = 1000,
[STEP_12_5kHz] = 1250,
[STEP_25kHz] = 2500,
[STEP_8_33kHz] = 833,
// custom steps
[STEP_0_01kHz] = 1,
[STEP_0_05kHz] = 5,
[STEP_0_1kHz] = 10,
[STEP_0_25kHz] = 25,
[STEP_0_5kHz] = 50,
[STEP_1kHz] = 100,
[STEP_1_25kHz] = 125,
[STEP_9kHz] = 900,
[STEP_15kHz] = 1500,
[STEP_20kHz] = 2000,
[STEP_30kHz] = 3000,
[STEP_50kHz] = 5000,
[STEP_100kHz] = 10000,
[STEP_125kHz] = 12500,
[STEP_200kHz] = 20000,
[STEP_250kHz] = 25000,
[STEP_500kHz] = 50000
};
uint8_t FREQUENCY_GetStepIdxFromSortedIdx(uint8_t sortedIdx)
const STEP_Setting_t StepSortedIndexes[] = {
STEP_0_01kHz, STEP_0_05kHz, STEP_0_1kHz, STEP_0_25kHz, STEP_0_5kHz, STEP_1kHz, STEP_1_25kHz, STEP_2_5kHz, STEP_5kHz, STEP_6_25kHz,
STEP_8_33kHz, STEP_9kHz, STEP_10kHz, STEP_12_5kHz, STEP_15kHz, STEP_20kHz, STEP_25kHz, STEP_30kHz, STEP_50kHz, STEP_100kHz,
STEP_125kHz, STEP_200kHz, STEP_250kHz, STEP_500kHz
};
STEP_Setting_t FREQUENCY_GetStepIdxFromSortedIdx(uint8_t sortedIdx)
{
return StepSortedIndexes[sortedIdx];
}
uint8_t FREQUENCY_GetSortedIdxFromStepIdx(uint8_t stepIdx)
uint32_t FREQUENCY_GetSortedIdxFromStepIdx(uint8_t stepIdx)
{
for(uint8_t i = 0; i < ARRAY_SIZE(gStepFrequencyTable); i++)
if(StepSortedIndexes[i] == stepIdx)
@@ -85,16 +112,16 @@ uint8_t FREQUENCY_GetSortedIdxFromStepIdx(uint8_t stepIdx)
return 0;
}
static_assert(ARRAY_SIZE(gStepFrequencyTable) == STEP_N_ELEM);
FREQUENCY_Band_t FREQUENCY_GetBand(uint32_t Frequency)
{
int band;
for (band = ARRAY_SIZE(frequencyBandTable) - 1; band >= 0; band--)
for (int32_t band = BAND_N_ELEM - 1; band >= 0; band--)
if (Frequency >= frequencyBandTable[band].lower)
// if (Frequency < frequencyBandTable[band].upper)
return (FREQUENCY_Band_t)band;
return BAND1_50MHz;
// return BAND_NONE;
}
uint8_t FREQUENCY_CalculateOutputPower(uint8_t TxpLow, uint8_t TxpMid, uint8_t TxpHigh, int32_t LowerLimit, int32_t Middle, int32_t UpperLimit, int32_t Frequency)
@@ -116,38 +143,35 @@ uint8_t FREQUENCY_CalculateOutputPower(uint8_t TxpLow, uint8_t TxpMid, uint8_t T
return TxpMid;
}
static int32_t rnd(int32_t freq, uint16_t step)
{
if(step == 1)
return freq;
return (freq + (step + 1) / 2) / step * step;
}
uint32_t FREQUENCY_RoundToStep(uint32_t freq, uint16_t step)
{
if(step == 833) {
uint32_t base = freq/2500*2500;
int f = rnd(freq - base, step);
int x = f / step;
return base + f + (x == 3);
int chno = (freq - base) / 700; // convert entered aviation 8.33Khz channel number scheme to actual frequency.
return base + (chno * 833) + (chno == 3);
}
return rnd(freq, step);
if(step == 1)
return freq;
if(step >= 1000)
step = step/2;
return (freq + (step + 1) / 2) / step * step;
}
int TX_freq_check(const uint32_t Frequency)
int32_t TX_freq_check(const uint32_t Frequency)
{ // return '0' if TX frequency is allowed
// otherwise return '-1'
if (Frequency < frequencyBandTable[0].lower || Frequency > frequencyBandTable[ARRAY_SIZE(frequencyBandTable) - 1].upper)
return -1; // not allowed outside this range
if (Frequency < frequencyBandTable[0].lower || Frequency > frequencyBandTable[BAND_N_ELEM - 1].upper)
return 1; // not allowed outside this range
if (Frequency >= BX4819_band1.upper && Frequency < BX4819_band2.lower)
return -1; // BX chip does not work in this range
switch (gSetting_F_LOCK)
{
case F_LOCK_OFF:
case F_LOCK_DEF:
if (Frequency >= frequencyBandTable[BAND3_137MHz].lower && Frequency < frequencyBandTable[BAND3_137MHz].upper)
return 0;
if (Frequency >= frequencyBandTable[BAND4_174MHz].lower && Frequency < frequencyBandTable[BAND4_174MHz].upper)
@@ -197,17 +221,26 @@ int TX_freq_check(const uint32_t Frequency)
if (Frequency >= 40000000 && Frequency < 43800000)
return 0;
break;
case F_LOCK_ALL:
break;
case F_LOCK_NONE:
for (uint32_t i = 0; i < ARRAY_SIZE(frequencyBandTable); i++)
if (Frequency >= frequencyBandTable[i].lower && Frequency < frequencyBandTable[i].upper)
return 0;
break;
}
// dis-allowed TX frequency
return -1;
}
int RX_freq_check(const uint32_t Frequency)
int32_t RX_freq_check(const uint32_t Frequency)
{ // return '0' if RX frequency is allowed
// otherwise return '-1'
if (Frequency < frequencyBandTable[0].lower || Frequency > frequencyBandTable[ARRAY_SIZE(frequencyBandTable) - 1].upper)
if (Frequency < frequencyBandTable[0].lower || Frequency > frequencyBandTable[BAND_N_ELEM - 1].upper)
return -1;
if (Frequency >= BX4819_band1.upper && Frequency < BX4819_band2.lower)

View File

@@ -19,6 +19,8 @@
#include <stdint.h>
#define _1GHz_in_KHz 100000000
typedef struct {
const uint32_t lower;
const uint32_t upper;
@@ -27,46 +29,52 @@ typedef struct {
extern const freq_band_table_t BX4819_band1;
extern const freq_band_table_t BX4819_band2;
extern const freq_band_table_t frequencyBandTable[7];
typedef enum {
BAND_NONE = -1,
BAND1_50MHz = 0,
BAND_NONE = -1,
BAND1_50MHz = 0,
BAND2_108MHz,
BAND3_137MHz,
BAND4_174MHz,
BAND5_350MHz,
BAND6_400MHz,
BAND7_470MHz
BAND7_470MHz,
BAND_N_ELEM
} FREQUENCY_Band_t;
extern const freq_band_table_t frequencyBandTable[];
typedef enum {
STEP_2_5kHz,
STEP_5kHz,
STEP_6_25kHz,
STEP_10kHz,
STEP_12_5kHz,
STEP_25kHz,
// standard steps
STEP_2_5kHz,
STEP_5kHz,
STEP_6_25kHz,
STEP_10kHz,
STEP_12_5kHz,
STEP_25kHz,
STEP_8_33kHz,
STEP_0_01kHz,
STEP_0_05kHz,
STEP_0_1kHz,
STEP_0_25kHz,
STEP_0_5kHz,
STEP_1kHz,
STEP_1_25kHz,
// custom steps
STEP_0_01kHz,
STEP_0_05kHz,
STEP_0_1kHz,
STEP_0_25kHz,
STEP_0_5kHz,
STEP_1kHz,
STEP_1_25kHz,
STEP_9kHz,
STEP_15kHz,
STEP_30kHz,
STEP_50kHz,
STEP_100kHz,
STEP_125kHz,
STEP_250kHz,
STEP_20kHz,
STEP_30kHz,
STEP_50kHz,
STEP_100kHz,
STEP_125kHz,
STEP_200kHz,
STEP_250kHz,
STEP_500kHz,
STEP_N_ELEM
} STEP_Setting_t;
extern const uint16_t gStepFrequencyTable[21];
extern const uint16_t gStepFrequencyTable[];
#ifdef ENABLE_NOAA
extern const uint32_t NoaaFrequencyTable[10];
@@ -76,10 +84,10 @@ FREQUENCY_Band_t FREQUENCY_GetBand(uint32_t Frequency);
uint8_t FREQUENCY_CalculateOutputPower(uint8_t TxpLow, uint8_t TxpMid, uint8_t TxpHigh, int32_t LowerLimit, int32_t Middle, int32_t UpperLimit, int32_t Frequency);
uint32_t FREQUENCY_RoundToStep(uint32_t freq, uint16_t step);
uint8_t FREQUENCY_GetStepIdxFromSortedIdx(uint8_t sortedIdx);
uint8_t FREQUENCY_GetSortedIdxFromStepIdx(uint8_t step);
STEP_Setting_t FREQUENCY_GetStepIdxFromSortedIdx(uint8_t sortedIdx);
uint32_t FREQUENCY_GetSortedIdxFromStepIdx(uint8_t step);
int TX_freq_check(const uint32_t Frequency);
int RX_freq_check(const uint32_t Frequency);
int32_t TX_freq_check(uint32_t Frequency);
int32_t RX_freq_check(uint32_t Frequency);
#endif

View File

@@ -42,218 +42,232 @@
FUNCTION_Type_t gCurrentFunction;
bool FUNCTION_IsRx()
{
return gCurrentFunction == FUNCTION_MONITOR ||
gCurrentFunction == FUNCTION_INCOMING ||
gCurrentFunction == FUNCTION_RECEIVE;
}
void FUNCTION_Init(void)
{
#ifdef ENABLE_NOAA
if (!IS_NOAA_CHANNEL(gRxVfo->CHANNEL_SAVE))
#endif
{
gCurrentCodeType = gSelectedCodeType;
if (gCssScanMode == CSS_SCAN_MODE_OFF)
gCurrentCodeType = (gRxVfo->Modulation != MODULATION_FM) ? CODE_TYPE_OFF : gRxVfo->pRX->CodeType;
}
#ifdef ENABLE_NOAA
else
gCurrentCodeType = CODE_TYPE_CONTINUOUS_TONE;
#endif
DTMF_clear_RX();
g_CxCSS_TAIL_Found = false;
g_CDCSS_Lost = false;
g_CTCSS_Lost = false;
#ifdef ENABLE_VOX
g_VOX_Lost = false;
#endif
g_SquelchLost = false;
gFlagTailNoteEliminationComplete = false;
gTailNoteEliminationCountdown_10ms = 0;
gFlagTailToneEliminationComplete = false;
gTailToneEliminationCountdown_10ms = 0;
gFoundCTCSS = false;
gFoundCDCSS = false;
gFoundCTCSSCountdown_10ms = 0;
gFoundCDCSSCountdown_10ms = 0;
gEndOfRxDetectedMaybe = false;
#ifdef ENABLE_NOAA
gNOAACountdown_10ms = 0;
#endif
gCurrentCodeType = (gRxVfo->Modulation != MODULATION_FM) ? CODE_TYPE_OFF : gRxVfo->pRX->CodeType;
#ifdef ENABLE_VOX
g_VOX_Lost = false;
#endif
#ifdef ENABLE_DTMF_CALLING
DTMF_clear_RX();
#endif
#ifdef ENABLE_NOAA
gNOAACountdown_10ms = 0;
if (IS_NOAA_CHANNEL(gRxVfo->CHANNEL_SAVE)) {
gCurrentCodeType = CODE_TYPE_CONTINUOUS_TONE;
}
#endif
gUpdateStatus = true;
}
void FUNCTION_Foreground(const FUNCTION_Type_t PreviousFunction)
{
#ifdef ENABLE_DTMF_CALLING
if (gDTMF_ReplyState != DTMF_REPLY_NONE)
RADIO_PrepareCssTX();
#endif
if (PreviousFunction == FUNCTION_TRANSMIT) {
ST7565_FixInterfGlitch();
gVFO_RSSI_bar_level[0] = 0;
gVFO_RSSI_bar_level[1] = 0;
} else if (PreviousFunction != FUNCTION_RECEIVE) {
return;
}
#if defined(ENABLE_FMRADIO)
if (gFmRadioMode)
gFM_RestoreCountdown_10ms = fm_restore_countdown_10ms;
#endif
#ifdef ENABLE_DTMF_CALLING
if (gDTMF_CallState == DTMF_CALL_STATE_CALL_OUT ||
gDTMF_CallState == DTMF_CALL_STATE_RECEIVED ||
gDTMF_CallState == DTMF_CALL_STATE_RECEIVED_STAY)
{
gDTMF_auto_reset_time_500ms = gEeprom.DTMF_auto_reset_time * 2;
}
#endif
gUpdateStatus = true;
}
void FUNCTION_PowerSave() {
gPowerSave_10ms = gEeprom.BATTERY_SAVE * 10;
gPowerSaveCountdownExpired = false;
gRxIdleMode = true;
gMonitor = false;
BK4819_DisableVox();
BK4819_Sleep();
BK4819_ToggleGpioOut(BK4819_GPIO0_PIN28_RX_ENABLE, false);
gUpdateStatus = true;
if (gScreenToDisplay != DISPLAY_MENU) // 1of11 .. don't close the menu
GUI_SelectNextDisplay(DISPLAY_MAIN);
}
void FUNCTION_Transmit()
{
// if DTMF is enabled when TX'ing, it changes the TX audio filtering !! .. 1of11
BK4819_DisableDTMF();
#ifdef ENABLE_DTMF_CALLING
// clear the DTMF RX buffer
DTMF_clear_RX();
#endif
// clear the DTMF RX live decoder buffer
gDTMF_RX_live_timeout = 0;
memset(gDTMF_RX_live, 0, sizeof(gDTMF_RX_live));
#if defined(ENABLE_FMRADIO)
if (gFmRadioMode)
BK1080_Init0();
#endif
#ifdef ENABLE_ALARM
if (gAlarmState == ALARM_STATE_SITE_ALARM)
{
GUI_DisplayScreen();
AUDIO_AudioPathOff();
SYSTEM_DelayMs(20);
BK4819_PlayTone(500, 0);
SYSTEM_DelayMs(2);
AUDIO_AudioPathOn();
gEnableSpeaker = true;
SYSTEM_DelayMs(60);
BK4819_ExitTxMute();
gAlarmToneCounter = 0;
return;
}
#endif
gUpdateStatus = true;
GUI_DisplayScreen();
RADIO_SetTxParameters();
// turn the RED LED on
BK4819_ToggleGpioOut(BK4819_GPIO5_PIN1_RED, true);
DTMF_Reply();
if (gCurrentVfo->DTMF_PTT_ID_TX_MODE == PTT_ID_APOLLO)
BK4819_PlaySingleTone(2525, 250, 0, gEeprom.DTMF_SIDE_TONE);
#if defined(ENABLE_ALARM) || defined(ENABLE_TX1750)
if (gAlarmState != ALARM_STATE_OFF) {
#ifdef ENABLE_TX1750
if (gAlarmState == ALARM_STATE_TX1750)
BK4819_TransmitTone(true, 1750);
#endif
#ifdef ENABLE_ALARM
if (gAlarmState == ALARM_STATE_TXALARM)
BK4819_TransmitTone(true, 500);
gAlarmToneCounter = 0;
#endif
SYSTEM_DelayMs(2);
AUDIO_AudioPathOn();
gEnableSpeaker = true;
return;
}
#endif
if (gCurrentVfo->SCRAMBLING_TYPE > 0 && gSetting_ScrambleEnable)
BK4819_EnableScramble(gCurrentVfo->SCRAMBLING_TYPE - 1);
else
BK4819_DisableScramble();
if (gSetting_backlight_on_tx_rx & BACKLIGHT_ON_TR_TX) {
BACKLIGHT_TurnOn();
}
}
void FUNCTION_Select(FUNCTION_Type_t Function)
{
const FUNCTION_Type_t PreviousFunction = gCurrentFunction;
const bool bWasPowerSave = (PreviousFunction == FUNCTION_POWER_SAVE);
const bool bWasPowerSave = PreviousFunction == FUNCTION_POWER_SAVE;
gCurrentFunction = Function;
if (bWasPowerSave && Function != FUNCTION_POWER_SAVE)
{
if (bWasPowerSave && Function != FUNCTION_POWER_SAVE) {
BK4819_Conditional_RX_TurnOn_and_GPIO6_Enable();
gRxIdleMode = false;
UI_DisplayStatus();
}
switch (Function)
{
switch (Function) {
case FUNCTION_FOREGROUND:
if (gDTMF_ReplyState != DTMF_REPLY_NONE)
RADIO_PrepareCssTX();
if (PreviousFunction == FUNCTION_TRANSMIT)
{
ST7565_FixInterfGlitch();
gVFO_RSSI_bar_level[0] = 0;
gVFO_RSSI_bar_level[1] = 0;
}
else
if (PreviousFunction != FUNCTION_RECEIVE)
break;
#if defined(ENABLE_FMRADIO)
if (gFmRadioMode)
gFM_RestoreCountdown_10ms = fm_restore_countdown_10ms;
#endif
if (gDTMF_CallState == DTMF_CALL_STATE_CALL_OUT ||
gDTMF_CallState == DTMF_CALL_STATE_RECEIVED ||
gDTMF_CallState == DTMF_CALL_STATE_RECEIVED_STAY)
{
gDTMF_auto_reset_time_500ms = gEeprom.DTMF_auto_reset_time * 2;
}
gUpdateStatus = true;
FUNCTION_Foreground(PreviousFunction);
return;
case FUNCTION_POWER_SAVE:
FUNCTION_PowerSave();
return;
case FUNCTION_TRANSMIT:
FUNCTION_Transmit();
break;
case FUNCTION_MONITOR:
gMonitor = true;
break;
case FUNCTION_INCOMING:
case FUNCTION_RECEIVE:
break;
case FUNCTION_POWER_SAVE:
gPowerSave_10ms = gEeprom.BATTERY_SAVE * 10;
gPowerSaveCountdownExpired = false;
gRxIdleMode = true;
gMonitor = false;
BK4819_DisableVox();
BK4819_Sleep();
BK4819_ToggleGpioOut(BK4819_GPIO0_PIN28_RX_ENABLE, false);
gUpdateStatus = true;
if (gScreenToDisplay != DISPLAY_MENU) // 1of11 .. don't close the menu
GUI_SelectNextDisplay(DISPLAY_MAIN);
return;
case FUNCTION_TRANSMIT:
// if DTMF is enabled when TX'ing, it changes the TX audio filtering !! .. 1of11
BK4819_DisableDTMF();
// clear the DTMF RX buffer
DTMF_clear_RX();
// clear the DTMF RX live decoder buffer
gDTMF_RX_live_timeout = 0;
gDTMF_RX_live_timeout = 0;
memset(gDTMF_RX_live, 0, sizeof(gDTMF_RX_live));
#if defined(ENABLE_FMRADIO)
if (gFmRadioMode)
BK1080_Init(0, false);
#endif
#ifdef ENABLE_ALARM
if (gAlarmState == ALARM_STATE_TXALARM && gEeprom.ALARM_MODE != ALARM_MODE_TONE)
{
gAlarmState = ALARM_STATE_ALARM;
GUI_DisplayScreen();
AUDIO_AudioPathOff();
SYSTEM_DelayMs(20);
BK4819_PlayTone(500, 0);
SYSTEM_DelayMs(2);
AUDIO_AudioPathOn();
gEnableSpeaker = true;
SYSTEM_DelayMs(60);
BK4819_ExitTxMute();
gAlarmToneCounter = 0;
break;
}
#endif
gUpdateStatus = true;
GUI_DisplayScreen();
RADIO_SetTxParameters();
// turn the RED LED on
BK4819_ToggleGpioOut(BK4819_GPIO5_PIN1_RED, true);
DTMF_Reply();
if (gCurrentVfo->DTMF_PTT_ID_TX_MODE == PTT_ID_APOLLO)
BK4819_PlaySingleTone(2525, 250, 0, gEeprom.DTMF_SIDE_TONE);
#if defined(ENABLE_ALARM) || defined(ENABLE_TX1750)
if (gAlarmState != ALARM_STATE_OFF)
{
#ifdef ENABLE_TX1750
if (gAlarmState == ALARM_STATE_TX1750)
BK4819_TransmitTone(true, 1750);
#endif
#ifdef ENABLE_ALARM
if (gAlarmState == ALARM_STATE_TXALARM)
BK4819_TransmitTone(true, 500);
#endif
SYSTEM_DelayMs(2);
AUDIO_AudioPathOn();
#ifdef ENABLE_ALARM
gAlarmToneCounter = 0;
#endif
gEnableSpeaker = true;
break;
}
#endif
if (gCurrentVfo->SCRAMBLING_TYPE > 0 && gSetting_ScrambleEnable)
BK4819_EnableScramble(gCurrentVfo->SCRAMBLING_TYPE - 1);
else
BK4819_DisableScramble();
if (gSetting_backlight_on_tx_rx == BACKLIGHT_ON_TR_TX ||
gSetting_backlight_on_tx_rx == BACKLIGHT_ON_TR_TXRX)
BACKLIGHT_TurnOn();
break;
case FUNCTION_BAND_SCOPE:
default:
break;
}
gBatterySaveCountdown_10ms = battery_save_count_10ms;
gSchedulePowerSave = false;
#if defined(ENABLE_FMRADIO)
#if defined(ENABLE_FMRADIO)
if(Function != FUNCTION_INCOMING)
gFM_RestoreCountdown_10ms = 0;
#endif
#endif
}

View File

@@ -27,7 +27,8 @@ enum FUNCTION_Type_t
FUNCTION_INCOMING, // receiving a signal (squelch is open)
FUNCTION_RECEIVE, // RX mode, squelch closed
FUNCTION_POWER_SAVE, // sleeping
FUNCTION_BAND_SCOPE // bandscope mode (panadpter/spectrum) .. not yet implemented
FUNCTION_BAND_SCOPE, // bandscope mode (panadpter/spectrum) .. not yet implemented
FUNCTION_N_ELEM
};
typedef enum FUNCTION_Type_t FUNCTION_Type_t;
@@ -36,6 +37,6 @@ extern FUNCTION_Type_t gCurrentFunction;
void FUNCTION_Init(void);
void FUNCTION_Select(FUNCTION_Type_t Function);
bool FUNCTION_IsRx();
#endif

View File

@@ -21,11 +21,10 @@ def obfuscate(fw):
return bytes([a^b for a, b in zip(fw, cycle(OBFUSCATION))])
plain = open(sys.argv[1], 'rb').read()
if len(sys.argv[2]) > 10:
print('Version suffix is too big!')
sys.exit(1)
version = b'*OEFW-' + bytes(sys.argv[2], 'ascii')
version = b'*' + bytes(sys.argv[2], 'ascii') + b' ' + bytes(sys.argv[3], 'ascii')
version = version[0:16]
if len(version) < 16:
version += b'\x00' * (16 - len(version))
@@ -36,5 +35,5 @@ crc.update(packed)
digest = crc.digest()
digest = bytes([digest[1], digest[0]])
open(sys.argv[3], 'wb').write(packed + digest)
open(sys.argv[4], 'wb').write(packed + digest)

View File

@@ -14,6 +14,8 @@
* limitations under the License.
*/
#include <assert.h>
#include "battery.h"
#include "driver/backlight.h"
#include "driver/st7565.h"
@@ -49,48 +51,45 @@ const uint16_t lowBatteryPeriod = 30;
volatile uint16_t gPowerSave_10ms;
unsigned int BATTERY_VoltsToPercent(const unsigned int voltage_10mV)
{
const uint16_t crv1600[][2] = {
const uint16_t Voltage2PercentageTable[][7][2] = {
[BATTERY_TYPE_1600_MAH] = {
{828, 100},
{814, 97 },
{760, 25 },
{729, 6 },
{630, 0 },
{0, 0 }
};
{0, 0 },
{0, 0 },
},
const uint16_t crv2200[][2] = {
[BATTERY_TYPE_2200_MAH] = {
{832, 100},
{813, 95 },
{740, 60 },
{707, 21 },
{682, 5 },
{630, 0 },
{0, 0 }
};
const BATTERY_Type_t type = gEeprom.BATTERY_TYPE;
const uint16_t(*crv)[2];
uint8_t size;
if (type == BATTERY_TYPE_2200_MAH) {
crv = crv2200;
size = ARRAY_SIZE(crv2200);
}
else {
crv = crv1600;
size = ARRAY_SIZE(crv1600);
}
{0, 0 },
},
};
static_assert(ARRAY_SIZE(Voltage2PercentageTable[BATTERY_TYPE_1600_MAH]) ==
ARRAY_SIZE(Voltage2PercentageTable[BATTERY_TYPE_2200_MAH]));
unsigned int BATTERY_VoltsToPercent(const unsigned int voltage_10mV)
{
const uint16_t (*crv)[2] = Voltage2PercentageTable[gEeprom.BATTERY_TYPE];
const int mulipl = 1000;
for (int i = 1; i < size; i++) {
for (unsigned int i = 1; i < ARRAY_SIZE(Voltage2PercentageTable[BATTERY_TYPE_2200_MAH]); i++) {
if (voltage_10mV > crv[i][0]) {
int a = (crv[i - 1][1] - crv[i][1]) * mulipl / (crv[i - 1][0] - crv[i][0]);
int b = crv[i][1] - a * crv[i][0] / mulipl;
int p = a * voltage_10mV / mulipl + b;
const int a = (crv[i - 1][1] - crv[i][1]) * mulipl / (crv[i - 1][0] - crv[i][0]);
const int b = crv[i][1] - a * crv[i][0] / mulipl;
const int p = a * voltage_10mV / mulipl + b;
return MIN(p, 100);
}
}
return 0;
}
@@ -99,8 +98,6 @@ void BATTERY_GetReadings(const bool bDisplayBatteryLevel)
const uint8_t PreviousBatteryLevel = gBatteryDisplayLevel;
const uint16_t Voltage = (gBatteryVoltages[0] + gBatteryVoltages[1] + gBatteryVoltages[2] + gBatteryVoltages[3]) / 4;
gBatteryVoltageAverage = (Voltage * 760) / gBatteryCalibration[3];
if(gBatteryVoltageAverage > 890)
@@ -116,11 +113,11 @@ void BATTERY_GetReadings(const bool bDisplayBatteryLevel)
gBatteryDisplayLevel = i;
break;
}
}
}
}
if ((gScreenToDisplay == DISPLAY_MENU) && GetCurrentMenuId() == MENU_VOL)
if ((gScreenToDisplay == DISPLAY_MENU) && UI_MENU_GetCurrentMenuId() == MENU_VOL)
gUpdateDisplay = true;
if (gBatteryCurrent < 501)
@@ -160,7 +157,7 @@ void BATTERY_GetReadings(const bool bDisplayBatteryLevel)
if (bDisplayBatteryLevel)
UI_DisplayBattery(gBatteryDisplayLevel, gLowBatteryBlink);
}
if(!gLowBatteryConfirmed)
gUpdateDisplay = true;
@@ -168,56 +165,61 @@ void BATTERY_GetReadings(const bool bDisplayBatteryLevel)
}
}
void BATTERY_TimeSlice500ms(void)
void BATTERY_TimeSlice500ms(void)
{
if (gLowBattery)
{
gLowBatteryBlink = ++lowBatteryCountdown & 1;
UI_DisplayBattery(0, gLowBatteryBlink);
if (gCurrentFunction != FUNCTION_TRANSMIT)
{ // not transmitting
if (lowBatteryCountdown < lowBatteryPeriod)
{
if (lowBatteryCountdown == lowBatteryPeriod-1 && !gChargingWithTypeC && !gLowBatteryConfirmed)
AUDIO_PlayBeep(BEEP_500HZ_60MS_DOUBLE_BEEP);
}
else
{
lowBatteryCountdown = 0;
if (!gChargingWithTypeC)
{ // not on charge
if(!gLowBatteryConfirmed) {
AUDIO_PlayBeep(BEEP_500HZ_60MS_DOUBLE_BEEP);
#ifdef ENABLE_VOICE
AUDIO_SetVoiceID(0, VOICE_ID_LOW_VOLTAGE);
#endif
}
if (gBatteryDisplayLevel == 0)
{
#ifdef ENABLE_VOICE
AUDIO_PlaySingleVoice(true);
#endif
gReducedService = true;
//if (gCurrentFunction != FUNCTION_POWER_SAVE)
FUNCTION_Select(FUNCTION_POWER_SAVE);
ST7565_HardwareReset();
if (gEeprom.BACKLIGHT_TIME < (ARRAY_SIZE(gSubMenu_BACKLIGHT) - 1))
BACKLIGHT_TurnOff(); // turn the backlight off
}
#ifdef ENABLE_VOICE
else
AUDIO_PlaySingleVoice(false);
#endif
}
}
}
if (!gLowBattery) {
return;
}
}
gLowBatteryBlink = ++lowBatteryCountdown & 1;
UI_DisplayBattery(0, gLowBatteryBlink);
if (gCurrentFunction == FUNCTION_TRANSMIT) {
return;
}
// not transmitting
if (lowBatteryCountdown < lowBatteryPeriod) {
if (lowBatteryCountdown == lowBatteryPeriod-1 && !gChargingWithTypeC && !gLowBatteryConfirmed) {
AUDIO_PlayBeep(BEEP_500HZ_60MS_DOUBLE_BEEP);
}
return;
}
lowBatteryCountdown = 0;
if (gChargingWithTypeC) {
return;
}
// not on charge
if (!gLowBatteryConfirmed) {
AUDIO_PlayBeep(BEEP_500HZ_60MS_DOUBLE_BEEP);
#ifdef ENABLE_VOICE
AUDIO_SetVoiceID(0, VOICE_ID_LOW_VOLTAGE);
#endif
}
if (gBatteryDisplayLevel != 0) {
#ifdef ENABLE_VOICE
AUDIO_PlaySingleVoice(false);
#endif
return;
}
#ifdef ENABLE_VOICE
AUDIO_PlaySingleVoice(true);
#endif
gReducedService = true;
FUNCTION_Select(FUNCTION_POWER_SAVE);
ST7565_HardwareReset();
if (gEeprom.BACKLIGHT_TIME < (ARRAY_SIZE(gSubMenu_BACKLIGHT) - 1)) {
BACKLIGHT_TurnOff();
}
}

View File

@@ -40,9 +40,9 @@ typedef enum {
BATTERY_TYPE_UNKNOWN
} BATTERY_Type_t;
unsigned int BATTERY_VoltsToPercent(const unsigned int voltage_10mV);
void BATTERY_GetReadings(const bool bDisplayBatteryLevel);
unsigned int BATTERY_VoltsToPercent(unsigned int voltage_10mV);
void BATTERY_GetReadings(bool bDisplayBatteryLevel);
void BATTERY_TimeSlice500ms(void);
#endif

BIN
images/codespace1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 81 KiB

BIN
images/codespace2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 122 KiB

9
init.c
View File

@@ -17,6 +17,7 @@
*/
#include <stdint.h>
#include <string.h>
extern uint32_t __bss_start__[];
extern uint32_t __bss_end__[];
@@ -29,9 +30,9 @@ void DATA_Init(void);
void BSS_Init(void)
{
uint32_t *pBss;
for (pBss = __bss_start__; pBss < __bss_end__; pBss++)
for (uint32_t *pBss = __bss_start__; pBss < __bss_end__; pBss++) {
*pBss = 0;
}
}
void DATA_Init(void)
@@ -39,8 +40,8 @@ void DATA_Init(void)
volatile uint32_t *pDataRam = (volatile uint32_t *)sram_data_start;
volatile uint32_t *pDataFlash = (volatile uint32_t *)flash_data_start;
uint32_t Size = (uint32_t)sram_data_end - (uint32_t)sram_data_start;
unsigned int i;
for (i = 0; i < (Size / 4); i++)
for (unsigned int i = 0; i < (Size / 4); i++) {
*pDataRam++ = *pDataFlash++;
}
}

82
main.c
View File

@@ -14,44 +14,52 @@
* limitations under the License.
*/
#include <stdint.h>
#include <string.h>
#include <stdio.h> // NULL
#ifdef ENABLE_AM_FIX
#include "am_fix.h"
#endif
#include "audio.h"
#include "board.h"
#include "misc.h"
#include "radio.h"
#include "settings.h"
#include "version.h"
#include "app/app.h"
#include "app/dtmf.h"
#include "audio.h"
#include "bsp/dp32g030/gpio.h"
#include "bsp/dp32g030/syscon.h"
#include "board.h"
#include "driver/backlight.h"
#include "driver/bk4819.h"
#include "driver/gpio.h"
#include "driver/system.h"
#include "driver/systick.h"
#include "driver/uart.h"
#ifdef ENABLE_UART
#include "driver/uart.h"
#endif
#include "helper/battery.h"
#include "helper/boot.h"
#include "misc.h"
#include "radio.h"
#include "settings.h"
#include "ui/lock.h"
#include "ui/welcome.h"
#include "ui/menu.h"
#include "version.h"
void _putchar(char c)
void _putchar(__attribute__((unused)) char c)
{
#ifdef ENABLE_UART
UART_Send((uint8_t *)&c, 1);
#endif
}
void Main(void)
{
unsigned int i;
BOOT_Mode_t BootMode;
// Enable clock gating of blocks we need
SYSCON_DEV_CLK_GATE = 0
| SYSCON_DEV_CLK_GATE_GPIOA_BITS_ENABLE
@@ -64,18 +72,19 @@ void Main(void)
| SYSCON_DEV_CLK_GATE_AES_BITS_ENABLE
| SYSCON_DEV_CLK_GATE_PWM_PLUS0_BITS_ENABLE;
SYSTICK_Init();
BOARD_Init();
UART_Init();
boot_counter_10ms = 250; // 2.5 sec
#ifdef ENABLE_UART
UART_Init();
UART_Send(UART_Version, strlen(UART_Version));
#endif
// Not implementing authentic device checks
memset(&gEeprom, 0, sizeof(gEeprom));
memset(gDTMF_String, '-', sizeof(gDTMF_String));
gDTMF_String[sizeof(gDTMF_String) - 1] = 0;
@@ -83,9 +92,9 @@ void Main(void)
BOARD_ADC_GetBatteryInfo(&gBatteryCurrentVoltage, &gBatteryCurrent);
BOARD_EEPROM_Init();
BOARD_EEPROM_LoadCalibration();
SETTINGS_InitEEPROM();
SETTINGS_WriteBuildOptions();
SETTINGS_LoadCalibration();
RADIO_ConfigureChannel(0, VFO_CONFIGURE_RELOAD);
RADIO_ConfigureChannel(1, VFO_CONFIGURE_RELOAD);
@@ -94,17 +103,17 @@ void Main(void)
RADIO_SetupRegisters(true);
for (i = 0; i < ARRAY_SIZE(gBatteryVoltages); i++)
for (unsigned int i = 0; i < ARRAY_SIZE(gBatteryVoltages); i++)
BOARD_ADC_GetBatteryInfo(&gBatteryVoltages[i], &gBatteryCurrent);
BATTERY_GetReadings(false);
#ifdef ENABLE_AM_FIX
AM_fix_init();
#endif
#ifdef ENABLE_AM_FIX
AM_fix_init();
#endif
const BOOT_Mode_t BootMode = BOOT_GetMode();
BootMode = BOOT_GetMode();
if (BootMode == BOOT_MODE_F_LOCK)
{
gF_LOCK = true; // flag to say include the hidden menu items
@@ -126,8 +135,9 @@ void Main(void)
{ // keys are pressed
UI_DisplayReleaseKeys();
BACKLIGHT_TurnOn();
i = 0;
while (i < 50) // 500ms
// 500ms
for (int i = 0; i < 50;)
{
i = (GPIO_CheckBit(&GPIOC->DATA, GPIOC_PIN_PTT) && KEYBOARD_Poll() == KEY_INVALID) ? i + 1 : 0;
SYSTEM_DelayMs(10);
@@ -207,24 +217,18 @@ void Main(void)
#ifdef ENABLE_NOAA
RADIO_ConfigureNOAA();
#endif
// ******************
}
while (1)
{
while (true) {
APP_Update();
if (gNextTimeslice)
{
APP_TimeSlice10ms();
gNextTimeslice = false;
}
if (gNextTimeslice) {
if (gNextTimeslice_500ms)
{
APP_TimeSlice500ms();
gNextTimeslice_500ms = false;
APP_TimeSlice10ms();
if (gNextTimeslice_500ms) {
APP_TimeSlice500ms();
}
}
}
}

41
misc.c
View File

@@ -30,9 +30,11 @@ const uint8_t menu_timeout_500ms = 20000 / 500; // 20 second
const uint16_t menu_timeout_long_500ms = 120000 / 500; // 2 minutes
const uint8_t DTMF_RX_live_timeout_500ms = 6000 / 500; // 6 seconds live decoder on screen
#ifdef ENABLE_DTMF_CALLING
const uint8_t DTMF_RX_timeout_500ms = 10000 / 500; // 10 seconds till we wipe the DTMF receiver
const uint8_t DTMF_decode_ring_countdown_500ms = 15000 / 500; // 15 seconds .. time we sound the ringing for
const uint8_t DTMF_txstop_countdown_500ms = 3000 / 500; // 6 seconds
#endif
const uint8_t key_input_timeout_500ms = 8000 / 500; // 8 seconds
@@ -78,22 +80,21 @@ const uint32_t gDefaultAesKey[4] = {0x4AA5CC60, 0x0312CC5F, 0x
const uint8_t gMicGain_dB2[5] = {3, 8, 16, 24, 31};
bool gSetting_350TX;
#ifdef ENABLE_DTMF_CALLING
bool gSetting_KILLED;
#endif
bool gSetting_200TX;
bool gSetting_500TX;
bool gSetting_350EN;
bool gSetting_TX_EN;
uint8_t gSetting_F_LOCK;
bool gSetting_ScrambleEnable;
uint8_t gSetting_backlight_on_tx_rx;
enum BacklightOnRxTx_t gSetting_backlight_on_tx_rx;
#ifdef ENABLE_AM_FIX
bool gSetting_AM_fix;
#endif
#ifdef ENABLE_AM_FIX_TEST1
uint8_t gSetting_AM_fix_test1 = 0;
#endif
#ifdef ENABLE_AUDIO_BAR
bool gSetting_mic_bar;
#endif
@@ -112,7 +113,7 @@ uint16_t gEEPROM_RSSI_CALIB[7][4];
uint16_t gEEPROM_1F8A;
uint16_t gEEPROM_1F8C;
uint8_t gMR_ChannelAttributes[FREQ_CHANNEL_LAST + 1];
ChannelAttributes_t gMR_ChannelAttributes[FREQ_CHANNEL_LAST + 1];
volatile uint16_t gBatterySaveCountdown_10ms = battery_save_count_10ms;
@@ -131,7 +132,7 @@ volatile bool gNextTimeslice_500ms;
volatile uint16_t gTxTimerCountdown_500ms;
volatile bool gTxTimeoutReached;
volatile uint16_t gTailNoteEliminationCountdown_10ms;
volatile uint16_t gTailToneEliminationCountdown_10ms;
volatile uint8_t gVFOStateResumeCountdown_500ms;
@@ -142,7 +143,7 @@ volatile uint8_t gVFOStateResumeCountdown_500ms;
bool gEnableSpeaker;
uint8_t gKeyInputCountdown = 0;
uint8_t gKeyLockCountdown;
uint8_t gRTTECountdown;
uint8_t gRTTECountdown_10ms;
bool bIsInLockScreen;
uint8_t gUpdateStatus;
uint8_t gFoundCTCSS;
@@ -154,8 +155,11 @@ uint8_t gVFO_RSSI_bar_level[2];
uint8_t gReducedService;
uint8_t gBatteryVoltageIndex;
CssScanMode_t gCssScanMode;
bool gUpdateRSSI;
bool gCssBackgroundScan;
volatile bool gScheduleScanListen = true;
volatile uint16_t gScanPauseDelayIn_10ms;
#if defined(ENABLE_ALARM) || defined(ENABLE_TX1750)
AlarmState_t gAlarmState;
#endif
@@ -177,9 +181,6 @@ bool gFlagPrepareTX;
bool gFlagAcceptSetting;
bool gFlagRefreshSetting;
bool gFlagSaveVfo;
bool gFlagSaveSettings;
bool gFlagSaveChannel;
#ifdef ENABLE_FMRADIO
bool gFlagSaveFM;
#endif
@@ -194,8 +195,9 @@ bool g_CxCSS_TAIL_Found;
uint16_t gVoxPauseCountdown;
#endif
bool g_SquelchLost;
uint8_t gFlashLightState;
volatile uint16_t gFlashLightBlinkCounter;
bool gFlagEndTransmission;
uint8_t gNextMrChannel;
ReceptionMode_t gRxReceptionMode;
@@ -211,9 +213,6 @@ uint8_t gPttDebounceCounter;
uint8_t gMenuListCount;
uint8_t gBackup_CROSS_BAND_RX_TX;
uint8_t gScanDelay_10ms;
#ifdef ENABLE_AIRCOPY
uint8_t gAircopySendCountdown;
#endif
uint8_t gFSKWriteIndex;
#ifdef ENABLE_NOAA
@@ -238,18 +237,18 @@ volatile bool gNextTimeslice40ms;
volatile uint16_t gNOAACountdown_10ms = 0;
volatile bool gScheduleNOAA = true;
#endif
volatile bool gFlagTailNoteEliminationComplete;
volatile bool gFlagTailToneEliminationComplete;
#ifdef ENABLE_FMRADIO
volatile bool gScheduleFM;
#endif
volatile uint8_t boot_counter_10ms;
int16_t gCurrentRSSI[2] = {0, 0}; // now one per VFO
uint8_t gIsLocked = 0xFF;
inline void FUNCTION_NOP() { ; }
int32_t NUMBER_AddWithWraparound(int32_t Base, int32_t Add, int32_t LowerLimit, int32_t UpperLimit)
{
@@ -274,4 +273,4 @@ unsigned long StrToUL(const char * str)
ul = ul * 10 + (uint8_t)(c-'0');
}
return ul;
}
}

87
misc.h
View File

@@ -32,6 +32,10 @@
#define MIN(a, b) ({ __typeof__ (a) _a = (a); __typeof__ (b) _b = (b); _a < _b ? _a : _b; })
#endif
#ifndef SWAP
#define SWAP(a, b) ({ __typeof__ (a) _c = (a); a = b; b = _c; })
#endif
#define IS_MR_CHANNEL(x) ((x) <= MR_CHANNEL_LAST)
#define IS_FREQ_CHANNEL(x) ((x) >= FREQ_CHANNEL_FIRST && (x) <= FREQ_CHANNEL_LAST)
#define IS_VALID_CHANNEL(x) ((x) < LAST_CHANNEL)
@@ -47,13 +51,6 @@ enum {
LAST_CHANNEL
};
enum {
FLASHLIGHT_OFF = 0,
FLASHLIGHT_ON,
FLASHLIGHT_BLINK,
FLASHLIGHT_SOS
};
enum {
VFO_CONFIGURE_NONE = 0,
VFO_CONFIGURE,
@@ -63,7 +60,7 @@ enum {
enum AlarmState_t {
ALARM_STATE_OFF = 0,
ALARM_STATE_TXALARM,
ALARM_STATE_ALARM,
ALARM_STATE_SITE_ALARM,
ALARM_STATE_TX1750
};
typedef enum AlarmState_t AlarmState_t;
@@ -75,14 +72,6 @@ enum ReceptionMode_t {
};
typedef enum ReceptionMode_t ReceptionMode_t;
enum CssScanMode_t
{
CSS_SCAN_MODE_OFF = 0,
CSS_SCAN_MODE_SCANNING,
CSS_SCAN_MODE_FOUND,
};
typedef enum CssScanMode_t CssScanMode_t;
enum BacklightOnRxTx_t {
BACKLIGHT_ON_TR_OFF,
BACKLIGHT_ON_TR_TX,
@@ -101,9 +90,11 @@ extern const uint8_t menu_timeout_500ms;
extern const uint16_t menu_timeout_long_500ms;
extern const uint8_t DTMF_RX_live_timeout_500ms;
#ifdef ENABLE_DTMF_CALLING
extern const uint8_t DTMF_RX_timeout_500ms;
extern const uint8_t DTMF_decode_ring_countdown_500ms;
extern const uint8_t DTMF_txstop_countdown_500ms;
#endif
extern const uint8_t key_input_timeout_500ms;
@@ -150,22 +141,21 @@ extern const uint16_t scan_pause_delay_in_7_10ms;
extern const uint8_t gMicGain_dB2[5];
extern bool gSetting_350TX;
#ifdef ENABLE_DTMF_CALLING
extern bool gSetting_KILLED;
#endif
extern bool gSetting_200TX;
extern bool gSetting_500TX;
extern bool gSetting_350EN;
extern bool gSetting_TX_EN;
extern uint8_t gSetting_F_LOCK;
extern bool gSetting_ScrambleEnable;
extern uint8_t gSetting_backlight_on_tx_rx;
extern enum BacklightOnRxTx_t gSetting_backlight_on_tx_rx;
#ifdef ENABLE_AM_FIX
extern bool gSetting_AM_fix;
#endif
#ifdef ENABLE_AM_FIX_TEST1
extern uint8_t gSetting_AM_fix_test1;
#endif
#ifdef ENABLE_AUDIO_BAR
extern bool gSetting_mic_bar;
#endif
@@ -185,7 +175,18 @@ extern uint16_t gEEPROM_RSSI_CALIB[7][4];
extern uint16_t gEEPROM_1F8A;
extern uint16_t gEEPROM_1F8C;
extern uint8_t gMR_ChannelAttributes[207];
typedef union {
struct {
uint8_t
band : 4,
compander : 2,
scanlist2 : 1,
scanlist1 : 1;
};
uint8_t __val;
} ChannelAttributes_t;
extern ChannelAttributes_t gMR_ChannelAttributes[207];
extern volatile uint16_t gBatterySaveCountdown_10ms;
@@ -204,18 +205,15 @@ extern volatile bool gNextTimeslice_500ms;
extern volatile uint16_t gTxTimerCountdown_500ms;
extern volatile bool gTxTimeoutReached;
extern volatile uint16_t gTailNoteEliminationCountdown_10ms;
extern volatile uint16_t gTailToneEliminationCountdown_10ms;
#ifdef ENABLE_FMRADIO
extern volatile uint16_t gFmPlayCountdown_10ms;
#endif
#ifdef ENABLE_NOAA
extern volatile uint16_t gNOAA_Countdown_10ms;
#endif
extern bool gEnableSpeaker;
extern uint8_t gKeyInputCountdown;
extern uint8_t gKeyLockCountdown;
extern uint8_t gRTTECountdown;
extern uint8_t gRTTECountdown_10ms;
extern bool bIsInLockScreen;
extern uint8_t gUpdateStatus;
extern uint8_t gFoundCTCSS;
@@ -229,10 +227,20 @@ extern uint8_t gVFO_RSSI_bar_level[2];
extern uint8_t gReducedService;
extern uint8_t gBatteryVoltageIndex;
// if not equal CSS_SCAN_MODE_OFF we are scanning CTCSS/DCS
// this is a scanning inside RX ctcss/dcs menu
extern CssScanMode_t gCssScanMode;
extern bool gUpdateRSSI;
// we are searching CTCSS/DCS inside RX ctcss/dcs menu
extern bool gCssBackgroundScan;
enum
{
SCAN_REV = -1,
SCAN_OFF = 0,
SCAN_FWD = +1
};
extern volatile bool gScheduleScanListen;
extern volatile uint16_t gScanPauseDelayIn_10ms;
extern AlarmState_t gAlarmState;
extern uint16_t gMenuCountdown;
extern bool gPttWasReleased;
@@ -252,9 +260,6 @@ extern bool gFlagPrepareTX;
extern bool gFlagAcceptSetting; // accept menu setting
extern bool gFlagRefreshSetting; // refresh menu display
extern bool gFlagSaveVfo;
extern bool gFlagSaveSettings;
extern bool gFlagSaveChannel;
#ifdef ENABLE_FMRADIO
extern bool gFlagSaveFM;
#endif
@@ -271,8 +276,9 @@ extern bool g_CxCSS_TAIL_Found;
// true means we are receiving signal
extern bool g_SquelchLost;
extern uint8_t gFlashLightState;
extern volatile uint16_t gFlashLightBlinkCounter;
extern bool gFlagEndTransmission;
extern uint8_t gNextMrChannel;
extern ReceptionMode_t gRxReceptionMode;
@@ -287,9 +293,6 @@ extern uint8_t gPttDebounceCounter;
extern uint8_t gMenuListCount;
extern uint8_t gBackup_CROSS_BAND_RX_TX;
extern uint8_t gScanDelay_10ms;
#ifdef ENABLE_AIRCOPY
extern uint8_t gAircopySendCountdown;
#endif
extern uint8_t gFSKWriteIndex;
#ifdef ENABLE_NOAA
extern bool gIsNoaaMode;
@@ -312,17 +315,19 @@ extern volatile bool gNextTimeslice40ms;
extern volatile uint16_t gNOAACountdown_10ms;
extern volatile bool gScheduleNOAA;
#endif
extern volatile bool gFlagTailNoteEliminationComplete;
extern volatile bool gFlagTailToneEliminationComplete;
extern volatile uint8_t gVFOStateResumeCountdown_500ms;
#ifdef ENABLE_FMRADIO
extern volatile bool gScheduleFM;
#endif
extern int16_t gCurrentRSSI[2]; // now one per VFO
extern uint8_t gIsLocked;
extern volatile uint8_t boot_counter_10ms;
int32_t NUMBER_AddWithWraparound(int32_t Base, int32_t Add, int32_t LowerLimit, int32_t UpperLimit);
unsigned long StrToUL(const char * str);
#endif
void FUNCTION_NOP();
inline bool SerialConfigInProgress() { return gSerialConfigCountDown_500ms != 0; }
#endif

772
radio.c

File diff suppressed because it is too large Load Diff

27
radio.h
View File

@@ -23,13 +23,6 @@
#include "dcs.h"
#include "frequencies.h"
enum {
MR_CH_BAND_MASK = 0x0F << 0,
MR_CH_COMPAND = 3u << 4, // new
MR_CH_SCANLIST2 = 1u << 6,
MR_CH_SCANLIST1 = 1u << 7
};
enum {
RADIO_CHANNEL_UP = 0x01u,
RADIO_CHANNEL_DOWN = 0xFFu,
@@ -57,7 +50,8 @@ enum VfoState_t
VFO_STATE_TX_DISABLE,
VFO_STATE_TIMEOUT,
VFO_STATE_ALARM,
VFO_STATE_VOLTAGE_HIGH
VFO_STATE_VOLTAGE_HIGH,
_VFO_STATE_LAST_ELEMENT
};
typedef enum VfoState_t VfoState_t;
@@ -124,8 +118,9 @@ typedef struct VFO_Info_t
uint8_t SCANLIST2_PARTICIPATION;
uint8_t Band;
#ifdef ENABLE_DTMF_CALLING
uint8_t DTMF_DECODING_ENABLE;
#endif
PTT_ID_t DTMF_PTT_ID_TX_MODE;
uint8_t BUSY_CHANNEL_LOCK;
@@ -138,7 +133,7 @@ typedef struct VFO_Info_t
} VFO_Info_t;
// Settings of the main VFO that is selected by the user
// The pointer follows gEeprom.RX_VFO index
// The pointer follows gEeprom.TX_VFO index
extern VFO_Info_t *gTxVfo;
// Settings of the actual VFO that is now used for RX,
@@ -149,32 +144,28 @@ extern VFO_Info_t *gRxVfo;
// Equal to gTxVfo unless dual watch changes it on incomming transmition (this can only happen when XB off and DW on)
extern VFO_Info_t *gCurrentVfo;
extern DCS_CodeType_t gSelectedCodeType;
extern DCS_CodeType_t gCurrentCodeType;
extern uint8_t gSelectedCode;
extern STEP_Setting_t gStepSetting;
extern VfoState_t VfoState[2];
bool RADIO_CheckValidChannel(uint16_t ChNum, bool bCheckScanList, uint8_t RadioNum);
bool RADIO_CheckValidChannel(uint16_t channel, bool checkScanList, uint8_t scanList);
uint8_t RADIO_FindNextChannel(uint8_t ChNum, int8_t Direction, bool bCheckScanList, uint8_t RadioNum);
void RADIO_InitInfo(VFO_Info_t *pInfo, const uint8_t ChannelSave, const uint32_t Frequency);
void RADIO_ConfigureChannel(const unsigned int VFO, const unsigned int configure);
void RADIO_ConfigureSquelchAndOutputPower(VFO_Info_t *pInfo);
void RADIO_ApplyOffset(VFO_Info_t *pInfo);
void RADIO_SelectVfos(void);
void RADIO_SetupRegisters(bool bSwitchToFunction0);
void RADIO_SetupRegisters(bool switchToForeground);
#ifdef ENABLE_NOAA
void RADIO_ConfigureNOAA(void);
#endif
void RADIO_SetTxParameters(void);
void RADIO_SetupAGC(bool listeningAM, bool disable);
void RADIO_SetModulation(ModulationMode_t modulation);
void RADIO_SetVfoState(VfoState_t State);
void RADIO_PrepareTX(void);
void RADIO_EnableCxCSS(void);
void RADIO_SendCssTail(void);
void RADIO_PrepareCssTX(void);
void RADIO_SendEndOfTransmission(void);
#endif

View File

@@ -14,6 +14,7 @@
* limitations under the License.
*/
#include "app/chFrScanner.h"
#ifdef ENABLE_FMRADIO
#include "app/fm.h"
#endif
@@ -52,8 +53,7 @@ void SystickHandler(void)
gNextTimeslice = true;
if ((gGlobalSysTickCounter % 50) == 0)
{
if ((gGlobalSysTickCounter % 50) == 0) {
gNextTimeslice_500ms = true;
DECREMENT_AND_TRIGGER(gTxTimerCountdown_500ms, gTxTimeoutReached);
@@ -63,9 +63,9 @@ void SystickHandler(void)
if ((gGlobalSysTickCounter & 3) == 0)
gNextTimeslice40ms = true;
#ifdef ENABLE_NOAA
DECREMENT(gNOAACountdown_10ms);
#endif
#ifdef ENABLE_NOAA
DECREMENT(gNOAACountdown_10ms);
#endif
DECREMENT(gFoundCDCSSCountdown_10ms);
@@ -77,36 +77,36 @@ void SystickHandler(void)
if (gCurrentFunction == FUNCTION_POWER_SAVE)
DECREMENT_AND_TRIGGER(gPowerSave_10ms, gPowerSaveCountdownExpired);
if (gScanStateDir == SCAN_OFF && gCssScanMode == CSS_SCAN_MODE_OFF && gEeprom.DUAL_WATCH != DUAL_WATCH_OFF)
if (gScanStateDir == SCAN_OFF && !gCssBackgroundScan && gEeprom.DUAL_WATCH != DUAL_WATCH_OFF)
if (gCurrentFunction != FUNCTION_MONITOR && gCurrentFunction != FUNCTION_TRANSMIT && gCurrentFunction != FUNCTION_RECEIVE)
DECREMENT_AND_TRIGGER(gDualWatchCountdown_10ms, gScheduleDualWatch);
#ifdef ENABLE_NOAA
if (gScanStateDir == SCAN_OFF && gCssScanMode == CSS_SCAN_MODE_OFF && gEeprom.DUAL_WATCH == DUAL_WATCH_OFF)
if (gIsNoaaMode && gCurrentFunction != FUNCTION_MONITOR && gCurrentFunction != FUNCTION_TRANSMIT)
if (gCurrentFunction != FUNCTION_RECEIVE)
DECREMENT_AND_TRIGGER(gNOAA_Countdown_10ms, gScheduleNOAA);
#endif
#ifdef ENABLE_NOAA
if (gScanStateDir == SCAN_OFF && !gCssBackgroundScan && gEeprom.DUAL_WATCH == DUAL_WATCH_OFF)
if (gIsNoaaMode && gCurrentFunction != FUNCTION_MONITOR && gCurrentFunction != FUNCTION_TRANSMIT)
if (gCurrentFunction != FUNCTION_RECEIVE)
DECREMENT_AND_TRIGGER(gNOAA_Countdown_10ms, gScheduleNOAA);
#endif
if (gScanStateDir != SCAN_OFF || gCssScanMode == CSS_SCAN_MODE_SCANNING)
if (gScanStateDir != SCAN_OFF)
if (gCurrentFunction != FUNCTION_MONITOR && gCurrentFunction != FUNCTION_TRANSMIT)
DECREMENT_AND_TRIGGER(gScanPauseDelayIn_10ms, gScheduleScanListen);
DECREMENT_AND_TRIGGER(gTailNoteEliminationCountdown_10ms, gFlagTailNoteEliminationComplete);
DECREMENT_AND_TRIGGER(gTailToneEliminationCountdown_10ms, gFlagTailToneEliminationComplete);
#ifdef ENABLE_VOICE
DECREMENT_AND_TRIGGER(gCountdownToPlayNextVoice_10ms, gFlagPlayQueuedVoice);
#endif
#ifdef ENABLE_FMRADIO
if (gFM_ScanState != FM_SCAN_OFF && gCurrentFunction != FUNCTION_MONITOR)
if (gCurrentFunction != FUNCTION_TRANSMIT && gCurrentFunction != FUNCTION_RECEIVE)
DECREMENT_AND_TRIGGER(gFmPlayCountdown_10ms, gScheduleFM);
#endif
#ifdef ENABLE_VOICE
DECREMENT_AND_TRIGGER(gCountdownToPlayNextVoice_10ms, gFlagPlayQueuedVoice);
#endif
#ifdef ENABLE_VOX
DECREMENT(gVoxStopCountdown_10ms);
#endif
#ifdef ENABLE_FMRADIO
if (gFM_ScanState != FM_SCAN_OFF && gCurrentFunction != FUNCTION_MONITOR)
if (gCurrentFunction != FUNCTION_TRANSMIT && gCurrentFunction != FUNCTION_RECEIVE)
DECREMENT_AND_TRIGGER(gFmPlayCountdown_10ms, gScheduleFM);
#endif
#ifdef ENABLE_VOX
DECREMENT(gVoxStopCountdown_10ms);
#endif
DECREMENT(boot_counter_10ms);
}

View File

@@ -16,36 +16,431 @@
#include <string.h>
#include "app/dtmf.h"
#ifdef ENABLE_FMRADIO
#include "app/fm.h"
#endif
#include "driver/bk1080.h"
#include "driver/bk4819.h"
#include "driver/eeprom.h"
#include "driver/uart.h"
#include "misc.h"
#include "settings.h"
#include "ui/menu.h"
EEPROM_Config_t gEeprom;
static const uint32_t gDefaultFrequencyTable[] =
{
14500000, //
14550000, //
43300000, //
43320000, //
43350000 //
};
EEPROM_Config_t gEeprom = { 0 };
void SETTINGS_InitEEPROM(void)
{
uint8_t Data[16] = {0};
// 0E70..0E77
EEPROM_ReadBuffer(0x0E70, Data, 8);
gEeprom.CHAN_1_CALL = IS_MR_CHANNEL(Data[0]) ? Data[0] : MR_CHANNEL_FIRST;
gEeprom.SQUELCH_LEVEL = (Data[1] < 10) ? Data[1] : 1;
gEeprom.TX_TIMEOUT_TIMER = (Data[2] < 11) ? Data[2] : 1;
#ifdef ENABLE_NOAA
gEeprom.NOAA_AUTO_SCAN = (Data[3] < 2) ? Data[3] : false;
#endif
gEeprom.KEY_LOCK = (Data[4] < 2) ? Data[4] : false;
#ifdef ENABLE_VOX
gEeprom.VOX_SWITCH = (Data[5] < 2) ? Data[5] : false;
gEeprom.VOX_LEVEL = (Data[6] < 10) ? Data[6] : 1;
#endif
gEeprom.MIC_SENSITIVITY = (Data[7] < 5) ? Data[7] : 4;
// 0E78..0E7F
EEPROM_ReadBuffer(0x0E78, Data, 8);
gEeprom.BACKLIGHT_MAX = (Data[0] & 0xF) <= 10 ? (Data[0] & 0xF) : 10;
gEeprom.BACKLIGHT_MIN = (Data[0] >> 4) < gEeprom.BACKLIGHT_MAX ? (Data[0] >> 4) : 0;
#ifdef ENABLE_BLMIN_TMP_OFF
gEeprom.BACKLIGHT_MIN_STAT = BLMIN_STAT_ON;
#endif
gEeprom.CHANNEL_DISPLAY_MODE = (Data[1] < 4) ? Data[1] : MDF_FREQUENCY; // 4 instead of 3 - extra display mode
gEeprom.CROSS_BAND_RX_TX = (Data[2] < 3) ? Data[2] : CROSS_BAND_OFF;
gEeprom.BATTERY_SAVE = (Data[3] < 5) ? Data[3] : 4;
gEeprom.DUAL_WATCH = (Data[4] < 3) ? Data[4] : DUAL_WATCH_CHAN_A;
gEeprom.BACKLIGHT_TIME = (Data[5] < ARRAY_SIZE(gSubMenu_BACKLIGHT)) ? Data[5] : 3;
gEeprom.TAIL_TONE_ELIMINATION = (Data[6] < 2) ? Data[6] : false;
gEeprom.VFO_OPEN = (Data[7] < 2) ? Data[7] : true;
// 0E80..0E87
EEPROM_ReadBuffer(0x0E80, Data, 8);
gEeprom.ScreenChannel[0] = IS_VALID_CHANNEL(Data[0]) ? Data[0] : (FREQ_CHANNEL_FIRST + BAND6_400MHz);
gEeprom.ScreenChannel[1] = IS_VALID_CHANNEL(Data[3]) ? Data[3] : (FREQ_CHANNEL_FIRST + BAND6_400MHz);
gEeprom.MrChannel[0] = IS_MR_CHANNEL(Data[1]) ? Data[1] : MR_CHANNEL_FIRST;
gEeprom.MrChannel[1] = IS_MR_CHANNEL(Data[4]) ? Data[4] : MR_CHANNEL_FIRST;
gEeprom.FreqChannel[0] = IS_FREQ_CHANNEL(Data[2]) ? Data[2] : (FREQ_CHANNEL_FIRST + BAND6_400MHz);
gEeprom.FreqChannel[1] = IS_FREQ_CHANNEL(Data[5]) ? Data[5] : (FREQ_CHANNEL_FIRST + BAND6_400MHz);
#ifdef ENABLE_NOAA
gEeprom.NoaaChannel[0] = IS_NOAA_CHANNEL(Data[6]) ? Data[6] : NOAA_CHANNEL_FIRST;
gEeprom.NoaaChannel[1] = IS_NOAA_CHANNEL(Data[7]) ? Data[7] : NOAA_CHANNEL_FIRST;
#endif
#ifdef ENABLE_FMRADIO
void SETTINGS_SaveFM(void)
{
unsigned int i;
{ // 0E88..0E8F
struct
{
uint16_t Frequency;
uint8_t Channel;
bool IsChannelSelected;
uint8_t Padding[4];
} State;
uint16_t selFreq;
uint8_t selChn;
uint8_t isMrMode:1;
uint8_t band:2;
//uint8_t space:2;
} __attribute__((packed)) fmCfg;
EEPROM_ReadBuffer(0x0E88, &fmCfg, 4);
memset(&State, 0xFF, sizeof(State));
State.Channel = gEeprom.FM_SelectedChannel;
State.Frequency = gEeprom.FM_SelectedFrequency;
State.IsChannelSelected = gEeprom.FM_IsMrMode;
gEeprom.FM_Band = fmCfg.band;
//gEeprom.FM_Space = fmCfg.space;
gEeprom.FM_SelectedFrequency =
(fmCfg.selFreq >= BK1080_GetFreqLoLimit(gEeprom.FM_Band) && fmCfg.selFreq <= BK1080_GetFreqHiLimit(gEeprom.FM_Band)) ?
fmCfg.selFreq : BK1080_GetFreqLoLimit(gEeprom.FM_Band);
gEeprom.FM_SelectedChannel = fmCfg.selChn;
gEeprom.FM_IsMrMode = fmCfg.isMrMode;
}
EEPROM_WriteBuffer(0x0E88, &State);
for (i = 0; i < 5; i++)
// 0E40..0E67
EEPROM_ReadBuffer(0x0E40, gFM_Channels, sizeof(gFM_Channels));
FM_ConfigureChannelState();
#endif
// 0E90..0E97
EEPROM_ReadBuffer(0x0E90, Data, 8);
gEeprom.BEEP_CONTROL = Data[0] & 1;
gEeprom.KEY_M_LONG_PRESS_ACTION = ((Data[0] >> 1) < ACTION_OPT_LEN) ? (Data[0] >> 1) : ACTION_OPT_NONE;
gEeprom.KEY_1_SHORT_PRESS_ACTION = (Data[1] < ACTION_OPT_LEN) ? Data[1] : ACTION_OPT_MONITOR;
gEeprom.KEY_1_LONG_PRESS_ACTION = (Data[2] < ACTION_OPT_LEN) ? Data[2] : ACTION_OPT_NONE;
gEeprom.KEY_2_SHORT_PRESS_ACTION = (Data[3] < ACTION_OPT_LEN) ? Data[3] : ACTION_OPT_SCAN;
gEeprom.KEY_2_LONG_PRESS_ACTION = (Data[4] < ACTION_OPT_LEN) ? Data[4] : ACTION_OPT_NONE;
gEeprom.SCAN_RESUME_MODE = (Data[5] < 3) ? Data[5] : SCAN_RESUME_CO;
gEeprom.AUTO_KEYPAD_LOCK = (Data[6] < 2) ? Data[6] : false;
gEeprom.POWER_ON_DISPLAY_MODE = (Data[7] < 4) ? Data[7] : POWER_ON_DISPLAY_MODE_VOLTAGE;
// 0E98..0E9F
EEPROM_ReadBuffer(0x0E98, Data, 8);
memcpy(&gEeprom.POWER_ON_PASSWORD, Data, 4);
// 0EA0..0EA7
EEPROM_ReadBuffer(0x0EA0, Data, 8);
#ifdef ENABLE_VOICE
gEeprom.VOICE_PROMPT = (Data[0] < 3) ? Data[0] : VOICE_PROMPT_ENGLISH;
#endif
#ifdef ENABLE_RSSI_BAR
if((Data[1] < 200 && Data[1] > 90) && (Data[2] < Data[1]-9 && Data[1] < 160 && Data[2] > 50)) {
gEeprom.S0_LEVEL = Data[1];
gEeprom.S9_LEVEL = Data[2];
}
else {
gEeprom.S0_LEVEL = 130;
gEeprom.S9_LEVEL = 76;
}
#endif
// 0EA8..0EAF
EEPROM_ReadBuffer(0x0EA8, Data, 8);
#ifdef ENABLE_ALARM
gEeprom.ALARM_MODE = (Data[0] < 2) ? Data[0] : true;
#endif
gEeprom.ROGER = (Data[1] < 3) ? Data[1] : ROGER_MODE_OFF;
gEeprom.REPEATER_TAIL_TONE_ELIMINATION = (Data[2] < 11) ? Data[2] : 0;
gEeprom.TX_VFO = (Data[3] < 2) ? Data[3] : 0;
gEeprom.BATTERY_TYPE = (Data[4] < BATTERY_TYPE_UNKNOWN) ? Data[4] : BATTERY_TYPE_1600_MAH;
// 0ED0..0ED7
EEPROM_ReadBuffer(0x0ED0, Data, 8);
gEeprom.DTMF_SIDE_TONE = (Data[0] < 2) ? Data[0] : true;
#ifdef ENABLE_DTMF_CALLING
gEeprom.DTMF_SEPARATE_CODE = DTMF_ValidateCodes((char *)(Data + 1), 1) ? Data[1] : '*';
gEeprom.DTMF_GROUP_CALL_CODE = DTMF_ValidateCodes((char *)(Data + 2), 1) ? Data[2] : '#';
gEeprom.DTMF_DECODE_RESPONSE = (Data[3] < 4) ? Data[3] : 0;
gEeprom.DTMF_auto_reset_time = (Data[4] < 61 && Data[4] >= 5) ? Data[4] : 10;
#endif
gEeprom.DTMF_PRELOAD_TIME = (Data[5] < 101) ? Data[5] * 10 : 300;
gEeprom.DTMF_FIRST_CODE_PERSIST_TIME = (Data[6] < 101) ? Data[6] * 10 : 100;
gEeprom.DTMF_HASH_CODE_PERSIST_TIME = (Data[7] < 101) ? Data[7] * 10 : 100;
// 0ED8..0EDF
EEPROM_ReadBuffer(0x0ED8, Data, 8);
gEeprom.DTMF_CODE_PERSIST_TIME = (Data[0] < 101) ? Data[0] * 10 : 100;
gEeprom.DTMF_CODE_INTERVAL_TIME = (Data[1] < 101) ? Data[1] * 10 : 100;
#ifdef ENABLE_DTMF_CALLING
gEeprom.PERMIT_REMOTE_KILL = (Data[2] < 2) ? Data[2] : true;
// 0EE0..0EE7
EEPROM_ReadBuffer(0x0EE0, Data, sizeof(gEeprom.ANI_DTMF_ID));
if (DTMF_ValidateCodes((char *)Data, sizeof(gEeprom.ANI_DTMF_ID))) {
memcpy(gEeprom.ANI_DTMF_ID, Data, sizeof(gEeprom.ANI_DTMF_ID));
} else {
strcpy(gEeprom.ANI_DTMF_ID, "123");
}
// 0EE8..0EEF
EEPROM_ReadBuffer(0x0EE8, Data, sizeof(gEeprom.KILL_CODE));
if (DTMF_ValidateCodes((char *)Data, sizeof(gEeprom.KILL_CODE))) {
memcpy(gEeprom.KILL_CODE, Data, sizeof(gEeprom.KILL_CODE));
} else {
strcpy(gEeprom.KILL_CODE, "ABCD9");
}
// 0EF0..0EF7
EEPROM_ReadBuffer(0x0EF0, Data, sizeof(gEeprom.REVIVE_CODE));
if (DTMF_ValidateCodes((char *)Data, sizeof(gEeprom.REVIVE_CODE))) {
memcpy(gEeprom.REVIVE_CODE, Data, sizeof(gEeprom.REVIVE_CODE));
} else {
strcpy(gEeprom.REVIVE_CODE, "9DCBA");
}
#endif
// 0EF8..0F07
EEPROM_ReadBuffer(0x0EF8, Data, sizeof(gEeprom.DTMF_UP_CODE));
if (DTMF_ValidateCodes((char *)Data, sizeof(gEeprom.DTMF_UP_CODE))) {
memcpy(gEeprom.DTMF_UP_CODE, Data, sizeof(gEeprom.DTMF_UP_CODE));
} else {
strcpy(gEeprom.DTMF_UP_CODE, "12345");
}
// 0F08..0F17
EEPROM_ReadBuffer(0x0F08, Data, sizeof(gEeprom.DTMF_DOWN_CODE));
if (DTMF_ValidateCodes((char *)Data, sizeof(gEeprom.DTMF_DOWN_CODE))) {
memcpy(gEeprom.DTMF_DOWN_CODE, Data, sizeof(gEeprom.DTMF_DOWN_CODE));
} else {
strcpy(gEeprom.DTMF_DOWN_CODE, "54321");
}
// 0F18..0F1F
EEPROM_ReadBuffer(0x0F18, Data, 8);
gEeprom.SCAN_LIST_DEFAULT = (Data[0] < 3) ? Data[0] : 0; // we now have 'all' channel scan option
for (unsigned int i = 0; i < 2; i++)
{
const unsigned int j = 1 + (i * 3);
gEeprom.SCAN_LIST_ENABLED[i] = (Data[j + 0] < 2) ? Data[j] : false;
gEeprom.SCANLIST_PRIORITY_CH1[i] = Data[j + 1];
gEeprom.SCANLIST_PRIORITY_CH2[i] = Data[j + 2];
}
// 0F40..0F47
EEPROM_ReadBuffer(0x0F40, Data, 8);
gSetting_F_LOCK = (Data[0] < F_LOCK_LEN) ? Data[0] : F_LOCK_DEF;
gSetting_350TX = (Data[1] < 2) ? Data[1] : false; // was true
#ifdef ENABLE_DTMF_CALLING
gSetting_KILLED = (Data[2] < 2) ? Data[2] : false;
#endif
gSetting_200TX = (Data[3] < 2) ? Data[3] : false;
gSetting_500TX = (Data[4] < 2) ? Data[4] : false;
gSetting_350EN = (Data[5] < 2) ? Data[5] : true;
gSetting_ScrambleEnable = (Data[6] < 2) ? Data[6] : true;
//gSetting_TX_EN = (Data[7] & (1u << 0)) ? true : false;
gSetting_live_DTMF_decoder = !!(Data[7] & (1u << 1));
gSetting_battery_text = (((Data[7] >> 2) & 3u) <= 2) ? (Data[7] >> 2) & 3 : 2;
#ifdef ENABLE_AUDIO_BAR
gSetting_mic_bar = !!(Data[7] & (1u << 4));
#endif
#ifdef ENABLE_AM_FIX
gSetting_AM_fix = !!(Data[7] & (1u << 5));
#endif
gSetting_backlight_on_tx_rx = (Data[7] >> 6) & 3u;
if (!gEeprom.VFO_OPEN)
{
gEeprom.ScreenChannel[0] = gEeprom.MrChannel[0];
gEeprom.ScreenChannel[1] = gEeprom.MrChannel[1];
}
// 0D60..0E27
EEPROM_ReadBuffer(0x0D60, gMR_ChannelAttributes, sizeof(gMR_ChannelAttributes));
for(uint16_t i = 0; i < sizeof(gMR_ChannelAttributes); i++) {
ChannelAttributes_t *att = &gMR_ChannelAttributes[i];
if(att->__val == 0xff){
att->__val = 0;
att->band = 0xf;
}
}
// 0F30..0F3F
EEPROM_ReadBuffer(0x0F30, gCustomAesKey, sizeof(gCustomAesKey));
bHasCustomAesKey = false;
for (unsigned int i = 0; i < ARRAY_SIZE(gCustomAesKey); i++)
{
if (gCustomAesKey[i] != 0xFFFFFFFFu)
{
bHasCustomAesKey = true;
return;
}
}
}
void SETTINGS_LoadCalibration(void)
{
// uint8_t Mic;
EEPROM_ReadBuffer(0x1EC0, gEEPROM_RSSI_CALIB[3], 8);
memcpy(gEEPROM_RSSI_CALIB[4], gEEPROM_RSSI_CALIB[3], 8);
memcpy(gEEPROM_RSSI_CALIB[5], gEEPROM_RSSI_CALIB[3], 8);
memcpy(gEEPROM_RSSI_CALIB[6], gEEPROM_RSSI_CALIB[3], 8);
EEPROM_ReadBuffer(0x1EC8, gEEPROM_RSSI_CALIB[0], 8);
memcpy(gEEPROM_RSSI_CALIB[1], gEEPROM_RSSI_CALIB[0], 8);
memcpy(gEEPROM_RSSI_CALIB[2], gEEPROM_RSSI_CALIB[0], 8);
EEPROM_ReadBuffer(0x1F40, gBatteryCalibration, 12);
if (gBatteryCalibration[0] >= 5000)
{
gBatteryCalibration[0] = 1900;
gBatteryCalibration[1] = 2000;
}
gBatteryCalibration[5] = 2300;
#ifdef ENABLE_VOX
EEPROM_ReadBuffer(0x1F50 + (gEeprom.VOX_LEVEL * 2), &gEeprom.VOX1_THRESHOLD, 2);
EEPROM_ReadBuffer(0x1F68 + (gEeprom.VOX_LEVEL * 2), &gEeprom.VOX0_THRESHOLD, 2);
#endif
//EEPROM_ReadBuffer(0x1F80 + gEeprom.MIC_SENSITIVITY, &Mic, 1);
//gEeprom.MIC_SENSITIVITY_TUNING = (Mic < 32) ? Mic : 15;
gEeprom.MIC_SENSITIVITY_TUNING = gMicGain_dB2[gEeprom.MIC_SENSITIVITY];
{
struct
{
int16_t BK4819_XtalFreqLow;
uint16_t EEPROM_1F8A;
uint16_t EEPROM_1F8C;
uint8_t VOLUME_GAIN;
uint8_t DAC_GAIN;
} __attribute__((packed)) Misc;
// radio 1 .. 04 00 46 00 50 00 2C 0E
// radio 2 .. 05 00 46 00 50 00 2C 0E
EEPROM_ReadBuffer(0x1F88, &Misc, 8);
gEeprom.BK4819_XTAL_FREQ_LOW = (Misc.BK4819_XtalFreqLow >= -1000 && Misc.BK4819_XtalFreqLow <= 1000) ? Misc.BK4819_XtalFreqLow : 0;
gEEPROM_1F8A = Misc.EEPROM_1F8A & 0x01FF;
gEEPROM_1F8C = Misc.EEPROM_1F8C & 0x01FF;
gEeprom.VOLUME_GAIN = (Misc.VOLUME_GAIN < 64) ? Misc.VOLUME_GAIN : 58;
gEeprom.DAC_GAIN = (Misc.DAC_GAIN < 16) ? Misc.DAC_GAIN : 8;
BK4819_WriteRegister(BK4819_REG_3B, 22656 + gEeprom.BK4819_XTAL_FREQ_LOW);
// BK4819_WriteRegister(BK4819_REG_3C, gEeprom.BK4819_XTAL_FREQ_HIGH);
}
}
uint32_t SETTINGS_FetchChannelFrequency(const int channel)
{
struct
{
uint32_t frequency;
uint32_t offset;
} __attribute__((packed)) info;
EEPROM_ReadBuffer(channel * 16, &info, sizeof(info));
return info.frequency;
}
void SETTINGS_FetchChannelName(char *s, const int channel)
{
if (s == NULL)
return;
s[0] = 0;
if (channel < 0)
return;
if (!RADIO_CheckValidChannel(channel, false, 0))
return;
EEPROM_ReadBuffer(0x0F50 + (channel * 16), s, 10);
int i;
for (i = 0; i < 10; i++)
if (s[i] < 32 || s[i] > 127)
break; // invalid char
s[i--] = 0; // null term
while (i >= 0 && s[i] == 32) // trim trailing spaces
s[i--] = 0; // null term
}
void SETTINGS_FactoryReset(bool bIsAll)
{
uint16_t i;
uint8_t Template[8];
memset(Template, 0xFF, sizeof(Template));
for (i = 0x0C80; i < 0x1E00; i += 8)
{
if (
!(i >= 0x0EE0 && i < 0x0F18) && // ANI ID + DTMF codes
!(i >= 0x0F30 && i < 0x0F50) && // AES KEY + F LOCK + Scramble Enable
!(i >= 0x1C00 && i < 0x1E00) && // DTMF contacts
!(i >= 0x0EB0 && i < 0x0ED0) && // Welcome strings
!(i >= 0x0EA0 && i < 0x0EA8) && // Voice Prompt
(bIsAll ||
(
!(i >= 0x0D60 && i < 0x0E28) && // MR Channel Attributes
!(i >= 0x0F18 && i < 0x0F30) && // Scan List
!(i >= 0x0F50 && i < 0x1C00) && // MR Channel Names
!(i >= 0x0E40 && i < 0x0E70) && // FM Channels
!(i >= 0x0E88 && i < 0x0E90) // FM settings
))
)
{
EEPROM_WriteBuffer(i, Template);
}
}
if (bIsAll)
{
RADIO_InitInfo(gRxVfo, FREQ_CHANNEL_FIRST + BAND6_400MHz, 43350000);
// set the first few memory channels
for (i = 0; i < ARRAY_SIZE(gDefaultFrequencyTable); i++)
{
const uint32_t Frequency = gDefaultFrequencyTable[i];
gRxVfo->freq_config_RX.Frequency = Frequency;
gRxVfo->freq_config_TX.Frequency = Frequency;
gRxVfo->Band = FREQUENCY_GetBand(Frequency);
SETTINGS_SaveChannel(MR_CHANNEL_FIRST + i, 0, gRxVfo, 2);
}
}
}
#ifdef ENABLE_FMRADIO
void SETTINGS_SaveFM(void)
{
union {
struct {
uint16_t selFreq;
uint8_t selChn;
uint8_t isMrMode:1;
uint8_t band:2;
//uint8_t space:2;
};
uint8_t __raw[8];
} __attribute__((packed)) fmCfg;
memset(fmCfg.__raw, 0xFF, sizeof(fmCfg.__raw));
fmCfg.selChn = gEeprom.FM_SelectedChannel;
fmCfg.selFreq = gEeprom.FM_SelectedFrequency;
fmCfg.isMrMode = gEeprom.FM_IsMrMode;
fmCfg.band = gEeprom.FM_Band;
//fmCfg.space = gEeprom.FM_Space;
EEPROM_WriteBuffer(0x0E88, fmCfg.__raw);
for (unsigned i = 0; i < 5; i++)
EEPROM_WriteBuffer(0x0E40 + (i * 8), &gFM_Channels[i * 4]);
}
#endif
@@ -126,8 +521,13 @@ void SETTINGS_SaveSettings(void)
memset(State, 0xFF, sizeof(State));
#ifdef ENABLE_VOICE
State[0] = gEeprom.VOICE_PROMPT;
EEPROM_WriteBuffer(0x0EA0, State);
#endif
#ifdef ENABLE_RSSI_BAR
State[1] = gEeprom.S0_LEVEL;
State[2] = gEeprom.S9_LEVEL;
#endif
EEPROM_WriteBuffer(0x0EA0, State);
#if defined(ENABLE_ALARM) || defined(ENABLE_TX1750)
State[0] = gEeprom.ALARM_MODE;
@@ -141,10 +541,12 @@ void SETTINGS_SaveSettings(void)
EEPROM_WriteBuffer(0x0EA8, State);
State[0] = gEeprom.DTMF_SIDE_TONE;
#ifdef ENABLE_DTMF_CALLING
State[1] = gEeprom.DTMF_SEPARATE_CODE;
State[2] = gEeprom.DTMF_GROUP_CALL_CODE;
State[3] = gEeprom.DTMF_DECODE_RESPONSE;
State[4] = gEeprom.DTMF_auto_reset_time;
#endif
State[5] = gEeprom.DTMF_PRELOAD_TIME / 10U;
State[6] = gEeprom.DTMF_FIRST_CODE_PERSIST_TIME / 10U;
State[7] = gEeprom.DTMF_HASH_CODE_PERSIST_TIME / 10U;
@@ -153,7 +555,9 @@ void SETTINGS_SaveSettings(void)
memset(State, 0xFF, sizeof(State));
State[0] = gEeprom.DTMF_CODE_PERSIST_TIME / 10U;
State[1] = gEeprom.DTMF_CODE_INTERVAL_TIME / 10U;
#ifdef ENABLE_DTMF_CALLING
State[2] = gEeprom.PERMIT_REMOTE_KILL;
#endif
EEPROM_WriteBuffer(0x0ED8, State);
State[0] = gEeprom.SCAN_LIST_DEFAULT;
@@ -169,12 +573,14 @@ void SETTINGS_SaveSettings(void)
memset(State, 0xFF, sizeof(State));
State[0] = gSetting_F_LOCK;
State[1] = gSetting_350TX;
#ifdef ENABLE_DTMF_CALLING
State[2] = gSetting_KILLED;
#endif
State[3] = gSetting_200TX;
State[4] = gSetting_500TX;
State[5] = gSetting_350EN;
State[6] = gSetting_ScrambleEnable;
if (!gSetting_TX_EN) State[7] &= ~(1u << 0);
//if (!gSetting_TX_EN) State[7] &= ~(1u << 0);
if (!gSetting_live_DTMF_decoder) State[7] &= ~(1u << 1);
State[7] = (State[7] & ~(3u << 2)) | ((gSetting_battery_text & 3u) << 2);
#ifdef ENABLE_AUDIO_BAR
@@ -184,73 +590,66 @@ void SETTINGS_SaveSettings(void)
if (!gSetting_AM_fix) State[7] &= ~(1u << 5);
#endif
State[7] = (State[7] & ~(3u << 6)) | ((gSetting_backlight_on_tx_rx & 3u) << 6);
EEPROM_WriteBuffer(0x0F40, State);
}
void SETTINGS_SaveChannel(uint8_t Channel, uint8_t VFO, const VFO_Info_t *pVFO, uint8_t Mode)
{
#ifdef ENABLE_NOAA
if (!IS_NOAA_CHANNEL(Channel))
#endif
{
const uint16_t OffsetMR = Channel * 16;
uint16_t OffsetVFO = OffsetMR;
#ifdef ENABLE_NOAA
if (IS_NOAA_CHANNEL(Channel))
return;
#endif
if (!IS_MR_CHANNEL(Channel))
{ // it's a VFO, not a channel
OffsetVFO = (VFO == 0) ? 0x0C80 : 0x0C90;
OffsetVFO += (Channel - FREQ_CHANNEL_FIRST) * 32;
}
uint16_t OffsetVFO = Channel * 16;
if (Mode >= 2 || !IS_MR_CHANNEL(Channel))
{ // copy VFO to a channel
if (IS_FREQ_CHANNEL(Channel)) { // it's a VFO, not a channel
OffsetVFO = (VFO == 0) ? 0x0C80 : 0x0C90;
OffsetVFO += (Channel - FREQ_CHANNEL_FIRST) * 32;
}
uint8_t State[8];
if (Mode >= 2 || IS_FREQ_CHANNEL(Channel)) { // copy VFO to a channel
union {
uint8_t _8[8];
uint32_t _32[2];
} State;
((uint32_t *)State)[0] = pVFO->freq_config_RX.Frequency;
((uint32_t *)State)[1] = pVFO->TX_OFFSET_FREQUENCY;
EEPROM_WriteBuffer(OffsetVFO + 0, State);
State._32[0] = pVFO->freq_config_RX.Frequency;
State._32[1] = pVFO->TX_OFFSET_FREQUENCY;
EEPROM_WriteBuffer(OffsetVFO + 0, State._32);
State[0] = pVFO->freq_config_RX.Code;
State[1] = pVFO->freq_config_TX.Code;
State[2] = (pVFO->freq_config_TX.CodeType << 4) | pVFO->freq_config_RX.CodeType;
State[3] = (pVFO->Modulation << 4) | pVFO->TX_OFFSET_FREQUENCY_DIRECTION;
State[4] = 0
| (pVFO->BUSY_CHANNEL_LOCK << 4)
| (pVFO->OUTPUT_POWER << 2)
| (pVFO->CHANNEL_BANDWIDTH << 1)
| (pVFO->FrequencyReverse << 0);
State[5] = ((pVFO->DTMF_PTT_ID_TX_MODE & 7u) << 1) | ((pVFO->DTMF_DECODING_ENABLE & 1u) << 0);
State[6] = pVFO->STEP_SETTING;
State[7] = pVFO->SCRAMBLING_TYPE;
EEPROM_WriteBuffer(OffsetVFO + 8, State);
State._8[0] = pVFO->freq_config_RX.Code;
State._8[1] = pVFO->freq_config_TX.Code;
State._8[2] = (pVFO->freq_config_TX.CodeType << 4) | pVFO->freq_config_RX.CodeType;
State._8[3] = (pVFO->Modulation << 4) | pVFO->TX_OFFSET_FREQUENCY_DIRECTION;
State._8[4] = 0
| (pVFO->BUSY_CHANNEL_LOCK << 4)
| (pVFO->OUTPUT_POWER << 2)
| (pVFO->CHANNEL_BANDWIDTH << 1)
| (pVFO->FrequencyReverse << 0);
State._8[5] = ((pVFO->DTMF_PTT_ID_TX_MODE & 7u) << 1)
#ifdef ENABLE_DTMF_CALLING
| ((pVFO->DTMF_DECODING_ENABLE & 1u) << 0)
#endif
;
State._8[6] = pVFO->STEP_SETTING;
State._8[7] = pVFO->SCRAMBLING_TYPE;
EEPROM_WriteBuffer(OffsetVFO + 8, State._8);
SETTINGS_UpdateChannel(Channel, pVFO, true);
SETTINGS_UpdateChannel(Channel, pVFO, true);
if (IS_MR_CHANNEL(Channel))
{ // it's a memory channel
#ifndef ENABLE_KEEP_MEM_NAME
// clear/reset the channel name
//memset(&State, 0xFF, sizeof(State));
memset(&State, 0x00, sizeof(State)); // follow the QS way
EEPROM_WriteBuffer(0x0F50 + OffsetMR, State);
EEPROM_WriteBuffer(0x0F58 + OffsetMR, State);
#else
if (Mode >= 3)
{ // save the channel name
memmove(State, pVFO->Name + 0, 8);
EEPROM_WriteBuffer(0x0F50 + OffsetMR, State);
//memset(State, 0xFF, sizeof(State));
memset(State, 0x00, sizeof(State)); // follow the QS way
memmove(State, pVFO->Name + 8, 2);
EEPROM_WriteBuffer(0x0F58 + OffsetMR, State);
}
#endif
if (IS_MR_CHANNEL(Channel)) {
#ifndef ENABLE_KEEP_MEM_NAME
// clear/reset the channel name
SETTINGS_SaveChannelName(Channel, "");
#else
if (Mode >= 3) {
SETTINGS_SaveChannelName(Channel, pVFO->Name);
}
#endif
}
}
}
void SETTINGS_SaveBatteryCalibration(const uint16_t * batteryCalibration)
@@ -263,55 +662,101 @@ void SETTINGS_SaveBatteryCalibration(const uint16_t * batteryCalibration)
EEPROM_WriteBuffer(0x1F48, buf);
}
void SETTINGS_UpdateChannel(uint8_t Channel, const VFO_Info_t *pVFO, bool keep)
void SETTINGS_SaveChannelName(uint8_t channel, const char * name)
{
#ifdef ENABLE_NOAA
if (!IS_NOAA_CHANNEL(Channel))
#endif
uint16_t offset = channel * 16;
uint8_t buf[16] = {0};
memcpy(buf, name, MIN(strlen(name), 10u));
EEPROM_WriteBuffer(0x0F50 + offset, buf);
EEPROM_WriteBuffer(0x0F58 + offset, buf + 8);
}
void SETTINGS_UpdateChannel(uint8_t channel, const VFO_Info_t *pVFO, bool keep)
{
#ifdef ENABLE_NOAA
if (!IS_NOAA_CHANNEL(channel))
#endif
{
uint8_t State[8];
uint8_t Attributes = 0xFF; // default attributes
uint16_t Offset = 0x0D60 + (Channel & ~7u);
Attributes &= (uint8_t)(~MR_CH_COMPAND); // default to '0' = compander disabled
uint8_t state[8];
ChannelAttributes_t att = {
.band = 0xf,
.compander = 0,
.scanlist1 = 0,
.scanlist2 = 0,
}; // default attributes
EEPROM_ReadBuffer(Offset, State, sizeof(State));
uint16_t offset = 0x0D60 + (channel & ~7u);
EEPROM_ReadBuffer(offset, state, sizeof(state));
if (keep)
{
Attributes = (pVFO->SCANLIST1_PARTICIPATION << 7) | (pVFO->SCANLIST2_PARTICIPATION << 6) | (pVFO->Compander << 4) | (pVFO->Band << 0);
if (State[Channel & 7u] == Attributes)
if (keep) {
att.band = pVFO->Band;
att.scanlist1 = pVFO->SCANLIST1_PARTICIPATION;
att.scanlist2 = pVFO->SCANLIST2_PARTICIPATION;
att.compander = pVFO->Compander;
if (state[channel & 7u] == att.__val)
return; // no change in the attributes
}
State[Channel & 7u] = Attributes;
state[channel & 7u] = att.__val;
EEPROM_WriteBuffer(offset, state);
EEPROM_WriteBuffer(Offset, State);
gMR_ChannelAttributes[channel] = att;
gMR_ChannelAttributes[Channel] = Attributes;
// #ifndef ENABLE_KEEP_MEM_NAME
if (IS_MR_CHANNEL(Channel))
{ // it's a memory channel
const uint16_t OffsetMR = Channel * 16;
if (!keep)
{ // clear/reset the channel name
//memset(&State, 0xFF, sizeof(State));
memset(&State, 0x00, sizeof(State)); // follow the QS way
EEPROM_WriteBuffer(0x0F50 + OffsetMR, State);
EEPROM_WriteBuffer(0x0F58 + OffsetMR, State);
}
// else
// { // update the channel name
// memmove(State, pVFO->Name + 0, 8);
// EEPROM_WriteBuffer(0x0F50 + OffsetMR, State);
// //memset(State, 0xFF, sizeof(State));
// memset(State, 0x00, sizeof(State)); // follow the QS way
// memmove(State, pVFO->Name + 8, 2);
// EEPROM_WriteBuffer(0x0F58 + OffsetMR, State);
// }
if (IS_MR_CHANNEL(channel)) { // it's a memory channel
if (!keep) {
// clear/reset the channel name
SETTINGS_SaveChannelName(channel, "");
}
// #endif
}
}
}
void SETTINGS_WriteBuildOptions(void)
{
uint8_t buf[8] = {0};
buf[0] = 0
#ifdef ENABLE_FMRADIO
| (1 << 0)
#endif
#ifdef ENABLE_NOAA
| (1 << 1)
#endif
#ifdef ENABLE_VOICE
| (1 << 2)
#endif
#ifdef ENABLE_VOX
| (1 << 3)
#endif
#ifdef ENABLE_ALARM
| (1 << 4)
#endif
#ifdef ENABLE_TX1750
| (1 << 5)
#endif
#ifdef ENABLE_PWRON_PASSWORD
| (1 << 6)
#endif
#ifdef ENABLE_DTMF_CALLING
| (1 << 7)
#endif
;
buf[1] = 0
#ifdef ENABLE_FLASHLIGHT
| (1 << 0)
#endif
#ifdef ENABLE_WIDE_RX
| (1 << 1)
#endif
#ifdef ENABLE_BYP_RAW_DEMODULATORS
| (1 << 2)
#endif
#ifdef ENABLE_BLMIN_TMP_OFF
| (1 << 3)
#endif
#ifdef ENABLE_AM_FIX
| (1 << 4)
#endif
;
EEPROM_WriteBuffer(0x1FF0, buf);
}

View File

@@ -23,6 +23,7 @@
#include "frequencies.h"
#include <helper/battery.h>
#include "radio.h"
#include <driver/backlight.h>
enum POWER_OnDisplayMode_t {
POWER_ON_DISPLAY_MODE_FULL_SCREEN = 0,
@@ -32,13 +33,16 @@ enum POWER_OnDisplayMode_t {
};
typedef enum POWER_OnDisplayMode_t POWER_OnDisplayMode_t;
enum {
F_LOCK_OFF = 0,
enum TxLockModes_t {
F_LOCK_DEF, //all default frequencies + configurable
F_LOCK_FCC,
F_LOCK_CE,
F_LOCK_GB,
F_LOCK_430,
F_LOCK_438
F_LOCK_438,
F_LOCK_ALL, // disable TX on all frequencies
F_LOCK_NONE, // enable TX on all frequencies
F_LOCK_LEN
};
enum {
@@ -71,7 +75,7 @@ enum {
OUTPUT_POWER_HIGH
};
enum {
enum ACTION_OPT_t {
ACTION_OPT_NONE = 0,
ACTION_OPT_FLASHLIGHT,
ACTION_OPT_POWER,
@@ -85,6 +89,7 @@ enum {
ACTION_OPT_A_B,
ACTION_OPT_VFO_MR,
ACTION_OPT_SWITCH_DEMODUL,
ACTION_OPT_BLMIN_TMP_OFF, //BackLight Minimum Temporay OFF
ACTION_OPT_LEN
};
@@ -120,12 +125,12 @@ enum CHANNEL_DisplayMode_t {
typedef enum CHANNEL_DisplayMode_t CHANNEL_DisplayMode_t;
typedef struct {
uint8_t ScreenChannel[2];
uint8_t FreqChannel[2];
uint8_t MrChannel[2];
#ifdef ENABLE_NOAA
uint8_t NoaaChannel[2];
#endif
uint8_t ScreenChannel[2]; // current channels set in the radio (memory or frequency channels)
uint8_t FreqChannel[2]; // last frequency channels used
uint8_t MrChannel[2]; // last memory channels used
#ifdef ENABLE_NOAA
uint8_t NoaaChannel[2];
#endif
// The actual VFO index (0-upper/1-lower) that is now used for RX,
// It is being alternated by dual watch, and flipped by crossband
@@ -138,23 +143,23 @@ typedef struct {
uint8_t field7_0xa;
uint8_t field8_0xb;
#ifdef ENABLE_FMRADIO
uint16_t FM_SelectedFrequency;
uint8_t FM_SelectedChannel;
bool FM_IsMrMode;
uint16_t FM_FrequencyPlaying;
uint16_t FM_LowerLimit;
uint16_t FM_UpperLimit;
#endif
#ifdef ENABLE_FMRADIO
uint16_t FM_SelectedFrequency;
uint8_t FM_SelectedChannel;
bool FM_IsMrMode;
uint16_t FM_FrequencyPlaying;
uint8_t FM_Band : 2;
//uint8_t FM_Space : 2;
#endif
uint8_t SQUELCH_LEVEL;
uint8_t TX_TIMEOUT_TIMER;
bool KEY_LOCK;
bool VOX_SWITCH;
uint8_t VOX_LEVEL;
#ifdef ENABLE_VOICE
VOICE_Prompt_t VOICE_PROMPT;
#endif
#ifdef ENABLE_VOICE
VOICE_Prompt_t VOICE_PROMPT;
#endif
bool BEEP_CONTROL;
uint8_t CHANNEL_DISPLAY_MODE;
bool TAIL_TONE_ELIMINATION;
@@ -176,9 +181,9 @@ typedef struct {
uint8_t field38_0x33;
bool AUTO_KEYPAD_LOCK;
#if defined(ENABLE_ALARM) || defined(ENABLE_TX1750)
ALARM_Mode_t ALARM_MODE;
#endif
#if defined(ENABLE_ALARM) || defined(ENABLE_TX1750)
ALARM_Mode_t ALARM_MODE;
#endif
POWER_OnDisplayMode_t POWER_ON_DISPLAY_MODE;
ROGER_Mode_t ROGER;
uint8_t REPEATER_TAIL_TONE_ELIMINATION;
@@ -189,9 +194,11 @@ typedef struct {
uint8_t MIC_SENSITIVITY;
uint8_t MIC_SENSITIVITY_TUNING;
uint8_t CHAN_1_CALL;
#ifdef ENABLE_DTMF_CALLING
char ANI_DTMF_ID[8];
char KILL_CODE[8];
char REVIVE_CODE[8];
#endif
char DTMF_UP_CODE[16];
uint8_t field57_0x6c;
@@ -202,21 +209,25 @@ typedef struct {
uint8_t field60_0x7e;
uint8_t field61_0x7f;
#ifdef ENABLE_DTMF_CALLING
char DTMF_SEPARATE_CODE;
char DTMF_GROUP_CALL_CODE;
uint8_t DTMF_DECODE_RESPONSE;
uint8_t DTMF_auto_reset_time;
#endif
uint16_t DTMF_PRELOAD_TIME;
uint16_t DTMF_FIRST_CODE_PERSIST_TIME;
uint16_t DTMF_HASH_CODE_PERSIST_TIME;
uint16_t DTMF_CODE_PERSIST_TIME;
uint16_t DTMF_CODE_INTERVAL_TIME;
bool DTMF_SIDE_TONE;
#ifdef ENABLE_DTMF_CALLING
bool PERMIT_REMOTE_KILL;
#endif
int16_t BK4819_XTAL_FREQ_LOW;
#ifdef ENABLE_NOAA
bool NOAA_AUTO_SCAN;
#endif
#ifdef ENABLE_NOAA
bool NOAA_AUTO_SCAN;
#endif
uint8_t VOLUME_GAIN;
uint8_t DAC_GAIN;
@@ -231,19 +242,33 @@ typedef struct {
uint8_t KEY_M_LONG_PRESS_ACTION;
uint8_t BACKLIGHT_MIN;
#ifdef ENABLE_BLMIN_TMP_OFF
BLMIN_STAT_t BACKLIGHT_MIN_STAT;
#endif
uint8_t BACKLIGHT_MAX;
BATTERY_Type_t BATTERY_TYPE;
#ifdef ENABLE_RSSI_BAR
uint8_t S0_LEVEL;
uint8_t S9_LEVEL;
#endif
} EEPROM_Config_t;
extern EEPROM_Config_t gEeprom;
void SETTINGS_InitEEPROM(void);
void SETTINGS_LoadCalibration(void);
uint32_t SETTINGS_FetchChannelFrequency(const int channel);
void SETTINGS_FetchChannelName(char *s, const int channel);
void SETTINGS_FactoryReset(bool bIsAll);
#ifdef ENABLE_FMRADIO
void SETTINGS_SaveFM(void);
#endif
void SETTINGS_SaveVfoIndices(void);
void SETTINGS_SaveSettings(void);
void SETTINGS_SaveChannelName(uint8_t channel, const char * name);
void SETTINGS_SaveChannel(uint8_t Channel, uint8_t VFO, const VFO_Info_t *pVFO, uint8_t Mode);
void SETTINGS_SaveBatteryCalibration(const uint16_t * batteryCalibration);
void SETTINGS_UpdateChannel(uint8_t Channel, const VFO_Info_t *pVFO, bool keep);
void SETTINGS_UpdateChannel(uint8_t channel, const VFO_Info_t *pVFO, bool keep);
void SETTINGS_WriteBuildOptions(void);
#endif

View File

@@ -29,41 +29,41 @@
void UI_DisplayAircopy(void)
{
char String[16];
char String[16] = { 0 };
char *pPrintStr = { 0 };
memset(gFrameBuffer, 0, sizeof(gFrameBuffer));
UI_DisplayClear();
if (gAircopyState == AIRCOPY_READY)
strcpy(String, "AIR COPY(RDY)");
else
if (gAircopyState == AIRCOPY_TRANSFER)
strcpy(String, "AIR COPY");
else
strcpy(String, "AIR COPY(CMP)");
UI_PrintString(String, 2, 127, 0, 8);
if (gAircopyState == AIRCOPY_READY) {
pPrintStr = "AIR COPY(RDY)";
} else if (gAircopyState == AIRCOPY_TRANSFER) {
pPrintStr = "AIR COPY";
} else {
pPrintStr = "AIR COPY(CMP)";
}
if (gInputBoxIndex == 0)
{
UI_PrintString(pPrintStr, 2, 127, 0, 8);
if (gInputBoxIndex == 0) {
uint32_t frequency = gRxVfo->freq_config_RX.Frequency;
sprintf(String, "%3u.%05u", frequency / 100000, frequency % 100000);
// show the remaining 2 small frequency digits
UI_PrintStringSmall(String + 7, 97, 0, 3);
UI_PrintStringSmallNormal(String + 7, 97, 0, 3);
String[7] = 0;
// show the main large frequency digits
UI_DisplayFrequency(String, 16, 2, false);
}
else {
const char * ascii = INPUTBOX_GetAscii();
sprintf(String, "%.3s.%.3s",ascii, ascii + 3);
} else {
const char *ascii = INPUTBOX_GetAscii();
sprintf(String, "%.3s.%.3s", ascii, ascii + 3);
UI_DisplayFrequency(String, 16, 2, false);
}
memset(String, 0, sizeof(String));
if (gAirCopyIsSendMode == 0)
if (gAirCopyIsSendMode == 0) {
sprintf(String, "RCV:%u E:%u", gAirCopyBlockNumber, gErrorsDuringAirCopy);
else
if (gAirCopyIsSendMode == 1)
} else if (gAirCopyIsSendMode == 1) {
sprintf(String, "SND:%u", gAirCopyBlockNumber);
}
UI_PrintString(String, 2, 127, 4, 8);
ST7565_BlitFullScreen();

View File

@@ -21,30 +21,29 @@
#include "driver/st7565.h"
#include "functions.h"
#include "ui/battery.h"
#include "../misc.h"
void UI_DrawBattery(uint8_t* bitmap, uint8_t level, uint8_t blink)
{
if (level < 2 && blink == 1) {
memset(bitmap, 0, sizeof(BITMAP_BatteryLevel1));
return;
}
else
{
memmove(bitmap, BITMAP_BatteryLevel1, sizeof(BITMAP_BatteryLevel1));
if (level > 2)
{
unsigned int i;
uint8_t bars = level - 2;
if (bars > 4)
bars = 4;
for (i = 0; i < bars; i++)
{
#ifndef ENABLE_REVERSE_BAT_SYMBOL
memcpy(bitmap + sizeof(BITMAP_BatteryLevel1) - 4 - (i * 3), BITMAP_BatteryLevel, 2);
#else
memcpy(bitmap + 3 + (i * 3) + 0, BITMAP_BatteryLevel, 2);
#endif
}
}
memcpy(bitmap, BITMAP_BatteryLevel1, sizeof(BITMAP_BatteryLevel1));
if (level <= 2) {
return;
}
const uint8_t bars = MIN(4, level - 2);
for (int i = 0; i < bars; i++) {
#ifndef ENABLE_REVERSE_BAT_SYMBOL
memcpy(bitmap + sizeof(BITMAP_BatteryLevel1) - 4 - (i * 3), BITMAP_BatteryLevel, 2);
#else
memcpy(bitmap + 3 + (i * 3) + 0, BITMAP_BatteryLevel, 2);
#endif
}
}
@@ -52,5 +51,5 @@ void UI_DisplayBattery(uint8_t level, uint8_t blink)
{
uint8_t bitmap[sizeof(BITMAP_BatteryLevel1)];
UI_DrawBattery(bitmap, level, blink);
ST7565_DrawLine(LCD_WIDTH - sizeof(bitmap), 0, sizeof(bitmap), bitmap);
ST7565_DrawLine(LCD_WIDTH - sizeof(bitmap), 0, bitmap, sizeof(bitmap));
}

View File

@@ -19,6 +19,7 @@
#include <string.h>
#include "app/fm.h"
#include "driver/bk1080.h"
#include "driver/st7565.h"
#include "external/printf/printf.h"
#include "misc.h"
@@ -30,83 +31,70 @@
void UI_DisplayFM(void)
{
unsigned int i;
char String[16];
char String[16] = {0};
char *pPrintStr = String;
UI_DisplayClear();
memset(gFrameBuffer, 0, sizeof(gFrameBuffer));
UI_PrintString("FM", 2, 0, 0, 8);
memset(String, 0, sizeof(String));
strcpy(String, "FM");
UI_PrintString(String, 0, 127, 0, 12);
sprintf(String, "%d%s-%dM",
BK1080_GetFreqLoLimit(gEeprom.FM_Band)/10,
gEeprom.FM_Band == 0 ? ".5" : "",
BK1080_GetFreqHiLimit(gEeprom.FM_Band)/10
);
UI_PrintStringSmallNormal(String, 1, 0, 6);
memset(String, 0, sizeof(String));
if (gAskToSave)
{
strcpy(String, "SAVE?");
}
else
if (gAskToDelete)
{
strcpy(String, "DEL?");
}
else
{
if (gFM_ScanState == FM_SCAN_OFF)
{
if (!gEeprom.FM_IsMrMode)
{
for (i = 0; i < 20; i++)
{
if (gEeprom.FM_FrequencyPlaying == gFM_Channels[i])
{
sprintf(String, "VFO(CH%02u)", i + 1);
break;
}
//uint8_t spacings[] = {20,10,5};
//sprintf(String, "%d0k", spacings[gEeprom.FM_Space % 3]);
//UI_PrintStringSmallNormal(String, 127 - 4*7, 0, 6);
if (gAskToSave) {
pPrintStr = "SAVE?";
} else if (gAskToDelete) {
pPrintStr = "DEL?";
} else if (gFM_ScanState == FM_SCAN_OFF) {
if (gEeprom.FM_IsMrMode) {
sprintf(String, "MR(CH%02u)", gEeprom.FM_SelectedChannel + 1);
pPrintStr = String;
} else {
pPrintStr = "VFO";
for (unsigned int i = 0; i < 20; i++) {
if (gEeprom.FM_FrequencyPlaying == gFM_Channels[i]) {
sprintf(String, "VFO(CH%02u)", i + 1);
pPrintStr = String;
break;
}
if (i == 20)
strcpy(String, "VFO");
}
else
sprintf(String, "MR(CH%02u)", gEeprom.FM_SelectedChannel + 1);
}
else
{
if (!gFM_AutoScan)
strcpy(String, "M-SCAN");
else
sprintf(String, "A-SCAN(%u)", gFM_ChannelPosition + 1);
}
} else if (gFM_AutoScan) {
sprintf(String, "A-SCAN(%u)", gFM_ChannelPosition + 1);
pPrintStr = String;
} else {
pPrintStr = "M-SCAN";
}
UI_PrintString(String, 0, 127, 2, 10);
UI_PrintString(pPrintStr, 0, 127, 3, 10); // memory, vfo, scan
memset(String, 0, sizeof(String));
if (gAskToSave || (gEeprom.FM_IsMrMode && gInputBoxIndex > 0))
{
if (gAskToSave || (gEeprom.FM_IsMrMode && gInputBoxIndex > 0)) {
UI_GenerateChannelString(String, gFM_ChannelPosition);
}
else
if (!gAskToDelete)
{
if (gInputBoxIndex == 0)
{
} else if (gAskToDelete) {
sprintf(String, "CH-%02u", gEeprom.FM_SelectedChannel + 1);
} else {
if (gInputBoxIndex == 0) {
sprintf(String, "%3d.%d", gEeprom.FM_FrequencyPlaying / 10, gEeprom.FM_FrequencyPlaying % 10);
UI_DisplayFrequency(String, 32, 4, true);
}
else {
} else {
const char * ascii = INPUTBOX_GetAscii();
sprintf(String, "%.3s.%.1s",ascii, ascii + 3);
UI_DisplayFrequency(String, 32, 4, false);
}
UI_DisplayFrequency(String, 36, 1, gInputBoxIndex == 0); // frequency
ST7565_BlitFullScreen();
return;
}
else
{
sprintf(String, "CH-%02u", gEeprom.FM_SelectedChannel + 1);
}
UI_PrintString(String, 0, 127, 4, 10);
UI_PrintString(String, 0, 127, 1, 10);
ST7565_BlitFullScreen();
}

View File

@@ -46,21 +46,36 @@ void UI_GenerateChannelString(char *pString, const uint8_t Channel)
void UI_GenerateChannelStringEx(char *pString, const bool bShowPrefix, const uint8_t ChannelNumber)
{
if (gInputBoxIndex > 0)
{
unsigned int i;
for (i = 0; i < 3; i++)
if (gInputBoxIndex > 0) {
for (unsigned int i = 0; i < 3; i++) {
pString[i] = (gInputBox[i] == 10) ? '-' : gInputBox[i] + '0';
}
pString[3] = 0;
return;
}
if (bShowPrefix)
if (bShowPrefix) {
// BUG here? Prefixed NULLs are allowed
sprintf(pString, "CH-%03u", ChannelNumber + 1);
else
if (ChannelNumber == 0xFF)
} else if (ChannelNumber == 0xFF) {
strcpy(pString, "NULL");
else
} else {
sprintf(pString, "%03u", ChannelNumber + 1);
}
}
void UI_PrintStringBuffer(const char *pString, uint8_t * buffer, uint32_t char_width, const uint8_t *font)
{
const size_t Length = strlen(pString);
const unsigned int char_spacing = char_width + 1;
for (size_t i = 0; i < Length; i++) {
const unsigned int index = pString[i] - ' ' - 1;
if (pString[i] > ' ' && pString[i] < 127) {
const uint32_t offset = i * char_spacing + 1;
memcpy(buffer + offset, font + index * char_width, char_width);
}
}
}
void UI_PrintString(const char *pString, uint8_t Start, uint8_t End, uint8_t Line, uint8_t Width)
@@ -77,72 +92,57 @@ void UI_PrintString(const char *pString, uint8_t Start, uint8_t End, uint8_t Lin
if (pString[i] > ' ' && pString[i] < 127)
{
const unsigned int index = pString[i] - ' ' - 1;
memmove(gFrameBuffer[Line + 0] + ofs, &gFontBig[index][0], 7);
memmove(gFrameBuffer[Line + 1] + ofs, &gFontBig[index][7], 7);
memcpy(gFrameBuffer[Line + 0] + ofs, &gFontBig[index][0], 7);
memcpy(gFrameBuffer[Line + 1] + ofs, &gFontBig[index][7], 7);
}
}
}
void UI_PrintStringSmall(const char *pString, uint8_t Start, uint8_t End, uint8_t Line)
void UI_PrintStringSmall(const char *pString, uint8_t Start, uint8_t End, uint8_t Line, uint8_t char_width, const uint8_t *font)
{
const size_t Length = strlen(pString);
size_t i;
if (End > Start)
Start += (((End - Start) - (Length * 8)) + 1) / 2;
const unsigned int char_width = ARRAY_SIZE(gFontSmall[0]);
const unsigned int char_spacing = char_width + 1;
uint8_t *pFb = gFrameBuffer[Line] + Start;
for (i = 0; i < Length; i++)
{
if (pString[i] > ' ')
{
const unsigned int index = (unsigned int)pString[i] - ' ' - 1;
if (index < ARRAY_SIZE(gFontSmall))
memmove(pFb + (i * char_spacing) + 1, &gFontSmall[index], char_width);
}
if (End > Start) {
Start += (((End - Start) - Length * char_spacing) + 1) / 2;
}
UI_PrintStringBuffer(pString, gFrameBuffer[Line] + Start, char_width, font);
}
void UI_PrintStringSmallNormal(const char *pString, uint8_t Start, uint8_t End, uint8_t Line)
{
UI_PrintStringSmall(pString, Start, End, Line, ARRAY_SIZE(gFontSmall[0]), (const uint8_t *)gFontSmall);
}
void UI_PrintStringSmallBold(const char *pString, uint8_t Start, uint8_t End, uint8_t Line)
{
#ifdef ENABLE_SMALL_BOLD
void UI_PrintStringSmallBold(const char *pString, uint8_t Start, uint8_t End, uint8_t Line)
{
const size_t Length = strlen(pString);
size_t i;
if (End > Start)
Start += (((End - Start) - (Length * 8)) + 1) / 2;
const unsigned int char_width = ARRAY_SIZE(gFontSmallBold[0]);
const unsigned int char_spacing = char_width + 1;
uint8_t *pFb = gFrameBuffer[Line] + Start;
for (i = 0; i < Length; i++)
{
if (pString[i] > ' ')
{
const unsigned int index = (unsigned int)pString[i] - ' ' - 1;
if (index < ARRAY_SIZE(gFontSmallBold))
memmove(pFb + (i * char_spacing) + 1, &gFontSmallBold[index], char_width);
}
}
}
const uint8_t *font = (uint8_t *)gFontSmallBold;
const uint8_t char_width = ARRAY_SIZE(gFontSmallBold[0]);
#else
const uint8_t *font = (uint8_t *)gFontSmall;
const uint8_t char_width = ARRAY_SIZE(gFontSmall[0]);
#endif
void UI_PrintStringSmallBuffer(const char *pString, uint8_t *buffer)
UI_PrintStringSmall(pString, Start, End, Line, char_width, font);
}
void UI_PrintStringSmallBufferNormal(const char *pString, uint8_t * buffer)
{
size_t i;
const unsigned int char_width = ARRAY_SIZE(gFontSmall[0]);
const unsigned int char_spacing = char_width + 1;
for (i = 0; i < strlen(pString); i++)
{
if (pString[i] > ' ')
{
const unsigned int index = (unsigned int)pString[i] - ' ' - 1;
if (index < ARRAY_SIZE(gFontSmall))
memmove(buffer + (i * char_spacing) + 1, &gFontSmall[index], char_width);
}
}
UI_PrintStringBuffer(pString, buffer, ARRAY_SIZE(gFontSmall[0]), (uint8_t *)gFontSmall);
}
void UI_PrintStringSmallBufferBold(const char *pString, uint8_t * buffer)
{
#ifdef ENABLE_SMALL_BOLD
const uint8_t *font = (uint8_t *)gFontSmallBold;
const uint8_t char_width = ARRAY_SIZE(gFontSmallBold[0]);
#else
const uint8_t *font = (uint8_t *)gFontSmall;
const uint8_t char_width = ARRAY_SIZE(gFontSmall[0]);
#endif
UI_PrintStringBuffer(pString, buffer, char_width, font);
}
void UI_DisplayFrequency(const char *string, uint8_t X, uint8_t Y, bool center)
@@ -169,7 +169,7 @@ void UI_DisplayFrequency(const char *string, uint8_t X, uint8_t Y, bool center)
*pFb1 = 0x60; pFb0++; pFb1++;
continue;
}
}
else if (center) {
pFb0 -= 6;
@@ -180,10 +180,13 @@ void UI_DisplayFrequency(const char *string, uint8_t X, uint8_t Y, bool center)
}
}
void UI_DrawPixel(uint8_t x, uint8_t y, bool black)
void UI_DrawPixelBuffer(uint8_t (*buffer)[128], uint8_t x, uint8_t y, bool black)
{
gFrameBuffer[y/8][x] &= ~(1 << (y%8));
gFrameBuffer[y/8][x] |= black << (y%8);
const uint8_t pattern = 1 << (y % 8);
if(black)
buffer[y/8][x] |= pattern;
else
buffer[y/8][x] &= ~pattern;
}
static void sort(int16_t *a, int16_t *b)
@@ -195,12 +198,12 @@ static void sort(int16_t *a, int16_t *b)
}
}
void UI_DrawLine(int16_t x1, int16_t y1, int16_t x2, int16_t y2, bool black)
void UI_DrawLineBuffer(uint8_t (*buffer)[128], int16_t x1, int16_t y1, int16_t x2, int16_t y2, bool black)
{
if(x2==x1) {
sort(&y1, &y2);
for(int16_t i = y1; i <= y2; i++) {
UI_DrawPixel(x1, i, black);
UI_DrawPixelBuffer(buffer, x1, i, black);
}
} else {
const int multipl = 1000;
@@ -210,39 +213,43 @@ void UI_DrawLine(int16_t x1, int16_t y1, int16_t x2, int16_t y2, bool black)
sort(&x1, &x2);
for(int i = x1; i<= x2; i++)
{
UI_DrawPixel(i, i*a/multipl +b, black);
UI_DrawPixelBuffer(buffer, i, i*a/multipl +b, black);
}
}
}
void UI_DrawRectangle(int16_t x1, int16_t y1, int16_t x2, int16_t y2, bool black)
void UI_DrawRectangleBuffer(uint8_t (*buffer)[128], int16_t x1, int16_t y1, int16_t x2, int16_t y2, bool black)
{
UI_DrawLine(x1,y1, x1,y2, black);
UI_DrawLine(x1,y1, x2,y1, black);
UI_DrawLine(x2,y1, x2,y2, black);
UI_DrawLine(x1,y2, x2,y2, black);
UI_DrawLineBuffer(buffer, x1,y1, x1,y2, black);
UI_DrawLineBuffer(buffer, x1,y1, x2,y1, black);
UI_DrawLineBuffer(buffer, x2,y1, x2,y2, black);
UI_DrawLineBuffer(buffer, x1,y2, x2,y2, black);
}
void UI_DisplayPopup(const char *string)
void UI_DisplayPopup(const char *string)
{
for(uint8_t i = 0; i < 7; i++) {
memset(gFrameBuffer[i], 0x00, 128);
}
UI_DisplayClear();
// for(uint8_t i = 1; i < 5; i++) {
// memset(gFrameBuffer[i]+8, 0x00, 111);
// }
// for(uint8_t x = 10; x < 118; x++) {
// UI_DrawPixel(x, 10, true);
// UI_DrawPixel(x, 46-9, true);
// UI_DrawPixelBuffer(x, 10, true);
// UI_DrawPixelBuffer(x, 46-9, true);
// }
// for(uint8_t y = 11; y < 37; y++) {
// UI_DrawPixel(10, y, true);
// UI_DrawPixel(117, y, true);
// UI_DrawPixelBuffer(10, y, true);
// UI_DrawPixelBuffer(117, y, true);
// }
// DrawRectangle(9,9, 118,38, true);
UI_PrintString(string, 9, 118, 2, 8);
UI_PrintStringSmall("Press EXIT", 9, 118, 6);
}
UI_PrintStringSmallNormal("Press EXIT", 9, 118, 6);
}
void UI_DisplayClear()
{
memset(gFrameBuffer, 0, sizeof(gFrameBuffer));
}

View File

@@ -23,17 +23,18 @@
void UI_GenerateChannelString(char *pString, const uint8_t Channel);
void UI_GenerateChannelStringEx(char *pString, const bool bShowPrefix, const uint8_t ChannelNumber);
void UI_PrintString(const char *pString, uint8_t Start, uint8_t End, uint8_t Line, uint8_t Width);
void UI_PrintStringSmall(const char *pString, uint8_t Start, uint8_t End, uint8_t Line);
#ifdef ENABLE_SMALL_BOLD
void UI_PrintStringSmallBold(const char *pString, uint8_t Start, uint8_t End, uint8_t Line);
#endif
void UI_PrintStringSmallBuffer(const char *pString, uint8_t *buffer);
void UI_PrintStringSmallNormal(const char *pString, uint8_t Start, uint8_t End, uint8_t Line);
void UI_PrintStringSmallBold(const char *pString, uint8_t Start, uint8_t End, uint8_t Line);
void UI_PrintStringSmallBufferNormal(const char *pString, uint8_t *buffer);
void UI_PrintStringSmallBufferBold(const char *pString, uint8_t * buffer);
void UI_DisplayFrequency(const char *string, uint8_t X, uint8_t Y, bool center);
#endif
void UI_DisplayPopup(const char *string);
void UI_DrawPixel(uint8_t x, uint8_t y, bool black);
void UI_DrawLine(int16_t x1, int16_t y1, int16_t x2, int16_t y2, bool black);
void UI_DrawRectangle(int16_t x1, int16_t y1, int16_t x2, int16_t y2, bool black);
void UI_DrawPixelBuffer(uint8_t (*buffer)[128], uint8_t x, uint8_t y, bool black);
void UI_DrawLineBuffer(uint8_t (*buffer)[128], int16_t x1, int16_t y1, int16_t x2, int16_t y2, bool black);
void UI_DrawRectangleBuffer(uint8_t (*buffer)[128], int16_t x1, int16_t y1, int16_t x2, int16_t y2, bool black);
void UI_DisplayClear();
#endif

View File

@@ -35,10 +35,9 @@ static void Render(void)
char String[7];
memset(gStatusLine, 0, sizeof(gStatusLine));
memset(gFrameBuffer, 0, sizeof(gFrameBuffer));
UI_DisplayClear();
strcpy(String, "LOCK");
UI_PrintString(String, 0, 127, 1, 10);
UI_PrintString("LOCK", 0, 127, 1, 10);
for (i = 0; i < 6; i++)
String[i] = (gInputBox[i] == 10) ? '-' : '*';
String[6] = 0;
@@ -143,13 +142,14 @@ void UI_DisplayLock(void)
gKeyReading0 = Key;
}
#ifdef ENABLE_UART
if (UART_IsCommandAvailable())
{
__disable_irq();
UART_HandleCommand();
__enable_irq();
}
#endif
if (gUpdateDisplay)
{
Render();

527
ui/main.c
View File

@@ -17,8 +17,9 @@
#include <string.h>
#include <stdlib.h> // abs()
#include "app/chFrScanner.h"
#include "app/dtmf.h"
#ifdef ENABLE_AM_FIX_SHOW_DATA
#ifdef ENABLE_AM_FIX
#include "am_fix.h"
#endif
#include "bitmaps.h"
@@ -38,6 +39,26 @@
center_line_t center_line = CENTER_LINE_NONE;
const int8_t dBmCorrTable[7] = {
-15, // band 1
-25, // band 2
-20, // band 3
-4, // band 4
-7, // band 5
-6, // band 6
-1 // band 7
};
const char *VfoStateStr[] = {
[VFO_STATE_NORMAL]="",
[VFO_STATE_BUSY]="BUSY",
[VFO_STATE_BAT_LOW]="BAT LOW",
[VFO_STATE_TX_DISABLE]="TX DISABLE",
[VFO_STATE_TIMEOUT]="TIMEOUT",
[VFO_STATE_ALARM]="ALARM",
[VFO_STATE_VOLTAGE_HIGH]="VOLT HIGH"
};
// ***************************************************************************
static void DrawSmallAntennaAndBars(uint8_t *p, unsigned int level)
@@ -52,6 +73,31 @@ static void DrawSmallAntennaAndBars(uint8_t *p, unsigned int level)
memset(p + 2 + i*3, bar, 2);
}
}
#if defined ENABLE_AUDIO_BAR || defined ENABLE_RSSI_BAR
static void DrawLevelBar(uint8_t xpos, uint8_t line, uint8_t level)
{
const char hollowBar[] = {
0b01111111,
0b01000001,
0b01000001,
0b01111111
};
uint8_t *p_line = gFrameBuffer[line];
level = MIN(level, 13);
for(uint8_t i = 0; i < level; i++) {
if(i < 9) {
for(uint8_t j = 0; j < 4; j++)
p_line[xpos + i * 5 + j] = (~(0x7F >> (i+1))) & 0x7F;
}
else {
memcpy(p_line + (xpos + i * 5), &hollowBar, ARRAY_SIZE(hollowBar));
}
}
}
#endif
#ifdef ENABLE_AUDIO_BAR
@@ -76,18 +122,21 @@ void UI_DisplayAudioBar(void)
{
if (gSetting_mic_bar)
{
if(gLowBattery && !gLowBatteryConfirmed)
return;
const unsigned int line = 3;
const unsigned int bar_x = 2;
const unsigned int bar_width = LCD_WIDTH - 2 - bar_x;
unsigned int i;
if (gCurrentFunction != FUNCTION_TRANSMIT ||
gScreenToDisplay != DISPLAY_MAIN ||
gDTMF_CallState != DTMF_CALL_STATE_NONE)
gScreenToDisplay != DISPLAY_MAIN
#ifdef ENABLE_DTMF_CALLING
|| gDTMF_CallState != DTMF_CALL_STATE_NONE
#endif
)
{
return; // screen is in use
}
#if defined(ENABLE_ALARM) || defined(ENABLE_TX1750)
if (gAlarmState != ALARM_STATE_OFF)
return;
@@ -95,16 +144,14 @@ void UI_DisplayAudioBar(void)
const unsigned int voice_amp = BK4819_GetVoiceAmplitudeOut(); // 15:0
// make non-linear to make more sensitive at low values
const unsigned int level = voice_amp * 8;
const unsigned int sqrt_level = sqrt16((level < 65535) ? level : 65535);
const unsigned int len = (sqrt_level <= bar_width) ? sqrt_level : bar_width;
const unsigned int level = MIN(voice_amp * 8, 65535u);
const unsigned int sqrt_level = MIN(sqrt16(level), 124u);
uint8_t bars = 13 * sqrt_level / 124;
uint8_t *p_line = gFrameBuffer[line];
memset(p_line, 0, LCD_WIDTH);
for (i = 0; i < bar_width; i++)
p_line[bar_x + i] = (i > len) ? ((i & 1) == 0) ? 0x41 : 0x00 : ((i & 1) == 0) ? 0x7f : 0x3e;
DrawLevelBar(62, line, bars);
if (gCurrentFunction == FUNCTION_TRANSMIT)
ST7565_BlitFullScreen();
@@ -112,73 +159,70 @@ void UI_DisplayAudioBar(void)
}
#endif
static void DisplayRSSIBar(const int16_t rssi, const bool now)
void DisplayRSSIBar(const bool now)
{
#if defined(ENABLE_RSSI_BAR)
if (center_line == CENTER_LINE_RSSI) {
const unsigned int txt_width = 7 * 8; // 8 text chars
const unsigned int bar_x = 2 + txt_width + 4; // X coord of bar graph
const unsigned int txt_width = 7 * 8; // 8 text chars
const unsigned int bar_x = 2 + txt_width + 4; // X coord of bar graph
const unsigned int line = 3;
uint8_t *p_line = gFrameBuffer[line];
char str[16];
const unsigned int line = 3;
uint8_t *p_line = gFrameBuffer[line];
char str[16];
const char plus[] = {
0b00011000,
0b00011000,
0b01111110,
0b01111110,
0b01111110,
0b00011000,
0b00011000,
};
const char plus[] = {
0b00011000,
0b00011000,
0b01111110,
0b01111110,
0b01111110,
0b00011000,
0b00011000,
};
const char hollowBar[] = {
0b01111111,
0b01000001,
0b01000001,
0b01111111
};
if ((gEeprom.KEY_LOCK && gKeypadLocked > 0) || center_line != CENTER_LINE_RSSI)
return; // display is in use
if (gEeprom.KEY_LOCK && gKeypadLocked > 0)
return; // display is in use
if (gCurrentFunction == FUNCTION_TRANSMIT ||
gScreenToDisplay != DISPLAY_MAIN
#ifdef ENABLE_DTMF_CALLING
|| gDTMF_CallState != DTMF_CALL_STATE_NONE
#endif
)
return; // display is in use
if (gCurrentFunction == FUNCTION_TRANSMIT ||
gScreenToDisplay != DISPLAY_MAIN ||
gDTMF_CallState != DTMF_CALL_STATE_NONE)
return; // display is in use
if (now)
memset(p_line, 0, LCD_WIDTH);
if (now)
memset(p_line, 0, LCD_WIDTH);
const int16_t s0_dBm = -147; // S0 .. base level
const int16_t rssi_dBm = (rssi / 2) - 160;
const uint8_t s_level = MIN(MAX((rssi_dBm - s0_dBm) / 6, 0), 9); // S0 - S9
uint8_t overS9dBm = MIN(MAX(rssi_dBm - (s0_dBm + 9*6), 0), 99);
uint8_t overS9Bars = MIN(overS9dBm/10, 4);
if(overS9Bars == 0) {
sprintf(str, "% 4d S%d", rssi_dBm, s_level);
}
else {
sprintf(str, "% 4d %2d", rssi_dBm, overS9dBm);
memcpy(p_line + 2 + 7*5, &plus, ARRAY_SIZE(plus));
}
const int16_t s0_dBm = -gEeprom.S0_LEVEL; // S0 .. base level
const int16_t rssi_dBm =
BK4819_GetRSSI_dBm()
#ifdef ENABLE_AM_FIX
+ ((gSetting_AM_fix && gRxVfo->Modulation == MODULATION_AM) ? AM_fix_get_gain_diff() : 0)
#endif
+ dBmCorrTable[gRxVfo->Band];
UI_PrintStringSmall(str, 2, 0, line);
int s0_9 = gEeprom.S0_LEVEL - gEeprom.S9_LEVEL;
const uint8_t s_level = MIN(MAX((int32_t)(rssi_dBm - s0_dBm)*100 / (s0_9*100/9), 0), 9); // S0 - S9
uint8_t overS9dBm = MIN(MAX(rssi_dBm + gEeprom.S9_LEVEL, 0), 99);
uint8_t overS9Bars = MIN(overS9dBm/10, 4);
for(uint8_t i = 0; i < s_level; i++) { // S bars
for(uint8_t j = 0; j < 4; j++)
p_line[bar_x + i * 5 + j] = (~(0x7F >> (i+1))) & 0x7F;
}
for(uint8_t i = 0; i < overS9Bars; i++) { // +10 hollow bars
memcpy(p_line + (bar_x + (i + 9) * 5), &hollowBar, ARRAY_SIZE(hollowBar));
}
if(overS9Bars == 0) {
sprintf(str, "% 4d S%d", rssi_dBm, s_level);
}
else {
sprintf(str, "% 4d %2d", rssi_dBm, overS9dBm);
memcpy(p_line + 2 + 7*5, &plus, ARRAY_SIZE(plus));
}
#else
UI_PrintStringSmallNormal(str, 2, 0, line);
DrawLevelBar(bar_x, line, s_level + overS9Bars);
if (now)
ST7565_BlitLine(line);
#else
int16_t rssi = BK4819_GetRSSI();
uint8_t Level;
if (rssi >= gEEPROM_RSSI_CALIB[gRxVfo->Band][3]) {
@@ -197,42 +241,75 @@ static void DisplayRSSIBar(const int16_t rssi, const bool now)
if (now)
memset(pLine, 0, 23);
DrawSmallAntennaAndBars(pLine, Level);
#endif
if (now)
ST7565_BlitFullScreen();
#endif
}
void UI_UpdateRSSI(const int16_t rssi, const int vfo)
#ifdef ENABLE_AGC_SHOW_DATA
void UI_MAIN_PrintAGC(bool now)
{
(void)vfo; // unused
// optional larger RSSI dBm, S-point and bar level
char buf[20];
memset(gFrameBuffer[3], 0, 128);
union {
struct {
uint16_t _ : 5;
uint16_t agcSigStrength : 7;
int16_t gainIdx : 3;
uint16_t agcEnab : 1;
};
uint16_t __raw;
} reg7e;
reg7e.__raw = BK4819_ReadRegister(0x7E);
uint8_t gainAddr = reg7e.gainIdx < 0 ? 0x14 : 0x10 + reg7e.gainIdx;
union {
struct {
uint16_t pga:3;
uint16_t mixer:2;
uint16_t lna:3;
uint16_t lnaS:2;
};
uint16_t __raw;
} agcGainReg;
agcGainReg.__raw = BK4819_ReadRegister(gainAddr);
int8_t lnaShortTab[] = {-28, -24, -19, 0};
int8_t lnaTab[] = {-24, -19, -14, -9, -6, -4, -2, 0};
int8_t mixerTab[] = {-8, -6, -3, 0};
int8_t pgaTab[] = {-33, -27, -21, -15, -9, -6, -3, 0};
int16_t agcGain = lnaShortTab[agcGainReg.lnaS] + lnaTab[agcGainReg.lna] + mixerTab[agcGainReg.mixer] + pgaTab[agcGainReg.pga];
if (gCurrentFunction == FUNCTION_RECEIVE ||
gCurrentFunction == FUNCTION_MONITOR ||
gCurrentFunction == FUNCTION_INCOMING)
{
DisplayRSSIBar(rssi, true);
sprintf(buf, "%d%2d %2d %2d %3d", reg7e.agcEnab, reg7e.gainIdx, -agcGain, reg7e.agcSigStrength, BK4819_GetRSSI());
UI_PrintStringSmallNormal(buf, 2, 0, 3);
if(now)
ST7565_BlitLine(3);
}
#endif
void UI_MAIN_TimeSlice500ms(void)
{
if(gScreenToDisplay==DISPLAY_MAIN) {
#ifdef ENABLE_AGC_SHOW_DATA
UI_MAIN_PrintAGC(true);
return;
#endif
if(FUNCTION_IsRx()) {
DisplayRSSIBar(true);
}
}
}
// ***************************************************************************
void UI_DisplayMain(void)
{
const unsigned int line0 = 0; // text screen line
const unsigned int line1 = 4;
char String[22];
unsigned int vfo_num;
center_line = CENTER_LINE_NONE;
// clear the screen
memset(gFrameBuffer, 0, sizeof(gFrameBuffer));
UI_DisplayClear();
if(gLowBattery && !gLowBatteryConfirmed) {
UI_DisplayPopup("LOW BATTERY");
@@ -247,56 +324,73 @@ void UI_DisplayMain(void)
ST7565_BlitFullScreen();
return;
}
unsigned int activeTxVFO = gRxVfoIsActive ? gEeprom.RX_VFO : gEeprom.TX_VFO;
for (vfo_num = 0; vfo_num < 2; vfo_num++)
for (unsigned int vfo_num = 0; vfo_num < 2; vfo_num++)
{
const unsigned int line0 = 0; // text screen line
const unsigned int line1 = 4;
const unsigned int line = (vfo_num == 0) ? line0 : line1;
const bool isMainVFO = (vfo_num == gEeprom.TX_VFO);
const bool isMainVFO = (vfo_num == gEeprom.TX_VFO);
uint8_t *p_line0 = gFrameBuffer[line + 0];
uint8_t *p_line1 = gFrameBuffer[line + 1];
unsigned int mode = 0;
enum Vfo_txtr_mode mode = VFO_MODE_NONE;
if (activeTxVFO != vfo_num) // this is not active TX VFO
{
if (gDTMF_CallState != DTMF_CALL_STATE_NONE || gDTMF_IsTx || gDTMF_InputMode)
{ // show DTMF stuff
#ifdef ENABLE_SCAN_RANGES
if(gScanRangeStart) {
UI_PrintString("ScnRng", 5, 0, line, 8);
sprintf(String, "%3u.%05u", gScanRangeStart / 100000, gScanRangeStart % 100000);
UI_PrintStringSmallNormal(String, 56, 0, line);
sprintf(String, "%3u.%05u", gScanRangeStop / 100000, gScanRangeStop % 100000);
UI_PrintStringSmallNormal(String, 56, 0, line + 1);
continue;
}
#endif
if (gDTMF_InputMode
#ifdef ENABLE_DTMF_CALLING
|| gDTMF_CallState != DTMF_CALL_STATE_NONE || gDTMF_IsTx
#endif
) {
char *pPrintStr = "";
// show DTMF stuff
#ifdef ENABLE_DTMF_CALLING
char Contact[16];
if (!gDTMF_InputMode) {
if (gDTMF_CallState == DTMF_CALL_STATE_CALL_OUT) {
pPrintStr = DTMF_FindContact(gDTMF_String, Contact) ? Contact : gDTMF_String;
} else if (gDTMF_CallState == DTMF_CALL_STATE_RECEIVED || gDTMF_CallState == DTMF_CALL_STATE_RECEIVED_STAY){
pPrintStr = DTMF_FindContact(gDTMF_Callee, Contact) ? Contact : gDTMF_Callee;
}else if (gDTMF_IsTx) {
pPrintStr = gDTMF_String;
}
}
if (!gDTMF_InputMode)
{
memset(Contact, 0, sizeof(Contact));
if (gDTMF_CallState == DTMF_CALL_STATE_CALL_OUT)
strcpy(String, (gDTMF_State == DTMF_STATE_CALL_OUT_RSP) ? "CALL OUT(RSP)" : "CALL OUT");
else
if (gDTMF_CallState == DTMF_CALL_STATE_RECEIVED || gDTMF_CallState == DTMF_CALL_STATE_RECEIVED_STAY)
UI_PrintString(pPrintStr, 2, 0, 2 + (vfo_num * 3), 8);
pPrintStr = "";
if (!gDTMF_InputMode) {
if (gDTMF_CallState == DTMF_CALL_STATE_CALL_OUT) {
pPrintStr = (gDTMF_State == DTMF_STATE_CALL_OUT_RSP) ? "CALL OUT(RSP)" : "CALL OUT";
} else if (gDTMF_CallState == DTMF_CALL_STATE_RECEIVED || gDTMF_CallState == DTMF_CALL_STATE_RECEIVED_STAY) {
sprintf(String, "CALL FRM:%s", (DTMF_FindContact(gDTMF_Caller, Contact)) ? Contact : gDTMF_Caller);
else
if (gDTMF_IsTx)
strcpy(String, (gDTMF_State == DTMF_STATE_TX_SUCC) ? "DTMF TX(SUCC)" : "DTMF TX");
pPrintStr = String;
} else if (gDTMF_IsTx) {
pPrintStr = (gDTMF_State == DTMF_STATE_TX_SUCC) ? "DTMF TX(SUCC)" : "DTMF TX";
}
}
else
#endif
{
sprintf(String, ">%s", gDTMF_InputBox);
pPrintStr = String;
}
UI_PrintString(String, 2, 0, 0 + (vfo_num * 3), 8);
memset(String, 0, sizeof(String));
if (!gDTMF_InputMode)
{
memset(Contact, 0, sizeof(Contact));
if (gDTMF_CallState == DTMF_CALL_STATE_CALL_OUT)
sprintf(String, ">%s", (DTMF_FindContact(gDTMF_String, Contact)) ? Contact : gDTMF_String);
else
if (gDTMF_CallState == DTMF_CALL_STATE_RECEIVED || gDTMF_CallState == DTMF_CALL_STATE_RECEIVED_STAY)
sprintf(String, ">%s", (DTMF_FindContact(gDTMF_Callee, Contact)) ? Contact : gDTMF_Callee);
else
if (gDTMF_IsTx)
sprintf(String, ">%s", gDTMF_String);
}
UI_PrintString(String, 2, 0, 2 + (vfo_num * 3), 8);
UI_PrintString(pPrintStr, 2, 0, 0 + (vfo_num * 3), 8);
center_line = CENTER_LINE_IN_USE;
continue;
@@ -304,69 +398,57 @@ void UI_DisplayMain(void)
// highlight the selected/used VFO with a marker
if (isMainVFO)
memmove(p_line0 + 0, BITMAP_VFO_Default, sizeof(BITMAP_VFO_Default));
memcpy(p_line0 + 0, BITMAP_VFO_Default, sizeof(BITMAP_VFO_Default));
}
else // active TX VFO
{ // highlight the selected/used VFO with a marker
if (isMainVFO)
memmove(p_line0 + 0, BITMAP_VFO_Default, sizeof(BITMAP_VFO_Default));
memcpy(p_line0 + 0, BITMAP_VFO_Default, sizeof(BITMAP_VFO_Default));
else
memmove(p_line0 + 0, BITMAP_VFO_NotDefault, sizeof(BITMAP_VFO_NotDefault));
memcpy(p_line0 + 0, BITMAP_VFO_NotDefault, sizeof(BITMAP_VFO_NotDefault));
}
if (gCurrentFunction == FUNCTION_TRANSMIT)
{ // transmitting
#ifdef ENABLE_ALARM
if (gAlarmState == ALARM_STATE_ALARM)
mode = 2;
if (gAlarmState == ALARM_STATE_SITE_ALARM)
mode = VFO_MODE_RX;
else
#endif
{
if (activeTxVFO == vfo_num)
{ // show the TX symbol
mode = 1;
#ifdef ENABLE_SMALL_BOLD
mode = VFO_MODE_TX;
UI_PrintStringSmallBold("TX", 14, 0, line);
#else
UI_PrintStringSmall("TX", 14, 0, line);
#endif
}
}
}
else
{ // receiving .. show the RX symbol
mode = 2;
if ((gCurrentFunction == FUNCTION_RECEIVE ||
gCurrentFunction == FUNCTION_MONITOR ||
gCurrentFunction == FUNCTION_INCOMING) &&
gEeprom.RX_VFO == vfo_num)
{
#ifdef ENABLE_SMALL_BOLD
mode = VFO_MODE_RX;
if (FUNCTION_IsRx() && gEeprom.RX_VFO == vfo_num) {
UI_PrintStringSmallBold("RX", 14, 0, line);
#else
UI_PrintStringSmall("RX", 14, 0, line);
#endif
}
}
if (IS_MR_CHANNEL(gEeprom.ScreenChannel[vfo_num]))
{ // channel mode
const unsigned int x = 2;
const bool inputting = (gInputBoxIndex == 0 || gEeprom.TX_VFO != vfo_num) ? false : true;
const bool inputting = gInputBoxIndex != 0 && gEeprom.TX_VFO == vfo_num;
if (!inputting)
sprintf(String, "M%u", gEeprom.ScreenChannel[vfo_num] + 1);
else
sprintf(String, "M%.3s", INPUTBOX_GetAscii()); // show the input text
UI_PrintStringSmall(String, x, 0, line + 1);
UI_PrintStringSmallNormal(String, x, 0, line + 1);
}
else if (IS_FREQ_CHANNEL(gEeprom.ScreenChannel[vfo_num]))
{ // frequency mode
// show the frequency band number
const unsigned int x = 2;
char * buf = gEeprom.VfoInfo[vfo_num].pRX->Frequency < 100000000 ? "" : "+";
char * buf = gEeprom.VfoInfo[vfo_num].pRX->Frequency < _1GHz_in_KHz ? "" : "+";
sprintf(String, "F%u%s", 1 + gEeprom.ScreenChannel[vfo_num] - FREQ_CHANNEL_FIRST, buf);
UI_PrintStringSmall(String, x, 0, line + 1);
UI_PrintStringSmallNormal(String, x, 0, line + 1);
}
#ifdef ENABLE_NOAA
else
@@ -379,16 +461,16 @@ void UI_DisplayMain(void)
{ // user entering channel number
sprintf(String, "N%u%u", '0' + gInputBox[0], '0' + gInputBox[1]);
}
UI_PrintStringSmall(String, 7, 0, line + 1);
UI_PrintStringSmallNormal(String, 7, 0, line + 1);
}
#endif
// ************
unsigned int state = VfoState[vfo_num];
enum VfoState_t state = VfoState[vfo_num];
#ifdef ENABLE_ALARM
if (gCurrentFunction == FUNCTION_TRANSMIT && gAlarmState == ALARM_STATE_ALARM) {
if (gCurrentFunction == FUNCTION_TRANSMIT && gAlarmState == ALARM_STATE_SITE_ALARM) {
if (activeTxVFO == vfo_num)
state = VFO_STATE_ALARM;
}
@@ -398,19 +480,18 @@ void UI_DisplayMain(void)
if (state != VFO_STATE_NORMAL)
{
const char *state_list[] = {"", "BUSY", "BAT LOW", "TX DISABLE", "TIMEOUT", "ALARM", "VOLT HIGH"};
if (state < ARRAY_SIZE(state_list))
UI_PrintString(state_list[state], 31, 0, line, 8);
if (state < ARRAY_SIZE(VfoStateStr))
UI_PrintString(VfoStateStr[state], 31, 0, line, 8);
}
else if (gInputBoxIndex > 0 && IS_FREQ_CHANNEL(gEeprom.ScreenChannel[vfo_num]) && gEeprom.TX_VFO == vfo_num)
{ // user entering a frequency
const char * ascii = INPUTBOX_GetAscii();
bool isGigaF = frequency>=100000000;
bool isGigaF = frequency>=_1GHz_in_KHz;
sprintf(String, "%.*s.%.3s", 3 + isGigaF, ascii, ascii + 3 + isGigaF);
#ifdef ENABLE_BIG_FREQ
if(!isGigaF) {
// show the remaining 2 small frequency digits
UI_PrintStringSmall(String + 7, 113, 0, line + 1);
UI_PrintStringSmallNormal(String + 7, 113, 0, line + 1);
String[7] = 0;
// show the main large frequency digits
UI_DisplayFrequency(String, 32, line, false);
@@ -422,7 +503,7 @@ void UI_DisplayMain(void)
UI_PrintString(String, 32, 0, line, 8);
}
break;
continue;
}
else
{
@@ -436,16 +517,16 @@ void UI_DisplayMain(void)
{ // it's a channel
// show the scan list assigment symbols
const uint8_t attributes = gMR_ChannelAttributes[gEeprom.ScreenChannel[vfo_num]];
if (attributes & MR_CH_SCANLIST1)
memmove(p_line0 + 113, BITMAP_ScanList1, sizeof(BITMAP_ScanList1));
if (attributes & MR_CH_SCANLIST2)
memmove(p_line0 + 120, BITMAP_ScanList2, sizeof(BITMAP_ScanList2));
const ChannelAttributes_t att = gMR_ChannelAttributes[gEeprom.ScreenChannel[vfo_num]];
if (att.scanlist1)
memcpy(p_line0 + 113, BITMAP_ScanList1, sizeof(BITMAP_ScanList1));
if (att.scanlist2)
memcpy(p_line0 + 120, BITMAP_ScanList2, sizeof(BITMAP_ScanList2));
// compander symbol
#ifndef ENABLE_BIG_FREQ
if ((attributes & MR_CH_COMPAND) > 0)
memmove(p_line0 + 120 + LCD_WIDTH, BITMAP_compand, sizeof(BITMAP_compand));
if (att.compander)
memcpy(p_line0 + 120 + LCD_WIDTH, BITMAP_compand, sizeof(BITMAP_compand));
#else
// TODO: // find somewhere else to put the symbol
#endif
@@ -455,9 +536,9 @@ void UI_DisplayMain(void)
case MDF_FREQUENCY: // show the channel frequency
sprintf(String, "%3u.%05u", frequency / 100000, frequency % 100000);
#ifdef ENABLE_BIG_FREQ
if(frequency < 100000000) {
if(frequency < _1GHz_in_KHz) {
// show the remaining 2 small frequency digits
UI_PrintStringSmall(String + 7, 113, 0, line + 1);
UI_PrintStringSmallNormal(String + 7, 113, 0, line + 1);
String[7] = 0;
// show the main large frequency digits
UI_DisplayFrequency(String, 32, line, false);
@@ -479,7 +560,7 @@ void UI_DisplayMain(void)
case MDF_NAME: // show the channel name
case MDF_NAME_FREQ: // show the channel name and frequency
BOARD_fetchChannelName(String, gEeprom.ScreenChannel[vfo_num]);
SETTINGS_FetchChannelName(String, gEeprom.ScreenChannel[vfo_num]);
if (String[0] == 0)
{ // no channel name, show the channel number instead
sprintf(String, "CH-%03u", gEeprom.ScreenChannel[vfo_num] + 1);
@@ -489,14 +570,10 @@ void UI_DisplayMain(void)
UI_PrintString(String, 32, 0, line, 8);
}
else {
#ifdef ENABLE_SMALL_BOLD
UI_PrintStringSmallBold(String, 32 + 4, 0, line);
#else
UI_PrintStringSmall(String, 32 + 4, 0, line);
#endif
// show the channel frequency below the channel number/name
sprintf(String, "%03u.%05u", frequency / 100000, frequency % 100000);
UI_PrintStringSmall(String, 32 + 4, 0, line + 1);
UI_PrintStringSmallNormal(String, 32 + 4, 0, line + 1);
}
break;
@@ -507,9 +584,9 @@ void UI_DisplayMain(void)
sprintf(String, "%3u.%05u", frequency / 100000, frequency % 100000);
#ifdef ENABLE_BIG_FREQ
if(frequency < 100000000) {
if(frequency < _1GHz_in_KHz) {
// show the remaining 2 small frequency digits
UI_PrintStringSmall(String + 7, 113, 0, line + 1);
UI_PrintStringSmallNormal(String + 7, 113, 0, line + 1);
String[7] = 0;
// show the main large frequency digits
UI_DisplayFrequency(String, 32, line, false);
@@ -522,12 +599,12 @@ void UI_DisplayMain(void)
}
// show the channel symbols
const uint8_t attributes = gMR_ChannelAttributes[gEeprom.ScreenChannel[vfo_num]];
if ((attributes & MR_CH_COMPAND) > 0)
const ChannelAttributes_t att = gMR_ChannelAttributes[gEeprom.ScreenChannel[vfo_num]];
if (att.compander)
#ifdef ENABLE_BIG_FREQ
memmove(p_line0 + 120, BITMAP_compand, sizeof(BITMAP_compand));
memcpy(p_line0 + 120, BITMAP_compand, sizeof(BITMAP_compand));
#else
memmove(p_line0 + 120 + LCD_WIDTH, BITMAP_compand, sizeof(BITMAP_compand));
memcpy(p_line0 + 120 + LCD_WIDTH, BITMAP_compand, sizeof(BITMAP_compand));
#endif
}
}
@@ -537,7 +614,7 @@ void UI_DisplayMain(void)
{ // show the TX/RX level
uint8_t Level = 0;
if (mode == 1)
if (mode == VFO_MODE_TX)
{ // TX power level
switch (gRxVfo->OUTPUT_POWER)
{
@@ -547,7 +624,7 @@ void UI_DisplayMain(void)
}
}
else
if (mode == 2)
if (mode == VFO_MODE_RX)
{ // RX signal level
#ifndef ENABLE_RSSI_BAR
// bar graph
@@ -562,13 +639,14 @@ void UI_DisplayMain(void)
// ************
String[0] = '\0';
const VFO_Info_t *vfoInfo = &gEeprom.VfoInfo[vfo_num];
// show the modulation symbol
const char * s = "";
const ModulationMode_t mod = gEeprom.VfoInfo[vfo_num].Modulation;
const ModulationMode_t mod = vfoInfo->Modulation;
switch (mod){
case MODULATION_FM: {
const FREQ_Config_t *pConfig = (mode == 1) ? gEeprom.VfoInfo[vfo_num].pTX : gEeprom.VfoInfo[vfo_num].pRX;
const FREQ_Config_t *pConfig = (mode == VFO_MODE_TX) ? vfoInfo->pTX : vfoInfo->pRX;
const unsigned int code_type = pConfig->CodeType;
const char *code_list[] = {"", "CT", "DCS", "DCR"};
if (code_type < ARRAY_SIZE(code_list))
@@ -578,56 +656,50 @@ void UI_DisplayMain(void)
default:
s = gModulationStr[mod];
break;
}
UI_PrintStringSmall(s, LCD_WIDTH + 24, 0, line + 1);
}
UI_PrintStringSmallNormal(s, LCD_WIDTH + 24, 0, line + 1);
if (state == VFO_STATE_NORMAL || state == VFO_STATE_ALARM)
{ // show the TX power
const char pwr_list[] = "LMH";
const unsigned int i = gEeprom.VfoInfo[vfo_num].OUTPUT_POWER;
String[0] = (i < ARRAY_SIZE(pwr_list)) ? pwr_list[i] : '\0';
String[1] = '\0';
UI_PrintStringSmall(String, LCD_WIDTH + 46, 0, line + 1);
const char pwr_list[][2] = {"L","M","H"};
int i = vfoInfo->OUTPUT_POWER % 3;
UI_PrintStringSmallNormal(pwr_list[i], LCD_WIDTH + 46, 0, line + 1);
}
if (gEeprom.VfoInfo[vfo_num].freq_config_RX.Frequency != gEeprom.VfoInfo[vfo_num].freq_config_TX.Frequency)
if (vfoInfo->freq_config_RX.Frequency != vfoInfo->freq_config_TX.Frequency)
{ // show the TX offset symbol
const char dir_list[] = "\0+-";
const unsigned int i = gEeprom.VfoInfo[vfo_num].TX_OFFSET_FREQUENCY_DIRECTION;
String[0] = (i < sizeof(dir_list)) ? dir_list[i] : '?';
String[1] = '\0';
UI_PrintStringSmall(String, LCD_WIDTH + 54, 0, line + 1);
const char dir_list[][2] = {"", "+", "-"};
int i = vfoInfo->TX_OFFSET_FREQUENCY_DIRECTION % 3;
UI_PrintStringSmallNormal(dir_list[i], LCD_WIDTH + 54, 0, line + 1);
}
// show the TX/RX reverse symbol
if (gEeprom.VfoInfo[vfo_num].FrequencyReverse)
UI_PrintStringSmall("R", LCD_WIDTH + 62, 0, line + 1);
if (vfoInfo->FrequencyReverse)
UI_PrintStringSmallNormal("R", LCD_WIDTH + 62, 0, line + 1);
{ // show the narrow band symbol
String[0] = '\0';
if (gEeprom.VfoInfo[vfo_num].CHANNEL_BANDWIDTH == BANDWIDTH_NARROW)
{
String[0] = 'N';
String[1] = '\0';
}
UI_PrintStringSmall(String, LCD_WIDTH + 70, 0, line + 1);
}
if (vfoInfo->CHANNEL_BANDWIDTH == BANDWIDTH_NARROW)
UI_PrintStringSmallNormal("N", LCD_WIDTH + 70, 0, line + 1);
#ifdef ENABLE_DTMF_CALLING
// show the DTMF decoding symbol
if (gEeprom.VfoInfo[vfo_num].DTMF_DECODING_ENABLE || gSetting_KILLED)
UI_PrintStringSmall("DTMF", LCD_WIDTH + 78, 0, line + 1);
if (vfoInfo->DTMF_DECODING_ENABLE || gSetting_KILLED)
UI_PrintStringSmallNormal("DTMF", LCD_WIDTH + 78, 0, line + 1);
#endif
// show the audio scramble symbol
if (gEeprom.VfoInfo[vfo_num].SCRAMBLING_TYPE > 0 && gSetting_ScrambleEnable)
UI_PrintStringSmall("SCR", LCD_WIDTH + 106, 0, line + 1);
if (vfoInfo->SCRAMBLING_TYPE > 0 && gSetting_ScrambleEnable)
UI_PrintStringSmallNormal("SCR", LCD_WIDTH + 106, 0, line + 1);
}
#ifdef ENABLE_AGC_SHOW_DATA
center_line = CENTER_LINE_IN_USE;
UI_MAIN_PrintAGC(false);
#endif
if (center_line == CENTER_LINE_NONE)
{ // we're free to use the middle line
const bool rx = (gCurrentFunction == FUNCTION_RECEIVE ||
gCurrentFunction == FUNCTION_MONITOR ||
gCurrentFunction == FUNCTION_INCOMING);
const bool rx = FUNCTION_IsRx();
#ifdef ENABLE_AUDIO_BAR
if (gSetting_mic_bar && gCurrentFunction == FUNCTION_TRANSMIT) {
@@ -640,13 +712,16 @@ void UI_DisplayMain(void)
#if defined(ENABLE_AM_FIX) && defined(ENABLE_AM_FIX_SHOW_DATA)
if (rx && gEeprom.VfoInfo[gEeprom.RX_VFO].Modulation == MODULATION_AM && gSetting_AM_fix)
{
if (gScreenToDisplay != DISPLAY_MAIN ||
gDTMF_CallState != DTMF_CALL_STATE_NONE)
if (gScreenToDisplay != DISPLAY_MAIN
#ifdef ENABLE_DTMF_CALLING
|| gDTMF_CallState != DTMF_CALL_STATE_NONE
#endif
)
return;
center_line = CENTER_LINE_AM_FIX_DATA;
AM_fix_print_data(gEeprom.RX_VFO, String);
UI_PrintStringSmall(String, 2, 0, 3);
UI_PrintStringSmallNormal(String, 2, 0, 3);
}
else
#endif
@@ -654,7 +729,7 @@ void UI_DisplayMain(void)
#ifdef ENABLE_RSSI_BAR
if (rx) {
center_line = CENTER_LINE_RSSI;
DisplayRSSIBar(gCurrentRSSI[gEeprom.RX_VFO], false);
DisplayRSSIBar(false);
}
else
#endif
@@ -666,15 +741,17 @@ void UI_DisplayMain(void)
const unsigned int len = strlen(gDTMF_RX_live);
const unsigned int idx = (len > (17 - 5)) ? len - (17 - 5) : 0; // limit to last 'n' chars
if (gScreenToDisplay != DISPLAY_MAIN ||
gDTMF_CallState != DTMF_CALL_STATE_NONE)
if (gScreenToDisplay != DISPLAY_MAIN
#ifdef ENABLE_DTMF_CALLING
|| gDTMF_CallState != DTMF_CALL_STATE_NONE
#endif
)
return;
center_line = CENTER_LINE_DTMF_DEC;
strcpy(String, "DTMF ");
strcat(String, gDTMF_RX_live + idx);
UI_PrintStringSmall(String, 2, 0, 3);
sprintf(String, "DTMF %s", gDTMF_RX_live + idx);
UI_PrintStringSmallNormal(String, 2, 0, 3);
}
#else
if (gSetting_live_DTMF_decoder && gDTMF_RX_index > 0)
@@ -687,26 +764,28 @@ void UI_DisplayMain(void)
return;
center_line = CENTER_LINE_DTMF_DEC;
strcpy(String, "DTMF ");
strcat(String, gDTMF_RX + idx);
UI_PrintStringSmall(String, 2, 0, 3);
sprintf(String, "DTMF %s", gDTMF_RX_live + idx);
UI_PrintStringSmallNormal(String, 2, 0, 3);
}
#endif
#ifdef ENABLE_SHOW_CHARGE_LEVEL
else if (gChargingWithTypeC)
{ // charging .. show the battery state
if (gScreenToDisplay != DISPLAY_MAIN ||
gDTMF_CallState != DTMF_CALL_STATE_NONE)
if (gScreenToDisplay != DISPLAY_MAIN
#ifdef ENABLE_DTMF_CALLING
|| gDTMF_CallState != DTMF_CALL_STATE_NONE
#endif
)
return;
center_line = CENTER_LINE_CHARGE_DATA;
sprintf(String, "Charge %u.%02uV %u%%",
gBatteryVoltageAverage / 100, gBatteryVoltageAverage % 100,
BATTERY_VoltsToPercent(gBatteryVoltageAverage));
UI_PrintStringSmall(String, 2, 0, 3);
UI_PrintStringSmallNormal(String, 2, 0, 3);
}
#endif
}

View File

@@ -26,13 +26,24 @@ enum center_line_t {
CENTER_LINE_DTMF_DEC,
CENTER_LINE_CHARGE_DATA
};
enum Vfo_txtr_mode{
VFO_MODE_NONE = 0,
VFO_MODE_TX = 1,
VFO_MODE_RX = 2,
};
typedef enum center_line_t center_line_t;
extern center_line_t center_line;
extern const int8_t dBmCorrTable[7];
void UI_DisplayAudioBar(void);
void UI_UpdateRSSI(const int16_t rssi, const int vfo);
void UI_MAIN_TimeSlice500ms(void);
void UI_DisplayMain(void);
#ifdef ENABLE_AGC_SHOW_DATA
void UI_MAIN_PrintAGC(bool force);
#endif
#endif

428
ui/menu.c
View File

@@ -15,26 +15,27 @@
*/
#include <string.h>
#include <stdlib.h> // abs()
#include <stdlib.h>
#include "../app/dtmf.h"
#include "../app/menu.h"
#include "../bitmaps.h"
#include "../board.h"
#include "../dcs.h"
#include "../driver/backlight.h"
#include "../driver/bk4819.h"
#include "../driver/eeprom.h"
#include "../driver/st7565.h"
#include "../external/printf/printf.h"
#include "../frequencies.h"
#include "../helper/battery.h"
#include "../misc.h"
#include "../settings.h"
#include "helper.h"
#include "inputbox.h"
#include "menu.h"
#include "ui.h"
#include "app/dtmf.h"
#include "app/menu.h"
#include "bitmaps.h"
#include "board.h"
#include "dcs.h"
#include "driver/backlight.h"
#include "driver/bk4819.h"
#include "driver/eeprom.h" // EEPROM_ReadBuffer()
#include "driver/st7565.h"
#include "external/printf/printf.h"
#include "frequencies.h"
#include "helper/battery.h"
#include "misc.h"
#include "settings.h"
#include "ui/helper.h"
#include "ui/inputbox.h"
#include "ui/menu.h"
#include "ui/ui.h"
const t_menu_item MenuList[] =
{
@@ -56,7 +57,7 @@ const t_menu_item MenuList[] =
{"ScAdd2", VOICE_ID_INVALID, MENU_S_ADD2 },
{"ChSave", VOICE_ID_MEMORY_CHANNEL, MENU_MEM_CH }, // was "MEM-CH"
{"ChDele", VOICE_ID_DELETE_CHANNEL, MENU_DEL_CH }, // was "DEL-CH"
{"ChName", VOICE_ID_INVALID, MENU_MEM_NAME },
{"ChName", VOICE_ID_INVALID, MENU_MEM_NAME },
{"SList", VOICE_ID_INVALID, MENU_S_LIST },
{"SList1", VOICE_ID_INVALID, MENU_SLIST1 },
@@ -65,7 +66,6 @@ const t_menu_item MenuList[] =
#ifdef ENABLE_NOAA
{"NOAA-S", VOICE_ID_INVALID, MENU_NOAA_S },
#endif
{"F1Shrt", VOICE_ID_INVALID, MENU_F1SHRT },
{"F1Long", VOICE_ID_INVALID, MENU_F1LONG },
{"F2Shrt", VOICE_ID_INVALID, MENU_F2SHRT },
@@ -78,10 +78,10 @@ const t_menu_item MenuList[] =
{"Mic", VOICE_ID_INVALID, MENU_MIC },
#ifdef ENABLE_AUDIO_BAR
{"MicBar", VOICE_ID_INVALID, MENU_MIC_BAR },
#endif
#endif
{"ChDisp", VOICE_ID_INVALID, MENU_MDF }, // was "MDF"
{"POnMsg", VOICE_ID_INVALID, MENU_PONMSG },
{"BatTxt", VOICE_ID_INVALID, MENU_BAT_TXT },
{"BatTxt", VOICE_ID_INVALID, MENU_BAT_TXT },
{"BackLt", VOICE_ID_INVALID, MENU_ABR }, // was "ABR"
{"BLMin", VOICE_ID_INVALID, MENU_ABR_MIN },
{"BLMax", VOICE_ID_INVALID, MENU_ABR_MAX },
@@ -97,23 +97,26 @@ const t_menu_item MenuList[] =
#ifdef ENABLE_ALARM
{"AlarmT", VOICE_ID_INVALID, MENU_AL_MOD },
#endif
#ifdef ENABLE_DTMF_CALLING
{"ANI ID", VOICE_ID_ANI_CODE, MENU_ANI_ID },
#endif
{"UPCode", VOICE_ID_INVALID, MENU_UPCODE },
{"DWCode", VOICE_ID_INVALID, MENU_DWCODE },
{"PTT ID", VOICE_ID_INVALID, MENU_PTT_ID },
{"D ST", VOICE_ID_INVALID, MENU_D_ST },
#ifdef ENABLE_DTMF_CALLING
{"D Resp", VOICE_ID_INVALID, MENU_D_RSP },
{"D Hold", VOICE_ID_INVALID, MENU_D_HOLD },
#endif
{"D Prel", VOICE_ID_INVALID, MENU_D_PRE },
#ifdef ENABLE_DTMF_CALLING
{"D Decd", VOICE_ID_INVALID, MENU_D_DCD },
{"D List", VOICE_ID_INVALID, MENU_D_LIST },
#endif
{"D Live", VOICE_ID_INVALID, MENU_D_LIVE_DEC }, // live DTMF decoder
#ifdef ENABLE_AM_FIX
{"AM Fix", VOICE_ID_INVALID, MENU_AM_FIX },
#endif
#ifdef ENABLE_AM_FIX_TEST1
{"AM FT1", VOICE_ID_INVALID, MENU_AM_FIX_TEST1 },
#endif
#ifdef ENABLE_VOX
{"VOX", VOICE_ID_VOX, MENU_VOX },
#endif
@@ -129,7 +132,6 @@ const t_menu_item MenuList[] =
{"Tx 500", VOICE_ID_INVALID, MENU_500TX }, // was "500TX"
{"350 En", VOICE_ID_INVALID, MENU_350EN }, // was "350EN"
{"ScraEn", VOICE_ID_INVALID, MENU_SCREN }, // was "SCREN"
{"TxEnab", VOICE_ID_INVALID, MENU_TX_EN }, // enable TX
#ifdef ENABLE_F_CAL_MENU
{"FrCali", VOICE_ID_INVALID, MENU_F_CALI }, // reference xtal calibration
#endif
@@ -142,33 +144,33 @@ const t_menu_item MenuList[] =
const uint8_t FIRST_HIDDEN_MENU_ITEM = MENU_F_LOCK;
const char gSubMenu_TXP[3][5] =
const char gSubMenu_TXP[][5] =
{
"LOW",
"MID",
"HIGH"
};
const char gSubMenu_SFT_D[3][4] =
const char gSubMenu_SFT_D[][4] =
{
"OFF",
"+",
"-"
};
const char gSubMenu_W_N[2][7] =
const char gSubMenu_W_N[][7] =
{
"WIDE",
"NARROW"
};
const char gSubMenu_OFF_ON[2][4] =
const char gSubMenu_OFF_ON[][4] =
{
"OFF",
"ON"
};
const char gSubMenu_SAVE[5][4] =
const char gSubMenu_SAVE[][4] =
{
"OFF",
"1:1",
@@ -177,7 +179,7 @@ const char gSubMenu_SAVE[5][4] =
"1:4"
};
const char gSubMenu_TOT[11][7] =
const char gSubMenu_TOT[][7] =
{
"30 sec",
"1 min",
@@ -192,7 +194,7 @@ const char gSubMenu_TOT[11][7] =
"15 min"
};
const char* gSubMenu_RXMode[4] =
const char* const gSubMenu_RXMode[] =
{
"MAIN\nONLY", // TX and RX on main only
"DUAL RX\nRESPOND", // Watch both and respond
@@ -201,7 +203,7 @@ const char* gSubMenu_RXMode[4] =
};
#ifdef ENABLE_VOICE
const char gSubMenu_VOICE[3][4] =
const char gSubMenu_VOICE[][4] =
{
"OFF",
"CHI",
@@ -209,14 +211,14 @@ const char* gSubMenu_RXMode[4] =
};
#endif
const char gSubMenu_SC_REV[3][8] =
const char gSubMenu_SC_REV[][8] =
{
"TIMEOUT",
"CARRIER",
"STOP"
};
const char* gSubMenu_MDF[4] =
const char* const gSubMenu_MDF[] =
{
"FREQ",
"CHANNEL\nNUMBER",
@@ -225,31 +227,33 @@ const char* gSubMenu_MDF[4] =
};
#ifdef ENABLE_ALARM
const char gSubMenu_AL_MOD[2][5] =
const char gSubMenu_AL_MOD[][5] =
{
"SITE",
"TONE"
};
#endif
const char gSubMenu_D_RSP[4][11] =
#ifdef ENABLE_DTMF_CALLING
const char gSubMenu_D_RSP[][11] =
{
"DO\nNOTHING",
"RING",
"REPLY",
"BOTH"
};
#endif
const char* gSubMenu_PTT_ID[5] =
const char* const gSubMenu_PTT_ID[] =
{
"OFF",
"KEY\nUP",
"KEY\nDOWN",
"KEY\nUP+DOWN",
"UP CODE",
"DOWN CODE",
"UP+DOWN\nCODE",
"APOLLO\nQUINDAR"
};
const char gSubMenu_PONMSG[4][8] =
const char gSubMenu_PONMSG[][8] =
{
"FULL",
"MESSAGE",
@@ -257,30 +261,32 @@ const char gSubMenu_PONMSG[4][8] =
"NONE"
};
const char* gSubMenu_ROGER[3] =
const char gSubMenu_ROGER[][6] =
{
"OFF",
"ROGER",
"MDC\n1200"
"MDC"
};
const char gSubMenu_RESET[2][4] =
const char gSubMenu_RESET[][4] =
{
"VFO",
"ALL"
};
const char gSubMenu_F_LOCK[6][4] =
const char * const gSubMenu_F_LOCK[] =
{
"OFF",
"FCC",
"CE",
"GB",
"430",
"438"
"DEFAULT+\n137-174\n400-470",
"FCC HAM\n144-148\n420-450",
"CE HAM\n144-146\n430-440",
"GB HAM\n144-148\n430-440",
"137-174\n400-430",
"137-174\n400-438",
"DISABLE\nALL",
"UNLOCK\nALL",
};
const char gSubMenu_BACKLIGHT[8][7] =
const char gSubMenu_BACKLIGHT[][7] =
{
"OFF",
"5 sec",
@@ -292,7 +298,7 @@ const char gSubMenu_BACKLIGHT[8][7] =
"ON"
};
const char gSubMenu_RX_TX[4][6] =
const char gSubMenu_RX_TX[][6] =
{
"OFF",
"TX",
@@ -300,30 +306,20 @@ const char gSubMenu_RX_TX[4][6] =
"TX/RX"
};
#ifdef ENABLE_AM_FIX_TEST1
const char gSubMenu_AM_fix_test1[4][8] =
{
"LNA-S 0",
"LNA-S 1",
"LNA-S 2",
"LNA-S 3"
};
#endif
const char gSubMenu_BAT_TXT[3][8] =
const char gSubMenu_BAT_TXT[][8] =
{
"NONE",
"VOLTAGE",
"PERCENT"
};
const char gSubMenu_BATTYP[2][9] =
const char gSubMenu_BATTYP[][9] =
{
"1600mAh",
"2200mAh"
};
const char gSubMenu_SCRAMBLER[11][7] =
const char gSubMenu_SCRAMBLER[][7] =
{
"OFF",
"2600Hz",
@@ -338,42 +334,55 @@ const char gSubMenu_SCRAMBLER[11][7] =
"3500Hz"
};
const t_sidefunction SIDEFUNCTIONS[] =
const t_sidefunction gSubMenu_SIDEFUNCTIONS[] =
{
{"NONE", ACTION_OPT_NONE},
#ifdef ENABLE_FLASHLIGHT
{"FLASH\nLIGHT", ACTION_OPT_FLASHLIGHT},
#endif
{"POWER", ACTION_OPT_POWER},
{"MONITOR", ACTION_OPT_MONITOR},
{"SCAN", ACTION_OPT_SCAN},
#ifdef ENABLE_VOX
{"VOX", ACTION_OPT_VOX},
#endif
#ifdef ENABLE_ALARM
#ifdef ENABLE_ALARM
{"ALARM", ACTION_OPT_ALARM},
#endif
#ifdef ENABLE_FMRADIO
{"FM RADIO", ACTION_OPT_FM},
#endif
#ifdef ENABLE_TX1750
#endif
#ifdef ENABLE_TX1750
{"1750HZ", ACTION_OPT_1750},
#endif
{"LOCK\nKEYPAD", ACTION_OPT_KEYLOCK},
{"SWITCH\nVFO", ACTION_OPT_A_B},
{"VFO/MR", ACTION_OPT_VFO_MR},
{"SWITCH\nDEMODUL", ACTION_OPT_SWITCH_DEMODUL},
#ifdef ENABLE_BLMIN_TMP_OFF
{"BLMIN\nTMP OFF", ACTION_OPT_BLMIN_TMP_OFF}, //BackLight Minimum Temporay OFF
#endif
};
const t_sidefunction* gSubMenu_SIDEFUNCTIONS = SIDEFUNCTIONS;
const uint8_t gSubMenu_SIDEFUNCTIONS_size = ARRAY_SIZE(SIDEFUNCTIONS);
const uint8_t gSubMenu_SIDEFUNCTIONS_size = ARRAY_SIZE(gSubMenu_SIDEFUNCTIONS);
bool gIsInSubMenu;
uint8_t gMenuCursor;
int GetCurrentMenuId() {
int UI_MENU_GetCurrentMenuId() {
if(gMenuCursor < ARRAY_SIZE(MenuList))
return MenuList[gMenuCursor].menu_id;
else
return MenuList[ARRAY_SIZE(MenuList)-1].menu_id;
return MenuList[ARRAY_SIZE(MenuList)-1].menu_id;
}
int8_t gMenuScrollDirection;
uint8_t UI_MENU_GetMenuIdx(uint8_t id)
{
for(uint8_t i = 0; i < ARRAY_SIZE(MenuList); i++)
if(MenuList[i].menu_id == id)
return i;
return 0;
}
int32_t gSubMenuSelection;
// edit box
@@ -388,54 +397,53 @@ void UI_DisplayMenu(void)
const unsigned int menu_item_x2 = LCD_WIDTH - 1;
unsigned int i;
char String[64]; // bigger cuz we can now do multi-line in one string (use '\n' char)
#ifdef ENABLE_DTMF_CALLING
char Contact[16];
#endif
// clear the screen buffer
memset(gFrameBuffer, 0, sizeof(gFrameBuffer));
UI_DisplayClear();
#if 0
#ifndef ENABLE_CUSTOM_MENU_LAYOUT
// original menu layout
for (i = 0; i < 3; i++)
if (gMenuCursor > 0 || i > 0)
if ((gMenuListCount - 1) != gMenuCursor || i != 2)
UI_PrintString(MenuList[gMenuCursor + i - 1].name, 0, 0, i * 2, 8);
for (i = 0; i < 3; i++)
if (gMenuCursor > 0 || i > 0)
if ((gMenuListCount - 1) != gMenuCursor || i != 2)
UI_PrintString(MenuList[gMenuCursor + i - 1].name, 0, 0, i * 2, 8);
// invert the current menu list item pixels
for (i = 0; i < (8 * menu_list_width); i++)
{
gFrameBuffer[2][i] ^= 0xFF;
gFrameBuffer[3][i] ^= 0xFF;
}
// invert the current menu list item pixels
for (i = 0; i < (8 * menu_list_width); i++)
{
gFrameBuffer[2][i] ^= 0xFF;
gFrameBuffer[3][i] ^= 0xFF;
}
// draw vertical separating dotted line
for (i = 0; i < 7; i++)
gFrameBuffer[i][(8 * menu_list_width) + 1] = 0xAA;
// draw vertical separating dotted line
for (i = 0; i < 7; i++)
gFrameBuffer[i][(8 * menu_list_width) + 1] = 0xAA;
// draw the little sub-menu triangle marker
if (gIsInSubMenu)
memcpy(gFrameBuffer[0] + (8 * menu_list_width) + 1, BITMAP_CurrentIndicator, sizeof(BITMAP_CurrentIndicator));
// draw the little sub-menu triangle marker
if (gIsInSubMenu)
memmove(gFrameBuffer[0] + (8 * menu_list_width) + 1, BITMAP_CurrentIndicator, sizeof(BITMAP_CurrentIndicator));
// draw the menu index number/count
sprintf(String, "%2u.%u", 1 + gMenuCursor, gMenuListCount);
// draw the menu index number/count
sprintf(String, "%2u.%u", 1 + gMenuCursor, gMenuListCount);
UI_PrintStringSmall(String, 2, 0, 6);
UI_PrintStringSmallNormal(String, 2, 0, 6);
#else
#else
{ // new menu layout .. experimental & unfinished
const int menu_index = gMenuCursor; // current selected menu item
i = 1;
if (!gIsInSubMenu)
{
if (!gIsInSubMenu) {
while (i < 2)
{ // leading menu items - small text
const int k = menu_index + i - 2;
if (k < 0)
UI_PrintStringSmall(MenuList[gMenuListCount + k].name, 0, 0, i); // wrap-a-round
else
if (k >= 0 && k < (int)gMenuListCount)
UI_PrintStringSmall(MenuList[k].name, 0, 0, i);
UI_PrintStringSmallNormal(MenuList[gMenuListCount + k].name, 0, 0, i); // wrap-a-round
else if (k >= 0 && k < (int)gMenuListCount)
UI_PrintStringSmallNormal(MenuList[k].name, 0, 0, i);
i++;
}
@@ -448,27 +456,24 @@ void UI_DisplayMenu(void)
{ // trailing menu item - small text
const int k = menu_index + i - 2;
if (k >= 0 && k < (int)gMenuListCount)
UI_PrintStringSmall(MenuList[k].name, 0, 0, 1 + i);
else
if (k >= (int)gMenuListCount)
UI_PrintStringSmall(MenuList[gMenuListCount - k].name, 0, 0, 1 + i); // wrap-a-round
UI_PrintStringSmallNormal(MenuList[k].name, 0, 0, 1 + i);
else if (k >= (int)gMenuListCount)
UI_PrintStringSmallNormal(MenuList[gMenuListCount - k].name, 0, 0, 1 + i); // wrap-a-round
i++;
}
// draw the menu index number/count
sprintf(String, "%2u.%u", 1 + gMenuCursor, gMenuListCount);
UI_PrintStringSmall(String, 2, 0, 6);
UI_PrintStringSmallNormal(String, 2, 0, 6);
}
else
if (menu_index >= 0 && menu_index < (int)gMenuListCount)
else if (menu_index >= 0 && menu_index < (int)gMenuListCount)
{ // current menu item
strcpy(String, MenuList[menu_index].name);
// strcat(String, ":");
UI_PrintString(String, 0, 0, 0, 8);
// UI_PrintStringSmall(String, 0, 0, 0);
UI_PrintString(MenuList[menu_index].name, 0, 0, 0, 8);
// UI_PrintStringSmallNormal(String, 0, 0, 0);
}
}
#endif
#endif
// **************
@@ -476,7 +481,13 @@ void UI_DisplayMenu(void)
bool already_printed = false;
switch (GetCurrentMenuId())
/* Brightness is set to max in some entries of this menu. Return it to the configured brightness
level the "next" time we enter here.I.e., when we move from one menu to another.
It also has to be set back to max when pressing the Exit key. */
BACKLIGHT_TurnOn();
switch (UI_MENU_GetCurrentMenuId())
{
case MENU_SQL:
sprintf(String, "%d", gSubMenuSelection);
@@ -572,7 +583,8 @@ void UI_DisplayMenu(void)
case MENU_ABR:
strcpy(String, gSubMenu_BACKLIGHT[gSubMenuSelection]);
BACKLIGHT_SetBrightness(-1);
if(BACKLIGHT_GetBrightness() < 4)
BACKLIGHT_SetBrightness(4);
break;
case MENU_ABR_MIN:
@@ -580,21 +592,14 @@ void UI_DisplayMenu(void)
sprintf(String, "%d", gSubMenuSelection);
if(gIsInSubMenu)
BACKLIGHT_SetBrightness(gSubMenuSelection);
else
BACKLIGHT_SetBrightness(-1);
break;
else if(BACKLIGHT_GetBrightness() < 4)
BACKLIGHT_SetBrightness(4);
break;
case MENU_AM:
strcpy(String, gModulationStr[gSubMenuSelection]);
break;
#ifdef ENABLE_AM_FIX_TEST1
case MENU_AM_FIX_TEST1:
strcpy(String, gSubMenu_AM_fix_test1[gSubMenuSelection]);
// gSetting_AM_fix = gSubMenuSelection;
break;
#endif
case MENU_AUTOLK:
strcpy(String, (gSubMenuSelection == 0) ? "OFF" : "AUTO");
break;
@@ -613,7 +618,9 @@ void UI_DisplayMenu(void)
case MENU_S_ADD2:
case MENU_STE:
case MENU_D_ST:
#ifdef ENABLE_DTMF_CALLING
case MENU_D_DCD:
#endif
case MENU_D_LIVE_DEC:
#ifdef ENABLE_NOAA
case MENU_NOAA_S:
@@ -623,7 +630,6 @@ void UI_DisplayMenu(void)
case MENU_500TX:
case MENU_350EN:
case MENU_SCREN:
case MENU_TX_EN:
strcpy(String, gSubMenu_OFF_ON[gSubMenuSelection]);
break;
@@ -638,11 +644,13 @@ void UI_DisplayMenu(void)
if (valid && !gAskForConfirmation)
{ // show the frequency so that the user knows the channels frequency
const uint32_t frequency = BOARD_fetchChannelFrequency(gSubMenuSelection);
const uint32_t frequency = SETTINGS_FetchChannelFrequency(gSubMenuSelection);
sprintf(String, "%u.%05u", frequency / 100000, frequency % 100000);
UI_PrintString(String, menu_item_x1, menu_item_x2, 4, 8);
}
SETTINGS_FetchChannelName(String, gSubMenuSelection);
UI_PrintString(String[0] ? String : "--", menu_item_x1, menu_item_x2, 2, 8);
already_printed = true;
break;
}
@@ -656,29 +664,25 @@ void UI_DisplayMenu(void)
if (valid)
{
const uint32_t frequency = BOARD_fetchChannelFrequency(gSubMenuSelection);
const uint32_t frequency = SETTINGS_FetchChannelFrequency(gSubMenuSelection);
if (!gIsInSubMenu || edit_index < 0)
{ // show the channel name
BOARD_fetchChannelName(String, gSubMenuSelection);
if (String[0] == 0)
strcpy(String, "--");
UI_PrintString(String, menu_item_x1, menu_item_x2, 2, 8);
SETTINGS_FetchChannelName(String, gSubMenuSelection);
char *pPrintStr = String[0] ? String : "--";
UI_PrintString(pPrintStr, menu_item_x1, menu_item_x2, 2, 8);
}
else
{ // show the channel name being edited
UI_PrintString(edit, menu_item_x1, 0, 2, 8);
if (edit_index < 10)
UI_PrintString( "^", menu_item_x1 + (8 * edit_index), 0, 4, 8); // show the cursor
UI_PrintString("^", menu_item_x1 + (8 * edit_index), 0, 4, 8); // show the cursor
}
if (!gAskForConfirmation)
{ // show the frequency so that the user knows the channels frequency
sprintf(String, "%u.%05u", frequency / 100000, frequency % 100000);
if (!gIsInSubMenu || edit_index < 0)
UI_PrintString(String, menu_item_x1, menu_item_x2, 4, 8);
else
UI_PrintString(String, menu_item_x1, menu_item_x2, 5, 8);
UI_PrintString(String, menu_item_x1, menu_item_x2, 4 + (gIsInSubMenu && edit_index >= 0), 8);
}
}
@@ -732,18 +736,20 @@ void UI_DisplayMenu(void)
break;
#endif
#ifdef ENABLE_DTMF_CALLING
case MENU_ANI_ID:
strcpy(String, gEeprom.ANI_DTMF_ID);
break;
#endif
case MENU_UPCODE:
strcpy(String, gEeprom.DTMF_UP_CODE);
sprintf(String, "%.8s\n%.8s", gEeprom.DTMF_UP_CODE, gEeprom.DTMF_UP_CODE + 8);
break;
case MENU_DWCODE:
strcpy(String, gEeprom.DTMF_DOWN_CODE);
sprintf(String, "%.8s\n%.8s", gEeprom.DTMF_DOWN_CODE, gEeprom.DTMF_DOWN_CODE + 8);
break;
#ifdef ENABLE_DTMF_CALLING
case MENU_D_RSP:
strcpy(String, gSubMenu_D_RSP[gSubMenuSelection]);
break;
@@ -751,7 +757,7 @@ void UI_DisplayMenu(void)
case MENU_D_HOLD:
sprintf(String, "%ds", gSubMenuSelection);
break;
#endif
case MENU_D_PRE:
sprintf(String, "%d*10ms", gSubMenuSelection);
break;
@@ -764,13 +770,15 @@ void UI_DisplayMenu(void)
strcpy(String, gSubMenu_BAT_TXT[gSubMenuSelection]);
break;
#ifdef ENABLE_DTMF_CALLING
case MENU_D_LIST:
gIsDtmfContactValid = DTMF_GetContact((int)gSubMenuSelection - 1, Contact);
if (!gIsDtmfContactValid)
strcpy(String, "NULL");
else
memmove(String, Contact, 8);
memcpy(String, Contact, 8);
break;
#endif
case MENU_PONMSG:
strcpy(String, gSubMenu_PONMSG[gSubMenuSelection]);
@@ -791,7 +799,10 @@ void UI_DisplayMenu(void)
break;
case MENU_F_LOCK:
strcpy(String, gSubMenu_F_LOCK[gSubMenuSelection]);
if(!gIsInSubMenu && gUnlockAllTxConfCnt>0 && gUnlockAllTxConfCnt<10)
strcpy(String, "READ\nMANUAL");
else
strcpy(String, gSubMenu_F_LOCK[gSubMenuSelection]);
break;
#ifdef ENABLE_F_CAL_MENU
@@ -818,7 +829,7 @@ void UI_DisplayMenu(void)
case MENU_BATTYP:
strcpy(String, gSubMenu_BATTYP[gSubMenuSelection]);
break;
break;
case MENU_F1SHRT:
case MENU_F1LONG:
@@ -867,7 +878,7 @@ void UI_DisplayMenu(void)
for (i = 0; i < len && lines > 0; lines--)
{
if (small)
UI_PrintStringSmall(String + i, menu_item_x1, menu_item_x2, y);
UI_PrintStringSmallNormal(String + i, menu_item_x1, menu_item_x2, y);
else
UI_PrintString(String + i, menu_item_x1, menu_item_x2, y, 8);
@@ -884,100 +895,73 @@ void UI_DisplayMenu(void)
}
}
if (GetCurrentMenuId() == MENU_SLIST1 || GetCurrentMenuId() == MENU_SLIST2)
if (UI_MENU_GetCurrentMenuId() == MENU_SLIST1 || UI_MENU_GetCurrentMenuId() == MENU_SLIST2)
{
i = (GetCurrentMenuId() == MENU_SLIST1) ? 0 : 1;
i = (UI_MENU_GetCurrentMenuId() == MENU_SLIST1) ? 0 : 1;
char *pPrintStr = String;
// if (gSubMenuSelection == 0xFF)
if (gSubMenuSelection < 0)
strcpy(String, "NULL");
else
if (gSubMenuSelection < 0) {
pPrintStr = "NULL";
} else {
UI_GenerateChannelStringEx(String, true, gSubMenuSelection);
// if (gSubMenuSelection == 0xFF || !gEeprom.SCAN_LIST_ENABLED[i])
if (gSubMenuSelection < 0 || !gEeprom.SCAN_LIST_ENABLED[i])
{
// channel number
UI_PrintString(String, menu_item_x1, menu_item_x2, 0, 8);
// channel name
BOARD_fetchChannelName(String, gSubMenuSelection);
if (String[0] == 0)
strcpy(String, "--");
UI_PrintString(String, menu_item_x1, menu_item_x2, 2, 8);
pPrintStr = String;
}
else
{
// channel number
UI_PrintString(String, menu_item_x1, menu_item_x2, 0, 8);
// channel name
BOARD_fetchChannelName(String, gSubMenuSelection);
if (String[0] == 0)
strcpy(String, "--");
UI_PrintStringSmall(String, menu_item_x1, menu_item_x2, 2);
// channel number
UI_PrintString(pPrintStr, menu_item_x1, menu_item_x2, 0, 8);
if (IS_MR_CHANNEL(gEeprom.SCANLIST_PRIORITY_CH1[i]))
{
sprintf(String, "PRI1:%u", gEeprom.SCANLIST_PRIORITY_CH1[i] + 1);
SETTINGS_FetchChannelName(String, gSubMenuSelection);
pPrintStr = String[0] ? String : "--";
// channel name and scan-list
if (gSubMenuSelection < 0 || !gEeprom.SCAN_LIST_ENABLED[i]) {
UI_PrintString(pPrintStr, menu_item_x1, menu_item_x2, 2, 8);
} else {
UI_PrintStringSmallNormal(pPrintStr, menu_item_x1, menu_item_x2, 2);
if (IS_MR_CHANNEL(gEeprom.SCANLIST_PRIORITY_CH1[i])) {
sprintf(String, "PRI%d:%u", 1, gEeprom.SCANLIST_PRIORITY_CH1[i] + 1);
UI_PrintString(String, menu_item_x1, menu_item_x2, 3, 8);
}
if (IS_MR_CHANNEL(gEeprom.SCANLIST_PRIORITY_CH2[i]))
{
sprintf(String, "PRI2:%u", gEeprom.SCANLIST_PRIORITY_CH2[i] + 1);
if (IS_MR_CHANNEL(gEeprom.SCANLIST_PRIORITY_CH2[i])) {
sprintf(String, "PRI%d:%u", 2, gEeprom.SCANLIST_PRIORITY_CH2[i] + 1);
UI_PrintString(String, menu_item_x1, menu_item_x2, 5, 8);
}
}
}
if (GetCurrentMenuId() == MENU_MEM_CH ||
GetCurrentMenuId() == MENU_DEL_CH ||
GetCurrentMenuId() == MENU_1_CALL)
{ // display the channel name
char s[11];
BOARD_fetchChannelName(s, gSubMenuSelection);
if (s[0] == 0)
strcpy(s, "--");
UI_PrintString(s, menu_item_x1, menu_item_x2, 2, 8);
}
if ((GetCurrentMenuId() == MENU_R_CTCS || GetCurrentMenuId() == MENU_R_DCS) && gCssScanMode != CSS_SCAN_MODE_OFF)
if ((UI_MENU_GetCurrentMenuId() == MENU_R_CTCS || UI_MENU_GetCurrentMenuId() == MENU_R_DCS) && gCssBackgroundScan)
UI_PrintString("SCAN", menu_item_x1, menu_item_x2, 4, 8);
if (GetCurrentMenuId() == MENU_UPCODE)
if (strlen(gEeprom.DTMF_UP_CODE) > 8)
UI_PrintString(gEeprom.DTMF_UP_CODE + 8, menu_item_x1, menu_item_x2, 4, 8);
if (GetCurrentMenuId() == MENU_DWCODE)
if (strlen(gEeprom.DTMF_DOWN_CODE) > 8)
UI_PrintString(gEeprom.DTMF_DOWN_CODE + 8, menu_item_x1, menu_item_x2, 4, 8);
if (GetCurrentMenuId() == MENU_D_LIST && gIsDtmfContactValid)
{
#ifdef ENABLE_DTMF_CALLING
if (UI_MENU_GetCurrentMenuId() == MENU_D_LIST && gIsDtmfContactValid) {
Contact[11] = 0;
memmove(&gDTMF_ID, Contact + 8, 4);
sprintf(String, "ID:%s", Contact + 8);
memcpy(&gDTMF_ID, Contact + 8, 4);
sprintf(String, "ID:%4s", gDTMF_ID);
UI_PrintString(String, menu_item_x1, menu_item_x2, 4, 8);
}
#endif
if (GetCurrentMenuId() == MENU_R_CTCS ||
GetCurrentMenuId() == MENU_T_CTCS ||
GetCurrentMenuId() == MENU_R_DCS ||
GetCurrentMenuId() == MENU_T_DCS ||
GetCurrentMenuId() == MENU_D_LIST)
{
if (UI_MENU_GetCurrentMenuId() == MENU_R_CTCS ||
UI_MENU_GetCurrentMenuId() == MENU_T_CTCS ||
UI_MENU_GetCurrentMenuId() == MENU_R_DCS ||
UI_MENU_GetCurrentMenuId() == MENU_T_DCS
#ifdef ENABLE_DTMF_CALLING
|| UI_MENU_GetCurrentMenuId() == MENU_D_LIST
#endif
) {
sprintf(String, "%2d", gSubMenuSelection);
UI_PrintStringSmall(String, 105, 0, 0);
UI_PrintStringSmallNormal(String, 105, 0, 0);
}
if ((GetCurrentMenuId() == MENU_RESET ||
GetCurrentMenuId() == MENU_MEM_CH ||
GetCurrentMenuId() == MENU_MEM_NAME ||
GetCurrentMenuId() == MENU_DEL_CH) && gAskForConfirmation)
if ((UI_MENU_GetCurrentMenuId() == MENU_RESET ||
UI_MENU_GetCurrentMenuId() == MENU_MEM_CH ||
UI_MENU_GetCurrentMenuId() == MENU_MEM_NAME ||
UI_MENU_GetCurrentMenuId() == MENU_DEL_CH) && gAskForConfirmation)
{ // display confirmation
strcpy(String, (gAskForConfirmation == 1) ? "SURE?" : "WAIT!");
UI_PrintString(String, menu_item_x1, menu_item_x2, 5, 8);
char *pPrintStr = (gAskForConfirmation == 1) ? "SURE?" : "WAIT!";
UI_PrintString(pPrintStr, menu_item_x1, menu_item_x2, 5, 8);
}
ST7565_BlitFullScreen();

View File

@@ -21,6 +21,7 @@
#include <stdint.h>
#include "audio.h" // VOICE_ID_t
#include "settings.h"
typedef struct {
const char name[7]; // menu display area only has room for 6 characters
@@ -78,16 +79,22 @@ enum
#ifdef ENABLE_ALARM
MENU_AL_MOD,
#endif
#ifdef ENABLE_DTMF_CALLING
MENU_ANI_ID,
#endif
MENU_UPCODE,
MENU_DWCODE,
MENU_PTT_ID,
MENU_D_ST,
#ifdef ENABLE_DTMF_CALLING
MENU_D_RSP,
MENU_D_HOLD,
#endif
MENU_D_PRE,
#ifdef ENABLE_DTMF_CALLING
MENU_D_DCD,
MENU_D_LIST,
#endif
MENU_D_LIVE_DEC,
MENU_PONMSG,
MENU_ROGER,
@@ -97,9 +104,6 @@ enum
#ifdef ENABLE_AM_FIX
MENU_AM_FIX,
#endif
#ifdef ENABLE_AM_FIX_TEST1
MENU_AM_FIX_TEST1,
#endif
#ifdef ENABLE_NOAA
MENU_NOAA_S,
#endif
@@ -110,8 +114,6 @@ enum
MENU_500TX,
MENU_350EN,
MENU_SCREN,
MENU_TX_EN, // enable TX
#ifdef ENABLE_F_CAL_MENU
MENU_F_CALI, // reference xtal calibration
#endif
@@ -133,40 +135,38 @@ extern const char gSubMenu_W_N[2][7];
extern const char gSubMenu_OFF_ON[2][4];
extern const char gSubMenu_SAVE[5][4];
extern const char gSubMenu_TOT[11][7];
extern const char* gSubMenu_RXMode[4];
extern const char* const gSubMenu_RXMode[4];
#ifdef ENABLE_VOICE
extern const char gSubMenu_VOICE[3][4];
#endif
extern const char gSubMenu_SC_REV[3][8];
extern const char* gSubMenu_MDF[4];
extern const char* const gSubMenu_MDF[4];
#ifdef ENABLE_ALARM
extern const char gSubMenu_AL_MOD[2][5];
#endif
#ifdef ENABLE_DTMF_CALLING
extern const char gSubMenu_D_RSP[4][11];
extern const char* gSubMenu_PTT_ID[5];
#endif
extern const char* const gSubMenu_PTT_ID[5];
extern const char gSubMenu_PONMSG[4][8];
extern const char* gSubMenu_ROGER[3];
extern const char gSubMenu_ROGER[3][6];
extern const char gSubMenu_RESET[2][4];
extern const char gSubMenu_F_LOCK[6][4];
extern const char* const gSubMenu_F_LOCK[F_LOCK_LEN];
extern const char gSubMenu_BACKLIGHT[8][7];
extern const char gSubMenu_RX_TX[4][6];
#ifdef ENABLE_AM_FIX_TEST1
extern const char gSubMenu_AM_fix_test1[4][8];
#endif
extern const char gSubMenu_BAT_TXT[3][8];
extern const char gSubMenu_BATTYP[2][9];
extern const char gSubMenu_SCRAMBLER[11][7];
typedef struct {char* name; uint8_t id;} t_sidefunction;
extern const uint8_t gSubMenu_SIDEFUNCTIONS_size;
extern const t_sidefunction* gSubMenu_SIDEFUNCTIONS;
extern const t_sidefunction gSubMenu_SIDEFUNCTIONS[];
extern bool gIsInSubMenu;
extern uint8_t gMenuCursor;
int GetCurrentMenuId();
extern int8_t gMenuScrollDirection;
extern int32_t gSubMenuSelection;
extern char edit_original[17];
@@ -174,5 +174,7 @@ extern char edit[17];
extern int edit_index;
void UI_DisplayMenu(void);
int UI_MENU_GetCurrentMenuId();
uint8_t UI_MENU_GetMenuIdx(uint8_t id);
#endif

View File

@@ -26,60 +26,58 @@
void UI_DisplayScanner(void)
{
char String[16];
bool bCentered;
char String[16] = {0};
char *pPrintStr = String;
bool bCentered;
uint8_t Start;
memset(gFrameBuffer, 0, sizeof(gFrameBuffer));
UI_DisplayClear();
memset(String, 0, sizeof(String));
if (gScanSingleFrequency || (gScanCssState != SCAN_CSS_STATE_OFF && gScanCssState != SCAN_CSS_STATE_FAILED))
if (gScanSingleFrequency || (gScanCssState != SCAN_CSS_STATE_OFF && gScanCssState != SCAN_CSS_STATE_FAILED)) {
sprintf(String, "FREQ:%u.%05u", gScanFrequency / 100000, gScanFrequency % 100000);
else
strcpy(String, "FREQ:**.*****");
UI_PrintString(String, 2, 0, 1, 8);
pPrintStr = String;
} else {
pPrintStr = "FREQ:**.*****";
}
memset(String, 0, sizeof(String));
if (gScanCssState < SCAN_CSS_STATE_FOUND || !gScanUseCssResult)
strcpy(String, "CTC:******");
else
if (gScanCssResultType == CODE_TYPE_CONTINUOUS_TONE)
UI_PrintString(pPrintStr, 2, 0, 1, 8);
if (gScanCssState < SCAN_CSS_STATE_FOUND || !gScanUseCssResult) {
pPrintStr = "CTC:******";
} else if (gScanCssResultType == CODE_TYPE_CONTINUOUS_TONE) {
sprintf(String, "CTC:%u.%uHz", CTCSS_Options[gScanCssResultCode] / 10, CTCSS_Options[gScanCssResultCode] % 10);
else
pPrintStr = String;
} else {
sprintf(String, "DCS:D%03oN", DCS_Options[gScanCssResultCode]);
UI_PrintString(String, 2, 0, 3, 8);
pPrintStr = String;
}
UI_PrintString(pPrintStr, 2, 0, 3, 8);
memset(String, 0, sizeof(String));
if (gScannerEditState == 2)
{
strcpy(String, "SAVE?");
if (gScannerSaveState == SCAN_SAVE_CHANNEL) {
pPrintStr = "SAVE?";
Start = 0;
bCentered = 1;
}
else
{
if (gScannerEditState == 1)
{
strcpy(String, "SAVE:");
UI_GenerateChannelStringEx(String + 5, gShowChPrefix, gScanChannel);
}
else
if (gScanCssState < SCAN_CSS_STATE_FOUND)
{
strcpy(String, "SCAN");
memset(String + 4, '.', (gScanProgressIndicator & 7) + 1);
}
else
if (gScanCssState == SCAN_CSS_STATE_FOUND)
strcpy(String, "SCAN CMP.");
else
strcpy(String, "SCAN FAIL.");
} else {
Start = 2;
bCentered = 0;
if (gScannerSaveState == SCAN_SAVE_CHAN_SEL) {
strcpy(String, "SAVE:");
UI_GenerateChannelStringEx(String + 5, gShowChPrefix, gScanChannel);
pPrintStr = String;
} else if (gScanCssState < SCAN_CSS_STATE_FOUND) {
strcpy(String, "SCAN");
memset(String + 4, '.', (gScanProgressIndicator & 7) + 1);
pPrintStr = String;
} else if (gScanCssState == SCAN_CSS_STATE_FOUND) {
pPrintStr = "SCAN CMP.";
} else {
pPrintStr = "SCAN FAIL.";
}
}
UI_PrintString(String, Start, bCentered ? 127 : 0, 5, 8);
UI_PrintString(pPrintStr, Start, bCentered ? 127 : 0, 5, 8);
ST7565_BlitFullScreen();
}

View File

@@ -16,10 +16,11 @@
#include <string.h>
#include "app/scanner.h"
#include "app/chFrScanner.h"
#ifdef ENABLE_FMRADIO
#include "app/fm.h"
#endif
#include "app/scanner.h"
#include "bitmaps.h"
#include "driver/keyboard.h"
#include "driver/st7565.h"
@@ -35,181 +36,152 @@
void UI_DisplayStatus()
{
uint8_t *line = gStatusLine;
unsigned int x = 0;
unsigned int x1 = 0;
gUpdateStatus = false;
memset(gStatusLine, 0, sizeof(gStatusLine));
uint8_t *line = gStatusLine;
unsigned int x = 0;
// **************
// POWER-SAVE indicator
if (gCurrentFunction == FUNCTION_TRANSMIT)
{
memmove(line + x, BITMAP_TX, sizeof(BITMAP_TX));
x1 = x + sizeof(BITMAP_TX);
if (gCurrentFunction == FUNCTION_TRANSMIT) {
memcpy(line + x, BITMAP_TX, sizeof(BITMAP_TX));
}
else
if (gCurrentFunction == FUNCTION_RECEIVE ||
gCurrentFunction == FUNCTION_MONITOR ||
gCurrentFunction == FUNCTION_INCOMING)
{
memmove(line + x, BITMAP_RX, sizeof(BITMAP_RX));
x1 = x + sizeof(BITMAP_RX);
else if (FUNCTION_IsRx()) {
memcpy(line + x, BITMAP_RX, sizeof(BITMAP_RX));
}
else
if (gCurrentFunction == FUNCTION_POWER_SAVE)
{
memmove(line + x, BITMAP_POWERSAVE, sizeof(BITMAP_POWERSAVE));
x1 = x + sizeof(BITMAP_POWERSAVE);
else if (gCurrentFunction == FUNCTION_POWER_SAVE) {
memcpy(line + x, BITMAP_POWERSAVE, sizeof(BITMAP_POWERSAVE));
}
x += sizeof(BITMAP_POWERSAVE);
x += 8;
unsigned int x1 = x;
#ifdef ENABLE_NOAA
// NOASS SCAN indicator
if (gIsNoaaMode)
{
memmove(line + x, BITMAP_NOAA, sizeof(BITMAP_NOAA));
x1 = x + sizeof(BITMAP_NOAA);
}
x += sizeof(BITMAP_NOAA);
#else
// hmmm, what to put in it's place
#endif
if (gSetting_KILLED)
{
#ifdef ENABLE_NOAA
if (gIsNoaaMode) { // NOASS SCAN indicator
memcpy(line + x, BITMAP_NOAA, sizeof(BITMAP_NOAA));
x1 = x + sizeof(BITMAP_NOAA);
}
x += sizeof(BITMAP_NOAA);
#endif
#ifdef ENABLE_DTMF_CALLING
if (gSetting_KILLED) {
memset(line + x, 0xFF, 10);
x1 = x + 10;
}
else
// SCAN indicator
if (gScanStateDir != SCAN_OFF || gScreenToDisplay == DISPLAY_SCANNER)
{
#endif
#ifdef ENABLE_FMRADIO
if (gFmRadioMode) { // FM indicator
memcpy(line + x, BITMAP_FM, sizeof(BITMAP_FM));
x1 = x + sizeof(BITMAP_FM);
}
else
#endif
{ // SCAN indicator
if (gScanStateDir != SCAN_OFF || SCANNER_IsScanning()) {
char * s = "";
if (IS_MR_CHANNEL(gNextMrChannel) && gScreenToDisplay != DISPLAY_SCANNER)
{ // channel mode
if (IS_MR_CHANNEL(gNextMrChannel) && !SCANNER_IsScanning()) { // channel mode
switch(gEeprom.SCAN_LIST_DEFAULT) {
case 0: s = "1"; break;
case 1: s = "2"; break;
case 2: s = "*"; break;
}
}
else
{ // frequency mode
else { // frequency mode
s = "S";
}
UI_PrintStringSmallBuffer(s, line + x);
x1 = x + 7;
}
x += 7; // font character width
#ifdef ENABLE_VOICE
// VOICE indicator
if (gEeprom.VOICE_PROMPT != VOICE_PROMPT_OFF)
{
memmove(line + x, BITMAP_VoicePrompt, sizeof(BITMAP_VoicePrompt));
x1 = x + sizeof(BITMAP_VoicePrompt);
}
x += sizeof(BITMAP_VoicePrompt) + 1;
#else
// hmmm, what to put in it's place
#endif
x++;
if(gScreenToDisplay != DISPLAY_SCANNER) {
uint8_t dw = (gEeprom.DUAL_WATCH != DUAL_WATCH_OFF) + (gEeprom.CROSS_BAND_RX_TX != CROSS_BAND_OFF) * 2;
if(dw == 1 || dw == 3) { // DWR - dual watch + respond
if(gDualWatchActive)
memmove(line + x, BITMAP_TDR1, sizeof(BITMAP_TDR1) - (dw==1?0:5));
else
memmove(line + x + 3, BITMAP_TDR2, sizeof(BITMAP_TDR2));
}
else if(dw == 2) { // XB - crossband
memmove(line + x, BITMAP_XB, sizeof(BITMAP_XB));
UI_PrintStringSmallBufferNormal(s, line + x + 1);
x1 = x + 10;
}
}
x += sizeof(BITMAP_TDR1) + 2;
#ifdef ENABLE_VOX
// VOX indicator
if (gEeprom.VOX_SWITCH)
{
memmove(line + x, BITMAP_VOX, sizeof(BITMAP_VOX));
x1 = x + sizeof(BITMAP_VOX);
}
x += sizeof(BITMAP_VOX) + 2;
#endif
x += 10; // font character width
x = MAX(x, 61u);
x1 = x;
#ifdef ENABLE_VOICE
// VOICE indicator
if (gEeprom.VOICE_PROMPT != VOICE_PROMPT_OFF){
memcpy(line + x, BITMAP_VoicePrompt, sizeof(BITMAP_VoicePrompt));
x1 = x + sizeof(BITMAP_VoicePrompt);
}
x += sizeof(BITMAP_VoicePrompt);
#endif
if(!SCANNER_IsScanning()) {
uint8_t dw = (gEeprom.DUAL_WATCH != DUAL_WATCH_OFF) + (gEeprom.CROSS_BAND_RX_TX != CROSS_BAND_OFF) * 2;
if(dw == 1 || dw == 3) { // DWR - dual watch + respond
if(gDualWatchActive)
memcpy(line + x + (dw==1?0:2), BITMAP_TDR1, sizeof(BITMAP_TDR1) - (dw==1?0:5));
else
memcpy(line + x + 3, BITMAP_TDR2, sizeof(BITMAP_TDR2));
}
else if(dw == 2) { // XB - crossband
memcpy(line + x + 2, BITMAP_XB, sizeof(BITMAP_XB));
}
}
x += sizeof(BITMAP_TDR1) + 1;
#ifdef ENABLE_VOX
// VOX indicator
if (gEeprom.VOX_SWITCH) {
memcpy(line + x, BITMAP_VOX, sizeof(BITMAP_VOX));
x1 = x + sizeof(BITMAP_VOX) + 1;
}
x += sizeof(BITMAP_VOX) + 1;
#endif
x = MAX(x1, 61u);
// KEY-LOCK indicator
if (gEeprom.KEY_LOCK)
{
memmove(line + x, BITMAP_KeyLock, sizeof(BITMAP_KeyLock));
if (gEeprom.KEY_LOCK) {
memcpy(line + x, BITMAP_KeyLock, sizeof(BITMAP_KeyLock));
x += sizeof(BITMAP_KeyLock);
x1 = x;
}
else
if (gWasFKeyPressed)
{
memmove(line + x, BITMAP_F_Key, sizeof(BITMAP_F_Key));
else if (gWasFKeyPressed) {
memcpy(line + x, BITMAP_F_Key, sizeof(BITMAP_F_Key));
x += sizeof(BITMAP_F_Key);
x1 = x;
}
{ // battery voltage or percentage
char s[8];
unsigned int space_needed;
unsigned int x2 = LCD_WIDTH - sizeof(BITMAP_BatteryLevel1) - 3;
char s[8] = "";
unsigned int x2 = LCD_WIDTH - sizeof(BITMAP_BatteryLevel1) - 0;
if (gChargingWithTypeC)
x2 -= sizeof(BITMAP_USB_C); // the radio is on charge
switch (gSetting_battery_text)
{
switch (gSetting_battery_text) {
default:
case 0:
break;
case 1: // voltage
{
case 1: { // voltage
const uint16_t voltage = (gBatteryVoltageAverage <= 999) ? gBatteryVoltageAverage : 999; // limit to 9.99V
sprintf(s, "%u.%02uV", voltage / 100, voltage % 100);
space_needed = (7 * strlen(s));
if (x2 >= (x1 + space_needed))
{
UI_PrintStringSmallBuffer(s, line + x2 - space_needed);
}
break;
}
case 2: // percentage
{
sprintf(s, "%u%%", BATTERY_VoltsToPercent(gBatteryVoltageAverage));
space_needed = (7 * strlen(s));
if (x2 >= (x1 + space_needed))
UI_PrintStringSmallBuffer(s, line + x2 - space_needed);
break;
}
}
unsigned int space_needed = (7 * strlen(s));
if (x2 >= (x1 + space_needed))
UI_PrintStringSmallBufferNormal(s, line + x2 - space_needed);
}
// move to right side of the screen
x = LCD_WIDTH - sizeof(BITMAP_BatteryLevel1) - sizeof(BITMAP_USB_C);
// USB-C charge indicator
if (gChargingWithTypeC)
memmove(line + x, BITMAP_USB_C, sizeof(BITMAP_USB_C));
memcpy(line + x, BITMAP_USB_C, sizeof(BITMAP_USB_C));
x += sizeof(BITMAP_USB_C);
// BATTERY LEVEL indicator
UI_DrawBattery(line + x, gBatteryDisplayLevel, gLowBatteryBlink);
// **************
ST7565_BlitStatusLine();

53
ui/ui.c
View File

@@ -14,13 +14,14 @@
* limitations under the License.
*/
#include <assert.h>
#include <string.h>
#include "app/chFrScanner.h"
#include "app/dtmf.h"
#ifdef ENABLE_FMRADIO
#include "app/fm.h"
#endif
#include "app/scanner.h"
#include "driver/keyboard.h"
#include "misc.h"
#ifdef ENABLE_AIRCOPY
@@ -34,6 +35,7 @@
#include "ui/menu.h"
#include "ui/scanner.h"
#include "ui/ui.h"
#include "../misc.h"
GUI_DisplayType_t gScreenToDisplay;
GUI_DisplayType_t gRequestDisplayScreen = DISPLAY_INVALID;
@@ -42,36 +44,27 @@ uint8_t gAskForConfirmation;
bool gAskToSave;
bool gAskToDelete;
void (*UI_DisplayFunctions[])(void) = {
[DISPLAY_MAIN] = &UI_DisplayMain,
[DISPLAY_MENU] = &UI_DisplayMenu,
[DISPLAY_SCANNER] = &UI_DisplayScanner,
#ifdef ENABLE_FMRADIO
[DISPLAY_FM] = &UI_DisplayFM,
#endif
#ifdef ENABLE_AIRCOPY
[DISPLAY_AIRCOPY] = &UI_DisplayAircopy,
#endif
};
static_assert(ARRAY_SIZE(UI_DisplayFunctions) == DISPLAY_N_ELEM);
void GUI_DisplayScreen(void)
{
switch (gScreenToDisplay)
{
case DISPLAY_MAIN:
UI_DisplayMain();
break;
#ifdef ENABLE_FMRADIO
case DISPLAY_FM:
UI_DisplayFM();
break;
#endif
case DISPLAY_MENU:
UI_DisplayMenu();
break;
case DISPLAY_SCANNER:
UI_DisplayScanner();
break;
#ifdef ENABLE_AIRCOPY
case DISPLAY_AIRCOPY:
UI_DisplayAircopy();
break;
#endif
default:
break;
if (gScreenToDisplay != DISPLAY_INVALID) {
UI_DisplayFunctions[gScreenToDisplay]();
}
}
@@ -86,7 +79,7 @@ void GUI_SelectNextDisplay(GUI_DisplayType_t Display)
gInputBoxIndex = 0;
gIsInSubMenu = false;
gCssScanMode = CSS_SCAN_MODE_OFF;
gCssBackgroundScan = false;
gScanStateDir = SCAN_OFF;
#ifdef ENABLE_FMRADIO
gFM_ScanState = FM_SCAN_OFF;

11
ui/ui.h
View File

@@ -23,10 +23,18 @@
enum GUI_DisplayType_t
{
DISPLAY_MAIN = 0,
DISPLAY_FM,
DISPLAY_MENU,
DISPLAY_SCANNER,
#ifdef ENABLE_FMRADIO
DISPLAY_FM,
#endif
#ifdef ENABLE_AIRCOPY
DISPLAY_AIRCOPY,
#endif
DISPLAY_N_ELEM,
DISPLAY_INVALID = 0xFFu
};
@@ -43,4 +51,3 @@ void GUI_DisplayScreen(void);
void GUI_SelectNextDisplay(GUI_DisplayType_t Display);
#endif

View File

@@ -30,7 +30,7 @@
void UI_DisplayReleaseKeys(void)
{
memset(gStatusLine, 0, sizeof(gStatusLine));
memset(gFrameBuffer, 0, sizeof(gFrameBuffer));
UI_DisplayClear();
UI_PrintString("RELEASE", 0, 127, 1, 10);
UI_PrintString("ALL KEYS", 0, 127, 3, 10);
@@ -43,21 +43,13 @@ void UI_DisplayWelcome(void)
{
char WelcomeString0[16];
char WelcomeString1[16];
memset(gStatusLine, 0, sizeof(gStatusLine));
memset(gFrameBuffer, 0, sizeof(gFrameBuffer));
if (gEeprom.POWER_ON_DISPLAY_MODE == POWER_ON_DISPLAY_MODE_NONE)
{
memset(gStatusLine, 0, sizeof(gStatusLine));
UI_DisplayClear();
if (gEeprom.POWER_ON_DISPLAY_MODE == POWER_ON_DISPLAY_MODE_NONE || gEeprom.POWER_ON_DISPLAY_MODE == POWER_ON_DISPLAY_MODE_FULL_SCREEN) {
ST7565_FillScreen(0xFF);
}
else
if (gEeprom.POWER_ON_DISPLAY_MODE == POWER_ON_DISPLAY_MODE_FULL_SCREEN)
{
ST7565_FillScreen(0xFF);
}
else
{
} else {
memset(WelcomeString0, 0, sizeof(WelcomeString0));
memset(WelcomeString1, 0, sizeof(WelcomeString1));
@@ -77,10 +69,9 @@ void UI_DisplayWelcome(void)
UI_PrintString(WelcomeString0, 0, 127, 0, 10);
UI_PrintString(WelcomeString1, 0, 127, 2, 10);
UI_PrintStringSmall(Version, 0, 0, 6);
UI_PrintStringSmallNormal(Version, 0, 128, 6);
ST7565_BlitStatusLine(); // blank status line
ST7565_BlitFullScreen();
}
}

View File

@@ -1,16 +1,11 @@
#define ONE_OF_ELEVEN_VER
#ifdef GIT_HASH
#define VER GIT_HASH
#ifdef VERSION_STRING
#define VER " "VERSION_STRING
#else
#define VER "231004"
#define VER ""
#endif
#ifndef ONE_OF_ELEVEN_VER
const char Version[] = "OEFW-"VER;
const char UART_Version[] = "UV-K5 Firmware, Open Edition, OEFW-"VER"\r\n";
#else
const char Version[] = "1o11+fagci-"VER;
const char UART_Version[] = "UV-K5 Firmware, Open Edition, 1o11+fagci-"VER"\r\n";
#endif
const char Version[] = AUTHOR_STRING VER;
const char UART_Version[] = "UV-K5 Firmware, Open Edition, " AUTHOR_STRING VER "\r\n";